Sandeep Somavarapu
90d · built 2026-07-24
90-day totals
- Commits
- 305
- Grow
- 54.7
- Maintenance
- 44.6
- Fixes
- 11.3
- Total ETV
- 110.7
Where this dev ranks
Percentile against the global top-100 leaderboard (all-time totals).
- By commits
- Top 16 %
- By Growth share
- Top 20 %
30-day trajectory
Last 30 days vs. the 30 days before. Up arrows on Growth and ETV mean improvement; up arrow on Fixes share means more time on fixes (worse).
↑+52.2 %
vs 90 prior
↑+7.2 pp
recent vs prior
↑+0.6 pp
recent vs prior
Daily performance
Daily ETV, stacked by Growth, Maintenance and Fixes.
Work-mix over time
Share of Growth / Maintenance / Fixes over a rolling 7-day window. Reads as 'where is effort flowing right now'.
Repository spread
Where this developer's commits land. Concentrated work (top1 > 80%) vs polymath spread (top1 < 30%).
Most impactful commits
Top 20 by ETV in the 90-day window.
- 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
- 2.5ETVsessions: support read-only chats and surface subagents as read-only tabs (#323960) Adds ChatInteractivity (Full/ReadOnly/Hidden) to IChat and hides the composer for non-interactive chats (gated via chatIsReadonly context key). Surfaces agent host subagent (tool-origin) chats as read-only peer tabs with a lock icon, persisted across restart. Adds an inline "Open Subagent" pill in the transcript and a "Subagents" dropdown above the chat input to reveal them. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>github.com-microsoft-vscode · 8f1b02ba · 2026-07-01
- 2.4ETVsessions: split session model from view service (#320139) * sessions: split session model from view service Separate the session model (ISessionsManagementService) from the view (ISessionsViewService) so the model owns canonical session state and the view owns visible-slot arrangement, focus and per-session view persistence. Introduces the new `browser/sessionsViewService.ts` core service and `browser/parts/sessionsParts.ts`, makes the part a passive renderer, and adds support for opening a session without focusing it (reactive preserve-focus intent published atomically with the active session). Also encapsulates the in-progress new-session draft in the model as a reactive `newSession` observable with a conditional `discardNewSession`, merges `openNewSessionView` into `openNewSession`, and routes new-session creation through the view so the draft is activated (fixing the session type picker rendering empty after reload). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * revert open from active session --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>github.com-microsoft-vscode · cbb90554 · 2026-06-05
- 2.1ETVfix #325750 (#326012) * fix #325750 * Fix sessions workbench layout regressions Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>github.com-microsoft-vscode · fd4e5a72 · 2026-07-15
- 2.0ETVsessions: expose session-management tools to Agent Host sessions (#325051) * Expose session management tools to Agent Host sessions Add list_sessions, get_current_session, create_session and create_chat server tools, a deterministic 'Session/Chat Created' pill, and an agent-host-session:// opener in the Agents window. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Add delete_session server tool Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Polish Open Session pill UI: unpin from thinking group, muted sentence-case label, tighter icon padding Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Hide Open Session pill outside the Agents window The agent-host-session:// opener and session services are only wired in the Agents window, so the pill button is dead in the editor-window chat. Gate the pill on the containing workbench root having the .agent-sessions-workbench class, falling back to the normal tool-call row elsewhere. Also route the spawn-depth _meta access through a validating reader (readSessionSpawnDepth) in sessionState.ts, and include the create_chat model param, depth-based recursion guard, and single-source server tool group refactor. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Encapsulate session spawn-depth _meta key in sessionState reader/writer Remove the redundant SESSION_SPAWN_DEPTH_META_KEY re-definition in agentService.ts; use the canonical SESSION_META_SPAWN_DEPTH_KEY via the readSessionSpawnDepth reader and a new withSessionSpawnDepth writer, matching the withSession* convention so the key stays in one place. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Inline single-use spawn-depth accessor helpers into the session tool accessor Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Show Open Session pill in editor-window chat with a working button Remove the Agents-window-only gate on the create_session/create_chat pill so it renders in the editor-window chat too. Add a workbench-side opener (AgentHostOpenSessionLinkOpenerContribution) that resolves agent-host-session:// links to the ambient/local client session resource and opens them via IChatWidgetService.openSession. Registered only from the workbench electron-browser chat contribution (not loaded by the Agents window), so it does not compete with the Agents-window opener. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Explain why sessionCreated suppresses generic tool result details Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Add status/workspace/withChanges filters to list_sessions Give list_sessions optional filter properties so an agent can narrow the result to sessions needing input or running (status), sessions in a given folder (workspace), or sessions with pending worktree changes (withChanges), instead of always returning every session. Validated and covered by unit tests. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Enrich list_sessions output with meaningful session metadata Surface the metadata fields list_sessions previously dropped: activity, project name, unread flag, last-modified timestamp, git state (branch, base/upstream branch, ahead/behind, uncommitted changes) and GitHub info (owner, repo, PR url), each only when present. Also fix describeSessionStatus to match the InputNeeded superset bits correctly so a plain InProgress no longer decodes as inputNeeded. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Expose more metadata-backed filters on list_sessions input Add unread, withPullRequest, and includeArchived filter properties (alongside the existing status/workspace/withChanges) so an agent can query for sessions with unseen updates, sessions linked to a GitHub PR, or exclude archived sessions. Backed by session metadata (isRead, GitHub PR url, isArchived/status). Covered by unit tests. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * list_sessions: hide archived by default and allow querying by creation time Flip includeArchived to default false so archived sessions (intentionally set aside) are omitted unless explicitly requested. Add createdAfter/createdBefore ISO-8601 range filters over a session's creation time, and surface createdAt in the serialized output. Covered by unit tests. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Refer to sessions (not Agent Host sessions) in session tool descriptions Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Collapse the created-session pill to a single 'Created session <pill>' line The pill previously composed a ChatToolProgressSubPart row ('Created session') plus a separate 'Session created' heading above the button, producing several redundant lines. Render a single compact line instead: agent icon + past-tense label ('Created session' / 'Created chat') + the open button. Drops the progress subpart and heading card entirely. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Simplify created-session pill to a single icon+title button Drop the redundant 'Created session' label from the pill (the model's summary line above already describes it) and move the agent codicon inside the button. Removes the now-unused heading field from IChatSessionCreatedData. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Use the conversation icon for create_chat pills Select the pill icon by tool: create_chat now shows the conversation icon (Codicon.commentDiscussion) while create_session keeps the agent icon. Threads an isChat flag through IChatSessionCreatedData. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Make the create_chat pill open the specific chat, not just the session create_chat now carries the new chat's id in the open link (as a ?chat= query), and the Agents-window opener resolves it to the peer chat (whose resource fragment is the chat id) and navigates via ISessionsService.openChat. Previously the link only pointed at the owning session, so clicking it opened the default chat rather than the newly created one. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Fix Windows test: compare URI.path not platform-specific fsPath The 'getCreateSessionArgs accepts an absolute filesystem path' test asserted workspace.fsPath === '/Users/me/work/repo', which fails on Windows where fsPath uses backslashes. Assert workspace.path (always forward-slash) instead. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Address PR review: parse open link once; await executeTool directly - buildSessionCreatedToolData: parse parseOpenSessionLinkUri once and reuse, dropping the redundant second call and the non-null assertion. - claudeServerToolMcpServer: await host.executeTool directly instead of storing the pending promise and awaiting it in the result literal. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>github.com-microsoft-vscode · 52573ace · 2026-07-09
- 1.6ETVagent host: persist and restore peer chats across restart (#321989) * agentHost: persist and restore peer chats across restart Peer (additional) chats in a Copilot CLI session were in-memory only and disappeared on restart. Persist each peer chat's backing SDK conversation id in the session DB, resume it on session restore, and re-register it (with history) in the state-manager chat catalog. - copilotAgent: persist {chatId -> {sdkSessionId, model}} under copilot.chats; add getChats, _ensureChatSession (resume from persisted id), and make disposeChat delete the persisted entry + SDK conversation. - IAgent: add optional getChats. - agentHostStateManager: add restoreChat to seed a peer chat's ChatState and add it to the catalog. - agentService: restoreSession now restores persisted peer chats with history. - Tests for getChats/disposeChat persistence and restore re-registration. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * agentHost: address CCR feedback on peer-chat persistence - Validate persisted peer-chat entries on read; drop ones without a usable string sdkSessionId instead of letting invalid ids reach deleteSession. - Build the serialized catalog with a null-prototype object to avoid prototype pollution from a client-chosen chatId (e.g. __proto__). - Clarify the disposeChat comment (it resolves the SDK id, it does not resume). - Add a regression test covering corrupted/invalid persisted entries. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * agentHost: fix restored peer chat stuck loading after reload Switching to a restored peer chat after a window reload left the chat on a perpetual loading spinner. Disposing the outgoing default chat session ran _releaseSessionSubscription(session), which tore down ALL chat subscriptions of the backend session — including the incoming peer chat's subscription that provideChatSessionContent was concurrently awaiting. _whenSubscriptionHydrated then waited forever on a disposed subscription, so the chat content promise never resolved. A chat session's dispose now releases only its own conversation subscription via _releaseChatSessionSubscriptions, never a sibling peer chat's. The shared session subscription (and its lockstep default-chat subscription) is kept alive while any sibling chat session is still active or mid-hydration (tracked by _hydratingChatSessions). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * agentHost: confirm before deleting a chat Deleting an individual chat in a Local/Remote Agent Host session (Copilot CLI) removed the chat immediately with no confirmation, unlike the Copilot Chat CLI session provider. Show the same confirmation dialog before disposing the chat, and bail out when the user cancels. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>github.com-microsoft-vscode · 4c2511ba · 2026-06-18
- 1.4ETVsessions: workspace picker emits folder URI, session type picker spans providers (#317525) * sessions: workspace picker emits folder URI, session type picker spans providers Refactor the new-session workspace picker so it selects only a folder URI instead of a (providerId, workspace) pair. The session management service resolves the provider from the URI at session-creation time. The session type picker now queries the management service for all session types every registered provider can serve for the folder, grouped by provider with a separator between groups. Highlights: - ISessionsManagementService gains: - getSessionTypesForFolder(folderUri): returns one entry per provider x sessionType supported for the URI. - resolveWorkspaceForFolder(folderUri): finds the first provider that can resolve the URI. - createNewSession(folderUri, options?): iterates providers and picks the first matching one when no providerId is supplied. - WorkspacePicker: - Emits URI | undefined; selectedFolderUri / setSelectedWorkspace(uri). - Drops the up-front quick-pick that asked the user to choose between multiple local providers when browsing. - Recents storage stores URI only (with backward-compat reads of old {uri, providerId} entries); recents resolution prefers the stored providerId hint so a re-picked folder stays with the same provider. - SessionTypePicker: - Reads getSessionTypesForFolder; groups items by provider with a separator between groups and the provider label as a header. - Emits IPickedSessionType = { providerId, sessionTypeId } so the same sessionType id (e.g. 'copilot-cli') from different providers is disambiguated. - Recomputes types at open time as a safety net for late-registering providers. - SessionsManagementService._updateSessionTypes now fires onDidChangeSessionTypes unconditionally; the previous dedup check skipped the event when a new provider contributed an overlapping sessionType id, leaving the per-folder list stale. - LocalAgentHostSessionsProvider drops the `[Local]` suffix from workspace labels so its sessions for a folder share the workspace group with other providers' sessions for the same folder. - NewChatViewPane is rewired to the URI flow and uses the picker's selectedResolved.providerId as the createNewSession fallback when the session type picker has no explicit pick yet, preserving the user's historical provider association for recently-picked folders. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> * sessions: address CCR feedback — providerId hint + legacy session type pref - selectWorkspace(folderUri, providerId?) plumbs an explicit providerId hint from "New Session" in a workspace section down through the workspace picker so the created session matches the section's provider. - setSelectedWorkspace accepts an options bag with { fireEvent?, providerId? }. - _readStoredPick now honors legacy storage shapes (raw string sessionTypeId and JSON without providerId) as a deferred preference; the provider is resolved lazily once the active folder is known. - New IPreferredSessionType type for stored / restored preferences where providerId may be missing; IPickedSessionType remains required-providerId for picker emissions. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * sessions: rename IFolderSessionType → IProviderSessionType and getSessionTypes → getSessionTypesForFolder - IFolderSessionType was misleading (implied 'a type for a folder'; it's really a provider × session-type pair) - ISessionsManagementService.getSessionTypes() collided in name with ISessionsProvider.getSessionTypes() but returned a different type - Rename to IProviderSessionType and getSessionTypesForFolder() for clarity Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>github.com-microsoft-vscode · 1e7597c9 · 2026-05-20
- 1.4ETVsessions: add background send and createAndSendNewChatRequest API (#319565) Adds a 'background' option to new-session sends so the new-session composer stays put while the started session commits and appears in the sessions list, and a new public ISessionsManagementService.createAndSendNewChatRequest API that creates a session and sends a chat request programmatically without navigating into it. Background sends are fire-and-forget at the management layer so the composer can reset and reseed immediately; the shared _sendNewChatRequestInBackground helper owns the full will/did send lifecycle. Providers are now multi-new-session aware (tracking new sessions in a DisposableMap and exposing deleteNewSession) so a graduating session and a freshly reseeded composer draft coexist; abandoned or failed drafts are disposed through their provider. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>github.com-microsoft-vscode · bfa877f8 · 2026-06-02
- 1.4ETVsessions: extract local chat sessions into standalone provider (#317979) Extract local chat sessions into standalone provider Move the local harness (in-process VS Code chat sessions) from CopilotChatSessionsProvider into its own LocalChatSessionsProvider under contrib/providers/localChatSessions/. The new provider uses IChatService directly instead of the agent sessions model: - startNewLocalSession() for creating chat models - sendRequest() for sending messages - IGitService for git state resolution Changes: - New LocalChatSessionsProvider implementing ISessionsProvider - New localChatSessions.contribution.ts with setting registration and ForkConversationAction override - Removed LocalNewSession class from copilotChatSessionsProvider - Removed LOCAL_SESSION_ENABLED_SETTING from copilot provider - Updated copilotChatSessionsActions to import LocalSessionType from new provider - Updated sessions.common.main.ts entry point Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>github.com-microsoft-vscode · db199eea · 2026-05-22
- 1.3ETVsessions: refactor ISession workspace model — ISessionFolder, ISessionGitRepository (#315990) * refactor: ISession file structure - ISessionRepository → ISessionGitRepository, folders, optional gitRepository Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> * Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>github.com-microsoft-vscode · 1e8d5efd · 2026-05-12
- 1.3ETVsessions: clean up ISessionsProvider chat API (#317875) * sessions: clean up ISessionsProvider chat API Simplify the provider contract and remove provider access to the chat widget service so widget opening is owned exclusively by the management service. Provider API - Remove `sendAndCreateChat` and `addChat` from `ISessionsProvider`. - Add `createNewChat(sessionId)` returning the committed `IChat` so the management service can open the widget on the real backend resource before sending. - `sendRequest(sessionId, chatResource, options)` now handles both the first-send (new session) and subsequent-send paths; providers dispatch internally based on `_currentNewSession`. - For multi-chat sessions, `createNewChat` on an existing session gates on `_isMultiChatEnabled()` and creates a fresh chat in the group. Session model - `ISession.mainChat` changes from `IChat` to `IObservable<IChat>` so providers can swap the chat when an untitled new session commits to a real backend resource (e.g. Claude). - `ICopilotChatSession` owns its own `ISettableObservable<IChat>` `mainChat` field; the provider no longer maintains a parallel map. Management service - `sendNewChatRequest` (renamed from `sendAndCreateChat`) calls `createNewChat`, opens the widget on the returned chat resource, then calls `sendRequest`. - `openNewChatInSession` is now async and opens the widget after `createNewChat` returns. Copilot provider - Drops the `IChatWidgetService` injection; the provider never opens widgets directly. - Drops `userSelectedTools` from the local send path (no widget available there). Spec - `SESSIONS.md`: document that `ISessionsProvider` must not have optional methods and that every addition to `ISession` or `ISessionsProvider` must be consumed by the agents-window core workbench (outside `contrib/providers/`). - `COPILOT_CHAT_SESSIONS_PROVIDER.md`: update the send-flow section to describe the new `createNewChat` + `sendRequest` two-step contract. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> * address review comments - sessionsManagementService.sendNewChatRequest: open the chat widget with ChatViewPaneTarget so it lands in the chat view (matches the other openSession call sites in this service). - copilotChatSessionsProvider.createNewChat & _createNewSubsequentChat: dispose the IDisposable returned by _createChatSession so the model reference acquired via acquireOrLoadSession is not leaked. - copilotChatSessionsProvider._sendExistingChat: capture the disposable from _updateChatSessionState and release it in a finally so the model reference does not leak on every send. - copilotChatSessionsProvider._sendFirstChat: when chatService.sendRequest returns kind 'rejected', clean up the temp session (cache, group cache, current-new-session, fire removed event, dispose) before throwing so the UI does not keep showing a stuck InProgress session. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>github.com-microsoft-vscode · de1cfec1 · 2026-05-21
- 1.3ETVsessions: split per-session layout controller by platform; refine maximize & changes behavior (#322789) sessions: split per-session layout controller by platform and refine maximize/changes behavior Split the monolithic `sessionLayoutController` into base / desktop / mobile controllers, each self-registering behind its own platform guard and imported from the appropriate entry point (desktop, web). Each controller has an adjacent spec (`*.md`) enumerating its behavioral rules as scenarios (B*/D*/M*), kept in sync with the implementation and tests. Behavioral changes: - New session submit keeps the auxiliary bar as the user left it; if it was open it switches to the Changes view so changes show as soon as the session is submitted. - The Changes toolbar action now reveals the Changes view in the auxiliary bar (3rd pane), so clicking it restores the side pane even if it was closed. - While the editor area is maximized the Changes view is always forced visible, irrespective of the session's saved state, and that forced state is never captured as a per-session preference. - `setEditorMaximized` snapshots the editor size and surrounding part visibility on maximize and restores the auxiliary bar visibility and editor size on un-maximize, so the editor returns to its previous size. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>github.com-microsoft-vscode · 8c3008e8 · 2026-06-24
- 1.3ETVAdopt AHP 0.7.0 workingDirectories + primaryWorkingDirectory in agent host (#326847) * Adopt AHP 0.6.0 workingDirectories property in agent host Sync the generated agent host protocol copy to spec version 0.6.0 (agent-host-protocol @ 11f1a65e), which renames the singular `workingDirectory` on session/chat state to a `workingDirectories` array in preparation for multiroot session support. This change is a pure, behaviour-preserving property adoption across all consumers: sessions continue to use a single working directory. Reads of a single directory now use `workingDirectories?.[0]`, field-copy sites pass the array through unchanged, and writes from a single URI produce a one-element array. No multiroot client support is added here (no capability advertising, state actions, multi-folder workspaces, or UI); those land in a follow-up milestone. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Address PR review feedback - Reject the not-yet-supported multiroot working-directory client actions (session|chat/workingDirectorySet|Removed) in the handwritten dispatch path so a client cannot mutate the synchronized working-directory set without the agent actually reconfiguring its directory access. The protocol declarations remain; only the operational dispatch is deferred until multiroot lands. - Compare workingDirectories by array identity (not just the primary entry) in the state manager summary-equality check, matching the immutable reducers and SessionSummaryNotifier so secondary-directory changes still dirty the summary. - Update ISessionWithDefaultChat / mergeSessionWithDefaultChat API docs to describe a chat's workingDirectories subset overriding or inheriting the session's full set, fixing links to the removed singular members. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Fix agentHost session-filter test for workingDirectories migration The `sessionAdded notification filters out sessions outside the workspace` test constructed session summaries with the removed singular `workingDirectory` field, so the production filter (which now reads `workingDirectories[0]`) saw no directory and dropped the in-workspace session. Update the two directly-built summaries to the `workingDirectories` array form. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Migrate test createSession wire calls to workingDirectories The createSession dispatch handler now reads the working directory from the renamed `CreateSessionParams.workingDirectories` array (AHP 0.6.0), but several node integration / e2e test call sites still sent the removed singular `workingDirectory` field. Since the field is silently ignored, sessions were created without a working directory and fell back to the default chats folder, failing the Agent Host E2E workspace/fileOperations/hostFeatures suites across all providers (wrong cwd cascades into file completions, renames, worktree resolution, and cd-prefix stripping). Send `workingDirectories: [dir]` from the shared `createProviderSession` helper and the remaining direct wire call sites so the requested directory reaches the session state again. The real VS Code client already sent the array form. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Adopt AHP 0.7.0 primaryWorkingDirectory + requiresPrimary Re-sync the generated protocol copy to the multiroot spec at 148c716b (spec version 0.7.0) and adopt the two follow-up changes: - Capability flag renamed `MultipleWorkingDirectoriesCapability.immutablePrimary` -> `requiresPrimary`, with the new "agent needs one directory designated as its primary root" semantics. No consumers referenced the old name. - New optional `primaryWorkingDirectory` field at both the session level (CreateSessionParams / SessionMetadata -> SessionState + SessionSummary) and the chat level (CreateChatParams / ChatState + ChatSummary). Mirror it through the state<->summary projection layer exactly like `workingDirectories`: createSessionState / createChatState / chatSummaryFromState / mergeSessionWithDefaultChat, plus the state manager's summary projection, field-equality check, SessionSummaryNotifier diff, and markSessionPersisted propagation. The generated SessionChatUpdated partial-summary merge is field-agnostic, so it carries the new field automatically. Purely additive optional fields; no client multiroot behavior is added (consumers still read `workingDirectories[0]` as the single effective root). Also preserve the VS Code-local `CompletionItem.label` field (added in #326807, ahead of the spec) which the verbatim re-sync would otherwise drop. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Reject unsupported working-directory actions via reconciliation path Address PR review feedback on the multiroot working-directory action gate: - Instead of silently dropping the four not-yet-supported session|chat/workingDirectorySet|Removed client actions (which never echoed the origin, leaving the client's optimistic write-ahead action pending until reconnect), emit a rejection envelope through the normal reconciliation path. Added AgentHostStateManager.rejectClientAction, which emits an ActionEnvelope carrying the original ActionOrigin and a rejectionReason without running the reducer (no synchronized state change), so the originating client rolls back its optimistic action. - Guard the write-ahead client reconcile (SessionStateSubscription / ChatStateSubscription) so a rejected envelope is never applied to confirmed state in any branch — this also prevents a broadcast rejection from leaking the rejected action into a non-origin client's state. - Add a table-driven test covering all four action types asserting no dispatch and exactly one rejection envelope preserving the original origin. - Simplify the create-session working-directory read to `URI.parse(params.workingDirectories[0])` now the branch proves index 0 exists. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Refine primaryWorkingDirectory to per-chat read-only (AHP ea279d99) Re-sync the protocol copy to spec ea279d99 (0.7.0) and adopt the refined primaryWorkingDirectory design: - Session has NO primary: `primaryWorkingDirectory` is removed from SessionState / SessionSummary. The session is just the equal-peer `workingDirectories` set. Dropped all session-level primary handling (createSessionState, the SessionSummaryNotifier diff, _toSummary, _summaryFieldsEqual, and markSessionPersisted propagation). - Primary is per-chat, read-only, fixed at chat creation: kept the ChatState <-> ChatSummary mirroring (createChatState / chatSummaryFromState) and carry the chat's own primary through the session+default-chat composite (ISessionWithDefaultChat gains its own primaryWorkingDirectory; the merge no longer falls back to a session primary). It is not sent via `session/chatUpdated` (the state manager only ever puts status/activity/title in those changes), so it never mutates post-creation. - Inputs `CreateSessionParams.primaryWorkingDirectory` (seeds the default chat's primary) and `CreateChatParams.primaryWorkingDirectory` are synced; capability `requiresPrimary` unchanged. Also re-preserve the VS Code-local `CompletionItem.label` field (#326807, ahead of the spec) that the verbatim re-sync drops. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>github.com-microsoft-vscode · 53ebd210 · 2026-07-22
- 1.3ETVsessions: move read/unread ownership to sessions providers (#325982) * sessions: move read/unread ownership to sessions providers Marking a session read/unread is now done by the sessions provider (surfaced via ISession.isRead) instead of the UI-layer SessionsListModelService. Existing locally-stored read state is migrated once into provider ownership. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * sessions: address read/unread migration review feedback Consolidate read state onto ISession.isRead as the single source of truth: drop the display-only isSessionRead override and instead persist the active session as read from the sessions service, so the list and header both read the provider-owned flag directly. Mark AgentHost sessions unread on cancelled and errored turns too, matching the Copilot and local-chat providers so a background session that errors or is cancelled while unwatched shows as unread. Also trims verbose migration comments across the touched files. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * sessions: address read/unread group and migration review feedback - Local and Copilot providers now mark read/unread across every chat in a group, not just the primary, so a session with an unread child can be cleared via Mark as Read. - Local sessions persisted before `isRead` existed now load as unread so the additive migration can promote genuinely-read legacy sessions. - Local first-chat model tracking is installed before awaiting turn completion, so a background completion/error marks the session unread even if the user navigates away mid-turn. - Update SESSIONS_LIST.md to describe the actual read/unread data flow. - Drop an unnecessary timeout in the agent-side-effects persistence test. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * sessions: provide isRead on the SessionHeader fixture mock session The session header now reads the provider-owned `session.isRead` observable directly, so the fixture's mock session must supply it — otherwise the component fixture throws while rendering. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>github.com-microsoft-vscode · e2d7a763 · 2026-07-15
- 1.3ETVsessions: avoid force-opening managed tabs when opening a file in single-pane layout (#325865) * sessions: do not force-open managed tabs when opening a file in single-pane layout Rework the single-pane managed docked tabs (Changes + Files placeholder) so they are only opened into an *empty* editor group on a view-open trigger, removing the fragile dismissal bookkeeping and aux-bar-visibility inference. - Add layout-service events `onDidRevealSidePane` (side pane goes fully hidden -> visible) and `onDidEndSessionLayoutRestore` (restore epoch settles) and drive the managed-tabs strategy off named triggers A-D. - Open default tabs only when the group is empty, so closing a managed tab sticks and closing a file no longer re-forces the tabs open / leaves the side pane un-closable. - Ensure Changes (opened active) on new-session submit; ensure all docked inputs on a details-only reveal. - Scope pending reconcile intents to their session so a superseded reconcile cannot leak its intent onto a switched-to session. - Gate responsive sessions-list auto-collapse on small windows (<= 1800px). - Only collapse editors on a details-only hide (aux still visible), not when the whole side pane closes. - Tests + docs (SINGLE_PANE_SCENARIOS.md, sessions SKILL.md) updated. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * sessions: address CCR review feedback on single-pane managed tabs - Guard the Files-tab tidy on onWillOpenEditor: resolve the event group via mainPart.getGroup and skip re-activations (already-open editors) and non-main-part groups, so selecting/closing-to-reveal an existing file no longer removes a user-added Files tab. - Open the submit Changes tab with preserveFocus so activating it for detail mapping never steals focus from the just-submitted chat. - Remove the now-dead internallyClosingEditors bookkeeping from the coordinator and both docked-tab strategies (no readers after dismissal tracking was removed). - Trim the SinglePaneManagedTabsStrategy class JSDoc to the ownership contract. - Tests: model production onWillOpenEditor ordering (fire before insert) and add a re-activation case; add onDidRevealSidePane transition assertions. - Docs: fix stale/nonexistent API references in the sessions SKILL.md pitfalls. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>github.com-microsoft-vscode · bc2ac764 · 2026-07-15