anomalyco / anomalyco/opencode

Free Zen models with reasoning=true show zero thinking variants (reasoning_options=[] blocks fallback)

Open
#49,013 1 comment 0 reactions 1 assignee View on GitHub

@nexxeln is already working on this.

Since Sep 14, 2026.

Dominant language
TypeScript
Stars
209k
Forks
27.5k
PR merge metrics
PR metrics pending

Description

Summary

Several free OpenCode Zen models advertise reasoning = true in models.dev but expose zero thinking variants in OpenCode (/models picker + variant_cycle). Users cannot select low / medium / high thinking effort for these models.

Affected models (provider = opencode)

Verified against https://models.dev/api.json (opencode provider) and Zen docs (2026-09-13):

Model ID reasoning reasoning_options Variants shown
big-pickle true [] none (bug)
mimo-v2.5-free true [] none (bug)
nemotron-3-ultra-free true [] none (bug)
nemotron-3.5-lightning-free true [] none (bug)
minimax-m2.5-free true [] none (bug)
ling-3.0-flash-fin-free true [{type="toggle"}] low/medium/high via fallback (OK)
muse-spark-1.3-contributor-free true [{type="effort", values=[minimal,low,medium,high,xhigh]}] 5 variants (OK)
deepseek-v4-flash-free true [{type="effort", values=[low,high,max]}] OK
kimi-k2.5-free / glm-5-free / qwen3.6-plus-free true [{type="toggle"}] (+budget for qwen) none — fallback denylisted (see below)

Zen endpoint table serves 5/6 advertised free models via https://opencode.ai/zen/v1/chat/completions (@ai-sdk/openai-compatible); only muse-spark-1.3-contributor-free uses .../v1/responses (@ai-sdk/openai).

Expected vs actual

  • Expected: models with reasoning = true served over OpenAI-compatible API expose generic low / medium / high variants (same as ling-3.0-flash-fin-free does today).
  • Actual: models with reasoning_options = [] show no variants at all.

Root cause (two layers)

1. reasoningVariants() returns {} instead of undefined for []

packages/opencode/src/provider/transform.ts:1704:

export function reasoningVariants(model: ModelsDev.Model, target: Provider.Model) {
  const options = model.reasoning_options
  if (options === undefined) return
  if (options.length === 0) return {}
  // ...
}
2. ?? fallback never runs on {}

packages/opencode/src/provider/provider.ts:1314:

const variants = ProviderTransform.reasoningVariants(model, base) ?? ProviderTransform.variants(base)

{} is not nullish, so generic variants(base) never runs for the [] models. Result: zero variants despite reasoning=true.

3. Hardcoded denylist in variants() also returns {}

packages/opencode/src/provider/transform.ts:777:

if (
  id.includes("deepseek-chat") ||
  id.includes("deepseek-reasoner") ||
  id.includes("deepseek-r1") ||
  id.includes("deepseek-v3") ||
  id.includes("minimax") ||
  (id.includes("glm") && !glm52) ||
  id.includes("kimi") ||
  id.includes("k2p") ||
  id.includes("qwen") ||
  id.includes("big-pickle")
)
  return {}

This blocks fallback for big-pickle, kimi-*, qwen-*, glm-* (non-5.2), minimax-* even when reasoning=true. For toggle-only models on @ai-sdk/openai-compatible, reasoningToggle() returns {} -> nonEmptyVariants({}) -> undefined -> fallback -> denylist {}. Net: no variants.

Models.dev evidence

Raw TOMLs (anomalyco/models.dev@dev:providers/opencode/models/):

  • mimo-v2.5-free.toml: reasoning = true, reasoning_options = []
  • nemotron-3-ultra-free.toml: reasoning = true, reasoning_options = []
  • nemotron-3.5-lightning-free.toml: reasoning_options = []
  • big-pickle.toml: reasoning = true, reasoning_options = []
  • minimax-m2.5-free.toml: reasoning = true, reasoning_options = []
  • ling-3.0-flash-fin-free.toml: reasoning_options = [{ type = "toggle" }] (works via fallback)
  • muse-spark-1.3-contributor-free.toml: reasoning_options = [{ type = "effort", values = [...] }] + [provider] npm = "@ai-sdk/openai" (works)

Suggested fix (either side, ideally both)

  • Option A (code, anomalyco/opencode): treat empty variants as missing. E.g. reasoningVariants() returns undefined for [], or change call site to fall back when Object.keys(variants).length === 0.
  • Option B (data, anomalyco/models.dev): give free OpenAI-compatible reasoning models real effort options, e.g. reasoning_options = [{ type = "effort", values = ["low", "medium", "high"] }], or document that [] means fixed always-on reasoning with no knob.
  • Re-evaluate denylist entry for big-pickle if reasoningEffort passthrough works on Zen chat-completions endpoint.

Workaround

Custom variants in opencode.json:

{
  "$schema": "https://opencode.ai/config.json",
  "provider": {
    "opencode": {
      "models": {
        "mimo-v2.5-free": {
          "variants": {
            "low": { "reasoningEffort": "low" },
            "medium": { "reasoningEffort": "medium" },
            "high": { "reasoningEffort": "high" }
          }
        }
      }
    }
  }
}

Environment

  • opencode v2.0.3 (Windows, C:\Users\baban\.bun\bin\opencode.exe)
  • Zen docs last updated 2026-09-13, /zen/v1/models checked 2026-09-14
  • models.dev opencode provider, 102 models

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.