Skip to main content
An action is a discrete operation an agent performs during a conversation: play a message, transfer the call, query a knowledge base, run a workflow, and more. Actions never run on their own. They are grouped into a tool that the LLM decides to call, so the model controls when an ability fires while the configuration controls what it does.

The tool model

A tool (ToolCall) exposes a single function to the LLM. When the model calls it, the agent runs the tool’s ordered list of actions, then renders an output the model can read back. Actions execute in order. Each action whose condition passes runs, and later actions, the output template and skip_reply can read what it returned through steps or data.

Reading earlier results: steps and data

Every action of the tool has an entry in steps, from before the first one runs: An action’s <id> is its id field when set, and otherwise its position counted from 1, as the editor numbers actions: steps.1, steps.2, and steps.on_error_1, steps.on_error_2 in actions_on_error. A position changes when you reorder actions; an id does not. An id starts with a letter, uses only letters, digits and _, does not start with on_error_, is not the name of a dict method (items, keys, values, get, update, pop, popitem, setdefault, copy, clear, fromkeys), and is unique within the tool. data is the last value any action returned. It is not always the data you mean: on text and email, play_message returns {"message": ...} and handoff returns {"handoff": ...}, so either one replaces a workflow’s result for every action after it. On voice, play_message returns nothing. Read a specific result with steps instead:
With data.allow_transfer in the last condition, the transfer would not happen on text channels: by then data is the message. Read an earlier action’s result through steps, not data, once anything else has run after it. Workflows also receive steps in their input, next to arguments and data.
The tool’s own variables (arguments, data, steps, and error and refused in skip_reply) win over a conversation custom_metadata key of the same name. The stored value is still available as custom_metadata.<key>, and the conversation logs a warning the first time a stored key is hidden this way. Workflows cannot save custom_metadata keys named arguments, data or steps. Workflows that no tool runs (pre- and post-conversation workflows) are unchanged: they get an empty arguments and data under the conversation’s variables, and no steps.

Skipping the model’s reply

By default the model replies after every tool call, reading the tool’s result. skip_reply lets a tool end the turn on what its own actions said, for example a confirmation read out word for word. It is an expression, checked after the tool finishes, that can read: "true" always skips. "steps.1.output.booked" skips once a booking succeeded and lets the model explain a failure. "error" skips only when the tool failed, after a play_message in actions_on_error apologised. What the customer gets instead:
  • Voice and web chat: what the tool’s play_message actions said, each as its own message, in the order the actions ran. Nothing more is added.
  • Text API and email, which send one message per turn: that step’s play_message messages become the reply, in the order the actions ran, after anything the model wrote alongside its tool calls.
  • A play_message with generate: true still produces its message on every channel, as one completion from its instruction, without tools, made where its action ran and told what was said before it. On web chat a word-for-word message is sent as soon as its tool has run, unless a generated one comes before it: then it waits its turn, so the visitor reads them in action order.
  • If no action said anything, the customer gets nothing this turn.
The tool result stays in the conversation, so the model sees it on the next turn. When the model calls several tools at once, the reply is skipped only if one of them skips it and every other one that needs a reply skips it too; a tool that returned nothing needs none. If the reply goes ahead, a tool that asked to skip it still has its say: what it said word for word goes out ahead of the reply on every channel, and the model is told it was already said, so the reply does not repeat it. Built-in tools have no skip_reply and count as needing a reply (a web search’s results still need answering), except set_thinking_hint, which only changes the “thinking…” text and has no say. A handoff still ends the turn as it always does. On web chat, a message the customer sends while the tools run supersedes the turn as it would a reply (nothing more is generated, and both messages are answered together) unless a tool has already said something or the visitor has seen part of the turn. A tool’s messages, word for word or generated, are always delivered, like canned ones: the turn then finishes and the newer message is answered next. Realtime voices that write their own tool replies (Gemini Live, Nova Sonic) cannot have the reply skipped. An expression that fails to evaluate is logged and counts as false. In the agent editor, Tools & Actions lists every tool and opens each one in an editor laid out like this model: the description, the inputs (as a table, or as a JSON Schema for nested objects and arrays), the actions in order, the actions to run if one fails, the reply to the model, whether to skip the model’s reply, and the identity settings. Drag actions to reorder them, give any action a condition from its menu, and name it with Step ID when you open it. The variable picker in a condition or template lists the steps that have run by that point.
Every action carries an optional condition expression and an optional id. When condition is set, the action runs only if the expression evaluates truthy against the tool call’s arguments, data and steps. Leave it empty to always run the action. id names the action’s entry in steps.

Timing of a tool call

Every tool call’s output in the transcript carries a timing record, and the agent logs it as a tool_call_timing line when the call returns. A conversation’s tool calls show it under Timing when you open them. Times are epoch seconds; durations are seconds. On text, email and web chat, the turn’s reply also records received_at (the customer’s message), started_at and completed_at (the reply handed to the channel). Where a tool’s message goes out with the turn (text, email, web chat that is not streamed) it has no said_at: completed_at is when it went. So, for a turn whose reply was skipped, end-to-end latency is the first said_at (or completed_at) minus the customer’s end of speech: stopped_speaking_at on the caller’s message on voice, received_at elsewhere.

Action catalog

Actions form a discriminated union keyed on type. The full set:
Transfers, conferencing, and DTMF have their own page. See /agents/transfers for the call-routing actions (cold_transfer, warm_transfer, conference, dtmf).

play_message

workflow

Runs a workflow either by reference (workflow_id + workflow_version) or as an inline definition. The two sources are mutually exclusive.
You must supply either workflow_id + workflow_version or a non-empty inline definition, but not both. When using a reference, initial_step is required.
The workflow runs synchronously. The tool-call arguments and conversation data are passed as input, and the workflow’s output (or its context if there is no output) becomes the action result. A reference stays on the version it names; publishing a newer version of the workflow does not change the agent. In the agent editor, add a Run a workflow action to a tool under Tools & Actions. See In-call workflow tools.

knowledge_base

Runs a retrieval query against a knowledge base dataset and returns the top matches as content and score pairs.

wait

play_audio / stop_audio

stop_audio takes only condition and stops the currently playing file.

update_endpointing

Adjusts turn-detection timing mid-call. Both delays are optional; leave one unset to keep its current value.

hangup / leave_room

Both take only condition. hangup ends the call; leave_room removes the agent from the room.

Which actions run on which channel

The action catalog is built for telephony. On the async text and email engine there is no audio playout or call control, so only three action types execute:
On async channels, play_message has no audio playout. The rendered message text is returned as the action output so the tool’s output template can reference it. Any voice-only action is skipped and logged, not failed.

Tools

How the LLM decides to call a tool and what arguments it passes.

Transfers and call routing

Cold transfer, warm transfer, conference, and DTMF in depth.

Workflows

Build the workflows a workflow action runs.

Knowledge bases with agents

Connect datasets a knowledge_base action can query.