Sandeep Somavarapu
90d · built 2026-09-08
Performance
What Sandeep Somavarapu shipped in the selected window, measured in ETV, and how it compares with the 90 days before it.
Effective capacity
+7.4engineers
delivers like 8.4 (8.4x pre-AI)
Output (ETV)
161.4ETV
+156.6% vs 62.9 prior
Features share
36.0%
−10.7 pp vs prior window
Fixes share
11.6%
+1.6 pp vs prior window
Work mix
36% Features13.8% Maintenance34.4% Tests4.2% Docs11.6% Fixes
310 commits over 90 days, ending 2026-09-08.
Where this dev ranks
Percentile against the global top-100 leaderboard (all-time totals).
- By commits
- Top 13 %
- By Features share
- Top 29 %
Daily performance
Daily ETV, stacked by Features, Maintenance, Tests, Docs and Fixes.
Repository spread
Where this developer's commits land. Concentrated work (top1 > 80%) vs polymath spread (top1 < 30%).
Most impactful commits
Top 10 by ETV in the last 90 days.
- 17.5ETVagentHost: make the orchestrator own session enumeration and chat lifecycle (#329633) * 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 aabdead86d7): - 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>github.com-microsoft-vscode · 150119bd · 2026-08-12
- 5.6ETVConvert workspace-less sessions to workspace sessions (#334250) * agentHost: support setting workspace on existing sessions Allow an agent to attach a workspace-less session to a folder or managed worktree without replacing the session or losing conversation history. Propagate the new project, working directory, continuation, and activity state through Agent Host and Sessions UI. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Agent Host changes for sandy081/agents/workspace-less-to-workspace-conversion * Keep workspace conversion progress continuous Reserve a visible host-authored turn while workspace setup completes, then route that same turn through normal provider admission. Keep project updates catalog-only, durably quarantine disposed provider sessions, atomically persist Copilot workspace metadata, and wire conversion without lazy service lookup.\n\nCo-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Show workspace conversion outcome in transcript Use a stable visible continuation request and add synchronized Workspace Set or Workspace Setup Failed notifications to the same turn.\n\nCo-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Remove stale workspace conversion imports Clean up imports left behind while adapting the workspace conversion changes to the current Agent Host composition. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Adapt workspace conversion to chat queue diagnostics Pass operation names through the updated Copilot chat queue API for working-directory mutations and their sequencing tests. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Fix workspace conversion tests on Windows Create in-memory customization directories before writing fixtures and derive expected paths from URI.fsPath so assertions follow the host platform.\n\nCo-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Avoid concurrent in-memory folder creation Serialize creation of customization fixture directories because the in-memory filesystem's recursive mkdir path is not safe when sibling operations race.\n\nCo-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Fix remaining workspace conversion CI failures Use the real disk provider for native Windows customization paths, prevent late aborted-idle events from cancelling replacement turns, and give the full property initialization checker enough heap for the expanded Agent Host sources.\n\nCo-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>github.com-microsoft-vscode · a9864c02 · 2026-09-04
- 5.1ETVsessions: single-pane layout as a sibling controller with composed strategies (#324657) * sessions: fix base-controller single-pane leak via Template Method hooks (R1) Move the single-pane branches out of BaseLayoutController into SinglePaneDesktopSessionLayoutController via three protected hooks (_suppressEditorVisibilityDuringRestore, _shouldRevealEditorPartOnApply, _shouldRevealEditorPartForEmptyWorkingSet). The base controller no longer reads isSinglePaneLayoutEnabled. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * sessions: segregate docked-editor layout concerns into IDockedEditorLayout (R3) Extract handleDockedEditorPartLayout and isEditorRevealedExplicitly into a focused IDockedEditorLayout interface that IAgentWorkbenchLayoutService extends, keeping the cross-cutting isSinglePaneLayoutEnabled and suppressEditorPartAutoVisibility on the main contract. Fix stale typo comment. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * sessions: extract side-pane presentation Strategy from workbench (R2/R4) Replace the 26 scattered _dockDetailPanel branches in workbench.ts with an ISidePaneLayoutStrategy (GridSidePaneStrategy + DockedSidePaneStrategy), selected once at initLayout. DockedSidePaneStrategy owns the docked width, the DockedAuxiliaryBarController lifecycle, the reveal-sync, and a DockedEditorSizeMemento for the docked size bookkeeping (R4). Workbench implements ISidePaneLayoutHost and delegates geometry, grid-descriptor, visibility-mutator, and reveal-sync work to the strategy. Behaviour is unchanged in both layouts; the only remaining _dockDetailPanel reference is the strategy selection point. Rewrites workbench.test.ts to drive the real strategy through a host harness. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * sessions: replace side-pane Strategy with Workbench subclass (R5) Convert the composition-based ISidePaneLayoutStrategy into inheritance, matching the layout-controller Template Method pattern. The base Workbench now carries the classic (grid) layout as protected _-prefixed hooks; SinglePaneWorkbench overrides them for the docked detail-panel layout and owns the docked width, DockedAuxiliaryBarController, reveal-sync, and DockedEditorSizeMemento. A createSessionsWorkbench factory picks the subclass from the setting at construction; web.main.ts and sessions.main.ts use it. Removes sidePaneLayoutStrategy.ts and the ISidePaneLayoutHost callback interface. No behaviour change in either layout. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * sessions: single-pane editor part owns the auxiliary bar (R6) Make editor + auxiliary bar a single unit in the single-pane (new) layout by having the editor part create and own the auxiliary bar instead of the workbench/pane-composite service: - New SinglePaneMainEditorPart extends MainEditorPart; lazily creates the SinglePaneAuxiliaryBarPart via a getter and owns the DockedAuxiliaryBarController (created in create(), calling setContentRightInset directly). - EditorParts.createMainEditorPart() returns SinglePaneMainEditorPart when the shared shouldUseSinglePaneLayout(config) predicate is true. - AgenticPaneCompositePartService retrieves the same aux bar instance from the editor part in single-pane; classic/mobile create it as before. - SinglePaneWorkbench drops DockedAuxiliaryBarController ownership; keeps the docked width (exposed via getDockedAuxiliaryBarWidth/setDockedAuxiliaryBarWidth on IDockedEditorLayout) and reveal-sync, delegating layout to the editor part. - workbenchFactory, EditorParts, and the pane-composite service all select via the single shouldUseSinglePaneLayout predicate so the workbench, editor part, and aux bar are always chosen together (fixes a phone-viewport + setting-on mismatch that would pair SinglePaneWorkbench with a plain MainEditorPart). Classic (default) and mobile layouts are unchanged. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * sessions: make isSinglePaneLayoutEnabled class-based, not a config read Address review feedback: since the workbench subclass is selected at construction (Workbench vs SinglePaneWorkbench), isSinglePaneLayoutEnabled is now a class-level constant — false in the base, overridden to true in SinglePaneWorkbench — instead of reading DOCK_DETAIL_PANEL_SETTING at runtime. Removes the _configurationServiceForLayout field. This also aligns the flag with the phone-aware workbench selection, so it no longer reports single-pane on a phone viewport where the classic workbench is used. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * sessions: single-pane editor-group header menus, docked aux bar, and header styling - Make the full-width Changes header a group-level editor concept: the editor part configures header menu ids via IEditorGroupViewOptions.headerMenuIds and the editor opts in via IEditorPane.getHeaderActions(); EditorGroupView renders the menus (no concrete menu points leak into core). - Docked aux bar: top border connecting to the sash, and hide editor/aux when their sash collapses them. - Changes pill and file-diff open reveal the editor explicitly (revealEditorPartExplicitly), and close the Files tab when a real file opens. - Header styling: re-scope diff-stats/picker CSS via marker classes, restore inter-action spacing, and shrink the right toolbar buttons to 24px. - Fix setHeaderContent wiping freshly-rendered content on re-render; tie per-group header listeners to group removal. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * sessions: reparent single-pane layout to a sibling controller with composed strategies Make `SinglePaneLayoutController` a sibling of the classic desktop `LayoutController` (both extend `BaseLayoutController`) instead of extending it, so the desktop controller can be deprecated/deleted without affecting single-pane. Its behaviour is composed from focused strategy objects under `contrib/layout/browser/singlePane/`: - Detail (aux bar) ownership split in two — `SinglePaneDetailVisibilityStrategy` owns per-session shown/hidden memory (D1-D4); `SinglePaneDetailPanelStrategy` owns container selection (Changes/Files), maximize, browser-hide, and the nothing-to-show hide. Removed the overlapping `EmptyAuxCleanup` (D10) strategy and desktop's redundant saved-container machinery. - `SinglePaneManagedTabsStrategy` + `SinglePaneEditorAreaCollapseStrategy` share a `SinglePaneDockedTabsCoordinator`; plus `SinglePaneResponsiveSidebarStrategy` (Toggle Details), `SinglePaneNewSessionRulesStrategy` (R1), and `SinglePaneQuickChatEditorHideStrategy`. - Strategies coordinate through the controller via `ISinglePaneLayoutContext`. - Fresh per-session storage keys (`sessions.singlePane.*`) so single-pane never shares state with the classic controller. Fix a chain of new-session-submit / Detail-only bugs (all verified in-app): - New-session submit no longer reveals the docked editor or hides the just-opened detail. `onDidReplaceSession` fires before the controller's later-registered listener, so submit is detected intrinsically from the reactive transition (`!previousIsCreated && isCreated`); D3c leaves the detail as-is when a session has no saved state; the empty-editor-group hide is skipped during a layout restore. - Detail-only sessions no longer flicker the editor open on switch or reload: the editor-part grid view (which hosts the docked aux bar) no longer maps its visibility to `setEditorHidden`, the width-based reveal-sync bails while editor-part auto-visibility is suppressed, and the persisted editor width uses the node's real visibility so a reload restores the collapsed node width. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Fix component fixture screenshot CI Add the missing workbench layout service mock needed by the changes view fixtures and update blocks-ci screenshot hashes to the expected CI output. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * sessions: fix cramped Changes actions bar in the single-pane editor header The `ChangesActionsBar` marker (`.changes-actions-bar`) only carried a height rule in the single-pane editor-group header; the classic `.session-changes-editor-header-right` normalization does not reach that header, so the primary split-button and the trailing secondary icon actions rendered cramped together with no spacing or button chrome. Add the container flex/gap layout and the secondary icon-button chrome (padding, corner radius, secondary background/border + hover) keyed off `.changes-actions-bar`, using design tokens, so it applies in the single-pane editor-group header while staying idempotent for the classic internal changes-editor header (whose element also carries `.session-changes-editor-header-right` with the same values). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * sessions: match classic Changes actions bar chrome in single-pane editor header The single-pane editor-group header renders the Changes actions bar (`.changes-actions-bar`) inside `.editor-group-header-secondary`, where the high-specificity `editorgroupview.css` rules stretched the primary split-button but gave the trailing secondary icon actions (Mark as Done, Run Code Review) no inter-button gap and no button chrome, so they rendered flat and cramped against the dropdown chevron. Add, at matching specificity in `editorgroupview.css`, the container flex/gap and the secondary icon-button chrome (padding, corner radius, secondary background/border + hover) mirroring the classic `.chat-editing-session-actions` actions bar. Drop the equivalent low-specificity rules from `sessionChangesEditor.css`, which lost the cascade to the editor-group-header selectors. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * sessions: fix single-pane Changes actions bar and move its styles out of core In the single-pane editor-group header the Changes actions bar renders as a toolbar action item inside a `.monaco-action-bar`, where the generic rule `.monaco-action-bar .action-item .codicon { width: 16px; height: 16px }` clamped every codicon — including the button elements themselves (which carry the `codicon` class), squashing the secondary icon buttons and detaching the split-button chevron. - Un-clamp the codicons and lay out the bar (primary split-button grows, trailing secondary icons stay natural size) scoped to `.monaco-action-bar .action-item.changes-actions-bar`, so the classic internal changes-editor header and the aux-bar Changes view are left untouched. - Move all `.changes-actions-bar`-specific rules OUT of core `editorgroupview.css` into the contributing component's `sessionChangesEditor.css`; core keeps only the generic header/toolbar layout. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * sessions: draw the single-pane header divider under the editor header/tab bar Move the single-pane detail-panel separator from the auxiliary bar's top border to a bottom divider on the editor header (spanning the editor content and docked detail), so the line runs the full header width. When the active editor has no header toolbars (e.g. Files), the divider is drawn under the tab bar instead so a separator is always present below the header row. The docked auxiliary bar is absolutely positioned over the right of the editor part with a solid background, so it would overlay the divider. Rather than fight it with z-index, start the aux bar one divider-thickness below the header/tab bar (new `DockedAuxiliaryBarController.DIVIDER` offset applied to the aux top/height and the resize sash), so its background sits just beneath the line. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * sessions: update docked aux geometry tests for the header-divider offset The docked auxiliary bar now starts one divider-thickness below the header/tab bar (`DockedAuxiliaryBarController.DIVIDER`), so its top and height shift by 1px (top 34->35, height 566->565). Update the two workbench geometry snapshot tests to the new expected values. Fixes the CI unit-test failures on the PR. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>github.com-microsoft-vscode · e656eb8d · 2026-07-07
- 4.6ETVsessions: quick chats (workspace-less sessions) in the Agents window (#323972) * sessions: quick chats — workspace-less single-chat sessions Adds quick chats to the Agents window: lightweight chats not scoped to a workspace, backed by an agent-host session. The host infers workspace-less from an absent workingDirectory (forks excluded) and assigns a stable scratch dir; the workspaceless tag rides the generic _meta bag. Quick chats are single-chat, use the normal session presentation (Done hidden), render in an always-visible in-list "Chats" section, and persist across reloads. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * sessions: New from a quick chat opens another quick chat (Round 23) The primary "New" action gated quick-chat routing on `isCreated && isQuickChat`, but a quick-chat draft is Untitled (isCreated=false), so it fell through to the workspace composer seeded with a throwaway scratch dir (no session-type picker, "No models available"). Route on `isQuickChat` alone so a quick chat — draft or committed — opens another quick chat mirroring its harness. Extract the routing into a pure, side-effect-free `openNewChatOrQuickChat` helper so it is unit-testable (chat.contribution.ts is not test-importable). Supersedes Round 14(2) and updates Round 22(3); the Round 14(2) discard branch and Round 17 picker re-parent are kept as internal defense. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * sessions: quick-chat list & layout polish (Round 22 items 1-2) - Suppress the redundant per-row chat icon when a quick chat is rendered under the always-visible "Chats" section (the section header already carries a chat icon); keep it in Pinned/custom/date groups where the chat identity is useful. - Disable the "Toggle Side Panel" command for quick chats via precondition IsQuickChatSessionContext.negate(), since a quick chat has no side pane (the empty aux bar is hidden and the chat is full-width). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * agentHost: persist empty peer-chat catalog sentinel to avoid re-running legacy migration When a session has no legacy peer chats, write an empty catalog so _readPersistedPeerChatCatalog returns [] on subsequent restores and _migrateLegacyPeerChats never re-runs. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * sessions: Cmd+N always creates a new session; New Quick Chat gets Cmd+K Cmd+N (Round 24) Per user feedback, Cmd+N must always open a NEW SESSION — never a quick chat. Drop the context-aware quick-chat routing from NewChatInSessionsWindowAction (rename its title "New Chat" -> "New Session", keep the id) so it unconditionally calls openNewSession from the active session; the helper is renamed openNewChatOrQuickChat -> openNewSessionFromActive. Quick chats are created only via the Chats-section "+" (NewQuickChatAction), which now has a default Cmd+K Cmd+N chord. The peer-chat "+" (Cmd+T) is unaffected. Supersedes the Round 22(3)/23 mirror routing; the Round 14(2) discard branch and Round 17 picker re-parent are untouched. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * sessions: Cmd+N never inherits a quick chat's folder into the workspace composer (Round 25) New from a quick chat must always land on the clean New Session composer with a visible session-type picker. Gate openNewSessionFromActive's folder inheritance on isQuickChat so a quick chat never carries a (possibly leaked scratch) workspace URI into openNewSession. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * sessions: re-seed workspace draft when composer swaps out of quick-chat mode (Round 25b) Cmd+N from a quick chat reuses the new-session composer and only _activate(undefined), leaving it session-less. The session-type picker hides itself when it has no folder types (no active session), so no picker showed. Re-run the constructor's workspace-draft seed from an autorun when the composer transitions out of quick-chat mode with no active session, matching a freshly opened new-session composer (folder + visible picker). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * sessions: quick-chat untitled title falls back to "New Chat" via shared helper (Round 26) An untitled quick chat's titlebar showed "New Session" because the empty-title fallback was hardcoded and not quick-chat aware. Add getUntitledSessionTitle(isQuickChat) to the common layer and route all 5 fallback sites (titlebar, session header x2, list hover, sessions picker) through it. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * sessions: track isQuickChat in titlebar re-render autorun (Round 27) The SessionsTitleBarWidget re-render autorun read the active session's title and workspace but not isQuickChat, which _render() consumes for the untitled title fallback. Track it as a reactive dependency for forward-safety and consistency with other reactive render sites. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * agentHost: move workspace-less marker ownership to the AH service Each agent used to persist and re-emit its own workspace-less (quick chat) marker (copilot.workspaceless / claude.workspaceless) in the shared session database, and agents that persist nothing (Codex) lost the marker on restart. Make the AH service the single owner: AgentService persists a single agentHost.workspaceless key at create/materialize (from the value it already infers in _buildInitialSummary) and overlays _meta.workspaceless onto every agent's summary in listSessions. Agents no longer write or namespace the marker; Copilot reads the shared key for its resume system prompt, and the now-dead workspace-less plumbing is removed from the Claude session. This fixes restored quick chats for every agent (including Codex) with no per-agent code. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * sessions/agentHost: address review feedback (naming + inline) - Rename the workspace-less launch-plan flag from isQuickChat to workspaceless in CopilotSessionLaunchPlan and IAgentHostPromptContext (and the disposeSession local) so the flag matches the workspaceless marker it flows from throughout the AH layer. Feature-descriptive names (COPILOT_AGENT_HOST_QUICK_CHAT_INSTRUCTIONS, _quickChatScratchDir) are kept. - Inline openNewSessionFromActive back into NewChatInSessionsWindowAction.run and remove the single-caller seam module + its test. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * agentHost: make the AH service the sole owner of the workspaceless marker Following the earlier ownership move, the agents still read + re-emitted _meta.workspaceless in their metadata projections, which was redundant on the listSessions path (AgentService overlays it centrally) and only load-bearing on the single-session restore path. Centralize the restore overlay in AgentService.restoreSession (reads agentHost.workspaceless in its existing batch metadata read and merges it into the restored summary _meta), then drop the per-agent re-emit: remove it from the Claude metadata store entirely (Claude has no runtime need) and from the Copilot listSessions/getSessionMetadata projections. Copilot keeps reading the AH key for its resume system prompt and scratch-dir cleanup. Codex is now covered centrally with no Codex code. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * sessions: inline openQuickChatAndFocus into NewQuickChatAction Single-caller helper folded into the action's run(). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * sessions: make ISessionsProvider.createQuickChat mandatory Replace the optional createQuickChat with a mandatory method that throws when the provider does not support quick chats; callers now gate solely on the supportsQuickChats capability instead of probing for the method. Workspace-bound providers (Copilot chat, local chat) get an explicit throwing implementation. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * agentHost: use "workspace-less chat" terminology instead of "quick chat" Rename the agent-host-internal quick-chat identifiers, prompt tags, and prose to workspace-less: COPILOT_AGENT_HOST_QUICK_CHAT_INSTRUCTIONS -> COPILOT_AGENT_HOST_WORKSPACELESS_INSTRUCTIONS, the <quick_chat> system-message tag -> <workspaceless_chat>, and the scratch-dir helpers (_quickChatScratchDir/_ensure*/_cleanup*/_withQuickChatScratch). The workbench UI term "Quick Chat" is kept only where the agent host documents that mapping. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * sessions: address Copilot Code Review feedback on quick chats - sessionsList: select the row chat icon from isQuickChatSession(), not from workspace === undefined, so a workspace session with a transiently-undefined workspace no longer briefly shows the chat icon. - sessionContextKeys: correct the isQuickChat comment to reflect that the key is sourced from the isQuickChat tag, never inferred from workspace absence. - Agents window accessibility help: document the New Quick Chat command (Cmd/Ctrl+K Cmd/Ctrl+N) and the Chats section plus button, and note that the workspace picker does not apply and Toggle Side Panel is disabled for quick chats. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>github.com-microsoft-vscode · e63efae7 · 2026-07-02
- 4.0ETVsessions: refine the single-pane detail-panel layout (#324348) * sessions: single-pane detail-panel layout for the Agents window Add an experimental `sessions.layout.singlePaneDetailPanel` setting (default off) that docks the detail panel (auxiliary bar) inside the editor part, so a single editor tab bar spans the editor content and the docked panel. Introduces a custom Changes (multi-diff) editor, Files/Browser tabs, and a "+" add-tab menu, with the Changes view and diff-stats split into standard vs single-pane subclasses chosen at startup. The redesign uses a mode-based architecture: all single-pane parts, editors, serializers, actions and views are registered/gated behind the setting via `IAgentWorkbenchLayoutService.isSinglePaneLayoutEnabled` (the single source of truth), so the standard Agents-window layout is unchanged when the setting is off. Core editor support: `EditorPart.setContentRightInset` (concrete class, not the public `IEditorPart` interface) insets only right-edge groups so the tab bar stays full-width; a generic `MenuId.EditorTabsBarAddTab` renders a core-owned "+" dropdown at the end of the tab strip. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * sessions: address CCR feedback on single-pane layout - empty-file editor: register a touch Gesture target and handle Tap (iOS) in addition to click, and set `touch-action: manipulation` to avoid the tap delay. - docked detail panel border: use `var(--vscode-strokeThickness)` instead of a hardcoded 1px. - drop the internal `[Option A]` design-discussion marker from comments across workbench.ts / style.css / sessionConfig.ts. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * sessions: fix use-before-init in DetailPanelController The _activeEditorObs / _auxBarVisibleObs field initializers referenced the constructor-injected _editorService / _layoutService, which run before the parameter properties are assigned (TS2729, caught by tsc in CI but not by the tsgo typechecker). Move their initialization into the constructor body. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * test: update blocks-ci screenshot hashes Refresh the committed blocks-ci-screenshots.md to the current CI-rendered image hashes (CodeEditor / InlineChatZoneWidget fixtures). These are bare editor-widget fixtures not affected by this PR's editor-tab changes; the drift is from the screenshot service re-render. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * sessions: make SessionChangesService resolvable without the workbench layout service SessionChangesService is a DI singleton also instantiated in component fixtures / unit tests, which do not register IAgentWorkbenchLayoutService. Read the single-pane setting via IConfigurationService (available everywhere) instead, so resolving ISessionChangesService no longer fails with 'depends on layoutService which is NOT registered'. The layout service remains the single source of truth for contributions that run only in the real Agents window. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * test: re-sync blocks-ci screenshot hashes Update the committed hashes to the current CI render (the 6 CodeEditor / InlineChatZoneWidget fixtures shifted with the merged upstream editor changes). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * sessions: fix single-pane layout bugs from layout audit Grid/sizing: persist the logical editor width (excluding the docked panel) so the Sessions Part no longer shrinks by the panel width on every reload; clamp the stored docked width to its minimum and yield to the editor's minimum in narrow windows; keep the editor grid leaf visible when only the docked aux bar toggles. Editor content inset: recompute on group maximize/restore so a maximized non-right group is not rendered under the docked panel, and re-layout the docked panel after the un-maximize resize. Controllers: DetailPanelController shows Changes while the editor is maximized (agreeing with the D5 rule) and classifies editor types (file/empty-file -> Files, Changes -> Changes, Browser -> hidden, other -> preserve); the LayoutController no longer auto-reveals the Changes view on editor open in single-pane, so existing sessions keep the 'never auto-open' rule. Docs: fix stale method references in LAYOUT.md. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * sessions: single-pane detail panel refinements and controller merge Merge the single-pane detail/tab controllers into the layout controller, add a dedicated Toggle Details command, refine R1 (transition-triggered editor hide), default a created session to the Changes editor with the detail closed, reveal the docked editor part for created sessions, and remove the docked reveal-sync suppression mechanism. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>github.com-microsoft-vscode · 5cfa7158 · 2026-07-05
- 4.0ETVsessions: support Multi-Chat in the Claude agent-host harness (#323625) * Support multiple chats for Claude agent-host sessions Enable a single Claude (agent-host `provider === 'claude'`) session to own multiple peer chats in the Agents window, matching the Copilot CLI experience. - ClaudeAgent: add `_chatSessions` map plus `createChat` / `disposeChat` / `getChats`, per-chat persistence, lazy resume of restored peer chats, and per-chat routing on `sendMessage` / `abortSession` / `changeModel` / `changeAgent`. Fork a peer chat from a source chat's SDK conversation at a turn, falling back to a fresh chat when the fork anchor can't be resolved. - Agent-host sessions provider: advertise `supportsMultipleChats` for the `claude` logical session type in addition to `copilotcli`. - Update SESSIONS.md and ClaudeAgent tests. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * sessions: fix Claude peer-chat signal routing and harden multi-chat lifecycle Fix additional (peer) chats in Claude agent-host sessions getting stuck in progress: a peer chat passes its `ahp-chat` channel URI as the session's `sessionUri`, but `ClaudeAgentSession` derived its routing channel via `buildDefaultChatUri(sessionUri)`, double-encoding it so the renderer never matched the channel. Use the chat URI directly when `sessionUri` is already an `ahp-chat` channel. Also harden the peer-chat lifecycle per code review: - serialize all catalog read-modify-write on the parent session id (createChat / disposeChat / _updateChatCatalogModel) to avoid lost updates - hold the per-chat lock across both materialize and send so disposeChat / disposeSession serialize against an in-flight turn (no use-after-dispose) - make _disposeChildChats async + per-chat serialized to avoid zombie entries - abort provisional peer chats up front during shutdown - route setPendingMessages steering to peer chats - shape-guard the persisted catalog model Refs https://github.com/microsoft/vscode/issues/322776 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * sessions: thread chat channel through setPendingMessages for peer-chat steering Address CCR feedback: peer-chat steering was non-functional because `AgentSideEffects._syncPendingMessages` always dispatched the parent session URI to `agent.setPendingMessages`, so the Claude peer-chat routing branch was never reached and steering landed on the default chat. Add an optional `chat?` param to `IAgent.setPendingMessages` (mirroring sendMessage/abortSession/changeModel), dispatch the chat channel from `_syncPendingMessages` (undefined for the default chat), and route via it in ClaudeAgent. Copilot/Codex 3-param implementations remain valid and unchanged. Adds an AgentSideEffects dispatch test asserting the peer chat URI is forwarded as the `chat` arg (and is undefined for the default chat). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * sessions: unify Claude session/peer-chat plumbing into one entry container Address review feedback (connor4312): stop overloading session/chat URIs and the parallel-map split that special-cased peer-chat dispatch. - ClaudeAgentSession now takes an explicit `chatChannelUri`; its `sessionUri` is always the real session URI and is never a chat URI (`isAhpChatChannel(sessionUri)` can no longer be true). Per-chat resources (db, overlay, config scope, server-tool advertise) key off a derived `_storageUri` so peer chats stay isolated without overloading `sessionUri`. - Drop the parallel `_chatSessions` map: a single `_sessions` map of `ClaudeSessionEntry` containers now holds each session's default chat plus its peer chats. Dispatch resolves a chat via `_findChat(session, chat)` / the entry, and teardown disposes the whole entry (main + peers) via `_teardownEntry`. - Unify peer-chat message reconstruction with `getSessionMessages` via a shared `_reconstructTurns(sdkId, routingUri, primeOn)`; remove the duplicated `_getChatMessages`. No behavior change to storage keying (main -> session URI, peer -> chat URI). All ClaudeAgent / AgentSideEffects / CopilotAgent / AgentService node tests pass (425 claude tests). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * agentHost: add opaque providerData to chat catalog + multi-chat tests Wave A + gate G-B1 of the multi-chat unification: - AgentHostStateManager: add an opaque, agent-owned `providerData?: string` to peer-chat catalog entries (addChat/restoreChat) plus getChatProviderData. Stored verbatim and never parsed; the default chat carries none. This becomes the single source of truth for a peer chat's backing-conversation token, replacing the agents' private copilot.chats/claude.chats persistence. - Add characterization tests for the StateManager catalog (default chat, add/ remove/restore, summary roll-up) and peer-chat + restore round-trip tests for CopilotAgent and ClaudeAgent, guarding the upcoming de-dup waves. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * agentHost: orchestrator owns the peer-chat catalog (Wave B de-dup) Make AgentHostStateManager's catalog the single source of truth for peer chats, removing the agents' private copilot.chats/claude.chats persistence: - agentService: restore peer chats by enumerating the orchestrator's own catalog (using the opaque providerData blob) instead of agent.getChats; call materializeConversation(chatUri, providerData) before getSessionMessages so the agent re-attaches its conversation backing; persist providerData on createChat and re-persist on onDidChangeConversationData. - IAgent: createChat returns IAgentCreateChatResult { providerData? }; add materializeConversation + onDidChangeConversationData. - CopilotAgent / ClaudeAgent: stop writing their private *.chats catalogs; shrink _chatSessions to a live-only map; decode providerData to rebuild the chatUri -> sdkSessionId mapping; emit onDidChangeConversationData on per-chat model/fork change. A one-time legacy *.chats READ (triggered by an undefined providerData blob) migrates in-flight sessions. Typecheck, valid-layers-check, and the agentService/Copilot/Claude/StateManager suites (511 tests) all pass. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * agentHost: add scope/conversation IAgent surface + dispatch mapper (gate G-C1) Introduce the orchestrator-owned scope/conversation vocabulary on IAgent, additively alongside the legacy (session, chat?) surface (kept as a compat shim until waves C2-C5 migrate each agent): - IAgent: add createScope/disposeScope and an IAgentConversations surface (createConversation/disposeConversation/getMessages/fork, conversation- addressed sendMessage/abort/changeModel/changeAgent). - AgentService: map feature-level (session, chat) -> (agent, scope, conversation) and own default-chat resolution; resolveConversationUri helper. Typecheck, valid-layers-check, and the AgentService dispatcher suites (112 passing) all pass. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * agentHost: agents adopt scope/conversation surface (Wave C) CopilotAgent, ClaudeAgent and CodexAgent now implement the new scope/ conversation IAgent surface (createScope + conversations: createConversation/disposeConversation/getMessages/fork and conversation- addressed sendMessage/abort/changeModel/changeAgent), and agentSideEffects threads it through where straightforward. The legacy (session, chat?) compat shim is intentionally retained for now; it is removed centrally in gate G-C2. Typecheck, valid-layers-check, and the Copilot/Claude/Codex/AgentService suites (563 passing) all pass. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * agentHost: remove legacy (session, chat?) shim from IAgent (gate G-C2) With every agent migrated to the scope/conversation surface (Wave C), drop the agent-facing legacy methods — sendMessage(session,chat,...)/createChat/ disposeChat/getChats and the chat?-suffixed abort/changeModel/changeAgent — leaving only the conversation-addressed surface on IAgent. AgentService, agentSideEffects and the three agents migrate their remaining call sites; the mock agent is updated to the new surface. The orchestrator-facing IAgentService/IAgentConnection (session,chat) API and the wire protocol are unchanged — they remain the (session,chat) -> conversation mapping boundary. Net -209 lines. Typecheck, valid-layers-check, and the Copilot/Claude/Codex/ AgentService suites (559 passing) all pass. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * agentHost: add harness spawn-conversation channel + catalog routing (gate G-D1) Generalize the subagent_started/subagent_completed signals into a first-class membership channel: IAgent.onDidSpawnConversation({ scope, conversation, parent? }) / onDidEndConversation(conversation). AgentService subscribes on provider registration and routes spawned conversations straight into the chat catalog (addChat/removeChat), so harness-spawned chats (teams, fleet, subagents) and user-driven chats share ONE catalog path, preserving the parent relation. Per-agent emission of these events lands in Wave D. Typecheck, valid-layers-check, and the AgentService suite (107 passing) pass. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * agentHost: agents emit spawn events + capability-driven UI gating (Wave D) - CopilotAgent / ClaudeAgent emit onDidSpawnConversation/onDidEndConversation from their subagent/fan-out paths, so harness-spawned chats flow into the shared catalog via the G-D1 channel (carrying the parent relation). - IAgentDescriptor advertises IAgentCapabilities { supportsMultipleChats, supportsFork, supportsTeams }; the agent-host sessions provider maps these onto ISessionCapabilities instead of the hardcoded supportsMultipleChats(logicalSessionType) session-type check, and exposes supportsFork/supportsTeams context keys so UI gates generically with no per-harness branches. Typecheck, valid-layers-check, and the agentHost + sessions provider suites (1725 passing) all pass. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * agentHost: test default-chat rename is restored on restoreSession Re-add coverage for restoring a default chat's independently-persisted custom title (customChatTitle:<defaultChatUri>), homed in the dedicated restoreSession suite using the localService + TestSessionDatabase pattern. A version of this test arrived via a merge but was misplaced in the createChat suite; this puts it in the right place. The behavior itself lives in AgentService.restoreSession. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Remove unused supportsTeams capability The supportsTeams capability was fully plumbed (protocol to agents to ISessionCapabilities to SessionSupportsTeamsContext) but had zero consumers: no when-clause and no widget read it. Harness-spawned teams/subagents surface automatically via onDidSpawnConversation regardless of any flag, so this was speculative dead weight. Remove all 13 references across 9 files. supportsMultipleChats and supportsFork are left untouched as they are actually consumed. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * agentHost: unify subagent catalog membership onto the spawn channel (DR1) Make the spawn-conversation channel the single owner of subagent catalog membership, removing the duplicate add path: - AgentSideEffects._handleSubagentStarted no longer calls addChat; it keeps only the subagent lifecycle (ChatTurnStarted, _subagentChats tracking, parent tool-call Subagent content, buffered-signal drain, teardown). - AgentService now sequences a subagent_started/subagent_completed signal onto the spawn-channel handlers (_onConversationSpawned/_onConversationEnded) via a new onDidSessionProgress subscription registered BEFORE the side-effects progress listener. This deterministically guarantees the subagent chat exists in the catalog before its turn is started, independent of when the agent registers its own subagent->spawn bridge (addChat/removeChat are idempotent). - Extract the subagent-signal -> spawn-event mapping into shared helpers (subagentSpawnConversationEvent/subagentEndConversation) reused by the agents' bridges and the AgentService sequencer. Adds a "subagent membership sequencing" suite: exactly one catalog entry with parent origin/title/started turn regardless of order, buffered inner-signal drain, and completion teardown. Typecheck, valid-layers, and the agent suites (567 passing) all pass. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * agentHost: add multi-chat architecture spec Living architecture spec for the agent-host multi-chat design (scope/session vs conversation/chat, orchestrator-owned catalog, opaque providerData, unified spawn channel, capability gating) with mermaid diagrams. Kept in sync with the implementation, like SESSIONS.md. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * agentHost: legacy peer-chat migration (BC1) + Copilot session container (F2) Two changes to the Copilot/Claude agents and the orchestrator restore path: BC1 - backward-compatible restore of legacy peer chats: sessions whose additional chats were persisted only in the old agent-owned copilot.chats / claude.chats format (no orchestrator peerChats catalog) previously restored with those chats invisible. AgentService now performs a one-time migration when the orchestrator catalog is absent (undefined, not []): it enumerates the agent's legacy chats via a new migration-only IAgent.listLegacyChats, restores them through the normal catalog path, and writes the peerChats key so the drain runs once. Fixes the stale JSDoc that claimed a fallback removed in G-C2. F2 - collapse CopilotAgent's default-vs-peer _sessions/_chatSessions two-map split into a single _sessions map of a CopilotSessionEntry container (mirroring ClaudeSessionEntry): the entry holds the default chat plus a nested _peerChats map. Removes the special-casing Connor flagged on #323625. Typecheck, valid-layers-check, and the AgentService/Copilot/Claude suites (570 passing, incl. the migrate-once / empty-catalog / new-format restore cases) all pass. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * agentHost: rename agent scope/conversation surface to session/chat (N1) Collapse the agent-facing vocabulary back to session/chat, so the whole stack (protocol, orchestrator, UI, agents) speaks one language. The scope/conversation terms were a 1:1 veneer over concepts already named session/chat elsewhere (the create* methods even returned IAgentCreateSessionResult). The sessionUri vs chatChannelUri TYPE separation is preserved — this is a naming change only. - IAgent: createScope/disposeScope -> createSession/disposeSession; the conversations surface (IAgentConversations) -> chats (IAgentChats) with createChat/disposeChat/getMessages/fork + conversation-addressed send/abort/ changeModel/changeAgent now chat-addressed; materializeConversation -> materializeChat; onDidSpawn/End/ChangeConversation* -> onDidSpawn/End/ChangeChat*. - Types: IAgentSpawnConversationEvent -> IAgentSpawnChatEvent, IAgentConversationDataChange -> IAgentChatDataChange; drop IAgentCreateConversationOptions (reuse IAgentCreateChatOptions). - Helpers: resolveConversationUri -> resolveChatUri and the private _*Conversation* members across AgentService/agents renamed to _*Chat*. - IAgentService/IAgentConnection/protocol/UI names unchanged (already session/chat). - Reconcile agentSideEffects tests to the renamed chat surface (mock URI normalization) and update MULTI_CHAT_ARCHITECTURE.md terms/diagrams. Typecheck, valid-layers-check, and the agent suites (686 passing) all pass. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * docs: align architecture diagram label with chat terminology Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * docs: align multi-chat spec terminology with the session/chat rename Refine MULTI_CHAT_ARCHITECTURE.md wording after N1: the default chat's backing SDK *session* (not "SDK chat") is the session, peer chats are backed by their own sdkSessionId, and clarify the (session, chat) -> (agent, session URI, chat URI) mapping label and the per-chat state description. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * agentHost: group refactor-added helpers into logical units (NS1) Reduce loose top-level exports in common/agentService.ts introduced by the multi-chat refactor (the pre-existing config/env helpers are left untouched): - Move resolveChatUri to common/state/sessionState.ts next to its sibling chat-URI helpers (buildChatUri/buildDefaultChatUri/isDefaultChatUri/ parseChatUri) — its logical home. - Group the subagent signal -> spawn-channel mappers into an `export namespace SubagentChatSignal { toSpawnEvent, toEndChat }` (mirroring the existing AgentSession namespace), updating the Copilot/Claude bridges and AgentService._sequenceSpawnedChat call sites. Pure move/regroup, no behavior change. Typecheck, valid-layers-check, and the agent suites (686 passing) all pass. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Make ISession.capabilities observable so late-hydrating capabilities reconcile The agent-host adapter exposed `capabilities` as a live plain getter reading the connection's root state. When `rootState.agents[].capabilities` hydrated after a session's first `SessionState`, existing sessions were never reconciled: a multi-chat catalog processed while `supportsMultipleChats` was still `false` stayed collapsed to `[defaultChat]`, and the `supportsMultipleChats`/`sessionSupportsFork` context keys stayed stale because a plain getter cannot be tracked by the `setActiveSessionContextKeys` autorun. Change `ISession.capabilities` to `IObservable<ISessionCapabilities>`. The agent-host adapter derives it from `connection.rootState` (bridged via `observableFromEvent`) with `derivedOpts` + `structuralEquals`, and re-applies the last `SessionState` catalog in an autorun when capabilities change. Static providers wrap their capabilities in `constObservable`; consumers read `.read(reader)` (context keys) or `.get()` (one-shot). Adds a regression test and updates SESSIONS.md and the sessions skill. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Keep completed subagent chats live (fix subagent integration tests) A DR1 regression conflated 'subagent turn completed' with 'chat removed': a subagent_completed -> removeChat path tore the child subagent chat out of the catalog on completion, so subscribing to it after the parent turn completed failed with 'Resource not found'. A completed subagent chat must stay live and subscribable (merely hidden from listSessions), with its turn completed via AgentSideEffects.completeSubagentSession; subagent chats are removed only on session teardown via removeSubagentSessions. - agentService._sequenceSpawnedChat: handle spawn only (no removal on completion) - copilotAgent/claudeAgent spawn bridges: stop firing onDidEndChat on completion - remove now-unused SubagentChatSignal.toEndChat (keep toSpawnEvent) - keep onDidEndChat as a generic membership-removal hook - tests: assert the subagent chat survives subagent_completed and that completion does not fire onDidEndChat Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Add non-opaque backingSession to IAgentCreateChatResult Introduces a first-class, non-opaque backingSession URI on the peer-chat create result so the orchestrator can correlate and suppress a peer chat's backing SDK session. Kept distinct from the opaque providerData blob so the providerData opacity invariant is preserved. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Report peer-chat backingSession from Claude and Copilot agents ClaudeAgent._createChat mints a fresh top-level SDK session per peer chat in the same store its listSessions enumerates, so it now returns that session as backingSession for the orchestrator to suppress. CopilotAgent sets it too for uniformity (harmless — its peer sessions already don't leak). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Filter peer-chat backing sessions from the top-level session list createChat now stamps a persisted peerChatBacking marker into the backing session's database, and listSessions drops any enumerated session carrying it (batched into the existing metadata overlay, mirroring the subagent filter). Fixes Claude peer chats leaking as separate top-level sessions. Adds a unit test covering the filter and its persistence across a restart, plus doc invariant I7. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Share peer-chat scaffolding across Claude & Copilot agents Extract the near-verbatim multi-chat peer scaffolding shared by the Claude and Copilot agents into a new node-target module `src/vs/platform/agentHost/node/agentPeerChats.ts`: - Move the opaque `providerData` codec (`IPersistedChat`, `encodeProviderData`, `decodeProviderData`) into the shared module and export it. Use Claude's stricter `model` validation, which is a superset of Copilot's unconditional cast. Both agents import it and drop their private copies. - Add a generic `AgentSessionEntry<TSession extends IDisposable>` container holding the optional default session plus the peer-chat map. Rewrite `CopilotSessionEntry` as an empty subclass and `ClaudeSessionEntry` as a subclass that narrows `session` to non-optional. Behavior-identical refactor; existing Agent* suites stay green. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Persist migrated legacy peer chats in a single atomic catalog write `_migrateLegacyPeerChats` wrote the migrated peer chats to the orchestrator catalog one entry at a time in a loop. Each `_persistPeerChat` is a separate read-modify-write of `PEER_CHATS_METADATA_KEY`, so after the first write the key is present containing only the first entry. If the agent-host process crashed (OS kill, power loss, forced restart) after write 1 but before write N, the catalog was left partial; on the next restart `_readPersistedPeerChatCatalog` returns that subset (not undefined), the catalog-present branch short-circuits, and migration never re-runs -- chats 1..N-1 are lost forever. Write the whole migrated set in a single atomic `_enqueuePeerChatCatalogWrite`, so the key is absent before and complete after; no partial catalog can survive a crash mid-migration. Adds regression tests asserting the full set is persisted in one write and that a rejected write leaves the key absent (never a subset). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>github.com-microsoft-vscode · b10844ef · 2026-07-01
- 3.8ETVagent host: multi-chat session support for Copilot CLI (#321888) * Implement multi-chat session support for Copilot CLI in Local Agent Host Provider Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Address CCR feedback: session-rename telemetry, createChat race, observable read - Add dedicated onDidRenameSession event + agents/sessionRenamed telemetry so session-title renames are no longer misclassified as chat renames - Re-check chat existence inside the per-session sequencer in createChat to avoid a race overwriting/disposing an already-registered conversation - Cache mainChat.title read in chatCompositeBar autorun Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * agentHost: dispatch default-chat turn lifecycle on session URI After merging origin/main's default-chat compat layer, turn-lifecycle actions (turnStarted, truncated, turnCancelled) must target the session URI for the default chat (and the peer chat URI for peer chats), so the server routes them to the default chat and subagent session URIs derive correctly. Conversation side-channel actions and tool-call observation keep using the resolved chat URI. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>github.com-microsoft-vscode · ee44398a · 2026-06-18
- 3.3ETVsessions: single-pane detail-panel layout for the Agents window (#324257) * sessions: single-pane detail-panel layout for the Agents window Add an experimental `sessions.layout.singlePaneDetailPanel` setting (default off) that docks the detail panel (auxiliary bar) inside the editor part, so a single editor tab bar spans the editor content and the docked panel. Introduces a custom Changes (multi-diff) editor, Files/Browser tabs, and a "+" add-tab menu, with the Changes view and diff-stats split into standard vs single-pane subclasses chosen at startup. The redesign uses a mode-based architecture: all single-pane parts, editors, serializers, actions and views are registered/gated behind the setting via `IAgentWorkbenchLayoutService.isSinglePaneLayoutEnabled` (the single source of truth), so the standard Agents-window layout is unchanged when the setting is off. Core editor support: `EditorPart.setContentRightInset` (concrete class, not the public `IEditorPart` interface) insets only right-edge groups so the tab bar stays full-width; a generic `MenuId.EditorTabsBarAddTab` renders a core-owned "+" dropdown at the end of the tab strip. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * sessions: address CCR feedback on single-pane layout - empty-file editor: register a touch Gesture target and handle Tap (iOS) in addition to click, and set `touch-action: manipulation` to avoid the tap delay. - docked detail panel border: use `var(--vscode-strokeThickness)` instead of a hardcoded 1px. - drop the internal `[Option A]` design-discussion marker from comments across workbench.ts / style.css / sessionConfig.ts. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * sessions: fix use-before-init in DetailPanelController The _activeEditorObs / _auxBarVisibleObs field initializers referenced the constructor-injected _editorService / _layoutService, which run before the parameter properties are assigned (TS2729, caught by tsc in CI but not by the tsgo typechecker). Move their initialization into the constructor body. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * test: update blocks-ci screenshot hashes Refresh the committed blocks-ci-screenshots.md to the current CI-rendered image hashes (CodeEditor / InlineChatZoneWidget fixtures). These are bare editor-widget fixtures not affected by this PR's editor-tab changes; the drift is from the screenshot service re-render. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * sessions: make SessionChangesService resolvable without the workbench layout service SessionChangesService is a DI singleton also instantiated in component fixtures / unit tests, which do not register IAgentWorkbenchLayoutService. Read the single-pane setting via IConfigurationService (available everywhere) instead, so resolving ISessionChangesService no longer fails with 'depends on layoutService which is NOT registered'. The layout service remains the single source of truth for contributions that run only in the real Agents window. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * test: re-sync blocks-ci screenshot hashes Update the committed hashes to the current CI render (the 6 CodeEditor / InlineChatZoneWidget fixtures shifted with the merged upstream editor changes). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>github.com-microsoft-vscode · 7317e60f · 2026-07-04
- 3.1ETVsessions: Add grid layout for chats (#330848) * Grid layout for chats in a session Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Show tab strip when lone chat title diverges from session title Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Active chat shares the session background (no per-group dimming) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Persist and restore chat grid layout across reloads Persist each session's chat group partition (group assignments, grid structure + sizes, active group) to workspace storage keyed by sessionId. On reopen, deserialize the grid and route chats — including ones whose catalog loads asynchronously — back to their saved groups, collapsing empty groups only once restore settles. Driven entirely off observables. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Fix chat tab drag-to-split broken by chat-reference drag payload Dragging a chat tab to place chats side by side did nothing for agent-host sessions: the group-move payload and the chat-reference payload both used the global single-slot LocalSelectionTransfer, so fillChatReferenceDragData clobbered the DraggedChatIdentifier the grid drop target checks — its dragenter saw no chat drag and never showed the split zones. Carry the group-move payload {sessionId, resource} on the drag event's dataTransfer (SessionsDataTransfers.CHAT) instead, decoupled from the singleton which the chat-reference keeps to itself. The dataTransfer types are readable during dragover (to gate the overlay) and its value on drop. Verified end-to-end in a launched Agents window: dragging a chat tab now shows the split overlay and drops into a new chat group (1 -> 2 groups). Adds a regression test and documents the LocalSelectionTransfer single-slot pitfall. * Cap read-only banner to the centered band in single-group layout The read-only chat banner spanned the full leaf width instead of aligning with the tab strip. When the banner moved from SessionView's centered content container into the full-width ChatGroupView bar, the tab strip got a single-group centering rule but the banner did not, so on wide windows the banner ran edge-to-edge while the tabs stayed centered. Add the matching .single-group rule so the banner caps to the centered content band and centers (overriding only its horizontal margins, preserving the negative top offset). Multi-group keeps the banner full-leaf like the tab strip. Verified live: at a 1304-1578px leaf the banner now caps to 950px, centers (equal 177px margins), and pixel-aligns with the tab strip (same x, same width). * sessions: improve chat grid interactions Keep focused chat groups synchronized with session state, make side opening and restoration deterministic, and add accessible keyboard navigation and regression coverage.\n\nCo-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * sessions: route child chats to adjacent groups Apply parent-aware placement to every chat activation path, preserve focus when removing groups, and dispose removed group resources promptly.\n\nCo-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * sessions: preserve chat grid placement Keep manual child-chat assignments authoritative, retain the initiating group across asynchronous chat creation, and align logical group order with left and top splits.\n\nCo-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * sessions: restore new session composer Keep the standalone composer for the no-session state, avoid restoring persisted grids into drafts, and update side-chat and visibility test harnesses for the grid dependencies.\n\nCo-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>github.com-microsoft-vscode · ed96883e · 2026-08-14
- 2.9ETVagentHost: discover provider-native chats (#330665) * agentHost: discover provider-native chats Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * agentHost: initialize legacy chat discovery Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * agentHost: retry provider chat discovery Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * agentHost: stabilize config restore integration test Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * agentHost: require Claude discovery readiness Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * agentHost: update Codex discovery test harness Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>github.com-microsoft-vscode · 5f169d01 · 2026-08-13