OpenAI’s o-series models (and compatible providers such as Groq’sDocumentation Index
Fetch the complete documentation index at: https://mintlify.com/phpaisdk/openai-compatible/llms.txt
Use this file to discover all available pages before exploring further.
deepseek-r1 variants) expose a reasoning capability that can be influenced at request time. The aisdk/openai-compatible wire adapter supports this through the portable Reasoning value object from aisdk/core. There is exactly one supported path: pass a normalized effort level and the builder emits the reasoning_effort field. Any other configuration either has no effect or throws immediately so that misconfigured requests fail fast rather than silently degrading.
The Single Resolution Path
ChatRequestBuilder::build() checks for reasoning configuration after all other body fields have been assembled. The logic is intentionally narrow:
Reasoning configuration | Result |
|---|---|
null (not set) | No reasoning_effort field in body |
Reasoning::effort('low') | "reasoning_effort": "low" |
Reasoning::effort('medium') | "reasoning_effort": "medium" |
Reasoning::effort('high') | "reasoning_effort": "high" |
Reasoning::budget(N) | Throws InvalidArgumentException immediately |
Using Reasoning Effort
PassReasoning::effort() with a level string when constructing your TextModelRequest. The builder handles the rest:
'low', 'medium', and 'high'. The adapter forwards whatever string you pass directly to the provider — no validation or normalization is applied beyond the field name mapping.
What Throws an Exception
Passing a token budget instead of an effort level throwsAiSdk\Exceptions\InvalidArgumentException before any HTTP call is made:
Why token budgets are rejected
The OpenAI-compatible wire format has no field for a portable token budget. Silently dropping the budget would mean a caller who explicitly configured reasoning depth gets a request body that ignores their intent. Throwing immediately surfaces the misconfiguration at build time rather than producing a subtly wrong response. If a specific provider you are targeting does accept a token budget under a custom field name, you can inject it via theraw escape hatch described on the Provider Options page.
Reasoning Tokens in Usage
When a reasoning model returns token counts,ChatUsage::fromArray() surfaces them in the Usage object:
reasoning_tokens detail is read from completion_tokens_details.reasoning_tokens in the raw payload. If the provider does not return that detail, reasoningTokens is null.
Reasoning Deltas in Streams
When streaming,
ChatStreamParser emits a ReasoningDeltaPart whenever a chunk contains a non-empty reasoning_content or reasoning key inside the choice delta. Some providers use reasoning_content, others use reasoning — the parser checks both and uses whichever is present:StreamState::record() accumulates all ReasoningDeltaPart fragments automatically.