# Reasoning models

> Control reasoning effort on MirAPI across the OpenAI, Anthropic, and Gemini protocols, read reasoning content in streams, and understand output-token billing.

Reasoning models spend extra tokens "thinking" before answering. MirAPI passes reasoning controls through in each protocol's native form, and in streaming responses the reasoning content arrives ahead of the final answer.

## Reasoning controls by protocol

### OpenAI — `reasoning_effort`

On the OpenAI-compatible `/v1/chat/completions` endpoint, pass `reasoning_effort` to set how hard the model reasons:

```python
import os
from openai import OpenAI

client = OpenAI(base_url="https://api.mirapi.ai/v1", api_key=os.environ["MIRAPI_API_KEY"])

response = client.chat.completions.create(
    model="deepseek-chat",
    messages=[{"role": "user", "content": "Prove that sqrt(2) is irrational"}],
    reasoning_effort="high",
)

print(response.choices[0].message.content)
```

`reasoning_effort` accepts the levels a model supports (for example `low` / `medium` / `high`). Non-reasoning models ignore it, so sending the field is always safe.

### Anthropic — `thinking`

On `/v1/messages`, reasoning is controlled with `thinking`:

```json
{
  "model": "deepseek-chat",
  "max_tokens": 4096,
  "thinking": {
    "type": "enabled",
    "budget_tokens": 2048
  },
  "messages": [
    {
      "role": "user",
      "content": "Design a file-cache eviction policy"
    }
  ]
}
```

`budget_tokens` caps how many tokens the model may spend on thinking. Keep it below `max_tokens` so tokens remain for the final answer.

### Gemini

MirAPI also exposes a Gemini-compatible endpoint at `https://api.mirapi.ai/v1beta` (`POST /v1beta/models/{model}:generateContent`). Reasoning support is model-dependent — check the model's `supported_parameters` in the catalogue to see whether it can reason. Reasoning tokens are billed as output tokens on every protocol.

## Reasoning in streams

With `stream: true`, reasoning arrives **before** the final answer as stream deltas (standard SSE with `data:` lines, ending in `data: [DONE]`):

```python
stream = client.chat.completions.create(
    model="deepseek-chat",
    messages=[{"role": "user", "content": "Solve: 17 × 23"}],
    stream=True,
)

for chunk in stream:
    delta = chunk.choices[0].delta
    if getattr(delta, "reasoning_content", None):
        print("[reasoning]", delta.reasoning_content)
    elif delta.content:
        print(delta.content, end="", flush=True)
```

The exact delta field depends on the model and protocol: OpenAI-compatible models commonly use `reasoning_content`, while Anthropic streams deliver thinking in `delta.thinking`.

## Parameter reference

| Protocol | Parameter | Meaning |
| --- | --- | --- |
| OpenAI | `reasoning_effort` | Reasoning strength; the model defines the supported levels. Ignored by non-reasoning models. |
| Anthropic | `thinking.type` | `enabled` turns reasoning on. |
| Anthropic | `thinking.budget_tokens` | Maximum tokens the model may use for thinking. |

## Billing

Reasoning/thinking tokens are billed as **output tokens** and are part of `usage.completion_tokens` (or the Anthropic equivalent). A large reasoning budget can dominate a request's cost, so keep the effort or budget low for simple tasks.

The `usage` object reports token counts only — it never includes an amount. See the exact cost in the console or via `GET /api/log/token`.

## Errors and retries

Reasoning parameters have no dedicated error codes. If the upstream model rejects a request, the failure surfaces in the standard error envelope (`type: "upstream_error"` for upstream failures, with the message redacted). Every error message ends with a request ID — include it in support tickets.

Follow the general retry rules: back off with jitter on `429` (there is no `Retry-After` header), and retry idempotent requests on `500`. An exhausted balance returns `403`; the key resumes immediately after a top-up.

## Troubleshooting

- **No reasoning content appears.** Some models reason internally but do not return the trace; check the model's `supported_parameters` in the catalogue and the stream/non-stream field names.
- **The parameter seems ignored.** Non-reasoning models ignore `reasoning_effort`; on other protocols the chosen channel may not support the control.
- **A request costs much more than expected.** Reasoning tokens are output tokens — lower `reasoning_effort` or `budget_tokens` for simple prompts.

## Related links

- [Models](/docs/models)
- [Billing](/docs/billing)
- [Structured outputs](/docs/guides/structured-outputs)
- [Prompt caching](/docs/guides/prompt-caching)
- [Authentication](/docs/api-reference/authentication)
- [Errors](/docs/api-reference/errors)