* feat(agentHost): add multi-root support for Claude agent sessions
- Introduced `AgentHostClaudeMultiRootEnabledSettingId` to enable multi-root capabilities for Claude agent-host sessions.
- Updated configuration schema to include `multiRootEnabled` setting for Claude agent.
- Enhanced `ClaudeAgent` to advertise `multipleWorkingDirectories` capability based on the new setting.
- Modified session handling to support additional working directories, allowing sessions to span multiple directories.
- Implemented persistence of additional directories in session metadata for cold resumes and forks.
- Added tests to verify the correct behavior of multi-root functionality, including session creation, metadata handling, and SDK options projection.
* test: add test for session creation with fork that inherits working directories
* agents: restore message timestamps from persisted agent transcripts
Chat request/response timestamps disappeared after restarting the client because the Copilot and Codex history replay mappers dropped turn timing when rebuilding sessions from persisted transcripts.
Restore Turn.startedAt/duration in both mappers: the Copilot mapper now reads the ISO timestamp from the SDK session event envelopes, and the Codex mapper derives timing from the persisted thread turns.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* agents: bound replayed turn duration by the turn's own events
Address PR review feedback: track the last event timestamp per turn builder instead of using the globally previous/current envelope timestamp, so events outside the turn (for example an ignored notification long after assistant.turn_end) no longer inflate its duration. Also shorten the new helper comments to one line.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
---------
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* fix: signature help active overload not updating
- Active overload now updates when typed arguments narrow the overload set
* fix: replace findIndex with direct index lookup in getActiveSignature
- Instead of searching signatures by label to get an index and comparing
it to info.selectedItemIndex, look up signatures[info.selectedItemIndex]
directly so both sides of the comparison use the same index source
* test: add unit tests for #268728 overload fix
- Extract getActiveSignature as an exported function so unit
tests can import it without the extension host
- Add BEFORE suite documenting the original bug: on retrigger,
old code returned the stale overload index even after
TypeScript updated selectedItemIndex (e.g. after a string
argument narrows the overload set on the comma trigger)
- Add AFTER suite verifying the fix: retrigger now honours
TypeScript's updated selectedItemIndex; the BUG test case
that returned 0 now correctly returns 1
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix: address Copilot review on #268728
- Rename exported helper to computeActiveSignatureIndex to
avoid identifier collision with the private method
- Stop returning activeSignatureHelp.activeSignature: that
index refers to the previous signature list, which is stale
if the list reorders between invocations; always use
tsSelectedItemIndex instead
- Add regression test for the reordering case: verifies that
when the list reorders and TS still selects the same overload
by label, the current index is returned, not the stale one
* fix: address Copilot review on #268728
- Simplify computeActiveSignatureIndex to only accept
tsSelectedItemIndex; the context and signatures params
were unused and made the API misleading
- Add @internal JSDoc to signal the
computeActiveSignatureIndex export is for unit
testing only, not public API
- Replace assertion-based BEFORE suite with block comment
documenting the original bug; asserting known-wrong
behaviour institutionalizes incorrect expectations
* fix: simplify active overload selection
- Replace the label-matching retrigger guard with result.activeSignature = info.selectedItemIndex;
the guard became a no-op after the existingIndex === selectedItemIndex fix and its removal is the correct minimal change
- Export TypeScriptSignatureHelpProvider as _TypeScriptSignatureHelpProvider
(VS Code underscore-prefix convention for test-only exports)
- Add unit tests via mock ITypeScriptServiceClient: documents the old buggy guard behavior
and verifies the fix — the FIX test would fail if the label-matching guard were reintroduced
* fix: address Copilot unit test review comments
- Move CancellationTokenSource into setup/teardown so it is properly disposed after each test
- Add success: true and message: '' to mock response to match the protocol shape
- Add @internal test-only export JSDoc to _TypeScriptSignatureHelpProvider to make the export intent explicit
* Fix signature help overload selection
Track TypeScript-selected and user-selected overloads separately so retriggers follow updated recommendations without resetting manual selections.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
---------
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-authored-by: Dmitriy Vasyura <dmitriv@microsoft.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* added classification comments for response events
* Classify forwarded Copilot identifiers as pseudonymous
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* agentHost: Emit toolCallDetails telemetry
Preserve the local per-turn tool-call aggregate on the Microsoft telemetry channel while retaining the restricted peer events. Include Agent Host correlation fields and report successful, cancelled, and failed turns once.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* agentHost: Report tool-call details before steering
Reuse the normal turn completion path when steering preempts a turn so its telemetry aggregate is emitted before state resets.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
---------
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* fix: remove all manual folding ranges when selection is empty
When editor.removeManualFoldingRanges is invoked with an empty selection
(just a cursor, no text selected), remove all manual folding ranges in
the document instead of only removing ranges intersecting the cursor
line. This makes it easy to clear broken manual folding ranges without
having to select all text first.
When text is explicitly selected, the existing behavior of only removing
manual ranges intersecting the selection is preserved.
Closes#266597
* fix: combine innermost removal with full-range fallback
When cursor is on a manual folding range, remove only the innermost one.
When cursor is NOT on any manual range, remove all manual ranges.
This addresses both #266597 and #212599 in a single approach.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* refactor: move cursor-aware logic into removeManualRanges
Address review feedback: move the "find innermost manual range at cursor,
or remove all" logic from RemoveFoldRangeFromSelectionAction.invoke()
into FoldingModel.removeManualRanges(), since that action is the only
caller. The action now simply passes raw selection ranges as before.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* test: add tests for removeManualRanges cursor behavior
Tests cover three scenarios:
- Cursor on a manual range removes only the innermost manual range
- Cursor not on any manual range removes all manual ranges
- Selection range removes only intersecting manual ranges
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix manual folding range removal
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* test manual folding range edge cases
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-authored-by: Martin Aeschlimann <martinae@microsoft.com>
Co-authored-by: Dmitriy Vasyura <dmitriv@microsoft.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* fix: send chat image attachments when signed out of GitHub
Image attachments were silently dropped for signed-out users even when a
vision-capable BYOK/local model was configured. The panel Image prompt
element gated image inclusion on
`copilotToken?.isEditorPreviewFeaturesEnabled()`, which is `undefined`
when there is no Copilot token (i.e. not signed in), so the negation
evaluated truthy and the image was omitted before the request was sent.
`isEditorPreviewFeaturesEnabled()` represents an org policy that is only
meaningful when a Copilot token exists; a missing token should not block
the feature. Default the check to enabled when the token is absent, using
the same `?? true` pattern already used in
claudeChatSessionContentProvider. This preserves the org-policy behavior
(explicit `editor_preview_features=0` still omits images) while letting
signed-out / BYOK users send images to vision-capable models.
Applied to both HistoricalImage and Image render paths, and added unit
tests covering signed-out, signed-in, org-policy-disabled, and
non-vision-model cases.
Fixes#323854
Co-authored-by: SamirSaji <samirsaji13@gmail.com>
* fix: report accurate omission reason for policy-blocked images
Address review feedback: when a vision-capable model has images omitted
because org policy disables editor preview features, the omitted-reference
status previously said the model "does not support images", which is
misleading. Set the status description based on the actual cause
(lack of vision vs. org policy). The catch/error path keeps the generic
message.
Co-authored-by: SamirSaji <samirsaji13@gmail.com>
---------
Co-authored-by: SamirSaji <samirsaji13@gmail.com>
Co-authored-by: Dmitriy Vasyura <dmitriv@microsoft.com>
* fix(server): propagate --enable-proposed-api in serve-web
The `code serve-web` CLI accepts `--enable-proposed-api EXTENSION_ID`
but never propagated the allowlist to the workbench environment service
or the server-side extension scanner. As a result, extensions declaring
`enabledApiProposals` in their package.json had their proposals wiped
at runtime by ExtensionsProposedApi and failed to activate.
This wires the flag through two paths so it matches desktop behavior:
1. Server scanner: extend IProductService.extensionsEnabledWithApiProposalVersion
in setupServerServices so the node extension scanner keeps the manifest's
enabledApiProposals when --enable-proposed-api is passed.
2. Workbench env service: add a new `enabledExtensionProposedApi` field to
IWorkbenchConstructionOptions, populate it from the CLI args in
webClientServer, and surface it via BrowserWorkbenchEnvironmentService
.extensionEnabledProposedApi so the runtime allowlist in
ExtensionsProposedApi matches the requested IDs.
Fixes#228781
* cli: forward --enable-proposed-api to serve-web subprocess
The Rust CLI parses --enable-proposed-api as a global EditorOptions flag
but was not forwarding it to the node server subprocess spawned by
serve-web. As a result, the flag never reached the server's argv parser
and the server-side plumbing in serverServices.ts and webClientServer.ts
had no input to act on.
Capture the flag in ConnectionManager from CommandContext and pass it
through StartArgs, then append --enable-proposed-api=<id> for each
requested extension ID when spawning the server process.
* fix(server): update proposed API propagation
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
---------
Co-authored-by: Martin Aeschlimann <martinae@microsoft.com>
Co-authored-by: Dmitriy Vasyura <dmitriv@microsoft.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Remove the minimum-height filler from the latest chat response and clean up the related layout state, option plumbing, CSS, and component fixture.\n\n(Written by Copilot)\n\nCo-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
During _onProcessExit → dispose(), the _onDisposed event fires before
super.dispose() is called, so isDisposed is still false. Event listeners
triggered during _onDisposed can reach setVisible → _resize →
_updatePtyDimensions, which accesses xterm's dimensions getter. The
getter throws because xterm's internal renderer is in a bad state during
the disposal process.
Add a _isDisposing flag set at the start of dispose() and check it in
_resize() to prevent resize operations during the entire disposal
process, not just after it completes.
Co-authored-by: vs-code-engineering[bot] <122617954+vs-code-engineering[bot]@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: rzhao271 <7199958+rzhao271@users.noreply.github.com>
Co-authored-by: Dmitriy Vasyura <dmitriv@microsoft.com>
* Fix validation error on JavaScript block comment with arrow in HTML script
* Add test suite
* html: handle multiple inline HTML comments
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
---------
Co-authored-by: Dmitriy Vasyura <dmitriv@microsoft.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* agentHost: cover the client-hosted filesystem end to end
The resource* family was the largest contract gap the protocol-surface
coverage surfaced: ten of the fourteen uncovered commands were filesystem
operations, tested only in the frozen protocol suite, which side-loads a mock
agent and so cannot describe the contract for a different AHP implementation.
Adds a conformance suite covering both directions. Client to server is the
command surface the host executes against its own filesystem. Server to client
is the reverse direction, where the host addresses client-side files through
the vscode-agent-client scheme and asks the connected client for them - a
configuration nothing in the E2E suite previously reached.
The reverse direction is driven by a real host feature rather than a synthetic
call: a client publishes a plugin customization, and the host materializes it
by copying the directory out of the client. TestProtocolClient now records the
reverse requests it serves, so the test asserts the host actually reached back
rather than resolving the path locally, and asserts the resulting load state -
the customization notification fires on both the success and failure paths, so
without it a sync that reads and then fails would still look green.
Protocol-surface command coverage moves from 15/29 (51.7%) to 25/29 (86.2%).
(Written by Copilot)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* agentHost: address filesystem coverage review feedback (Written by Copilot)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* agentHost: compare reverse-request paths through URI on both sides
The Windows E2E leg failed on the client-hosted plugin test. The host had in
fact reached back to the client - the log shows resourceResolve, resourceList
and a resourceRead of plugin.json - but the assertion did not recognize them.
The filter compared `URI.parse(uri).fsPath` against the raw `pluginRoot`, and
`fsPath` lower-cases the Windows drive letter: a served `file:///c%3A/...`
never matches a root of `C:\...`. Both sides now go through `URI`, so they
are normalized identically on whichever platform the test runs.
Introduced by the earlier review fix that replaced a substring match with a
path comparison; the substring version happened not to hit this.
(Written by Copilot)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
---------
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* updates
* agent host: sync user customizations to remote hosts
- Remote Agent Hosts discover the remote home rather than the client's, so
forward enabled user agents, skills, instructions, and prompts.
- Keep local Agent Hosts on native discovery to avoid duplicating same-machine
customizations.
- Preserve per-file opt-out and client-origin grouping for recovered user
customizations.
Fixes#327754
(Commit message generated by Copilot)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
---------
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Initial plan
* Stop dictation via toggle of start command; remove Escape keybinding
Co-authored-by: meganrogge <29464607+meganrogge@users.noreply.github.com>
* Potential fix for pull request finding
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
* Potential fix for pull request finding
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
* Add dictation help text to editor and terminal accessibility help dialogs
- Add `AccessibilityHelpNLS.editorDictation` string to standaloneStrings.ts
with keybinding reference to workbench.action.editorDictation.start
- Update editorAccessibilityHelp.ts to surface dictation start/stop toggle
help text when speech is available (HasSpeechProvider or built-in engine)
- Update terminalAccessibilityHelp.ts to document that
workbench.action.terminal.startVoice starts and stops dictation
Co-authored-by: meganrogge <29464607+meganrogge@users.noreply.github.com>
---------
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: meganrogge <29464607+meganrogge@users.noreply.github.com>
Co-authored-by: Megan Rogge <merogge@microsoft.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
- Resolves the selected response from the text nodes that actually
contribute characters rather than the raw anchor/focus nodes. Browsers
park a line selection's endpoint at offset 0 of the *next* block, which
for the last line of a response lands outside the markdown part
entirely, so a triple-click (the natural way to select a whole line)
looked like an out-of-scope selection and dismissed the widget.
- Paints the captured range with a CSS custom highlight once the native
selection is gone. Focusing the textarea collapses the document
selection as a browser side effect, so the text the question is about
visually disappeared the moment the user clicked in to type it.
- Sources the highlight color from a theming participant instead of a
stylesheet, because highlight pseudo-elements only inherit custom
properties from the root element and cannot see the `--vscode-*`
variables scoped to `.monaco-workbench`.
- Positions the widget from the range's visible line boxes, so the empty
box a line selection leaves in the following block no longer pushes it
a line too low.
Fixes#327706Fixes#327707
(Commit message generated by Copilot)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>