context on a handoff decides what the next agent starts from. It is the
single most consequential field on a multi-agent call: it sets what the target
can answer without asking again, and it sets what you pay on every turn the
target then takes.
It uses the same three words as an agent’s own
conversation.context, because it is the same
question asked about the next agent rather than about the next call.
transcript — everything said so far
The default. The target inherits the whole conversation and needs no
configuration at all. It knows what the caller said forty turns ago and can pick
up anything.
It also pays for all of it on every turn it takes, on your own provider key.
A long call handed to a second agent is a long context re-read on every one of
that agent’s replies. On a five-turn call that is nothing; on a twenty-minute
support call it is the largest line on the bill.
recent_turns and summary_prompt are refused here rather than ignored —
transcript already carries every turn, so a turn count is a misunderstanding
worth an error:
summary — a summary this agent writes
Under summary, the generated handoff_to_* tool takes exactly one argument:
the summary. This agent writes it, as that argument, in the same turn as the
decision to hand over.
That is what makes the mode cheap. There is no second LLM call and no summarizer
model — so a realtime speech-to-speech agent can use it too, which it could not
if the platform had to run a separate pass. What it costs is a pause before
the handoff: the agent writes 60–100 tokens before the tool returns, and the
caller waits through it. What it buys is a short, focused context that the
source agent chose, instead of forty turns the target re-reads on every turn.
The target receives one system message, headed by where the text came from, and
then the verbatim tail:
The summary argument is marked required on the tool, which is a request rather
than a guarantee. If the model calls the tool with nothing in it, the handoff
still happens and the target is handed the full transcript instead — the
caller notices nothing. The call’s
agent.handoff event records it as
summary_fallback.none — only its own instructions
The target starts with its system prompt, its tools and its knowledge, and no
history at all unless you opt into a tail with recent_turns. With no tail it
is told plainly that it has not been told what came before, and opens by
introducing itself briefly and asking what the caller needs.
Reach for it when the target’s job does not depend on the conversation so far: a
survey agent at the end of a support call, a payment step, a language-specific
desk that starts over.
recent_turns — the verbatim tail
integer | null
default:"null"
How many recent turns cross verbatim, alongside the summary or in place of
one. 1 to 10.
- Under
summary, the tail defaults to two turns. - Under
none, the tail defaults to none.
summary the tail can be sized down to one turn but not switched off:
1 is the minimum, and there is no 0. A summary with no tail leaves the target
knowing the history and not the question.
Under none the tail is opt-in, and {"context": "none", "recent_turns": 3} is
a real and useful combination — the last three turns and nothing else, with no
pause to write a summary. It is the cheapest useful handoff there is.
Past ten turns the honest answer is transcript, which is why the maximum is 10.
summary_prompt — what this agent is asked to write
string | null
default:"null"
Replaces the platform’s default line. Only under
context: "summary".summary_prompt is the description of the tool argument, so it is literally
what the agent is asked to write. The default, with the destination’s name
substituted in, is one line naming three buckets:
{{userdata.…}}, {{system_vars.…}} and {{vars.…}}, substituted at build
time like the description and the message.
Keep it to a line or two. It sits in the source agent’s tool schema on every
request of the call, and a longer prompt buys a longer pause before the handoff
— the caller is listening to silence while the agent writes it.
Outside summary it is refused:
summary is not a privacy boundary
Do not describe it as one, to yourself or to a customer. It narrows what the
target model is shown. It guarantees nothing.
- The tail always crosses. Under
summaryit is at least one turn, verbatim, whatever the summary says. userdatacrosses regardless. It is session state every agent on the call shares, and no context policy touches it — see userdata.- The full transcript is still recorded and still displayed. Nothing is dropped from the call record, the recording or the dashboard.
- A later
transcripthop shows that agent the whole call, including the partsummaryscoped away one hop earlier. - The summary is written by an LLM the caller has been talking to, so it is exactly as trustworthy as anything else that model says. It can be wrong, and it can include something you would rather it did not.
Choosing
A reasonable default for a support line:
summary outbound to a specialist
who needs to know why the caller is there, and none with a small
recent_turns on the way back to the front desk, which does not need the
specialist’s detour re-read on every turn.
Seeing what actually crossed
The one fact no config can reconstruct afterwards is how much actually crossed — an edge asking for five turns on a call that has had two crossed two.GET /v1/calls/{session_id} returns the call’s event trace, and each handoff
appears there as agent.handoff:
via is handoffs for an edge on the agent and operation for a
handoff operation. tail_items is how many
messages the tail came to, which is usually more than recent_turns because a
turn can contain several.
Next
Handoffs
The rest of the handoff entry, and the rules across a team.
Patterns
Which policy each hop of a real design should use.
Conversation memory
The other
context field: what a new call knows about earlier ones.