Repository navigation
fix(cursor): fail broken Cursor turns and keep permanent errors after turn end - #425
Merged
Merged
Conversation
…e patch Run each workspace manifest's dependencies through the same pin-and-match check desktop and CLI staging use, so a spec that drifts from a patched version (as @cursor/sdk 1.2.0 did against the 1.3.1 patch) fails in the scripts tests instead of at release time. Claude Opus 5.5 via Cursor in T3 Code
finalizeTurn always reported the provider thread as active, so after an unconfirmed checkpoint the session manager kept the loaded runtime and the next turn reused the uncertain agent. Report error for a broken disposition, as OpenCode does, so the next turn opens a fresh agent with a context handoff. Claude Opus 5.5 via Cursor in T3 Code Co-authored-by: Cursor <cursoragent@cursor.com>
The 1.3.1 retry guard replaced every non-cancelled classifier decision after turnEnded with the checkpoint-uncertain error, so authentication and other permanent failures lost their kind and message. Only block retries; throw decisions now pass through with their original error and diagnostics. Claude Opus 5.5 via Cursor in T3 Code Co-authored-by: Cursor <cursoragent@cursor.com>
Assert that finalizeTurn reports error for a broken disposition and active otherwise, and that after turnEnded the SDK retry guard rewrites only retry decisions; every throw keeps its original error and kind. Claude Opus 5.5 via Cursor in T3 Code Co-authored-by: Cursor <cursoragent@cursor.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Base:
main(branched from8d639a339662c67b794486acc9a5a0ec713eeb34; merges cleanly with current main25e868c3d1383ba23e3910e4b6e0e67dc8b614e7, which adds only #424's one-lineci-full.ymltimeout change) · Head:fix/cursor-sdk-1.3.1-release-staging(88f29f5dac8b8da11fc7952af174f7b73127d72b)Problem
The #422 post-merge review returned HOLD (medium) with two Cursor state-correctness findings:
finalizeTurnin the Cursor adapter always reported the provider thread asactive, even when the turn ended with abrokenthread disposition (an unconfirmed checkpoint). The session manager unloads a runtime only when it seesstatus: "error", so the next message in the same runtime reused the uncertain agent instead of starting fresh.@cursor/sdk@1.3.1patch's retry guard (dist/s2code-retry.cjs) replaced every classifier decision afterturnEnded, other than cancellation, with the checkpoint-uncertain error. Permanent failures such asAuthenticationErrorlost their kind, message and diagnostics.#423 already shipped the
apps/server@cursor/sdk1.3.1 pin and its lockfile refresh, the cause of the desktop-staging failure in Fork release run 42321780105. This PR does not repeat that change.Fix
packages/provider-cursor/src/server/adapter.ts:finalizeTurnnow sendsstatus: threadDisposition === "broken" ? "error" : "active", as the OpenCode adapter does, so the manager drops the loaded runtime.patches/@cursor__sdk@1.3.1.patch: the guard now blocks only retry decisions:blocked = turnEnded && decision.action === "retry" && checkpoint !== "ineligible_terminal_turn".throwdecisions, including auth, permanent and cancelled errors, pass through unchanged with their original diagnostics. The patch's hunk length andindexhash were corrected.pnpm-lock.yaml: only the@cursor/sdk@1.3.1patch hash changes (9539e59b…to55ea990e…). No specifier or version changes.scripts/build-desktop-artifact.test.ts: a broader check runs every workspace manifest'sdependencies,optionalDependenciesanddevDependencies(after resolvingcatalog:specs) through the same pin-and-match logic that desktop and CLI staging use. A spec that drifts from a patched version now fails in the scripts tests instead of at release time. This sits alongside fix(release): align packaged Cursor SDK with retry patch #423's narrower server-equals-provider assertion.Regression tests
adapter.test.ts"ends the turn with $reason": the lastprovider_thread.updatediserrorfor abrokendisposition andactiveotherwise.OrchestratorReplayRecovery.integration.test.ts"hands the next Cursor turn to a fresh agent after an unconfirmed checkpoint": both turns run in the same runtime, and the second turn must open a new agent (agent-after-checkpoint-failure) with an inlineContext handoff (full_thread_summary).cursorRetry.test.ts"authentication failure after an answer", for both cjs and esm: the error keeps its original message andkind: AuthenticationError, and the diagnostic recordsthrowwith the original cause.cursorRetry.test.ts"turns only retries into checkpoint failures": afterturnEnded,retrybecomes the checkpoint error, andthrowdecisions withAuthenticationError,CancelledErrororNonRetriableErrorcome back as the identical decision object.Verification (local, final SHA
88f29f5dac8b8da11fc7952af174f7b73127d72b)vp run check:changedpackages/provider-cursorfull suiteapps/serverorchestration-v2 Cursor suites (21 files)scripts/build-desktop-artifact.test.tsNegative controls. Each test fails without its fix and passes with it:
expected 'active' to equal 'error'throw AuthenticationErrorandthrow NonRetriableErrorrows fail1.2.0)apps/server/package.json dependencies: @cursor/sdk spec 1.2.0 does not match patched versions 1.3.1For (a) and (b), "without the fix" means reversing only the
finalizeTurnchange. For (c) and (d), it means swapping the base guard file intonode_modules.Staging proof (macOS arm64, built from
88f29f5dac8b8da11fc7952af174f7b73127d72b)The steps follow
release-desktop.yml, with Node 26.12.1, previous outputs deleted,--no-cacheon the bundle and desktop steps, and local placeholder version0.1.7-nightly.20261107.913:update-release-package-versions.ts, then restore afterwardsvp run --no-cache build:desktopcargo build --release --target aarch64-apple-darwincli.ts build-exebuild-cli-archive.tssmoke-cli-archive.tsvp run --no-cache dist:desktop:artifact --platform mac --target dmg --arch arm64 --skip-build --verbose --keep-stage/tmp/s2stage/final/release-cli/s2code-0.1.7-nightly.20261107.913-darwin-arm64.tar.gz03ea940ec57af0f299c20a11e9a03c1a6cc2672398a4fb5daf6b362c5909cc93release/S2Code-0.1.7-nightly.20261107.913-arm64.dmg033a08e18fd4c1557e5cc9f3ff15e561a2af8a7a1991211e92e0afe9a5decefcrelease/S2Code-0.1.7-nightly.20261107.913-arm64.zipb1d7e62d26396ddc3f0691503873a1261e4ace27e0bb6a1e2041a40ed9ec03be--version,__service-launcher, andserveanswered on port 47700.@cursor/sdk1.3.1 and@cursor/sdk-darwin-arm641.3.1.dist/s2code-retry.cjshasconst blocked = turnEnded && decision.action === "retry" && checkpoint !== "ineligible_terminal_turn";, and bothdist/cjs/305.jsanddist/esm/305.jscalls2codeRetryGuard.guard.isPublish: false.@cursor+sdk@1.3.1_patch_hash=55ea990e….app.asarcontains@cursor/sdk1.3.1 with the same guard line, called from both thecjsandesm305.js.package.jsonis version0.1.7-nightly.20261107.913and declares@cursor/sdk1.3.1. The unpacked@cursor/sdk-darwin-arm64is 1.3.1.Logs (under
/tmp/s2stage/final/):check-changed.log,provider-cursor-suite.log,server-cursor-suites-fg.log,build-desktop-artifact-test.loggate-{a,b,c,d}-{with,without}-fix.log,manifest-without-fix.logstamp.log,build-desktop.log,cargo.log,brand.log,build-exe.log,cli-archive.log,smoke-cli.log,desktop.logstaged-sha.txtrecords the staged SHA.Limits
dist/bundled/index.js, used only under thebunexport condition) is dormant and unpatched. The current Node CJS/ESM load path (requiretodist/cjs,importtodist/esm) is covered.Pending gates
None of these has completed yet: