Publish editor and standalone agent hosts through a shared user-data registry with cross-process locking. Update CLI discovery and management commands to work across all registered hosts without the legacy lockfile.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* agentHost: cover the changeset lifecycle end to end
Changeset lifecycle was the top remaining item in the migration backlog and
existed only in the frozen protocol suite, where it cannot describe the
contract for any other AHP implementation: that test drives a mock agent with
the magic prompt terminal-edit:<path>, side-loaded via --enable-mock-agent.
Adds a conformance-tier suite covering subscription and computation status, an
added file, an edit to a committed file, client-owned review state, and the
per-session changeset catalog. Actions move from 44/85 to 50/85 (51.8% to
58.8%), covering changeset/statusChanged, contentChanged, filesReviewChanged,
operationsChanged, cleared, and chat/activityChanged.
Every scenario drives real file changes through host-executed bang commands,
so the changeset is computed from git rather than from what a tool reported and
no scenario crosses the model boundary. The shapes asserted here were taken
from a throwaway probe against a real session rather than from reading the
service, which is also how the branch changeset was confirmed to be the one
that reports a new file.
Three changeset actions remain uncovered and are recorded in the README with
what each would need: fileSet and fileRemoved are the incremental per-file
updates rather than the bulk path a fresh session takes, and
operationStatusChanged needs an invoked operation.
Conformance 57 -> 62 passing, stable across repeated runs; Copilot 49,
Claude 44, Codex 8, 0 failing.
(Written by Copilot)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* agentHost: assert changeset operations, and harden the suite's inputs
Review feedback, all three accepted.
The README claimed the suite covered operations while nothing asserted them:
they were reaching the coverage recorder incidentally, on the wire, which is
exactly the "covered means it appeared once" floor the README warns about. A
scenario now asserts them, and a probe first established when they appear at
all - only on the uncommitted changeset, once there are real uncommitted
changes, as commit (changeset scope) and discard-changes (resource scope).
The bang command interpolated the file name and contents into a node -e script
literal, so a value containing a quote or backslash could break out of it or
change what ran. Both are passed as process.argv entries now.
clientSeq was hard-coded per scenario, which is unsafe when the suite shares
one client and sequence numbers must strictly increase. Replaced with a
monotonic counter.
Conformance 62 -> 63 passing, verified clean across twelve consecutive runs.
(Written by Copilot)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Take the reconnect cutoff from the subscribe response, not from an echo
`reconnect replays only the actions a dropped client missed` timed out on Linux
CI having received no notifications at all. The test learned its
`lastSeenServerSeq` by dispatching an action on the second connection and
waiting for the server to echo it back, but a subscription is not guaranteed to
be installed before a dispatch sent immediately afterwards is handled — so the
echo can be broadcast to no subscribers and the wait never completes.
`SubscribeResult.snapshot.fromSeq` is the same boundary and is guaranteed by
the response itself, so the test no longer needs the second client to receive
anything before it drops. The contract under test is unchanged: the replay must
exclude everything at or below the cutoff and include the gap above it.
(Written by Copilot)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
---------
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Agent Host changes for lramos15/agents/investigate-issue-318977-fix
* Use KEY_IN_COMPOSITION as the single IME signal
Drop the `isComposing` member from both `IKeyboardEvent` interfaces and rely on
the normalized key code instead.
`StandardKeyboardEvent` already reports `KEY_IN_COMPOSITION` for every composing
keystroke, so a parallel `isComposing` flag was a second source of truth for the
same fact. It also broke the standalone editor build: `@internal` members are
stripped from `out-editor-src`, which left `base`'s interface without the
property while `platform`'s still required it, so the two `IKeyboardEvent` types
stopped being assignable (5 errors in editor-distro).
Using the key code fixes that build, keeps `monaco.d.ts` unchanged, and reverts
the `isComposing: false` churn from the keyboard mapper tests.
Also cancel any in-flight dynamic filter when a composition starts: a request
issued for the previous value could otherwise resolve mid-composition and splice
and re-layout the list underneath the IME candidate window.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: c4ba1417-a152-448b-af4b-1a5017b949e8
---------
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: c4ba1417-a152-448b-af4b-1a5017b949e8
Browsers and subagents were merged into a single background-activities pill.
Split browsers out into an independent pill so each surface stands on its own,
and keep the background-activities pill for subagents plus the activity kinds
that will be added to it later.
- Add `SessionActivityPill`, a content-agnostic widget owning only the button,
single-vs-many behavior, visibility and the picker. Consumers supply their
activities, per-activity icons, category titles and multi-activity summary.
- Add `SessionBrowsersControl` for live browsers, including the preference for a
browser already sharing with the agent.
- Trim `SessionBackgroundActivitiesControl` to subagents.
- Keep the turn pills at their natural width in the toolbar row: they set
`flex-shrink: 0` on their inner pills, so squeezing them made those pills
paint over a neighbouring pill. The activity pills absorb the shrink and
ellipsize instead.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Voice: queue concurrent question forms instead of swapping them
Two forms can be pending on one request at once - askQuestions can open one
while an MCP elicitation attaches another outside the agent loop. Voice is a
serial channel, but both functions that decide which form is "current" picked
the newest one independently, so a form arriving silently retargeted the answer
the user was in the middle of giving, and dropped the first form's draft.
Both now go through one selector that returns the oldest still-open actionable
part, which is what the chat model itself does in _pendingInfo. Resolved parts
are already skipped, so the oldest open part is by construction the one voice
already published: the queue needs no stored state, and payload/detail
disagreement becomes unrepresentable.
Fixing only the payload would be worse than the bug: the detail would still
flip to the new form, isDetailTransition would fire on the detail alone, and
the narration path would read the OLD form aloud again.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 1c4672e9-182f-4a2f-8a79-bd8b770961a1
* voice: send each session's label so the backend can tell two apart
The backend renders [SESSIONS] for the model and its prompt says "Do NOT
guess" when several sessions are waiting — but every entry we sent was
anonymous, so two concurrent question forms arrived as two identical lines
and there was nothing to disambiguate on. Send the label that already exists
on both session kinds: `label` for agent sessions, `title` for plain chats.
Drop `active_session` while here. It was declared on the wire type and
diffed on every context send, but the only place that would have assigned it
was an empty try/catch, so it has always been undefined: `activeChanged` was
permanently false and the delta never carried the field. The per-entry
`is_active` flag is what actually names the focused session.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 1c4672e9-182f-4a2f-8a79-bd8b770961a1
* Potential fix for pull request finding
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
* voice: cover the session label on the wire, and trim a JSDoc
The label is the only human-readable handle the backend has for a session,
so without it two waiting forms cannot be told apart by name. It was
emitted from two branches with no test on either; a refactor could have
made sessions anonymous again silently.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 1c4672e9-182f-4a2f-8a79-bd8b770961a1
---------
Co-authored-by: Arthur Cnops <arthurcnops@microsoft.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Megan Rogge <megan.rogge@microsoft.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Copilot-Session: 1c4672e9-182f-4a2f-8a79-bd8b770961a1
* agentHost: preserve drafts when switching sessions
Flush pending debounced input state when a chat session is disposed so switching away cannot lose recently typed draft text.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* agentHost: refine draft disposal flush
Read the final input state directly during disposal and keep the regression test independent of fake timers.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
---------
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Support offline dictation model install for registry-blocked networks
Adds a 'Chat: Install Dictation Model from Local Package...' command that
imports the official Foundry Local expansion pack (ZIP or extracted OCI
layout) or a prepared model directory into the dictation model cache, so
dictation works in environments where the Azure ML model registry is
unreachable.
When a model download fails with a network/registry error, the failure
notification now offers an 'Install from Local Package...' action so the
recovery is discoverable exactly when the user is blocked.
Reuses the existing utility-process transcription service and base zip
helper; no new dependencies.
Fixes#328154
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Validate model identity/integrity and harden install swap
Address review feedback:
- Reject OCI packages whose embedded inference_model.json names a
different model, so a wrong CPU expansion pack is not stamped as
nemotron (with test).
- Verify each OCI blob against its content digest (streaming, Node
built-in crypto only) so a corrupt package fails at install rather
than cryptically in the native loader (with test).
- Never force-remove the backup during install cleanup; a failed swap
rollback must not delete the only surviving copy of a working model.
- Name the specific model in the install dialog and the recovery
notification so users know which package to obtain offline.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
---------
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Drive session cost from SDK's API
* Address PR feedback on SDK-driven session cost
- Serialize `usage.getMetrics` reads behind a `Throttler`. Several handlers
refresh the session total, so their RPCs could overlap and an older one
resolving last would publish a session cost that visibly regresses. A
high-water guard can't reject the stale value because the total is
legitimately non-monotonic — `history.truncate` makes the SDK re-fold usage
from the surviving events. Keeping one read in flight removes the
interleaving and coalesces the redundant reads a burst of events would issue.
- Emit the compaction's per-turn cost synchronously, before awaiting the
metrics read, then re-emit to enrich it with the session total. The terminal
`session.idle` can close the turn mid-read, after which the reducer drops its
usage — so a compaction whose turn ends immediately was never persisted.
- Teach `hasReportedUsage` about `sessionTotalNanoAiu`. A compaction billed
while no turn was active advances only the session total, and such a report
was being treated as empty and dropped by `usageInfoToChatUsage`.
- Correct two comments that described the wrong billing source: per-turn cost
accumulates synchronously from each event's `copilotUsage`; the SDK's usage
metrics supply only the session-wide total.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: c33a0289-7f6d-40de-9f11-4b2e474a5e9c
---------
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: c33a0289-7f6d-40de-9f11-4b2e474a5e9c
* make text selectable in the ask user widget
* only change the question area
* chat: remove obsolete selection-aware clicks
Question selection is scoped to the non-interactive title, so answer rows no longer need drag-aware click handling.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
---------
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Cover annotations, protocol contracts, and terminal lifecycle in agent host E2E
Adds conformance coverage for protocol areas that no E2E test reached, chosen
from the protocol-surface `uncovered` lists rather than to hit a number.
- `suites/annotationsSuite.ts` — the whole `annotations/*` channel, which was
covered by neither the E2E suite nor the frozen protocol suite.
- `suites/protocolContractsSuite.ts` — liveness (`ping`), turn-history paging
(`fetchTurns` / `chat/turnsLoaded`), connection recovery (`reconnect`, both
the replay-gap and unresumable-subscription cases), and the rejection
contract for the four declared-but-unsupported working-directory actions.
- `stateOperationsSuite.ts` — terminal clear and exit, root's view of terminals
appearing and disappearing, and queued-message promotion.
`reconnect` is only answerable on a transport that has not completed the
handshake, so it needs a second connection that can be dropped and
re-established. `IAgentHostE2ETestContext.connectClient` is that seam; the
shared per-test client cannot express it.
The queued-message test started out asserting that two queued messages
accumulate. They do not: a message queued onto an idle chat is promoted
straight into a turn, so the queue is empty again by the next reduction. The
dispatch envelope looked entirely normal, and every other test in that suite
asserts only the result of its last dispatch, which is why this had gone
unnoticed. The test now asserts the real contract, and KNOWN_ISSUES records
the test-shape lesson.
Protocol surface: commands 27/29 -> 28/29, actions 54/85 -> 59/85. The one
remaining uncovered command and the eight `changeset/*` actions are covered by
the changeset branch. Conformance tier 62 -> 73 tests; full suite 172 passing,
0 failing, stable across repeated runs.
(Written by Copilot)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Drive the two new host-local turns with /rename instead of a bang command
Windows CI timed out on `fetchTurns reports the turns a chat already has` and
`a message queued on an idle chat is promoted straight into a turn`. Both
needed a real turn that never reaches the model, and both used `!echo` to get
one.
That is a documented Windows defect, already recorded in KNOWN_ISSUES and
already the reason `a bang command runs locally and exposes terminal output`
is Windows-scoped: a successful bang command produces output but does not
complete reliably, so waiting on `chat/turnComplete` hangs.
`/rename` is handled by the same local-command dispatcher but spawns no shell,
and it is exercised on Windows today by the host-features suite. Neither test
cares how the turn was produced, only that one exists, so this removes the
dependency rather than scoping the tests to non-Windows.
(Written by Copilot)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Tighten notification predicates and correct the migration backlog table
Addresses code review feedback:
- The turn waits in the queued-message test and in `fetchTurns` now constrain
`channel`, so a shared client cannot match a notification from another
session's chat.
- `dispatchAndWaitOnShared` now matches the action type as well as the channel
and originating `clientSeq`.
- The migration backlog table's third column listed symbols as uncovered that
this change covers. Renamed it to "Protocol symbols", marked each row's
actual status, and pointed at `coverage/protocol-surface.json` as the
authoritative source.
(Written by Copilot)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
---------
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* feat(agentHost): add multi-root support for Codex sessions
Gate Codex multi-root support behind a hidden setting, forward workspace roots through the app-server lifecycle, and persist them for resume and fork recovery. Preserve existing additional writable-directory behavior and disabled defaults.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* fix(agentHost): normalize Codex workspace root identity
Deduplicate roots using platform-aware filesystem comparison keys and make additional-directory tests portable on Windows.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* fix(agentHost): preserve Codex single-root behavior
Activate Codex multi-root protocol and persistence work only for sessions with more than one distinct workspace root. Reuse existing metadata operations so single-folder sessions retain their original wire shape and I/O costs.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
---------
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* agentHost: correct the recorded symptom of the Claude fork defect
The entry claimed a provider-context fork "rejects the AHP turn id as an
invalid upToMessageId". Enabling the gate and recording against the live SDK
shows that is not what happens: the E2E fork path never reaches forkSession at
all. That string comes from a unit-test stub and the SDK.
What actually happens is quieter and worse. The fork silently produces a chat
with no provider context: the forked chat's AHP transcript is seeded with the
source turn and looks correct, but the model request carries no prior history,
so the model cannot recall anything from the source conversation. No error
reaches the client.
Root cause is anchor resolution. resolveForkAnchorUuid matches the requested
turn id against Claude SDK envelope uuids, so it resolves only when the AHP
turn id happens to be an SDK uuid. AHP lets a client choose its own turn id on
dispatch and Copilot honors that; for such an id the anchor never resolves,
_forkChat warns, and createChat continues with a fresh chat.
The same test passes for Copilot with the full inherited history in its
capture, so this is provider-specific rather than a fault in the shared fork
contract or the test.
Tests stay disabled - the defect is unfixed - but the entry now describes the
symptom someone would actually observe, and records that the unknown-turn test
asserts correct behavior and shares the gate only by construction.
(Written by Copilot)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* agentHost: link the Claude fork defect to its tracking issue
(Written by Copilot)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
---------
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Initiall
* agentHost: parallelize Claude customization scans
Preserve deterministic scope and settings precedence while reading independent customization roots concurrently.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* agentHost: fix Claude multi-root discovery edge cases
Run independent scans concurrently while preserving user-scope attribution and primary-root behavior for cached plugin hooks.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* agentHost: preserve Claude single-root discovery behavior
Route one-root sessions through the original scanners and watcher lifecycle while reserving multi-root precedence and concurrency for sessions with additional directories.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* agentHost: clarify Claude customization scope buckets
Document how URI-backed buckets distinguish multiple workspace roots from user scope.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
---------
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Enhance multi-root workspace support for Copilot Agent Host
- Introduced configuration options to include folder-root `.mcp.json` servers in multi-root workspaces.
- Updated `collectNonPluginMcpServers` to accept a flag for workspace discovery.
- Modified `resolveCustomizationRefs` to pass the new flag.
- Added tests to verify inclusion of workspace-discovered servers and exclusion of `.code-workspace` servers.
- Refactored `WorkspaceDotMcpDiscovery` to use a constant for collection ID prefix.
* Add shouldSyncWorkspaceDotMcp function and related tests for multi-root workspace support
* agentHost: fix replayed text doubling and split the overloaded Codex gate
Three findings, from actually running the gated Codex scenarios rather than
trusting the inventory.
Replayed text was doubled. The Responses regenerator announced each output item
with its final content already attached, then streamed the same text as deltas,
so a consumer that accumulates both counted it twice: a recorded
SHELL_VALUE_73 replayed as SHELL_VALUE_73SHELL_VALUE_73. An announced item now
arrives empty. Recording proxies real bytes and was never affected, which is why
the capture looked right while the replayed snapshot did not. This is the
response duplication KNOWN_ISSUES attributed to the provider; it was ours.
Codex has no file tools. Its captures contain only exec_command, where Claude's
contain Read/Write/Bash. The shared file-operation prompts steer the agent away
from the shell to keep captures platform-neutral, and Codex cannot satisfy that:
it refuses, or flails and answers 3 for a four-line file. That is a capability
difference, not something re-recording fixes.
The gate conflated both, plus a third thing. stableNewScenarioResponse covered
"replays unstably", "never recorded", and "cannot run this at all".
KNOWN_ISSUES already said splitting it was a prerequisite for reducing it. It is
replaced by supportsFileTools, and "retains context across consecutive turns" -
which involves no files and no tools, and was only ever caught by the same flag
- now runs for Codex.
Codex goes from 8 to 9 passing, stable across repeated runs. The remaining
file-operation scenarios stay gated with the real reason recorded, including
that enabling the pinned-shell ones naively fails about one run in four through
the shared-server load ceiling.
(Written by Copilot)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* agentHost: address Codex gate review feedback
Splits the gate again along the line the reviewer identified. supportsFileTools
was doing two jobs: naming a capability Codex lacks, and standing in for the
shared-server instability of the scenarios it can technically run. Four of the
scenarios behind it pin a portable shell command and need no file tools at all,
so gating them on a file-tool capability was both misleading and stricter than
the facts.
They now gate on stableSharedServerFileScenarios, a distinct flag that carries
the load-ceiling rationale. supportsFileTools keeps only the scenarios whose
prompt requires file tools.
Also from review:
- Three comments still blamed Codex for duplicating its response. That was our
own SSE regenerator, fixed earlier in this PR; they now state the real reason.
- isLinux was left above the import list by an earlier restore. Moved below,
next to the sibling isWindows const.
- The reproduction command sets AGENT_HOST_UPDATE_SNAPSHOTS=1, which rewrites
artifacts. It is genuinely required here, since these scenarios have no Codex
capture and plain replay stops at fixture resolution - so the command stays,
with a note on what it rewrites and where the failure actually shows up.
No behavior change: Codex still 9 passing across repeated runs, conformance 57,
Copilot 49, Claude 44, 0 failing.
(Written by Copilot)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
---------
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* chat: enable agent host defaults
Flip the Agent Host migration settings to their rolled-out defaults and enable remote Agent Host support for web clients attached to a remote extension host. Serverless web retains extension-host fallbacks. (Written by Copilot)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* test: cover web agent host disablement
Add web-remote coverage for configuration and AI disablement, and clarify the serverless web requirement in the setting description. (Written by Copilot)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* test: pin smoke session providers
Pre-seed extension-host smoke profiles before startup and update Agent Host picker labels so the suites exercise their intended providers after the default flip. (Written by Copilot)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* chat: restore agent host setting description
Keep the existing concise setting and policy description while retaining the runtime availability behavior. (Written by Copilot)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
---------
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* agentHost: Emit initiator client type in CTS telemetry
Propagate the initiating AHP client type to skill, auto-mode, and repository-info telemetry, including standard CTS skill events. (Written by Copilot)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* agentHost: Preserve repo telemetry initiator
Cache the initiating client type with the begin capture so repository telemetry always attributes begin and end consistently. (Written by Copilot)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
---------
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* fix: detect interrupted commands in terminal exit code hack
When a command is interrupted with Ctrl+C, the shell integration's
history-based command detection incorrectly inherits the previous
command's exit code. This happens because bash's `history` deduplicates
identical commands, so the hack that compensates for this sees the same
command text with an undefined exit code and assigns the last known one.
Fix by checking if the raw command line in the terminal buffer ends
with ^C before applying the history-merge heuristic. When interrupted,
report exit code 130 (128 + SIGINT) instead of inheriting.
Closes#237517
* fix: preserve undefined exit code for interrupted commands
Use the prompt input model's Ctrl+C signal to avoid applying the duplicate-history exit code workaround to canceled commands. Update the regression tests to cover the real duplicate-history command line and retain prior commands in expectations.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
---------
Co-authored-by: Megan Rogge <merogge@microsoft.com>
Co-authored-by: Dmitriy Vasyura <dmitriv@microsoft.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* nes: feat: generate samples from workspace recordings
Parse stateful local workspace recordings, select deterministic user-edit and cursor pivots, materialize privacy-safe replay slices, and support bounded parallel datagen without splitting raw timelines.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 62cca64b-0581-410e-ab89-034e20f02ca7
* nes: fix: include cursor boundaries in sample deduplication
Hash the complete post-pivot label so identical prompts with different cursor destinations are rejected as conflicting samples.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 62cca64b-0581-410e-ab89-034e20f02ca7
* nes: fix: consolidate workspace recording imports
Use inline type specifiers so the Copilot extension lint job accepts the new workspace-recording modules.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 62cca64b-0581-410e-ab89-034e20f02ca7
---------
Copilot-Session: 62cca64b-0581-410e-ab89-034e20f02ca7
* agentHost: preserve steering before queued messages
Buffer steering before invoking the SDK so synchronous echoes are correlated, and keep queued messages pending across the SDK's intermediate idle until steering is promoted.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* agentHost: strengthen steering timing tests
Keep mocked SDK sends unresolved while emitting steering events so the regressions exercise the in-flight race directly.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
---------
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Wait for the intentional sample failure and final telemetry event instead of relying on a fixed wall-clock delay.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Add Copilot cloud sandbox sessions over a live AHP relay
Copilot cloud sessions whose tasks run in a Mission Control sandbox (agent slug
`copilot-developer-cli`) are rendered by polling REST logs today, so they have no
slash commands and no steering.
Connect to the sandbox instead: `copilotd` runs inside it and speaks the Agent
Host Protocol, so once a relay is open the existing agent-host stack renders the
session natively — history, live output, steering and slash commands.
The sandbox is not directly addressable, so both sides connect outward to an
Azure Web PubSub relay brokered by Mission Control. Credentials are minted per
connection, and the user's GitHub token is forwarded only as a sealed envelope
the relay cannot read.
Everything runs in the renderer, so this also works in VS Code Web, where no
Copilot extension host is available. Mission Control is reached over the Copilot
API host: `api.github.com/agents/*` omits CORS headers on authenticated
responses, so a renderer fetch receives the reply and then discards it.
The AHP `initialize` now advertises every protocol version this client can
negotiate rather than only the newest, so a sandbox running an older `copilotd`
can negotiate down instead of being rejected.
Gated behind `chat.agentHost.cloudSandbox.enabled`, off by default.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Address PR review feedback for cloud sandbox sessions
- Subscribe to host state by the backend URI. Session output, changesets and
last-turn changes still rebuilt the URI from the UI scheme, so an aliased
sandbox session subscribed to a URI the host's registry does not know.
- Apply the session-scheme alias on the live `SessionAdded` path too. Only the
refresh and persistence paths adopted, so a session created while connected
kept the host's scheme and never routed to a content provider.
- Report discovery completeness instead of a bare list. A failed or partial scan
read as "these sessions no longer exist", so a transient request failure could
tear down live providers and cancel the auth retry. Only a complete scan is
reconciled against.
- Cancel in-flight work when the feature is disabled. Discovery and connect ran
with `CancellationToken.None` and did not recheck enablement after their
awaits, so either could commit state — including a live relay — after teardown.
- Document why publish acks are not tracked, and why the feature is gated on a
setting: sandbox tasks carry a slug the Copilot extension's cloud provider does
not list today, but that is expected to change.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Reuse the shared Copilot API host constant
The cloud sandbox service declared its own copy of `https://api.githubcopilot.com`
alongside the one in `githubEndpoints.ts`. Export the existing constant and use it,
noting that it is distinct from `IGitHubEndpoints.apiBaseUri` (`api.github.com`).
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
---------
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* agentHost: Remove obsolete tool arguments metadata
Use the AHP toolInput field as the sole source of tool invocation input instead of duplicating serialized arguments in the provider-specific _meta bag. Remove the legacy producer, typed metadata slot, and obsolete tests.\n\n(Written by Copilot)\n\nCo-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* agentHost: Address tool input review feedback
Reject array-valued tool input when synthesizing structured SDK arguments and make the history assertion validate the raw AHP toolInput representation directly.\n\n(Written by Copilot)\n\nCo-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* sessions: Fix voice bridge test construction
Supply the sessions and chat widget service mocks required by NewChatVoiceTargetService after concurrent voice changes landed on main.\n\n(Written by Copilot)\n\nCo-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Keep terminal tool failures expanded while preserving the collapsed state for other failed tool calls.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>