fix(server): Grok replies finish when Grok finishes them, not when background work does - #13728
Conversation
…ckground work does When Grok's prompt ends while a background subagent or monitor keeps running, the ACP adapter holds the run open for that work but left the last assistant message streaming until the next item or the run's end. A short final reply like ROOT_DONE stayed "streaming" until the background work finished. Close the turn's text streams when the prompt settles into the deferred hold. The run stays open for background work as before. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
ApprovabilityVerdict: Approved at Macroscope's review found this PR approvable — This focused Grok server fix closes the assistant message when the prompt completes while preserving the run for background work, with a targeted regression assertion covering the timing. The remaining change is test-only, and no defaults, schemas, infrastructure, or static-analysis settings are modified. You can add or adjust custom eligibility rules. Learn more. |
Thread transfer impact✅ Thread transfer remains within every enforced ceiling.
Baseline: unavailable · PR result: Scenario and decoded snapshot size10 historical turns, 5 command tools per turn, 878.9 KiB retained MCP result per historical turn, and a 1.05 MiB retained result in the measured turn.
Updated in place by a trusted workflow. PR artifacts are strictly validated and never executed. |
f969b21
into
t3code/codex-turn-mapping
When Grok ends its prompt while a background subagent or monitor keeps running, the ACP adapter keeps the run open for that work (#13594, #13609). But it also left the last assistant message streaming, because it closes a text stream only when the next item starts or the run ends. In the maintainer's live thread, Grok's reply
ROOT_DONEshowed as streaming from 22:57:10 until 22:57:33, and completed only after the subagent finished at 22:57:31. In the monitor run it streamed from 22:58:37 until 22:58:44, when the first monitor tick arrived.Fix
When the prompt ends and the adapter holds the run for background work (
deferFinalizeForBackgroundWork, Grok only), it now closes the turn's text streams right away. Grok ends the reply with its prompt:session/promptresolves, or theturn_completed/prompt_completenotifications for that prompt id settle it throughmakeXAiPromptCompletionRuntime. So the reply completes then, not when the background work does. The run stays open exactly as before. Anything Grok sends later in the run opens a new segment, as it already did after a tool call.Proof
grok_background_subagent(recorded live) now asserts that the root run'sROOT_DONEassistant item completes before the subagent completes.AssertionError: ROOT_DONE streamed until the subagent finished: expected 160 to be below 157.I added no such assertion to
grok_monitor, because it would pass without the fix. The replay feeds recorded frames back to back, so the first monitor tick (a new tool update) already closes the reply before the monitor completes. Live, that tick came 7 s later (22:58:44), which is the gap this fix removes. Only the subagent recording can tell the two behaviors apart, since its later frames are on the child session and never close root text.Verification
vp test run src/orchestration-v2/testkit/OrchestratorReplayFixtures.integration.test.ts -t "grok|acp": 21 passedvp test run src/orchestration-v2/Adapters/AcpAdapterV2.test.ts src/orchestration-v2/Adapters/GrokAdapterV2.test.ts src/orchestration-v2/testkit/OrchestratorReplayFixtures.contract.test.ts: 133 passedvp exec tsc --noEmit -p .(apps/server): noerror TS/warning TSvp run knip:check: cleanvp linton the touched files: only the existing unusedNodePathimport warning in AcpAdapterV2.tsModel: Claude Opus 5.5 (Claude Code)
🤖 Generated with Claude Code