Reasoning
Use `reasoning_effort` on o-series and DeepSeek-R1 style models. Read `reasoning_content` from the stream.
Reasoning models emit hidden chain-of-thought tokens before they
produce the visible answer. CleverRouter exposes a single
reasoning_effort knob and a typed reasoning_content field so you
don't have to special-case per provider.
At a glance
| Wire format | OpenAI reasoning_effort (mapped to provider equivalents) |
| Recommended models | deepseek/deepseek-r1-distill-llama-70b, mistral/magistral-medium |
| Billed as | Completion tokens (completion_tokens_details.reasoning_tokens) |
| Latency budget | Seconds (low) → minute+ (high) |
Set the effort
import { createCleverRouter } from '@cleverrouter/sdk';
const cr = createCleverRouter({ apiKey: process.env.CLEVERROUTER_API_KEY! });
const res = await cr.chat({
model: 'deepseek/deepseek-r1-distill-llama-70b',
reasoning_effort: 'high', // 'low' | 'medium' | 'high'
messages: [
{
role: 'user',
content: 'Prove that for every prime p > 2, p² mod 24 = 1.',
},
],
});
console.log(res.choices[0]?.message.content);
console.log(res.usage?.completion_tokens_details?.reasoning_tokens);Effort vs latency vs cost
| Effort | Use case | Typical latency |
|---|---|---|
low | Validation, simple refactors, lookups | 2 – 6 s |
medium | Complex tasks, multi-step planning | 6 – 20 s |
high | Proofs, architecture reviews, debugging | 20 – 90 s |
Reasoning tokens cost real money
Hidden thinking tokens are billed at the same rate as visible
completion tokens. 'high' can quietly double or triple your bill
on long-form questions. Default to 'low'; upgrade only when the
problem actually needs it.
Read reasoning content from the stream
Some models stream their chain-of-thought as a separate
reasoning_content delta before the answer starts:
const stream = cr.stream({
model: 'deepseek/deepseek-r1-distill-llama-70b',
reasoning_effort: 'medium',
messages: [{ role: 'user', content: 'Hard question.' }],
});
let thinking = '';
let answer = '';
for await (const chunk of stream) {
const delta = chunk.choices[0]?.delta;
if (delta?.reasoning_content) {
thinking += delta.reasoning_content;
// typically hidden in UI, shown behind a "Show thinking" toggle
}
if (delta?.content) {
answer += delta.content;
process.stdout.write(delta.content);
}
}How the gateway maps reasoning_effort
The gateway translates the OpenAI-shape reasoning_effort to the
provider's equivalent so your code stays portable:
| Provider | Underlying field |
|---|---|
| OpenAI o-series | reasoning_effort |
| Anthropic (via Bedrock) | thinking.budget_tokens |
| DeepSeek-R1 family | reasoning_effort passthrough |
| Mistral Magistral | reasoning.budget |
Common gotchas
- Tensorix Kimi-K2 quirk. This provider emits
reasoning_contentbut sometimes leavescontentempty even after the answer finishes. The SDK forwardsreasoning_contentseparately so you can recover the visible text from it ifcontentis missing. - Streaming without
reasoning_content. Not every reasoning model streams chain-of-thought — some only expose it in non-stream mode undercompletion_tokens_details.reasoning_tokens. - Long-running streams. With
high, set{ timeoutMs: 120_000 }on the call — the SDK's 60s default will abort mid-thought.
Related
- Chat completions — base request body.
- Streaming —
reasoning_contentdeltas. - Model catalog —
frontier-reasoningclass.