* Mock policy server: upstream passthrough, per-endpoint mocking, request log
The mock policy server only worked via product.overrides.json, which limits it
to Code OSS running from sources, requires a reload after every change, and
cannot exercise a stable/Insiders build or the CLI. Support a system HTTP proxy
as a second wiring path, keeping product.overrides.json as the default.
- Proxy anything not explicitly mocked to the real API (--upstream, default
https://api.github.com) and stream it back, so a blanket proxy rule is safe:
only endpoints deliberately switched on are faked. Rewrites Host, strips
hop-by-hop headers and accept-encoding, forwards Authorization untouched, and
reports upstream failures as 502.
- Add a per-endpoint mock/passthrough toggle. Only managed settings is mocked by
default; applying a preset implicitly switches mocking on.
- Add managed-settings disk cache clearing. A cache entry under an hour old
makes the runtime skip the network entirely, so an override is never even
requested. Paths verified against managed_settings_cache.rs and
path_helpers.rs, including the COPILOT_CACHE_HOME override.
- Add a rolling request log (GET/DELETE /api/log) surfaced in the GUI, so it is
obvious whether the client actually reached the server.
- Add realistic managed-settings presets, each validated against the schema, and
branch-point presets for the other endpoints.
- Only warn about unknown schema keys on 2xx, and re-validate on status change:
a 404/466/500 body is an error payload, not a policy document.
- Route GUI assets from an explicit allowlist instead of probing public/ for
anything that looks like a file, which would otherwise shadow proxied paths.
UX:
- Make save semantics consistent: everything auto-saves, with a pill showing
whether the editor matches what is being served.
- Surface mocked vs proxied via tab dots, a checkbox, and reactive help text.
- Add a light palette; the dark-only one declared color-scheme: light dark, so
UA form controls rendered light on a dark page.
- Make the schema disclosure a real button with aria-expanded, add focus-visible
styles, and expose tab state to screen readers.
- Build the validation table from DOM nodes rather than innerHTML.
- Surface save and wire failures instead of failing silently, and fall back to
the shared endpoint definitions when the control API is unreachable.
- Answer the GUI's own favicon request so it stops appearing in the log as a
proxied 404.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
* Polish mock policy server workflows
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Route runtime policy diagnostics through proxy
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Minimize runtime proxy integration
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Move runtime proxy fix to separate PR
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Address mock policy server review feedback
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
---------
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
* Support top-level model in managed settings while retaining permissions.model
VS Code drove the default chat model (ChatDefaultModel policy) only from the
legacy nested `permissions.model` managed-settings key. Also consume the new
top-level `model` key, retaining `permissions.model` for original-schema
deployments; when both are present the top-level `model` wins.
Because the server and file channels funnel through `normalizeManagedSettings`
(which flattens scalar leaves) and native MDM watches only declared keys, the
fix is: declare `model` on the policy so it is watched + projected on every
channel, and resolve the top-level-over-legacy precedence in the policy value
callback (`managedModelValue`). Precedence is key-level, so a non-empty
top-level `model` wins even over a `permissions.model` from a higher-precedence
channel; a blank top-level value falls back to the legacy key.
Fixes#330364
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Address PR review: condense JSDoc/comments and doc table
Trim the model constant + `managedModelValue` JSDoc to the 1-2 sentence limit,
drop the multi-line inline comments in the normalize tests, and leave the
schema table's `x-composition.strategy` cells as em dashes (top-level-vs-legacy
precedence stays in the constants table and the "Multi-key precedence" note).
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
---------
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* agentHost: restore Codex Desktop session continuity
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* agentHost: link delegated Codex sessions
Restore delegated prompts with source provenance and render durable links for created and messaged target sessions.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* agentHost: update peer sandbox expectation
Use the shared SDK sandbox builder so the peer-chat test follows the current sandbox contract.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* agentHost: harden Codex session restoration
Restore canonical Desktop threads without requiring prior enumeration, preserve folder isolation alongside legacy settings, and bound cold session reads.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* agentHost: isolate Codex customization tests
Run Codex provider integration tests with temporary home and user-data directories so synthetic mock rollouts cannot enter a developer session history.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* agentHost: update Codex restore test seam
Model the canonical-thread probe before fallback to persisted backing, and keep the SDK downloader fake aligned with its required contract.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* agentHost: pin Codex test home across platforms
Provide an explicit, pre-created Codex home to provider integration servers so Windows and POSIX tests share the same isolated rollout location.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
---------
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* sessions: simplify single pane lifecycle strategies
Consolidate single-pane behavior into New, Existing, and Quick Chat strategies while keeping shared tab and detail mechanics in coordinators. Preserve New Session editor visibility through isolated entry, toggle, and close transitions.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* sessions: stabilize single pane lifecycle behavior
Separate lifecycle visibility policy from shared detail content mechanics, preserve Existing session layouts, and avoid close/open and sizing flicker during session navigation.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* sessions: preserve managed tabs across session switches
Replace session-specific Changes inputs in place while retaining generation safety and restoring default Files tabs for the incoming session.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* sessions: address single pane review feedback
Handle detail sync failures, gate Changes tab actions to created sessions, and align Quick Chat documentation with its entry policy.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
---------
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Fixes the 11 integration test failures this branch introduced, plus four
review findings.
CI regressions:
- Restore `setWorktreeIsolation` (and the `CopilotApiService` /
`WorktreeIsolation` construction it depends on) inside
`if (!options.quiet)` in agentHostServerMain. Integration test servers
run with `--quiet`, so hoisting this out gave them host-owned isolation
schema for the first time, resolving a non-git working directory to
`isolation: 'folder'` and dropping `branch`. Broke 7 sessionConfig and
toolApproval tests.
- Register `IAgentHostCustomizationEnablementService` in the Claude
integration test's own service collection via a new shared
`createNoopCustomizationEnablementService()` helper.
- Codex cached a transient `workingDirectory`-pending verdict at plugin
parse time, permanently excluding the plugin from the SDK projection.
Re-resolve enablement at each projection instead.
Review findings:
- Gate root-configured MCP servers at Copilot launch. Only plugin children
were filtered, so a globally or workspace-disabled root server could
start and request authentication before the turn-start reconcile ran.
- Resolve MCP auth enablement live rather than from the immutable launch
snapshot, suppressing only on a definitive disabled decision so servers
we have no opinion about still authenticate.
- Compare Claude client customizations structurally, covering
`childEnablement`, so identical snapshots stop marking the plugin set
dirty and child-only toggles trigger reconciliation.
- Track Claude client enablement per client and rebuild the merged maps on
snapshot replace or client removal, so decisions omitted by a new
snapshot no longer leak onto a newly parsed plugin.
Also adds a `customizations-in-the-agent-host` skill documenting the
overlay model, host-vs-client global ownership, position-independent
identity, and the "every publication path goes through resolution" rule.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* agentHost: recover from expired GitHub credentials
Recover Agent Host sessions when GitHub credentials expire without requiring a
window restart.
- Emit complete protected resource metadata when providers require authentication.
- Resend the current client token before escalating to the shared sign-in flow.
- Update live Copilot SDK sessions with new credentials and restart only as a fallback.
- Re-arm authentication notifications after each client authentication attempt.
- Handle model-list authorization failures as authentication challenges.
- Keep recovery and transformed-token state isolated per Agent Host connection.
- Add local, remote, multi-host, concurrency, and live credential update coverage.
(Commit message generated by Copilot)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* agentHost: clear stale credentials during recovery
Clear a notification-scoped Agent Host credential when the client no longer has
a matching authentication session.
- Forward an empty token after token resolution fails.
- Reset staged recovery state after credential removal.
- Verify that a later token can start recovery again without prompting.
(Commit message generated by Copilot)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
---------
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Make the Windows Electron download retry actually retry
The step wraps the download in a 3-attempt loop, but the retry never
fired. `npm exec` is a native command, and a non-zero exit code from a
native command does not raise a terminating error in PowerShell, so the
`catch` block was unreachable: the first attempt fell through to `break`
and the step then failed on the non-zero exit code.
Wrap the call in `exec { }` from build/azure-pipelines/win32/exec.ps1,
which checks $lastexitcode and throws. This is the same shape the `npm
ci` retry in this file already uses, and it is why that one works.
Seen on a PR run where a transient socket close while fetching Electron
from github.com failed the job on the first attempt, with no retry:
TypeError: fetch failed
cause: SocketError: other side closed (UND_ERR_SOCKET)
at @vscode/gulp-electron/src/download.js
The Linux and macOS workflows are unaffected: their loops use
`if npm exec ...; then`, which tests the exit code directly.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 3c35355f-4d36-46e5-8d7a-cb0bc7207449
* agentHost: relocate Session ownership into the orchestrator (T2/T4)
Make the orchestrator (AgentService + AgentHostStateManager) own the Session
concept - identity, lifecycle, and grouping - so the agent harness talks only in
chats. Session provisioning stays agent-specific but is now invoked through the
chat surface instead of a Session-typed method, honoring "represent, don't
orchestrate".
- Create: `_provisionSessionViaDefaultChat` allocates the session URI and drives
`chats.createChat(defaultChatUri, { provisionSession })`; the agent's
provisioning runs inside creating the default chat and returns
`IAgentCreateChatResult.provision`.
- Dispose: routes to `chats.disposeChat(defaultChatUri)`.
- Enumerate: `_enumerateProviderSessions` groups `listConversations()` into
sessions via the default-chat URI convention.
Gated per harness by `IAgent.orchestratorOwnsSession` (Codex, Claude, Copilot all
opt in). Storage-preserving: session URIs and the derived `sdkSessionId == session
raw id` (I3) are unchanged, agents read/write the same SDK stores, and
providerData / PEER_CHATS_METADATA_KEY / protocol types are untouched. The legacy
createSession/disposeSession/listSessions remain as the delegated fallback.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* agentHost: drop orchestratorOwnsSession opt-in; chat surface is the single path
Address review feedback: the agent should not declare an orchestration policy,
and the interface should not carry an optional flag that splits behavior. The
opt-in was transitional scaffolding for a per-agent rollout; all harnesses have
migrated, so remove it and make the orchestrator drive the chat surface
unconditionally.
- Remove `IAgent.orchestratorOwnsSession`; make `listConversations` required.
- `AgentService` always provisions (non-fork/import) / disposes / enumerates
through the chat surface; no per-agent branch.
- Drop the flag from Claude/Copilot/Codex.
- Make both test mocks first-class chat-surface agents (provisionSession bridge,
default-chat disposeChat, listConversations) so their existing createSession/
disposeSession assertions still hold via the bridge.
- Update the routing test to assert session create/dispose now also flow through
the chat surface; refresh the architecture doc.
Storage-preserving; no protocol/data change.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* agentHost: trim verbose comments on the T2/T4 session-ownership code
Shorten the JSDoc/inline comments added for the session-ownership relocation to
1-2 sentences per the coding guidelines; drop obvious per-field comments. No
behavior change.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* agentHost: drop redundant session-typed methods from IAgent (Category C)
Remove `listSessions` and `getSessionMessages` from the IAgent contract - they are
superseded by `listConversations` and `chats.getMessages`. Reroute the one
remaining internal caller (the restore metadata catalog fallback) to
`_enumerateProviderSessions` (which uses `listConversations`). The harnesses keep
those methods privately as the implementation their chat/conversation bridges
delegate to.
`createSession`/`disposeSession` stay on IAgent as the session-lifecycle
provisioning primitives the chat-surface bridge delegates to; `createSession` is
also still used directly for fork/import, whose session id is minted server-side
(sessions.fork) and so cannot fit the orchestrator-allocates-URI seam - left as a
documented follow-up.
No behavior change; storage-preserving.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* agentHost: rename IAgent.getSessionMetadata to getConversationMetadata
Align the single-item metadata lookup with the chat-addressed conversation
surface: the method is now keyed by a chat URI and returns
IAgentConversationMetadata, mirroring listConversations. All five implementers
(Copilot, Claude, Codex, and both test mocks) derive the session from the chat
URI and return chat-keyed metadata; the orchestrator maps the default-chat URI
back to a session when hydrating restore metadata.
Also reframe the fork/import createSession path in MULTI_CHAT_ARCHITECTURE.md
from a deferred follow-up into a permanent, by-design exception (the fork id is
minted server-side by the SDK, so the orchestrator cannot pre-allocate the URI).
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* agentHost: clarify IAgentConversationMetadata._meta is session-generic by design
Document why the field keeps the SessionMeta alias rather than a
conversation-specific type: _meta is the protocol's open property bag on
SessionState / SessionSummary, carried through verbatim.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* agentHost: clarify Claude disposeSession takes the agent's own SDK session URI
Document that the session parameter is the provider's own SDK session (the
SDK's terminology), NOT the AH-level Session grouping - that grouping lives in
the orchestrator and the agent only ever deals in chats. The URI backs the
default chat (invariant I3), so chats.disposeChat routes here when a default
chat is disposed; peer chats go to _disposeChat. Teardown disposes that SDK
session plus the peer-chat backings the agent parents under it.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* agentHost: document the AH-session vs SDK-session terminology convention
Add a 'session is overloaded' convention table to the Mental Model section:
in the protocol/orchestrator 'session' means the AH grouping; inside an agent
harness it means the provider's own SDK session (Codex: thread); at the IAgent
seam the session URI is a shared identity (AH-minted, SDK-session-id raw id per
I3). Explains why we do not rename the provider-internal 'session' symbols.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* agentHost: make IAgent enumeration session-keyed (orchestrator owns session->chat)
Revert the chat-keyed enumeration surface (listConversations /
getConversationMetadata) back to session-keyed listSessions / getSessionMetadata
on IAgent. Chat-keyed enumeration forced every harness to derive default-chat
URIs via buildDefaultChatUri for cold (SDK-discovered) sessions it never created
in-process - re-deriving the session<->default-chat encoding that belongs to the
orchestrator/protocol.
Now each agent returns its own SDK-session identity (AgentSession.uri: provider
scheme + SDK id, no protocol-chat knowledge) and the orchestrator owns the
session->chat mapping. Drops the orchestrator's _conversationToSessionMetadata
bridge (the enumeration/restore round-trip) and deletes the now-unused
IAgentConversationMetadata type.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* agentHost: stop agents synthesizing default-chat URIs at runtime
Agents no longer call buildDefaultChatUri. Outbound events, default-vs-peer
comparisons, and session-or-chat normalizers now reuse the chat URI the agent
was already given - read back from the session entry's stored defaultChatKey (new
getter on AgentSessionEntry) or the live session's stored chat channel, or tested
with isDefaultChatUri - instead of re-deriving it from the session URI.
The one irreducible conversion (a session URI first born inside the agent: a
freshly forked SDK-assigned id, or a cold-restore/create seed) is centralized in
a single node-layer helper, defaultChatUriForSession, in agentPeerChats.ts. This
is creation-time only; no runtime routing/event path derives chat URIs anymore.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* agents: reuse orchestrator default-chat URI on the provision path
The provision (create) path already hands the agent the orchestrator-allocated
default-chat URI via createChat(defaultChatUri, { provisionSession }). Claude and
Codex decoded it to a session and then re-derived the identical URI inside
createSession. Thread the supplied chat URI straight through (createSession's new
optional defaultChat argument) so the agent seeds its entry with the URI it was
handed instead of re-deriving the session-to-default-chat mapping itself.
Copilot has no synchronous create seed (it stores a provisional session and
seeds the default-chat key at materialize/resume), so it has no provision
round-trip to thread; its derivations are the restart-lazy category.
The remaining defaultChatUriForSession callers are the restart-lazy paths (cold
resume, peer-send provisional default, fork/restore materialize) where the
orchestrator supplies no chat URI in-call; documented as the single sanctioned,
irreducible conversion. Behavior is unchanged (the mapping is deterministic);
two Claude tests that deep-equal the emitted URI object are aligned with the
file's toString-based convention since keying now populates the URI's cache.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* agentHost: flatten provider chat bindings
Make Agent Host own chat membership and pass contextual data only for individual operations. Providers route exact chats to their SDK conversations without deriving default or peer roles.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* agentHost: make chat lifecycle exact and retry-safe
Post-merge repairs and review follow-ups for the AH-owned multi-chat
architecture, keeping providers on exact chat-to-SDK bindings:
- Make `IAgentChats.releaseChat` mandatory so AgentService has one
exact-chat release path with no optional legacy fallback; Claude,
Copilot, Codex, and the test agents implement it explicitly.
- Copilot chat disposal now propagates SDK deletion failures (preserving
routing/state for retry) but tolerates an already-deleted session via an
O(1) `getSessionMetadata` recheck, keeping a partially-completed
multi-chat teardown retry-safe.
- Claude: gate materialization on post-await cancellation, abort every
live session's controller on dispose, and restore session-addressed
resume without inferring chat membership from the URI.
- Rename `IAgentCreateChatOptions.provisionSession` to `newSession` to
state intent (this createChat creates the owning session).
Verified typecheck, transpile, AgentService/Claude/Copilot/Codex unit
suites, valid-layers, and hygiene.
* agentHost: restore subagent transcripts via the chat-surface getMessages
Copilot's `chats.getMessages` routes to `_getChatMessages`, which lacked the
subagent-session-URI branch that only lived in the now-orphaned
`getSessionMessages`. On the persisted replay/restore path the orchestrator
loads a subagent's turns through the chat surface, so reopening a session
rebuilt an empty subagent transcript — failing the "reopening a session keeps
sub-agent messages out of the parent transcript (replay path)" E2E test on all
platforms. Extract a shared `_getSubagentMessages` helper and route subagent
URIs through it from both `_getChatMessages` and `getSessionMessages` (matching
Claude, which already shares one path).
Also address PR review feedback:
- `AgentService._releaseSession` releases every catalog chat even if one
rejects, then propagates the first error (idle eviction has already dropped
the session state, so a skipped leaf would stay resident indefinitely).
- `CopilotAgentSession` stores the host-supplied `IAgentChatContext.resource`
as its persistence scope instead of re-deriving it from the mutable chat
channel via `isDefaultChatUri`, so an explicitly chosen resource survives a
later `bindChatChannel`.
- MULTI_CHAT_ARCHITECTURE.md: correct the flat `IClaudeChatBinding` shape
(`{ sdkSessionId, model? }`, no retained session/storageUri).
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* agentHost: orchestrator owns session provisioning; agents only create chats
Removes the `newSession` seam so an agent no longer distinguishes "a chat for a
new session" from "a chat for an existing session". Session provisioning now
always goes through the agent's dedicated `createSession` + `chats.bindSessionChat`
(the same path fork/import already used), and `chats.createChat` has exactly one
meaning: add an additional chat to an already-provisioned session.
Contract:
- Delete `IAgentProvisionSession`, `IAgentCreateChatOptions.newSession`,
`IAgentProvisionResult`, and `IAgentCreateChatResult.provision`.
- Add `IAgentCreateChatOptions.inheritedContext` ({ workingDirectory, config }):
the orchestrator supplies the owning session's resolved context when creating
an additional chat, so the agent never reads it back from the parent session.
Orchestrator:
- `_createProviderSession` always provisions via `createSession` +
`bindSessionChat`; delete `_provisionSessionViaDefaultChat`.
- `_buildInheritedChatContext` resolves the AH-owned worktree/folder + session
config values and passes them to `chats.createChat`/`fork`.
Agents (Claude, Copilot, Codex):
- Drop the `if (options.newSession)` branch and the `_provisionChat` method; the
chat surface handles additional chats only.
- Claude/Copilot consume `inheritedContext` for the additional-chat working
directory (and Claude for its permission mode) instead of resolving the parent
session; remove the now-dead `_createSession(target)` plumbing where the
provision path was its only caller.
Tests/docs:
- Rewrite the AgentService routing test to assert provisioning via
createSession + bindSessionChat.
- Update MULTI_CHAT_ARCHITECTURE.md §2/§7 to the new seam.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* agentHost: enable multi-chat for Codex (base for I3-removal branch)
Adds Codex multi-chat support (parity with Claude/Copilot): the
`multipleChats: { fork: true }` capability, `chats.createChat`/`chats.fork`
minting a fresh backing Codex thread per chat, `materializeChat` restore, and a
providerData codec. This is committed as the base of the dedicated I3-removal
branch (it is intentionally not on the PR branch).
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* agentHost: add orchestrator-owned session registry (I3 removal stage 1)
Introduce AgentSessionRegistry, a durable, orchestrator-owned index of the
sessions that exist, keyed by session URI and persisted as a JSON blob in a
reserved session database with serialized read-modify-write. Wire it into
AgentService: register on every createSession success and on restoreSession,
unregister on true delete (disposeSession). Add a Stage 1 validation surface
(getRegisteredSessions) plus component and parity unit tests.
This is additive and does NOT yet drive enumeration; listSessions still uses
the provider-derived path. It is the foundation for switching enumeration off
invariant I3 in stage 2.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* agentHost: enumerate sessions from the registry, not providers (I3 removal stage 2)
Switch AgentService.listSessions to iterate the orchestrator-owned session
registry instead of unioning each provider's listSessions(). Per-session
metadata still comes from the agent's direct getSessionMetadata lookup (I3
keeps the default chat's SDK id == session id, so it resolves), then flows
through the existing DB and state-manager overlays unchanged.
This decouples AH enumeration from the agents' SDK stores: peer-chat backings
and subagent sessions never enter the registry (so they cannot leak as
top-level entries), and a provider that transiently drops a session from its
own snapshot no longer evicts it. Idle provisional sessions are suppressed
explicitly via a new state-manager predicate (isIdleProvisionalSession),
preserving #321269 now that the registry — not the provider snapshot — is the
session source. A one-time, marker-gated backfill seeds the registry from the
legacy provider enumeration so hosts created before the registry keep their
on-disk sessions.
I3 is unchanged; agents are untouched. Adds backfill and transient-drop tests.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* agentHost: clarify Codex is already I3-decoupled (I3 removal stage 3a)
Codex's default chat does not actively satisfy I3: a fresh session's raw id is
an AH-minted provisional UUID while its backing thread id is app-server-assigned,
with the real mapping persisted in the per-session metadata overlay. The residual
sessionId == threadId uses (_readSession's ?? sessionId fallback and listSessions'
thread->URI mapping) are legacy-compat shims for pre-existing sessions whose
persisted identity is the thread id; they cannot be removed without a data
migration (disallowed), so Codex is treated as already I3-satisfied.
Comment/doc-only: clarifies the two shim sites and adds a per-agent nuance note
to the I3 invariant in MULTI_CHAT_ARCHITECTURE.md. No behavior change. The active
I3 removal targets are Claude and Copilot.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* agentHost: collapse fresh-session provisioning into chats.createSessionChat (I3 removal stage 4, step 1)
Add an optional chat-surface entry, chats.createSessionChat, that provisions a
session AND binds its session-backed (default) chat in one call — the
replacement for the IAgent.createSession + bindSessionChat provisioning pair.
The agent reuses the session id as its SDK id (id-reuse kept; no storage
change, no I7 for the default chat). The orchestrator mints the session URI,
derives the default-chat URI, and calls createSessionChat; agents that don't
implement it fall back to the create-then-bind pair.
Claude implements it via its existing { kind: 'chat' } provisioning path (also
used by truncate), so routing state is identical to create-then-bind. Only
fresh sessions collapse: fork and import mint a fresh SDK-assigned session id
inside the agent, so the orchestrator can't know the default-chat URI up front
and keeps them on the create-then-bind pair. bindSessionChat is now documented
as the restore-time counterpart.
Additive and always-green: Copilot/Codex still use createSession. Validated
typecheck, layers, eslint, hygiene; Claude units 206, AgentService 140, Claude
E2E replay 8.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* agentHost: implement chats.createSessionChat in Copilot and Codex (I3 removal stage 4, step 2)
Both agents now provision a fresh session and bind its session-backed (default)
chat through the collapsed chats.createSessionChat entry, delegating to their
existing _createSession and then binding the default chat (id-reuse; no storage
change, no I7 for the default chat). The orchestrator already prefers this path
for fresh sessions across all providers; fork/import still use createSession.
Validated typecheck, layers, eslint, hygiene; Copilot 347, Codex 47,
AgentService 140 units; E2E replay Copilot 15 / Codex 6 / Claude 8.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* agentHost: enable Codex multi-chat capability
Advertise Codex multiple-chat and fork support now that the exact chat binding, model-provider forwarding, and registry-owned enumeration paths are complete. Keep provider-owned side chats disabled for Codex.
Add replay-only parity gating for Codex model-backed peer/fork tests. Host-only capability checks and conformance catalog/lifecycle coverage remain enabled; recording mode still runs the gated tests once the documented live Codex recording defect is fixed. No capture files are fabricated or hand-edited.
Validated typecheck, layers, ESLint, Agent Host unit suites, and Claude/Copilot/Codex strict replay.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* agentHost: allow recording gated multi-chat E2E tests
Keep Codex model-backed peer/fork tests skipped in strict replay while permitting both focused recording modes to execute them and generate fixtures.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* agentHost: harden session registry and chat lifecycle
Make registry load/write mutations durable and retryable, require successful provider enumeration before marking backfill complete, and unregister before irreversible deletion. Dispose every peer and always run provider-level session finalization before surfacing the first error.
Harden Codex workspace-less peer/fork managed-directory ownership across create, release, restore, and disposal; refresh an empty model catalog before validating restored provider-qualified models.
Remove unsupported multi-chat capability from ScriptedMockAgent and add regression coverage for every reported failure/retry path.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* agentHost: remove Claude default-chat URI inference
Use exact chat state routing and retain only the legacy bare-session compatibility path.\n\nCo-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* agentHost: make chat backings session-neutral
Give every provider an exact default-chat backing, keep Agent Host authoritative for membership and lifecycle, and isolate provider enumeration to legacy discovery.\n\nCo-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* agentHost: dispose legacy Claude sessions
Retain exact default-chat disposal while falling back to an unbound same-ID SDK conversation for direct legacy provider callers.\n\nCo-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* agentHost: route peer session events to owners
Normalize session-scoped progress from exact chat resources, keep Codex peer lifecycle off backing session URIs, and resolve peer configuration through the owning AH session.\n\nCo-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* agentHost: restore Codex peer chat history
Resume cold Codex peer threads before reading their turns and honor the persisted replacement thread ID. Share concurrent resume work with the first send and suppress idle usage notifications emitted during restore.\n\nCo-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* test: update AgentService worktree deletion stub
Use the current prepare/remove worktree deletion contract so durable registry retry coverage reaches the expected cleanup path.\n\nCo-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* agentHost: fork the exact Copilot source chat
Pass the orchestrator-owned default chat channel through session forks so Copilot resolves independent SDK backings. Preserve refork support when imported protocol turn IDs already match provider event IDs.\n\nCo-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* docs: clarify btw command input
Document that selecting the slash command consumes the command token, so the remaining input must contain only the side question.\n\nCo-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Restore persisted subagent chats
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Store orchestrator state separately
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Attach restored peer rejection eagerly
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Cancel session cleanup before revival
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Enforce Agent Host routing channels
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Use plural session working directories
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Apply provider feedback consistently
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Clarify provider chat backing terminology
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Stop inferring chat role from resource
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Simplify provider chat resolution
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Require exact source chat for forks
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Let providers observe session config
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Restore subagent transcripts lazily
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Complete chat-only provider ownership
Route provider provisioning, restore, lifecycle, configuration, and active-client behavior through exact chat-addressed seams. Preserve additive legacy default-chat migration across Claude, Copilot, and Codex and remove obsolete session compatibility paths.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Fix chat test field initialization
Avoid directly reading the overridden chat surface from subclass field initializers so define-class-fields compilation remains safe.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Keep session chat roles in Agent Host
Move legacy backing selection and session-versus-peer materialization filtering into Agent Host. Providers now recover or materialize exact opaque chat backings without retaining session/peer classifications.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Make provider chat creation uniform
Remove provider-visible chat role classification and collapse runtime initialization and additional chat creation into one createChat operation. Document and test the registry backfill's idempotent, coalesced migration behavior.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Flatten provider chat creation
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Remove session ownership from agent chats
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Address active clients by chat
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Make agent provider seams chat-only
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Organize agent provider contract
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Group legacy chat recovery APIs
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Document agent capability optionality
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Separate agent provider model
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Fix cold peer-chat fork to read source chat's own persistence resource
Cold peer-chat fork previously read the shared configurationResource
overlay instead of the source chat's own persistence resource, so
inherited model/agent/permissionMode came from the wrong scope for any
non-default source chat. _chatConfigScopes now records both the
configurationResource and the exact resource (IChatScopeBinding) for
each chat, and _bindInheritedConversation reads the source overlay by
the source's own resource. Also adds a backing-model fallback for a
source that was created but never materialized.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Add regression tests for cold peer-chat fork scope inheritance
Covers two scenarios for the claudeAgent.ts fix (commit aabdead86d):
- a peer chat materialized before a cold restart forks with its own
model/agent/permissionMode/workingDirectories, not the session-wide
decoy overlay
- a peer chat never materialized before a cold restart still recovers
its model via the _chatBackings fallback
Also adds a per-resource-aware ISessionDataService test double, since
the shared sessionTestHelpers.ts fake ignores the resource argument and
returns one flat database for all resources, which would otherwise mask
the session-vs-peer overlay bug.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Complete Agent Host chat ownership migration
Make session registry migration durable, preserve exact chat backings across provider restore and lifecycle paths, and harden deletion and rollback behavior. Rename the architecture spec and add regression coverage across providers, migration, concurrency, and protocol restore.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Restore Agent Host checkpoint lifecycle
* Fix Agent Host CI test portability
---------
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* agentHost: bridge legacy settings to managed permissions
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* agentHost: apply managed settings with extension methods disabled
Treat the typed managed-settings notification independently from generic extension requests, and cover the local host configuration. Initialize the Copilot managed-settings snapshot in the constructor to satisfy class-field ordering checks.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* agentHost: isolate managed settings bridge plumbing
Send managed permissions before fresh-connect restoration and assert that wire order. Inject the dedicated managed-settings service into the protocol handler so the provider-neutral agent service no longer exposes Copilot SDK types.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* agentHost: keep managed permission types host-owned
Use a restrictive host DTO across common and browser layers so Copilot SDK Node globals do not pollute Monaco compilation. Cover the exact local apply and clear notifications, and correct the AHP notification terminology.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* agentHost: clean managed settings on handler disposal
Remove every handler-owned client's managed permission contribution before disposing active connections or disconnect-grace timers, preventing stale restrictions when an endpoint handler is replaced.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* agentHost: scope managed settings by protocol handler
Namespace managed permission contributions per ProtocolServerHandler so handler-local client IDs cannot collide in the shared aggregate. Preserve same-handler reconnect identity and cover cross-handler cleanup.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
---------
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* test: add comprehensive unit tests for single-pane layout strategies
Add singlePaneStrategies.test.ts covering each composed single-pane
strategy in isolation (NewSessionRules, QuickChatEditorHide,
DetailVisibility, DetailPanel, ManagedTabs, EditorAreaCollapse,
ResponsiveSidebar) via a hand-built ISinglePaneLayoutContext backed by
the shared test harness. Focuses on the bug-prone edges surfaced during
the refactor: intrinsic submit detection, D3c leave-as-is with no saved
state, empty-group Preserve during restore, R1 editor re-hide, managed
tab dismissal memory, and responsive sidebar auto-hide/restore.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* test: drop unused restoreCalls scaffolding from strategy test context
Address CCR feedback: the restoreCalls field was never read or asserted.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
---------
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Agent Host changes for osortega/agents/remove-all-the-code-for-backend-v1-of
* Preserve pending cloud tasks until workspace opens
Only consume cross-window task deep links after Git reports the matching repository, preventing the source window from clearing shared pending state.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Migrate cloud session state from pull request URIs
PR-backed cloud tasks are listed under a stable /task/<id> resource and report the /<prNumber> URI they were previously listed under, so archived, pinned and read state migrates forward instead of being orphaned.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
---------
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* agentHost: Handle interactive Copilot permission denial
Map a user-skipped permission prompt to the SDK's reject decision with feedback, re-enable the Copilot E2E variant, and pin the clean denial result.\n\n(Written by Copilot)\n\nCo-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* agentHost: Check final denial response suffix
Keep the shared file-denial assertion compatible with providers that emit Markdown before invoking the tool.\n\n(Written by Copilot)\n\nCo-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* sessions: use action widget for conversations picker
Contribute labeled Chats, Side chats, and Subagents groups while keeping the Sessions workbench responsible for rendering the scoped Action Widget dropdown.\n\nCo-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* sessions: improve conversations picker
Render the Agents window conversations picker with Action Widget navigation semantics, active-item focus, chat status indicators, and a scoped Subagents group. Covers #329176.\n\nCo-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* actionWidget: fix navigation accessibility and focus
Preserve undefined checked state for menu items and consume initial focus only once so filtering does not override user navigation.\n\nCo-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* agentHost: skip unaffected E2E tests in PR CI
Classify changed PR files inside the existing Electron jobs and skip the bundled-provider Agent Host E2E suite when no relevant source, SDK, build, or harness files changed.
(Written by Copilot)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* agentHost: fail open when change detection fails
Run the full Agent Host E2E suite when pull request file enumeration fails, keeping the classifier an optimization rather than a CI dependency.
(Written by Copilot)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
---------
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Basic "create session from PR"
* All working, with tests
* Properly exclude PRs for which we already have a session
* Get click working, try to make llm use attached context
* Better rendering of PR context
* Use existing progress messages
* Wire up PR data
* CCR feedback
* Fix showing PR with existing session showing in picker
* Fix tests
* sessions: remove local chat enablement setting
Always register the local chat provider and its customization harness, and remove obsolete setting gates, tests, and documentation. (Written by Copilot)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* sessions: remove Local harness from Agents window
Remove the Local sessions provider, harness registration, picker actions, documentation, and smoke coverage while preserving Agent Host fork behavior in its own contribution. (Written by Copilot)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* sessions: avoid Local customization fallback
Activate the first real provider harness and suppress the shared Local fallback label in the Agents window when no harness is available. (Written by Copilot)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
---------
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* agentHost: run E2E suites in parallel
Run the deterministic conformance and provider entrypoints concurrently while preserving serial server reuse within each suite. Integrate the parallel runner into coverage and full integration runs.\n\n(Written by Copilot)\n\nCo-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* agentHost: harden parallel E2E runner
Preserve Windows argument boundaries through a PowerShell wrapper and fail coverage runs when a worker does not emit protocol-surface observations.
(Written by Copilot)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* agentHost: stabilize terminal clear E2E test
Wait for a marker that appears only in command output, not in the shell's echoed input, before clearing terminal state.
(Written by Copilot)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
---------
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>