Commit Graph

1384 Commits

Author SHA1 Message Date
Sandeep Somavarapu 94c155c4d9 sessions: single-pane layout controller cleanup (#324410)
* sessions: single-pane layout controller cleanup (no workbench.ts)

Base/single-pane layout controller changes assembled without the
workbench.ts side-pane Strategy extraction:
- R1: remove the base-controller single-pane leak via Template Method hooks
  and override them in SinglePaneDesktopSessionLayoutController.
- Additional single-pane controller / editor contribution refinements and
  spec updates (LAYOUT.md, SINGLE_PANE_SCENARIOS.md, sessions SKILL.md).

Excludes workbench.ts, sidePaneLayoutStrategy.ts and workbench.test.ts by design.

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

* sessions: capture editor-part hidden state eagerly to fix side-pane restore race

The per-session editor-part hidden state was captured lazily in
_saveWorkingSet by reading live editor visibility at switch-away time.
That races the switch derive (activeSessionForWorkingSet lags the raw
active session), so the incoming session's layout could flip the outgoing
session's recorded state to visible — reopening a side pane the user had
closed when switching back to it.

Capture it eagerly via a [B2] onDidChangePartVisibility(EDITOR_PART)
listener (mirroring the [B1] panel capture), guarded by single-session
and not-restoring, and drop the racy lazy read.

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

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-07-05 22:48:31 +00:00
Sandeep Somavarapu 5cfa71584e sessions: 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>
2026-07-05 03:11:38 +00:00
Sandeep Somavarapu 7317e60fe4 sessions: 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>
2026-07-04 09:31:19 +00:00
Henning Dieterichs f6a4e0843f updates rspack
* reduces memory usage
* loads fixtures from source instead of out
2026-07-03 17:48:37 +02:00
Giuseppe Cianci 6e0b2e9398 Guard node_modules cache against missing native optional-dep packages
Some deps ship their native binary in a per-platform package declared as an
*optional* dependency of a small base package (e.g. `@openai/codex` ->
`@openai/codex-<platform>-<arch>`, `@anthropic-ai/claude-agent-sdk` ->
`@anthropic-ai/claude-agent-sdk-<platform>-<arch>`). npm does not fail when an
optional dependency can't be installed, so a transient hiccup can leave the base
package present but the per-platform package missing — and that broken tree then
gets frozen into the shared node_modules cache and served to every consumer
(see #323881).

Add build/azure-pipelines/common/checkNativeOptionalDeps.ts and run it after
`npm ci` in the linux, macOS and windows cache-build jobs (before the cache is
saved). For each configured base package that is installed, it asserts the
matching `<base>-<platform>-<arch>` package exists, and fails the job otherwise
so a poisoned cache is never saved.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-07-03 11:13:03 +02:00
Benjamin Christopher Simmonds 4090e86ce8 sessions: show file icons in Session Files changes list (#324053)
The Session Files list in the Changes view did not render per-file-type icons because its list was placed outside the file-icon themeable scope. Add a file-icon themeable scope to the SessionFilesWidget root node and align its resource label rendering with ChangesTreeRenderer (strikethrough for deleted files). Also document the show-file-icons requirement in best-practices.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-07-02 13:45:59 +00:00
Benjamin Christopher Simmonds 6162ed61f7 sessions: tweak session files widget in changes view (#324034)
* sessions: tweak session files widget in changes view

- Use default ResourceLabels (no supportIcons) so file icons render
- Drop the resource path from the file description
- Only open a diff for modified files when the original has content
- Show A/M/D change decoration badges like the changes view
- Remove strikethrough for deleted files
- Add an Open File action to the row toolbar matching the changes view

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

* sessions: remove file count from session files header

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

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-07-02 11:41:32 +00:00
Sandeep Somavarapu e63efae792 sessions: 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>
2026-07-02 00:38:15 +00:00
Paul 90b81ef265 Fix issues with chat perf pipeline (#323917) 2026-07-01 22:10:25 +00:00
Josh Spicer 5a270e6dbd policy: resolve managed settings per-key across delivery channels (#323780)
* policy: resolve managed settings per-key across delivery channels

Managed settings previously used a single authoritative source: the first
non-empty delivery channel (native MDM > server > file) won wholesale and the
others were ignored entirely. Switch to per-key precedence: the same order is
honored, but resolved key-by-key. A key locked by a higher-precedence channel
still cannot be overwritten, while keys a higher channel leaves unset are now
filled in by a lower channel.

Centralize the resolution in a new pickManagedSettings() (replacing
selectManagedSettings) that returns the merged bag, per-key provenance, and the
active sources, so policy evaluation and the Policy Diagnostics report share one
implementation. Build the merged bag with Object.fromEntries so an untrusted
__proto__ key cannot corrupt its prototype chain.

Rework the Policy Diagnostics report to show every contributing source, a per-key
Resolution table (effective value, winning source, and struck-through overrides),
and per-key policy attribution.

Add unit coverage for the per-key merge (provenance, fill-down, falsy values,
ordering, prototype-pollution guard) plus an end-to-end test proving two keys can
win from two different channels and both reach policy evaluation.

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

* policy: iterate managed-settings bags with Object.keys over own props

Address PR feedback: switch pickManagedSettings from `for...in` to a guarded
`Object.keys` loop so only own enumerable properties are visited (managed-settings
bags are untrusted input) and absent channels are skipped explicitly.

Note: `for...in` over an undefined bag was already a no-op (never threw), so this is
a robustness/clarity improvement rather than a crash fix.

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

* policy: tidy pickManagedSettings unit suite

Drop two redundant cases (distinct-keys and standalone activeSources ordering,
both already covered by the headline and empty/absent tests) and fold the
non-contributing-middle-channel ordering check into the empty/absent snapshot.
Verified against the live node unit runner (all green).

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

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-07-01 13:55:15 -07:00
Sandeep Somavarapu b10844efce sessions: 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>
2026-07-01 16:53:16 +00:00
Kyle Cutler 84bf6e2e10 Add agent skill for integrated browser work (#323788)
* Add agent skill for integrated browser work

* update

* update

* update
2026-07-01 00:19:52 +00:00
Sandeep Somavarapu ece376a4db sessions: persist main chat rename across restore for agent host (#323785)
* sessions: persist main chat rename across restore for agent host

For agent host multichat sessions, renaming the default/main chat sets an
independent title persisted on the host as customChatTitle:<defaultChatUri>.
However restoreSession always re-seeded the default chat with an empty title
(inherit the session title), so after a process restart or idle eviction the
main chat tab reverted to the session title. Peer chats were already restored
via _restorePeerChats.

Read the persisted default-chat title on restore and seed it back through
restoreSession/_ensureDefaultChat, mirroring the peer-chat restore path.

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

* sessions: clarify _readPersistedChatTitle doc comment

Addresses CCR feedback: the helper now reads the default chat's title too,
not only peer chats.

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

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-06-30 22:18:39 +00:00
Josh Spicer 6d52b5c5da policy: let native MDM win over server for managed settings (#323615)
* policy: let native MDM win over server for managed settings

Flip the managed-settings precedence so native MDM takes priority over
the GitHub server endpoint. selectManagedSettings now resolves native
MDM first, then server, then the on-disk file, and the Policy Diagnostics
report lists the channels in that same precedence order.

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

* policy: update accountPolicyService tests, comment, and docs for MDM precedence

Flip the AccountPolicyService precedence unit tests so native MDM wins
over the server channel, fix the stale getPolicyData() comment, and
update the add-policy skill docs to describe native MDM > server > file.

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

* policy: reorder selectManagedSettings params to match precedence

Address PR review: make the parameter order (nativeMdm, server, file)
match the resolution precedence so same-typed call sites are
self-documenting and harder to transpose. Update both call sites, the
unit tests, and the skill docs.

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

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-06-29 23:14:01 +00:00
Sandeep Somavarapu b86f454a6f sessions: fix chat tab ordering in the Agents window (#323597)
Chat tabs reordered for two reasons. (1) The renderer partitioned chats
by status, pushing in-composer Untitled chats to the end, so committing a
draft out of creation order made its tab jump. (2) restoreSession seeded
peer chats in Promise.all resolution order rather than getChats() order,
scrambling the catalog on reload.

Render the provider's stable creation order as-is, and restore peer chats
in getChats() order while still loading their data in parallel. Update the
sessions skill pitfall to match.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-06-29 19:55:00 +00:00
Alexandru Dima 884913d065 build: avoid per-section Electron re-download in PR test runs (#323341)
The GitHub Actions PR test workflows run integration/smoke tests out of
sources, so each test section launches scripts/code.bat, which runs
build/lib/preLaunch.ts. Unlike the Azure Pipelines product builds, the
GitHub workflows did not set VSCODE_SKIP_PRELAUNCH, so preLaunch ran on
every section and getElectron() unconditionally deleted and re-downloaded
.build/electron each time. On Windows this races with file locks held by
the just-exited Electron process and intermittently fails the whole job
with the bare 'The system cannot find the path specified.' error.

- Set VSCODE_SKIP_PRELAUNCH=1 on the unit/integration/remote test steps of
  the win32, linux and darwin PR workflows, matching Azure Pipelines (the
  workflows already prepare node_modules, out, built-in extensions and
  Electron in dedicated steps before the tests run).
- Make getElectron() version-aware: skip the destructive re-download when
  the installed Electron already matches the expected version, falling back
  to a download on any detection failure.
- Make scripts/code.bat fail fast with a clear message when preLaunch.ts
  fails instead of falling through to launch a missing executable.
- Retry rimraf on EBUSY/EPERM (Windows file-lock codes), not just ENOTEMPTY.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-06-29 08:44:22 +00:00
Connor Peet b83c011c4c Merge pull request #323223 from microsoft/connor/agent-host-chat-channels
agentHost: route session state through chat channels
2026-06-27 08:55:43 -07:00
Zhichao Li 997c3786fa docs(add-policy): warn that policyData must be regenerated in a clean env
A plain 'npm run export-policy-data' loads dev-profile extensions, injecting
referencedSettings the fixture-based PolicyExport integration test won't
produce — failing CI in a way that is not reproducible locally. Document the
isolated regeneration command.
2026-06-26 22:18:59 -07:00
Connor Peet 45448a01ca Merge origin/main into agent host chat channels
Resolve upstream conflicts while preserving strict AHP chat-channel routing and the PR feedback fixes.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-06-26 17:35:30 -07:00
Connor Peet e4a80816a3 Agent host: route session state through chat channels
Move turn state and tool confirmations onto AHP chat channels so peer chats and subagents do not cross-talk. Persist draft/config metadata through side effects, harden malformed chat-channel handling, and keep subscription hydration from hanging on errors.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-06-26 16:33:01 -07:00
Connor Peet 9372f5dba6 Merge remote-tracking branch 'origin/main' into connor4312/ahp-flattened-session-today
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-06-26 14:03:40 -07:00
Connor Peet 4b8cddfa50 Agent host: persist chat drafts
Store chat drafts in the per-session database and restore draft text, attachments, model, and agent selection into the chat input. Rebuild restored Copilot turns with best-effort model and attachment metadata while avoiding unresolved subagent names as agent URIs.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-06-26 13:57:17 -07:00
Benjamin Christopher Simmonds ebe1112161 best-practices: discourage getComputedStyle (#323091)
* best-practices: discourage getComputedStyle

Add guidance to avoid getComputedStyle and prefer hardcoding style values in TypeScript or setting a CSS variable via setProperty when shared across CSS rules.

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

* best-practices: clarify setProperty guidance

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

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-06-26 10:25:39 +00:00
Alexandru Dima ba2a3ee737 ci: pre-initialize fontconfig to fix Pango threaded-FcInit crash in smoke tests (#323015)
Symbolizing the intermittent Electron-startup SIGSEGV crash dumps (Ubuntu debug
symbols + frame-pointer walk) shows the fault is an upstream Pango concurrency
bug, not a VS Code bug:

    pango:      fc_thread_func -> init_in_thread -> FcInit()   (pangofc-fontmap.c)
    fontconfig: FcInit -> FcConfigParseAndLoadFromMemory -> _FcConfigParse
    libexpat:   XML_ParseBuffer -> libc  (NULL deref, SIGSEGV)

Pango >= 1.52's pango_fc_font_map_init() unconditionally spawns a
"[pango] fontconfig" thread that runs FcInit(); that races with the
Electron/Chromium main thread's own fontconfig use during startup and corrupts
fontconfig's global config while it is being parsed. The threaded design is a
known-bad area upstream (pango#784 "single fontconfig thread introduces a hang
... seems to be due to a race condition", pango#872), and there is no env var to
disable it (still present in Pango 1.56).

It only manifests in our CI because the race window is microscopic: it needs a
cold process, two threads hitting first-time FcInit() simultaneously, and a slow
machine. Our smoke job is a near-perfect trigger — fresh contended runners, a
wiped fontconfig cache + custom FONTCONFIG_FILE (so FcInit re-parses cold), and
~25 cold Electron starts per run. (This also explains why the expat version was
irrelevant and why dropping the config DOCTYPE made it worse: it is pure timing,
not parser/content.)

Fix: initialize fontconfig once, single-threaded, from an ELF constructor that
runs before main() (and thus before any thread exists), via a tiny LD_PRELOAD
shim. Pango's later threaded FcInit() then finds fontconfig already initialized
and returns immediately, so the concurrent parse never happens and the race is
eliminated.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-06-25 22:53:43 +00:00
Alexandru Dima 84e743a053 Revert "ci: drop external DTD from minimal fontconfig to avoid expat NULL-deref crash" (#323009)
Revert "ci: drop external DTD from minimal fontconfig to avoid expat NULL-der…"

This reverts commit 70c0a5de8e.
2026-06-25 21:33:19 +00:00
Raymond Zhao c740f81b31 feat: add MSRC trailer check (#322988) 2026-06-25 11:47:11 -07:00
Ladislau Szomoru 1c80314e3b Engineering - update code owners (#322944) 2026-06-25 15:39:36 +02:00
Alexandru Dima 70c0a5de8e ci: drop external DTD from minimal fontconfig to avoid expat NULL-deref crash (#322909)
The Linux smoke-test job works around the expat 2.6.1 fontconfig NULL-deref
CVEs by pointing FONTCONFIG_FILE at a minimal config with <include> removed.
However that config still declared an external DTD:

    <!DOCTYPE fontconfig SYSTEM "urn:fontconfig:fonts.dtd">

fontconfig feeds that DTD to expat as an external *parameter* entity, which
still hits the not-yet-backported CVE-2026-32776 / CVE-2026-32778 crash paths
on expat 2.6.1 even with <include> gone. This was observed in CI as a SIGSEGV
inside libexpat (called from libfontconfig) during Chromium browser-process
font initialization, which crashed Electron at startup. Because the smoke-test
launch used no timeout, that crash surfaced only as an opaque 120s Mocha
"before all" hook timeout.

fontconfig does not require the DOCTYPE, so drop it to remove the last
external-entity codepath. The full workaround can be removed once the runner
ships libexpat >= 2.7.5 (the step already auto-disables itself in that case).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-06-25 15:06:31 +02:00
Josh Spicer 865f5a0bc1 Load managed-settings.json from well-known disk path (#321870)
Add a file-based managed-settings delivery channel that reads
managed-settings.json from a well-known per-OS disk path in the main
process and exposes it to renderer windows over IPC. Mirrors the
existing Copilot managed-settings (server / native MDM) channels.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-06-24 16:09:39 -07:00
Ben Villalobos fa88bce44d Document OSS NOTICE cutover (#322827) 2026-06-24 21:56:44 +00:00
Sandeep Somavarapu adc7ecf823 sessions: responsive auto-collapse of the sessions sidebar (D7) (#322819)
On a narrow Agents window, auto-hide the sessions sidebar while both the
editor and the side panel (auxiliary bar) are open, and show it again once
either closes or the window grows wide. A manual close suppresses auto-show
until the user opens it again; suspended while the editor is maximized or
multiple sessions are visible. Gated by the experimental setting
`sessions.layout.autoCollapseSessionsSidebar` (default on in non-stable builds).

Session navigation never auto-hides the sidebar: a base-controller restore
epoch (`_withSessionLayoutRestore` / `_isRestoringSessionLayout`) wraps both
the aux-bar restore and the editor working-set apply (`_applyWorkingSet`, which
reveals the editor part after an await). The D7 autorun re-baselines instead of
reacting while a restore is in flight. The epoch is a depth counter so the
guard stays up across overlapping/independently-settling restores, and it
decrements synchronously for void work so it never leaks for no-op restores.

Layout-controller registration moves to a new
`sessions.layout.contribution.ts` that picks the desktop or mobile controller
per platform and registers the experimental setting.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-06-24 14:09:52 -07:00
Ben Villalobos eacf067153 Cut over ThirdPartyNotices to the Component Governance generated notice (#322780)
* Cutover ThirdPartyNotices to CG-generated NOTICE

Add downloadNotice.ts: pulls the CG-generated NOTICE from the parallel Quality stage notice_output artifact and overwrites repo-root ThirdPartyNotices.txt before gulp packages it, on the desktop-client platform stages (win32, linux, darwin). Clones the copilot VSIX background-download harness (deemon detach/attach) so added wall-clock is near-zero when the artifact is ready in time. Non-fatal with legacy fallback; gated on VSCODE_OVERWRITE_TPN. Alpine/Web (server/REH only) are out of scope.

* Fix notice_output race: wait for Quality job completion before accepting artifact

The notice_output artifact is populated in two phases (generated.txt+meta, then the shipping ThirdPartyNotices.new.txt seconds later). Build 450466 showed the downloader grabbing the artifact after phase 1 but before .new.txt landed, falling back to legacy. Gate acceptance on the Quality job being completed so both upload phases are done. Bump poll budget to 7.5min.

* Bump notice poll budget to 20 attempts (10 min)

Observed acceptance at ~attempt 10 (~4.5min) in builds 450470/450477; 20 attempts gives ~2x margin while staying well under copilot's 30min. Clarify in comments that this outer poll is distinct from retry.ts's inner per-API-call retry.

* Accept CG NOTICE as soon as .new.txt lands in artifact

Change the E-lite acceptance gate from a Quality-job-completed proxy to a
direct check that ThirdPartyNotices.new.txt is present inside the notice_output
container artifact. Container file uploads are atomic per file, so the file
appears in the listing only after its upload finishes -- a race-free, earlier
readiness signal. Observed ~80s wasted in build 450470 waiting for the whole
Quality job after .new.txt was already available.

Backstops kept: (a) if Quality completes and .new.txt is still absent, give up
and fall back to legacy (do not burn the full poll budget); (b) post-download
>1KB size guard on .new.txt. POLL_ATTEMPTS stays 20 (10 min budget).

* Fix cache artifact mismatch: use DownloadBuildArtifacts + guard upload

The cache download steps used DownloadPipelineArtifact@2 but the upload
uses ##vso[artifact.upload] (which creates build artifacts, not pipeline
artifacts). These are different storage systems in ADO -- the download
was looking in the wrong store, which is why cache misses on both branch
and main.

Changes:
- Switch cache downloads to DownloadBuildArtifacts@1 (matches the upload)
- Update file paths to include notice_output/ subfolder (task behavior)
- Guard upload with condition eq(CG_NOTICE_OK, 'true') -- never upload
  a cached copy, only fresh CG output
- Remove NOTICE_FROM_CACHE branching in upload (redundant with guard)
- Always write notice-meta.txt sidecar when uploading (step only runs
  on fresh generation now)

* Validate extracted NOTICE content before accepting, re-poll on mid-upload miss

The accept-gate decided based on the container LISTING showing ThirdPartyNotices.new.txt, but a listing entry can appear before the file's content has finished committing. The consumer then downloaded+extracted and, when .new.txt was not yet in the extract, terminally fell back to the legacy notice. On a fast-compiling platform (e.g. linux armhf) this raced and shipped MIXED notices across architectures in a single build.

Move download+extract+validation into the poll loop: accept only when .new.txt is present AND non-empty (>1KB) in the extracted output. A listing-hit that does not yet yield a valid extracted file is treated as still-uploading and re-polls (consuming an attempt) rather than falling back. Fallback now only triggers on genuine budget exhaustion, or when .new.txt never appears in the listing and the Quality job has completed. Size guard, non-fatal exit 0, and the fresh/fallback/disabled RESULT markers are unchanged.

* Add "Use legacy OSS Tool" pipeline parameter to bypass CG notice

Surfaces a queue-time checkbox (default off) that, when checked, keeps the
legacy mixin ThirdPartyNotices.txt instead of overwriting it with the
Component Governance notice. Mirrors the VSCODE_STEP_ON_IT plumbing andderives VSCODE_OVERWRITE_TPN as an explicit lowercase string literal so
downloadNotice.ts's case-sensitive check matches. The derived variable is
threaded into the detached Pull CG NOTICE step env on win32/linux/darwin.

* Use 'definition' input alias for DownloadBuildArtifacts@1 NOTICE cache download

* Guard notice unzip against zip-slip and handle write-stream errors

Validate each extracted entry path stays within the output directory before
writing, and reject on write-stream errors so extraction failures surface
instead of hanging the poll.

* Rename legacy notice param displayName to 'Use legacy OSS Notice'

* Harden CG NOTICE feature flag plumbing

Make the VSCODE_OVERWRITE_TPN check case-insensitive and empty-safe so
YAML casing can't silently disable the rollback lever, and pass the flag
to the Apply (--attach) steps as well as Pull (--detach) so the legacy
notice is honored even if the script ever runs from the attach step.
2026-06-24 13:34:38 -07:00
Sandeep Somavarapu 6a8aa19cac sessions: fork into a new chat for multi-chat agent host sessions (#322799)
* sessions: fork into a new chat for multi-chat agent host sessions

Forking a conversation in an agent host session that supports multiple
chats now creates a new peer chat in the same session instead of a brand
new session. Single-chat and non-agent-host sessions keep the existing
fork-into-a-new-session behavior.

- Add a `fork` option to chat creation and plumb it through the AHP
  protocol, state manager, agent service and the Copilot agent SDK fork.
- Add required `forkChat`/`forkChatInSession` operations (return the new
  chat or throw; never return undefined). Capability gating happens in
  the caller before invoking the service.
- Fork before the selected request (turnId is the last turn to keep),
  matching the new-session fork boundary.
- Drop the fork when the requested turn is unknown so the provider does
  not inherit the whole backend conversation while the UI is seeded with
  no turns.
- Generate a content-derived title for forked chats/sessions via the
  utility model, with a short framing note that the conversation was
  branched from the source chat.

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

* sessions: use isEqual for chat/session URI comparison

Address CCR feedback: compare URIs with the standard `isEqual` helper
instead of `toString()` so equality is robust to normalization.

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

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-06-24 20:12:44 +00:00
BeniBenj 479a4986c9 CONTEXT KEYS CLEANUP 2026-06-24 19:51:11 +02:00
John Murray 3e7b249a06 💄 correct command capitalization in /causedByExtension response (#298925)
Co-authored-by: Dmitriy Vasyura <dmitriv@microsoft.com>
2026-06-24 16:47:01 +00:00
Sandeep Somavarapu ea3a084767 sessions: support background send for a new chat in an existing session (#322642)
* sessions: support background send for a new chat in an existing session

Add background-send (Alt+Enter) support for a new chat created inside an
existing multi-chat session, mirroring the new-session composer behavior.

- Plumb a `background` flag and `forceNew` option through the new-chat
  composer, sessions service, and management service so a background send
  resets the composer before dispatching (avoiding a shared chat-session
  state race) and runs fire-and-forget without navigating the visible slot.
- Keep tab order in the renderer: move in-composer `Untitled` chats to the
  end so a just-completed background chat never jumps last.
- Agent host: present a freshly created peer chat as `Untitled` until its
  first request is sent (the host commits it eagerly as `Completed`), so the
  sessions view shows the composer that owns the Alt+Enter handler. Add a
  committed-chat branch to `sendRequest` and revert the chat to its real
  status once sent.

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

* sessions: update remote provider not-found assertion

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

* sessions: partition chat tabs instead of sort for stable status tracking

Address CCR feedback: read each chat status exactly once inside the autorun
so dependency tracking is complete, and preserve provider order by partition.

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

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-06-24 00:10:21 +00:00
Sandeep Somavarapu 27725b9a63 sessions: resolve ${workspaceFolder} in agent-host tasks (#322629)
* sessions: resolve ${workspaceFolder} in agent-host tasks via IConfigurationResolverService

Agent-host worktree sessions build their task command line through
AgentHostSessionTaskRunner/resolveTaskCommand, which bypassed variable
resolution and sent ${workspaceFolder} to the terminal verbatim (causing
EROFS errors writing to a literal "${workspaceFolder}" path).

Expand variables using the workbench IConfigurationResolverService (already
registered in the Agents window), passing the session's worktree folder so
${workspaceFolder} resolves to the worktree rather than the Agents window's
own workspace. The resolver API is async, so the resolveTaskCommand pipeline
is now async; the hook is attached only when a cwd is known so variables are
left untouched otherwise.

Also adds the Agents-window worktree dev tasks (Install & Watch Client,
Run Client, Install & Watch) to .vscode/tasks.json, and tightens the
over-commenting guidance in the coding guidelines and sessions skill.

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

* sessions: address CCR feedback on agent-host variable resolution

- Resolve ${workspaceFolder} for remote hosts using the POSIX URI path
  instead of IConfigurationResolverService.resolveAsync (whose fsPath uses
  renderer-OS separators, wrong for a differently-OS'd remote host).
- Wrap the local resolveAsync call in try/catch so an unresolvable variable
  (e.g. ${command:}/${input:}) leaves the string unchanged rather than
  failing task dispatch.
- Fix the _getCwd comment to reference the real scheme (vscode-agent-host).
- Add a remote-host test asserting POSIX-path expansion and that the
  renderer resolver is not consulted.

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

* sessions: make agent-host task runner test platform-independent

The expansion test asserted against the resolver substituting URI.fsPath,
which on Windows yields backslash separators. Backslash is in
POSIX_NEEDS_QUOTING, so the expanded arg was strong-quoted on Windows and
the unquoted assertion failed. Substitute the POSIX URI path instead so the
test is deterministic across platforms.

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

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-06-23 16:11:39 -07:00
Josh Spicer a4ce08f735 Refactor Copilot managed-settings for maintainability (#322439)
* Refactor Copilot managed-settings for maintainability

Centralize structured (object/array) managed-setting handling behind a
single descriptor table so adding a key touches one place, consolidate the
duplicated equality helpers onto `equals`, and add shared
`hasManagedSettingsDefinitions` and `managedSettingValue` helpers. Strictly
behavior-preserving.

Incorporates a 3-model maintainability review:

- `adaptManagedSettings` builds the scalar remainder via `{ ...response }`
  plus delete (CopyDataProperties) instead of for..in + assignment, so a
  server-sent own `__proto__` key cannot trigger the inherited setter. This
  matches the original `...rest` semantics; adds a regression test.
- `managedSettingValue` is memoized per key so its policy-definition
  reference identity is real rather than incidental to the call site.
- Corrected JSDoc and skill docs that overstated `responseField` as
  compiler-checked; it is a hand-maintained union backstopped by tests.

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

* Clarify why structured managed-settings keys must declare type: 'string'

The bag-carrying `type` is load-bearing, not cosmetic: `projectManagedSettings`
gates each value with `typeof value === type` and drops mismatches, and the
native MDM watcher reads the registry/plist value as that type. Spell out that
omitting it (or declaring the object/array type) makes a structured key fail
projection and silently never apply.

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

* Address PR review: allocation-free empty check, __proto__ test, doc accuracy

- hasManagedSettingsDefinitions: reuse the allocation-free isEmptyObject
  helper instead of Object.keys(...).length (the bot's only valid nit).
- Add a primitive `__proto__` regression test proving a server-sent
  `{"__proto__": true}` scalar is dropped, never pollutes the result
  (disproves the reviewer's prototype-pollution concern).
- Fix github-managed-settings.md: omitting `type` or declaring
  `'object'`/`'array'` is a compile error (the field is required and
  constrained to `'string' | 'number' | 'boolean'`), not a runtime drop;
  only `'number'`/`'boolean'` compile-but-drop-at-runtime.

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

* Surface managed-settings source in Policy Diagnostics

Centralize the server-over-MDM precedence into a shared selectManagedSettings
helper (plus a ManagedSettingsSource union) and reuse it in both
AccountPolicyService and the Policy Diagnostics report, so the report can never
drift from the source that policy evaluation actually applies.

Rewrite the diagnostics "Managed Settings" section to:
- show the Active source (GitHub Server API / Native MDM / None)
- break down each channel (server fetch status + raw response, native MDM bag)
- label the raw response as the last *successful* fetch, so a later failed
  fetch (e.g. a 404) no longer looks like it contradicts an empty effective bag
- compute the true effective bag via the shared projectManagedSettings

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

* Fix mock policy server "Generate example" not persisting

The "Generate example" button filled the editor and the localStorage draft but
never called debouncedSave(), so the generated body was never POSTed to
/api/state and the endpoint kept serving the empty preset. Add the missing
debouncedSave() to match applyPreset() and the editor input handler.

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

* Strip prose from Policy Diagnostics and collect managed-settings parse errors

The Developer: Policy Diagnostics "Managed Settings" section now renders
data only (tables and JSON blocks, no explanatory paragraphs).

It also collects non-fatal parsing/normalization warnings from every stage
of the managed-settings pipeline, jsonc-style (accumulate, never throw), and
surfaces them in a new "Parse Errors" section:
- adapt: re-runs adaptManagedSettings on the raw server response
- project: re-runs projectManagedSettings against the declared policy keys
- parse: re-parses JSON-payload string values with the jsonc parser

This explains why a key is silently dropped. For example a server
extraKnownMarketplaces entry with source "github" but no "repo" now shows
the "requires \"repo\"" warning instead of just vanishing from the bag.

Adds a focused test for that github-without-repo normalization case.

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

* Tighten Policy Diagnostics managed-settings rendering (review follow-up)

Code-quality pass on the managed-settings diagnostics section:

- Extract a jsonBlock() helper for the repeated fenced-JSON rendering
  (4 call sites collapsed).
- Parse only the known JSON-payload keys (enabledPlugins,
  strictKnownMarketplaces, extraKnownMarketplaces) instead of a
  leading-brace heuristic. This mirrors what PolicyConfiguration actually
  parses, avoids mis-sniffing scalar values, and catches malformed payloads
  that don't start with a brace.
- Unify the raw-response guard on isObject() so the printed raw response and
  the adapt-stage warning harvest use one predicate.
- Drop the defensive object copy in projectManagedSettings(); it is read-only,
  so normalize undefined with `?? {}` instead of spreading.

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

* Fix native MDM availability in Policy Diagnostics; tidy table headers

The diagnostics report showed "Native MDM | Available | no (desktop only)"
even on desktop. ICopilotManagedSettingsService was registered only in the
electron-main process and hand-plumbed into AccountPolicyService, but never
placed in the renderer service collection, so the report's
accessor.get(ICopilotManagedSettingsService) always threw and mislabeled the
channel as unavailable.

Register the CopilotManagedSettingsChannelClient (the renderer's handle to the
main-process service) in the service collection in both desktop.main.ts and
sessions.main.ts. The diagnostics now resolves it on desktop and Agents windows
and reports real native MDM availability and values; web still has no native
channel and correctly reports unavailable.

Also tidy the report builder: extract a PROPERTY_VALUE_TABLE_HEADER constant for
the five repeated two-column table headers, and drop the now-misleading
"(desktop only)" annotation on the availability row.

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

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-06-22 17:42:10 -07:00
Ben Villalobos fd396ed9a2 OSS: Generate ThirdPartyNotices via Component Governance + Helper Scripts (#322410) 2026-06-22 21:30:20 +00:00
Megan Rogge 7a9cd87b8b voice mode: enable transcript scrolling in chat input and aux window (#322390) 2026-06-22 11:12:48 -07:00
Henning Dieterichs a4f90ca16a Fetch oidc token just before uploading 2026-06-22 12:14:06 +02:00
Sandeep Somavarapu 98bf19c30c agent host: fix custom agent selection and per-chat agent/model changes (#322300)
* agent host: fix custom agent selection and per-chat agent/model changes

Two fixes for Copilot CLI agent-host sessions:

- The selected custom agent (e.g. a plugin/extension agent like "Inbox")
  failed with "Custom agent '<name>' not found". The SDK validates the
  session-start `agent:` option against `customAgents` by name and does not
  consult `pluginDirectories`, but file-dir plugin agents were excluded from
  `customAgents`. The new `toSdkSessionCustomAgents` helper force-includes the
  resolved selected agent while other file-dir agents still load via
  `pluginDirectories`.

- An additional (peer) chat in a session did not respect agent/model changes.
  `SessionAgentChanged`/`SessionModelChanged` were dispatched to the session
  URI (the default chat) instead of the per-chat turn channel, and the
  `chatChannel` was dropped before reaching `changeAgent`/`changeModel`. These
  now route to the peer chat's backend conversation in `_chatSessions`.

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

* sessions: address Copilot code review feedback

- Trim SDK custom-agent names to match parseAgentFile so a whitespace-padded
  frontmatter name still matches the resolved selected agent (CCR finding 3).
- Dedup peer-chat agent/model side-channel dispatch against the last value
  sent for that chat (tracked on AgentHostChatSession) instead of the session
  summary, which only exists for the default chat (CCR findings 1 & 2).

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

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-06-22 00:02:32 +02:00
Alexandru Dima 044134364a ci: split Electron PR test jobs into unit/integration and smoke (#322145)
* ci: split Electron test jobs into unit/integration and smoke

The Linux, Windows and macOS Electron PR test jobs are the slowest in CI,
dominated by the smoke test run. Split each into two parallel jobs - one
running unit + integration tests, the other running smoke tests - to cut
wall-clock time.

Done via two new parameters on the reusable workflows
(unit_and_integration_tests and smoke_tests, both defaulting to true) so
Browser and Remote jobs are unchanged. Artifact names get a -smoke suffix
on the smoke-only job to avoid upload collisions.

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

* ci: gate build and diagnostics to correct Electron test phase

Follow-up to the Electron job split. Ensure each half only does the work
it needs:

- Gate "Build integration tests" on unit_and_integration_tests so the
  smoke-only job skips it.
- Scope the before/after diagnostics steps to their phase (combined with
  always()) so they don't run in the wrong job.
- Move the Copilot extension build into the smoke phase (gated on
  smoke_tests) instead of compiling it unconditionally; align Linux,
  Windows and macOS on the same ordering.

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

* ci: drop space and parens from Electron-Smoke job name

The Windows 1ES runner builds its JobId label from job_name, producing
"windows-test-Electron (Smoke)-...". The space and parentheses prevented
the runner from picking up the job. Rename the smoke job to Electron-Smoke
on all three platforms so the JobId is a plain slug.

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

* Fixes

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-06-19 23:40:20 +02:00
Alexandru Dima 3980424ce8 Refactor restore-node-modules action for lookup-only functionality (#322140)
refactor: update restore-node-modules action to support lookup-only functionality

- Replaced 'extract' input with 'lookup-only' to allow cache entry checks without downloading or extracting.
- Updated action logic to conditionally extract node_modules based on the new 'lookup-only' input.
- Adjusted workflow files to utilize 'lookup-only' for cache-warming jobs on Linux, macOS, and Windows.
2026-06-19 19:38:47 +00:00
Alexandru Dima 37e7e85b10 Optimize node_modules caching for CI & PR checks (#322074)
* CI: speed up node_modules cache with zstd + shared scripts

Switch the Linux/macOS node_modules cache from single-threaded gzip
(tar -czf) to multi-threaded zstd. The "Create node_modules archive"
step was spending ~5min of single-core gzip on a multi-GB tree on every
cache miss; zstd -T0 uses all cores and decompresses much faster, so
cache-hit jobs benefit too. Windows stays on 7-Zip (already threaded).

Extract the archive/extract commands into shared per-platform scripts
under .github/workflows/node_modules_cache/ (cache.sh / cache.ps1, each
dispatching on an archive|extract argument) so the format and flags live
in one place instead of being duplicated across ~8 workflows. Bump
build/.cachesalt to invalidate existing gzip caches.

Also remove the obsolete extensions/copilot CI workflows
(copilot-setup-steps.yml, ensure-node-modules-cache.yml, pr.yml) and the
unused build/listBuildCacheFiles.js, and drop their now-stale entries
(plus lit-html and signals-core) from .eslint-allowed-javascript-files.

* ci: seed copilot node_modules cache on main and rename cache keys

Add copilot-linux and copilot-windows jobs to pr-node-modules.yml so the
copilot node_modules cache is populated on main. Rename the copilot cache
keys to copilot-node_modules-linux / copilot-node_modules-windows in pr.yml.

* ci: extract node_modules cache into composite actions

Factor the repeated node_modules cache plumbing into two local composite
actions, restore-node-modules and save-node-modules, and migrate all
workflows that used the cache.sh/cache.ps1 archive flow (pr, pr-node-modules,
pr-{linux,darwin,win32}-test, copilot-setup-steps, component-fixtures,
css-order-scan).

- restore-node-modules computes the key, restores the cache, optionally
  extracts on a hit, and exports the resolved key via $GITHUB_ENV.
- save-node-modules archives node_modules and saves it to the cache, reusing
  the key exported by restore so callers don't repeat the prefix.
- Bespoke install steps stay in the workflows, so per-job env/secrets never
  cross the action boundary.
- Only seed the cache on branch pushes (component-fixtures skips PRs, whose
  caches aren't shared).

* save the node_modules cache for now to test it

* ci: fix node_modules cache save dropping the archive

cache.sh wrote its archive as cache.tzst, but actions/cache reserves that
name for its own tarball and passes --exclude cache.tzst, so our archive was
excluded and an empty (~200 B) cache was saved on Linux/macOS. Rename the
archive to node-modules.tzst and bump build/.cachesalt to invalidate the
broken cache entries.

* empty commit

* Remove again saving to the node modules cache from PR steps
2026-06-19 17:21:43 +02:00
Josh Spicer 593c7f2366 policy: dev mock server for copilot_internal policy endpoints (#321871)
* policy: add dev mock server for copilot_internal policy endpoints

Adds scripts/mock-policy-server, a standalone dev tool (npm run
mock-policy-server) that mocks the Copilot policy endpoints
DefaultAccountService calls: entitlements (/copilot_internal/user), token
(/copilot_internal/v2/token), MCP registry (/copilot/mcp_registry) and
managed settings (/copilot_internal/managed_settings).

A small web GUI lets devs pick presets or edit each JSON response, and
Wire/Unwire buttons point product.overrides.json at the local server
(preserving the rest of defaultChatAgent, since bootstrap-meta merges
overrides shallowly). The managed-settings JSON schema is loaded from
--schema/MANAGED_SETTINGS_SCHEMA, defaulting to
./copilot-agent-runtime/schema/managed-settings-schema.json relative to
the app cwd; web URLs and file URIs are accepted, and the GUI warns about
keys not declared in the schema.

The three browser/shared .js files are added to
.eslint-allowed-javascript-files since the GUI loads them directly.

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

* policy: address mock-policy-server review feedback

- Scope permissive CORS to the mocked GET endpoints only; keep /api/*
  same-origin so a website can't drive /api/wire and rewrite
  product.overrides.json (CSRF).
- Coerce an empty editor body to {} instead of "" so mocked responses
  stay JSON objects.
- Build the endpoint meta line with textContent/DOM nodes instead of
  innerHTML.
- Drop the misused tablist/tab ARIA roles; the nav now has an aria-label
  and the active item uses aria-current.

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

* policy: document mock policy server in add-policy skill

Add local-testing.md to the add-policy skill with basic steps for using
the mock policy server (scripts/mock-policy-server) to exercise the
account/managed-settings flow locally, and link it from SKILL.md and
github-managed-settings.md.

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

* policy: polish mock server GUI — schema validation, wiring backup, localStorage persistence

* policy: auto-save, rename wiring to product.overrides.json, copy path button

* mock-policy-server: convert server.js to TypeScript; add raw response diagnostics

- Convert server.js → server.ts (runs via --experimental-strip-types)
- Add endpoints.d.ts type declarations for the UMD endpoints module
- Add managedSettingsRawResponse to IDefaultAccountProvider/IDefaultAccountService
- Show raw response in Developer: Sync Account Policy output
- Remove server.js from eslint allowed-javascript-files

* mock-policy-server: convert all JS to TypeScript

- endpoints.js → endpoints.ts with proper interfaces (replaces .d.ts)
- public/app.js → public/app.ts with full type annotations
- Server uses module.stripTypeScriptTypes() to serve .ts as plain JS
  to the browser — no build step needed
- Remove all mock-policy-server entries from .eslint-allowed-javascript-files

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-06-18 21:55:01 +00:00
Josh Spicer 49484d1c91 policy: server-delivered managed settings win over native MDM (#321970)
* policy: server-delivered managed settings win over native MDM

Managed settings can arrive from two channels: the server `managed_settings`
endpoint and native MDM (Windows registry / macOS plist). Previously the two
were merged with native MDM winning. This changes the precedence so the two
layers are never merged: at any point in time there is a single authoritative
source. The server is harder to bypass than local MDM/file policies, so when
the server delivers managed settings it wins outright and native MDM is ignored
entirely. Native MDM applies only when the server provides no managed settings.

Client-side merging still happens within the winning layer (e.g. enabledPlugins,
extraKnownMarketplaces).

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

* policy: move managed-settings precedence rationale into add-policy skill

Trim the verbose inline comment in AccountPolicyService.getPolicyData() down to
a one-line pointer; the full precedence rationale lives in the managed-settings
section of the add-policy skill doc.

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

* policy: drop code snippet from managed-settings precedence doc

Keep the precedence explanation as prose; the code lives in
AccountPolicyService.getPolicyData().

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

* policy: add skill learning — prefer behavior/contract prose over copy-pasted code

Skills should document behavior and business-logic expectations and reserve
code blocks for the author-facing API contract, rather than reproducing
internal implementation that rots when the source changes.

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

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-06-18 14:45:18 -07:00
Sandeep Somavarapu ee44398a29 agent 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>
2026-06-18 09:54:11 +00:00
Josh Spicer 35054242b4 Document GitHub Copilot managed settings in add-policy skill (#321808)
* Document GitHub Copilot managed settings in add-policy skill

Add a github-managed-settings.md sub-file covering the new enterprise
managed-settings modality (native MDM / file / GitHub server -> the
canonical IPolicyData.managedSettings bag) and the policyReference
mechanism (one policy governing many settings). Update SKILL.md to link
the sub-file and refresh the policy-sources and key-files tables.

Grounded in PRs #318623, #320991, #321218, #321515.

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

* Tighten managed-settings skill after council fact-check

Cross-checked every claim against the source and the four PRs:
- Correct the channel count: VS Code feeds the bag from native MDM +
  server endpoint only; managed-settings.json is external-schema-only and
  not read by VS Code.
- Fix "JSON.parse" -> PolicyConfiguration.parse() (lenient JSONC visitor).
- Quote ManagedSettingValue verbatim (= PolicyValue).
- Clarify native MDM is a separate input merged in getPolicyData, not on
  policyData; document MDM-wins merge order precisely.
- Note schema is nested vs the flattened bag key; add the
  extraKnownMarketplaces github/git-only divergence alongside the strict
  boolean one.
- Soften the catalog claim: referencedSettings only captures references
  loaded at export time (sessions Claude ref absent from policyData.jsonc).
- Fix example file path (chat.shared.contribution.ts) and restore the
  chat_preview_features_enabled OR in the ChatToolsAutoApprove sample.
- Make the main.ts wiring snippet match the real two-step structure.

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

* Address PR review: annotate example minimumVersion values

Mark the concrete minimumVersion values in example blocks as historical
values transcribed from existing policies, with an inline note that new
policies derive minimumVersion from package.json major.minor (Step 1).

The file-based-channel and JSON.parse review comments were already
resolved in the prior council-fix commit.

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

* Clarify policy multiplexing in add-policy skill

After another pass through the policy wiring, clarify that
MultiplexPolicyService is used in two places: main-process OS/file policy
reader multiplexing, and renderer/session multiplexing of the main policy
channel with AccountPolicyService.

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

* Promote policyReference guidance to main add-policy skill

policyReference is a general policy mechanism, not specific to Copilot
managed settings. Make the main SKILL.md section self-contained with the
owner/reference model, validation rules, export behavior, IPC-safe
serialization, and diagnostics notes. Keep the managed-settings sub-file
as a cross-reference only for managed-settings-specific examples.

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

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-06-17 23:35:21 +02:00
Henning Dieterichs 7533927257 improved cssOrderScan 2026-06-17 19:10:01 +02:00