Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Reasoning controls

llmshim exposes one reasoning vocabulary across providers. You state the desired depth; the selected provider adapter maps it to what that model accepts.

Availability: Rust: top-level fields · CLI: high by default · Proxy/clients: fields under config

The two knobs

KnobValuesMeaning
reasoning_effortnone | low | medium | high | xhigh | maxRequested thinking or reasoning depth
reasoning_modestandard (default) | proRequests substantially more model work, accepting higher latency and cost

In a Rust request, both are top-level fields:

{
  "model": "anthropic/claude-sonnet-5",
  "messages": [{"role": "user", "content": "Solve this carefully."}],
  "reasoning_effort": "high",
  "reasoning_mode": "pro"
}

In the proxy contract, put them under config:

{
  "model": "anthropic/claude-sonnet-5",
  "messages": [{"role": "user", "content": "Solve this carefully."}],
  "config": {
    "reasoning_effort": "high",
    "reasoning_mode": "pro"
  }
}

Provider-returned reasoning is normalized as reasoning_content in Rust responses and chunks, and as reasoning or a typed reasoning event through the proxy. A provider or model may keep its reasoning hidden or return only a summary.

Portable intent or native control

Choose per request:

  1. Use the unified controls. llmshim maps the requested effort and mode to the selected model family, clamping to the nearest accepted tier when the model has a smaller vocabulary.
  2. Use the provider's native dialect. Pass an exact native object through x-openai, x-anthropic, or x-gemini. Native configuration wins over the unified controls.
flowchart LR
    U[Unified effort + mode] --> P{Native override present?}
    P -- Yes --> N[x-provider native config]
    P -- No --> F[Model-family mapping]
    F --> C[Clamp to supported tier]
    C --> W[Provider-native reasoning control]

See Native provider controls for passthrough examples.

Effort mapping tables

These mappings were verified against the live provider APIs. A bold value is a clamp rather than a direct name-for-name mapping.

OpenAI Responses API

unifiedgpt-5.6-sol/terra/lunagpt-5.5gpt-5.5-pro / gpt-5.4-progpt-5.4 / -mini / -nano
nonenonenonemedium (pro tier rejects none)none
lowlowlowmediumlow
mediummediummediummediummedium
highhighhighhighhigh
xhighxhighxhighxhighxhigh
maxmaxxhigh (max is 5.6-only)xhighxhigh

OpenAI receives reasoning.effort. Legacy minimal input is also accepted: it remains native on gpt-5.5 and clamps to low where other listed families would reject it.

Anthropic Messages API

Adaptive models use thinking: {type} plus output_config: {effort}:

unifiedOpus 4.7/4.8, Sonnet 5Opus/Sonnet 4.6
nonethinking: {type: "disabled"}thinking: {type: "disabled"}
lowadaptive + lowadaptive + low
mediumadaptive + mediumadaptive + medium
highadaptive + highadaptive + high
xhighadaptive + xhighadaptive + max
maxadaptive + maxadaptive + max

Adaptive models think by default even when no reasoning config is sent. reasoning_effort: "none" maps to disabled thinking and is the way to request zero thinking tokens.

Pre-4.6 models such as Haiku 4.5 and Claude 3.7 use enabled thinking with a token budget scaled from max_tokens and floored at 1024:

unifiedbudget
noneno thinking key
low25% of max_tokens
medium50%
high75%
xhigh90%
maxmax_tokens - 1

Gemini

Gemini uses the four-rung generationConfig.thinkingConfig.thinkingLevel enum:

unifiedgemini-3.5-flash / 3-flash-preview / 3.1-flash-lite-previewgemini-3.1-pro-preview
noneminimal (zero thinking tokens)low (this model cannot disable thinking)
lowlowlow
mediummediummedium
highhighhigh
xhighhighhigh
maxhighhigh

Gemini 3.1 Pro rejects both minimal and thinkingBudget: 0, so none clamps to its low floor. The legacy integer thinkingBudget remains available only through x-gemini.thinkingConfig.

xAI Responses API

xAI receives the nested native shape reasoning: {effort}:

unifiedgrok-4.3 / grok-4-1-fast-*grok-4.5grok-4.20-*-reasoning / -non-reasoning
nonenonelowomitted
lowlowlowomitted
mediummediummediumomitted
highhighhighomitted
xhighxhighxhighomitted
maxxhighxhighomitted

grok-4.5 cannot disable reasoning, so none clamps to low. grok-4.20 models are name-locked: reasoning on or off is encoded in the model name, and the API rejects any reasoning parameter. llmshim therefore omits it for that family.

Mode mapping: reasoning_mode: "pro"

Provider / modelWhat pro does
OpenAI gpt-5.6 family, gpt-5.5-pro, gpt-5.4-proNative reasoning.mode: "pro"
OpenAI other modelsOne-tier effort bump (low → medium → high → xhigh)
AnthropicOne-tier effort bump (low → medium → high → xhigh → max)
GeminiOne-tier bump within its four-rung enum, capped at high
xAI effort-controlled modelsOne-tier bump, capped at xhigh
xAI grok-4.20 familyNo effect because reasoning is name-locked

Rules that hold across providers:

  • standard is the default and is not sent on the wire.
  • An explicit effort of none wins over pro; a request to turn reasoning off is not bumped back on, except where the model itself cannot disable it.
  • pro without an effort lets OpenAI native-mode models select their own effort. Other models behave as a default medium bumped to high.

Precedence

  1. Native passthrough under x-openai, x-anthropic, or x-gemini wins and is not translated into another dialect. Anthropic also accepts top-level thinking and output_config in the Rust contract.
  2. Otherwise, unified reasoning_effort and reasoning_mode are mapped and clamped according to the tables above.
  3. With neither, the provider/model default applies. Anthropic adaptive models and Gemini 3.1 Pro think by default; most other families do not.

The non-obvious boundaries above were live-probed as of July 2026 and are pinned by provider unit tests. Provider capabilities can change, so the implementation and these tables must move together.