Show progress while downloading agent SDK binaries#322919
Draft
Giuspepe wants to merge 5 commits into
Draft
Conversation
VS Code ships the Claude and Codex agents but not their native SDK binaries (70-95 MB), which are downloaded from the CDN the first time a session of that type starts and then cached. On a cold cache the first session start blocked for several seconds with no feedback. This surfaces a client-side progress indicator. How it works: - The downloader counts bytes in `_fetch` (using Content-Length when present), and fires a process-global `onDidDownloadProgress` event with throttled lifecycle frames (started -> progress -> completed/failed). Callers stay ignorant of progress. - The agent host forwards that event into `AgentHostStateManager.emitSdkDownloadProgress`, which emits the new `root/sdkDownloadProgress` AHP notification on the same `onDidEmitNotification` path used by session notifications. That reaches BOTH the local Agents window (IPC proxy) and remote hosts (WebSocket ProtocolServerHandler) with no transport-specific special casing. - `BaseAgentHostSessionsProvider` renders an `IProgressService` notification keyed by `downloadId` (determinate % when the total is known, MB otherwise), gated on `chat.disableAIFeatures`. Also gates the eager `listSessions` path (new `isSdkResolvableWithoutDownload` / `canLoadWithoutDownload`) so a cold download is triggered by the user's first message, not at agent-host startup. The protocol files mirror agent-host-protocol's `root/sdkDownloadProgress` addition (unreleased spec 0.5.0). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Codex eagerly prewarms a session on `createSession` (materializing the thread so the first turn is instant), which spawns the native binary and therefore loads the SDK. When the SDK isn't cached yet, that prewarm kicked off a multi-second cold download the moment the user landed on a Codex new-session composer — before sending any message. Gate `_schedulePrewarm` on the same `isSdkResolvableWithoutDownload` check already used for `listSessions`: when the SDK isn't local, skip prewarm and let the first `sendMessage` materialize the thread and fire the (progress-reported) download. This brings Codex in line with Claude, which already loads the SDK lazily on first use rather than on session creation. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Rename the protocol notification from the SDK-specific `root/sdkDownloadProgress`
to a resource-agnostic `root/downloadProgress`, so the same channel can report
future host-side downloads (additional agent runtimes, plugins, models, …)
without a new method. Done now while the notification is still in the unreleased
0.5.0 spec, so it costs nothing; renaming a shipped wire method would otherwise
mean a deprecation cycle across the generated language clients.
Protocol changes (mirrors agent-host-protocol):
- `SdkDownloadProgressParams` → `DownloadProgressParams`.
- `SdkDownloadPhase` → `DownloadPhase`, now a string-valued `const enum` to match
every other protocol discriminant (and so the AHP code generators emit it).
- Add a `kind` discriminant (open string, `'agent-sdk'` today) and rename
`packageId` → `resourceId`.
The vscode SDK downloader stays SDK-specific (it only downloads SDKs) and keeps
its own `AgentSdkDownloadPhase` string union; the agent-host bridges map its
event onto the generic frame, stamping `kind: 'agent-sdk'` and translating the
phase to the protocol `DownloadPhase` enum. The state manager method is now
`emitDownloadProgress`, and the renderer uses `kind` to pick a
resource-appropriate label ("Downloading {name} agent…" for agent SDKs,
"Downloading {name}…" otherwise).
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…rogress-ahp # Conflicts: # src/vs/platform/agentHost/common/state/protocol/.ahp-version # src/vs/platform/agentHost/node/claude/claudeAgentSdkService.ts # src/vs/sessions/contrib/providers/agentHost/browser/baseAgentHostSessionsProvider.ts
Contributor
There was a problem hiding this comment.
Pull request overview
This PR adds end-to-end download progress reporting for on-demand agent SDK binary downloads (Claude/Codex), forwarding progress from the agent host through the Agent Host Protocol (root/downloadProgress) and surfacing it in the Sessions (Agents) window as an IProgressService notification.
Changes:
- Emit throttled byte/total download progress from
AgentSdkDownloaderand forward it viaAgentHostStateManager.emitDownloadProgress()onto the AHP root notification channel. - Render
root/downloadProgressnotifications in the Sessions providers as notification progress toasts keyed bydownloadId. - Avoid cold-download side effects from non-user-initiated Codex/Claude operations (e.g. prewarm / listSessions) by gating them on “SDK already local” checks; add/extend unit tests for protocol forwarding and downloader progress.
Show a summary per file
| File | Description |
|---|---|
| src/vs/sessions/contrib/providers/remoteAgentHost/test/browser/remoteAgentHostSessionsProvider.test.ts | Stubs IProgressService for provider tests after adding progress dependency. |
| src/vs/sessions/contrib/providers/remoteAgentHost/browser/remoteAgentHostSessionsProvider.ts | Plumbs IProgressService into the remote sessions provider base constructor. |
| src/vs/sessions/contrib/providers/agentHost/test/browser/localAgentHostSessionsProvider.test.ts | Stubs IProgressService for provider tests after adding progress dependency. |
| src/vs/sessions/contrib/providers/agentHost/browser/localAgentHostSessionsProvider.ts | Plumbs IProgressService into the local sessions provider base constructor. |
| src/vs/sessions/contrib/providers/agentHost/browser/baseAgentHostSessionsProvider.ts | Tracks active downloads and renders root/downloadProgress as notification progress toasts. |
| src/vs/platform/agentHost/test/node/protocolServerHandler.test.ts | Adds coverage verifying root/downloadProgress frames are forwarded to connected clients. |
| src/vs/platform/agentHost/test/node/claudeSubagentResolver.test.ts | Updates fake Claude SDK service to satisfy new canLoadWithoutDownload() API. |
| src/vs/platform/agentHost/test/node/claudeAgent.test.ts | Updates fakes/stubs for new downloader + Claude SDK service APIs. |
| src/vs/platform/agentHost/test/node/claudeAgent.integrationTest.ts | Updates integration fake to satisfy new canLoadWithoutDownload() API. |
| src/vs/platform/agentHost/test/node/agentSdkDownloader.test.ts | Adds tests validating monotonic progress frames and terminal completion semantics. |
| src/vs/platform/agentHost/node/codex/codexAgent.ts | Prevents prewarm/listing from triggering cold SDK downloads; adds displayName. |
| src/vs/platform/agentHost/node/claude/claudeAgentSdkService.ts | Adds displayName and canLoadWithoutDownload() to gate session listing. |
| src/vs/platform/agentHost/node/claude/claudeAgent.ts | Gates listSessions() to avoid cold downloads at startup. |
| src/vs/platform/agentHost/node/agentSdkDownloader.ts | Implements progress eventing + “resolvable without download” checks; adds display name to packages. |
| src/vs/platform/agentHost/node/agentHostStateManager.ts | Adds emitDownloadProgress() on the root notification channel. |
| src/vs/platform/agentHost/node/agentHostServerMain.ts | Wires SDK download progress events into root/downloadProgress notifications. |
| src/vs/platform/agentHost/node/agentHostMain.ts | Wires SDK download progress events into root/downloadProgress notifications. |
| src/vs/platform/agentHost/common/state/sessionActions.ts | Exposes DownloadPhase / DownloadProgressParams and adds NotificationType.DownloadProgress. |
| src/vs/platform/agentHost/common/state/protocol/version/registry.ts | Declares root/downloadProgress as introduced in protocol 0.5.0. |
| src/vs/platform/agentHost/common/state/protocol/common/messages.ts | Adds root/downloadProgress to the server notification map. |
| src/vs/platform/agentHost/common/state/protocol/channels-root/notifications.ts | Defines the root/downloadProgress wire contract (phase/bytes/ids). |
| src/vs/platform/agentHost/common/state/protocol/.ahp-version | Updates vendored protocol revision pointer. |
| src/vs/platform/agentHost/browser/remoteAgentHostProtocolClient.ts | Allows root/downloadProgress notifications through the client switch. |
Copilot's findings
- Files reviewed: 23/23 changed files
- Comments generated: 2
AgentSdkDownloader extends Disposable and owns a registered Emitter (onDidDownloadProgress), but both construction sites created it via createInstance(...) without adding it to the function's DisposableStore — unlike every sibling service. That left its Emitter undisposed for the process lifetime. Wrap both in disposables.add(...) to match the pattern. Addresses Copilot code-review feedback on the PR. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
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.
Warning
Not ready to merge — draft. Depends on microsoft/agent-host-protocol#263, which defines the
root/downloadProgresswire contract this PR consumes. That PR must merge first. Once it does, the vendored protocol copy here needs a final re-sync from merged AHPmain(refreshingsrc/vs/platform/agentHost/common/state/protocol/.ahp-versionto the merged commit) before this comes out of draft.Screen.Recording.2026-06-25.at.15.19.44.mov
Why
VS Code ships the Claude and Codex agents but not their native binaries — those download on demand from the CDN (70–95 MB compressed) the first time a session of that type starts, then cache. On a cold cache the first turn blocks for several seconds with no feedback (it looks hung). This surfaces a progress indicator in the Agents window instead.
What you see
A toast in the Agents window — "Downloading Claude…" / "Downloading Codex…" — filling 0→100% (determinate when the CDN sends
Content-Length, indeterminate otherwise), clearing on completion.How it works
The download runs in the agent host (utility process locally, or the remote server over WSL/SSH); the UI is in the renderer. Progress crosses the agent-host protocol via the new
root/downloadProgressnotification:agentSdkDownloader._fetchcounts received bytes vsContent-Length, throttles, and firesonDidDownloadProgress.kind: 'agent-sdk',resourceId,phase) through the state manager — the same fan-out path as session notifications, so it reaches both local (IPC) and remote (WebSocket) clients.IProgressServicetoast keyed bydownloadId.Also gates Codex's eager prewarm-on-create so it no longer triggers a cold download with no user action — the download now happens on first message.
Depends on
Vendors the protocol types from microsoft/agent-host-protocol#263, which defines
root/downloadProgress. That PR should merge first — it's the source of truth for the wire contract; the vendored copy here (src/vs/platform/agentHost/common/state/protocol/) mirrors it.