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

# Tool Calling

> Enable your AI to call functions and take actions in the world. Tool calling lets models interact with external APIs, databases, and services.

Tool calling (also called function calling) allows models to request the execution of specific functions you define. The model decides when to call a tool and with what arguments — your application executes the tool and returns the result.

ARouter supports tool calling for all major providers. The interface follows the OpenAI tool calling standard.

## How It Works

Tool calling follows a 3-step cycle:

1. **Inference with tools** — You send a request with tool definitions. The model decides to call a tool and returns a `tool_calls` response.
2. **Tool execution (client-side)** — Your application runs the requested function and collects the result.
3. **Inference with tool results** — You send the tool result back to the model, which generates a final response.

### Step 1: Inference with Tools

```json theme={null}
{
  "model": "openai/gpt-5.4",
  "messages": [
    { "role": "user", "content": "What is the weather in San Francisco?" }
  ],
  "tools": [
    {
      "type": "function",
      "function": {
        "name": "get_weather",
        "description": "Get the current weather for a location",
        "parameters": {
          "type": "object",
          "properties": {
            "location": {
              "type": "string",
              "description": "City name, e.g. 'San Francisco'"
            },
            "unit": {
              "type": "string",
              "enum": ["celsius", "fahrenheit"]
            }
          },
          "required": ["location"]
        }
      }
    }
  ],
  "tool_choice": "auto"
}
```

The model responds with a `tool_calls` array:

```json theme={null}
{
  "id": "chatcmpl-xxx",
  "choices": [
    {
      "message": {
        "role": "assistant",
        "content": null,
        "tool_calls": [
          {
            "id": "call_abc123",
            "type": "function",
            "function": {
              "name": "get_weather",
              "arguments": "{\"location\": \"San Francisco\", \"unit\": \"fahrenheit\"}"
            }
          }
        ]
      },
      "finish_reason": "tool_calls"
    }
  ]
}
```

### Step 2: Tool Execution (Client-Side)

Your application executes the function with the model's arguments:

```python theme={null}
import json

tool_call = response.choices[0].message.tool_calls[0]
args = json.loads(tool_call.function.arguments)

# Execute your function
result = get_weather(
    location=args["location"],
    unit=args.get("unit", "fahrenheit")
)
# result = {"temperature": 72, "condition": "sunny", "unit": "fahrenheit"}
```

### Step 3: Inference with Tool Results

Send the tool result back as a `tool` role message:

```json theme={null}
{
  "model": "openai/gpt-5.4",
  "messages": [
    { "role": "user", "content": "What is the weather in San Francisco?" },
    {
      "role": "assistant",
      "content": null,
      "tool_calls": [
        {
          "id": "call_abc123",
          "type": "function",
          "function": {
            "name": "get_weather",
            "arguments": "{\"location\": \"San Francisco\", \"unit\": \"fahrenheit\"}"
          }
        }
      ]
    },
    {
      "role": "tool",
      "tool_call_id": "call_abc123",
      "content": "{\"temperature\": 72, \"condition\": \"sunny\", \"unit\": \"fahrenheit\"}"
    }
  ],
  "tools": [...]
}
```

## Full Example

<Tabs>
  <Tab title="Python (OpenAI)">
    ```python theme={null}
    import json
    from openai import OpenAI

    client = OpenAI(
        base_url="https://api.arouter.ai/v1",
        api_key="lr_live_xxxx",
    )

    # Define the tool
    tools = [
        {
            "type": "function",
            "function": {
                "name": "get_weather",
                "description": "Get the current weather for a location",
                "parameters": {
                    "type": "object",
                    "properties": {
                        "location": {
                            "type": "string",
                            "description": "City name, e.g. 'San Francisco'",
                        },
                        "unit": {"type": "string", "enum": ["celsius", "fahrenheit"]},
                    },
                    "required": ["location"],
                },
            },
        }
    ]

    messages = [{"role": "user", "content": "What is the weather in San Francisco?"}]

    # Step 1: First inference
    response = client.chat.completions.create(
        model="openai/gpt-5.4",
        messages=messages,
        tools=tools,
        tool_choice="auto",
    )

    assistant_message = response.choices[0].message
    messages.append(assistant_message)

    # Step 2: Execute tools
    if assistant_message.tool_calls:
        for tool_call in assistant_message.tool_calls:
            if tool_call.function.name == "get_weather":
                args = json.loads(tool_call.function.arguments)
                # Simulate weather API
                result = {"temperature": 72, "condition": "sunny", "unit": args.get("unit", "fahrenheit")}

                messages.append({
                    "role": "tool",
                    "tool_call_id": tool_call.id,
                    "content": json.dumps(result),
                })

    # Step 3: Final inference
    final_response = client.chat.completions.create(
        model="openai/gpt-5.4",
        messages=messages,
        tools=tools,
    )

    print(final_response.choices[0].message.content)
    # "The current weather in San Francisco is 72°F and sunny."
    ```
  </Tab>

  <Tab title="Node.js (OpenAI)">
    ```typescript theme={null}
    import OpenAI from "openai";

    const client = new OpenAI({
      baseURL: "https://api.arouter.ai/v1",
      apiKey: "lr_live_xxxx",
    });

    // Define the tool
    const tools: OpenAI.Chat.ChatCompletionTool[] = [
      {
        type: "function",
        function: {
          name: "get_weather",
          description: "Get the current weather for a location",
          parameters: {
            type: "object",
            properties: {
              location: {
                type: "string",
                description: "City name, e.g. 'San Francisco'",
              },
              unit: { type: "string", enum: ["celsius", "fahrenheit"] },
            },
            required: ["location"],
          },
        },
      },
    ];

    const messages: OpenAI.Chat.ChatCompletionMessageParam[] = [
      { role: "user", content: "What is the weather in San Francisco?" },
    ];

    // Step 1: First inference
    const response = await client.chat.completions.create({
      model: "openai/gpt-5.4",
      messages,
      tools,
      tool_choice: "auto",
    });

    const assistantMessage = response.choices[0].message;
    messages.push(assistantMessage);

    // Step 2: Execute tools
    if (assistantMessage.tool_calls) {
      for (const toolCall of assistantMessage.tool_calls) {
        if (toolCall.function.name === "get_weather") {
          const args = JSON.parse(toolCall.function.arguments);
          const result = {
            temperature: 72,
            condition: "sunny",
            unit: args.unit ?? "fahrenheit",
          };

          messages.push({
            role: "tool",
            tool_call_id: toolCall.id,
            content: JSON.stringify(result),
          });
        }
      }
    }

    // Step 3: Final inference
    const finalResponse = await client.chat.completions.create({
      model: "openai/gpt-5.4",
      messages,
      tools,
    });

    console.log(finalResponse.choices[0].message.content);
    ```
  </Tab>

  <Tab title="Go">
    ```go theme={null}
    package main

    import (
        "context"
        "encoding/json"
        "fmt"
        "log"

        "github.com/arouter-ai/arouter-go"
    )

    func main() {
        client := arouter.NewClient("lr_live_xxxx",
            arouter.WithBaseURL("https://api.arouter.ai/v1"),
        )

        tools := []arouter.Tool{
            {
                Type: "function",
                Function: &arouter.FunctionDefinition{
                    Name:        "get_weather",
                    Description: "Get the current weather for a location",
                    Parameters: map[string]any{
                        "type": "object",
                        "properties": map[string]any{
                            "location": map[string]any{
                                "type":        "string",
                                "description": "City name",
                            },
                            "unit": map[string]any{
                                "type": "string",
                                "enum": []string{"celsius", "fahrenheit"},
                            },
                        },
                        "required": []string{"location"},
                    },
                },
            },
        }

        messages := []arouter.Message{
            {Role: "user", Content: "What is the weather in San Francisco?"},
        }

        // Step 1
        resp, err := client.CreateChatCompletion(context.Background(), arouter.ChatCompletionRequest{
            Model:    "openai/gpt-5.4",
            Messages: messages,
            Tools:    tools,
        })
        if err != nil {
            log.Fatal(err)
        }

        assistantMsg := resp.Choices[0].Message
        messages = append(messages, assistantMsg)

        // Step 2 & 3
        for _, tc := range assistantMsg.ToolCalls {
            var args map[string]string
            json.Unmarshal([]byte(tc.Function.Arguments), &args)
            result := fmt.Sprintf(`{"temperature":72,"condition":"sunny","unit":"%s"}`, args["unit"])
            messages = append(messages, arouter.Message{
                Role:       "tool",
                ToolCallID: tc.ID,
                Content:    result,
            })
        }

        finalResp, err := client.CreateChatCompletion(context.Background(), arouter.ChatCompletionRequest{
            Model:    "openai/gpt-5.4",
            Messages: messages,
            Tools:    tools,
        })
        if err != nil {
            log.Fatal(err)
        }

        fmt.Println(finalResp.Choices[0].Message.Content)
    }
    ```
  </Tab>

  <Tab title="cURL">
    ```bash theme={null}
    # Step 1: Inference with tools
    curl https://api.arouter.ai/v1/chat/completions \
      -H "Authorization: Bearer lr_live_xxxx" \
      -H "Content-Type: application/json" \
      -d '{
        "model": "openai/gpt-5.4",
        "messages": [
          {"role": "user", "content": "What is the weather in San Francisco?"}
        ],
        "tools": [
          {
            "type": "function",
            "function": {
              "name": "get_weather",
              "description": "Get the current weather for a location",
              "parameters": {
                "type": "object",
                "properties": {
                  "location": {"type": "string"},
                  "unit": {"type": "string", "enum": ["celsius", "fahrenheit"]}
                },
                "required": ["location"]
              }
            }
          }
        ],
        "tool_choice": "auto"
      }'

    # Step 3: Send tool result
    curl https://api.arouter.ai/v1/chat/completions \
      -H "Authorization: Bearer lr_live_xxxx" \
      -H "Content-Type: application/json" \
      -d '{
        "model": "openai/gpt-5.4",
        "messages": [
          {"role": "user", "content": "What is the weather in San Francisco?"},
          {
            "role": "assistant",
            "content": null,
            "tool_calls": [{"id": "call_abc123", "type": "function", "function": {"name": "get_weather", "arguments": "{\"location\": \"San Francisco\"}"}}]
          },
          {
            "role": "tool",
            "tool_call_id": "call_abc123",
            "content": "{\"temperature\": 72, \"condition\": \"sunny\"}"
          }
        ]
      }'
    ```
  </Tab>
</Tabs>

## Streaming Tool Calls

When streaming is enabled, tool call arguments are delivered incrementally via `delta.tool_calls`:

```typescript theme={null}
const stream = await client.chat.completions.create({
  model: "openai/gpt-5.4",
  messages: [{ role: "user", content: "What's the weather in NYC?" }],
  tools,
  stream: true,
});

let toolCallArgs = "";
let toolCallId = "";
let toolCallName = "";

for await (const chunk of stream) {
  const delta = chunk.choices[0]?.delta;

  if (delta?.tool_calls) {
    const tc = delta.tool_calls[0];
    if (tc.id) toolCallId = tc.id;
    if (tc.function?.name) toolCallName = tc.function.name;
    if (tc.function?.arguments) toolCallArgs += tc.function.arguments;
  }

  if (chunk.choices[0]?.finish_reason === "tool_calls") {
    // All arguments have been received
    const args = JSON.parse(toolCallArgs);
    console.log(`Calling ${toolCallName} with:`, args);
  }
}
```

## Supported Models

Use `GET /v1/models` to find models that support tool calling. Models with `tools` in their capabilities list support this feature.

```bash theme={null}
curl https://api.arouter.ai/v1/models \
  -H "Authorization: Bearer lr_live_xxxx"
```

Tool calling is supported by most frontier models, including:

* `openai/gpt-5.4`, `openai/gpt-5.4-pro`
* `anthropic/claude-sonnet-4.6`, `anthropic/claude-opus-4.5`
* `google/gemini-2.5-flash`, `google/gemini-2.5-pro`
* `deepseek/deepseek-v3.2`
