Agent Host session refresh stalls while remote exporter drains oversized events
- Dominant language
- TypeScript
- Stars
- 193k
- Forks
- 42.4k
- PR merge metrics
- PR metrics pending
Description
- Copilot Chat Extension Version: Built-in development version
- VS Code Version: Current Insiders source build, 2026-08-06
- OS Version: macOS
- Feature (e.g. agent/edit/ask mode): Agents window / Copilot CLI session resume
- Selected model (e.g. GPT 4.1, Claude 3.7 Sonnet): GPT-5.6 Sol
- Logs: Agent Host debug bundle was analyzed locally but is not attached because it contains sensitive session content. Sanitized evidence follows.
Steps to Reproduce:
1. Restore a large Copilot CLI session with remote session export enabled (the affected session contained about 11,790 persisted events).
2. Before the remote exporter finishes backfilling the history, change structural active-client configuration such as plugins, tools, MCP servers, or workspace roots so the next send requires a session refresh.
3. Send a message.
4. Observe that the turn remains on **Working…** for 10+ minutes with no model or tool activity.
## Expected
Remote session export is fire-and-forget and does not delay session teardown, refresh, or a new turn. A refresh should either resume promptly or fail with a surfaced error.
## Actual
The AHP server accepts `chat/turnStarted` and marks the chat in progress. Agent Host detects `requiresRestart`, disconnects the cached SDK session, clears the default chat, and calls `_resumeSession`. The new `resumeSession` request then waits for destruction of the previous runtime instance.
Runtime destruction waits for `RemoteSessionExporter` to drain the persisted-event backlog. Mission Control responds with HTTP 413. The exporter halves its per-flush event count from 500 to 250, 125, 62, 31, 15, 7, 3, and finally 1. It then submits and drops oversized events one at a time, paying one network round trip per event.
In the captured incident:
- 11,790 events were loaded for export.
- 941 HTTP 413 responses occurred over 9 minutes 29 seconds before capture ended.
- A previous identical refresh produced 1,189 HTTP 413 responses and delayed destruction for 13 minutes 14 seconds; the SDK resumed immediately after destruction and the subsequent turn completed normally.
- Event-size analysis found roughly 1,210 events above the inferred single-event payload boundary in the current history, consistent with the previous drop count.
- AHP remained healthy throughout: monotonic sequencing, successful pings, no reconnect, and no missing transport delivery.
- The affected turn produced no SDK/model/tool/permission events at all. It was blocked before provider execution.
- `setPendingMessages: chat not found` was a consequence of the default chat being cleared while resume remained pending, not the cause.
## Source path
The blocking chain is:
1. `src/vs/platform/agentHost/node/copilot/copilotAgent.ts:2681-2692` refreshes after structural configuration changes and awaits `_resumeSession`.
2. `src/vs/platform/agentHost/node/copilot/copilotAgentSession.ts:2460-2467` requests SDK disconnect.
3. `src/vs/platform/agentHost/node/copilot/copilotSessionLauncher.ts:419` waits in `client.resumeSession(...)` until the prior runtime instance is destroyed.
4. The runtime does not emit `session.shutdown` or destroy the session until remote export finishes draining.
This is a stricter variant of #328391. That fix lets `CopilotSessionWrapper.disconnect()` complete when either the disconnect response or `session.shutdown` arrives. In this incident no `session.shutdown` arrives before the exporter drain, so the previous escape hatch cannot help.
## Suggested direction
The primary fix should be in the CLI runtime exporter:
- Batch by serialized byte size rather than event count.
- Reject or trim individually oversized events locally instead of discovering each one through an HTTP 413.
- Do not synchronously drain remote export during session disconnect/destruction; use a bounded deadline or persist an export cursor for later continuation.
- Allow session shutdown/resume to complete independently of cloud export.
Agent Host should defensively time out the refresh and surface a terminal error instead of leaving the chat indefinitely in progress. It may also be worth avoiding the immediate restore-then-refresh cycle by waiting until the active-client customization snapshot is stable.
cc @roblourens
Contributor guide
Assessment
This issue has not been assessed yet.