ModelSelection silently ignores unrecognized fields, and run.model echoes the request

Where does the bug appear (feature/product)?

Cursor SDK

Describe the Bug

Model parameters must travel in params as {id, value} pairs. A parameter written as a top-level key, such as { id: "grok-4.5", effort: "high", fast: true }, is discarded with no error. In dist/esm/357.js the request proto is built from { modelId: t.model.id, parameters: (t.model.params ?? []).map(...) }, so nothing else on the selection is read. Values inside params are unvalidated too. Worst of all, run.model returns the object I passed rather than the resolved selection, so a dropped parameter is undetectable. Six of my pinned agents ran at default effort for months before I noticed.

Steps to Reproduce

Create a local agent with model: { id: "grok-4.5", effort: "high", fast: true }, send a prompt, and read run.model. It returns my object verbatim, including effort: "not-a-real-effort" if I substitute that. Reading dist/esm/357.js confirms why: the proto is new G4({ modelId: t.model.id, parameters: (t.model.params ?? []).map(...) }), and that value becomes runOptions.requestedModel, which the executor maps to modelParams. Top-level keys never enter the chain. Separately, params: [{ id: "effort", value: "not-a-real-effort" }] also runs to completion with no error.

Expected Behavior

Reject unrecognized fields on ModelSelection, and unknown parameter ids or values inside params, instead of dropping them silently. Failing that, make run.model report the resolved selection so a discarded parameter is at least observable.

Version Information

@cursor/sdk 1.0.24, Node 20.11.0, Linux 6.12.67. Local agents via Agent.create with JsonlLocalAgentStore. Models: grok-4.5, claude-opus-5.

Hey, thanks for the detailed write-up, the dist/esm/357.js analysis and the repro help a lot.

A couple quick notes on the expected behavior so your agents run with the right settings:

Model params are passed inside params as { id, value } pairs, not as top-level keys. So instead of { id: "grok-4.5", effort: "high", fast: true }, you should do:

model: {
  id: "grok-4.5",
  params: [
    { id: "effort", value: "high" },
    { id: "fast", value: "true" }
  ]
}

You can see the valid id and value options for each model via Cursor.models.list(). The catalog returns the available params and choices per model.

Also, for grok-4.5 the defaults are already effort=high and fast=true, so your pinned grok agents were probably running with exactly what you wanted the whole time. But for models with different defaults, like claude-opus-5, those top-level keys would be ignored and the model would run with its own defaults.

On the main point, I agree that silently normalizing unknown top-level keys and invalid params values, plus having run.model return the passed object instead of the resolved selection, makes it hard to detect when the SDK drops a param. That isn’t the intended developer experience. I passed this to the team as feedback, including a request to reject or warn on unknown keys and to return the resolved selection. No timeline yet, but I’ll post here if I get an update.