Skip to content

[Feature Request] Expose Cursor per-model config options (thinking, effort, context, fast) over ACP and make model switching reliable #343

Description

@Tigatron

Affected area

Agent runtime / ACP

Problem or workflow pressure

When Lody connects to the registry Cursor agent (cursor-agent acp), the run-config menu shows only what the one session/new snapshot happened to describe. Two problems follow:

  1. Cursor's ACP agent exposes its model parameters — a thinking on/off select, an effort/reasoning ladder, a context window select, and a fast on/off select — per model, and only when the client declares clientCapabilities._meta.parameterizedModelPicker: true at initialize. Lody does not declare it, so Cursor runs in its legacy "variants" mode: exploded model ids, no per-model options, and an in-session model switch through session/set_config_option matches by variant string and silently fails (the same failure is reported for Zed in Cursor ACP in Zed: Composer 2.5 Fast Mode Issue zed-industries/zed#57571 and in the Cursor forum thread "Can't select thinking level or variant in Cursor ACP").
  2. Even with the picker enabled, a capability probe snapshot describes only the model that was current at probe time. Cursor rebuilds the option set on every model switch and rejects a value the new model does not support, so a landing/draft chat (which has no live ACP session yet) cannot show the right options for any other model, and an existing session shows the probe-time model's options whichever model is selected.

This affects every Cursor user of the desktop app: thinking, effort, context, and fast are not reachable from Lody, and switching models can leave the agent on the wrong model.

Desired outcome

  • Adding the Cursor agent in Settings or pressing its Test/refresh action fetches the whole per-model option catalog once and stores it with the machine's capability cache.
  • The composer (landing, draft, and existing sessions alike) shows, for the selected model, exactly that model's options: the effort ladder in the Reasoning row, a Thinking toggle, a Fast toggle, and provider-defined selects such as Context; models without options show none.
  • Existing Cursor sessions pick up new models and per-model options after a refresh without any per-session migration, and switching the model inside a session applies the model before the per-model options so Cursor accepts them.
  • MCP lody_session_create / lody_session_create_options map reasoningEffort / fastMode against the target model's options rather than the probe-time model.

Proposed solution

Three independently reviewable PRs, all provider-neutral below the Cursor entry point:

  1. CLI + shared foundation: opt registry Cursor (identity cliType: 'registry', agentType: 'cursor'; never a same-named custom config) into parameterizedModelPicker at initialize; during the explicit machine/acp-capabilities-refresh probe call Cursor's side-effect-free cursor/list_available_models once after session/new and store the result as AcpCapabilityCacheEntry.configOptionsByModel (JSON-RPC -32601 = no catalog; validation failure, duplicate model, timeout, or any other failure fails the probe with [ACP_CAPABILITIES_INCOMPLETE] so Test can be retried; a real session's snapshot write preserves the stored catalog for the same sourceVersion). Add the one composition rule resolveAcpConfigOptionsForModel in @lody/shared (snapshot options no catalog entry owns + the selected model's entry; model/mode always from the snapshot; unknown model → snapshot) and true/false toggle recognition for Fast. Make the ACP run-config applier switch the model before applying per-model options. No RPC schema, SessionDoc, or cache-version change.
  2. Components: resolve landing/draft/session/Role selector catalogs through that rule using the model the composer actually writes (model config option for registry/custom agents, dedicated picker for builtin); split toggle-shaped thought_level options into their own Thinking row beside Plan/Fast (desktop menu + mobile sheet) with a face mark, keeping the Reasoning row bound to the multi-level ladder; Fast accepts true/false selects.
  3. MCP/CLI: map reasoningEffort/fastMode and validate/inherit turn config options against the target model's composed options.

Real cursor-agent 2026.08.31 output shaped the parser: 37 models; thinking/fast values are exactly "false"/"true"; one model can carry both thinking and effort; context is category model_config; some models publish no options.

Alternatives or workarounds

  • Enumerating models through session/set_config_option during the probe: rejected, because each call rewrites the user's global Cursor CLI config (selectedModel) and costs N round trips; cursor/list_available_models performs no writes.
  • Persisting a live option catalog per session in the SessionDoc: rejected; the catalog is a machine-level capability, and landing/draft chats have no SessionDoc.
  • Refreshing the catalog from inside a running session: rejected to keep sessions free of extra RPCs; the startup capability refresh and the Settings Test action own the catalog.
  • Running Cursor CLI outside ACP, as the Cursor team suggests in the forum thread, loses Lody's session model entirely.

Trade-offs or non-goals

  • The opt-in is gated on registry identity only; a custom config that launches the same binary keeps standard ACP behavior.
  • No catalog completeness check against the snapshot's model list: a model the catalog does not know falls back to the snapshot on purpose (explicit and documented), so a backend that omits one model cannot make the whole catalog unavailable.
  • The Test/refresh action is the only catalog source; adding the agent does not auto-probe (matching current behavior for registry agents), and the startup capability refresh re-probes every configured agent anyway.
  • Related work: [Bug] Grok 4.6 reasoning effort picker is missing Medium (uses probed model's ladder) #149 / fix(acp): pick the reasoning-effort ladder from the selected model #286 make the reasoning-effort ladder follow the selected model for Grok through modelReasoningEfforts. This proposal composes with it — the shared mapping prefers modelReasoningEfforts when present and otherwise reads the per-model catalog — but the two touch acp-selector-options.ts, agent-role-editor-dialog.tsx, and ai.ts, so whichever lands second rebases. Happy to sequence the UI part after fix(acp): pick the reasoning-effort ladder from the selected model #286 if that is preferred.
  • A Kimi model whose only thought control is an off/on thinking select renders as a Thinking toggle instead of a two-row Reasoning dropdown; the Kimi adapter's own comment states the select shape exists only because Zed's chip strip cannot draw booleans.

Additional context

  • parameterizedModelPicker is a Cursor-side _meta extension that is not publicly documented (Cursor forum: "Can't select thinking level or variant in Cursor ACP"); Zed does not declare it yet (Cursor ACP in Zed: Composer 2.5 Fast Mode Issue zed-industries/zed#57571).
  • Verified against the desktop app with an isolated data directory: adding Cursor and pressing refresh yields the catalog in about 5 seconds; claude-opus-4-7 shows Context 300K/1M, effort low…max, Thinking and Fast toggles; gemini-3.1-pro shows none; gpt-5.4 shows reasoning none…extra-high, Fast, Context and no Thinking; a turn with Thinking on and effort high completes without a rejected-selection warning, and switching the same session to gpt-5.4 updates the menu immediately.
  • Implementation is ready on a fork; PR 1 will be opened for review and PRs 2–3 as drafts stacked on it so the whole change is visible.

Before submitting

  • I searched the existing issues and did not find a duplicate request.
  • This request concerns an open-source component in this repository, not a hosted service, Web or mobile app, account, or billing issue.
  • I removed credentials, private source, conversations, prompts, personal data, and other sensitive information.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions