Skip to content

chat: persist timing for contiguous reasoning runs - #345121

Merged
Justin Chen (justschen) merged 4 commits into
mainfrom
agents/persistence-timing-tools-reasoning
Oct 30, 2026
Merged

Justin Chen (justschen) merged 4 commits into
mainfrom
agents/persistence-timing-tools-reasoning

Conversation

@justschen

@justschen Justin Chen (justschen) commented Oct 30, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

Persist the duration of each contiguous thinking run, not a total for an assistant message or a UI group.

tool -> thinking (5s) -> markdown -> thinking (12s) -> tool

This retains two independent durations, 5000 and 12000, including after database restart and UI reload. A run starts at its first nonempty reasoning text and ends at the next markdown/tool part or turn termination. SDK reasoning IDs, reasoning-complete events, full-message boundaries, and sideband notifications do not split it.

  • Measure each run with a monotonic clock and stable reasoning-part ID. A run spanning multiple SDK messages keeps one clock and one final duration.
  • Persist ordered reasoning/markdown pieces and tool references in assistant_response_parts, keyed by durable assistant-message IDs. Final timing updates earlier fragments of an unfinished run.
  • Restore the observed boundaries and retain canonical provider tool results. Merge fragments by run identity without adding their repeated duration; use recorded projections only when their text still matches the native transcript.
  • Carry timing through AHP updates, reconnects, local imports, and chat serialization. Single-run fallback headers show "Thought for 5s"; expanded conversation groups expose each run's own duration without a group-wide sum. Generated titles and conversation grouping remain available.
  • Keep turn remapping/pruning behavior and migrate without treating the earlier draft's aggregate reasoning_timing rows as individual run timings. Unknown or unfinished history stays untimed.
  • Preserve imported reasoning projections against synthesized SDK event IDs before resume; refresh finalized visible/ARIA labels when timing arrives late; and mark all AHP reasoning as provider-owned independently of optional timing values so reconnect tails never fabricate totals.

Companion protocol PR: microsoft/agent-host-protocol#552 is merged. The generated protocol source is pinned to merge commit d7a5579b; the protocol dependency is satisfied.

Scope: producer-side capture is implemented for Copilot. Other conforming hosts can supply the optional timing fields; this does not add capture to other providers, estimate older history, or change tool timing. Local, non-AHP providers retain their existing client-side reasoning measurement.

No issue was supplied for this feature request.

Validation

  • npm run build-fast -- --client-only — passed.

  • npm run typecheck-client — passed.

  • Changed-file ESLint — passed, using this command before committing:

    (git diff --name-only --diff-filter=ACM -z -- '*.ts'; git ls-files --others --exclude-standard -z -- '*.ts') | xargs -0 npm run eslint --
  • Repository hygiene — passed, using this command before committing:

    (git diff --name-only -z; git ls-files --others --exclude-standard -z) | xargs -0 npm run precommit --
  • npm run stylelint -- src/vs/workbench/contrib/chat/browser/widget/chatContentParts/media/chatThinkingContent.css — passed, with 15 pre-existing design-token suggestions. CSS is unchanged by the review follow-up.

  • Initial contiguous-run implementation validation, before the review follow-up below — 3,378 passed; 2 existing pending:

    ./scripts/test.sh --reporter dot \
      --run src/vs/platform/agentHost/test/node/copilotReasoningTiming.test.ts \
      --run src/vs/platform/agentHost/test/node/sessionDatabase.test.ts \
      --run src/vs/platform/agentHost/test/node/mapSessionEvents.test.ts \
      --run src/vs/platform/agentHost/test/node/copilotAgentSession.test.ts \
      --run src/vs/platform/agentHost/test/node/copilotSubagentTracking.test.ts \
      --run src/vs/workbench/contrib/chat/test/common/model/chatModel.test.ts \
      --run src/vs/workbench/contrib/chat/test/browser/agentSessions/stateToProgressAdapter.test.ts \
      --run src/vs/workbench/contrib/chat/test/browser/agentSessions/agentHostChatContribution.test.ts \
      --run src/vs/workbench/contrib/chat/test/browser/agentSessions/importLocalConversationToAgentSession.test.ts \
      --run src/vs/workbench/contrib/chat/test/browser/widget/chatContentParts/chatThinkingContentPart.test.ts \
      --run src/vs/workbench/contrib/chat/test/browser/widget/chatListRenderer.test.ts \
      --grep 'CopilotAgentSession|CopilotReasoningTiming|SessionDatabase|mapSessionEvents|ChatModel|^Response|ChatResponseModel|stateToProgressAdapter|ChatThinkingContentPart|importedTurnsFromChatModel|CopilotSubagentTracking|ChatList|AgentHostChatContribution.*reasoning'

The tests cover separate 5s/12s markdown/tool boundaries through real SQLite close/reopen and UI reload in Compact, Verbose, and Conversation modes; a single run spanning SDK messages; partial/mismatched recordings; parent/child isolation; legacy aggregate migration; and accessible labels.

The final AHP pin update left all 62 generated protocol TypeScript files byte-identical to the validated code. The companion PR records protocol/client validation and Kotlin/.NET toolchain limitations.

Live-provider/E2E flows and manual screen-reader testing were not run.

Review follow-up validation

Commit 4709ddbace5 addresses the three selected review comments. New regressions cover imported 45s/zero/unknown timing through event-log and real database reopen (including synthesized turn IDs), late header/ARIA refresh for string and array reasoning, an earlier run in a finalized conversation group, and continued untimed AHP output after reconnect without changing local-provider measurement.

Build, client type-check, changed-file ESLint, and hygiene were rerun successfully. The focused surrounding regression selection passed 1,773 tests, with 2 existing pending:

./scripts/test.sh --reporter dot \
  --run src/vs/platform/agentHost/test/node/buildSessionEvents.test.ts \
  --run src/vs/platform/agentHost/test/node/copilotAgent.test.ts \
  --run src/vs/platform/agentHost/test/node/mapSessionEvents.test.ts \
  --run src/vs/platform/agentHost/test/node/copilotReasoningTiming.test.ts \
  --run src/vs/workbench/contrib/chat/test/common/model/chatModel.test.ts \
  --run src/vs/workbench/contrib/chat/test/browser/agentSessions/stateToProgressAdapter.test.ts \
  --run src/vs/workbench/contrib/chat/test/browser/agentSessions/agentHostChatContribution.test.ts \
  --run src/vs/workbench/contrib/chat/test/browser/widget/chatContentParts/chatThinkingContentPart.test.ts \
  --run src/vs/workbench/contrib/chat/test/browser/widget/chatListRenderer.test.ts \
  --grep 'buildSessionEventsFromTurns|CopilotAgent.*import|mapSessionEvents|CopilotReasoningTiming|ChatModel|^Response|ChatResponseModel|stateToProgressAdapter|ChatThinkingContentPart|ChatList|AgentHostChatContribution.*reasoning'

Preserve producer-owned timing across live updates, reconnection, and saved chat history so fallback thinking headers retain their elapsed time. Record Copilot reasoning against durable assistant-message IDs without timing replay or inventing missing historical durations.

Sync the optional protocol fields from microsoft/agent-host-protocol commit f9d401d7.

Co-authored-by: Copilot <[email protected]>
@github-actions

github-actions Bot commented Oct 30, 2026 •

Copy link
Copy Markdown
Contributor

Screenshot Changes

Base: 7d3d76df Current: 6553ea6b

Changed (8)

chat/agent-lifecycle/chatAgentLifecycle/CompletedSectionBeforeSubagents/Light
Before After
before after
chat/agent-lifecycle/chatAgentLifecycle/CompletedThinkingAfterSubagents/Light
Before After
before after
chat/agent-lifecycle/chatAgentLifecycle/CompletedAgentReadAfterSubagents/Light
Before After
before after
chat/agent-lifecycle/chatAgentLifecycle/PersistentCompletedSectionBeforeSubagents/Light
Before After
before after
chat/agent-lifecycle/chatAgentLifecycle/PersistentCompletedThinkingAfterSubagents/Light
Before After
before after
chat/agent-lifecycle/chatAgentLifecycle/PersistentCompletedAgentReadAfterSubagents/Light
Before After
before after
chat/chatSubagentContent/ThinkingAcrossCompletion/Light
Before After
before after
chat/chatSubagentContent/ReadOnlyThinkingAcrossCompletion/Light
Before After
before after

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Reasoning timing is lost after import and reopen, does not refresh finalized headers or ARIA labels, and can produce fabricated totals after reconnect when hosts omit timing fields.

3 open issues
What changed in this PR

This PR carries producer-recorded reasoning durations through the Agent Host and chat UI so untitled thinking sections can retain labels such as “Thought for 45s” after reload or reconnect.

Changes:

  • Measures Copilot reasoning fragments and persists timing with turn remapping and pruning support.
  • Adds optional protocol timing fields and forwards them through live updates, restored history, imports, and chat serialization.
  • Updates fallback headers and accessible labels, with focused persistence, reconnect, model, and UI tests.
File Description
src/​vs/​workbench/​contrib/​chat/​test/​common/​model/​chatModel.test.ts Tests timing-only updates, distinct IDs, and serialization.
src/​vs/​workbench/​contrib/​chat/​test/​browser/​widget/​chatContentParts/​chatThinkingContentPart.test.ts Tests recorded-duration headers and accessible labels.
src/​vs/​workbench/​contrib/​chat/​test/​browser/​agentSessions/​stateToProgressAdapter.test.ts Tests history and reconnect timing conversion.
src/​vs/​workbench/​contrib/​chat/​test/​browser/​agentSessions/​importLocalConversationToAgentSession.test.ts Tests timing fields in imported turns.
src/​vs/​workbench/​contrib/​chat/​test/​browser/​agentSessions/​agentHostChatContribution.test.ts Tests timing-only updates on opaque advertised chats.
src/​vs/​workbench/​contrib/​chat/​common/​model/​chatModel.ts Applies timing updates and separates reasoning IDs.
src/​vs/​workbench/​contrib/​chat/​browser/​widget/​chatContentParts/​chatThinkingContentPart.ts Displays recorded durations in fallback thinking titles.
src/​vs/​workbench/​contrib/​chat/​browser/​agentSessions/​agentHost/​stateToProgressAdapter.ts Converts protocol timing into chat thinking metadata.
src/​vs/​workbench/​contrib/​chat/​browser/​agentSessions/​agentHost/​importLocalConversationToAgentSession.ts Includes timing in imported reasoning parts.
src/​vs/​workbench/​contrib/​chat/​browser/​agentSessions/​agentHost/​agentHostSessionHandler.ts Emits timing changes independently of text changes.
src/​vs/​platform/​agentHost/​test/​node/​sessionDatabase.test.ts Tests timing storage, validation, remapping, and pruning.
src/​vs/​platform/​agentHost/​test/​node/​README.md Documents timing semantics and test coverage.
src/​vs/​platform/​agentHost/​test/​node/​copilotReasoningTiming.test.ts Tests measurement and database reopen restoration.
src/​vs/​platform/​agentHost/​test/​node/​copilotAgentSession.test.ts Tests producer timing publication and persistence.
src/​vs/​platform/​agentHost/​test/​common/​sessionTestHelpers.ts Adds timing storage to the database test double.
src/​vs/​platform/​agentHost/​node/​sessionDatabase.ts Adds the timing table and persistence operations.
src/​vs/​platform/​agentHost/​node/​copilot/​mapSessionEvents.ts Restores timing by durable assistant-event ID.
src/​vs/​platform/​agentHost/​node/​copilot/​copilotSubagentTracking.ts Exposes the owning root turn for subagent timing.
src/​vs/​platform/​agentHost/​node/​copilot/​copilotReasoningTiming.ts Measures and aggregates live reasoning intervals.
src/​vs/​platform/​agentHost/​node/​copilot/​copilotAgentSession.ts Integrates measurement with provider events and storage.
src/​vs/​platform/​agentHost/​node/​compatibleSessionDatabase.ts Delegates timing persistence operations.
src/​vs/​platform/​agentHost/​common/​state/​protocol/​channels-chat/​state.ts Adds optional reasoning start and duration fields.
src/​vs/​platform/​agentHost/​common/​state/​protocol/​channels-chat/​reducer.ts Applies reasoning timing updates to protocol state.
src/​vs/​platform/​agentHost/​common/​state/​protocol/​channels-chat/​actions.ts Defines optional timing fields and timing-only updates.
src/​vs/​platform/​agentHost/​common/​state/​protocol/​.ahp-version Pins the companion protocol revision.
src/​vs/​platform/​agentHost/​common/​sessionDataService.ts Defines the reasoning timing persistence contract.

Review effort: Balanced

Keep one reasoning identity and clock until markdown, a new tool call, or turn termination. Persist the observed response-part ordering and update runs that span SDK messages, rather than storing message-level totals.

Restore separate run durations and canonical tool positions, retain conversation grouping with per-run labels, and cover 5s/12s boundaries across database restart and UI reload. Pin the clarified contract from microsoft/agent-host-protocol#552.

Co-authored-by: Copilot <[email protected]>
@justschen Justin Chen (justschen) changed the title chat: persist agent-host reasoning timing chat: persist timing for contiguous reasoning runs Oct 30, 2026
Persist imported response projections against synthesized Copilot event IDs before resume. Refresh timing labels on finalized reasoning sections, including array and grouped content, and keep AHP timing provider-owned even when optional timing fields are absent.

Add import/reopen, late visible/ARIA label, and untimed reconnect regressions while preserving local-provider measurement.

Co-authored-by: Copilot <[email protected]>
Reference the merge commit of microsoft/agent-host-protocol#552. The generated protocol sources are unchanged.

Co-authored-by: Copilot <[email protected]>
@justschen
Justin Chen (justschen) marked this pull request as ready for review October 30, 2026 17:40
@justschen
Justin Chen (justschen) enabled auto-merge (squash) October 30, 2026 17:41
@justschen
Justin Chen (justschen) merged commit 2780fc5 into main Oct 30, 2026
55 checks passed
@justschen
Justin Chen (justschen) deleted the agents/persistence-timing-tools-reasoning branch October 30, 2026 18:43
@vs-code-engineering vs-code-engineering Bot added this to the 1.145.0 milestone Oct 30, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants