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

# Tool Calling for LLM

> Define reusable tools, attach them to any PAL, and deliver tool calls via app message or API call.

**LLM tool calling** lets the PAL trigger functions based on what the user says during a conversation. Tools are reusable objects: create them once, and attach them to any number of PALs. They dispatch via the channel you pick on the `delivery` field - see [Tool Delivery](/sections/conversational-video-interface/pal/llm-tool-delivery) and [Tool Authentication](/sections/conversational-video-interface/pal/llm-tool-auth).

<Note>
  This page documents the **tools registry** (`/v2/tools`). If your PAL still defines tools inline under `layers.llm.tools`, see [Legacy inline tool calling](/sections/troubleshooting#legacy-inline-tool-calling).
</Note>

## Tool Object

### Top-Level Fields

| Field           | Type   | Required | Description                                                                                                                                                                                         |
| --------------- | ------ | -------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `name`          | string | ✅        | A unique identifier for the tool, scoped to your account. Must match OpenAI function naming rules (`^[a-zA-Z_][a-zA-Z0-9_]{0,63}$`).                                                                |
| `description`   | string | ✅        | Natural language explanation of what the tool does. Used by the model to decide when to call it.                                                                                                    |
| `parameters`    | object | ❌        | JSON Schema object describing the tool's input arguments. Defaults to `{}` (no arguments).                                                                                                          |
| `origin`        | string | ❌        | One of `llm`, `vision`, `audio`. Defaults to `llm`. This page covers `llm`; see [Tool Calling for Perception](/sections/conversational-video-interface/pal/perception-tool) for `vision` / `audio`. |
| `on_call`       | string | ❌        | what the PAL does **while** the tool is running. See [`on_call` reference](#on-call-reference). Defaults to `generate_filler` for `llm` tools; must be omitted for `vision` / `audio` tools.        |
| `on_resolve`    | string | ❌        | what the PAL does **after** the tool returns a result. See [`on_resolve` reference](#on-resolve-reference). Defaults to `fire_and_forget`.                                                          |
| `static_filler` | string | ❌        | The exact line the PAL speaks while the tool runs when `on_call` is `static_filler`. Required in that case.                                                                                         |
| `delivery`      | object | ❌        | How the tool call is delivered. See [Tool Delivery](/sections/conversational-video-interface/pal/llm-tool-delivery). Defaults to `{"app_message": true}`.                                           |

### `parameters`

Standard JSON Schema. Same shape as the OpenAI `function.parameters` object.

| Field        | Type             | Required | Description                                                                |
| ------------ | ---------------- | -------- | -------------------------------------------------------------------------- |
| `type`       | string           | ✅        | Always `"object"`.                                                         |
| `properties` | object           | ✅        | Map of parameter name to its schema (`type`, `description`, `enum`, etc.). |
| `required`   | array of strings | ❌        | Names of mandatory parameters.                                             |

#### Examples

<Tabs>
  <Tab title="No arguments">
    ```json parameters theme={null}
    {
      "type": "object",
      "properties": {}
    }
    ```
  </Tab>

  <Tab title="Single required argument">
    ```json parameters theme={null}
    {
      "type": "object",
      "properties": {
        "city": {
          "type": "string",
          "description": "The city to get the weather for, e.g. San Francisco"
        }
      },
      "required": ["city"]
    }
    ```
  </Tab>

  <Tab title="Enum + optional argument">
    ```json parameters theme={null}
    {
      "type": "object",
      "properties": {
        "city": {
          "type": "string",
          "description": "The city to get the weather for"
        },
        "unit": {
          "type": "string",
          "enum": ["celsius", "fahrenheit"],
          "description": "Temperature unit"
        }
      },
      "required": ["city"]
    }
    ```
  </Tab>
</Tabs>

### `on_call` reference

`on_call` controls what the PAL does **while a tool is dispatched but has not yet returned**. Defaults to `generate_filler` for `llm` tools; set it explicitly if you want a different behavior.

| Value             | Behavior                                                                                                                                                                                                    |
| ----------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `generate_filler` | The LLM produces a short filler line itself (a `response_to_user` argument is injected into the tool's schema). the PAL speaks it via TTS.                                                                  |
| `static_filler`   | The PAL speaks the configured `static_filler` string at dispatch time. The top-level `static_filler` field is required.                                                                                     |
| `silent`          | The face stays silent while the tool runs.                                                                                                                                                                  |
| `passthrough`     | The tool spec is untouched. You manage the prompt and the schema. Use this when the LLM is already configured to preamble (i.e. the model naturally speaks a short line on its own before invoking a tool). |

#### Examples

<Tabs>
  <Tab title="generate_filler">
    ```json theme={null}
    {
      "on_call": "generate_filler"
    }
    ```

    The LLM picks the filler line per-call (e.g. "Let me check that for you.").
  </Tab>

  <Tab title="static_filler">
    ```json theme={null}
    {
      "on_call": "static_filler",
      "static_filler": "One moment - checking the weather now."
    }
    ```

    The PAL speaks the exact `static_filler` string every time the tool fires.
  </Tab>

  <Tab title="silent">
    ```json theme={null}
    {
      "on_call": "silent"
    }
    ```

    The face says nothing while the tool runs.
  </Tab>

  <Tab title="passthrough">
    ```json theme={null}
    {
      "on_call": "passthrough"
    }
    ```

    The tool spec is untouched. Use when your LLM is already configured to preamble before tool calls.
  </Tab>
</Tabs>

### `on_resolve` reference

`on_resolve` controls what the PAL does **with the tool's result once it returns**.

| Value                | Behavior                                                                                                                                                                                                                                                                                                                                     |
| -------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `generate_response`  | The LLM regenerates a contextual reply using the tool's result. Most common choice; The PAL speaks a natural-language summary of the result.                                                                                                                                                                                                 |
| `response_in_result` | The tool's response body is spoken **verbatim** via TTS - return `Content-Type: text/plain` with a single natural-language string. Use when the tool already returns a fully-formed natural-language reply. On timeout, non-2xx, or transport error, the tool call falls back to `generate_response` so the PAL still acknowledges the user. |
| `add_to_context`     | The result lands silently in the conversation history as a system message. Nothing is spoken on the result-landing turn; the next user utterance's LLM call sees it.                                                                                                                                                                         |
| `fire_and_forget`    | The result is not awaited or processed. Used when the tool's side effect is what matters (e.g. logging a CRM event). The default when `on_resolve` is omitted.                                                                                                                                                                               |

#### Examples

<Tabs>
  <Tab title="generate_response">
    ```json theme={null}
    {
      "on_resolve": "generate_response"
    }
    ```

    The LLM regenerates a contextual reply using the tool's result. Most common choice.
  </Tab>

  <Tab title="response_in_result">
    ```json theme={null}
    {
      "on_resolve": "response_in_result"
    }
    ```

    The tool's response body is spoken verbatim via TTS. Return `Content-Type: text/plain` with a natural-language string.
  </Tab>

  <Tab title="add_to_context">
    ```json theme={null}
    {
      "on_resolve": "add_to_context"
    }
    ```

    The result lands silently in conversation history; the next user turn's LLM call sees it.
  </Tab>

  <Tab title="fire_and_forget">
    ```json theme={null}
    {
      "on_resolve": "fire_and_forget"
    }
    ```

    The result is not awaited or processed. Use for side-effect-only tools (e.g. logging a CRM event).
  </Tab>
</Tabs>

## Creating a Tool

```bash Create tool [expandable] theme={null}
curl --request POST \
  --url https://tavusapi.com/v2/tools \
  --header 'Content-Type: application/json' \
  --header 'x-api-key: <api-key>' \
  --data '{
    "name": "get_current_weather",
    "description": "Get the current weather for a city.",
    "parameters": {
      "type": "object",
      "properties": {
        "city": {
          "type": "string",
          "description": "The city to get the weather for, e.g. San Francisco"
        },
        "unit": {
          "type": "string",
          "enum": ["celsius", "fahrenheit"]
        }
      },
      "required": ["city"]
    },
    "origin": "llm",
    "on_call": "generate_filler",
    "on_resolve": "generate_response",
    "delivery": {
      "api": {
        "url": "https://api.example.com/tools/get_weather",
        "method": "POST",
        "auth": { "type": "hmac", "secret": "whsec_long_random_string" },
        "timeout": 20
      }
    }
  }'
```

A successful create returns the full tool object including its `tool_id`:

```json Response theme={null}
{
  "tool_id": "tabc123def456",
  "owner_id": 12345,
  "name": "get_current_weather",
  "description": "Get the current weather for a city.",
  "parameters": { "...": "..." },
  "delivery": { "api": { "...": "..." } },
  "is_system_tool": false,
  "origin": "llm",
  "on_call": "generate_filler",
  "on_resolve": "generate_response",
  "static_filler": null,
  "created_at": "2026-05-20 14:22:01.123456",
  "updated_at": "2026-05-20 14:22:01.123456"
}
```

<Note>
  The `tool_id` (prefix `t…`) is how you reference the tool when attaching it to a PAL or updating / deleting it.
</Note>

## Attaching Tools to a PAL

A PAL only sees a tool if it is attached. Attach one or more tools in a single call:

```bash Attach tools to PAL theme={null}
curl --request POST \
  --url https://tavusapi.com/v2/pals/{pal_id}/tools \
  --header 'Content-Type: application/json' \
  --header 'x-api-key: <api-key>' \
  --data '{
    "tool_ids": ["tabc123def456", "tdef456abc789"]
  }'
```

List the tools currently attached to a PAL:

```bash List PAL tools theme={null}
curl --request GET \
  --url https://tavusapi.com/v2/pals/{pal_id}/tools \
  --header 'x-api-key: <api-key>'
```

Detach a single tool from a PAL:

```bash Detach tool from PAL theme={null}
curl --request DELETE \
  --url https://tavusapi.com/v2/pals/{pal_id}/tools/{tool_id} \
  --header 'x-api-key: <api-key>'
```

<Note>
  Detaching removes the link between the PAL and the tool. The tool itself is untouched and still attached to any other PALs that use it.
</Note>

## End-to-End Example

1. **Create the tool** at `/v2/tools` (see above). Save the returned `tool_id`.
2. **Attach it to a PAL** at `/v2/pals/{pal_id}/tools`.
3. **Start a conversation** with that PAL. The tool is now available to the face.
4. **Handle the tool call** in your application:
   * If `delivery.app_message: true`, listen for [`conversation.tool_call`](/sections/event-schemas/conversation-toolcall) events in your frontend.
   * If `delivery.api` is set, your endpoint receives the call. See [Tool Delivery](/sections/conversational-video-interface/pal/llm-tool-delivery).
5. **Return a result** (only meaningful when `on_resolve` is not `fire_and_forget`):
   * App message delivery: send a `conversation.tool_result` event with the matching `tool_call_id`. See [Tool Delivery](/sections/conversational-video-interface/pal/llm-tool-delivery#app-message-delivery).
   * API delivery: return a `2xx` response with the result in the response body.

## Errors

| Status | When                                                                                                                                        |
| ------ | ------------------------------------------------------------------------------------------------------------------------------------------- |
| `400`  | Validation failure (bad `name`, missing `on_call` on an `llm` tool, both delivery channels set, invalid API URL, unknown enum value, etc.). |
| `400`  | Attempted to attach a non-existent `tool_id`.                                                                                               |
| `409`  | A tool with the same `name` already exists in your account. Names are unique per owner.                                                     |
| `404`  | `tool_id` not found, or the authenticated account does not own it.                                                                          |

<Note>
  Replace `<api-key>` with your actual API key. You can generate one in the <a href="https://maker.tavus.io/dev/api-keys" target="_blank">PAL Maker</a>.
</Note>
