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

# Tool calling.

> Tool calling works on all three protocols — Chat Completions, Responses and Messages — and Sideren carries your tools, the model's calls and your results exactly as sent. The loop is the same everywhere: define, receive a call, execute, return the result.

## Transparent by default

Sideren doesn't run tools and doesn't rewrite them. Every tool you define (any number,
any names and schemas, function and custom tools), your `tool_choice`,
`parallel_tool_calls` and `strict` settings, the model's tool calls and your tool results
are carried exactly as sent — on [Chat Completions](/api/chat-completions),
[Responses](/api/responses) and [Messages](/api/messages).

Tool calls the model emits are forwarded **as-is** and streamed immediately — including a
call to a tool name you didn't define, or arguments that don't match your schema. That is
the same behaviour you get from the model vendors' own APIs, and it is what agent
harnesses expect: they report the bad call back to the model and let it correct itself. A
call cut off by `max_tokens` keeps its `length` / `max_tokens` stop reason and is never
marked complete. Only models that declare `capabilities.tools` serve requests that carry
tools — a handful of small open-weight models don't. Check the
[catalog](/api/models-endpoint) before you build a tool loop on one model.

## 1 · Define tools

<CodeGroup>
  ```json Chat Completions theme={null}
  {
    "model": "@sdn/gpt-oss-120b",
    "messages": [{ "role": "user", "content": "Weather in Paris?" }],
    "tools": [{
      "type": "function",
      "function": {
        "name": "get_weather",
        "description": "Current weather for a city",
        "parameters": {
          "type": "object",
          "properties": { "city": { "type": "string" } },
          "required": ["city"]
        }
      }
    }]
  }
  ```

  ```json Messages theme={null}
  {
    "model": "@sdn/glm-5.3",
    "max_tokens": 1024,
    "messages": [{ "role": "user", "content": "Weather in Paris?" }],
    "tools": [{
      "name": "get_weather",
      "description": "Current weather for a city",
      "input_schema": {
        "type": "object",
        "properties": { "city": { "type": "string" } },
        "required": ["city"]
      }
    }]
  }
  ```
</CodeGroup>

## 2 · The model calls

When the model decides to use a tool, the response carries a call instead of (or alongside)
text:

```json title="Chat Completions — finish_reason: tool_calls" theme={null}
{
  "message": {
    "role": "assistant",
    "tool_calls": [{
      "id": "call_abc123",
      "type": "function",
      "function": { "name": "get_weather", "arguments": "{\"city\": \"Paris\"}" }
    }]
  },
  "finish_reason": "tool_calls"
}
```

```json title="Messages — stop_reason: tool_use" theme={null}
{
  "content": [{
    "type": "tool_use",
    "id": "toolu_abc123",
    "name": "get_weather",
    "input": { "city": "Paris" }
  }],
  "stop_reason": "tool_use"
}
```

Parse the arguments, validate them against your schema, run the tool, and send the result
back. Models may emit **several calls in one turn** (parallel tool use); execute them all
and return one result per call id.

## 3 · Return results

<CodeGroup>
  ```json Chat Completions theme={null}
  {
    "role": "tool",
    "tool_call_id": "call_abc123",
    "content": "{\"temp_c\": 18, \"sky\": \"clear\"}"
  }
  ```

  ```json Messages theme={null}
  {
    "role": "user",
    "content": [{
      "type": "tool_result",
      "tool_use_id": "toolu_abc123",
      "content": "{\"temp_c\": 18, \"sky\": \"clear\"}"
    }]
  }
  ```
</CodeGroup>

Append the result to the conversation and call the endpoint again — the model continues
with the tool output in context. Repeat until it answers in text.

## Steering with tool\_choice

* `auto` (default) — the model decides whether to call.
* `required` / `{ "type": "any" }` — must call some tool (Chat Completions / Messages
  respectively).
* Named — force one specific tool:
  `{ "type": "function", "function": { "name": "get_weather" } }` or
  `{ "type": "tool", "name": "get_weather" }`.
* `none` — text only, tools stay visible but uncallable.

A forced or `strict` request only goes to a placement that actually enforces it. If none
can, you get a `422` before anything is sent to a model rather than a silently weaker
request.

<Note>
  Tool calls stream too: argument deltas arrive incrementally on both dialects
  ([Streaming](/guides/streaming)). For extracting structured data without any real tool,
  prefer [Structured output](/guides/structured-output).
</Note>


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