Skip to content

[pull] main from microsoft:main - #1661

Merged
pull[bot] merged 15 commits into
code:mainfrom
microsoft:main
Sep 3, 2026
Merged

[pull] main from microsoft:main#1661
pull[bot] merged 15 commits into
code:mainfrom
microsoft:main

Conversation

@pull

@pull pull Bot commented Sep 3, 2026

Copy link
Copy Markdown

See Commits and Changes for more details.


Created by pull[bot] (v2.0.0-alpha.4)

Can you help keep this open source service alive? 💖 Please sponsor : )

vritant24 and others added 15 commits September 2, 2026 14:40
Use the provisional session's creation roots until the Agent Host session
snapshot arrives so first-request migration hints assess the correct scope.
Confirmed session state remains authoritative once hydrated.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Use the last confirmed session snapshot when a subscription errors so
provisional roots are only used before session state is hydrated.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
)

* build: omit peer deps from agent SDK tarballs, bump claude to 0.3.258

npm 7+ installs peerDependencies automatically, so the claude tarball has
been carrying 100 packages the agent host never loads —
@modelcontextprotocol/sdk, zod, ajv and their transitive graph. The SDK
inlines all of that into sdk.mjs at publish time: sdk.mjs statically imports
node builtins and nothing else, and the one external module it resolves at
runtime is its own native binary package. Every reference to those packages
on the VS Code side is an `import type`, which TypeScript erases.

Adding --omit=peer to the packaging install leaves exactly two packages in
the tarball, both pinned to the SDK version. That makes the bytes a function
of (SDK version, target) and nothing else, so a transitive peer bump can no
longer change the content at a CDN path that is already published — the
failure that took #333870 and its revert #334094. Unlike --omit=optional,
this doesn't touch the native binary package. codex declares no peers, so
its tarball is byte-identical either way.

That the SDK inlines its peers is an implementation detail Anthropic never
promised, so package.ts now runs a load probe before tarring: in a child
process it imports sdk.mjs out of the staged tree and builds an MCP server
from it, peers absent. If a future version starts importing a peer for real,
the build fails there rather than on a user's machine against a tarball that
is already immutable on the CDN.

Bumping claude in the same change since the CDN path moves regardless.
0.3.258 adds a required Query.updateSettings, hence the three test fakes.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* build: verify the staged tree for every agent SDK, not just claude

`--omit=peer` applies to every SDK, and `Sdk` is an open string type, so
adding one is a single folder under `agents/`. The load probe that
justified the flag only ran for claude, which left any other SDK — codex
today, anything added later — inheriting the flag with nothing checking
it.

Replace the `if (sdk === 'claude')` guard with a `verifyStagedTree`
dispatcher whose `default` branch fails the build. The per-SDK checks
stay different on purpose: claude's tarball is dynamic-imported by the
agent host, so the build imports it too; codex's never is, since the
host spawns the vendored binary directly, so the binary layout is what's
worth asserting.

codex gets a structural check — the platform package vendors exactly one
rust triple, holding a non-empty executable binary. It deliberately does
not copy `codexAgent.ts`'s `sdkTarget → triple` table; a second copy
could drift and then validate a path nothing uses.

Also fixes a latent bug in `chmodPlatformBinaries`: the claude branch
looked for `claude` on every target, so it silently skipped win32's
`claude.exe`. Nothing shipped broken — the registry already publishes
that binary 0755 and Windows ignores POSIX modes on extract — but the
loop's filename assumption was wrong, and the new assertion checks the
same path it chmods.

Verified by fault injection against a real extracted tree: all seven
codex checks and the unknown-SDK branch fire, and an untouched tree
passes. Five real builds (claude darwin-arm64/win32-x64/linux-x64-musl,
codex darwin-arm64/win32-arm64) succeed; the claude darwin-arm64 sha is
byte-identical to one built before these checks existed.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* build: exercise the real tool() path in the SDK load probe, bound it with a timeout

Three fixes from PR review.

The probe checked that `tool` was a function but never called it. The
shipped path is `buildClientToolMcpServer`, which passes a zod raw shape
into `sdk.tool()` and the result into `createSdkMcpServer()`. A future SDK
that resolved zod lazily inside `tool()` would sail past the old check and
break at runtime. The probe now makes that exact call, using VS Code's own
zod, which is what the agent host hands across the boundary. Verified by
substituting a `tool()` that resolves a peer from disk: exit 1 with
ERR_MODULE_NOT_FOUND.

`spawnSync` without a timeout blocks forever, so the old comment claiming a
child process kept a stray handle from wedging the build was wrong. Added a
2 minute timeout and a `result.signal` check, since a timeout surfaces as
SIGTERM with a null status and would otherwise report a confusing exit code.

The README claimed every reference to the peers in non-test `src/` was
`import type`. That is true of `@modelcontextprotocol/sdk` but not of zod:
`claudeJsonSchemaToZod.ts` imports `z` at runtime. The invariant that
`--omit=peer` actually needs is narrower, that zod comes from VS Code's own
dependency rather than the downloaded tree, so the README says that instead.

Tarball sha is unchanged, since the probe file sits outside `node_modules`.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* build: trim comments in agent-sdk package.ts

Review feedback: the comments on the new verification code ran far longer
than the code they described. Cut them roughly in half, and point at
README.md for the rationale instead of restating it in three places.

Also drops `nativeBinaryName` for a one-line `exeName(base, sdkTarget)`.
It took an `Sdk` parameter every call site already knew statically, and
`sdk === 'claude' ? 'claude' : 'codex'` would have silently returned
'codex' for any SDK added later. The only rule the two share is the
`.exe` suffix on win32.

No behavior change: claude darwin-arm64 still builds to sha256
1050d42b5e86f1d5b0c3a910e5325894d7b1dcfb684fe08ff4ffbf09dcfe0cda and
codex darwin-arm64 to a32d7afd7f088e8e4fb9f237283bfb93f656ac1da5c78fb879d31e48422a241d.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* build: correct which SDK call the load probe leans on

createSdkMcpServer() is what validates and converts the zod raw shape;
tool() is a plain constructor that never touches zod. Verified by passing
a non-zod shape: tool() returns fine, createSdkMcpServer() throws
"inputSchema must be a Zod schema or raw shape".

Comment and README said tool() was the load-bearing call. The sequence
was already right, only the explanation was wrong.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* build: drop SDK-specific logic from the staged-tree check

verifyStagedTree was a switch with a claude case that imported sdk.mjs and
replayed buildClientToolMcpServer's call shape (zod raw shape into tool(),
result into createSdkMcpServer()) and a codex case that asserted the
vendor/<triple>/bin layout. That put one SDK's API into the packaging step
for a small gain: a peer that stops being inlined will come back as a
static import, which a plain import of the entry point already catches.

Now nothing in the check is conditioned on which SDK is building:

- The entry point comes from the installed manifest's `main`, which is the
  same path claudeAgentSdkService.ts imports at runtime. codex declares no
  `main`, so it is skipped without a special case.
- Every native binary must be present, non-empty and executable.

The per-SDK binary layouts move into listPlatformBinaries, which
chmodPlatformBinaries now shares, so the chmod and the assertion can no
longer disagree about where the binaries are. That is also the new-SDK
guard: no layout entry means no binaries found, and the build fails naming
the function to edit.

Removes the zod dependency from the build script and ~50 lines.

Fault-injected, all caught: binary missing / empty / not executable,
codex vendor/ removed, sdk.mjs importing an uninstalled peer (inserted
after the shebang so it is a real ERR_MODULE_NOT_FOUND), and
listPlatformBinaries returning [] for an unknown SDK.

Tarball bytes unchanged: claude darwin-arm64 1050d42b…, claude win32-x64
b4e00f75…, codex darwin-arm64 a32d7afd….

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* test: re-record /model stdout for claude 0.3.258

The bumped CLI now backticks the model name in its `/model` slash command
output, so the recorded request no longer matched the live one and the E2E
replay failed on Linux and macOS.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
Co-authored-by: vs-code-engineering[bot] <vs-code-engineering[bot]@users.noreply.github.com>
Show harness and workspace in Customizations modal title

Keep the modal title concise while surfacing its active harness and workspace as regular-weight context.\n\nCo-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* agentHost: classify worked items as artifacts

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* agentHost: clarify artifact references

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* agentHost: strengthen artifact guidance test

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* agentHost: guard artifact schema description

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* agentHost: snapshot artifact schema guidance

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…-customization-roots

Preserve customization roots during provisional sessions
* Polish mock policy server UI

Improve schema controls, delivery setup, theming, and the editable schema source workflow.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Address mock policy server review feedback

Restrict schema source mutation to loopback URLs, avoid :has state styling, and keep the schema status live region rendered.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…334133)

* Surface sandbox model fallbacks and honour confirmation editability

Three follow-ups to the sandbox model and approval work in #333897 and
#333883, all found while re-reviewing those changes against the agent
host protocol.

Report when a sandbox turn does not use the model the user picked. The
three give-up paths logged and sent the turn with no model, which the
protocol reads as "the host decides" - so the turn ran at a capability
and price the user had not chosen and nothing said so.

Keep a host's context-tier option instead of dropping it when the
workbench cannot label it. Partially reverts #333897: the token-count
labels paired two independent catalogues by array position, which
mislabels as soon as either list changes, and dropping the property
outright hid a control the session supports whenever the model was
unknown to the workbench. The host's own labels are used instead.

Honour editability on tool confirmation inputs. The confirmation editor
writes back into rawInput, which ILanguageModelToolsService applies for
extension tools, but an agent-host confirmation never returns it - so a
user could edit a command they were approving and watch the original
run. Adds an optional editable flag, defaulting to editable so existing
tools are unaffected.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Correct the removal criterion on the model catalogue fallback

The comment claimed the join could be removed once the agent host
publishes its own token counts and billing metadata. The billing half is
not coming: pricing is deliberately kept off the protocol as
operator-sensitive, so removing the join means dropping pricing for
these models rather than tidying up after a migration.

Separates the two halves: token limits are native protocol fields a host
can populate, pricing is a product decision.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Make terminal confirmations read-only on the agent host too

The read-only safeguard only covered the generic-input branch. A
terminal confirmation renders its own editor, writes edits into
commandLine.userEdited, and only the built-in terminal tool reads that
back when it runs the command. An agent-host confirmation returns
nothing, so the edit was discarded and the original command ran - the
same bug as the generic input, on the path that actually carries shell
commands.

Adds editable to the terminal invocation data, sets it false in the
agent-host adapter, and honours it alongside the existing
presentationOverrides read-only case.

Also states the model fallback in the future tense: the warning is
raised before the turn is dispatched, so the fallback has not been used
yet at that point.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Enhance agent merge status display and update related tests

* Refactor agent merge widget for improved message display and interaction

* Improve accessibility for agent message toggle and enhance related tests

* Update agent merge message toggle icon and enhance source display behavior

* Enhance chat agent merge styles for high contrast themes and update fixture for darkHighContrast support

* Add hover effects to agent merge header and enhance related tests

* Attach status hover to interactive disclosure in agent merge widget and update tests

* Refactor agent message button handling in chat agent merge widget for clarity and consistency

* Add section title for review feedback when failed checks are present in chat agent merge widget

* Add background color for agent merge widget and remove hover tracking from header

* Add timestamp metadata to agent merge widget and update related tests

* Update section title in agent merge widget from "Review Feedback" to "Feedback"

* Enhance pointer handling in chat agent merge widget to support touch input and suppress mouse focus

* Fix agent merge fixture after rebase

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

---------

Co-authored-by: mrleemurray <mrleemurray@users.noreply.github.com>
Co-authored-by: BeniBenj <besimmonds@microsoft.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* sessions: consolidate remote workspace options

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* sessions: address workspace picker feedback

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* sessions: enable remote workspace experiment

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* sessions: complete consolidated workspace filtering

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* sessions: refine consolidated workspace picker

Include GitHub entries in the web picker, move issue and pull request actions into Add Context, and focus workspace search when consolidated mode opens.\n\nCo-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* sessions: gate tabbed picker search and require repo for context actions

Co-authored-by: meganrogge <29464607+meganrogge@users.noreply.github.com>

* sessions: expose consolidated workspace setting

Register the workspace experiment in shared Chat settings and always surface GitHub issue and pull request actions through Add Context.\n\nCo-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* chat: add GitHub context picks to all inputs

Expose issue and pull request attachments through the shared Add Context registry. Prompt for the target repository first when multiple GitHub repositories are open.\n\nCo-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* chat: always show GitHub context picks

Fall back to the existing global GitHub search when repository discovery has not produced a scoped repository.\n\nCo-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* chat: align GitHub attachment menus

Keep native file and session attachments ahead of GitHub Issue and Pull Request actions, and expose those actions in the Agents new-session composer before repository resolution completes.\n\nCo-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* sessions: select repository before GitHub context

Use the repository picker whenever the Agents new-session context action has no unambiguous repository, including multi-root workspaces, before opening scoped Issue or Pull Request search.\n\nCo-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* sessions: scope GitHub context to local workspace

Resolve a selected local folder's GitHub remote before deciding whether repository selection is needed. This avoids showing the repository picker when the folder already identifies a single GitHub repository.\n\nCo-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* sessions: resolve GitHub remotes for selected folders

Context actions can receive a provider-neutral local workspace before Git metadata is attached. Resolve file folders through the Git service so a single GitHub remote skips repository selection.\n\nCo-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* sessions: avoid repository picker for selected folders

Resolve a selected folder's GitHub remote when available. If resolution finds no GitHub remote, open global Issue or pull request search instead of prompting for a repository.\n\nCo-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* sessions: reject stale Git roots for context

Only reuse GitHub remote metadata when the resolved Git repository contains the selected folder. Fall back to repository selection when the folder has no matching Git root.\n\nCo-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* sessions: pass selected workspace to context actions

Issue and pull request attachment actions must resolve repository context from the folder the user selected, not an alternate provider workspace candidate.\n\nCo-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* sessions: resolve context workspace through provider

Re-resolve the currently selected folder through the context action's provider at invocation time, preventing cached or cross-provider workspace metadata from selecting the wrong GitHub repository.\n\nCo-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: meganrogge <29464607+meganrogge@users.noreply.github.com>
* Agent Host: surface remote connection state in sessions

A session backed by an unreachable remote host previously spun forever with
no explanation and no way to recover. Surface that state and make it
actionable:

- Derive a session-scoped `remoteConnectionStatus` from the provider so the
  chat surface can react to connection state, not just host-scoped UI.
- Add machine-readable transport failure reasons so a stopped host is
  distinguishable from an unreachable one.
- Show a centered recovery state with a Start action when a session has no
  visible transcript, and a quiet inline banner when a rendered transcript
  drops mid-use.
- Report live bootstrap progress ("Downloading server (24%)") while a
  connect is in flight, via a shared progress parser.
- Split WSL startup, idle, and ceiling timeouts so a cold VM boot is not
  mistaken for a hung connection.
- Gate terminal launches on host availability and re-resolve chat content
  when a provider registers late.

Collect the connection concerns in ChatGroupView behind a single
SessionRemoteConnection, expressing state as observables with one derived
resolving which surface is visible. Read-only remains a peer of connection
state rather than part of it, since a read-only chat can also be
reconnecting. The quiet-reconnect delay is now a deadline, so re-arming is
idempotent instead of relying on a guard field.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Agent Host: auto-start a stopped remote host from the recovery surface

Adds an opt-in, kind-scoped policy that starts a stopped remote agent host
instead of waiting for the user to press Start. Providers expose it through
`IAgentHostAutoConnect` (label, observable value, setter) and choose how it is
backed; WSL backs it with `chat.agentHost.wsl.autoStart`.

The recovery screen and the inline banner both render the checkbox and live
connect progress. The Start action is never rendered while an automatic start
is pending: the content derivation itself returns the connecting presentation,
so this holds structurally rather than depending on autorun ordering.

Two ordering bugs surfaced while building this.

A connect that resolved without reaching the host cleared the in-flight attempt
and re-opened the automatic gate, spinning forever behind a permanent "Waiting
for agent host connection...". The gate is now latched per outage and released
once the host is reachable, so a mid-session drop still gets its own attempt
while an ineffective connect does not retrigger.

The service fired its connection-change notification from inside a failing dial,
before clearing the in-flight marker. A consumer dialing from that notification
joined the dial that had just failed, so nothing reconnected and its
`waitForConnection` never settled. The marker is now cleared before notifying;
`_connectTo` clears by identity, so a dial started from the notification
survives.

Both are covered by regression tests that reproduce the original hangs.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Agent Host: show reconnect backoff and offer a manual retry

While a protocol client waits out its exponential backoff the banner now reads
"Reconnecting to <host> in 5s" and counts down, with a Try Now action that skips
the remaining delay.

Try Now accelerates the client's in-place retry rather than redialling, so the
outbox and session state survive. It falls back to a fresh dial only when there
is no client to accelerate, which happens now that a rejected factory retains a
client-less entry.

The backoff deadline travels on the `reconnecting` status. The client stays in
that state across rounds, so the deadline is refreshed through a dedicated
`onDidScheduleReconnect` event rather than by re-firing the connection-state
event: consumers of that event do real work per transition, and repeating it
each round would have unclear blast radius.

Also offers a Retry action on the generic "Cannot reach <host>" state, on both
the banner and the centered recovery surface. A tunnel that dies is usually
transient. This stays manual: unlike a stopped WSL distro there is nothing local
to start, so retrying automatically would only hammer an unreachable endpoint.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Agent Host: address review feedback on remote connection state

Retaining a disconnected entry turned `connections` from a liveness list into a
status catalog, but three consumers still read presence as "connected": cloud
sandbox negative reconciliation would never tear down a failed environment, and
the cloud sandbox and Dev Container connect-failure paths would skip their
cleanup and leak a staged connection. Each now tests the status. Documented the
broadened semantics on the interface and removed an orphaned JSDoc block for an
accessor that no longer exists.

Reverted a stray `1.0.0` entry in the supported-protocol list. It broke the
registry's documented first-entry invariant against `PROTOCOL_VERSION` and the
handshake test, and had nothing to do with this work.

`setSession` now writes in one transaction. These observable writes notify
autoruns synchronously, so clearing the gates while the previous session was
still selected could start the host being switched away from.

The banner explains an incompatible host instead of staying silent. Once a
transcript is rendered the centered recovery state is skipped, leaving the
banner as the only surface, so suppressing it meant no explanation at all.

Accessibility: the banner's live region now announces dedicated text rather than
its visible text, so a per-second countdown no longer queues an utterance per
tick, and connect progress is announced as it advances.

Bootstrap progress discards a queued report before publishing an immediate one.
If the event loop stalled past the throttle interval, the stale pending value
could land after the newer one and make displayed progress run backwards.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Agent Host: describe the automatic-start latch scope accurately

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Agent Host: assign the session connection in the constructor

Its field initializer read _instantiationService, a parameter property of
the same class, which class-field semantics initialize after field
initializers run. Caught by define-class-fields-check.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* agentHost: Add copy path action to debug log exports

Return the saved export resource so the completion notification can copy the exact ZIP or folder path. (Written by Copilot)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* agentHost: Test copying debug log export paths

Cover the notification action for desktop archive and web export folder paths. (Written by Copilot)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@pull pull Bot locked and limited conversation to collaborators Sep 3, 2026
@pull pull Bot added the ⤵️ pull label Sep 3, 2026
@pull
pull Bot merged commit d2078dc into code:main Sep 3, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.