## Overview

Tool (function) calling lets a model decide when to invoke an external function—a weather API, a database query, a calculator—and emit a structured request for it. Your application runs the function and feeds the result back to the model.

Parasail exposes tool calling through two OpenAI-compatible surfaces:

- **Chat Completions API** (`/v1/chat/completions`)—the classic single-call interface. You pass `tools`, inspect `message.tool_calls`, run the tool, and append a `tool` message for the next call.

- **Responses API** (`/v1/responses`)—the newer agentic interface built for multi-step loops. You pass `tools`, inspect `response.output` for `function_call` items, and append `function_call_output` items.

Both use the same base URL and API key:

```
https://api.parasail.io/v1
```

The **tool schema** (name, description, JSON Schema parameters) is the same in both APIs—only the wrapper shape and the response handling differ. Pick Chat Completions for simple one-shot tool calls, and the Responses API for multi-turn agentic workflows.

## Supported models

The following models support tool calling and `tool_choice` as of June 2026. Verify current availability via the models endpoint.

Treat this table as a starting point for validation. Test your actual tool schema and prompt before depending on tool calls in production.

| Model                              | Tools | Tool Choice |
|------------------------------------|-------|-------------|
| parasail-llama-33-70b-fp8         | ✅    | ✅          |
| parasail-llama-4-scout-instruct   | ✅    | ✅          |
| parasail-llama-4-maverick-instruct-fp8 | ✅ | ✅          |
| parasail-qwen3-30b-a3b            | ✅    | ✅          |
| parasail-qwen3-235b-a22b          | ✅    | ✅          |
| parasail-qwen3-32b                | ✅    | ✅          |
| parasail-mistral-devstral-small    | ✅    | ✅          |

In the Chat Completions API, each tool must be wrapped as `{"type": "function", "function": {...}}`. The `function` object holds the `name`, `description`, and a JSON Schema `parameters`.

```
import os
import json
from openai import OpenAI

client = OpenAI(
    base_url="https://api.parasail.io/v1",
    api_key="<PARASAIL_API_KEY>",
)

tools = [
    {
        "type": "function",
        "function": {
            "name": "get_weather",
            "description": "Retrieve weather information for a given location and date.",
            "parameters": {
                "type": "object",
                "properties": {
                    "location": {"type": "string"},
                    "date": {"type": "string", "pattern": "^\\d{4}-\\d{2}-\\d{2}$"},
                },
                "required": ["location", "date"],
            },
        },
    }
]

messages = [
    {"role": "user", "content": "What's the weather like in Manhattan Beach on 2025-06-03?"}
]

response = client.chat.completions.create(
    model="parasail-llama-4-scout-instruct",
    messages=messages,
    tools=tools,
    tool_choice="auto",
)

tool_call = response.choices[0].message.tool_calls[0]
args = json.loads(tool_call.function.arguments)
print(json.dumps(args, indent=2))
```

Expected arguments:

```
{
  "location": "Manhattan Beach",
  "date": "2025-06-03"
}
```

### Returning the tool result

Run your function, then append the assistant's tool call and a `tool` message with the result before calling the model again:

```
def get_weather(location, date):
    # Replace with a real API call
    return {"location": location, "date": date, "weather": "Sunny", "temperature": "75F"}

result = get_weather(**args)

messages.append(response.choices[0].message)  # the assistant's tool call
messages.append(
    {
        "role": "tool",
        "tool_call_id": tool_call.id,
        "content": json.dumps(result),
    }
)

final = client.chat.completions.create(
    model="parasail-llama-4-scout-instruct",
    messages=messages,
    tools=tools,
)
print(final.choices[0].message.content)
```

In the Responses API, tools are defined with a flat shape—`type`, `name`, `description`, and `parameters` at the top level (no nested `function` object). Tool calls come back as `function_call` items in `response.output`, and you return results as `function_call_output` items.

```
import json
from openai import OpenAI

client = OpenAI(
    base_url="https://api.parasail.io/v1",
    api_key="<PARASAIL_API_KEY>",
)

tools = [
    {
        "type": "function",
        "name": "get_weather",
        "description": "Get the current weather for a city.",
        "parameters": {
            "type": "object",
            "properties": {
                "city": {"type": "string", "description": "City name"},
                "units": {
                    "type": "string",
                    "enum": ["celsius", "fahrenheit"],
                    "default": "celsius",
                },
            },
            "required": ["city"],
        },
    }
]

def handle_tool_call(name, arguments):
    args = json.loads(arguments)
    if name == "get_weather":
        return json.dumps({"city": args["city"], "temperature": 22, "condition": "sunny"})
    return json.dumps({"error": "unknown function"})

# Initial request (store must be false on the Parasail gateway)
response = client.responses.create(
    model="parasail-kimi-k25-elicit",
    store=False,
    tools=tools,
    input=[{"role": "user", "content": "What's the weather in Tokyo?"}],
)

# Agentic loop—continue until the model stops calling tools
while response.output:
    tool_calls = [item for item in response.output if item.type == "function_call"]
    if not tool_calls:
        break

next_input = list(response.output)
    for tool_call in tool_calls:
        result = handle_tool_call(tool_call.name, tool_call.arguments)
        next_input.append(
            {
                "type": "function_call_output",
                "call_id": tool_call.call_id,
                "output": result,
            }
        )

response = client.responses.create(
        model="parasail-kimi-k25-elicit",
        store=False,
        tools=tools,
        input=next_input,
    )

print(response.output_text)
```

The Responses API requires `store=False` on every request.

## Chat Completions tools vs. Responses tools

| Features                       | Chat Completions                        | Responses API                               |
|--------------------------------|-----------------------------------------|---------------------------------------------|
| Tool definition                | `{"type": "function", "function": {name, description, parameters}}` | `{"type": "function", name, description, parameters}` (flat) |
| Where calls appear             | `message.tool_calls[]`                 | `response.output[]` items with `type == "function_call"` |
| Returning results              | `{"role": "tool", "tool_call_id": ..., "content": ...}` | `{"type": "function_call_output", "call_id": ..., "output": ...}` |
| Best for                       | One-shot tool calls                    | Multi-step agentic loops                    |

The underlying schema—the function `name`, `description`, and JSON Schema `parameters`—is identical between the two; only the wrapper and the result-handling differ.

## Next steps

- Structured output guide
- Chat Completions API reference
- Responses API reference
- Models endpoint
