Configure messages and rejection rules

Set what the caller hears during a handoff and when a handoff attempt is blocked

Two settings shape how a handoff feels to the caller: the tool messages the assistant speaks while the transfer happens, and the rejection conditions that decide whether the handoff proceeds at all.

Tool messages

Configure what the assistant says during each phase of the handoff. Add a messages array to the Handoff tool to control the spoken responses.

Message types

TypeTriggerDefault behavior
request-startHandoff begins executingSays a random filler: “Hold on a sec”, “One moment”, etc.
request-completeHandoff completes successfullyModel generates a response
request-failedHandoff failsModel generates a response
request-response-delayedServer is slow or user speaks during processingSays “Sorry, a few more seconds.”

Example configuration

1{
2 "tools": [
3 {
4 "type": "handoff",
5 "messages": [
6 {
7 "type": "request-start",
8 "content": "Let me transfer you now. One moment please."
9 },
10 {
11 "type": "request-complete",
12 "content": "You're now connected. How can the next specialist help you?"
13 },
14 {
15 "type": "request-failed",
16 "content": "I'm sorry, I wasn't able to complete the transfer. Let me try to help you directly."
17 },
18 {
19 "type": "request-response-delayed",
20 "content": "Still working on the transfer, thank you for your patience.",
21 "timingMilliseconds": 3000
22 }
23 ],
24 "destinations": [
25 {
26 "type": "assistant",
27 "assistantId": "your-assistant-id",
28 "description": "transfer to specialist"
29 }
30 ]
31 }
32 ]
33}

Message properties

request-start

  • content (string) — The text the assistant speaks when the handoff begins.
  • blocking (boolean, default: false) — When true, the tool call waits until the message finishes speaking before executing.
  • conditions (array) — Optional conditions that must match for this message to trigger.
  • contents (array) — Multilingual variants of the content. Overrides content when provided.

request-complete

  • content (string) — The text the assistant speaks when the handoff completes.
  • role ("assistant" | "system", default: "assistant") — When "assistant", the content is spoken aloud. When "system", the content is passed as a system message hint to the model.
  • endCallAfterSpokenEnabled (boolean, default: false) — When true, the call ends after this message is spoken.
  • conditions (array) — Optional conditions for triggering this message.
  • contents (array) — Multilingual variants.

request-failed

  • content (string) — The text the assistant speaks when the handoff fails.
  • endCallAfterSpokenEnabled (boolean, default: false) — When true, the call ends after this message.
  • conditions (array) — Optional conditions for triggering.
  • contents (array) — Multilingual variants.

request-response-delayed

  • content (string) — The text the assistant speaks when the handoff is taking longer than expected.
  • timingMilliseconds (number, 100-120000) — Milliseconds to wait before triggering this message.
  • conditions (array) — Optional conditions for triggering.
  • contents (array) — Multilingual variants.

For the full schema, see the API reference.

Rejection plan

Use rejectionPlan to prevent a handoff from executing based on conversation state. When all conditions in the plan match, the tool call is rejected and the rejection message is added to the conversation.

Regex condition

Match against message content using regular expressions:

1{
2 "tools": [
3 {
4 "type": "handoff",
5 "rejectionPlan": {
6 "conditions": [
7 {
8 "type": "regex",
9 "regex": "(?i)\\b(cancel|stop|nevermind)\\b",
10 "target": {
11 "role": "user",
12 "position": -1
13 }
14 }
15 ]
16 },
17 "destinations": [
18 {
19 "type": "assistant",
20 "assistantId": "your-assistant-id",
21 "description": "transfer to billing"
22 }
23 ]
24 }
25 ]
26}

This rejects the handoff if the user’s most recent message contains “cancel”, “stop”, or “nevermind” (case-insensitive).

Liquid condition

Use Liquid templates for more complex logic. The template must return exactly "true" or "false":

1{
2 "rejectionPlan": {
3 "conditions": [
4 {
5 "type": "liquid",
6 "liquid": "{% assign userMsgs = messages | where: 'role', 'user' %}{% if userMsgs.size < 3 %}true{% else %}false{% endif %}"
7 }
8 ]
9 }
10}

This rejects the handoff if fewer than 3 user messages exist in the conversation. Available Liquid variables include messages (array of recent messages), now (current timestamp), and any assistant variable values.

Group condition

Combine multiple conditions with AND or OR logic:

1{
2 "rejectionPlan": {
3 "conditions": [
4 {
5 "type": "group",
6 "operator": "OR",
7 "conditions": [
8 {
9 "type": "regex",
10 "regex": "(?i)\\b(cancel|stop)\\b",
11 "target": { "role": "user" }
12 },
13 {
14 "type": "liquid",
15 "liquid": "{% assign userMsgs = messages | where: 'role', 'user' %}{% if userMsgs.size < 2 %}true{% else %}false{% endif %}"
16 }
17 ]
18 }
19 ]
20 }
21}

By default, all top-level conditions in the conditions array use AND logic — all must match for the rejection to trigger. Use a group condition with operator: "OR" to reject when any single condition matches.

For the full schema, see the API reference.