Reasoning effort

Set how much a tier thinks before it answers, from none to high, and keep hidden thinking from spending your whole max_tokens budget.

reasoning_effort caps the hidden thinking a tier does before it answers. You send one of four values on a chat request, or omit it and the tier applies its default. The effort the call ran at comes back on the response as cruxy.reasoning_effort.

This request asks kavi for a one-line answer, so it turns thinking off and keeps the budget small:

curl https://api.cruxy.ai/api/v1/chat \
  -H "Authorization: Bearer $CRUXY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "kavi",
    "stream": false,
    "reasoning_effort": "none",
    "max_tokens": 256,
    "messages": [
      { "role": "user", "content": "Is Mumbai north or south of Chennai? Answer in one sentence." }
    ]
  }'

The four values

ValueEffect
noneTurns thinking off. The tier answers directly.
low, medium, highTurn thinking on. On a graded tier the three are different depths, from low to high; on an on-or-off tier each one turns thinking on.

Any other value is 400. The field is accepted on POST /api/v1/chat, POST /api/v2/chat, and POST /v1/chat/completions.

Defaults per tier

Omit reasoning_effort and each tier applies its own default. graded says whether low, medium, and high are different depths on the tier. When it is false the control is on or off: none turns thinking off, every other value turns it on, low thinks as long as high, and only max_tokens bounds it.

TierProfileDefaultgraded
kaviDeephighfalse: on or off
vaaniBalancedlowtrue
miraFastnonetrue

With model: "auto", the router chooses the effort per request unless you send one. These are the shipped defaults; GET /api/v1/models reports each tier's live reasoning.default_effort and reasoning.graded, read from the same configuration the chat endpoints apply.

Thinking spends max_tokens

A tier that thinks generates its thinking inside the same output budget as its answer. On POST /api/v1/chat and POST /v1/chat/completions, the thinking is not returned as content. So a small max_tokens on a tier that thinks can be used up before the answer starts.

Check for the trap when you read a response, so a truncated turn never reaches your user as an empty answer:

const { message, finish_reason } = completion
if (finish_reason === 'length' && !message.content) {
  // The budget ran out before the answer began. Resend with
  // reasoning_effort: 'none', or with max_tokens unset.
}

When to send none

Send none when the answer needs no deliberation and you want it fast:

  • Short, direct answers: a classification, a yes or no, an extracted field, a one-line reply.
  • A small max_tokens: any time you cap the output tightly, so thinking cannot consume the cap.
  • A turn that times out: a stream: false call is bounded by the tier's deadline and answered 504 upstream_timeout past it. Lowering reasoning_effort or max_tokens shortens the turn; streaming lifts the limit to five minutes.

Keep thinking on when the answer needs deliberation, and leave max_tokens unset there so the thinking and the answer share the tier's full cap.

See the thinking

The OpenAI-shaped wires do not return the thinking. The native wire, POST /api/v2/chat, does: a non-streaming response carries a top-level reasoning string, and a stream sends the thinking as reasoning events, separate from the answer's delta events. Either way it is present only when the tier reasoned.

  • It is not part of the answer, and it sits outside message on purpose. Do not send it back in the conversation.
  • There is no separate reasoning-token count. usage.output_tokens already includes the thinking, undivided.
  • The effort is echoed as routing.reasoning_effort on the native wire.

Next steps

Was this page helpful?