Skip to content

fix(provider): pin per-model default params on subagent turns#71

Merged
justin-carper merged 2 commits into
mainfrom
subagent-default-model
Jul 16, 2026
Merged

fix(provider): pin per-model default params on subagent turns#71
justin-carper merged 2 commits into
mainfrom
subagent-default-model

Conversation

@justin-carper

Copy link
Copy Markdown
Collaborator

Problem

Subagents that don't set their own model inherit the invoking primary agent's model (per opencode's documented resolution). When that model is a Cursor model like composer-2.5, the subagent turn reaches the provider with the model's opencode options.params dropped, so resolveControls produced a bare { id: "composer-2.5" } with no fast param — and Cursor's server-side fast: true default silently applied. Result: subagents ran "composer-2.5 fast" even though the plugin pins fast off on the normal chat path.

The model choice itself (inheritance) is correct/expected. The bug was only the fast leak on the inherited path.

Fix

  • resolveControls floor (controls.ts): StaticControls.defaults applied under static params and per-request options (defaults < params < per-request). On the subagent path (params dropped) the floor re-applies fast: "false"; an explicit fast variant or static param still wins.
  • Plumbing (plugin/index.tsprovider/index.tslanguage-model.ts): the config hook builds a modelId → defaultModelParams map from the discovered catalog (reusing existing defaultModelParams) and injects it into provider options — a per-provider channel that survives opencode's subagent param-drop. The provider passes it as the defaults floor for the current model.
  • Confirmation instrument: OPENCODE_CURSOR_DEBUG=1 now logs the resolved modelSelection per turn, so the leak (and its fix) is observable.

Verification

  • npm test306 passed (27 files), including:
    • new resolveControls cases: floor applies when no params; per-request and static params override the floor;
    • new end-to-end language-model test: a params-less turn sends Agent.create { id: "composer-2.5", params: [{ id: "fast", value: "false" }] }.
  • npm run build (tsup) → clean.
  • tsc --noEmit: no errors in changed files. (Pre-existing @types/semver errors in version-check.* are unrelated and reproduce on main.)

Notes

  • No behavior change on the normal chat path (opencode already forwards options.params there, so re-applying the floor is a no-op).

Subagents inherit the primary agent's model but reach the provider with
the model's opencode options.params dropped, so Cursor's server-side
`fast: true` default silently applied (e.g. composer-2.5 ran "fast" in
subagent calls).

Thread each discovered model's defaultModelParams through provider options
(a per-provider channel that survives opencode's subagent param-drop) and
re-apply them as a lowest-precedence floor in resolveControls, so
`fast: "false"` holds even when per-request params are absent. Explicit
variant/static params still win. Add an OPENCODE_CURSOR_DEBUG log of the
resolved modelSelection to confirm per-turn behavior.
Collapse the repeated subagent/fast rationale to a single home (the
plugin config hook where the map originates); reduce the type-field
docstrings to one-liners and drop the self-evident debug-log comment.
@justin-carper
justin-carper merged commit 30b13e6 into main Jul 16, 2026
6 checks passed
@justin-carper
justin-carper deleted the subagent-default-model branch July 16, 2026 19:41
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