Functions (tools) let an agent act during a call: hang up, transfer, press keypad digits, text the caller, call your API, run JavaScript, call an MCP server or run an action in a connected app. The LLM decides when to call a function from its name, its description and the conversation so far. The voice worker then runs the function, records the call and the result in the transcript, and (for most types) feeds the result back to the LLM so the agent can reply.
Tool types#
Every tool is one entry in the Tool discriminated union in packages/shared. The type field selects the shape.
| Dashboard label | type |
What it does | Page |
|---|---|---|---|
| End Call | end_call |
Says goodbye if needed, then hangs up | End call |
| Call Transfer | transfer_call |
Cold, warm or agentic warm transfer to a number or SIP URI | Transfer call |
| Press Digit (IVR Navigation) | press_digit |
Sends DTMF digits to a phone menu | Press digit |
| Custom Function | custom |
Calls your HTTP endpoint | Custom function |
| Extract Dynamic Variable | extract_dynamic_variable |
Captures values from the conversation into variables | Extract variables |
| Send SMS | send_sms |
Texts the caller during the call | Send SMS |
| Code | code |
Runs JavaScript in a sandbox | Code tool |
| Agent Transfer | agent_swap |
Continues the same call on another agent | Agent transfer |
| MCP Tool | mcp |
Calls one tool on an MCP server | MCP tools |
| Integration App | integration_app |
Runs an action in Cal.com, HubSpot, Calendly, Zendesk or a CRM | Integration tools |
| Bridge Transfer | bridge_transfer |
Transfer agents only: connect the waiting caller | Transfer agent tools |
| Cancel Transfer | cancel_transfer |
Transfer agents only: give the call back | Transfer agent tools |
Bridge Transfer and Cancel Transfer only appear in the Add menu when the agent has Transfer agent turned on under Agent Settings.
Where tools live#
| Agent type | Field | Notes |
|---|---|---|
| Single prompt | general_tools[] on the Retell LLM |
Available on every turn |
| Multi-prompt | general_tools[] plus states[].tools[] |
State tools are only offered while that state is active |
| Conversation flow | tools[] on the flow, each with a tool_id |
Used by function nodes and subagent nodes. Plain conversation nodes do not get flow tools |
| Custom LLM | none | Your WebSocket server owns the tools. See /custom-llm |
In the dashboard, open the agent and expand Functions in the settings column next to the prompt. Click Add, pick a type, fill in the modal and click Save. Each saved tool shows as a row with an edit (pencil) and a delete button. In a conversation flow, the same Functions section sits under Global settings.
How a function call runs#
The LLM sees a schema#
For each tool the worker builds an LLM function with the tool's name, its description (rendered with dynamic variables) and a JSON schema of arguments. Some types build the schema for you (for example press_digit asks for a digit string, an inferred transfer_call asks for a number). custom, code and mcp tools use your parameters schema.
The LLM calls it#
When the model returns a tool call, the worker emits a tool_call_invocation event with the arguments as a JSON string.
Optional speech while it runs#
If speak_during_execution is on, the agent speaks the execution message first. If typing_sound is on, soft keyboard sounds play until the result comes back.
The tool executes#
The worker runs the tool. Errors never end the call: a failing tool returns an error text (usually starting with Error, or Transfer failed for transfers) to the LLM.
The result goes back#
A tool_call_result event is recorded. If the tool type replies after execution and speak_after_execution is not false, the LLM generates the next agent turn with the result in context.
Both events appear in transcript_with_tool_calls on the call object and in the test panel as Tool Invocation rows.
Name and description#
| Field | Type | Rules |
|---|---|---|
name |
string | Required. Must match ^[a-zA-Z0-9_-]{1,64}$. Must be unique within the agent (the modal shows "Another function already uses this name.") |
description |
string | Defaults to "". Tells the LLM when to call the function. {{variables}} are rendered before the LLM sees it |
The dashboard pre-fills a name per type (end_call, transfer_call, press_digit, custom_function, extract_variables, send_sms, run_code, agent_transfer, mcp_tool, app_action) and appends _2, _3 when the name is taken.
Write the description as a rule for when to call the function, not as a summary of what it does. "Call this after the caller confirms the date and time of the booking" works better than "Books appointments".
Execution options#
These fields exist on every tool type (toolBase in packages/shared). In the modal they are grouped under While it runs. The group is hidden for End Call, Bridge Transfer and Cancel Transfer.
| UI label | Field | Type | Default | Behaviour |
|---|---|---|---|---|
| Speak during execution | speak_during_execution |
boolean | off (false on custom) |
The agent says something before the tool runs |
| Prompt / Exact words | execution_message_type |
"prompt" or "static_text" |
unset | prompt: the LLM writes the line from your text. Anything else: your text is spoken verbatim |
| (text box) | execution_message_description |
string | unset | The prompt or the exact words. {{variables}} are rendered |
| Typing sound | typing_sound |
boolean | off | Plays keyboard sounds until the result is back |
| Speak after execution | speak_after_execution |
boolean | on (true on custom) |
Generate a reply once the result returns. Hidden for Call Transfer, Agent Transfer and Press Digit |
- If
speak_during_executionis on and the text is empty, the agent says "One moment please." - If
execution_message_typeis unset, the worker speaks the text as exact words. The modal shows Prompt selected by default but only saves it once you click it, so click Prompt (or set"prompt"through the API) when you want the LLM to phrase it.
Which types reply after running#
| Type | Reply after the result |
|---|---|
custom, code, mcp, integration_app |
Yes, unless speak_after_execution is false |
extract_dynamic_variable, send_sms |
Yes, unless speak_after_execution is false |
press_digit |
No: the agent waits for the phone menu to speak |
end_call |
No: the call ends |
transfer_call |
No on success (the call leaves the agent). Yes on failure, so the agent can tell the caller |
agent_swap |
The new agent generates the next turn |
bridge_transfer, cancel_transfer |
No: the transfer agent's leg ends |
Parameters (JSON schema)#
custom, code, mcp and integration_app tools take a parameters object: a JSON schema of type object whose properties are the arguments the LLM fills in.
The Parameters editor has two modes:
- Form: one row per argument with a name, a type (Text, Number, Integer, Boolean, Choice), Description for the LLM, Required and Pin value.
- JSON schema: the raw schema. Invalid JSON blocks Save and shows "Invalid JSON".
The Custom Function modal also offers Example 1 and Example 2 buttons that load sample schemas.
{
"type": "object",
"properties": {
"date": { "type": "string", "description": "Appointment date (YYYY-MM-DD)" },
"time": { "type": "string", "description": "Time in 24h format" },
"source": { "type": "string", "const": "phone" }
},
"required": ["date", "time"]
}Pinned values#
Pin value writes a JSON schema const on the property. For Custom Function tools the worker removes const properties from the schema the LLM sees and injects the pinned value (rendered with {{variables}}) into the arguments at call time. Pinned properties are never marked required.
Strict mode#
tool_call_strict_mode on the Retell LLM (default true) and on the flow (optional, off when unset) sends the tool schemas to the model in strict mode, so arguments follow the schema exactly.
Response variables#
custom, code, mcp and integration_app tools can save parts of the result as dynamic variables with response_variables: a map of variable name to JSON path. Saved values are added to collected_dynamic_variables, can be used as {{name}} in later prompts and tools, and can drive equation transitions in flows. Objects and arrays are stored as JSON strings.
{ "response_variables": { "slot": "$.data.slots[0]", "booking_id": "$.booking.uid" } }Results and limits#
| Limit | Value |
|---|---|
| Result text handed to the LLM (custom, MCP, integration app, code) | 15,000 characters |
| Custom function timeout | 1,000 to 600,000 ms, default 120,000 |
| Code tool timeout | 1,000 to 60,000 ms (dashboard: 5 to 60 seconds), default 10,000 |
| Integration app timeout | 1,000 to 120,000 ms |
| MCP timeout | 1,000 to 600,000 ms, default 30,000 |
| Custom function retries | max_retry 0 to 5 |
Testing tools#
In the test panel, Test LLM shows each Tool Invocation with its arguments. Test LLM does not call your endpoints: add a canned output under Mocks (the wrench tab) and the chat feeds it back to the agent as the result, marked Mocked. Use Test Audio or a real phone call to run the tools for real.
Call transfers need a SIP caller. The Test Audio panel notes "Please note call transfer is not supported in web calls."