Skip to content

fix(cursor): recover restarted threads with older runs - #24540

Open
juliusmarminge wants to merge 6 commits into
mainfrom
fix/issue-24498
Open

juliusmarminge wants to merge 6 commits into
mainfrom
fix/issue-24498

Conversation

@juliusmarminge

Copy link
Copy Markdown
Member

Problem

After a server restart interrupts a Cursor turn, later sends can fail permanently with already has active run. Reproduced on Linux with Cursor Auto by restarting twice during sleep 90: the first recovery cancels its orphan, but the second reads that older cancelled run and misses the currently running one.

Change

Follow the Cursor SDK run-list cursors and select the newest running run before the existing cancel-and-retry recovery. Keep the same resumed-session guard and single recovery attempt. The regression mock now models oldest-first pagination, with the abandoned run after 50 terminal runs.

Scope and approval

Fixes #24498

GitCafe: https://git.cafe/pingdotgg/t3code/issues/24498

Triaged bug via the automated issue flow. This changes only Cursor server recovery and its focused test; clients and wire contracts are unchanged. The reporter’s existing #24499 is left untouched.

Verification

  • Red regression on main: CursorAgentSdkRunnerError: Cursor Agent SDK run.start failed, caused by already has active run (one failed, one passed).
  • Final focused run after merging main: vp test run src/server/CursorAgentSdk.test.ts in packages/provider-cursor: 2 passed. The regression requires the active run on page two; a mock with no next cursor fails.
  • Scoped lint, format, and provider tsc --noEmit passed.
  • Two independent review rounds (GPT-6.1-Sol and Claude Opus 5.5) approved the final diff; proof audit passed.
Evidence Before After
Real web app, Linux x64, Cursor Auto, SDK 1.0.35 Runtime transcript: second restart and subsequent send fail Runtime transcript: both orphans cancelled, second recovery completes, subsequent send completes

Runtime proof used main 8176b58931 before and 1e2fe076db after. Final head merges current main; the two changed Cursor files are byte-identical to that tested after revision. The clean after run uses its own native agent, consistently across both recoveries and the follow-up. No render paths changed, so the visual matrix is empty. No platform-specific code changed; desktop/mobile shells were not separately exercised.

Models and harnesses: Claude Opus 5.5 through the Claude harness (tests and implementation); GPT-6.1-Sol through Codex and Claude Opus 5.5 through Claude (reviews); GPT-6.1-Sol through Codex (issue lead and proof).

juliusmarminge and others added 4 commits October 24, 2026 20:29
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Cursor's local store lists runs oldest first, so `listRuns({ limit: 1 })`
returned the thread's first run. Once an earlier restart had cancelled one
run, the next recovery saw that cancelled run, skipped the cancel, and the
resumed send failed with "already has active run" on every retry. Recovery
now walks every page via `nextCursor` and cancels the newest running run.

Fixes #24498

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@github-actions github-actions Bot added vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. size:S 10-29 changed lines (additions + deletions). labels Oct 24, 2026
macroscopeapp[bot]
macroscopeapp Bot previously approved these changes Oct 24, 2026
@macroscopeapp

macroscopeapp Bot commented Oct 24, 2026 •

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Approved at dd882d9

Macroscope's review found this PR approvable — The change searches all pages of local run history so resumed Cursor threads can recover when older runs precede the active run. It preserves the existing one-time, conflict-triggered cancellation and retry behavior.

You can add or adjust custom eligibility rules. Learn more.

@github-actions

github-actions Bot commented Oct 24, 2026 •

Copy link
Copy Markdown
Contributor

Thread transfer impact

✅ Thread transfer remains within every enforced ceiling.

Provider Metric Main baseline This PR Impact PR ceiling
Codex Total thread wire 5.0 KiB 5.0 KiB 0 B (0.0%) 6.8 KiB ✅
Codex Thread snapshot wire 3.8 KiB 3.8 KiB 0 B (0.0%) 4.9 KiB ✅
Codex Live turn WebSocket wire 1.2 KiB 1.2 KiB 0 B (0.0%) 2.0 KiB ✅
Codex Live turn WebSocket decoded 21.5 KiB 21.5 KiB 0 B (0.0%) 24.4 KiB ✅
Codex Live turn messages 1 1 0 (0.0%) 8 ✅
Claude Total thread wire 5.0 KiB 5.0 KiB 0 B (0.0%) 6.8 KiB ✅
Claude Thread snapshot wire 3.8 KiB 3.8 KiB 0 B (0.0%) 4.9 KiB ✅
Claude Live turn WebSocket wire 1.2 KiB 1.2 KiB 0 B (0.0%) 2.0 KiB ✅
Claude Live turn WebSocket decoded 21.9 KiB 21.9 KiB 0 B (0.0%) 24.4 KiB ✅
Claude Live turn messages 1 1 0 (0.0%) 8 ✅

Baseline: 3a8c250 · PR result: dd882d9 · Source CI: success

Scenario and decoded snapshot size

10 historical turns, 5 command tools per turn, 878.9 KiB retained MCP result per historical turn, and a 1.05 MiB retained result in the measured turn.

  • Codex decoded thread snapshot: 108.5 KiB
  • Claude decoded thread snapshot: 108.8 KiB

Updated in place by a trusted workflow. PR artifacts are strictly validated and never executed.

@coderabbitai

coderabbitai Bot commented Oct 24, 2026 •

Copy link
Copy Markdown
Contributor

Explain Change →

No actionable comments were generated in the recent review.

Walkthrough

The Cursor runner now paginates through run results during active-run recovery. It finds a running run beyond the first page, cancels it, and retries the send.

Changes: Cursor run recovery

Layer / File(s) Summary
Paginated abandoned-run recovery
packages/provider-cursor/src/server/CursorAgentSdk.ts, packages/provider-cursor/src/server/CursorAgentSdk.test.ts
The runner checks successive run-list pages and retains the last running run found. The test mock models paginated results and cancellation. A new test verifies cancellation of a running run on the second page and the subsequent retry.

Estimated code review effort: 2 (Simple) | ~10 minutes

Change: Bug fix · Severity of issue fixed: Medium

Sequence Diagram(s)

sequenceDiagram
  participant Runner as CursorAgentSdk
  participant SDK as Cursor Agent SDK
  Runner->>SDK: Agent.listRuns for successive pages
  SDK-->>Runner: Runs and next cursor
  Runner->>SDK: Agent.cancelRun for the running run
  Runner->>SDK: Agent.run.start retry
Loading

Possibly related PRs

  • pingdotgg/t3code#28718: This PR changes the CursorSdk loader used to obtain Agent for listRuns and cancelRun.

Suggested reviewers: yash-singh1, t3dotgg

Merge Risk: Minimal · up to dd882

This change lets Cursor threads recover after a server restart when the abandoned run is beyond the first page of runs. No actionable merge-blocking risk was identified.

Pre-merge checks: Passed 4

Check name Status Explanation
Title check Passed The title is concise, follows the conventional format, and clearly describes recovery for restarted Cursor threads with older runs.
Description check Passed The description includes all required sections: problem, change, scope and approval, and verification. It provides reproduction details, linked issue context, focused test results, and runtime evidenc…
Linked Issues check Passed Issue [#24498] requires recovery to find and cancel an abandoned Cursor run after restart, including when older terminal runs precede it. packages/provider-cursor/src/server/CursorAgentSdk.ts now fo…
Out of Scope Changes check Passed The changes are limited to Cursor server recovery and its focused test in packages/provider-cursor. The production change updates run pagination and active-run selection. The test change supports th…
Full details: Description check

Explanation

The description includes all required sections: problem, change, scope and approval, and verification. It provides reproduction details, linked issue context, focused test results, and runtime evidence.

Full details: Linked Issues check

Explanation

Issue [#24498] requires recovery to find and cancel an abandoned Cursor run after restart, including when older terminal runs precede it. packages/provider-cursor/src/server/CursorAgentSdk.ts now follows listRuns cursors and retains the last running run found. The existing cancellation and retry path remains in use. CursorAgentSdk.test.ts models oldest-first pagination and verifies that a running run after 50 terminal runs is found, cancelled, and followed by a new start.

Full details: Out of Scope Changes check

Explanation

The changes are limited to Cursor server recovery and its focused test in packages/provider-cursor. The production change updates run pagination and active-run selection. The test change supports that regression case. No client, wire contract, or unrelated change is shown.

Finishing Touches

Generate docstrings

  • Commit to this branch
  • Create a new PR
Generate unit tests (beta)

  • Commit to this branch
  • Create a new PR
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Usage-based review receipt

Note

This review was completed with usage-based billing: files reviewed beyond your plan's included limits are billed at $0.25/file. View usage-based billing.

Recent review info

Run configuration

Commits

Reviewing files that changed from the base of the PR and between 340cab4 and dd882d9.

Files selected for processing: 2

  • packages/provider-cursor/src/server/CursorAgentSdk.test.ts
  • packages/provider-cursor/src/server/CursorAgentSdk.ts

Limit details: You’ve used all 10 included reviews currently available.

Copy link
Copy Markdown
Member Author

The automated pipeline stopped on this pull request and will not merge it:

someone else pushed to fix/issue-24498 (head is now 340cab4); the pipeline does not build on commits it did not review

It stays open for a person to finish or close.

@macroscopeapp
macroscopeapp Bot dismissed their stale review November 11, 2026 08:13

Dismissing prior approval to re-evaluate dd882d9

This branch has not been deployed

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

Labels

bugfix Fix PR opened by an issue lead; enters the PR loop pr:gate-failed A land gate failed size:S 10-29 changed lines (additions + deletions). vouch:trusted PR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: Cursor thread never recovers after a restart during a run ("already has active run")

1 participant