Skip to content

agentHost: implement Claude truncateSession (Phase 6.7 — Restore Checkpoint + Start Over)#323197

Merged
TylerLeonhardt merged 2 commits into
mainfrom
tyleonha/claude-truncate-session
Jun 26, 2026
Merged

agentHost: implement Claude truncateSession (Phase 6.7 — Restore Checkpoint + Start Over)#323197
TylerLeonhardt merged 2 commits into
mainfrom
tyleonha/claude-truncate-session

Conversation

@TylerLeonhardt

Copy link
Copy Markdown
Member

What

Implements IAgent.truncateSession for the Claude agent host, so the workbench's Restore Checkpoint and Start Over actions work end-to-end for Claude sessions (previously a no-op — only Copilot supported it).

This is Phase 6.7 of the Claude agent-host roadmap. Full implementation log: src/vs/platform/agentHost/node/claude/phase6.7-plan.md; roadmap entry marked done in src/vs/platform/agentHost/node/claude/roadmap.md.

How

Two flows, both keeping the same SDK session id / protocol URI (unlike fork, which mints a new id):

  • Restore Checkpoint (point-restore, turnId) — truncates the conversation in place via the SDK's resumeSessionAt option. The protocol turn is resolved to its SDK assistant-envelope uuid (reusing Phase 6.5's resolveForkAnchorUuid) and staged as a one-shot anchor the next turn's rebuild applies. The write is lazy: if the user restores then walks away without sending, the full pre-restore history is preserved.
  • Start Over (remove-all, no turnId) — tears down the live subprocess, deletes the on-disk transcript, and recreates a fresh provisional under the same id, preserving the model/agent/permissionMode overlay.

Notable sub-fixes

  • Deterministic teardown — remove-all awaits the subprocess's actual exit (Query.return() → the SDK's memoized cleanup()transport.waitForExit()) before deleting + respawning the same --session-id. Without this, the dying process re-flushed <id>.jsonl and the respawn failed with Session ID … is already in use.
  • Rebind consumer-loop handoff — fixed a pre-existing race (surfaced by truncation) where a post-restore turn could hang because the consumer loop didn't hand off to the rebound query.
  • Pipeline handle simplification — collapsed three overlapping query/process handles to two with one clear meaning each: _warm (subprocess), _query (the stream bound to it, lifetime mirrors _warm), and _needsRebind as the sole health signal.

Testing

  • Unit/integration: 427 Claude tests pass (incl. new coverage for resumeSessionAt projection, warm + cold point-restore, warm + cold remove-all, teardown ordering, the rebind handoff, and the post-abort steering guard).
  • Gates: typecheck-client, valid-layers-check, eslint, hygiene all clean.
  • Live E2E (real Claude): both flows verified — Restore Checkpoint (BANANA/ELEPHANT memory test: model forgot the truncated turn) and Start Over (clean recreate on same id), each across two cycles with zero already in use / stream ended / exit-1 / crashed errors across an 8-turn session.

🤖 Generated with Copilot CLI

…kpoint + Start Over)

Implements IAgent.truncateSession for the Claude agent host so the
workbench "Restore Checkpoint" and "Start Over" actions work end-to-end:

- Point-restore (turnId): truncates the conversation in place on the same
  SDK session id / protocol URI via the SDK's `resumeSessionAt` option. The
  protocol turn is resolved to its SDK assistant-envelope uuid and staged as
  a one-shot anchor the next turn's rebuild applies (lazy — full history is
  preserved if the user restores then walks away).
- Remove-all (no turnId, "Start Over"): tears down the live subprocess,
  deletes the on-disk transcript, and recreates a fresh provisional under the
  same id, preserving the model/agent/permissionMode overlay.

Teardown awaits the subprocess's actual exit (Query.return() -> the SDK's
memoized cleanup -> transport.waitForExit()) before deleting + respawning the
same `--session-id`, fixing a "Session ID ... is already in use" race. Also
fixes a pre-existing rebind consumer-loop handoff race surfaced by truncation
(post-restore turn could hang), and simplifies the pipeline's query handles
(single `_query` mirroring the warm subprocess; `_needsRebind` as the sole
health signal).

Unit + integration green (427 Claude tests); both flows live-E2E verified
against real Claude. See node/claude/phase6.7-plan.md for the implementation
log and node/claude/roadmap.md (Phase 6.7) marked done.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings June 26, 2026 19:42

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.

Pull request overview

Implements IAgent.truncateSession for the Claude agent host so the workbench’s Restore Checkpoint (point restore) and Start Over (remove-all) actions work end-to-end for Claude-backed sessions, aligning Claude with Copilot’s existing truncate behavior while preserving the same protocol session URI.

Changes:

  • Plumbs resumeSessionAt through Claude SDK options and stages a one-shot truncation anchor on ClaudeAgentSession to apply on the next rebuild.
  • Adds a deleteSession SDK binding and implements remove-all truncation by tearing down the live subprocess, deleting the transcript, and recreating a fresh session under the same id/URI.
  • Hardens the Claude SDK pipeline lifecycle (deterministic teardown + consumer-loop rebind handoff) and adds extensive regression tests + roadmap/plan documentation.
Show a summary per file
File Description
src/vs/platform/agentHost/node/claude/claudeAgent.ts Implements truncateSession (turnId restore + remove-all) and same-id recreation flow.
src/vs/platform/agentHost/node/claude/claudeAgentSdkService.ts Adds deleteSession to the Claude SDK service surface and passthrough bindings.
src/vs/platform/agentHost/node/claude/claudeAgentSession.ts Adds pending resumeSessionAt anchor + DB pruning helpers and forces rebind when anchor is staged.
src/vs/platform/agentHost/node/claude/claudeSdkOptions.ts Adds resumeSessionAt to buildOptions projection (resume-only).
src/vs/platform/agentHost/node/claude/claudeSdkPipeline.ts Adds deterministic shutdownAndWait, separates _needsRebind health, and fixes consumer-loop handoff across rebind.
src/vs/platform/agentHost/test/node/claudeAgent.test.ts Adds truncation test coverage (warm/cold restore, remove-all, teardown ordering, one-shot anchor).
src/vs/platform/agentHost/test/node/claudeAgent.integrationTest.ts Updates integration fake to include deleteSession stub.
src/vs/platform/agentHost/test/node/claudeSdkOptions.test.ts Adds tests validating resumeSessionAt option projection behavior.
src/vs/platform/agentHost/test/node/claudeSdkPipeline.test.ts Adds regression tests for rebind handoff and post-abort steering buffering.
src/vs/platform/agentHost/test/node/claudeSubagentResolver.test.ts Updates SDK fake to include deleteSession stub.
src/vs/platform/agentHost/test/common/sessionTestHelpers.ts Makes TestSessionDatabase record pruning calls for assertions.
src/vs/platform/agentHost/node/claude/roadmap.md Documents Phase 6.7 completion and supersedes earlier “no truncateSession” rationale.
src/vs/platform/agentHost/node/claude/phase6.7-plan.md Adds the Phase 6.7 implementation plan/retrospective documentation.

Review details

  • Files reviewed: 13/13 changed files
  • Comments generated: 4
  • Review effort level: Low

Comment thread src/vs/platform/agentHost/node/claude/claudeSdkPipeline.ts
Comment thread src/vs/platform/agentHost/node/claude/claudeSdkPipeline.ts
Comment thread src/vs/platform/agentHost/node/claude/claudeAgent.ts
Comment thread src/vs/platform/agentHost/node/claude/claudeAgentSession.ts Outdated
- claudeAgentSession: retain the pending truncation anchor until a rebuild
  succeeds (read it without clearing, clear only after materialize / rebuild
  installs the pipeline). A throw/cancel after reading no longer silently
  drops `resumeSessionAt`, so the next send retries the checkpoint restore.
  + regression test.
- claudeSdkPipeline: `_ensureQueryBound` now honors `_needsRebind` (rebuilds
  via the rematerializer like `send()` does) so pre-flight helpers
  (reloadPlugins / snapshotResolvedCustomizations) never operate on a dead
  stream after an abort/crash.
- claudeAgent: cold remove-all fails fast when no working directory is
  available (SDK cwd absent and no live session), mirroring `_resumeSession`
  and the fork path, instead of recreating a provisional that fails later.
- claudeSdkPipeline: pass the error object to the logger in shutdownAndWait
  instead of stringifying it, preserving stack traces.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@TylerLeonhardt TylerLeonhardt marked this pull request as ready for review June 26, 2026 20:32
@TylerLeonhardt TylerLeonhardt enabled auto-merge (squash) June 26, 2026 20:32
@TylerLeonhardt TylerLeonhardt merged commit cd6804d into main Jun 26, 2026
29 checks passed
@TylerLeonhardt TylerLeonhardt deleted the tyleonha/claude-truncate-session branch June 26, 2026 20:36
@vs-code-engineering vs-code-engineering Bot added this to the 1.127.0 milestone Jun 26, 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