Skip to main content
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 and Tool Authentication.
This page documents the tools registry (/v2/tools). If your PAL still defines tools inline under layers.llm.tools, see Legacy inline tool calling.

Tool Object

Top-Level Fields

FieldTypeRequiredDescription
namestringA unique identifier for the tool, scoped to your account. Must match OpenAI function naming rules (^[a-zA-Z_][a-zA-Z0-9_]{0,63}$).
descriptionstringNatural language explanation of what the tool does. Used by the model to decide when to call it.
parametersobjectJSON Schema object describing the tool’s input arguments. Defaults to {} (no arguments).
originstringOne of llm, vision, audio. Defaults to llm. This page covers llm; see Tool Calling for Perception for vision / audio.
on_callstringwhat the PAL does while the tool is running. See on_call reference. Defaults to generate_filler for llm tools; must be omitted for vision / audio tools.
on_resolvestringwhat the PAL does after the tool returns a result. See on_resolve reference. Defaults to fire_and_forget.
static_fillerstringThe exact line the PAL speaks while the tool runs when on_call is static_filler. Required in that case.
deliveryobjectHow the tool call is delivered. See Tool Delivery. Defaults to {"app_message": true}.

parameters

Standard JSON Schema. Same shape as the OpenAI function.parameters object.
FieldTypeRequiredDescription
typestringAlways "object".
propertiesobjectMap of parameter name to its schema (type, description, enum, etc.).
requiredarray of stringsNames of mandatory parameters.

Examples

parameters
{
  "type": "object",
  "properties": {}
}

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.
ValueBehavior
generate_fillerThe 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_fillerThe PAL speaks the configured static_filler string at dispatch time. The top-level static_filler field is required.
silentThe face stays silent while the tool runs.
passthroughThe 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

{
  "on_call": "generate_filler"
}
The LLM picks the filler line per-call (e.g. “Let me check that for you.”).

on_resolve reference

on_resolve controls what the PAL does with the tool’s result once it returns.
ValueBehavior
generate_responseThe 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_resultThe 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_contextThe 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_forgetThe 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

{
  "on_resolve": "generate_response"
}
The LLM regenerates a contextual reply using the tool’s result. Most common choice.

Creating a Tool

Create tool
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:
Response
{
  "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"
}
The tool_id (prefix t…) is how you reference the tool when attaching it to a PAL or updating / deleting it.

Attaching Tools to a PAL

A PAL only sees a tool if it is attached. Attach one or more tools in a single call:
Attach tools to PAL
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:
List PAL tools
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:
Detach tool from PAL
curl --request DELETE \
  --url https://tavusapi.com/v2/pals/{pal_id}/tools/{tool_id} \
  --header 'x-api-key: <api-key>'
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.

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:
  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.
    • API delivery: return a 2xx response with the result in the response body.

Errors

StatusWhen
400Validation failure (bad name, missing on_call on an llm tool, both delivery channels set, invalid API URL, unknown enum value, etc.).
400Attempted to attach a non-existent tool_id.
409A tool with the same name already exists in your account. Names are unique per owner.
404tool_id not found, or the authenticated account does not own it.
Replace <api-key> with your actual API key. You can generate one in the PAL Maker.