Skip to content
Reasoning effort

Reasoning effort

New

A model that reasons returns its reasoning text next to the answer, in a field of its own. On the hosted open-weight models one request field sets how deeply the model reasons before it answers.

POST https://api.shannon-ai.com/v1/chat/completions

from openai import OpenAI

client = OpenAI(api_key="YOUR_API_KEY", base_url="https://api.shannon-ai.com/v1")

response = client.chat.completions.create(
    model="Kimi-K3-3BIT-REAP",
    reasoning_effort="low",
    messages=[{"role": "user", "content": "Is 221 a prime number?"}],
)

message = response.choices[0].message
print("Reasoning:", getattr(message, "reasoning_content", None))
print("Answer:", message.content)
print("Reasoning tokens:", response.usage.completion_tokens_details.reasoning_tokens)

The reply carries the reasoning text in reasoning_content, the answer in content, and the reasoning tokens in usage:

200 JSON
{
  "id": "chatcmpl-2a6c8e0b4d1f4a3c9e7b5d3f1a8c6e4b",
  "object": "chat.completion",
  "created": 1791590400,
  "model": "Kimi-K3-3BIT-REAP",
  "choices": [
    {
      "index": 0,
      "message": {
        "role": "assistant",
        "content": "No. 221 = 13 x 17, so it is not prime.",
        "reasoning_content": "Try small primes. 221 / 13 = 17, so 221 = 13 x 17."
      },
      "finish_reason": "stop"
    }
  ],
  "usage": {
    "prompt_tokens": 14,
    "completion_tokens": 43,
    "total_tokens": 57,
    "prompt_tokens_details": {"cached_tokens": 0},
    "completion_tokens_details": {"reasoning_tokens": 27}
  }
}

Which models reason

Model Returns reasoning text Applies the effort field
shannon-1.6-lite — —
shannon-1.6-pro, shannon-2-lite, shannon-2-pro, shannon-3, shannon-3-pro, shannon-3.1, shannon-3.1-pro, shannon-coder-1 Yes —
Every hosted open-weight model Yes Yes

These are the flags capabilities.reasoning and capabilities.reasoning_effort that GET /v1/models reports for each id. A reply carries reasoning text only when the model produced some. Models & pricing

Setting the effort

Each endpoint has its own spelling of the effort. All of them select one of the same four levels.

Field Type Default Description Applied by
reasoning_effort string high /v1/chat/completions. How deeply the model reasons before it answers: off, low, medium or high. Hosted open-weight models
reasoning object | string /v1/chat/completions. The same value as {"effort": "low"} or as a bare string. When both fields are sent, reasoning_effort counts. Hosted open-weight models
reasoning.effort string high /v1/responses. Written as the object {"effort": "low"}. Hosted open-weight models
thinking object /v1/messages. {"type": "enabled", "budget_tokens": n} or {"type": "disabled"}. The budget selects one of the levels; see the table further down. Hosted open-weight models
{
  "model": "Kimi-K3-3BIT-REAP",
  "reasoning_effort": "low",
  "messages": [{"role": "user", "content": "Is 221 a prime number?"}]
}
Value Also accepted Effect
off none, minimal No reasoning. The reply carries no reasoning text.
low Brief reasoning.
medium default Medium depth.
high max The deepest level. This is the level of a request that sends no value.
  • Values are read without regard to upper or lower case.
  • The value default means medium. Leaving the field out means high.
  • The Shannon models (shannon-*) set their own depth in every request; GET /v1/models reports reasoning_effort: false for them.

The thinking budget on /v1/messages

On /v1/messages the thinking field selects the level. budget_tokens picks one of the levels above; it is not a token limit of its own. adaptive is read like enabled.

You send Level
{"type": "disabled"} off
{"type": "enabled", "budget_tokens": n} with n up to 2,048 low
n from 2,049 to 8,192 medium
A larger n, or enabled without budget_tokens high
No thinking field high

Where the reasoning text arrives

Reasoning text is always separate from the answer. Each format has its own place for it:

Endpoint Not streamed Streamed
/v1/chat/completions choices[0].message.reasoning_content: a string, or null when the model produced none. Chunks with choices[0].delta.reasoning_content, before the chunks with delta.content.
/v1/responses An output item {"type": "reasoning", "summary": [{"type": "summary_text", "text": "…"}]} before the message item. No item when there is no reasoning. response.output_item.added with a reasoning item, then response.reasoning_summary_text.delta events and one response.reasoning_summary_text.done.
/v1/messages A first content block {"type": "thinking", "thinking": "…"}, then the text block. No thinking block when there is no reasoning. A thinking content block: content_block_start, content_block_delta events with thinking_delta, content_block_stop. The text block follows.
{
  "choices": [
    {
      "index": 0,
      "message": {
        "role": "assistant",
        "content": "No. 221 = 13 x 17, so it is not prime.",
        "reasoning_content": "Try small primes. 221 / 13 = 17, so 221 = 13 x 17."
      },
      "finish_reason": "stop"
    }
  ],
  "usage": {
    "prompt_tokens": 14,
    "completion_tokens": 43,
    "total_tokens": 57,
    "prompt_tokens_details": {"cached_tokens": 0},
    "completion_tokens_details": {"reasoning_tokens": 27}
  }
}

Where to look, per model:

Models Where the text arrives
Hosted open-weight models On every endpoint, streamed or not. A request with effort off, or with response_format / text.format, is answered without reasoning text.
shannon-3, shannon-3-pro, shannon-3.1, shannon-3.1-pro On every endpoint, streamed or not, whenever the model produced reasoning text.
shannon-2-lite, shannon-2-pro /v1/chat/completions, not streamed: in message.reasoning_content. Streamed, in a request without tools or response_format: the stream carries comment lines : thinking while the model reasons, then the answer chunks. /v1/messages, streamed: a thinking block before the text block.
shannon-1.6-pro, shannon-coder-1 In streamed replies and in replies to requests that carry tools, whenever the model produced reasoning text.

On /v1/responses, a reply that is not streamed carries the reasoning item for the Shannon 3 family and the hosted open-weight models.

Reading a stream

In a stream the reasoning text comes first, in deltas of its own, and the answer follows. Print or store the two separately:

from openai import OpenAI

client = OpenAI(api_key="YOUR_API_KEY", base_url="https://api.shannon-ai.com/v1")

stream = client.chat.completions.create(
    model="Kimi-K3-3BIT-REAP",
    reasoning_effort="medium",
    stream=True,
    messages=[{"role": "user", "content": "Is 221 a prime number?"}],
)

for chunk in stream:
    if not chunk.choices:
        continue
    delta = chunk.choices[0].delta
    reasoning = getattr(delta, "reasoning_content", None)
    if reasoning:
        print(reasoning, end="", flush=True)      # the reasoning text comes first
    if delta.content:
        print(delta.content, end="", flush=True)  # then the answer

The first chunk of a hosted open-weight model, reasoning or answer, also carries delta.role: "assistant". Streaming

Reasoning tokens and billing

On the hosted open-weight models, reasoning tokens are output tokens: they are billed at the output price of the model, and the output count already includes them. usage shows the reasoning share here:

Endpoint Field Note
/v1/chat/completions usage.completion_tokens_details.reasoning_tokens Already included in completion_tokens.
/v1/responses usage.output_tokens_details.reasoning_tokens Already included in output_tokens.
/v1/messages usage.output_tokens Reasoning and answer together. This format has no separate count.
  • On the hosted open-weight models max_tokens limits the answer text. Reasoning tokens are not counted against it.
  • Because reasoning is billed as output, the effort level is also a cost setting: off produces no reasoning tokens.
  • The Shannon models report prompt_tokens, completion_tokens and total_tokens (input_tokens and output_tokens on /v1/messages) without a reasoning share, and bill one flat price per token. Models & pricing

Reasoning in the next request

You do not have to send reasoning back. A thinking block or a reasoning item in the conversation you send is not passed on to the model, so an assistant turn can go back with or without it. A thinking block has the two fields type and thinking; it has no signature.

Errors

Status Type Message When
400 invalid_request_error unknown reasoning effort '<value>'; expected off, low, medium or high A hosted open-weight model received a value outside the list, for example xhigh. Nothing is drawn from your balance.
422 invalid_request_error Failed to deserialize the JSON body into the target type: … reasoning_effort is not a string.

Authentication, balance and server errors are the same as for every request. Error Handling