5.21 Thinking Depth Configuration
Treat "thinking depth" like gears: shallow for speed, deep for stability.
What You'll Learn
- Set thinking budget for individual models
- Understand how the "variants" mechanism controls thinking depth
- Use Ctrl+T to switch between different thinking depths
Your Current Dilemma
- Same model, sometimes you want fast, sometimes deep, but don't know how to switch
- After writing config in
opencode.json, unsure if it took effect - When using relay/proxy models, unsure if you can still control thinking depth
When to Use This
- When you need: make "thinking depth" a switchable gear
- And don't want: change models or modify config every time
🎒 Before You Start
- [ ] Completed 5.1 Configuration Complete Guide
- [ ] Can start OpenCode normally
Core Concept
- OpenCode uses model variants to save different thinking depths
- Variants are model-level configurations with higher priority than defaults
- Ctrl+T cycles through variants
ℹ️ What is "Thinking Depth"?
It refers to the model's "available thinking budget", such as Anthropic's thinking.budgetTokens. Higher values mean more tokens available for reasoning, but slower response and higher cost.
Follow Along
Step 1: Confirm Model Supports Thinking Variants
Why Not all models have variants, OpenCode checks capabilities.reasoning first.
How Choose a model that supports reasoning (e.g., Anthropic / Gemini 3 / OpenAI).
You Should See Variants like high / max appear in the model list.
Step 2: Set Thinking Budget for Individual Models in opencode.json
Why Variant config goes under provider.models.[modelID].variants, which can override defaults.
How Fill in the corresponding fields based on your Provider:
Anthropic Example (thinking.budgetTokens)
{
"$schema": "https://opencode.ai/config.json",
"provider": {
"anthropic": {
"models": {
"claude-sonnet-4-5": {
"variants": {
"high": {
"thinking": { "type": "enabled", "budgetTokens": 20000 }
},
"max": {
"thinking": { "type": "enabled", "budgetTokens": 32000 }
}
}
}
}
}
}
}Gemini 3 Example (thinkingConfig.thinkingBudget)
{
"$schema": "https://opencode.ai/config.json",
"provider": {
"google": {
"models": {
"gemini-3-flash": {
"variants": {
"high": {
"thinkingConfig": { "includeThoughts": true, "thinkingBudget": 16000 }
},
"max": {
"thinkingConfig": { "includeThoughts": true, "thinkingBudget": 24576 }
}
}
}
}
}
}
}You Should See Variant values take effect after restart.
Step 3: Switch Thinking Depths with Ctrl+T
Why After setting up variants, using a shortcut to switch is more convenient.
How Press Ctrl+T in the chat input box to cycle:
(none) → high → max → (none) → high → ...You Should See Status bar shows current variant name (e.g., high).
Step 4: Customize Variant Names (Optional)
Why Variant names aren't fixed, you can change them to things like "Deep Think" / "Fast".
How Use custom keys in variants:
{
"provider": {
"anthropic": {
"models": {
"claude-sonnet-4-5": {
"variants": {
"fast": { "thinking": { "type": "enabled", "budgetTokens": 8000 } },
"deep": { "thinking": { "type": "enabled", "budgetTokens": 32000 } }
}
}
}
}
}
}You Should See Ctrl+T switches between "fast/deep".
ℹ️ Custom Variants Are "Added", Not "Replaced"
OpenCode merges the variants you write in opencode.json with default variants. If you only want custom variants, explicitly disable the default high/max:
{
"provider": {
"anthropic": {
"models": {
"claude-sonnet-4-5": {
"variants": {
"high": { "disabled": true },
"max": { "disabled": true },
"fast": { "thinking": { "type": "enabled", "budgetTokens": 8000 } },
"deep": { "thinking": { "type": "enabled", "budgetTokens": 32000 } }
}
}
}
}
}
}How to Configure Third-Party Relays
If your relay uses openai-compatible, it defaults to reasoningEffort. Example:
{
"provider": {
"relay": {
"options": {
"baseURL": "https://your-relay.example.com/v1",
"apiKey": "{env:RELAY_API_KEY}"
},
"models": {
"gpt-5": {
"variants": {
"low": { "reasoningEffort": "low" },
"high": { "reasoningEffort": "high" }
}
}
}
}
}
}If your relay actually forwards to Anthropic (still using openai-compatible SDK), you can directly override with Anthropic fields:
{
"provider": {
"relay": {
"options": {
"baseURL": "https://your-relay.example.com/v1",
"apiKey": "{env:RELAY_API_KEY}"
},
"models": {
"claude-sonnet-4-5": {
"variants": {
"high": {
"thinking": { "type": "enabled", "budgetTokens": 20000 }
},
"max": {
"thinking": { "type": "enabled", "budgetTokens": 32000 }
}
}
}
}
}
}
}Prerequisite: your relay server forwards the thinking field to Anthropic as-is.
Checklist ✅
- [ ]
opencode.jsoncontainsprovider.models.[modelID].variants - [ ] Variant name appears in status bar after startup
- [ ] Ctrl+T can cycle through variants
Common Issues
| Symptom | Cause | Solution |
|---|---|---|
| Ctrl+T does nothing | Current model has no variants | Switch to a reasoning-capable model or add variants |
| Variants exist but don't show | Haven't switched to a variant yet | Press Ctrl+T once |
| Config doesn't take effect | Wrong model ID | Copy complete ID from model list |
| Relay shows no change | Using openai-compatible, only supports reasoningEffort | Manually override parameters in variants |
Lesson Summary
You learned:
- Variants are "thinking depth gears", configured in
provider.models.[modelID].variants - Default variants are auto-generated by ProviderTransform, can be overridden by config
- Ctrl+T cycles through variants
Next Lesson Preview
Next we'll learn Debugging & Diagnostic Tools.
You'll learn:
- How to use
opencode debugcommands- Diagnose LSP, config, and search issues
- Analyze OpenCode like a developer
Appendix: Source Code Reference
Click to expand source code locations
Updated: 2026-01-16
| Feature | File Path | Lines |
|---|---|---|
| Variant generation entry | src/provider/transform.ts | 297-477 |
| Reasoning filter & exclusion | src/provider/transform.ts | 298-301 |
| Anthropic thinking budget defaults | src/provider/transform.ts | 371-385 |
| Gemini 3 thinking budget defaults | src/provider/transform.ts | 421-439 |
| Variant config Schema | src/config/config.ts | 818-833 |
| Variant config merge | src/provider/provider.ts | 929-936 |
| Ctrl+T default shortcut | src/config/config.ts | 632-688 |
| Ctrl+T command binding | src/cli/cmd/tui/app.tsx | 393-399 |
| Variant cycling logic | src/cli/cmd/tui/context/local.tsx | 310-346 |
| Variant display logic | src/cli/cmd/tui/component/prompt/index.tsx | 696-700 |
| Variant name rendering | src/cli/cmd/tui/component/prompt/index.tsx | 946-950 |
| Variant applied to LLM params | src/session/llm.ts | 96-109 |
| Variant keybind config | src/config/config.ts | 632-688 |
Key Constants:
WIDELY_SUPPORTED_EFFORTS = ["low", "medium", "high"]OPENAI_EFFORTS = ["none", "minimal", "low", "medium", "high", "xhigh"]

