Skip to content

fix(server): Grok background shell commands stay in the run that started them - #13789

Merged
juliusmarminge merged 1 commit into
t3code/codex-turn-mappingfrom
t3code/grok-background-bash-run
Sep 26, 2026
Merged

juliusmarminge merged 1 commit into
t3code/codex-turn-mappingfrom
t3code/grok-background-bash-run

Conversation

@juliusmarminge

@juliusmarminge juliusmarminge commented Sep 26, 2026 •

Copy link
Copy Markdown
Member

When Grok runs a shell command in the background, T3 shows the command as finished the moment it starts. When the command really ends, T3 moves it out of the run that started it into an empty extra run, so the thread shows an extra "Worked for" fold and the command appears in the wrong place.

Seen live on a Supervised Grok 4.7 Fast thread ("start for i in 1..6; do echo tock-$i; sleep 10; done in the background, reply 'started'"). The projection kept the command row at its run 2 ordinal but moved its runId to run 3, Grok's own task-completed-* wake run:

ordinal  type               status     run
2000004  command_execution  completed  run:…:ordinal:3   output "tock-1 … tock-6"
2000007  assistant_message  completed  run:…:ordinal:2   "started"
3000001  notification       completed  run:…:ordinal:3
3000005  assistant_message  completed  run:…:ordinal:3   "The last tock was tock-6."

Why

Grok acknowledges a background shell command with a completed tool update carrying rawOutput: { type: "BackgroundTaskStarted", task_id } while the process keeps running (crates/codegen/xai-grok-shell/src/session/acp_conversion.rs:340 at f0e3be1; the bash tool returns it for both is_background and the auto-background timeout, crates/codegen/xai-grok-tools/src/implementations/grok_build/bash/mod.rs:1885). It then streams the command's output as in_progress Bash frames on the same tool call and ends it only with x.ai/task_completed for that task_id.

GrokAdapterV2 already tracks monitors this way. It did not recognise BackgroundTaskStarted, so the start acknowledgement completed the command, the root run finished without waiting for it, and the first late output frame opened a synthetic continuation run that took over the command row. Grok's real wake reply then opened another run.

What changed

extractXAiMonitorTaskId and normalizeXAiAcpToolCallState treat a BackgroundTaskStarted acknowledgement like a monitor start: the task id is registered and the tool stays in progress. From there the existing monitor path holds the run open until x.ai/task_completed, hydrates the output, and leaves Grok's reply to a single continuation run.

Verification

  • New replay fixture grok_background_bash, recorded live with scripts/record-grok-acp-replay-fixture.ts against Grok 1.0.41 and grok-4.7-build-fast. It asserts 2 runs, the command in run 1, every tick shown running before the end, run 1 completing after the command, and Grok's reply in the continuation run.
    • Without the fix: expected [ … ] to have a length of 2 but got 3 (the command lands in a synthetic run 2).
    • With the fix: passes.
  • vp test run src/orchestration-v2/testkit/OrchestratorReplayFixtures.integration.test.ts -t grok: 14 passed (all Grok fixtures, including grok_monitor and grok_background_subagent).
  • vp test run src/provider/acp/XAiAcpExtension.test.ts src/provider/acp/XAiBackgroundTasks.test.ts src/orchestration-v2/Adapters/GrokAdapterV2.test.ts src/orchestration-v2/Adapters/AcpAdapterV2.test.ts src/orchestration-v2/testkit/OrchestratorReplayFixtures.contract.test.ts: all passed.
  • vp exec tsc --noEmit -p . in apps/server: no errors. knip --workspace apps/server --exports: clean. vp lint on touched files: one pre-existing warning on an untouched line.
  • Not run: repo-wide checks.

Model: Claude Opus 5.5 (Claude Code)

🤖 Generated with Claude Code


Devin Review

…ted them

Grok acknowledges a command it runs in the background with a completed
`BackgroundTaskStarted` tool update while the process keeps running, then
streams its output and ends it only with `x.ai/task_completed`. The adapter
only tracked monitors that way, so the start acknowledgement finished the
command, the first late output frame opened a synthetic continuation run
and moved the command into it, and Grok's own wake reply opened another.

Track `BackgroundTaskStarted` like a monitor start: keep the command
running, hold its run open until the task ends, and leave Grok's reply to
the continuation run. Recorded replay fixture: grok_background_bash.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@github-actions github-actions Bot added vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. size:L 100-499 changed lines (additions + deletions). labels Sep 26, 2026
{"type":"emit_inbound","label":"notification:session/update:agent_thought_chunk:t3-xai-prompt-1","frame":{"kind":"notification","method":"session/update","params":{"sessionId":"00000000-0000-4000-8000-000000000001","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" was"}},"_meta":{"totalTokens":23745,"eventId":"00000000-0000-4000-8000-000000000001-85","agentTimestampMs":1790405183378,"promptId":"t3-xai-prompt-1","streamStartMs":1790405182783,"turnStartMs":1790405167500,"updateType":"AgentThoughtChunk","chunkId":22}}}}
{"type":"emit_inbound","label":"notification:session/update:agent_thought_chunk:t3-xai-prompt-1","frame":{"kind":"notification","method":"session/update","params":{"sessionId":"00000000-0000-4000-8000-000000000001","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" very"}},"_meta":{"totalTokens":23745,"eventId":"00000000-0000-4000-8000-000000000001-86","agentTimestampMs":1790405183378,"promptId":"t3-xai-prompt-1","streamStartMs":1790405182783,"turnStartMs":1790405167500,"updateType":"AgentThoughtChunk","chunkId":23}}}}
{"type":"emit_inbound","label":"notification:session/update:agent_thought_chunk:t3-xai-prompt-1","frame":{"kind":"notification","method":"session/update","params":{"sessionId":"00000000-0000-4000-8000-000000000001","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" explicit"}},"_meta":{"totalTokens":23745,"eventId":"00000000-0000-4000-8000-000000000001-87","agentTimestampMs":1790405183378,"promptId":"t3-xai-prompt-1","streamStartMs":1790405182783,"turnStartMs":1790405167500,"updateType":"AgentThoughtChunk","chunkId":24}}}}
{"type":"emit_inbound","label":"notification:session/update:agent_thought_chunk:t3-xai-prompt-1","frame":{"kind":"notification","method":"session/update","params":{"sessionId":"00000000-0000-4000-8000-000000000001","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":":"}},"_meta":{"totalTokens":23745,"eventId":"00000000-0000-4000-8000-000000000001-88","agentTimestampMs":1790405183378,"promptId":"t3-xai-prompt-1","streamStartMs":1790405182783,"turnStartMs":1790405167500,"updateType":"AgentThoughtChunk","chunkId":25}}}}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Medium grok_background_bash/grok_transcript.ndjson:120

The replay loader rejects grok_background_bash at line 120 because the text field is malformed, so the fixture cannot execute. Replace the malformed value with a valid JSON string containing the intended colon.

🚀 Reply "fix it for me" or copy this AI Prompt for your agent:
In file @apps/server/src/orchestration-v2/testkit/fixtures/grok_background_bash/grok_transcript.ndjson around line 120:

The replay loader rejects `grok_background_bash` at line 120 because the `text` field is malformed, so the fixture cannot execute. Replace the malformed value with a valid JSON string containing the intended colon.

@github-actions

Copy link
Copy Markdown
Contributor

Thread transfer impact

✅ Thread transfer remains within every enforced ceiling.

ℹ️ No successful main baseline artifact is available yet. This run establishes the initial measurement.

Provider Metric Main baseline This PR Impact PR ceiling
Codex Total thread wire — 4.9 KiB — 6.8 KiB ✅
Codex Thread snapshot wire — 3.7 KiB — 4.9 KiB ✅
Codex Live turn WebSocket wire — 1.2 KiB — 2.0 KiB ✅
Codex Live turn WebSocket decoded — 20.4 KiB — 29.3 KiB ✅
Codex Live turn messages — 2 — 8 ✅
Claude Total thread wire — 4.9 KiB — 6.8 KiB ✅
Claude Thread snapshot wire — 3.7 KiB — 4.9 KiB ✅
Claude Live turn WebSocket wire — 1.2 KiB — 2.0 KiB ✅
Claude Live turn WebSocket decoded — 20.8 KiB — 29.3 KiB ✅
Claude Live turn messages — 2 — 8 ✅

Baseline: unavailable · PR result: 7710a32 · Source CI: success

Scenario and decoded snapshot size

10 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.

  • Codex decoded thread snapshot: 106.1 KiB
  • Claude decoded thread snapshot: 106.4 KiB

Updated in place by a trusted workflow. PR artifacts are strictly validated and never executed.

@macroscopeapp

macroscopeapp Bot commented Sep 26, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Would Approve

Macroscope's review found this PR approvable — This is a narrow Grok ACP bug fix that keeps background shell commands running and attached to their originating run until the provider reports completion, with focused replay coverage and no product-default or static-analysis changes. An unresolved Medium finding reports that the new replay fixture is malformed at line 120, which would prevent that regression test from executing.

Not approved because:

  • 1 blocking correctness issue found at or above your repo's Minimum Blocking Severity

Adjust the Minimum Blocking Severity for this repo — including turning it Off — in Settings. You can add or adjust custom eligibility rules. Learn more.

@juliusmarminge
juliusmarminge merged commit 75afe68 into t3code/codex-turn-mapping Sep 26, 2026
24 of 25 checks passed
@juliusmarminge
juliusmarminge deleted the t3code/grok-background-bash-run branch September 26, 2026 18:28
juliusmarminge added a commit that referenced this pull request Sep 26, 2026
Brings in the V2 bug-hunt fixes merged while this PR was refreshed
(#13787, #13789, #13790, #13797, #13805, #13806). No conflicts.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:L 100-499 changed lines (additions + deletions). vouch:trusted PR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant