fix(cursor): reuse conversation checkpoints for incremental continuation (#2054 rebased) - #2277
Conversation
Preserve Cursor's returned ConversationStateStructure after a successful no-tool turn and reuse that snapshot on validated linear continuations instead of rebuilding the full root history. Tool-result turns reuse the last completed checkpoint plus only the uncovered suffix. Compaction, helper/shadow isolation, account or model mismatch, missing refs, decode failures, and invalid_argument recovery keep the existing full-replay path. Bind checkpoint snapshots to conversation, credential identity, and model affinity. Keep an opaque process-local checkpointRef on Responses continuation state, pin referenced blobs for the checkpoint lifetime, and never treat OpenCodex usage as a cache-hit counter. Refs #1527
Chat Completions / Codex Sol hops often omit previous_response_id and thread headers, so every hop minted a new conversation and missed the checkpoint store. Pin those hops to the first user text and reuse the live snapshot. Isolated helpers keep their own cache and stay off the parent thread. Refs #1527
Do not invalidate the checkpoint just committed during forced-fresh recovery. Invalidate the inherited ref, including compaction leftovers. Pin checkpoint blobs atomically, collect nested subagent blob ids, and keep suffix replay off the system prompt. Refs #1527
An explicit missing checkpointRef now expires instead of picking another snapshot. Ref-less Chat hops look up only a unique covered-prefix plus system digest. Identical first prompts no longer share a conversation. Expired snapshots are pruned by an unref timer, not the next request. Refs #1527
Length-prefix instruction and prefix hashes so delimiter splits cannot collide. Clear the failed transport before forced-fresh retry so the recovered turn cannot commit the previous attempt. The idle TTL test now pins a real blob and asserts the lease is gone after prune. Refs #1527
|
✅ Deterministic PR hygiene checks passed. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: a2f3c907b3
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| ): CursorCheckpointSnapshot | undefined { | ||
| const systemDigest = cursorInstructionDigest(parsed); | ||
| const modelId = cursorCheckpointModelAffinityId(request.modelId); | ||
| for (let covered = parsed.context.messages.length; covered >= 1; covered--) { |
There was a problem hiding this comment.
Exclude complete-prefix matches from checkpoint lookup
When a same-account request has no continuation ref and its entire message list matches a stored checkpoint prefix, this loop accepts the checkpoint even if the request is a brand-new chat. For example, after one chat sends "fix the tests", another new chat with the same system prompt and sole user message reuses the first chat's post-turn state and then sends that user message again as the active action, contaminating the new conversation with the earlier chat and duplicating its prompt. Require a strict uncovered suffix and proof of the provider-authored continuation, or otherwise bind prefix reuse to conversation/thread identity.
Useful? React with 👍 / 👎.
| || lastTransport.captured.byteLength === 0 | ||
| ) return; | ||
| const previousRef = _parsed._providerContinuation?.cursor?.checkpointRef; | ||
| const coveredMessageCount = _parsed.context.messages.length; |
There was a problem hiding this comment.
Advance checkpoint coverage past the generated reply
The captured post-turn ConversationStateStructure must already contain the assistant reply—otherwise the next ordinary checkpoint continuation, which sends only the new user action, would lose that reply—but this boundary counts only the request's input messages. If that next turn emits a tool call, the following tool-result request slices its suffix from this stale count and appends the already-checkpointed assistant reply again before the new user/tool exchange, duplicating model-visible history and potentially changing or invalidating the continuation. Record the actual expanded-message boundary including the generated assistant output before using it as checkpointSuffixStart.
AGENTS.md reference: src/AGENTS.md:L19-L19
Useful? React with 👍 / 👎.
Summary
Lands PR #2054 by @keepitmello (Cursor conversation-checkpoint reuse for incremental continuation), rebased onto current dev with the reviewer's fail-closed contract proven:
Verification
Checklist