diff --git a/src/content/docs-es/models.mdx b/src/content/docs-es/models.mdx index 27e615f..28ece00 100644 --- a/src/content/docs-es/models.mdx +++ b/src/content/docs-es/models.mdx @@ -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 diff --git a/src/content/docs/models.mdx b/src/content/docs/models.mdx index eebc628..693cc09 100644 --- a/src/content/docs/models.mdx +++ b/src/content/docs/models.mdx @@ -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. diff --git a/src/tests/lib/docsReasoning.test.ts b/src/tests/lib/docsReasoning.test.ts index b53adc2..b9fbd4a 100644 --- a/src/tests/lib/docsReasoning.test.ts +++ b/src/tests/lib/docsReasoning.test.ts @@ -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`, () => {