* agentHost: scope server tools to exact chats
Pass exact Agent Host chat channels through every provider and derive owning session context centrally for session-scoped tools. This fixes rename_chat targeting for Claude and Codex peer chats while preserving Agent Merge and feedback behavior.\n\nFixes #331165\n\nCo-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* agentHost: test Claude peer server tool routing
Capture Claude SDK server-tool handlers in the provider test double and verify a materialized peer chat forwards its exact Agent Host chat URI.\n\nCo-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* agentHost: make startup session discovery registry-first (#331155)
A 2026-08-17 Insiders reproduction with 941 SDK sessions and 1,437
per-session databases (~946 MB) showed the ~60s delay is not migration —
`sessionRegistryBackfilled:copilotcli` was already true and migration was
skipped. The time went to per-session SQLite work during discovery and
listing: classification took 66.9s (113 external, 342 adoptable
extension-host, 486 already known), registration of the 113 emitted
candidates another 21.9s, and the first two AHP `listSessions` calls
109.8s and 91.0s, with a third 73.2s window after discovery.
Each measured phase is addressed:
- Classification (66.9s): discovery is now registry-first. `IAgent` gains
an optional `setKnownSessionsFilter` seam that `AgentService` installs
at provider registration; it answers, in one registry query for the
whole candidate set, which sessions the host already owns.
`CopilotAgent` drops those candidates instead of opening a session
database each, so the 486 already-known sessions cost no DB opens.
Tombstoned sessions are absent from the registry and therefore never
reported as known, so an explicitly deleted session still reaches
`register`, whose atomic tombstone check declines it. Provenance of a
registered row stays owned by the explicit create/restore paths.
- Classification (the 342 adoptable rows): while migrate-legacy is off,
adoptable extension-host candidates are never emitted, so their
Git-touching project resolution is now skipped entirely instead of
being computed and then filtered away. `_emitCopilotChats` keeps its
filter as a re-check, since the setting can flip mid-pass.
- Registration (21.9s): `_registerDiscoveredChats` rejects an
already-registered candidate with unchanged provenance before
`_isChatBacking()` or any other per-session I/O.
- Listing (109.8s / 91.0s / 73.2s): `listSessions()` coalesces concurrent
computations per external-sessions mode, so the burst a multi-window
restore produces shares one registry traversal. The shared entry
records the registry epoch it started at and every registry mutation
invalidates it, so a caller arriving after a mutation starts a fresh
pass rather than joining a possibly pre-mutation one. Each caller gets
its own array; rejections are shared only with callers already waiting.
- `_readStoredSessionMetadata` / `_readSessionMetadata` now issue one
bulk `getMetadataObject()` query instead of nine and six single-key
reads, shrinking the cost of the fallback path that runs when no host
filter is installed.
Deferred deliberately: seeding a newly discovered external session as
read still creates its database purely to hold one flag. Dropping the
write without a durable default would flip every discovered external
session to unread, because the list overlay only applies `IsRead` when
the key is present. The correct default belongs on the registry row and
is left to the registry list-projection change; the reasoning is
recorded on `_initializeExternalSessionReadState`. Removal of
`_awaitInitialProviderMigration()` is likewise not attempted: the
reproduction proves migration was already skipped.
Tests assert call/open counts rather than wall-clock thresholds:
registry-known candidates cause zero session DB opens; disabled
adoptable candidates resolve no projects; re-registering a known
discovered chat performs no per-session I/O; the known-sessions filter
reports registered sessions only and leaves tombstones to registration;
concurrent list calls share one computation but not their arrays; a
mutation during an in-flight list is not served from it; and stored
metadata is read with a single bulk query.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* agentHost: address discovery review feedback
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* agentHost: update discovery perf fixture
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
---------
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Route both synthesized failure descriptions through @vscode/l10n with
placeholders for the provider code and diagnostic details, matching the
localized endpoint error pattern in imageLimits.ts. These strings reach the
user as the BYOK failure reason, so a non-English install should not receive
untranslated text. The bracketed identifiers stay verbatim so they remain
greppable and pasteable into a provider support request.
Revert the Agent Host integration test expansion. It exercised parameterless
tool schemas and tool-call continuations, which ruled out two alternative
causes while investigating, but no production tool handling changes here and
that coverage does not validate this fix.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
A provider can end a Responses stream with a terminal event whose error
object omits the code and message the API contract requires. Serializing
that object produced {"code":0,"message":"","metadata":{}}, which the BYOK
endpoint promotes to the entire user-facing reason, so an outage and a
malformed request looked identical and neither users nor maintainers could
tell them apart.
Describe such failures instead, naming the terminal event, response status,
and response id so the failure stays correlatable with the provider, and
omit absent metadata keys so serialization cannot collapse them to an empty
object. Keep the fetcher's original reason when a stream error carries no
message, so a hollow struct never replaces an actionable one.
The mapping predates the reports; the Agent Host BYOK proxy moving from
Chat Completions to Responses in 1.132.0 is what first exposed it in the
Agents Window. This restores diagnosability rather than stopping the
upstream failure, so it does not close the report on its own.
Related to #330408
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* sessions: Synchronize live last turn changes
Use active-turn chat edits for Last Turn Changes until the finalized host changeset is available, and route the live changes pill to the same changeset. Keep historical turn selections workspace-scoped.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* sessions: Address live turn review feedback
Keep live turn changes until the finalized host changeset is ready, tighten workspace filtering, and prune per-chat observable cache entries.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
---------
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
A session can carry two customizations for a single MCP server. The agent host
publishes the declaration as a child of whatever declared it -- a plugin, or
the .mcp.json VS Code syncs into the agent -- and separately mints a top-level
customization for any server the SDK reports before that child can be resolved
by name. `McpCustomizationController._applyOne` never retires the minted entry
once the child becomes resolvable ("Once promoted to a top-level entry, stay
top-level for the session"), so both remain in state:
notion -> file:///.../vscode-synced-customization-.../.mcp.json#mcp=notion
state: stopped <- the declaration
notion -> mcp-top-level:copilotcli:<session>:notion
state: ready, channel: mcp:// <- the live one
Every consumer of getMcpServers saw both, so the servers list rendered the same
server twice with contradictory status. It was worse than a repeat: the list's
matcher only matches when exactly one candidate answers a key, so with two
copies the server's local row could not adopt either, and both fell through as
extra rows.
getMcpServers now drops a child that a top-level customization already speaks
for. The top-level copy wins because it is the one the host treats as live: it
carries the running state and channel, and its id is what the host resolves for
lifecycle and enablement. Position in the tree is the signal, not the shape of
the minted id, which is the host's own business -- and not the absence of an
owning plugin either, since a directory-declared child has none. That last one
is a live trap rather than a hypothetical, so it has its own test.
Nothing else is collapsed. Two plugins that each declare a server named
`search` stay two rows, because they are two servers. Only the presentation
path dedupes; log, diagnostics and id lookups still walk every customization,
so an id from either copy continues to resolve.
The host-side repair is tracked in #330893.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
`updateStatus` began by clearing the row's action disposables and emptying its
actions node, then rebuilt them. It runs from an autorun over the server's
connection state, and an erroring server re-runs it about twice a second while
producing byte-identical content: measured in a real Code OSS build, 9-10
rebuilds per 5 seconds, every one of them a no-op.
A DOM node replaced between mousedown and mouseup never receives the click, so
the inline `Show Output` button did nothing on precisely the rows that needed
it -- the failing ones, which are the only rows that offer it at all.
The row's actions are now rebuilt only when something about them changed.
`getMcpStatusRenderSignature` reduces them to a comparable value covering both
what they render and what they act on; leaving anything out would drop an
update that matters, so it is a pure exported function whose test fails to
compile if a field is added without being covered.
The list re-splices on every customizations change, so `renderElement` would
otherwise undo this by clearing the actions itself. It now keys on the row's
content identity rather than the entry object, which is recreated on every
refresh and therefore says nothing about whether this is the same row.
Both guards are pinned by tests that drive the renderer itself, since that is
the only place the failure is observable: an erroring server's update is fired
repeatedly with unchanged content, and the button must be the same node
afterwards, still attached, and still reach `showMcpServerLog` when clicked. A
third test asserts a real status change does still rebuild, so the guard cannot
be satisfied by never updating. Reverting either guard fails them.
`McpServerItemRenderer` is exported for this.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
`text-transform: capitalize` on the shared group header re-cased strings that
were already cased correctly, and got them wrong: "Included Based on Context"
rendered as "Included Based On Context" and "Loaded on Demand" as "Loaded On
Demand", against this repo's own rule that short prepositions stay lowercase,
and "Built-in" rendered as "Built-In".
Per-word capitalization is also not a transform that survives translation, so
the rule was wrong for every locale rather than just awkward in English.
The header is shared, so this reaches every customizations tab -- Agents,
Skills, Instructions, Hooks, Prompts, Plugins and MCP Servers. Every group
label on those tabs is already a correctly cased localized string, so the only
rendered differences are the three the transform was getting wrong: four
screenshot baselines change, on the Instructions and MCP Servers tabs.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
* agentHost: Filter external Copilot sessions
Only discover standalone Copilot CLI and GitHub Copilot app sessions that have repository metadata and were modified within the last seven days. Preserve legacy extension-host adoption and cover accepted and rejected metadata boundaries.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* agentHost: Fix Copilot discovery gating test
Gate the raw session-list RPC used by external discovery so the migration-toggle test no longer waits on the obsolete convenience listSessions seam.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* agentHost: Format Copilot discovery test
Apply the repository TypeScript formatter to the raw session-list test fixture.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
---------
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* agentHost: address agent merge review feedback
Follow-ups to PR #331010 review comments:
- Rename settings from `chat.agentHost.agentMerge.*` to `chat.agentMerge.*`.
- Reject client writes to host-owned `agentMerge.controller` session config so a
forged controller state cannot drive a native merge.
- Reconcile injected autonomy configuration every cycle and roll back keys that
policy later revokes; never widen configuration while a turn is active.
- Revalidate the merge target before starting a turn and before merging, and
refresh live state, config and top-level comments inside the merge step.
- Split `AgentMergeRepairAction` out of `AgentMergeAction` so repair paths
cannot express a merge.
- Carry all feedback comments per review thread and bound the prompt with
explicit caps and an aggregate character budget.
- Fail closed when fork head provenance is missing, and ignore refs from a
different GitHub host.
- Cancel the controller turn when the runtime stops.
- Split the enable/disable command preconditions with a dedicated context key and
make the configure quick pick's reset a title button.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* agentHost: address agent merge PR review feedback
- Preserve host-written session config across a client `SessionConfigChanged`
with `replace: true`. Omitting `agentMerge.controller` previously cleared the
bound target, comment watermark and attempt budgets, which bypassed the
authorization boundary that explicit-write rejection was meant to enforce.
- Canonicalize pull request web hosts to their API host when checking that the
credential matches. GitHub Enterprise Cloud serves `tenant.ghe.com` from
`api.tenant.ghe.com`, so comparing the web host rejected every GHE Cloud pull
request. The derivation now reuses `deriveGitHubEndpoints`.
- Refresh top-level comments inside `prepareMerge`, last, before the snapshot and
token are captured. Refreshing them in the controller beforehand left a window
across `prepareMerge`'s own authoritative refreshes in which a new maintainer
comment could be missed; refreshing afterwards would invalidate the preparation
generation. A comment landing after capture now invalidates the preparation.
- Migrate the legacy `chat.agentHost.agentMerge.*` setting ids to their new
`chat.agentMerge.*` names so an explicit opt-out is not silently discarded.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
---------
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Every cached AgentHostSessionAdapter eagerly subscribed to the shared
agent-capabilities observable, so a window restoring hundreds of sessions
installed hundreds of observers and tripped the listener leak detector.
Most of those observers had nothing to do: the autorun only re-applies a
chat catalog, and an adapter that never received one has no catalog to
reconcile. Install the observer on the first applyChatCatalog call instead,
so only adapters with catalog state to reapply subscribe. Late-hydrating
capabilities still re-expand a collapsed peer catalog.
Found while self-hosting Insiders.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* agentHost: fix: preserve active peer chats during idle eviction
Use the session-wide active-turn tracker when deciding whether an unsubscribed session can be released, so peer chat turns keep their host state alive.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: ea077bee-57a9-4f08-8c14-a8778fbcea83
* agentHost: fix: retry eviction after peer turn race
Re-arm idle release when a peer chat becomes active while session data is draining, and cover eviction after that turn completes.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: ea077bee-57a9-4f08-8c14-a8778fbcea83
---------
Copilot-Session: ea077bee-57a9-4f08-8c14-a8778fbcea83
* agentHost: Add agent merge controller
Add provider-neutral pull request lifecycle automation backed by the shared GitHub service, with scoped repair tools, native merge execution, persisted session controls, and Agents Window commands.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Refactor agent merge feature implementation and update tests
- Improve agent merge logic in various files.
- Update tests to reflect changes in agent merge functionality.
- Enhance documentation for AGENT_HOST_SESSIONS_PROVIDER.
* agentHost: Let providers own autonomous agent merge config
Provider agents now select and restore their native unattended configuration, repair prompts carry bounded authorized review-thread detail, and branch and session-wide turn checks are revalidated before claiming a turn or merging.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* agentHost: Advertise agent merge tools only when enabled
Gate the Agent Merge server tool group on the host feature setting so sessions without Agent Merge keep their existing tool catalog and provider prompts, and re-advertise host tools when the setting is toggled.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
---------
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Clarify restricted telemetry size safeguards
Document the backend chunk-key casing exception and make the oversized telemetry regression test verify the serialized body byte limit directly.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Document restricted telemetry chunk key exception
Name the messagesJSONChunk wire family explicitly in the compressed telemetry documentation.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
---------
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Keep summary baselines current for unpublished restored sessions without broadcasting root deltas. When the session is later published, clients receive the latest complete summary before normal incremental updates resume.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Keep pending sash reset intent across session switches and later sash drags, and avoid rewriting the saved Editor width from live composition changes.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Require real provider test servers and direct SDK integrations to use temporary provider homes so test sessions, logs, and configuration never reach the developer's real ~/.copilot directory. (Written by Copilot)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Forward external provenance through visible session wrappers and distinguish summaries recorded for diffing from summaries actually published to clients. This restores the banner in the Agents Window and allows hidden restored sessions to appear when the setting changes.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Record the active host/provider stage when the turn hang watchdog fires so no-progress incidents can be separated by pre-provider and provider execution boundaries.\n\n(Written by Copilot)\n\nCo-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* sessions: add session details developer command
Add a developer command that opens a copyable list of non-archived session names, working directories, and resources. (Written by Copilot)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* sessions: address session details feedback
Localize visible action and editor labels, clarify the empty state, and make path coverage platform-aware. (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 external session visibility banner
Explain when an Agent Host session came from another application and let users choose which external sessions remain visible. Confirm choices that hide the open session, persist banner dismissal, and reconcile restored session publication with the setting.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* sessions: Add external session filter menus
Expose the external-session visibility setting beneath provider filters in both the regular agent sessions list and the Agents Window. Keep the checked option synchronized with effective configuration and update the user setting from either menu.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* sessions: Fix external filter menu test mock
Use an overload-compatible configuration service mock so the native TypeScript compiler accepts the external-session menu setting test.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* agentHost: Fix external session metadata test
Make the stale metadata overlay test opt into all external sessions so it exercises overlay behavior independently from the new age-based visibility filter.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
---------
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
test: stabilize agent host reconnect coverage
Use distinct logical client IDs for the dropped transports so reconnect scenarios cannot race the shared client for action delivery.\n\n(Written by Copilot)\n\nCo-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* agentHost: discover external Copilot sessions
`CopilotAgent` never emitted an external chat. Its only discovery path,
`_discoverExtHostChats()`, matched exclusively legacy VS Code
extension-host CLI sessions (a `vscode.metadata.json` sidecar with
`origin: 'vscode'`), hard-coded `external: false`, and was gated behind
`migrateLegacyCopilotCli.enabled`. A session created by the standalone
CLI or the GitHub Copilot app — which share `~/.copilot` — was dropped
before it ever reached the session registry, so `showExternalSessions`
had nothing to show even when set to `all`. Claude and Codex both emit
every unknown native chat as external; Copilot was the outlier.
Replace it with `_discoverCopilotChats()` / `_emitCopilotChats()`, which
enumerate the SDK catalog and classify each chat Agent Host does not
already own: a legacy extension-host chat stays internal and adoptable
in place (still gated on migrate-legacy), anything else is external and
ungated. Discovery starts on first-listener attach behind a `retry`
wrapper, mirroring Claude and Codex, so a cold CLI client does not lose
the pass; the retry honors `_shutdownPromise` so teardown stops it
rather than sleeping on a dead client.
Chats whose SDK context carries no working directory are still dropped:
`_doResumeSession` requires one and a discovered chat has no other
source for it, so surfacing one would produce a row that throws on open.
Add logging along the whole pipeline — provider enumeration, per-pass
classification counts, registry registration, and how many sessions the
`showExternalSessions` filter is holding back — since a session that was
discovered but filtered was previously indistinguishable from one that
was never discovered at all.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* agentHost: address review feedback on Copilot discovery
- Classify each discovered chat inside a try/catch so one unreadable
session database no longer rejects the whole catalog scan (and fails
every retry with it); the failing chat is logged and skipped instead.
- Count only mode-excluded rows in the hidden-sessions log. Adoptable
legacy rows are withheld by migrate-legacy, so attributing them to
showExternalSessions could report external filtering in 'all' mode.
- Await the memoized discovery pass in the test helper instead of
polling for a non-empty result, so an expected-empty assertion can no
longer pass before classification has run.
- Trim inline comments to one line per the coding guidelines.
- Describe discovery in AGENTS.md as emitting provider-classified
provenance, matching the Copilot legacy exception documented above it.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
---------
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* sessions: Stabilize docked side pane sizing
Keep the shared editor node width stable across reloads, session transitions, detail-only layouts, and whole-pane closure. Preserve composition-specific sizing so docked Details takes space from Sessions without cumulative width drift.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* sessions: Preserve pane sizing across layout restores
Clear transient sash-reset behavior on session switches, keep live Editor widths synchronized for docked restores, and preserve classic hidden-Editor persistence semantics.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* sessions: Clear stale sash sizing state
Discard responsive auto-hide state when the side pane closes and cancel reset-only Details sizing after a later manual sash resize.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
---------
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Address review feedback for exact-chat MCP routing.
- Reject stale Copilot chat bindings that point to another runtime.
- Document the encoded chat URI channel format.
- Cover AgentService forwarding and Codex exact-chat rejection.
(Commit message generated by Copilot)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* agentHost: Expand E2E coverage
Add broad deterministic coverage for protocol, filesystem, terminal, completion, OTLP, reconnect, and session tool behavior across the conformance and provider suites.
Harden the new cases with repeated full-suite and focused stress runs.
(Written by Copilot)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* agentHost: Avoid duplicate resource watch subscription
Reuse the first subscription when equivalent watch descriptors resolve to the same channel, preventing the watcher refcount from being incremented twice.
(Written by Copilot)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* agentHost: Stabilize OTLP subscription coverage
Replace the timing-sensitive duplicate-delivery count with a deterministic unsubscribe and resubscribe lifecycle assertion.
(Written by Copilot)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
---------
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Route MCP App side-channel requests through concrete Agent Host chat URIs instead of
provider SDK conversation IDs.
- Give MCP customization controllers an immutable AHP chat URI and derive their session
and provider identity from it.
- Route Copilot and Codex MCP requests to the exact bound chat.
- Pass chat routing identity into restored Copilot tool metadata.
- Add focused coverage for channel parsing, provider routing, and history restoration.
(Commit message generated by Copilot)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* agentHost: Respect telemetry disablement during initialization
Send each client's effective telemetry level with initialize and reconnect so the host applies consent before connection telemetry or queued actions. Keep the host disabled until a client level arrives, and propagate process-level restrictions to generic remote telemetry.\n\n(Written by Copilot)\n\nCo-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* agentHost: Preserve telemetry wrapper defaults for direct callers
Keep fail-closed startup explicit to the production factory while preserving the established constructor behavior used by isolated Agent Host components and tests.\n\n(Written by Copilot)\n\nCo-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* agentHost: Gate telemetry on client consent
Keep seeded root configuration from enabling telemetry before initialize or reconnect provides a client telemetry level. Preserve existing direct-construction defaults for isolated callers and tests.\n\n(Written by Copilot)\n\nCo-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* agentHost: Propagate telemetry level at process launch
Start controlled Agent Host processes with the launcher's effective telemetry level so opted-in clients retain early diagnostics while opted-out clients disable telemetry before startup. Keep initialize and reconnect updates as a monotonic multi-client clamp across local, remote-server, SSH, WSL, and CLI-supervised hosts.\n\n(Written by Copilot)\n\nCo-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Update generated extension point cache
Include the link presentation provider extension point generated by hygiene after merging origin/main.\n\n(Written by Copilot)\n\nCo-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* agentHost: Derive SSH telemetry in shared process
Use the shared process telemetry service when launching SSH and WSL Agent Hosts instead of threading the telemetry level through renderer IPC contracts.\n\n(Written by Copilot)\n\nCo-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* agentHost: Don't split the final response at the reconnect boundary
Reconnecting to an active turn ran two independent converters over the
same response parts: the one-shot `activeTurnToProgress` snapshot and the
always-on `_observeTurn` graph. They de-duplicate via `adoptInvocations`,
which is keyed on live `ChatToolInvocation` instances — so a tool call
that had already settled, and which the snapshot renders as a
`toolInvocationSerialized` part, could not be adopted and was emitted a
second time as a live invocation.
That duplicate lands between the restored markdown prefix and the
markdown still streaming into the same response part. The response model
only merges a markdown update into an immediately preceding markdown
part, so the final answer was split in two — in the observed case
mid-word, with the prefix folded into the collapsed activity section and
the remainder rendered as a separate response.
Record what the snapshot emitted per tool call instead of only the
adoptable subset, so per-tool setup can skip a settled tool call that is
already fully rendered. Subagent tools are excluded because their setup
is what streams the child session's inner tool calls into the response.
(Written by Copilot)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* agentHost: Don't re-emit a settled subagent parent card on reconnect
Code review caught that the subagent exception left the reconnect split
in place for completed subagent calls: the guard declined to skip them so
their child session would still be observed, but that fell through to
`_setupServerToolCall`, which sinks a second live parent invocation. That
part lands between the restored markdown prefix and its continuation —
the very split the guard exists to prevent.
Separate child-session observation from emitting the parent invocation.
The invocation is still built so subagent observation has something to
drive, but a tool call the snapshot already rendered as a serialized part
is no longer emitted a second time.
Also trims the inline commentary flagged in review.
(Written by Copilot)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
---------
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>