Skip to content

fix(core): carry v1 model reasoning flag into migrated capabilities - #53683

Open
hril3 wants to merge 2 commits into
anomalyco:devfrom
hril3:fix-v1-reasoning-capability
Open

hril3 wants to merge 2 commits into
anomalyco:devfrom
hril3:fix-v1-reasoning-capability

Conversation

@hril3

@hril3 hril3 commented Oct 7, 2026 •

Copy link
Copy Markdown

Issue for this PR

Closes #51846

Type of change

  • Bug fix
  • New feature
  • Refactor / code improvement
  • Documentation

What does this PR do?

A v1 config can mark a model as reasoning-capable with reasoning: true. migrateModel in packages/core/src/v1/config/migrate.ts builds the v2 capabilities object out of tool_call and modalities and never looked at reasoning, so the flag was dropped during migration. For a model that only declares reasoning the result is no capabilities object at all, the config merge in config/plugin/provider.ts is skipped entirely, and the model keeps the catalog default, which has no reasoning capability. The client then renders "No reasoning" in the model tooltip for a model the user explicitly configured as reasoning-capable.

The fix reads the flag in two places:

Building capabilities for a reasoning-only model is safe for the other fields: ModelV2.Info.empty() defaults to {tools: false, input: [], output: []}, which is exactly what the fallbacks in this function produce, so the model ends up with the values it already had, plus the declared reasoning flag.

This depends on #50283, which adds reasoning to Model.Capabilities and preserves config.capabilities.reasoning when config is merged over the catalog. Without it the key is stripped while the migrated config is decoded, so this change alone would be a no-op. That commit is currently in this branch; I will rebase so only the migration change remains once it lands.

How did you verify your code works?

Unit: bun test test/config/config.test.ts in packages/core, 18/18 pass. Three tests added: the flag is carried through, a reasoning-only model still gets capabilities and the migrated document still decodes as valid v2 config, and the key is omitted when the v1 model does not declare it. The existing FastCheck property test over arbitrary v1 configs still passes.

Static: bun turbo typecheck --filter=@opencode-ai/core passes, bun run lint on the changed files reports 0 errors (one pre-existing unused-import warning in that test file, untouched). The full packages/core suite fails the same 16 tests with and without my change (cross-spawn / npm / network tests that need a different environment on Windows), so nothing regressed.

End to end, with the config shape from the issue in the project directory:

{
  "provider": {
    "localtest": {
      "npm": "@ai-sdk/openai-compatible",
      "options": { "baseURL": "http://127.0.0.1:9999/v1", "apiKey": "sk-local-test" },
      "models": {
        "glm-flash": { "name": "GLM Flash", "reasoning": true },
        "plain-model": { "name": "Plain Model", "tool_call": true }
      }
    }
  }
}

Running both versions of migrate.ts side by side over that config:

pre-fix: {"glm-flash":null,"plain-model":{"tools":true,"input":[],"output":[]}}
this PR: {"glm-flash":{"tools":false,"reasoning":true,"input":[],"output":[]},"plain-model":{"tools":true,"input":[],"output":[]}}

glm-flash previously got no capabilities object at all. plain-model, which does not declare the flag, is identical before and after.

GET /api/model from a source server booted in that directory:

{"id":"glm-flash","providerID":"localtest","capabilities":{"tools":false,"reasoning":true,"input":[],"output":[]}}
{"id":"plain-model","providerID":"localtest","capabilities":{"tools":true,"input":[],"output":[]}}

Reverting only migrate.ts and restarting the same server drops the reasoning key from glm-flash, which is the state the client renders as "No reasoning".

UI: ran that server against bun run dev:web and hovered both rows in the model picker.

Screenshots / recordings

glm-flash, declared with v1 reasoning: true, after the fix:

model tooltip showing reasoning supported

plain-model in the same list still shows "No reasoning", so the fallback is unchanged.

Checklist

zhengkaics and others added 2 commits October 7, 2026 11:26
The models.dev catalog carries a `reasoning` flag for every model, but
it was dropped when building V2 model capabilities, so the desktop model
picker tooltip always showed "No reasoning".

Carry the flag through the chain:

- schema: add optional `reasoning` to `Model.Capabilities`
- models-dev plugin: populate it from the catalog entry
- config provider plugin: preserve it when user config overrides
  capabilities (and allow explicit override)
- app global-sync mapper: map `capabilities.reasoning` into the app
  model store instead of hardcoding `false`
- regenerate client types and refresh the vendored client snapshot so
  the app typecheck sees the new optional field

The tooltip itself already reads `model.capabilities.reasoning` and
needs no change.
The v1 provider config allowed declaring reasoning: true on a model, but
migrateModel dropped it while building v2 capabilities, so explicitly
configured reasoning models still reported no reasoning capability (the
desktop model tooltip showed "No reasoning").

Include the flag in the capabilities construction condition and pass it
through when defined, so a reasoning-only model still receives
capabilities while keeping the empty defaults for tools/input/output.

Requires anomalyco#50283 (reasoning on Model.Capabilities). Fixes anomalyco#51846
@github-actions github-actions Bot added the needs:compliance This means the issue will auto-close after 2 hours. label Oct 7, 2026
@github-actions

github-actions Bot commented Oct 7, 2026

Copy link
Copy Markdown
Contributor

The following comment was made by an LLM, it may be inaccurate:

@hril3

hril3 commented Oct 7, 2026

Copy link
Copy Markdown
Author

Verification

Verified on Windows from a source build (bun 1.4.2), reproducing the config from #51846.

1. Unit — packages/core/test/config/config.test.ts: 18/18 pass, including the 3 new tests and the existing FastCheck property test (arbitrary v1 configs must still decode as valid v2 config).

2. Static — bun turbo typecheck --filter=@opencode-ai/core passes; bun run lint on the changed files reports 0 errors. The full packages/core suite has the same failing set as the pre-change baseline (16 pre-existing Windows environment failures in cross-spawn / npm / network tests), 0 introduced.

3. API, end to end — with a v1 config in the project directory:

{
  "provider": {
    "localtest": {
      "npm": "@ai-sdk/openai-compatible",
      "options": { "baseURL": "http://127.0.0.1:9999/v1", "apiKey": "sk-local-test" },
      "models": {
        "glm-flash": { "name": "GLM Flash", "reasoning": true },
        "plain-model": { "name": "Plain Model", "tool_call": true }
      }
    }
  }
}

GET /api/model on this branch returns:

{"id":"glm-flash","providerID":"localtest","capabilities":{"tools":false,"reasoning":true,"input":[],"output":[]}}
{"id":"plain-model","providerID":"localtest","capabilities":{"tools":true,"input":[],"output":[]}}

Reverting only migrate.ts to the pre-fix version and restarting the same server drops the key entirely — "capabilities":{"tools":false,"input":[],"output":[]} — which is exactly what makes the client fall back to "No reasoning". Causality confirmed, and a model that does not declare the flag is untouched (no fabricated capability).

4. UI — in the model picker (packages/app, bun run dev:web against the source server): hovering the config-only model shows the reasoning row as supported, while the sibling model without the flag still shows "No reasoning". Screenshot in the follow-up comment.


Heads-up: this branch currently also carries the commit from #50283 (the reasoning field on Model.Capabilities plus preserving it during the config merge), since the migration output needs that field to survive decoding. I will rebase so only the migration change remains once that PR lands.

@hril3

hril3 commented Oct 7, 2026 •

Copy link
Copy Markdown
Author

Screenshot after the fix -- config-only model declared with v1 reasoning: true:

v1-reasoning-tooltip-fixed

@github-actions github-actions Bot removed the needs:compliance This means the issue will auto-close after 2 hours. label Oct 7, 2026
@github-actions

github-actions Bot commented Oct 7, 2026

Copy link
Copy Markdown
Contributor

Thanks for updating your PR! It now meets our contributing guidelines. 👍

This branch has not been deployed

No deployments
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.

desktop: model tooltip shows "No reasoning" for openai-compatible models configured with reasoning: true

2 participants