Symptom

The previous post got the CommandCode GOAT plan hooked up, and the models chat fine, but there was one detail I never looked at closely: deepseek-v4-flash won’t expose thinking levels.

With the opencode go plan, the same batch of models could switch thinking levels just fine; on goat they were all gone. My first reaction was “the goat plan doesn’t support it” — but after digging in, this had nothing to do with the plan at all. It was a missing piece of config.

TL;DR

Tweak the config file once more: for every model that needs selectable thinking depth, just add one line:
"reasoning": true
and you’re done.

For example

        "deepseek/deepseek-v4-flash": {
          "name": "DeepSeek V4 Flash (latest)",
          "limit": {
            "context": 1000000,
            "output": 262144
          },
          "reasoning": true
        },

Oh, and by the way, today I also turned the GOAT plan usage estimator into a live table:

Project is at: https://github.com/mousebomb/opencode-go-limits

Trimmed the config a bit

{
  "$schema": "https://opencode.ai/config.json",
  "permission": {
  },
  "mcp": {
  },
  "provider": {
    "goat": {
      "npm": "@ai-sdk/openai-compatible",
      "name": "goat",
      "options": {
        "baseURL": "https://api.commandcode.ai/provider/v1",
        "headers": {}
      },
      "models": {
        "deepseek/deepseek-v4-flash-vision-exp": {
          "name": "DeepSeek V4 Flash Vision (exp)",
          "limit": {
            "context": 1000000,
            "output": 262144
          },
          "reasoning": true
        },
        "Qwen/Qwen3.8-Flash": {
          "name": "Qwen 3.8 Flash",
          "limit": {
            "context": 1000000,
            "output": 262144
          },
          "reasoning": true
        },
        "stepfun/Step-3.7-Flash": {
          "name": "Step 3.7 Flash",
          "limit": {
            "context": 256000,
            "output": 262144
          },
          "reasoning": true
        },
        "poolside/laguna-s-2.1-free": {
          "name": "Laguna S 2.1",
          "limit": {
            "context": 256000,
            "output": 262144
          },
          "reasoning": true
        },
        "meta/muse-spark-1.2": {
          "name": "Muse Spark 1.2",
          "limit": {
            "context": 1048576,
            "output": 262144
          },
          "reasoning": true
        },
        "meta/muse-spark-1.2-contributor": {
          "name": "Muse Spark 1.2 Contributor",
          "limit": {
            "context": 1048576,
            "output": 262144
          },
          "reasoning": true
        },
        "xai/grok-4.5": {
          "name": "Grok 4.5",
          "limit": {
            "context": 500000,
            "output": 262144
          },
          "reasoning": true
        },
        "xai/grok-4.6": {
          "name": "Grok 4.6",
          "limit": {
            "context": 500000,
            "output": 262144
          },
          "reasoning": true
        }
      }
    },
    "goat-zdr": {
      "npm": "@ai-sdk/openai-compatible",
      "name": "goat-zdr",
      "options": {
        "baseURL": "https://api.commandcode.ai/provider/v1",
        "headers": {
          "x-cmd-zdr": "1"
        }
      },
      "models": {
        "deepseek/deepseek-v4-pro": {
          "name": "DeepSeek V4 Pro (latest)",
          "limit": {
            "context": 1000000,
            "output": 262144
          },
          "reasoning": true
        },
        "deepseek/deepseek-v4-flash": {
          "name": "DeepSeek V4 Flash (latest)",
          "limit": {
            "context": 1000000,
            "output": 262144
          },
          "reasoning": true
        },
        "deepseek/deepseek-v4-flash-fast": {
          "name": "DeepSeek V4 Flash Fast",
          "limit": {
            "context": 1000000,
            "output": 262144
          },
          "reasoning": true
        },
        "moonshotai/Kimi-K3": {
          "name": "Kimi K3",
          "limit": {
            "context": 1000000,
            "output": 262144
          },
          "reasoning": true
        },
        "moonshotai/Kimi-K2.7-Code": {
          "name": "Kimi K2.7 Code",
          "limit": {
            "context": 256000,
            "output": 262144
          },
          "reasoning": true
        },
        "moonshotai/Kimi-K2.7-Code-Highspeed": {
          "name": "Kimi K2.7 Code HighSpeed",
          "limit": {
            "context": 262000,
            "output": 262144
          },
          "reasoning": true
        },
        "moonshotai/Kimi-K2.6": {
          "name": "Kimi K2.6",
          "limit": {
            "context": 256000,
            "output": 262144
          },
          "reasoning": true
        },
        "moonshotai/Kimi-K2.5": {
          "name": "Kimi K2.5",
          "limit": {
            "context": 256000,
            "output": 262144
          },
          "reasoning": true
        },
        "z-ai/glm-5.3-flash": {
          "name": "GLM-5.3 Flash",
          "limit": {
            "context": 1048576,
            "output": 262144
          },
          "reasoning": true
        },
        "zai-org/GLM-5.3": {
          "name": "GLM-5.3",
          "limit": {
            "context": 1000000,
            "output": 262144
          },
          "reasoning": true
        },
        "zai-org/GLM-5.2": {
          "name": "GLM-5.2",
          "limit": {
            "context": 1000000,
            "output": 262144
          },
          "reasoning": true
        },
        "zai-org/GLM-5.2-Fast": {
          "name": "GLM-5.2 Fast",
          "limit": {
            "context": 1000000,
            "output": 262144
          },
          "reasoning": true
        },
        "zai-org/GLM-5.1": {
          "name": "GLM-5.1",
          "limit": {
            "context": 200000,
            "output": 262144
          },
          "reasoning": true
        },
        "zai-org/GLM-5": {
          "name": "GLM-5",
          "limit": {
            "context": 200000,
            "output": 262144
          },
          "reasoning": true
        },
        "MiniMaxAI/MiniMax-M3": {
          "name": "MiniMax M3",
          "limit": {
            "context": 1000000,
            "output": 262144
          },
          "reasoning": true
        },
        "MiniMaxAI/MiniMax-M2.7": {
          "name": "MiniMax M2.7",
          "limit": {
            "context": 200000,
            "output": 262144
          },
          "reasoning": true
        },
        "MiniMaxAI/MiniMax-M2.5": {
          "name": "MiniMax M2.5",
          "limit": {
            "context": 200000,
            "output": 262144
          },
          "reasoning": true
        },
        "xiaomi/mimo-v2.5-pro": {
          "name": "MiMo V2.5 Pro",
          "limit": {
            "context": 1000000,
            "output": 262144
          },
          "reasoning": true
        },
        "xiaomi/mimo-v2.5": {
          "name": "MiMo V2.5",
          "limit": {
            "context": 1000000,
            "output": 262144
          },
          "reasoning": true
        },
        "Qwen/Qwen3.8-Max": {
          "name": "Qwen 3.8 Max",
          "limit": {
            "context": 1000000,
            "output": 262144
          },
          "reasoning": true
        },
        "Qwen/Qwen3.8-27B": {
          "name": "Qwen 3.8 27B",
          "limit": {
            "context": 262144,
            "output": 262144
          },
          "reasoning": true
        },
        "Qwen/Qwen3.7-Max": {
          "name": "Qwen 3.7 Max",
          "limit": {
            "context": 1000000,
            "output": 262144
          },
          "reasoning": true
        },
        "Qwen/Qwen3.7-Plus": {
          "name": "Qwen 3.7 Plus",
          "limit": {
            "context": 1000000,
            "output": 262144
          },
          "reasoning": true
        },
        "Qwen/Qwen3.7-Flash": {
          "name": "Qwen 3.7 Flash",
          "limit": {
            "context": 1000000,
            "output": 262144
          },
          "reasoning": true
        },
        "Qwen/Qwen3.6-Max-Preview": {
          "name": "Qwen 3.6 Max Preview",
          "limit": {
            "context": 200000,
            "output": 262144
          },
          "reasoning": true
        },
        "Qwen/Qwen3.6-Plus": {
          "name": "Qwen 3.6 Plus",
          "limit": {
            "context": 200000,
            "output": 262144
          },
          "reasoning": true
        },
        "stepfun/Step-3.5-Flash": {
          "name": "Step 3.5 Flash",
          "limit": {
            "context": 1000000,
            "output": 262144
          },
          "reasoning": true
        },
        "tencent/hy3-paid": {
          "name": "Tencent Hy3",
          "limit": {
            "context": 262144,
            "output": 262144
          },
          "reasoning": true
        },
        "tencent/hy4-preview": {
          "name": "Tencent Hy4 Preview",
          "limit": {
            "context": 1048576,
            "output": 262144
          },
          "reasoning": true
        },
        "nvidia/nemotron-3-ultra-550b-a55b": {
          "name": "Nemotron 3 Ultra",
          "limit": {
            "context": 1000000,
            "output": 262144
          },
          "reasoning": true
        },
        "thinkingmachines/inkling": {
          "name": "Inkling",
          "limit": {
            "context": 256000,
            "output": 262144
          },
          "reasoning": true
        },
        "thinkingmachines/inkling-small": {
          "name": "Inkling Small",
          "limit": {
            "context": 1000000,
            "output": 262144
          },
          "reasoning": true
        },
        "gpt-5.6-sol": {
          "name": "GPT-5.6 Sol",
          "limit": {
            "context": 1050000,
            "output": 262144
          },
          "reasoning": true
        }
      }
    }
  },
  "plugin": [
  ]
}

Root cause: custom providers lack a reasoning capability declaration

The entry point where opencode generates “thinking levels” (variants) for a model is the variants() function, and the very first gatekeeper is:

if (!model.capabilities.reasoning) return {}   // 没声明推理能力 → 直接不给档位

Built-in providers (opencode-go, official deepseek, etc.) get their model metadata from models.dev, which ships with reasoning: true and reasoning_options out of the box, so thinking levels show up.

goat, on the other hand, is a custom provider (@ai-sdk/openai-compatible), and all its models were hand-written by me in opencode.json. At the time I only wrote name and limit, not reasoning: true → the capability declaration defaults to false → variants() returns empty right away, and of course the TUI doesn’t show thinking levels.

It’s crystal clear when you read the code (packages/opencode/src/provider/transform.ts):

case "@ai-sdk/openai-compatible":
  const efforts = [...WIDELY_SUPPORTED_EFFORTS]        // ["low","medium","high"]
  if (model.api.id.toLowerCase().includes("deepseek-v4")) {
    efforts.push("max")                                // deepseek-v4 额外加 max
  }
  return Object.fromEntries(efforts.map(e => [e, { reasoningEffort: e }]))

In other words: for @ai-sdk/openai-compatible models, as long as reasoning: true is declared, opencode will assign thinking levels automatically based on the model ID — the deepseek-v4 series gets low/medium/high/max.

The GOAT gateway itself does support effort

I verified the gateway layer on the way: the reasoning_effort parameter is genuinely accepted and forwarded, and in practice deepseek-v4-flash really does produce different reasoning token counts at different effort levels. The level enum is low|medium|high|xhigh (none errors out), and max passes too.

Conclusion locked in: the capability is there, opencode just was never told this model can reason.

The fix: add reasoning: true to the models

Just add the declaration to the model entries under the goat and goat-zdr providers:

"deepseek/deepseek-v4-flash": {
  "name": "DeepSeek V4 Flash (latest)",
  "limit": { "context": 1000000, "output": 262144 },
  "reasoning": true
}

Restart after that, and opencode run -m goat/deepseek/deepseek-v4-flash --variant max passes in practice — the level really takes effect.

A follow-up question: is it safe to mark every model reasoning:true?

After fixing deepseek, a thought occurred to me: instead of judging model by model which ones should be marked, why not mark them all true and let opencode’s built-in model logic make the final call (it has its own internal blacklist of “which models should get levels”). But is that safe?

Reading the source: before handing out levels, variants() has a hardcoded blacklist, and any matching model just gets return {}:

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

That means kimi, qwen, glm (not 5.2), minimax (not M3) and friends won’t get thinking levels even with reasoning:true — the upstream simply doesn’t honor effort control (in practice, sending Kimi-K3 the high level barely changes its reasoning tokens, which confirms the blacklist makes sense).

The remaining question: for models marked true but blocked by the blacklist, will opencode sneak a default effort into the request body? Packet capture put that worry to rest — after marking Qwen3.8-Flash (blacklisted) as reasoning:true, the outgoing request body contains no reasoning_effort field at all, and the conversation behaves exactly as before. Compare that with non-blacklisted deepseek-v4-flash, where --variant high really does put reasoning_effort: high in the request body.

So I confidently marked all 74 models under goat and goat-zdr as reasoning: true, letting opencode’s mechanism handle the rest. After refactoring the config, /models works fine and every model chats normally in practice.

Final results comparison

Model Thinking levels that appear in the TUI after marking reasoning:true
deepseek-v4 series (pro/flash/fast/vision) low / medium / high / max
mimo-v2.5, stepfun, tencent, nemotron, inkling, gpt-5.6-sol, muse, grok, etc. low / medium / high
GLM-5.2 high / max (special-cased)
MiniMax-M3 thinking on / off (toggle special case)
Kimi series, Qwen series, GLM-5/5.1/5.3, MiniMax-M2.x no levels (hardcoded blacklist, upstream doesn’t support effort)

Takeaways

  1. For custom providers (openai-compatible), model levels are entirely up to your own declarations. reasoning: true is a necessary but not sufficient condition for getting levels — whether levels appear at all, and which ones, is decided a second time by opencode’s built-in model logic (blacklist included).
  2. Marking blacklisted models as reasoning:true has no side effects: it only affects the “can thinking levels appear” UI switch, and no default effort parameter gets injected into the request body. Mark them all with confidence.
  3. After fixing the config, remember to restart opencode (config is only loaded at startup, no hot reload), then select a model in /models and press Tab to cycle through the levels.