* sessions: use OS-specific task overrides for local agent host tasks
The agent host session task runner always emitted the POSIX (.sh) command
when resolving tasks, ignoring the windows/osx/linux overrides in tasks.json.
On Windows this meant 'Run and Compile Agents - OSS' ran ./scripts/code.sh
instead of .\scripts\code.bat.
Pass targetOS to resolveTaskCommand for the local agent host (which runs on
the same machine as the renderer) so the renderer's OS picks the right
override. Remote hosts, whose OS is unknown here, keep falling back to the
task's default command.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* sessions: ensure osToTaskTargetOS returns on all code paths
Add a default branch so the function always returns a TaskTargetOS,
satisfying noImplicitReturns and avoiding undefined for unexpected
enum values.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
---------
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* agent host: fix subagent message leak on session reopen; use real SDK types in replay parser
When a subagent ran and its session was reopened, the subagent's
assistant.message content leaked into the parent transcript as a new
assistant turn. The live-streaming path already routes subagent events by
the envelope-level `agentId` (the SDK migrated away from per-event
`data.parentToolCallId`, now deprecated), but the history-replay path in
`mapSessionEvents.ts` had not adopted this, so replayed subagent messages
were attributed to the parent.
This change migrates the replay parser to reference the real
`@github/copilot-sdk` types instead of hand-copied local interfaces:
- `mapSessionEvents.ts` now consumes `readonly SessionEvent[]` and narrows
via the discriminated union, removing all `(e as ISessionEvent…)` casts,
the duplicated local `ISessionEvent*` interfaces, the trivial
`IToolRequestInfo` alias, and the now-redundant SDK drift guard. Subagent
routing keys off `agentId`, keeping the deprecated `parentToolCallId` only
as a backward-compat fallback for sessions persisted before the migration.
- New test-only `copilotTestEvents.ts` houses minimal event shapes plus a
`toSessionEvents()` helper that upcasts them to the real `SessionEvent[]`,
so production no longer duplicates SDK types just for test ergonomics.
- Tests/fixtures updated, including a new-format `subagent-session-agentid`
fixture covering `agentId`-based routing on replay.
(Written by Copilot)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* agent host: address Copilot review feedback on test event shapes
- Make `data` required on `ISessionEventMessage` so test fixtures can't
silently omit it (the production mapper always reads `e.data.*`), better
mirroring the real SDK message events.
- Use `interactionId` instead of the dead `messageId` for `user.message`
fixtures: the real `UserMessageData` has no `messageId`, and the mapper's
user-message path keys off `interactionId` / the envelope id.
(Written by Copilot)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
---------
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Avoid CPU-pegging process report in libc detection
detectLibc() called process.report.getReport() on every Linux process to
tell glibc from musl. That report serializes heap, native stack and libuv
state, and the network/socket enumeration can peg the CPU on busy hosts.
Detect cheapest-first instead: parse the ELF PT_INTERP dynamic-linker path
from the head of /proc/self/exe, then string-match the head of /usr/bin/ldd,
and only fall back to the process report (now with excludeNetwork = true to
skip the expensive libuv section, also inspecting sharedObjects). Default to
glibc when nothing is conclusive.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Read ELF64 offsets as 64-bit with safe-integer guards
Address PR review: e_phoff, p_offset and p_filesz are 64-bit fields in
ELF64. Read them via readBigUInt64LE through a bounded helper that rejects
values past Number.MAX_SAFE_INTEGER, validate e_phentsize covers a full
Elf64_Phdr, and widen the per-entry bounds check to the 8-byte p_filesz.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Use detect-libc package instead of hand-rolled libc detection
Replace the bespoke ELF/ldd/process-report probing in detectLibc() with the
detect-libc package (already present transitively, now a direct dependency).
It performs the same cheapest-first detection and sets process.report's
excludeNetwork flag internally, so the CPU-pegging libuv enumeration is still
avoided without us maintaining the ELF parser. Add detect-libc to the
hasNode import allowlist in eslint.config.js.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Declare detect-libc in remote/package.json
detectLibc() (via agentSdkDownloader) is reached from agentHostServerMain,
so the server/REH build requires detect-libc. It was only present in the
remote node_modules transitively (through @parcel/watcher); declare it
directly to match the root manifest and the direct import.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Rename detectLibc to detectLibcSync
Signal the blocking nature in the name and leave room for a future
promise-based detectLibc that wraps detect-libc's async family(). Update
the agentSdkDownloader consumer and the unit test.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
---------
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
When an idle background session is evicted from the AHP state manager but
its cached SDK session keeps running turns, end-of-turn status updates land
on an unknown session and are dropped, leaving the session badge stuck on
"running".
Surface this lifecycle at info level so it can be reconstructed from a
standard log capture:
- Promote the idle-session eviction log in AgentService from trace to info,
mirroring the existing info-level "Restored session" log so the in-memory
session lifecycle (restore -> evict -> restore) is visible.
- Log at turn start in AgentSideEffects when a turn runs for a session that
is absent from the state manager, pinpointing the desync at the moment it
occurs rather than only via the later "unknown session" warnings.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Add in-editor PMF survey pane (POC)
Moves in-product surveys from notification-based flows into an editor
pane, following the same pattern as the issue reporter editor.
- EditorInput + EditorPane architecture (singleton, readonly)
- Segmented control (Q1) styled with --vscode-radio-* tokens
- List-row selection (Q2/Q3) with native radios visually hidden inside
full-width label elements, styled via :has(:checked)
- Responsive container query (collapses 2-col to 1-col at 600px)
- HC/focus-visible support for both segment and list-row patterns
- Success animation with auto-close after 3s
- Telemetry event for survey submission (survey/submit)
- Works in both workbench and sessions/agent window
- Testable via Developer: Open Survey command
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Address PR feedback: accessibility, localization, design tokens
- Gate 'Open Survey' command behind IsDevelopmentContext (dev builds only)
- Localize all user-facing strings (title, description, questions, options)
- Use stable option IDs for telemetry instead of locale-dependent labels
- Replace custom submit button CSS with shared Button widget
- Add aria-hidden on decorative icons (sparkle, checkAll)
- Add role=status + aria-live=polite on success container
- Announce 'Response sent' via status() for screen readers
- Move focus to success container after submit
- Use --vscode-strokeThickness token for border widths
- Snap padding to spacing ramp (7px → 8px)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Fix responsive layout and accessibility
Responsive:
- Remove broken flex-wrap on segment control (caused 2x2+1 orphan grid)
- At narrow widths, segment stacks vertically (flex-direction: column)
with full-width items and proper border-radius per edge
- Segment labels get min-width: 0 + text-overflow: ellipsis so they
shrink gracefully in horizontal mode without wrapping
- Remove overflow: hidden from segment group (was clipping focus rings)
Accessibility:
- Add role=form + aria-label on the editor pane container
- Increase auto-close timeout to 5s (gives screen readers time to read)
- Add position: relative on focus-visible segments for z-index stacking
- Segment labels get explicit border-radius on first/last (no overflow
hidden needed)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Fix review findings: focus, URI, error handling, a11y
Engineering:
- Override focus() to move focus to first radio when survey opens
- Make resource URI dynamic (vscode-survey:/{surveyId}) to prevent
collisions across multiple survey definitions
- Guard closeEditor in auto-close timeout with .catch(onUnexpectedError)
Accessibility:
- Add aria-required=true on all radio groups
- Fix HC focus-visible vs checked outline conflict: checked uses 1px
solid contrastActiveBorder, focus-visible uses 2px dashed focusBorder
- Add completion hint ('Answer all questions to submit') with
aria-describedby on the submit button; hides once all answered
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* fix: prevent segment control wrapping with explicit flex-wrap: nowrap
Add position: relative to contain absolutely-positioned radio inputs,
and flex-wrap: nowrap to ensure 5 segment items always stay in a single
row at widths above the 600px container-query breakpoint.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* fix: list selection style, compact spacing, scroll visibility
- Remove one-sided border-radius + left-accent on selected list rows;
use full rectangular border matching VS Code's native list selection
- Reduce row padding (8px→6px), gap (4px→2px), question margin (24→20px)
and submit margin (28→20px) for a more compact layout
- Add 60px bottom padding to ensure the Submit button is always reachable
when scrolling
- Split container queries: segment stacks at 560px, list grid collapses
to single-column at 480px (was 600px for both — too aggressive)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Address review: accessibility help, design tokens, compact styling
- Add SurveyAccessibilityHelp with AccessibleViewProviderId.Survey and
AccessibilityVerbositySettingId.Survey for screen reader discovery
- Use var(--vscode-strokeThickness) for list-option border
- Use var(--vscode-codiconFontSize) + transform: scale(2) for success icon
- Reduce list-option padding to 6px 10px (on spacing ramp)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* feat: track source signal, programmatic command, structured telemetry
- Add 'source' field to SurveyEditorInput so the triggering feature
(completions, panel.agent, agent.codeEdit) is captured with the response
- Register '_workbench.action.openCopilotSurvey' command for the Copilot
extension to open the in-editor survey instead of external URL
- Restructure telemetry: extract pmfScore, primaryBenefit, primaryFriction
as top-level fields for direct Kusto querying (keep JSON blob for
forward-compat)
- Rename question IDs: main-benefit→primary-benefit, blockers→primary-friction
- Add pmfQuestionId to ISurveyDefinition schema
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* fix: pmfScore as numeric 0-4, update extension to open in-editor survey
- pmfScore is now a number (0=not at all, 4=extremely) with
isMeasurement:true for direct Kusto aggregation - no JSON blob
- Update Copilot SurveyService.promptSurvey() to call
'_workbench.action.openCopilotSurvey' command instead of opening
external URL - works in both main workbench and agent window
- Remove unused IAuthenticationService, IEnvService, SURVEY_URI from
SurveyService (no longer needed without external URL)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* fix: sanitize source arg, restore focus, handle singleton re-open
- Validate command source against allowlist (telemetry safety)
- Add runtime guard for dev command in stable builds
- Make SurveyEditorInput.source mutable via updateSource()
- Update existing input's source when singleton is re-opened
- Restore focus to survey pane when closing a11y help
- Await command execution in extension with error handling
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* generalize survey telemetry with telemetryKey mappings
Questions now declare their own telemetry field via telemetryKey and
asMeasurement properties. The pane iterates these at submit time
instead of hardcoding field names.
Telemetry fields:
- score (number): primary measure, option index
- primaryBenefit (string): value driver option ID
- primaryFriction (string): friction point option ID
- programmingExperience (number): experience bracket index
Added Q4: programming experience (5 brackets, 0-4 numeric measure).
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
---------
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* 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>