Skip to content

feat(provider): forward cursorParams to Cursor SDK model params - #132

Merged
Nomadcxx merged 1 commit into
Nomadcxx:mainfrom
breath57:feat/model-params-passthrough
Sep 26, 2026
Merged

Nomadcxx merged 1 commit into
Nomadcxx:mainfrom
breath57:feat/model-params-passthrough

Conversation

@breath57

Copy link
Copy Markdown
Contributor

What

Adds an optional cursorParams field that flows from the opencode request body into Cursor SDK model.params, so per-model parameters (reasoning effort, fast mode, context size, thinking) become selectable from opencode.

Why

The Cursor SDK catalog already exposes per-model parameters, e.g.

  • claude-opus-5: effort=[low|medium|high|xhigh|max], thinking=[false|true], context=[300k|1m], fast=[false|true]
  • gpt-5.6-sol: reasoning=[none|low|medium|high|xhigh|max]
  • composer-2.5: fast=[false|true]

and Agent.create({ model: { id, params: [{ id, value }] } }) accepts them (ModelSelection.params). Today the plugin drops all of it — the model id is carried as a plain string from the proxy to the runner.

How

cursorParams rides the same channel as the existing cursorModel field (opencode model options / variants.<name> → provider request body):

{
  "models": {
    "claude-opus-5": {
      "name": "Claude Opus 5",
      "options": { "cursorModel": "claude-opus-5", "cursorParams": "effort=high" },
      "variants": {
        "max": { "cursorParams": "effort=max,fast=true" }
      }
    }
  }
}

Accepted forms (normalized to [{ id, value }]):

  • "effort=high,fast=true" (comma/space separated k=v pairs)
  • JSON string: '[{"id":"effort","value":"high"}]'
  • array of { id, value }
  • plain object: { "effort": "high" }

Implementation (4 layers, minimal diff):

  • src/provider/boundary.ts — new pure resolveRuntimeParams() (tested)
  • src/plugin.ts — read body.cursorParams at both handler sites
  • src/client/sdk-child.ts — carry params in the NDJSON request (only when non-empty)
  • scripts/sdk-runner.mjs — buildModelSelection() → model: { id, params }

Compatibility

  • No cursorParams present → byte-for-byte identical behavior to today
  • Older runner + newer plugin: the extra field is ignored
  • cursor-agent backend: params are not representable there and are ignored

Tests

  • Unit: all accepted forms, invalid/empty → undefined, dedupe last-wins; NDJSON payload presence/absence; runner model-selection building
  • E2E (real API, SDK backend): the same request with and without params both complete (exitCode=0, done=true, no error events)

Notes

  • The plugin only forwards parameters; valid ids/values come from Cursor.models.list() (parameters per model, plus preset variants).
  • Follow-up (not in this PR): auto-generating opencode variants from catalog parameters, and documenting the parameter matrix.


Re-submission note

This is a re-submission: the previous PR (#130) was closed pending local verification on real hardware. GitHub refuses to reopen it (state cannot be changed — the branch was force-pushed or recreated), so a new PR is opened from the same branch. Branch content is unchanged (1 commit ahead of main, 0 behind). Now verified locally before submitting.

@Nomadcxx
Nomadcxx merged commit 4d600a6 into Nomadcxx:main Sep 26, 2026
2 checks passed
@Nomadcxx

Copy link
Copy Markdown
Owner

Thanks mate for the PR. The plugin now forwards OpenCode’s per-model settings to the Cursor SDK through cursorParams. Unit and integration checks pass, and the real API check covers requests with and without params. Thanks again.

cheers, RAMA

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.

2 participants