diff --git a/fern/apis/api/openapi.json b/fern/apis/api/openapi.json index 91508f86..7d637393 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,197 @@ "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" + ] + }, + "HandoffDestinationAssistant": { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "assistant" + ] + }, + "contextEngineeringPlan": { + "type": "array", + "description": "This is the plan for manipulating the message context before handing off the call to the next assistant.", + "items": { + "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" + } + ] + }, + "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 +12287,10 @@ "$ref": "#/components/schemas/CreateGoogleSheetsRowAppendToolDTO", "title": "GoogleSheetsRowAppendTool" }, + { + "$ref": "#/components/schemas/CreateHandoffToolDTO", + "title": "HandoffTool" + }, { "$ref": "#/components/schemas/CreateMcpToolDTO", "title": "McpTool" @@ -12168,6 +12463,10 @@ "$ref": "#/components/schemas/CreateGoogleSheetsRowAppendToolDTO", "title": "GoogleSheetsRowAppendTool" }, + { + "$ref": "#/components/schemas/CreateHandoffToolDTO", + "title": "HandoffTool" + }, { "$ref": "#/components/schemas/CreateMcpToolDTO", "title": "McpTool" @@ -12339,6 +12638,10 @@ "$ref": "#/components/schemas/CreateGoogleSheetsRowAppendToolDTO", "title": "GoogleSheetsRowAppendTool" }, + { + "$ref": "#/components/schemas/CreateHandoffToolDTO", + "title": "HandoffTool" + }, { "$ref": "#/components/schemas/CreateMcpToolDTO", "title": "McpTool" @@ -12494,6 +12797,10 @@ "$ref": "#/components/schemas/CreateGoogleSheetsRowAppendToolDTO", "title": "GoogleSheetsRowAppendTool" }, + { + "$ref": "#/components/schemas/CreateHandoffToolDTO", + "title": "HandoffTool" + }, { "$ref": "#/components/schemas/CreateMcpToolDTO", "title": "McpTool" @@ -12676,6 +12983,10 @@ "$ref": "#/components/schemas/CreateGoogleSheetsRowAppendToolDTO", "title": "GoogleSheetsRowAppendTool" }, + { + "$ref": "#/components/schemas/CreateHandoffToolDTO", + "title": "HandoffTool" + }, { "$ref": "#/components/schemas/CreateMcpToolDTO", "title": "McpTool" @@ -12827,6 +13138,10 @@ "$ref": "#/components/schemas/CreateGoogleSheetsRowAppendToolDTO", "title": "GoogleSheetsRowAppendTool" }, + { + "$ref": "#/components/schemas/CreateHandoffToolDTO", + "title": "HandoffTool" + }, { "$ref": "#/components/schemas/CreateMcpToolDTO", "title": "McpTool" @@ -13051,6 +13366,10 @@ "$ref": "#/components/schemas/CreateGoogleSheetsRowAppendToolDTO", "title": "GoogleSheetsRowAppendTool" }, + { + "$ref": "#/components/schemas/CreateHandoffToolDTO", + "title": "HandoffTool" + }, { "$ref": "#/components/schemas/CreateMcpToolDTO", "title": "McpTool" @@ -13226,6 +13545,10 @@ "$ref": "#/components/schemas/CreateGoogleSheetsRowAppendToolDTO", "title": "GoogleSheetsRowAppendTool" }, + { + "$ref": "#/components/schemas/CreateHandoffToolDTO", + "title": "HandoffTool" + }, { "$ref": "#/components/schemas/CreateMcpToolDTO", "title": "McpTool" @@ -13393,6 +13716,10 @@ "$ref": "#/components/schemas/CreateGoogleSheetsRowAppendToolDTO", "title": "GoogleSheetsRowAppendTool" }, + { + "$ref": "#/components/schemas/CreateHandoffToolDTO", + "title": "HandoffTool" + }, { "$ref": "#/components/schemas/CreateMcpToolDTO", "title": "McpTool" @@ -13547,6 +13874,10 @@ "$ref": "#/components/schemas/CreateGoogleSheetsRowAppendToolDTO", "title": "GoogleSheetsRowAppendTool" }, + { + "$ref": "#/components/schemas/CreateHandoffToolDTO", + "title": "HandoffTool" + }, { "$ref": "#/components/schemas/CreateMcpToolDTO", "title": "McpTool" @@ -14012,6 +14343,10 @@ "$ref": "#/components/schemas/CreateGoogleSheetsRowAppendToolDTO", "title": "GoogleSheetsRowAppendTool" }, + { + "$ref": "#/components/schemas/CreateHandoffToolDTO", + "title": "HandoffTool" + }, { "$ref": "#/components/schemas/CreateMcpToolDTO", "title": "McpTool" @@ -14163,6 +14498,10 @@ "$ref": "#/components/schemas/CreateGoogleSheetsRowAppendToolDTO", "title": "GoogleSheetsRowAppendTool" }, + { + "$ref": "#/components/schemas/CreateHandoffToolDTO", + "title": "HandoffTool" + }, { "$ref": "#/components/schemas/CreateMcpToolDTO", "title": "McpTool" @@ -14314,6 +14653,10 @@ "$ref": "#/components/schemas/CreateGoogleSheetsRowAppendToolDTO", "title": "GoogleSheetsRowAppendTool" }, + { + "$ref": "#/components/schemas/CreateHandoffToolDTO", + "title": "HandoffTool" + }, { "$ref": "#/components/schemas/CreateMcpToolDTO", "title": "McpTool" @@ -14978,6 +15321,10 @@ "$ref": "#/components/schemas/CreateGoogleSheetsRowAppendToolDTO", "title": "GoogleSheetsRowAppendTool" }, + { + "$ref": "#/components/schemas/CreateHandoffToolDTO", + "title": "HandoffTool" + }, { "$ref": "#/components/schemas/CreateMcpToolDTO", "title": "McpTool" @@ -15115,6 +15462,10 @@ "$ref": "#/components/schemas/CreateGoogleSheetsRowAppendToolDTO", "title": "GoogleSheetsRowAppendTool" }, + { + "$ref": "#/components/schemas/CreateHandoffToolDTO", + "title": "HandoffTool" + }, { "$ref": "#/components/schemas/CreateMcpToolDTO", "title": "McpTool" @@ -16620,6 +16971,10 @@ "$ref": "#/components/schemas/CreateGoogleSheetsRowAppendToolDTO", "title": "GoogleSheetsRowAppendTool" }, + { + "$ref": "#/components/schemas/CreateHandoffToolDTO", + "title": "HandoffTool" + }, { "$ref": "#/components/schemas/CreateMcpToolDTO", "title": "McpTool" @@ -16783,6 +17138,10 @@ "$ref": "#/components/schemas/CreateGoogleSheetsRowAppendToolDTO", "title": "GoogleSheetsRowAppendTool" }, + { + "$ref": "#/components/schemas/CreateHandoffToolDTO", + "title": "HandoffTool" + }, { "$ref": "#/components/schemas/CreateMcpToolDTO", "title": "McpTool" @@ -23162,6 +23521,10 @@ "$ref": "#/components/schemas/CreateGoogleSheetsRowAppendToolDTO", "title": "GoogleSheetsRowAppendTool" }, + { + "$ref": "#/components/schemas/CreateHandoffToolDTO", + "title": "HandoffTool" + }, { "$ref": "#/components/schemas/CreateMcpToolDTO", "title": "McpTool" @@ -23848,6 +24211,7 @@ "transcript[transcriptType=\"final\"]", "tool-calls", "transfer-destination-request", + "handoff-destination-request", "transfer-update", "user-interrupted", "voice-input", @@ -23866,9 +24230,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 +24251,7 @@ "transcript[transcriptType=\"final\"]", "tool-calls", "transfer-destination-request", + "handoff-destination-request", "transfer-update", "user-interrupted", "voice-input", @@ -24637,6 +25003,7 @@ "transcript[transcriptType=\"final\"]", "tool-calls", "transfer-destination-request", + "handoff-destination-request", "transfer-update", "user-interrupted", "voice-input", @@ -24655,9 +25022,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 +25043,7 @@ "transcript[transcriptType=\"final\"]", "tool-calls", "transfer-destination-request", + "handoff-destination-request", "transfer-update", "user-interrupted", "voice-input", @@ -29310,6 +29679,7 @@ "transcript[transcriptType=\"final\"]", "tool-calls", "transfer-destination-request", + "handoff-destination-request", "transfer-update", "user-interrupted", "voice-input", @@ -29328,9 +29698,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 +29719,7 @@ "transcript[transcriptType=\"final\"]", "tool-calls", "transfer-destination-request", + "handoff-destination-request", "transfer-update", "user-interrupted", "voice-input", @@ -30159,6 +30531,7 @@ "transcript[transcriptType=\"final\"]", "tool-calls", "transfer-destination-request", + "handoff-destination-request", "transfer-update", "user-interrupted", "voice-input", @@ -30177,9 +30550,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 +30571,7 @@ "transcript[transcriptType=\"final\"]", "tool-calls", "transfer-destination-request", + "handoff-destination-request", "transfer-update", "user-interrupted", "voice-input", @@ -32690,6 +33065,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 +35042,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 +43817,10 @@ "$ref": "#/components/schemas/CreateGoogleSheetsRowAppendToolDTO", "title": "GoogleSheetsRowAppendTool" }, + { + "$ref": "#/components/schemas/CreateHandoffToolDTO", + "title": "HandoffTool" + }, { "$ref": "#/components/schemas/CreateMcpToolDTO", "title": "McpTool" @@ -43463,6 +43980,10 @@ "$ref": "#/components/schemas/CreateGoogleSheetsRowAppendToolDTO", "title": "GoogleSheetsRowAppendTool" }, + { + "$ref": "#/components/schemas/CreateHandoffToolDTO", + "title": "HandoffTool" + }, { "$ref": "#/components/schemas/CreateMcpToolDTO", "title": "McpTool" @@ -43644,6 +44165,10 @@ "$ref": "#/components/schemas/CreateGoogleSheetsRowAppendToolDTO", "title": "GoogleSheetsRowAppendTool" }, + { + "$ref": "#/components/schemas/CreateHandoffToolDTO", + "title": "HandoffTool" + }, { "$ref": "#/components/schemas/CreateMcpToolDTO", "title": "McpTool" @@ -49321,6 +49846,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 +50044,10 @@ "$ref": "#/components/schemas/ServerMessageResponseAssistantRequest", "title": "AssistantRequest" }, + { + "$ref": "#/components/schemas/ServerMessageResponseHandoffDestinationRequest", + "title": "HandoffDestinationRequest" + }, { "$ref": "#/components/schemas/ServerMessageResponseKnowledgeBaseRequest", "title": "KnowledgeBaseRequest"