anomalyco / anomalyco/opencode
Qwen3.8 Flash: variant=xhigh silently disables reasoning by sending output_config.effort without thinking
@rekram1-node is already working on this.
Since Sep 14, 2026.
- Dominant language
- TypeScript
- Stars
- 209k
- Forks
- 27.5k
- PR merge metrics
- PR metrics pending
Description
Description
On opencode-go/qwen3.8-flash, selecting the reasoning variant xhigh makes OpenCode send a bare output_config.effort to POST /zen/go/v1/messages with no thinking block. The request succeeds (HTTP 200) and no error is shown, but reasoning is never enabled: tokens.reasoning is always 0 for these sessions.
So variant=xhigh looks active but does nothing. This is deterministic, not intermittent.
Wire symptom:
variant=xhigh
-> POST /messages
-> output_config: {"effort":"xhigh"}
-> no "thinking" field
-> HTTP 200, no thinking block
-> tokens.reasoning = 0
OpenCode version
1.18.31 (Linux). Relevant UA: opencode/1.18.31 ai-sdk/provider-utils/4.0.46 runtime/bun/1.3.14. Bundled @ai-sdk/anthropic is 3.0.111.
Steps to reproduce
opencode run --model opencode-go/qwen3.8-flash --variant xhigh "Reply with exactly: OK"
Check the session usage:
DB="$HOME/.local/share/opencode/opencode.db"
sqlite3 "$DB" "
SELECT json_extract(model,'\$.variant'), tokens_reasoning, tokens_output
FROM session
WHERE model LIKE '%qwen3.8-flash%' AND model LIKE '%xhigh%'
ORDER BY time_created DESC LIMIT 5;"
Result: tokens_reasoning = 0 on every row.
To see the body OpenCode actually sends, point the provider at a local recording endpoint (provider.opencode-go.options.baseURL) and run the same command. Captured body for the xhigh request (message/system content redacted):
{
"model": "qwen3.8-flash",
"stream": true,
"max_tokens": 32000,
"output_config": { "effort": "xhigh" },
"tool_choice": { "type": "auto" },
"tools": ["<14 tools>"]
}
There is no thinking key. (For comparison, the auxiliary/title request is sent the same way with effort: "low".)
Expected behavior
variant=xhigh should enable the model's reasoning mode and produce reasoning tokens. If the requested mode cannot be honoured, OpenCode should warn instead of silently sending a no-op parameter.
Root cause (source)
packages/opencode/src/provider/transform.ts:
reasoningVariants() -> model has { type:"effort", values:["low","medium","xhigh"] }
-> effortVariants() -> reasoningEffort(model, "xhigh")
case "@ai-sdk/anthropic":
return anthropicEffort(model, effort) ?? { effort } // fallback taken
anthropicEffort(): anthropicAdaptiveEfforts("qwen3.8-flash") -> null // needs claude-/kimi
-> returns undefined
=> { effort: "xhigh" }
@ai-sdk/anthropic 3.0.111 then faithfully serialises effort into output_config.effort; since no thinking was provided, none is sent. The catalog defines qwen3.8-flash with a model-level provider.npm: "@ai-sdk/anthropic" (provider default is @ai-sdk/openai-compatible).
Evidence
Local opencode.db, qwen3.8-flash on opencode-go:
| variant | sessions | reasoning tokens |
|---|---|---|
| xhigh | 42 | 0 |
| default | 16 | 0 |
| high | 3 | 0 |
| max | 2 | 0 |
42/42 xhigh sessions (100%) have reasoning = 0; message-level cross-check: 1,656 messages, 0 with reasoning.
Controls on the same provider:
| model | reasoning tokens |
|---|---|
qwen3.7-plus |
29,577 |
deepseek-v4.1-flash |
242,466 |
qwen3.8-flash |
0 |
So the provider/adapter path does produce reasoning for other models; only the qwen3.8-flash effort-variant path yields zero.
Related (separate) compatibility note
On the same endpoint for this model, thinking: {"type":"adaptive"} returns HTTP 200 with a thinking block, while thinking: {"type":"enabled","budget_tokens":N} is rejected (HTTP 500 before ~2026-09-14 23:13 UTC, later HTTP 400 {"model":"qwen3.8-flash"}). The enabled form is accepted for qwen3.7-plus and minimax-m3. This looks like a provider/model compatibility limitation, and it means replacing the bare effort with enabled + budget_tokens is not safe — adaptive is what this model accepts.
Proposed fix
Guard the Anthropic effort mapping for Qwen models so the variant produces a real thinking config, e.g. in anthropicEffort():
if (isQwenAnthropicFamily(model)) // family === "qwen" on @ai-sdk/anthropic
return { thinking: { type: "adaptive", display: "summarized" }, effort }
adaptive is confirmed accepted by this endpoint. If mapping xhigh -> adaptive changes the intended semantics of xhigh, the alternative is to not expose effort variants for this model on this adapter and surface that the capability is unavailable — rather than emitting a parameter that does nothing.
Regression test
Given opencode-go/qwen3.8-flash + variant=xhigh, assert the generated body contains a thinking block and does not rely on bare output_config.effort alone; then assert the response contains a thinking block and tokens.reasoning > 0. Keep default qwen3.8-flash, qwen3.7-plus, deepseek-v4.1-flash, and non-reasoning models covered as controls.
Related issues
- #40182 —
--variantsilently ignored when the value is not inreasoning_options. Different cause: here the value is valid and applied, but has no effect. - #17876 (closed, not planned) — opposite symptom on native Anthropic (adaptive + effort sent, causes 400).
Note
Separately, opencode-go/qwen3.8-flash also has intermittent Internal server error / Type validation failed failures (26 of 63 local sessions). That is a different failure domain and is not related to this reasoning-variant bug.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Assessment
This issue has not been assessed yet.