Repository navigation
Open
Description
Before submitting
- I searched existing issues and did not find a duplicate.
- I included enough detail to reproduce or investigate the problem.
Area
apps/server
Steps to reproduce
- Start a Claude Code thread (e.g. using
antigravity/gemini-4-argonvia a local Anthropic-compatible gateway) and have the agent launch a backgroundBashcommand (task_a) plus aMonitortask (task_b) that emits progress lines every 30–60 seconds. - Following
CLAUDE_BACKGROUND_WAIT_INSTRUCTIONS("To wait for a background command or Monitor you started (tests, a build), call t3_background_wait with its task ID before you end your turn"), the agent callsmcp__t3-code__t3_background_wait({"taskIds": ["task_a", "task_b"], "waiting": true}). - Observe what happens during and after the
t3_background_waitcall:- While
t3_background_waitor the subsequent LLM round-trip is in flight,Monitoremits a<task-notification><task-id>task_b</task-id><summary>Monitor event: ...</summary><event>...</event></task-notification>, which Claude Code enqueues as aqueued_commandand drains at thet3_background_waittool-result boundary. - Seeing the newly injected
<task-notification>, the agent callst3_background_waitagain in the same turn (repeating 2–3 times in a single turn as newMonitorlines arrive). - Once
t3_background_waitreturns{"matched":["task_a","task_b"],"unmatched":[]}with no queued notification at that exact millisecond, the model treats the turn as already waiting and emits 0 output tokens on the post-tool/v1/messagesturn, causing gateways that reject 0-token Gemini streams to fail with 502 after exhausting retries.
- While
- When that turn ends with
status: "failed"(or"interrupted"), observe the next turn (woken 1 second later by the still-runningMonitortask in the same live Claude Code process):- The agent calls
t3_background_wait({"taskIds": ["task_a", "task_b"], "waiting": true})again. - Even though the Claude Code subprocess is still alive and both
task_aandtask_bare still running (andtask_alater emits its completion<task-notification>),t3_background_waitnow returns{"matched":[],"unmatched":["task_a","task_b"]}.
- The agent calls
Expected behavior
- Clear post-
t3_background_waitturn completion &Monitorguidance:t3_background_wait's tool description / result (orCLAUDE_BACKGROUND_WAIT_INSTRUCTIONS) should instruct the model to end its turn immediately with a brief one-line status text after callingt3_background_wait(preventing 0-token post-tool responses on Gemini models), and clarify thatt3_background_waitonly needs to be called once when entering a wait state rather than re-called on every intermediateMonitor<task-notification>event.
- Preserve live background task roster across failed/interrupted turns on a still-alive Claude subprocess:
- In
ClaudeAdapterV2, when a turn ends withinput.status !== "completed"("failed"or"interrupted") whileliveQueryremains alive,pendingBackgroundTasksByNativeThreadandwakeEligibleBackgroundTasksByNativeThreadshould not be unconditionally wiped for background tasks that are still running in that process.
- In
Actual behavior
- Repeated
t3_background_waitcalls and silent post-tool turn:- Every streaming
<task-notification>fromMonitorcauses the agent to re-invoket3_background_wait(both multiple times within the same turn and on every wake turn), and the post-t3_background_wait/v1/messagesrequest frequently produces 0 output tokens because the model has nothing left to say after{"matched":[...],"unmatched":[]}.
- Every streaming
- Roster wipe on non-
completedturn termination:- In
ClaudeAdapterV2turn finalization:Becauseif (nativeThreadId !== null) { if (input.status !== "completed") { yield* clearPendingBackgroundTasksForNativeThread(nativeThreadId); yield* clearNativeThreadTaskIdSet(wakeEligibleBackgroundTasksByNativeThread, nativeThreadId); yield* clearNativeThreadTaskIdSet(opaqueBackgroundTaskReplayTombstonesByNativeThread, nativeThreadId); } }
clearPendingBackgroundTasksForNativeThread(nativeThreadId)is called on any"failed"or"interrupted"turn even when the underlying Claude Code subprocess stays alive, still-running backgroundBashandMonitortasks are erased frompendingBackgroundTasksByNativeThread. Subsequentt3_background_waitcalls in the next turn return{"matched":[],"unmatched":[...]}while those tasks are still actively running.
- In
Impact
Major degradation or frequent failure
Version or commit
0.1.8-nightly.20261106.4247
Environment
Linux x64 (Ubuntu), T3 Code v0.1.8-nightly.20261106.4247, Claude Code 2.1.318 (CLAUDE_PROVIDER), model antigravity/gemini-4-argon
Logs or stack traces
# Run 12: Monitor starts and emits streaming events while t3_background_wait is called twice in the same turn
01:49:46.811Z tool_result (Monitor): "Monitor started (task bd2o2yhwp, expires in 30m...)"
01:49:47.021Z queue-operation enqueue: <task-notification><task-id>bd2o2yhwp</task-id><summary>Monitor event: ...</summary><event>[LOCAL] ...</event></task-notification>
01:49:54.039Z tool_use: mcp__t3-code__t3_background_wait {"taskIds": ["bfyvtbzo0", "bd2o2yhwp"], "waiting": true}
01:49:54.062Z tool_result: {"matched":["bfyvtbzo0","bd2o2yhwp"],"unmatched":[]}
01:49:54.171Z queue-operation remove (queued_command drained into same turn)
01:50:01.260Z tool_use: mcp__t3-code__t3_background_wait {"taskIds": ["bfyvtbzo0", "bd2o2yhwp"], "waiting": true}
01:50:01.277Z tool_result: {"matched":["bfyvtbzo0","bd2o2yhwp"],"unmatched":[]}
01:50:01.286Z api-request -> model produces 0 output tokens after tool_result -> 502 retry loop until 02:14:12Z (Run 12 ends with status: "failed")
# Run 13 (1 second later): both bfyvtbzo0 and bd2o2yhwp are still running in the same Claude process,
# but clearPendingBackgroundTasksForNativeThread wiped the roster when Run 12 failed:
02:14:21.358Z tool_use: mcp__t3-code__t3_background_wait {"taskIds": ["bfyvtbzo0", "bd2o2yhwp"], "waiting": true}
02:14:21.493Z tool_result: {"matched":[],"unmatched":["bfyvtbzo0","bd2o2yhwp"]}
02:14:32.152Z tool_use: mcp__t3-code__t3_background_wait {"taskIds": ["bfyvtbzo0", "bd2o2yhwp"], "waiting": true}
02:14:32.241Z tool_result: {"matched":[],"unmatched":["bfyvtbzo0","bd2o2yhwp"]}
02:19:46.811Z queue-operation enqueue: <task-notification><task-id>bd2o2yhwp</task-id>...[Monitor expired after 30m with 7 events delivered.]</task-notification>
02:40:20.663Z queue-operation enqueue: <task-notification><task-id>bfyvtbzo0</task-id><status>completed</status>...</task-notification>
Workaround
Avoid combining Monitor with t3_background_wait on Gemini models, or instruct the agent to always emit a short status line when ending its turn after t3_background_wait.
Metadata
Metadata
Assignees
Labels
No labels
Activity