Skip to content

[pull] main from microsoft:main#1392

Merged
pull[bot] merged 39 commits into
KingDEV95:mainfrom
microsoft:main
May 7, 2026
Merged

[pull] main from microsoft:main#1392
pull[bot] merged 39 commits into
KingDEV95:mainfrom
microsoft:main

Conversation

@pull
Copy link
Copy Markdown

@pull pull Bot commented May 7, 2026

See Commits and Changes for more details.


Created by pull[bot] (v2.0.0-alpha.4)

Can you help keep this open source service alive? 💖 Please sponsor : )

bryanchen-d and others added 30 commits May 5, 2026 09:18
Wrap the user callback of DisposableResizeObserver with
scheduleAtNextAnimationFrame so layout writes done by the callback
(scanDomNode, KaTeX layout, height assignments, ...) land in the next
layout pass instead of re-entering the current one. Also coalesce
multiple deliveries within a frame into a single callback invocation.

This fixes the root cause of the "ResizeObserver loop completed with
undelivered notifications" warning that has been the top error bucket
since v1.106 (#293359 - 54M hits / 2.5M users). The warning is benign
on its own (Chromium just defers the leftover entries to the next
frame), but every occurrence costs an extra layout pass per frame on
the affected element. With chat streaming UI (thinking, tool
confirmations, plan review, KaTeX) all observing simultaneously, this
adds up to several extra layout passes per streamed token on slow
machines.

Also accept an optional targetWindow so observers created for elements
in an auxiliary window use that window's ResizeObserver constructor and
animation-frame timer.

Convert the three remaining raw `new ResizeObserver(...)` sites to use
the wrapper so they inherit the batching + disposable lifetime:
- chatMarkdownContentPart (KaTeX layout participants)
- chatTerminalToolProgressPart (terminal output resize)
- browserEditorFindFeature (find widget height tracking - now passes
  getWindow(container) to preserve aux-window correctness)

Refs #293359
Addresses Copilot review feedback on #314411 — covers rAF deferral, per-frame coalescing, cancel-on-dispose, and reschedule-after-frame.
Addresses @mjbvz review on #314411 — drops the global mutation and any-casts in the DisposableResizeObserver test suite by adding an optional resizeObserverCtor parameter (DI). Also addresses Copilot's coalescing finding: per-target latest-wins so consumers reading entries[0] always see the freshest size.
…tions

Records the rule that arose from review on #314411: don't mutate globals or use any-casts to install fakes in tests; inject the dependency via an optional constructor parameter.
…ution

Reverts the rAF deferral and per-frame coalescing introduced earlier in this PR. Behavior is now identical to the pre-PR sync wrapper, plus:

- targetWindow parameter (preserved) for aux-window correctness.

- try/catch around the user callback so a single bad consumer cannot kill delivery for every other observer in the realm.

- name + creationStack capture, plus a one-shot window 'error' listener that prints which DisposableResizeObservers' callbacks ran in the same task whenever the 'ResizeObserver loop completed with undelivered notifications' warning fires. The browser dispatches that warning as an ErrorEvent (not a thrown exception, error is null), so a try/catch around the callback cannot capture it; we use addEventListener('error', ...).

- resizeObserverCtor option for tests (DI seam, replaces global mutation in the test suite).
…r name

Replace the previous suspect-set + window error listener attribution with
a simpler design:

- DisposableResizeObserver now takes a required `name: string` as its first
  constructor parameter. Drop the per-instance creation stack capture
  (callstacks change across releases and bloat telemetry).
- Track the most recently invoked observer in a module-level slot and
  expose `getRecentDisposableResizeObserverAttributionForLoopError(msg)`
  which, for the stackless `ResizeObserver loop completed with undelivered
  notifications` warning, returns
  `[DisposableResizeObserver(<name>)] <msg>`.
- Browser ErrorTelemetry uses the helper to prefix both `msg` and
  `callstack` so the telemetry bucket carries the offending observer's
  name instead of just the generic warning.
- Name all 17 production sites with `<ClassName>.<purpose>` (e.g.
  ChatListItemRenderer.itemHeight, ChatInputPart.containerHeight).

Refs #293359.
…microtask

The slot is set just before the user callback runs and cleared by a microtask in the same step, so the attribution helper only returns a name when the loop warning fires in the same task as the offending observer's callback. Unrelated errors fired later in the renderer no longer inherit a stale observer name.
chat: add copy microinteraction to code blocks (#314490)

Reuse the existing chat copy action view item for code block toolbars so the copy button shows the same copy-to-check transition, tooltip, ARIA label, and clipboard announcement as response copy actions.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…setTimeout(0)

queueMicrotask clears the slot too eagerly: Chromium runs a microtask checkpoint after each ResizeObserver callback returns, which is *before* the synthetic 'ResizeObserver loop completed with undelivered notifications' error fires at the end of the observation phase. A 0-ms timer runs after the entire current task (callbacks + loop-error dispatch) completes, so the slot is still set when window.onerror picks it up, while still being cleared before any unrelated error in the next task can inherit a stale name. Verified by hand in Code-OSS DevTools.
…-batch

dom: attribute ResizeObserver loop telemetry to DisposableResizeObserver name
Add logging for unexpected InstancePolicy.prompt in sessions window
* Discover plugins installed by Copilot CLI (#302152)

Adds `CopilotCliAgentPluginDiscovery` which scans
`~/.copilot/installed-plugins/<marketplace>/< the two-levelplugin>/`
directory layout used by the Copilot  and surfaces each leafCLI
directory as an `IAgentPlugin`, so CLI-installed plugins appear in VS
Code without a separate install step.

File watchers are set up on the root and each marketplace bucket so
installs and uninstalls made via the CLI are reflected live.

The remove() action prompts the user before deleting the directory
from disk, since the CLI manages this location.

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

* Address PR review feedback

- Watch the deepest existing ancestor of installed-plugins so the
  first-ever CLI install is detected without a reload (non-recursive
  Node watchers fail on ENOENT).
- Use trash on UI-driven plugin removal and update the prompt detail
  to say so.
- Wrap the recursive setupWatchers() call inside the change handler
  with a .catch() to keep watcher setup best-effort.
- Update AGENTS_PLUGINS.md to accurately describe the (non-recursive)
  watcher strategy.

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

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
NODE_OPTIONS can be used to inject arbitrary flags (--require, --inspect, etc.)
into forked Node processes, which can cause crashes and unexpected behavior in
the extension host and other forked processes.

Co-authored-by: Megan Rogge <meganrogge@Megans-MacBook-Pro.local>
)

* Fix stale OSC 8 link hover tooltip when mouse cursor unhovers before trigger

* Dismiss hover tooltip on leave/scroll

* Address feedback from Copilot

* Refactor and fix tests
…314822)

* chat: use ILabelService for remote agent host names in permission UI

`AgentHostPermissionUiContribution` is registered for VS Code proper, but in VS Code we cannot
depend directly on `IRemoteAgentHostService` since that service is only registered in the Agents
window / sessions layer. Route the human-readable host name lookup through `ILabelService`
instead.

- `RemoteAgentHostService` now registers a per-host `ResourceLabelFormatter` for the
  `vscode-agent-host` scheme, with the entry name as the formatter's `workspaceSuffix`. The
  formatter is refreshed on entry add / name change and disposed on removal.
- `AgentHostPermissionUiContribution` drops the `IRemoteAgentHostService` dependency and
  resolves the host name via `ILabelService.getHostLabel(AGENT_HOST_SCHEME,
  agentHostAuthority(address))`, falling back to the raw address when no formatter is
  registered (e.g. in regular VS Code workbench).
- Updates the contribution and service tests accordingly.

(Commit message generated by Copilot)

* address review feedback
* sessions: retain attached editor maximize state

Remember the maximized state of main editors that are reopened from the auxiliary-bar-attached flow so closing and reopening an embedded editor preserves its layout.

Keep modal editor flows unchanged and document the behavior in the sessions layout spec.

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

* sessions: clear attached editor restore on aux hide

Cancel the remembered attached-editor maximize restore when the auxiliary bar is hidden and add regression coverage for hiding and showing the bar before the next editor reopen.

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

* Potential fix for pull request finding

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

---------

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

Co-authored-by: Copilot <copilot@github.com>
* agent-host: restore selected model in picker

Use session state as the source of truth for existing agent host sessions, while keeping resource-scheme-scoped storage as the view-state fallback for new untitled sessions. (Written by Copilot)

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

* agent-host: track status for model picker restore

Recompute Agent Host model picker state when the active session status changes so storage fallback is only used while a session is untitled. (Written by Copilot)

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

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Fixes tool invocation permalinks in MCP by using chatStreamToolCallId
  when available, with a fallback to callId for backward compatibility
- Ensures tool results in chat responses are correctly linked to their
  stream tool call context

Fixes #314706

(Commit message generated by Copilot)
dmitrivMS and others added 9 commits May 6, 2026 16:02
* Fix loc files encoding

* Address review feedback: strip duplicate BOM and fix Hungarian disk-space key

* Remove unused codePage / InnoSetup config from i18n pipeline

* Strip leading BOM in TextModel so .isl parsing is BOM-tolerant
adding request.options.tools event to 3p
* Implement Pull Request state for Agent Host sessions

Adds an Open Pull Request button + live PR/CI state for Agent Host
sessions, mirroring what already works for Extension Host CLI sessions.

Server-side (platform/agentHost):
- Extend ISessionGitState with githubOwner/githubRepo
- agentHostGitService parses 'git remote -v' (preferring origin, falling
  back to first GitHub remote) and writes {owner, repo} to _meta.git
  alongside the existing branch/upstream/changes data
- Handles SCP-like (git@github.com:o/r), https://, and ssh:// remotes

Client-side (sessions/contrib):
- IGitHubService.findPullRequestNumberByHeadBranch(owner, repo, branch)
  uses GET /repos/{o}/{r}/pulls?head={o}:{branch}&state=all to find the
  most recently updated PR for a head branch; cached in-memory per key
- AgentHostSessionAdapter.gitHubInfo is now a derived chain:
    _meta.git -> {owner, repo, branch} -> PR number lookup -> IGitHubInfo
  with live PR icon refresh via createPullRequestModelReference +
  computePullRequestIcon
- Thread IGitHubService through local + remote agent-host providers

Result: the existing OpenPullRequestAction (gated by
ActiveSessionContextKeys.HasPullRequest) now lights up automatically once
the session's branch has a PR on GitHub, with the live status icon.

Tests: extends agentHostGitService.test.ts with a parseGitHubRepoFromRemote
suite covering ssh, https, ssh://, origin-preferred, fallback-to-non-origin,
empty input, and non-GitHub remotes.

(Written by Copilot)

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

* Address PR review feedback

- githubService: don't cache transient failures or undefined PR lookups
  so a later retry succeeds once a PR is created. Successful numeric
  results are still cached indefinitely (PR number is monotonic).
- sessionState: clarify githubOwner/githubRepo doc comments to reflect
  actual fallback behavior (origin-preferred, otherwise first GitHub
  remote).
- Stub IGitHubService in localAgentHostSessionsProvider and
  remoteAgentHostSessionsProvider tests.

(Written by Copilot)

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

* Hide Sync PR button when there's nothing to sync

When the working tree is fully in sync with the open PR, the
'Sync Pull Request' primary button was still shown alongside
'Mark as Done', resulting in two competing primary buttons in the
changes view toolbar.

Match the EH CLI guard: only show 'Sync Pull Request' when there are
incoming, outgoing, or uncommitted changes. This is mutually exclusive
with 'Mark as Done' (which requires no such changes).

(Written by Copilot)

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

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* sessions: match panel tabs to auxiliary bar

Reuse the same title-tab treatment for the sessions panel that the Changes/Files tabs already use in the auxiliary bar. This removes the persistent active underline, switches labels to sentence case, tightens the pill spacing, and bumps the label weight to 500.

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

* sessions: correct panel tab casing docs

Update the sessions layout spec to describe the existing panel and auxiliary bar tab labels as title case.

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

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…e-land) (#314533)

* agentHost/claude: post-Phase-4 cleanup

- roadmap.md: mark Phase 4 as DONE, link merged PR #313780.
- phase4-plan.md: record live-system smoke completion in §7.8;
  disabled-gate run skipped (covered by unit tests + env-var guard).
- claudeAgent.test.ts: drop gratuitous 'as unknown as' cast in the
  CCAModel fixture (literal already matches CCAModelBilling exactly;
  plan §7.4 forbids unsafe casts in tests).

* agentHost/claude: lock Phase 5 implementation plan

Handoff plan for Phase 5 (replace 7 throwing stubs in claudeAgent.ts).
Locked against post-PR-#313841 reality (provisional sessions,
onDidMaterializeSession, 30s empty-session GC) and the IAgent contract
on origin/main.

Decisions captured:
- Non-fork createSession is synchronous and in-memory; fork deferred
  to Phase 6 (throws TODO).
- IClaudeAgentSdkService surface mirrors IAgent (no dir parameter on
  listSessions); SDK loader caches resolved module, retries on
  failure, logs once.
- listSessions joins SDK enumeration with workbench session DB
  metadata via ISessionDataService; per-entry try/catch resilience.
- shutdown() routes per-session teardown through the same
  SequencerByKey<string> used by disposeSession() so concurrent
  shutdown/disposeSession cannot double-dispose a wrapper in Phase 6.
- 14 unit tests defined (12 lifecycle + 2 resolved-config), including
  log-once contract and shutdown/disposeSession race guard.

* agentHost/claude: Phase 5 — IAgent provider skeleton

Lands the ClaudeAgent IAgent provider behind the
'chat.agentHost.claudeAgent.enabled' setting (env gate
VSCODE_AGENT_HOST_ENABLE_CLAUDE=1). Pins
@anthropic-ai/claude-agent-sdk@0.2.112 in workspace + remote/.

Implemented in this phase:
* createSession - non-fork, in-memory wrapper only. Honors
  config.session for restore. The fork path and SDK session
  creation are deferred to Phase 6.
* listSessions - SDK is source of truth; per-session DB read
  is a best-effort overlay (failure never excludes an entry).
* disposeSession / shutdown - routed through a per-session
  SequencerByKey to serialize teardown.
* getDescriptor, getProtectedResources, models,
  onDidSessionProgress, setClientCustomizations,
  setClientTools, onClientToolCallComplete,
  setCustomizationEnabled, authenticate, respondTo*Request -
  minimal Phase-5 wiring.

Stubbed for Phase 6 (throw async 'TODO: Phase 6'):
sendMessage, abortSession, changeModel, getSessionMessages,
plus the createSession fork path.

Tests: 29 unit tests in claudeAgent.test.ts cover the
createSession restore-id path, listSessions overlay resilience,
dispose serialization, and stub surfaces.

Note: provisional / onDidMaterializeSession is intentionally
omitted in Phase 5 (see plan section 3.3.1) - the workbench needs
an immediate sessionAdded until the agent has real materialization
work, which arrives in Phase 6 alongside SDK query() startup.

* agentHost/claude: Phase 6 — sendMessage, single-turn, no tools

Implements the Phase 6 plan: provisional sessions materialize on first sendMessage, route a single-turn prompt through the Anthropic Claude Agent SDK's WarmQuery, and stream SDKMessages back as protocol AgentSignals via a pure mapSDKMessageToAgentSignals reducer.

Tools remain denied (canUseTool: 'deny'); fork moves to Phase 6.5; Plan Mode UI moves to Phase 7.

Highlights:

- ClaudeAgent.sendMessage routes through _sessionSequencer to collapse concurrent first sends into one materialize + N ordered sends.

- _materializeProvisional has two abort gates (post-startup + post-customizationDirectory write) so disposeSession landing mid-materialize cannot leak a WarmQuery subprocess.

- ClaudeAgentSession owns the prompt iterator + per-turn deferreds; mapSDKMessageToAgentSignals is a pure reducer with state owned by the session.

- IClaudeAgentSdkService gains startup() alongside listSessions().

Tests: 43 unit + 2 proxy-backed integration. Council-review fixes (C1 dispose race, C2 missing integration test, S1 cwd-less ratification) included.

* agentHost/claude: address PR review (listSessions resilience, dispose abort)

Two Copilot-reviewer comments on #314216:

1. listSessions: wrap _sdkService.listSessions() in try/catch. AgentService.listSessions fans out across providers via Promise.all; an SDK dynamic-import failure would otherwise nuke every other provider's session list. Now logs and returns [].

2. dispose: abort _provisionalSessions AbortControllers before super.dispose(). Previously a racing first sendMessage parked inside _writeCustomizationDirectory could pass the materialize abort gates and call _sessions.set on a disposed DisposableMap, orphaning the WarmQuery. Aborting first triggers the existing post-customization-write abort gate, which asyncDisposes the WarmQuery.

Tests: 2 new regressions (listSessions empty on SDK throw; agent.dispose() during racing materialize disposes the WarmQuery). 45/45 unit + 2/2 integration pass.

* Drop stale @anthropic-ai/sandbox-runtime dep from merge resolution

* Bump @anthropic-ai/claude-agent-sdk 0.2.112 → 0.2.128

The new SDK no longer vendors native binaries inside the main package.
It now ships a ~200MB `claude` executable per platform via 8 optional
platform-specific packages, mirroring the @github/copilot pattern:

  @anthropic-ai/claude-agent-sdk-{darwin,win32}-{x64,arm64}
  @anthropic-ai/claude-agent-sdk-linux-{x64,arm64}{,-musl}

The SDK loader picks the right package at runtime via process.platform
/process.arch (and tries -musl first on linux).

To strip off-target packages from the build output:
- build/lib/claudeAgentSdk.ts mirrors build/lib/copilot.ts
- gulpfile.vscode.ts and gulpfile.reh.ts apply the filter alongside
  the existing copilot one
- gulpfile.vscode.ts asar-unpacks @anthropic-ai/claude-agent-sdk-* so
  the executable stays on disk (asar would break exec permissions)
- alpine-{arch} maps to linux-{arch}-musl (claude is statically linked
  against libc and must match the host)

cglicenses.json gets 8 new entries mirroring the parent SDK's
"© Anthropic PBC. All rights reserved." text.

The new SDK Query interface adds a `readFile` method; FakeQuery and
RoundTripQuery test doubles get matching stubs.

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

* build: cross-copy @anthropic-ai/claude-agent-sdk darwin packages for universal app

Mirror the existing @github/copilot pattern in create-universal-app.ts.
Each darwin arch build only contains its own platform package (npm only
installs the optionalDependency matching the host CPU), so the universal
merger fails with files unique to one side.

Cross-copy node_modules/@anthropic-ai/claude-agent-sdk-{darwin-x64,darwin-arm64}/
between the two builds, skip them from the equality comparison, and tag
the per-arch `claude` executable as arch-specific so the merger keeps both.

Also extend verify-macho's skip list to ignore the single-arch `claude`
binaries inside the universal app.

* agentHost/claude: address PR review

- claudeAgent: rewrite `rgPath` from node_modules.asar →
  node_modules.asar.unpacked before putting it on the Claude subprocess
  PATH. Mirrors copilotAgent.ts and the workbench search engine helpers;
  without this, packaged builds advertise a path that doesn't exist on
  disk.
- cglicenses.json: add "// Reason: …" justification comments to the
  parent @anthropic-ai/claude-agent-sdk entry and each of the 8 new
  platform sub-packages, matching the file's convention.

* build: bump DMG volume size from 1g to 2g

The universal macOS app now carries platform-specific binaries for both
x64 and arm64 — @github/copilot-darwin-* (~128MB each) and the new
@anthropic-ai/claude-agent-sdk-darwin-* (~207MB each) — so the source
filesystem the DMG is built from has crossed 1GB. dmgbuild fails with
`No space left on device` when ditto can't fit the app inside the
volume.

Output DMG is LZMA-compressed (format = 'ULMO') so this only changes
the build-time staging size, not the shipped artifact size.

* agentHost/claude: don't bundle claude-agent-sdk; load it from a user-specified path

Move `@anthropic-ai/claude-agent-sdk` from `dependencies` to
`devDependencies` so the ~200MB-per-arch platform binaries are no longer
shipped with VS Code. The SDK becomes opt-in and externally-installed.

User-facing surface:
  - Replace boolean setting `chat.agentHost.claudeAgent.enabled` with
    string setting `chat.agentHost.claudeAgent.path`. When the setting
    is non-empty, the Claude provider registers; when empty (the default),
    it does not.
  - The setting value is forwarded to the agent host via the
    `VSCODE_AGENT_HOST_CLAUDE_SDK_PATH` env var (replacing the previous
    `VSCODE_AGENT_HOST_ENABLE_CLAUDE` flag).
  - `agentHostServerMain` exposes a `--claude-sdk-path <path>` CLI flag
    in place of the previous `--enable-claude-agent` flag.

Runtime loader:
  - `ClaudeAgentSdkService._loadSdk()` now reads the env var and
    dynamic-imports from there. If the path is a directory, the package's
    main entry is resolved from `package.json` (`exports['.']` /
    `main`) before the import — Node ESM does not support directory
    imports of `file://` URLs.

Build/packaging cleanup (no longer needed once the SDK is gone from
production deps):
  - Drop `build/lib/claudeAgentSdk.ts` and its callers in
    `gulpfile.{vscode,reh}.ts`.
  - Drop the `@anthropic-ai/claude-agent-sdk-*` glob from the
    asar-unpack list in `gulpfile.vscode.ts`.
  - Revert universal-app cross-copy + filesToSkip + x64ArchFiles entries
    in `build/darwin/create-universal-app.ts` and the corresponding
    skip patterns in `build/darwin/verify-macho.ts`.
  - Revert DMG volume size from 2g back to 1g in
    `build/darwin/dmg-settings.py.template` (was bumped earlier in
    this branch to fit the bundled SDK; no longer needed).
  - Remove the 9 `@anthropic-ai/claude-agent-sdk*` entries from
    `cglicenses.json` (no longer shipped, no manifest to license).

Type imports of `@anthropic-ai/claude-agent-sdk` continue to work via
the devDependency, so source code that does `import type` from the
package still typechecks.

* revert cglicenses change

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Agent host: prefer origin/<default> for worktree base

Match the extension-host CLI behaviour of preferring the remote-tracking
ref over a possibly-stale local branch when picking the worktree start
point, and pass --no-track to git worktree add so the new agent branch
does not pick up upstream tracking from the start point.

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

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@pull pull Bot locked and limited conversation to collaborators May 7, 2026
@pull pull Bot added the ⤵️ pull label May 7, 2026
@pull pull Bot merged commit 2c6eb47 into KingDEV95:main May 7, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.