diff --git a/fern/apis/api/openapi.json b/fern/apis/api/openapi.json index 91508f86..38fea669 100644 --- a/fern/apis/api/openapi.json +++ b/fern/apis/api/openapi.json @@ -2086,6 +2086,10 @@ "$ref": "#/components/schemas/CreateTransferCallToolDTO", "title": "TransferCallTool" }, + { + "$ref": "#/components/schemas/CreateHandoffToolDTO", + "title": "HandoffTool" + }, { "$ref": "#/components/schemas/CreateBashToolDTO", "title": "BashTool" @@ -2151,6 +2155,7 @@ "endCall": "#/components/schemas/CreateEndCallToolDTO", "function": "#/components/schemas/CreateFunctionToolDTO", "transferCall": "#/components/schemas/CreateTransferCallToolDTO", + "handoff": "#/components/schemas/CreateHandoffToolDTO", "bash": "#/components/schemas/CreateBashToolDTO", "computer": "#/components/schemas/CreateComputerToolDTO", "textEditor": "#/components/schemas/CreateTextEditorToolDTO", @@ -2202,6 +2207,10 @@ "$ref": "#/components/schemas/TransferCallTool", "title": "TransferCallTool" }, + { + "$ref": "#/components/schemas/HandoffTool", + "title": "HandoffTool" + }, { "$ref": "#/components/schemas/BashTool", "title": "BashTool" @@ -2267,6 +2276,7 @@ "endCall": "#/components/schemas/EndCallTool", "function": "#/components/schemas/FunctionTool", "transferCall": "#/components/schemas/TransferCallTool", + "handoff": "#/components/schemas/HandoffTool", "bash": "#/components/schemas/BashTool", "computer": "#/components/schemas/ComputerTool", "textEditor": "#/components/schemas/TextEditorTool", @@ -2426,6 +2436,10 @@ "$ref": "#/components/schemas/TransferCallTool", "title": "TransferCallTool" }, + { + "$ref": "#/components/schemas/HandoffTool", + "title": "HandoffTool" + }, { "$ref": "#/components/schemas/BashTool", "title": "BashTool" @@ -2491,6 +2505,7 @@ "endCall": "#/components/schemas/EndCallTool", "function": "#/components/schemas/FunctionTool", "transferCall": "#/components/schemas/TransferCallTool", + "handoff": "#/components/schemas/HandoffTool", "bash": "#/components/schemas/BashTool", "computer": "#/components/schemas/ComputerTool", "textEditor": "#/components/schemas/TextEditorTool", @@ -2568,6 +2583,10 @@ "$ref": "#/components/schemas/TransferCallTool", "title": "TransferCallTool" }, + { + "$ref": "#/components/schemas/HandoffTool", + "title": "HandoffTool" + }, { "$ref": "#/components/schemas/BashTool", "title": "BashTool" @@ -2633,6 +2652,7 @@ "endCall": "#/components/schemas/EndCallTool", "function": "#/components/schemas/FunctionTool", "transferCall": "#/components/schemas/TransferCallTool", + "handoff": "#/components/schemas/HandoffTool", "bash": "#/components/schemas/BashTool", "computer": "#/components/schemas/ComputerTool", "textEditor": "#/components/schemas/TextEditorTool", @@ -2702,6 +2722,10 @@ "$ref": "#/components/schemas/UpdateTransferCallToolDTO", "title": "TransferCallTool" }, + { + "$ref": "#/components/schemas/UpdateHandoffToolDTO", + "title": "HandoffTool" + }, { "$ref": "#/components/schemas/UpdateBashToolDTO", "title": "BashTool" @@ -2767,6 +2791,7 @@ "endCall": "#/components/schemas/UpdateEndCallToolDTO", "function": "#/components/schemas/UpdateFunctionToolDTO", "transferCall": "#/components/schemas/UpdateTransferCallToolDTO", + "handoff": "#/components/schemas/UpdateHandoffToolDTO", "bash": "#/components/schemas/UpdateBashToolDTO", "computer": "#/components/schemas/UpdateComputerToolDTO", "textEditor": "#/components/schemas/UpdateTextEditorToolDTO", @@ -2818,6 +2843,10 @@ "$ref": "#/components/schemas/TransferCallTool", "title": "TransferCallTool" }, + { + "$ref": "#/components/schemas/HandoffTool", + "title": "HandoffTool" + }, { "$ref": "#/components/schemas/BashTool", "title": "BashTool" @@ -2883,6 +2912,7 @@ "endCall": "#/components/schemas/EndCallTool", "function": "#/components/schemas/FunctionTool", "transferCall": "#/components/schemas/TransferCallTool", + "handoff": "#/components/schemas/HandoffTool", "bash": "#/components/schemas/BashTool", "computer": "#/components/schemas/ComputerTool", "textEditor": "#/components/schemas/TextEditorTool", @@ -2957,6 +2987,10 @@ "$ref": "#/components/schemas/TransferCallTool", "title": "TransferCallTool" }, + { + "$ref": "#/components/schemas/HandoffTool", + "title": "HandoffTool" + }, { "$ref": "#/components/schemas/BashTool", "title": "BashTool" @@ -3022,6 +3056,7 @@ "endCall": "#/components/schemas/EndCallTool", "function": "#/components/schemas/FunctionTool", "transferCall": "#/components/schemas/TransferCallTool", + "handoff": "#/components/schemas/HandoffTool", "bash": "#/components/schemas/BashTool", "computer": "#/components/schemas/ComputerTool", "textEditor": "#/components/schemas/TextEditorTool", @@ -6212,6 +6247,63 @@ } } }, + "TurnLatency": { + "type": "object", + "properties": { + "modelLatency": { + "type": "number", + "description": "This is the model latency for the first token." + }, + "voiceLatency": { + "type": "number", + "description": "This is the voice latency from the model output." + }, + "transcriberLatency": { + "type": "number", + "description": "This is the transcriber latency from the user speech." + }, + "endpointingLatency": { + "type": "number", + "description": "This is the endpointing latency." + }, + "turnLatency": { + "type": "number", + "description": "This is the latency for the whole turn." + } + } + }, + "PerformanceMetrics": { + "type": "object", + "properties": { + "turnLatencies": { + "description": "These are the individual latencies for each turn.", + "type": "array", + "items": { + "$ref": "#/components/schemas/TurnLatency" + } + }, + "modelLatencyAverage": { + "type": "number", + "description": "This is the average latency for the model to output the first token." + }, + "voiceLatencyAverage": { + "type": "number", + "description": "This is the average latency for the text to speech." + }, + "transcriberLatencyAverage": { + "type": "number", + "description": "This is the average latency for the transcriber." + }, + "endpointingLatencyAverage": { + "type": "number", + "description": "This is the average latency for the endpointing." + }, + "turnLatencyAverage": { + "type": "number", + "description": "This is the average latency for complete turns." + } + } + }, "Artifact": { "type": "object", "properties": { @@ -6300,6 +6392,14 @@ "variableValues": { "type": "object", "description": "These are the variable values at the end of the workflow execution." + }, + "performanceMetrics": { + "description": "This is the performance metrics for the call. It contains the turn latency, broken down by component.", + "allOf": [ + { + "$ref": "#/components/schemas/PerformanceMetrics" + } + ] } } }, @@ -11349,6 +11449,243 @@ "type" ] }, + "ContextEngineeringPlanLastNMessages": { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "lastNMessages" + ] + }, + "maxMessages": { + "type": "number", + "description": "This is the maximum number of messages to include in the context engineering plan.", + "minimum": 0 + } + }, + "required": [ + "type", + "maxMessages" + ] + }, + "ContextEngineeringPlanNone": { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "none" + ] + } + }, + "required": [ + "type" + ] + }, + "ContextEngineeringPlanAll": { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "all" + ] + } + }, + "required": [ + "type" + ] + }, + "VariableExtractionAlias": { + "type": "object", + "properties": { + "key": { + "type": "string", + "description": "This is the key of the variable.\n\nThis variable will be accessible during the call as `{{key}}` and stored in `call.artifact.variableValues` after the call.\n\nRules:\n- Must start with a letter (a-z, A-Z).\n- Subsequent characters can be letters, numbers, or underscores.\n- Minimum length of 1 and maximum length of 40.", + "minLength": 1, + "maxLength": 40, + "pattern": "/^[a-zA-Z][a-zA-Z0-9_]*$/" + }, + "value": { + "type": "string", + "description": "This is the value of the variable.\n\nThis can reference existing variables, use filters, and perform transformations.\n\nExamples: \"{{name}}\", \"{{customer.email}}\", \"Hello {{name | upcase}}\"", + "maxLength": 10000 + } + }, + "required": [ + "key", + "value" + ] + }, + "VariableExtractionPlan": { + "type": "object", + "properties": { + "schema": { + "description": "This is the schema to extract.\n\nExamples:\n1. To extract object properties, you can use the following schema:\n```json\n{\n \"type\": \"object\",\n \"properties\": {\n \"name\": {\n \"type\": \"string\"\n },\n \"age\": {\n \"type\": \"number\"\n }\n }\n}\n```\n\nThese will be extracted as `{{ name }}` and `{{ age }}` respectively. To emphasize, object properties are extracted as direct global variables.\n\n2. To extract nested properties, you can use the following schema:\n```json\n{\n \"type\": \"object\",\n \"properties\": {\n \"name\": {\n \"type\": \"object\",\n \"properties\": {\n \"first\": {\n \"type\": \"string\"\n },\n \"last\": {\n \"type\": \"string\"\n }\n }\n }\n }\n}\n```\n\nThese will be extracted as `{{ name }}`. And, `{{ name.first }}` and `{{ name.last }}` will be accessible.\n\n3. To extract array items, you can use the following schema:\n```json\n{\n \"type\": \"array\",\n \"title\": \"zipCodes\",\n \"items\": {\n \"type\": \"string\"\n }\n}\n```\n\nThis will be extracted as `{{ zipCodes }}`. To access the array items, you can use `{{ zipCodes[0] }}` and `{{ zipCodes[1] }}`.\n\n4. To extract array of objects, you can use the following schema:\n\n```json\n{\n \"type\": \"array\",\n \"name\": \"people\",\n \"items\": {\n \"type\": \"object\",\n \"properties\": {\n \"name\": {\n \"type\": \"string\"\n },\n \"age\": {\n \"type\": \"number\"\n },\n \"zipCodes\": {\n \"type\": \"array\",\n \"items\": {\n \"type\": \"string\"\n }\n }\n }\n }\n}\n```\n\nThis will be extracted as `{{ people }}`. To access the array items, you can use `{{ people[n].name }}`, `{{ people[n].age }}`, `{{ people[n].zipCodes }}`, `{{ people[n].zipCodes[0] }}` and `{{ people[n].zipCodes[1] }}`.", + "allOf": [ + { + "$ref": "#/components/schemas/JsonSchema" + } + ] + }, + "aliases": { + "description": "These are additional variables to create.\n\nThese will be accessible during the call as `{{key}}` and stored in `call.artifact.variableValues` after the call.\n\nExample:\n```json\n{\n \"aliases\": [\n {\n \"key\": \"customerName\",\n \"value\": \"{{name}}\"\n },\n {\n \"key\": \"fullName\",\n \"value\": \"{{firstName}} {{lastName}}\"\n },\n {\n \"key\": \"greeting\",\n \"value\": \"Hello {{name}}, welcome to {{company}}!\"\n },\n {\n \"key\": \"customerCity\",\n \"value\": \"{{addresses[0].city}}\"\n },\n {\n \"key\": \"something\",\n \"value\": \"{{any liquid}}\"\n }\n ]\n}\n```\n\nThis will create variables `customerName`, `fullName`, `greeting`, `customerCity`, and `something`. To access these variables, you can reference them as `{{customerName}}`, `{{fullName}}`, `{{greeting}}`, `{{customerCity}}`, and `{{something}}`.", + "type": "array", + "items": { + "$ref": "#/components/schemas/VariableExtractionAlias" + } + } + } + }, + "HandoffDestinationAssistant": { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "assistant" + ] + }, + "contextEngineeringPlan": { + "description": "This is the plan for manipulating the message context before handing off the call to the next assistant.", + "oneOf": [ + { + "$ref": "#/components/schemas/ContextEngineeringPlanLastNMessages", + "title": "Last N Messages" + }, + { + "$ref": "#/components/schemas/ContextEngineeringPlanNone", + "title": "None" + }, + { + "$ref": "#/components/schemas/ContextEngineeringPlanAll", + "title": "All" + } + ] + }, + "assistantName": { + "type": "string", + "description": "This is the assistant to transfer the call to. You must provide either assistantName or assistantId." + }, + "assistantId": { + "type": "string", + "description": "This is the assistant id to transfer the call to. You must provide either assistantName or assistantId." + }, + "assistant": { + "description": "This is a transient assistant to transfer the call to. You may provide a transient assistant in the response `handoff-destination-request` in a dynamic handoff.", + "allOf": [ + { + "$ref": "#/components/schemas/CreateAssistantDTO" + } + ] + }, + "variableExtractionPlan": { + "description": "This is the variable extraction plan for the handoff tool.", + "allOf": [ + { + "$ref": "#/components/schemas/VariableExtractionPlan" + } + ] + }, + "description": { + "type": "string", + "description": "This is the description of the destination, used by the AI to choose when and how to transfer the call." + } + }, + "required": [ + "type" + ] + }, + "HandoffDestinationDynamic": { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "dynamic" + ] + }, + "server": { + "description": "This is where Vapi will send the handoff-destination-request webhook in a dynamic handoff.\n\nThe order of precedence is:\n\n1. tool.server.url\n2. assistant.server.url\n3. phoneNumber.server.url\n4. org.server.url", + "allOf": [ + { + "$ref": "#/components/schemas/Server" + } + ] + }, + "description": { + "type": "string", + "description": "This is the description of the destination, used by the AI to choose when and how to transfer the call." + } + }, + "required": [ + "type" + ] + }, + "CreateHandoffToolDTO": { + "type": "object", + "properties": { + "messages": { + "type": "array", + "description": "These are the messages that will be spoken to the user as the tool is running.\n\nFor some tools, this is auto-filled based on special fields like `tool.destinations`. For others like the function tool, these can be custom configured.", + "items": { + "oneOf": [ + { + "$ref": "#/components/schemas/ToolMessageStart", + "title": "ToolMessageStart" + }, + { + "$ref": "#/components/schemas/ToolMessageComplete", + "title": "ToolMessageComplete" + }, + { + "$ref": "#/components/schemas/ToolMessageFailed", + "title": "ToolMessageFailed" + }, + { + "$ref": "#/components/schemas/ToolMessageDelayed", + "title": "ToolMessageDelayed" + } + ] + } + }, + "type": { + "type": "string", + "description": "This is the type of the tool.\nWhen you're using handoff tool, we recommend adding this to your system prompt\n---\n# System context\n\nYou are part of a multi-agent system designed to make agent coordination and execution easy. Agents uses two primary abstraction: **Agents** and **Handoffs**. An agent encompasses instructions and tools and can hand off a conversation to another agent when appropriate. Handoffs are achieved by calling a handoff function, generally named `handoff_to_`. Handoffs between agents are handled seamlessly in the background; do not mention or draw attention to these handoffs in your conversation with the user.\n\n# Agent context\n\n{put your agent system prompt here}\n---", + "enum": [ + "handoff" + ] + }, + "destinations": { + "type": "array", + "description": "These are the destinations that the call can be handed off to.\n\nUsage:\n1. Single destination\n\nUse `assistantId` to handoff the call to a saved assistant, or `assistantName` to handoff the call to an assistant in the same squad.\n\n```json\n{\n \"tools\": [\n {\n \"type\": \"handoff\",\n \"destinations\": [\n {\n \"type\": \"assistant\",\n \"assistantId\": \"assistant-123\", // or \"assistantName\": \"Assistant123\"\n \"description\": \"customer wants to be handed off to assistant-123\",\n \"contextEngineeringPlan\": {\n \"type\": \"all\"\n }\n }\n ],\n }\n ]\n}\n```\n\n2. Multiple destinations\n\n2.1. Multiple Tools, Each With One Destination (OpenAI recommended)\n\n```json\n{\n \"tools\": [\n {\n \"type\": \"handoff\",\n \"destinations\": [\n {\n \"type\": \"assistant\",\n \"assistantId\": \"assistant-123\",\n \"description\": \"customer wants to be handed off to assistant-123\",\n \"contextEngineeringPlan\": {\n \"type\": \"all\"\n }\n },\n ],\n },\n {\n \"type\": \"handoff\",\n \"destinations\": [\n {\n \"type\": \"assistant\",\n \"assistantId\": \"assistant-456\",\n \"description\": \"customer wants to be handed off to assistant-456\",\n \"contextEngineeringPlan\": {\n \"type\": \"all\"\n }\n }\n ],\n }\n ]\n}\n```\n\n2.2. One Tool, Multiple Destinations (Anthropic recommended)\n\n```json\n{\n \"tools\": [\n {\n \"type\": \"handoff\",\n \"destinations\": [\n {\n \"type\": \"assistant\",\n \"assistantId\": \"assistant-123\",\n \"description\": \"customer wants to be handed off to assistant-123\",\n \"contextEngineeringPlan\": {\n \"type\": \"all\"\n }\n },\n {\n \"type\": \"assistant\",\n \"assistantId\": \"assistant-456\",\n \"description\": \"customer wants to be handed off to assistant-456\",\n \"contextEngineeringPlan\": {\n \"type\": \"all\"\n }\n }\n ],\n }\n ]\n}\n```\n\n3. Dynamic destination\n\n3.1 To determine the destination dynamically, supply a `dynamic` handoff destination type and a `server` object.\n VAPI will send a handoff-destination-request webhook to the `server.url`.\n The response from the server will be used as the destination (if valid).\n\n```json\n{\n \"tools\": [\n {\n \"type\": \"handoff\",\n \"destinations\": [\n {\n \"type\": \"dynamic\",\n \"server\": {\n \"url\": \"https://example.com\"\n }\n }\n ],\n }\n ]\n}\n```\n\n3.2. To pass custom parameters to the server, you can use the `function` object.\n\n```json\n{\n \"tools\": [\n {\n \"type\": \"handoff\",\n \"destinations\": [\n {\n \"type\": \"dynamic\",\n \"server\": {\n \"url\": \"https://example.com\"\n },\n }\n ],\n \"function\": {\n \"type\": \"function\",\n \"name\": \"handoff\",\n \"description\": \"Call this function when the customer is ready to be handed off to the next assistant\",\n \"parameters\": {\n \"type\": \"object\",\n \"properties\": {\n \"destination\": {\n \"type\": \"string\",\n \"description\": \"Use dynamic when customer is ready to be handed off to the next assistant\",\n \"enum\": [\"dynamic\"]\n },\n \"customerAreaCode\": {\n \"type\": \"number\",\n \"description\": \"Area code of the customer\"\n },\n \"customerIntent\": {\n \"type\": \"string\",\n \"enum\": [\"new-customer\", \"existing-customer\"],\n \"description\": \"Use new-customer when customer is a new customer, existing-customer when customer is an existing customer\"\n },\n \"customerSentiment\": {\n \"type\": \"string\",\n \"enum\": [\"positive\", \"negative\", \"neutral\"],\n \"description\": \"Use positive when customer is happy, negative when customer is unhappy, neutral when customer is neutral\"\n }\n }\n }\n }\n }\n ]\n}\n```\n\nThe properties `customerAreaCode`, `customerIntent`, and `customerSentiment` will be passed to the server in the webhook request body.", + "items": { + "oneOf": [ + { + "$ref": "#/components/schemas/HandoffDestinationAssistant", + "title": "Assistant" + }, + { + "$ref": "#/components/schemas/HandoffDestinationDynamic", + "title": "Dynamic" + } + ] + } + }, + "rejectionPlan": { + "description": "This is the plan to reject a tool call based on the conversation state.\n\n// Example 1: Reject endCall if user didn't say goodbye\n```json\n{\n conditions: [{\n type: 'regex',\n regex: '(?i)\\\\b(bye|goodbye|farewell|see you later|take care)\\\\b',\n target: { position: -1, role: 'user' },\n negate: true // Reject if pattern does NOT match\n }]\n}\n```\n\n// Example 2: Reject transfer if user is actually asking a question\n```json\n{\n conditions: [{\n type: 'regex',\n regex: '\\\\?',\n target: { position: -1, role: 'user' }\n }]\n}\n```\n\n// Example 3: Reject transfer if user didn't mention transfer recently\n```json\n{\n conditions: [{\n type: 'liquid',\n liquid: `{% assign recentMessages = messages | last: 5 %}\n{% assign userMessages = recentMessages | where: 'role', 'user' %}\n{% assign mentioned = false %}\n{% for msg in userMessages %}\n {% if msg.content contains 'transfer' or msg.content contains 'connect' or msg.content contains 'speak to' %}\n {% assign mentioned = true %}\n {% break %}\n {% endif %}\n{% endfor %}\n{% if mentioned %}\n false\n{% else %}\n true\n{% endif %}`\n }]\n}\n```\n\n// Example 4: Reject endCall if the bot is looping and trying to exit\n```json\n{\n conditions: [{\n type: 'liquid',\n liquid: `{% assign recentMessages = messages | last: 6 %}\n{% assign userMessages = recentMessages | where: 'role', 'user' | reverse %}\n{% if userMessages.size < 3 %}\n false\n{% else %}\n {% assign msg1 = userMessages[0].content | downcase %}\n {% assign msg2 = userMessages[1].content | downcase %}\n {% assign msg3 = userMessages[2].content | downcase %}\n {% comment %} Check for repetitive messages {% endcomment %}\n {% if msg1 == msg2 or msg1 == msg3 or msg2 == msg3 %}\n true\n {% comment %} Check for common loop phrases {% endcomment %}\n {% elsif msg1 contains 'cool thanks' or msg2 contains 'cool thanks' or msg3 contains 'cool thanks' %}\n true\n {% elsif msg1 contains 'okay thanks' or msg2 contains 'okay thanks' or msg3 contains 'okay thanks' %}\n true\n {% elsif msg1 contains 'got it' or msg2 contains 'got it' or msg3 contains 'got it' %}\n true\n {% else %}\n false\n {% endif %}\n{% endif %}`\n }]\n}\n```", + "allOf": [ + { + "$ref": "#/components/schemas/ToolRejectionPlan" + } + ] + } + }, + "required": [ + "type" + ] + }, "CreateCustomKnowledgeBaseDTO": { "type": "object", "properties": { @@ -11996,6 +12333,10 @@ "$ref": "#/components/schemas/CreateGoogleSheetsRowAppendToolDTO", "title": "GoogleSheetsRowAppendTool" }, + { + "$ref": "#/components/schemas/CreateHandoffToolDTO", + "title": "HandoffTool" + }, { "$ref": "#/components/schemas/CreateMcpToolDTO", "title": "McpTool" @@ -12168,6 +12509,10 @@ "$ref": "#/components/schemas/CreateGoogleSheetsRowAppendToolDTO", "title": "GoogleSheetsRowAppendTool" }, + { + "$ref": "#/components/schemas/CreateHandoffToolDTO", + "title": "HandoffTool" + }, { "$ref": "#/components/schemas/CreateMcpToolDTO", "title": "McpTool" @@ -12339,6 +12684,10 @@ "$ref": "#/components/schemas/CreateGoogleSheetsRowAppendToolDTO", "title": "GoogleSheetsRowAppendTool" }, + { + "$ref": "#/components/schemas/CreateHandoffToolDTO", + "title": "HandoffTool" + }, { "$ref": "#/components/schemas/CreateMcpToolDTO", "title": "McpTool" @@ -12494,6 +12843,10 @@ "$ref": "#/components/schemas/CreateGoogleSheetsRowAppendToolDTO", "title": "GoogleSheetsRowAppendTool" }, + { + "$ref": "#/components/schemas/CreateHandoffToolDTO", + "title": "HandoffTool" + }, { "$ref": "#/components/schemas/CreateMcpToolDTO", "title": "McpTool" @@ -12676,6 +13029,10 @@ "$ref": "#/components/schemas/CreateGoogleSheetsRowAppendToolDTO", "title": "GoogleSheetsRowAppendTool" }, + { + "$ref": "#/components/schemas/CreateHandoffToolDTO", + "title": "HandoffTool" + }, { "$ref": "#/components/schemas/CreateMcpToolDTO", "title": "McpTool" @@ -12827,6 +13184,10 @@ "$ref": "#/components/schemas/CreateGoogleSheetsRowAppendToolDTO", "title": "GoogleSheetsRowAppendTool" }, + { + "$ref": "#/components/schemas/CreateHandoffToolDTO", + "title": "HandoffTool" + }, { "$ref": "#/components/schemas/CreateMcpToolDTO", "title": "McpTool" @@ -13051,6 +13412,10 @@ "$ref": "#/components/schemas/CreateGoogleSheetsRowAppendToolDTO", "title": "GoogleSheetsRowAppendTool" }, + { + "$ref": "#/components/schemas/CreateHandoffToolDTO", + "title": "HandoffTool" + }, { "$ref": "#/components/schemas/CreateMcpToolDTO", "title": "McpTool" @@ -13226,6 +13591,10 @@ "$ref": "#/components/schemas/CreateGoogleSheetsRowAppendToolDTO", "title": "GoogleSheetsRowAppendTool" }, + { + "$ref": "#/components/schemas/CreateHandoffToolDTO", + "title": "HandoffTool" + }, { "$ref": "#/components/schemas/CreateMcpToolDTO", "title": "McpTool" @@ -13393,6 +13762,10 @@ "$ref": "#/components/schemas/CreateGoogleSheetsRowAppendToolDTO", "title": "GoogleSheetsRowAppendTool" }, + { + "$ref": "#/components/schemas/CreateHandoffToolDTO", + "title": "HandoffTool" + }, { "$ref": "#/components/schemas/CreateMcpToolDTO", "title": "McpTool" @@ -13547,6 +13920,10 @@ "$ref": "#/components/schemas/CreateGoogleSheetsRowAppendToolDTO", "title": "GoogleSheetsRowAppendTool" }, + { + "$ref": "#/components/schemas/CreateHandoffToolDTO", + "title": "HandoffTool" + }, { "$ref": "#/components/schemas/CreateMcpToolDTO", "title": "McpTool" @@ -14012,6 +14389,10 @@ "$ref": "#/components/schemas/CreateGoogleSheetsRowAppendToolDTO", "title": "GoogleSheetsRowAppendTool" }, + { + "$ref": "#/components/schemas/CreateHandoffToolDTO", + "title": "HandoffTool" + }, { "$ref": "#/components/schemas/CreateMcpToolDTO", "title": "McpTool" @@ -14163,6 +14544,10 @@ "$ref": "#/components/schemas/CreateGoogleSheetsRowAppendToolDTO", "title": "GoogleSheetsRowAppendTool" }, + { + "$ref": "#/components/schemas/CreateHandoffToolDTO", + "title": "HandoffTool" + }, { "$ref": "#/components/schemas/CreateMcpToolDTO", "title": "McpTool" @@ -14314,6 +14699,10 @@ "$ref": "#/components/schemas/CreateGoogleSheetsRowAppendToolDTO", "title": "GoogleSheetsRowAppendTool" }, + { + "$ref": "#/components/schemas/CreateHandoffToolDTO", + "title": "HandoffTool" + }, { "$ref": "#/components/schemas/CreateMcpToolDTO", "title": "McpTool" @@ -14727,47 +15116,6 @@ } } }, - "VariableExtractionAlias": { - "type": "object", - "properties": { - "key": { - "type": "string", - "description": "This is the key of the variable.\n\nThis variable will be accessible during the call as `{{key}}` and stored in `call.artifact.variableValues` after the call.\n\nRules:\n- Must start with a letter (a-z, A-Z).\n- Subsequent characters can be letters, numbers, or underscores.\n- Minimum length of 1 and maximum length of 40.", - "minLength": 1, - "maxLength": 40, - "pattern": "/^[a-zA-Z][a-zA-Z0-9_]*$/" - }, - "value": { - "type": "string", - "description": "This is the value of the variable.\n\nThis can reference existing variables, use filters, and perform transformations.\n\nExamples: \"{{name}}\", \"{{customer.email}}\", \"Hello {{name | upcase}}\"", - "maxLength": 10000 - } - }, - "required": [ - "key", - "value" - ] - }, - "VariableExtractionPlan": { - "type": "object", - "properties": { - "schema": { - "description": "This is the schema to extract.\n\nExamples:\n1. To extract object properties, you can use the following schema:\n```json\n{\n \"type\": \"object\",\n \"properties\": {\n \"name\": {\n \"type\": \"string\"\n },\n \"age\": {\n \"type\": \"number\"\n }\n }\n}\n```\n\nThese will be extracted as `{{ name }}` and `{{ age }}` respectively. To emphasize, object properties are extracted as direct global variables.\n\n2. To extract nested properties, you can use the following schema:\n```json\n{\n \"type\": \"object\",\n \"properties\": {\n \"name\": {\n \"type\": \"object\",\n \"properties\": {\n \"first\": {\n \"type\": \"string\"\n },\n \"last\": {\n \"type\": \"string\"\n }\n }\n }\n }\n}\n```\n\nThese will be extracted as `{{ name }}`. And, `{{ name.first }}` and `{{ name.last }}` will be accessible.\n\n3. To extract array items, you can use the following schema:\n```json\n{\n \"type\": \"array\",\n \"title\": \"zipCodes\",\n \"items\": {\n \"type\": \"string\"\n }\n}\n```\n\nThis will be extracted as `{{ zipCodes }}`. To access the array items, you can use `{{ zipCodes[0] }}` and `{{ zipCodes[1] }}`.\n\n4. To extract array of objects, you can use the following schema:\n\n```json\n{\n \"type\": \"array\",\n \"name\": \"people\",\n \"items\": {\n \"type\": \"object\",\n \"properties\": {\n \"name\": {\n \"type\": \"string\"\n },\n \"age\": {\n \"type\": \"number\"\n },\n \"zipCodes\": {\n \"type\": \"array\",\n \"items\": {\n \"type\": \"string\"\n }\n }\n }\n }\n}\n```\n\nThis will be extracted as `{{ people }}`. To access the array items, you can use `{{ people[n].name }}`, `{{ people[n].age }}`, `{{ people[n].zipCodes }}`, `{{ people[n].zipCodes[0] }}` and `{{ people[n].zipCodes[1] }}`.", - "allOf": [ - { - "$ref": "#/components/schemas/JsonSchema" - } - ] - }, - "aliases": { - "description": "These are additional variables to create.\n\nThese will be accessible during the call as `{{key}}` and stored in `call.artifact.variableValues` after the call.\n\nExample:\n```json\n{\n \"aliases\": [\n {\n \"key\": \"customerName\",\n \"value\": \"{{name}}\"\n },\n {\n \"key\": \"fullName\",\n \"value\": \"{{firstName}} {{lastName}}\"\n },\n {\n \"key\": \"greeting\",\n \"value\": \"Hello {{name}}, welcome to {{company}}!\"\n },\n {\n \"key\": \"customerCity\",\n \"value\": \"{{addresses[0].city}}\"\n },\n {\n \"key\": \"something\",\n \"value\": \"{{any liquid}}\"\n }\n ]\n}\n```\n\nThis will create variables `customerName`, `fullName`, `greeting`, `customerCity`, and `something`. To access these variables, you can reference them as `{{customerName}}`, `{{fullName}}`, `{{greeting}}`, `{{customerCity}}`, and `{{something}}`.", - "type": "array", - "items": { - "$ref": "#/components/schemas/VariableExtractionAlias" - } - } - } - }, "ConversationNode": { "type": "object", "properties": { @@ -14978,6 +15326,10 @@ "$ref": "#/components/schemas/CreateGoogleSheetsRowAppendToolDTO", "title": "GoogleSheetsRowAppendTool" }, + { + "$ref": "#/components/schemas/CreateHandoffToolDTO", + "title": "HandoffTool" + }, { "$ref": "#/components/schemas/CreateMcpToolDTO", "title": "McpTool" @@ -15115,6 +15467,10 @@ "$ref": "#/components/schemas/CreateGoogleSheetsRowAppendToolDTO", "title": "GoogleSheetsRowAppendTool" }, + { + "$ref": "#/components/schemas/CreateHandoffToolDTO", + "title": "HandoffTool" + }, { "$ref": "#/components/schemas/CreateMcpToolDTO", "title": "McpTool" @@ -16620,6 +16976,10 @@ "$ref": "#/components/schemas/CreateGoogleSheetsRowAppendToolDTO", "title": "GoogleSheetsRowAppendTool" }, + { + "$ref": "#/components/schemas/CreateHandoffToolDTO", + "title": "HandoffTool" + }, { "$ref": "#/components/schemas/CreateMcpToolDTO", "title": "McpTool" @@ -16783,6 +17143,10 @@ "$ref": "#/components/schemas/CreateGoogleSheetsRowAppendToolDTO", "title": "GoogleSheetsRowAppendTool" }, + { + "$ref": "#/components/schemas/CreateHandoffToolDTO", + "title": "HandoffTool" + }, { "$ref": "#/components/schemas/CreateMcpToolDTO", "title": "McpTool" @@ -23162,6 +23526,10 @@ "$ref": "#/components/schemas/CreateGoogleSheetsRowAppendToolDTO", "title": "GoogleSheetsRowAppendTool" }, + { + "$ref": "#/components/schemas/CreateHandoffToolDTO", + "title": "HandoffTool" + }, { "$ref": "#/components/schemas/CreateMcpToolDTO", "title": "McpTool" @@ -23848,6 +24216,7 @@ "transcript[transcriptType=\"final\"]", "tool-calls", "transfer-destination-request", + "handoff-destination-request", "transfer-update", "user-interrupted", "voice-input", @@ -23866,9 +24235,10 @@ "status-update", "tool-calls", "transfer-destination-request", + "handoff-destination-request", "user-interrupted" ], - "description": "These are the messages that will be sent to your Server URL. Default is conversation-update,end-of-call-report,function-call,hang,speech-update,status-update,tool-calls,transfer-destination-request,user-interrupted. You can check the shape of the messages in ServerMessage schema.", + "description": "These are the messages that will be sent to your Server URL. Default is conversation-update,end-of-call-report,function-call,hang,speech-update,status-update,tool-calls,transfer-destination-request,handoff-destination-request,user-interrupted. You can check the shape of the messages in ServerMessage schema.", "items": { "type": "string", "enum": [ @@ -23886,6 +24256,7 @@ "transcript[transcriptType=\"final\"]", "tool-calls", "transfer-destination-request", + "handoff-destination-request", "transfer-update", "user-interrupted", "voice-input", @@ -24637,6 +25008,7 @@ "transcript[transcriptType=\"final\"]", "tool-calls", "transfer-destination-request", + "handoff-destination-request", "transfer-update", "user-interrupted", "voice-input", @@ -24655,9 +25027,10 @@ "status-update", "tool-calls", "transfer-destination-request", + "handoff-destination-request", "user-interrupted" ], - "description": "These are the messages that will be sent to your Server URL. Default is conversation-update,end-of-call-report,function-call,hang,speech-update,status-update,tool-calls,transfer-destination-request,user-interrupted. You can check the shape of the messages in ServerMessage schema.", + "description": "These are the messages that will be sent to your Server URL. Default is conversation-update,end-of-call-report,function-call,hang,speech-update,status-update,tool-calls,transfer-destination-request,handoff-destination-request,user-interrupted. You can check the shape of the messages in ServerMessage schema.", "items": { "type": "string", "enum": [ @@ -24675,6 +25048,7 @@ "transcript[transcriptType=\"final\"]", "tool-calls", "transfer-destination-request", + "handoff-destination-request", "transfer-update", "user-interrupted", "voice-input", @@ -27207,6 +27581,10 @@ "type": "string", "description": "This is an optional name for the participant", "maxLength": 40 + }, + "metadata": { + "type": "object", + "description": "This is an optional metadata for the message" } }, "required": [ @@ -27368,6 +27746,10 @@ "type": "string", "description": "This is an optional name for the participant", "maxLength": 40 + }, + "metadata": { + "type": "object", + "description": "This is an optional metadata for the message" } }, "required": [ @@ -27398,6 +27780,10 @@ "type": "string", "description": "This is an optional name for the participant", "maxLength": 40 + }, + "metadata": { + "type": "object", + "description": "This is an optional metadata for the message" } }, "required": [ @@ -29310,6 +29696,7 @@ "transcript[transcriptType=\"final\"]", "tool-calls", "transfer-destination-request", + "handoff-destination-request", "transfer-update", "user-interrupted", "voice-input", @@ -29328,9 +29715,10 @@ "status-update", "tool-calls", "transfer-destination-request", + "handoff-destination-request", "user-interrupted" ], - "description": "These are the messages that will be sent to your Server URL. Default is conversation-update,end-of-call-report,function-call,hang,speech-update,status-update,tool-calls,transfer-destination-request,user-interrupted. You can check the shape of the messages in ServerMessage schema.", + "description": "These are the messages that will be sent to your Server URL. Default is conversation-update,end-of-call-report,function-call,hang,speech-update,status-update,tool-calls,transfer-destination-request,handoff-destination-request,user-interrupted. You can check the shape of the messages in ServerMessage schema.", "items": { "type": "string", "enum": [ @@ -29348,6 +29736,7 @@ "transcript[transcriptType=\"final\"]", "tool-calls", "transfer-destination-request", + "handoff-destination-request", "transfer-update", "user-interrupted", "voice-input", @@ -30159,6 +30548,7 @@ "transcript[transcriptType=\"final\"]", "tool-calls", "transfer-destination-request", + "handoff-destination-request", "transfer-update", "user-interrupted", "voice-input", @@ -30177,9 +30567,10 @@ "status-update", "tool-calls", "transfer-destination-request", + "handoff-destination-request", "user-interrupted" ], - "description": "These are the messages that will be sent to your Server URL. Default is conversation-update,end-of-call-report,function-call,hang,speech-update,status-update,tool-calls,transfer-destination-request,user-interrupted. You can check the shape of the messages in ServerMessage schema.", + "description": "These are the messages that will be sent to your Server URL. Default is conversation-update,end-of-call-report,function-call,hang,speech-update,status-update,tool-calls,transfer-destination-request,handoff-destination-request,user-interrupted. You can check the shape of the messages in ServerMessage schema.", "items": { "type": "string", "enum": [ @@ -30197,6 +30588,7 @@ "transcript[transcriptType=\"final\"]", "tool-calls", "transfer-destination-request", + "handoff-destination-request", "transfer-update", "user-interrupted", "voice-input", @@ -32690,6 +33082,91 @@ "updatedAt" ] }, + "HandoffTool": { + "type": "object", + "properties": { + "messages": { + "type": "array", + "description": "These are the messages that will be spoken to the user as the tool is running.\n\nFor some tools, this is auto-filled based on special fields like `tool.destinations`. For others like the function tool, these can be custom configured.", + "items": { + "oneOf": [ + { + "$ref": "#/components/schemas/ToolMessageStart", + "title": "ToolMessageStart" + }, + { + "$ref": "#/components/schemas/ToolMessageComplete", + "title": "ToolMessageComplete" + }, + { + "$ref": "#/components/schemas/ToolMessageFailed", + "title": "ToolMessageFailed" + }, + { + "$ref": "#/components/schemas/ToolMessageDelayed", + "title": "ToolMessageDelayed" + } + ] + } + }, + "type": { + "type": "string", + "description": "This is the type of the tool.\nWhen you're using handoff tool, we recommend adding this to your system prompt\n---\n# System context\n\nYou are part of a multi-agent system designed to make agent coordination and execution easy. Agents uses two primary abstraction: **Agents** and **Handoffs**. An agent encompasses instructions and tools and can hand off a conversation to another agent when appropriate. Handoffs are achieved by calling a handoff function, generally named `handoff_to_`. Handoffs between agents are handled seamlessly in the background; do not mention or draw attention to these handoffs in your conversation with the user.\n\n# Agent context\n\n{put your agent system prompt here}\n---", + "enum": [ + "handoff" + ] + }, + "destinations": { + "type": "array", + "description": "These are the destinations that the call can be handed off to.\n\nUsage:\n1. Single destination\n\nUse `assistantId` to handoff the call to a saved assistant, or `assistantName` to handoff the call to an assistant in the same squad.\n\n```json\n{\n \"tools\": [\n {\n \"type\": \"handoff\",\n \"destinations\": [\n {\n \"type\": \"assistant\",\n \"assistantId\": \"assistant-123\", // or \"assistantName\": \"Assistant123\"\n \"description\": \"customer wants to be handed off to assistant-123\",\n \"contextEngineeringPlan\": {\n \"type\": \"all\"\n }\n }\n ],\n }\n ]\n}\n```\n\n2. Multiple destinations\n\n2.1. Multiple Tools, Each With One Destination (OpenAI recommended)\n\n```json\n{\n \"tools\": [\n {\n \"type\": \"handoff\",\n \"destinations\": [\n {\n \"type\": \"assistant\",\n \"assistantId\": \"assistant-123\",\n \"description\": \"customer wants to be handed off to assistant-123\",\n \"contextEngineeringPlan\": {\n \"type\": \"all\"\n }\n },\n ],\n },\n {\n \"type\": \"handoff\",\n \"destinations\": [\n {\n \"type\": \"assistant\",\n \"assistantId\": \"assistant-456\",\n \"description\": \"customer wants to be handed off to assistant-456\",\n \"contextEngineeringPlan\": {\n \"type\": \"all\"\n }\n }\n ],\n }\n ]\n}\n```\n\n2.2. One Tool, Multiple Destinations (Anthropic recommended)\n\n```json\n{\n \"tools\": [\n {\n \"type\": \"handoff\",\n \"destinations\": [\n {\n \"type\": \"assistant\",\n \"assistantId\": \"assistant-123\",\n \"description\": \"customer wants to be handed off to assistant-123\",\n \"contextEngineeringPlan\": {\n \"type\": \"all\"\n }\n },\n {\n \"type\": \"assistant\",\n \"assistantId\": \"assistant-456\",\n \"description\": \"customer wants to be handed off to assistant-456\",\n \"contextEngineeringPlan\": {\n \"type\": \"all\"\n }\n }\n ],\n }\n ]\n}\n```\n\n3. Dynamic destination\n\n3.1 To determine the destination dynamically, supply a `dynamic` handoff destination type and a `server` object.\n VAPI will send a handoff-destination-request webhook to the `server.url`.\n The response from the server will be used as the destination (if valid).\n\n```json\n{\n \"tools\": [\n {\n \"type\": \"handoff\",\n \"destinations\": [\n {\n \"type\": \"dynamic\",\n \"server\": {\n \"url\": \"https://example.com\"\n }\n }\n ],\n }\n ]\n}\n```\n\n3.2. To pass custom parameters to the server, you can use the `function` object.\n\n```json\n{\n \"tools\": [\n {\n \"type\": \"handoff\",\n \"destinations\": [\n {\n \"type\": \"dynamic\",\n \"server\": {\n \"url\": \"https://example.com\"\n },\n }\n ],\n \"function\": {\n \"type\": \"function\",\n \"name\": \"handoff\",\n \"description\": \"Call this function when the customer is ready to be handed off to the next assistant\",\n \"parameters\": {\n \"type\": \"object\",\n \"properties\": {\n \"destination\": {\n \"type\": \"string\",\n \"description\": \"Use dynamic when customer is ready to be handed off to the next assistant\",\n \"enum\": [\"dynamic\"]\n },\n \"customerAreaCode\": {\n \"type\": \"number\",\n \"description\": \"Area code of the customer\"\n },\n \"customerIntent\": {\n \"type\": \"string\",\n \"enum\": [\"new-customer\", \"existing-customer\"],\n \"description\": \"Use new-customer when customer is a new customer, existing-customer when customer is an existing customer\"\n },\n \"customerSentiment\": {\n \"type\": \"string\",\n \"enum\": [\"positive\", \"negative\", \"neutral\"],\n \"description\": \"Use positive when customer is happy, negative when customer is unhappy, neutral when customer is neutral\"\n }\n }\n }\n }\n }\n ]\n}\n```\n\nThe properties `customerAreaCode`, `customerIntent`, and `customerSentiment` will be passed to the server in the webhook request body.", + "items": { + "oneOf": [ + { + "$ref": "#/components/schemas/HandoffDestinationAssistant", + "title": "Assistant" + }, + { + "$ref": "#/components/schemas/HandoffDestinationDynamic", + "title": "Dynamic" + } + ] + } + }, + "id": { + "type": "string", + "description": "This is the unique identifier for the tool." + }, + "orgId": { + "type": "string", + "description": "This is the unique identifier for the organization that this tool belongs to." + }, + "createdAt": { + "format": "date-time", + "type": "string", + "description": "This is the ISO 8601 date-time string of when the tool was created." + }, + "updatedAt": { + "format": "date-time", + "type": "string", + "description": "This is the ISO 8601 date-time string of when the tool was last updated." + }, + "rejectionPlan": { + "description": "This is the plan to reject a tool call based on the conversation state.\n\n// Example 1: Reject endCall if user didn't say goodbye\n```json\n{\n conditions: [{\n type: 'regex',\n regex: '(?i)\\\\b(bye|goodbye|farewell|see you later|take care)\\\\b',\n target: { position: -1, role: 'user' },\n negate: true // Reject if pattern does NOT match\n }]\n}\n```\n\n// Example 2: Reject transfer if user is actually asking a question\n```json\n{\n conditions: [{\n type: 'regex',\n regex: '\\\\?',\n target: { position: -1, role: 'user' }\n }]\n}\n```\n\n// Example 3: Reject transfer if user didn't mention transfer recently\n```json\n{\n conditions: [{\n type: 'liquid',\n liquid: `{% assign recentMessages = messages | last: 5 %}\n{% assign userMessages = recentMessages | where: 'role', 'user' %}\n{% assign mentioned = false %}\n{% for msg in userMessages %}\n {% if msg.content contains 'transfer' or msg.content contains 'connect' or msg.content contains 'speak to' %}\n {% assign mentioned = true %}\n {% break %}\n {% endif %}\n{% endfor %}\n{% if mentioned %}\n false\n{% else %}\n true\n{% endif %}`\n }]\n}\n```\n\n// Example 4: Reject endCall if the bot is looping and trying to exit\n```json\n{\n conditions: [{\n type: 'liquid',\n liquid: `{% assign recentMessages = messages | last: 6 %}\n{% assign userMessages = recentMessages | where: 'role', 'user' | reverse %}\n{% if userMessages.size < 3 %}\n false\n{% else %}\n {% assign msg1 = userMessages[0].content | downcase %}\n {% assign msg2 = userMessages[1].content | downcase %}\n {% assign msg3 = userMessages[2].content | downcase %}\n {% comment %} Check for repetitive messages {% endcomment %}\n {% if msg1 == msg2 or msg1 == msg3 or msg2 == msg3 %}\n true\n {% comment %} Check for common loop phrases {% endcomment %}\n {% elsif msg1 contains 'cool thanks' or msg2 contains 'cool thanks' or msg3 contains 'cool thanks' %}\n true\n {% elsif msg1 contains 'okay thanks' or msg2 contains 'okay thanks' or msg3 contains 'okay thanks' %}\n true\n {% elsif msg1 contains 'got it' or msg2 contains 'got it' or msg3 contains 'got it' %}\n true\n {% else %}\n false\n {% endif %}\n{% endif %}`\n }]\n}\n```", + "allOf": [ + { + "$ref": "#/components/schemas/ToolRejectionPlan" + } + ] + } + }, + "required": [ + "type", + "id", + "orgId", + "createdAt", + "updatedAt" + ] + }, "OutputTool": { "type": "object", "properties": { @@ -34582,6 +35059,59 @@ } } }, + "UpdateHandoffToolDTO": { + "type": "object", + "properties": { + "messages": { + "type": "array", + "description": "These are the messages that will be spoken to the user as the tool is running.\n\nFor some tools, this is auto-filled based on special fields like `tool.destinations`. For others like the function tool, these can be custom configured.", + "items": { + "oneOf": [ + { + "$ref": "#/components/schemas/ToolMessageStart", + "title": "ToolMessageStart" + }, + { + "$ref": "#/components/schemas/ToolMessageComplete", + "title": "ToolMessageComplete" + }, + { + "$ref": "#/components/schemas/ToolMessageFailed", + "title": "ToolMessageFailed" + }, + { + "$ref": "#/components/schemas/ToolMessageDelayed", + "title": "ToolMessageDelayed" + } + ] + } + }, + "destinations": { + "type": "array", + "description": "These are the destinations that the call can be handed off to.\n\nUsage:\n1. Single destination\n\nUse `assistantId` to handoff the call to a saved assistant, or `assistantName` to handoff the call to an assistant in the same squad.\n\n```json\n{\n \"tools\": [\n {\n \"type\": \"handoff\",\n \"destinations\": [\n {\n \"type\": \"assistant\",\n \"assistantId\": \"assistant-123\", // or \"assistantName\": \"Assistant123\"\n \"description\": \"customer wants to be handed off to assistant-123\",\n \"contextEngineeringPlan\": {\n \"type\": \"all\"\n }\n }\n ],\n }\n ]\n}\n```\n\n2. Multiple destinations\n\n2.1. Multiple Tools, Each With One Destination (OpenAI recommended)\n\n```json\n{\n \"tools\": [\n {\n \"type\": \"handoff\",\n \"destinations\": [\n {\n \"type\": \"assistant\",\n \"assistantId\": \"assistant-123\",\n \"description\": \"customer wants to be handed off to assistant-123\",\n \"contextEngineeringPlan\": {\n \"type\": \"all\"\n }\n },\n ],\n },\n {\n \"type\": \"handoff\",\n \"destinations\": [\n {\n \"type\": \"assistant\",\n \"assistantId\": \"assistant-456\",\n \"description\": \"customer wants to be handed off to assistant-456\",\n \"contextEngineeringPlan\": {\n \"type\": \"all\"\n }\n }\n ],\n }\n ]\n}\n```\n\n2.2. One Tool, Multiple Destinations (Anthropic recommended)\n\n```json\n{\n \"tools\": [\n {\n \"type\": \"handoff\",\n \"destinations\": [\n {\n \"type\": \"assistant\",\n \"assistantId\": \"assistant-123\",\n \"description\": \"customer wants to be handed off to assistant-123\",\n \"contextEngineeringPlan\": {\n \"type\": \"all\"\n }\n },\n {\n \"type\": \"assistant\",\n \"assistantId\": \"assistant-456\",\n \"description\": \"customer wants to be handed off to assistant-456\",\n \"contextEngineeringPlan\": {\n \"type\": \"all\"\n }\n }\n ],\n }\n ]\n}\n```\n\n3. Dynamic destination\n\n3.1 To determine the destination dynamically, supply a `dynamic` handoff destination type and a `server` object.\n VAPI will send a handoff-destination-request webhook to the `server.url`.\n The response from the server will be used as the destination (if valid).\n\n```json\n{\n \"tools\": [\n {\n \"type\": \"handoff\",\n \"destinations\": [\n {\n \"type\": \"dynamic\",\n \"server\": {\n \"url\": \"https://example.com\"\n }\n }\n ],\n }\n ]\n}\n```\n\n3.2. To pass custom parameters to the server, you can use the `function` object.\n\n```json\n{\n \"tools\": [\n {\n \"type\": \"handoff\",\n \"destinations\": [\n {\n \"type\": \"dynamic\",\n \"server\": {\n \"url\": \"https://example.com\"\n },\n }\n ],\n \"function\": {\n \"type\": \"function\",\n \"name\": \"handoff\",\n \"description\": \"Call this function when the customer is ready to be handed off to the next assistant\",\n \"parameters\": {\n \"type\": \"object\",\n \"properties\": {\n \"destination\": {\n \"type\": \"string\",\n \"description\": \"Use dynamic when customer is ready to be handed off to the next assistant\",\n \"enum\": [\"dynamic\"]\n },\n \"customerAreaCode\": {\n \"type\": \"number\",\n \"description\": \"Area code of the customer\"\n },\n \"customerIntent\": {\n \"type\": \"string\",\n \"enum\": [\"new-customer\", \"existing-customer\"],\n \"description\": \"Use new-customer when customer is a new customer, existing-customer when customer is an existing customer\"\n },\n \"customerSentiment\": {\n \"type\": \"string\",\n \"enum\": [\"positive\", \"negative\", \"neutral\"],\n \"description\": \"Use positive when customer is happy, negative when customer is unhappy, neutral when customer is neutral\"\n }\n }\n }\n }\n }\n ]\n}\n```\n\nThe properties `customerAreaCode`, `customerIntent`, and `customerSentiment` will be passed to the server in the webhook request body.", + "items": { + "oneOf": [ + { + "$ref": "#/components/schemas/HandoffDestinationAssistant", + "title": "Assistant" + }, + { + "$ref": "#/components/schemas/HandoffDestinationDynamic", + "title": "Dynamic" + } + ] + } + }, + "rejectionPlan": { + "description": "This is the plan to reject a tool call based on the conversation state.\n\n// Example 1: Reject endCall if user didn't say goodbye\n```json\n{\n conditions: [{\n type: 'regex',\n regex: '(?i)\\\\b(bye|goodbye|farewell|see you later|take care)\\\\b',\n target: { position: -1, role: 'user' },\n negate: true // Reject if pattern does NOT match\n }]\n}\n```\n\n// Example 2: Reject transfer if user is actually asking a question\n```json\n{\n conditions: [{\n type: 'regex',\n regex: '\\\\?',\n target: { position: -1, role: 'user' }\n }]\n}\n```\n\n// Example 3: Reject transfer if user didn't mention transfer recently\n```json\n{\n conditions: [{\n type: 'liquid',\n liquid: `{% assign recentMessages = messages | last: 5 %}\n{% assign userMessages = recentMessages | where: 'role', 'user' %}\n{% assign mentioned = false %}\n{% for msg in userMessages %}\n {% if msg.content contains 'transfer' or msg.content contains 'connect' or msg.content contains 'speak to' %}\n {% assign mentioned = true %}\n {% break %}\n {% endif %}\n{% endfor %}\n{% if mentioned %}\n false\n{% else %}\n true\n{% endif %}`\n }]\n}\n```\n\n// Example 4: Reject endCall if the bot is looping and trying to exit\n```json\n{\n conditions: [{\n type: 'liquid',\n liquid: `{% assign recentMessages = messages | last: 6 %}\n{% assign userMessages = recentMessages | where: 'role', 'user' | reverse %}\n{% if userMessages.size < 3 %}\n false\n{% else %}\n {% assign msg1 = userMessages[0].content | downcase %}\n {% assign msg2 = userMessages[1].content | downcase %}\n {% assign msg3 = userMessages[2].content | downcase %}\n {% comment %} Check for repetitive messages {% endcomment %}\n {% if msg1 == msg2 or msg1 == msg3 or msg2 == msg3 %}\n true\n {% comment %} Check for common loop phrases {% endcomment %}\n {% elsif msg1 contains 'cool thanks' or msg2 contains 'cool thanks' or msg3 contains 'cool thanks' %}\n true\n {% elsif msg1 contains 'okay thanks' or msg2 contains 'okay thanks' or msg3 contains 'okay thanks' %}\n true\n {% elsif msg1 contains 'got it' or msg2 contains 'got it' or msg3 contains 'got it' %}\n true\n {% else %}\n false\n {% endif %}\n{% endif %}`\n }]\n}\n```", + "allOf": [ + { + "$ref": "#/components/schemas/ToolRejectionPlan" + } + ] + } + } + }, "UpdateTransferCallToolDTO": { "type": "object", "properties": { @@ -43304,6 +43834,10 @@ "$ref": "#/components/schemas/CreateGoogleSheetsRowAppendToolDTO", "title": "GoogleSheetsRowAppendTool" }, + { + "$ref": "#/components/schemas/CreateHandoffToolDTO", + "title": "HandoffTool" + }, { "$ref": "#/components/schemas/CreateMcpToolDTO", "title": "McpTool" @@ -43463,6 +43997,10 @@ "$ref": "#/components/schemas/CreateGoogleSheetsRowAppendToolDTO", "title": "GoogleSheetsRowAppendTool" }, + { + "$ref": "#/components/schemas/CreateHandoffToolDTO", + "title": "HandoffTool" + }, { "$ref": "#/components/schemas/CreateMcpToolDTO", "title": "McpTool" @@ -43644,6 +44182,10 @@ "$ref": "#/components/schemas/CreateGoogleSheetsRowAppendToolDTO", "title": "GoogleSheetsRowAppendTool" }, + { + "$ref": "#/components/schemas/CreateHandoffToolDTO", + "title": "HandoffTool" + }, { "$ref": "#/components/schemas/CreateMcpToolDTO", "title": "McpTool" @@ -49321,6 +49863,22 @@ } } }, + "ServerMessageResponseHandoffDestinationRequest": { + "type": "object", + "properties": { + "destination": { + "description": "This is the destination you'd like the call to be transferred to.", + "allOf": [ + { + "$ref": "#/components/schemas/HandoffDestinationAssistant" + } + ] + } + }, + "required": [ + "destination" + ] + }, "KnowledgeBaseResponseDocument": { "type": "object", "properties": { @@ -49503,6 +50061,10 @@ "$ref": "#/components/schemas/ServerMessageResponseAssistantRequest", "title": "AssistantRequest" }, + { + "$ref": "#/components/schemas/ServerMessageResponseHandoffDestinationRequest", + "title": "HandoffDestinationRequest" + }, { "$ref": "#/components/schemas/ServerMessageResponseKnowledgeBaseRequest", "title": "KnowledgeBaseRequest"