Problem
Requests to some OpenCode Go models (e.g. ox-alpha-free) fail upstream with:
[1210] This model always engages in thinking and cannot be disabled; please use low, high, or max
The relay treats an absent reasoning parameter as "thinking off", so any client that doesn't send one gets rejected. GoModel currently forwards such requests untouched:
internal/providers/opencodego/opencodego.go embeds openai.ChatCompatible without an AdaptChatRequest hook, unlike other providers that use it for per-provider parameter quirks.
internal/providers/openai/openai.go::chatRequestBody only adapts requests for OpenAI o-series/GPT-5 (isReasoningChatModel); everything else marshals as-is.
- If the client omits
reasoning, ChatRequest.Reasoning stays nil and nothing downstream fills it in.
Result: every client routed through GoModel to these models fails, even ones that do have reasoning configured but whose provider layer gates emission by model family (e.g. Hermes's custom-provider path sends no reasoning field at all).
Proposed change
Add an AdaptChatRequest hook to the opencode_go provider's ChatCompatible config:
- When
req.Reasoning == nil, inject a default effort into the outgoing body:
- Preferred wire shape per upstream docs: top-level
reasoning_effort: "low" (safe default; "high"/"max" opt-in).
- When
req.Reasoning != nil, map its effort through unchanged (downgrading unknown levels to the closest of low/high/max).
- Allow an env override (consistent with existing conventions), e.g.
OPENCODE_GO_DEFAULT_REASONING_EFFORT, so operators can raise the default or set it to a per-deployment value.
Optionally scope injection to models known to require it once upstream exposes per-model metadata — until then, injecting only when absent is safe: models that ignore the parameter are unaffected, and clients that already send reasoning keep full control.
Why in this layer
- It fixes all gateway clients uniformly, not just one caller.
- The codebase already designates
AdaptChatRequest as the right place for exactly this class of quirk ("remapping reasoning effort levels"), so no new mechanism is needed.
- Responses-via-chat translation picks up the adaptation automatically since it goes through
ChatCompletion.
Tests
ox-alpha-free request without reasoning → outgoing body contains reasoning_effort.
- Request with explicit
reasoning.effort → forwarded (mapped) and not overridden.
- Env override respected.
- Models routed to
/messages unaffected.
Problem
Requests to some OpenCode Go models (e.g.
ox-alpha-free) fail upstream with:[1210] This model always engages in thinking and cannot be disabled; please use low, high, or maxThe relay treats an absent reasoning parameter as "thinking off", so any client that doesn't send one gets rejected. GoModel currently forwards such requests untouched:
internal/providers/opencodego/opencodego.goembedsopenai.ChatCompatiblewithout anAdaptChatRequesthook, unlike other providers that use it for per-provider parameter quirks.internal/providers/openai/openai.go::chatRequestBodyonly adapts requests for OpenAI o-series/GPT-5 (isReasoningChatModel); everything else marshals as-is.reasoning,ChatRequest.Reasoningstaysniland nothing downstream fills it in.Result: every client routed through GoModel to these models fails, even ones that do have reasoning configured but whose provider layer gates emission by model family (e.g. Hermes's custom-provider path sends no reasoning field at all).
Proposed change
Add an
AdaptChatRequesthook to the opencode_go provider'sChatCompatibleconfig:req.Reasoning == nil, inject a default effort into the outgoing body:reasoning_effort: "low"(safe default;"high"/"max"opt-in).req.Reasoning != nil, map itseffortthrough unchanged (downgrading unknown levels to the closest of low/high/max).OPENCODE_GO_DEFAULT_REASONING_EFFORT, so operators can raise the default or set it to a per-deployment value.Optionally scope injection to models known to require it once upstream exposes per-model metadata — until then, injecting only when absent is safe: models that ignore the parameter are unaffected, and clients that already send reasoning keep full control.
Why in this layer
AdaptChatRequestas the right place for exactly this class of quirk ("remapping reasoning effort levels"), so no new mechanism is needed.ChatCompletion.Tests
ox-alpha-freerequest withoutreasoning→ outgoing body containsreasoning_effort.reasoning.effort→ forwarded (mapped) and not overridden./messagesunaffected.