# Tools

One tool loop that works on every provider. Call ids and result pairing differ underneath — Anthropic refuses punctuation Gemini puts in an id — and that is handled, so changing the model does not change your code.

## Declaring a tool

`parameters` is ordinary JSON Schema. Check the catalog first: sending `tools` to a model whose
`capabilities.toolUse` is `false` is refused with `422` before any provider is called.

```json
"tools": [
  {
    "name": "getWeather",
    "description": "Current conditions for a city.",
    "parameters": {
      "type": "object",
      "properties": { "city": { "type": "string", "description": "City name" } },
      "required": ["city"]
    }
  }
]
```

## The full loop

Four steps. The turn you get back is appended to `messages` verbatim, the tool result goes after it paired on the
call's `id`, and you send the whole thing again. Nothing is rewritten by hand.

### 1. Ask

```json
{
  "model": "claude-sonnet-5",
  "systemPrompt": "Use tools when they help.",
  "messages": [{ "type": "user", "value": "What is the weather in Lagos?" }],
  "tools": [ … ],
  "parameters": { "maxTokens": 1024 }
}
```

### 2. The model calls

```json
{
  "type": "monolith",
  "model": { "name": "claude-sonnet-5", "tier": "high", "publisher": "Anthropic", "provider": "Anthropic" },
  "messages": [
    { "type": "content", "value": "Let me check.", "data": {} },
    { "type": "toolCall", "call": { "id": "toolu_01A", "name": "getWeather", "arguments": "{\"city\":\"Lagos\"}" } }
  ],
  "usage": { "finishReason": "tool_use" }
}
```

### 3. Run it and answer

```json
{
  "model": "claude-sonnet-5",
  "systemPrompt": "Use tools when they help.",
  "messages": [
    { "type": "user", "value": "What is the weather in Lagos?" },
    { "type": "content", "value": "Let me check." },
    { "type": "toolCall", "call": { "id": "toolu_01A", "name": "getWeather", "arguments": "{\"city\":\"Lagos\"}" } },
    { "type": "toolResult", "result": { "id": "toolu_01A", "name": "getWeather", "content": "31C, humid, scattered thunderstorms" } }
  ],
  "tools": [ … ]
}
```

### 4. The answer

```json
{
  "type": "monolith",
  "messages": [
    { "type": "content", "value": "It is 31C and humid in Lagos, with scattered thunderstorms.", "data": {} }
  ],
  "usage": { "finishReason": "end_turn" }
}
```

> **`arguments` is a string**
> Not an object. That is what every provider sends and what they expect back. `name` travels beside `id` because
> some providers pair a result by name while others pair by id.

## When a tool fails

Report it as a result rather than inventing prose. The pairing is unchanged; `failure` is what tells the model the
call did not succeed, and `content` stays whatever the tool produced.

```json
{
  "type": "toolResult",
  "result": {
    "id": "toolu_01A",
    "name": "getWeather",
    "content": "upstream timed out",
    "failure": { "success": false, "code": 504, "message": "The weather service did not answer." }
  }
}
```

## Forcing or forbidding a call

`parameters.toolUse` decides whether the model may call, must call, or must not.

| Value | Meaning |
|---|---|
| `{ "type": "auto" }` | The model decides. The default. |
| `{ "type": "none" }` | The model may not call a tool, even though tools are declared. |
| `{ "type": "any" }` | The model must call one of the declared tools. |
| `{ "type": "use", "toolCall": { … } }` | The model must call the named tool and no other. `toolCall` is a full tool declaration, not just a name. |

## Structured output

To hold the answer to a JSON Schema instead, send `responseSchema`. See
[structured output](/docs/gateway/structured-output/).

## Files returned by tools

A tool result can carry files in `result.documents`; the same file-source and processing rules apply as to files on
a user message. See [files and file processing](/docs/gateway/files/) for the public source shape, native model
capabilities, `none`, `auto`, `directed`, and the named processor catalog.
