Repository navigation
fix(server): write thinking with the switched-to Cursor model's option id - #6995
hungthai1401 wants to merge 2 commits into
Conversation
…n id Cursor names its thinking option per model: gpt uses `reasoning`, grok-4.6 uses `effort`, grok-4.7 uses `reasoning_effort`, Claude uses `thinking`. Paseo switched models with session/set_model, which answers with an empty result, so it kept the previous model's config options. The stored thinking level was then written with the old model's option id, and Cursor rejected it with "Unknown model config option". Creating or resuming an agent failed whenever the CLI's default model used a different thinking id than the agent's model. Cursor now switches models with a config-option write, which returns the new model's options, so the thinking and Fast writes that follow use the right ids. The behavior sits behind `switchModelViaConfigOption`, set only by the Cursor client, so the other ACP providers keep session/set_model. Checked against a real cursor-agent: creating grok-4.6 with thinking `low` from a gpt default failed before the change and starts after it. The new test fails on the old code with the same error. To undo, revert this commit. Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
[Medium impact] The PR appears safe to merge.
|
There was a problem hiding this comment.
Verified the startup fix for #7148 against the real Cursor CLI on Linux. With thinking low, switching from a GPT-5.6 Sol default to Grok 4.6 fails on main with Unknown model config option: reasoning; the reverse fails with ...option: effort. Both start with the requested model and thinking on 39b9de5c3.
The regression test fails on main with the matching error, and all 137 tests across the four related provider suites pass on this head. Local server build, repository typecheck and lint, and formatting checks for the changed files pass.
Resume remains unverified: the attempted conversation did not produce a resumable session, and lookup failed before thinking could be applied. The GUI was not exercised; this verifies provider startup.
CI run 38835707322 is green on this head, including Linux and Windows server tests. No review threads are unresolved. This PR is the verified fix for the reported startup failure; updates remain here.
There was a problem hiding this comment.
Stopped for the maintainer. The fix is correct at the layer that owns the stale state, and every checklist item passed on a real Cursor run, but a reply from a named Cursor model (Grok 4.6 or GPT-5.6 Sol) after the switch could not be run here, so that part of the checklist is not a pass.
Product delta: a Cursor agent created, resumed, or switched to a model whose thinking option has a different id than the model the Cursor CLI started on now starts with the requested model and thinking level, where it used to fail with Invalid params: Unknown model config option: reasoning (or effort).
Protocol delta: none.
For the maintainer:
-
Merge without having seen a named Cursor model answer a turn after the new model switch? Session setup, resume, and the switch were observed working against the real Cursor CLI. yes or no (yes)
-
Durability:adds one internal boolean on the ACP client options (switchModelViaConfigOption), not a user setting or wire change. -
Specificity:one contained branch insetModelWithSelection; only Cursor opts in, other ACP providers take the unchanged path. -
Risk:ships beside everything else; for Cursor the model is now switched withsession/set_config_optioninstead ofsession/set_model, which Cursor answers with the new model's options. -
Serves:any Cursor user whose agent's model differs from the CLI's starting model and whose stored thinking level differs; no workaround besides clearing thinking, and the fix is about 17 lines plus a test. -
Recommendation:merge.
What the pull request does
For Cursor, ACPAgentSession.setModelWithSelection (packages/server/src/server/agent/providers/acp-agent.ts) switches the model through the model config option when the session advertises it, so the session holds the new model's config options and the thinking and Fast writes that follow use the new model's option ids.
Review
- Fixes what was reported: yes. On main,
unstable_setSessionModelsucceeds but Cursor answers{}, soconfigOptionskeeps the previous model'sthought_leveloption, andsetThinkingOptioninapplyConfiguredOverrideswritesreasoningto a Grok session. The error escapesinitializeNewSession/initializeResumedSession. The regression test drivesinitializeNewSessionthrough a scripted ACP transport and fails on the merge base with the reported error. - Right fix: yes. The stale state is
ACPAgentSession.configOptions, and the change makes the session take the write whose response carries the new options, through the existingapplyConfigOptionResponse. Theset_modelpreference dates from a large unrelated commit, not a decision about this behavior. A wider reshaping is possible: preferring the config-option write for every ACP provider that advertises amodeloption would remove the flag and the stale-options case behindisStaleFeatureValueError(#5274) for all of them. That is not needed for this fix. - Anything else: no protocol, schema, user setting, dependency, or design change. Other providers are unchanged by construction: the flag defaults to
false, and onlyCursorACPAgentClientsets it. - Worth shipping: yes, a small change for a startup failure any Cursor user can hit by picking a different model with a thinking level.
QA checklist
All runs on the real Cursor CLI, an isolated daemon, and the web app from this branch, with the merge base swapped in for comparison.
- Reported scenario (CLI on GPT-5.6 Sol, agent created on Grok 4.6 / Low): pass for setup. Head creates the agent showing Grok 4.6 / Low; the merge base fails with
Unknown model config option: reasoning. Mirror case (CLI on Grok, agent on GPT-5.6 Sol / Low) starts on head. A reply from the named model was not run. - Regression test: pass.
cursor-acp-agent.test.ts10/10 on head, 1/10 failing on the merge base with the reported error; the four related provider suites 137/137 on head. - Resume: pass for setup. Seeded with a completed turn, switched to Grok 4.6 / Low, CLI default back to GPT, daemon restarted: head resumes showing Grok 4.6 / Low with no error; the merge base fails the same resume with
Unknown model config option: reasoningfrominitializeResumedSession. The follow-up turn on the named model did not produce a reply. - Model switch on a running agent: pass for the switch. Head switches GPT-5.6 Sol to Grok 4.6, shows Grok's thinking choices, and accepts the new level; on the merge base the model changes but setting Low fails with the same error. A reply from the named model was not run.
- Fast after a switch at creation: pass. Head creates Grok 4.6 / Low with Fast, and the agent's stored state records Fast on.
- Cursor CLI saved default model: no difference from main. Creating or switching an agent updates the CLI's saved default model on both head and the merge base.
Findings outside the checklist
- A
npm run typecheckafter rebuilding locally reported two errors in app files the pull request does not touch; an earlier local typecheck on the same head passed and CI typecheck is green on it. Not counted. - No review threads.
Decision
Stopped with needs-maintainer. Blocker: no turn on a named Cursor model was observed after the switch through setSessionConfigOption (acp-agent.ts, setModelWithSelection). What settles it: one Cursor turn on Grok 4.6 / Low after starting from a GPT default, answering on Grok 4.6.
Reviewed commit: 39b9de5
janacm
left a comment
There was a problem hiding this comment.
Looks good. I hit this from a running agent and landed on the same fix independently.
Field report: Paseo 0.11.4 desktop daemon, cursor-agent 2026.10.01-e373342, macOS. On a live Cursor agent, switching GPT-5.4 mini to Claude Opus 5.5 succeeds (set_agent_model_request success), then set_agent_thinking_request (xhigh) fails with Invalid params: Unknown model config option: reasoning. The same daemon log has the startup variant from metadata generation: cursor (gpt-5.4-mini): failed (Invalid params: Unknown model config option: reasoning_effort) and ...: effort. So this also stops branch-name generation from failing over when Cursor is the structured-generation provider.
Against the real CLI (same version): session/set_model answers {} with no config_option_update. session/set_config_option with model=claude-opus-5-5 returns mode, model, context, effort, fast, and the effort write after it succeeds. That matches the QA above.
Two small suggestions, neither blocking:
- The regression test covers
initializeNewSession. The path I hit issetModelfollowed bysetThinkingOptionon a live session. It goes through the samesetModelWithSelectionbranch, but a test for it would pin the mid-chat case. - The body says no issue was filed. #7148 exists now, so
Fixes #7148would close it on merge.
|
Ran the open item from the maintainer stop: a Cursor turn on Grok 4.6 / Low after starting from a GPT default, on head Setup: cursor-agent 2026.10.01-e373342, macOS, Running agent: created on GPT-5.6 Sol, then Reported scenario: CLI default GPT-5.6 Sol, agent created on Grok 4.6 / Low, then one turn: No Not covered: resume, and the app UI. |
|
Independent Linux reproduction confirms the same root cause for the This PR's model-switch-through- |
|
Additional affected-version confirmation: Paseo daemon 0.15.0, cursor-agent 2026.10.22-27dcf5f, Linux, built-in Cursor provider. Creating a chat on Grok 4.6 / High fails with I reviewed head One adjacent, apparently pre-existing correctness gap remains worth a regression test (not claiming this PR introduced it): the refreshed options do not update the cached
I isolated this using the installed ACP session implementation with this PR's config-option preference branch applied in memory, a scripted connection, and no live Cursor calls: This is an isolated check of the branch plus surrounding logic, not an end-to-end test of the PR checkout. The same missing synchronization is visible in the reviewed head. Suggestion: reconcile the cached thinking level with the target model's returned The exact |
Linked issue
No issue filed. The report and reproduction are below. Same root cause as #5274 (stale option snapshot after a Cursor model switch, there for Fast): this PR fixes it for thinking.
Type of change
Reasoning
Create a Cursor agent on Grok 4.6 with a thinking level stored on it (or resume one) while the Cursor CLI's saved default model is GPT-5.6 Sol. The agent is not created, and the composer shows
Invalid params: Unknown model config option: reasoning. The mirror case (default Grok, agent on GPT) fails with...option: effort. It only happens when the stored thinking level differs from the session's current value, so it shows up for some agents and not others.Cursor names its thinking option per model. From
cursor/list_available_modelson cursor-agent 2026.10.14:effortreasoning_effortreasoningthinkingsetModelWithSelectionswitches models withunstable_setSessionModel. Cursor answers it with{}, so Paseo keeps the previous model'sconfigOptions.applyConfiguredOverridesthen callssetThinkingOption, which finds the old model's option in that list and writes it for the new model. Cursor rejects the unknown id, the error escapesinitializeNewSession/initializeResumedSession, and the agent never starts.Cursor answers a config-option model write (
setSessionConfigOptionwith themodeloption) with the new model'sconfigOptions, andapplyConfigOptionResponsealready stores them. The Cursor client now uses that path when the session exposes a model option, so the thinking and Fast writes that follow use the right ids.Goals
switchModelViaConfigOption).Non-goals
unstable_setSessionModelreturn refreshed options, which Start a Cursor agent on a model that has no Fast variant #5274 left open. This sidesteps it by not using that call for Cursor.xhighon a model that stops athigh). That write still fails session start.QA
Environment: macOS 15, cursor-agent 2026.10.14-941492e, logged in. Server change only, no UI.
Reproduced the cause against the real CLI over ACP. Session starts on grok-4.6; after switching:
Before and after through
createSessionwith the real CLI (a throwaway script that built the Cursor client with and without the flag). The saved default wasgpt-5.6-sol, the agent asks forgrok-4.6with thinkinglow:The regression test (
writes the stored thinking level with the id of the model it switched to) fails on the oldacp-agent.tswith the same error and passes with the change:After, in a checkout installed with
npm ciandnpm run build:server:vitest runoncursor-acp-agent,cursor-acp-catalog,acp-agentandgeneric-acp-agent: 4 files, 137 tests passed.npm run typecheck,npm run lintandnpm run format:checkpass (the pre-commit hook runs them too).Not covered: I ran
createSession, notresumeSessionthrough a live daemon, though both call the sameapplyConfiguredOverrides. Only macOS and the CLI were exercised. Nothing in the change is platform specific, but I did not run it on Windows or Linux.Checklist
npm run typecheckpassesnpm run lintpassesnpm run formatpasses