Skip to content

fix(cursor): reuse conversation checkpoints for incremental continuation (#2054 rebased) - #2277

Merged
lidge-jun merged 6 commits into
devfrom
codex/land-2054
Aug 21, 2026
Merged

fix(cursor): reuse conversation checkpoints for incremental continuation (#2054 rebased)#2277
lidge-jun merged 6 commits into
devfrom
codex/land-2054

Conversation

@lidge-jun

Copy link
Copy Markdown
Owner

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:

  • Explicit stale/expired checkpointRef -> full-replay with the expired marker and no checkpoint bytes (mutation-proven: latest-fallback reuse fails the regression).
  • No-ref path keeps eligible prefix checkpoint reuse.
  • Restores Cursor prompt-cache reuse (root rebuild 58 -> 43k bytes previously resent every turn).

Verification

  • Focused five-file cursor suite 259/0 (2679 expects); tsc clean; mutation proof recorded.

Checklist

keepitmello and others added 6 commits August 21, 2026 15:38
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
@lidge-jun
lidge-jun requested a review from Ingwannu as a code owner August 21, 2026 06:43
@lidge-jun lidge-jun added the bug Something isn't working label Aug 21, 2026
@lidge-jun
lidge-jun merged commit c378435 into dev Aug 21, 2026
6 of 7 checks passed
@github-actions

Copy link
Copy Markdown
Contributor

Deterministic PR hygiene checks passed.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 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--) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge 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 👍 / 👎.

Comment thread src/adapters/cursor.ts
|| lastTransport.captured.byteLength === 0
) return;
const previousRef = _parsed._providerContinuation?.cursor?.checkpointRef;
const coveredMessageCount = _parsed.context.messages.length;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge 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 👍 / 👎.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants