Skip to content

agentHost: preserve Claude tool state across steering results - #336752

Open
Aleksandr Logunov (Longarithm) wants to merge 3 commits into
microsoft:mainfrom
Longarithm:fix/claude-steering-tool-state
Open

Aleksandr Logunov (Longarithm) wants to merge 3 commits into
microsoft:mainfrom
Longarithm:fix/claude-steering-tool-state

Conversation

@Longarithm

@Longarithm Aleksandr Logunov (Longarithm) commented Sep 18, 2026

Copy link
Copy Markdown

Problem

A steering prompt can cause an intermediate Claude SDK result while the protocol turn is still running. The pipeline delays ChatTurnComplete until the prompt queue drains, but the mapper clears pending tool calls and foreground subagent spawns on every result. Later tool results then lose their pending state. The SDK's [ede_diagnostic] entry can also appear as a user-facing error.

Change

  • Use queue state, not diagnostic text, to preserve tools and foreground subagents across intermediate results.
  • Classify the result, settle its queue entry, map its signals, and emit completion synchronously. Steering cannot arrive between cleanup classification and settlement; result signals still precede completion.
  • Clear foreground state on final results, abort, stream failure and disposal. Background subagent registrations remain independent of foreground cleanup.
  • Filter diagnostic entries from displayed execution errors while retaining real errors in the same result.

Related work

Related to #330785, which also filters the diagnostic and proposes separate protocol turns for steering. This PR retains same-turn steering behavior and fixes pending-state cleanup independently.

Validation

Regression tests failed before the corresponding fixes and now pass:

  • Foreground subagent/tool completion after an intermediate result.
  • Steering queued in a result-signal microtask cannot split cleanup and completion decisions.
  • Intermediate result followed by abort or stream failure clears state before recovery; late tool results cannot complete a stale tool.
  • Diagnostic-only and mixed-error results, including cleanup on a final diagnostic-only result.

363 tests pass across claudeAgent, claudePromptQueue, claudeMapSessionEvents, claudeSdkMessageRouter, and claudeSdkPipeline. Three existing multi-turn tests now wait for the fake SDK to consume the next prompt before returning its result, rather than depending on microtask timing.

Targeted TypeScript checking of changed files and their imports, and repository hygiene/formatting/ESLint on all changed files, pass. Validation reused existing dependencies and Electron. No full application build or live SDK/UI reproduction was run for this upstream branch.

Copilot AI balanced review requested due to automatic review settings September 18, 2026 10:44
@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/claudePromptQueue.ts
  • src/vs/platform/agentHost/node/claude/claudeSdkMessageRouter.ts
  • src/vs/platform/agentHost/node/claude/claudeSdkPipeline.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

Result handling has a queue-state race and lacks cleanup when an intermediate result is followed by abort or failure.

Get a fresh assessment by requesting another Copilot review.

Pull request overview

Preserves Claude tool and subagent state across intermediate steering results while filtering internal diagnostics.

Changes:

  • Propagates intermediate-result state through the queue, pipeline, and router.
  • Defers pending tool/subagent cleanup until the final result.
  • Adds regression coverage for steering and diagnostic filtering.
File summaries
File Description
claudePromptQueue.ts Detects prompts remaining after the current head.
claudeSdkPipeline.ts Classifies intermediate results.
claudeSdkMessageRouter.ts Forwards result classification.
claudeMapSessionEvents.ts Preserves state and filters diagnostics.
claudePromptQueue.test.ts Tests queue classification.
claudeMapSessionEvents.test.ts Tests filtering and final cleanup.
claudeAgent.test.ts Tests steering with foreground subagents.
Review details
  • Files reviewed: 7/7 changed files
  • Comments generated: 2
  • 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/node/claude/claudeMapSessionEvents.ts
Comment thread src/vs/platform/agentHost/node/claude/claudeSdkPipeline.ts Outdated
@Longarithm

Copy link
Copy Markdown
Author

@microsoft-github-policy-service agree

…tate

Keep result classification, queue settlement, mapped signals and completion in one synchronous operation. Clear foreground mapper state on abort, failure and disposal. Cover microtask steering and recovery after interrupted results. Make multi-turn SDK tests wait for prompt consumption rather than incidental microtask ordering.

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.

🟢 Approval recommended

The prior cleanup and race issues are addressed with focused regression coverage, and no unresolved correctness issues were found.

Review details
  • Files reviewed: 7/7 changed files
  • Comments generated: 0 new
  • Review effort level: Balanced

@saitanallensantiago26-beep

Problem

A steering prompt can cause an intermediate Claude SDK result while the protocol turn is still running. The pipeline delays ChatTurnComplete until the prompt queue drains, but the mapper clears pending tool calls and foreground subagent spawns on every result. Later tool results then lose their pending state. The SDK's [ede_diagnostic] entry can also appear as a user-facing error.

Change

  • Use queue state, not diagnostic text, to preserve tools and foreground subagents across intermediate results.
  • Classify the result, settle its queue entry, map its signals, and emit completion synchronously. Steering cannot arrive between cleanup classification and settlement; result signals still precede completion.
  • Clear foreground state on final results, abort, stream failure and disposal. Background subagent registrations remain independent of foreground cleanup.
  • Filter diagnostic entries from displayed execution errors while retaining real errors in the same result.

Related work

Related to #330785, which also filters the diagnostic and proposes separate protocol turns for steering. This PR retains same-turn steering behavior and fixes pending-state cleanup independently.

Validation

Regression tests failed before the corresponding fixes and now pass:

  • Foreground subagent/tool completion after an intermediate result.
  • Steering queued in a result-signal microtask cannot split cleanup and completion decisions.
  • Intermediate result followed by abort or stream failure clears state before recovery; late tool results cannot complete a stale tool.
  • Diagnostic-only and mixed-error results, including cleanup on a final diagnostic-only result.

363 tests pass across claudeAgent, claudePromptQueue, claudeMapSessionEvents, claudeSdkMessageRouter, and claudeSdkPipeline. Three existing multi-turn tests now wait for the fake SDK to consume the next prompt before returning its result, rather than depending on microtask timing.

Targeted TypeScript checking of changed files and their imports, and repository hygiene/formatting/ESLint on all changed files, pass. Validation reused existing dependencies and Electron. No full application build or live SDK/UI reproduction was run for this upstream branch.

@Longarithm

Copy link
Copy Markdown
Author

Before

The SDK's [ede_diagnostic] entry is shown as a user-facing execution error after a normal follow-up prompt:

Raw ede_diagnostic error shown in chat

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants