* agentHost/claude: post-Phase-4 cleanup
- roadmap.md: mark Phase 4 as DONE, link merged PR #313780.
- phase4-plan.md: record live-system smoke completion in §7.8;
disabled-gate run skipped (covered by unit tests + env-var guard).
- claudeAgent.test.ts: drop gratuitous 'as unknown as' cast in the
CCAModel fixture (literal already matches CCAModelBilling exactly;
plan §7.4 forbids unsafe casts in tests).
* agentHost/claude: lock Phase 5 implementation plan
Handoff plan for Phase 5 (replace 7 throwing stubs in claudeAgent.ts).
Locked against post-PR-#313841 reality (provisional sessions,
onDidMaterializeSession, 30s empty-session GC) and the IAgent contract
on origin/main.
Decisions captured:
- Non-fork createSession is synchronous and in-memory; fork deferred
to Phase 6 (throws TODO).
- IClaudeAgentSdkService surface mirrors IAgent (no dir parameter on
listSessions); SDK loader caches resolved module, retries on
failure, logs once.
- listSessions joins SDK enumeration with workbench session DB
metadata via ISessionDataService; per-entry try/catch resilience.
- shutdown() routes per-session teardown through the same
SequencerByKey<string> used by disposeSession() so concurrent
shutdown/disposeSession cannot double-dispose a wrapper in Phase 6.
- 14 unit tests defined (12 lifecycle + 2 resolved-config), including
log-once contract and shutdown/disposeSession race guard.
* agentHost/claude: Phase 5 — IAgent provider skeleton
Lands the ClaudeAgent IAgent provider behind the
'chat.agentHost.claudeAgent.enabled' setting (env gate
VSCODE_AGENT_HOST_ENABLE_CLAUDE=1). Pins
@anthropic-ai/claude-agent-sdk@0.2.112 in workspace + remote/.
Implemented in this phase:
* createSession - non-fork, in-memory wrapper only. Honors
config.session for restore. The fork path and SDK session
creation are deferred to Phase 6.
* listSessions - SDK is source of truth; per-session DB read
is a best-effort overlay (failure never excludes an entry).
* disposeSession / shutdown - routed through a per-session
SequencerByKey to serialize teardown.
* getDescriptor, getProtectedResources, models,
onDidSessionProgress, setClientCustomizations,
setClientTools, onClientToolCallComplete,
setCustomizationEnabled, authenticate, respondTo*Request -
minimal Phase-5 wiring.
Stubbed for Phase 6 (throw async 'TODO: Phase 6'):
sendMessage, abortSession, changeModel, getSessionMessages,
plus the createSession fork path.
Tests: 29 unit tests in claudeAgent.test.ts cover the
createSession restore-id path, listSessions overlay resilience,
dispose serialization, and stub surfaces.
Note: provisional / onDidMaterializeSession is intentionally
omitted in Phase 5 (see plan section 3.3.1) - the workbench needs
an immediate sessionAdded until the agent has real materialization
work, which arrives in Phase 6 alongside SDK query() startup.
* agentHost/claude: Phase 6 — sendMessage, single-turn, no tools
Implements the Phase 6 plan: provisional sessions materialize on first sendMessage, route a single-turn prompt through the Anthropic Claude Agent SDK's WarmQuery, and stream SDKMessages back as protocol AgentSignals via a pure mapSDKMessageToAgentSignals reducer.
Tools remain denied (canUseTool: 'deny'); fork moves to Phase 6.5; Plan Mode UI moves to Phase 7.
Highlights:
- ClaudeAgent.sendMessage routes through _sessionSequencer to collapse concurrent first sends into one materialize + N ordered sends.
- _materializeProvisional has two abort gates (post-startup + post-customizationDirectory write) so disposeSession landing mid-materialize cannot leak a WarmQuery subprocess.
- ClaudeAgentSession owns the prompt iterator + per-turn deferreds; mapSDKMessageToAgentSignals is a pure reducer with state owned by the session.
- IClaudeAgentSdkService gains startup() alongside listSessions().
Tests: 43 unit + 2 proxy-backed integration. Council-review fixes (C1 dispose race, C2 missing integration test, S1 cwd-less ratification) included.
* agentHost/claude: address PR review (listSessions resilience, dispose abort)
Two Copilot-reviewer comments on #314216:
1. listSessions: wrap _sdkService.listSessions() in try/catch. AgentService.listSessions fans out across providers via Promise.all; an SDK dynamic-import failure would otherwise nuke every other provider's session list. Now logs and returns [].
2. dispose: abort _provisionalSessions AbortControllers before super.dispose(). Previously a racing first sendMessage parked inside _writeCustomizationDirectory could pass the materialize abort gates and call _sessions.set on a disposed DisposableMap, orphaning the WarmQuery. Aborting first triggers the existing post-customization-write abort gate, which asyncDisposes the WarmQuery.
Tests: 2 new regressions (listSessions empty on SDK throw; agent.dispose() during racing materialize disposes the WarmQuery). 45/45 unit + 2/2 integration pass.
Picks up xterm.js commit 08ae141 (xtermjs/xterm.js#5826) which adds dispose / hasRenderer guards in OverviewRulerRenderer and cancels its pending requestAnimationFrame on dispose. This addresses the long-standing 'Cannot read properties of undefined (reading ''dimensions'')' crash tracked in microsoft/vscode#303546.
The previous reverts only changed the spec to ^1.0.34, but the resolved entries in the lockfiles still pointed at 1.0.38 (with 1.0.38 tarballs and integrity hashes). Since ^1.0.34 satisfies 1.0.38, npm ci would still install the broken version. Pin to exact 1.0.34 in all three package.json files and regenerate the lockfiles.
* agents: bump @github/copilot to 1.0.38
Tracks the version pinned in extensions/copilot/package.json. Updates
both root and remote/ package.json + lockfiles. Verified by re-running
the real-SDK 'listModels returns well-shaped model entries' integration
test (AGENT_HOST_REAL_SDK=1).
(Written by Copilot)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* fix: skip electron re-download when correct version already present
The macOS/Electron CI job was failing because `electron.ts` unconditionally
deletes `.build/electron` and re-downloads Electron on every invocation.
When integration tests run CSS/HTML tests via `node-electron.sh`, they call
`npm run electron` which triggers this re-download. This can fail due to
transient network errors (e.g. 502 Bad Gateway from GitHub), causing the
integration test step to fail even though Electron was already downloaded
successfully in the dedicated "Download Electron and Playwright" CI step.
Fix: add a `.version` marker file inside `.build/electron` that records the
Electron version, MS build ID, and architecture. On the next invocation,
`main()` reads this marker and returns early if it matches the expected
version, skipping the unnecessary delete-and-re-download cycle.
Agent-Logs-Url: https://github.com/microsoft/vscode/sessions/8d0b4207-2616-497e-9a4f-bf8a39671934
Co-authored-by: roblourens <323878+roblourens@users.noreply.github.com>
* Revert "fix: skip electron re-download when correct version already present"
This reverts commit e1811ece5b. That
commit was pushed to this PR by another agent and is unrelated to the
@github/copilot bump that this PR is for.
(Written by Copilot)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
---------
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: roblourens <323878+roblourens@users.noreply.github.com>
* adding allowRead and testing with defaults
* Rename terminal sandbox read allow list
* Remove Copilot settings change from sandbox PR
* changes
* changes
* Updating sandbox runtime package
* Updating tests
* Add macOS test cases for denyRead/allowRead behavior and ~ path handling
Agent-Logs-Url: https://github.com/microsoft/vscode/sessions/ec5cf3c2-6c7b-4577-bdbb-8ac3d42bdfb0
Co-authored-by: dileepyavan <52841896+dileepyavan@users.noreply.github.com>
* changes for readonly home dir
* skipping integrated tests for sandbox
* running srt in tmp_dir for linux
* running srt in tmp_dir for linux
---------
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
* Fix broken sessions list
From #311751
Co-authored-by: Copilot <copilot@github.com>
* fix tests
* agentHost: settings followups
- Unrelated: fix local agent host being broken on main following
some overnight cleanups
- Register a JSON schema for agent session settings (only when they're
open since it has a perf cost)
- When there are multiple custom approval buttons, show them in a
dropdown similar to other tool calls.
* Add tests for agent session settings schema registration
* Bump @github/copilot from ^1.0.28 to ^1.0.34
Matches the version used in extensions/copilot.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* agentHost: tolerate synthetic Copilot models with empty capabilities
After bumping @github/copilot to 1.0.34, listModels() returns a synthetic
'auto' router entry shaped like { id: 'auto', name: 'Auto', capabilities: {} }.
The SDK's ModelInfo type still declares capabilities.limits.max_context_window_tokens
as required, so reading it crashed _listModels and zeroed out the model list.
Wrap the SDK type in a local ICopilotModelInfo with the actually-optional
fields marked optional, and skip entries lacking max_context_window_tokens
with a warn log instead of throwing.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* agentHost: surface synthetic 'auto' model with optional maxContextWindow
Instead of dropping the synthetic 'auto' router model, make
IAgentModelInfo.maxContextWindow optional and pass it through as
undefined when the SDK doesn't report a fixed context window. The
agentHostLanguageModelProvider already handles undefined via '?? 0',
and the protocol state type already had the field optional.
Update the real-SDK listModels test to allow undefined maxContextWindow
and to assert the 'auto' entry is present.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
---------
Co-authored-by: Copilot <copilot@github.com>
Co-authored-by: Connor Peet <connor@peet.io>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Bump @github/copilot in root and remote package.json to ^1.0.28 to match
the version pinned by the bundled copilot extension (extensions/copilot).
Also adds a real-SDK integration test for listModels that subscribes to
the root state, authenticates, and asserts every model has a well-formed
shape (id, name, numeric maxContextWindow). This guards against SDK
schema drift like the issue in 1.0.34, where the server returned models
with optional capabilities.limits, causing _listModels to throw a
TypeError that _refreshModels silently swallowed (resulting in no models
in the UI).
Drive-by: fix stale provider id 'copilot' -> 'copilotcli' in the same
test file.
(Written by Copilot)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Add SSH remote agent host bootstrap
Adds a new ISSHRemoteAgentHostService that automates connecting to a
remote machine via SSH, installing the VS Code CLI, starting
'code agent-host', and forwarding the agent host port back through
the SSH tunnel.
- New service interface and types in common/sshRemoteAgentHost.ts
- Full implementation using ssh2 in electron-browser/ with dynamic
imports to respect layering rules
- Multi-step quick input flow for SSH connection details integrated
into the remote agent host picker
- 'Connect via SSH' command registered in contributions
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Address PR review feedback
- Strip password/privateKeyPath from ISSHAgentHostConnection.config
so secrets are not exposed to consumers after connect
- Redact connection tokens (?tkn=...) in all log output and error
messages to prevent credential leakage
- Parse user@host:port format in SSH host input with proper validation
for port range and missing components
- Guard onDidClose with a closed flag to prevent double-fire when
dispose and SSH close/error events overlap
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* SSH working through main process
Co-authored-by: Copilot <copilot@github.com>
* Resolve ssh configs
Co-authored-by: Copilot <copilot@github.com>
* progress
* Granular connect progress, test fix
Co-authored-by: Copilot <copilot@github.com>
* Test, refactor
Co-authored-by: Copilot <copilot@github.com>
* Resolve comments
Co-authored-by: Copilot <copilot@github.com>
* Get rid of cpu-features
* Move to shared process
Co-authored-by: Copilot <copilot@github.com>
* fixes
Co-authored-by: Copilot <copilot@github.com>
* add ssh2 to remote/package.json
* Cleanup and fixes
Co-authored-by: Copilot <copilot@github.com>
* fix
Co-authored-by: Copilot <copilot@github.com>
* fix
Co-authored-by: Copilot <copilot@github.com>
* resolve comments
Co-authored-by: Copilot <copilot@github.com>
* comments
Co-authored-by: Copilot <copilot@github.com>
---------
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Raymond Zhao <7199958+rzhao271@users.noreply.github.com>
Co-authored-by: Copilot <copilot@github.com>
* Update conpty to 1.25
* see if changes fix 1.2.0-beta11 defering conptyNative.connect()
* Revert "see if changes fix 1.2.0-beta11 defering conptyNative.connect()"
This reverts commit c5d9064efa.
* Reapply "see if changes fix 1.2.0-beta11 defering conptyNative.connect()"
This reverts commit ded49adb14.
Exposes --agent-host-port/--agent-host-path to specify an additional
port for them to listen on. This runs as a separate process mirroring
the architecture from main.
Does a 'hello world', I need to keep testing it some more. I honestly
don't know a lot about the import changes Opus is doing here. Without
them, there is an error:
```
import { CopilotClient } from "@github/copilot-sdk";
^^^^^^^^^^^^^
SyntaxError: The requested module '@github/copilot-sdk' does not provide an export named 'CopilotClient'
```
This was Copilot's explanation for why they're needed here but not in Electron:
>The agent host process itself didn't change — the issue is the **module resolution environment** differs between Electron and the server.
>
>**Electron (desktop):** `ElectronAgentHostStarter` spawns a utility process that inherits the main process's module resolution. It resolves packages from the **root** node_modules, where `@github/copilot-sdk`, `ws`, etc. are all installed. Everything just works.
>
>**Server:** `NodeAgentHostStarter` spawns a child via `bootstrap-fork.js`, which registers a custom ESM resolver hook (bootstrap-import.ts) that **redirects** all module lookups to node_modules instead of root node_modules. That's the `[bootstrap-import] Initialized node_modules redirector for: ...\remote\node_modules` log line. The remote folder has its own package.json with a curated set of server-specific dependencies.
>
>The problems were:
>1. **Missing deps** — `@github/copilot-sdk`, `@github/copilot`, and `ws` weren't in package.json because the agent host had never run in the server context before
>2. **Resolver bugs** — bootstrap-import.ts was written when all remote deps were CJS. It hardcoded `format: 'commonjs'`, didn't handle `exports` maps, didn't handle `.mjs` files, and didn't resolve subpath imports like `vscode-jsonrpc/node`. These are pre-existing limitations that never mattered until now because no server component previously depended on ESM-only npm packages.
>
>So in short: the agent host code is identical — it's the server's module resolution plumbing that needed updating to support the ESM packages the agent host depends on.
cc @bpasero as the expert in this area