[pull] main from microsoft:main#1372
Merged
Merged
Conversation
We shouldn't look at the scheme directly
These belong to a follow up PR
Doesn't work 100% nicely as once toggled back it switch back to the normal inline editor instead of back to the side by side diff view. Will follow up Co-authored-by: Copilot <copilot@github.com>
Use backticks for proper template literal interpolation of ${ToolName.ReadFile}.
Fix duplicate 'and and' → 'and'.
Import ToolName from registry so message stays in sync if tool name changes.
Addresses Copilot AI review feedback: keeps tool name in sync with registry.
* Add Cache Explorer view to chat debug panel
Add a new "Cache Explorer" entry under "Explore Trace Data" in the
chat debug overview. The view helps diagnose prompt-cache misses by
diffing two model-turn requests side by side.
The pure diff engine (chatDebugCacheDiff.ts) parses the input messages
JSON exposed via IChatDebugEventModelTurnContent.sections, normalizes
each message to {role, name, text, byteLength}, and produces a per-
position signature of the prompt prefix. The first position whose role,
length, or content diverges is reported as the cache break — anything
after that point cannot be served from the prompt cache.
The view (chatDebugCacheExplorerView.ts) lays out a left rail of model
turns annotated with cache hit %, A/B summary cards, the prompt
signature with the break marker, and a Components accordion that diffs
the system prompt and any divergent messages.
Sequential pairing is the default (B = current selection, A = previous
turn); click in the rail to set B and shift-click to set A. The diff
engine ships with 10 unit tests in chatDebugCacheDiff.test.ts.
* Cache Explorer iteration: rail groups, OTel-backed metrics, prompt signature bars
Iterate on the Cache Explorer view added earlier on this branch:
- Left rail groups model turns by parent request and shows the user
prompt as the group header. Group rows are collapsible and the full
request id is shown in the header.
- Each rail row reports agent source, cache hit %, duration, and time
for the turn; rows with hit < 90% render the chip in red.
- Single-selection model: clicking a row sets it as the current request
and the row above is implicitly the previous one to diff against.
- Producer plumbing: the file logger now persists copilot_chat.debug_name
and gen_ai.response.id alongside the model-turn entry, and the
modelTurn content carries a requestId. The summary card surfaces the
full network requestId so it can be copied.
- Replaced the chip-style prompt signature with a horizontal role-
colored bar visualization showing both requests on a shared scale,
with a vertical break marker at the divergence index.
- Cache performance card replaces the pill row with a structured
layout: cache hit headline + token reuse, where the cache broke +
estimated lost tokens, and a one-line diff summary.
- Component diff and signature lanes use Previous/Current labels
instead of A/B.
Refs #313608
* Cache Explorer: char-level inline diff in Components accordion
Replace the plain-text body of each Components row with a side-by-side
line + character diff rendered directly into HTML. Uses the existing
linesDiffComputers.getDefault().computeDiff() that Monaco's diff editor
also uses internally; ignoreTrimWhitespace stays off so cache-relevant
whitespace is visible.
- Each line is emitted as a div with one of three classes `context`,
`add`, `remove` for full-line styling.
- Inner range mappings produce char-level <span> highlights inside
added or removed lines.
- Multi-line inner range mappings are skipped for v1; the surrounding
add/remove styling already conveys the change.
- Bounded by maxComputationTimeMs=200 so a stray giant tool-result
diff cannot stall the renderer.
No widget, no editor instance, no layout calls; replaces the existing
two raw <div> bodies with a directly-styled HTML diff.
Refs #313620
* Cache Explorer: extract text from tool_call_response and tool_call parts
The OTel input messages format wraps tool I/O as part-level objects,
not as top-level text:
- A user/tool message that returns tool output uses
{ type: 'tool_call_response', id, response: '...' }
- An assistant message that invokes a tool uses
{ type: 'tool_call', id, name, arguments: {...} }
Until now parseInputMessages only counted parts with type === 'text',
so these messages showed up as zero-byte slots in the diff with both
sides labeled '(not present)' \u2014 confusing because tool I/O is the
single most cache-relevant content in an agentic loop.
This change pulls the response payload out of tool_call_response (and
the tool name + arguments out of tool_call) and includes them in the
normalized text we diff against. We also reclassify the row's display
role to 'tool' when the message is dominated by a tool result so the
rail / signature / accordion label it consistently.
Two new unit tests pin the extraction behaviour.
Refs #313620
* Cache Explorer: track request options + likely cache expiration
Prompt caches invalidate on more than just message-array changes \u2014
flipping tool_choice, raising reasoning_effort, switching to Claude
extended thinking, or changing the response_format all bust the cache
even when the prompt prefix is byte-identical. Surface those changes.
Producer:
- New OTel attribute copilot_chat.request.options carrying a curated
subset of the request body. Captures tool_choice, reasoning,
reasoning_effort, thinking, thinking_budget, output_config,
response_format, text, truncation, context_management, the various
penalties, store, stream, stream_options, prediction, seed,
parallel_tool_calls, service_tier, metadata, verbosity, snippy,
state, intent, intent_threshold, include, plus an 'extra' catch-all
for any unrecognised top-level fields.
- Persisted onto llm_request entries in the file logger so the data
survives session reloads.
Consumer plumbing:
- New requestOptions?: string on IChatDebugEventModelTurnContent and
the matching DTO + ext-host class + proposed API. Read on both the
live OTel span path and the on-disk entry path.
View:
- New 'Request Options' table renders every captured option with
Previous and Current columns; rows whose values differ are
highlighted with the diff-removed background. The model id is
layered on top of the request_options blob so model swaps show up
in the same table.
- An inline 'Options changed: ...' banner sits below the summary
cards so the user spots option drift without scrolling.
- Cache performance card now detects the 'likely cache expiration'
case: when the model reports 0% hit, the structural diff finds no
prefix break, AND the option table is identical, the headline
switches to '\u2014 likely cache expiration' with an explanation. When
options are the only thing that changed, the break line says so
explicitly.
Refs #313620
* Cache Explorer: address Copilot review nits from #313608 + #313602
Six small follow-ups:
- Switch truthy checks to '!== undefined' for token fields in
chatDebugFlowGraph.ts (model-turn tooltip) so a turn with 0 input
or output tokens still gets a tooltip line.
- Same fix for the modelTurn aria label in chatDebugLogsView.ts \u2014
a 0-token turn now still announces 'Model turn: <model> 0 tokens'
instead of dropping the count.
- Add the cached-tokens row to the modelTurn branch of
formatEventDetail in chatDebugEventDetailRenderer.ts (regressed
during a recent merge) and add the cachedTokens field to the
existing 'modelTurn - with all fields' unit test.
- chatDebugFlowGraph tooltip also gains a 'Cached tokens: N' line
when present.
- Restore the requestName deserialize in ExtHostChatDebug._deserialize
Event \u2014 the serializer sends it but the round trip was dropping
it. Add the corresponding requestName field to the
ChatDebugModelTurnEvent ext-host class so the assignment compiles.
* Cache Explorer: address Copilot review on #313620
Five fixes from Copilot's review:
- Rename INormalizedMessage.byteLength to charLength (text.length is
UTF-16 code units, not bytes), and update all UI labels from 'B' to
'chars' so the displayed unit matches what we actually measure.
Touches the diff engine, the explorer view, and the unit tests.
- setSession now clears collapsedGroups and resets openComponents to
the default expanded set, mirroring how Flow Chart resets its
collapse state on session change. Prevents unbounded growth and
cross-session collapse-state leaks.
- Rail rows are now keyboard accessible: each row is focusable
(tabIndex=0), exposes role='button', aria-selected, and aria-label,
and responds to Enter/Space. Adds a focus-visible outline.
- render() now uses a monotonically-increasing renderToken captured
at the start of each call and re-checked after each await; an older
render whose model-turn resolves come back late will no longer
write into a DOM the newer render has already rebuilt.
- _reviveResolvedContent in mainThreadChatDebug now passes through
maxInputTokens and maxOutputTokens, which were silently dropped.
Refs #313620
* Cache Explorer: address Councillor-Opus follow-up nits
Five fixes prompted by the council review:
- breakBytePos used to fall through to 'cumulative' (the right edge of
the bar) when the diff's break index was outside the side's segment
list \u2014 it now returns undefined, which the renderer already handles
as 'no break marker for this side'. Prevents a logic mismatch
between the diff and the segment list from being silently masked
as a misleading 'cache broke at the end' marker.
- pickCacheRelevantRequestOptions drops the 'extra' catch-all. We
now only forward an explicit allowlist of cache-keying body fields
to OTel and the on-disk debug log. Keeps any future provider-
specific body fields (auth tokens, API keys, personalization)
from leaking through; new cache knobs must be added explicitly.
- Replace the local JSON-stringify based deepEqual helper in the
view with the equals function from vs/base/common/objects, which
is already used elsewhere in the workbench for value comparisons.
- Add a fast-fail comment to messagesEqual explaining why charLength
stays even though it is implied by text equality.
- Document the trailing-context loop in renderInlineDiff and the
silent selectedIndex clamp on session change so future readers
don't think they're bugs. Expand the isLikelyCacheExpiration
JSDoc to enumerate other invalidation causes the heuristic
cannot distinguish.
* Cache Explorer: clarify stableStringify fallback intent
Document why stableStringify falls back to String(value) (circular
refs / BigInt) and why the diff engine deliberately does not take an
ILogService dependency to log such cases. The fallback produces a
stable but lossy representation that still surfaces as content drift
in the UI, so the failure mode is visible rather than silent.
* Cache Explorer: address Copilot review nits round 2
Four small fixes from the latest Copilot review pass:
- Update parseInputMessages JSDoc: was still describing charLength as
'byte length' even though the field was renamed.
- Update diffPromptSignature comment: it claimed every position from
the divergence onward is reported as non-identical, but the
algorithm classifies each position independently. The first
divergence is what breaks the cache; later identical positions are
reported truthfully and the UI keys off the first break index.
- Rename the 'bytes' field on the local renderSignature segment type
to 'chars' (and the breakBytePos helper to breakCharPos) so the
source code matches what the user-visible labels already say.
- Drop the dead 'tools' entry from the openComponents Set seed in
setSession and the field initializer; the diff pipeline only emits
'system' and 'messages[N]' component names, so the 'tools' entry
never matched and had no visible effect.
themes: improve quick pick focus contrast in 2026 themes (#307581) Update the 2026 Light and 2026 Dark quick input focused row colors to meet non-text contrast requirements against the quick input background. Also switch the focused row foreground and icon foreground to white so the stronger focus background remains legible. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Use proper functions to get chat session types
This should be documented, not deprecated :)
Enable the toggle markdown preview command for agent diff views too
* Evict idle restored agent host sessions Adds reference-counted resource subscribers to AgentService so the agent-host can drop session state for restored sessions that nobody is viewing. Server side (src/vs/platform/agentHost): - AgentService: new addSubscriber/removeSubscriber + per-resource refcount via _resourceSubscribers; on last release, run _maybeEvictIdleRestoredSession which drops state when the session is restored AND idle. - AgentHostStateManager: new _restoredSessions set + isRestoredAndIdle. - protocolServerHandler: wire subscribe/unsubscribe RPCs to the new refcount, and drain a client's subscriptions in transport.onClose. Renderer side (src/vs/sessions/contrib/agentHost): - baseAgentHostSessionsProvider: 30 s idle timer (_keepSessionStateAlive) before tearing down the per-session subscription, using the existing IAgentConnection refcount. Tests: agentService, agentHostStateManager, protocolServerHandler, localAgentHostSessionsProvider — all updated. (Written by Copilot) * Drop restored-vs-created distinction; evict any idle session The previous implementation gated eviction behind an _restoredSessions set, on the theory that in-process sessions might not yet be persisted to the agent SDK. In practice, by the time AgentService.createSession returns, provider.createSession has resolved — meaning the backend agent owns the session and listSessions() will return it. So the gate was guarding against a scenario that doesn't happen. Remove the set, the predicate, and its tests. Eviction now keys solely on the active-turn veto, which is the only correctness-critical guard. The next subscribe rehydrates via the existing restoreSession path. (Written by Copilot) * Wire renderer subscribe through addSubscriber/removeSubscriber Drop IAgentService.unsubscribe. It was a no-op on the agent host side, which meant the electron renderer's subscriptions never decremented the per-resource refcount — so the idle-session eviction added in this PR only fired for the CLI/remote path. The renderer now pairs every subscribe with addSubscriber and routes the AgentSubscriptionManager unsubscribe callback to removeSubscriber. The CLI/remote path is unchanged: protocolServerHandler still maps the 'unsubscribe' wire notification to removeSubscriber. (Written by Copilot) * Fold subscriber registration into IAgentService.subscribe The subscribe/addSubscriber pairing was a footgun: callers had to remember to call both, and forgetting addSubscriber meant the per-resource refcount never tracked them, so idle eviction would never fire. Now subscribe(resource, clientId) registers the subscriber as part of the call. Also rename removeSubscriber → unsubscribe so the cleanup half of the pair has the obvious counterpart name (the previous unsubscribe was a no-op and was removed earlier in this PR). addSubscriber stays on the interface for the JSON-RPC handshake fast path (initialize / reconnect serve snapshots out of the in-memory state cache without going through the async subscribe()), with docs narrowing it to that use case. (Written by Copilot) * fixes Co-authored-by: Copilot <copilot@github.com> * Reconnect: rehydrate evicted state via subscribe() When all clients disconnect, _maybeEvictIdleSession drops the cached state. The reconnect path was calling getSnapshot() to re-attach prior subscriptions, which silently dropped any subscription whose state had been evicted — the client would think it had reconnected, but the server held no subscription and no state for that resource. Have _handleReconnect call IAgentService.subscribe(uri, clientId) per prior subscription instead. subscribe() both registers the subscriber and restores state if missing, which is exactly what reconnect needs. Per-subscription failures are logged and skipped so one bad URI doesn't fail the whole reconnect. Splits the handler into a sync part (installs the client object so any in-flight messages can find it) plus an async response promise. Updates the existing two reconnect tests to await the response, and adds a new test that asserts reconnect re-hydrates state evicted while the client was disconnected. (Written by Copilot) --------- Co-authored-by: Copilot <copilot@github.com>
Fix custom editor field documentation
fix: enable text selection in elicitation dialog markdown content
* Optin UX Co-authored-by: Copilot <copilot@github.com> * setting rename and updates Co-authored-by: Copilot <copilot@github.com> * cleanup Co-authored-by: Copilot <copilot@github.com> * few updates Co-authored-by: Copilot <copilot@github.com> * Feedback updates Co-authored-by: Copilot <copilot@github.com> * policy doc * few updates Co-authored-by: Copilot <copilot@github.com> * minor update * excludeRepo changes Co-authored-by: Copilot <copilot@github.com> * update policy name Co-authored-by: Copilot <copilot@github.com> * delete Co-authored-by: Copilot <copilot@github.com> * status UI Co-authored-by: Copilot <copilot@github.com> * delete and reindex updates Co-authored-by: Copilot <copilot@github.com> * UX and status updates Co-authored-by: Copilot <copilot@github.com> * policy update * feedback updates Co-authored-by: Copilot <copilot@github.com> * telemetry update Co-authored-by: Copilot <copilot@github.com> --------- Co-authored-by: Copilot <copilot@github.com>
fix: resolve NoChangeError tool name interpolation and typo
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to subscribe to this conversation on GitHub.
Already have an account?
Sign in.
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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 : )