> ## Documentation Index
> Fetch the complete documentation index at: https://docs.gloo.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Reasoning

> Set how much a model thinks before it answers, read its reasoning streamed or not, and pick an effort level from the model catalog.

Some models think before they answer. You set how much with a reasoning effort, and most of them can return their reasoning alongside the answer.

What you get back depends on the model. Claude, Gemini and OpenAI models return the provider's **summary** of their reasoning, not the full chain of thought. Open-weight models such as DeepSeek, GLM and gpt-oss return their raw reasoning text.

Reasoning is opt-in: set an effort to get it back.

## Quick reference

| Endpoint | Ask for reasoning | Non-streamed | Streamed |
| :- | :- | :- | :- |
| [Direct Completions](/api-guides/direct-completions) | `reasoning_effort` (any level except `none`) | `choices[0].message.reasoning_content` | `choices[0].delta.reasoning_content` chunks, before the answer |
| [Completions](/api-guides/completions-v2), [Grounded Completions](/api-guides/grounded-completions) | `reasoning_effort` (any level except `none`) | `choices[0].message.reasoning_content` | Not returned |
| [Direct Responses](/api-guides/direct-responses) | `reasoning.effort` **and** `reasoning.summary` | A `reasoning` item in `output[]`, before the `message` item | `response.reasoning_summary_text.delta` events for OpenAI models served over OpenAI's Responses API; not returned for other models |
| [Responses](/api-guides/responses), [Grounded Responses](/api-guides/grounded-responses) | `reasoning.effort` **and** `reasoning.summary` | A `reasoning` item in `output[]`, before the `message` item | Not returned |

## Effort levels

Every endpoint accepts the same levels, from least to most thinking:

`none`, `minimal`, `low`, `medium`, `high`, `xhigh`, `max`

* **Which levels a model takes** is listed in its `reasoning.effort_levels` in the [model catalog](#pick-an-effort-from-the-model-catalog). Levels differ by model: Claude 5 models take `low` to `max`, for example, and GPT-5.4 takes `none`, `low`, `medium`, `high` and `xhigh`.
* **A level the model doesn't take normally runs at the nearest level it does.** For example, `none` and `minimal` run as `low` on Claude 5 models, and an effort sent to a model that doesn't reason is not sent at all. On Gemini 2.5 models, `xhigh` and `max` can be refused with a `400`, so send `high`.
* **Gemini models take levels up to `high`.** Send `high` rather than `xhigh` or `max`.
* **`none` asks for no reasoning.** Models that can't stop thinking (`can_disable: false`) still think, but return no reasoning.
* **Stay within `effort_levels` to be sure of the level you get.** A few models can still receive a level they don't list, for example `low` on GPT-5.2 Pro and GPT-5.4 Pro.

## Pick an effort from the model catalog

[`GET /platform/v2/models`](/api-reference/get-models/v2) returns a `reasoning` object on every model that reasons, and `null` on every model that doesn't:

| Field | Meaning |
| :- | :- |
| `effort_levels` | The `reasoning_effort` values the model runs as that level. Any other level is not refused: it runs at the nearest level the model has, or without an effort. When the list has no graded level (`[]` or `["none"]`), any value other than `none` runs reasoning at the model's own default level, if the model reasons by default. Empty when the model ignores the effort (Claude Opus 4.5 to 4.8 and Sonnet 4.6 think only when a request turns thinking on, and Gloo does not forward an effort to them; Gemma reasons with no control), or when Gloo does not record which levels the model accepts. |
| `returns_summary` | Whether a request with an effort gets the reasoning text back. |
| `thinks_by_default` | Whether the model reasons when you send no effort. |
| `can_disable` | Whether `none` turns reasoning off. Also `true` for a model that doesn't reason by default. |

```json theme={null}
[
  {
    "id": "gloo-anthropic-claude-opus-5",
    "supports_reasoning": true,
    "reasoning": { "effort_levels": ["low", "medium", "high", "xhigh", "max"], "returns_summary": true, "thinks_by_default": true, "can_disable": false }
  },
  {
    "id": "gloo-openai-gpt-5.4",
    "supports_reasoning": true,
    "reasoning": { "effort_levels": ["none", "low", "medium", "high", "xhigh"], "returns_summary": true, "thinks_by_default": false, "can_disable": true }
  },
  {
    "id": "gloo-openai-gpt-4.1",
    "supports_reasoning": false,
    "reasoning": null
  }
]
```

To pick an effort, take the level you want if the model lists it, otherwise the nearest level it does list:

```bash cURL theme={null}
# The reasoning object for one model (public endpoint, no key needed)
curl -s 'https://platform.ai.gloo.com/platform/v2/models' \
  | jq '.data[] | select(.id == "gloo-anthropic-claude-opus-5") | .reasoning'
```

```python Python theme={null}
import requests

ORDER = ["none", "minimal", "low", "medium", "high", "xhigh", "max"]

def pick_effort(model: dict, wanted: str) -> str | None:
    """The level to send for `wanted`, or None to send no effort."""
    reasoning = model.get("reasoning")
    if reasoning is None:
        return None  # The model doesn't reason.
    levels = reasoning["effort_levels"]
    if wanted == "none":
        # Without "none" in the list the model keeps its default behavior.
        return "none" if "none" in levels else None
    graded = [level for level in levels if level != "none"]
    if not graded:
        return None  # No graded levels: an effort would change nothing.
    return min(graded, key=lambda level: abs(ORDER.index(level) - ORDER.index(wanted)))

models = requests.get("https://platform.ai.gloo.com/platform/v2/models").json()["data"]
by_id = {m["id"]: m for m in models}

print(pick_effort(by_id["gloo-anthropic-claude-opus-5"], "minimal"))  # low
print(pick_effort(by_id["gloo-openai-gpt-5.4"], "max"))  # xhigh
print(pick_effort(by_id["gloo-openai-gpt-4.1"], "high"))  # None
```

```typescript TypeScript theme={null}
type ModelReasoning = {
  effort_levels: string[];
  returns_summary: boolean;
  thinks_by_default: boolean;
  can_disable: boolean;
};
type Model = { id: string; reasoning: ModelReasoning | null };

const ORDER = ['none', 'minimal', 'low', 'medium', 'high', 'xhigh', 'max'];

// The level to send for `wanted`, or undefined to send no effort.
function pickEffort(model: Model, wanted: string): string | undefined {
  if (!model.reasoning) return undefined; // The model doesn't reason.
  const levels = model.reasoning.effort_levels;
  if (wanted === 'none') return levels.includes('none') ? 'none' : undefined;
  const graded = levels.filter((level) => level !== 'none');
  if (graded.length === 0) return undefined; // No graded levels: an effort would change nothing.
  const distance = (level: string) =>
    Math.abs(ORDER.indexOf(level) - ORDER.indexOf(wanted));
  return graded.reduce((best, level) => (distance(level) < distance(best) ? level : best));
}

const res = await fetch('https://platform.ai.gloo.com/platform/v2/models');
const { data } = (await res.json()) as { data: Model[] };
const opus = data.find((m) => m.id === 'gloo-anthropic-claude-opus-5')!;

console.log(pickEffort(opus, 'minimal')); // low
```

## What comes back

### Chat Completions

A non-streamed answer carries the reasoning in `message.reasoning_content`:

```json theme={null}
{
  "choices": [
    {
      "message": {
        "role": "assistant",
        "content": "About 380 distinct people attend.",
        "reasoning_content": "Total attendance is 445. Removing the 15% who are counted twice..."
      },
      "finish_reason": "stop"
    }
  ]
}
```

On [Direct Completions](/api-guides/direct-completions), a stream sends the reasoning as `delta.reasoning_content` chunks before the first answer chunk (chunks trimmed):

```text theme={null}
data: {"object":"chat.completion.chunk","choices":[{"index":0,"delta":{"reasoning_content":"Total attendance is 445. "},"finish_reason":null}]}

data: {"object":"chat.completion.chunk","choices":[{"index":0,"delta":{"reasoning_content":"Removing the 15% counted twice leaves about 378."},"finish_reason":null}]}

data: {"object":"chat.completion.chunk","choices":[{"index":0,"delta":{"content":"About 380 distinct people attend."},"finish_reason":null}]}

data: {"object":"chat.completion.chunk","choices":[{"index":0,"delta":{},"finish_reason":"stop"}]}

data: [DONE]
```

The guarded and grounded chat streams carry no reasoning: a streamed answer there, Claude's included, has no summary. To read reasoning from those endpoints, send a non-streamed request.

### Responses

On the Responses endpoints, set `reasoning.summary` (`auto`, `concise` or `detailed`) to get the reasoning back. Without it, OpenAI and Claude models normally return no summary.

The summary comes back as a `reasoning` item in `output[]`, before the `message` item:

```json theme={null}
{
  "id": "resp_...",
  "object": "response",
  "status": "completed",
  "model": "gloo-anthropic-claude-sonnet-5.5",
  "output": [
    {
      "type": "reasoning",
      "id": "reasoning_...",
      "summary": [
        { "type": "summary_text", "text": "The user wants two sentences. Ruth stays with Naomi after loss, then Boaz redeems the family line..." }
      ]
    },
    {
      "type": "message",
      "role": "assistant",
      "content": [
        { "type": "output_text", "text": "After losing her husband, Ruth stays loyal to her mother-in-law Naomi..." }
      ]
    }
  ],
  "usage": { "input_tokens": 21, "output_tokens": 412, "output_tokens_details": { "reasoning_tokens": 318 }, "total_tokens": 433 }
}
```

Claude models on the guarded and grounded endpoints return reasoning item ids that start with `reasoning_`; OpenAI models return `rs_` ids.

Only [Direct Responses](/api-guides/direct-responses#reasoning-summaries) streams the summary, and only for OpenAI models served over OpenAI's Responses API, which pass on OpenAI's own reasoning events. They arrive before the message item opens (payloads trimmed):

```text theme={null}
event: response.output_item.added
data: {"type":"response.output_item.added","output_index":0,"item":{"type":"reasoning","id":"rs_abc","summary":[]}}

event: response.reasoning_summary_part.added
data: {"type":"response.reasoning_summary_part.added","item_id":"rs_abc","output_index":0,"summary_index":0,"part":{"type":"summary_text","text":""}}

event: response.reasoning_summary_text.delta
data: {"type":"response.reasoning_summary_text.delta","item_id":"rs_abc","output_index":0,"summary_index":0,"delta":"The user wants two sentences. "}

event: response.reasoning_summary_text.done
data: {"type":"response.reasoning_summary_text.done","item_id":"rs_abc","output_index":0,"summary_index":0,"text":"The user wants two sentences. Ruth stays with Naomi..."}

event: response.reasoning_summary_part.done
data: {"type":"response.reasoning_summary_part.done","item_id":"rs_abc","output_index":0,"summary_index":0,"part":{"type":"summary_text","text":"The user wants two sentences. Ruth stays with Naomi..."}}

event: response.output_item.done
data: {"type":"response.output_item.done","output_index":0,"item":{"type":"reasoning","id":"rs_abc","summary":[{"type":"summary_text","text":"The user wants two sentences. Ruth stays with Naomi..."}]}}

event: response.output_item.added
data: {"type":"response.output_item.added","output_index":1,"item":{"type":"message","role":"assistant",...}}

event: response.output_text.delta
data: {"type":"response.output_text.delta","output_index":1,"content_index":0,"delta":"After losing her husband, "}
```

Read the reasoning from `response.reasoning_summary_text.delta` (or the final text from `.done`) and the answer from `response.output_text.delta`, as with OpenAI.

## Examples by endpoint

Each example sets an effort and reads the reasoning and the answer. Streamed examples are shown for the endpoints that stream reasoning. The OpenAI SDKs send `reasoning_effort` and `reasoning` natively. They don't type `reasoning_content`, so read it with `getattr` in Python and a wider type in TypeScript. Parameters the SDKs don't know, such as the grounding parameters, go in `extra_body` in Python and top-level with a cast in TypeScript. If your SDK version doesn't type a level you send (such as `max`), pass it in `extra_body` as well.

### Completions

`POST /ai/v2/guarded/chat/completions`. The answer is moderated; the reasoning is not ([see below](#reasoning-is-not-moderated)).

```bash cURL theme={null}
curl -X POST 'https://platform.ai.gloo.com/ai/v2/guarded/chat/completions' \
  -H "Authorization: Bearer $GLOO_API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{
    "model": "gloo-anthropic-claude-sonnet-5.5",
    "reasoning_effort": "medium",
    "messages": [
      { "role": "user", "content": "Three Masses draw 140, 95 and 210 people, and 15% attend more than one. About how many distinct people attend?" }
    ]
  }'
```

```python Python theme={null}
import os
from openai import OpenAI

client = OpenAI(
    api_key=os.environ["GLOO_API_KEY"],
    base_url="https://platform.ai.gloo.com/ai/v2/guarded",
)

completion = client.chat.completions.create(
    model="gloo-anthropic-claude-sonnet-5.5",
    reasoning_effort="medium",
    messages=[{"role": "user", "content": "Three Masses draw 140, 95 and 210 people, and 15% attend more than one. About how many distinct people attend?"}],
)

message = completion.choices[0].message
print("Reasoning:", getattr(message, "reasoning_content", None))
print("Answer:", message.content)
```

```typescript TypeScript theme={null}
import OpenAI from 'openai';

const client = new OpenAI({
  apiKey: process.env.GLOO_API_KEY,
  baseURL: 'https://platform.ai.gloo.com/ai/v2/guarded',
});

const completion = await client.chat.completions.create({
  model: 'gloo-anthropic-claude-sonnet-5.5',
  reasoning_effort: 'medium',
  messages: [{ role: 'user', content: 'Three Masses draw 140, 95 and 210 people, and 15% attend more than one. About how many distinct people attend?' }],
});

// reasoning_content is not in the SDK's types.
const message: { content: string | null; reasoning_content?: string | null } =
  completion.choices[0].message;
console.log('Reasoning:', message.reasoning_content);
console.log('Answer:', message.content);
```

### Grounded Completions

`POST /ai/v2/grounded/chat/completions`. Point the SDK at `https://platform.ai.gloo.com/ai/v2/grounded` and send the grounding parameters as extra fields. The answer is moderated; the reasoning is not.

```bash cURL theme={null}
curl -X POST 'https://platform.ai.gloo.com/ai/v2/grounded/chat/completions' \
  -H "Authorization: Bearer $GLOO_API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{
    "model": "gloo-anthropic-claude-sonnet-5.5",
    "reasoning_effort": "medium",
    "rag_publisher": "YourPublisherName",
    "sources_limit": 3,
    "messages": [
      { "role": "user", "content": "What are practical ways to build stronger community in a local church?" }
    ]
  }'
```

```python Python theme={null}
import os
from openai import OpenAI

client = OpenAI(
    api_key=os.environ["GLOO_API_KEY"],
    base_url="https://platform.ai.gloo.com/ai/v2/grounded",
)

completion = client.chat.completions.create(
    model="gloo-anthropic-claude-sonnet-5.5",
    reasoning_effort="medium",
    messages=[{"role": "user", "content": "What are practical ways to build stronger community in a local church?"}],
    extra_body={"rag_publisher": "YourPublisherName", "sources_limit": 3},
)

message = completion.choices[0].message
print("Reasoning:", getattr(message, "reasoning_content", None))
print("Answer:", message.content)
```

```typescript TypeScript theme={null}
import OpenAI from 'openai';

const client = new OpenAI({
  apiKey: process.env.GLOO_API_KEY,
  baseURL: 'https://platform.ai.gloo.com/ai/v2/grounded',
});

const completion = await client.chat.completions.create({
  model: 'gloo-anthropic-claude-sonnet-5.5',
  reasoning_effort: 'medium',
  messages: [{ role: 'user', content: 'What are practical ways to build stronger community in a local church?' }],
  // Grounding parameters are not in the SDK's types.
  rag_publisher: 'YourPublisherName',
  sources_limit: 3,
} as OpenAI.Chat.ChatCompletionCreateParamsNonStreaming);

const message: { content: string | null; reasoning_content?: string | null } =
  completion.choices[0].message;
console.log('Reasoning:', message.reasoning_content);
console.log('Answer:', message.content);
```

### Direct Completions

`POST /ai/v2/direct/chat/completions`. Nothing is moderated on direct endpoints.

```bash cURL theme={null}
curl -X POST 'https://platform.ai.gloo.com/ai/v2/direct/chat/completions' \
  -H "Authorization: Bearer $GLOO_API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{
    "model": "gloo-anthropic-claude-sonnet-5.5",
    "reasoning_effort": "high",
    "messages": [
      { "role": "user", "content": "Three Masses draw 140, 95 and 210 people, and 15% attend more than one. About how many distinct people attend?" }
    ]
  }'
```

```python Python theme={null}
import os
from openai import OpenAI

client = OpenAI(
    api_key=os.environ["GLOO_API_KEY"],
    base_url="https://platform.ai.gloo.com/ai/v2/direct",
)

completion = client.chat.completions.create(
    model="gloo-anthropic-claude-sonnet-5.5",
    reasoning_effort="high",
    messages=[{"role": "user", "content": "Three Masses draw 140, 95 and 210 people, and 15% attend more than one. About how many distinct people attend?"}],
)

message = completion.choices[0].message
print("Reasoning:", getattr(message, "reasoning_content", None))
print("Answer:", message.content)
```

```typescript TypeScript theme={null}
import OpenAI from 'openai';

const client = new OpenAI({
  apiKey: process.env.GLOO_API_KEY,
  baseURL: 'https://platform.ai.gloo.com/ai/v2/direct',
});

const completion = await client.chat.completions.create({
  model: 'gloo-anthropic-claude-sonnet-5.5',
  reasoning_effort: 'high',
  messages: [{ role: 'user', content: 'Three Masses draw 140, 95 and 210 people, and 15% attend more than one. About how many distinct people attend?' }],
});

const message: { content: string | null; reasoning_content?: string | null } =
  completion.choices[0].message;
console.log('Reasoning:', message.reasoning_content);
console.log('Answer:', message.content);
```

Streamed:

```bash cURL theme={null}
curl -N -X POST 'https://platform.ai.gloo.com/ai/v2/direct/chat/completions' \
  -H "Authorization: Bearer $GLOO_API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{
    "model": "gloo-anthropic-claude-sonnet-5.5",
    "reasoning_effort": "high",
    "stream": true,
    "messages": [
      { "role": "user", "content": "Three Masses draw 140, 95 and 210 people, and 15% attend more than one. About how many distinct people attend?" }
    ]
  }'
```

```python Python theme={null}
stream = client.chat.completions.create(
    model="gloo-anthropic-claude-sonnet-5.5",
    reasoning_effort="high",
    stream=True,
    messages=[{"role": "user", "content": "Three Masses draw 140, 95 and 210 people, and 15% attend more than one. About how many distinct people attend?"}],
)

for chunk in stream:
    if not chunk.choices:
        continue
    delta = chunk.choices[0].delta
    reasoning = getattr(delta, "reasoning_content", None)
    if reasoning:
        print(reasoning, end="", flush=True)
    if delta.content:
        print(delta.content, end="", flush=True)
```

```typescript TypeScript theme={null}
const stream = await client.chat.completions.create({
  model: 'gloo-anthropic-claude-sonnet-5.5',
  reasoning_effort: 'high',
  stream: true,
  messages: [{ role: 'user', content: 'Three Masses draw 140, 95 and 210 people, and 15% attend more than one. About how many distinct people attend?' }],
});

for await (const chunk of stream) {
  const delta: { content?: string | null; reasoning_content?: string | null } | undefined =
    chunk.choices[0]?.delta;
  if (delta?.reasoning_content) process.stdout.write(delta.reasoning_content);
  if (delta?.content) process.stdout.write(delta.content);
}
```

### Responses

`POST /ai/v2/guarded/responses`. The answer is moderated; the reasoning summary is not.

```bash cURL theme={null}
curl -X POST 'https://platform.ai.gloo.com/ai/v2/guarded/responses' \
  -H "Authorization: Bearer $GLOO_API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{
    "model": "gloo-anthropic-claude-sonnet-5.5",
    "reasoning": { "effort": "medium", "summary": "auto" },
    "input": "Summarize the book of Ruth in two sentences."
  }'
```

```python Python theme={null}
import os
from openai import OpenAI

client = OpenAI(
    api_key=os.environ["GLOO_API_KEY"],
    base_url="https://platform.ai.gloo.com/ai/v2/guarded",
)

response = client.responses.create(
    model="gloo-anthropic-claude-sonnet-5.5",
    reasoning={"effort": "medium", "summary": "auto"},
    input="Summarize the book of Ruth in two sentences.",
)

for item in response.output:
    if item.type == "reasoning":
        print("Reasoning:", " ".join(part.text for part in item.summary))
print("Answer:", response.output_text)
```

```typescript TypeScript theme={null}
import OpenAI from 'openai';

const client = new OpenAI({
  apiKey: process.env.GLOO_API_KEY,
  baseURL: 'https://platform.ai.gloo.com/ai/v2/guarded',
});

const response = await client.responses.create({
  model: 'gloo-anthropic-claude-sonnet-5.5',
  reasoning: { effort: 'medium', summary: 'auto' },
  input: 'Summarize the book of Ruth in two sentences.',
});

for (const item of response.output) {
  if (item.type === 'reasoning') {
    console.log('Reasoning:', item.summary.map((part) => part.text).join(' '));
  }
}
console.log('Answer:', response.output_text);
```

### Grounded Responses

`POST /ai/v1/grounded/responses`. Point the SDK at `https://platform.ai.gloo.com/ai/v1/grounded` and send the grounding parameters as extra fields.

```bash cURL theme={null}
curl -X POST 'https://platform.ai.gloo.com/ai/v1/grounded/responses' \
  -H "Authorization: Bearer $GLOO_API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{
    "model": "gloo-anthropic-claude-sonnet-5.5",
    "reasoning": { "effort": "medium", "summary": "auto" },
    "input": "What resources do you have on family counseling?",
    "rag_publisher": "YourPublisherName",
    "sources_limit": 3
  }'
```

```python Python theme={null}
import os
from openai import OpenAI

client = OpenAI(
    api_key=os.environ["GLOO_API_KEY"],
    base_url="https://platform.ai.gloo.com/ai/v1/grounded",
)

response = client.responses.create(
    model="gloo-anthropic-claude-sonnet-5.5",
    reasoning={"effort": "medium", "summary": "auto"},
    input="What resources do you have on family counseling?",
    extra_body={"rag_publisher": "YourPublisherName", "sources_limit": 3},
)

for item in response.output:
    if item.type == "reasoning":
        print("Reasoning:", " ".join(part.text for part in item.summary))
print("Answer:", response.output_text)
```

```typescript TypeScript theme={null}
import OpenAI from 'openai';

const client = new OpenAI({
  apiKey: process.env.GLOO_API_KEY,
  baseURL: 'https://platform.ai.gloo.com/ai/v1/grounded',
});

const response = await client.responses.create({
  model: 'gloo-anthropic-claude-sonnet-5.5',
  reasoning: { effort: 'medium', summary: 'auto' },
  input: 'What resources do you have on family counseling?',
  // Grounding parameters are not in the SDK's types.
  rag_publisher: 'YourPublisherName',
  sources_limit: 3,
} as OpenAI.Responses.ResponseCreateParamsNonStreaming);

for (const item of response.output) {
  if (item.type === 'reasoning') {
    console.log('Reasoning:', item.summary.map((part) => part.text).join(' '));
  }
}
console.log('Answer:', response.output_text);
```

### Direct Responses

`POST /ai/v2/direct/responses`. A non-streamed response carries the summary for every model that returns one. A stream carries it only for OpenAI models served over OpenAI's Responses API, such as GPT-5.4.

```bash cURL theme={null}
curl -X POST 'https://platform.ai.gloo.com/ai/v2/direct/responses' \
  -H "Authorization: Bearer $GLOO_API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{
    "model": "gloo-anthropic-claude-sonnet-5.5",
    "reasoning": { "effort": "high", "summary": "auto" },
    "input": "Summarize the book of Ruth in two sentences."
  }'
```

```python Python theme={null}
import os
from openai import OpenAI

client = OpenAI(
    api_key=os.environ["GLOO_API_KEY"],
    base_url="https://platform.ai.gloo.com/ai/v2/direct",
)

response = client.responses.create(
    model="gloo-anthropic-claude-sonnet-5.5",
    reasoning={"effort": "high", "summary": "auto"},
    input="Summarize the book of Ruth in two sentences.",
)

for item in response.output:
    if item.type == "reasoning":
        print("Reasoning:", " ".join(part.text for part in item.summary))
print("Answer:", response.output_text)
```

```typescript TypeScript theme={null}
import OpenAI from 'openai';

const client = new OpenAI({
  apiKey: process.env.GLOO_API_KEY,
  baseURL: 'https://platform.ai.gloo.com/ai/v2/direct',
});

const response = await client.responses.create({
  model: 'gloo-anthropic-claude-sonnet-5.5',
  reasoning: { effort: 'high', summary: 'auto' },
  input: 'Summarize the book of Ruth in two sentences.',
});

for (const item of response.output) {
  if (item.type === 'reasoning') {
    console.log('Reasoning:', item.summary.map((part) => part.text).join(' '));
  }
}
console.log('Answer:', response.output_text);
```

Streamed, with an OpenAI model:

```bash cURL theme={null}
curl -N -X POST 'https://platform.ai.gloo.com/ai/v2/direct/responses' \
  -H "Authorization: Bearer $GLOO_API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{
    "model": "gloo-openai-gpt-5.4",
    "reasoning": { "effort": "high", "summary": "auto" },
    "stream": true,
    "input": "Summarize the book of Ruth in two sentences."
  }'
```

```python Python theme={null}
stream = client.responses.create(
    model="gloo-openai-gpt-5.4",
    reasoning={"effort": "high", "summary": "auto"},
    stream=True,
    input="Summarize the book of Ruth in two sentences.",
)

for event in stream:
    if event.type == "response.reasoning_summary_text.delta":
        print(event.delta, end="", flush=True)
    elif event.type == "response.output_text.delta":
        print(event.delta, end="", flush=True)
```

```typescript TypeScript theme={null}
const stream = await client.responses.create({
  model: 'gloo-openai-gpt-5.4',
  reasoning: { effort: 'high', summary: 'auto' },
  stream: true,
  input: 'Summarize the book of Ruth in two sentences.',
});

for await (const event of stream) {
  if (event.type === 'response.reasoning_summary_text.delta') {
    process.stdout.write(event.delta);
  } else if (event.type === 'response.output_text.delta') {
    process.stdout.write(event.delta);
  }
}
```

## How the endpoints differ

| | Completions | Grounded Completions | Direct Completions | Responses | Grounded Responses | Direct Responses |
| :- | :- | :- | :- | :- | :- | :- |
| Reasoning comes back when | An effort other than `none` is set | Same | Same | `reasoning.summary` is set | Same | Same |
| Streamed reasoning | No | No | Yes, in `delta.reasoning_content` | No | No | OpenAI models served over OpenAI's Responses API only |
| Answer moderated | Yes; reasoning is not | Yes; reasoning is not | No | Yes; reasoning summary is not | No | No |
| Reasoning items passed back in `input` | — | — | — | Removed; reported in `reasoning_carryover` | Same | Removed; reported as `input.reasoning=<n>` in `ignored_params` |

## By model family

| Family | Reasoning returned | Levels | `none` and `minimal` |
| :- | :- | :- | :- |
| **Claude 5**: Sonnet 5 and 5.5, Opus 5 and 5.5, Haiku 5.5, Fable 5 and 5.1 | Summary on non-streamed requests; also streamed on Direct Completions | `low` to `max` | These models can't stop thinking. `none` runs as `low` and returns no reasoning; if the request fails over to another provider, reasoning may still come back. `minimal` runs as `low` and returns the summary. |
| **Gemini**: 2.5 Flash, Flash-Lite and Pro; 3.x models | Thought summary on non-streamed requests; also streamed on Direct Completions | Per model, up to `high` | `none` turns thinking off where `can_disable` is true; other Gemini models keep thinking and return no summary. |
| **OpenAI reasoning models** (GPT-5 family and later) | Summary on non-streamed requests; also streamed on Direct Completions and Direct Responses | Per model, for example `none` to `xhigh` on GPT-5.4 | `none` turns reasoning off where the model lists it. |
| **Claude Opus 4.5 to 4.8, Sonnet 4.6** | None | `effort_levels` is empty | These models support extended thinking, but Gloo does not turn it on for them: the effort is not sent. |
| **Open-weight reasoning models**: gpt-oss, DeepSeek, GLM, Qwen, Kimi, MiniMax, MiMo | Raw reasoning text | Per model. Many have only an on/off switch (`["none"]`) or always reason (`[]`) | `none` turns reasoning off only where `effort_levels` lists it. |
| **Gemma** | Not guaranteed (`returns_summary: false`) | `effort_levels` is empty | The model reasons with no control; an effort is not sent. |
| **Other models** | None | `reasoning` is `null` | The effort is not sent. |

Check the live [model catalog](/api-guides/supported-models) for current model IDs and each model's `reasoning` object.

## Reasoning is not moderated

On the guarded endpoints ([Completions](/api-guides/completions-v2), [Grounded Completions](/api-guides/grounded-completions) and [Responses](/api-guides/responses)), output moderation checks the answer, not the reasoning. When moderation replaces an answer, the reasoning from the original answer is still returned.

> [!WARNING]
>
> If you show reasoning to your end users and rely on Gloo's output moderation, check `reasoning_content` (or the Responses `reasoning` item) yourself first, or don't show it.

## Thinking uses your output limit

Thinking tokens count toward `max_tokens` (`max_output_tokens` on Responses) and are billed as output tokens, whether or not any reasoning comes back.

For Claude 5 models and Gemini 2.5 Flash and Flash-Lite, Gloo sends your limit to the provider as you set it. A high effort can use up a small limit before the answer starts, and the response then ends with `finish_reason: "length"` and little or no answer text. Leave room for the thinking as well as the answer, or lower the effort. See [Reasoning models and the output limit](/api-guides/provider-failover#reasoning-models-and-the-output-limit).

## When a provider fails mid-reasoning

For the Claude models that always think, if the provider fails after a [Direct Completions](/api-guides/direct-completions#claude-models-that-always-think) stream has sent reasoning but no answer text, Gloo can send the request to another provider instead of ending the stream with an error. The new provider's reasoning then arrives in the same stream, starting from the beginning. No chunk marks the switch. If you show reasoning as it arrives, be ready for it to start over, or show only the answer in `delta.content`. Once answer text has been sent, the stream is not switched this way.

## Reasoning across turns

Reasoning items never include `encrypted_content`, and `include: ["reasoning.encrypted_content"]` returns none. Reasoning items you send back in `input` are not used as reasoning state: any encrypted reasoning in them is removed before a model is called, and the request still succeeds.

The removal is reported:

* **Responses and Grounded Responses** add a `reasoning_carryover` field, for example `{"received": 2, "carried": 0, "dropped": [{"id": "rs_1", "reason": "not_gloo_state"}], "not_sealed": null}`. On a stream, the counts are in the `X-Gloo-Reasoning-Carryover` header and the final field is in `response.completed`.
* **Direct Responses** reports it as `input.reasoning=<n>` in `ignored_params`.

Other items tied to removed reasoning, such as a hosted tool call from the same turn, can be removed with it (`paired_removed` in `reasoning_carryover`, `input.reasoning_paired=<n>` in `ignored_params`). Send the full conversation in `input` each turn; the model reasons afresh.

## `supports_reasoning` and `reasoning_level`

On [`GET /platform/v2/models`](/api-reference/get-models/v2), `supports_reasoning` is `true` exactly when `reasoning` is not `null`. It does not promise that reasoning text comes back; `reasoning.returns_summary` says that. `reasoning_level` is an overall quality rating from 0 to 5, not a measure of reasoning: a model that does not reason can score 4.

## Related Documentation

* [Supported Models](/api-guides/supported-models) — Model IDs and the `reasoning` object
* [Provider Failover](/api-guides/provider-failover) — What happens when a provider fails, including reasoning and the output limit
* [Endpoint Types](/api-guides/endpoint-types) — Which endpoints run guardrails and moderation


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.