Skip to content

fix: track Cursor SDK 1.0.37 protocol and catalog - #36

Open
CasualDeveloper wants to merge 1 commit into
otto-assistant:betafrom
CasualDeveloper:fix/cursor-sdk-1.0.37-compat
Open

CasualDeveloper wants to merge 1 commit into
otto-assistant:betafrom
CasualDeveloper:fix/cursor-sdk-1.0.37-compat

Conversation

@CasualDeveloper

@CasualDeveloper CasualDeveloper commented Oct 15, 2026 •

Copy link
Copy Markdown
Contributor

Hey @makeittech, here's a follow-up to #35 that brings the adapter up to Cursor SDK 1.0.37. Our protocol handling was still based on 1.0.31.

Issue for this PR

Refs #31.

Type of change

  • Bug fix

What does this PR do?

Safety-fallback notices no longer show up as assistant text. When Claude Opus hits Cursor's safety filter and Cursor switches models, Cursor streams a "Switched to …" notice. The adapter treated it as part of the model's reply, so it was saved to OpenCode's history and replayed on later turns. SDK 1.0.37 marks these notices with TextDeltaUpdate.is_server_notice, so I now use that flag to keep them out of the reply and the continuation history. The notice text goes to providerMetadata.cursor.serverNotice, plus a warning from doGenerate. This doesn't depend on model names or notice wording.

New Cursor messages no longer fail Runs. SDK 1.0.37 adds a few messages the adapter didn't know about:

  • Client-presentation updates (routed model, prompts, branch changes, feedback, response comparisons, context state, nudges) are ignored. Before, one arriving after turnEnded failed the Run.
  • AgentServerMessage.ttft_breakdown is latency telemetry and is ignored. Before, it failed the Run as an unsupported interaction.
  • New Cursor-hosted requests (PR management, MCP auth, image generation, environment replacement, source-control connection) are declined with the same fail-closed reply layout the official SDK uses for local runs.

No more duplicate Claude Opus 4.6 1M. GetUsableModels also returned a legacy Opus 4.6 alias under a different id that routed to the same Cursor model. The picker therefore showed two "Claude Opus 4.6 1M" entries, one with the wrong context window. A usable-model family whose wire ids already belong to an AvailableModels family is now dropped.

One shared client version. Both workers and the capability probes now read the Cursor CLI client version from one constant. It stays at the January build, cli-2026.01.09-231024f. Cursor varies server behavior by client version, so a bump should wait for a live end-to-end check.

Clearer truncated-stream errors. A premature-eof error now says whether Cursor cut the stream in the middle of a frame. If it did, the error gives the frame's declared size, the bytes received, and how many frames came before it. The Run also reports whether turnEnded and a final checkpoint had arrived. In long conversations (about 1,080 messages) Cursor closed the stream partway through a roughly 36 KB message, before turnEnded, and that message grew by 68 bytes on each retry. The size fits the end-of-turn checkpoint, which lists every message. This PR only reports the problem. Those Runs still fail.

How did you verify your code works?

npm test passes with 97 tests and npm run typecheck is clean. The tests include new regressions for flagged notices, presentation updates, latency telemetry, the newer hosted requests, and the alias duplicate. On an earlier revision of this branch, npm run verify passed, Composer completed real read and shell calls through the rebuilt plugin, and the live catalog showed one Claude Opus 4.6 1M with a 1M context. Those live checks ran before the client version and diagnostics changes, and I haven't repeated them since.

The notice regression uses a synthetic flagged message. I haven't yet caught a real Opus fallback going through the rebuilt adapter.

OpenCode currently drops provider warnings from streamed responses, so the notice is kept in metadata but not shown in the UI. Displaying it would need an OpenCode change.

Checklist

  • I have tested my changes locally.
  • I have not included unrelated changes in this PR.

Cursor marks its own notices, such as a safety-filter model fallback,
with TextDeltaUpdate.is_server_notice. The adapter streamed them as
assistant text, so the notice was saved and replayed as model output.
Keep flagged text out of the reply and the continuation history, and
report it as providerMetadata.cursor.serverNotice and a doGenerate
warning. The flag identifies notices without matching model names or
message wording.

Ignore SDK 1.0.37 client-presentation updates (routed model, prompts,
branch changes, feedback, comparisons, context state, nudges) and
AgentServerMessage.ttft_breakdown latency telemetry. Each was previously
an unsupported interaction or output after turnEnded, failing the Run.

Decline the newer Cursor-hosted interaction queries (PR management, MCP
authentication, image generation, environment replacement, and source
control connection) in the reply layout the official SDK uses for local
runs, instead of failing the Run.

Drop a GetUsableModels family whose wire IDs already belong to an
AvailableModels family under another id. Cursor listed a legacy Opus
4.6 alias that way, so the picker showed two "Claude Opus 4.6 1M"
entries, one with the wrong context window.

Report the Cursor CLI client version from one shared constant used by
both workers and the capability probes. Keep it at
cli-2026.01.09-231024f: Cursor varies server behavior by client version,
so a bump needs a live end-to-end check first.

Describe truncated streams in premature-eof errors. The transport
reports the cut frame's declared and received sizes and the frame count,
and the Run adds whether turnEnded and a final checkpoint arrived. Long
conversations showed Cursor closing the stream mid-message before
turnEnded; these details separate that from a missing end frame.

Verified with npm test (97 tests) and npm run typecheck. Earlier live
read and shell calls on Composer through the rebuilt plugin showed one
Claude Opus 4.6 1M catalog entry; they predate the client version and
diagnostics changes.

Refs otto-assistant#31
@CasualDeveloper
CasualDeveloper force-pushed the fix/cursor-sdk-1.0.37-compat branch from e5e386d to f32d68c Compare October 15, 2026 20:48
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.

1 participant