* sessions: support multi-session delete via session capability
Enable deleting multiple sessions at once and consolidate the delete
action into the sessions workbench core instead of each provider.
- Add required `deleteSessions(sessionIds)` batch API to `ISessionsProvider`
and `deleteSessions(sessions)` to the sessions management service, which
groups sessions by provider before delegating.
- Implement a real batch delete in the agent host base provider that
resolves all targets synchronously up front before disposing, avoiding a
reconcile dropping not-yet-processed cached sessions.
- Introduce a `supportsDelete` session capability and a
`chatSessionSupportsDelete` context key, mirroring the `supportsRename`
pattern. A single core `DeleteSessionAction` (gated on the capability)
replaces the per-provider delete actions and the delete-session helper.
- Move the delete confirmation dialog into the action and remove it from
the provider implementations.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* sessions: address CCR feedback on multi-session delete
- Filter the action's incoming context to sessions that advertise
`capabilities.supportsDelete`, so a mixed multi-selection never deletes
sessions that don't support it.
- Use a singular vs plural delete error message and distinct localization
keys instead of a plural-only message.
- Make the management service batch delete best-effort: continue deleting
other providers' sessions if one provider rejects, then surface the first
error. Emit `onDidDeleteSession` only for providers that succeeded.
- Clarify the `deleteSessions` JSDoc to say implementations may batch or
delegate to `deleteSession`.
- Revert the unrelated "Copilot CLI" -> "Copilot" session type label change.
- Add a best-effort batch delete test to the management service suite.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
---------
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Respect workspace trust for the local agent host
Gate spawning local agent-host sessions on workspace trust as a UI-layer
concern, mirroring how extension-host chat is gated. Viewing chat and the
agent list does not require trust; sending the first message prompts to
trust the workspace, and no session is ever spawned (even eagerly) in an
untrusted folder.
Editor window:
- AgentHostSessionHandler._invokeAgent requests workspace trust before
spawning a session and aborts cleanly on decline.
- AgentHostUntitledProvisionalSessionService.getOrCreate no longer
eagerly pre-warms a backend session in an untrusted workspace.
Agents window:
- baseAgentHostSessionsProvider skips the eager createSession when the
target folder is untrusted (defense-in-depth; the interactive prompt
stays at folder-pick time). Config resolution for the picker remains
ungated. Remote providers (requiresWorkspaceTrust: false) are
unaffected.
Refs microsoft/vscode-internalbacklog#8082
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Address Copilot review: gate provisional on folder trust, guard stale eager-create
- AgentHostUntitledProvisionalSessionService.getOrCreate now gates on the
trust of the actual target working directory (which can be a standalone
folder outside the open workspace) via getUriTrustInfo, falling back to
whole-workspace trust only when no working directory is known. The check
moved into the creation path so existing/inflight fast paths are intact.
- baseAgentHostSessionsProvider: after awaiting trust info in the eager
create path, bail if the NewSession draft was abandoned/replaced, to
avoid spawning a backend session for a stale entry.
- Add tests for the untrusted/trusted working-directory-folder cases.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
---------
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* agentHost: centralize and type-check AHP `_meta` access
The Agent Host Protocol uses an open `_meta` bag (`Record<string, unknown>`)
on many protocol/state messages to carry well-known extra data between server
and client. This was read in an ad-hoc, untyped way in many places.
This change makes all `_meta` access type-safe and centralized:
- Add typed reader/builder functions per well-known slot, grouped under
`platform/agentHost/common/meta/`, so nothing reads `_meta` untyped.
- Readers take their parent object (e.g. `ToolCallState`, `AgentCustomization`,
`RootState`, `ErrorInfo`, `UsageInfo`) and read `source._meta` internally, so
passing the wrong slot's bag is a compile error. `readSessionGitState` stays a
raw-value reader (the sessions provider holds a detached `_meta` snapshot).
- De-duplicate the feedback-annotation slot: the sessions browser layer now maps
the shared validated wire shape into its client view instead of re-declaring
and re-validating it.
- Replace a serialize-then-reparse round-trip in the Claude subagent signal path
with a direct typed builder.
- Add a syntactic local ESLint rule `code-no-untyped-meta-access` that flags
member access off / casts of `x._meta`, scoped to the agent host surface.
(Written by Copilot)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* agentHost: address Copilot review on `_meta` type-safety PR
- protocolUpgrade: `readUnsupportedProtocolVersionErrorMeta` now returns
`undefined` (not an empty `{}`) when `_meta` has no validated fields, matching
its documented contract so presence checks stay correct.
- code-no-untyped-meta-access: update the rule's header comment and diagnostic
messages to recommend the new parent-object reader form
(`readToolCallMeta(toolCall)`) instead of the old bag form.
- stateToProgressAdapter: drop unreachable `resourceUri.length === 0` /
`channel.length === 0` guards — `readToolCallMeta().ui` already guarantees a
non-empty `resourceUri` and only sets `channel` when non-empty.
(Written by Copilot)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
---------
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* sessions: add command palette entry to update an incompatible remote agent host server
Expose the existing remote agent host server upgrade flow ("Update Server")
as a command palette command. Connecting to a remote agent host that runs an
old build leaves it in the `incompatible` state; when that host was spawned by
a VS Code CLI willing to receive upgrade signals it advertises an upgrade
method. Previously this was only reachable from the incompatible notification
or the per-host options quickpick.
The new "Update Remote Agent Host Server..." command (f1, Sessions category,
gated on chat.remoteAgentHostsEnabled) collects incompatible hosts that
advertise an upgrade method, prompts when there is more than one, and reuses
the shared runServerUpgrade flow.
(Written by Copilot)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* sessions: clarify message when no incompatible host can be updated in place
Address Copilot review feedback: the previous "No remote agent hosts need
updating." message was misleading when incompatible hosts exist but none was
spawned by a VS Code CLI that can update it in place. Distinguish the two cases
so users who can see an Incompatible host get an accurate explanation.
(Written by Copilot)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
---------
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* sessions: hide session picker groups when no duplicate session names
Section headers in the session type picker exist to disambiguate session
types that share a label across providers (e.g. two providers both
offering "Claude"). When every type's label is unique there is nothing
to disambiguate, so render a flat list without group headers even when
multiple providers contribute.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* sessions: rename Copilot CLI session type label to "Copilot"
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* test: update Agents Window smoke test for renamed Copilot label
The Copilot CLI session type label was renamed to "Copilot" (shared
CopilotCLISessionType used by the Copilot Chat provider), so the picker
no longer exposes a "Copilot CLI" entry. Select "Copilot" instead.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
---------
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* 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>
A session can contain multiple peer chats that share the same context/workspace, each addressed by its own ahp-chat URI. The feedback (comments) server tools received the chat URI, so comments were stored on the individual chat's annotations channel instead of the session's. Resolve the URI back to its owning session before reading/writing annotations so comments always target the main session.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* extensions: show configured auto-update delay in delayed label
The extension status label hardcoded "2 hours" as the auto-update delay,
so changing extensions.autoUpdateDelay still showed 2h. Add a
getAutoUpdateDelay() method that returns the configured delay and use it
to format the label dynamically.
Fixes#321577
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* extensions: format auto-update delay as a duration
Use a past timestamp with fromNow so the configured delay reads as a
duration (e.g. "2 hours") instead of "in 2 hours".
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
---------
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The agent feedback editor input previously appeared for empty selections
when the cursor was inside a diff hunk. The input should only appear for
non-empty selections, so remove the diff-hunk special casing and hide the
widget whenever the selection is empty.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The model can stream malformed JSON for tool-call arguments. The language model wrapper threw a bare Error from a fire-and-forget finished callback, producing an unhandled rejection in error telemetry without cleanly aborting the response. Align with the other tool-call consumers (langModelServer, messagesApi) by logging the diagnostic and falling back to empty parameters so the tool call is still surfaced to the consuming extension.
Co-authored-by: vs-code-engineering[bot] <122617954+vs-code-engineering[bot]@users.noreply.github.com>
* agent host: fix blank response after aborting a turn with a queued message
When a running turn was aborted while a follow-up message was queued, the
Copilot SDK's asynchronous terminal `session.idle` (delivered after the
abort teardown) completed the wrong turn: the queued message's send() had
already reassigned the session's current turn id, so the stale idle emitted
an empty ChatTurnComplete for the freshly-started turn and orphaned its real
response and pending permission prompt.
Read the SDK's authoritative `IdleData.aborted` flag, and replace the
scattered per-turn fields (turn id, usage counter, streaming part-id maps)
with a single CopilotTurn object carrying an explicit lifecycle state
(pending | running | completed | aborted). A turn is pending between send()
and the first SDK event and running thereafter; an abort's idle tears down a
running turn (the client's ChatTurnCancelled finalizes it) and leaves a
pending queued turn open, so the next turn's response is no longer orphaned.
Steering turns are marked running on creation since they are promoted
mid-loop.
Also assert that cancelling a turn intentionally does not drain queued
messages (they stay for manual dequeue), and keep the subagent routing map
session-scoped since background subagents can outlive a turn.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* agent host: address PR review feedback
- Log an error and drop markdown/reasoning deltas emitted with no active
turn (previously a no-op set that re-allocated a part per delta).
- Split the abort-idle trace message by turn state (running turns are torn
down, not left open).
- Tidy a test title to sentence case.
- Give delta/plan-mode mapping tests an active turn instead of relying on
the old emit-without-a-turn behavior; assert the new drop+log behavior.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
---------
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Render the memory instructions and context blocks only when the memory
tool is in availableTools, so the prompt and available tools stay in sync.
Fixes#321833
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The off-flag conversation summarization path forced `stream: false` on the
chat request. The response processor is selected by the endpoint's static
`supportsStreaming` capability, not by this flag, so for a streaming Chat
Completions model (e.g. gemini-3-flash) the single non-streamed JSON blob is
still routed through the SSE processor, which fails to parse it and reports a
spurious RESPONSE_CONTAINED_NO_CHOICES failure. Both Full and Simple modes hit
this, so /compact reported failure even though the model returned valid
summaries.
Removing `stream: false` lets the request stream (the safe default for every
endpoint type); `interceptBody` still forces `stream: false` for models that
genuinely don't support streaming.
Fixes#321085
The SessionPermissionManager 'auto-approves a normal file inside the
working directory' test failed on Windows CI because it chose its temp
base via `process.env.RUNNER_TEMP || tmpdir()`. `RUNNER_TEMP` is a
GitHub Actions variable and is unset on VS Code's Azure DevOps CI, so it
fell back to `os.tmpdir()`, an 8.3 short path containing a `~1`
segment. `fs.realpathSync` does not expand short names to long form, so
`workDir` kept the `~1` segment and `assertPathIsSafe` rejected it,
making write auto-approval return undefined instead of NotNeeded.
Use `AGENT_TEMPDIRECTORY` (set by Azure DevOps, a long path) ahead of
`RUNNER_TEMP`, matching how the rest of the VS Code build resolves the
CI temp directory.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The Chat Sessions smoke test runs right after the Chat Disabled suite,
which disables AI features. When the suite re-enables them, there is a
brief window where copilot-chat is still disabled and its commands are
not yet registered. The smoke helper invoked
'github.copilot.debug.extensionState' to force-activate copilot-chat,
but that executeCommand rejected with 'command not found' during this
window, aborting the handler before it could open the chat editor and
causing a 60s timeout on '.editor-instance .interactive-session'.
Wait for the diagnostic command to be registered (via the existing
waitForCommand helper) before invoking it, so the handler no longer
races copilot-chat enablement/activation.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Native extension host crashes (e.g. from a faulty native addon such as the
node-pty bundled with the Copilot CLI SDK) print to the process' stderr but
never reach the JavaScript layer: there is no JS stack and, for utility
processes, frequently no crash dump either. The output is also only forwarded
to the renderer DevTools console debounced, so the final pre-crash bytes can be
lost.
Capture the raw, undebounced extension host stdout/stderr from the renderer
side (which survives the crash) into the renderer log so such crashes remain
diagnosable from the published smoke-test log artifacts. Gated to smoke tests
via the existing --enable-smoke-test-driver flag so regular sessions are
unaffected.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
getAvailableTools(): skip virtual-tool grouping for any tool-search-capable endpoint (not just Anthropic). Previously GPT-5.4/5.5 ran virtual-tool grouping AND responses-API client tool search simultaneously, so real MCP tools were hidden behind activate_* groups (or trimmed) and never appeared in the request's tools map - making them searchable via tool_search but not callable.
toolSearchTool: exclude always-available (non-deferred) tools from the tool_search candidate set so the limited result slots only go to tools that actually need loading.
Fixes#317998Fixes#317992
* Add per-model system-prompt registry for Copilot agent-host sessions
Introduces a prompt registry (mirroring the Copilot extension's PromptRegistry/IAgentPrompt) so Copilot CLI agent-host sessions resolve their SDK system message per model instead of a single hardcoded constant. First contributor: a Claude Opus 4.8 resolver applying customize-mode section overrides, opt-in via the new chat.agentHost.opus48Prompt.enabled setting (forwarded into the local agent host root config). Forwarding is registered for the VS Code workbench only, not the Agents window.
* Address PR review: empty section overrides fall back to default; strongly type test schema helper
- promptRegistry: treat an empty resolveSectionOverrides() result as 'no override' so the default identity customization is preserved instead of emitting customize-mode with empty sections.
- agentHostCopilotPromptContribution.test: import ConfigPropertySchema and type makeRootStateWithSchema, removing the unsafe Record<string, never> cast.
- agentHostPromptRegistry.test: add regression test for the empty-overrides fallback.
- anthropicPrompt: lead the Opus 4.8 tone append with a newline so it doesn't run on from the SDK foundation tone.
* Fix Copilot real-SDK agent host integration tests
The Copilot real-SDK suite (gated behind AGENT_HOST_REAL_SDK=1) had drifted
from the agent host protocol. This adapts the test harness to the current
behavior so the suite is green again (12 passing, 1 pending, 0 failing):
- Multi-chat channel migration: chat actions are now emitted on a session's
default chat channel (buildDefaultChatUri(sessionUri)) rather than the bare
session URI. Update the usage-action channel assertion and the subagent
test's channel filters/subscriptions accordingly, and subscribe to the
worktree session's default chat channel.
- driveTurn dispatched chat actions (toolCallConfirmed / inputCompleted)
without a top-level channel, crashing the server in buildDefaultChatUri.
Include the channel and drop the now-dead session field from the bodies.
- Plan-mode answers: prefer the exit_only option so approving a plan ends the
turn instead of continuing to implement in-turn, which surfaced tool-call
confirmations the planning test asserts against.
- Worktree test: the host custom terminal tool became opt-in
(EnableCustomTerminalTool defaults off). Enable it via a root/configChanged
action before the session launches so the shell tool routes through the
host terminal manager.
These are test-harness adaptations only; no product behavior changes.
(Written by Copilot)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Add required confirmed/reason fields to toolCallConfirmed dispatches
The real-SDK test harness dispatched chat/toolCallConfirmed approve
actions without the required `confirmed` field (and the deny action
without the required `reason` field), so the chat reducer stored
`undefined` for those properties, violating the protocol action shape.
Populate `confirmed: ToolCallConfirmationReason.UserAction` on approvals
and `reason: ToolCallCancellationReason.Denied` on the denial path.
(Written by Copilot)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Add typed dispatch helper to agent host test client
The test client's `notify(method, params?: unknown)` erased all action-shape
type checking, which is why a missing required `confirmed` field on
`chat/toolCallConfirmed` dispatches slipped past the compiler.
Add a typed `dispatch(params: DispatchActionParams)` method to
`TestProtocolClient` so dispatched actions are validated against the
`StateAction` union at compile time, and migrate the real-StateAction
dispatch sites in the Copilot real-SDK test files to it (using `ActionType`
enum members instead of raw strings). This also fixed a malformed dispatch in
copilotRealSdk.integrationTest.ts that was missing its channel and `confirmed`
field and carried a bogus `session` field.
The two `session/abortTurn` sites are left on raw `notify` since that action
is not part of the `StateAction` union.
(Written by Copilot)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
---------
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* fix: handle pending_confirmation signals when no active protocol turn exists
When a hook-triggered continuation (e.g. userPromptSubmitted) runs after
the protocol turn has already completed, the state manager has no active
turn. Action signals use a fallback path that dispatches with an empty
turnId, but pending_confirmation signals were silently dropped. This
caused the permission deferred promise to never resolve, blocking the SDK
session indefinitely (stuck in 'thinking').
Fix: route pending_confirmation through _handleToolReady with an empty
turnId in the no-active-turn fallback, matching the action signal path.
Also fix the subagent path to always call _handleToolReady (using empty
string fallback) instead of conditionally skipping when subTurnId is
undefined.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* test: deterministic regression test for pending_confirmation without active turn
Adds an end-to-end integration test that drives the real agent host
server, AHP protocol, AgentSideEffects signal handling, and permission
manager to guard the fix for pending_confirmation signals arriving after
the protocol turn has completed.
A new ScriptedMockAgent 'orphan-confirmation' scenario completes a turn,
then emits a tool + pending_confirmation with no active turn (simulating
a hook-triggered continuation). The test asserts the confirmation is
dispatched and the session continues instead of hanging. Reverting the
production fix makes the test time out.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
---------
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Rob Lourens <roblourens@gmail.com>
- toSdkMcpServersFromConfigMap: treat the user-controlled root mcpServers map
as Record<string, unknown> and skip entries that don't match a supported
shape (stdio+command / http+url), so malformed config can't surface as
command/url: undefined in the SDK config.
- copilotAgent._getMcpServers: clone via structuredClone instead of
JSON.parse(JSON.stringify(...)) (cheaper, value-preserving) on the
snapshot/restart path.
- IAgentHostConnectionsService.connections: correct the doc — the ambient
entry always has a live connection; only remote entries may be undefined.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
`resolveRealPathForNonexistent` imported `realpath` from `fs/promises`,
which internally calls `fs.realpath.native`. On Windows that resolves
subst drives to their target (and normalizes differently) than the JS
`fs.realpath` implementation the tests use via `fs.realpathSync`. The
symlink-resolved path could then diverge from the working directory and
be judged outside it, so `getAutoApproval` returned `undefined` instead
of `NotNeeded`.
Use `Promises.realpath` from `vs/base/node/pfs`, which deliberately
avoids `fs.realpath.native` (see microsoft/vscode#118562), aligning
production with the test and the rest of the codebase.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Hide the chat response username and avatar for Agent Host Copilot responses so they match the default Copilot presentation while keeping other Agent Host agents distinguishable.
(Written by Copilot)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Cancel pending initial config resolution before the picker render store is disposed, and ignore late render attempts after disposal.\n\n(Written by Copilot)\n\nCo-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Add build-fast npm script for fast full builds
Adds a 'build-fast' script that fully builds the repo with as little
typechecking as possible by composing existing tasks: esbuild transpile
for the core (transpile-client), tsgo compile for extensions
(compile-extensions + compile-extension-media), the copilot extension
(compile-copilot), and the codicon.ttf copy (copy-codicons).
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Remove transpile and transpile-extensions scripts in favor of build-fast
build-fast replaces the transpile script. The transpile-extensions npm
script is no longer needed; CI invokes the gulp transpile-extensions
task directly via `npm run gulp`.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
---------
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Move the local agent host chat-session item controller into an editor-window-only contribution so the Agents window keeps using its sessions provider list path without loading AgentHostSessionListController. Keep the shared agent-host contribution focused on chat content, models, auth, and customization wiring, and add focused tests for editor-window registration versus sessions-window suppression.
(Written by Copilot)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Disable process.report in copilot extension
Override process.report.getReport to return undefined, loaded as the first import in the copilot extension entrypoint. Cherry-picked from #321998 and #322036.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
AHP 0.4 moves turns/active_turn off SessionState onto per-chat ChatState
(SessionState now carries a `chats` catalog), and SessionStatus is now a
newtype bitset instead of a repr enum.
- agent_ps: use SessionStatus::bits()/from_bits().contains() instead of
`as u32` casts
- agent_stop: resolve in-progress chats from the session catalog, subscribe
to each chat to find its active turn, and dispatch the renamed
StateAction::ChatTurnCancelled to the chat URI
- agent_logs: print the session's chats catalog instead of the removed
turns/active_turn
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The "Agents Window > Test Copilot CLI session" smoke test flakily timed
out at `activateSessionByLabel`, which located the just-completed session
row by its title and expected it to equal the mocked reply
`MOCKED_COPILOT_RESPONSE`. That title is set asynchronously by a utility
model after the first turn and races the untitled->committed session
swap, so it is non-deterministically either the user's prompt (the
synchronous fallback) or the generated reply. The test passed on macOS
(title-gen landed) and failed on Linux (it didn't) in the same run.
Decouple row identification from response verification:
`activateSessionByLabel` now accepts one or several row substrings and
matches a row containing ANY of them, while a separate `responseLabel`
is verified against the active session's response bubble. The smoke test
passes both the first prompt and the reply, so activation is
deterministic regardless of when title generation completes.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The WorktreeCreatedTaskDispatcher launched setup/build tasks but never
stopped them, so their (potentially remote) host processes leaked when a
session was archived ("Mark as Done"). See #321021.
Task runners now return an IDisposable stop handle. The dispatcher tracks
these per session and disposes them when the session is archived or
removed, terminating the launched terminals/processes. Agent-host task
terminals are disposed directly (prompt-free) so the AgentHostPty shuts
down and the node-pty process on the host is killed.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* agent host: bring tool approval to parity with the extension
- The agent host auto-approved write tool calls using only working-directory
and glob checks, while the extension's edit-confirmation pipeline also guards
against unsafe paths, system/platform-config locations, and symlinks that
redirect edits outside the workspace; this closes that gap so the agent host
no longer silently approves edits the extension would prompt for.
- Resolves symlinks (including not-yet-created ancestors) so a link cannot be
used to escape the working directory, and treats permission-denied resolution
as requiring confirmation.
- Makes the approval path async rather than relying on synchronous filesystem
calls, while keeping the shell-command approver synchronous so its existing
behavior and tests are unaffected.
- Adds unit tests covering the new path-safety, platform-restriction, and
symlink-escape checks.
(Commit message generated by Copilot)
* agent host: address review feedback and fix async approval tests
- Treat EACCES like EPERM when resolving symlinks so an execute-only
directory cannot be used to bypass the working-directory check; permission
errors now require confirmation rather than silently checking the literal
path.
- Fix mis-indented JSDoc in claudeCanUseTool.
- Update AgentSideEffects tests to await the now-async tool-approval dispatch
via a deterministic waitForState helper (re-checks on each state emit)
instead of depending on a fixed timing delay.
(Commit message generated by Copilot)
* agent host: fix SessionPermissionManager test on Windows CI
- The test built its working directory under `os.tmpdir()`, which on Windows
CI is an 8.3 short path (`C:\Users\RUNNER~1\...`). `assertPathIsSafe`
correctly rejects the `~1` segment, so every auto-approval returned
"needs confirmation" and the suite failed. Base the temp dir on
`RUNNER_TEMP` (a plain long path) when available so the working directory
is free of 8.3 short names.
(Commit message generated by Copilot)