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_content natively (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.