Skip to content

reasoning_options=[toggle] yields zero variants for @ai-sdk/openai-compatible providers (485 models, e.g. all Xiaomi MiMo) #51541

Open

Description

@DanielKa76

Description

Models whose models.dev entry declares reasoning_options = [{ type = "toggle" }] get no variants at all when their provider package is @ai-sdk/openai-compatible. Since variants is what clients render a reasoning control from, those models look like they have no reasoning support — even though reasoning: true is set and the API does support toggling.

reasoningToggle() in packages/opencode/src/provider/transform.ts only maps two packages and returns an empty object for everything else:

function reasoningToggle(model: Provider.Model) {
  if (model.api.npm === "@ai-sdk/alibaba")
    return { none: { enableThinking: false }, high: { enableThinking: true } }
  if (model.api.npm === "@ai-sdk/cohere")
    return { none: { thinking: { type: "disabled" } }, high: { thinking: { type: "enabled" } } }
  return {}
}

reasoningVariants() then calls nonEmptyVariants(reasoningToggle(target)), and nonEmptyVariants({}) returns undefined → variants is empty. nvidia escapes via a dedicated branch in reasoningEffort's sibling path, and openrouter has its own transform that implements case "toggle".

Count from the current models.dev catalog: 499 models across 83 providers declare a toggle on @ai-sdk/openai-compatible; 14 of those are nvidia, so 485 get no reasoning control. Affected providers include all four Xiaomi token-plan providers (xiaomi, xiaomi-token-plan-cn, xiaomi-token-plan-ams, xiaomi-token-plan-sgp — every mimo-v2*, mimo-v2.5*, mimo-v2.6* model), plus zenmux, llmgateway-providers, novita-ai, qiniu-ai, ofox, wandb, zhipuai, empiriolabs, 302ai, opencode, and ~70 more.

Concrete case: MiMo-V2.6-Pro on Xiaomi Token Plan (Europe)

models.dev is correct here and documents its source:

# providers/xiaomi-token-plan-ams/models/mimo-v2.6-pro.toml
# Toggle: thinking.type = enabled|disabled
# Source: https://mimo.mi.com/docs/en-US/tokenplan/Token Plan/quick-access
reasoning_options = [{ type = "toggle" }]

Measured against the live endpoint (token-plan-ams.xiaomimimo.com, mimo-v2.6-pro, identical prompt):

request completion_tokens_details.reasoning_tokens reasoning_content in reply
thinking: {type: "disabled"} 0 absent
thinking: {type: "enabled"} 12 present
reasoning_effort: "low" 12 present
reasoning_effort: "high" 12 present

So the toggle is the only control the API honours, reasoning_effort is ignored, and opencode v2 cannot express the toggle on this package.

For contrast, an effort model on the same package does get variants: deepseek-v4.1-flash → low/high/max.

No config-level workaround

Model-level options are filtered through opencode's own option schema before reaching the provider, not passed through verbatim. Against a local echo server on the OpenAI-compatible path:

  • options: { reasoningEffort: "high" } → body contains reasoning_effort: "high"
  • options: { thinking: { type: "disabled" } } → body contains thinking: null
  • options: { user: "probe-marker" } → dropped

So there is no way to hand-write the thinking body field from config for an openai-compatible provider.

Steps to reproduce

  1. Configure an @ai-sdk/openai-compatible provider, e.g. xiaomi-token-plan-ams with npm: "@ai-sdk/openai-compatible".
  2. Request the model info for a toggle model, e.g. GET /provider (v2.0.12) and read variants for mimo-v2.6-pro → [].
  3. Repeat with an effort model on the same provider, e.g. deepseek-v4.1-flash → ["low", "high", "max"].
  4. reasoningVariants() in packages/opencode/src/provider/transform.ts shows the toggle branch resolving to undefined for this package.

Question about the fix shape

Adding a reasoningToggle() case is a small code change, but the wire field is provider-specific: MiMo wants thinking.type, Alibaba enableThinking, nvidia chat_template_kwargs.enable_thinking, OpenRouter reasoning.enabled. A generic default for @ai-sdk/openai-compatible would be wrong for most of the 485. Options I see:

  1. models.dev gains a field describing the toggle body shape (e.g. reasoning_options: [{ type = "toggle", body = { thinking = { type = ... } } }]), and reasoningToggle() honours it.
  2. dedicated provider packages for the big ones (@opencode/ai/providers/xiaomi), as exists for deepseek/zai/anthropic/etc.
  3. at minimum, keep the capability visible to clients even when no variant can be built, so the model isn't presented as non-reasoning.

Happy to go with whatever direction you prefer — I can also test a candidate mapping against the providers' documented APIs.

Environment

  • OpenCode version: 2.0.12
  • Operating System: macOS (darwin-arm64)
  • Terminal: OpenChamber desktop (managed opencode serve)
  • Plugins: none

Activity

  1. github-actions commented on Sep 26, 2026

    @github-actions
    Contributor

    This issue might overlap with existing reports. Please check:

    • #42793: reports reasoningToggle() returning {} for @ai-sdk/openai-compatible models declaring a toggle, leaving GLM models without reasoning variants.
    • #47871: reports OpenAI-compatible reasoning toggles falling back to unsupported effort variants for LongCat.
  2. opencodejr commented on Oct 28, 2026

    @opencodejr

    Thanks for the detailed write-up and the live-endpoint measurements!

    To restate the request: models on the generic @ai-sdk/openai-compatible package whose catalog entry declares only a reasoning toggle (e.g. all Xiaomi MiMo models) should get none/thinking variants, sent in the shape each provider expects (for MiMo, thinking.type).

    A couple of notes from the current v2 code:

    • In v2, variants are built in packages/core/src/variant.ts, not provider/transform.ts. There, @opencode/ai/providers/openai-compatible only builds toggle variants for nvidia. For every other provider it falls back to effort-only, so toggle models get no variants. That's deliberate for now, because, as you point out, the toggle field differs per provider and a generic default would be wrong for most of them. So I'm treating this as a feature request rather than a bug.
    • Workaround: v2 config can define variants with a raw request body, which is a different mechanism from options. Something like this should send the thinking field as-is:
    {
      "providers": {
        "xiaomi-token-plan-ams": {
          "models": {
            "mimo-v2.6-pro": {
              "variants": [
                { "id": "none", "body": { "thinking": { "type": "disabled" } } },
                { "id": "thinking", "body": { "thinking": { "type": "enabled" } } }
              ]
            }
          }
        }
      }
    }

    The fix directions you listed are useful input: a toggle body shape in models.dev, per-provider mappings or dedicated packages, or keeping the reasoning capability visible to clients. Maintainers will consider which one fits. Please reply if the body variants above don't reach the wire for you.

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

Metadata

Metadata

Assignees

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