Skip to content

Spare a background subagent's in-flight tool call from the turn-end wipe - #334559

Open
Ryan Ewen (RyanEwen) wants to merge 2 commits into
microsoft:mainfrom
RyanEwen:fix/clear-pending-spares-background-subagents
Open

Spare a background subagent's in-flight tool call from the turn-end wipe#334559
Ryan Ewen (RyanEwen) wants to merge 2 commits into
microsoft:mainfrom
RyanEwen:fix/clear-pending-spares-background-subagents

Conversation

@RyanEwen

Copy link
Copy Markdown
Contributor

clearPending drops all cross-message tool attribution on every result envelope. A background subagent outlives the turn that spawned it, so its inner tool call is still in flight and its result is still coming, but its entry is wiped along with the genuinely orphaned ones.

Why it matters

The registry exists because a tool_use and its tool_result arrive in different SDK messages, so the tool name, parsed input and invocation message have to survive between them. Once the entry is gone, the late result renders with the generic past-tense message instead of the real one, and live output diverges from what replay produces from the same transcript.

The precedent

drainForegroundSpawns is called from mapResult two lines after clearPendingToolCalls, and already makes exactly this distinction:

Turn-end cleanup: remove and return foreground spawns whose completion never closed them. Background spawns survive across turns by design (their completion arrives later via system.task_notification).

The subagent registry keeps that state; the tool call registry simply never consulted it.

The change

clearPending takes an optional lookup and skips entries whose parent spawn is background, leaving every other orphan drained and warned exactly as before. The lookup is declared as a narrow local interface rather than importing the subagent registry, to avoid a cycle between the two modules. clearPendingToolCalls already runs before drainForegroundSpawns, so the spawn and its inner edges are still present when the check happens.

Tests

  • clearPending spares an inner tool of a background subagent and still drains the rest fails without the change.
  • clearPending still drains an inner tool whose parent subagent is foreground is the control and passes either way.

The suite goes from 12 passing with 1 failing to 13 passing, and both pre-existing clearPending tests are unaffected. No new type errors.

AI disclosure: this comment and the related code were written with the assistance of AI.

`clearPending` drops all cross-message tool attribution on every `result`
envelope. A background subagent outlives the turn that spawned it, so its
inner tool call is still in flight and its result is still coming, but its
entry is wiped along with the genuinely orphaned ones.

When that result arrives the tool name and input are gone, so the call
renders with a generic past-tense label and live diverges from replay.

`drainForegroundSpawns`, called on the same envelope two lines later,
already spares background spawns for exactly this reason.
@vs-code-engineering

Copy link
Copy Markdown
Contributor

📬 CODENOTIFY

The following users are being notified based on files changed in this PR:

TylerLeonhardt

Matched files:

  • src/vs/platform/agentHost/node/claude/claudeMapSessionEvents.ts
  • src/vs/platform/agentHost/node/claude/claudeToolCallRegistry.ts

Copilot AI left a comment

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.

🟡 Changes recommended

The tests bypass the production mapper wiring, leaving the reported regression insufficiently covered.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Pull request overview

Preserves in-flight tool attribution for background Claude subagents across turn cleanup.

Changes:

  • Skips background-subagent tools during pending-call cleanup.
  • Passes subagent state into result handling.
  • Adds background and foreground cleanup tests.
File summaries
File Description
claudeToolCallRegistry.ts Adds background-aware cleanup.
claudeMapSessionEvents.ts Connects subagent lookup to cleanup.
claudeToolCallRegistry.test.ts Tests selective cleanup behavior.
Review details
  • Files reviewed: 3/3 changed files
  • Comments generated: 1
  • Review effort level: Balanced

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread src/vs/platform/agentHost/test/node/claudeToolCallRegistry.test.ts
The registry-level tests pass a synthetic lookup straight to `clearPending`,
so dropping the `registry` argument at the `mapResult` call site would not
fail them and the divergence would return unnoticed.

Adds a test that drives the real path: a background spawn with its inner
tool, a streamed `tool_use`, then a `result` envelope through
`mapSDKMessageToAgentSignals`.
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.

3 participants