Skip to main content

Reasoning

Many current models reason before answering. Where the depth is adjustable, it is a parameter: reasoning_effort on Chat Completions, reasoning.effort on Responses, output_config.effort (or a thinking object) on Messages. Where it isn't adjustable, the model still reasons, and you pay for it as output tokens.

Works with​

Models whose catalog entry lists reasoning_efforts. The levels vary by model and GET /v1/models is authoritative; the per-model ladder is also on the capability matrix. Models with reasoning_efforts: null (mindshub_air, kimi among them) reason internally on every request and the level isn't tunable.

A model can also pin the level it runs at without offering a choice of it: a null reasoning_efforts alongside a non-null default_reasoning_effort. mindshub_air is pinned to medium this way, so every request reasons at medium and a reasoning_effort you send is replaced by the pinned level rather than honored — reported as a clamp in X-MindsHub-Clamped-Params. Pick a model that publishes a ladder if you need to choose the level.

Request​

response = client.chat.completions.create(
model="deepseek-v4-flash",
messages=[{"role": "user", "content": "Prove that √2 is irrational."}],
reasoning_effort="high",
)
print(response.choices[0].message.content)

These samples use deepseek-v4-flash, which takes none, low, high and max and draws the prepaid wallet.

Requests never fail over the effort level. A recognized level outside a model's ladder is clamped onto it: below the floor, including none on a model without an off switch, you get the cheapest supported rung (which can cost more than the unsupported level you requested); above the ceiling you get the top rung; between rungs you get the lower one. Clamps are reported in X-MindsHub-Clamped-Params.

An unrecognized value such as a typo fits no rung. On a model that publishes a default_reasoning_effort you get that level, clamped onto the ladder like any other, and it is reported as a clamp; only a model that publishes no default drops the parameter and reports it in X-MindsHub-Dropped-Params, letting the provider's own default apply. On models with reasoning_efforts: null and no default the drop still comes with no header.

A clamp on an unrecognized level names the category other, not the value you sent — reasoning_effort=other>medium, never reasoning_effort=hgih>medium — because a level we don't recognize is caller-supplied text and isn't echoed back in a response header. A level we do recognize is named exactly as you sent it.

One consequence worth planning for: a typo no longer lands on the provider's default, it lands on the model's published one. On models whose default is the top of their ladder (glm, qwen, gemini, grok-4-5 among them) that is the dearest rung; on gpt-mini and gpt-nano, whose default is none, it turns reasoning off. Read default_reasoning_effort off GET /v1/models if that matters to you, and send a level you have validated.

If you send nothing, the model's default_reasoning_effort applies, which for most reasoning models is not "off". Send the lowest listed level explicitly if you want speed over depth.

Extended thinking on Messages​

A thinking object on a Messages request ({"type": "enabled", "budget_tokens": 8000}) is forwarded to the target model where that model accepts it, including its budget_tokens; the current Claude 5 models accept it. thinking and redacted_thinking blocks in your message history are replayed to the model unmodified, so a multi-turn tool workflow on a thinking model keeps working. On the OpenAI-shaped APIs there is no thinking object; use the effort level.

Carrying reasoning across turns on Responses​

include: ["reasoning.encrypted_content"] carries a reasoning model's thinking across chained turns (previous_response_id); the other include values are ignored. reasoning.summary asks for a summary on the returned reasoning item.

Response​

  • Chat Completions and Responses never return reasoning content; you get the final answer. usage.completion_tokens_details.reasoning_tokens (or output_tokens_details.reasoning_tokens) is a subset of the output count, not an addition to it, broken out by the GPT/Grok families and Gemini models. Elsewhere it reads 0, which means no separately-reported reasoning rather than no reasoning: the Claude family bills thinking as output without separating it.
  • Messages returns thinking blocks, on streamed and non-streamed turns alike, in Anthropic's required order (before the text), with their signature, usually with empty or withheld content. Don't assume the first block is your text.

Streaming​

On Messages, thinking blocks stream as content_block_* events before the text and carry a signature so a streaming client can replay them. On the OpenAI-shaped APIs nothing about the stream changes. See Streaming.

Per-model differences​

  • Levels differ by model: sonnet supports low through max, deepseek-v4-flash takes none, low, high and max, gpt-mini adds none. Read the model's own list rather than assuming a family shares one ladder.
  • mindshub_air and kimi reason internally with no adjustable level. Budget max_tokens generously for them (a few hundred tokens of headroom) or the reasoning uses the cap and the visible answer arrives truncated with finish_reason: "length".
  • mindshub_air is pinned to medium: it publishes no ladder but does publish a default_reasoning_effort, so every request reasons at that level and one you send is replaced by it. kimi publishes neither, so a level you send it is dropped with no header.
  • Gemini sets depth through thinking_level, which the effort parameter carries; it accepts no thinking object.

Errors you can hit​

None specific to this feature: an out-of-ladder level is clamped, and an unrecognized one falls back to the model's published default where it has one and is dropped where it does not — all reported in headers. A turn whose reasoning exhausted max_tokens ends with finish_reason: "length" (stop_reason: "max_tokens" on Messages, status: "incomplete" on Responses). See Errors.