Agentic UI: Keep a queued follow-up from vanishing when the agent is stopped - #4622
Agentic UI: Keep a queued follow-up from vanishing when the agent is stopped#4622shaunandrews wants to merge 3 commits into
Conversation
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
📊 Performance Test ResultsComparing 5f0454e vs trunk app-size
site-editor
site-startup
Results are median values from multiple test runs. Legend: 🟢 Improvement (faster) | 🔴 Regression (slower) | ⚪ No change (<50ms diff) |
There was a problem hiding this comment.
Pull request overview
Prevents queued follow-ups from disappearing or overlapping an interrupted agent run.
Changes:
- Waits for interrupted child processes to exit before continuing.
- Guards optimistic transcripts against stale refetches and abandoned events.
- Adds lifecycle and queued-handoff tests.
Reviewed changes
Copilot reviewed 8 out of 8 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
packages/common/ai/tests/run-manager.test.ts |
Tests interrupt completion behavior. |
packages/common/ai/run-manager.ts |
Adds exit-aware interruption. |
apps/ui/src/data/queries/use-agent-run.tsx |
Protects queued optimistic messages. |
apps/ui/src/data/queries/use-agent-run.test.tsx |
Covers queued-stop races. |
apps/studio/src/modules/ai-agent/run-manager.ts |
Propagates asynchronous interruption. |
apps/studio/src/ipc-handlers.ts |
Awaits interrupted process exit. |
apps/studio/src/components/studio-code-session/use-agent-run.tsx |
Applies transcript guards to Desktop. |
apps/local/src/index.ts |
Delays interrupt responses until exit. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
| api.post( '/runs/:runId/interrupt', async ( req: Request, res: Response ) => { | ||
| // Responds only once the child is gone, so the UI can safely start the | ||
| // session's next run when this resolves. | ||
| await runManager.interruptAgentRun( req.params.runId ); |
There was a problem hiding this comment.
🤖 Claude Code — finding accurate, deliberately deferred to a follow-up. Leaving this thread open to track it.
The divergence is real, but it is not reachable today:
apps/hosted/src/agent-runs.tsis a separate implementation, not the shared@studio/commonrun manager, so it did not inherit the contract change either way.- Its only runtime is
stubRuntime, which throws onstart(). No agent run can begin on the hosted backend, so no overlapping follow-up can occur. - Hosted runs are intended for a per-session remote sandbox rather than the same local session JSONL, so the two-writer hazard this promise guards against does not transfer unchanged.
Worth mirroring the awaited-exit contract before a real runtime is injected. Tracking that separately rather than expanding this PR.
…ches Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Related issues
How AI was used in this PR
Claude Code investigated the report, reproduced the race in a unit test against the unmodified code, wrote the fix and the tests. I reviewed the diff.
Proposed Changes
Stopping the agent while a follow-up is queued sends that follow-up right away — the agent visibly starts working on it — but the message itself disappeared from the conversation.
run.interrupted, which leaves therun.exitedthat always follows it unguarded.exit/close, never onerror— that event also fires for a failedsend()/kill()while the child is still alive and still writing. As a side effect this fixes a pre-existing hang: a child that fails to spawn emitscloseand neverexit, so the session slot stayed occupied forever and the UI never got arun.exited.Both front ends (Desktop and the agentic UI) had the bug and both are fixed. No visual changes.
Testing Instructions
Automated:
npm test -- apps/ui/src/data/queries/use-agent-run.test.tsx packages/common/ai/tests/run-manager.test.ts. The newkeeps a queued prompt when the interrupted run exits mid-startcase fails on trunk and passes here.Not run:
npm run e2e(no coverage of this flow) and the agent evals — this changes run-lifecycle plumbing, not agent-facing prompts, tools, or result shapes.Pre-merge Checklist
🤖 Generated with Claude Code