anomalyco / anomalyco/opencode

Qwen3.8 Flash: variant=xhigh silently disables reasoning by sending output_config.effort without thinking

Open
#49,079 0 comments 0 reactions 1 assignee View on GitHub

@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 — --variant silently ignored when the value is not in reasoning_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

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.