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

# Tool calling in relay mode

> Let a model call your tools on Chat Completions, the Responses API and Anthropic Messages, with full request and response examples for each surface.

The gateway supports **tool (function) calling** on Chat Completions, the
Responses API, and Messages. Declare your tools in the request; if the model
decides to use one, the gateway streams the tool call back to you.

## Relay mode

The gateway runs tools in **relay mode** — it never executes them. It declares
your tool definitions to the model, returns the call the model wants to make, and
stops. **You** run the tool and send the result back on the next turn. A typical
loop:

1. Send a request with `tools` (and optionally `tool_choice`).
2. The model responds with one or more tool calls and a tool-call finish reason
   instead of final text.
3. Run each tool yourself and append the result to the conversation.
4. Send the updated conversation back; the model continues (more tool calls, or a
   final text answer).

Because the gateway speaks each provider's native wire format, the official SDKs'
tool-calling helpers work unchanged — point them at the gateway base URL and key.

## Chat Completions

**Request** — `tools[]` are function definitions; `tool_choice` is
`auto` (default), `none`, `required`, or `{ "type": "function", "function": { "name": "..." } }`.

```bash theme={null}
curl https://api.impossibl.com/v1/chat/completions \
  -H "Authorization: Bearer imp-rt-..." \
  -H 'content-type: application/json' \
  -d '{
    "model": "openai/gpt-4o-mini",
    "messages": [{"role":"user","content":"What is the weather in Paris?"}],
    "tools": [{
      "type": "function",
      "function": {
        "name": "get_weather",
        "description": "Get the current weather for a city",
        "parameters": {
          "type": "object",
          "properties": { "city": { "type": "string" } },
          "required": ["city"]
        }
      }
    }]
  }'
```

**Response** — the assistant message carries `tool_calls` and `finish_reason` is
`tool_calls`. Each call's `function.arguments` is a **JSON-encoded string**.

```json theme={null}
{
  "choices": [{
    "index": 0,
    "message": {
      "role": "assistant",
      "content": null,
      "tool_calls": [{
        "id": "call_abc",
        "type": "function",
        "function": { "name": "get_weather", "arguments": "{\"city\":\"Paris\"}" }
      }]
    },
    "finish_reason": "tool_calls"
  }]
}
```

**Returning the result** — append the assistant message and a `tool` message
whose `tool_call_id` matches, then send the conversation again:

```json theme={null}
{ "role": "tool", "tool_call_id": "call_abc", "content": "{\"tempC\":18}" }
```

**Streaming** — tool calls arrive as `delta.tool_calls[]` fragments. The first
fragment for a call carries `id`, `type`, and `function.name`; later fragments
stream `function.arguments` text. The `index` field correlates fragments of the
same call.

## Responses API

**Request** — Responses flattens the function fields onto each tool. `tool_choice`
is `auto` / `none` / `required` / `{ "type": "function", "name": "..." }`.

```bash theme={null}
curl https://api.impossibl.com/v1/responses \
  -H "Authorization: Bearer imp-rt-..." \
  -H 'content-type: application/json' \
  -d '{
    "model": "openai/gpt-4o-mini",
    "input": "What is the weather in Paris?",
    "tools": [{
      "type": "function",
      "name": "get_weather",
      "description": "Get the current weather for a city",
      "parameters": {
        "type": "object",
        "properties": { "city": { "type": "string" } },
        "required": ["city"]
      }
    }]
  }'
```

**Response** — the model emits a `function_call` output item with a `call_id` and
a JSON-string `arguments`:

```json theme={null}
{ "type": "function_call", "id": "fc_1", "call_id": "call_abc",
  "name": "get_weather", "arguments": "{\"city\":\"Paris\"}", "status": "completed" }
```

**Returning the result** — add a `function_call_output` input item referencing the
same `call_id`:

```json theme={null}
{ "type": "function_call_output", "call_id": "call_abc", "output": "{\"tempC\":18}" }
```

**Streaming** — a `response.output_item.added` event opens the `function_call`
item, `response.function_call_arguments.delta` events stream the argument text,
and `response.function_call_arguments.done` closes it.

## Messages (Anthropic)

**Request** — `tools[]` use `input_schema`; `tool_choice` is `{ "type": "auto" }`,
`{ "type": "any" }`, `{ "type": "tool", "name": "..." }`, or `{ "type": "none" }`.
(A bare `claude-...` model id routes to Anthropic; any `provider/model` id also
works here — see [SDKs & integrations](/docs/integrations#anthropic-sdk).)

```bash theme={null}
curl https://api.impossibl.com/v1/messages \
  -H "x-api-key: imp-rt-..." \
  -H 'content-type: application/json' \
  -d '{
    "model": "claude-haiku-4-5",
    "max_tokens": 256,
    "messages": [{"role":"user","content":"What is the weather in Paris?"}],
    "tools": [{
      "name": "get_weather",
      "description": "Get the current weather for a city",
      "input_schema": {
        "type": "object",
        "properties": { "city": { "type": "string" } },
        "required": ["city"]
      }
    }]
  }'
```

**Response** — a `tool_use` content block (with a parsed `input` object) and
`stop_reason: "tool_use"`:

```json theme={null}
{ "type": "tool_use", "id": "toolu_1", "name": "get_weather",
  "input": { "city": "Paris" } }
```

**Returning the result** — send a `user` turn containing a `tool_result` block
referencing the `tool_use_id`:

```json theme={null}
{ "role": "user", "content": [
  { "type": "tool_result", "tool_use_id": "toolu_1", "content": "{\"tempC\":18}" }
]}
```

**Streaming** — the `tool_use` block opens with a `content_block_start`, its input
streams as `content_block_delta` events of type `input_json_delta`
(`partial_json`), and closes with `content_block_stop`.

<Note>
  Across all three surfaces, **arguments arrive as JSON text** (a string for
  OpenAI-style calls, streamed `partial_json` for Anthropic). Parse them yourself
  before running the tool, and tolerate empty/partial fragments while streaming.
</Note>

## Gemini thought signatures

Gemini 3 models attach an opaque signature to the first function call of each
step and **reject the tool-result turn unless it comes back verbatim**. The
gateway round-trips it for you: on Chat Completions the tool call carries
`extra_content.google.thought_signature` (Google's OpenAI-compat mapping — in
streaming it rides a `tool_calls` fragment), and on the Responses API the
`function_call` item carries the same `extra_content` field. **Send the tool
call back exactly as you received it** — clients that echo the assistant
message unchanged (the OpenAI SDK and Vercel AI SDK loops already do) need no
extra code. The Gemini-native endpoint uses Google's own `Part.thoughtSignature`
unchanged.
