Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 41 additions & 0 deletions src/content/docs-es/models.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -455,6 +455,47 @@ const chat = await client.chat.completions.create({
});
```

### Limitar el razonamiento con un presupuesto de tokens.

En `qwen3.6`, `gemma4` y `qwen3.8-flash` también puedes limitar la fase de
razonamiento a un número de tokens, en Chat Completions. Envía
`thinking_token_budget` o `thinking_budget`: son dos nombres del mismo
parámetro, así que usa el que ya envíe tu código. Cada modelo
recibe el nombre que entiende. Ponlo en el primer nivel del cuerpo o dentro de
`extra_body`.

- Un entero de `1` a `32768` limita el razonamiento a ese número de tokens. Es
un tope estricto: el modelo deja de razonar ahí y escribe su respuesta.
- `0` apaga el razonamiento, igual que `reasoning_effort: "none"`.
- En NaN, un valor mayor (o que no sea un entero) se reduce a `32768`.

Envía un presupuesto o `reasoning_effort`, no los dos: combinados, el
resultado depende del modelo. En el resto de modelos el presupuesto no forma
parte de este contrato (según el modelo se rechaza con un `400` o se ignora);
usa `reasoning_effort`. En Responses el presupuesto no está garantizado; usa
`reasoning: {"effort": ...}`.

```bash
curl https://api.nan.builders/v1/chat/completions \
-H "Authorization: Bearer $NAN_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "qwen3.8-flash",
"thinking_budget": 2048,
"messages": [{"role": "user", "content": "How many primes are there below 200?"}]
}'
```

Con el SDK de OpenAI va por `extra_body`:

```python
chat = client.chat.completions.create(
model="qwen3.8-flash",
extra_body={"thinking_budget": 2048},
messages=[{"role": "user", "content": "How many primes are there below 200?"}],
)
```

## Respuestas largas: usa streaming.

Una petición sin `stream: true` no devuelve nada hasta que la respuesta
Expand Down
41 changes: 41 additions & 0 deletions src/content/docs/models.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -452,6 +452,47 @@ const chat = await client.chat.completions.create({
});
```

### Capping reasoning with a token budget.

On `qwen3.6`, `gemma4` and `qwen3.8-flash` you can also cap the reasoning
phase at a number of tokens, on Chat Completions. Send
`thinking_token_budget` or `thinking_budget`: they are two names for the same
parameter, so use whichever your code already sends. Each model
receives the name it reads. Put it at the top level of the body or inside
`extra_body`.

- An integer from `1` to `32768` caps reasoning at that many tokens. It is a
hard cap: the model stops reasoning there and writes its answer.
- `0` turns reasoning off, like `reasoning_effort: "none"`.
- On NaN, a larger value (or one that is not an integer) is lowered to `32768`.

Send either a budget or `reasoning_effort`, not both: combined, the result
differs by model. On the other models a budget is not part of this contract
(depending on the model it is rejected with a `400` or ignored); use
`reasoning_effort` there. On Responses the budget is not guaranteed to apply;
use `reasoning: {"effort": ...}` there.

```bash
curl https://api.nan.builders/v1/chat/completions \
-H "Authorization: Bearer $NAN_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "qwen3.8-flash",
"thinking_budget": 2048,
"messages": [{"role": "user", "content": "How many primes are there below 200?"}]
}'
```

With the OpenAI SDK it goes through `extra_body`:

```python
chat = client.chat.completions.create(
model="qwen3.8-flash",
extra_body={"thinking_budget": 2048},
messages=[{"role": "user", "content": "How many primes are there below 200?"}],
)
```

## Long outputs: stream them.

A request without `stream: true` returns nothing until the whole answer is ready, and it has to be ready within **120 seconds**. Past that, the connection is closed with a `524` (or an error a few seconds earlier), whatever the model. At `deepseek-v4-flash` speeds that is roughly 10,000 to 15,000 output tokens; slower models, and reasoning models that think before they answer, fit less.
Expand Down
26 changes: 26 additions & 0 deletions src/tests/lib/docsReasoning.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,32 @@ describe('models page: the per-model table is the contract (en + es)', () => {
}
});

describe('models page: the reasoning token budget (en + es)', () => {
// Measured live 2026-10-19 (nan-devops#895): both names reach every model
// under the name it reads; 64 caps reasoning on qwen3.6, gemma4 and
// qwen3.8-flash, 0 turns it off, NaN lowers anything above 32768.
for (const locale of ['', '-es'] as const) {
const text = section(locale);
it(`${locale || 'en'}: names both parameters, the three models, the range and the off value`, () => {
expect(text).toContain('`thinking_token_budget`');
expect(text).toContain('`thinking_budget`');
for (const model of ['`qwen3.6`', '`gemma4`', '`qwen3.8-flash`']) expect(text).toContain(model);
expect(text).toContain('`32768`');
expect(text).toMatch(locale === '' ? /`0` turns reasoning off/ : /`0` apaga el razonamiento/);
});

it(`${locale || 'en'}: says not to combine it with reasoning_effort, and what the other models do`, () => {
expect(text).toMatch(locale === '' ? /not both/ : /no los dos/);
expect(text).toMatch(locale === '' ? /a budget is not part of this contract/ : /el presupuesto no forma\s+parte de este contrato/);
});

it(`${locale || 'en'}: shows it top level and through extra_body`, () => {
expect(text).toContain('"thinking_budget": 2048');
expect(text).toContain('extra_body={"thinking_budget": 2048}');
});
}
});

describe('model cards agree with the table (en + es)', () => {
for (const locale of ['', '-es'] as const) {
it(`${locale || 'en'}: every chat card says how reasoning is controlled`, () => {
Expand Down
Loading