Skip to content

fix: drain background task turns before processing prompt response#359

Closed
ElleNajt wants to merge 2 commits intoagentclientprotocol:mainfrom
ElleNajt:fix/drain-background-task-turns
Closed

fix: drain background task turns before processing prompt response#359
ElleNajt wants to merge 2 commits intoagentclientprotocol:mainfrom
ElleNajt:fix/drain-background-task-turns

Conversation

@ElleNajt
Copy link
Copy Markdown
Contributor

@ElleNajt ElleNajt commented Feb 27, 2026

I've run into a problem in agent-shell where if tasks return in the background, Claude's responses to them are returned instead of it's responses to my messages, and messages can get out of sync: xenodium/agent-shell#201

I put Claude in a vm with a test of the bug and it solved it; it produced a patch that has fixed it locally for me. I haven't had time to think about what this code is doing (and it's not a priority).

All I can claim is that it seems reasonable and works, so here is a draft PR with the fix and tests in case it's useful to anyone else.

Here is Claude's description of the problem and solution:

When background tasks (e.g. sleep with run_in_background) complete between prompts, their completion messages are buffered in the SDK's async generator. On the next prompt() call, these buffered messages are yielded first and sent as ACP notifications, causing the response to appear shifted — the client receives the background task's completion output instead of (or before) the actual prompt response.

Steps to reproduce:

  1. Send a prompt that launches background tasks (e.g. "Run these 3 bash commands in the background: sleep 1, sleep 2, sleep 3")
  2. Wait for the prompt response (agent says "done" or similar)
  3. Wait for the background tasks to complete (a few seconds)
  4. Send a second prompt (e.g. "Just say HELLO")
  5. Observed: The second prompt's response contains the background task completion output ("The first sleep 1 task completed...") instead of the expected response
  6. Expected: The second prompt's response contains "HELLO"

Root cause: The prompt() method iterates the SDK's async generator in a while(true) loop and returns at the first result message. But background task completions that happen between prompts produce their own complete message sequences (task_notification → init → [stream events] → result) that get buffered. On the next prompt() call, these are processed first and forwarded to the client as if they were part of the new prompt's response.

When background tasks (e.g. `sleep` with `run_in_background`) complete
between prompts, their completion messages are buffered in the SDK's
async generator. On the next prompt() call, these buffered messages are
processed first and sent as ACP notifications, causing responses to
appear shifted to later prompts.

Fix: detect background task turns by their message sequence
(task_notification → init → ... → result) and skip them before
processing the real prompt response. An `init` preceded by
`task_notification` starts a background turn; an `init` NOT preceded
starts the real response.

Also remove noisy "No onPostToolUseHook found" error log in tools.ts,
which fires benignly when background task tool_use hooks aren't
registered (because their stream events are now skipped).

Fixes: xenodim/agent-shell#201

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@cla-bot cla-bot bot added the cla-signed label Feb 27, 2026
@ElleNajt
Copy link
Copy Markdown
Contributor Author

Related: #353

@ElleNajt ElleNajt closed this Mar 5, 2026
@ElleNajt ElleNajt reopened this Mar 6, 2026
The "No onPostToolUseHook found for tool use ID" message was logged via
logger.error(), which goes to stderr. acp.el treats every non-empty
stderr line as an error and agent-shell displays it in the "Notices"
drawer — making an expected condition (subagent tools, server_tool_use)
appear as a user-visible error.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@ElleNajt ElleNajt closed this Mar 6, 2026
@ElleNajt
Copy link
Copy Markdown
Contributor Author

ElleNajt commented Mar 7, 2026

can't reopen this PR bc of a force push, it's now here: #388

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant