Reasoning models
Many Grove models are reasoning models: they think before they answer. The
thinking is returned to you separately from the answer, in a
reasoning_content field, using the same convention popularized by DeepSeek's
API. Your content stays clean; the reasoning rides alongside it.
Non-streaming
message.reasoning_content sits next to message.content:
{
"choices": [{
"message": {
"role": "assistant",
"content": "391",
"reasoning_content": "17 * 23 = 391"
},
"finish_reason": "stop"
}]
}
Streaming
Reasoning streams first as delta.reasoning_content chunks, then the answer
streams as delta.content chunks:
data: {"choices":[{"delta":{"reasoning_content":"17 ×"}}]}
data: {"choices":[{"delta":{"reasoning_content":" 23 = 39"}}]}
data: {"choices":[{"delta":{"content":"**391**"}}]}
A simple accumulator:
reasoning, answer = "", ""
for chunk in stream:
d = chunk.choices[0].delta
if getattr(d, "reasoning_content", None):
reasoning += d.reasoning_content
if d.content:
answer += d.content
Billing
Reasoning tokens are completion (output) tokens: they are generated
tokens and bill at the model's output rate. The usage object's
completion_tokens already includes them. Reasoning-heavy prompts on
reasoning models cost more than their short answers suggest; budget
accordingly.
Client support
Clients vary:
- Handles
reasoning_contentnatively (renders a thinking block): most modern SDK integrations and chat UIs that support DeepSeek-style reasoning. - Ignores unknown fields: you'll see only the final answer; the reasoning is still in the raw response if you want it.
- Some tools mishandle it for custom providers and print reasoning as
plain text. That is a client-side rendering choice; the API always delivers
reasoning in the separate field, never inlined into
content.
Controlling reasoning
Standard OpenAI-style request parameters pass through to the model untouched (this is a zero-injection passthrough API). Reasoning-capable models that support effort control accept, for example:
{ "model": "mimo-v2.5", "reasoning_effort": "none", "messages": [...] }
Support and accepted values vary by model; treat unsupported values as model-defined behavior. When in doubt, send nothing: every model's default is its recommended setting.