agentHost: parallelize message send and git checkpoint capture (experiment) - #339195
Draft
Vijay Upadya (vijayupadya) wants to merge 2 commits into
Draft
Vijay Upadya (vijayupadya) wants to merge 2 commits into
Vijay Upadya (vijayupadya) wants to merge 2 commits into
Conversation
…experiment) Behind the experiment-controlled setting chat.agentHost.experimental.deferTurnStartCheckpoint (default off), a turn is sent to a provider that sets IAgentChats.supportsTurnStartBarrier while its turn-start checkpoint is still being captured. The pending capture is passed as IAgentChatContext.turnStartBarrier, and Copilot holds every tool in its onPreToolUse hook until it settles, so tools still cannot modify the working tree before the checkpoint describes it. Providers without the flag keep waiting before dispatch. Checkpoint readers (getBaselineCheckpoint, getTurnCheckpointPair) wait for a session's in-flight turn-start captures, since a session's first capture also creates its baseline. A failed deferred capture is logged and the turn continues. The experiment trigger fires in both arms once a turn with a checkpoint reaches a provider that supports the barrier. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot started reviewing on behalf of
Vijay Upadya (vijayupadya)
October 1, 2026 23:17
View session
Contributor
There was a problem hiding this comment.
Copilot review overview
🟡 Changes recommended
Mutation-capable prompt and session hooks can bypass the barrier and race checkpoint capture.
Review effort: Balanced
Findings: 1
Open (2)
What changed in this PR
Parallelizes turn dispatch with checkpoint capture behind an experimental setting while preserving tool-time checkpoint barriers.
Changes:
- Adds provider barrier capability and Copilot enforcement.
- Makes checkpoint readers await pending captures.
- Adds configuration, telemetry documentation, and tests.
| File | Description |
|---|---|
common/agent.ts |
Defines barrier contracts. |
common/agentHostSchema.ts |
Adds host configuration schema. |
common/agentHostStarter.config.contribution.ts |
Registers the experiment setting. |
common/agentService.ts |
Defines the setting identifier. |
node/agentSideEffects.ts |
Defers checkpoint waiting and reports exposure. |
node/agentHostCheckpointService.ts |
Tracks pending captures for readers. |
node/copilot/copilotAgent.ts |
Advertises and forwards barrier support. |
node/copilot/copilotAgentSession.ts |
Blocks tool execution on the barrier. |
OTEL.md |
Documents checkpoint timing behavior. |
test/node/agentSideEffects.test.ts |
Tests deferred dispatch and failure behavior. |
test/node/agentHostCheckpointService.test.ts |
Tests baseline-reader synchronization. |
test/node/copilotAgentSession.test.ts |
Tests tool barrier enforcement. |
💡 Configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Contributor
|
Base:
|
Plugin hook commands (SessionStart, UserPromptSubmit, ErrorOccurred, ...) can modify the working tree, so they now wait for the turn-start checkpoint like tools do. The barrier is also handed to prepareTurn and tracked per chat, so hooks that run while a session starts (before send installs the turn's barrier) wait too. Clarify when sendStageCheckpointMs is absent. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This branch has not been deployed
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 join this conversation on GitHub.
Already have an account?
Sign in to comment
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.


Summary
What's slow today: before the agent host sends your message to Copilot, it saves a snapshot of your workspace (a git checkpoint) so the agent's edits can be undone later. The message waits until that snapshot is finished. On Windows that takes 200–500 ms in a large repo, and it happens on every message, so the chat looks idle for that long before anything appears.
What this PR changes: the message is sent right away, and the snapshot is saved at the same time. The model can start thinking and responding immediately. The snapshot only has to be finished before anything changes the workspace, so every tool call (file edits, terminal commands, subagents) and every plugin hook command waits for it.
Result: on Windows, follow-up messages reach the model about 150–200 ms (around 30%) sooner, with the same undo and checkpoint guarantees as before.
It's off by default and behind the experiment setting
chat.agentHost.experimental.deferTurnStartCheckpoint. Follow-up to #339053.Before: the message waits for the snapshot
sequenceDiagram autonumber participant AH as Agent host participant Git as Checkpoint (git) participant CLI as Copilot runtime participant M as Model AH->>Git: capture turn-start checkpoint Git-->>AH: done (200–500 ms on Windows) AH->>CLI: send(turn) CLI->>M: first model request M-->>CLI: tool call CLI->>CLI: run toolAfter: the message is sent while the snapshot is saved, and tools and hook commands wait for it
sequenceDiagram autonumber participant AH as Agent host participant Git as Checkpoint (git) participant CLI as Copilot runtime participant M as Model par AH->>Git: capture turn-start checkpoint and AH->>CLI: send(turn, turnStartBarrier) CLI->>M: first model request end Git-->>AH: done M-->>CLI: tool call CLI->>AH: tool and hook commands wait for turnStartBarrier note over AH,CLI: Also applies to plugin hooks (SessionStart, UserPromptSubmit, ...) AH-->>CLI: barrier settled CLI->>CLI: run toolChanges
agentSideEffects.ts: when the provider supports it (IAgentChats.supportsTurnStartBarrier):turnStartBarrierthat settles with the checkpoint capture and hands it to bothprepareTurnandsendMessage;_reportExperimentTrigger(settingId)and held until the assignment context is available.copilotAgent.ts: keeps the current barrier for each chat. A session that is still starting (beforesend()) reads it from there, so SessionStart hooks also wait.copilotAgentSession.ts:_handlePreToolUsewaits for the barrier before any tool runs, and the runtime exposeswaitForTurnStartBarrier()for hooks.copilotPluginConverters.ts: every plugin hook command (PreToolUse, PostToolUse, UserPromptSubmit, SessionStart, SessionEnd, ErrorOccurred) waits for the barrier before it runs. Hooks with no plugin commands don't wait.agentHostCheckpointService.ts:getBaselineCheckpointandgetTurnCheckpointPairwait for any in-flight turn-start capture, so readers never see a missing baseline;sendStageCheckpointMsis left out whenever deferral is on and the provider supports the barrier, even if the capture already finished (documented inOTEL.md).timeToProviderDispatchshows the gain.Measurements
Setup:
ec2e580with this change's bundle.* Leaves out runs where
session.send()was held for up to 1.3 s by agithub-mcp-serverauth retry loop. The benchmark has no GitHub MCP auth, and the loop happened in both arms. It's tracked on the runtime side in github/copilot-agent-runtime#24238.† Within run-to-run noise. Time to first progress (UI) includes the model's own response time, which varies by about ±1 s between runs, so at n=4 differences under ~15% aren't meaningful. The "first model call" column is the reliable measure of this change, and the experiment will give the real UI number.
Notes:
How to test
"chat.agentHost.experimental.deferTurnStartCheckpoint": trueand use an agent-host (Copilot CLI) session in a git workspace.agenthost.log,sendMessage called/session.send() returnedappear beforegit write-treefinishes.SessionStartorUserPromptSubmithook command and confirm it runs only after the capture finishes.