Repository navigation
agentHost: stabilize subagent streams and snapshots - #340653
Draft
roblourens wants to merge 4 commits into
Draft
roblourens wants to merge 4 commits into
roblourens wants to merge 4 commits into
Conversation
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Contributor
|
Base:
|
Contributor
There was a problem hiding this comment.
🟡 Changes recommended
Quarantined post-cancellation child events can seed invisible part IDs and cause later deltas to be lost.
1 open finding
What changed in this PR
Separates subagent stream state from parent-turn state so child responses can continue after parent completion or replacement.
Changes:
- Adds child-owned markdown/reasoning part tracking and lifecycle resets.
- Adds regression tests for parent boundaries and repeated child turns.
- Documents subagent stream troubleshooting.
| File | Description |
|---|---|
src/vs/platform/agentHost/node/copilot/copilotAgentSession.ts |
Manages subagent response-part state independently. |
src/vs/platform/agentHost/test/node/copilotAgentSession.test.ts |
Adds subagent stream-lifetime coverage. |
src/vs/platform/agentHost/test/node/e2e/README.md |
Documents the lifecycle invariant. |
🧠 Review effort: Balanced
💡 Configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Comment on lines
+2452
to
+2457
| private _getResponsePartState(parentToolCallId: string | undefined): ICopilotResponsePartState | undefined { | ||
| // Fusion phase content belongs to the root turn; retained subagent content does not. | ||
| return parentToolCallId !== undefined && !this._fusionPhaseLabels.has(parentToolCallId) | ||
| ? this._subagentResponsePartState | ||
| : this._currentTurn.value; | ||
| } |
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.

Summary
Address two independent subagent stability findings:
Observed in GitHub 37852164334, macOS:
custom agent without a display name completes as a subagentreturned one completed child turn with two distinct markdown parts containing the same answer. The duplication was present in the authoritative AHP subscription snapshot, not just the test's notification buffer. Linux and Windows passed that revision.Cause and ownership
The trace has child text delta at
22:18:06.770, parent idle at.812, then the child's assembled message at.834. Both response parts came from live callbacks; no history reconstruction occurred between them.The host kept child part identifiers on the parent's
CopilotTurn. Completing or replacing that parent discarded the child's identifiers. A later assembled child message consequently looked unstreamed and was emitted again. Further child text/reasoning deltas were also dropped when no parent turn remained.This confirmed defect is VS Code-owned. Retained/background children can legitimately outlive the parent. The SDK's inter-agent delivery timing exposes the incorrect lifetime assumption; the fix does not require delaying SDK idle or changing native event ordering.
Cross-chat snapshot contract
GitHub 37816575914, macOS passed the retained-subagent test's primary response/turn-state assertions but failed because parent tool completion interleaved differently with a child's response. This is a test projection issue, not evidence that the runtime must serialize independent agents.
Use the existing
orderIndependentActionTypesopt-in only for this scenario. The generated AHP snapshot has identical client actions and identical server fields, event counts, and per-chat sequences in all three rounds; only cross-chat order changes. A deterministic regression verifies that same-chat reordering, failed tools, and missing or duplicated child replies still fail.Changes
No model fixtures, timeouts, retries, platform gates, runtime event ordering, or primary final-response assertions are changed.
Validation
env -u COPILOT_HOME VSCODE_SKIP_PRELAUNCH=1 ./scripts/test.sh --run src/vs/platform/agentHost/test/node/copilotAgentSession.test.ts --grep 'subagent content lifetime' --reporter dot— 1 passed, 5 failed on unchanged production code.env -u COPILOT_HOME VSCODE_SKIP_PRELAUNCH=1 ./scripts/test.sh --run src/vs/platform/agentHost/test/node/copilotAgentSession.test.ts --grep 'subagent content lifetime|subagent message delta does not suppress|subagent reasoning delta routes|reasoning delta after tool_start' --reporter dot— all 9 passed.env -u COPILOT_HOME VSCODE_SKIP_PRELAUNCH=1 ./scripts/test.sh --run src/vs/platform/agentHost/test/node/copilotAgentSession.test.ts --run src/vs/platform/agentHost/test/node/copilotAgent.test.ts --run src/vs/platform/agentHost/test/node/ahpSnapshot.test.ts --reporter dot— final implementation: 1621 passed, 1 existing pending. The added cancelled-tail test failed before the quarantine guard and passes with it.env -u COPILOT_HOME VSCODE_SKIP_PRELAUNCH=1 ./scripts/test-integration.sh --run src/vs/platform/agentHost/test/node/e2e/providers/copilotAgentHostE2E.integrationTest.ts --grep 'custom agent without a display name completes as a subagent|retained background subagent completes repeated follow-up turns|provider errors:' --reporter dot— five unchanged strict-replay executions, all 6 passed each time (30 passes).env -u COPILOT_HOME VSCODE_SKIP_PRELAUNCH=1 ./scripts/test-integration.sh --run src/vs/platform/agentHost/test/node/e2e/providers/copilotAgentHostE2E.integrationTest.ts --grep 'retained background subagent completes repeated follow-up turns|custom agent without a display name completes as a subagent' --reporter dotpassed five times (10 passes).npm run typecheck-client— passed.npm run eslint -- src/vs/platform/agentHost/node/copilot/copilotAgentSession.ts src/vs/platform/agentHost/test/node/copilotAgentSession.test.ts src/vs/platform/agentHost/test/node/ahpSnapshot.test.ts src/vs/platform/agentHost/test/node/e2e/suites/subagentSuite.ts— passed.node build/lib/formatter.ts --verify src/vs/platform/agentHost/node/copilot/copilotAgentSession.ts src/vs/platform/agentHost/test/node/copilotAgentSession.test.ts src/vs/platform/agentHost/test/node/ahpSnapshot.test.ts src/vs/platform/agentHost/test/node/e2e/suites/subagentSuite.ts— passed.git diff --checkand signed commit hygiene — passed.Client output was refreshed using the repository incremental transpiler. Shared dependencies were not modified. Main, including the landed full-snapshot diagnostics, was merged without rewriting history.
Final head
10fec39a15a5passed GitHub 37882030913 overall, including Compile & Hygiene and all three Electron integration jobs. Its Linux Dev Container preparation UI smoke timeout, also observed on the unchanged diagnostics-only branch, passed on an isolated retry without code changes; the original UI timeout's cause is not claimed fixed.Both independent packaged Windows x64/Linux x64/macOS ARM64 Electron integration matrices passed: 482615 and 482616. All six logs explicitly show both the originally failing custom-agent case and retained-subagent follow-up case executing and passing (12 packaged regression passes, excluding other providers' intentional skips).
Remaining overall Azure gates are Windows smoke in 482615 and Linux smoke in 482616: the same
272Kmodel-picker DOM click timeout reproduced on unchanged main 482526. Logs are preserved; only those failed jobs are being retried, without UI/product/test changes. Publishing and release are disabled. Old-head builds 482609/482610 and GitHub runs were superseded. The PR remains draft pending final CI gates and maintainer review; auto-merge is not enabled.(Written by Copilot)