Skip to content

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

Closed as not planned

Description

@midnight000spark

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

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.

Activity

  1. thdxr commented on Oct 11, 2026

    @thdxr
    Member

    Thanks for the report! OpenCode 2.0 is now out and development is focused on V2, so we're closing issues filed against OpenCode 1. Please upgrade (opencode upgrade --major, details: https://anoma.ly/notes/opencode-2-0), and if this is still relevant on 2.0, reopen this issue or open a new one with your 2.0 version.

    — from 𝕺𝖕𝖊𝖓𝕮𝖔𝖉𝖊

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions