* chat: enable agent host defaults
Flip the Agent Host migration settings to their rolled-out defaults and enable remote Agent Host support for web clients attached to a remote extension host. Serverless web retains extension-host fallbacks. (Written by Copilot)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* test: cover web agent host disablement
Add web-remote coverage for configuration and AI disablement, and clarify the serverless web requirement in the setting description. (Written by Copilot)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* test: pin smoke session providers
Pre-seed extension-host smoke profiles before startup and update Agent Host picker labels so the suites exercise their intended providers after the default flip. (Written by Copilot)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* chat: restore agent host setting description
Keep the existing concise setting and policy description while retaining the runtime availability behavior. (Written by Copilot)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
---------
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Default editor and panel chat to Agent Host Copilot when the agent host is enabled
Builds on the chat.editor.preferCopilotHarness behavior to make Agent Host
Copilot the computed default chat provider for both editor and panel chat
whenever the agent host is enabled, so first-time users land on Copilot instead
of Local. chat.editor.preferCopilotHarness stays scoped to the one-time
Local -> Copilot migration only.
- Thread an agentHostEnabled flag (from IAgentHostEnablementService) through the
default-session-type resolution and its callers.
- Keep Local visible and selectable; honor explicit and remembered selections.
- New Local Chat opens a local session directly: it cancels the in-flight
default-provider resolution (which would otherwise block on agent host
activation) so the local request wins immediately.
- Open a Local chat first in all chat participant API tests, since chat
participants are a Local-harness feature.
- Add a smoketest.openLocalChat command for Local panel smoke scenarios; the
sandbox reopen path reveals the existing local session to avoid a focus race.
- Register an IAgentHostEnablementService stub in the component fixtures.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* chat: honor resolved session type when starting a new chat
Fixes the New Chat drop bug (review comment #2 on #326086): when the
agent host is enabled the computed default is a non-local harness, so the
editor clear path recomputed that default and dropped explicit or
preserved local requests.
- clearChatSessionPreservingType now branches on the resolved session
type for the sidebar (non-local -> loadSession, local ->
startNewLocalSession) so a generic New Chat from a Local panel
preserves Local, consistent with contributed panels.
- The resolved type is threaded through IChatWidget.clear ->
viewOptions.clear -> chatEditor.clear -> clearChatEditor so the editor
opens a session of that type instead of recomputing the default. This
restores explicit "New Local Chat" from a non-local editor.
- clearChatEditor applies an explicit target type directly and keeps its
swap-aware default only for direct (untargeted) calls.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* chat: cancel the previous applyModel resolution before replacing it
Assigning a new CancellationTokenSource to the MutableDisposable only
disposes the previous source, and disposing a CancellationTokenSource
does not cancel it. So a re-entrant applyModel() (view render, switch
session) left the prior in-flight resolution running, racing to call
showModel with a stale result. Cancel the previous source explicitly
before replacing it.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
---------
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Restart the application after updating sandbox settings so
configuration changes are loaded before running the allowRead
and allowNetwork probes.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Re-enables the 'Test Codex session' smoke test (skipped in #323867).
The native Codex binary ships as a per-platform *optional* dependency of the
`@openai/codex` launcher shim; npm silently ignores an optional dep that fails
to install, so a node_modules cache built during such a hiccup keeps the shim
(which makes Codex report as "available") but loses the binary — the session
then fails at spawn time and the test only times out after 5 minutes.
Add a from-source pre-check that fails fast with an actionable message when the
shim is present but the native binary is missing. No cache change is needed
here (main's lockfile has since rolled to a healthy cache); if it recurs,
bumping build/.cachesalt forces a fresh npm ci that reinstalls the binary.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* chore: bump electron@42.4.0
* chore: apply temp dir workaround for short paths
* chore: use 24.15.x for CI node
* chore: update nodejs build
* chore: bump electron@42.5.0
* fix: unblock playwright install on node 24.17
Node 24.16+ made Readable pause()/resume() a no-op on destroyed streams
which makes yauzl 2.x / extract-zip 2.x and older playwright extraction
hang forever.
- extensions/copilot: add "yauzl": "^3.3.1" override (was missed by #318682)
so electron and @vscode/vsce no longer resolve the broken yauzl 2.10, fixing the
hung `npm ci` in the Copilot and Extract chat-lib pipelines.
- extensions/copilot: bump electron ^39.8.5 -> ^42.5.0 so its install
script uses the native @electron-internal/extract-zip instead of extract-zip.
- bump @playwright/test ^1.56.1 -> ^1.61.1 so `playwright install`
uses the fixed extractor, unblocking the "Download Electron and
Playwright" step in all electron test pipelines.
* chore: update build
* agentHost: fix macOS sandbox smoke sentinel parsing
On macOS CI, the AgentHost sandbox smoke test resolves the shell to
/bin/sh, which uses the sentinel-based completion path. In that path, the
parser could consume the echoed sentinel command text
(`<<<COPILOT_SENTINEL_..._EXIT_$?>>>`) before the real numeric marker
arrived, causing a false `Exit code: -1` failure even though the command
later completed successfully.
Harden the sentinel parser to ignore echoed/non-numeric sentinel text
and use the latest complete numeric marker instead. Also force the
macOS AgentHost sandbox smoke test to use /bin/sh and assert that in the
suite log so local runs exercise the same path as CI.
Adds a regression test for echoed sentinel command text.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* chore: update screenshot baseline after playwright bump
* chore: bump distro
* chore: fix typecheck
* chore: bump distro
---------
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Reenable 2nd turn of Copilot CLI test
* test running on azure dev ops
* Restore title change guard
* Run even if failure
* Try fix missing chat session
* Try to prevent session from getting disposed
* Try to fix another flake
* Remove flake probe
`app.quality === Quality.Dev` is not a precise "running from source" signal:
`parseQuality()` also returns `Quality.Dev` for a `--build` product when
`VSCODE_QUALITY` is unset, which would wrongly hard-fail a packaged build that
legitimately lacks Codex. Use `process.env.VSCODE_DEV === '1'` instead — the
smoke runner sets it deterministically only in the no-`--build` (dev electron)
branch, mirroring the agent host's `isBuilt === false` that gates the
node_modules fallback. This matches existing dev-detection in main.ts and the
diagnostics already logged in this file.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Previously the Codex smoke test was a hard requirement only in dev and skipped
on all built products. But publish builds stamp `product.agentSdks.codex`
(only when VSCODE_PUBLISH=true) and resolve the SDK from the CDN, so Codex
should be available there too — skipping would hide a CDN-resolution
regression.
Fail when the build is supposed to resolve Codex (dev OR VSCODE_PUBLISH=true),
and skip only on built non-publish CI builds where the SDK is neither shipped
nor stamped. VSCODE_PUBLISH is an Azure pipeline variable auto-injected into
the smoke step env; it is absent in dev (GitHub Actions) runs, which the
`Quality.Dev` branch already covers.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Now that Codex resolves from the repo's `node_modules` in dev, the Codex
smoke test must always run when running from source instead of skipping when
the session type is unavailable. Make it a hard requirement in `Quality.Dev`
(throw if Codex is unexpectedly unavailable) and keep the graceful skip only
for built products, where the SDK is not shipped (devDependencies are
stripped) and is fetched from `product.agentSdks.codex` on publish builds
only — so non-publish CI builds legitimately have no Codex.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* sessions: hide session picker groups when no duplicate session names
Section headers in the session type picker exist to disambiguate session
types that share a label across providers (e.g. two providers both
offering "Claude"). When every type's label is unique there is nothing
to disambiguate, so render a flat list without group headers even when
multiple providers contribute.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* sessions: rename Copilot CLI session type label to "Copilot"
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* test: update Agents Window smoke test for renamed Copilot label
The Copilot CLI session type label was renamed to "Copilot" (shared
CopilotCLISessionType used by the Copilot Chat provider), so the picker
no longer exposes a "Copilot CLI" entry. Select "Copilot" instead.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
---------
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The "Agents Window > Test Copilot CLI session" smoke test flakily timed
out at `activateSessionByLabel`, which located the just-completed session
row by its title and expected it to equal the mocked reply
`MOCKED_COPILOT_RESPONSE`. That title is set asynchronously by a utility
model after the first turn and races the untitled->committed session
swap, so it is non-deterministically either the user's prompt (the
synchronous fallback) or the generated reply. The test passed on macOS
(title-gen landed) and failed on Linux (it didn't) in the same run.
Decouple row identification from response verification:
`activateSessionByLabel` now accepts one or several row substrings and
matches a row containing ANY of them, while a separate `responseLabel`
is verified against the active session's response bubble. The smoke test
passes both the first prompt and the reply, so activation is
deterministic regardless of when title generation completes.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The local agent host runs a single sessions provider whose session cache
holds every agent-host session type (codex, claude, copilot). When a new
session is sent, the provider identifies the freshly-committed backend
session in `_waitForNewSession` purely by novelty — the first cached
session whose raw id was not present before the send. The session's
type/scheme was never checked.
That is wrong when a session of a *different* type appears in the cache
during the send. A slow Codex session (which cold-starts a native
app-server before its first /responses turn) sent while a Claude session
from an earlier run is present would latch onto the Claude session and
return it as the Codex commit. `sendRequest` then reports an
"active session replaced: codex -> claude", the workbench swaps the
active slot to the wrong session, removes the Codex one, and the Codex
reply renders nowhere. A claude harness that is suppressed in the current
window (preferAgentHost=false) additionally throws "Agent host targets
must have an item provider" when activated. This is exactly why the
Codex smoke test timed out on the Windows CI runner (where the cold-start
race is widest), failing build 449022.
Filter `_waitForNewSession` by the `chatResource` scheme so a send only
ever commits a session of its own type, in both the immediate cache scan
and the onDidChangeSessions wait. Re-enable the Codex smoke test that was
disabled in #321983 to keep the build green.
Verified: a new unit test reproduces the cross-type latch (fails before,
passes after); live launch with stale claude sessions present shows the
Codex session stays active with no wrong swap; and the (re-enabled) Codex
smoke test passes locally end-to-end.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Reduce duplicate code
* Add a second turn to the chat smoke tests
* Fix tests
* "fix" sandbox test
* Make things work
* Get tests passing
* CCR feedback
* Simplify diff
* Undo chatView.ts changes
* Missing Claude warm up
The Codex smoke test previously could only skip: when the Codex session
type WAS available, the agent host's shared CopilotApiService discovered
CAPI endpoints by calling a hardcoded `api.github.com/copilot_internal/user`,
which 401s with the fake smoke token (the other harnesses avoid this —
Copilot CLI uses the @github/copilot SDK pointed at COPILOT_API_URL, and
the renderer-side Claude test uses the extension token manager). So no
agent-host model path had ever been mocked.
- copilotApiService.ts: honor a test-only `VSCODE_AGENT_HOST_CAPI_URL_OVERRIDE`
env. When set, skip the api.github.com discovery and route every CAPI
request (models/responses/messages) at the override. Never set in
production, so per-token discovery is unchanged.
- agentsWindow.test.ts (setupAgentHostSuite): set that override to the mock
server URL, so the codex harness's model list + /responses traffic reach
the mock.
- agentsWindow.ts (isSessionTypeAvailable): the picker dropdown is a one-shot
snapshot, so a provider that registers a few seconds after load (codex
spawns a native app-server first) was missed when the dropdown opened too
early. Re-open the dropdown on each poll and use a generous timeout so the
gate reliably runs when codex is present and only skips when it is absent.
Verified locally end-to-end: with codex available the test selects Codex,
the real app-server drives a turn through the proxy to the mock /responses
endpoint (codex's native payload), and MOCKED_CODEX_RESPONSE renders. With
codex unavailable it skips. 71 codex + 83 copilotApiService unit tests pass.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Adds an end-to-end smoke test for the codex harness that uses the REAL
codex app-server and fakes only the LLM. It reuses the existing
Agents-Window smoke harness, which already drives:
real Agents-Window UI -> agent host -> real spawned `codex` binary ->
real CodexProxyService -> mock LLM server
The mock LLM server (scripts/chat-simulation/common/mock-llm-server.ts)
already speaks codex's OpenAI `/responses` API and ships a
`gpt-5.3-codex` `/responses` chat-default model, so no LLM-side changes
are needed.
- test/smoke/.../agentsWindow.test.ts: new `Agents Window (Codex)` suite
via the existing setupAgentHostSuite helper with
`chat.agentHost.codexAgent.enabled` (codex is off by default). The test
selects the `Codex` session type, submits a scenario prompt, and
asserts the mocked reply plus a `chat/turnStarted` frame in the AHP
transcript (proving the codex harness, not a renderer fallback, served
it). Adds a warmUpCodexModel helper mirroring warmUpClaudeModel.
- test/automation/src/agentsWindow.ts: new isSessionTypeAvailable(label)
used to skip gracefully when codex isn't registered.
Codex only registers when its SDK is resolvable (product.agentSdks.codex
in packaged builds, or VSCODE_AGENT_HOST_CODEX_SDK_ROOT in dev); when
absent the test skips rather than fails.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* chore: sync agent-host-protocol to b55919a (multi-chat)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* refactor: route turn access via defaultChat helpers
Adopt the multi-chat Agent Host Protocol: turns, active turn, steering,
queued messages and input requests moved off the session and onto a
per-chat channel. A single default-chat compatibility layer recombines
the session with its default chat so existing consumers keep working:
- Server (AgentHostStateManager) routes chat actions to the default chat
and exposes a merged ISessionWithDefaultChat view.
- Client (AgentHostSessionHandler) subscribes to both the session and its
default chat channel and merges them for reads.
- Widen action dispatch/emit signatures to SessionAction | ChatAction and
migrate turn/tool-call/input wire strings from session/* to chat/*.
- Update tests and mock connection to serve ChatState for default-chat
subscriptions and route chat actions accordingly.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* test: adapt post-merge tests to multi-chat Chat* action names
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* fix: repair chat retrieval and config regressions from multi-chat adoption
The multi-chat AHP adoption introduced two classes of regressions:
1. Chat retrieval/echo routing: chat actions now emit on the derived
default-chat channel, but several consumers were still keyed on the
session URI. Await both the session and default-chat subscriptions
before reading history, restore the chat channel on subscribe, forward
ChatActions, and normalize chat<->session URIs in dispatch/side-effects.
2. Session config loss: getSessionState() now returns a merged composite
copy (mergeSessionWithDefaultChat), and _ensureDefaultChat replaced the
live map entry with a clone. Callers mutating the returned object
(state.config = ...) stranded the mutation on a throwaway. Fix:
_ensureDefaultChat mutates in place to preserve createSession/
restoreSession return identity, and a new setSessionConfig() mutates the
live map object for the async restore path.
Tests migrated to setSessionConfig() where they previously seeded config by
mutating getSessionState() returns; duplicate-restore and client-echo tests
updated to reflect the two-channel (session + default-chat) model.
All agentHost node suites (409) and the browser contribution suite (148)
pass; typecheck and valid-layers-check are clean.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* chore: sync agent-host-protocol to d7f592e (chat interactivity)
Regenerates the vendored protocol/ from agent-host-protocol @ d7f592e,
which adds the optional `interactivity?: "full" | "read-only" | "hidden"`
metadata to `ChatState`/`ChatSummary` and the `ChatInteractivity` type.
Mechanical sync only (scripts/sync-agent-host-protocol.ts); no hand edits.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* refactor: preserve chat interactivity across summary/state helpers
Carries the new optional `interactivity` field through the VS Code glue
converters so it round-trips between `ChatState` and `ChatSummary`
(`createChatState`, `chatSummaryFromState`) and re-exports the
`ChatInteractivity` type alongside the other chat types.
Absence still defaults to "full", so single-default-chat sessions are
unchanged; this just stops the field being dropped during denormalization.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* agentHost: sync protocol to 83fae5a (ChatInteractivity const enum)
Re-sync the vendored agent-host-protocol from a685a3e to 83fae5a, which
refactors ChatInteractivity from a string-union type to a const enum.
Pure type-level change with identical runtime string values; glue code
only passes interactivity through, so no source changes required.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* address PR review feedback on multi-chat adoption
- sync protocol to b88a4a3: Snapshot.state union now includes ChatState,
dropping the IStateSnapshot widening shim (con1)
- handler: resolve the default chat URI from the live session state's
defaultChat field instead of assuming a URI structure, with the
deterministic fallback clearly marked as temporary migration (con2, con3)
- protocolServerHandler: reject createChat for non-default chats with a
ProtocolError instead of silently succeeding (ccr2)
- agentSubscription: make getPendingActions type-honest by widening the
pending-action type to SessionAction | ChatAction and renaming the
channel field, removing the unsafe cast (ccr3)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* fix turn telemetry test stranded config mutation
getSessionState returns a detached composite (session merged with its
default chat), so mutating its config stranded the change. Use the
stateManager.setSessionConfig API to write the authoritative session
state instead, matching what agentService does in production.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* test: route protocol integration tests through default chat channel
The multi-chat protocol adoption moved conversation contents (turns,
activeTurn, queued/steering messages, input requests) onto the session's
default chat channel, and renamed turn/tool-call/responsePart actions from
`session/*` to `chat/*`. The Protocol WebSocket integration tests still
subscribed only to the session channel and dispatched/awaited the old
`session/*` action types, causing notification timeouts and reads of
undefined turn arrays.
- Add `fetchSessionWithChat` helper that subscribes to both the session and
its default chat channel and returns the merged ISessionWithDefaultChat view
- Update turnExecution, sessionFeatures, sessionLifecycle, multiClient to read
turn/conversation state via the merged helper
- Rename stale `session/*` conversation actions to `chat/*` in clientTools,
toolApproval, turnExecution, and realSdkTestHelpers
- Subscribe secondary multi-client clients to the default chat channel
- Fix copilotRealSdk usage assertion to read turns from the default chat
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* test: assert chat/turnStarted in AgentHost smoke test
The multi-chat protocol adoption dispatches turns as `chat/turnStarted`
on the session's default chat channel instead of `session/turnStarted`.
Update the Agents Window smoke test to look for the new action type in
the AHP JSONL transcript.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* agentHost: re-pin protocol to b3319ca (multi-chat merged to main)
The multi-chat sessions change landed on agent-host-protocol main as
b3319ca ("feat: multi-chat sessions (#213)"). The vendored copy was
previously synced from the PR branch (b88a4a3); the generated types are
byte-identical, so this only advances the .ahp-version pin to the merged
commit.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
---------
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Lots of logging for chat smoke tests
* PR test workflows: build extensions/copilot before smoke tests
* PR test workflows: drop duplicate copilot compile from linux/win32 (was already built before integration tests)
* smoke tests: remove musl Claude binary on Linux glibc runner
The musl variant is probed first by @anthropic-ai/claude-agent-sdk and
fails to exec on glibc (ENOENT from missing ELF interpreter), which
caused the Test Claude session tests to time out.