Skip to content

Issue: inject reasoning_effort for thinking-mandatory models when unset #768

Description

@a-bali

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:

  1. 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).
  2. When req.Reasoning != nil, map its effort through unchanged (downgrading unknown levels to the closest of low/high/max).
  3. 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.

Metadata

Metadata

Labels

No labels
No labels

Type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions