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 (see Request parameters for the few fields the API sets). Reasoning-capable models that support effort control accept, for example:

{ "model": "mimo-v2.6-flash", "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.

Models that default to no reasoning

A few hybrid models ship with thinking off by default and only reason when you ask. The DeepSeek V4 Flash family (deepseek-v4-flash, deepseek-v4-flash-0731) is the main one: send "reasoning_effort": "high" (or "max") and the model thinks, returning its reasoning in reasoning_content as above. No parameter means a fast, direct answer. If a reasoning-capable model seems to have reasoning "disabled", this is almost always why.

Through LiteLLM and similar proxies

LiteLLM (and some other client proxies) drops request parameters it does not recognize for a custom provider — including reasoning_effort — so your setting may never reach us, and a default-off model stays off. Pass it through extra_body, which bypasses the parameter filter. (The openai/ prefix selects LiteLLM's OpenAI-compatible adapter; it does not mean the model is from OpenAI.)

response = litellm.completion(
    model="openai/deepseek-v4-flash-0731",   # or the -turbo id
    api_base="https://api.pgsgrove.com/v1",
    api_key="pgsk_...",
    messages=[...],
    extra_body={"reasoning_effort": "high"},
)
print(response.choices[0].message.reasoning_content)

On the LiteLLM proxy, the equivalent is allowed_openai_params: ["reasoning_effort"] in the model config (or extra_body per request). The reasoning comes back in reasoning_content as usual, streaming included.

Reasoning on the native protocols

Each native protocol has its own thinking control, and all of them map to the same underlying switch:

  • Anthropic Messages (Claude Code): "thinking": {"type": "enabled"} turns reasoning on (large budgets map to max effort), {"type": "disabled"} turns it off, and output_config.effort is honored when present. Adaptive thinking leaves the model at its own default.
  • Ollama protocol: "think": true / "think": false, or the string levels "low", "medium", "high".
  • OpenAI Responses: reasoning_effort, same as chat completions.