From edf537db814e349c4ee825b2e90f1fcabde06af1 Mon Sep 17 00:00:00 2001 From: zachm-vapi <276893101+zachm-vapi@users.noreply.github.com> Date: Fri, 30 Oct 2026 15:45:12 -0700 Subject: [PATCH] Regenerate API and remove Tavus support Tavus was removed from Vapi, so its no longer in the API, which broke type checks --- api.ts | 11425 +++++++++++++++++++++++++++++------------------------- vapi.ts | 22 +- 2 files changed, 6198 insertions(+), 5249 deletions(-) diff --git a/api.ts b/api.ts index 32c04979e..cb911e324 100644 --- a/api.ts +++ b/api.ts @@ -906,6 +906,16 @@ export interface DeepgramTranscriber { * @example 0.4 */ confidenceThreshold?: number; + /** + * Controls whether Vapi filters user transcripts that repeat text from the + * assistant's recent transcript. Disable this only when legitimate caller + * responses are being mistaken for assistant audio feedback. + * + * @default true + * @default true + * @example true + */ + feedbackFilterEnabled?: boolean; /** * End-of-turn confidence required to finish a turn. Only used with Flux models. * @@ -3504,6 +3514,16 @@ export interface FallbackDeepgramTranscriber { * @example 0.4 */ confidenceThreshold?: number; + /** + * Controls whether Vapi filters user transcripts that repeat text from the + * assistant's recent transcript. Disable this only when legitimate caller + * responses are being mistaken for assistant audio feedback. + * + * @default true + * @default true + * @example true + */ + feedbackFilterEnabled?: boolean; /** * End-of-turn confidence required to finish a turn. Only used with Flux models. * @@ -6912,7 +6932,6 @@ export interface TransferAssistant { | WellSaidVoice | RimeAIVoice | SmallestAIVoice - | TavusVoice | VapiVoice | SesameVoice | InworldVoice @@ -6980,6 +6999,19 @@ export interface TransferAssistant { * @example 120 */ maxDurationSeconds?: number; + /** + * This decides whether the transfer assistant runs the main assistant's hooks on the operator leg of a `warm-transfer-experimental` transfer. The operator is the "customer" there. When unset or `true`, the transfer assistant runs all of the main assistant's hooks, plus `hooks`. When `false`, it runs only `hooks`, plus the main assistant's `call.ending` hooks. An `endCall` in an inherited `customer.speech.timeout` hook ends the whole call when the operator is silent, so set this to `false` to stop that. + * @default true + */ + assistantHooksInheritEnabled?: boolean; + /** These are the hooks the transfer assistant runs on the operator leg of a `warm-transfer-experimental` transfer. The operator is the "customer" there, so `customer.speech.timeout` fires on operator silence. Whether the main assistant's other hooks also run on the operator leg depends on `assistantHooksInheritEnabled`. These hooks run after them. `call.ending` and `call.timeElapsed` are not allowed here. The main assistant's `call.ending` hooks are kept automatically. Time-elapsed hooks are not armed on the operator leg. An `endCall` tool in these hooks ends the whole call, not only the operator leg. A `tool` action must carry an inline `tool`, because `toolId` is not resolved for the transfer assistant. */ + hooks?: ( + | CallHookAssistantSpeechInterrupted + | CallHookCustomerSpeechInterrupted + | CallHookCustomerSpeechTimeout + | CallHookModelResponseTimeout + | CallHookTranscriberEndpointedSpeechLowConfidence + )[]; /** * This enables filtering of noise and background speech while the user is talking. * @@ -7630,2307 +7662,1749 @@ export interface ContextEngineeringPlanPreviousAssistantMessages { type: "previousAssistantMessages"; } -export interface HandoffDestinationAssistant { - type: "assistant"; - /** This is the plan for manipulating the message context before handing off the call to the next assistant. */ - contextEngineeringPlan?: - | ContextEngineeringPlanLastNMessages - | ContextEngineeringPlanNone - | ContextEngineeringPlanAll - | ContextEngineeringPlanUserAndAssistantMessages - | ContextEngineeringPlanPreviousAssistantMessages; - /** This is the assistant to transfer the call to. You must provide either assistantName or assistantId. */ - assistantName?: string; - /** This is the assistant id to transfer the call to. You must provide either assistantName or assistantId. */ - assistantId?: string; - /** 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. */ - assistant?: CreateAssistantDTO; - /** This is the variable extraction plan for the handoff tool. */ - variableExtractionPlan?: VariableExtractionPlan; - /** These are the assistant overrides to apply to the destination assistant. */ - assistantOverrides?: AssistantOverrides; - /** This is the description of the destination, used by the AI to choose when and how to transfer the call. */ - description?: string; -} - -export interface HandoffDestinationDynamic { - type: "dynamic"; +export interface RecordingConsentPlanStayOnLine { /** - * This is where Vapi will send the handoff-destination-request webhook in a dynamic handoff. + * This is the message asking for consent to record the call. + * If the type is `stay-on-line`, the message should ask the user to hang up if they do not consent. + * If the type is `verbal`, the message should ask the user to verbally consent or decline. + * @maxLength 1000 + */ + message: string; + /** + * This is the voice to use for the consent message. If not specified, inherits from the assistant's voice. + * Use a different voice for the consent message for a better user experience. + */ + voice?: + | AzureVoice + | CartesiaVoice + | CustomVoice + | DeepgramVoice + | ElevenLabsVoice + | HumeVoice + | LMNTVoice + | NeuphonicVoice + | OpenAIVoice + | PlayHTVoice + | WellSaidVoice + | RimeAIVoice + | SmallestAIVoice + | VapiVoice + | SesameVoice + | InworldVoice + | MinimaxVoice + | XaiVoice + | MicrosoftVoice; + /** + * This controls whether the consent assistant speaks first or waits for the caller to speak first. * - * The order of precedence is: + * Use: + * - `assistant-speaks-first` (default) to have the consent assistant play the consent message as soon as the call is answered. + * - `assistant-waits-for-user` to have the consent assistant wait for the caller to speak before playing the consent message. * - * 1. tool.server.url - * 2. assistant.server.url - * 3. phoneNumber.server.url - * 4. org.server.url + * We strongly recommend `assistant-waits-for-user` for outbound calls. Some telephony providers signal "answered" while the line is still ringing, which can cause the consent message to play into a ringing line and be missed by the caller. Waiting for the caller to speak first guarantees they hear the full consent message. + * + * Note: when combined with `type: 'stay-on-line'`, silence only counts toward consent after the caller has spoken at least once. + * + * @default 'assistant-speaks-first' + * @default "assistant-speaks-first" + * @example "assistant-speaks-first" */ - server?: Server; - /** This is the description of the destination, used by the AI to choose when and how to transfer the call. */ - description?: string; -} - -export interface SquadMemberDTO { + firstMessageMode?: "assistant-speaks-first" | "assistant-waits-for-user"; /** - * This is the assistant version (e.g. `v3`) to pin for this squad member. When set, the call uses - * the snapshot from `assistant_version` (by `(assistantId, version)`) instead of the latest. Valid - * only with `assistantId`; rejected with inline `assistant`. Omit to follow the latest version. + * This is the type of recording consent plan. This type assumes consent is granted if the user stays on the line. + * @example "stay-on-line" */ - assistantVersion?: string | null; - assistantDestinations?: ( - | TransferDestinationAssistant - | HandoffDestinationAssistant - )[]; - /** This is the assistant that will be used for the call. To use a transient assistant, use `assistant` instead. */ - assistantId?: string | null; - /** This is the assistant that will be used for the call. To use an existing assistant, use `assistantId` instead. */ - assistant?: CreateAssistantDTO; - /** This can be used to override the assistant's settings and provide values for it's template variables. */ - assistantOverrides?: AssistantOverrides; + type: "stay-on-line"; + /** + * Number of seconds to wait before transferring to the assistant if user stays on the call + * @min 1 + * @max 6 + * @default 3 + * @example 3 + */ + waitSeconds?: number; } -export interface CreateSquadDTO { - /** This is the name of the squad. */ - name?: string; +export interface RecordingConsentPlanVerbal { /** - * This is the list of assistants that make up the squad. - * - * The call will start with the first assistant in the list. + * This is the message asking for consent to record the call. + * If the type is `stay-on-line`, the message should ask the user to hang up if they do not consent. + * If the type is `verbal`, the message should ask the user to verbally consent or decline. + * @maxLength 1000 */ - members: SquadMemberDTO[]; + message: string; /** - * This can be used to override all the assistants' settings and provide values for their template variables. + * This is the voice to use for the consent message. If not specified, inherits from the assistant's voice. + * Use a different voice for the consent message for a better user experience. + */ + voice?: + | AzureVoice + | CartesiaVoice + | CustomVoice + | DeepgramVoice + | ElevenLabsVoice + | HumeVoice + | LMNTVoice + | NeuphonicVoice + | OpenAIVoice + | PlayHTVoice + | WellSaidVoice + | RimeAIVoice + | SmallestAIVoice + | VapiVoice + | SesameVoice + | InworldVoice + | MinimaxVoice + | XaiVoice + | MicrosoftVoice; + /** + * This controls whether the consent assistant speaks first or waits for the caller to speak first. * - * Both `membersOverrides` and `members[n].assistantOverrides` can be used together. First, `members[n].assistantOverrides` is applied. Then, `membersOverrides` is applied as a global override. + * Use: + * - `assistant-speaks-first` (default) to have the consent assistant play the consent message as soon as the call is answered. + * - `assistant-waits-for-user` to have the consent assistant wait for the caller to speak before playing the consent message. + * + * We strongly recommend `assistant-waits-for-user` for outbound calls. Some telephony providers signal "answered" while the line is still ringing, which can cause the consent message to play into a ringing line and be missed by the caller. Waiting for the caller to speak first guarantees they hear the full consent message. + * + * Note: when combined with `type: 'stay-on-line'`, silence only counts toward consent after the caller has spoken at least once. + * + * @default 'assistant-speaks-first' + * @default "assistant-speaks-first" + * @example "assistant-speaks-first" */ - membersOverrides?: AssistantOverrides; + firstMessageMode?: "assistant-speaks-first" | "assistant-waits-for-user"; + /** + * This is the type of recording consent plan. This type assumes consent is granted if the user verbally consents or declines. + * @example "verbal" + */ + type: "verbal"; + /** Tool to execute if user verbally declines recording consent */ + declineTool?: object; + /** ID of existing tool to execute if user verbally declines recording consent */ + declineToolId?: string; } -export interface HandoffDestinationSquad { - type: "squad"; - /** This is the plan for manipulating the message context before handing off the call to the squad. */ - contextEngineeringPlan?: - | ContextEngineeringPlanLastNMessages - | ContextEngineeringPlanNone - | ContextEngineeringPlanAll - | ContextEngineeringPlanUserAndAssistantMessages - | ContextEngineeringPlanPreviousAssistantMessages; - /** This is the squad id to transfer the call to. */ - squadId?: string; - /** This is a transient squad to transfer the call to. */ - squad?: CreateSquadDTO; +export type SecurityFilterBase = object; + +export interface SecurityFilterPlan { /** - * This is the name of the entry assistant to start with when handing off to the squad. - * If not provided, the first member of the squad will be used. + * Whether the security filter is enabled. + * @default false + * @default false */ - entryAssistantName?: string; - /** This is the variable extraction plan for the handoff tool. */ - variableExtractionPlan?: VariableExtractionPlan; + enabled?: boolean; /** - * These are the overrides to apply to the squad configuration. - * Maps to squad-level membersOverrides. + * Array of security filter types to apply. + * If array is not empty, only those security filters are run. + * @example "[{ type: "sql-injection" }, { type: "xss" }]" */ - squadOverrides?: AssistantOverrides; - /** This is the description of the destination, used by the AI to choose when and how to transfer the call. */ - description?: string; + filters?: SecurityFilterBase[]; + /** + * Mode of operation when a security threat is detected. + * - 'sanitize': Remove or replace the threatening content + * - 'reject': Replace the entire transcript with replacement text + * - 'replace': Replace threatening patterns with replacement text + * @default 'sanitize' + * @default "sanitize" + */ + mode?: "sanitize" | "reject" | "replace"; + /** + * Text to use when replacing filtered content. + * @default '[FILTERED]' + * @default "[FILTERED]" + */ + replacementText?: string; } -export interface CreateHandoffToolDTO { - /** Messages spoken while the tool is running. Multiple request-start messages are variants. For request-response-delayed, same timing means variants and different timings mean staged updates. */ - messages?: ( - | ToolMessageStart - | ToolMessageComplete - | ToolMessageFailed - | ToolMessageDelayed - )[]; +export interface CompliancePlan { + /** When this is enabled, logs, recordings, and transcriptions will be stored in HIPAA-compliant storage. Defaults to false. Only HIPAA-compliant providers will be available for LLM, Voice, and Transcriber respectively. This setting is only honored if the organization is on an Enterprise subscription or has purchased the HIPAA add-on. */ + hipaaEnabled?: boolean; /** - * This is the type of the tool. - * When you're using handoff tool, we recommend adding this to your system prompt - * --- - * # System context + * When this is enabled, the user will be restricted to use PCI-compliant providers, and no logs or transcripts are stored. + * At the end of the call, you will receive an end-of-call-report message to store on your server. Defaults to false. + * @example {"pciEnabled":false} + */ + pciEnabled?: boolean; + /** This is the security filter plan for the assistant. It allows filtering of transcripts for security threats before sending to LLM. */ + securityFilterPlan?: SecurityFilterPlan; + recordingConsentPlan?: + | ({ + type: "stay-on-line"; + } & RecordingConsentPlanStayOnLine) + | ({ + type: "verbal"; + } & RecordingConsentPlanVerbal); +} + +export interface StructuredDataPlan { + /** + * These are the messages used to generate the structured data. * - * You 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. + * @default: ``` + * [ + * { + * "role": "system", + * "content": "You are an expert data extractor. You will be given a transcript of a call. Extract structured data per the JSON Schema. DO NOT return anything except the structured data.\n\nJson Schema:\\n{{schema}}\n\nOnly respond with the JSON." + * }, + * { + * "role": "user", + * "content": "Here is the transcript:\n\n{{transcript}}\n\n. Here is the ended reason of the call:\n\n{{endedReason}}\n\n" + * } + * ]``` * - * # Agent context + * You can customize by providing any messages you want. * - * {put your agent system prompt here} - * --- + * Here are the template variables available: + * - {{transcript}}: the transcript of the call from `call.artifact.transcript`- {{systemPrompt}}: the system prompt of the call from `assistant.model.messages[type=system].content`- {{messages}}: the messages of the call from `assistant.model.messages`- {{schema}}: the schema of the structured data from `structuredDataPlan.schema`- {{endedReason}}: the ended reason of the call from `call.endedReason` */ - type: "handoff"; - /** This is the default local tool result message used when no runtime handoff result override is returned. */ - defaultResult?: string; + messages?: object[]; /** - * These are the destinations that the call can be handed off to. + * This determines whether structured data is generated and stored in `call.analysis.structuredData`. Defaults to false. * * Usage: - * 1. Single destination + * - If you want to extract structured data, set this to true and provide a `schema`. * - * Use `assistantId` to handoff the call to a saved assistant, or `assistantName` to handoff the call to an assistant in the same squad. + * @default false + */ + enabled?: boolean; + /** + * This is the schema of the structured data. The output is stored in `call.analysis.structuredData`. * - * ```json - * { - * "tools": [ - * { - * "type": "handoff", - * "destinations": [ - * { - * "type": "assistant", - * "assistantId": "assistant-123", // or "assistantName": "Assistant123" - * "description": "customer wants to be handed off to assistant-123", - * "contextEngineeringPlan": { - * "type": "all" - * } - * } - * ], - * } - * ] - * } - * ``` + * Complete guide on JSON Schema can be found [here](https://ajv.js.org/json-schema.html#json-data-type). + */ + schema?: JsonSchema; + /** + * This is how long the request is tried before giving up. When request times out, `call.analysis.structuredData` will be empty. * - * 2. Multiple destinations + * Usage: + * - To guarantee the structured data is generated, set this value high. Note, this will delay the end of call report in cases where model is slow to respond. * - * 2.1. Multiple Tools, Each With One Destination (OpenAI recommended) + * @default 5 seconds + * @min 1 + * @max 60 + */ + timeoutSeconds?: number; +} + +export interface StructuredDataMultiPlan { + /** This is the key of the structured data plan in the catalog. */ + key: string; + /** This is an individual structured data plan in the catalog. */ + plan: StructuredDataPlan; +} + +export interface SuccessEvaluationPlan { + /** + * This enforces the rubric of the evaluation. The output is stored in `call.analysis.successEvaluation`. * - * ```json - * { - * "tools": [ - * { - * "type": "handoff", - * "destinations": [ - * { - * "type": "assistant", - * "assistantId": "assistant-123", - * "description": "customer wants to be handed off to assistant-123", - * "contextEngineeringPlan": { - * "type": "all" - * } - * }, - * ], - * }, - * { - * "type": "handoff", - * "destinations": [ - * { - * "type": "assistant", - * "assistantId": "assistant-456", - * "description": "customer wants to be handed off to assistant-456", - * "contextEngineeringPlan": { - * "type": "all" - * } - * } - * ], - * } - * ] - * } - * ``` + * Options include: + * - 'NumericScale': A scale of 1 to 10. + * - 'DescriptiveScale': A scale of Excellent, Good, Fair, Poor. + * - 'Checklist': A checklist of criteria and their status. + * - 'Matrix': A grid that evaluates multiple criteria across different performance levels. + * - 'PercentageScale': A scale of 0% to 100%. + * - 'LikertScale': A scale of Strongly Agree, Agree, Neutral, Disagree, Strongly Disagree. + * - 'AutomaticRubric': Automatically break down evaluation into several criteria, each with its own score. + * - 'PassFail': A simple 'true' if call passed, 'false' if not. * - * 2.2. One Tool, Multiple Destinations (Anthropic recommended) + * Default is 'PassFail'. + */ + rubric?: + | "NumericScale" + | "DescriptiveScale" + | "Checklist" + | "Matrix" + | "PercentageScale" + | "LikertScale" + | "AutomaticRubric" + | "PassFail"; + /** + * These are the messages used to generate the success evaluation. * - * ```json - * { - * "tools": [ - * { - * "type": "handoff", - * "destinations": [ - * { - * "type": "assistant", - * "assistantId": "assistant-123", - * "description": "customer wants to be handed off to assistant-123", - * "contextEngineeringPlan": { - * "type": "all" - * } - * }, - * { - * "type": "assistant", - * "assistantId": "assistant-456", - * "description": "customer wants to be handed off to assistant-456", - * "contextEngineeringPlan": { - * "type": "all" - * } - * } - * ], - * } - * ] - * } - * ``` + * @default: ``` + * [ + * { + * "role": "system", + * "content": "You are an expert call evaluator. You will be given a transcript of a call and the system prompt of the AI participant. Determine if the call was successful based on the objectives inferred from the system prompt. DO NOT return anything except the result.\n\nRubric:\\n{{rubric}}\n\nOnly respond with the result." + * }, + * { + * "role": "user", + * "content": "Here is the transcript:\n\n{{transcript}}\n\n" + * }, + * { + * "role": "user", + * "content": "Here was the system prompt of the call:\n\n{{systemPrompt}}\n\n. Here is the ended reason of the call:\n\n{{endedReason}}\n\n" + * } + * ]``` * - * 3. Dynamic destination + * You can customize by providing any messages you want. * - * 3.1 To determine the destination dynamically, supply a `dynamic` handoff destination type and a `server` object. - * VAPI will send a handoff-destination-request webhook to the `server.url`. - * The response from the server will be used as the destination (if valid). + * Here are the template variables available: + * - {{transcript}}: the transcript of the call from `call.artifact.transcript`- {{systemPrompt}}: the system prompt of the call from `assistant.model.messages[type=system].content`- {{messages}}: the messages of the call from `assistant.model.messages`- {{rubric}}: the rubric of the success evaluation from `successEvaluationPlan.rubric`- {{endedReason}}: the ended reason of the call from `call.endedReason` + */ + messages?: object[]; + /** + * This determines whether a success evaluation is generated and stored in `call.analysis.successEvaluation`. Defaults to true. * - * ```json - * { - * "tools": [ - * { - * "type": "handoff", - * "destinations": [ - * { - * "type": "dynamic", - * "server": { - * "url": "https://example.com" - * } - * } - * ], - * } - * ] - * } - * ``` + * Usage: + * - If you want to disable the success evaluation, set this to false. * - * 3.2. To pass custom parameters to the server, you can use the `function` object. + * @default true + */ + enabled?: boolean; + /** + * This is how long the request is tried before giving up. When request times out, `call.analysis.successEvaluation` will be empty. * - * ```json - * { - * "tools": [ - * { - * "type": "handoff", - * "destinations": [ - * { - * "type": "dynamic", - * "server": { - * "url": "https://example.com" - * }, - * } - * ], - * "function": { - * "name": "handoff", - * "description": "Call this function when the customer is ready to be handed off to the next assistant", - * "parameters": { - * "type": "object", - * "properties": { - * "destination": { - * "type": "string", - * "description": "Use dynamic when customer is ready to be handed off to the next assistant", - * "enum": ["dynamic"] - * }, - * "customerAreaCode": { - * "type": "number", - * "description": "Area code of the customer" - * }, - * "customerIntent": { - * "type": "string", - * "enum": ["new-customer", "existing-customer"], - * "description": "Use new-customer when customer is a new customer, existing-customer when customer is an existing customer" - * }, - * "customerSentiment": { - * "type": "string", - * "enum": ["positive", "negative", "neutral"], - * "description": "Use positive when customer is happy, negative when customer is unhappy, neutral when customer is neutral" - * } - * } - * } - * } - * } - * ] - * } - * ``` + * Usage: + * - To guarantee the success evaluation is generated, set this value high. Note, this will delay the end of call report in cases where model is slow to respond. * - * The properties `customerAreaCode`, `customerIntent`, and `customerSentiment` will be passed to the server in the webhook request body. + * @default 5 seconds + * @min 1 + * @max 60 */ - destinations?: ( - | HandoffDestinationAssistant - | HandoffDestinationDynamic - | HandoffDestinationSquad - )[]; + timeoutSeconds?: number; +} + +export interface AnalysisPlan { /** - * This is the optional function definition that will be passed to the LLM. - * If this is not defined, we will construct this based on the other properties. - * - * For example, given the following tools definition: - * ```json - * { - * "tools": [ - * { - * "type": "handoff", - * "destinations": [ - * { - * "type": "assistant", - * "assistantId": "assistant-123", - * "description": "customer wants to be handed off to assistant-123", - * "contextEngineeringPlan": { - * "type": "all" - * } - * }, - * { - * "type": "assistant", - * "assistantId": "assistant-456", - * "description": "customer wants to be handed off to assistant-456", - * "contextEngineeringPlan": { - * "type": "all" - * } - * } - * ], - * } - * ] - * } - * ``` - * - * We will construct the following function definition: - * ```json - * { - * "function": { - * "name": "handoff_to_assistant-123", - * "description": " - * Use this function to handoff the call to the next assistant. - * Only use it when instructions explicitly ask you to use the handoff_to_assistant function. - * DO NOT call this function unless you are instructed to do so. - * Here are the destinations you can handoff the call to: - * 1. assistant-123. When: customer wants to be handed off to assistant-123 - * 2. assistant-456. When: customer wants to be handed off to assistant-456 - * ", - * "parameters": { - * "type": "object", - * "properties": { - * "destination": { - * "type": "string", - * "description": "Options: assistant-123 (customer wants to be handed off to assistant-123), assistant-456 (customer wants to be handed off to assistant-456)", - * "enum": ["assistant-123", "assistant-456"] - * }, - * }, - * "required": ["destination"] - * } - * } - * } - * ``` + * The minimum number of messages required to run the analysis plan. + * If the number of messages is less than this, analysis will be skipped. * - * To override this function, please provide an OpenAI function definition and refer to it in the system prompt. - * You may override parts of the function definition (i.e. you may only want to change the function name for your prompt). - * If you choose to override the function parameters, it must include `destination` as a required parameter, and it must evaluate to either an assistantId, assistantName, or a the string literal `dynamic`. + * @default 2 + * @deprecated + * @min 0 + */ + minMessagesThreshold?: number; + /** + * This is the plan for generating the summary of the call. This outputs to `call.analysis.summary`. + * @deprecated + */ + summaryPlan?: SummaryPlan; + /** + * This is the plan for generating the structured data from the call. This outputs to `call.analysis.structuredData`. + * @deprecated + */ + structuredDataPlan?: StructuredDataPlan; + /** + * This is an array of structured data plan catalogs. Each entry includes a `key` and a `plan` for generating the structured data from the call. This outputs to `call.analysis.structuredDataMulti`. + * @deprecated + */ + structuredDataMultiPlan?: StructuredDataMultiPlan[]; + /** + * This is the plan for generating the success evaluation of the call. This outputs to `call.analysis.successEvaluation`. + * @deprecated + */ + successEvaluationPlan?: SuccessEvaluationPlan; + /** + * This is an array of outcome UUIDs to be calculated during analysis. + * The outcomes will be calculated and stored in `call.analysis.outcomes`. + * @deprecated + */ + outcomeIds?: string[]; +} + +export interface TranscriptPlan { + /** + * This determines whether the transcript is stored in `call.artifact.transcript`. Defaults to true. * - * To pass custom parameters to the server in a dynamic handoff, you can use the function parameters, with `dynamic` as the destination. - * ```json - * { - * "function": { - * "name": "dynamic_handoff", - * "description": " - * Call this function when the customer is ready to be handed off to the next assistant - * ", - * "parameters": { - * "type": "object", - * "properties": { - * "destination": { - * "type": "string", - * "enum": ["dynamic"] - * }, - * "customerAreaCode": { - * "type": "number", - * "description": "Area code of the customer" - * }, - * "customerIntent": { - * "type": "string", - * "enum": ["new-customer", "existing-customer"], - * "description": "Use new-customer when customer is a new customer, existing-customer when customer is an existing customer" - * }, - * "customerSentiment": { - * "type": "string", - * "enum": ["positive", "negative", "neutral"], - * "description": "Use positive when customer is happy, negative when customer is unhappy, neutral when customer is neutral" - * } - * }, - * "required": ["destination", "customerAreaCode", "customerIntent", "customerSentiment"] - * } - * } - * } - * ``` + * @default true + * @example true */ - function?: OpenAIFunction; + enabled?: boolean; /** - * This is the plan to reject a tool call based on the conversation state. + * This is the name of the assistant in the transcript. Defaults to 'AI'. * - * // Example 1: Reject endCall if user didn't say goodbye - * ```json - * { - * conditions: [{ - * type: 'regex', - * regex: '(?i)\\b(bye|goodbye|farewell|see you later|take care)\\b', - * target: { position: -1, role: 'user' }, - * negate: true // Reject if pattern does NOT match - * }] - * } + * Usage: + * - If you want to change the name of the assistant in the transcript, set this. Example, here is what the transcript would look like with `assistantName` set to 'Buyer': * ``` - * - * // Example 2: Reject transfer if user is actually asking a question - * ```json - * { - * conditions: [{ - * type: 'regex', - * regex: '\\?', - * target: { position: -1, role: 'user' } - * }] - * } + * User: Hello, how are you? + * Buyer: I'm fine. + * User: Do you want to buy a car? + * Buyer: No. * ``` * - * // Example 3: Reject transfer if user didn't mention transfer recently - * ```json - * { - * conditions: [{ - * type: 'liquid', - * liquid: `{% assign recentMessages = messages | last: 5 %} - * {% assign userMessages = recentMessages | where: 'role', 'user' %} - * {% assign mentioned = false %} - * {% for msg in userMessages %} - * {% if msg.content contains 'transfer' or msg.content contains 'connect' or msg.content contains 'speak to' %} - * {% assign mentioned = true %} - * {% break %} - * {% endif %} - * {% endfor %} - * {% if mentioned %} - * false - * {% else %} - * true - * {% endif %}` - * }] - * } - * ``` + * @default 'AI' + */ + assistantName?: string; + /** + * This is the name of the user in the transcript. Defaults to 'User'. * - * // Example 4: Reject endCall if the bot is looping and trying to exit - * ```json - * { - * conditions: [{ - * type: 'liquid', - * liquid: `{% assign recentMessages = messages | last: 6 %} - * {% assign userMessages = recentMessages | where: 'role', 'user' | reverse %} - * {% if userMessages.size < 3 %} - * false - * {% else %} - * {% assign msg1 = userMessages[0].content | downcase %} - * {% assign msg2 = userMessages[1].content | downcase %} - * {% assign msg3 = userMessages[2].content | downcase %} - * {% comment %} Check for repetitive messages {% endcomment %} - * {% if msg1 == msg2 or msg1 == msg3 or msg2 == msg3 %} - * true - * {% comment %} Check for common loop phrases {% endcomment %} - * {% elsif msg1 contains 'cool thanks' or msg2 contains 'cool thanks' or msg3 contains 'cool thanks' %} - * true - * {% elsif msg1 contains 'okay thanks' or msg2 contains 'okay thanks' or msg3 contains 'okay thanks' %} - * true - * {% elsif msg1 contains 'got it' or msg2 contains 'got it' or msg3 contains 'got it' %} - * true - * {% else %} - * false - * {% endif %} - * {% endif %}` - * }] - * } + * Usage: + * - If you want to change the name of the user in the transcript, set this. Example, here is what the transcript would look like with `userName` set to 'Seller': + * ``` + * Seller: Hello, how are you? + * AI: I'm fine. + * Seller: Do you want to buy a car? + * AI: No. * ``` + * + * @default 'User' */ - rejectionPlan?: ToolRejectionPlan; + userName?: string; } -export interface CreateCustomKnowledgeBaseDTO { - /** This knowledge base is bring your own knowledge base implementation. */ - provider: "custom-knowledge-base"; +export interface MinMessagesCondition { /** - * This is where the knowledge base request will be sent. - * - * Request Example: - * - * POST https://{server.url} - * Content-Type: application/json - * - * { - * "messsage": { - * "type": "knowledge-base-request", - * "messages": [ - * { - * "role": "user", - * "content": "Why is ocean blue?" - * } - * ], - * ...other metadata about the call... - * } - * } + * This is the type discriminator for the minMessages condition. + * @example "minMessages" + */ + type: "minMessages"; + /** + * This is the minimum number of conversation messages required for the + * structured output to run. * - * Response Expected: - * ``` - * { - * "message": { - * "role": "assistant", - * "content": "The ocean is blue because water absorbs everything but blue.", - * }, // YOU CAN RETURN THE EXACT RESPONSE TO SPEAK - * "documents": [ - * { - * "content": "The ocean is blue primarily because water absorbs colors in the red part of the light spectrum and scatters the blue light, making it more visible to our eyes.", - * "similarity": 1 - * }, - * { - * "content": "Blue light is scattered more by the water molecules than other colors, enhancing the blue appearance of the ocean.", - * "similarity": .5 - * } - * ] // OR, YOU CAN RETURN AN ARRAY OF DOCUMENTS THAT WILL BE SENT TO THE MODEL - * } - * ``` + * A count of 0 removes the runtime default minimum, so the structured output + * runs regardless of how few messages the conversation has. + * @min 0 + * @example 4 */ - server: Server; + count: number; } -export interface KnowledgeBase { +export interface MinCallDurationCondition { /** - * The name of the knowledge base - * @example "My Knowledge Base" + * This is the type discriminator for the minCallDuration condition. + * @example "minCallDuration" */ - name: string; + type: "minCallDuration"; /** - * The provider of the knowledge base - * @example "google" + * This is the minimum call duration in seconds required for the structured + * output to run. + * + * When timestamps are unavailable (for example, chat sessions have no call + * timestamps), this check passes and does not block the structured output. + * @min 0 + * @example 10 */ - provider: "google"; - /** The model to use for the knowledge base */ - model?: - | "gemini-3.8-flash" - | "gemini-3.5-flash" - | "gemini-3.1-flash-lite" - | "gemini-3-flash-preview" - | "gemini-2.5-pro" - | "gemini-2.5-flash" - | "gemini-2.5-flash-lite" - | "gemini-2.0-flash-thinking-exp" - | "gemini-2.0-pro-exp-02-05" - | "gemini-2.0-flash" - | "gemini-2.0-flash-lite" - | "gemini-2.0-flash-exp" - | "gemini-2.0-flash-realtime-exp" - | "gemini-1.5-flash" - | "gemini-1.5-flash-002" - | "gemini-1.5-pro" - | "gemini-1.5-pro-002" - | "gemini-1.0-pro"; - /** A description of the knowledge base */ - description: string; - /** The file IDs associated with this knowledge base */ - fileIds: string[]; + seconds: number; } -export interface CreateQueryToolDTO { - /** Messages spoken while the tool is running. Multiple request-start messages are variants. For request-response-delayed, same timing means variants and different timings mean staged updates. */ - messages?: ( - | ToolMessageStart - | ToolMessageComplete - | ToolMessageFailed - | ToolMessageDelayed - )[]; - /** The type of tool. "query" for Query tool. */ - type: "query"; - /** The knowledge bases to query */ - knowledgeBases?: KnowledgeBase[]; +export interface EndedReasonCondition { /** - * This is the plan to reject a tool call based on the conversation state. - * - * // Example 1: Reject endCall if user didn't say goodbye - * ```json - * { - * conditions: [{ - * type: 'regex', - * regex: '(?i)\\b(bye|goodbye|farewell|see you later|take care)\\b', - * target: { position: -1, role: 'user' }, - * negate: true // Reject if pattern does NOT match - * }] - * } - * ``` - * - * // Example 2: Reject transfer if user is actually asking a question - * ```json - * { - * conditions: [{ - * type: 'regex', - * regex: '\\?', - * target: { position: -1, role: 'user' } - * }] - * } - * ``` + * This is the type discriminator for the endedReason condition. + * @example "endedReason" + */ + type: "endedReason"; + /** + * This is the membership operator applied against `values`. * - * // Example 3: Reject transfer if user didn't mention transfer recently - * ```json - * { - * conditions: [{ - * type: 'liquid', - * liquid: `{% assign recentMessages = messages | last: 5 %} - * {% assign userMessages = recentMessages | where: 'role', 'user' %} - * {% assign mentioned = false %} - * {% for msg in userMessages %} - * {% if msg.content contains 'transfer' or msg.content contains 'connect' or msg.content contains 'speak to' %} - * {% assign mentioned = true %} - * {% break %} - * {% endif %} - * {% endfor %} - * {% if mentioned %} - * false - * {% else %} - * true - * {% endif %}` - * }] - * } - * ``` + * - 'oneOf': the structured output runs only if the call's ended reason is in `values`. + * - 'notOneOf': the structured output runs only if the call's ended reason is NOT in `values`. + * @example "oneOf" + */ + operator: "oneOf" | "notOneOf"; + /** + * These are the ended reasons compared against the call's ended reason. * - * // Example 4: Reject endCall if the bot is looping and trying to exit - * ```json - * { - * conditions: [{ - * type: 'liquid', - * liquid: `{% assign recentMessages = messages | last: 6 %} - * {% assign userMessages = recentMessages | where: 'role', 'user' | reverse %} - * {% if userMessages.size < 3 %} - * false - * {% else %} - * {% assign msg1 = userMessages[0].content | downcase %} - * {% assign msg2 = userMessages[1].content | downcase %} - * {% assign msg3 = userMessages[2].content | downcase %} - * {% comment %} Check for repetitive messages {% endcomment %} - * {% if msg1 == msg2 or msg1 == msg3 or msg2 == msg3 %} - * true - * {% comment %} Check for common loop phrases {% endcomment %} - * {% elsif msg1 contains 'cool thanks' or msg2 contains 'cool thanks' or msg3 contains 'cool thanks' %} - * true - * {% elsif msg1 contains 'okay thanks' or msg2 contains 'okay thanks' or msg3 contains 'okay thanks' %} - * true - * {% elsif msg1 contains 'got it' or msg2 contains 'got it' or msg3 contains 'got it' %} - * true - * {% else %} - * false - * {% endif %} - * {% endif %}` - * }] - * } - * ``` + * Any string is accepted so configurations never break when new ended + * reasons are introduced. Must contain at least one value. + * @example ["customer-ended-call"] */ - rejectionPlan?: ToolRejectionPlan; + values: string[]; } -export interface CreateGoogleCalendarCreateEventToolDTO { - /** Messages spoken while the tool is running. Multiple request-start messages are variants. For request-response-delayed, same timing means variants and different timings mean staged updates. */ - messages?: ( - | ToolMessageStart - | ToolMessageComplete - | ToolMessageFailed - | ToolMessageDelayed - )[]; - /** The type of tool. "google.calendar.event.create" for Google Calendar Create Event tool. */ - type: "google.calendar.event.create"; +export interface ComplianceOverride { /** - * This is the plan to reject a tool call based on the conversation state. + * Force storage for this output under HIPAA. Only enable if output contains no sensitive data. + * @example false + */ + forceStoreOnHipaaEnabled?: boolean; +} + +export interface CreateStructuredOutputDTO { + /** + * This is the type of structured output. * - * // Example 1: Reject endCall if user didn't say goodbye - * ```json - * { - * conditions: [{ - * type: 'regex', - * regex: '(?i)\\b(bye|goodbye|farewell|see you later|take care)\\b', - * target: { position: -1, role: 'user' }, - * negate: true // Reject if pattern does NOT match - * }] - * } - * ``` + * - 'ai': Uses an LLM to extract structured data from the conversation (default). + * - 'regex': Uses a regex pattern to extract data from the transcript without an LLM. * - * // Example 2: Reject transfer if user is actually asking a question - * ```json - * { - * conditions: [{ - * type: 'regex', - * regex: '\\?', - * target: { position: -1, role: 'user' } - * }] - * } - * ``` - * - * // Example 3: Reject transfer if user didn't mention transfer recently - * ```json - * { - * conditions: [{ - * type: 'liquid', - * liquid: `{% assign recentMessages = messages | last: 5 %} - * {% assign userMessages = recentMessages | where: 'role', 'user' %} - * {% assign mentioned = false %} - * {% for msg in userMessages %} - * {% if msg.content contains 'transfer' or msg.content contains 'connect' or msg.content contains 'speak to' %} - * {% assign mentioned = true %} - * {% break %} - * {% endif %} - * {% endfor %} - * {% if mentioned %} - * false - * {% else %} - * true - * {% endif %}` - * }] - * } - * ``` - * - * // Example 4: Reject endCall if the bot is looping and trying to exit - * ```json - * { - * conditions: [{ - * type: 'liquid', - * liquid: `{% assign recentMessages = messages | last: 6 %} - * {% assign userMessages = recentMessages | where: 'role', 'user' | reverse %} - * {% if userMessages.size < 3 %} - * false - * {% else %} - * {% assign msg1 = userMessages[0].content | downcase %} - * {% assign msg2 = userMessages[1].content | downcase %} - * {% assign msg3 = userMessages[2].content | downcase %} - * {% comment %} Check for repetitive messages {% endcomment %} - * {% if msg1 == msg2 or msg1 == msg3 or msg2 == msg3 %} - * true - * {% comment %} Check for common loop phrases {% endcomment %} - * {% elsif msg1 contains 'cool thanks' or msg2 contains 'cool thanks' or msg3 contains 'cool thanks' %} - * true - * {% elsif msg1 contains 'okay thanks' or msg2 contains 'okay thanks' or msg3 contains 'okay thanks' %} - * true - * {% elsif msg1 contains 'got it' or msg2 contains 'got it' or msg3 contains 'got it' %} - * true - * {% else %} - * false - * {% endif %} - * {% endif %}` - * }] - * } - * ``` + * Defaults to 'ai' if not specified. + * @default "ai" */ - rejectionPlan?: ToolRejectionPlan; -} - -export interface CreateGoogleSheetsRowAppendToolDTO { - /** Messages spoken while the tool is running. Multiple request-start messages are variants. For request-response-delayed, same timing means variants and different timings mean staged updates. */ - messages?: ( - | ToolMessageStart - | ToolMessageComplete - | ToolMessageFailed - | ToolMessageDelayed - )[]; - /** The type of tool. "google.sheets.row.append" for Google Sheets Row Append tool. */ - type: "google.sheets.row.append"; + type?: "ai" | "regex"; /** - * This is the plan to reject a tool call based on the conversation state. + * This is the regex pattern to match against the transcript. * - * // Example 1: Reject endCall if user didn't say goodbye - * ```json - * { - * conditions: [{ - * type: 'regex', - * regex: '(?i)\\b(bye|goodbye|farewell|see you later|take care)\\b', - * target: { position: -1, role: 'user' }, - * negate: true // Reject if pattern does NOT match - * }] - * } - * ``` + * Simulation evaluations use a canonical transcript built from recorded messages: + * User: and AI: dialogue, AI: tool_calls: JSON name/arguments records, and + * AI: tool_call_results: JSON results. System messages are excluded. These + * fixed labels apply even when custom artifact transcript labels are configured. + * Tool payloads participate in first-match and all-match extraction in event order. + * An empty message array falls back to the supplied transcript verbatim. + * Production-call extraction and call preview use their existing transcripts, + * so previewing the same output on a simulation's call can return a different result. * - * // Example 2: Reject transfer if user is actually asking a question - * ```json - * { - * conditions: [{ - * type: 'regex', - * regex: '\\?', - * target: { position: -1, role: 'user' } - * }] - * } - * ``` + * Only used when type is 'regex'. Supports both raw patterns (e.g. '\d+') and + * regex literal format (e.g. '/\d+/gi'). Uses RE2 syntax for safety. * - * // Example 3: Reject transfer if user didn't mention transfer recently - * ```json - * { - * conditions: [{ - * type: 'liquid', - * liquid: `{% assign recentMessages = messages | last: 5 %} - * {% assign userMessages = recentMessages | where: 'role', 'user' %} - * {% assign mentioned = false %} - * {% for msg in userMessages %} - * {% if msg.content contains 'transfer' or msg.content contains 'connect' or msg.content contains 'speak to' %} - * {% assign mentioned = true %} - * {% break %} - * {% endif %} - * {% endfor %} - * {% if mentioned %} - * false - * {% else %} - * true - * {% endif %}` - * }] - * } - * ``` + * The result depends on the schema type: + * - boolean: true if the pattern matches, false otherwise + * - string: the first match or first capture group + * - number/integer: the first match parsed as a number + * - array: all matches + * @minLength 1 + * @maxLength 1000 + */ + regex?: string; + /** + * This is the model that will be used to extract the structured output. * - * // Example 4: Reject endCall if the bot is looping and trying to exit - * ```json - * { - * conditions: [{ - * type: 'liquid', - * liquid: `{% assign recentMessages = messages | last: 6 %} - * {% assign userMessages = recentMessages | where: 'role', 'user' | reverse %} - * {% if userMessages.size < 3 %} - * false - * {% else %} - * {% assign msg1 = userMessages[0].content | downcase %} - * {% assign msg2 = userMessages[1].content | downcase %} - * {% assign msg3 = userMessages[2].content | downcase %} - * {% comment %} Check for repetitive messages {% endcomment %} - * {% if msg1 == msg2 or msg1 == msg3 or msg2 == msg3 %} - * true - * {% comment %} Check for common loop phrases {% endcomment %} - * {% elsif msg1 contains 'cool thanks' or msg2 contains 'cool thanks' or msg3 contains 'cool thanks' %} - * true - * {% elsif msg1 contains 'okay thanks' or msg2 contains 'okay thanks' or msg3 contains 'okay thanks' %} - * true - * {% elsif msg1 contains 'got it' or msg2 contains 'got it' or msg3 contains 'got it' %} - * true - * {% else %} - * false - * {% endif %} - * {% endif %}` - * }] - * } - * ``` + * To provide your own custom system and user prompts for structured output extraction, populate the messages array with your system and user messages. You can specify liquid templating in your system and user messages. + * For text extraction, you must reference 'transcript', 'messages', or 'messagesWithConfidence' with the `{{}}` syntax to access the conversation history. + * In structured outputs, `{{messages}}` includes conversation text and tool calls/results but omits caller transcription-confidence fields. Text extraction can use `{{messagesWithConfidence}}` when the output needs the original message history with transcription confidence. These variables also apply in structured-output schema descriptions. Audio-targeted (`messages-with-audio`) extraction ignores custom messages. Stored call artifacts and API messages retain their confidence data. + * Between the system or user messages, you must reference a variation of the structured output with the `{{}}` syntax to access the structured output definition. + * i.e.: + * `{{structuredOutput}}` + * `{{structuredOutput.name}}` + * `{{structuredOutput.description}}` + * `{{structuredOutput.schema}}` + * + * If model is not specified, GPT-4.1 will be used by default for extraction, utilizing default system and user prompts. + * If messages or required fields are not specified, the default system and user prompts will be used. */ - rejectionPlan?: ToolRejectionPlan; -} - -export interface CreateGoogleCalendarCheckAvailabilityToolDTO { - /** Messages spoken while the tool is running. Multiple request-start messages are variants. For request-response-delayed, same timing means variants and different timings mean staged updates. */ - messages?: ( - | ToolMessageStart - | ToolMessageComplete - | ToolMessageFailed - | ToolMessageDelayed - )[]; - /** The type of tool. "google.calendar.availability.check" for Google Calendar Check Availability tool. */ - type: "google.calendar.availability.check"; + model?: + | WorkflowOpenAIModel + | WorkflowAnthropicModel + | WorkflowAnthropicBedrockModel + | WorkflowGoogleModel + | WorkflowCustomModel; /** - * This is the plan to reject a tool call based on the conversation state. + * Compliance configuration for this output. Only enable overrides if no sensitive data will be stored. + * @example {"forceStoreOnHipaaEnabled":false} + */ + compliancePlan?: ComplianceOverride; + /** + * These are the conditions that gate the execution of this structured output. Every condition must pass for the structured output to run (AND semantics). When omitted or empty, no user-defined conditions gate this output. Send null to clear a previously saved gate. + * @example [{"type":"minMessages","count":4},{"type":"minCallDuration","seconds":10}] + */ + conditions?: + | (MinMessagesCondition | MinCallDurationCondition | EndedReasonCondition)[] + | null; + /** + * This is the name of the structured output. + * @minLength 1 + * @maxLength 40 + */ + name: string; + /** + * This is the JSON Schema definition for the structured output. * - * // Example 1: Reject endCall if user didn't say goodbye - * ```json - * { - * conditions: [{ - * type: 'regex', - * regex: '(?i)\\b(bye|goodbye|farewell|see you later|take care)\\b', - * target: { position: -1, role: 'user' }, - * negate: true // Reject if pattern does NOT match - * }] - * } - * ``` + * This is required when creating a structured output. Defines the structure and validation rules for the data that will be extracted. Supports all JSON Schema features including: + * - Objects and nested properties + * - Arrays and array validation + * - String, number, boolean, and null types + * - Enums and const values + * - Validation constraints (min/max, patterns, etc.) + * - Composition with allOf, anyOf, oneOf + */ + schema: JsonSchema; + /** + * This is the description of what the structured output extracts. * - * // Example 2: Reject transfer if user is actually asking a question - * ```json - * { - * conditions: [{ - * type: 'regex', - * regex: '\\?', - * target: { position: -1, role: 'user' } - * }] - * } - * ``` + * Use this to provide context about what data will be extracted and how it will be used. + */ + description?: string; + /** + * These are the assistant IDs that this structured output is linked to. * - * // Example 3: Reject transfer if user didn't mention transfer recently - * ```json - * { - * conditions: [{ - * type: 'liquid', - * liquid: `{% assign recentMessages = messages | last: 5 %} - * {% assign userMessages = recentMessages | where: 'role', 'user' %} - * {% assign mentioned = false %} - * {% for msg in userMessages %} - * {% if msg.content contains 'transfer' or msg.content contains 'connect' or msg.content contains 'speak to' %} - * {% assign mentioned = true %} - * {% break %} - * {% endif %} - * {% endfor %} - * {% if mentioned %} - * false - * {% else %} - * true - * {% endif %}` - * }] - * } - * ``` + * When linked to assistants, this structured output will be available for extraction during those assistant's calls. + */ + assistantIds?: string[]; + /** + * These are the workflow IDs that this structured output is linked to. * - * // Example 4: Reject endCall if the bot is looping and trying to exit - * ```json - * { - * conditions: [{ - * type: 'liquid', - * liquid: `{% assign recentMessages = messages | last: 6 %} - * {% assign userMessages = recentMessages | where: 'role', 'user' | reverse %} - * {% if userMessages.size < 3 %} - * false - * {% else %} - * {% assign msg1 = userMessages[0].content | downcase %} - * {% assign msg2 = userMessages[1].content | downcase %} - * {% assign msg3 = userMessages[2].content | downcase %} - * {% comment %} Check for repetitive messages {% endcomment %} - * {% if msg1 == msg2 or msg1 == msg3 or msg2 == msg3 %} - * true - * {% comment %} Check for common loop phrases {% endcomment %} - * {% elsif msg1 contains 'cool thanks' or msg2 contains 'cool thanks' or msg3 contains 'cool thanks' %} - * true - * {% elsif msg1 contains 'okay thanks' or msg2 contains 'okay thanks' or msg3 contains 'okay thanks' %} - * true - * {% elsif msg1 contains 'got it' or msg2 contains 'got it' or msg3 contains 'got it' %} - * true - * {% else %} - * false - * {% endif %} - * {% endif %}` - * }] - * } - * ``` + * When linked to workflows, this structured output will be available for extraction during those workflow's execution. */ - rejectionPlan?: ToolRejectionPlan; + workflowIds?: string[]; } -export interface CreateSlackSendMessageToolDTO { - /** Messages spoken while the tool is running. Multiple request-start messages are variants. For request-response-delayed, same timing means variants and different timings mean staged updates. */ - messages?: ( - | ToolMessageStart - | ToolMessageComplete - | ToolMessageFailed - | ToolMessageDelayed - )[]; - /** The type of tool. "slack.message.send" for Slack Send Message tool. */ - type: "slack.message.send"; +export interface NumberComparatorScorecardMetricCondition { + /** This is the type of the condition. Currently only 'comparator' is supported. */ + type: "comparator"; /** - * This is the plan to reject a tool call based on the conversation state. - * - * // Example 1: Reject endCall if user didn't say goodbye - * ```json - * { - * conditions: [{ - * type: 'regex', - * regex: '(?i)\\b(bye|goodbye|farewell|see you later|take care)\\b', - * target: { position: -1, role: 'user' }, - * negate: true // Reject if pattern does NOT match - * }] - * } - * ``` - * - * // Example 2: Reject transfer if user is actually asking a question - * ```json - * { - * conditions: [{ - * type: 'regex', - * regex: '\\?', - * target: { position: -1, role: 'user' } - * }] - * } - * ``` - * - * // Example 3: Reject transfer if user didn't mention transfer recently - * ```json - * { - * conditions: [{ - * type: 'liquid', - * liquid: `{% assign recentMessages = messages | last: 5 %} - * {% assign userMessages = recentMessages | where: 'role', 'user' %} - * {% assign mentioned = false %} - * {% for msg in userMessages %} - * {% if msg.content contains 'transfer' or msg.content contains 'connect' or msg.content contains 'speak to' %} - * {% assign mentioned = true %} - * {% break %} - * {% endif %} - * {% endfor %} - * {% if mentioned %} - * false - * {% else %} - * true - * {% endif %}` - * }] - * } - * ``` - * - * // Example 4: Reject endCall if the bot is looping and trying to exit - * ```json - * { - * conditions: [{ - * type: 'liquid', - * liquid: `{% assign recentMessages = messages | last: 6 %} - * {% assign userMessages = recentMessages | where: 'role', 'user' | reverse %} - * {% if userMessages.size < 3 %} - * false - * {% else %} - * {% assign msg1 = userMessages[0].content | downcase %} - * {% assign msg2 = userMessages[1].content | downcase %} - * {% assign msg3 = userMessages[2].content | downcase %} - * {% comment %} Check for repetitive messages {% endcomment %} - * {% if msg1 == msg2 or msg1 == msg3 or msg2 == msg3 %} - * true - * {% comment %} Check for common loop phrases {% endcomment %} - * {% elsif msg1 contains 'cool thanks' or msg2 contains 'cool thanks' or msg3 contains 'cool thanks' %} - * true - * {% elsif msg1 contains 'okay thanks' or msg2 contains 'okay thanks' or msg3 contains 'okay thanks' %} - * true - * {% elsif msg1 contains 'got it' or msg2 contains 'got it' or msg3 contains 'got it' %} - * true - * {% else %} - * false - * {% endif %} - * {% endif %}` - * }] - * } - * ``` + * This is the comparator that will be used to compare the result of the structured output with the value specified. + * Only '=', '!=', '>', '<', '>=', and '<=' are supported for number conditions + * Only '=' is supported for boolean conditions. */ - rejectionPlan?: ToolRejectionPlan; + comparator: "=" | "!=" | ">" | "<" | ">=" | "<="; + /** + * This is the value that will be used to compare the result of the structured output with the comparator. + * If the result of the comparison is true, the points will be added to the overall score. + */ + value: number; + /** + * These are the points that will be added to the overall score if the condition is met. + * The points must be between 0 and 100. + * @min 0 + * @max 100 + */ + points: number; } -export interface McpToolMessages { - /** The name of the tool from the MCP server. */ - name: string; - /** Custom messages for this specific tool. Set to an empty array to suppress all messages for this tool. If not provided, the tool will use the default messages from the parent MCP tool configuration. Multiple request-start messages are variants. For request-response-delayed, same timing means variants and different timings mean staged updates. */ - messages?: ( - | ToolMessageStart - | ToolMessageComplete - | ToolMessageFailed - | ToolMessageDelayed +export interface BooleanComparatorScorecardMetricCondition { + /** This is the type of the condition. Currently only 'comparator' is supported. */ + type: "comparator"; + /** The comparator can only be '=' for boolean conditions. */ + comparator: "="; + /** + * This is the value that will be used to compare the result of the structured output with the comparator. + * If the result of the comparison is true, the points will be added to the overall score. + */ + value: boolean; + /** + * These are the points that will be added to the overall score if the condition is met. + * The points must be between 0 and 100. + * @min 0 + * @max 100 + */ + points: number; +} + +export interface ScorecardMetric { + /** + * These are the conditions that will be used to evaluate the scorecard. + * Each condition will have a comparator, value, and points that will be used to calculate the final score. + * The points will be added to the overall score if the condition is met. + * The overall score will be normalized to a 100 point scale to ensure uniformity across different scorecards. + */ + conditions: ( + | NumberComparatorScorecardMetricCondition + | BooleanComparatorScorecardMetricCondition )[]; + /** + * This is the unique identifier for the structured output that will be used to evaluate the scorecard. + * The structured output must be of type number or boolean only for now. + */ + structuredOutputId: string; } -export interface McpToolMetadata { - /** This is the protocol used for MCP communication. Defaults to Streamable HTTP. */ - protocol?: "sse" | "shttp"; +export interface CreateScorecardDTO { + /** + * This is the name of the scorecard. It is only for user reference and will not be used for any evaluation. + * @maxLength 80 + */ + name?: string; + /** + * This is the description of the scorecard. It is only for user reference and will not be used for any evaluation. + * @maxLength 500 + */ + description?: string; + /** + * These are the metrics that will be used to evaluate the scorecard. + * Each metric will have a set of conditions and points that will be used to generate the score. + */ + metrics: ScorecardMetric[]; + /** + * These are the assistant IDs that this scorecard is linked to. + * When linked to assistants, this scorecard will be available for evaluation during those assistants' calls. + */ + assistantIds?: string[]; } -export interface CreateMcpToolDTO { - /** Messages spoken while the tool is running. Multiple request-start messages are variants. For request-response-delayed, same timing means variants and different timings mean staged updates. */ - messages?: ( - | ToolMessageStart - | ToolMessageComplete - | ToolMessageFailed - | ToolMessageDelayed - )[]; - /** The type of tool. "mcp" for MCP tool. */ - type: "mcp"; +export interface ArtifactPlan { /** + * This determines whether assistant's calls are recorded. Defaults to true. * - * This is the server where a `tool-calls` webhook will be sent. + * Usage: + * - If you don't want to record the calls, set this to false. + * - If you want to record the calls when `assistant.hipaaEnabled` (deprecated) or `assistant.compliancePlan.hipaaEnabled` explicity set this to true and make sure to provide S3 or GCP credentials on the Provider Credentials page in the Dashboard. * - * Notes: - * - Webhook is sent to this server when a tool call is made. - * - Webhook contains the call, assistant, and phone number objects. - * - Webhook contains the variables set on the assistant. - * - Webhook is sent to the first available URL in this order: {{tool.server.url}}, {{assistant.server.url}}, {{phoneNumber.server.url}}, {{org.server.url}}. - * - Webhook expects a response with tool call result. + * You can find the recording at `call.artifact.recordingUrl` and `call.artifact.stereoRecordingUrl` after the call is ended. + * + * @default true + * @example true */ - server?: Server; - /** Per-tool message overrides for individual tools loaded from the MCP server. Set messages to an empty array to suppress messages for a specific tool. Tools not listed here will use the default messages from the parent tool. */ - toolMessages?: McpToolMessages[]; - metadata?: McpToolMetadata; + recordingEnabled?: boolean; /** - * This is the plan to reject a tool call based on the conversation state. - * - * // Example 1: Reject endCall if user didn't say goodbye - * ```json - * { - * conditions: [{ - * type: 'regex', - * regex: '(?i)\\b(bye|goodbye|farewell|see you later|take care)\\b', - * target: { position: -1, role: 'user' }, - * negate: true // Reject if pattern does NOT match - * }] - * } - * ``` - * - * // Example 2: Reject transfer if user is actually asking a question - * ```json - * { - * conditions: [{ - * type: 'regex', - * regex: '\\?', - * target: { position: -1, role: 'user' } - * }] - * } - * ``` - * - * // Example 3: Reject transfer if user didn't mention transfer recently - * ```json - * { - * conditions: [{ - * type: 'liquid', - * liquid: `{% assign recentMessages = messages | last: 5 %} - * {% assign userMessages = recentMessages | where: 'role', 'user' %} - * {% assign mentioned = false %} - * {% for msg in userMessages %} - * {% if msg.content contains 'transfer' or msg.content contains 'connect' or msg.content contains 'speak to' %} - * {% assign mentioned = true %} - * {% break %} - * {% endif %} - * {% endfor %} - * {% if mentioned %} - * false - * {% else %} - * true - * {% endif %}` - * }] - * } - * ``` + * This determines the format of the recording. Defaults to `wav;l16`. * - * // Example 4: Reject endCall if the bot is looping and trying to exit - * ```json - * { - * conditions: [{ - * type: 'liquid', - * liquid: `{% assign recentMessages = messages | last: 6 %} - * {% assign userMessages = recentMessages | where: 'role', 'user' | reverse %} - * {% if userMessages.size < 3 %} - * false - * {% else %} - * {% assign msg1 = userMessages[0].content | downcase %} - * {% assign msg2 = userMessages[1].content | downcase %} - * {% assign msg3 = userMessages[2].content | downcase %} - * {% comment %} Check for repetitive messages {% endcomment %} - * {% if msg1 == msg2 or msg1 == msg3 or msg2 == msg3 %} - * true - * {% comment %} Check for common loop phrases {% endcomment %} - * {% elsif msg1 contains 'cool thanks' or msg2 contains 'cool thanks' or msg3 contains 'cool thanks' %} - * true - * {% elsif msg1 contains 'okay thanks' or msg2 contains 'okay thanks' or msg3 contains 'okay thanks' %} - * true - * {% elsif msg1 contains 'got it' or msg2 contains 'got it' or msg3 contains 'got it' %} - * true - * {% else %} - * false - * {% endif %} - * {% endif %}` - * }] - * } - * ``` + * @default 'wav;l16' */ - rejectionPlan?: ToolRejectionPlan; -} - -export interface CreateGoHighLevelCalendarAvailabilityToolDTO { - /** Messages spoken while the tool is running. Multiple request-start messages are variants. For request-response-delayed, same timing means variants and different timings mean staged updates. */ - messages?: ( - | ToolMessageStart - | ToolMessageComplete - | ToolMessageFailed - | ToolMessageDelayed - )[]; - /** The type of tool. "gohighlevel.calendar.availability.check" for GoHighLevel Calendar Availability Check tool. */ - type: "gohighlevel.calendar.availability.check"; + recordingFormat?: "wav;l16" | "mp3"; /** - * This is the plan to reject a tool call based on the conversation state. + * This determines whether to use custom storage (S3 or GCP) for call recordings when storage credentials are configured. * - * // Example 1: Reject endCall if user didn't say goodbye - * ```json - * { - * conditions: [{ - * type: 'regex', - * regex: '(?i)\\b(bye|goodbye|farewell|see you later|take care)\\b', - * target: { position: -1, role: 'user' }, - * negate: true // Reject if pattern does NOT match - * }] - * } - * ``` + * When set to false, recordings will be stored on Vapi's storage instead of your custom storage, even if you have custom storage credentials configured. * - * // Example 2: Reject transfer if user is actually asking a question - * ```json - * { - * conditions: [{ - * type: 'regex', - * regex: '\\?', - * target: { position: -1, role: 'user' } - * }] - * } - * ``` + * Usage: + * - Set to false if you have custom storage configured but want to store recordings on Vapi's storage for this assistant. + * - Set to true (or leave unset) to use your custom storage for recordings when available. * - * // Example 3: Reject transfer if user didn't mention transfer recently - * ```json - * { - * conditions: [{ - * type: 'liquid', - * liquid: `{% assign recentMessages = messages | last: 5 %} - * {% assign userMessages = recentMessages | where: 'role', 'user' %} - * {% assign mentioned = false %} - * {% for msg in userMessages %} - * {% if msg.content contains 'transfer' or msg.content contains 'connect' or msg.content contains 'speak to' %} - * {% assign mentioned = true %} - * {% break %} - * {% endif %} - * {% endfor %} - * {% if mentioned %} - * false - * {% else %} - * true - * {% endif %}` - * }] - * } - * ``` + * If your organization has ZDR (zero data retention) or PCI enabled, recordings are never written to Vapi storage. In that case, false means "do not use my custom storage", so nothing is stored at all. * - * // Example 4: Reject endCall if the bot is looping and trying to exit - * ```json - * { - * conditions: [{ - * type: 'liquid', - * liquid: `{% assign recentMessages = messages | last: 6 %} - * {% assign userMessages = recentMessages | where: 'role', 'user' | reverse %} - * {% if userMessages.size < 3 %} - * false - * {% else %} - * {% assign msg1 = userMessages[0].content | downcase %} - * {% assign msg2 = userMessages[1].content | downcase %} - * {% assign msg3 = userMessages[2].content | downcase %} - * {% comment %} Check for repetitive messages {% endcomment %} - * {% if msg1 == msg2 or msg1 == msg3 or msg2 == msg3 %} - * true - * {% comment %} Check for common loop phrases {% endcomment %} - * {% elsif msg1 contains 'cool thanks' or msg2 contains 'cool thanks' or msg3 contains 'cool thanks' %} - * true - * {% elsif msg1 contains 'okay thanks' or msg2 contains 'okay thanks' or msg3 contains 'okay thanks' %} - * true - * {% elsif msg1 contains 'got it' or msg2 contains 'got it' or msg3 contains 'got it' %} - * true - * {% else %} - * false - * {% endif %} - * {% endif %}` - * }] - * } - * ``` + * @default true + * @example true */ - rejectionPlan?: ToolRejectionPlan; -} - -export interface CreateGoHighLevelCalendarEventCreateToolDTO { - /** Messages spoken while the tool is running. Multiple request-start messages are variants. For request-response-delayed, same timing means variants and different timings mean staged updates. */ - messages?: ( - | ToolMessageStart - | ToolMessageComplete - | ToolMessageFailed - | ToolMessageDelayed - )[]; - /** The type of tool. "gohighlevel.calendar.event.create" for GoHighLevel Calendar Event Create tool. */ - type: "gohighlevel.calendar.event.create"; + recordingUseCustomStorageEnabled?: boolean; /** - * This is the plan to reject a tool call based on the conversation state. + * This determines whether the video is recorded during the call. Defaults to false. Only relevant for `webCall` type. * - * // Example 1: Reject endCall if user didn't say goodbye - * ```json - * { - * conditions: [{ - * type: 'regex', - * regex: '(?i)\\b(bye|goodbye|farewell|see you later|take care)\\b', - * target: { position: -1, role: 'user' }, - * negate: true // Reject if pattern does NOT match - * }] - * } - * ``` + * You can find the video recording at `call.artifact.videoRecordingUrl` after the call is ended. * - * // Example 2: Reject transfer if user is actually asking a question - * ```json - * { - * conditions: [{ - * type: 'regex', - * regex: '\\?', - * target: { position: -1, role: 'user' } - * }] - * } - * ``` + * @default false + * @example false + */ + videoRecordingEnabled?: boolean; + /** + * This determines whether the artifact contains the full message history, even after handoff context engineering. Defaults to false. + * @example false + */ + fullMessageHistoryEnabled?: boolean; + /** + * This determines whether the SIP packet capture is enabled. Defaults to true. Only relevant for `phone` type calls where phone number's provider is `vapi` or `byo-phone-number`. * - * // Example 3: Reject transfer if user didn't mention transfer recently - * ```json - * { - * conditions: [{ - * type: 'liquid', - * liquid: `{% assign recentMessages = messages | last: 5 %} - * {% assign userMessages = recentMessages | where: 'role', 'user' %} - * {% assign mentioned = false %} - * {% for msg in userMessages %} - * {% if msg.content contains 'transfer' or msg.content contains 'connect' or msg.content contains 'speak to' %} - * {% assign mentioned = true %} - * {% break %} - * {% endif %} - * {% endfor %} - * {% if mentioned %} - * false - * {% else %} - * true - * {% endif %}` - * }] - * } - * ``` + * You can find the packet capture at `call.artifact.pcapUrl` after the call is ended. * - * // Example 4: Reject endCall if the bot is looping and trying to exit - * ```json - * { - * conditions: [{ - * type: 'liquid', - * liquid: `{% assign recentMessages = messages | last: 6 %} - * {% assign userMessages = recentMessages | where: 'role', 'user' | reverse %} - * {% if userMessages.size < 3 %} - * false - * {% else %} - * {% assign msg1 = userMessages[0].content | downcase %} - * {% assign msg2 = userMessages[1].content | downcase %} - * {% assign msg3 = userMessages[2].content | downcase %} - * {% comment %} Check for repetitive messages {% endcomment %} - * {% if msg1 == msg2 or msg1 == msg3 or msg2 == msg3 %} - * true - * {% comment %} Check for common loop phrases {% endcomment %} - * {% elsif msg1 contains 'cool thanks' or msg2 contains 'cool thanks' or msg3 contains 'cool thanks' %} - * true - * {% elsif msg1 contains 'okay thanks' or msg2 contains 'okay thanks' or msg3 contains 'okay thanks' %} - * true - * {% elsif msg1 contains 'got it' or msg2 contains 'got it' or msg3 contains 'got it' %} - * true - * {% else %} - * false - * {% endif %} - * {% endif %}` - * }] - * } - * ``` + * @default true + * @example true */ - rejectionPlan?: ToolRejectionPlan; -} - -export interface CreateGoHighLevelContactCreateToolDTO { - /** Messages spoken while the tool is running. Multiple request-start messages are variants. For request-response-delayed, same timing means variants and different timings mean staged updates. */ - messages?: ( - | ToolMessageStart - | ToolMessageComplete - | ToolMessageFailed - | ToolMessageDelayed - )[]; - /** The type of tool. "gohighlevel.contact.create" for GoHighLevel Contact Create tool. */ - type: "gohighlevel.contact.create"; + pcapEnabled?: boolean; /** - * This is the plan to reject a tool call based on the conversation state. - * - * // Example 1: Reject endCall if user didn't say goodbye - * ```json - * { - * conditions: [{ - * type: 'regex', - * regex: '(?i)\\b(bye|goodbye|farewell|see you later|take care)\\b', - * target: { position: -1, role: 'user' }, - * negate: true // Reject if pattern does NOT match - * }] - * } - * ``` + * This is the path where the SIP packet capture will be uploaded. This is only used if you have provided S3 or GCP credentials on the Provider Credentials page in the Dashboard. * - * // Example 2: Reject transfer if user is actually asking a question - * ```json - * { - * conditions: [{ - * type: 'regex', - * regex: '\\?', - * target: { position: -1, role: 'user' } - * }] - * } - * ``` + * If credential.s3PathPrefix or credential.bucketPlan.path is set, this will append to it. * - * // Example 3: Reject transfer if user didn't mention transfer recently - * ```json - * { - * conditions: [{ - * type: 'liquid', - * liquid: `{% assign recentMessages = messages | last: 5 %} - * {% assign userMessages = recentMessages | where: 'role', 'user' %} - * {% assign mentioned = false %} - * {% for msg in userMessages %} - * {% if msg.content contains 'transfer' or msg.content contains 'connect' or msg.content contains 'speak to' %} - * {% assign mentioned = true %} - * {% break %} - * {% endif %} - * {% endfor %} - * {% if mentioned %} - * false - * {% else %} - * true - * {% endif %}` - * }] - * } - * ``` + * Usage: + * - If you want to upload the packet capture to a specific path, set this to the path. Example: `/my-assistant-captures`. + * - If you want to upload the packet capture to the root of the bucket, set this to `/`. * - * // Example 4: Reject endCall if the bot is looping and trying to exit - * ```json - * { - * conditions: [{ - * type: 'liquid', - * liquid: `{% assign recentMessages = messages | last: 6 %} - * {% assign userMessages = recentMessages | where: 'role', 'user' | reverse %} - * {% if userMessages.size < 3 %} - * false - * {% else %} - * {% assign msg1 = userMessages[0].content | downcase %} - * {% assign msg2 = userMessages[1].content | downcase %} - * {% assign msg3 = userMessages[2].content | downcase %} - * {% comment %} Check for repetitive messages {% endcomment %} - * {% if msg1 == msg2 or msg1 == msg3 or msg2 == msg3 %} - * true - * {% comment %} Check for common loop phrases {% endcomment %} - * {% elsif msg1 contains 'cool thanks' or msg2 contains 'cool thanks' or msg3 contains 'cool thanks' %} - * true - * {% elsif msg1 contains 'okay thanks' or msg2 contains 'okay thanks' or msg3 contains 'okay thanks' %} - * true - * {% elsif msg1 contains 'got it' or msg2 contains 'got it' or msg3 contains 'got it' %} - * true - * {% else %} - * false - * {% endif %} - * {% endif %}` - * }] - * } - * ``` + * @default '/' + * @example "/pcaps" */ - rejectionPlan?: ToolRejectionPlan; -} - -export interface CreateGoHighLevelContactGetToolDTO { - /** Messages spoken while the tool is running. Multiple request-start messages are variants. For request-response-delayed, same timing means variants and different timings mean staged updates. */ - messages?: ( - | ToolMessageStart - | ToolMessageComplete - | ToolMessageFailed - | ToolMessageDelayed - )[]; - /** The type of tool. "gohighlevel.contact.get" for GoHighLevel Contact Get tool. */ - type: "gohighlevel.contact.get"; + pcapS3PathPrefix?: string; /** - * This is the plan to reject a tool call based on the conversation state. + * This determines whether to use custom storage (S3 or GCP) for SIP packet captures when storage credentials are configured. * - * // Example 1: Reject endCall if user didn't say goodbye - * ```json - * { - * conditions: [{ - * type: 'regex', - * regex: '(?i)\\b(bye|goodbye|farewell|see you later|take care)\\b', - * target: { position: -1, role: 'user' }, - * negate: true // Reject if pattern does NOT match - * }] - * } - * ``` + * When set to false, packet captures will be stored on Vapi's storage instead of your custom storage, even if you have custom storage credentials configured. * - * // Example 2: Reject transfer if user is actually asking a question - * ```json - * { - * conditions: [{ - * type: 'regex', - * regex: '\\?', - * target: { position: -1, role: 'user' } - * }] - * } - * ``` + * Usage: + * - Set to false if you have custom storage configured but want to store packet captures on Vapi's storage for this assistant. + * - Set to true (or leave unset) to use your custom storage for packet captures when available. * - * // Example 3: Reject transfer if user didn't mention transfer recently - * ```json - * { - * conditions: [{ - * type: 'liquid', - * liquid: `{% assign recentMessages = messages | last: 5 %} - * {% assign userMessages = recentMessages | where: 'role', 'user' %} - * {% assign mentioned = false %} - * {% for msg in userMessages %} - * {% if msg.content contains 'transfer' or msg.content contains 'connect' or msg.content contains 'speak to' %} - * {% assign mentioned = true %} - * {% break %} - * {% endif %} - * {% endfor %} - * {% if mentioned %} - * false - * {% else %} - * true - * {% endif %}` - * }] - * } - * ``` + * If your organization has ZDR (zero data retention) or PCI enabled, packet captures are never written to Vapi storage. In that case, false means "do not use my custom storage", so nothing is stored at all. * - * // Example 4: Reject endCall if the bot is looping and trying to exit - * ```json - * { - * conditions: [{ - * type: 'liquid', - * liquid: `{% assign recentMessages = messages | last: 6 %} - * {% assign userMessages = recentMessages | where: 'role', 'user' | reverse %} - * {% if userMessages.size < 3 %} - * false - * {% else %} - * {% assign msg1 = userMessages[0].content | downcase %} - * {% assign msg2 = userMessages[1].content | downcase %} - * {% assign msg3 = userMessages[2].content | downcase %} - * {% comment %} Check for repetitive messages {% endcomment %} - * {% if msg1 == msg2 or msg1 == msg3 or msg2 == msg3 %} - * true - * {% comment %} Check for common loop phrases {% endcomment %} - * {% elsif msg1 contains 'cool thanks' or msg2 contains 'cool thanks' or msg3 contains 'cool thanks' %} - * true - * {% elsif msg1 contains 'okay thanks' or msg2 contains 'okay thanks' or msg3 contains 'okay thanks' %} - * true - * {% elsif msg1 contains 'got it' or msg2 contains 'got it' or msg3 contains 'got it' %} - * true - * {% else %} - * false - * {% endif %} - * {% endif %}` - * }] - * } - * ``` + * @default true + * @example true */ - rejectionPlan?: ToolRejectionPlan; -} - -export interface OpenAIMessage { - /** @maxLength 100000000 */ - content: string | null; - role: "assistant" | "function" | "user" | "system" | "tool"; -} - -export interface ToolRef { + pcapUseCustomStorageEnabled?: boolean; /** - * This is the unique identifier of the tool whose version is being pinned. - * @format uuid + * This determines whether the call logs are enabled. Defaults to true. + * + * @default true + * @example true */ - toolId: string; - /** Public version label of the tool, e.g. "v3" */ - version: string; -} - -export interface AnyscaleModel { - /** This is the starting state for the conversation. */ - messages?: OpenAIMessage[]; + loggingEnabled?: boolean; /** - * These are the tools that the assistant can use during the call. To use existing tools, use `toolIds`. + * This determines whether to use custom storage (S3 or GCP) for call logs when storage credentials are configured. * - * Both `tools` and `toolIds` can be used together. - */ - tools?: ( - | CreateApiRequestToolDTO - | CreateBashToolDTO - | CreateCodeToolDTO - | CreateComputerToolDTO - | CreateDtmfToolDTO - | CreateEndCallToolDTO - | CreateFunctionToolDTO - | CreateGoHighLevelCalendarAvailabilityToolDTO - | CreateGoHighLevelCalendarEventCreateToolDTO - | CreateGoHighLevelContactCreateToolDTO - | CreateGoHighLevelContactGetToolDTO - | CreateGoogleCalendarCheckAvailabilityToolDTO - | CreateGoogleCalendarCreateEventToolDTO - | CreateGoogleSheetsRowAppendToolDTO - | CreateHandoffToolDTO - | CreateMcpToolDTO - | CreateQueryToolDTO - | CreateSlackSendMessageToolDTO - | CreateSmsToolDTO - | CreateTextEditorToolDTO - | CreateTransferCallToolDTO - | CreateSipRequestToolDTO - | CreateVoicemailToolDTO - )[]; - /** - * These are the tools that the assistant can use during the call. To use transient tools, use `tools`. + * When set to false, logs will be stored on Vapi's storage instead of your custom storage, even if you have custom storage credentials configured. * - * Both `tools` and `toolIds` can be used together. - */ - toolIds?: string[]; - /** - * These are version-pinned references to tools. Each entry pins a specific - * version of a tool by `(toolId, version)`. When the same `toolId` appears - * in both `toolIds` and `toolRefs[]`, the `toolRefs` pin wins (the - * `toolIds` entry is dropped at write time). - */ - toolRefs?: ToolRef[]; - /** These are the options for the knowledge base. */ - knowledgeBase?: CreateCustomKnowledgeBaseDTO; - provider: "anyscale"; - /** This is the name of the model. Ex. cognitivecomputations/dolphin-mixtral-8x7b */ - model: string; - /** - * This is the temperature that will be used for calls. Default is 0.5. - * @min 0 - * @max 2 - */ - temperature?: number; - /** - * This is the max number of tokens that the assistant will be allowed to generate in each turn of the conversation. Default is 250. On gpt-6-luna and claude-haiku-5-5 no cap is applied unless you set one (claude-haiku-5-5 sends its 128,000-token maximum), because reasoning uses output tokens and a small cap can leave the reply empty. - * @min 50 - * @max 10000 - */ - maxTokens?: number; - /** - * This determines whether we detect user's emotion while they speak and send it as an additional info to model. + * Usage: + * - Set to false if you have custom storage configured but want to store logs on Vapi's storage for this assistant. + * - Set to true (or leave unset) to use your custom storage for logs when available. * - * Default `false` because the model is usually are good at understanding the user's emotion from text. + * If your organization has ZDR (zero data retention) or PCI enabled, logs are never written to Vapi storage. In that case, false means "do not use my custom storage", so nothing is stored at all. * - * @default false + * @default true + * @example true */ - emotionRecognitionEnabled?: boolean; + loggingUseCustomStorageEnabled?: boolean; + /** This is the plan for `call.artifact.transcript`. To disable, set `transcriptPlan.enabled` to false. */ + transcriptPlan?: TranscriptPlan; /** - * This sets how many turns at the start of the conversation to use a smaller, faster model from the same provider before switching to the primary model. Example, gpt-3.5-turbo if provider is openai. - * - * Default is 0. + * This is the path where the recording will be uploaded. This is only used if you have provided S3 or GCP credentials on the Provider Credentials page in the Dashboard. * - * @default 0 - * @min 0 - */ - numFastTurns?: number; -} - -export interface AnthropicThinkingConfig { - type: "enabled"; - /** - * The maximum number of tokens to allocate for thinking. - * Must be between 1024 and 100000 tokens. - * @min 1024 - * @max 100000 - */ - budgetTokens: number; -} - -export interface AnthropicModel { - /** This is the starting state for the conversation. */ - messages?: OpenAIMessage[]; - /** - * These are the tools that the assistant can use during the call. To use existing tools, use `toolIds`. + * If credential.s3PathPrefix or credential.bucketPlan.path is set, this will append to it. * - * Both `tools` and `toolIds` can be used together. - */ - tools?: ( - | CreateApiRequestToolDTO - | CreateBashToolDTO - | CreateCodeToolDTO - | CreateComputerToolDTO - | CreateDtmfToolDTO - | CreateEndCallToolDTO - | CreateFunctionToolDTO - | CreateGoHighLevelCalendarAvailabilityToolDTO - | CreateGoHighLevelCalendarEventCreateToolDTO - | CreateGoHighLevelContactCreateToolDTO - | CreateGoHighLevelContactGetToolDTO - | CreateGoogleCalendarCheckAvailabilityToolDTO - | CreateGoogleCalendarCreateEventToolDTO - | CreateGoogleSheetsRowAppendToolDTO - | CreateHandoffToolDTO - | CreateMcpToolDTO - | CreateQueryToolDTO - | CreateSlackSendMessageToolDTO - | CreateSmsToolDTO - | CreateTextEditorToolDTO - | CreateTransferCallToolDTO - | CreateSipRequestToolDTO - | CreateVoicemailToolDTO - )[]; - /** - * These are the tools that the assistant can use during the call. To use transient tools, use `tools`. + * Usage: + * - If you want to upload the recording to a specific path, set this to the path. Example: `/my-assistant-recordings`. + * - If you want to upload the recording to the root of the bucket, set this to `/`. * - * Both `tools` and `toolIds` can be used together. - */ - toolIds?: string[]; - /** - * These are version-pinned references to tools. Each entry pins a specific - * version of a tool by `(toolId, version)`. When the same `toolId` appears - * in both `toolIds` and `toolRefs[]`, the `toolRefs` pin wins (the - * `toolIds` entry is dropped at write time). + * @default '/' */ - toolRefs?: ToolRef[]; - /** These are the options for the knowledge base. */ - knowledgeBase?: CreateCustomKnowledgeBaseDTO; - /** The specific Anthropic/Claude model that will be used. */ - model: - | "claude-3-opus-20240229" - | "claude-3-sonnet-20240229" - | "claude-3-haiku-20240307" - | "claude-3-5-sonnet-20240620" - | "claude-3-5-sonnet-20241022" - | "claude-3-5-haiku-20241022" - | "claude-3-7-sonnet-20250219" - | "claude-opus-4-20250514" - | "claude-opus-4-5-20251101" - | "claude-opus-4-6" - | "claude-sonnet-4-20250514" - | "claude-sonnet-4-5-20250929" - | "claude-sonnet-4-6" - | "claude-sonnet-5" - | "claude-haiku-4-5-20251001" - | "claude-haiku-5-5"; + recordingPath?: string; /** - * Reasoning effort for claude-haiku-5-5. `none` turns thinking off. `low` to `max` - * use adaptive thinking at that effort; higher effort can add latency before the - * model speaks. Unset means `none`. Rejected for every other model. + * This is an array of structured output IDs to be calculated during the call. + * The outputs will be extracted and stored in `call.artifact.structuredOutputs` after the call is ended. */ - reasoningEffort?: "none" | "low" | "medium" | "high" | "xhigh" | "max"; - /** The provider identifier for Anthropic. */ - provider: "anthropic"; + structuredOutputIds?: string[]; /** - * Optional configuration for Anthropic's thinking feature. - * Only applicable for claude-3-7-sonnet-20250219 model. - * If provided, maxTokens must be greater than thinking.budgetTokens. + * This is an array of transient structured outputs to be calculated during the call. + * The outputs will be extracted and stored in `call.artifact.structuredOutputs` after the call is ended. + * Use this to provide inline structured output configurations instead of referencing existing ones via structuredOutputIds. */ - thinking?: AnthropicThinkingConfig; + structuredOutputs?: CreateStructuredOutputDTO[]; /** - * This is the temperature that will be used for calls. Default is 0.5. - * @min 0 - * @max 2 + * This is an array of scorecard IDs that will be evaluated based on the structured outputs extracted during the call. + * The scorecards will be evaluated and the results will be stored in `call.artifact.scorecards` after the call has ended. */ - temperature?: number; + scorecardIds?: string[]; /** - * This is the max number of tokens that the assistant will be allowed to generate in each turn of the conversation. Default is 250. On gpt-6-luna and claude-haiku-5-5 no cap is applied unless you set one (claude-haiku-5-5 sends its 128,000-token maximum), because reasoning uses output tokens and a small cap can leave the reply empty. - * @min 50 - * @max 10000 + * This is the array of scorecards that will be evaluated based on the structured outputs extracted during the call. + * The scorecards will be evaluated and the results will be stored in `call.artifact.scorecards` after the call has ended. */ - maxTokens?: number; + scorecards?: CreateScorecardDTO[]; /** - * This determines whether we detect user's emotion while they speak and send it as an additional info to model. + * This is the path where the call logs will be uploaded. This is only used if you have provided S3 or GCP credentials on the Provider Credentials page in the Dashboard. * - * Default `false` because the model is usually are good at understanding the user's emotion from text. + * If credential.s3PathPrefix or credential.bucketPlan.path is set, this will append to it. * - * @default false + * Usage: + * - If you want to upload the call logs to a specific path, set this to the path. Example: `/my-assistant-logs`. + * - If you want to upload the call logs to the root of the bucket, set this to `/`. + * + * @default '/' */ - emotionRecognitionEnabled?: boolean; + loggingPath?: string; +} + +export interface StopSpeakingPlan { /** - * This sets how many turns at the start of the conversation to use a smaller, faster model from the same provider before switching to the primary model. Example, gpt-3.5-turbo if provider is openai. + * This is the number of words that the customer has to say before the assistant will stop talking. * - * Default is 0. + * Words like "stop", "actually", "no", etc. will always interrupt immediately regardless of this value. + * + * Words like "okay", "yeah", "right" will never interrupt. + * + * When set to 0, `voiceSeconds` is used in addition to the transcriptions to determine the customer has started speaking. + * + * Defaults to 0. * * @default 0 * @min 0 + * @max 10 + * @example 0 */ - numFastTurns?: number; -} - -export interface AnthropicBedrockModel { - /** This is the starting state for the conversation. */ - messages?: OpenAIMessage[]; + numWords?: number; /** - * These are the tools that the assistant can use during the call. To use existing tools, use `toolIds`. + * This is the seconds customer has to speak before the assistant stops talking. This uses the VAD (Voice Activity Detection) spike to determine if the customer has started speaking. * - * Both `tools` and `toolIds` can be used together. - */ - tools?: ( - | CreateApiRequestToolDTO - | CreateBashToolDTO - | CreateCodeToolDTO - | CreateComputerToolDTO - | CreateDtmfToolDTO - | CreateEndCallToolDTO - | CreateFunctionToolDTO - | CreateGoHighLevelCalendarAvailabilityToolDTO - | CreateGoHighLevelCalendarEventCreateToolDTO - | CreateGoHighLevelContactCreateToolDTO - | CreateGoHighLevelContactGetToolDTO - | CreateGoogleCalendarCheckAvailabilityToolDTO - | CreateGoogleCalendarCreateEventToolDTO - | CreateGoogleSheetsRowAppendToolDTO - | CreateHandoffToolDTO - | CreateMcpToolDTO - | CreateQueryToolDTO - | CreateSlackSendMessageToolDTO - | CreateSmsToolDTO - | CreateTextEditorToolDTO - | CreateTransferCallToolDTO - | CreateSipRequestToolDTO - | CreateVoicemailToolDTO - )[]; - /** - * These are the tools that the assistant can use during the call. To use transient tools, use `tools`. + * Considerations: + * - A lower value might be more responsive but could potentially pick up non-speech sounds. + * - A higher value reduces false positives but might slightly delay the detection of speech onset. * - * Both `tools` and `toolIds` can be used together. - */ - toolIds?: string[]; - /** - * These are version-pinned references to tools. Each entry pins a specific - * version of a tool by `(toolId, version)`. When the same `toolId` appears - * in both `toolIds` and `toolRefs[]`, the `toolRefs` pin wins (the - * `toolIds` entry is dropped at write time). - */ - toolRefs?: ToolRef[]; - /** These are the options for the knowledge base. */ - knowledgeBase?: CreateCustomKnowledgeBaseDTO; - /** The provider identifier for Anthropic via AWS Bedrock. */ - provider: "anthropic-bedrock"; - /** The specific Anthropic/Claude model that will be used via Bedrock. */ - model: - | "claude-3-opus-20240229" - | "claude-3-sonnet-20240229" - | "claude-3-haiku-20240307" - | "claude-3-5-sonnet-20240620" - | "claude-3-5-sonnet-20241022" - | "claude-3-5-haiku-20241022" - | "claude-3-7-sonnet-20250219" - | "claude-opus-4-20250514" - | "claude-opus-4-5-20251101" - | "claude-opus-4-6" - | "claude-sonnet-4-20250514" - | "claude-sonnet-4-5-20250929" - | "claude-sonnet-4-6" - | "claude-haiku-4-5-20251001" - | "claude-haiku-5-5" - | "global.anthropic.claude-haiku-4-5-20251001-v1:0"; - /** - * At most one same-provider Bedrock fallback model, tried if the primary fails. Cannot be combined with thinking in this release. Resolution uses the call's Bedrock credential region (or ANTHROPIC_BEDROCK_AWS_REGION). Names with no inference profile in that region are skipped and warned, never remapped to US or global. On Vapi EU, fallback names without an EU inference profile are rejected at write time. - * @maxItems 1 - * @example ["claude-haiku-4-5-20251001"] - */ - fallbackModels?: - | "claude-3-opus-20240229" - | "claude-3-sonnet-20240229" - | "claude-3-haiku-20240307" - | "claude-3-5-sonnet-20240620" - | "claude-3-5-sonnet-20241022" - | "claude-3-5-haiku-20241022" - | "claude-3-7-sonnet-20250219" - | "claude-opus-4-20250514" - | "claude-opus-4-5-20251101" - | "claude-opus-4-6" - | "claude-sonnet-4-20250514" - | "claude-sonnet-4-5-20250929" - | "claude-sonnet-4-6" - | "claude-haiku-4-5-20251001" - | "claude-haiku-5-5" - | "global.anthropic.claude-haiku-4-5-20251001-v1:0"; - /** - * Reasoning effort for claude-haiku-5-5. `none` turns thinking off. `low` to `max` - * use adaptive thinking at that effort; higher effort can add latency before the - * model speaks. Unset means `none`. Rejected for every other model. + * This is only used if `numWords` is set to 0. + * + * Defaults to 0.2 + * + * @default 0.2 + * @min 0 + * @max 0.5 + * @example 0.2 */ - reasoningEffort?: "none" | "low" | "medium" | "high" | "xhigh" | "max"; + voiceSeconds?: number; /** - * Optional configuration for Anthropic's thinking feature. - * Only applicable for claude-3-7-sonnet-20250219 model. - * If provided, maxTokens must be greater than thinking.budgetTokens. + * This is the seconds to wait before the assistant will start talking again after being interrupted. + * + * Defaults to 1. + * + * @default 1 + * @min 0 + * @max 10 + * @example 1 */ - thinking?: AnthropicThinkingConfig; + backoffSeconds?: number; /** - * This is the temperature that will be used for calls. Default is 0.5. - * @min 0 - * @max 2 + * These are the phrases that will never interrupt the assistant, even if numWords threshold is met. + * These are typically acknowledgement or backchanneling phrases. + * @default ["i understand","i see","i got it","i hear you","im listening","im with you","right","okay","ok","sure","alright","got it","understood","yeah","yes","uh-huh","mm-hmm","gotcha","mhmm","ah","yeah okay","yeah sure"] + * @example ["i understand","i see","i got it","i hear you","im listening","im with you","right","okay","ok","sure","alright","got it","understood","yeah","yes","uh-huh","mm-hmm","gotcha","mhmm","ah","yeah okay","yeah sure"] */ - temperature?: number; + acknowledgementPhrases?: string[]; /** - * This is the max number of tokens that the assistant will be allowed to generate in each turn of the conversation. Default is 250. On gpt-6-luna and claude-haiku-5-5 no cap is applied unless you set one (claude-haiku-5-5 sends its 128,000-token maximum), because reasoning uses output tokens and a small cap can leave the reply empty. - * @min 50 - * @max 10000 + * These are the phrases that will always interrupt the assistant immediately, regardless of numWords. + * These are typically phrases indicating disagreement or desire to stop. + * @default ["stop","shut","up","enough","quiet","silence","but","dont","not","no","hold","wait","cut","pause","nope","nah","nevermind","never","bad","actually"] + * @example ["stop","shut","up","enough","quiet","silence","but","dont","not","no","hold","wait","cut","pause","nope","nah","nevermind","never","bad","actually"] */ - maxTokens?: number; + interruptionPhrases?: string[]; +} + +export interface MonitorPlan { /** - * This determines whether we detect user's emotion while they speak and send it as an additional info to model. + * This determines whether the assistant's calls allow live listening. Defaults to true. * - * Default `false` because the model is usually are good at understanding the user's emotion from text. + * Fetch `call.monitor.listenUrl` to get the live listening URL. * - * @default false + * @default true + * @example false */ - emotionRecognitionEnabled?: boolean; + listenEnabled?: boolean; /** - * This sets how many turns at the start of the conversation to use a smaller, faster model from the same provider before switching to the primary model. Example, gpt-3.5-turbo if provider is openai. + * This enables authentication on the `call.monitor.listenUrl`. * - * Default is 0. + * If `listenAuthenticationEnabled` is `true`, the `call.monitor.listenUrl` will require an `Authorization: Bearer ` header. * - * @default 0 - * @min 0 + * @default false + * @example false */ - numFastTurns?: number; -} - -export interface CerebrasModel { - /** This is the starting state for the conversation. */ - messages?: OpenAIMessage[]; + listenAuthenticationEnabled?: boolean; /** - * These are the tools that the assistant can use during the call. To use existing tools, use `toolIds`. + * This determines whether the assistant's calls allow live control. Defaults to true. * - * Both `tools` and `toolIds` can be used together. - */ - tools?: ( - | CreateApiRequestToolDTO - | CreateBashToolDTO - | CreateCodeToolDTO - | CreateComputerToolDTO - | CreateDtmfToolDTO - | CreateEndCallToolDTO - | CreateFunctionToolDTO - | CreateGoHighLevelCalendarAvailabilityToolDTO - | CreateGoHighLevelCalendarEventCreateToolDTO - | CreateGoHighLevelContactCreateToolDTO - | CreateGoHighLevelContactGetToolDTO - | CreateGoogleCalendarCheckAvailabilityToolDTO - | CreateGoogleCalendarCreateEventToolDTO - | CreateGoogleSheetsRowAppendToolDTO - | CreateHandoffToolDTO - | CreateMcpToolDTO - | CreateQueryToolDTO - | CreateSlackSendMessageToolDTO - | CreateSmsToolDTO - | CreateTextEditorToolDTO - | CreateTransferCallToolDTO - | CreateSipRequestToolDTO - | CreateVoicemailToolDTO - )[]; - /** - * These are the tools that the assistant can use during the call. To use transient tools, use `tools`. + * Fetch `call.monitor.controlUrl` to get the live control URL. * - * Both `tools` and `toolIds` can be used together. - */ - toolIds?: string[]; - /** - * These are version-pinned references to tools. Each entry pins a specific - * version of a tool by `(toolId, version)`. When the same `toolId` appears - * in both `toolIds` and `toolRefs[]`, the `toolRefs` pin wins (the - * `toolIds` entry is dropped at write time). - */ - toolRefs?: ToolRef[]; - /** These are the options for the knowledge base. */ - knowledgeBase?: CreateCustomKnowledgeBaseDTO; - /** This is the name of the model. Ex. cognitivecomputations/dolphin-mixtral-8x7b */ - model: "llama3.1-8b" | "llama-3.3-70b"; - provider: "cerebras"; - /** - * This is the temperature that will be used for calls. Default is 0.5. - * @min 0 - * @max 2 - */ - temperature?: number; - /** - * This is the max number of tokens that the assistant will be allowed to generate in each turn of the conversation. Default is 250. On gpt-6-luna and claude-haiku-5-5 no cap is applied unless you set one (claude-haiku-5-5 sends its 128,000-token maximum), because reasoning uses output tokens and a small cap can leave the reply empty. - * @min 50 - * @max 10000 + * To use, send any control message via a POST request to `call.monitor.controlUrl`. Here are the types of controls supported: https://docs.vapi.ai/api-reference/messages/client-inbound-message + * + * @default true + * @example false */ - maxTokens?: number; + controlEnabled?: boolean; /** - * This determines whether we detect user's emotion while they speak and send it as an additional info to model. + * This enables authentication on the `call.monitor.controlUrl`. * - * Default `false` because the model is usually are good at understanding the user's emotion from text. + * If `controlAuthenticationEnabled` is `true`, the `call.monitor.controlUrl` will require an `Authorization: Bearer ` header. * * @default false + * @example false */ - emotionRecognitionEnabled?: boolean; + controlAuthenticationEnabled?: boolean; /** - * This sets how many turns at the start of the conversation to use a smaller, faster model from the same provider before switching to the primary model. Example, gpt-3.5-turbo if provider is openai. - * - * Default is 0. + * This the set of monitor ids that are attached to the assistant. + * The source of truth for the monitor ids is the assistant_monitor join table. + * This field can be used for transient assistants and to update assistants with new monitor ids. * - * @default 0 - * @min 0 + * @default [] + * @example ["123e4567-e89b-12d3-a456-426614174000"] */ - numFastTurns?: number; + monitorIds?: string[]; } -export interface CustomLLMModel { - /** This is the starting state for the conversation. */ - messages?: OpenAIMessage[]; +export interface KeypadInputPlan { /** - * These are the tools that the assistant can use during the call. To use existing tools, use `toolIds`. + * This keeps track of whether the user has enabled keypad input. + * By default, it is off. * - * Both `tools` and `toolIds` can be used together. + * @default false */ - tools?: ( - | CreateApiRequestToolDTO - | CreateBashToolDTO - | CreateCodeToolDTO - | CreateComputerToolDTO - | CreateDtmfToolDTO - | CreateEndCallToolDTO - | CreateFunctionToolDTO - | CreateGoHighLevelCalendarAvailabilityToolDTO - | CreateGoHighLevelCalendarEventCreateToolDTO - | CreateGoHighLevelContactCreateToolDTO - | CreateGoHighLevelContactGetToolDTO - | CreateGoogleCalendarCheckAvailabilityToolDTO - | CreateGoogleCalendarCreateEventToolDTO - | CreateGoogleSheetsRowAppendToolDTO - | CreateHandoffToolDTO - | CreateMcpToolDTO - | CreateQueryToolDTO - | CreateSlackSendMessageToolDTO - | CreateSmsToolDTO - | CreateTextEditorToolDTO - | CreateTransferCallToolDTO - | CreateSipRequestToolDTO - | CreateVoicemailToolDTO - )[]; + enabled?: boolean; /** - * These are the tools that the assistant can use during the call. To use transient tools, use `tools`. + * This is the time in seconds to wait before processing the input. + * If the input is not received within this time, the input will be ignored. + * If set to "off", the input will be processed when the user enters a delimiter or immediately if no delimiter is used. * - * Both `tools` and `toolIds` can be used together. + * @default 2 + * @min 0 + * @max 10 */ - toolIds?: string[]; + timeoutSeconds?: number; /** - * These are version-pinned references to tools. Each entry pins a specific - * version of a tool by `(toolId, version)`. When the same `toolId` appears - * in both `toolIds` and `toolRefs[]`, the `toolRefs` pin wins (the - * `toolIds` entry is dropped at write time). + * This is the delimiter(s) that will be used to process the input. + * Can be '#', '*', or an empty array. */ - toolRefs?: ToolRef[]; - /** These are the options for the knowledge base. */ - knowledgeBase?: CreateCustomKnowledgeBaseDTO; - /** This is the provider that will be used for the model. Any service, including your own server, that is compatible with the OpenAI API can be used. */ - provider: "custom-llm"; + delimiters?: "#" | "*" | ""; +} + +export interface TransientAssistantDTO { + /** These are the options for the assistant's transcriber. */ + transcriber?: + | AssemblyAITranscriber + | AzureSpeechTranscriber + | CustomTranscriber + | DeepgramTranscriber + | ElevenLabsTranscriber + | GladiaTranscriber + | GoogleTranscriber + | SpeechmaticsTranscriber + | TalkscriberTranscriber + | OpenAITranscriber + | CartesiaTranscriber + | SonioxTranscriber + | XaiTranscriber + | VapiTranscriber; + /** These are the options for the assistant's LLM. */ + model?: + | AnthropicModel + | AnthropicBedrockModel + | AnyscaleModel + | CerebrasModel + | CustomLLMModel + | DeepInfraModel + | DeepSeekModel + | GoogleModel + | GroqModel + | InflectionAIModel + | MinimaxLLMModel + | OpenAIModel + | OpenRouterModel + | PerplexityAIModel + | TogetherAIModel + | XaiModel + | VapiModel; + /** These are the options for the assistant's voice. */ + voice?: + | AzureVoice + | CartesiaVoice + | CustomVoice + | DeepgramVoice + | ElevenLabsVoice + | HumeVoice + | LMNTVoice + | NeuphonicVoice + | OpenAIVoice + | PlayHTVoice + | WellSaidVoice + | RimeAIVoice + | SmallestAIVoice + | VapiVoice + | SesameVoice + | InworldVoice + | MinimaxVoice + | XaiVoice + | MicrosoftVoice; /** - * This determines whether metadata is sent in requests to the custom provider. + * This is the first message that the assistant will say. This can also be a URL to a containerized audio file (mp3, wav, etc.). * - * - `off` will not send any metadata. payload will look like `{ messages }` - * - `variable` will send `assistant.metadata` as a variable on the payload. payload will look like `{ messages, metadata }` - * - `destructured` will send `assistant.metadata` fields directly on the payload. payload will look like `{ messages, ...metadata }` + * If unspecified, assistant will wait for user to speak and use the model to respond once they speak. + * @example "Hello! How can I help you today?" + */ + firstMessage?: string; + /** @default false */ + firstMessageInterruptionsEnabled?: boolean; + /** + * This is the mode for the first message. Default is 'assistant-speaks-first'. * - * Further, `variable` and `destructured` will send `call`, `phoneNumber`, and `customer` objects in the payload. + * Use: + * - 'assistant-speaks-first' to have the assistant speak first. + * - 'assistant-waits-for-user' to have the assistant wait for the user to speak first. + * - 'assistant-speaks-first-with-model-generated-message' to have the assistant speak first with a message generated by the model based on the conversation state. (`assistant.model.messages` at call start, `call.messages` at squad transfer points). * - * Default is `variable`. + * @default 'assistant-speaks-first' + * @example "assistant-speaks-first" */ - metadataSendMode?: "off" | "variable" | "destructured"; + firstMessageMode?: + | "assistant-speaks-first" + | "assistant-speaks-first-with-model-generated-message" + | "assistant-waits-for-user"; /** - * Custom headers to send with requests. These headers can override default OpenAI headers except for Authorization (which should be specified using a custom-llm credential). - * @example {"X-Custom-Header":"value"} + * These are the settings to configure or disable voicemail detection. Alternatively, voicemail detection can be configured using the model.tools=[VoicemailTool]. + * By default, voicemail detection is disabled. */ - headers?: Record; - /** These is the URL we'll use for the OpenAI client's `baseURL`. Ex. https://openrouter.ai/api/v1 */ - url: string; + voicemailDetection?: + | "off" + | GoogleVoicemailDetectionPlan + | OpenAIVoicemailDetectionPlan + | TwilioVoicemailDetectionPlan + | VapiVoicemailDetectionPlan; /** - * This determines whether the transcriber's word level confidence is sent in requests to the custom provider. Default is false. - * This only works for Deepgram transcribers. + * These are the messages that will be sent to your Client SDKs. Default is conversation-update,function-call,hang,model-output,speech-update,status-update,transfer-update,transcript,tool-calls,user-interrupted,voice-input,workflow.node.started,assistant.started. You can check the shape of the messages in ClientMessage schema. + * @example ["conversation-update","function-call","hang","model-output","speech-update","status-update","transfer-update","transcript","tool-calls","user-interrupted","voice-input","workflow.node.started","assistant.started"] */ - wordLevelConfidenceEnabled?: boolean; + clientMessages?: + | "conversation-update" + | "assistant.speechStarted" + | "function-call" + | "function-call-result" + | "hang" + | "language-changed" + | "metadata" + | "model-output" + | "speech-update" + | "status-update" + | "transcript" + | "tool-calls" + | "tool-calls-result" + | "tool.completed" + | "transfer-update" + | "user-interrupted" + | "voice-input" + | "workflow.node.started" + | "assistant.started"; /** - * This sets the timeout for the connection to the custom provider without needing to stream any tokens back. Default is 20 seconds. - * @min 0 - * @max 300 + * 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,assistant.started. You can check the shape of the messages in ServerMessage schema. + * @example ["conversation-update","end-of-call-report","function-call","hang","speech-update","status-update","tool-calls","transfer-destination-request","handoff-destination-request","user-interrupted","assistant.started"] */ - timeoutSeconds?: number; - /** This is the name of the model. Ex. cognitivecomputations/dolphin-mixtral-8x7b */ - model: string; + serverMessages?: + | "assistant.started" + | "assistant.speechStarted" + | "conversation-update" + | "end-of-call-report" + | "function-call" + | "hang" + | "language-changed" + | "language-change-detected" + | "model-output" + | "phone-call-control" + | "speech-update" + | "status-update" + | "transcript" + | "transcript[transcriptType='final']" + | "tool-calls" + | "transfer-destination-request" + | "handoff-destination-request" + | "transfer-update" + | "user-interrupted" + | "voice-input" + | "chat.created" + | "chat.deleted" + | "session.created" + | "session.updated" + | "session.deleted" + | "call.deleted" + | "call.delete.failed" + | "call.artifact.upload"; /** - * This is the temperature that will be used for calls. Default is 0.5. - * @min 0 - * @max 2 + * This is the maximum number of seconds that the call will last. When the call reaches this duration, it will be ended. + * + * @default 600 (10 minutes) + * @min 10 + * @max 43200 + * @example 600 */ - temperature?: number; + maxDurationSeconds?: number; /** - * This is the max number of tokens that the assistant will be allowed to generate in each turn of the conversation. Default is 250. On gpt-6-luna and claude-haiku-5-5 no cap is applied unless you set one (claude-haiku-5-5 sends its 128,000-token maximum), because reasoning uses output tokens and a small cap can leave the reply empty. - * @min 50 - * @max 10000 + * This is the background sound in the call. Default for phone calls is 'office' and default for web calls is 'off'. + * You can also provide a custom sound by providing a URL to an audio file. */ - maxTokens?: number; + backgroundSound?: "off" | "office" | string; /** - * This determines whether we detect user's emotion while they speak and send it as an additional info to model. - * - * Default `false` because the model is usually are good at understanding the user's emotion from text. + * This determines whether the model's output is used in conversation history rather than the transcription of assistant's speech. * * @default false + * @example false */ - emotionRecognitionEnabled?: boolean; + modelOutputInMessagesEnabled?: boolean; + /** These are the configurations to be passed to the transport providers of assistant's calls, like Twilio. You can store multiple configurations for different transport providers. For a call, only the configuration matching the call transport provider is used. */ + transportConfigurations?: TransportConfigurationTwilio[]; /** - * This sets how many turns at the start of the conversation to use a smaller, faster model from the same provider before switching to the primary model. Example, gpt-3.5-turbo if provider is openai. - * - * Default is 0. + * This is the plan for observability of assistant's calls. * - * @default 0 - * @min 0 + * Currently, only Langfuse is supported. */ - numFastTurns?: number; -} - -export interface DeepInfraModel { - /** This is the starting state for the conversation. */ - messages?: OpenAIMessage[]; + observabilityPlan?: LangfuseObservabilityPlan; + /** These are dynamic credentials that will be used for the assistant calls. By default, all the credentials are available for use in the call but you can supplement an additional credentials using this. Dynamic credentials override existing credentials. */ + credentials?: ( + | ({ + provider: "11labs"; + } & CreateElevenLabsCredentialDTO) + | ({ + provider: "anthropic"; + } & CreateAnthropicCredentialDTO) + | ({ + provider: "anthropic-bedrock"; + } & CreateAnthropicBedrockCredentialDTO) + | ({ + provider: "anyscale"; + } & CreateAnyscaleCredentialDTO) + | ({ + provider: "assembly-ai"; + } & CreateAssemblyAICredentialDTO) + | ({ + provider: "azure-openai"; + } & CreateAzureOpenAICredentialDTO) + | ({ + provider: "azure"; + } & CreateAzureCredentialDTO) + | ({ + provider: "byo-sip-trunk"; + } & CreateByoSipTrunkCredentialDTO) + | ({ + provider: "cartesia"; + } & CreateCartesiaCredentialDTO) + | ({ + provider: "cerebras"; + } & CreateCerebrasCredentialDTO) + | ({ + provider: "cloudflare"; + } & CreateCloudflareCredentialDTO) + | ({ + provider: "custom-llm"; + } & CreateCustomLLMCredentialDTO) + | ({ + provider: "deepgram"; + } & CreateDeepgramCredentialDTO) + | ({ + provider: "deepinfra"; + } & CreateDeepInfraCredentialDTO) + | ({ + provider: "deep-seek"; + } & CreateDeepSeekCredentialDTO) + | ({ + provider: "gcp"; + } & CreateGcpCredentialDTO) + | ({ + provider: "gladia"; + } & CreateGladiaCredentialDTO) + | ({ + provider: "gohighlevel"; + } & CreateGoHighLevelCredentialDTO) + | ({ + provider: "google"; + } & CreateGoogleCredentialDTO) + | ({ + provider: "groq"; + } & CreateGroqCredentialDTO) + | ({ + provider: "inflection-ai"; + } & CreateInflectionAICredentialDTO) + | ({ + provider: "langfuse"; + } & CreateLangfuseCredentialDTO) + | ({ + provider: "lmnt"; + } & CreateLmntCredentialDTO) + | ({ + provider: "make"; + } & CreateMakeCredentialDTO) + | ({ + provider: "openai"; + } & CreateOpenAICredentialDTO) + | ({ + provider: "openrouter"; + } & CreateOpenRouterCredentialDTO) + | ({ + provider: "perplexity-ai"; + } & CreatePerplexityAICredentialDTO) + | ({ + provider: "playht"; + } & CreatePlayHTCredentialDTO) + | ({ + provider: "rime-ai"; + } & CreateRimeAICredentialDTO) + | ({ + provider: "runpod"; + } & CreateRunpodCredentialDTO) + | ({ + provider: "s3"; + } & CreateS3CredentialDTO) + | ({ + provider: "s3-compatible"; + } & CreateS3CompatibleCredentialDTO) + | ({ + provider: "supabase"; + } & CreateSupabaseCredentialDTO) + | ({ + provider: "smallest-ai"; + } & CreateSmallestAICredentialDTO) + | ({ + provider: "tavus"; + } & CreateTavusCredentialDTO) + | ({ + provider: "together-ai"; + } & CreateTogetherAICredentialDTO) + | ({ + provider: "twilio"; + } & CreateTwilioCredentialDTO) + | ({ + provider: "vonage"; + } & CreateVonageCredentialDTO) + | ({ + provider: "webhook"; + } & CreateWebhookCredentialDTO) + | ({ + provider: "custom-credential"; + } & CreateCustomCredentialDTO) + | ({ + provider: "xai"; + } & CreateXAiCredentialDTO) + | ({ + provider: "microsoft"; + } & CreateMicrosoftCredentialDTO) + | ({ + provider: "neuphonic"; + } & CreateNeuphonicCredentialDTO) + | ({ + provider: "hume"; + } & CreateHumeCredentialDTO) + | ({ + provider: "mistral"; + } & CreateMistralCredentialDTO) + | ({ + provider: "speechmatics"; + } & CreateSpeechmaticsCredentialDTO) + | ({ + provider: "soniox"; + } & CreateSonioxCredentialDTO) + | ({ + provider: "google.calendar.oauth2-client"; + } & CreateGoogleCalendarOAuth2ClientCredentialDTO) + | ({ + provider: "google.calendar.oauth2-authorization"; + } & CreateGoogleCalendarOAuth2AuthorizationCredentialDTO) + | ({ + provider: "google.sheets.oauth2-authorization"; + } & CreateGoogleSheetsOAuth2AuthorizationCredentialDTO) + | ({ + provider: "slack.oauth2-authorization"; + } & CreateSlackOAuth2AuthorizationCredentialDTO) + | ({ + provider: "ghl.oauth2-authorization"; + } & CreateGoHighLevelMCPCredentialDTO) + | ({ + provider: "inworld"; + } & CreateInworldCredentialDTO) + | ({ + provider: "minimax"; + } & CreateMinimaxCredentialDTO) + | ({ + provider: "wellsaid"; + } & CreateWellSaidCredentialDTO) + | ({ + provider: "email"; + } & CreateEmailCredentialDTO) + | ({ + provider: "slack-webhook"; + } & CreateSlackWebhookCredentialDTO) + )[]; + /** This is a set of actions that will be performed on certain events. */ + hooks?: ( + | CallHookCallEnding + | CallHookAssistantSpeechInterrupted + | CallHookCustomerSpeechInterrupted + | CallHookCustomerSpeechTimeout + | SessionCreatedHook + )[]; /** - * These are the tools that the assistant can use during the call. To use existing tools, use `toolIds`. + * This is the name of the assistant. * - * Both `tools` and `toolIds` can be used together. + * This is required when you want to transfer between assistants in a call. + * @maxLength 40 */ - tools?: ( - | CreateApiRequestToolDTO - | CreateBashToolDTO - | CreateCodeToolDTO - | CreateComputerToolDTO - | CreateDtmfToolDTO - | CreateEndCallToolDTO - | CreateFunctionToolDTO - | CreateGoHighLevelCalendarAvailabilityToolDTO - | CreateGoHighLevelCalendarEventCreateToolDTO - | CreateGoHighLevelContactCreateToolDTO - | CreateGoHighLevelContactGetToolDTO - | CreateGoogleCalendarCheckAvailabilityToolDTO - | CreateGoogleCalendarCreateEventToolDTO - | CreateGoogleSheetsRowAppendToolDTO - | CreateHandoffToolDTO - | CreateMcpToolDTO - | CreateQueryToolDTO - | CreateSlackSendMessageToolDTO - | CreateSmsToolDTO - | CreateTextEditorToolDTO - | CreateTransferCallToolDTO - | CreateSipRequestToolDTO - | CreateVoicemailToolDTO - )[]; + name?: string; /** - * These are the tools that the assistant can use during the call. To use transient tools, use `tools`. + * This is the message that the assistant will say if the call is forwarded to voicemail. * - * Both `tools` and `toolIds` can be used together. + * If unspecified, it will hang up. + * @maxLength 1000 */ - toolIds?: string[]; + voicemailMessage?: string; /** - * These are version-pinned references to tools. Each entry pins a specific - * version of a tool by `(toolId, version)`. When the same `toolId` appears - * in both `toolIds` and `toolRefs[]`, the `toolRefs` pin wins (the - * `toolIds` entry is dropped at write time). + * This is the message that the assistant will say if it ends the call. + * + * If unspecified, it will hang up without saying anything. + * @maxLength 1000 */ - toolRefs?: ToolRef[]; - /** These are the options for the knowledge base. */ - knowledgeBase?: CreateCustomKnowledgeBaseDTO; - provider: "deepinfra"; - /** This is the name of the model. Ex. cognitivecomputations/dolphin-mixtral-8x7b */ - model: string; + endCallMessage?: string; + /** This list contains phrases that, if spoken by the assistant, will trigger the call to be hung up. Case insensitive. */ + endCallPhrases?: string[]; + compliancePlan?: CompliancePlan; + /** This is for metadata you want to store on the assistant. */ + metadata?: object; /** - * This is the temperature that will be used for calls. Default is 0.5. - * @min 0 - * @max 2 + * This enables filtering of noise and background speech while the user is talking. + * + * Features: + * - Smart denoising using Krisp + * - Fourier denoising + * + * Smart denoising can be combined with or used independently of Fourier denoising. + * + * Order of precedence: + * - Smart denoising + * - Fourier denoising */ - temperature?: number; + backgroundSpeechDenoisingPlan?: BackgroundSpeechDenoisingPlan; /** - * This is the max number of tokens that the assistant will be allowed to generate in each turn of the conversation. Default is 250. On gpt-6-luna and claude-haiku-5-5 no cap is applied unless you set one (claude-haiku-5-5 sends its 128,000-token maximum), because reasoning uses output tokens and a small cap can leave the reply empty. - * @min 50 - * @max 10000 + * This is the plan for analysis of assistant's calls. Stored in `call.analysis`. + * @deprecated */ - maxTokens?: number; + analysisPlan?: AnalysisPlan; + /** This is the plan for artifacts generated during assistant's calls. Stored in `call.artifact`. */ + artifactPlan?: ArtifactPlan; /** - * This determines whether we detect user's emotion while they speak and send it as an additional info to model. - * - * Default `false` because the model is usually are good at understanding the user's emotion from text. + * This is the plan for when the assistant should start talking. * - * @default false + * You should configure this if you're running into these issues: + * - The assistant is too slow to start talking after the customer is done speaking. + * - The assistant is too fast to start talking after the customer is done speaking. + * - The assistant is so fast that it's actually interrupting the customer. */ - emotionRecognitionEnabled?: boolean; + startSpeakingPlan?: StartSpeakingPlan; /** - * This sets how many turns at the start of the conversation to use a smaller, faster model from the same provider before switching to the primary model. Example, gpt-3.5-turbo if provider is openai. - * - * Default is 0. + * This is the plan for when assistant should stop talking on customer interruption. * - * @default 0 - * @min 0 + * You should configure this if you're running into these issues: + * - The assistant is too slow to recognize customer's interruption. + * - The assistant is too fast to recognize customer's interruption. + * - The assistant is getting interrupted by phrases that are just acknowledgments. + * - The assistant is getting interrupted by background noises. + * - The assistant is not properly stopping -- it starts talking right after getting interrupted. */ - numFastTurns?: number; -} - -export interface DeepSeekModel { - /** This is the starting state for the conversation. */ - messages?: OpenAIMessage[]; + stopSpeakingPlan?: StopSpeakingPlan; /** - * These are the tools that the assistant can use during the call. To use existing tools, use `toolIds`. + * This is the plan for real-time monitoring of the assistant's calls. * - * Both `tools` and `toolIds` can be used together. + * Usage: + * - To enable live listening of the assistant's calls, set `monitorPlan.listenEnabled` to `true`. + * - To enable live control of the assistant's calls, set `monitorPlan.controlEnabled` to `true`. + * - To attach monitors to the assistant, set `monitorPlan.monitorIds` to the set of monitor ids. */ - tools?: ( - | CreateApiRequestToolDTO - | CreateBashToolDTO - | CreateCodeToolDTO - | CreateComputerToolDTO - | CreateDtmfToolDTO - | CreateEndCallToolDTO - | CreateFunctionToolDTO - | CreateGoHighLevelCalendarAvailabilityToolDTO - | CreateGoHighLevelCalendarEventCreateToolDTO - | CreateGoHighLevelContactCreateToolDTO - | CreateGoHighLevelContactGetToolDTO - | CreateGoogleCalendarCheckAvailabilityToolDTO - | CreateGoogleCalendarCreateEventToolDTO - | CreateGoogleSheetsRowAppendToolDTO - | CreateHandoffToolDTO - | CreateMcpToolDTO - | CreateQueryToolDTO - | CreateSlackSendMessageToolDTO - | CreateSmsToolDTO - | CreateTextEditorToolDTO - | CreateTransferCallToolDTO - | CreateSipRequestToolDTO - | CreateVoicemailToolDTO - )[]; + monitorPlan?: MonitorPlan; + /** These are the credentials that will be used for the assistant calls. By default, all the credentials are available for use in the call but you can provide a subset using this. */ + credentialIds?: string[]; /** - * These are the tools that the assistant can use during the call. To use transient tools, use `tools`. + * This is where Vapi will send webhooks. You can find all webhooks available along with their shape in ServerMessage schema. * - * Both `tools` and `toolIds` can be used together. - */ - toolIds?: string[]; - /** - * These are version-pinned references to tools. Each entry pins a specific - * version of a tool by `(toolId, version)`. When the same `toolId` appears - * in both `toolIds` and `toolRefs[]`, the `toolRefs` pin wins (the - * `toolIds` entry is dropped at write time). - */ - toolRefs?: ToolRef[]; - /** These are the options for the knowledge base. */ - knowledgeBase?: CreateCustomKnowledgeBaseDTO; - /** This is the name of the model. Ex. cognitivecomputations/dolphin-mixtral-8x7b */ - model: - | "deepseek-chat" - | "deepseek-reasoner" - | "deepseek-flash" - | "deepseek-flash-thinking"; - provider: "deep-seek"; - /** - * This is the temperature that will be used for calls. Default is 0.5. - * @min 0 - * @max 2 + * The order of precedence is: + * + * 1. assistant.server.url + * 2. phoneNumber.serverUrl + * 3. org.serverUrl */ - temperature?: number; + server?: Server; + keypadInputPlan?: KeypadInputPlan; +} + +export interface AssistantOverrides { + /** These are the options for the assistant's transcriber. */ + transcriber?: + | AssemblyAITranscriber + | AzureSpeechTranscriber + | CustomTranscriber + | DeepgramTranscriber + | ElevenLabsTranscriber + | GladiaTranscriber + | GoogleTranscriber + | SpeechmaticsTranscriber + | TalkscriberTranscriber + | OpenAITranscriber + | CartesiaTranscriber + | SonioxTranscriber + | XaiTranscriber + | VapiTranscriber; + /** These are the options for the assistant's LLM. */ + model?: + | AnthropicModel + | AnthropicBedrockModel + | AnyscaleModel + | CerebrasModel + | CustomLLMModel + | DeepInfraModel + | DeepSeekModel + | GoogleModel + | GroqModel + | InflectionAIModel + | MinimaxLLMModel + | OpenAIModel + | OpenRouterModel + | PerplexityAIModel + | TogetherAIModel + | XaiModel + | VapiModel; + /** These are the options for the assistant's voice. */ + voice?: + | AzureVoice + | CartesiaVoice + | CustomVoice + | DeepgramVoice + | ElevenLabsVoice + | HumeVoice + | LMNTVoice + | NeuphonicVoice + | OpenAIVoice + | PlayHTVoice + | WellSaidVoice + | RimeAIVoice + | SmallestAIVoice + | VapiVoice + | SesameVoice + | InworldVoice + | MinimaxVoice + | XaiVoice + | MicrosoftVoice; /** - * This is the max number of tokens that the assistant will be allowed to generate in each turn of the conversation. Default is 250. On gpt-6-luna and claude-haiku-5-5 no cap is applied unless you set one (claude-haiku-5-5 sends its 128,000-token maximum), because reasoning uses output tokens and a small cap can leave the reply empty. - * @min 50 - * @max 10000 + * This is the first message that the assistant will say. This can also be a URL to a containerized audio file (mp3, wav, etc.). + * + * If unspecified, assistant will wait for user to speak and use the model to respond once they speak. + * @example "Hello! How can I help you today?" */ - maxTokens?: number; + firstMessage?: string; + /** @default false */ + firstMessageInterruptionsEnabled?: boolean; /** - * This determines whether we detect user's emotion while they speak and send it as an additional info to model. + * This is the mode for the first message. Default is 'assistant-speaks-first'. * - * Default `false` because the model is usually are good at understanding the user's emotion from text. + * Use: + * - 'assistant-speaks-first' to have the assistant speak first. + * - 'assistant-waits-for-user' to have the assistant wait for the user to speak first. + * - 'assistant-speaks-first-with-model-generated-message' to have the assistant speak first with a message generated by the model based on the conversation state. (`assistant.model.messages` at call start, `call.messages` at squad transfer points). * - * @default false + * @default 'assistant-speaks-first' + * @example "assistant-speaks-first" */ - emotionRecognitionEnabled?: boolean; + firstMessageMode?: + | "assistant-speaks-first" + | "assistant-speaks-first-with-model-generated-message" + | "assistant-waits-for-user"; /** - * This sets how many turns at the start of the conversation to use a smaller, faster model from the same provider before switching to the primary model. Example, gpt-3.5-turbo if provider is openai. - * - * Default is 0. - * - * @default 0 - * @min 0 + * These are the settings to configure or disable voicemail detection. Alternatively, voicemail detection can be configured using the model.tools=[VoicemailTool]. + * By default, voicemail detection is disabled. */ - numFastTurns?: number; -} - -export interface GeminiMultimodalLivePrebuiltVoiceConfig { - voiceName: "Puck" | "Charon" | "Kore" | "Fenrir" | "Aoede"; -} - -export interface GeminiMultimodalLiveVoiceConfig { - prebuiltVoiceConfig: GeminiMultimodalLivePrebuiltVoiceConfig; -} - -export interface GeminiMultimodalLiveSpeechConfig { - voiceConfig: GeminiMultimodalLiveVoiceConfig; -} - -export interface GoogleRealtimeConfig { + voicemailDetection?: + | "off" + | GoogleVoicemailDetectionPlan + | OpenAIVoicemailDetectionPlan + | TwilioVoicemailDetectionPlan + | VapiVoicemailDetectionPlan; /** - * This is the nucleus sampling parameter that controls the cumulative probability of tokens considered during text generation. - * Only applicable with the Gemini Flash 2.0 Multimodal Live API. + * These are the messages that will be sent to your Client SDKs. Default is conversation-update,function-call,hang,model-output,speech-update,status-update,transfer-update,transcript,tool-calls,user-interrupted,voice-input,workflow.node.started,assistant.started. You can check the shape of the messages in ClientMessage schema. + * @example ["conversation-update","function-call","hang","model-output","speech-update","status-update","transfer-update","transcript","tool-calls","user-interrupted","voice-input","workflow.node.started","assistant.started"] */ - topP?: number; + clientMessages?: + | "conversation-update" + | "assistant.speechStarted" + | "function-call" + | "function-call-result" + | "hang" + | "language-changed" + | "metadata" + | "model-output" + | "speech-update" + | "status-update" + | "transcript" + | "tool-calls" + | "tool-calls-result" + | "tool.completed" + | "transfer-update" + | "user-interrupted" + | "voice-input" + | "workflow.node.started" + | "assistant.started"; /** - * This is the top-k sampling parameter that limits the number of highest probability tokens considered during text generation. - * Only applicable with the Gemini Flash 2.0 Multimodal Live API. + * 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,assistant.started. You can check the shape of the messages in ServerMessage schema. + * @example ["conversation-update","end-of-call-report","function-call","hang","speech-update","status-update","tool-calls","transfer-destination-request","handoff-destination-request","user-interrupted","assistant.started"] */ - topK?: number; + serverMessages?: + | "assistant.started" + | "assistant.speechStarted" + | "conversation-update" + | "end-of-call-report" + | "function-call" + | "hang" + | "language-changed" + | "language-change-detected" + | "model-output" + | "phone-call-control" + | "speech-update" + | "status-update" + | "transcript" + | "transcript[transcriptType='final']" + | "tool-calls" + | "transfer-destination-request" + | "handoff-destination-request" + | "transfer-update" + | "user-interrupted" + | "voice-input" + | "chat.created" + | "chat.deleted" + | "session.created" + | "session.updated" + | "session.deleted" + | "call.deleted" + | "call.delete.failed" + | "call.artifact.upload"; /** - * This is the presence penalty parameter that influences the model's likelihood to repeat information by penalizing tokens based on their presence in the text. - * Only applicable with the Gemini Flash 2.0 Multimodal Live API. + * This is the maximum number of seconds that the call will last. When the call reaches this duration, it will be ended. + * + * @default 600 (10 minutes) + * @min 10 + * @max 43200 + * @example 600 */ - presencePenalty?: number; + maxDurationSeconds?: number; /** - * This is the frequency penalty parameter that influences the model's likelihood to repeat tokens by penalizing them based on their frequency in the text. - * Only applicable with the Gemini Flash 2.0 Multimodal Live API. + * This is the background sound in the call. Default for phone calls is 'office' and default for web calls is 'off'. + * You can also provide a custom sound by providing a URL to an audio file. */ - frequencyPenalty?: number; + backgroundSound?: "off" | "office" | string; /** - * This is the speech configuration object that defines the voice settings to be used for the model's speech output. - * Only applicable with the Gemini Flash 2.0 Multimodal Live API. + * This determines whether the model's output is used in conversation history rather than the transcription of assistant's speech. + * + * @default false + * @example false */ - speechConfig?: GeminiMultimodalLiveSpeechConfig; -} - -export interface GoogleModel { - /** This is the starting state for the conversation. */ - messages?: OpenAIMessage[]; + modelOutputInMessagesEnabled?: boolean; + /** These are the configurations to be passed to the transport providers of assistant's calls, like Twilio. You can store multiple configurations for different transport providers. For a call, only the configuration matching the call transport provider is used. */ + transportConfigurations?: TransportConfigurationTwilio[]; /** - * These are the tools that the assistant can use during the call. To use existing tools, use `toolIds`. + * This is the plan for observability of assistant's calls. * - * Both `tools` and `toolIds` can be used together. + * Currently, only Langfuse is supported. */ - tools?: ( + observabilityPlan?: LangfuseObservabilityPlan; + /** These are dynamic credentials that will be used for the assistant calls. By default, all the credentials are available for use in the call but you can supplement an additional credentials using this. Dynamic credentials override existing credentials. */ + credentials?: ( + | ({ + provider: "11labs"; + } & CreateElevenLabsCredentialDTO) + | ({ + provider: "anthropic"; + } & CreateAnthropicCredentialDTO) + | ({ + provider: "anthropic-bedrock"; + } & CreateAnthropicBedrockCredentialDTO) + | ({ + provider: "anyscale"; + } & CreateAnyscaleCredentialDTO) + | ({ + provider: "assembly-ai"; + } & CreateAssemblyAICredentialDTO) + | ({ + provider: "azure-openai"; + } & CreateAzureOpenAICredentialDTO) + | ({ + provider: "azure"; + } & CreateAzureCredentialDTO) + | ({ + provider: "byo-sip-trunk"; + } & CreateByoSipTrunkCredentialDTO) + | ({ + provider: "cartesia"; + } & CreateCartesiaCredentialDTO) + | ({ + provider: "cerebras"; + } & CreateCerebrasCredentialDTO) + | ({ + provider: "cloudflare"; + } & CreateCloudflareCredentialDTO) + | ({ + provider: "custom-llm"; + } & CreateCustomLLMCredentialDTO) + | ({ + provider: "deepgram"; + } & CreateDeepgramCredentialDTO) + | ({ + provider: "deepinfra"; + } & CreateDeepInfraCredentialDTO) + | ({ + provider: "deep-seek"; + } & CreateDeepSeekCredentialDTO) + | ({ + provider: "gcp"; + } & CreateGcpCredentialDTO) + | ({ + provider: "gladia"; + } & CreateGladiaCredentialDTO) + | ({ + provider: "gohighlevel"; + } & CreateGoHighLevelCredentialDTO) + | ({ + provider: "google"; + } & CreateGoogleCredentialDTO) + | ({ + provider: "groq"; + } & CreateGroqCredentialDTO) + | ({ + provider: "inflection-ai"; + } & CreateInflectionAICredentialDTO) + | ({ + provider: "langfuse"; + } & CreateLangfuseCredentialDTO) + | ({ + provider: "lmnt"; + } & CreateLmntCredentialDTO) + | ({ + provider: "make"; + } & CreateMakeCredentialDTO) + | ({ + provider: "openai"; + } & CreateOpenAICredentialDTO) + | ({ + provider: "openrouter"; + } & CreateOpenRouterCredentialDTO) + | ({ + provider: "perplexity-ai"; + } & CreatePerplexityAICredentialDTO) + | ({ + provider: "playht"; + } & CreatePlayHTCredentialDTO) + | ({ + provider: "rime-ai"; + } & CreateRimeAICredentialDTO) + | ({ + provider: "runpod"; + } & CreateRunpodCredentialDTO) + | ({ + provider: "s3"; + } & CreateS3CredentialDTO) + | ({ + provider: "s3-compatible"; + } & CreateS3CompatibleCredentialDTO) + | ({ + provider: "supabase"; + } & CreateSupabaseCredentialDTO) + | ({ + provider: "smallest-ai"; + } & CreateSmallestAICredentialDTO) + | ({ + provider: "tavus"; + } & CreateTavusCredentialDTO) + | ({ + provider: "together-ai"; + } & CreateTogetherAICredentialDTO) + | ({ + provider: "twilio"; + } & CreateTwilioCredentialDTO) + | ({ + provider: "vonage"; + } & CreateVonageCredentialDTO) + | ({ + provider: "webhook"; + } & CreateWebhookCredentialDTO) + | ({ + provider: "custom-credential"; + } & CreateCustomCredentialDTO) + | ({ + provider: "xai"; + } & CreateXAiCredentialDTO) + | ({ + provider: "microsoft"; + } & CreateMicrosoftCredentialDTO) + | ({ + provider: "neuphonic"; + } & CreateNeuphonicCredentialDTO) + | ({ + provider: "hume"; + } & CreateHumeCredentialDTO) + | ({ + provider: "mistral"; + } & CreateMistralCredentialDTO) + | ({ + provider: "speechmatics"; + } & CreateSpeechmaticsCredentialDTO) + | ({ + provider: "soniox"; + } & CreateSonioxCredentialDTO) + | ({ + provider: "google.calendar.oauth2-client"; + } & CreateGoogleCalendarOAuth2ClientCredentialDTO) + | ({ + provider: "google.calendar.oauth2-authorization"; + } & CreateGoogleCalendarOAuth2AuthorizationCredentialDTO) + | ({ + provider: "google.sheets.oauth2-authorization"; + } & CreateGoogleSheetsOAuth2AuthorizationCredentialDTO) + | ({ + provider: "slack.oauth2-authorization"; + } & CreateSlackOAuth2AuthorizationCredentialDTO) + | ({ + provider: "ghl.oauth2-authorization"; + } & CreateGoHighLevelMCPCredentialDTO) + | ({ + provider: "inworld"; + } & CreateInworldCredentialDTO) + | ({ + provider: "minimax"; + } & CreateMinimaxCredentialDTO) + | ({ + provider: "wellsaid"; + } & CreateWellSaidCredentialDTO) + | ({ + provider: "email"; + } & CreateEmailCredentialDTO) + | ({ + provider: "slack-webhook"; + } & CreateSlackWebhookCredentialDTO) + )[]; + /** This is a set of actions that will be performed on certain events. */ + hooks?: ( + | CallHookCallEnding + | CallHookAssistantSpeechInterrupted + | CallHookCustomerSpeechInterrupted + | CallHookCustomerSpeechTimeout + | SessionCreatedHook + )[]; + "tools:append"?: ( | CreateApiRequestToolDTO | CreateBashToolDTO | CreateCodeToolDTO @@ -9956,853 +9430,2046 @@ export interface GoogleModel { | CreateVoicemailToolDTO )[]; /** - * These are the tools that the assistant can use during the call. To use transient tools, use `tools`. + * These are values that will be used to replace the template variables in the assistant messages and other text-based fields. + * This uses LiquidJS syntax. https://liquidjs.com/tutorials/intro-to-liquid.html * - * Both `tools` and `toolIds` can be used together. + * So for example, `{{ name }}` will be replaced with the value of `name` in `variableValues`. + * `{{"now" | date: "%b %d, %Y, %I:%M %p", "America/New_York"}}` will be replaced with the current date and time in New York. + * Some VAPI reserved defaults: + * - *customer* - the customer object */ - toolIds?: string[]; + variableValues?: object; /** - * These are version-pinned references to tools. Each entry pins a specific - * version of a tool by `(toolId, version)`. When the same `toolId` appears - * in both `toolIds` and `toolRefs[]`, the `toolRefs` pin wins (the - * `toolIds` entry is dropped at write time). + * This is the name of the assistant. + * + * This is required when you want to transfer between assistants in a call. + * @maxLength 40 */ - toolRefs?: ToolRef[]; - /** These are the options for the knowledge base. */ - knowledgeBase?: CreateCustomKnowledgeBaseDTO; - /** This is the Google model that will be used. */ - model: - | "gemini-3.8-flash" - | "gemini-3.5-flash" - | "gemini-3.1-flash-lite" - | "gemini-3-flash-preview" - | "gemini-2.5-pro" - | "gemini-2.5-flash" - | "gemini-2.5-flash-lite" - | "gemini-2.0-flash-thinking-exp" - | "gemini-2.0-pro-exp-02-05" - | "gemini-2.0-flash" - | "gemini-2.0-flash-lite" - | "gemini-2.0-flash-exp" - | "gemini-2.0-flash-realtime-exp" - | "gemini-1.5-flash" - | "gemini-1.5-flash-002" - | "gemini-1.5-pro" - | "gemini-1.5-pro-002" - | "gemini-1.0-pro"; - provider: "google"; + name?: string; /** - * This is the session configuration for the Gemini Flash 2.0 Multimodal Live API. - * Only applicable if the model `gemini-2.0-flash-realtime-exp` is selected. + * This is the message that the assistant will say if the call is forwarded to voicemail. + * + * If unspecified, it will hang up. + * @maxLength 1000 */ - realtimeConfig?: GoogleRealtimeConfig; + voicemailMessage?: string; /** - * This is the temperature that will be used for calls. Default is 0.5. - * @min 0 - * @max 2 + * This is the message that the assistant will say if it ends the call. + * + * If unspecified, it will hang up without saying anything. + * @maxLength 1000 */ - temperature?: number; - /** - * This is the max number of tokens that the assistant will be allowed to generate in each turn of the conversation. Default is 250. On gpt-6-luna and claude-haiku-5-5 no cap is applied unless you set one (claude-haiku-5-5 sends its 128,000-token maximum), because reasoning uses output tokens and a small cap can leave the reply empty. - * @min 50 - * @max 10000 - */ - maxTokens?: number; + endCallMessage?: string; + /** This list contains phrases that, if spoken by the assistant, will trigger the call to be hung up. Case insensitive. */ + endCallPhrases?: string[]; + compliancePlan?: CompliancePlan; + /** This is for metadata you want to store on the assistant. */ + metadata?: object; /** - * This determines whether we detect user's emotion while they speak and send it as an additional info to model. - * - * Default `false` because the model is usually are good at understanding the user's emotion from text. + * This enables filtering of noise and background speech while the user is talking. * - * @default false - */ - emotionRecognitionEnabled?: boolean; - /** - * This sets how many turns at the start of the conversation to use a smaller, faster model from the same provider before switching to the primary model. Example, gpt-3.5-turbo if provider is openai. + * Features: + * - Smart denoising using Krisp + * - Fourier denoising * - * Default is 0. + * Smart denoising can be combined with or used independently of Fourier denoising. * - * @default 0 - * @min 0 + * Order of precedence: + * - Smart denoising + * - Fourier denoising */ - numFastTurns?: number; -} - -export interface GroqModel { - /** This is the starting state for the conversation. */ - messages?: OpenAIMessage[]; + backgroundSpeechDenoisingPlan?: BackgroundSpeechDenoisingPlan; /** - * These are the tools that the assistant can use during the call. To use existing tools, use `toolIds`. - * - * Both `tools` and `toolIds` can be used together. + * This is the plan for analysis of assistant's calls. Stored in `call.analysis`. + * @deprecated */ - tools?: ( - | CreateApiRequestToolDTO - | CreateBashToolDTO - | CreateCodeToolDTO - | CreateComputerToolDTO - | CreateDtmfToolDTO - | CreateEndCallToolDTO - | CreateFunctionToolDTO - | CreateGoHighLevelCalendarAvailabilityToolDTO - | CreateGoHighLevelCalendarEventCreateToolDTO - | CreateGoHighLevelContactCreateToolDTO - | CreateGoHighLevelContactGetToolDTO - | CreateGoogleCalendarCheckAvailabilityToolDTO - | CreateGoogleCalendarCreateEventToolDTO - | CreateGoogleSheetsRowAppendToolDTO - | CreateHandoffToolDTO - | CreateMcpToolDTO - | CreateQueryToolDTO - | CreateSlackSendMessageToolDTO - | CreateSmsToolDTO - | CreateTextEditorToolDTO - | CreateTransferCallToolDTO - | CreateSipRequestToolDTO - | CreateVoicemailToolDTO - )[]; + analysisPlan?: AnalysisPlan; + /** This is the plan for artifacts generated during assistant's calls. Stored in `call.artifact`. */ + artifactPlan?: ArtifactPlan; /** - * These are the tools that the assistant can use during the call. To use transient tools, use `tools`. + * This is the plan for when the assistant should start talking. * - * Both `tools` and `toolIds` can be used together. - */ - toolIds?: string[]; - /** - * These are version-pinned references to tools. Each entry pins a specific - * version of a tool by `(toolId, version)`. When the same `toolId` appears - * in both `toolIds` and `toolRefs[]`, the `toolRefs` pin wins (the - * `toolIds` entry is dropped at write time). - */ - toolRefs?: ToolRef[]; - /** These are the options for the knowledge base. */ - knowledgeBase?: CreateCustomKnowledgeBaseDTO; - /** This is the name of the model. Ex. cognitivecomputations/dolphin-mixtral-8x7b */ - model: - | "openai/gpt-oss-20b" - | "openai/gpt-oss-120b" - | "deepseek-r1-distill-llama-70b" - | "llama-3.3-70b-versatile" - | "llama-3.1-405b-reasoning" - | "llama-3.1-8b-instant" - | "llama3-8b-8192" - | "llama3-70b-8192" - | "gemma2-9b-it" - | "moonshotai/kimi-k2-instruct-0905" - | "meta-llama/llama-4-scout-17b-16e-instruct" - | "mistral-saba-24b" - | "compound-beta" - | "compound-beta-mini"; - provider: "groq"; - /** - * This is the temperature that will be used for calls. Default is 0.5. - * @min 0 - * @max 2 + * You should configure this if you're running into these issues: + * - The assistant is too slow to start talking after the customer is done speaking. + * - The assistant is too fast to start talking after the customer is done speaking. + * - The assistant is so fast that it's actually interrupting the customer. */ - temperature?: number; + startSpeakingPlan?: StartSpeakingPlan; /** - * This is the max number of tokens that the assistant will be allowed to generate in each turn of the conversation. Default is 250. On gpt-6-luna and claude-haiku-5-5 no cap is applied unless you set one (claude-haiku-5-5 sends its 128,000-token maximum), because reasoning uses output tokens and a small cap can leave the reply empty. - * @min 50 - * @max 10000 + * This is the plan for when assistant should stop talking on customer interruption. + * + * You should configure this if you're running into these issues: + * - The assistant is too slow to recognize customer's interruption. + * - The assistant is too fast to recognize customer's interruption. + * - The assistant is getting interrupted by phrases that are just acknowledgments. + * - The assistant is getting interrupted by background noises. + * - The assistant is not properly stopping -- it starts talking right after getting interrupted. */ - maxTokens?: number; + stopSpeakingPlan?: StopSpeakingPlan; /** - * This determines whether we detect user's emotion while they speak and send it as an additional info to model. - * - * Default `false` because the model is usually are good at understanding the user's emotion from text. + * This is the plan for real-time monitoring of the assistant's calls. * - * @default false + * Usage: + * - To enable live listening of the assistant's calls, set `monitorPlan.listenEnabled` to `true`. + * - To enable live control of the assistant's calls, set `monitorPlan.controlEnabled` to `true`. + * - To attach monitors to the assistant, set `monitorPlan.monitorIds` to the set of monitor ids. */ - emotionRecognitionEnabled?: boolean; + monitorPlan?: MonitorPlan; + /** These are the credentials that will be used for the assistant calls. By default, all the credentials are available for use in the call but you can provide a subset using this. */ + credentialIds?: string[]; /** - * This sets how many turns at the start of the conversation to use a smaller, faster model from the same provider before switching to the primary model. Example, gpt-3.5-turbo if provider is openai. + * This is where Vapi will send webhooks. You can find all webhooks available along with their shape in ServerMessage schema. * - * Default is 0. + * The order of precedence is: * - * @default 0 - * @min 0 + * 1. assistant.server.url + * 2. phoneNumber.serverUrl + * 3. org.serverUrl */ - numFastTurns?: number; + server?: Server; + keypadInputPlan?: KeypadInputPlan; } -export interface InflectionAIModel { - /** This is the starting state for the conversation. */ - messages?: OpenAIMessage[]; - /** - * These are the tools that the assistant can use during the call. To use existing tools, use `toolIds`. - * - * Both `tools` and `toolIds` can be used together. - */ - tools?: ( - | CreateApiRequestToolDTO - | CreateBashToolDTO - | CreateCodeToolDTO - | CreateComputerToolDTO - | CreateDtmfToolDTO - | CreateEndCallToolDTO - | CreateFunctionToolDTO - | CreateGoHighLevelCalendarAvailabilityToolDTO - | CreateGoHighLevelCalendarEventCreateToolDTO - | CreateGoHighLevelContactCreateToolDTO - | CreateGoHighLevelContactGetToolDTO - | CreateGoogleCalendarCheckAvailabilityToolDTO - | CreateGoogleCalendarCreateEventToolDTO - | CreateGoogleSheetsRowAppendToolDTO - | CreateHandoffToolDTO - | CreateMcpToolDTO - | CreateQueryToolDTO - | CreateSlackSendMessageToolDTO - | CreateSmsToolDTO - | CreateTextEditorToolDTO - | CreateTransferCallToolDTO - | CreateSipRequestToolDTO - | CreateVoicemailToolDTO - )[]; - /** - * These are the tools that the assistant can use during the call. To use transient tools, use `tools`. - * - * Both `tools` and `toolIds` can be used together. - */ - toolIds?: string[]; - /** - * These are version-pinned references to tools. Each entry pins a specific - * version of a tool by `(toolId, version)`. When the same `toolId` appears - * in both `toolIds` and `toolRefs[]`, the `toolRefs` pin wins (the - * `toolIds` entry is dropped at write time). - */ - toolRefs?: ToolRef[]; - /** These are the options for the knowledge base. */ - knowledgeBase?: CreateCustomKnowledgeBaseDTO; - /** This is the name of the model. Ex. cognitivecomputations/dolphin-mixtral-8x7b */ - model: "inflection_3_pi"; - provider: "inflection-ai"; - /** - * This is the temperature that will be used for calls. Default is 0.5. - * @min 0 - * @max 2 - */ - temperature?: number; - /** - * This is the max number of tokens that the assistant will be allowed to generate in each turn of the conversation. Default is 250. On gpt-6-luna and claude-haiku-5-5 no cap is applied unless you set one (claude-haiku-5-5 sends its 128,000-token maximum), because reasoning uses output tokens and a small cap can leave the reply empty. - * @min 50 - * @max 10000 - */ - maxTokens?: number; - /** - * This determines whether we detect user's emotion while they speak and send it as an additional info to model. - * - * Default `false` because the model is usually are good at understanding the user's emotion from text. - * - * @default false - */ - emotionRecognitionEnabled?: boolean; - /** - * This sets how many turns at the start of the conversation to use a smaller, faster model from the same provider before switching to the primary model. Example, gpt-3.5-turbo if provider is openai. - * - * Default is 0. - * - * @default 0 - * @min 0 - */ - numFastTurns?: number; +export interface HandoffDestinationAssistant { + type: "assistant"; + /** This is the plan for manipulating the message context before handing off the call to the next assistant. */ + contextEngineeringPlan?: + | ContextEngineeringPlanLastNMessages + | ContextEngineeringPlanNone + | ContextEngineeringPlanAll + | ContextEngineeringPlanUserAndAssistantMessages + | ContextEngineeringPlanPreviousAssistantMessages; + /** This is the assistant to transfer the call to. You must provide either assistantName or assistantId. */ + assistantName?: string; + /** This is the assistant id to transfer the call to. You must provide either assistantName or assistantId. */ + assistantId?: string; + /** 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. */ + assistant?: TransientAssistantDTO; + /** This is the variable extraction plan for the handoff tool. */ + variableExtractionPlan?: VariableExtractionPlan; + /** These are the assistant overrides to apply to the destination assistant. */ + assistantOverrides?: AssistantOverrides; + /** This is the description of the destination, used by the AI to choose when and how to transfer the call. */ + description?: string; } -export interface MinimaxLLMModel { - /** This is the starting state for the conversation. */ - messages?: OpenAIMessage[]; - /** - * These are the tools that the assistant can use during the call. To use existing tools, use `toolIds`. - * - * Both `tools` and `toolIds` can be used together. - */ - tools?: ( - | CreateApiRequestToolDTO - | CreateBashToolDTO - | CreateCodeToolDTO - | CreateComputerToolDTO - | CreateDtmfToolDTO - | CreateEndCallToolDTO - | CreateFunctionToolDTO - | CreateGoHighLevelCalendarAvailabilityToolDTO - | CreateGoHighLevelCalendarEventCreateToolDTO - | CreateGoHighLevelContactCreateToolDTO - | CreateGoHighLevelContactGetToolDTO - | CreateGoogleCalendarCheckAvailabilityToolDTO - | CreateGoogleCalendarCreateEventToolDTO - | CreateGoogleSheetsRowAppendToolDTO - | CreateHandoffToolDTO - | CreateMcpToolDTO - | CreateQueryToolDTO - | CreateSlackSendMessageToolDTO - | CreateSmsToolDTO - | CreateTextEditorToolDTO - | CreateTransferCallToolDTO - | CreateSipRequestToolDTO - | CreateVoicemailToolDTO - )[]; - /** - * These are the tools that the assistant can use during the call. To use transient tools, use `tools`. - * - * Both `tools` and `toolIds` can be used together. - */ - toolIds?: string[]; - /** - * These are version-pinned references to tools. Each entry pins a specific - * version of a tool by `(toolId, version)`. When the same `toolId` appears - * in both `toolIds` and `toolRefs[]`, the `toolRefs` pin wins (the - * `toolIds` entry is dropped at write time). - */ - toolRefs?: ToolRef[]; - /** These are the options for the knowledge base. */ - knowledgeBase?: CreateCustomKnowledgeBaseDTO; - provider: "minimax"; - /** This is the name of the model. Ex. cognitivecomputations/dolphin-mixtral-8x7b */ - model: "MiniMax-M2.7"; - /** - * This is the temperature that will be used for calls. Default is 0.5. - * @min 0 - * @max 2 - */ - temperature?: number; - /** - * This is the max number of tokens that the assistant will be allowed to generate in each turn of the conversation. Default is 250. On gpt-6-luna and claude-haiku-5-5 no cap is applied unless you set one (claude-haiku-5-5 sends its 128,000-token maximum), because reasoning uses output tokens and a small cap can leave the reply empty. - * @min 50 - * @max 10000 - */ - maxTokens?: number; - /** - * This determines whether we detect user's emotion while they speak and send it as an additional info to model. - * - * Default `false` because the model is usually are good at understanding the user's emotion from text. - * - * @default false - */ - emotionRecognitionEnabled?: boolean; +export interface HandoffDestinationDynamic { + type: "dynamic"; /** - * This sets how many turns at the start of the conversation to use a smaller, faster model from the same provider before switching to the primary model. Example, gpt-3.5-turbo if provider is openai. + * This is where Vapi will send the handoff-destination-request webhook in a dynamic handoff. * - * Default is 0. + * The order of precedence is: * - * @default 0 - * @min 0 + * 1. tool.server.url + * 2. assistant.server.url + * 3. phoneNumber.server.url + * 4. org.server.url */ - numFastTurns?: number; -} - -export interface OpenAISpeaker { - /** Omit to use model.systemPrompt, or system-role messages when systemPrompt is absent. An explicit empty string is preserved. */ - instructions?: string; - /** Personality packs append speaking-style guidance to the speaker prompt. Set to an array of pack IDs and test one pack at a time. These are prompt instructions, not fixed speed controls. */ - personalityPacks?: ( - | "eager-listener" - | "idle-hummer" - | "bouncy" - | "unhurried" - )[]; + server?: Server; + /** This is the description of the destination, used by the AI to choose when and how to transfer the call. */ + description?: string; } -export interface OpenAIReasonerSkill { - /** - * Unique name within this assistant. - * @maxLength 64 - * @pattern /^[a-z][a-z0-9_-]*$/ - */ - name: string; - /** - * Explain when the reasoner should load this skill. Always visible in its catalog. - * @maxLength 1024 - * @pattern /\S/ - */ - description: string; - /** - * Full skill instructions, loaded only while this skill is active. - * @maxLength 32000 - * @pattern /\S/ - */ - content: string; +export interface SquadMemberDTO { /** - * Tools available only after loading this skill. Can be combined with toolIds. - * @maxItems 20 + * This is the assistant version (e.g. `v3`) to pin for this squad member. When set, the call uses + * the snapshot from `assistant_version` (by `(assistantId, version)`) instead of the latest. Valid + * only with `assistantId`; rejected with inline `assistant`. Omit to follow the latest version. */ - tools?: ( - | CreateFunctionToolDTO - | CreateApiRequestToolDTO - | CreateMcpToolDTO - | CreateEndCallToolDTO - | CreateDtmfToolDTO - | CreateTransferCallToolDTO + assistantVersion?: string | null; + assistantDestinations?: ( + | TransferDestinationAssistant + | HandoffDestinationAssistant )[]; - /** - * Existing organization-owned tools available only after loading this skill. - * @maxItems 20 - */ - toolIds?: string[]; + /** This is the assistant that will be used for the call. To use a transient assistant, use `assistant` instead. */ + assistantId?: string | null; + /** This is the assistant that will be used for the call. To use an existing assistant, use `assistantId` instead. */ + assistant?: TransientAssistantDTO; + /** This can be used to override the assistant's settings and provide values for it's template variables. */ + assistantOverrides?: AssistantOverrides; } -export interface OpenAIReasoner { - /** - * The reasoner uses OpenAI. Omit to use OpenAI. - * @default "openai" - */ - provider?: "openai"; +export interface CreateSquadDTO { + /** This is the name of the squad. */ + name?: string; /** - * The delegated reasoning model. Omit to use GPT-5.6 Terra. - * @default "gpt-5.6-terra" + * This is the list of assistants that make up the squad. + * + * The call will start with the first assistant in the list. */ - model?: "gpt-5.6-sol" | "gpt-5.6-terra" | "gpt-5.6-luna"; + members: SquadMemberDTO[]; /** - * Higher effort can increase response time. Omit to use low. - * @default "low" + * This can be used to override all the assistants' settings and provide values for their template variables. + * + * Both `membersOverrides` and `members[n].assistantOverrides` can be used together. First, `members[n].assistantOverrides` is applied. Then, `membersOverrides` is applied as a global override. */ - reasoningEffort?: "none" | "low" | "medium" | "high" | "xhigh" | "max"; + membersOverrides?: AssistantOverrides; +} + +export interface HandoffDestinationSquad { + type: "squad"; + /** This is the plan for manipulating the message context before handing off the call to the squad. */ + contextEngineeringPlan?: + | ContextEngineeringPlanLastNMessages + | ContextEngineeringPlanNone + | ContextEngineeringPlanAll + | ContextEngineeringPlanUserAndAssistantMessages + | ContextEngineeringPlanPreviousAssistantMessages; + /** This is the squad id to transfer the call to. */ + squadId?: string; + /** This is a transient squad to transfer the call to. */ + squad?: CreateSquadDTO; /** - * Complete reasoner instructions. An explicit empty string is preserved. - * Omit to use Vapi's default reasoner instructions. No behavioral instructions - * are appended unless skills are configured; skill loading guidance and active - * skill content are then composed with these instructions. + * This is the name of the entry assistant to start with when handing off to the squad. + * If not provided, the first member of the squad will be used. */ - instructions?: string; + entryAssistantName?: string; + /** This is the variable extraction plan for the handoff tool. */ + variableExtractionPlan?: VariableExtractionPlan; /** - * Inline skills whose instructions and tools the GPT-Live reasoner loads on demand. - * @maxItems 20 + * These are the overrides to apply to the squad configuration. + * Maps to squad-level membersOverrides. */ - skills?: OpenAIReasonerSkill[]; + squadOverrides?: AssistantOverrides; + /** This is the description of the destination, used by the AI to choose when and how to transfer the call. */ + description?: string; } -export interface OpenAIModel { - /** This is the starting state for the conversation. */ - messages?: OpenAIMessage[]; - /** - * These are the tools that the assistant can use during the call. To use existing tools, use `toolIds`. - * - * Both `tools` and `toolIds` can be used together. - */ - tools?: ( - | CreateApiRequestToolDTO - | CreateBashToolDTO - | CreateCodeToolDTO - | CreateComputerToolDTO - | CreateDtmfToolDTO - | CreateEndCallToolDTO - | CreateFunctionToolDTO - | CreateGoHighLevelCalendarAvailabilityToolDTO - | CreateGoHighLevelCalendarEventCreateToolDTO - | CreateGoHighLevelContactCreateToolDTO - | CreateGoHighLevelContactGetToolDTO - | CreateGoogleCalendarCheckAvailabilityToolDTO - | CreateGoogleCalendarCreateEventToolDTO - | CreateGoogleSheetsRowAppendToolDTO - | CreateHandoffToolDTO - | CreateMcpToolDTO - | CreateQueryToolDTO - | CreateSlackSendMessageToolDTO - | CreateSmsToolDTO - | CreateTextEditorToolDTO - | CreateTransferCallToolDTO - | CreateSipRequestToolDTO - | CreateVoicemailToolDTO +export interface CreateHandoffToolDTO { + /** Messages spoken while the tool is running. Multiple request-start messages are variants. For request-response-delayed, same timing means variants and different timings mean staged updates. */ + messages?: ( + | ToolMessageStart + | ToolMessageComplete + | ToolMessageFailed + | ToolMessageDelayed )[]; /** - * These are the tools that the assistant can use during the call. To use transient tools, use `tools`. + * This is the type of the tool. + * When you're using handoff tool, we recommend adding this to your system prompt + * --- + * # System context * - * Both `tools` and `toolIds` can be used together. + * You 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. + * + * # Agent context + * + * {put your agent system prompt here} + * --- */ - toolIds?: string[]; + type: "handoff"; + /** This is the default local tool result message used when no runtime handoff result override is returned. */ + defaultResult?: string; /** - * These are version-pinned references to tools. Each entry pins a specific - * version of a tool by `(toolId, version)`. When the same `toolId` appears - * in both `toolIds` and `toolRefs[]`, the `toolRefs` pin wins (the - * `toolIds` entry is dropped at write time). - */ + * These are the destinations that the call can be handed off to. + * + * Usage: + * 1. Single destination + * + * Use `assistantId` to handoff the call to a saved assistant, or `assistantName` to handoff the call to an assistant in the same squad. + * + * ```json + * { + * "tools": [ + * { + * "type": "handoff", + * "destinations": [ + * { + * "type": "assistant", + * "assistantId": "assistant-123", // or "assistantName": "Assistant123" + * "description": "customer wants to be handed off to assistant-123", + * "contextEngineeringPlan": { + * "type": "all" + * } + * } + * ], + * } + * ] + * } + * ``` + * + * 2. Multiple destinations + * + * 2.1. Multiple Tools, Each With One Destination (OpenAI recommended) + * + * ```json + * { + * "tools": [ + * { + * "type": "handoff", + * "destinations": [ + * { + * "type": "assistant", + * "assistantId": "assistant-123", + * "description": "customer wants to be handed off to assistant-123", + * "contextEngineeringPlan": { + * "type": "all" + * } + * }, + * ], + * }, + * { + * "type": "handoff", + * "destinations": [ + * { + * "type": "assistant", + * "assistantId": "assistant-456", + * "description": "customer wants to be handed off to assistant-456", + * "contextEngineeringPlan": { + * "type": "all" + * } + * } + * ], + * } + * ] + * } + * ``` + * + * 2.2. One Tool, Multiple Destinations (Anthropic recommended) + * + * ```json + * { + * "tools": [ + * { + * "type": "handoff", + * "destinations": [ + * { + * "type": "assistant", + * "assistantId": "assistant-123", + * "description": "customer wants to be handed off to assistant-123", + * "contextEngineeringPlan": { + * "type": "all" + * } + * }, + * { + * "type": "assistant", + * "assistantId": "assistant-456", + * "description": "customer wants to be handed off to assistant-456", + * "contextEngineeringPlan": { + * "type": "all" + * } + * } + * ], + * } + * ] + * } + * ``` + * + * 3. Dynamic destination + * + * 3.1 To determine the destination dynamically, supply a `dynamic` handoff destination type and a `server` object. + * VAPI will send a handoff-destination-request webhook to the `server.url`. + * The response from the server will be used as the destination (if valid). + * + * ```json + * { + * "tools": [ + * { + * "type": "handoff", + * "destinations": [ + * { + * "type": "dynamic", + * "server": { + * "url": "https://example.com" + * } + * } + * ], + * } + * ] + * } + * ``` + * + * 3.2. To pass custom parameters to the server, you can use the `function` object. + * + * ```json + * { + * "tools": [ + * { + * "type": "handoff", + * "destinations": [ + * { + * "type": "dynamic", + * "server": { + * "url": "https://example.com" + * }, + * } + * ], + * "function": { + * "name": "handoff", + * "description": "Call this function when the customer is ready to be handed off to the next assistant", + * "parameters": { + * "type": "object", + * "properties": { + * "destination": { + * "type": "string", + * "description": "Use dynamic when customer is ready to be handed off to the next assistant", + * "enum": ["dynamic"] + * }, + * "customerAreaCode": { + * "type": "number", + * "description": "Area code of the customer" + * }, + * "customerIntent": { + * "type": "string", + * "enum": ["new-customer", "existing-customer"], + * "description": "Use new-customer when customer is a new customer, existing-customer when customer is an existing customer" + * }, + * "customerSentiment": { + * "type": "string", + * "enum": ["positive", "negative", "neutral"], + * "description": "Use positive when customer is happy, negative when customer is unhappy, neutral when customer is neutral" + * } + * } + * } + * } + * } + * ] + * } + * ``` + * + * The properties `customerAreaCode`, `customerIntent`, and `customerSentiment` will be passed to the server in the webhook request body. + */ + destinations?: ( + | HandoffDestinationAssistant + | HandoffDestinationDynamic + | HandoffDestinationSquad + )[]; + /** + * This is the optional function definition that will be passed to the LLM. + * If this is not defined, we will construct this based on the other properties. + * + * For example, given the following tools definition: + * ```json + * { + * "tools": [ + * { + * "type": "handoff", + * "destinations": [ + * { + * "type": "assistant", + * "assistantId": "assistant-123", + * "description": "customer wants to be handed off to assistant-123", + * "contextEngineeringPlan": { + * "type": "all" + * } + * }, + * { + * "type": "assistant", + * "assistantId": "assistant-456", + * "description": "customer wants to be handed off to assistant-456", + * "contextEngineeringPlan": { + * "type": "all" + * } + * } + * ], + * } + * ] + * } + * ``` + * + * We will construct the following function definition: + * ```json + * { + * "function": { + * "name": "handoff_to_assistant-123", + * "description": " + * Use this function to handoff the call to the next assistant. + * Only use it when instructions explicitly ask you to use the handoff_to_assistant function. + * DO NOT call this function unless you are instructed to do so. + * Here are the destinations you can handoff the call to: + * 1. assistant-123. When: customer wants to be handed off to assistant-123 + * 2. assistant-456. When: customer wants to be handed off to assistant-456 + * ", + * "parameters": { + * "type": "object", + * "properties": { + * "destination": { + * "type": "string", + * "description": "Options: assistant-123 (customer wants to be handed off to assistant-123), assistant-456 (customer wants to be handed off to assistant-456)", + * "enum": ["assistant-123", "assistant-456"] + * }, + * }, + * "required": ["destination"] + * } + * } + * } + * ``` + * + * To override this function, please provide an OpenAI function definition and refer to it in the system prompt. + * You may override parts of the function definition (i.e. you may only want to change the function name for your prompt). + * If you choose to override the function parameters, it must include `destination` as a required parameter, and it must evaluate to either an assistantId, assistantName, or a the string literal `dynamic`. + * + * To pass custom parameters to the server in a dynamic handoff, you can use the function parameters, with `dynamic` as the destination. + * ```json + * { + * "function": { + * "name": "dynamic_handoff", + * "description": " + * Call this function when the customer is ready to be handed off to the next assistant + * ", + * "parameters": { + * "type": "object", + * "properties": { + * "destination": { + * "type": "string", + * "enum": ["dynamic"] + * }, + * "customerAreaCode": { + * "type": "number", + * "description": "Area code of the customer" + * }, + * "customerIntent": { + * "type": "string", + * "enum": ["new-customer", "existing-customer"], + * "description": "Use new-customer when customer is a new customer, existing-customer when customer is an existing customer" + * }, + * "customerSentiment": { + * "type": "string", + * "enum": ["positive", "negative", "neutral"], + * "description": "Use positive when customer is happy, negative when customer is unhappy, neutral when customer is neutral" + * } + * }, + * "required": ["destination", "customerAreaCode", "customerIntent", "customerSentiment"] + * } + * } + * } + * ``` + */ + function?: OpenAIFunction; + /** + * This is the plan to reject a tool call based on the conversation state. + * + * // Example 1: Reject endCall if user didn't say goodbye + * ```json + * { + * conditions: [{ + * type: 'regex', + * regex: '(?i)\\b(bye|goodbye|farewell|see you later|take care)\\b', + * target: { position: -1, role: 'user' }, + * negate: true // Reject if pattern does NOT match + * }] + * } + * ``` + * + * // Example 2: Reject transfer if user is actually asking a question + * ```json + * { + * conditions: [{ + * type: 'regex', + * regex: '\\?', + * target: { position: -1, role: 'user' } + * }] + * } + * ``` + * + * // Example 3: Reject transfer if user didn't mention transfer recently + * ```json + * { + * conditions: [{ + * type: 'liquid', + * liquid: `{% assign recentMessages = messages | last: 5 %} + * {% assign userMessages = recentMessages | where: 'role', 'user' %} + * {% assign mentioned = false %} + * {% for msg in userMessages %} + * {% if msg.content contains 'transfer' or msg.content contains 'connect' or msg.content contains 'speak to' %} + * {% assign mentioned = true %} + * {% break %} + * {% endif %} + * {% endfor %} + * {% if mentioned %} + * false + * {% else %} + * true + * {% endif %}` + * }] + * } + * ``` + * + * // Example 4: Reject endCall if the bot is looping and trying to exit + * ```json + * { + * conditions: [{ + * type: 'liquid', + * liquid: `{% assign recentMessages = messages | last: 6 %} + * {% assign userMessages = recentMessages | where: 'role', 'user' | reverse %} + * {% if userMessages.size < 3 %} + * false + * {% else %} + * {% assign msg1 = userMessages[0].content | downcase %} + * {% assign msg2 = userMessages[1].content | downcase %} + * {% assign msg3 = userMessages[2].content | downcase %} + * {% comment %} Check for repetitive messages {% endcomment %} + * {% if msg1 == msg2 or msg1 == msg3 or msg2 == msg3 %} + * true + * {% comment %} Check for common loop phrases {% endcomment %} + * {% elsif msg1 contains 'cool thanks' or msg2 contains 'cool thanks' or msg3 contains 'cool thanks' %} + * true + * {% elsif msg1 contains 'okay thanks' or msg2 contains 'okay thanks' or msg3 contains 'okay thanks' %} + * true + * {% elsif msg1 contains 'got it' or msg2 contains 'got it' or msg3 contains 'got it' %} + * true + * {% else %} + * false + * {% endif %} + * {% endif %}` + * }] + * } + * ``` + */ + rejectionPlan?: ToolRejectionPlan; +} + +export interface CreateCustomKnowledgeBaseDTO { + /** This knowledge base is bring your own knowledge base implementation. */ + provider: "custom-knowledge-base"; + /** + * This is where the knowledge base request will be sent. + * + * Request Example: + * + * POST https://{server.url} + * Content-Type: application/json + * + * { + * "messsage": { + * "type": "knowledge-base-request", + * "messages": [ + * { + * "role": "user", + * "content": "Why is ocean blue?" + * } + * ], + * ...other metadata about the call... + * } + * } + * + * Response Expected: + * ``` + * { + * "message": { + * "role": "assistant", + * "content": "The ocean is blue because water absorbs everything but blue.", + * }, // YOU CAN RETURN THE EXACT RESPONSE TO SPEAK + * "documents": [ + * { + * "content": "The ocean is blue primarily because water absorbs colors in the red part of the light spectrum and scatters the blue light, making it more visible to our eyes.", + * "similarity": 1 + * }, + * { + * "content": "Blue light is scattered more by the water molecules than other colors, enhancing the blue appearance of the ocean.", + * "similarity": .5 + * } + * ] // OR, YOU CAN RETURN AN ARRAY OF DOCUMENTS THAT WILL BE SENT TO THE MODEL + * } + * ``` + */ + server: Server; +} + +export interface KnowledgeBase { + /** + * The name of the knowledge base + * @example "My Knowledge Base" + */ + name: string; + /** + * The provider of the knowledge base + * @example "google" + */ + provider: "google"; + /** The model to use for the knowledge base */ + model?: + | "gemini-3.8-flash" + | "gemini-3.5-flash" + | "gemini-3.1-flash-lite" + | "gemini-3-flash-preview" + | "gemini-2.5-pro" + | "gemini-2.5-flash" + | "gemini-2.5-flash-lite" + | "gemini-2.0-flash-thinking-exp" + | "gemini-2.0-pro-exp-02-05" + | "gemini-2.0-flash" + | "gemini-2.0-flash-lite" + | "gemini-2.0-flash-exp" + | "gemini-2.0-flash-realtime-exp" + | "gemini-1.5-flash" + | "gemini-1.5-flash-002" + | "gemini-1.5-pro" + | "gemini-1.5-pro-002" + | "gemini-1.0-pro"; + /** A description of the knowledge base */ + description: string; + /** The file IDs associated with this knowledge base */ + fileIds: string[]; +} + +export interface CreateQueryToolDTO { + /** Messages spoken while the tool is running. Multiple request-start messages are variants. For request-response-delayed, same timing means variants and different timings mean staged updates. */ + messages?: ( + | ToolMessageStart + | ToolMessageComplete + | ToolMessageFailed + | ToolMessageDelayed + )[]; + /** The type of tool. "query" for Query tool. */ + type: "query"; + /** The knowledge bases to query */ + knowledgeBases?: KnowledgeBase[]; + /** + * This is the plan to reject a tool call based on the conversation state. + * + * // Example 1: Reject endCall if user didn't say goodbye + * ```json + * { + * conditions: [{ + * type: 'regex', + * regex: '(?i)\\b(bye|goodbye|farewell|see you later|take care)\\b', + * target: { position: -1, role: 'user' }, + * negate: true // Reject if pattern does NOT match + * }] + * } + * ``` + * + * // Example 2: Reject transfer if user is actually asking a question + * ```json + * { + * conditions: [{ + * type: 'regex', + * regex: '\\?', + * target: { position: -1, role: 'user' } + * }] + * } + * ``` + * + * // Example 3: Reject transfer if user didn't mention transfer recently + * ```json + * { + * conditions: [{ + * type: 'liquid', + * liquid: `{% assign recentMessages = messages | last: 5 %} + * {% assign userMessages = recentMessages | where: 'role', 'user' %} + * {% assign mentioned = false %} + * {% for msg in userMessages %} + * {% if msg.content contains 'transfer' or msg.content contains 'connect' or msg.content contains 'speak to' %} + * {% assign mentioned = true %} + * {% break %} + * {% endif %} + * {% endfor %} + * {% if mentioned %} + * false + * {% else %} + * true + * {% endif %}` + * }] + * } + * ``` + * + * // Example 4: Reject endCall if the bot is looping and trying to exit + * ```json + * { + * conditions: [{ + * type: 'liquid', + * liquid: `{% assign recentMessages = messages | last: 6 %} + * {% assign userMessages = recentMessages | where: 'role', 'user' | reverse %} + * {% if userMessages.size < 3 %} + * false + * {% else %} + * {% assign msg1 = userMessages[0].content | downcase %} + * {% assign msg2 = userMessages[1].content | downcase %} + * {% assign msg3 = userMessages[2].content | downcase %} + * {% comment %} Check for repetitive messages {% endcomment %} + * {% if msg1 == msg2 or msg1 == msg3 or msg2 == msg3 %} + * true + * {% comment %} Check for common loop phrases {% endcomment %} + * {% elsif msg1 contains 'cool thanks' or msg2 contains 'cool thanks' or msg3 contains 'cool thanks' %} + * true + * {% elsif msg1 contains 'okay thanks' or msg2 contains 'okay thanks' or msg3 contains 'okay thanks' %} + * true + * {% elsif msg1 contains 'got it' or msg2 contains 'got it' or msg3 contains 'got it' %} + * true + * {% else %} + * false + * {% endif %} + * {% endif %}` + * }] + * } + * ``` + */ + rejectionPlan?: ToolRejectionPlan; +} + +export interface CreateGoogleCalendarCreateEventToolDTO { + /** Messages spoken while the tool is running. Multiple request-start messages are variants. For request-response-delayed, same timing means variants and different timings mean staged updates. */ + messages?: ( + | ToolMessageStart + | ToolMessageComplete + | ToolMessageFailed + | ToolMessageDelayed + )[]; + /** The type of tool. "google.calendar.event.create" for Google Calendar Create Event tool. */ + type: "google.calendar.event.create"; + /** + * This is the plan to reject a tool call based on the conversation state. + * + * // Example 1: Reject endCall if user didn't say goodbye + * ```json + * { + * conditions: [{ + * type: 'regex', + * regex: '(?i)\\b(bye|goodbye|farewell|see you later|take care)\\b', + * target: { position: -1, role: 'user' }, + * negate: true // Reject if pattern does NOT match + * }] + * } + * ``` + * + * // Example 2: Reject transfer if user is actually asking a question + * ```json + * { + * conditions: [{ + * type: 'regex', + * regex: '\\?', + * target: { position: -1, role: 'user' } + * }] + * } + * ``` + * + * // Example 3: Reject transfer if user didn't mention transfer recently + * ```json + * { + * conditions: [{ + * type: 'liquid', + * liquid: `{% assign recentMessages = messages | last: 5 %} + * {% assign userMessages = recentMessages | where: 'role', 'user' %} + * {% assign mentioned = false %} + * {% for msg in userMessages %} + * {% if msg.content contains 'transfer' or msg.content contains 'connect' or msg.content contains 'speak to' %} + * {% assign mentioned = true %} + * {% break %} + * {% endif %} + * {% endfor %} + * {% if mentioned %} + * false + * {% else %} + * true + * {% endif %}` + * }] + * } + * ``` + * + * // Example 4: Reject endCall if the bot is looping and trying to exit + * ```json + * { + * conditions: [{ + * type: 'liquid', + * liquid: `{% assign recentMessages = messages | last: 6 %} + * {% assign userMessages = recentMessages | where: 'role', 'user' | reverse %} + * {% if userMessages.size < 3 %} + * false + * {% else %} + * {% assign msg1 = userMessages[0].content | downcase %} + * {% assign msg2 = userMessages[1].content | downcase %} + * {% assign msg3 = userMessages[2].content | downcase %} + * {% comment %} Check for repetitive messages {% endcomment %} + * {% if msg1 == msg2 or msg1 == msg3 or msg2 == msg3 %} + * true + * {% comment %} Check for common loop phrases {% endcomment %} + * {% elsif msg1 contains 'cool thanks' or msg2 contains 'cool thanks' or msg3 contains 'cool thanks' %} + * true + * {% elsif msg1 contains 'okay thanks' or msg2 contains 'okay thanks' or msg3 contains 'okay thanks' %} + * true + * {% elsif msg1 contains 'got it' or msg2 contains 'got it' or msg3 contains 'got it' %} + * true + * {% else %} + * false + * {% endif %} + * {% endif %}` + * }] + * } + * ``` + */ + rejectionPlan?: ToolRejectionPlan; +} + +export interface CreateGoogleSheetsRowAppendToolDTO { + /** Messages spoken while the tool is running. Multiple request-start messages are variants. For request-response-delayed, same timing means variants and different timings mean staged updates. */ + messages?: ( + | ToolMessageStart + | ToolMessageComplete + | ToolMessageFailed + | ToolMessageDelayed + )[]; + /** The type of tool. "google.sheets.row.append" for Google Sheets Row Append tool. */ + type: "google.sheets.row.append"; + /** + * This is the plan to reject a tool call based on the conversation state. + * + * // Example 1: Reject endCall if user didn't say goodbye + * ```json + * { + * conditions: [{ + * type: 'regex', + * regex: '(?i)\\b(bye|goodbye|farewell|see you later|take care)\\b', + * target: { position: -1, role: 'user' }, + * negate: true // Reject if pattern does NOT match + * }] + * } + * ``` + * + * // Example 2: Reject transfer if user is actually asking a question + * ```json + * { + * conditions: [{ + * type: 'regex', + * regex: '\\?', + * target: { position: -1, role: 'user' } + * }] + * } + * ``` + * + * // Example 3: Reject transfer if user didn't mention transfer recently + * ```json + * { + * conditions: [{ + * type: 'liquid', + * liquid: `{% assign recentMessages = messages | last: 5 %} + * {% assign userMessages = recentMessages | where: 'role', 'user' %} + * {% assign mentioned = false %} + * {% for msg in userMessages %} + * {% if msg.content contains 'transfer' or msg.content contains 'connect' or msg.content contains 'speak to' %} + * {% assign mentioned = true %} + * {% break %} + * {% endif %} + * {% endfor %} + * {% if mentioned %} + * false + * {% else %} + * true + * {% endif %}` + * }] + * } + * ``` + * + * // Example 4: Reject endCall if the bot is looping and trying to exit + * ```json + * { + * conditions: [{ + * type: 'liquid', + * liquid: `{% assign recentMessages = messages | last: 6 %} + * {% assign userMessages = recentMessages | where: 'role', 'user' | reverse %} + * {% if userMessages.size < 3 %} + * false + * {% else %} + * {% assign msg1 = userMessages[0].content | downcase %} + * {% assign msg2 = userMessages[1].content | downcase %} + * {% assign msg3 = userMessages[2].content | downcase %} + * {% comment %} Check for repetitive messages {% endcomment %} + * {% if msg1 == msg2 or msg1 == msg3 or msg2 == msg3 %} + * true + * {% comment %} Check for common loop phrases {% endcomment %} + * {% elsif msg1 contains 'cool thanks' or msg2 contains 'cool thanks' or msg3 contains 'cool thanks' %} + * true + * {% elsif msg1 contains 'okay thanks' or msg2 contains 'okay thanks' or msg3 contains 'okay thanks' %} + * true + * {% elsif msg1 contains 'got it' or msg2 contains 'got it' or msg3 contains 'got it' %} + * true + * {% else %} + * false + * {% endif %} + * {% endif %}` + * }] + * } + * ``` + */ + rejectionPlan?: ToolRejectionPlan; +} + +export interface CreateGoogleCalendarCheckAvailabilityToolDTO { + /** Messages spoken while the tool is running. Multiple request-start messages are variants. For request-response-delayed, same timing means variants and different timings mean staged updates. */ + messages?: ( + | ToolMessageStart + | ToolMessageComplete + | ToolMessageFailed + | ToolMessageDelayed + )[]; + /** The type of tool. "google.calendar.availability.check" for Google Calendar Check Availability tool. */ + type: "google.calendar.availability.check"; + /** + * This is the plan to reject a tool call based on the conversation state. + * + * // Example 1: Reject endCall if user didn't say goodbye + * ```json + * { + * conditions: [{ + * type: 'regex', + * regex: '(?i)\\b(bye|goodbye|farewell|see you later|take care)\\b', + * target: { position: -1, role: 'user' }, + * negate: true // Reject if pattern does NOT match + * }] + * } + * ``` + * + * // Example 2: Reject transfer if user is actually asking a question + * ```json + * { + * conditions: [{ + * type: 'regex', + * regex: '\\?', + * target: { position: -1, role: 'user' } + * }] + * } + * ``` + * + * // Example 3: Reject transfer if user didn't mention transfer recently + * ```json + * { + * conditions: [{ + * type: 'liquid', + * liquid: `{% assign recentMessages = messages | last: 5 %} + * {% assign userMessages = recentMessages | where: 'role', 'user' %} + * {% assign mentioned = false %} + * {% for msg in userMessages %} + * {% if msg.content contains 'transfer' or msg.content contains 'connect' or msg.content contains 'speak to' %} + * {% assign mentioned = true %} + * {% break %} + * {% endif %} + * {% endfor %} + * {% if mentioned %} + * false + * {% else %} + * true + * {% endif %}` + * }] + * } + * ``` + * + * // Example 4: Reject endCall if the bot is looping and trying to exit + * ```json + * { + * conditions: [{ + * type: 'liquid', + * liquid: `{% assign recentMessages = messages | last: 6 %} + * {% assign userMessages = recentMessages | where: 'role', 'user' | reverse %} + * {% if userMessages.size < 3 %} + * false + * {% else %} + * {% assign msg1 = userMessages[0].content | downcase %} + * {% assign msg2 = userMessages[1].content | downcase %} + * {% assign msg3 = userMessages[2].content | downcase %} + * {% comment %} Check for repetitive messages {% endcomment %} + * {% if msg1 == msg2 or msg1 == msg3 or msg2 == msg3 %} + * true + * {% comment %} Check for common loop phrases {% endcomment %} + * {% elsif msg1 contains 'cool thanks' or msg2 contains 'cool thanks' or msg3 contains 'cool thanks' %} + * true + * {% elsif msg1 contains 'okay thanks' or msg2 contains 'okay thanks' or msg3 contains 'okay thanks' %} + * true + * {% elsif msg1 contains 'got it' or msg2 contains 'got it' or msg3 contains 'got it' %} + * true + * {% else %} + * false + * {% endif %} + * {% endif %}` + * }] + * } + * ``` + */ + rejectionPlan?: ToolRejectionPlan; +} + +export interface CreateSlackSendMessageToolDTO { + /** Messages spoken while the tool is running. Multiple request-start messages are variants. For request-response-delayed, same timing means variants and different timings mean staged updates. */ + messages?: ( + | ToolMessageStart + | ToolMessageComplete + | ToolMessageFailed + | ToolMessageDelayed + )[]; + /** The type of tool. "slack.message.send" for Slack Send Message tool. */ + type: "slack.message.send"; + /** + * This is the plan to reject a tool call based on the conversation state. + * + * // Example 1: Reject endCall if user didn't say goodbye + * ```json + * { + * conditions: [{ + * type: 'regex', + * regex: '(?i)\\b(bye|goodbye|farewell|see you later|take care)\\b', + * target: { position: -1, role: 'user' }, + * negate: true // Reject if pattern does NOT match + * }] + * } + * ``` + * + * // Example 2: Reject transfer if user is actually asking a question + * ```json + * { + * conditions: [{ + * type: 'regex', + * regex: '\\?', + * target: { position: -1, role: 'user' } + * }] + * } + * ``` + * + * // Example 3: Reject transfer if user didn't mention transfer recently + * ```json + * { + * conditions: [{ + * type: 'liquid', + * liquid: `{% assign recentMessages = messages | last: 5 %} + * {% assign userMessages = recentMessages | where: 'role', 'user' %} + * {% assign mentioned = false %} + * {% for msg in userMessages %} + * {% if msg.content contains 'transfer' or msg.content contains 'connect' or msg.content contains 'speak to' %} + * {% assign mentioned = true %} + * {% break %} + * {% endif %} + * {% endfor %} + * {% if mentioned %} + * false + * {% else %} + * true + * {% endif %}` + * }] + * } + * ``` + * + * // Example 4: Reject endCall if the bot is looping and trying to exit + * ```json + * { + * conditions: [{ + * type: 'liquid', + * liquid: `{% assign recentMessages = messages | last: 6 %} + * {% assign userMessages = recentMessages | where: 'role', 'user' | reverse %} + * {% if userMessages.size < 3 %} + * false + * {% else %} + * {% assign msg1 = userMessages[0].content | downcase %} + * {% assign msg2 = userMessages[1].content | downcase %} + * {% assign msg3 = userMessages[2].content | downcase %} + * {% comment %} Check for repetitive messages {% endcomment %} + * {% if msg1 == msg2 or msg1 == msg3 or msg2 == msg3 %} + * true + * {% comment %} Check for common loop phrases {% endcomment %} + * {% elsif msg1 contains 'cool thanks' or msg2 contains 'cool thanks' or msg3 contains 'cool thanks' %} + * true + * {% elsif msg1 contains 'okay thanks' or msg2 contains 'okay thanks' or msg3 contains 'okay thanks' %} + * true + * {% elsif msg1 contains 'got it' or msg2 contains 'got it' or msg3 contains 'got it' %} + * true + * {% else %} + * false + * {% endif %} + * {% endif %}` + * }] + * } + * ``` + */ + rejectionPlan?: ToolRejectionPlan; +} + +export interface McpToolMessages { + /** The name of the tool from the MCP server. */ + name: string; + /** Custom messages for this specific tool. Set to an empty array to suppress all messages for this tool. If not provided, the tool will use the default messages from the parent MCP tool configuration. Multiple request-start messages are variants. For request-response-delayed, same timing means variants and different timings mean staged updates. */ + messages?: ( + | ToolMessageStart + | ToolMessageComplete + | ToolMessageFailed + | ToolMessageDelayed + )[]; +} + +export interface McpToolMetadata { + /** This is the protocol used for MCP communication. Defaults to Streamable HTTP. */ + protocol?: "sse" | "shttp"; +} + +export interface CreateMcpToolDTO { + /** Messages spoken while the tool is running. Multiple request-start messages are variants. For request-response-delayed, same timing means variants and different timings mean staged updates. */ + messages?: ( + | ToolMessageStart + | ToolMessageComplete + | ToolMessageFailed + | ToolMessageDelayed + )[]; + /** The type of tool. "mcp" for MCP tool. */ + type: "mcp"; + /** + * + * This is the server where a `tool-calls` webhook will be sent. + * + * Notes: + * - Webhook is sent to this server when a tool call is made. + * - Webhook contains the call, assistant, and phone number objects. + * - Webhook contains the variables set on the assistant. + * - Webhook is sent to the first available URL in this order: {{tool.server.url}}, {{assistant.server.url}}, {{phoneNumber.server.url}}, {{org.server.url}}. + * - Webhook expects a response with tool call result. + */ + server?: Server; + /** Per-tool message overrides for individual tools loaded from the MCP server. Set messages to an empty array to suppress messages for a specific tool. Tools not listed here will use the default messages from the parent tool. */ + toolMessages?: McpToolMessages[]; + metadata?: McpToolMetadata; + /** + * This is the plan to reject a tool call based on the conversation state. + * + * // Example 1: Reject endCall if user didn't say goodbye + * ```json + * { + * conditions: [{ + * type: 'regex', + * regex: '(?i)\\b(bye|goodbye|farewell|see you later|take care)\\b', + * target: { position: -1, role: 'user' }, + * negate: true // Reject if pattern does NOT match + * }] + * } + * ``` + * + * // Example 2: Reject transfer if user is actually asking a question + * ```json + * { + * conditions: [{ + * type: 'regex', + * regex: '\\?', + * target: { position: -1, role: 'user' } + * }] + * } + * ``` + * + * // Example 3: Reject transfer if user didn't mention transfer recently + * ```json + * { + * conditions: [{ + * type: 'liquid', + * liquid: `{% assign recentMessages = messages | last: 5 %} + * {% assign userMessages = recentMessages | where: 'role', 'user' %} + * {% assign mentioned = false %} + * {% for msg in userMessages %} + * {% if msg.content contains 'transfer' or msg.content contains 'connect' or msg.content contains 'speak to' %} + * {% assign mentioned = true %} + * {% break %} + * {% endif %} + * {% endfor %} + * {% if mentioned %} + * false + * {% else %} + * true + * {% endif %}` + * }] + * } + * ``` + * + * // Example 4: Reject endCall if the bot is looping and trying to exit + * ```json + * { + * conditions: [{ + * type: 'liquid', + * liquid: `{% assign recentMessages = messages | last: 6 %} + * {% assign userMessages = recentMessages | where: 'role', 'user' | reverse %} + * {% if userMessages.size < 3 %} + * false + * {% else %} + * {% assign msg1 = userMessages[0].content | downcase %} + * {% assign msg2 = userMessages[1].content | downcase %} + * {% assign msg3 = userMessages[2].content | downcase %} + * {% comment %} Check for repetitive messages {% endcomment %} + * {% if msg1 == msg2 or msg1 == msg3 or msg2 == msg3 %} + * true + * {% comment %} Check for common loop phrases {% endcomment %} + * {% elsif msg1 contains 'cool thanks' or msg2 contains 'cool thanks' or msg3 contains 'cool thanks' %} + * true + * {% elsif msg1 contains 'okay thanks' or msg2 contains 'okay thanks' or msg3 contains 'okay thanks' %} + * true + * {% elsif msg1 contains 'got it' or msg2 contains 'got it' or msg3 contains 'got it' %} + * true + * {% else %} + * false + * {% endif %} + * {% endif %}` + * }] + * } + * ``` + */ + rejectionPlan?: ToolRejectionPlan; +} + +export interface CreateGoHighLevelCalendarAvailabilityToolDTO { + /** Messages spoken while the tool is running. Multiple request-start messages are variants. For request-response-delayed, same timing means variants and different timings mean staged updates. */ + messages?: ( + | ToolMessageStart + | ToolMessageComplete + | ToolMessageFailed + | ToolMessageDelayed + )[]; + /** The type of tool. "gohighlevel.calendar.availability.check" for GoHighLevel Calendar Availability Check tool. */ + type: "gohighlevel.calendar.availability.check"; + /** + * This is the plan to reject a tool call based on the conversation state. + * + * // Example 1: Reject endCall if user didn't say goodbye + * ```json + * { + * conditions: [{ + * type: 'regex', + * regex: '(?i)\\b(bye|goodbye|farewell|see you later|take care)\\b', + * target: { position: -1, role: 'user' }, + * negate: true // Reject if pattern does NOT match + * }] + * } + * ``` + * + * // Example 2: Reject transfer if user is actually asking a question + * ```json + * { + * conditions: [{ + * type: 'regex', + * regex: '\\?', + * target: { position: -1, role: 'user' } + * }] + * } + * ``` + * + * // Example 3: Reject transfer if user didn't mention transfer recently + * ```json + * { + * conditions: [{ + * type: 'liquid', + * liquid: `{% assign recentMessages = messages | last: 5 %} + * {% assign userMessages = recentMessages | where: 'role', 'user' %} + * {% assign mentioned = false %} + * {% for msg in userMessages %} + * {% if msg.content contains 'transfer' or msg.content contains 'connect' or msg.content contains 'speak to' %} + * {% assign mentioned = true %} + * {% break %} + * {% endif %} + * {% endfor %} + * {% if mentioned %} + * false + * {% else %} + * true + * {% endif %}` + * }] + * } + * ``` + * + * // Example 4: Reject endCall if the bot is looping and trying to exit + * ```json + * { + * conditions: [{ + * type: 'liquid', + * liquid: `{% assign recentMessages = messages | last: 6 %} + * {% assign userMessages = recentMessages | where: 'role', 'user' | reverse %} + * {% if userMessages.size < 3 %} + * false + * {% else %} + * {% assign msg1 = userMessages[0].content | downcase %} + * {% assign msg2 = userMessages[1].content | downcase %} + * {% assign msg3 = userMessages[2].content | downcase %} + * {% comment %} Check for repetitive messages {% endcomment %} + * {% if msg1 == msg2 or msg1 == msg3 or msg2 == msg3 %} + * true + * {% comment %} Check for common loop phrases {% endcomment %} + * {% elsif msg1 contains 'cool thanks' or msg2 contains 'cool thanks' or msg3 contains 'cool thanks' %} + * true + * {% elsif msg1 contains 'okay thanks' or msg2 contains 'okay thanks' or msg3 contains 'okay thanks' %} + * true + * {% elsif msg1 contains 'got it' or msg2 contains 'got it' or msg3 contains 'got it' %} + * true + * {% else %} + * false + * {% endif %} + * {% endif %}` + * }] + * } + * ``` + */ + rejectionPlan?: ToolRejectionPlan; +} + +export interface CreateGoHighLevelCalendarEventCreateToolDTO { + /** Messages spoken while the tool is running. Multiple request-start messages are variants. For request-response-delayed, same timing means variants and different timings mean staged updates. */ + messages?: ( + | ToolMessageStart + | ToolMessageComplete + | ToolMessageFailed + | ToolMessageDelayed + )[]; + /** The type of tool. "gohighlevel.calendar.event.create" for GoHighLevel Calendar Event Create tool. */ + type: "gohighlevel.calendar.event.create"; + /** + * This is the plan to reject a tool call based on the conversation state. + * + * // Example 1: Reject endCall if user didn't say goodbye + * ```json + * { + * conditions: [{ + * type: 'regex', + * regex: '(?i)\\b(bye|goodbye|farewell|see you later|take care)\\b', + * target: { position: -1, role: 'user' }, + * negate: true // Reject if pattern does NOT match + * }] + * } + * ``` + * + * // Example 2: Reject transfer if user is actually asking a question + * ```json + * { + * conditions: [{ + * type: 'regex', + * regex: '\\?', + * target: { position: -1, role: 'user' } + * }] + * } + * ``` + * + * // Example 3: Reject transfer if user didn't mention transfer recently + * ```json + * { + * conditions: [{ + * type: 'liquid', + * liquid: `{% assign recentMessages = messages | last: 5 %} + * {% assign userMessages = recentMessages | where: 'role', 'user' %} + * {% assign mentioned = false %} + * {% for msg in userMessages %} + * {% if msg.content contains 'transfer' or msg.content contains 'connect' or msg.content contains 'speak to' %} + * {% assign mentioned = true %} + * {% break %} + * {% endif %} + * {% endfor %} + * {% if mentioned %} + * false + * {% else %} + * true + * {% endif %}` + * }] + * } + * ``` + * + * // Example 4: Reject endCall if the bot is looping and trying to exit + * ```json + * { + * conditions: [{ + * type: 'liquid', + * liquid: `{% assign recentMessages = messages | last: 6 %} + * {% assign userMessages = recentMessages | where: 'role', 'user' | reverse %} + * {% if userMessages.size < 3 %} + * false + * {% else %} + * {% assign msg1 = userMessages[0].content | downcase %} + * {% assign msg2 = userMessages[1].content | downcase %} + * {% assign msg3 = userMessages[2].content | downcase %} + * {% comment %} Check for repetitive messages {% endcomment %} + * {% if msg1 == msg2 or msg1 == msg3 or msg2 == msg3 %} + * true + * {% comment %} Check for common loop phrases {% endcomment %} + * {% elsif msg1 contains 'cool thanks' or msg2 contains 'cool thanks' or msg3 contains 'cool thanks' %} + * true + * {% elsif msg1 contains 'okay thanks' or msg2 contains 'okay thanks' or msg3 contains 'okay thanks' %} + * true + * {% elsif msg1 contains 'got it' or msg2 contains 'got it' or msg3 contains 'got it' %} + * true + * {% else %} + * false + * {% endif %} + * {% endif %}` + * }] + * } + * ``` + */ + rejectionPlan?: ToolRejectionPlan; +} + +export interface CreateGoHighLevelContactCreateToolDTO { + /** Messages spoken while the tool is running. Multiple request-start messages are variants. For request-response-delayed, same timing means variants and different timings mean staged updates. */ + messages?: ( + | ToolMessageStart + | ToolMessageComplete + | ToolMessageFailed + | ToolMessageDelayed + )[]; + /** The type of tool. "gohighlevel.contact.create" for GoHighLevel Contact Create tool. */ + type: "gohighlevel.contact.create"; + /** + * This is the plan to reject a tool call based on the conversation state. + * + * // Example 1: Reject endCall if user didn't say goodbye + * ```json + * { + * conditions: [{ + * type: 'regex', + * regex: '(?i)\\b(bye|goodbye|farewell|see you later|take care)\\b', + * target: { position: -1, role: 'user' }, + * negate: true // Reject if pattern does NOT match + * }] + * } + * ``` + * + * // Example 2: Reject transfer if user is actually asking a question + * ```json + * { + * conditions: [{ + * type: 'regex', + * regex: '\\?', + * target: { position: -1, role: 'user' } + * }] + * } + * ``` + * + * // Example 3: Reject transfer if user didn't mention transfer recently + * ```json + * { + * conditions: [{ + * type: 'liquid', + * liquid: `{% assign recentMessages = messages | last: 5 %} + * {% assign userMessages = recentMessages | where: 'role', 'user' %} + * {% assign mentioned = false %} + * {% for msg in userMessages %} + * {% if msg.content contains 'transfer' or msg.content contains 'connect' or msg.content contains 'speak to' %} + * {% assign mentioned = true %} + * {% break %} + * {% endif %} + * {% endfor %} + * {% if mentioned %} + * false + * {% else %} + * true + * {% endif %}` + * }] + * } + * ``` + * + * // Example 4: Reject endCall if the bot is looping and trying to exit + * ```json + * { + * conditions: [{ + * type: 'liquid', + * liquid: `{% assign recentMessages = messages | last: 6 %} + * {% assign userMessages = recentMessages | where: 'role', 'user' | reverse %} + * {% if userMessages.size < 3 %} + * false + * {% else %} + * {% assign msg1 = userMessages[0].content | downcase %} + * {% assign msg2 = userMessages[1].content | downcase %} + * {% assign msg3 = userMessages[2].content | downcase %} + * {% comment %} Check for repetitive messages {% endcomment %} + * {% if msg1 == msg2 or msg1 == msg3 or msg2 == msg3 %} + * true + * {% comment %} Check for common loop phrases {% endcomment %} + * {% elsif msg1 contains 'cool thanks' or msg2 contains 'cool thanks' or msg3 contains 'cool thanks' %} + * true + * {% elsif msg1 contains 'okay thanks' or msg2 contains 'okay thanks' or msg3 contains 'okay thanks' %} + * true + * {% elsif msg1 contains 'got it' or msg2 contains 'got it' or msg3 contains 'got it' %} + * true + * {% else %} + * false + * {% endif %} + * {% endif %}` + * }] + * } + * ``` + */ + rejectionPlan?: ToolRejectionPlan; +} + +export interface CreateGoHighLevelContactGetToolDTO { + /** Messages spoken while the tool is running. Multiple request-start messages are variants. For request-response-delayed, same timing means variants and different timings mean staged updates. */ + messages?: ( + | ToolMessageStart + | ToolMessageComplete + | ToolMessageFailed + | ToolMessageDelayed + )[]; + /** The type of tool. "gohighlevel.contact.get" for GoHighLevel Contact Get tool. */ + type: "gohighlevel.contact.get"; + /** + * This is the plan to reject a tool call based on the conversation state. + * + * // Example 1: Reject endCall if user didn't say goodbye + * ```json + * { + * conditions: [{ + * type: 'regex', + * regex: '(?i)\\b(bye|goodbye|farewell|see you later|take care)\\b', + * target: { position: -1, role: 'user' }, + * negate: true // Reject if pattern does NOT match + * }] + * } + * ``` + * + * // Example 2: Reject transfer if user is actually asking a question + * ```json + * { + * conditions: [{ + * type: 'regex', + * regex: '\\?', + * target: { position: -1, role: 'user' } + * }] + * } + * ``` + * + * // Example 3: Reject transfer if user didn't mention transfer recently + * ```json + * { + * conditions: [{ + * type: 'liquid', + * liquid: `{% assign recentMessages = messages | last: 5 %} + * {% assign userMessages = recentMessages | where: 'role', 'user' %} + * {% assign mentioned = false %} + * {% for msg in userMessages %} + * {% if msg.content contains 'transfer' or msg.content contains 'connect' or msg.content contains 'speak to' %} + * {% assign mentioned = true %} + * {% break %} + * {% endif %} + * {% endfor %} + * {% if mentioned %} + * false + * {% else %} + * true + * {% endif %}` + * }] + * } + * ``` + * + * // Example 4: Reject endCall if the bot is looping and trying to exit + * ```json + * { + * conditions: [{ + * type: 'liquid', + * liquid: `{% assign recentMessages = messages | last: 6 %} + * {% assign userMessages = recentMessages | where: 'role', 'user' | reverse %} + * {% if userMessages.size < 3 %} + * false + * {% else %} + * {% assign msg1 = userMessages[0].content | downcase %} + * {% assign msg2 = userMessages[1].content | downcase %} + * {% assign msg3 = userMessages[2].content | downcase %} + * {% comment %} Check for repetitive messages {% endcomment %} + * {% if msg1 == msg2 or msg1 == msg3 or msg2 == msg3 %} + * true + * {% comment %} Check for common loop phrases {% endcomment %} + * {% elsif msg1 contains 'cool thanks' or msg2 contains 'cool thanks' or msg3 contains 'cool thanks' %} + * true + * {% elsif msg1 contains 'okay thanks' or msg2 contains 'okay thanks' or msg3 contains 'okay thanks' %} + * true + * {% elsif msg1 contains 'got it' or msg2 contains 'got it' or msg3 contains 'got it' %} + * true + * {% else %} + * false + * {% endif %} + * {% endif %}` + * }] + * } + * ``` + */ + rejectionPlan?: ToolRejectionPlan; +} + +export interface OpenAIMessage { + /** @maxLength 100000000 */ + content: string | null; + role: "assistant" | "function" | "user" | "system" | "tool"; +} + +export interface ToolRef { + /** + * This is the unique identifier of the tool whose version is being pinned. + * @format uuid + */ + toolId: string; + /** Public version label of the tool, e.g. "v3" */ + version: string; +} + +export interface AnyscaleModel { + /** This is the starting state for the conversation. */ + messages?: OpenAIMessage[]; + /** + * These are the tools that the assistant can use during the call. To use existing tools, use `toolIds`. + * + * Both `tools` and `toolIds` can be used together. + */ + tools?: ( + | CreateApiRequestToolDTO + | CreateBashToolDTO + | CreateCodeToolDTO + | CreateComputerToolDTO + | CreateDtmfToolDTO + | CreateEndCallToolDTO + | CreateFunctionToolDTO + | CreateGoHighLevelCalendarAvailabilityToolDTO + | CreateGoHighLevelCalendarEventCreateToolDTO + | CreateGoHighLevelContactCreateToolDTO + | CreateGoHighLevelContactGetToolDTO + | CreateGoogleCalendarCheckAvailabilityToolDTO + | CreateGoogleCalendarCreateEventToolDTO + | CreateGoogleSheetsRowAppendToolDTO + | CreateHandoffToolDTO + | CreateMcpToolDTO + | CreateQueryToolDTO + | CreateSlackSendMessageToolDTO + | CreateSmsToolDTO + | CreateTextEditorToolDTO + | CreateTransferCallToolDTO + | CreateSipRequestToolDTO + | CreateVoicemailToolDTO + )[]; + /** + * These are the tools that the assistant can use during the call. To use transient tools, use `tools`. + * + * Both `tools` and `toolIds` can be used together. + */ + toolIds?: string[]; + /** + * These are version-pinned references to tools. Each entry pins a specific + * version of a tool by `(toolId, version)`. When the same `toolId` appears + * in both `toolIds` and `toolRefs[]`, the `toolRefs` pin wins (the + * `toolIds` entry is dropped at write time). + */ toolRefs?: ToolRef[]; /** These are the options for the knowledge base. */ knowledgeBase?: CreateCustomKnowledgeBaseDTO; - /** Configuration for the GPT-Live speaker. */ - speaker?: OpenAISpeaker; - /** Configuration for the reasoner supporting the GPT-Live speaker. */ - reasoner?: OpenAIReasoner; - /** This is the provider that will be used for the model. */ - provider: "openai"; + provider: "anyscale"; + /** This is the name of the model. Ex. cognitivecomputations/dolphin-mixtral-8x7b */ + model: string; /** - * This is the OpenAI model that will be used. - * For GPT-Live configuration and supported settings, see https://docs.vapi.ai/gpt-live/overview. - * - * When using Vapi OpenAI or your own Azure Credentials, you have the option to specify the region for the selected model. This shouldn't be specified unless you have a specific reason to do so. Vapi will automatically find the fastest region that make sense. - * This is helpful when you are required to comply with Data Residency rules. Learn more about Azure regions here https://azure.microsoft.com/en-us/explore/global-infrastructure/data-residency/. - * - * @default undefined + * This is the temperature that will be used for calls. Default is 0.5. + * @min 0 + * @max 2 */ - model: - | "gpt-6-luna" - | "gpt-5.6-sol" - | "gpt-5.6-terra" - | "gpt-5.6-luna" - | "gpt-5.5" - | "chat-latest" - | "gpt-5.4" - | "gpt-5.4-mini" - | "gpt-5.4-nano" - | "gpt-5.2" - | "gpt-5.2-chat-latest" - | "gpt-5.1" - | "gpt-5.1-chat-latest" - | "gpt-5" - | "gpt-5-chat-latest" - | "gpt-5-mini" - | "gpt-5-nano" - | "gpt-4.1-2025-04-14" - | "gpt-4.1-mini-2025-04-14" - | "gpt-4.1-nano-2025-04-14" - | "gpt-4.1" - | "gpt-4.1-mini" - | "gpt-4.1-nano" - | "chatgpt-4o-latest" - | "o3" - | "o3-mini" - | "o4-mini" - | "o1-mini" - | "o1-mini-2024-09-12" - | "gpt-4o-realtime-preview-2024-10-01" - | "gpt-4o-realtime-preview-2024-12-17" - | "gpt-4o-mini-realtime-preview-2024-12-17" - | "gpt-realtime-2025-08-28" - | "gpt-realtime-mini-2025-12-15" - | "gpt-realtime-2" - | "gpt-4o-mini-2024-07-18" - | "gpt-4o-mini" - | "gpt-4o" - | "gpt-4o-2024-05-13" - | "gpt-4o-2024-08-06" - | "gpt-4o-2024-11-20" - | "gpt-4-turbo" - | "gpt-4-turbo-2024-04-09" - | "gpt-4-turbo-preview" - | "gpt-4-0125-preview" - | "gpt-4-1106-preview" - | "gpt-4" - | "gpt-4-0613" - | "gpt-3.5-turbo" - | "gpt-3.5-turbo-0125" - | "gpt-3.5-turbo-1106" - | "gpt-3.5-turbo-16k" - | "gpt-3.5-turbo-0613" - | "gpt-5.6-luna:westus3" - | "gpt-5.6-terra:westus3" - | "gpt-5.6-sol:westus3" - | "gpt-5.4:eastus2" - | "gpt-5.4:swedencentral" - | "gpt-5.4-mini:eastus2" - | "gpt-5.4-mini:swedencentral" - | "gpt-5.4-nano:eastus2" - | "gpt-5.4-nano:swedencentral" - | "gpt-5.2:eastus2" - | "gpt-5.2:swedencentral" - | "gpt-5.1:eastus2" - | "gpt-5.1:swedencentral" - | "gpt-5:eastus2" - | "gpt-5:swedencentral" - | "gpt-5:canadaeast" - | "gpt-5:eastus" - | "gpt-5:westeurope" - | "gpt-5:germanywestcentral" - | "gpt-5:polandcentral" - | "gpt-5:spaincentral" - | "gpt-5-mini:eastus2" - | "gpt-5-mini:swedencentral" - | "gpt-5-mini:westeurope" - | "gpt-5-mini:germanywestcentral" - | "gpt-5-mini:polandcentral" - | "gpt-5-mini:spaincentral" - | "gpt-5-nano:eastus2" - | "gpt-5-nano:swedencentral" - | "gpt-4.1-2025-04-14:westus" - | "gpt-4.1-2025-04-14:eastus2" - | "gpt-4.1-2025-04-14:eastus" - | "gpt-4.1-2025-04-14:westus3" - | "gpt-4.1-2025-04-14:northcentralus" - | "gpt-4.1-2025-04-14:southcentralus" - | "gpt-4.1-2025-04-14:westeurope" - | "gpt-4.1-2025-04-14:germanywestcentral" - | "gpt-4.1-2025-04-14:polandcentral" - | "gpt-4.1-2025-04-14:spaincentral" - | "gpt-4.1-mini-2025-04-14:westus" - | "gpt-4.1-mini-2025-04-14:eastus2" - | "gpt-4.1-mini-2025-04-14:eastus" - | "gpt-4.1-mini-2025-04-14:westus3" - | "gpt-4.1-mini-2025-04-14:northcentralus" - | "gpt-4.1-mini-2025-04-14:southcentralus" - | "gpt-4.1-mini-2025-04-14:westeurope" - | "gpt-4.1-mini-2025-04-14:germanywestcentral" - | "gpt-4.1-mini-2025-04-14:polandcentral" - | "gpt-4.1-mini-2025-04-14:spaincentral" - | "gpt-4.1-nano-2025-04-14:westus" - | "gpt-4.1-nano-2025-04-14:eastus2" - | "gpt-4.1-nano-2025-04-14:westus3" - | "gpt-4.1-nano-2025-04-14:northcentralus" - | "gpt-4.1-nano-2025-04-14:southcentralus" - | "gpt-4o-2024-11-20:swedencentral" - | "gpt-4o-2024-11-20:westus" - | "gpt-4o-2024-11-20:eastus2" - | "gpt-4o-2024-11-20:eastus" - | "gpt-4o-2024-11-20:westus3" - | "gpt-4o-2024-11-20:southcentralus" - | "gpt-4o-2024-11-20:westeurope" - | "gpt-4o-2024-11-20:germanywestcentral" - | "gpt-4o-2024-11-20:polandcentral" - | "gpt-4o-2024-11-20:spaincentral" - | "gpt-4o-2024-08-06:westus" - | "gpt-4o-2024-08-06:westus3" - | "gpt-4o-2024-08-06:eastus" - | "gpt-4o-2024-08-06:eastus2" - | "gpt-4o-2024-08-06:northcentralus" - | "gpt-4o-2024-08-06:southcentralus" - | "gpt-4o-mini-2024-07-18:westus" - | "gpt-4o-mini-2024-07-18:westus3" - | "gpt-4o-mini-2024-07-18:eastus" - | "gpt-4o-mini-2024-07-18:eastus2" - | "gpt-4o-mini-2024-07-18:northcentralus" - | "gpt-4o-mini-2024-07-18:southcentralus" - | "gpt-4o-2024-05-13:eastus2" - | "gpt-4o-2024-05-13:eastus" - | "gpt-4o-2024-05-13:northcentralus" - | "gpt-4o-2024-05-13:southcentralus" - | "gpt-4o-2024-05-13:westus3" - | "gpt-4o-2024-05-13:westus" - | "gpt-4-turbo-2024-04-09:eastus2" - | "gpt-4-0125-preview:eastus" - | "gpt-4-0125-preview:northcentralus" - | "gpt-4-0125-preview:southcentralus" - | "gpt-4-1106-preview:australiaeast" - | "gpt-4-1106-preview:canadaeast" - | "gpt-4-1106-preview:france" - | "gpt-4-1106-preview:india" - | "gpt-4-1106-preview:norway" - | "gpt-4-1106-preview:swedencentral" - | "gpt-4-1106-preview:uk" - | "gpt-4-1106-preview:westus" - | "gpt-4-1106-preview:westus3" - | "gpt-4-0613:canadaeast" - | "gpt-3.5-turbo-0125:canadaeast" - | "gpt-3.5-turbo-0125:northcentralus" - | "gpt-3.5-turbo-0125:southcentralus" - | "gpt-3.5-turbo-1106:canadaeast" - | "gpt-3.5-turbo-1106:westus" - | "gpt-4.1:australiaeast" - | "gpt-4o:australiaeast" - | "gpt-5.4-mini:australiaeast" - | "gpt-live-1"; + temperature?: number; + /** + * This is the max number of tokens that the assistant will be allowed to generate in each turn of the conversation. Default is 250. On gpt-6-luna and claude-haiku-5-5 no cap is applied unless you set one (claude-haiku-5-5 sends its 128,000-token maximum), because reasoning uses output tokens and a small cap can leave the reply empty. + * @min 50 + * @max 10000 + */ + maxTokens?: number; + /** + * This determines whether we detect user's emotion while they speak and send it as an additional info to model. + * + * Default `false` because the model is usually are good at understanding the user's emotion from text. + * + * @default false + */ + emotionRecognitionEnabled?: boolean; /** - * These are the fallback models that will be used if the primary model fails. This shouldn't be specified unless you have a specific reason to do so. Vapi will automatically find the fastest fallbacks that make sense. - * @example ["gpt-4-0125-preview","gpt-4-0613"] + * This sets how many turns at the start of the conversation to use a smaller, faster model from the same provider before switching to the primary model. Example, gpt-3.5-turbo if provider is openai. + * + * Default is 0. + * + * @default 0 + * @min 0 */ - fallbackModels?: ( - | "gpt-6-luna" - | "gpt-5.6-sol" - | "gpt-5.6-terra" - | "gpt-5.6-luna" - | "gpt-5.5" - | "chat-latest" - | "gpt-5.4" - | "gpt-5.4-mini" - | "gpt-5.4-nano" - | "gpt-5.2" - | "gpt-5.2-chat-latest" - | "gpt-5.1" - | "gpt-5.1-chat-latest" - | "gpt-5" - | "gpt-5-chat-latest" - | "gpt-5-mini" - | "gpt-5-nano" - | "gpt-4.1-2025-04-14" - | "gpt-4.1-mini-2025-04-14" - | "gpt-4.1-nano-2025-04-14" - | "gpt-4.1" - | "gpt-4.1-mini" - | "gpt-4.1-nano" - | "chatgpt-4o-latest" - | "o3" - | "o3-mini" - | "o4-mini" - | "o1-mini" - | "o1-mini-2024-09-12" - | "gpt-4o-realtime-preview-2024-10-01" - | "gpt-4o-realtime-preview-2024-12-17" - | "gpt-4o-mini-realtime-preview-2024-12-17" - | "gpt-realtime-2025-08-28" - | "gpt-realtime-mini-2025-12-15" - | "gpt-realtime-2" - | "gpt-4o-mini-2024-07-18" - | "gpt-4o-mini" - | "gpt-4o" - | "gpt-4o-2024-05-13" - | "gpt-4o-2024-08-06" - | "gpt-4o-2024-11-20" - | "gpt-4-turbo" - | "gpt-4-turbo-2024-04-09" - | "gpt-4-turbo-preview" - | "gpt-4-0125-preview" - | "gpt-4-1106-preview" - | "gpt-4" - | "gpt-4-0613" - | "gpt-3.5-turbo" - | "gpt-3.5-turbo-0125" - | "gpt-3.5-turbo-1106" - | "gpt-3.5-turbo-16k" - | "gpt-3.5-turbo-0613" - | "gpt-5.6-luna:westus3" - | "gpt-5.6-terra:westus3" - | "gpt-5.6-sol:westus3" - | "gpt-5.4:eastus2" - | "gpt-5.4:swedencentral" - | "gpt-5.4-mini:eastus2" - | "gpt-5.4-mini:swedencentral" - | "gpt-5.4-nano:eastus2" - | "gpt-5.4-nano:swedencentral" - | "gpt-5.2:eastus2" - | "gpt-5.2:swedencentral" - | "gpt-5.1:eastus2" - | "gpt-5.1:swedencentral" - | "gpt-5:eastus2" - | "gpt-5:swedencentral" - | "gpt-5:canadaeast" - | "gpt-5:eastus" - | "gpt-5:westeurope" - | "gpt-5:germanywestcentral" - | "gpt-5:polandcentral" - | "gpt-5:spaincentral" - | "gpt-5-mini:eastus2" - | "gpt-5-mini:swedencentral" - | "gpt-5-mini:westeurope" - | "gpt-5-mini:germanywestcentral" - | "gpt-5-mini:polandcentral" - | "gpt-5-mini:spaincentral" - | "gpt-5-nano:eastus2" - | "gpt-5-nano:swedencentral" - | "gpt-4.1-2025-04-14:westus" - | "gpt-4.1-2025-04-14:eastus2" - | "gpt-4.1-2025-04-14:eastus" - | "gpt-4.1-2025-04-14:westus3" - | "gpt-4.1-2025-04-14:northcentralus" - | "gpt-4.1-2025-04-14:southcentralus" - | "gpt-4.1-2025-04-14:westeurope" - | "gpt-4.1-2025-04-14:germanywestcentral" - | "gpt-4.1-2025-04-14:polandcentral" - | "gpt-4.1-2025-04-14:spaincentral" - | "gpt-4.1-mini-2025-04-14:westus" - | "gpt-4.1-mini-2025-04-14:eastus2" - | "gpt-4.1-mini-2025-04-14:eastus" - | "gpt-4.1-mini-2025-04-14:westus3" - | "gpt-4.1-mini-2025-04-14:northcentralus" - | "gpt-4.1-mini-2025-04-14:southcentralus" - | "gpt-4.1-mini-2025-04-14:westeurope" - | "gpt-4.1-mini-2025-04-14:germanywestcentral" - | "gpt-4.1-mini-2025-04-14:polandcentral" - | "gpt-4.1-mini-2025-04-14:spaincentral" - | "gpt-4.1-nano-2025-04-14:westus" - | "gpt-4.1-nano-2025-04-14:eastus2" - | "gpt-4.1-nano-2025-04-14:westus3" - | "gpt-4.1-nano-2025-04-14:northcentralus" - | "gpt-4.1-nano-2025-04-14:southcentralus" - | "gpt-4o-2024-11-20:swedencentral" - | "gpt-4o-2024-11-20:westus" - | "gpt-4o-2024-11-20:eastus2" - | "gpt-4o-2024-11-20:eastus" - | "gpt-4o-2024-11-20:westus3" - | "gpt-4o-2024-11-20:southcentralus" - | "gpt-4o-2024-11-20:westeurope" - | "gpt-4o-2024-11-20:germanywestcentral" - | "gpt-4o-2024-11-20:polandcentral" - | "gpt-4o-2024-11-20:spaincentral" - | "gpt-4o-2024-08-06:westus" - | "gpt-4o-2024-08-06:westus3" - | "gpt-4o-2024-08-06:eastus" - | "gpt-4o-2024-08-06:eastus2" - | "gpt-4o-2024-08-06:northcentralus" - | "gpt-4o-2024-08-06:southcentralus" - | "gpt-4o-mini-2024-07-18:westus" - | "gpt-4o-mini-2024-07-18:westus3" - | "gpt-4o-mini-2024-07-18:eastus" - | "gpt-4o-mini-2024-07-18:eastus2" - | "gpt-4o-mini-2024-07-18:northcentralus" - | "gpt-4o-mini-2024-07-18:southcentralus" - | "gpt-4o-2024-05-13:eastus2" - | "gpt-4o-2024-05-13:eastus" - | "gpt-4o-2024-05-13:northcentralus" - | "gpt-4o-2024-05-13:southcentralus" - | "gpt-4o-2024-05-13:westus3" - | "gpt-4o-2024-05-13:westus" - | "gpt-4-turbo-2024-04-09:eastus2" - | "gpt-4-0125-preview:eastus" - | "gpt-4-0125-preview:northcentralus" - | "gpt-4-0125-preview:southcentralus" - | "gpt-4-1106-preview:australiaeast" - | "gpt-4-1106-preview:canadaeast" - | "gpt-4-1106-preview:france" - | "gpt-4-1106-preview:india" - | "gpt-4-1106-preview:norway" - | "gpt-4-1106-preview:swedencentral" - | "gpt-4-1106-preview:uk" - | "gpt-4-1106-preview:westus" - | "gpt-4-1106-preview:westus3" - | "gpt-4-0613:canadaeast" - | "gpt-3.5-turbo-0125:canadaeast" - | "gpt-3.5-turbo-0125:northcentralus" - | "gpt-3.5-turbo-0125:southcentralus" - | "gpt-3.5-turbo-1106:canadaeast" - | "gpt-3.5-turbo-1106:westus" - | "gpt-4.1:australiaeast" - | "gpt-4o:australiaeast" - | "gpt-5.4-mini:australiaeast" + numFastTurns?: number; +} + +export interface AnthropicThinkingConfig { + type: "enabled"; + /** + * The maximum number of tokens to allocate for thinking. + * Must be between 1024 and 100000 tokens. + * @min 1024 + * @max 100000 + */ + budgetTokens: number; +} + +export interface AnthropicModel { + /** This is the starting state for the conversation. */ + messages?: OpenAIMessage[]; + /** + * These are the tools that the assistant can use during the call. To use existing tools, use `toolIds`. + * + * Both `tools` and `toolIds` can be used together. + */ + tools?: ( + | CreateApiRequestToolDTO + | CreateBashToolDTO + | CreateCodeToolDTO + | CreateComputerToolDTO + | CreateDtmfToolDTO + | CreateEndCallToolDTO + | CreateFunctionToolDTO + | CreateGoHighLevelCalendarAvailabilityToolDTO + | CreateGoHighLevelCalendarEventCreateToolDTO + | CreateGoHighLevelContactCreateToolDTO + | CreateGoHighLevelContactGetToolDTO + | CreateGoogleCalendarCheckAvailabilityToolDTO + | CreateGoogleCalendarCreateEventToolDTO + | CreateGoogleSheetsRowAppendToolDTO + | CreateHandoffToolDTO + | CreateMcpToolDTO + | CreateQueryToolDTO + | CreateSlackSendMessageToolDTO + | CreateSmsToolDTO + | CreateTextEditorToolDTO + | CreateTransferCallToolDTO + | CreateSipRequestToolDTO + | CreateVoicemailToolDTO )[]; /** - * Azure OpenAI doesn't support `maxLength` right now https://learn.microsoft.com/en-us/azure/ai-services/openai/how-to/structured-outputs?tabs=python-secure%2Cdotnet-entra-id&pivots=programming-language-csharp#unsupported-type-specific-keywords. Need to strip. + * These are the tools that the assistant can use during the call. To use transient tools, use `tools`. * - * - `strip-parameters-with-unsupported-validation` will strip parameters with unsupported validation. - * - `strip-unsupported-validation` will keep the parameters but strip unsupported validation. + * Both `tools` and `toolIds` can be used together. + */ + toolIds?: string[]; + /** + * These are version-pinned references to tools. Each entry pins a specific + * version of a tool by `(toolId, version)`. When the same `toolId` appears + * in both `toolIds` and `toolRefs[]`, the `toolRefs` pin wins (the + * `toolIds` entry is dropped at write time). + */ + toolRefs?: ToolRef[]; + /** These are the options for the knowledge base. */ + knowledgeBase?: CreateCustomKnowledgeBaseDTO; + /** The specific Anthropic/Claude model that will be used. */ + model: + | "claude-3-opus-20240229" + | "claude-3-sonnet-20240229" + | "claude-3-haiku-20240307" + | "claude-3-5-sonnet-20240620" + | "claude-3-5-sonnet-20241022" + | "claude-3-5-haiku-20241022" + | "claude-3-7-sonnet-20250219" + | "claude-opus-4-20250514" + | "claude-opus-4-5-20251101" + | "claude-opus-4-6" + | "claude-sonnet-4-20250514" + | "claude-sonnet-4-5-20250929" + | "claude-sonnet-4-6" + | "claude-sonnet-5" + | "claude-haiku-4-5-20251001" + | "claude-haiku-5-5"; + /** + * Reasoning effort for claude-haiku-5-5. `none` turns thinking off. `low` to `max` + * use adaptive thinking at that effort; higher effort can add latency before the + * model speaks. Unset means `none`. Rejected for every other model. + */ + reasoningEffort?: "none" | "low" | "medium" | "high" | "xhigh" | "max"; + /** The provider identifier for Anthropic. */ + provider: "anthropic"; + /** + * Optional configuration for Anthropic's thinking feature. + * Only applicable for claude-3-7-sonnet-20250219 model. + * If provided, maxTokens must be greater than thinking.budgetTokens. + */ + thinking?: AnthropicThinkingConfig; + /** + * This is the temperature that will be used for calls. Default is 0.5. + * @min 0 + * @max 2 + */ + temperature?: number; + /** + * This is the max number of tokens that the assistant will be allowed to generate in each turn of the conversation. Default is 250. On gpt-6-luna and claude-haiku-5-5 no cap is applied unless you set one (claude-haiku-5-5 sends its 128,000-token maximum), because reasoning uses output tokens and a small cap can leave the reply empty. + * @min 50 + * @max 10000 + */ + maxTokens?: number; + /** + * This determines whether we detect user's emotion while they speak and send it as an additional info to model. * - * @default `strip-unsupported-validation` + * Default `false` because the model is usually are good at understanding the user's emotion from text. + * + * @default false */ - toolStrictCompatibilityMode?: - | "strip-parameters-with-unsupported-validation" - | "strip-unsupported-validation"; + emotionRecognitionEnabled?: boolean; /** - * This controls the prompt cache retention policy for models that support extended caching (GPT-4.1, GPT-5 series). + * This sets how many turns at the start of the conversation to use a smaller, faster model from the same provider before switching to the primary model. Example, gpt-3.5-turbo if provider is openai. * - * - `in_memory`: Default behavior, cache retained in GPU memory only - * - `24h`: Extended caching, keeps cached prefixes active for up to 24 hours by offloading to GPU-local storage + * Default is 0. * - * Only applies to models: gpt-5.6-sol, gpt-5.6-terra, gpt-5.6-luna, gpt-5.5, chat-latest, gpt-5.4, gpt-5.4-mini, gpt-5.4-nano, gpt-5.2, gpt-5.1, gpt-5.1-codex, gpt-5.1-codex-mini, gpt-5.1-chat-latest, gpt-5, gpt-5-codex, gpt-4.1 + * @default 0 + * @min 0 + */ + numFastTurns?: number; +} + +export interface AnthropicBedrockModel { + /** This is the starting state for the conversation. */ + messages?: OpenAIMessage[]; + /** + * These are the tools that the assistant can use during the call. To use existing tools, use `toolIds`. * - * @default undefined (uses API default which is 'in_memory') + * Both `tools` and `toolIds` can be used together. */ - promptCacheRetention?: "in_memory" | "24h"; + tools?: ( + | CreateApiRequestToolDTO + | CreateBashToolDTO + | CreateCodeToolDTO + | CreateComputerToolDTO + | CreateDtmfToolDTO + | CreateEndCallToolDTO + | CreateFunctionToolDTO + | CreateGoHighLevelCalendarAvailabilityToolDTO + | CreateGoHighLevelCalendarEventCreateToolDTO + | CreateGoHighLevelContactCreateToolDTO + | CreateGoHighLevelContactGetToolDTO + | CreateGoogleCalendarCheckAvailabilityToolDTO + | CreateGoogleCalendarCreateEventToolDTO + | CreateGoogleSheetsRowAppendToolDTO + | CreateHandoffToolDTO + | CreateMcpToolDTO + | CreateQueryToolDTO + | CreateSlackSendMessageToolDTO + | CreateSmsToolDTO + | CreateTextEditorToolDTO + | CreateTransferCallToolDTO + | CreateSipRequestToolDTO + | CreateVoicemailToolDTO + )[]; /** - * This is the prompt cache key for models that support extended caching (GPT-4.1, GPT-5 series). + * These are the tools that the assistant can use during the call. To use transient tools, use `tools`. * - * Providing a cache key allows you to share cached prefixes across requests. + * Both `tools` and `toolIds` can be used together. + */ + toolIds?: string[]; + /** + * These are version-pinned references to tools. Each entry pins a specific + * version of a tool by `(toolId, version)`. When the same `toolId` appears + * in both `toolIds` and `toolRefs[]`, the `toolRefs` pin wins (the + * `toolIds` entry is dropped at write time). + */ + toolRefs?: ToolRef[]; + /** These are the options for the knowledge base. */ + knowledgeBase?: CreateCustomKnowledgeBaseDTO; + /** The provider identifier for Anthropic via AWS Bedrock. */ + provider: "anthropic-bedrock"; + /** The specific Anthropic/Claude model that will be used via Bedrock. */ + model: + | "claude-3-opus-20240229" + | "claude-3-sonnet-20240229" + | "claude-3-haiku-20240307" + | "claude-3-5-sonnet-20240620" + | "claude-3-5-sonnet-20241022" + | "claude-3-5-haiku-20241022" + | "claude-3-7-sonnet-20250219" + | "claude-opus-4-20250514" + | "claude-opus-4-5-20251101" + | "claude-opus-4-6" + | "claude-sonnet-4-20250514" + | "claude-sonnet-4-5-20250929" + | "claude-sonnet-4-6" + | "claude-haiku-4-5-20251001" + | "claude-haiku-5-5" + | "global.anthropic.claude-haiku-4-5-20251001-v1:0"; + /** + * At most one same-provider Bedrock fallback model, tried if the primary fails. Cannot be combined with thinking in this release. Resolution uses the call's Bedrock credential region (or ANTHROPIC_BEDROCK_AWS_REGION). Names with no inference profile in that region are skipped and warned, never remapped to US or global. On Vapi EU, fallback names without an EU inference profile are rejected at write time. + * @maxItems 1 + * @example ["claude-haiku-4-5-20251001"] + */ + fallbackModels?: + | "claude-3-opus-20240229" + | "claude-3-sonnet-20240229" + | "claude-3-haiku-20240307" + | "claude-3-5-sonnet-20240620" + | "claude-3-5-sonnet-20241022" + | "claude-3-5-haiku-20241022" + | "claude-3-7-sonnet-20250219" + | "claude-opus-4-20250514" + | "claude-opus-4-5-20251101" + | "claude-opus-4-6" + | "claude-sonnet-4-20250514" + | "claude-sonnet-4-5-20250929" + | "claude-sonnet-4-6" + | "claude-haiku-4-5-20251001" + | "claude-haiku-5-5" + | "global.anthropic.claude-haiku-4-5-20251001-v1:0"; + /** + * Reasoning effort for claude-haiku-5-5. `none` turns thinking off. `low` to `max` + * use adaptive thinking at that effort; higher effort can add latency before the + * model speaks. Unset means `none`. Rejected for every other model. + */ + reasoningEffort?: "none" | "low" | "medium" | "high" | "xhigh" | "max"; + /** + * Optional configuration for Anthropic's thinking feature. + * Only applicable for claude-3-7-sonnet-20250219 model. + * If provided, maxTokens must be greater than thinking.budgetTokens. + */ + thinking?: AnthropicThinkingConfig; + /** + * This is the temperature that will be used for calls. Default is 0.5. + * @min 0 + * @max 2 + */ + temperature?: number; + /** + * This is the max number of tokens that the assistant will be allowed to generate in each turn of the conversation. Default is 250. On gpt-6-luna and claude-haiku-5-5 no cap is applied unless you set one (claude-haiku-5-5 sends its 128,000-token maximum), because reasoning uses output tokens and a small cap can leave the reply empty. + * @min 50 + * @max 10000 + */ + maxTokens?: number; + /** + * This determines whether we detect user's emotion while they speak and send it as an additional info to model. * - * @default undefined - * @maxLength 64 + * Default `false` because the model is usually are good at understanding the user's emotion from text. + * + * @default false */ - promptCacheKey?: string; + emotionRecognitionEnabled?: boolean; /** - * This is the OpenAI service tier to request. + * This sets how many turns at the start of the conversation to use a smaller, faster model from the same provider before switching to the primary model. Example, gpt-3.5-turbo if provider is openai. * - * - `fast`: requests Fast mode, which gives faster responses at a higher per-token rate. How much faster depends on the model. - * - `priority`: the old name for `fast`, accepted and billed the same. - * - `default`: standard processing. - * - `auto`: the default when unset. On Vapi's OpenAI keys this is standard processing; on your own OpenAI key, OpenAI applies your project's default tier. + * Default is 0. * - * OpenAI sets Fast mode rates per model, and they are not a fixed multiple of the standard rates. Vapi bills them only when OpenAI reports that it served the request in Fast mode. Otherwise the request is billed at standard rates, for example when Fast mode isn't available for the model on Vapi, OpenAI downgrades the request, or the request runs on Azure OpenAI. + * @default 0 + * @min 0 + */ + numFastTurns?: number; +} + +export interface CerebrasModel { + /** This is the starting state for the conversation. */ + messages?: OpenAIMessage[]; + /** + * These are the tools that the assistant can use during the call. To use existing tools, use `toolIds`. * - * Supported models and their Fast mode rates: https://docs.vapi.ai/providers/model/openai + * Both `tools` and `toolIds` can be used together. */ - serviceTier?: "auto" | "default" | "fast" | "priority"; + tools?: ( + | CreateApiRequestToolDTO + | CreateBashToolDTO + | CreateCodeToolDTO + | CreateComputerToolDTO + | CreateDtmfToolDTO + | CreateEndCallToolDTO + | CreateFunctionToolDTO + | CreateGoHighLevelCalendarAvailabilityToolDTO + | CreateGoHighLevelCalendarEventCreateToolDTO + | CreateGoHighLevelContactCreateToolDTO + | CreateGoHighLevelContactGetToolDTO + | CreateGoogleCalendarCheckAvailabilityToolDTO + | CreateGoogleCalendarCreateEventToolDTO + | CreateGoogleSheetsRowAppendToolDTO + | CreateHandoffToolDTO + | CreateMcpToolDTO + | CreateQueryToolDTO + | CreateSlackSendMessageToolDTO + | CreateSmsToolDTO + | CreateTextEditorToolDTO + | CreateTransferCallToolDTO + | CreateSipRequestToolDTO + | CreateVoicemailToolDTO + )[]; /** - * Reasoning effort for reasoning-capable OpenAI models. - * For `gpt-realtime-2`: forwarded to V2 stream's session.update as `reasoning.effort`. - * For non-realtime OpenAI models, model-aware validation limits newly public - * values while preserving the existing four-value storage contract. + * These are the tools that the assistant can use during the call. To use transient tools, use `tools`. + * + * Both `tools` and `toolIds` can be used together. */ - reasoningEffort?: "minimal" | "none" | "low" | "medium" | "high" | "xhigh"; + toolIds?: string[]; + /** + * These are version-pinned references to tools. Each entry pins a specific + * version of a tool by `(toolId, version)`. When the same `toolId` appears + * in both `toolIds` and `toolRefs[]`, the `toolRefs` pin wins (the + * `toolIds` entry is dropped at write time). + */ + toolRefs?: ToolRef[]; + /** These are the options for the knowledge base. */ + knowledgeBase?: CreateCustomKnowledgeBaseDTO; + /** This is the name of the model. Ex. cognitivecomputations/dolphin-mixtral-8x7b */ + model: "llama3.1-8b" | "llama-3.3-70b"; + provider: "cerebras"; /** * This is the temperature that will be used for calls. Default is 0.5. * @min 0 @@ -10834,7 +11501,7 @@ export interface OpenAIModel { numFastTurns?: number; } -export interface OpenRouterModel { +export interface CustomLLMModel { /** This is the starting state for the conversation. */ messages?: OpenAIMessage[]; /** @@ -10870,19 +11537,50 @@ export interface OpenRouterModel { /** * These are the tools that the assistant can use during the call. To use transient tools, use `tools`. * - * Both `tools` and `toolIds` can be used together. + * Both `tools` and `toolIds` can be used together. + */ + toolIds?: string[]; + /** + * These are version-pinned references to tools. Each entry pins a specific + * version of a tool by `(toolId, version)`. When the same `toolId` appears + * in both `toolIds` and `toolRefs[]`, the `toolRefs` pin wins (the + * `toolIds` entry is dropped at write time). + */ + toolRefs?: ToolRef[]; + /** These are the options for the knowledge base. */ + knowledgeBase?: CreateCustomKnowledgeBaseDTO; + /** This is the provider that will be used for the model. Any service, including your own server, that is compatible with the OpenAI API can be used. */ + provider: "custom-llm"; + /** + * This determines whether metadata is sent in requests to the custom provider. + * + * - `off` will not send any metadata. payload will look like `{ messages }` + * - `variable` will send `assistant.metadata` as a variable on the payload. payload will look like `{ messages, metadata }` + * - `destructured` will send `assistant.metadata` fields directly on the payload. payload will look like `{ messages, ...metadata }` + * + * Further, `variable` and `destructured` will send `call`, `phoneNumber`, and `customer` objects in the payload. + * + * Default is `variable`. */ - toolIds?: string[]; + metadataSendMode?: "off" | "variable" | "destructured"; /** - * These are version-pinned references to tools. Each entry pins a specific - * version of a tool by `(toolId, version)`. When the same `toolId` appears - * in both `toolIds` and `toolRefs[]`, the `toolRefs` pin wins (the - * `toolIds` entry is dropped at write time). + * Custom headers to send with requests. These headers can override default OpenAI headers except for Authorization (which should be specified using a custom-llm credential). + * @example {"X-Custom-Header":"value"} */ - toolRefs?: ToolRef[]; - /** These are the options for the knowledge base. */ - knowledgeBase?: CreateCustomKnowledgeBaseDTO; - provider: "openrouter"; + headers?: Record; + /** These is the URL we'll use for the OpenAI client's `baseURL`. Ex. https://openrouter.ai/api/v1 */ + url: string; + /** + * This determines whether the transcriber's word level confidence is sent in requests to the custom provider. Default is false. + * This only works for Deepgram transcribers. + */ + wordLevelConfidenceEnabled?: boolean; + /** + * This sets the timeout for the connection to the custom provider without needing to stream any tokens back. Default is 20 seconds. + * @min 0 + * @max 300 + */ + timeoutSeconds?: number; /** This is the name of the model. Ex. cognitivecomputations/dolphin-mixtral-8x7b */ model: string; /** @@ -10916,7 +11614,7 @@ export interface OpenRouterModel { numFastTurns?: number; } -export interface PerplexityAIModel { +export interface DeepInfraModel { /** This is the starting state for the conversation. */ messages?: OpenAIMessage[]; /** @@ -10964,7 +11662,7 @@ export interface PerplexityAIModel { toolRefs?: ToolRef[]; /** These are the options for the knowledge base. */ knowledgeBase?: CreateCustomKnowledgeBaseDTO; - provider: "perplexity-ai"; + provider: "deepinfra"; /** This is the name of the model. Ex. cognitivecomputations/dolphin-mixtral-8x7b */ model: string; /** @@ -10998,7 +11696,7 @@ export interface PerplexityAIModel { numFastTurns?: number; } -export interface TogetherAIModel { +export interface DeepSeekModel { /** This is the starting state for the conversation. */ messages?: OpenAIMessage[]; /** @@ -11046,9 +11744,13 @@ export interface TogetherAIModel { toolRefs?: ToolRef[]; /** These are the options for the knowledge base. */ knowledgeBase?: CreateCustomKnowledgeBaseDTO; - provider: "together-ai"; /** This is the name of the model. Ex. cognitivecomputations/dolphin-mixtral-8x7b */ - model: string; + model: + | "deepseek-chat" + | "deepseek-reasoner" + | "deepseek-flash" + | "deepseek-flash-thinking"; + provider: "deep-seek"; /** * This is the temperature that will be used for calls. Default is 0.5. * @min 0 @@ -11080,339 +11782,95 @@ export interface TogetherAIModel { numFastTurns?: number; } -export interface HangupNode { - type: "hangup"; - /** @maxLength 80 */ - name: string; - /** This is whether or not the node is the start of the workflow. */ - isStart?: boolean; - /** This is for metadata you want to store on the task. */ - metadata?: object; +export interface GeminiMultimodalLivePrebuiltVoiceConfig { + voiceName: "Puck" | "Charon" | "Kore" | "Fenrir" | "Aoede"; } -export interface WorkflowOpenAIModel { - /** - * These are the messages used to customize the prompt used for structured output extraction. - * - * When provided, these messages replace the default prompts. For text extraction, message contents support LiquidJS templating with the following variables: - * - `{{transcript}}`, `{{messages}}`, or `{{messagesWithConfidence}}` to reference the conversation (one is required) - * - `{{structuredOutput.name}}`, `{{structuredOutput.description}}`, or `{{structuredOutput.schema}}` to reference the structured output definition (one is required) - * - `{{systemPrompt}}`, `{{callEndedReason}}`, `{{duration}}`, `{{startedAt}}`, `{{endedAt}}`, and any `assistantOverrides.variableValues` - * - * In structured outputs, `{{messages}}` includes conversation text and tool calls/results, but omits caller transcription-confidence fields. For text extraction, `{{messagesWithConfidence}}` includes the original message history with transcription confidence for outputs that explicitly need it. These variables also apply in structured-output schema descriptions. Audio-targeted (`messages-with-audio`) extraction ignores custom messages. Stored call artifacts and API messages retain their confidence data. `{{transcript}}` is the spoken text only, which uses significantly fewer tokens. - * - * If not provided, default system and user prompts are used. - */ - messages?: OpenAIMessage[]; - /** This is the provider of the model (`openai`). */ - provider: "openai"; - /** - * This is the OpenAI model that will be used. - * - * When using Vapi OpenAI or your own Azure Credentials, you have the option to specify the region for the selected model. This shouldn't be specified unless you have a specific reason to do so. Vapi will automatically find the fastest region that make sense. - * This is helpful when you are required to comply with Data Residency rules. Learn more about Azure regions here https://azure.microsoft.com/en-us/explore/global-infrastructure/data-residency/. - * @maxLength 100 - */ - model: - | "gpt-6-luna" - | "gpt-5.6-sol" - | "gpt-5.6-terra" - | "gpt-5.6-luna" - | "gpt-5.5" - | "chat-latest" - | "gpt-5.4" - | "gpt-5.4-mini" - | "gpt-5.4-nano" - | "gpt-5.2" - | "gpt-5.2-chat-latest" - | "gpt-5.1" - | "gpt-5.1-chat-latest" - | "gpt-5" - | "gpt-5-chat-latest" - | "gpt-5-mini" - | "gpt-5-nano" - | "gpt-4.1-2025-04-14" - | "gpt-4.1-mini-2025-04-14" - | "gpt-4.1-nano-2025-04-14" - | "gpt-4.1" - | "gpt-4.1-mini" - | "gpt-4.1-nano" - | "chatgpt-4o-latest" - | "o3" - | "o3-mini" - | "o4-mini" - | "o1-mini" - | "o1-mini-2024-09-12" - | "gpt-4o-mini-2024-07-18" - | "gpt-4o-mini" - | "gpt-4o" - | "gpt-4o-2024-05-13" - | "gpt-4o-2024-08-06" - | "gpt-4o-2024-11-20" - | "gpt-4-turbo" - | "gpt-4-turbo-2024-04-09" - | "gpt-4-turbo-preview" - | "gpt-4-0125-preview" - | "gpt-4-1106-preview" - | "gpt-4" - | "gpt-4-0613" - | "gpt-3.5-turbo" - | "gpt-3.5-turbo-0125" - | "gpt-3.5-turbo-1106" - | "gpt-3.5-turbo-16k" - | "gpt-3.5-turbo-0613" - | "gpt-5.6-luna:westus3" - | "gpt-5.6-terra:westus3" - | "gpt-5.6-sol:westus3" - | "gpt-5.4:eastus2" - | "gpt-5.4:swedencentral" - | "gpt-5.4-mini:eastus2" - | "gpt-5.4-mini:swedencentral" - | "gpt-5.4-nano:eastus2" - | "gpt-5.4-nano:swedencentral" - | "gpt-5.2:eastus2" - | "gpt-5.2:swedencentral" - | "gpt-5.1:eastus2" - | "gpt-5.1:swedencentral" - | "gpt-5:eastus2" - | "gpt-5:swedencentral" - | "gpt-5:canadaeast" - | "gpt-5:eastus" - | "gpt-5:westeurope" - | "gpt-5:germanywestcentral" - | "gpt-5:polandcentral" - | "gpt-5:spaincentral" - | "gpt-5-mini:eastus2" - | "gpt-5-mini:swedencentral" - | "gpt-5-mini:westeurope" - | "gpt-5-mini:germanywestcentral" - | "gpt-5-mini:polandcentral" - | "gpt-5-mini:spaincentral" - | "gpt-5-nano:eastus2" - | "gpt-5-nano:swedencentral" - | "gpt-4.1-2025-04-14:westus" - | "gpt-4.1-2025-04-14:eastus2" - | "gpt-4.1-2025-04-14:eastus" - | "gpt-4.1-2025-04-14:westus3" - | "gpt-4.1-2025-04-14:northcentralus" - | "gpt-4.1-2025-04-14:southcentralus" - | "gpt-4.1-2025-04-14:westeurope" - | "gpt-4.1-2025-04-14:germanywestcentral" - | "gpt-4.1-2025-04-14:polandcentral" - | "gpt-4.1-2025-04-14:spaincentral" - | "gpt-4.1-mini-2025-04-14:westus" - | "gpt-4.1-mini-2025-04-14:eastus2" - | "gpt-4.1-mini-2025-04-14:eastus" - | "gpt-4.1-mini-2025-04-14:westus3" - | "gpt-4.1-mini-2025-04-14:northcentralus" - | "gpt-4.1-mini-2025-04-14:southcentralus" - | "gpt-4.1-mini-2025-04-14:westeurope" - | "gpt-4.1-mini-2025-04-14:germanywestcentral" - | "gpt-4.1-mini-2025-04-14:polandcentral" - | "gpt-4.1-mini-2025-04-14:spaincentral" - | "gpt-4.1-nano-2025-04-14:westus" - | "gpt-4.1-nano-2025-04-14:eastus2" - | "gpt-4.1-nano-2025-04-14:westus3" - | "gpt-4.1-nano-2025-04-14:northcentralus" - | "gpt-4.1-nano-2025-04-14:southcentralus" - | "gpt-4o-2024-11-20:swedencentral" - | "gpt-4o-2024-11-20:westus" - | "gpt-4o-2024-11-20:eastus2" - | "gpt-4o-2024-11-20:eastus" - | "gpt-4o-2024-11-20:westus3" - | "gpt-4o-2024-11-20:southcentralus" - | "gpt-4o-2024-11-20:westeurope" - | "gpt-4o-2024-11-20:germanywestcentral" - | "gpt-4o-2024-11-20:polandcentral" - | "gpt-4o-2024-11-20:spaincentral" - | "gpt-4o-2024-08-06:westus" - | "gpt-4o-2024-08-06:westus3" - | "gpt-4o-2024-08-06:eastus" - | "gpt-4o-2024-08-06:eastus2" - | "gpt-4o-2024-08-06:northcentralus" - | "gpt-4o-2024-08-06:southcentralus" - | "gpt-4o-mini-2024-07-18:westus" - | "gpt-4o-mini-2024-07-18:westus3" - | "gpt-4o-mini-2024-07-18:eastus" - | "gpt-4o-mini-2024-07-18:eastus2" - | "gpt-4o-mini-2024-07-18:northcentralus" - | "gpt-4o-mini-2024-07-18:southcentralus" - | "gpt-4o-2024-05-13:eastus2" - | "gpt-4o-2024-05-13:eastus" - | "gpt-4o-2024-05-13:northcentralus" - | "gpt-4o-2024-05-13:southcentralus" - | "gpt-4o-2024-05-13:westus3" - | "gpt-4o-2024-05-13:westus" - | "gpt-4-turbo-2024-04-09:eastus2" - | "gpt-4-0125-preview:eastus" - | "gpt-4-0125-preview:northcentralus" - | "gpt-4-0125-preview:southcentralus" - | "gpt-4-1106-preview:australiaeast" - | "gpt-4-1106-preview:canadaeast" - | "gpt-4-1106-preview:france" - | "gpt-4-1106-preview:india" - | "gpt-4-1106-preview:norway" - | "gpt-4-1106-preview:swedencentral" - | "gpt-4-1106-preview:uk" - | "gpt-4-1106-preview:westus" - | "gpt-4-1106-preview:westus3" - | "gpt-4-0613:canadaeast" - | "gpt-3.5-turbo-0125:canadaeast" - | "gpt-3.5-turbo-0125:northcentralus" - | "gpt-3.5-turbo-0125:southcentralus" - | "gpt-3.5-turbo-1106:canadaeast" - | "gpt-3.5-turbo-1106:westus" - | "gpt-4.1:australiaeast" - | "gpt-4o:australiaeast" - | "gpt-5.4-mini:australiaeast"; - /** - * This is the temperature of the model. - * @min 0 - * @max 2 - */ - temperature?: number; - /** - * This is the max tokens of the model. - * @min 50 - * @max 10000 - */ - maxTokens?: number; +export interface GeminiMultimodalLiveVoiceConfig { + prebuiltVoiceConfig: GeminiMultimodalLivePrebuiltVoiceConfig; } -export interface WorkflowAnthropicModel { +export interface GeminiMultimodalLiveSpeechConfig { + voiceConfig: GeminiMultimodalLiveVoiceConfig; +} + +export interface GoogleRealtimeConfig { /** - * These are the messages used to customize the prompt used for structured output extraction. - * - * When provided, these messages replace the default prompts. For text extraction, message contents support LiquidJS templating with the following variables: - * - `{{transcript}}`, `{{messages}}`, or `{{messagesWithConfidence}}` to reference the conversation (one is required) - * - `{{structuredOutput.name}}`, `{{structuredOutput.description}}`, or `{{structuredOutput.schema}}` to reference the structured output definition (one is required) - * - `{{systemPrompt}}`, `{{callEndedReason}}`, `{{duration}}`, `{{startedAt}}`, `{{endedAt}}`, and any `assistantOverrides.variableValues` - * - * In structured outputs, `{{messages}}` includes conversation text and tool calls/results, but omits caller transcription-confidence fields. For text extraction, `{{messagesWithConfidence}}` includes the original message history with transcription confidence for outputs that explicitly need it. These variables also apply in structured-output schema descriptions. Audio-targeted (`messages-with-audio`) extraction ignores custom messages. Stored call artifacts and API messages retain their confidence data. `{{transcript}}` is the spoken text only, which uses significantly fewer tokens. - * - * If not provided, default system and user prompts are used. + * This is the nucleus sampling parameter that controls the cumulative probability of tokens considered during text generation. + * Only applicable with the Gemini Flash 2.0 Multimodal Live API. */ - messages?: OpenAIMessage[]; - /** This is the provider of the model (`anthropic`). */ - provider: "anthropic"; + topP?: number; /** - * This is the specific model that will be used. - * @maxLength 100 + * This is the top-k sampling parameter that limits the number of highest probability tokens considered during text generation. + * Only applicable with the Gemini Flash 2.0 Multimodal Live API. */ - model: - | "claude-3-opus-20240229" - | "claude-3-sonnet-20240229" - | "claude-3-haiku-20240307" - | "claude-3-5-sonnet-20240620" - | "claude-3-5-sonnet-20241022" - | "claude-3-5-haiku-20241022" - | "claude-3-7-sonnet-20250219" - | "claude-opus-4-20250514" - | "claude-opus-4-5-20251101" - | "claude-opus-4-6" - | "claude-sonnet-4-20250514" - | "claude-sonnet-4-5-20250929" - | "claude-sonnet-4-6" - | "claude-sonnet-5" - | "claude-haiku-4-5-20251001" - | "claude-haiku-5-5"; + topK?: number; /** - * This is the optional configuration for Anthropic's thinking feature. - * - * - If provided, `maxTokens` must be greater than `thinking.budgetTokens`. + * This is the presence penalty parameter that influences the model's likelihood to repeat information by penalizing tokens based on their presence in the text. + * Only applicable with the Gemini Flash 2.0 Multimodal Live API. */ - thinking?: AnthropicThinkingConfig; + presencePenalty?: number; /** - * This is the temperature of the model. - * @min 0 - * @max 2 + * This is the frequency penalty parameter that influences the model's likelihood to repeat tokens by penalizing them based on their frequency in the text. + * Only applicable with the Gemini Flash 2.0 Multimodal Live API. */ - temperature?: number; + frequencyPenalty?: number; /** - * This is the max tokens of the model. - * @min 50 - * @max 10000 + * This is the speech configuration object that defines the voice settings to be used for the model's speech output. + * Only applicable with the Gemini Flash 2.0 Multimodal Live API. */ - maxTokens?: number; + speechConfig?: GeminiMultimodalLiveSpeechConfig; } -export interface WorkflowAnthropicBedrockModel { - /** - * These are the messages used to customize the prompt used for structured output extraction. - * - * When provided, these messages replace the default prompts. For text extraction, message contents support LiquidJS templating with the following variables: - * - `{{transcript}}`, `{{messages}}`, or `{{messagesWithConfidence}}` to reference the conversation (one is required) - * - `{{structuredOutput.name}}`, `{{structuredOutput.description}}`, or `{{structuredOutput.schema}}` to reference the structured output definition (one is required) - * - `{{systemPrompt}}`, `{{callEndedReason}}`, `{{duration}}`, `{{startedAt}}`, `{{endedAt}}`, and any `assistantOverrides.variableValues` - * - * In structured outputs, `{{messages}}` includes conversation text and tool calls/results, but omits caller transcription-confidence fields. For text extraction, `{{messagesWithConfidence}}` includes the original message history with transcription confidence for outputs that explicitly need it. These variables also apply in structured-output schema descriptions. Audio-targeted (`messages-with-audio`) extraction ignores custom messages. Stored call artifacts and API messages retain their confidence data. `{{transcript}}` is the spoken text only, which uses significantly fewer tokens. - * - * If not provided, default system and user prompts are used. - */ +export interface GoogleModel { + /** This is the starting state for the conversation. */ messages?: OpenAIMessage[]; - /** This is the provider of the model (`anthropic-bedrock`). */ - provider: "anthropic-bedrock"; - /** - * This is the specific model that will be used. - * @maxLength 100 - */ - model: - | "claude-3-opus-20240229" - | "claude-3-sonnet-20240229" - | "claude-3-haiku-20240307" - | "claude-3-5-sonnet-20240620" - | "claude-3-5-sonnet-20241022" - | "claude-3-5-haiku-20241022" - | "claude-3-7-sonnet-20250219" - | "claude-opus-4-20250514" - | "claude-opus-4-5-20251101" - | "claude-opus-4-6" - | "claude-sonnet-4-20250514" - | "claude-sonnet-4-5-20250929" - | "claude-sonnet-4-6" - | "claude-haiku-4-5-20251001" - | "claude-haiku-5-5" - | "global.anthropic.claude-haiku-4-5-20251001-v1:0"; /** - * This is the optional configuration for Anthropic's thinking feature. + * These are the tools that the assistant can use during the call. To use existing tools, use `toolIds`. * - * - If provided, `maxTokens` must be greater than `thinking.budgetTokens`. - */ - thinking?: AnthropicThinkingConfig; - /** - * This is the temperature of the model. - * @min 0 - * @max 2 - */ - temperature?: number; - /** - * This is the max tokens of the model. - * @min 50 - * @max 10000 + * Both `tools` and `toolIds` can be used together. */ - maxTokens?: number; -} - -export interface WorkflowGoogleModel { + tools?: ( + | CreateApiRequestToolDTO + | CreateBashToolDTO + | CreateCodeToolDTO + | CreateComputerToolDTO + | CreateDtmfToolDTO + | CreateEndCallToolDTO + | CreateFunctionToolDTO + | CreateGoHighLevelCalendarAvailabilityToolDTO + | CreateGoHighLevelCalendarEventCreateToolDTO + | CreateGoHighLevelContactCreateToolDTO + | CreateGoHighLevelContactGetToolDTO + | CreateGoogleCalendarCheckAvailabilityToolDTO + | CreateGoogleCalendarCreateEventToolDTO + | CreateGoogleSheetsRowAppendToolDTO + | CreateHandoffToolDTO + | CreateMcpToolDTO + | CreateQueryToolDTO + | CreateSlackSendMessageToolDTO + | CreateSmsToolDTO + | CreateTextEditorToolDTO + | CreateTransferCallToolDTO + | CreateSipRequestToolDTO + | CreateVoicemailToolDTO + )[]; /** - * These are the messages used to customize the prompt used for structured output extraction. - * - * When provided, these messages replace the default prompts. For text extraction, message contents support LiquidJS templating with the following variables: - * - `{{transcript}}`, `{{messages}}`, or `{{messagesWithConfidence}}` to reference the conversation (one is required) - * - `{{structuredOutput.name}}`, `{{structuredOutput.description}}`, or `{{structuredOutput.schema}}` to reference the structured output definition (one is required) - * - `{{systemPrompt}}`, `{{callEndedReason}}`, `{{duration}}`, `{{startedAt}}`, `{{endedAt}}`, and any `assistantOverrides.variableValues` - * - * In structured outputs, `{{messages}}` includes conversation text and tool calls/results, but omits caller transcription-confidence fields. For text extraction, `{{messagesWithConfidence}}` includes the original message history with transcription confidence for outputs that explicitly need it. These variables also apply in structured-output schema descriptions. Audio-targeted (`messages-with-audio`) extraction ignores custom messages. Stored call artifacts and API messages retain their confidence data. `{{transcript}}` is the spoken text only, which uses significantly fewer tokens. + * These are the tools that the assistant can use during the call. To use transient tools, use `tools`. * - * If not provided, default system and user prompts are used. + * Both `tools` and `toolIds` can be used together. */ - messages?: OpenAIMessage[]; - /** This is the provider of the model (`google`). */ - provider: "google"; + toolIds?: string[]; /** - * This is the name of the model. Ex. cognitivecomputations/dolphin-mixtral-8x7b - * @maxLength 100 + * These are version-pinned references to tools. Each entry pins a specific + * version of a tool by `(toolId, version)`. When the same `toolId` appears + * in both `toolIds` and `toolRefs[]`, the `toolRefs` pin wins (the + * `toolIds` entry is dropped at write time). */ + toolRefs?: ToolRef[]; + /** These are the options for the knowledge base. */ + knowledgeBase?: CreateCustomKnowledgeBaseDTO; + /** This is the Google model that will be used. */ model: | "gemini-3.8-flash" | "gemini-3.5-flash" @@ -11432,166 +11890,144 @@ export interface WorkflowGoogleModel { | "gemini-1.5-pro" | "gemini-1.5-pro-002" | "gemini-1.0-pro"; + provider: "google"; /** - * This is the temperature of the model. + * This is the session configuration for the Gemini Flash 2.0 Multimodal Live API. + * Only applicable if the model `gemini-2.0-flash-realtime-exp` is selected. + */ + realtimeConfig?: GoogleRealtimeConfig; + /** + * This is the temperature that will be used for calls. Default is 0.5. * @min 0 * @max 2 */ temperature?: number; /** - * This is the max tokens of the model. + * This is the max number of tokens that the assistant will be allowed to generate in each turn of the conversation. Default is 250. On gpt-6-luna and claude-haiku-5-5 no cap is applied unless you set one (claude-haiku-5-5 sends its 128,000-token maximum), because reasoning uses output tokens and a small cap can leave the reply empty. * @min 50 * @max 10000 */ maxTokens?: number; -} - -export interface WorkflowCustomModel { /** - * These are the messages used to customize the prompt used for structured output extraction. - * - * When provided, these messages replace the default prompts. For text extraction, message contents support LiquidJS templating with the following variables: - * - `{{transcript}}`, `{{messages}}`, or `{{messagesWithConfidence}}` to reference the conversation (one is required) - * - `{{structuredOutput.name}}`, `{{structuredOutput.description}}`, or `{{structuredOutput.schema}}` to reference the structured output definition (one is required) - * - `{{systemPrompt}}`, `{{callEndedReason}}`, `{{duration}}`, `{{startedAt}}`, `{{endedAt}}`, and any `assistantOverrides.variableValues` + * This determines whether we detect user's emotion while they speak and send it as an additional info to model. * - * In structured outputs, `{{messages}}` includes conversation text and tool calls/results, but omits caller transcription-confidence fields. For text extraction, `{{messagesWithConfidence}}` includes the original message history with transcription confidence for outputs that explicitly need it. These variables also apply in structured-output schema descriptions. Audio-targeted (`messages-with-audio`) extraction ignores custom messages. Stored call artifacts and API messages retain their confidence data. `{{transcript}}` is the spoken text only, which uses significantly fewer tokens. + * Default `false` because the model is usually are good at understanding the user's emotion from text. * - * If not provided, default system and user prompts are used. + * @default false */ - messages?: OpenAIMessage[]; - /** This is the provider of the model (`custom-llm`). */ - provider: "custom-llm"; + emotionRecognitionEnabled?: boolean; /** - * This determines whether metadata is sent in requests to the custom provider. + * This sets how many turns at the start of the conversation to use a smaller, faster model from the same provider before switching to the primary model. Example, gpt-3.5-turbo if provider is openai. * - * - `off` will not send any metadata. payload will look like `{ messages }` - * - `variable` will send `assistant.metadata` as a variable on the payload. payload will look like `{ messages, metadata }` - * - `destructured` will send `assistant.metadata` fields directly on the payload. payload will look like `{ messages, ...metadata }` + * Default is 0. * - * Further, `variable` and `destructured` will send `call`, `phoneNumber`, and `customer` objects in the payload. + * @default 0 + * @min 0 + */ + numFastTurns?: number; +} + +export interface GroqModel { + /** This is the starting state for the conversation. */ + messages?: OpenAIMessage[]; + /** + * These are the tools that the assistant can use during the call. To use existing tools, use `toolIds`. * - * Default is `variable`. + * Both `tools` and `toolIds` can be used together. */ - metadataSendMode?: "off" | "variable" | "destructured"; - /** These is the URL we'll use for the OpenAI client's `baseURL`. Ex. https://openrouter.ai/api/v1 */ - url: string; - /** These are the headers we'll use for the OpenAI client's `headers`. */ - headers?: object; + tools?: ( + | CreateApiRequestToolDTO + | CreateBashToolDTO + | CreateCodeToolDTO + | CreateComputerToolDTO + | CreateDtmfToolDTO + | CreateEndCallToolDTO + | CreateFunctionToolDTO + | CreateGoHighLevelCalendarAvailabilityToolDTO + | CreateGoHighLevelCalendarEventCreateToolDTO + | CreateGoHighLevelContactCreateToolDTO + | CreateGoHighLevelContactGetToolDTO + | CreateGoogleCalendarCheckAvailabilityToolDTO + | CreateGoogleCalendarCreateEventToolDTO + | CreateGoogleSheetsRowAppendToolDTO + | CreateHandoffToolDTO + | CreateMcpToolDTO + | CreateQueryToolDTO + | CreateSlackSendMessageToolDTO + | CreateSmsToolDTO + | CreateTextEditorToolDTO + | CreateTransferCallToolDTO + | CreateSipRequestToolDTO + | CreateVoicemailToolDTO + )[]; /** - * This sets the timeout for the connection to the custom provider without needing to stream any tokens back. Default is 20 seconds. - * @min 20 - * @max 600 + * These are the tools that the assistant can use during the call. To use transient tools, use `tools`. + * + * Both `tools` and `toolIds` can be used together. */ - timeoutSeconds?: number; + toolIds?: string[]; /** - * This is the name of the model. Ex. cognitivecomputations/dolphin-mixtral-8x7b - * @maxLength 100 + * These are version-pinned references to tools. Each entry pins a specific + * version of a tool by `(toolId, version)`. When the same `toolId` appears + * in both `toolIds` and `toolRefs[]`, the `toolRefs` pin wins (the + * `toolIds` entry is dropped at write time). */ - model: string; + toolRefs?: ToolRef[]; + /** These are the options for the knowledge base. */ + knowledgeBase?: CreateCustomKnowledgeBaseDTO; + /** This is the name of the model. Ex. cognitivecomputations/dolphin-mixtral-8x7b */ + model: + | "openai/gpt-oss-20b" + | "openai/gpt-oss-120b" + | "deepseek-r1-distill-llama-70b" + | "llama-3.3-70b-versatile" + | "llama-3.1-405b-reasoning" + | "llama-3.1-8b-instant" + | "llama3-8b-8192" + | "llama3-70b-8192" + | "gemma2-9b-it" + | "moonshotai/kimi-k2-instruct-0905" + | "meta-llama/llama-4-scout-17b-16e-instruct" + | "mistral-saba-24b" + | "compound-beta" + | "compound-beta-mini"; + provider: "groq"; /** - * This is the temperature of the model. + * This is the temperature that will be used for calls. Default is 0.5. * @min 0 * @max 2 */ temperature?: number; /** - * This is the max tokens of the model. + * This is the max number of tokens that the assistant will be allowed to generate in each turn of the conversation. Default is 250. On gpt-6-luna and claude-haiku-5-5 no cap is applied unless you set one (claude-haiku-5-5 sends its 128,000-token maximum), because reasoning uses output tokens and a small cap can leave the reply empty. * @min 50 * @max 10000 */ maxTokens?: number; -} - -export interface GlobalNodePlan { /** - * This is the flag to determine if this node is a global node + * This determines whether we detect user's emotion while they speak and send it as an additional info to model. + * + * Default `false` because the model is usually are good at understanding the user's emotion from text. * - * @default false * @default false */ - enabled?: boolean; + emotionRecognitionEnabled?: boolean; /** - * This is the condition that will be checked to determine if the global node should be executed. + * This sets how many turns at the start of the conversation to use a smaller, faster model from the same provider before switching to the primary model. Example, gpt-3.5-turbo if provider is openai. * - * @default '' - * @maxLength 1000 - * @default "" + * Default is 0. + * + * @default 0 + * @min 0 */ - enterCondition?: string; + numFastTurns?: number; } -export interface ConversationNode { - /** - * This is the Conversation node. This can be used to start a conversation with the customer. - * - * The flow is: - * - Workflow starts the conversation node - * - Model is active with the `prompt` and global context. - * - Model will call a tool to exit this node. - * - Workflow will extract variables from the conversation. - * - Workflow continues. - */ - type: "conversation"; - /** - * This is the model for the node. - * - * This overrides `workflow.model`. - */ - model?: - | WorkflowOpenAIModel - | WorkflowAnthropicModel - | WorkflowAnthropicBedrockModel - | WorkflowGoogleModel - | WorkflowCustomModel; - /** - * This is the transcriber for the node. - * - * This overrides `workflow.transcriber`. - */ - transcriber?: - | AssemblyAITranscriber - | AzureSpeechTranscriber - | CustomTranscriber - | DeepgramTranscriber - | ElevenLabsTranscriber - | GladiaTranscriber - | GoogleTranscriber - | SpeechmaticsTranscriber - | TalkscriberTranscriber - | OpenAITranscriber - | CartesiaTranscriber - | SonioxTranscriber - | XaiTranscriber - | VapiTranscriber; - /** - * This is the voice for the node. - * - * This overrides `workflow.voice`. - */ - voice?: - | AzureVoice - | CartesiaVoice - | CustomVoice - | DeepgramVoice - | ElevenLabsVoice - | HumeVoice - | LMNTVoice - | NeuphonicVoice - | OpenAIVoice - | PlayHTVoice - | WellSaidVoice - | RimeAIVoice - | SmallestAIVoice - | TavusVoice - | VapiVoice - | SesameVoice - | InworldVoice - | MinimaxVoice - | XaiVoice - | MicrosoftVoice; +export interface InflectionAIModel { + /** This is the starting state for the conversation. */ + messages?: OpenAIMessage[]; /** - * These are the tools that the conversation node can use during the call. To use existing tools, use `toolIds`. + * These are the tools that the assistant can use during the call. To use existing tools, use `toolIds`. * * Both `tools` and `toolIds` can be used together. */ @@ -11621,87 +12057,63 @@ export interface ConversationNode { | CreateVoicemailToolDTO )[]; /** - * These are the tools that the conversation node can use during the call. To use transient tools, use `tools`. + * These are the tools that the assistant can use during the call. To use transient tools, use `tools`. * * Both `tools` and `toolIds` can be used together. */ toolIds?: string[]; - /** @maxLength 5000 */ - prompt?: string; - /** This is the plan for the global node. */ - globalNodePlan?: GlobalNodePlan; /** - * This is the plan that controls the variable extraction from the user's responses. - * - * Usage: - * Use `schema` to specify what you want to extract from the user's responses. - * ```json - * { - * "schema": { - * "type": "object", - * "properties": { - * "user": { - * "type": "object", - * "properties": { - * "name": { - * "type": "string" - * }, - * "age": { - * "type": "number" - * } - * } - * } - * } - * } - * } - * ``` - * - * This will be extracted as `{{ user.name }}` and `{{ user.age }}` respectively. + * These are version-pinned references to tools. Each entry pins a specific + * version of a tool by `(toolId, version)`. When the same `toolId` appears + * in both `toolIds` and `toolRefs[]`, the `toolRefs` pin wins (the + * `toolIds` entry is dropped at write time). + */ + toolRefs?: ToolRef[]; + /** These are the options for the knowledge base. */ + knowledgeBase?: CreateCustomKnowledgeBaseDTO; + /** This is the name of the model. Ex. cognitivecomputations/dolphin-mixtral-8x7b */ + model: "inflection_3_pi"; + provider: "inflection-ai"; + /** + * This is the temperature that will be used for calls. Default is 0.5. + * @min 0 + * @max 2 + */ + temperature?: number; + /** + * This is the max number of tokens that the assistant will be allowed to generate in each turn of the conversation. Default is 250. On gpt-6-luna and claude-haiku-5-5 no cap is applied unless you set one (claude-haiku-5-5 sends its 128,000-token maximum), because reasoning uses output tokens and a small cap can leave the reply empty. + * @min 50 + * @max 10000 + */ + maxTokens?: number; + /** + * This determines whether we detect user's emotion while they speak and send it as an additional info to model. * - * (Optional) Use `aliases` to create new variables. + * Default `false` because the model is usually are good at understanding the user's emotion from text. * - * ```json - * { - * "aliases": [ - * { - * "key": "userAge", - * "value": "{{user.age}}" - * }, - * { - * "key": "userName", - * "value": "{{user.name}}" - * } - * ] - * } - * ``` + * @default false + */ + emotionRecognitionEnabled?: boolean; + /** + * This sets how many turns at the start of the conversation to use a smaller, faster model from the same provider before switching to the primary model. Example, gpt-3.5-turbo if provider is openai. * - * This will be extracted as `{{ userAge }}` and `{{ userName }}` respectively. + * Default is 0. * - * Note: The `schema` field is required for Conversation nodes if you want to extract variables from the user's responses. `aliases` is just a convenience. + * @default 0 + * @min 0 */ - variableExtractionPlan?: VariableExtractionPlan; - /** @maxLength 80 */ - name: string; - /** This is whether or not the node is the start of the workflow. */ - isStart?: boolean; - /** This is for metadata you want to store on the task. */ - metadata?: object; + numFastTurns?: number; } -export interface ToolNode { +export interface MinimaxLLMModel { + /** This is the starting state for the conversation. */ + messages?: OpenAIMessage[]; /** - * This is the Tool node. This can be used to call a tool in your workflow. + * These are the tools that the assistant can use during the call. To use existing tools, use `toolIds`. * - * The flow is: - * - Workflow starts the tool node - * - Model is called to extract parameters needed by the tool from the conversation history - * - Tool is called with the parameters - * - Server returns a response - * - Workflow continues with the response + * Both `tools` and `toolIds` can be used together. */ - type: "tool"; - /** This is the tool to call. To use an existing tool, send `toolId` instead. */ - tool?: + tools?: ( | CreateApiRequestToolDTO | CreateBashToolDTO | CreateCodeToolDTO @@ -11724,425 +12136,613 @@ export interface ToolNode { | CreateTextEditorToolDTO | CreateTransferCallToolDTO | CreateSipRequestToolDTO - | CreateVoicemailToolDTO; - /** This is the tool to call. To use a transient tool, send `tool` instead. */ - toolId?: string; - /** @maxLength 80 */ - name: string; - /** This is whether or not the node is the start of the workflow. */ - isStart?: boolean; - /** This is for metadata you want to store on the task. */ - metadata?: object; -} - -export interface VoicemailDetectionBackoffPlan { + | CreateVoicemailToolDTO + )[]; /** - * This is the number of seconds to wait before starting the first retry attempt. - * @min 0 - * @default 5 + * These are the tools that the assistant can use during the call. To use transient tools, use `tools`. + * + * Both `tools` and `toolIds` can be used together. */ - startAtSeconds?: number; + toolIds?: string[]; /** - * This is the interval in seconds between retry attempts. - * @min 2.5 - * @default 5 + * These are version-pinned references to tools. Each entry pins a specific + * version of a tool by `(toolId, version)`. When the same `toolId` appears + * in both `toolIds` and `toolRefs[]`, the `toolRefs` pin wins (the + * `toolIds` entry is dropped at write time). */ - frequencySeconds?: number; + toolRefs?: ToolRef[]; + /** These are the options for the knowledge base. */ + knowledgeBase?: CreateCustomKnowledgeBaseDTO; + provider: "minimax"; + /** This is the name of the model. Ex. cognitivecomputations/dolphin-mixtral-8x7b */ + model: "MiniMax-M2.7"; /** - * This is the maximum number of retry attempts before giving up. - * @min 1 - * @max 10 - * @default 6 + * This is the temperature that will be used for calls. Default is 0.5. + * @min 0 + * @max 2 */ - maxRetries?: number; -} - -export interface GoogleVoicemailDetectionPlan { + temperature?: number; /** - * This is the maximum duration from the start of the call that we will wait for a voicemail beep, before speaking our message - * - * - If we detect a voicemail beep before this, we will speak the message at that point. + * This is the max number of tokens that the assistant will be allowed to generate in each turn of the conversation. Default is 250. On gpt-6-luna and claude-haiku-5-5 no cap is applied unless you set one (claude-haiku-5-5 sends its 128,000-token maximum), because reasoning uses output tokens and a small cap can leave the reply empty. + * @min 50 + * @max 10000 + */ + maxTokens?: number; + /** + * This determines whether we detect user's emotion while they speak and send it as an additional info to model. * - * - Setting too low a value means that the bot will start speaking its voicemail message too early. If it does so before the actual beep, it will get cut off. You should definitely tune this to your use case. + * Default `false` because the model is usually are good at understanding the user's emotion from text. * - * @default 30 - * @min 0 - * @max 60 - * @min 0 - * @max 30 - * @default 30 + * @default false */ - beepMaxAwaitSeconds?: number; - /** This is the provider to use for voicemail detection. */ - provider: "google"; - /** This is the backoff plan for the voicemail detection. */ - backoffPlan?: VoicemailDetectionBackoffPlan; + emotionRecognitionEnabled?: boolean; /** - * This is the detection type to use for voicemail detection. - * - 'audio': Uses native audio models (default) - * - 'transcript': Uses ASR/transcript-based detection - * @default 'audio' (audio detection) + * This sets how many turns at the start of the conversation to use a smaller, faster model from the same provider before switching to the primary model. Example, gpt-3.5-turbo if provider is openai. + * + * Default is 0. + * + * @default 0 + * @min 0 */ - type?: "audio" | "transcript"; + numFastTurns?: number; } -export interface OpenAIVoicemailDetectionPlan { +export interface OpenAISpeaker { + /** Omit to use model.systemPrompt, or system-role messages when systemPrompt is absent. An explicit empty string is preserved. */ + instructions?: string; + /** Personality packs append speaking-style guidance to the speaker prompt. Set to an array of pack IDs and test one pack at a time. These are prompt instructions, not fixed speed controls. */ + personalityPacks?: ( + | "eager-listener" + | "idle-hummer" + | "bouncy" + | "unhurried" + )[]; +} + +export interface OpenAIReasonerSkill { /** - * This is the maximum duration from the start of the call that we will wait for a voicemail beep, before speaking our message - * - * - If we detect a voicemail beep before this, we will speak the message at that point. - * - * - Setting too low a value means that the bot will start speaking its voicemail message too early. If it does so before the actual beep, it will get cut off. You should definitely tune this to your use case. - * - * @default 30 - * @min 0 - * @max 60 - * @min 0 - * @max 30 - * @default 30 + * Unique name within this assistant. + * @maxLength 64 + * @pattern /^[a-z][a-z0-9_-]*$/ */ - beepMaxAwaitSeconds?: number; - /** This is the provider to use for voicemail detection. */ - provider: "openai"; - /** This is the backoff plan for the voicemail detection. */ - backoffPlan?: VoicemailDetectionBackoffPlan; + name: string; /** - * This is the detection type to use for voicemail detection. - * - 'audio': Uses native audio models (default) - * - 'transcript': Uses ASR/transcript-based detection - * @default 'audio' (audio detection) + * Explain when the reasoner should load this skill. Always visible in its catalog. + * @maxLength 1024 + * @pattern /\S/ */ - type?: "audio" | "transcript"; + description: string; + /** + * Full skill instructions, loaded only while this skill is active. + * @maxLength 32000 + * @pattern /\S/ + */ + content: string; + /** + * Tools available only after loading this skill. Can be combined with toolIds. + * @maxItems 20 + */ + tools?: ( + | CreateFunctionToolDTO + | CreateApiRequestToolDTO + | CreateMcpToolDTO + | CreateEndCallToolDTO + | CreateDtmfToolDTO + | CreateTransferCallToolDTO + )[]; + /** + * Existing organization-owned tools available only after loading this skill. + * @maxItems 20 + */ + toolIds?: string[]; } -export interface TwilioVoicemailDetectionPlan { - /** This is the provider to use for voicemail detection. */ - provider: "twilio"; +export interface OpenAIReasoner { /** - * These are the AMD messages from Twilio that are considered as voicemail. Default is ['machine_end_beep', 'machine_end_silence']. - * - * @default {Array} ['machine_end_beep', 'machine_end_silence'] - * @example ["machine_end_beep","machine_end_silence"] + * The reasoner uses OpenAI. Omit to use OpenAI. + * @default "openai" */ - voicemailDetectionTypes?: - | "machine_start" - | "human" - | "fax" - | "unknown" - | "machine_end_beep" - | "machine_end_silence" - | "machine_end_other"; + provider?: "openai"; /** - * This sets whether the assistant should detect voicemail. Defaults to true. - * - * @default true + * The delegated reasoning model. Omit to use GPT-5.6 Terra. + * @default "gpt-5.6-terra" */ - enabled?: boolean; + model?: "gpt-5.6-sol" | "gpt-5.6-terra" | "gpt-5.6-luna"; /** - * The number of seconds that Twilio should attempt to perform answering machine detection before timing out and returning AnsweredBy as unknown. Default is 30 seconds. - * - * Increasing this value will provide the engine more time to make a determination. This can be useful when DetectMessageEnd is provided in the MachineDetection parameter and there is an expectation of long answering machine greetings that can exceed 30 seconds. - * - * Decreasing this value will reduce the amount of time the engine has to make a determination. This can be particularly useful when the Enable option is provided in the MachineDetection parameter and you want to limit the time for initial detection. - * - * Check the [Twilio docs](https://www.twilio.com/docs/voice/answering-machine-detection#optional-api-tuning-parameters) for more info. - * - * @default 30 - * @min 3 - * @max 59 + * Higher effort can increase response time. Omit to use low. + * @default "low" */ - machineDetectionTimeout?: number; + reasoningEffort?: "none" | "low" | "medium" | "high" | "xhigh" | "max"; /** - * The number of milliseconds that is used as the measuring stick for the length of the speech activity. Durations lower than this value will be interpreted as a human, longer as a machine. Default is 2400 milliseconds. - * - * Increasing this value will reduce the chance of a False Machine (detected machine, actually human) for a long human greeting (e.g., a business greeting) but increase the time it takes to detect a machine. - * - * Decreasing this value will reduce the chances of a False Human (detected human, actually machine) for short voicemail greetings. The value of this parameter may need to be reduced by more than 1000ms to detect very short voicemail greetings. A reduction of that significance can result in increased False Machine detections. Adjusting the MachineDetectionSpeechEndThreshold is likely the better approach for short voicemails. Decreasing MachineDetectionSpeechThreshold will also reduce the time it takes to detect a machine. - * - * Check the [Twilio docs](https://www.twilio.com/docs/voice/answering-machine-detection#optional-api-tuning-parameters) for more info. - * - * @default 2400 - * @min 1000 - * @max 6000 + * Complete reasoner instructions. An explicit empty string is preserved. + * Omit to use Vapi's default reasoner instructions. No behavioral instructions + * are appended unless skills are configured; skill loading guidance and active + * skill content are then composed with these instructions. */ - machineDetectionSpeechThreshold?: number; + instructions?: string; /** - * The number of milliseconds of silence after speech activity at which point the speech activity is considered complete. Default is 1200 milliseconds. - * - * Increasing this value will typically be used to better address the short voicemail greeting scenarios. For short voicemails, there is typically 1000-2000ms of audio followed by 1200-2400ms of silence and then additional audio before the beep. Increasing the MachineDetectionSpeechEndThreshold to ~2500ms will treat the 1200-2400ms of silence as a gap in the greeting but not the end of the greeting and will result in a machine detection. The downsides of such a change include: - * - Increasing the delay for human detection by the amount you increase this parameter, e.g., a change of 1200ms to 2500ms increases human detection delay by 1300ms. - * - Cases where a human has two utterances separated by a period of silence (e.g. a "Hello", then 2000ms of silence, and another "Hello") may be interpreted as a machine. - * - * Decreasing this value will result in faster human detection. The consequence is that it can lead to increased False Human (detected human, actually machine) detections because a silence gap in a voicemail greeting (not necessarily just in short voicemail scenarios) can be incorrectly interpreted as the end of speech. - * - * Check the [Twilio docs](https://www.twilio.com/docs/voice/answering-machine-detection#optional-api-tuning-parameters) for more info. - * - * @default 1200 - * @min 500 - * @max 5000 + * Inline skills whose instructions and tools the GPT-Live reasoner loads on demand. + * @maxItems 20 */ - machineDetectionSpeechEndThreshold?: number; + skills?: OpenAIReasonerSkill[]; +} + +export interface OpenAIModel { + /** This is the starting state for the conversation. */ + messages?: OpenAIMessage[]; /** - * The number of milliseconds of initial silence after which an unknown AnsweredBy result will be returned. Default is 5000 milliseconds. - * - * Increasing this value will result in waiting for a longer period of initial silence before returning an 'unknown' AMD result. - * - * Decreasing this value will result in waiting for a shorter period of initial silence before returning an 'unknown' AMD result. + * These are the tools that the assistant can use during the call. To use existing tools, use `toolIds`. * - * Check the [Twilio docs](https://www.twilio.com/docs/voice/answering-machine-detection#optional-api-tuning-parameters) for more info. + * Both `tools` and `toolIds` can be used together. + */ + tools?: ( + | CreateApiRequestToolDTO + | CreateBashToolDTO + | CreateCodeToolDTO + | CreateComputerToolDTO + | CreateDtmfToolDTO + | CreateEndCallToolDTO + | CreateFunctionToolDTO + | CreateGoHighLevelCalendarAvailabilityToolDTO + | CreateGoHighLevelCalendarEventCreateToolDTO + | CreateGoHighLevelContactCreateToolDTO + | CreateGoHighLevelContactGetToolDTO + | CreateGoogleCalendarCheckAvailabilityToolDTO + | CreateGoogleCalendarCreateEventToolDTO + | CreateGoogleSheetsRowAppendToolDTO + | CreateHandoffToolDTO + | CreateMcpToolDTO + | CreateQueryToolDTO + | CreateSlackSendMessageToolDTO + | CreateSmsToolDTO + | CreateTextEditorToolDTO + | CreateTransferCallToolDTO + | CreateSipRequestToolDTO + | CreateVoicemailToolDTO + )[]; + /** + * These are the tools that the assistant can use during the call. To use transient tools, use `tools`. * - * @default 5000 - * @min 2000 - * @max 10000 + * Both `tools` and `toolIds` can be used together. */ - machineDetectionSilenceTimeout?: number; -} - -export interface VapiVoicemailDetectionPlan { + toolIds?: string[]; + /** + * These are version-pinned references to tools. Each entry pins a specific + * version of a tool by `(toolId, version)`. When the same `toolId` appears + * in both `toolIds` and `toolRefs[]`, the `toolRefs` pin wins (the + * `toolIds` entry is dropped at write time). + */ + toolRefs?: ToolRef[]; + /** These are the options for the knowledge base. */ + knowledgeBase?: CreateCustomKnowledgeBaseDTO; + /** Configuration for the GPT-Live speaker. */ + speaker?: OpenAISpeaker; + /** Configuration for the reasoner supporting the GPT-Live speaker. */ + reasoner?: OpenAIReasoner; + /** This is the provider that will be used for the model. */ + provider: "openai"; /** - * This is the maximum duration from the start of the call that we will wait for a voicemail beep, before speaking our message - * - * - If we detect a voicemail beep before this, we will speak the message at that point. + * This is the OpenAI model that will be used. + * For GPT-Live configuration and supported settings, see https://docs.vapi.ai/gpt-live/overview. * - * - Setting too low a value means that the bot will start speaking its voicemail message too early. If it does so before the actual beep, it will get cut off. You should definitely tune this to your use case. + * When using Vapi OpenAI or your own Azure Credentials, you have the option to specify the region for the selected model. This shouldn't be specified unless you have a specific reason to do so. Vapi will automatically find the fastest region that make sense. + * This is helpful when you are required to comply with Data Residency rules. Learn more about Azure regions here https://azure.microsoft.com/en-us/explore/global-infrastructure/data-residency/. * - * @default 30 - * @min 0 - * @max 60 - * @min 0 - * @max 30 - * @default 30 + * @default undefined */ - beepMaxAwaitSeconds?: number; - /** This is the provider to use for voicemail detection. */ - provider: "vapi"; - /** This is the backoff plan for the voicemail detection. */ - backoffPlan?: VoicemailDetectionBackoffPlan; + model: + | "gpt-6-luna" + | "gpt-5.6-sol" + | "gpt-5.6-terra" + | "gpt-5.6-luna" + | "gpt-5.5" + | "chat-latest" + | "gpt-5.4" + | "gpt-5.4-mini" + | "gpt-5.4-nano" + | "gpt-5.2" + | "gpt-5.2-chat-latest" + | "gpt-5.1" + | "gpt-5.1-chat-latest" + | "gpt-5" + | "gpt-5-chat-latest" + | "gpt-5-mini" + | "gpt-5-nano" + | "gpt-4.1-2025-04-14" + | "gpt-4.1-mini-2025-04-14" + | "gpt-4.1-nano-2025-04-14" + | "gpt-4.1" + | "gpt-4.1-mini" + | "gpt-4.1-nano" + | "chatgpt-4o-latest" + | "o3" + | "o3-mini" + | "o4-mini" + | "o1-mini" + | "o1-mini-2024-09-12" + | "gpt-4o-realtime-preview-2024-10-01" + | "gpt-4o-realtime-preview-2024-12-17" + | "gpt-4o-mini-realtime-preview-2024-12-17" + | "gpt-realtime-2025-08-28" + | "gpt-realtime-mini-2025-12-15" + | "gpt-realtime-2" + | "gpt-4o-mini-2024-07-18" + | "gpt-4o-mini" + | "gpt-4o" + | "gpt-4o-2024-05-13" + | "gpt-4o-2024-08-06" + | "gpt-4o-2024-11-20" + | "gpt-4-turbo" + | "gpt-4-turbo-2024-04-09" + | "gpt-4-turbo-preview" + | "gpt-4-0125-preview" + | "gpt-4-1106-preview" + | "gpt-4" + | "gpt-4-0613" + | "gpt-3.5-turbo" + | "gpt-3.5-turbo-0125" + | "gpt-3.5-turbo-1106" + | "gpt-3.5-turbo-16k" + | "gpt-3.5-turbo-0613" + | "gpt-5.6-luna:westus3" + | "gpt-5.6-terra:westus3" + | "gpt-5.6-sol:westus3" + | "gpt-5.4:eastus2" + | "gpt-5.4:swedencentral" + | "gpt-5.4-mini:eastus2" + | "gpt-5.4-mini:swedencentral" + | "gpt-5.4-nano:eastus2" + | "gpt-5.4-nano:swedencentral" + | "gpt-5.2:eastus2" + | "gpt-5.2:swedencentral" + | "gpt-5.1:eastus2" + | "gpt-5.1:swedencentral" + | "gpt-5:eastus2" + | "gpt-5:swedencentral" + | "gpt-5:canadaeast" + | "gpt-5:eastus" + | "gpt-5:westeurope" + | "gpt-5:germanywestcentral" + | "gpt-5:polandcentral" + | "gpt-5:spaincentral" + | "gpt-5-mini:eastus2" + | "gpt-5-mini:swedencentral" + | "gpt-5-mini:westeurope" + | "gpt-5-mini:germanywestcentral" + | "gpt-5-mini:polandcentral" + | "gpt-5-mini:spaincentral" + | "gpt-5-nano:eastus2" + | "gpt-5-nano:swedencentral" + | "gpt-4.1-2025-04-14:westus" + | "gpt-4.1-2025-04-14:eastus2" + | "gpt-4.1-2025-04-14:eastus" + | "gpt-4.1-2025-04-14:westus3" + | "gpt-4.1-2025-04-14:northcentralus" + | "gpt-4.1-2025-04-14:southcentralus" + | "gpt-4.1-2025-04-14:westeurope" + | "gpt-4.1-2025-04-14:germanywestcentral" + | "gpt-4.1-2025-04-14:polandcentral" + | "gpt-4.1-2025-04-14:spaincentral" + | "gpt-4.1-mini-2025-04-14:westus" + | "gpt-4.1-mini-2025-04-14:eastus2" + | "gpt-4.1-mini-2025-04-14:eastus" + | "gpt-4.1-mini-2025-04-14:westus3" + | "gpt-4.1-mini-2025-04-14:northcentralus" + | "gpt-4.1-mini-2025-04-14:southcentralus" + | "gpt-4.1-mini-2025-04-14:westeurope" + | "gpt-4.1-mini-2025-04-14:germanywestcentral" + | "gpt-4.1-mini-2025-04-14:polandcentral" + | "gpt-4.1-mini-2025-04-14:spaincentral" + | "gpt-4.1-nano-2025-04-14:westus" + | "gpt-4.1-nano-2025-04-14:eastus2" + | "gpt-4.1-nano-2025-04-14:westus3" + | "gpt-4.1-nano-2025-04-14:northcentralus" + | "gpt-4.1-nano-2025-04-14:southcentralus" + | "gpt-4o-2024-11-20:swedencentral" + | "gpt-4o-2024-11-20:westus" + | "gpt-4o-2024-11-20:eastus2" + | "gpt-4o-2024-11-20:eastus" + | "gpt-4o-2024-11-20:westus3" + | "gpt-4o-2024-11-20:southcentralus" + | "gpt-4o-2024-11-20:westeurope" + | "gpt-4o-2024-11-20:germanywestcentral" + | "gpt-4o-2024-11-20:polandcentral" + | "gpt-4o-2024-11-20:spaincentral" + | "gpt-4o-2024-08-06:westus" + | "gpt-4o-2024-08-06:westus3" + | "gpt-4o-2024-08-06:eastus" + | "gpt-4o-2024-08-06:eastus2" + | "gpt-4o-2024-08-06:northcentralus" + | "gpt-4o-2024-08-06:southcentralus" + | "gpt-4o-mini-2024-07-18:westus" + | "gpt-4o-mini-2024-07-18:westus3" + | "gpt-4o-mini-2024-07-18:eastus" + | "gpt-4o-mini-2024-07-18:eastus2" + | "gpt-4o-mini-2024-07-18:northcentralus" + | "gpt-4o-mini-2024-07-18:southcentralus" + | "gpt-4o-2024-05-13:eastus2" + | "gpt-4o-2024-05-13:eastus" + | "gpt-4o-2024-05-13:northcentralus" + | "gpt-4o-2024-05-13:southcentralus" + | "gpt-4o-2024-05-13:westus3" + | "gpt-4o-2024-05-13:westus" + | "gpt-4-turbo-2024-04-09:eastus2" + | "gpt-4-0125-preview:eastus" + | "gpt-4-0125-preview:northcentralus" + | "gpt-4-0125-preview:southcentralus" + | "gpt-4-1106-preview:australiaeast" + | "gpt-4-1106-preview:canadaeast" + | "gpt-4-1106-preview:france" + | "gpt-4-1106-preview:india" + | "gpt-4-1106-preview:norway" + | "gpt-4-1106-preview:swedencentral" + | "gpt-4-1106-preview:uk" + | "gpt-4-1106-preview:westus" + | "gpt-4-1106-preview:westus3" + | "gpt-4-0613:canadaeast" + | "gpt-3.5-turbo-0125:canadaeast" + | "gpt-3.5-turbo-0125:northcentralus" + | "gpt-3.5-turbo-0125:southcentralus" + | "gpt-3.5-turbo-1106:canadaeast" + | "gpt-3.5-turbo-1106:westus" + | "gpt-4.1:australiaeast" + | "gpt-4o:australiaeast" + | "gpt-5.4-mini:australiaeast" + | "gpt-live-1"; /** - * This is the detection type to use for voicemail detection. - * - 'audio': Uses native audio models (default) - * - 'transcript': Uses ASR/transcript-based detection - * @default 'audio' (audio detection) + * These are the fallback models that will be used if the primary model fails. This shouldn't be specified unless you have a specific reason to do so. Vapi will automatically find the fastest fallbacks that make sense. + * @example ["gpt-4-0125-preview","gpt-4-0613"] */ - type?: "audio" | "transcript"; -} - -export interface TransferHookAction { - /** This is the type of action - must be "transfer" */ - type: "transfer"; - /** This is the destination details for the transfer - can be a phone number or SIP URI */ - destination?: TransferDestinationNumber | TransferDestinationSip; -} - -export interface FunctionCallHookAction { - /** Messages spoken while the tool is running. Multiple request-start messages are variants. For request-response-delayed, same timing means variants and different timings mean staged updates. */ - messages?: ( - | ToolMessageStart - | ToolMessageComplete - | ToolMessageFailed - | ToolMessageDelayed + fallbackModels?: ( + | "gpt-6-luna" + | "gpt-5.6-sol" + | "gpt-5.6-terra" + | "gpt-5.6-luna" + | "gpt-5.5" + | "chat-latest" + | "gpt-5.4" + | "gpt-5.4-mini" + | "gpt-5.4-nano" + | "gpt-5.2" + | "gpt-5.2-chat-latest" + | "gpt-5.1" + | "gpt-5.1-chat-latest" + | "gpt-5" + | "gpt-5-chat-latest" + | "gpt-5-mini" + | "gpt-5-nano" + | "gpt-4.1-2025-04-14" + | "gpt-4.1-mini-2025-04-14" + | "gpt-4.1-nano-2025-04-14" + | "gpt-4.1" + | "gpt-4.1-mini" + | "gpt-4.1-nano" + | "chatgpt-4o-latest" + | "o3" + | "o3-mini" + | "o4-mini" + | "o1-mini" + | "o1-mini-2024-09-12" + | "gpt-4o-realtime-preview-2024-10-01" + | "gpt-4o-realtime-preview-2024-12-17" + | "gpt-4o-mini-realtime-preview-2024-12-17" + | "gpt-realtime-2025-08-28" + | "gpt-realtime-mini-2025-12-15" + | "gpt-realtime-2" + | "gpt-4o-mini-2024-07-18" + | "gpt-4o-mini" + | "gpt-4o" + | "gpt-4o-2024-05-13" + | "gpt-4o-2024-08-06" + | "gpt-4o-2024-11-20" + | "gpt-4-turbo" + | "gpt-4-turbo-2024-04-09" + | "gpt-4-turbo-preview" + | "gpt-4-0125-preview" + | "gpt-4-1106-preview" + | "gpt-4" + | "gpt-4-0613" + | "gpt-3.5-turbo" + | "gpt-3.5-turbo-0125" + | "gpt-3.5-turbo-1106" + | "gpt-3.5-turbo-16k" + | "gpt-3.5-turbo-0613" + | "gpt-5.6-luna:westus3" + | "gpt-5.6-terra:westus3" + | "gpt-5.6-sol:westus3" + | "gpt-5.4:eastus2" + | "gpt-5.4:swedencentral" + | "gpt-5.4-mini:eastus2" + | "gpt-5.4-mini:swedencentral" + | "gpt-5.4-nano:eastus2" + | "gpt-5.4-nano:swedencentral" + | "gpt-5.2:eastus2" + | "gpt-5.2:swedencentral" + | "gpt-5.1:eastus2" + | "gpt-5.1:swedencentral" + | "gpt-5:eastus2" + | "gpt-5:swedencentral" + | "gpt-5:canadaeast" + | "gpt-5:eastus" + | "gpt-5:westeurope" + | "gpt-5:germanywestcentral" + | "gpt-5:polandcentral" + | "gpt-5:spaincentral" + | "gpt-5-mini:eastus2" + | "gpt-5-mini:swedencentral" + | "gpt-5-mini:westeurope" + | "gpt-5-mini:germanywestcentral" + | "gpt-5-mini:polandcentral" + | "gpt-5-mini:spaincentral" + | "gpt-5-nano:eastus2" + | "gpt-5-nano:swedencentral" + | "gpt-4.1-2025-04-14:westus" + | "gpt-4.1-2025-04-14:eastus2" + | "gpt-4.1-2025-04-14:eastus" + | "gpt-4.1-2025-04-14:westus3" + | "gpt-4.1-2025-04-14:northcentralus" + | "gpt-4.1-2025-04-14:southcentralus" + | "gpt-4.1-2025-04-14:westeurope" + | "gpt-4.1-2025-04-14:germanywestcentral" + | "gpt-4.1-2025-04-14:polandcentral" + | "gpt-4.1-2025-04-14:spaincentral" + | "gpt-4.1-mini-2025-04-14:westus" + | "gpt-4.1-mini-2025-04-14:eastus2" + | "gpt-4.1-mini-2025-04-14:eastus" + | "gpt-4.1-mini-2025-04-14:westus3" + | "gpt-4.1-mini-2025-04-14:northcentralus" + | "gpt-4.1-mini-2025-04-14:southcentralus" + | "gpt-4.1-mini-2025-04-14:westeurope" + | "gpt-4.1-mini-2025-04-14:germanywestcentral" + | "gpt-4.1-mini-2025-04-14:polandcentral" + | "gpt-4.1-mini-2025-04-14:spaincentral" + | "gpt-4.1-nano-2025-04-14:westus" + | "gpt-4.1-nano-2025-04-14:eastus2" + | "gpt-4.1-nano-2025-04-14:westus3" + | "gpt-4.1-nano-2025-04-14:northcentralus" + | "gpt-4.1-nano-2025-04-14:southcentralus" + | "gpt-4o-2024-11-20:swedencentral" + | "gpt-4o-2024-11-20:westus" + | "gpt-4o-2024-11-20:eastus2" + | "gpt-4o-2024-11-20:eastus" + | "gpt-4o-2024-11-20:westus3" + | "gpt-4o-2024-11-20:southcentralus" + | "gpt-4o-2024-11-20:westeurope" + | "gpt-4o-2024-11-20:germanywestcentral" + | "gpt-4o-2024-11-20:polandcentral" + | "gpt-4o-2024-11-20:spaincentral" + | "gpt-4o-2024-08-06:westus" + | "gpt-4o-2024-08-06:westus3" + | "gpt-4o-2024-08-06:eastus" + | "gpt-4o-2024-08-06:eastus2" + | "gpt-4o-2024-08-06:northcentralus" + | "gpt-4o-2024-08-06:southcentralus" + | "gpt-4o-mini-2024-07-18:westus" + | "gpt-4o-mini-2024-07-18:westus3" + | "gpt-4o-mini-2024-07-18:eastus" + | "gpt-4o-mini-2024-07-18:eastus2" + | "gpt-4o-mini-2024-07-18:northcentralus" + | "gpt-4o-mini-2024-07-18:southcentralus" + | "gpt-4o-2024-05-13:eastus2" + | "gpt-4o-2024-05-13:eastus" + | "gpt-4o-2024-05-13:northcentralus" + | "gpt-4o-2024-05-13:southcentralus" + | "gpt-4o-2024-05-13:westus3" + | "gpt-4o-2024-05-13:westus" + | "gpt-4-turbo-2024-04-09:eastus2" + | "gpt-4-0125-preview:eastus" + | "gpt-4-0125-preview:northcentralus" + | "gpt-4-0125-preview:southcentralus" + | "gpt-4-1106-preview:australiaeast" + | "gpt-4-1106-preview:canadaeast" + | "gpt-4-1106-preview:france" + | "gpt-4-1106-preview:india" + | "gpt-4-1106-preview:norway" + | "gpt-4-1106-preview:swedencentral" + | "gpt-4-1106-preview:uk" + | "gpt-4-1106-preview:westus" + | "gpt-4-1106-preview:westus3" + | "gpt-4-0613:canadaeast" + | "gpt-3.5-turbo-0125:canadaeast" + | "gpt-3.5-turbo-0125:northcentralus" + | "gpt-3.5-turbo-0125:southcentralus" + | "gpt-3.5-turbo-1106:canadaeast" + | "gpt-3.5-turbo-1106:westus" + | "gpt-4.1:australiaeast" + | "gpt-4o:australiaeast" + | "gpt-5.4-mini:australiaeast" )[]; - /** The type of tool. "function" for Function tool. */ - type: "function"; /** - * This determines if the tool is async. - * - * If async, the assistant will move forward without waiting for your server to respond. This is useful if you just want to trigger something on your server. + * Azure OpenAI doesn't support `maxLength` right now https://learn.microsoft.com/en-us/azure/ai-services/openai/how-to/structured-outputs?tabs=python-secure%2Cdotnet-entra-id&pivots=programming-language-csharp#unsupported-type-specific-keywords. Need to strip. * - * If sync, the assistant will wait for your server to respond. This is useful if want assistant to respond with the result from your server. + * - `strip-parameters-with-unsupported-validation` will strip parameters with unsupported validation. + * - `strip-unsupported-validation` will keep the parameters but strip unsupported validation. * - * Defaults to synchronous (`false`). - * @example false + * @default `strip-unsupported-validation` */ - async?: boolean; + toolStrictCompatibilityMode?: + | "strip-parameters-with-unsupported-validation" + | "strip-unsupported-validation"; /** + * This controls the prompt cache retention policy for models that support extended caching (GPT-4.1, GPT-5 series). * - * This is the server where a `tool-calls` webhook will be sent. + * - `in_memory`: Default behavior, cache retained in GPU memory only + * - `24h`: Extended caching, keeps cached prefixes active for up to 24 hours by offloading to GPU-local storage * - * Notes: - * - Webhook is sent to this server when a tool call is made. - * - Webhook contains the call, assistant, and phone number objects. - * - Webhook contains the variables set on the assistant. - * - Webhook is sent to the first available URL in this order: {{tool.server.url}}, {{assistant.server.url}}, {{phoneNumber.server.url}}, {{org.server.url}}. - * - Webhook expects a response with tool call result. + * Only applies to models: gpt-5.6-sol, gpt-5.6-terra, gpt-5.6-luna, gpt-5.5, chat-latest, gpt-5.4, gpt-5.4-mini, gpt-5.4-nano, gpt-5.2, gpt-5.1, gpt-5.1-codex, gpt-5.1-codex-mini, gpt-5.1-chat-latest, gpt-5, gpt-5-codex, gpt-4.1 + * + * @default undefined (uses API default which is 'in_memory') */ - server?: Server; - /** Plan to extract variables from the tool response */ - variableExtractionPlan?: VariableExtractionPlan; - /** Static key-value pairs merged into the request body. Values support Liquid templates. */ - parameters?: ToolParameter[]; + promptCacheRetention?: "in_memory" | "24h"; /** - * This is the plan to reject a tool call based on the conversation state. - * - * // Example 1: Reject endCall if user didn't say goodbye - * ```json - * { - * conditions: [{ - * type: 'regex', - * regex: '(?i)\\b(bye|goodbye|farewell|see you later|take care)\\b', - * target: { position: -1, role: 'user' }, - * negate: true // Reject if pattern does NOT match - * }] - * } - * ``` - * - * // Example 2: Reject transfer if user is actually asking a question - * ```json - * { - * conditions: [{ - * type: 'regex', - * regex: '\\?', - * target: { position: -1, role: 'user' } - * }] - * } - * ``` + * This is the prompt cache key for models that support extended caching (GPT-4.1, GPT-5 series). * - * // Example 3: Reject transfer if user didn't mention transfer recently - * ```json - * { - * conditions: [{ - * type: 'liquid', - * liquid: `{% assign recentMessages = messages | last: 5 %} - * {% assign userMessages = recentMessages | where: 'role', 'user' %} - * {% assign mentioned = false %} - * {% for msg in userMessages %} - * {% if msg.content contains 'transfer' or msg.content contains 'connect' or msg.content contains 'speak to' %} - * {% assign mentioned = true %} - * {% break %} - * {% endif %} - * {% endfor %} - * {% if mentioned %} - * false - * {% else %} - * true - * {% endif %}` - * }] - * } - * ``` + * Providing a cache key allows you to share cached prefixes across requests. * - * // Example 4: Reject endCall if the bot is looping and trying to exit - * ```json - * { - * conditions: [{ - * type: 'liquid', - * liquid: `{% assign recentMessages = messages | last: 6 %} - * {% assign userMessages = recentMessages | where: 'role', 'user' | reverse %} - * {% if userMessages.size < 3 %} - * false - * {% else %} - * {% assign msg1 = userMessages[0].content | downcase %} - * {% assign msg2 = userMessages[1].content | downcase %} - * {% assign msg3 = userMessages[2].content | downcase %} - * {% comment %} Check for repetitive messages {% endcomment %} - * {% if msg1 == msg2 or msg1 == msg3 or msg2 == msg3 %} - * true - * {% comment %} Check for common loop phrases {% endcomment %} - * {% elsif msg1 contains 'cool thanks' or msg2 contains 'cool thanks' or msg3 contains 'cool thanks' %} - * true - * {% elsif msg1 contains 'okay thanks' or msg2 contains 'okay thanks' or msg3 contains 'okay thanks' %} - * true - * {% elsif msg1 contains 'got it' or msg2 contains 'got it' or msg3 contains 'got it' %} - * true - * {% else %} - * false - * {% endif %} - * {% endif %}` - * }] - * } - * ``` - */ - rejectionPlan?: ToolRejectionPlan; - /** This is the function definition of the tool. */ - function?: OpenAIFunction; -} - -export interface SayHookAction { - /** This is the type of action - must be "say" */ - type: "say"; - /** This is the exact message to say. When a string array is provided, one is randomly selected. */ - exact?: string | string[]; - /** - * This is the prompt for the assistant to generate a response based on existing conversation. - * Can be a string or an array of chat messages. + * @default undefined + * @maxLength 64 */ - prompt?: - | string - | ( - | SystemMessage - | UserMessage - | AssistantMessage - | ToolMessage - | DeveloperMessage - )[]; -} - -export interface MessageAddHookAction { - /** This is the type of action - must be "message.add" */ - type: "message.add"; + promptCacheKey?: string; /** - * The message to add to the conversation in OpenAI format - * @example {"role":"system","content":"Context update from hook"} + * This is the OpenAI service tier to request. + * + * - `fast`: requests Fast mode, which gives faster responses at a higher per-token rate. How much faster depends on the model. + * - `priority`: the old name for `fast`, accepted and billed the same. + * - `default`: standard processing. + * - `auto`: the default when unset. On Vapi's OpenAI keys this is standard processing; on your own OpenAI key, OpenAI applies your project's default tier. + * + * OpenAI sets Fast mode rates per model, and they are not a fixed multiple of the standard rates. Vapi bills them only when OpenAI reports that it served the request in Fast mode. Otherwise the request is billed at standard rates, for example when Fast mode isn't available for the model on Vapi, OpenAI downgrades the request, or the request runs on Azure OpenAI. + * + * Supported models and their Fast mode rates: https://docs.vapi.ai/providers/model/openai */ - message: OpenAIMessage; + serviceTier?: "auto" | "default" | "fast" | "priority"; /** - * Whether to trigger an assistant response after adding the message - * @default true + * Reasoning effort for reasoning-capable OpenAI models. + * For `gpt-realtime-2`: forwarded to V2 stream's session.update as `reasoning.effort`. + * For non-realtime OpenAI models, model-aware validation limits newly public + * values while preserving the existing four-value storage contract. */ - triggerResponseEnabled?: boolean; -} - -export interface CallHookFilter { + reasoningEffort?: "minimal" | "none" | "low" | "medium" | "high" | "xhigh"; /** - * This is the type of filter - currently only "oneOf" is supported - * @maxLength 1000 + * This is the temperature that will be used for calls. Default is 0.5. + * @min 0 + * @max 2 */ - type: "oneOf"; + temperature?: number; /** - * This is the key to filter on (e.g. "call.endedReason") - * @maxLength 1000 + * This is the max number of tokens that the assistant will be allowed to generate in each turn of the conversation. Default is 250. On gpt-6-luna and claude-haiku-5-5 no cap is applied unless you set one (claude-haiku-5-5 sends its 128,000-token maximum), because reasoning uses output tokens and a small cap can leave the reply empty. + * @min 50 + * @max 10000 */ - key: string; - /** This is the array of possible values to match against */ - oneOf: string[]; -} - -export interface CallHookCallEnding { + maxTokens?: number; /** - * This is the event that triggers this hook - * @maxLength 1000 + * This determines whether we detect user's emotion while they speak and send it as an additional info to model. + * + * Default `false` because the model is usually are good at understanding the user's emotion from text. + * + * @default false */ - on: "call.ending"; - /** This is the set of actions to perform when the hook triggers */ - do: (ToolCallHookAction | MessageAddHookAction)[]; - /** This is the set of filters that must match for the hook to trigger */ - filters?: CallHookFilter[]; -} - -export interface CallHookAssistantSpeechInterrupted { + emotionRecognitionEnabled?: boolean; /** - * This is the event that triggers this hook - * @maxLength 1000 + * This sets how many turns at the start of the conversation to use a smaller, faster model from the same provider before switching to the primary model. Example, gpt-3.5-turbo if provider is openai. + * + * Default is 0. + * + * @default 0 + * @min 0 */ - on: "assistant.speech.interrupted"; - /** This is the set of actions to perform when the hook triggers */ - do: (SayHookAction | ToolCallHookAction | MessageAddHookAction)[]; + numFastTurns?: number; } -export interface CallHookCustomerSpeechInterrupted { +export interface OpenRouterModel { + /** This is the starting state for the conversation. */ + messages?: OpenAIMessage[]; /** - * This is the event that triggers this hook - * @maxLength 1000 + * These are the tools that the assistant can use during the call. To use existing tools, use `toolIds`. + * + * Both `tools` and `toolIds` can be used together. */ - on: "customer.speech.interrupted"; - /** This is the set of actions to perform when the hook triggers */ - do: (SayHookAction | ToolCallHookAction | MessageAddHookAction)[]; -} - -export interface ToolCallHookAction { - /** This is the type of action - must be "tool" */ - type: "tool"; - /** This is the tool to call. To use an existing tool, send `toolId` instead. */ - tool?: + tools?: ( | CreateApiRequestToolDTO | CreateBashToolDTO | CreateCodeToolDTO @@ -12165,1021 +12765,1393 @@ export interface ToolCallHookAction { | CreateTextEditorToolDTO | CreateTransferCallToolDTO | CreateSipRequestToolDTO - | CreateVoicemailToolDTO; - /** This is the tool to call. To use a transient tool, send `tool` instead. */ - toolId?: string; -} - -export interface CustomerSpeechTimeoutOptions { - /** - * This is whether the counter for hook trigger resets the user speaks. - * - * @default never - */ - triggerResetMode?: "onUserSpeech" | "never"; - /** - * This is the timeout in seconds before action is triggered. - * The clock starts when the assistant finishes speaking and remains active until the user speaks. - * - * @default 7.5 - * @minimum 2 - * @maximum 1000 - * @min 1 - * @max 1000 - */ - timeoutSeconds: number; - /** - * This is the maximum number of times the hook will trigger in a call. - * - * @default 3 - * @min 1 - * @max 10 - */ - triggerMaxCount?: number; -} - -export interface CallHookCustomerSpeechTimeout { - /** - * Must be either "customer.speech.timeout" or match the pattern "customer.speech.timeout[property=value]" - * @maxLength 1000 - */ - on: string; - /** This is the set of actions to perform when the hook triggers */ - do: (SayHookAction | ToolCallHookAction | MessageAddHookAction)[]; - /** This is the set of filters that must match for the hook to trigger */ - options?: CustomerSpeechTimeoutOptions; + | CreateVoicemailToolDTO + )[]; /** - * This is the name of the hook, it can be set by the user to identify the hook. - * If no name is provided, the hook will be auto generated as UUID. + * These are the tools that the assistant can use during the call. To use transient tools, use `tools`. * - * @default UUID - * @maxLength 1000 - */ - name?: string; -} - -export interface CallHookModelResponseTimeout { - /** - * This is the event that triggers this hook - * @maxLength 1000 + * Both `tools` and `toolIds` can be used together. */ - on: "model.response.timeout"; - /** This is the set of actions to perform when the hook triggers */ - do: (SayHookAction | ToolCallHookAction | MessageAddHookAction)[]; -} - -export interface AIEdgeCondition { - type: "ai"; + toolIds?: string[]; /** - * This is the prompt for the AI edge condition. It should evaluate to a boolean. - * @maxLength 1000 + * These are version-pinned references to tools. Each entry pins a specific + * version of a tool by `(toolId, version)`. When the same `toolId` appears + * in both `toolIds` and `toolRefs[]`, the `toolRefs` pin wins (the + * `toolIds` entry is dropped at write time). */ - prompt: string; -} - -export interface Edge { - condition?: AIEdgeCondition; - /** @maxLength 80 */ - from: string; - /** @maxLength 80 */ - to: string; - /** This is for metadata you want to store on the edge. */ - metadata?: object; -} - -export interface RecordingConsentPlanStayOnLine { + toolRefs?: ToolRef[]; + /** These are the options for the knowledge base. */ + knowledgeBase?: CreateCustomKnowledgeBaseDTO; + provider: "openrouter"; + /** This is the name of the model. Ex. cognitivecomputations/dolphin-mixtral-8x7b */ + model: string; /** - * This is the message asking for consent to record the call. - * If the type is `stay-on-line`, the message should ask the user to hang up if they do not consent. - * If the type is `verbal`, the message should ask the user to verbally consent or decline. - * @maxLength 1000 + * This is the temperature that will be used for calls. Default is 0.5. + * @min 0 + * @max 2 */ - message: string; + temperature?: number; /** - * This is the voice to use for the consent message. If not specified, inherits from the assistant's voice. - * Use a different voice for the consent message for a better user experience. + * This is the max number of tokens that the assistant will be allowed to generate in each turn of the conversation. Default is 250. On gpt-6-luna and claude-haiku-5-5 no cap is applied unless you set one (claude-haiku-5-5 sends its 128,000-token maximum), because reasoning uses output tokens and a small cap can leave the reply empty. + * @min 50 + * @max 10000 */ - voice?: - | AzureVoice - | CartesiaVoice - | CustomVoice - | DeepgramVoice - | ElevenLabsVoice - | HumeVoice - | LMNTVoice - | NeuphonicVoice - | OpenAIVoice - | PlayHTVoice - | WellSaidVoice - | RimeAIVoice - | SmallestAIVoice - | TavusVoice - | VapiVoice - | SesameVoice - | InworldVoice - | MinimaxVoice - | XaiVoice - | MicrosoftVoice; + maxTokens?: number; /** - * This controls whether the consent assistant speaks first or waits for the caller to speak first. - * - * Use: - * - `assistant-speaks-first` (default) to have the consent assistant play the consent message as soon as the call is answered. - * - `assistant-waits-for-user` to have the consent assistant wait for the caller to speak before playing the consent message. - * - * We strongly recommend `assistant-waits-for-user` for outbound calls. Some telephony providers signal "answered" while the line is still ringing, which can cause the consent message to play into a ringing line and be missed by the caller. Waiting for the caller to speak first guarantees they hear the full consent message. + * This determines whether we detect user's emotion while they speak and send it as an additional info to model. * - * Note: when combined with `type: 'stay-on-line'`, silence only counts toward consent after the caller has spoken at least once. + * Default `false` because the model is usually are good at understanding the user's emotion from text. * - * @default 'assistant-speaks-first' - * @default "assistant-speaks-first" - * @example "assistant-speaks-first" - */ - firstMessageMode?: "assistant-speaks-first" | "assistant-waits-for-user"; - /** - * This is the type of recording consent plan. This type assumes consent is granted if the user stays on the line. - * @example "stay-on-line" - */ - type: "stay-on-line"; - /** - * Number of seconds to wait before transferring to the assistant if user stays on the call - * @min 1 - * @max 6 - * @default 3 - * @example 3 - */ - waitSeconds?: number; -} - -export interface RecordingConsentPlanVerbal { - /** - * This is the message asking for consent to record the call. - * If the type is `stay-on-line`, the message should ask the user to hang up if they do not consent. - * If the type is `verbal`, the message should ask the user to verbally consent or decline. - * @maxLength 1000 - */ - message: string; - /** - * This is the voice to use for the consent message. If not specified, inherits from the assistant's voice. - * Use a different voice for the consent message for a better user experience. + * @default false */ - voice?: - | AzureVoice - | CartesiaVoice - | CustomVoice - | DeepgramVoice - | ElevenLabsVoice - | HumeVoice - | LMNTVoice - | NeuphonicVoice - | OpenAIVoice - | PlayHTVoice - | WellSaidVoice - | RimeAIVoice - | SmallestAIVoice - | TavusVoice - | VapiVoice - | SesameVoice - | InworldVoice - | MinimaxVoice - | XaiVoice - | MicrosoftVoice; + emotionRecognitionEnabled?: boolean; /** - * This controls whether the consent assistant speaks first or waits for the caller to speak first. - * - * Use: - * - `assistant-speaks-first` (default) to have the consent assistant play the consent message as soon as the call is answered. - * - `assistant-waits-for-user` to have the consent assistant wait for the caller to speak before playing the consent message. - * - * We strongly recommend `assistant-waits-for-user` for outbound calls. Some telephony providers signal "answered" while the line is still ringing, which can cause the consent message to play into a ringing line and be missed by the caller. Waiting for the caller to speak first guarantees they hear the full consent message. + * This sets how many turns at the start of the conversation to use a smaller, faster model from the same provider before switching to the primary model. Example, gpt-3.5-turbo if provider is openai. * - * Note: when combined with `type: 'stay-on-line'`, silence only counts toward consent after the caller has spoken at least once. + * Default is 0. * - * @default 'assistant-speaks-first' - * @default "assistant-speaks-first" - * @example "assistant-speaks-first" - */ - firstMessageMode?: "assistant-speaks-first" | "assistant-waits-for-user"; - /** - * This is the type of recording consent plan. This type assumes consent is granted if the user verbally consents or declines. - * @example "verbal" + * @default 0 + * @min 0 */ - type: "verbal"; - /** Tool to execute if user verbally declines recording consent */ - declineTool?: object; - /** ID of existing tool to execute if user verbally declines recording consent */ - declineToolId?: string; + numFastTurns?: number; } -export type SecurityFilterBase = object; - -export interface SecurityFilterPlan { +export interface PerplexityAIModel { + /** This is the starting state for the conversation. */ + messages?: OpenAIMessage[]; /** - * Whether the security filter is enabled. - * @default false - * @default false + * These are the tools that the assistant can use during the call. To use existing tools, use `toolIds`. + * + * Both `tools` and `toolIds` can be used together. */ - enabled?: boolean; + tools?: ( + | CreateApiRequestToolDTO + | CreateBashToolDTO + | CreateCodeToolDTO + | CreateComputerToolDTO + | CreateDtmfToolDTO + | CreateEndCallToolDTO + | CreateFunctionToolDTO + | CreateGoHighLevelCalendarAvailabilityToolDTO + | CreateGoHighLevelCalendarEventCreateToolDTO + | CreateGoHighLevelContactCreateToolDTO + | CreateGoHighLevelContactGetToolDTO + | CreateGoogleCalendarCheckAvailabilityToolDTO + | CreateGoogleCalendarCreateEventToolDTO + | CreateGoogleSheetsRowAppendToolDTO + | CreateHandoffToolDTO + | CreateMcpToolDTO + | CreateQueryToolDTO + | CreateSlackSendMessageToolDTO + | CreateSmsToolDTO + | CreateTextEditorToolDTO + | CreateTransferCallToolDTO + | CreateSipRequestToolDTO + | CreateVoicemailToolDTO + )[]; /** - * Array of security filter types to apply. - * If array is not empty, only those security filters are run. - * @example "[{ type: "sql-injection" }, { type: "xss" }]" + * These are the tools that the assistant can use during the call. To use transient tools, use `tools`. + * + * Both `tools` and `toolIds` can be used together. */ - filters?: SecurityFilterBase[]; + toolIds?: string[]; /** - * Mode of operation when a security threat is detected. - * - 'sanitize': Remove or replace the threatening content - * - 'reject': Replace the entire transcript with replacement text - * - 'replace': Replace threatening patterns with replacement text - * @default 'sanitize' - * @default "sanitize" + * These are version-pinned references to tools. Each entry pins a specific + * version of a tool by `(toolId, version)`. When the same `toolId` appears + * in both `toolIds` and `toolRefs[]`, the `toolRefs` pin wins (the + * `toolIds` entry is dropped at write time). */ - mode?: "sanitize" | "reject" | "replace"; + toolRefs?: ToolRef[]; + /** These are the options for the knowledge base. */ + knowledgeBase?: CreateCustomKnowledgeBaseDTO; + provider: "perplexity-ai"; + /** This is the name of the model. Ex. cognitivecomputations/dolphin-mixtral-8x7b */ + model: string; /** - * Text to use when replacing filtered content. - * @default '[FILTERED]' - * @default "[FILTERED]" + * This is the temperature that will be used for calls. Default is 0.5. + * @min 0 + * @max 2 */ - replacementText?: string; -} - -export interface CompliancePlan { - /** When this is enabled, logs, recordings, and transcriptions will be stored in HIPAA-compliant storage. Defaults to false. Only HIPAA-compliant providers will be available for LLM, Voice, and Transcriber respectively. This setting is only honored if the organization is on an Enterprise subscription or has purchased the HIPAA add-on. */ - hipaaEnabled?: boolean; + temperature?: number; /** - * When this is enabled, the user will be restricted to use PCI-compliant providers, and no logs or transcripts are stored. - * At the end of the call, you will receive an end-of-call-report message to store on your server. Defaults to false. - * @example {"pciEnabled":false} + * This is the max number of tokens that the assistant will be allowed to generate in each turn of the conversation. Default is 250. On gpt-6-luna and claude-haiku-5-5 no cap is applied unless you set one (claude-haiku-5-5 sends its 128,000-token maximum), because reasoning uses output tokens and a small cap can leave the reply empty. + * @min 50 + * @max 10000 */ - pciEnabled?: boolean; - /** This is the security filter plan for the assistant. It allows filtering of transcripts for security threats before sending to LLM. */ - securityFilterPlan?: SecurityFilterPlan; - recordingConsentPlan?: - | ({ - type: "stay-on-line"; - } & RecordingConsentPlanStayOnLine) - | ({ - type: "verbal"; - } & RecordingConsentPlanVerbal); -} - -export interface StructuredDataPlan { + maxTokens?: number; /** - * These are the messages used to generate the structured data. - * - * @default: ``` - * [ - * { - * "role": "system", - * "content": "You are an expert data extractor. You will be given a transcript of a call. Extract structured data per the JSON Schema. DO NOT return anything except the structured data.\n\nJson Schema:\\n{{schema}}\n\nOnly respond with the JSON." - * }, - * { - * "role": "user", - * "content": "Here is the transcript:\n\n{{transcript}}\n\n. Here is the ended reason of the call:\n\n{{endedReason}}\n\n" - * } - * ]``` + * This determines whether we detect user's emotion while they speak and send it as an additional info to model. * - * You can customize by providing any messages you want. + * Default `false` because the model is usually are good at understanding the user's emotion from text. * - * Here are the template variables available: - * - {{transcript}}: the transcript of the call from `call.artifact.transcript`- {{systemPrompt}}: the system prompt of the call from `assistant.model.messages[type=system].content`- {{messages}}: the messages of the call from `assistant.model.messages`- {{schema}}: the schema of the structured data from `structuredDataPlan.schema`- {{endedReason}}: the ended reason of the call from `call.endedReason` + * @default false */ - messages?: object[]; + emotionRecognitionEnabled?: boolean; /** - * This determines whether structured data is generated and stored in `call.analysis.structuredData`. Defaults to false. + * This sets how many turns at the start of the conversation to use a smaller, faster model from the same provider before switching to the primary model. Example, gpt-3.5-turbo if provider is openai. * - * Usage: - * - If you want to extract structured data, set this to true and provide a `schema`. + * Default is 0. * - * @default false + * @default 0 + * @min 0 */ - enabled?: boolean; + numFastTurns?: number; +} + +export interface TogetherAIModel { + /** This is the starting state for the conversation. */ + messages?: OpenAIMessage[]; /** - * This is the schema of the structured data. The output is stored in `call.analysis.structuredData`. + * These are the tools that the assistant can use during the call. To use existing tools, use `toolIds`. * - * Complete guide on JSON Schema can be found [here](https://ajv.js.org/json-schema.html#json-data-type). + * Both `tools` and `toolIds` can be used together. */ - schema?: JsonSchema; + tools?: ( + | CreateApiRequestToolDTO + | CreateBashToolDTO + | CreateCodeToolDTO + | CreateComputerToolDTO + | CreateDtmfToolDTO + | CreateEndCallToolDTO + | CreateFunctionToolDTO + | CreateGoHighLevelCalendarAvailabilityToolDTO + | CreateGoHighLevelCalendarEventCreateToolDTO + | CreateGoHighLevelContactCreateToolDTO + | CreateGoHighLevelContactGetToolDTO + | CreateGoogleCalendarCheckAvailabilityToolDTO + | CreateGoogleCalendarCreateEventToolDTO + | CreateGoogleSheetsRowAppendToolDTO + | CreateHandoffToolDTO + | CreateMcpToolDTO + | CreateQueryToolDTO + | CreateSlackSendMessageToolDTO + | CreateSmsToolDTO + | CreateTextEditorToolDTO + | CreateTransferCallToolDTO + | CreateSipRequestToolDTO + | CreateVoicemailToolDTO + )[]; /** - * This is how long the request is tried before giving up. When request times out, `call.analysis.structuredData` will be empty. - * - * Usage: - * - To guarantee the structured data is generated, set this value high. Note, this will delay the end of call report in cases where model is slow to respond. + * These are the tools that the assistant can use during the call. To use transient tools, use `tools`. * - * @default 5 seconds - * @min 1 - * @max 60 + * Both `tools` and `toolIds` can be used together. */ - timeoutSeconds?: number; -} - -export interface StructuredDataMultiPlan { - /** This is the key of the structured data plan in the catalog. */ - key: string; - /** This is an individual structured data plan in the catalog. */ - plan: StructuredDataPlan; -} - -export interface SuccessEvaluationPlan { + toolIds?: string[]; /** - * This enforces the rubric of the evaluation. The output is stored in `call.analysis.successEvaluation`. - * - * Options include: - * - 'NumericScale': A scale of 1 to 10. - * - 'DescriptiveScale': A scale of Excellent, Good, Fair, Poor. - * - 'Checklist': A checklist of criteria and their status. - * - 'Matrix': A grid that evaluates multiple criteria across different performance levels. - * - 'PercentageScale': A scale of 0% to 100%. - * - 'LikertScale': A scale of Strongly Agree, Agree, Neutral, Disagree, Strongly Disagree. - * - 'AutomaticRubric': Automatically break down evaluation into several criteria, each with its own score. - * - 'PassFail': A simple 'true' if call passed, 'false' if not. - * - * Default is 'PassFail'. + * These are version-pinned references to tools. Each entry pins a specific + * version of a tool by `(toolId, version)`. When the same `toolId` appears + * in both `toolIds` and `toolRefs[]`, the `toolRefs` pin wins (the + * `toolIds` entry is dropped at write time). + */ + toolRefs?: ToolRef[]; + /** These are the options for the knowledge base. */ + knowledgeBase?: CreateCustomKnowledgeBaseDTO; + provider: "together-ai"; + /** This is the name of the model. Ex. cognitivecomputations/dolphin-mixtral-8x7b */ + model: string; + /** + * This is the temperature that will be used for calls. Default is 0.5. + * @min 0 + * @max 2 */ - rubric?: - | "NumericScale" - | "DescriptiveScale" - | "Checklist" - | "Matrix" - | "PercentageScale" - | "LikertScale" - | "AutomaticRubric" - | "PassFail"; + temperature?: number; /** - * These are the messages used to generate the success evaluation. - * - * @default: ``` - * [ - * { - * "role": "system", - * "content": "You are an expert call evaluator. You will be given a transcript of a call and the system prompt of the AI participant. Determine if the call was successful based on the objectives inferred from the system prompt. DO NOT return anything except the result.\n\nRubric:\\n{{rubric}}\n\nOnly respond with the result." - * }, - * { - * "role": "user", - * "content": "Here is the transcript:\n\n{{transcript}}\n\n" - * }, - * { - * "role": "user", - * "content": "Here was the system prompt of the call:\n\n{{systemPrompt}}\n\n. Here is the ended reason of the call:\n\n{{endedReason}}\n\n" - * } - * ]``` - * - * You can customize by providing any messages you want. - * - * Here are the template variables available: - * - {{transcript}}: the transcript of the call from `call.artifact.transcript`- {{systemPrompt}}: the system prompt of the call from `assistant.model.messages[type=system].content`- {{messages}}: the messages of the call from `assistant.model.messages`- {{rubric}}: the rubric of the success evaluation from `successEvaluationPlan.rubric`- {{endedReason}}: the ended reason of the call from `call.endedReason` + * This is the max number of tokens that the assistant will be allowed to generate in each turn of the conversation. Default is 250. On gpt-6-luna and claude-haiku-5-5 no cap is applied unless you set one (claude-haiku-5-5 sends its 128,000-token maximum), because reasoning uses output tokens and a small cap can leave the reply empty. + * @min 50 + * @max 10000 */ - messages?: object[]; + maxTokens?: number; /** - * This determines whether a success evaluation is generated and stored in `call.analysis.successEvaluation`. Defaults to true. + * This determines whether we detect user's emotion while they speak and send it as an additional info to model. * - * Usage: - * - If you want to disable the success evaluation, set this to false. + * Default `false` because the model is usually are good at understanding the user's emotion from text. * - * @default true + * @default false */ - enabled?: boolean; + emotionRecognitionEnabled?: boolean; /** - * This is how long the request is tried before giving up. When request times out, `call.analysis.successEvaluation` will be empty. + * This sets how many turns at the start of the conversation to use a smaller, faster model from the same provider before switching to the primary model. Example, gpt-3.5-turbo if provider is openai. * - * Usage: - * - To guarantee the success evaluation is generated, set this value high. Note, this will delay the end of call report in cases where model is slow to respond. + * Default is 0. * - * @default 5 seconds - * @min 1 - * @max 60 + * @default 0 + * @min 0 */ - timeoutSeconds?: number; + numFastTurns?: number; } -export interface AnalysisPlan { +export interface HangupNode { + type: "hangup"; + /** @maxLength 80 */ + name: string; + /** This is whether or not the node is the start of the workflow. */ + isStart?: boolean; + /** This is for metadata you want to store on the task. */ + metadata?: object; +} + +export interface WorkflowOpenAIModel { /** - * The minimum number of messages required to run the analysis plan. - * If the number of messages is less than this, analysis will be skipped. + * These are the messages used to customize the prompt used for structured output extraction. * - * @default 2 - * @deprecated - * @min 0 - */ - minMessagesThreshold?: number; - /** - * This is the plan for generating the summary of the call. This outputs to `call.analysis.summary`. - * @deprecated + * When provided, these messages replace the default prompts. For text extraction, message contents support LiquidJS templating with the following variables: + * - `{{transcript}}`, `{{messages}}`, or `{{messagesWithConfidence}}` to reference the conversation (one is required) + * - `{{structuredOutput.name}}`, `{{structuredOutput.description}}`, or `{{structuredOutput.schema}}` to reference the structured output definition (one is required) + * - `{{systemPrompt}}`, `{{callEndedReason}}`, `{{duration}}`, `{{startedAt}}`, `{{endedAt}}`, and any `assistantOverrides.variableValues` + * + * In structured outputs, `{{messages}}` includes conversation text and tool calls/results, but omits caller transcription-confidence fields. For text extraction, `{{messagesWithConfidence}}` includes the original message history with transcription confidence for outputs that explicitly need it. These variables also apply in structured-output schema descriptions. Audio-targeted (`messages-with-audio`) extraction ignores custom messages. Stored call artifacts and API messages retain their confidence data. `{{transcript}}` is the spoken text only, which uses significantly fewer tokens. + * + * If not provided, default system and user prompts are used. */ - summaryPlan?: SummaryPlan; + messages?: OpenAIMessage[]; + /** This is the provider of the model (`openai`). */ + provider: "openai"; /** - * This is the plan for generating the structured data from the call. This outputs to `call.analysis.structuredData`. - * @deprecated + * This is the OpenAI model that will be used. + * + * When using Vapi OpenAI or your own Azure Credentials, you have the option to specify the region for the selected model. This shouldn't be specified unless you have a specific reason to do so. Vapi will automatically find the fastest region that make sense. + * This is helpful when you are required to comply with Data Residency rules. Learn more about Azure regions here https://azure.microsoft.com/en-us/explore/global-infrastructure/data-residency/. + * @maxLength 100 */ - structuredDataPlan?: StructuredDataPlan; + model: + | "gpt-6-luna" + | "gpt-5.6-sol" + | "gpt-5.6-terra" + | "gpt-5.6-luna" + | "gpt-5.5" + | "chat-latest" + | "gpt-5.4" + | "gpt-5.4-mini" + | "gpt-5.4-nano" + | "gpt-5.2" + | "gpt-5.2-chat-latest" + | "gpt-5.1" + | "gpt-5.1-chat-latest" + | "gpt-5" + | "gpt-5-chat-latest" + | "gpt-5-mini" + | "gpt-5-nano" + | "gpt-4.1-2025-04-14" + | "gpt-4.1-mini-2025-04-14" + | "gpt-4.1-nano-2025-04-14" + | "gpt-4.1" + | "gpt-4.1-mini" + | "gpt-4.1-nano" + | "chatgpt-4o-latest" + | "o3" + | "o3-mini" + | "o4-mini" + | "o1-mini" + | "o1-mini-2024-09-12" + | "gpt-4o-mini-2024-07-18" + | "gpt-4o-mini" + | "gpt-4o" + | "gpt-4o-2024-05-13" + | "gpt-4o-2024-08-06" + | "gpt-4o-2024-11-20" + | "gpt-4-turbo" + | "gpt-4-turbo-2024-04-09" + | "gpt-4-turbo-preview" + | "gpt-4-0125-preview" + | "gpt-4-1106-preview" + | "gpt-4" + | "gpt-4-0613" + | "gpt-3.5-turbo" + | "gpt-3.5-turbo-0125" + | "gpt-3.5-turbo-1106" + | "gpt-3.5-turbo-16k" + | "gpt-3.5-turbo-0613" + | "gpt-5.6-luna:westus3" + | "gpt-5.6-terra:westus3" + | "gpt-5.6-sol:westus3" + | "gpt-5.4:eastus2" + | "gpt-5.4:swedencentral" + | "gpt-5.4-mini:eastus2" + | "gpt-5.4-mini:swedencentral" + | "gpt-5.4-nano:eastus2" + | "gpt-5.4-nano:swedencentral" + | "gpt-5.2:eastus2" + | "gpt-5.2:swedencentral" + | "gpt-5.1:eastus2" + | "gpt-5.1:swedencentral" + | "gpt-5:eastus2" + | "gpt-5:swedencentral" + | "gpt-5:canadaeast" + | "gpt-5:eastus" + | "gpt-5:westeurope" + | "gpt-5:germanywestcentral" + | "gpt-5:polandcentral" + | "gpt-5:spaincentral" + | "gpt-5-mini:eastus2" + | "gpt-5-mini:swedencentral" + | "gpt-5-mini:westeurope" + | "gpt-5-mini:germanywestcentral" + | "gpt-5-mini:polandcentral" + | "gpt-5-mini:spaincentral" + | "gpt-5-nano:eastus2" + | "gpt-5-nano:swedencentral" + | "gpt-4.1-2025-04-14:westus" + | "gpt-4.1-2025-04-14:eastus2" + | "gpt-4.1-2025-04-14:eastus" + | "gpt-4.1-2025-04-14:westus3" + | "gpt-4.1-2025-04-14:northcentralus" + | "gpt-4.1-2025-04-14:southcentralus" + | "gpt-4.1-2025-04-14:westeurope" + | "gpt-4.1-2025-04-14:germanywestcentral" + | "gpt-4.1-2025-04-14:polandcentral" + | "gpt-4.1-2025-04-14:spaincentral" + | "gpt-4.1-mini-2025-04-14:westus" + | "gpt-4.1-mini-2025-04-14:eastus2" + | "gpt-4.1-mini-2025-04-14:eastus" + | "gpt-4.1-mini-2025-04-14:westus3" + | "gpt-4.1-mini-2025-04-14:northcentralus" + | "gpt-4.1-mini-2025-04-14:southcentralus" + | "gpt-4.1-mini-2025-04-14:westeurope" + | "gpt-4.1-mini-2025-04-14:germanywestcentral" + | "gpt-4.1-mini-2025-04-14:polandcentral" + | "gpt-4.1-mini-2025-04-14:spaincentral" + | "gpt-4.1-nano-2025-04-14:westus" + | "gpt-4.1-nano-2025-04-14:eastus2" + | "gpt-4.1-nano-2025-04-14:westus3" + | "gpt-4.1-nano-2025-04-14:northcentralus" + | "gpt-4.1-nano-2025-04-14:southcentralus" + | "gpt-4o-2024-11-20:swedencentral" + | "gpt-4o-2024-11-20:westus" + | "gpt-4o-2024-11-20:eastus2" + | "gpt-4o-2024-11-20:eastus" + | "gpt-4o-2024-11-20:westus3" + | "gpt-4o-2024-11-20:southcentralus" + | "gpt-4o-2024-11-20:westeurope" + | "gpt-4o-2024-11-20:germanywestcentral" + | "gpt-4o-2024-11-20:polandcentral" + | "gpt-4o-2024-11-20:spaincentral" + | "gpt-4o-2024-08-06:westus" + | "gpt-4o-2024-08-06:westus3" + | "gpt-4o-2024-08-06:eastus" + | "gpt-4o-2024-08-06:eastus2" + | "gpt-4o-2024-08-06:northcentralus" + | "gpt-4o-2024-08-06:southcentralus" + | "gpt-4o-mini-2024-07-18:westus" + | "gpt-4o-mini-2024-07-18:westus3" + | "gpt-4o-mini-2024-07-18:eastus" + | "gpt-4o-mini-2024-07-18:eastus2" + | "gpt-4o-mini-2024-07-18:northcentralus" + | "gpt-4o-mini-2024-07-18:southcentralus" + | "gpt-4o-2024-05-13:eastus2" + | "gpt-4o-2024-05-13:eastus" + | "gpt-4o-2024-05-13:northcentralus" + | "gpt-4o-2024-05-13:southcentralus" + | "gpt-4o-2024-05-13:westus3" + | "gpt-4o-2024-05-13:westus" + | "gpt-4-turbo-2024-04-09:eastus2" + | "gpt-4-0125-preview:eastus" + | "gpt-4-0125-preview:northcentralus" + | "gpt-4-0125-preview:southcentralus" + | "gpt-4-1106-preview:australiaeast" + | "gpt-4-1106-preview:canadaeast" + | "gpt-4-1106-preview:france" + | "gpt-4-1106-preview:india" + | "gpt-4-1106-preview:norway" + | "gpt-4-1106-preview:swedencentral" + | "gpt-4-1106-preview:uk" + | "gpt-4-1106-preview:westus" + | "gpt-4-1106-preview:westus3" + | "gpt-4-0613:canadaeast" + | "gpt-3.5-turbo-0125:canadaeast" + | "gpt-3.5-turbo-0125:northcentralus" + | "gpt-3.5-turbo-0125:southcentralus" + | "gpt-3.5-turbo-1106:canadaeast" + | "gpt-3.5-turbo-1106:westus" + | "gpt-4.1:australiaeast" + | "gpt-4o:australiaeast" + | "gpt-5.4-mini:australiaeast"; /** - * This is an array of structured data plan catalogs. Each entry includes a `key` and a `plan` for generating the structured data from the call. This outputs to `call.analysis.structuredDataMulti`. - * @deprecated + * This is the reasoning effort for structured output extraction. It applies to the primary extraction attempt only; the GPT-4.1 and Gemini fallbacks run without it. Other features that use this model type ignore it. + * + * Only reasoning models accept it, and each accepts only the efforts OpenAI supports for it (for example `none` and `xhigh` on gpt-5.6, `minimal` on gpt-5). When unset, OpenAI's default effort for the model applies, except on GPT-6 models, which Vapi sends with `none`. + * + * Reasoning tokens are billed as output tokens. */ - structuredDataMultiPlan?: StructuredDataMultiPlan[]; + reasoningEffort?: "minimal" | "none" | "low" | "medium" | "high" | "xhigh"; /** - * This is the plan for generating the success evaluation of the call. This outputs to `call.analysis.successEvaluation`. - * @deprecated + * This is the temperature of the model. + * @min 0 + * @max 2 */ - successEvaluationPlan?: SuccessEvaluationPlan; + temperature?: number; /** - * This is an array of outcome UUIDs to be calculated during analysis. - * The outcomes will be calculated and stored in `call.analysis.outcomes`. - * @deprecated + * This is the max tokens of the model. + * @min 50 + * @max 10000 */ - outcomeIds?: string[]; + maxTokens?: number; } -export interface TranscriptPlan { +export interface WorkflowAnthropicModel { /** - * This determines whether the transcript is stored in `call.artifact.transcript`. Defaults to true. + * These are the messages used to customize the prompt used for structured output extraction. * - * @default true - * @example true - */ - enabled?: boolean; - /** - * This is the name of the assistant in the transcript. Defaults to 'AI'. + * When provided, these messages replace the default prompts. For text extraction, message contents support LiquidJS templating with the following variables: + * - `{{transcript}}`, `{{messages}}`, or `{{messagesWithConfidence}}` to reference the conversation (one is required) + * - `{{structuredOutput.name}}`, `{{structuredOutput.description}}`, or `{{structuredOutput.schema}}` to reference the structured output definition (one is required) + * - `{{systemPrompt}}`, `{{callEndedReason}}`, `{{duration}}`, `{{startedAt}}`, `{{endedAt}}`, and any `assistantOverrides.variableValues` * - * Usage: - * - If you want to change the name of the assistant in the transcript, set this. Example, here is what the transcript would look like with `assistantName` set to 'Buyer': - * ``` - * User: Hello, how are you? - * Buyer: I'm fine. - * User: Do you want to buy a car? - * Buyer: No. - * ``` + * In structured outputs, `{{messages}}` includes conversation text and tool calls/results, but omits caller transcription-confidence fields. For text extraction, `{{messagesWithConfidence}}` includes the original message history with transcription confidence for outputs that explicitly need it. These variables also apply in structured-output schema descriptions. Audio-targeted (`messages-with-audio`) extraction ignores custom messages. Stored call artifacts and API messages retain their confidence data. `{{transcript}}` is the spoken text only, which uses significantly fewer tokens. * - * @default 'AI' + * If not provided, default system and user prompts are used. */ - assistantName?: string; + messages?: OpenAIMessage[]; + /** This is the provider of the model (`anthropic`). */ + provider: "anthropic"; /** - * This is the name of the user in the transcript. Defaults to 'User'. - * - * Usage: - * - If you want to change the name of the user in the transcript, set this. Example, here is what the transcript would look like with `userName` set to 'Seller': - * ``` - * Seller: Hello, how are you? - * AI: I'm fine. - * Seller: Do you want to buy a car? - * AI: No. - * ``` - * - * @default 'User' + * This is the specific model that will be used. + * @maxLength 100 */ - userName?: string; -} - -export interface MinMessagesCondition { + model: + | "claude-3-opus-20240229" + | "claude-3-sonnet-20240229" + | "claude-3-haiku-20240307" + | "claude-3-5-sonnet-20240620" + | "claude-3-5-sonnet-20241022" + | "claude-3-5-haiku-20241022" + | "claude-3-7-sonnet-20250219" + | "claude-opus-4-20250514" + | "claude-opus-4-5-20251101" + | "claude-opus-4-6" + | "claude-sonnet-4-20250514" + | "claude-sonnet-4-5-20250929" + | "claude-sonnet-4-6" + | "claude-sonnet-5" + | "claude-haiku-4-5-20251001" + | "claude-haiku-5-5"; /** - * This is the type discriminator for the minMessages condition. - * @example "minMessages" + * This is the optional configuration for Anthropic's thinking feature. + * + * - If provided, `maxTokens` must be greater than `thinking.budgetTokens`. */ - type: "minMessages"; + thinking?: AnthropicThinkingConfig; /** - * This is the minimum number of conversation messages required for the - * structured output to run. - * - * A count of 0 removes the runtime default minimum, so the structured output - * runs regardless of how few messages the conversation has. + * This is the temperature of the model. * @min 0 - * @example 4 + * @max 2 */ - count: number; -} - -export interface MinCallDurationCondition { + temperature?: number; /** - * This is the type discriminator for the minCallDuration condition. - * @example "minCallDuration" + * This is the max tokens of the model. + * @min 50 + * @max 10000 */ - type: "minCallDuration"; + maxTokens?: number; +} + +export interface WorkflowAnthropicBedrockModel { /** - * This is the minimum call duration in seconds required for the structured - * output to run. + * These are the messages used to customize the prompt used for structured output extraction. * - * When timestamps are unavailable (for example, chat sessions have no call - * timestamps), this check passes and does not block the structured output. - * @min 0 - * @example 10 + * When provided, these messages replace the default prompts. For text extraction, message contents support LiquidJS templating with the following variables: + * - `{{transcript}}`, `{{messages}}`, or `{{messagesWithConfidence}}` to reference the conversation (one is required) + * - `{{structuredOutput.name}}`, `{{structuredOutput.description}}`, or `{{structuredOutput.schema}}` to reference the structured output definition (one is required) + * - `{{systemPrompt}}`, `{{callEndedReason}}`, `{{duration}}`, `{{startedAt}}`, `{{endedAt}}`, and any `assistantOverrides.variableValues` + * + * In structured outputs, `{{messages}}` includes conversation text and tool calls/results, but omits caller transcription-confidence fields. For text extraction, `{{messagesWithConfidence}}` includes the original message history with transcription confidence for outputs that explicitly need it. These variables also apply in structured-output schema descriptions. Audio-targeted (`messages-with-audio`) extraction ignores custom messages. Stored call artifacts and API messages retain their confidence data. `{{transcript}}` is the spoken text only, which uses significantly fewer tokens. + * + * If not provided, default system and user prompts are used. */ - seconds: number; -} - -export interface EndedReasonCondition { + messages?: OpenAIMessage[]; + /** This is the provider of the model (`anthropic-bedrock`). */ + provider: "anthropic-bedrock"; /** - * This is the type discriminator for the endedReason condition. - * @example "endedReason" + * This is the specific model that will be used. + * @maxLength 100 */ - type: "endedReason"; + model: + | "claude-3-opus-20240229" + | "claude-3-sonnet-20240229" + | "claude-3-haiku-20240307" + | "claude-3-5-sonnet-20240620" + | "claude-3-5-sonnet-20241022" + | "claude-3-5-haiku-20241022" + | "claude-3-7-sonnet-20250219" + | "claude-opus-4-20250514" + | "claude-opus-4-5-20251101" + | "claude-opus-4-6" + | "claude-sonnet-4-20250514" + | "claude-sonnet-4-5-20250929" + | "claude-sonnet-4-6" + | "claude-haiku-4-5-20251001" + | "claude-haiku-5-5" + | "global.anthropic.claude-haiku-4-5-20251001-v1:0"; /** - * This is the membership operator applied against `values`. + * This is the optional configuration for Anthropic's thinking feature. * - * - 'oneOf': the structured output runs only if the call's ended reason is in `values`. - * - 'notOneOf': the structured output runs only if the call's ended reason is NOT in `values`. - * @example "oneOf" + * - If provided, `maxTokens` must be greater than `thinking.budgetTokens`. */ - operator: "oneOf" | "notOneOf"; + thinking?: AnthropicThinkingConfig; /** - * These are the ended reasons compared against the call's ended reason. - * - * Any string is accepted so configurations never break when new ended - * reasons are introduced. Must contain at least one value. - * @example ["customer-ended-call"] + * This is the temperature of the model. + * @min 0 + * @max 2 */ - values: string[]; -} - -export interface ComplianceOverride { + temperature?: number; /** - * Force storage for this output under HIPAA. Only enable if output contains no sensitive data. - * @example false + * This is the max tokens of the model. + * @min 50 + * @max 10000 */ - forceStoreOnHipaaEnabled?: boolean; + maxTokens?: number; } -export interface CreateStructuredOutputDTO { - /** - * This is the type of structured output. - * - * - 'ai': Uses an LLM to extract structured data from the conversation (default). - * - 'regex': Uses a regex pattern to extract data from the transcript without an LLM. - * - * Defaults to 'ai' if not specified. - * @default "ai" - */ - type?: "ai" | "regex"; +export interface WorkflowGoogleModel { /** - * This is the regex pattern to match against the transcript. - * - * Simulation evaluations use a canonical transcript built from recorded messages: - * User: and AI: dialogue, AI: tool_calls: JSON name/arguments records, and - * AI: tool_call_results: JSON results. System messages are excluded. These - * fixed labels apply even when custom artifact transcript labels are configured. - * Tool payloads participate in first-match and all-match extraction in event order. - * An empty message array falls back to the supplied transcript verbatim. - * Production-call extraction and call preview use their existing transcripts, - * so previewing the same output on a simulation's call can return a different result. - * - * Only used when type is 'regex'. Supports both raw patterns (e.g. '\d+') and - * regex literal format (e.g. '/\d+/gi'). Uses RE2 syntax for safety. + * These are the messages used to customize the prompt used for structured output extraction. * - * The result depends on the schema type: - * - boolean: true if the pattern matches, false otherwise - * - string: the first match or first capture group - * - number/integer: the first match parsed as a number - * - array: all matches - * @minLength 1 - * @maxLength 1000 - */ - regex?: string; - /** - * This is the model that will be used to extract the structured output. + * When provided, these messages replace the default prompts. For text extraction, message contents support LiquidJS templating with the following variables: + * - `{{transcript}}`, `{{messages}}`, or `{{messagesWithConfidence}}` to reference the conversation (one is required) + * - `{{structuredOutput.name}}`, `{{structuredOutput.description}}`, or `{{structuredOutput.schema}}` to reference the structured output definition (one is required) + * - `{{systemPrompt}}`, `{{callEndedReason}}`, `{{duration}}`, `{{startedAt}}`, `{{endedAt}}`, and any `assistantOverrides.variableValues` * - * To provide your own custom system and user prompts for structured output extraction, populate the messages array with your system and user messages. You can specify liquid templating in your system and user messages. - * For text extraction, you must reference 'transcript', 'messages', or 'messagesWithConfidence' with the `{{}}` syntax to access the conversation history. - * In structured outputs, `{{messages}}` includes conversation text and tool calls/results but omits caller transcription-confidence fields. Text extraction can use `{{messagesWithConfidence}}` when the output needs the original message history with transcription confidence. These variables also apply in structured-output schema descriptions. Audio-targeted (`messages-with-audio`) extraction ignores custom messages. Stored call artifacts and API messages retain their confidence data. - * Between the system or user messages, you must reference a variation of the structured output with the `{{}}` syntax to access the structured output definition. - * i.e.: - * `{{structuredOutput}}` - * `{{structuredOutput.name}}` - * `{{structuredOutput.description}}` - * `{{structuredOutput.schema}}` + * In structured outputs, `{{messages}}` includes conversation text and tool calls/results, but omits caller transcription-confidence fields. For text extraction, `{{messagesWithConfidence}}` includes the original message history with transcription confidence for outputs that explicitly need it. These variables also apply in structured-output schema descriptions. Audio-targeted (`messages-with-audio`) extraction ignores custom messages. Stored call artifacts and API messages retain their confidence data. `{{transcript}}` is the spoken text only, which uses significantly fewer tokens. * - * If model is not specified, GPT-4.1 will be used by default for extraction, utilizing default system and user prompts. - * If messages or required fields are not specified, the default system and user prompts will be used. - */ - model?: - | WorkflowOpenAIModel - | WorkflowAnthropicModel - | WorkflowAnthropicBedrockModel - | WorkflowGoogleModel - | WorkflowCustomModel; - /** - * Compliance configuration for this output. Only enable overrides if no sensitive data will be stored. - * @example {"forceStoreOnHipaaEnabled":false} + * If not provided, default system and user prompts are used. */ - compliancePlan?: ComplianceOverride; + messages?: OpenAIMessage[]; + /** This is the provider of the model (`google`). */ + provider: "google"; /** - * These are the conditions that gate the execution of this structured output. Every condition must pass for the structured output to run (AND semantics). When omitted or empty, no user-defined conditions gate this output. Send null to clear a previously saved gate. - * @example [{"type":"minMessages","count":4},{"type":"minCallDuration","seconds":10}] + * This is the name of the model. Ex. cognitivecomputations/dolphin-mixtral-8x7b + * @maxLength 100 */ - conditions?: - | (MinMessagesCondition | MinCallDurationCondition | EndedReasonCondition)[] - | null; + model: + | "gemini-3.8-flash" + | "gemini-3.5-flash" + | "gemini-3.1-flash-lite" + | "gemini-3-flash-preview" + | "gemini-2.5-pro" + | "gemini-2.5-flash" + | "gemini-2.5-flash-lite" + | "gemini-2.0-flash-thinking-exp" + | "gemini-2.0-pro-exp-02-05" + | "gemini-2.0-flash" + | "gemini-2.0-flash-lite" + | "gemini-2.0-flash-exp" + | "gemini-2.0-flash-realtime-exp" + | "gemini-1.5-flash" + | "gemini-1.5-flash-002" + | "gemini-1.5-pro" + | "gemini-1.5-pro-002" + | "gemini-1.0-pro"; /** - * This is the name of the structured output. - * @minLength 1 - * @maxLength 40 + * This is the temperature of the model. + * @min 0 + * @max 2 */ - name: string; + temperature?: number; /** - * This is the JSON Schema definition for the structured output. - * - * This is required when creating a structured output. Defines the structure and validation rules for the data that will be extracted. Supports all JSON Schema features including: - * - Objects and nested properties - * - Arrays and array validation - * - String, number, boolean, and null types - * - Enums and const values - * - Validation constraints (min/max, patterns, etc.) - * - Composition with allOf, anyOf, oneOf + * This is the max tokens of the model. + * @min 50 + * @max 10000 */ - schema: JsonSchema; + maxTokens?: number; +} + +export interface WorkflowCustomModel { /** - * This is the description of what the structured output extracts. + * These are the messages used to customize the prompt used for structured output extraction. * - * Use this to provide context about what data will be extracted and how it will be used. - */ - description?: string; - /** - * These are the assistant IDs that this structured output is linked to. + * When provided, these messages replace the default prompts. For text extraction, message contents support LiquidJS templating with the following variables: + * - `{{transcript}}`, `{{messages}}`, or `{{messagesWithConfidence}}` to reference the conversation (one is required) + * - `{{structuredOutput.name}}`, `{{structuredOutput.description}}`, or `{{structuredOutput.schema}}` to reference the structured output definition (one is required) + * - `{{systemPrompt}}`, `{{callEndedReason}}`, `{{duration}}`, `{{startedAt}}`, `{{endedAt}}`, and any `assistantOverrides.variableValues` * - * When linked to assistants, this structured output will be available for extraction during those assistant's calls. + * In structured outputs, `{{messages}}` includes conversation text and tool calls/results, but omits caller transcription-confidence fields. For text extraction, `{{messagesWithConfidence}}` includes the original message history with transcription confidence for outputs that explicitly need it. These variables also apply in structured-output schema descriptions. Audio-targeted (`messages-with-audio`) extraction ignores custom messages. Stored call artifacts and API messages retain their confidence data. `{{transcript}}` is the spoken text only, which uses significantly fewer tokens. + * + * If not provided, default system and user prompts are used. */ - assistantIds?: string[]; + messages?: OpenAIMessage[]; + /** This is the provider of the model (`custom-llm`). */ + provider: "custom-llm"; /** - * These are the workflow IDs that this structured output is linked to. + * This determines whether metadata is sent in requests to the custom provider. * - * When linked to workflows, this structured output will be available for extraction during those workflow's execution. + * - `off` will not send any metadata. payload will look like `{ messages }` + * - `variable` will send `assistant.metadata` as a variable on the payload. payload will look like `{ messages, metadata }` + * - `destructured` will send `assistant.metadata` fields directly on the payload. payload will look like `{ messages, ...metadata }` + * + * Further, `variable` and `destructured` will send `call`, `phoneNumber`, and `customer` objects in the payload. + * + * Default is `variable`. */ - workflowIds?: string[]; -} - -export interface NumberComparatorScorecardMetricCondition { - /** This is the type of the condition. Currently only 'comparator' is supported. */ - type: "comparator"; + metadataSendMode?: "off" | "variable" | "destructured"; + /** These is the URL we'll use for the OpenAI client's `baseURL`. Ex. https://openrouter.ai/api/v1 */ + url: string; + /** These are the headers we'll use for the OpenAI client's `headers`. */ + headers?: object; /** - * This is the comparator that will be used to compare the result of the structured output with the value specified. - * Only '=', '!=', '>', '<', '>=', and '<=' are supported for number conditions - * Only '=' is supported for boolean conditions. + * This sets the timeout for the connection to the custom provider without needing to stream any tokens back. Default is 20 seconds. + * @min 20 + * @max 600 */ - comparator: "=" | "!=" | ">" | "<" | ">=" | "<="; + timeoutSeconds?: number; /** - * This is the value that will be used to compare the result of the structured output with the comparator. - * If the result of the comparison is true, the points will be added to the overall score. + * This is the name of the model. Ex. cognitivecomputations/dolphin-mixtral-8x7b + * @maxLength 100 */ - value: number; + model: string; /** - * These are the points that will be added to the overall score if the condition is met. - * The points must be between 0 and 100. + * This is the temperature of the model. * @min 0 - * @max 100 - */ - points: number; -} - -export interface BooleanComparatorScorecardMetricCondition { - /** This is the type of the condition. Currently only 'comparator' is supported. */ - type: "comparator"; - /** The comparator can only be '=' for boolean conditions. */ - comparator: "="; - /** - * This is the value that will be used to compare the result of the structured output with the comparator. - * If the result of the comparison is true, the points will be added to the overall score. + * @max 2 */ - value: boolean; + temperature?: number; /** - * These are the points that will be added to the overall score if the condition is met. - * The points must be between 0 and 100. - * @min 0 - * @max 100 + * This is the max tokens of the model. + * @min 50 + * @max 10000 */ - points: number; + maxTokens?: number; } -export interface ScorecardMetric { +export interface GlobalNodePlan { /** - * These are the conditions that will be used to evaluate the scorecard. - * Each condition will have a comparator, value, and points that will be used to calculate the final score. - * The points will be added to the overall score if the condition is met. - * The overall score will be normalized to a 100 point scale to ensure uniformity across different scorecards. + * This is the flag to determine if this node is a global node + * + * @default false + * @default false */ - conditions: ( - | NumberComparatorScorecardMetricCondition - | BooleanComparatorScorecardMetricCondition - )[]; + enabled?: boolean; /** - * This is the unique identifier for the structured output that will be used to evaluate the scorecard. - * The structured output must be of type number or boolean only for now. + * This is the condition that will be checked to determine if the global node should be executed. + * + * @default '' + * @maxLength 1000 + * @default "" */ - structuredOutputId: string; + enterCondition?: string; } -export interface CreateScorecardDTO { +export interface ConversationNode { /** - * This is the name of the scorecard. It is only for user reference and will not be used for any evaluation. - * @maxLength 80 + * This is the Conversation node. This can be used to start a conversation with the customer. + * + * The flow is: + * - Workflow starts the conversation node + * - Model is active with the `prompt` and global context. + * - Model will call a tool to exit this node. + * - Workflow will extract variables from the conversation. + * - Workflow continues. */ - name?: string; + type: "conversation"; /** - * This is the description of the scorecard. It is only for user reference and will not be used for any evaluation. - * @maxLength 500 + * This is the model for the node. + * + * This overrides `workflow.model`. */ - description?: string; + model?: + | WorkflowOpenAIModel + | WorkflowAnthropicModel + | WorkflowAnthropicBedrockModel + | WorkflowGoogleModel + | WorkflowCustomModel; /** - * These are the metrics that will be used to evaluate the scorecard. - * Each metric will have a set of conditions and points that will be used to generate the score. + * This is the transcriber for the node. + * + * This overrides `workflow.transcriber`. */ - metrics: ScorecardMetric[]; + transcriber?: + | AssemblyAITranscriber + | AzureSpeechTranscriber + | CustomTranscriber + | DeepgramTranscriber + | ElevenLabsTranscriber + | GladiaTranscriber + | GoogleTranscriber + | SpeechmaticsTranscriber + | TalkscriberTranscriber + | OpenAITranscriber + | CartesiaTranscriber + | SonioxTranscriber + | XaiTranscriber + | VapiTranscriber; /** - * These are the assistant IDs that this scorecard is linked to. - * When linked to assistants, this scorecard will be available for evaluation during those assistants' calls. + * This is the voice for the node. + * + * This overrides `workflow.voice`. */ - assistantIds?: string[]; -} - -export interface ArtifactPlan { + voice?: + | AzureVoice + | CartesiaVoice + | CustomVoice + | DeepgramVoice + | ElevenLabsVoice + | HumeVoice + | LMNTVoice + | NeuphonicVoice + | OpenAIVoice + | PlayHTVoice + | WellSaidVoice + | RimeAIVoice + | SmallestAIVoice + | VapiVoice + | SesameVoice + | InworldVoice + | MinimaxVoice + | XaiVoice + | MicrosoftVoice; /** - * This determines whether assistant's calls are recorded. Defaults to true. - * - * Usage: - * - If you don't want to record the calls, set this to false. - * - If you want to record the calls when `assistant.hipaaEnabled` (deprecated) or `assistant.compliancePlan.hipaaEnabled` explicity set this to true and make sure to provide S3 or GCP credentials on the Provider Credentials page in the Dashboard. - * - * You can find the recording at `call.artifact.recordingUrl` and `call.artifact.stereoRecordingUrl` after the call is ended. + * These are the tools that the conversation node can use during the call. To use existing tools, use `toolIds`. * - * @default true - * @example true + * Both `tools` and `toolIds` can be used together. */ - recordingEnabled?: boolean; + tools?: ( + | CreateApiRequestToolDTO + | CreateBashToolDTO + | CreateCodeToolDTO + | CreateComputerToolDTO + | CreateDtmfToolDTO + | CreateEndCallToolDTO + | CreateFunctionToolDTO + | CreateGoHighLevelCalendarAvailabilityToolDTO + | CreateGoHighLevelCalendarEventCreateToolDTO + | CreateGoHighLevelContactCreateToolDTO + | CreateGoHighLevelContactGetToolDTO + | CreateGoogleCalendarCheckAvailabilityToolDTO + | CreateGoogleCalendarCreateEventToolDTO + | CreateGoogleSheetsRowAppendToolDTO + | CreateHandoffToolDTO + | CreateMcpToolDTO + | CreateQueryToolDTO + | CreateSlackSendMessageToolDTO + | CreateSmsToolDTO + | CreateTextEditorToolDTO + | CreateTransferCallToolDTO + | CreateSipRequestToolDTO + | CreateVoicemailToolDTO + )[]; /** - * This determines the format of the recording. Defaults to `wav;l16`. + * These are the tools that the conversation node can use during the call. To use transient tools, use `tools`. * - * @default 'wav;l16' + * Both `tools` and `toolIds` can be used together. */ - recordingFormat?: "wav;l16" | "mp3"; + toolIds?: string[]; + /** @maxLength 5000 */ + prompt?: string; + /** This is the plan for the global node. */ + globalNodePlan?: GlobalNodePlan; /** - * This determines whether to use custom storage (S3 or GCP) for call recordings when storage credentials are configured. - * - * When set to false, recordings will be stored on Vapi's storage instead of your custom storage, even if you have custom storage credentials configured. + * This is the plan that controls the variable extraction from the user's responses. * * Usage: - * - Set to false if you have custom storage configured but want to store recordings on Vapi's storage for this assistant. - * - Set to true (or leave unset) to use your custom storage for recordings when available. + * Use `schema` to specify what you want to extract from the user's responses. + * ```json + * { + * "schema": { + * "type": "object", + * "properties": { + * "user": { + * "type": "object", + * "properties": { + * "name": { + * "type": "string" + * }, + * "age": { + * "type": "number" + * } + * } + * } + * } + * } + * } + * ``` * - * If your organization has ZDR (zero data retention) or PCI enabled, recordings are never written to Vapi storage. In that case, false means "do not use my custom storage", so nothing is stored at all. + * This will be extracted as `{{ user.name }}` and `{{ user.age }}` respectively. * - * @default true - * @example true + * (Optional) Use `aliases` to create new variables. + * + * ```json + * { + * "aliases": [ + * { + * "key": "userAge", + * "value": "{{user.age}}" + * }, + * { + * "key": "userName", + * "value": "{{user.name}}" + * } + * ] + * } + * ``` + * + * This will be extracted as `{{ userAge }}` and `{{ userName }}` respectively. + * + * Note: The `schema` field is required for Conversation nodes if you want to extract variables from the user's responses. `aliases` is just a convenience. */ - recordingUseCustomStorageEnabled?: boolean; + variableExtractionPlan?: VariableExtractionPlan; + /** @maxLength 80 */ + name: string; + /** This is whether or not the node is the start of the workflow. */ + isStart?: boolean; + /** This is for metadata you want to store on the task. */ + metadata?: object; +} + +export interface ToolNode { /** - * This determines whether the video is recorded during the call. Defaults to false. Only relevant for `webCall` type. - * - * You can find the video recording at `call.artifact.videoRecordingUrl` after the call is ended. + * This is the Tool node. This can be used to call a tool in your workflow. * - * @default false - * @example false + * The flow is: + * - Workflow starts the tool node + * - Model is called to extract parameters needed by the tool from the conversation history + * - Tool is called with the parameters + * - Server returns a response + * - Workflow continues with the response */ - videoRecordingEnabled?: boolean; + type: "tool"; + /** This is the tool to call. To use an existing tool, send `toolId` instead. */ + tool?: + | CreateApiRequestToolDTO + | CreateBashToolDTO + | CreateCodeToolDTO + | CreateComputerToolDTO + | CreateDtmfToolDTO + | CreateEndCallToolDTO + | CreateFunctionToolDTO + | CreateGoHighLevelCalendarAvailabilityToolDTO + | CreateGoHighLevelCalendarEventCreateToolDTO + | CreateGoHighLevelContactCreateToolDTO + | CreateGoHighLevelContactGetToolDTO + | CreateGoogleCalendarCheckAvailabilityToolDTO + | CreateGoogleCalendarCreateEventToolDTO + | CreateGoogleSheetsRowAppendToolDTO + | CreateHandoffToolDTO + | CreateMcpToolDTO + | CreateQueryToolDTO + | CreateSlackSendMessageToolDTO + | CreateSmsToolDTO + | CreateTextEditorToolDTO + | CreateTransferCallToolDTO + | CreateSipRequestToolDTO + | CreateVoicemailToolDTO; + /** This is the tool to call. To use a transient tool, send `tool` instead. */ + toolId?: string; + /** @maxLength 80 */ + name: string; + /** This is whether or not the node is the start of the workflow. */ + isStart?: boolean; + /** This is for metadata you want to store on the task. */ + metadata?: object; +} + +export interface VoicemailDetectionBackoffPlan { /** - * This determines whether the artifact contains the full message history, even after handoff context engineering. Defaults to false. - * @example false + * This is the number of seconds to wait before starting the first retry attempt. + * @min 0 + * @default 5 */ - fullMessageHistoryEnabled?: boolean; + startAtSeconds?: number; /** - * This determines whether the SIP packet capture is enabled. Defaults to true. Only relevant for `phone` type calls where phone number's provider is `vapi` or `byo-phone-number`. - * - * You can find the packet capture at `call.artifact.pcapUrl` after the call is ended. - * - * @default true - * @example true + * This is the interval in seconds between retry attempts. + * @min 2.5 + * @default 5 */ - pcapEnabled?: boolean; + frequencySeconds?: number; /** - * This is the path where the SIP packet capture will be uploaded. This is only used if you have provided S3 or GCP credentials on the Provider Credentials page in the Dashboard. + * This is the maximum number of retry attempts before giving up. + * @min 1 + * @max 10 + * @default 6 + */ + maxRetries?: number; +} + +export interface GoogleVoicemailDetectionPlan { + /** + * This is the maximum duration from the start of the call that we will wait for a voicemail beep, before speaking our message * - * If credential.s3PathPrefix or credential.bucketPlan.path is set, this will append to it. + * - If we detect a voicemail beep before this, we will speak the message at that point. * - * Usage: - * - If you want to upload the packet capture to a specific path, set this to the path. Example: `/my-assistant-captures`. - * - If you want to upload the packet capture to the root of the bucket, set this to `/`. + * - Setting too low a value means that the bot will start speaking its voicemail message too early. If it does so before the actual beep, it will get cut off. You should definitely tune this to your use case. * - * @default '/' - * @example "/pcaps" + * @default 30 + * @min 0 + * @max 60 + * @min 0 + * @max 30 + * @default 30 */ - pcapS3PathPrefix?: string; + beepMaxAwaitSeconds?: number; + /** This is the provider to use for voicemail detection. */ + provider: "google"; + /** This is the backoff plan for the voicemail detection. */ + backoffPlan?: VoicemailDetectionBackoffPlan; /** - * This determines whether to use custom storage (S3 or GCP) for SIP packet captures when storage credentials are configured. - * - * When set to false, packet captures will be stored on Vapi's storage instead of your custom storage, even if you have custom storage credentials configured. + * This is the detection type to use for voicemail detection. + * - 'audio': Uses native audio models (default) + * - 'transcript': Uses ASR/transcript-based detection + * @default 'audio' (audio detection) + */ + type?: "audio" | "transcript"; +} + +export interface OpenAIVoicemailDetectionPlan { + /** + * This is the maximum duration from the start of the call that we will wait for a voicemail beep, before speaking our message * - * Usage: - * - Set to false if you have custom storage configured but want to store packet captures on Vapi's storage for this assistant. - * - Set to true (or leave unset) to use your custom storage for packet captures when available. + * - If we detect a voicemail beep before this, we will speak the message at that point. * - * If your organization has ZDR (zero data retention) or PCI enabled, packet captures are never written to Vapi storage. In that case, false means "do not use my custom storage", so nothing is stored at all. + * - Setting too low a value means that the bot will start speaking its voicemail message too early. If it does so before the actual beep, it will get cut off. You should definitely tune this to your use case. * - * @default true - * @example true + * @default 30 + * @min 0 + * @max 60 + * @min 0 + * @max 30 + * @default 30 */ - pcapUseCustomStorageEnabled?: boolean; + beepMaxAwaitSeconds?: number; + /** This is the provider to use for voicemail detection. */ + provider: "openai"; + /** This is the backoff plan for the voicemail detection. */ + backoffPlan?: VoicemailDetectionBackoffPlan; /** - * This determines whether the call logs are enabled. Defaults to true. - * - * @default true - * @example true + * This is the detection type to use for voicemail detection. + * - 'audio': Uses native audio models (default) + * - 'transcript': Uses ASR/transcript-based detection + * @default 'audio' (audio detection) */ - loggingEnabled?: boolean; + type?: "audio" | "transcript"; +} + +export interface TwilioVoicemailDetectionPlan { + /** This is the provider to use for voicemail detection. */ + provider: "twilio"; /** - * This determines whether to use custom storage (S3 or GCP) for call logs when storage credentials are configured. - * - * When set to false, logs will be stored on Vapi's storage instead of your custom storage, even if you have custom storage credentials configured. - * - * Usage: - * - Set to false if you have custom storage configured but want to store logs on Vapi's storage for this assistant. - * - Set to true (or leave unset) to use your custom storage for logs when available. + * These are the AMD messages from Twilio that are considered as voicemail. Default is ['machine_end_beep', 'machine_end_silence']. * - * If your organization has ZDR (zero data retention) or PCI enabled, logs are never written to Vapi storage. In that case, false means "do not use my custom storage", so nothing is stored at all. + * @default {Array} ['machine_end_beep', 'machine_end_silence'] + * @example ["machine_end_beep","machine_end_silence"] + */ + voicemailDetectionTypes?: + | "machine_start" + | "human" + | "fax" + | "unknown" + | "machine_end_beep" + | "machine_end_silence" + | "machine_end_other"; + /** + * This sets whether the assistant should detect voicemail. Defaults to true. * * @default true - * @example true */ - loggingUseCustomStorageEnabled?: boolean; - /** This is the plan for `call.artifact.transcript`. To disable, set `transcriptPlan.enabled` to false. */ - transcriptPlan?: TranscriptPlan; + enabled?: boolean; /** - * This is the path where the recording will be uploaded. This is only used if you have provided S3 or GCP credentials on the Provider Credentials page in the Dashboard. + * The number of seconds that Twilio should attempt to perform answering machine detection before timing out and returning AnsweredBy as unknown. Default is 30 seconds. * - * If credential.s3PathPrefix or credential.bucketPlan.path is set, this will append to it. + * Increasing this value will provide the engine more time to make a determination. This can be useful when DetectMessageEnd is provided in the MachineDetection parameter and there is an expectation of long answering machine greetings that can exceed 30 seconds. * - * Usage: - * - If you want to upload the recording to a specific path, set this to the path. Example: `/my-assistant-recordings`. - * - If you want to upload the recording to the root of the bucket, set this to `/`. + * Decreasing this value will reduce the amount of time the engine has to make a determination. This can be particularly useful when the Enable option is provided in the MachineDetection parameter and you want to limit the time for initial detection. * - * @default '/' - */ - recordingPath?: string; - /** - * This is an array of structured output IDs to be calculated during the call. - * The outputs will be extracted and stored in `call.artifact.structuredOutputs` after the call is ended. - */ - structuredOutputIds?: string[]; - /** - * This is an array of transient structured outputs to be calculated during the call. - * The outputs will be extracted and stored in `call.artifact.structuredOutputs` after the call is ended. - * Use this to provide inline structured output configurations instead of referencing existing ones via structuredOutputIds. - */ - structuredOutputs?: CreateStructuredOutputDTO[]; - /** - * This is an array of scorecard IDs that will be evaluated based on the structured outputs extracted during the call. - * The scorecards will be evaluated and the results will be stored in `call.artifact.scorecards` after the call has ended. - */ - scorecardIds?: string[]; - /** - * This is the array of scorecards that will be evaluated based on the structured outputs extracted during the call. - * The scorecards will be evaluated and the results will be stored in `call.artifact.scorecards` after the call has ended. + * Check the [Twilio docs](https://www.twilio.com/docs/voice/answering-machine-detection#optional-api-tuning-parameters) for more info. + * + * @default 30 + * @min 3 + * @max 59 */ - scorecards?: CreateScorecardDTO[]; + machineDetectionTimeout?: number; /** - * This is the path where the call logs will be uploaded. This is only used if you have provided S3 or GCP credentials on the Provider Credentials page in the Dashboard. + * The number of milliseconds that is used as the measuring stick for the length of the speech activity. Durations lower than this value will be interpreted as a human, longer as a machine. Default is 2400 milliseconds. * - * If credential.s3PathPrefix or credential.bucketPlan.path is set, this will append to it. + * Increasing this value will reduce the chance of a False Machine (detected machine, actually human) for a long human greeting (e.g., a business greeting) but increase the time it takes to detect a machine. * - * Usage: - * - If you want to upload the call logs to a specific path, set this to the path. Example: `/my-assistant-logs`. - * - If you want to upload the call logs to the root of the bucket, set this to `/`. + * Decreasing this value will reduce the chances of a False Human (detected human, actually machine) for short voicemail greetings. The value of this parameter may need to be reduced by more than 1000ms to detect very short voicemail greetings. A reduction of that significance can result in increased False Machine detections. Adjusting the MachineDetectionSpeechEndThreshold is likely the better approach for short voicemails. Decreasing MachineDetectionSpeechThreshold will also reduce the time it takes to detect a machine. * - * @default '/' + * Check the [Twilio docs](https://www.twilio.com/docs/voice/answering-machine-detection#optional-api-tuning-parameters) for more info. + * + * @default 2400 + * @min 1000 + * @max 6000 */ - loggingPath?: string; -} - -export interface StopSpeakingPlan { + machineDetectionSpeechThreshold?: number; /** - * This is the number of words that the customer has to say before the assistant will stop talking. - * - * Words like "stop", "actually", "no", etc. will always interrupt immediately regardless of this value. + * The number of milliseconds of silence after speech activity at which point the speech activity is considered complete. Default is 1200 milliseconds. * - * Words like "okay", "yeah", "right" will never interrupt. + * Increasing this value will typically be used to better address the short voicemail greeting scenarios. For short voicemails, there is typically 1000-2000ms of audio followed by 1200-2400ms of silence and then additional audio before the beep. Increasing the MachineDetectionSpeechEndThreshold to ~2500ms will treat the 1200-2400ms of silence as a gap in the greeting but not the end of the greeting and will result in a machine detection. The downsides of such a change include: + * - Increasing the delay for human detection by the amount you increase this parameter, e.g., a change of 1200ms to 2500ms increases human detection delay by 1300ms. + * - Cases where a human has two utterances separated by a period of silence (e.g. a "Hello", then 2000ms of silence, and another "Hello") may be interpreted as a machine. * - * When set to 0, `voiceSeconds` is used in addition to the transcriptions to determine the customer has started speaking. + * Decreasing this value will result in faster human detection. The consequence is that it can lead to increased False Human (detected human, actually machine) detections because a silence gap in a voicemail greeting (not necessarily just in short voicemail scenarios) can be incorrectly interpreted as the end of speech. * - * Defaults to 0. + * Check the [Twilio docs](https://www.twilio.com/docs/voice/answering-machine-detection#optional-api-tuning-parameters) for more info. * - * @default 0 - * @min 0 - * @max 10 - * @example 0 + * @default 1200 + * @min 500 + * @max 5000 */ - numWords?: number; + machineDetectionSpeechEndThreshold?: number; /** - * This is the seconds customer has to speak before the assistant stops talking. This uses the VAD (Voice Activity Detection) spike to determine if the customer has started speaking. + * The number of milliseconds of initial silence after which an unknown AnsweredBy result will be returned. Default is 5000 milliseconds. * - * Considerations: - * - A lower value might be more responsive but could potentially pick up non-speech sounds. - * - A higher value reduces false positives but might slightly delay the detection of speech onset. + * Increasing this value will result in waiting for a longer period of initial silence before returning an 'unknown' AMD result. * - * This is only used if `numWords` is set to 0. + * Decreasing this value will result in waiting for a shorter period of initial silence before returning an 'unknown' AMD result. * - * Defaults to 0.2 + * Check the [Twilio docs](https://www.twilio.com/docs/voice/answering-machine-detection#optional-api-tuning-parameters) for more info. * - * @default 0.2 - * @min 0 - * @max 0.5 - * @example 0.2 + * @default 5000 + * @min 2000 + * @max 10000 */ - voiceSeconds?: number; + machineDetectionSilenceTimeout?: number; +} + +export interface VapiVoicemailDetectionPlan { /** - * This is the seconds to wait before the assistant will start talking again after being interrupted. + * This is the maximum duration from the start of the call that we will wait for a voicemail beep, before speaking our message * - * Defaults to 1. + * - If we detect a voicemail beep before this, we will speak the message at that point. * - * @default 1 + * - Setting too low a value means that the bot will start speaking its voicemail message too early. If it does so before the actual beep, it will get cut off. You should definitely tune this to your use case. + * + * @default 30 * @min 0 - * @max 10 - * @example 1 - */ - backoffSeconds?: number; - /** - * These are the phrases that will never interrupt the assistant, even if numWords threshold is met. - * These are typically acknowledgement or backchanneling phrases. - * @default ["i understand","i see","i got it","i hear you","im listening","im with you","right","okay","ok","sure","alright","got it","understood","yeah","yes","uh-huh","mm-hmm","gotcha","mhmm","ah","yeah okay","yeah sure"] - * @example ["i understand","i see","i got it","i hear you","im listening","im with you","right","okay","ok","sure","alright","got it","understood","yeah","yes","uh-huh","mm-hmm","gotcha","mhmm","ah","yeah okay","yeah sure"] + * @max 60 + * @min 0 + * @max 30 + * @default 30 */ - acknowledgementPhrases?: string[]; + beepMaxAwaitSeconds?: number; + /** This is the provider to use for voicemail detection. */ + provider: "vapi"; + /** This is the backoff plan for the voicemail detection. */ + backoffPlan?: VoicemailDetectionBackoffPlan; /** - * These are the phrases that will always interrupt the assistant immediately, regardless of numWords. - * These are typically phrases indicating disagreement or desire to stop. - * @default ["stop","shut","up","enough","quiet","silence","but","dont","not","no","hold","wait","cut","pause","nope","nah","nevermind","never","bad","actually"] - * @example ["stop","shut","up","enough","quiet","silence","but","dont","not","no","hold","wait","cut","pause","nope","nah","nevermind","never","bad","actually"] + * This is the detection type to use for voicemail detection. + * - 'audio': Uses native audio models (default) + * - 'transcript': Uses ASR/transcript-based detection + * @default 'audio' (audio detection) */ - interruptionPhrases?: string[]; + type?: "audio" | "transcript"; } -export interface MonitorPlan { +export interface TransferHookAction { + /** This is the type of action - must be "transfer" */ + type: "transfer"; + /** This is the destination details for the transfer - can be a phone number or SIP URI */ + destination?: TransferDestinationNumber | TransferDestinationSip; +} + +export interface FunctionCallHookAction { + /** Messages spoken while the tool is running. Multiple request-start messages are variants. For request-response-delayed, same timing means variants and different timings mean staged updates. */ + messages?: ( + | ToolMessageStart + | ToolMessageComplete + | ToolMessageFailed + | ToolMessageDelayed + )[]; + /** The type of tool. "function" for Function tool. */ + type: "function"; /** - * This determines whether the assistant's calls allow live listening. Defaults to true. + * This determines if the tool is async. * - * Fetch `call.monitor.listenUrl` to get the live listening URL. + * If async, the assistant will move forward without waiting for your server to respond. This is useful if you just want to trigger something on your server. * - * @default true + * If sync, the assistant will wait for your server to respond. This is useful if want assistant to respond with the result from your server. + * + * Defaults to synchronous (`false`). * @example false */ - listenEnabled?: boolean; + async?: boolean; /** - * This enables authentication on the `call.monitor.listenUrl`. * - * If `listenAuthenticationEnabled` is `true`, the `call.monitor.listenUrl` will require an `Authorization: Bearer ` header. + * This is the server where a `tool-calls` webhook will be sent. * - * @default false - * @example false + * Notes: + * - Webhook is sent to this server when a tool call is made. + * - Webhook contains the call, assistant, and phone number objects. + * - Webhook contains the variables set on the assistant. + * - Webhook is sent to the first available URL in this order: {{tool.server.url}}, {{assistant.server.url}}, {{phoneNumber.server.url}}, {{org.server.url}}. + * - Webhook expects a response with tool call result. */ - listenAuthenticationEnabled?: boolean; + server?: Server; + /** Plan to extract variables from the tool response */ + variableExtractionPlan?: VariableExtractionPlan; + /** Static key-value pairs merged into the request body. Values support Liquid templates. */ + parameters?: ToolParameter[]; /** - * This determines whether the assistant's calls allow live control. Defaults to true. + * This is the plan to reject a tool call based on the conversation state. * - * Fetch `call.monitor.controlUrl` to get the live control URL. + * // Example 1: Reject endCall if user didn't say goodbye + * ```json + * { + * conditions: [{ + * type: 'regex', + * regex: '(?i)\\b(bye|goodbye|farewell|see you later|take care)\\b', + * target: { position: -1, role: 'user' }, + * negate: true // Reject if pattern does NOT match + * }] + * } + * ``` * - * To use, send any control message via a POST request to `call.monitor.controlUrl`. Here are the types of controls supported: https://docs.vapi.ai/api-reference/messages/client-inbound-message + * // Example 2: Reject transfer if user is actually asking a question + * ```json + * { + * conditions: [{ + * type: 'regex', + * regex: '\\?', + * target: { position: -1, role: 'user' } + * }] + * } + * ``` + * + * // Example 3: Reject transfer if user didn't mention transfer recently + * ```json + * { + * conditions: [{ + * type: 'liquid', + * liquid: `{% assign recentMessages = messages | last: 5 %} + * {% assign userMessages = recentMessages | where: 'role', 'user' %} + * {% assign mentioned = false %} + * {% for msg in userMessages %} + * {% if msg.content contains 'transfer' or msg.content contains 'connect' or msg.content contains 'speak to' %} + * {% assign mentioned = true %} + * {% break %} + * {% endif %} + * {% endfor %} + * {% if mentioned %} + * false + * {% else %} + * true + * {% endif %}` + * }] + * } + * ``` * + * // Example 4: Reject endCall if the bot is looping and trying to exit + * ```json + * { + * conditions: [{ + * type: 'liquid', + * liquid: `{% assign recentMessages = messages | last: 6 %} + * {% assign userMessages = recentMessages | where: 'role', 'user' | reverse %} + * {% if userMessages.size < 3 %} + * false + * {% else %} + * {% assign msg1 = userMessages[0].content | downcase %} + * {% assign msg2 = userMessages[1].content | downcase %} + * {% assign msg3 = userMessages[2].content | downcase %} + * {% comment %} Check for repetitive messages {% endcomment %} + * {% if msg1 == msg2 or msg1 == msg3 or msg2 == msg3 %} + * true + * {% comment %} Check for common loop phrases {% endcomment %} + * {% elsif msg1 contains 'cool thanks' or msg2 contains 'cool thanks' or msg3 contains 'cool thanks' %} + * true + * {% elsif msg1 contains 'okay thanks' or msg2 contains 'okay thanks' or msg3 contains 'okay thanks' %} + * true + * {% elsif msg1 contains 'got it' or msg2 contains 'got it' or msg3 contains 'got it' %} + * true + * {% else %} + * false + * {% endif %} + * {% endif %}` + * }] + * } + * ``` + */ + rejectionPlan?: ToolRejectionPlan; + /** This is the function definition of the tool. */ + function?: OpenAIFunction; +} + +export interface SayHookAction { + /** This is the type of action - must be "say" */ + type: "say"; + /** This is the exact message to say. When a string array is provided, one is randomly selected. */ + exact?: string | string[]; + /** + * This is the prompt for the assistant to generate a response based on existing conversation. + * Can be a string or an array of chat messages. + */ + prompt?: + | string + | ( + | SystemMessage + | UserMessage + | AssistantMessage + | ToolMessage + | DeveloperMessage + )[]; +} + +export interface MessageAddHookAction { + /** This is the type of action - must be "message.add" */ + type: "message.add"; + /** + * The message to add to the conversation in OpenAI format + * @example {"role":"system","content":"Context update from hook"} + */ + message: OpenAIMessage; + /** + * Whether to trigger an assistant response after adding the message * @default true - * @example false */ - controlEnabled?: boolean; + triggerResponseEnabled?: boolean; +} + +export interface CallHookFilter { /** - * This enables authentication on the `call.monitor.controlUrl`. + * This is the type of filter - currently only "oneOf" is supported + * @maxLength 1000 + */ + type: "oneOf"; + /** + * This is the key to filter on (e.g. "call.endedReason") + * @maxLength 1000 + */ + key: string; + /** This is the array of possible values to match against */ + oneOf: string[]; +} + +export interface CallHookCallEnding { + /** + * This is the event that triggers this hook + * @maxLength 1000 + */ + on: "call.ending"; + /** This is the set of actions to perform when the hook triggers */ + do: (ToolCallHookAction | MessageAddHookAction)[]; + /** This is the set of filters that must match for the hook to trigger */ + filters?: CallHookFilter[]; +} + +export interface CallHookAssistantSpeechInterrupted { + /** + * This is the event that triggers this hook + * @maxLength 1000 + */ + on: "assistant.speech.interrupted"; + /** This is the set of actions to perform when the hook triggers */ + do: (SayHookAction | ToolCallHookAction | MessageAddHookAction)[]; +} + +export interface CallHookCustomerSpeechInterrupted { + /** + * This is the event that triggers this hook + * @maxLength 1000 + */ + on: "customer.speech.interrupted"; + /** This is the set of actions to perform when the hook triggers */ + do: (SayHookAction | ToolCallHookAction | MessageAddHookAction)[]; +} + +export interface ToolCallHookAction { + /** This is the type of action - must be "tool" */ + type: "tool"; + /** This is the tool to call. To use an existing tool, send `toolId` instead. */ + tool?: + | CreateApiRequestToolDTO + | CreateBashToolDTO + | CreateCodeToolDTO + | CreateComputerToolDTO + | CreateDtmfToolDTO + | CreateEndCallToolDTO + | CreateFunctionToolDTO + | CreateGoHighLevelCalendarAvailabilityToolDTO + | CreateGoHighLevelCalendarEventCreateToolDTO + | CreateGoHighLevelContactCreateToolDTO + | CreateGoHighLevelContactGetToolDTO + | CreateGoogleCalendarCheckAvailabilityToolDTO + | CreateGoogleCalendarCreateEventToolDTO + | CreateGoogleSheetsRowAppendToolDTO + | CreateHandoffToolDTO + | CreateMcpToolDTO + | CreateQueryToolDTO + | CreateSlackSendMessageToolDTO + | CreateSmsToolDTO + | CreateTextEditorToolDTO + | CreateTransferCallToolDTO + | CreateSipRequestToolDTO + | CreateVoicemailToolDTO; + /** This is the tool to call. To use a transient tool, send `tool` instead. */ + toolId?: string; +} + +export interface CustomerSpeechTimeoutOptions { + /** + * This is whether the counter for hook trigger resets the user speaks. * - * If `controlAuthenticationEnabled` is `true`, the `call.monitor.controlUrl` will require an `Authorization: Bearer ` header. + * @default never + */ + triggerResetMode?: "onUserSpeech" | "never"; + /** + * This is the timeout in seconds before action is triggered. + * The clock starts when the assistant finishes speaking and remains active until the user speaks. * - * @default false - * @example false + * @default 7.5 + * @minimum 2 + * @maximum 1000 + * @min 1 + * @max 1000 */ - controlAuthenticationEnabled?: boolean; + timeoutSeconds: number; /** - * This the set of monitor ids that are attached to the assistant. - * The source of truth for the monitor ids is the assistant_monitor join table. - * This field can be used for transient assistants and to update assistants with new monitor ids. + * This is the maximum number of times the hook will trigger in a call. * - * @default [] - * @example ["123e4567-e89b-12d3-a456-426614174000"] + * @default 3 + * @min 1 + * @max 10 */ - monitorIds?: string[]; + triggerMaxCount?: number; } -export interface KeypadInputPlan { +export interface CallHookCustomerSpeechTimeout { /** - * This keeps track of whether the user has enabled keypad input. - * By default, it is off. - * - * @default false + * Must be either "customer.speech.timeout" or match the pattern "customer.speech.timeout[property=value]" + * @maxLength 1000 */ - enabled?: boolean; + on: string; + /** This is the set of actions to perform when the hook triggers */ + do: (SayHookAction | ToolCallHookAction | MessageAddHookAction)[]; + /** This is the set of filters that must match for the hook to trigger */ + options?: CustomerSpeechTimeoutOptions; /** - * This is the time in seconds to wait before processing the input. - * If the input is not received within this time, the input will be ignored. - * If set to "off", the input will be processed when the user enters a delimiter or immediately if no delimiter is used. + * This is the name of the hook, it can be set by the user to identify the hook. + * If no name is provided, the hook will be auto generated as UUID. * - * @default 2 - * @min 0 - * @max 10 + * @default UUID + * @maxLength 1000 */ - timeoutSeconds?: number; + name?: string; +} + +export interface CallHookModelResponseTimeout { /** - * This is the delimiter(s) that will be used to process the input. - * Can be '#', '*', or an empty array. + * This is the event that triggers this hook + * @maxLength 1000 */ - delimiters?: "#" | "*" | ""; + on: "model.response.timeout"; + /** This is the set of actions to perform when the hook triggers */ + do: (SayHookAction | ToolCallHookAction | MessageAddHookAction)[]; +} + +export interface AIEdgeCondition { + type: "ai"; + /** + * This is the prompt for the AI edge condition. It should evaluate to a boolean. + * @maxLength 1000 + */ + prompt: string; +} + +export interface Edge { + condition?: AIEdgeCondition; + /** @maxLength 80 */ + from: string; + /** @maxLength 80 */ + to: string; + /** This is for metadata you want to store on the edge. */ + metadata?: object; } export interface WorkflowUserEditable { @@ -13234,7 +14206,6 @@ export interface WorkflowUserEditable { | WellSaidVoice | RimeAIVoice | SmallestAIVoice - | TavusVoice | VapiVoice | SesameVoice | InworldVoice @@ -13913,7 +14884,6 @@ export interface FallbackPlan { | FallbackWellSaidVoice | FallbackRimeAIVoice | FallbackSmallestAIVoice - | FallbackTavusVoice | FallbackNeuphonicVoice | FallbackSesameVoice | FallbackInworldVoice @@ -14769,8 +15739,7 @@ export interface OpenAIVoice { provider: "openai"; /** * This is the provider-specific ID that will be used. - * Voice availability depends on the selected model. - * quartz, ripple, vesper, willow, stone, gleam, meridian, bossa, tempo, beacon, delta, cinder are only supported with GPT-Live models. + * Voice availability depends on the selected model: voices offered only by GPT-Live are rejected for other models. */ voiceId: | "alloy" @@ -14785,14 +15754,23 @@ export interface OpenAIVoice { | "ballad" | "beacon" | "bossa" + | "brise" | "cinder" | "coral" | "delta" + | "flitz" | "gleam" + | "harema" + | "juni" | "meridian" + | "nira" + | "noeul" + | "nuri" | "quartz" | "ripple" | "sage" + | "shida" + | "sillage" | "stone" | "tempo" | "verse" @@ -15135,76 +16113,6 @@ export interface SmallestAIVoice { fallbackPlan?: FallbackPlan; } -export interface TavusConversationProperties { - /** - * The maximum duration of the call in seconds. The default `maxCallDuration` is 3600 seconds (1 hour). - * Once the time limit specified by this parameter has been reached, the conversation will automatically shut down. - */ - maxCallDuration?: number; - /** The duration in seconds after which the call will be automatically shut down once the last participant leaves. */ - participantLeftTimeout?: number; - /** - * Starting from conversation creation, the duration in seconds after which the call will be automatically shut down if no participant joins the call. - * Default is 300 seconds (5 minutes). - */ - participantAbsentTimeout?: number; - /** If true, the user will be able to record the conversation. */ - enableRecording?: boolean; - /** - * If true, the user will be able to transcribe the conversation. - * You can find more instructions on displaying transcriptions if you are using your custom DailyJS components here. - * You need to have an event listener on Daily that listens for `app-messages`. - */ - enableTranscription?: boolean; - /** - * If true, the background will be replaced with a greenscreen (RGB values: `[0, 255, 155]`). - * You can use WebGL on the frontend to make the greenscreen transparent or change its color. - */ - applyGreenscreen?: boolean; - /** - * The language of the conversation. Please provide the **full language name**, not the two-letter code. - * If you are using your own TTS voice, please ensure it supports the language you provide. - * If you are using a stock replica or default persona, please note that only ElevenLabs and Cartesia supported languages are available. - * You can find a full list of supported languages for Cartesia here, for ElevenLabs here, and for PlayHT here. - */ - language?: string; - /** The name of the S3 bucket where the recording will be stored. */ - recordingS3BucketName?: string; - /** The region of the S3 bucket where the recording will be stored. */ - recordingS3BucketRegion?: string; - /** The ARN of the role that will be assumed to access the S3 bucket. */ - awsAssumeRoleArn?: string; -} - -export interface TavusVoice { - /** - * This is the flag to toggle voice caching for the assistant. - * @default true - * @example true - */ - cachingEnabled?: boolean; - /** This is the voice provider that will be used. */ - provider: "tavus"; - /** This is the provider-specific ID that will be used. */ - voiceId: "r52da2535a" | string; - /** This is the plan for chunking the model output before it is sent to the voice provider. */ - chunkPlan?: ChunkPlan; - /** This is the unique identifier for the persona that the replica will use in the conversation. */ - personaId?: string; - /** This is the url that will receive webhooks with updates regarding the conversation state. */ - callbackUrl?: string; - /** This is the name for the conversation. */ - conversationName?: string; - /** This is the context that will be appended to any context provided in the persona, if one is provided. */ - conversationalContext?: string; - /** This is the custom greeting that the replica will give once a participant joines the conversation. */ - customGreeting?: string; - /** These are optional properties used to customize the conversation. */ - properties?: TavusConversationProperties; - /** This is the plan for voice provider fallbacks in the event that the primary voice provider fails. */ - fallbackPlan?: FallbackPlan; -} - export interface VapiPronunciationDictionaryLocator { /** * The pronunciation dictionary ID @@ -16645,8 +17553,7 @@ export interface FallbackOpenAIVoice { provider: "openai"; /** * This is the provider-specific ID that will be used. - * Voice availability depends on the selected model. - * quartz, ripple, vesper, willow, stone, gleam, meridian, bossa, tempo, beacon, delta, cinder are only supported with GPT-Live models. + * Voice availability depends on the selected model: voices offered only by GPT-Live are rejected for other models. */ voiceId: | "alloy" @@ -16661,14 +17568,23 @@ export interface FallbackOpenAIVoice { | "ballad" | "beacon" | "bossa" + | "brise" | "cinder" | "coral" | "delta" + | "flitz" | "gleam" + | "harema" + | "juni" | "meridian" + | "nira" + | "noeul" + | "nuri" | "quartz" | "ripple" | "sage" + | "shida" + | "sillage" | "stone" | "tempo" | "verse" @@ -17001,33 +17917,6 @@ export interface FallbackSmallestAIVoice { chunkPlan?: ChunkPlan; } -export interface FallbackTavusVoice { - /** - * This is the flag to toggle voice caching for the assistant. - * @default true - * @example true - */ - cachingEnabled?: boolean; - /** This is the voice provider that will be used. */ - provider: "tavus"; - /** This is the provider-specific ID that will be used. */ - voiceId: "r52da2535a" | string; - /** This is the unique identifier for the persona that the replica will use in the conversation. */ - personaId?: string; - /** This is the url that will receive webhooks with updates regarding the conversation state. */ - callbackUrl?: string; - /** This is the name for the conversation. */ - conversationName?: string; - /** This is the context that will be appended to any context provided in the persona, if one is provided. */ - conversationalContext?: string; - /** This is the custom greeting that the replica will give once a participant joines the conversation. */ - customGreeting?: string; - /** These are optional properties used to customize the conversation. */ - properties?: TavusConversationProperties; - /** This is the plan for chunking the model output before it is sent to the voice provider. */ - chunkPlan?: ChunkPlan; -} - export interface FallbackVapiVoice { /** * This is the flag to toggle voice caching for the assistant. @@ -18396,631 +19285,171 @@ export interface CreateGoogleCalendarOAuth2ClientCredentialDTO { * @maxLength 40 */ name?: string; -} - -export interface CreateGoogleCalendarOAuth2AuthorizationCredentialDTO { - provider: "google.calendar.oauth2-authorization"; - /** The authorization ID for the OAuth2 authorization */ - authorizationId: string; - /** - * This is the name of credential. This is just for your reference. - * @minLength 1 - * @maxLength 40 - */ - name?: string; -} - -export interface CreateGoogleSheetsOAuth2AuthorizationCredentialDTO { - provider: "google.sheets.oauth2-authorization"; - /** The authorization ID for the OAuth2 authorization */ - authorizationId: string; - /** - * This is the name of credential. This is just for your reference. - * @minLength 1 - * @maxLength 40 - */ - name?: string; -} - -export interface CreateSlackOAuth2AuthorizationCredentialDTO { - provider: "slack.oauth2-authorization"; - /** The authorization ID for the OAuth2 authorization */ - authorizationId: string; - /** - * This is the name of credential. This is just for your reference. - * @minLength 1 - * @maxLength 40 - */ - name?: string; -} - -export interface CreateMinimaxCredentialDTO { - provider: "minimax"; - /** This is not returned in the API. */ - apiKey: string; - /** This is the Minimax Group ID. */ - groupId: string; - /** - * This is the name of credential. This is just for your reference. - * @minLength 1 - * @maxLength 40 - */ - name?: string; -} - -export interface EndpointedSpeechLowConfidenceOptions { - /** - * This is the minimum confidence threshold. - * Transcripts with confidence below this value will be discarded. - * - * @default confidenceMax - 0.2 - * @min 0 - * @max 1 - */ - confidenceMin?: number; - /** - * This is the maximum confidence threshold. - * Transcripts with confidence at or above this value will be processed normally. - * - * @default transcriber's confidenceThreshold - * @min 0 - * @max 1 - */ - confidenceMax?: number; -} - -export interface CallHookTranscriberEndpointedSpeechLowConfidence { - /** This is the set of actions to perform when the hook triggers */ - do: (SayHookAction | ToolCallHookAction | MessageAddHookAction)[]; - /** - * This is the event that triggers this hook - * @maxLength 1000 - */ - on: string; - /** This is the options for the hook including confidence thresholds */ - options?: EndpointedSpeechLowConfidenceOptions; -} - -export interface SessionCreatedHook { - /** - * This is the event that triggers this hook - * @maxLength 1000 - */ - on: "session.created"; - /** This is the set of actions to perform when the hook triggers. */ - do: ToolCallHookAction[]; - /** - * Optional name for this hook instance. - * If no name is provided, the hook will be auto generated as UUID. - * - * @default UUID - * @maxLength 1000 - */ - name?: string; -} - -export interface SQLInjectionSecurityFilter { - /** The type of security threat to filter. */ - type: "sql-injection"; -} - -export interface XSSSecurityFilter { - /** The type of security threat to filter. */ - type: "xss"; -} - -export interface SSRFSecurityFilter { - /** The type of security threat to filter. */ - type: "ssrf"; -} - -export interface RCESecurityFilter { - /** The type of security threat to filter. */ - type: "rce"; -} - -export interface PromptInjectionSecurityFilter { - /** The type of security threat to filter. */ - type: "prompt-injection"; -} - -export interface RegexSecurityFilter { - /** The type of security threat to filter. */ - type: "regex"; - /** - * The regex pattern to filter. - * @example "badword1|badword2" - */ - regex: string; -} - -export interface AssistantOverrides { - /** These are the options for the assistant's transcriber. */ - transcriber?: - | AssemblyAITranscriber - | AzureSpeechTranscriber - | CustomTranscriber - | DeepgramTranscriber - | ElevenLabsTranscriber - | GladiaTranscriber - | GoogleTranscriber - | SpeechmaticsTranscriber - | TalkscriberTranscriber - | OpenAITranscriber - | CartesiaTranscriber - | SonioxTranscriber - | XaiTranscriber - | VapiTranscriber; - /** These are the options for the assistant's LLM. */ - model?: - | AnthropicModel - | AnthropicBedrockModel - | AnyscaleModel - | CerebrasModel - | CustomLLMModel - | DeepInfraModel - | DeepSeekModel - | GoogleModel - | GroqModel - | InflectionAIModel - | MinimaxLLMModel - | OpenAIModel - | OpenRouterModel - | PerplexityAIModel - | TogetherAIModel - | XaiModel - | VapiModel; - /** These are the options for the assistant's voice. */ - voice?: - | AzureVoice - | CartesiaVoice - | CustomVoice - | DeepgramVoice - | ElevenLabsVoice - | HumeVoice - | LMNTVoice - | NeuphonicVoice - | OpenAIVoice - | PlayHTVoice - | WellSaidVoice - | RimeAIVoice - | SmallestAIVoice - | TavusVoice - | VapiVoice - | SesameVoice - | InworldVoice - | MinimaxVoice - | XaiVoice - | MicrosoftVoice; - /** - * This is the first message that the assistant will say. This can also be a URL to a containerized audio file (mp3, wav, etc.). - * - * If unspecified, assistant will wait for user to speak and use the model to respond once they speak. - * @example "Hello! How can I help you today?" - */ - firstMessage?: string; - /** @default false */ - firstMessageInterruptionsEnabled?: boolean; - /** - * This is the mode for the first message. Default is 'assistant-speaks-first'. - * - * Use: - * - 'assistant-speaks-first' to have the assistant speak first. - * - 'assistant-waits-for-user' to have the assistant wait for the user to speak first. - * - 'assistant-speaks-first-with-model-generated-message' to have the assistant speak first with a message generated by the model based on the conversation state. (`assistant.model.messages` at call start, `call.messages` at squad transfer points). - * - * @default 'assistant-speaks-first' - * @example "assistant-speaks-first" - */ - firstMessageMode?: - | "assistant-speaks-first" - | "assistant-speaks-first-with-model-generated-message" - | "assistant-waits-for-user"; - /** - * These are the settings to configure or disable voicemail detection. Alternatively, voicemail detection can be configured using the model.tools=[VoicemailTool]. - * By default, voicemail detection is disabled. - */ - voicemailDetection?: - | "off" - | GoogleVoicemailDetectionPlan - | OpenAIVoicemailDetectionPlan - | TwilioVoicemailDetectionPlan - | VapiVoicemailDetectionPlan; - /** - * These are the messages that will be sent to your Client SDKs. Default is conversation-update,function-call,hang,model-output,speech-update,status-update,transfer-update,transcript,tool-calls,user-interrupted,voice-input,workflow.node.started,assistant.started. You can check the shape of the messages in ClientMessage schema. - * @example ["conversation-update","function-call","hang","model-output","speech-update","status-update","transfer-update","transcript","tool-calls","user-interrupted","voice-input","workflow.node.started","assistant.started"] - */ - clientMessages?: - | "conversation-update" - | "assistant.speechStarted" - | "function-call" - | "function-call-result" - | "hang" - | "language-changed" - | "metadata" - | "model-output" - | "speech-update" - | "status-update" - | "transcript" - | "tool-calls" - | "tool-calls-result" - | "tool.completed" - | "transfer-update" - | "user-interrupted" - | "voice-input" - | "workflow.node.started" - | "assistant.started"; - /** - * 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,assistant.started. You can check the shape of the messages in ServerMessage schema. - * @example ["conversation-update","end-of-call-report","function-call","hang","speech-update","status-update","tool-calls","transfer-destination-request","handoff-destination-request","user-interrupted","assistant.started"] - */ - serverMessages?: - | "assistant.started" - | "assistant.speechStarted" - | "conversation-update" - | "end-of-call-report" - | "function-call" - | "hang" - | "language-changed" - | "language-change-detected" - | "model-output" - | "phone-call-control" - | "speech-update" - | "status-update" - | "transcript" - | "transcript[transcriptType='final']" - | "tool-calls" - | "transfer-destination-request" - | "handoff-destination-request" - | "transfer-update" - | "user-interrupted" - | "voice-input" - | "chat.created" - | "chat.deleted" - | "session.created" - | "session.updated" - | "session.deleted" - | "call.deleted" - | "call.delete.failed" - | "call.artifact.upload"; - /** - * This is the maximum number of seconds that the call will last. When the call reaches this duration, it will be ended. - * - * @default 600 (10 minutes) - * @min 10 - * @max 43200 - * @example 600 - */ - maxDurationSeconds?: number; - /** - * This is the background sound in the call. Default for phone calls is 'office' and default for web calls is 'off'. - * You can also provide a custom sound by providing a URL to an audio file. - */ - backgroundSound?: "off" | "office" | string; +} + +export interface CreateGoogleCalendarOAuth2AuthorizationCredentialDTO { + provider: "google.calendar.oauth2-authorization"; + /** The authorization ID for the OAuth2 authorization */ + authorizationId: string; /** - * This determines whether the model's output is used in conversation history rather than the transcription of assistant's speech. - * - * @default false - * @example false + * This is the name of credential. This is just for your reference. + * @minLength 1 + * @maxLength 40 */ - modelOutputInMessagesEnabled?: boolean; - /** These are the configurations to be passed to the transport providers of assistant's calls, like Twilio. You can store multiple configurations for different transport providers. For a call, only the configuration matching the call transport provider is used. */ - transportConfigurations?: TransportConfigurationTwilio[]; + name?: string; +} + +export interface CreateGoogleSheetsOAuth2AuthorizationCredentialDTO { + provider: "google.sheets.oauth2-authorization"; + /** The authorization ID for the OAuth2 authorization */ + authorizationId: string; /** - * This is the plan for observability of assistant's calls. - * - * Currently, only Langfuse is supported. + * This is the name of credential. This is just for your reference. + * @minLength 1 + * @maxLength 40 */ - observabilityPlan?: LangfuseObservabilityPlan; - /** These are dynamic credentials that will be used for the assistant calls. By default, all the credentials are available for use in the call but you can supplement an additional credentials using this. Dynamic credentials override existing credentials. */ - credentials?: ( - | ({ - provider: "11labs"; - } & CreateElevenLabsCredentialDTO) - | ({ - provider: "anthropic"; - } & CreateAnthropicCredentialDTO) - | ({ - provider: "anthropic-bedrock"; - } & CreateAnthropicBedrockCredentialDTO) - | ({ - provider: "anyscale"; - } & CreateAnyscaleCredentialDTO) - | ({ - provider: "assembly-ai"; - } & CreateAssemblyAICredentialDTO) - | ({ - provider: "azure-openai"; - } & CreateAzureOpenAICredentialDTO) - | ({ - provider: "azure"; - } & CreateAzureCredentialDTO) - | ({ - provider: "byo-sip-trunk"; - } & CreateByoSipTrunkCredentialDTO) - | ({ - provider: "cartesia"; - } & CreateCartesiaCredentialDTO) - | ({ - provider: "cerebras"; - } & CreateCerebrasCredentialDTO) - | ({ - provider: "cloudflare"; - } & CreateCloudflareCredentialDTO) - | ({ - provider: "custom-llm"; - } & CreateCustomLLMCredentialDTO) - | ({ - provider: "deepgram"; - } & CreateDeepgramCredentialDTO) - | ({ - provider: "deepinfra"; - } & CreateDeepInfraCredentialDTO) - | ({ - provider: "deep-seek"; - } & CreateDeepSeekCredentialDTO) - | ({ - provider: "gcp"; - } & CreateGcpCredentialDTO) - | ({ - provider: "gladia"; - } & CreateGladiaCredentialDTO) - | ({ - provider: "gohighlevel"; - } & CreateGoHighLevelCredentialDTO) - | ({ - provider: "google"; - } & CreateGoogleCredentialDTO) - | ({ - provider: "groq"; - } & CreateGroqCredentialDTO) - | ({ - provider: "inflection-ai"; - } & CreateInflectionAICredentialDTO) - | ({ - provider: "langfuse"; - } & CreateLangfuseCredentialDTO) - | ({ - provider: "lmnt"; - } & CreateLmntCredentialDTO) - | ({ - provider: "make"; - } & CreateMakeCredentialDTO) - | ({ - provider: "openai"; - } & CreateOpenAICredentialDTO) - | ({ - provider: "openrouter"; - } & CreateOpenRouterCredentialDTO) - | ({ - provider: "perplexity-ai"; - } & CreatePerplexityAICredentialDTO) - | ({ - provider: "playht"; - } & CreatePlayHTCredentialDTO) - | ({ - provider: "rime-ai"; - } & CreateRimeAICredentialDTO) - | ({ - provider: "runpod"; - } & CreateRunpodCredentialDTO) - | ({ - provider: "s3"; - } & CreateS3CredentialDTO) - | ({ - provider: "s3-compatible"; - } & CreateS3CompatibleCredentialDTO) - | ({ - provider: "supabase"; - } & CreateSupabaseCredentialDTO) - | ({ - provider: "smallest-ai"; - } & CreateSmallestAICredentialDTO) - | ({ - provider: "tavus"; - } & CreateTavusCredentialDTO) - | ({ - provider: "together-ai"; - } & CreateTogetherAICredentialDTO) - | ({ - provider: "twilio"; - } & CreateTwilioCredentialDTO) - | ({ - provider: "vonage"; - } & CreateVonageCredentialDTO) - | ({ - provider: "webhook"; - } & CreateWebhookCredentialDTO) - | ({ - provider: "custom-credential"; - } & CreateCustomCredentialDTO) - | ({ - provider: "xai"; - } & CreateXAiCredentialDTO) - | ({ - provider: "microsoft"; - } & CreateMicrosoftCredentialDTO) - | ({ - provider: "neuphonic"; - } & CreateNeuphonicCredentialDTO) - | ({ - provider: "hume"; - } & CreateHumeCredentialDTO) - | ({ - provider: "mistral"; - } & CreateMistralCredentialDTO) - | ({ - provider: "speechmatics"; - } & CreateSpeechmaticsCredentialDTO) - | ({ - provider: "soniox"; - } & CreateSonioxCredentialDTO) - | ({ - provider: "google.calendar.oauth2-client"; - } & CreateGoogleCalendarOAuth2ClientCredentialDTO) - | ({ - provider: "google.calendar.oauth2-authorization"; - } & CreateGoogleCalendarOAuth2AuthorizationCredentialDTO) - | ({ - provider: "google.sheets.oauth2-authorization"; - } & CreateGoogleSheetsOAuth2AuthorizationCredentialDTO) - | ({ - provider: "slack.oauth2-authorization"; - } & CreateSlackOAuth2AuthorizationCredentialDTO) - | ({ - provider: "ghl.oauth2-authorization"; - } & CreateGoHighLevelMCPCredentialDTO) - | ({ - provider: "inworld"; - } & CreateInworldCredentialDTO) - | ({ - provider: "minimax"; - } & CreateMinimaxCredentialDTO) - | ({ - provider: "wellsaid"; - } & CreateWellSaidCredentialDTO) - | ({ - provider: "email"; - } & CreateEmailCredentialDTO) - | ({ - provider: "slack-webhook"; - } & CreateSlackWebhookCredentialDTO) - )[]; - /** This is a set of actions that will be performed on certain events. */ - hooks?: ( - | CallHookCallEnding - | CallHookAssistantSpeechInterrupted - | CallHookCustomerSpeechInterrupted - | CallHookCustomerSpeechTimeout - | SessionCreatedHook - )[]; - "tools:append"?: ( - | CreateApiRequestToolDTO - | CreateBashToolDTO - | CreateCodeToolDTO - | CreateComputerToolDTO - | CreateDtmfToolDTO - | CreateEndCallToolDTO - | CreateFunctionToolDTO - | CreateGoHighLevelCalendarAvailabilityToolDTO - | CreateGoHighLevelCalendarEventCreateToolDTO - | CreateGoHighLevelContactCreateToolDTO - | CreateGoHighLevelContactGetToolDTO - | CreateGoogleCalendarCheckAvailabilityToolDTO - | CreateGoogleCalendarCreateEventToolDTO - | CreateGoogleSheetsRowAppendToolDTO - | CreateHandoffToolDTO - | CreateMcpToolDTO - | CreateQueryToolDTO - | CreateSlackSendMessageToolDTO - | CreateSmsToolDTO - | CreateTextEditorToolDTO - | CreateTransferCallToolDTO - | CreateSipRequestToolDTO - | CreateVoicemailToolDTO - )[]; + name?: string; +} + +export interface CreateSlackOAuth2AuthorizationCredentialDTO { + provider: "slack.oauth2-authorization"; + /** The authorization ID for the OAuth2 authorization */ + authorizationId: string; /** - * These are values that will be used to replace the template variables in the assistant messages and other text-based fields. - * This uses LiquidJS syntax. https://liquidjs.com/tutorials/intro-to-liquid.html - * - * So for example, `{{ name }}` will be replaced with the value of `name` in `variableValues`. - * `{{"now" | date: "%b %d, %Y, %I:%M %p", "America/New_York"}}` will be replaced with the current date and time in New York. - * Some VAPI reserved defaults: - * - *customer* - the customer object + * This is the name of credential. This is just for your reference. + * @minLength 1 + * @maxLength 40 */ - variableValues?: object; + name?: string; +} + +export interface CreateMinimaxCredentialDTO { + provider: "minimax"; + /** This is not returned in the API. */ + apiKey: string; + /** This is the Minimax Group ID. */ + groupId: string; /** - * This is the name of the assistant. - * - * This is required when you want to transfer between assistants in a call. + * This is the name of credential. This is just for your reference. + * @minLength 1 * @maxLength 40 */ name?: string; +} + +export interface EndpointedSpeechLowConfidenceOptions { /** - * This is the message that the assistant will say if the call is forwarded to voicemail. + * This is the minimum confidence threshold. + * Transcripts with confidence below this value will be discarded. * - * If unspecified, it will hang up. - * @maxLength 1000 + * @default confidenceMax - 0.2 + * @min 0 + * @max 1 */ - voicemailMessage?: string; + confidenceMin?: number; /** - * This is the message that the assistant will say if it ends the call. + * This is the maximum confidence threshold. + * Transcripts with confidence at or above this value will be processed normally. * - * If unspecified, it will hang up without saying anything. - * @maxLength 1000 + * @default transcriber's confidenceThreshold + * @min 0 + * @max 1 */ - endCallMessage?: string; - /** This list contains phrases that, if spoken by the assistant, will trigger the call to be hung up. Case insensitive. */ - endCallPhrases?: string[]; - compliancePlan?: CompliancePlan; - /** This is for metadata you want to store on the assistant. */ - metadata?: object; + confidenceMax?: number; +} + +export interface CallHookTranscriberEndpointedSpeechLowConfidence { + /** This is the set of actions to perform when the hook triggers */ + do: (SayHookAction | ToolCallHookAction | MessageAddHookAction)[]; /** - * This enables filtering of noise and background speech while the user is talking. - * - * Features: - * - Smart denoising using Krisp - * - Fourier denoising - * - * Smart denoising can be combined with or used independently of Fourier denoising. - * - * Order of precedence: - * - Smart denoising - * - Fourier denoising + * This is the event that triggers this hook + * @maxLength 1000 */ - backgroundSpeechDenoisingPlan?: BackgroundSpeechDenoisingPlan; + on: string; + /** This is the options for the hook including confidence thresholds */ + options?: EndpointedSpeechLowConfidenceOptions; +} + +export interface SessionCreatedHook { /** - * This is the plan for analysis of assistant's calls. Stored in `call.analysis`. - * @deprecated + * This is the event that triggers this hook + * @maxLength 1000 */ - analysisPlan?: AnalysisPlan; - /** This is the plan for artifacts generated during assistant's calls. Stored in `call.artifact`. */ - artifactPlan?: ArtifactPlan; + on: "session.created"; + /** This is the set of actions to perform when the hook triggers. */ + do: ToolCallHookAction[]; /** - * This is the plan for when the assistant should start talking. + * Optional name for this hook instance. + * If no name is provided, the hook will be auto generated as UUID. * - * You should configure this if you're running into these issues: - * - The assistant is too slow to start talking after the customer is done speaking. - * - The assistant is too fast to start talking after the customer is done speaking. - * - The assistant is so fast that it's actually interrupting the customer. + * @default UUID + * @maxLength 1000 */ - startSpeakingPlan?: StartSpeakingPlan; + name?: string; +} + +export interface SQLInjectionSecurityFilter { + /** The type of security threat to filter. */ + type: "sql-injection"; +} + +export interface XSSSecurityFilter { + /** The type of security threat to filter. */ + type: "xss"; +} + +export interface SSRFSecurityFilter { + /** The type of security threat to filter. */ + type: "ssrf"; +} + +export interface RCESecurityFilter { + /** The type of security threat to filter. */ + type: "rce"; +} + +export interface PromptInjectionSecurityFilter { + /** The type of security threat to filter. */ + type: "prompt-injection"; +} + +export interface RegexSecurityFilter { + /** The type of security threat to filter. */ + type: "regex"; /** - * This is the plan for when assistant should stop talking on customer interruption. - * - * You should configure this if you're running into these issues: - * - The assistant is too slow to recognize customer's interruption. - * - The assistant is too fast to recognize customer's interruption. - * - The assistant is getting interrupted by phrases that are just acknowledgments. - * - The assistant is getting interrupted by background noises. - * - The assistant is not properly stopping -- it starts talking right after getting interrupted. + * The regex pattern to filter. + * @example "badword1|badword2" */ - stopSpeakingPlan?: StopSpeakingPlan; + regex: string; +} + +export interface GuardrailFailurePolicy { + type: "end-call"; +} + +export interface GuardrailPlan { + /** Explicit fallback for evaluator failures and exhausted recovery. */ + failurePolicy?: GuardrailFailurePolicy; /** - * This is the plan for real-time monitoring of the assistant's calls. - * - * Usage: - * - To enable live listening of the assistant's calls, set `monitorPlan.listenEnabled` to `true`. - * - To enable live control of the assistant's calls, set `monitorPlan.controlEnabled` to `true`. - * - To attach monitors to the assistant, set `monitorPlan.monitorIds` to the set of monitor ids. + * Effective default is true; omission on PATCH preserves the saved value. + * @default true */ - monitorPlan?: MonitorPlan; - /** These are the credentials that will be used for the assistant calls. By default, all the credentials are available for use in the call but you can provide a subset using this. */ - credentialIds?: string[]; + enabled?: boolean; + /** Omission preserves direct selections; [] clears local selections. */ + guardrailIds?: string[]; + /** Omission preserves pack selections; [] clears local selections. */ + packIds?: string[]; /** - * This is where Vapi will send webhooks. You can find all webhooks available along with their shape in ServerMessage schema. - * - * The order of precedence is: - * - * 1. assistant.server.url - * 2. phoneNumber.serverUrl - * 3. org.serverUrl + * Legacy inline rules retained separately from shared selections. + * @maxLength 10000 + * @maxItems 100 */ - server?: Server; - keypadInputPlan?: KeypadInputPlan; + guardrails?: string[]; } export interface CreateAssistantDTO { + /** Local settings and selections. Omitted ID arrays preserve selections; [] clears that kind. */ + guardrailPlan?: GuardrailPlan | null; /** These are the options for the assistant's transcriber. */ transcriber?: | AssemblyAITranscriber @@ -19071,7 +19500,6 @@ export interface CreateAssistantDTO { | WellSaidVoice | RimeAIVoice | SmallestAIVoice - | TavusVoice | VapiVoice | SesameVoice | InworldVoice @@ -19516,6 +19944,8 @@ export interface ModelDeprecationNotice { } export interface Assistant { + /** Local settings and selections. Omitted ID arrays preserve selections; [] clears that kind. */ + guardrailPlan?: GuardrailPlan | null; /** These are the options for the assistant's transcriber. */ transcriber?: | AssemblyAITranscriber @@ -19566,7 +19996,6 @@ export interface Assistant { | WellSaidVoice | RimeAIVoice | SmallestAIVoice - | TavusVoice | VapiVoice | SesameVoice | InworldVoice @@ -20042,6 +20471,8 @@ export interface AssistantPaginatedResponse { } export interface AssistantDraft { + /** Local settings and selections. Omitted ID arrays preserve selections; [] clears that kind. */ + guardrailPlan?: GuardrailPlan | null; /** These are the options for the assistant's transcriber. */ transcriber?: | AssemblyAITranscriber @@ -20092,7 +20523,6 @@ export interface AssistantDraft { | WellSaidVoice | RimeAIVoice | SmallestAIVoice - | TavusVoice | VapiVoice | SesameVoice | InworldVoice @@ -20535,6 +20965,8 @@ export interface LegacyAssistantVersionPaginatedResponse { } export interface AssistantVersion { + /** Local settings and selections. Omitted ID arrays preserve selections; [] clears that kind. */ + guardrailPlan?: GuardrailPlan | null; /** These are the options for the assistant's transcriber. */ transcriber?: | AssemblyAITranscriber @@ -20585,7 +21017,6 @@ export interface AssistantVersion { | WellSaidVoice | RimeAIVoice | SmallestAIVoice - | TavusVoice | VapiVoice | SesameVoice | InworldVoice @@ -21061,6 +21492,8 @@ export interface UpdateAssistantVersionMetadataDTO { } export interface CreateAssistantDraftDTO { + /** Local settings and selections. Omitted ID arrays preserve selections; [] clears that kind. */ + guardrailPlan?: GuardrailPlan | null; /** These are the options for the assistant's transcriber. */ transcriber?: | AssemblyAITranscriber @@ -21111,7 +21544,6 @@ export interface CreateAssistantDraftDTO { | WellSaidVoice | RimeAIVoice | SmallestAIVoice - | TavusVoice | VapiVoice | SesameVoice | InworldVoice @@ -21526,6 +21958,8 @@ export interface AssistantDraftConflictResponseDTO { } export interface UpdateAssistantDraftDTO { + /** Local settings and selections. Omitted ID arrays preserve selections; [] clears that kind. */ + guardrailPlan?: GuardrailPlan | null; /** These are the options for the assistant's transcriber. */ transcriber?: | AssemblyAITranscriber @@ -21576,7 +22010,6 @@ export interface UpdateAssistantDraftDTO { | WellSaidVoice | RimeAIVoice | SmallestAIVoice - | TavusVoice | VapiVoice | SesameVoice | InworldVoice @@ -21977,6 +22410,8 @@ export interface UpdateAssistantDraftDTO { } export interface UpdateAssistantDTO { + /** Local settings and selections. Omitted ID arrays preserve selections; [] clears that kind. */ + guardrailPlan?: GuardrailPlan | null; /** These are the options for the assistant's transcriber. */ transcriber?: | AssemblyAITranscriber @@ -22027,7 +22462,6 @@ export interface UpdateAssistantDTO { | WellSaidVoice | RimeAIVoice | SmallestAIVoice - | TavusVoice | VapiVoice | SesameVoice | InworldVoice @@ -22615,7 +23049,6 @@ export interface Workflow { | WellSaidVoice | RimeAIVoice | SmallestAIVoice - | TavusVoice | VapiVoice | SesameVoice | InworldVoice @@ -22966,7 +23399,6 @@ export interface CreateWorkflowDTO { | WellSaidVoice | RimeAIVoice | SmallestAIVoice - | TavusVoice | VapiVoice | SesameVoice | InworldVoice @@ -23311,7 +23743,6 @@ export interface UpdateWorkflowDTO { | WellSaidVoice | RimeAIVoice | SmallestAIVoice - | TavusVoice | VapiVoice | SesameVoice | InworldVoice @@ -23978,6 +24409,8 @@ export interface StructuredOutputCostBreakdown { completionTokens: number; /** This is the number of cached prompt tokens used to evaluate this structured output. This is a subset of `promptTokens`, not an addition to it. */ cachedPromptTokens?: number; + /** This is the number of reasoning tokens the model generated for this structured output. This is a subset of `completionTokens`, not an addition to it: reasoning tokens are already billed at the output-token rate, so this is for visibility only and does not affect `cost`. */ + reasoningTokens?: number; } export interface AnalysisCost { @@ -23997,6 +24430,8 @@ export interface AnalysisCost { completionTokens: number; /** This is the number of cached prompt tokens used in the analysis. This is only applicable to certain providers (e.g., OpenAI, Azure OpenAI) that support prompt caching. Cached tokens are billed at a discounted rate. */ cachedPromptTokens?: number; + /** This is the number of reasoning tokens generated in the analysis, reported only by reasoning models (e.g., GPT-5) on providers that report them. This is a subset of `completionTokens`, not an addition to it: reasoning tokens are already billed at the output-token rate, so this is for visibility only and does not affect `cost`. */ + reasoningTokens?: number; /** * This is the per-structured-output breakdown of this cost. The `cost`, `promptTokens`, `completionTokens` and `cachedPromptTokens` above are the sums of these rows. * @@ -24074,6 +24509,10 @@ export interface VapiWebCallTransport { * recording automatically server-side, which is more reliable than the * client starting it after joining. Set by the server; only present when * video recording is enabled. + * + * With `videoRecordingStartMode: 'server'`, joining with the token doesn't + * start the recording: Vapi starts it once the user joins, and the client + * must not start it either. */ callToken?: string; /** This is the URL of the web call. */ @@ -24715,6 +25154,11 @@ export interface Call { | "deletion-failed"; /** This is the explanation for how the call ended. */ endedReason?: + | "call.in-progress.error-vapifault-guardrail-evaluation-failed" + | "call.in-progress.error-vapifault-guardrail-playback-timeout" + | "call.in-progress.guardrail-blocked" + | "call.in-progress.error-vapifault-call-start-failed" + | "call.in-progress.error-vapifault-assistant-handoff-start-failed" | "call-start-error-neither-assistant-nor-server-set" | "assistant-request-failed" | "assistant-request-returned-error" @@ -25413,7 +25857,7 @@ export interface Call { * - Squad, use `squad` * - Workflow, use `workflow` */ - assistant?: CreateAssistantDTO; + assistant?: TransientAssistantDTO; /** These are the overrides for the `assistant` or `assistantId`'s settings and template variables. */ assistantOverrides?: AssistantOverrides; /** @@ -25768,7 +26212,7 @@ export interface CreateCallDTO { * - Squad, use `squad` * - Workflow, use `workflow` */ - assistant?: CreateAssistantDTO; + assistant?: TransientAssistantDTO; /** These are the overrides for the `assistant` or `assistantId`'s settings and template variables. */ assistantOverrides?: AssistantOverrides; /** @@ -25913,7 +26357,7 @@ export interface CreateOutboundCallDTO { * - Squad, use `squad` * - Workflow, use `workflow` */ - assistant?: CreateAssistantDTO; + assistant?: TransientAssistantDTO; /** These are the overrides for the `assistant` or `assistantId`'s settings and template variables. */ assistantOverrides?: AssistantOverrides; /** @@ -25998,6 +26442,23 @@ export interface CreateWebCallDTO { squadVersion?: string | null; /** @default true */ roomDeleteOnUserLeaveEnabled?: boolean; + /** + * This determines who starts the video recording. Only applies when video + * recording is enabled (`artifactPlan.videoRecordingEnabled`). + * + * - `client`: the web client starts the recording when it joins. + * - `server`: Vapi starts the recording once when the user first joins, so a + * weak client connection can't stop it from starting. The returned + * `transport.callToken` doesn't start the recording, and the client should + * not start it either. If Vapi can't set up the server-side start, no token + * is returned. If the start itself fails, the client is told during the + * call. + * + * Defaults to `client`. + * @default "client" + * @example "server" + */ + videoRecordingStartMode?: "client" | "server"; /** * This is the assistant ID that will be used for the call. To use a transient assistant, use `assistant` instead. * @@ -26015,7 +26476,7 @@ export interface CreateWebCallDTO { * - Squad, use `squad` * - Workflow, use `workflow` */ - assistant?: CreateAssistantDTO; + assistant?: TransientAssistantDTO; /** These are the overrides for the `assistant` or `assistantId`'s settings and template variables. */ assistantOverrides?: AssistantOverrides; /** @@ -26183,7 +26644,7 @@ export interface Chat { /** This is the assistant that will be used for the chat. To use an existing assistant, use `assistantId` instead. */ assistantId?: string; /** This is the assistant that will be used for the chat. To use an existing assistant, use `assistantId` instead. */ - assistant?: CreateAssistantDTO; + assistant?: TransientAssistantDTO; /** * These are the variable values that will be used to replace template variables in the assistant messages. * Only variable substitution is supported in chat contexts - other assistant properties cannot be overridden. @@ -26305,7 +26766,7 @@ export interface CreateChatDTO { /** This is the assistant that will be used for the chat. To use an existing assistant, use `assistantId` instead. */ assistantId?: string; /** This is the assistant that will be used for the chat. To use an existing assistant, use `assistantId` instead. */ - assistant?: CreateAssistantDTO; + assistant?: TransientAssistantDTO; /** * These are the variable values that will be used to replace template variables in the assistant messages. * Only variable substitution is supported in chat contexts - other assistant properties cannot be overridden. @@ -26462,7 +26923,7 @@ export interface OpenAIResponsesRequest { /** This is the assistant that will be used for the chat. To use an existing assistant, use `assistantId` instead. */ assistantId?: string; /** This is the assistant that will be used for the chat. To use an existing assistant, use `assistantId` instead. */ - assistant?: CreateAssistantDTO; + assistant?: TransientAssistantDTO; /** * These are the variable values that will be used to replace template variables in the assistant messages. * Only variable substitution is supported in chat contexts - other assistant properties cannot be overridden. @@ -26580,7 +27041,7 @@ export interface CreateWebChatDTO { /** This is the assistant ID to use for this chat. To use a transient assistant, use `assistant` instead. */ assistantId?: string; /** This is the transient assistant configuration for this chat. To use an existing assistant, use `assistantId` instead. */ - assistant?: CreateAssistantDTO; + assistant?: TransientAssistantDTO; /** * This is the ID of the session that will be used for the chat. * If provided, the conversation will continue from the previous state. @@ -26651,7 +27112,7 @@ export interface OpenAIWebChatRequest { /** This is the assistant ID to use for this chat. To use a transient assistant, use `assistant` instead. */ assistantId?: string; /** This is the transient assistant configuration for this chat. To use an existing assistant, use `assistantId` instead. */ - assistant?: CreateAssistantDTO; + assistant?: TransientAssistantDTO; /** * This is the ID of the session that will be used for the chat. * If provided, the conversation will continue from the previous state. @@ -27348,7 +27809,7 @@ export interface Session { * This is the assistant configuration for this session. Use this when creating a new assistant configuration. * If assistantId is provided, this will be ignored. */ - assistant?: CreateAssistantDTO; + assistant?: TransientAssistantDTO; /** * These are the overrides for the assistant configuration. * Use this to provide variable values and other overrides when using assistantId. @@ -27409,7 +27870,7 @@ export interface CreateSessionDTO { * This is the assistant configuration for this session. Use this when creating a new assistant configuration. * If assistantId is provided, this will be ignored. */ - assistant?: CreateAssistantDTO; + assistant?: TransientAssistantDTO; /** * These are the overrides for the assistant configuration. * Use this to provide variable values and other overrides when using assistantId. @@ -38254,7 +38715,7 @@ export interface TesterPlan { * * Make sure to write a detailed system prompt for a test assistant, and use the {{test.script}} variable to access the test script. */ - assistant?: CreateAssistantDTO; + assistant?: TransientAssistantDTO; /** * Pass an assistant id that can be access * @@ -38703,7 +39164,7 @@ export interface CreatePersonalityDTO { * This is the full assistant configuration for this personality. * It defines the tester's voice, model, behavior via system prompt, and other settings. */ - assistant: CreateAssistantDTO; + assistant: TransientAssistantDTO; /** * Optional folder path for organizing personalities. * Supports up to 3 levels (e.g., "dept/feature/variant"). @@ -38745,7 +39206,7 @@ export interface Personality { * This is the full assistant configuration for this personality. * It defines the tester's voice, model, behavior via system prompt, and other settings. */ - assistant: CreateAssistantDTO; + assistant: TransientAssistantDTO; /** * Optional folder path for organizing personalities. * Supports up to 3 levels (e.g., "dept/feature/variant"). @@ -38763,7 +39224,7 @@ export interface UpdatePersonalityDTO { */ name?: string; /** Complete assistant replacement. Omitted credentials and redacted server secrets are preserved when their endpoint URL is unchanged. Send credentials: [] to clear credentials; omit a server container to remove it. */ - assistant?: CreateAssistantDTO; + assistant?: TransientAssistantDTO; /** * Optional folder path for organizing personalities. * Supports up to 3 levels (e.g., "dept/feature/variant"). @@ -39120,7 +39581,7 @@ export interface SimulationRunTargetAssistant { */ assistantId?: string; /** Inline assistant configuration to test against. Cannot be combined with assistantId. */ - assistant?: CreateAssistantDTO; + assistant?: TransientAssistantDTO; } export interface SimulationRunTargetSquad { @@ -39141,6 +39602,11 @@ export interface SimulationRunTransportConfiguration { } export interface CreateSimulationRunDTO { + /** + * Generate directly attached target structured outputs. Default false. Enabled extraction may incur additional model charges. + * @default false + */ + includeTargetStructuredOutputs?: boolean; /** Array of simulations and/or suites to run */ simulations: (SimulationRunSimulationEntry | SimulationRunSuiteEntry)[]; /** Target to test against */ @@ -39217,6 +39683,11 @@ export interface CreateSimulationRunResponse { updatedAt: string; /** Aggregate counts of run items by status */ itemCounts?: SimulationRunItemCounts; + /** + * Generate directly attached target structured outputs. Default false. Enabled extraction may incur additional model charges. + * @default false + */ + includeTargetStructuredOutputs?: boolean; /** Array of simulations and/or suites to run */ simulations: (SimulationRunSimulationEntry | SimulationRunSuiteEntry)[]; /** Target to test against */ @@ -39296,77 +39767,87 @@ export interface SimulationRun { updatedAt: string; /** Aggregate counts of run items by status */ itemCounts?: SimulationRunItemCounts; - /** Array of simulations and/or suites to run */ - simulations: (SimulationRunSimulationEntry | SimulationRunSuiteEntry)[]; - /** Target to test against */ - target: SimulationRunTargetAssistant | SimulationRunTargetSquad; /** - * Number of times to run each simulation (default: 1) - * @min 1 - * @default 1 - */ - iterations?: number; - /** Transport configuration for the simulation runs */ - transport?: SimulationRunTransportConfiguration; -} - -export interface SimulationRunListSource { - type: "suite" | "simulation" | "adHoc" | "api"; - /** @format uuid */ - id?: string; - name: string; - linkable: boolean; - simulationIds: string[]; -} - -export interface SimulationRunListSummary { - source: SimulationRunListSource; - targetSnapshotName?: string; - simulationCount: number; -} - -export interface SimulationRunListItem { - /** - * Unique identifier for the run - * @format uuid - */ - id: string; - /** - * Organization ID - * @format uuid - */ - orgId: string; - /** Current status of the run */ - status: "queued" | "running" | "ended"; - /** - * When the run was queued - * @format date-time - */ - queuedAt: string; - /** - * When the run started - * @format date-time - */ - startedAt?: string; - /** - * When the run ended - * @format date-time - */ - endedAt?: string; - /** Reason the run ended */ - endedReason?: string; - /** - * ISO 8601 date-time when created - * @format date-time - */ - createdAt: string; - /** - * ISO 8601 date-time when last updated - * @format date-time + * Generate directly attached target structured outputs. Default false. Enabled extraction may incur additional model charges. + * @default false + */ + includeTargetStructuredOutputs?: boolean; + /** Array of simulations and/or suites to run */ + simulations: (SimulationRunSimulationEntry | SimulationRunSuiteEntry)[]; + /** Target to test against */ + target: SimulationRunTargetAssistant | SimulationRunTargetSquad; + /** + * Number of times to run each simulation (default: 1) + * @min 1 + * @default 1 + */ + iterations?: number; + /** Transport configuration for the simulation runs */ + transport?: SimulationRunTransportConfiguration; +} + +export interface SimulationRunListSource { + type: "suite" | "simulation" | "adHoc" | "api"; + /** @format uuid */ + id?: string; + name: string; + linkable: boolean; + simulationIds: string[]; +} + +export interface SimulationRunListSummary { + source: SimulationRunListSource; + targetSnapshotName?: string; + simulationCount: number; +} + +export interface SimulationRunListItem { + /** + * Unique identifier for the run + * @format uuid + */ + id: string; + /** + * Organization ID + * @format uuid + */ + orgId: string; + /** Current status of the run */ + status: "queued" | "running" | "ended"; + /** + * When the run was queued + * @format date-time + */ + queuedAt: string; + /** + * When the run started + * @format date-time + */ + startedAt?: string; + /** + * When the run ended + * @format date-time + */ + endedAt?: string; + /** Reason the run ended */ + endedReason?: string; + /** + * ISO 8601 date-time when created + * @format date-time + */ + createdAt: string; + /** + * ISO 8601 date-time when last updated + * @format date-time + */ + updatedAt: string; + /** Aggregate counts of run items by status */ + itemCounts?: SimulationRunItemCounts; + /** + * Generate directly attached target structured outputs. Default false. Enabled extraction may incur additional model charges. + * @default false */ - updatedAt: string; - /** Aggregate counts of run items by status */ - itemCounts?: SimulationRunItemCounts; + includeTargetStructuredOutputs?: boolean; /** Array of simulations and/or suites to run */ simulations: (SimulationRunSimulationEntry | SimulationRunSuiteEntry)[]; /** Target to test against */ @@ -39496,6 +39977,25 @@ export interface LatencyEvaluationResult { } export interface SimulationRunItemResults { + /** Retention-permitted target extraction values, present only when enabled. */ + structuredOutputs?: Record< + string, + { + name: string; + result: any; + } + >; + /** Condition-gated outputs or audio outputs unsupported by chat. */ + skippedStructuredOutputs?: Record< + string, + { + name: string; + unmetCondition?: Record; + reason?: "audio-not-supported"; + } + >; + /** Sanitized diagnostic; optional target extraction never changes pass/fail. */ + structuredOutputError?: string; /** This is the list of results from structured output evaluations. */ evaluations: StructuredOutputEvaluationResult[]; /** This indicates whether all required, non-skipped structured output evaluations and latency expectations passed. */ @@ -39530,6 +40030,11 @@ export interface SimulationRunItemImprovements { } export interface SimulationRunConfiguration { + /** + * Generate directly attached target structured outputs. Default false. Enabled extraction may incur additional model charges. + * @default false + */ + includeTargetStructuredOutputs?: boolean; /** Transport configuration for the simulation run */ transport?: SimulationRunTransportConfiguration; } @@ -39773,6 +40278,242 @@ export interface GenerateScenariosResponse { coverageNotes: string; } +export interface SimulationOnboardingErrorDTO { + /** Which refusal this is. Retry `SIMULATION_ONBOARDING_GENERATION_IN_PROGRESS` with the same key and `SIMULATION_ONBOARDING_CONCURRENCY_LIMITED` or `SIMULATION_ONBOARDING_QUOTA_UNAVAILABLE` after `retryAfterSeconds`, send a new key for `SIMULATION_ONBOARDING_IDEMPOTENCY_KEY_REUSED`, and stop for `SIMULATION_ONBOARDING_QUOTA_EXCEEDED`. */ + code: + | "SIMULATION_ONBOARDING_GENERATION_IN_PROGRESS" + | "SIMULATION_ONBOARDING_IDEMPOTENCY_KEY_REUSED" + | "SIMULATION_ONBOARDING_CONCURRENCY_LIMITED" + | "SIMULATION_ONBOARDING_QUOTA_EXCEEDED" + | "SIMULATION_ONBOARDING_QUOTA_UNAVAILABLE"; + /** What happened, written for the user. */ + message: string; + /** Seconds to wait before retrying, the same value as the `Retry-After` header. For a daily limit, the seconds until 00:00 UTC. */ + retryAfterSeconds?: number; + /** The daily limit that was reached, on a daily-limit refusal only. */ + limit?: number; +} + +export interface SimulationOnboardingRequirementDTO { + /** Stable requirement id, e.g. `R3`. */ + id: string; + /** + * One observable behaviour the assistant must get right. + * @maxLength 1000 + */ + text: string; + /** Indicates an assumption, a requirement that needs a voice simulation, or a requirement that cannot be tested. */ + tag?: "assumption" | "not-testable" | "voice-only"; + /** + * What was assumed, why only a voice run can check it, or why it cannot be tested. + * @maxLength 1000 + */ + note?: string; +} + +export interface SimulationOnboardingOpenQuestionDTO { + /** Question id within its draft, e.g. `Q1`. */ + id: string; + /** + * A question about expected assistant behavior that needs clarification. + * @maxLength 1000 + */ + text: string; + /** + * Which requirement the answer changes, and how. + * @maxLength 1000 + */ + why: string; +} + +export interface SimulationOnboardingRequirementsDraftDTO { + /** + * Draft version, 1 for a first draft. + * @min 1 + */ + version: number; + /** + * What changed since the previous draft. + * @maxLength 1000 + */ + changeNote?: string; + /** + * What the draft was based on, e.g. the prompt and tools. + * @maxItems 10 + */ + sources: string[]; + /** + * Draft test requirements describing the expected assistant behavior. Review and refine these before generating a simulation suite. + * @maxItems 50 + * @minItems 1 + */ + requirements: SimulationOnboardingRequirementDTO[]; + /** + * Questions about ambiguous or missing assistant behavior to resolve before generating a simulation suite. + * @maxItems 3 + */ + openQuestions: SimulationOnboardingOpenQuestionDTO[]; +} + +export interface SimulationOnboardingRequirementsCreateDTO { + /** + * Assistant to draft requirements for. + * @format uuid + */ + assistantId: string; + /** The draft being revised, exactly as this endpoint returned it. Send it with `feedback`. */ + previousDraft?: SimulationOnboardingRequirementsDraftDTO; + /** + * Natural-language instructions for revising the requirements in `previousDraft`, including answers to open questions. Required when `previousDraft` is provided. + * @maxLength 8000 + */ + feedback?: string; +} + +export interface SimulationOnboardingSuiteCreateDTO { + /** + * Assistant the suite tests and is assigned to. + * @format uuid + */ + assistantId: string; + /** + * A unique key for this suite generation request. Retrying with the same key returns the saved suite, or a 409 while generation is in progress. Use a new key for a different assistant or requirements. + * @minLength 1 + * @maxLength 200 + */ + idempotencyKey: string; + /** + * The reviewed test requirements to generate simulations for, from the requirements draft. Each requirement must have a unique id. + * @maxItems 50 + * @minItems 1 + */ + requirements: SimulationOnboardingRequirementDTO[]; +} + +export interface SimulationOnboardingSuiteRefDTO { + /** Suite id; pass it to edit or run the suite. */ + id: string; + /** Suite name. */ + name: string; +} + +export interface SimulationOnboardingSuiteSimulationDTO { + /** Simulation id; pass it back to edit or remove the simulation. */ + id: string; + /** Scenario the simulation runs. */ + scenarioId: string; + /** Scenario name. */ + name: string; + /** Name of the simulated caller's personality. */ + personalityName?: string; + /** Each success criterion, as the yes/no question it is judged by. */ + successCriteria: string[]; + /** Requirement ids this simulation covers, e.g. `R3`. */ + requirementIds: string[]; + /** Tools the scenario mocks. */ + mockedTools: string[]; +} + +export interface SimulationOnboardingCoverageGapDTO { + /** Requirement the gap is for, e.g. `R4`. */ + requirementId: string; + /** Why no simulation covers it. `failed` and `budget` gaps are regenerated by an edit with `retryFailed`. */ + reason: "not-testable" | "unmapped" | "failed" | "budget"; + /** A short explanation for the user. */ + detail?: string; +} + +export interface SimulationOnboardingSuiteCoverageDTO { + /** Requirements at least one simulation covers. */ + covered: number; + /** Requirements in the agreed draft. */ + total: number; + /** Requirements no simulation covers, and why. */ + gaps: SimulationOnboardingCoverageGapDTO[]; + /** Planned scenarios an edit with `retryFailed` would regenerate. */ + retryable: number; +} + +export interface SimulationOnboardingSuiteDocsDTO { + /** Link to testing best practices. */ + bestPractices: string; + /** Link explaining why tools are mocked by default. */ + toolMocks: string; +} + +export interface SimulationOnboardingToolGapDTO { + /** Function name of the tool, e.g. `handoff_to_group_1` or `transferCall`. */ + toolName: string; + /** Assistant the tool belongs to, when it is a handoff destination's tool. Unset for the assistant's own tools. */ + assistantName?: string; + /** Why the path is not exercised: a reason the simulations mock the tool, or why a native path is never reached. New reasons may be added. */ + reason: + | "dynamic-handoff" + | "destination-not-plain" + | "destination-unresolved" + | "destination-truncated" + | "transfer-external" + | "destination-name-unscoped" + | "native-tool-shadowed"; + /** Static destinations the simulations do not reach through this tool. */ + destinationNames?: string[]; +} + +export interface SimulationOnboardingSuiteViewDTO { + /** The generated simulation suite id and name. */ + suite: SimulationOnboardingSuiteRefDTO; + /** Assistant the suite is assigned to. */ + assistantId: string; + /** The suite's simulations, in order. */ + simulations: SimulationOnboardingSuiteSimulationDTO[]; + /** Counts of covered and total requirements, uncovered requirements, and scenarios available to retry. */ + coverage: SimulationOnboardingSuiteCoverageDTO; + /** The test requirements used to generate the suite. Match their ids to `coverage.gaps` to identify uncovered requirements. */ + requirements: SimulationOnboardingRequirementDTO[]; + /** Links to simulation testing best practices and tool mocking documentation. */ + docs: SimulationOnboardingSuiteDocsDTO; + /** True when the request matched one already applied (same `idempotencyKey` or `patchKey`) and nothing changed. */ + reused: boolean; + /** Simulations an edit asked to rewrite that were not rewritten, for example because the rewrite did not generate in time. Retry them with a new `patchKey`. */ + failedEditSimulationIds?: string[]; + /** Tool paths the suite's simulations do not exercise as configured, such as a tool mocked although it runs natively. Omitted when there are none. */ + toolGaps?: SimulationOnboardingToolGapDTO[]; +} + +export interface SimulationOnboardingSuiteEditDTO { + /** + * Simulation in the suite whose scenario is rewritten. + * @format uuid + */ + simulationId: string; + /** + * Natural-language instructions for revising this simulation's scenario, such as "Have the caller ask for a refund after 30 days." + * @maxLength 8000 + */ + instruction: string; +} + +export interface SimulationOnboardingSuiteUpdateDTO { + /** + * A new key for each edit. Replaying an applied key changes nothing and returns the current suite. A suite remembers its last 50 keys, so never reuse one. + * @minLength 1 + * @maxLength 200 + */ + patchKey: string; + /** + * Simulations to take out of the suite. They are unlinked, not deleted. + * @maxItems 100 + */ + removeSimulationIds?: string[]; + /** + * Simulations to rewrite in place, at most one edit per simulation: put every change for a simulation in one instruction. + * @maxItems 10 + */ + edits?: SimulationOnboardingSuiteEditDTO[]; + /** Regenerate the scenarios that failed or did not fit when the suite was generated. */ + retryFailed?: boolean; +} + export interface CreateSimulationDTO { /** * This is an optional friendly name for the simulation. @@ -42698,7 +43439,7 @@ export interface GetEvalRunPaginatedDTO { export interface EvalRunTargetAssistant { /** This is the transient assistant that will be run against the eval */ - assistant?: CreateAssistantDTO; + assistant?: TransientAssistantDTO; /** * This is the overrides that will be applied to the assistant. * @example "{" @@ -42803,6 +43544,67 @@ export interface UpdateScorecardDTO { assistantIds?: string[]; } +export interface GoalEvaluationCurrentDTO { + /** @format uuid */ + assistantId: string; + /** @format uuid */ + goalId: string; + /** + * Current immutable goal revision, encoded as a decimal bigint string. + * @pattern ^[1-9][0-9]*$ + */ + goalVersion: string; + /** @format date-time */ + callEndedAt: string; + processingState: + | "pending" + | "running" + | "parked" + | "unavailable" + | "excluded" + | "completed"; + /** Absent until a semantic result is accepted. Processing failures are never goal_not_met. */ + goalOutcome?: "goal_met" | "goal_not_met" | "ineligible"; +} + +export interface GoalEvaluationCurrentCallResponseDTO { + /** @format uuid */ + callId: string; + /** @format uuid */ + goalId: string; + /** + * Current revision of the requested goal for a visible call. Absent when that goal does not belong to the source assistant or the source is hidden. An absent evaluation does not imply queued or pending work. + * @pattern ^[1-9][0-9]*$ + */ + currentGoalVersion?: string; + currentEvaluation?: GoalEvaluationCurrentDTO; +} + +export interface GoalEvaluationCurrentCallRequestDTO { + /** @format uuid */ + callId: string; + /** @format uuid */ + goalId: string; +} + +export interface GoalEvaluationCurrentBatchRequestDTO { + /** + * Explicit call/goal pairs. The organization comes from the authenticated caller. + * @maxItems 100 + * @minItems 1 + * @uniqueItems true + */ + evaluations: GoalEvaluationCurrentCallRequestDTO[]; +} + +export interface GoalEvaluationCurrentBatchResponseDTO { + /** + * One entry per requested call/goal pair, in request order, including entries without a current evaluation. + * @maxItems 100 + */ + results: GoalEvaluationCurrentCallResponseDTO[]; +} + export interface CreateOrgDTO { /** * When this is enabled, logs, recordings, and transcriptions will be stored in HIPAA-compliant storage. Defaults to false. @@ -47999,6 +48801,11 @@ export interface ServerMessageEndOfCallReport { type: "end-of-call-report"; /** This is the reason the call ended. This can also be found at `call.endedReason` on GET /call/:id. */ endedReason: + | "call.in-progress.error-vapifault-guardrail-evaluation-failed" + | "call.in-progress.error-vapifault-guardrail-playback-timeout" + | "call.in-progress.guardrail-blocked" + | "call.in-progress.error-vapifault-call-start-failed" + | "call.in-progress.error-vapifault-assistant-handoff-start-failed" | "call-start-error-neither-assistant-nor-server-set" | "assistant-request-failed" | "assistant-request-returned-error" @@ -48929,6 +49736,11 @@ export interface ServerMessageStatusUpdate { | "deletion-failed"; /** This is the reason the call ended. This is only sent if the status is "ended". */ endedReason?: + | "call.in-progress.error-vapifault-guardrail-evaluation-failed" + | "call.in-progress.error-vapifault-guardrail-playback-timeout" + | "call.in-progress.guardrail-blocked" + | "call.in-progress.error-vapifault-call-start-failed" + | "call.in-progress.error-vapifault-assistant-handoff-start-failed" | "call-start-error-neither-assistant-nor-server-set" | "assistant-request-failed" | "assistant-request-returned-error" @@ -50539,7 +51351,7 @@ export interface ServerMessageResponseAssistantRequest { * - Squad, use `squad` * - Workflow, use `workflow` */ - assistant?: CreateAssistantDTO; + assistant?: TransientAssistantDTO; /** These are the overrides for the `assistant` or `assistantId`'s settings and template variables. */ assistantOverrides?: AssistantOverrides; /** @@ -54892,6 +55704,55 @@ export class Api< secure: true, ...params, }), + + /** + * No description + * + * @tags Calls + * @name GoalEvaluationCurrentControllerCurrentGet + * @summary Get the current goal evaluation for a call + * @request GET:/call/{id}/goal-evaluation + * @secure + */ + goalEvaluationCurrentControllerCurrentGet: ( + id: string, + query: { + /** @format uuid */ + goalId: string; + }, + params: RequestParams = {}, + ) => + this.request({ + path: `/call/${id}/goal-evaluation`, + method: "GET", + query: query, + secure: true, + format: "json", + ...params, + }), + + /** + * No description + * + * @tags Calls + * @name GoalEvaluationCurrentControllerCurrentBatchGet + * @summary Get current goal evaluations for up to 100 call/goal pairs + * @request POST:/call/goal-evaluation/batch + * @secure + */ + goalEvaluationCurrentControllerCurrentBatchGet: ( + data: GoalEvaluationCurrentBatchRequestDTO, + params: RequestParams = {}, + ) => + this.request({ + path: `/call/goal-evaluation/batch`, + method: "POST", + body: data, + secure: true, + type: ContentType.Json, + format: "json", + ...params, + }), }; chat = { /** @@ -55844,7 +56705,7 @@ export class Api< }; trafficAllocations = { /** - * @description Creates a new traffic allocation for an assistant, replacing the one currently in effect. To start or adjust a split, send targets naming published versions (such as "v7") with percentages totaling 100; allocationIntent is inferred as 'explicit'. To stop splitting and send every call to the newest published version, send allocationIntent 'follow-latest' with no targets field; stopping always names its intent, so a dropped targets field can never end a split by accident. Traffic splitting is in beta, rolling out to select organizations; requests from organizations without access receive a 403. + * @description Creates a new traffic allocation for an assistant, replacing the one currently in effect. To start or adjust a split, send targets naming published versions (such as "v7") with percentages totaling 100; allocationIntent is inferred as 'explicit'. To stop splitting and send every call to the newest published version, send allocationIntent 'follow-latest' with no targets field; stopping always names its intent, so a dropped targets field can never end a split by accident. * * @tags Traffic Allocations * @name TrafficAllocationControllerCreate @@ -55878,7 +56739,7 @@ export class Api< }), /** - * @description The append-only history of an assistant's allocations, newest first. Traffic splitting is in beta, rolling out to select organizations; requests from organizations without access receive a 403. + * @description The append-only history of an assistant's allocations, newest first. * * @tags Traffic Allocations * @name TrafficAllocationControllerFindAllPaginated @@ -55916,7 +56777,7 @@ export class Api< }), /** - * @description The allocation currently in effect for the assistant, with its targets. The response carries no allocation field when traffic splitting has never been configured. Traffic splitting is in beta, rolling out to select organizations; requests from organizations without access receive a 403. + * @description The allocation currently in effect for the assistant, with its targets. The response carries no allocation field when traffic splitting has never been configured. * * @tags Traffic Allocations * @name TrafficAllocationControllerLatestGet @@ -55941,7 +56802,7 @@ export class Api< }), /** - * @description Per-assistant-version call metrics over a time window: call counts, configured vs actual traffic share, duration, cost per minute, latency, ended reasons, a bucketed timeseries, and optional structured output aggregations. Calls with no assistant version are reported as an 'unversioned' row. Traffic splitting is in beta, rolling out to select organizations; requests from organizations without access receive a 403. + * @description Per-assistant-version call metrics over a time window: call counts, configured vs actual traffic share, duration, cost per minute, latency, ended reasons, a bucketed timeseries, and optional structured output aggregations. Calls with no assistant version are reported as an 'unversioned' row. * * @tags Traffic Allocations * @name TrafficAllocationControllerMetricsGet @@ -55983,7 +56844,7 @@ export class Api< }), /** - * @description Returns a single allocation by id, including its targets and actor attribution. Traffic splitting is in beta, rolling out to select organizations; requests from organizations without access receive a 403. + * @description Returns a single allocation by id, including its targets and actor attribution. * * @tags Traffic Allocations * @name TrafficAllocationControllerFindOne @@ -57905,9 +58766,7 @@ export class Api< params: RequestParams = {}, ) => this.request< - | (StructuredOutputRunPreviewResponse & - Record) - | StructuredOutputRerunResponse, + StructuredOutputRunPreviewResponse | StructuredOutputRerunResponse, any >({ path: `/structured-output/run`, @@ -59351,6 +60210,112 @@ export class Api< ...params, }), + /** + * @description Generate draft test requirements from an assistant's prompt, tools, and handoff configuration. The response includes numbered requirements describing expected behavior and open questions about behavior that needs clarification. Use this endpoint before generating a simulation suite. Review the requirements and resolve any open questions. To revise a draft, send it as `previousDraft` together with natural-language `feedback` describing the changes or answers. Once the requirements are ready, pass them to `POST /eval/simulation/onboarding/suite`. Requests can take up to 2 minutes. Each organization can draft requirements 60 times per UTC day, shared with the dashboard. A 429 `SIMULATION_ONBOARDING_QUOTA_EXCEEDED` response means the daily limit has been reached. Wait until the limit resets at 00:00 UTC before retrying. + * + * @tags Simulation Suites + * @name SimulationOnboardingControllerRequirementsDraft + * @summary Draft simulation requirements + * @request POST:/eval/simulation/onboarding/requirements + * @secure + */ + simulationOnboardingControllerRequirementsDraft: ( + data: SimulationOnboardingRequirementsCreateDTO, + params: RequestParams = {}, + ) => + this.request< + SimulationOnboardingRequirementsDraftDTO, + | void + | SimulationOnboardingErrorDTO + | ( + | SimulationOnboardingErrorDTO + | { + statusCode: number; + message: string; + error: string; + } + ) + >({ + path: `/eval/simulation/onboarding/requirements`, + method: "POST", + body: data, + secure: true, + type: ContentType.Json, + format: "json", + ...params, + }), + + /** + * @description Generate and save a simulation suite from reviewed test requirements, and assign it to an assistant. First draft requirements with `POST /eval/simulation/onboarding/requirements`. The response includes the saved suite, its simulations, and requirement coverage, including any gaps. Requests can take up to 3 minutes. Set a client timeout of at least 200 seconds. Use a unique `idempotencyKey` for each suite generation request. Retrying with the same key does not create a duplicate suite: - On a timeout or a 5xx (502, 504, 524), retry with the same key. You get the saved suite, a 409 while it is still generating, or a fresh generation if the first one never saved. - On a 409 `SIMULATION_ONBOARDING_GENERATION_IN_PROGRESS`, the first request is still generating. Wait `Retry-After` seconds (15) and retry with the same key. - On a 409 `SIMULATION_ONBOARDING_IDEMPOTENCY_KEY_REUSED`, the key was used for a different assistant or requirements. Send a new key. Review the generated simulations and coverage gaps. Revise the suite with `PATCH /eval/simulation/onboarding/suite/{suiteId}`, then run it with `POST /eval/simulation/run`. Each organization can generate 20 suites per UTC day, shared with the dashboard, and 2 at a time. A retry that returns a saved suite does not count toward these limits. On a 429 `SIMULATION_ONBOARDING_CONCURRENCY_LIMITED`, wait `Retry-After` seconds (30) before retrying. On a 429 `SIMULATION_ONBOARDING_QUOTA_EXCEEDED`, wait until the daily limit resets at 00:00 UTC before retrying. + * + * @tags Simulation Suites + * @name SimulationOnboardingControllerSuiteCreate + * @summary Generate a simulation suite + * @request POST:/eval/simulation/onboarding/suite + * @secure + */ + simulationOnboardingControllerSuiteCreate: ( + data: SimulationOnboardingSuiteCreateDTO, + params: RequestParams = {}, + ) => + this.request< + SimulationOnboardingSuiteViewDTO, + | void + | SimulationOnboardingErrorDTO + | ( + | SimulationOnboardingErrorDTO + | { + statusCode: number; + message: string; + error: string; + } + ) + >({ + path: `/eval/simulation/onboarding/suite`, + method: "POST", + body: data, + secure: true, + type: ContentType.Json, + format: "json", + ...params, + }), + + /** + * @description Revise a suite created by `POST /eval/simulation/onboarding/suite`. Remove simulations, rewrite scenarios using natural-language instructions, or set `retryFailed` to regenerate scenarios that failed or exceeded generation limits. The response includes the updated suite and requirement coverage. Requests can take up to 2 minutes. Send a new `patchKey` for each edit. Replaying an applied key changes nothing and returns the current suite, with `failedEditSimulationIds` listing the simulations that edit could not rewrite, so retry a timeout or a 5xx with the same key. A suite remembers its last 50 keys, so never reuse one. Each organization can make 60 edits per UTC day, shared with the dashboard. Requests that only remove simulations and replays of applied edits do not count toward this limit. On a 429 `SIMULATION_ONBOARDING_QUOTA_EXCEEDED`, wait until the daily limit resets at 00:00 UTC before retrying. + * + * @tags Simulation Suites + * @name SimulationOnboardingControllerSuiteUpdate + * @summary Edit a generated simulation suite + * @request PATCH:/eval/simulation/onboarding/suite/{suiteId} + * @secure + */ + simulationOnboardingControllerSuiteUpdate: ( + suiteId: string, + data: SimulationOnboardingSuiteUpdateDTO, + params: RequestParams = {}, + ) => + this.request< + SimulationOnboardingSuiteViewDTO, + | void + | SimulationOnboardingErrorDTO + | ( + | SimulationOnboardingErrorDTO + | { + statusCode: number; + message: string; + error: string; + } + ) + >({ + path: `/eval/simulation/onboarding/suite/${suiteId}`, + method: "PATCH", + body: data, + secure: true, + type: ContentType.Json, + format: "json", + ...params, + }), + /** * No description * @@ -60666,7 +61631,7 @@ export class Api< memberId: string, params: RequestParams = {}, ) => - this.request({ + this.request({ path: `/org/${id}/member/${memberId}/leave`, method: "DELETE", secure: true, diff --git a/vapi.ts b/vapi.ts index af3c9c914..37f7961a0 100644 --- a/vapi.ts +++ b/vapi.ts @@ -297,14 +297,13 @@ function subscribeToTracks( e: DailyEventObjectParticipant, call: DailyCall, isVideoRecordingEnabled?: boolean, - isVideoEnabled?: boolean, ) { if (e.participant.local) return; call.updateParticipant(e.participant.session_id, { setSubscribedTracks: { audio: true, - video: isVideoRecordingEnabled || isVideoEnabled, + video: isVideoRecordingEnabled, }, }); } @@ -585,8 +584,6 @@ export default class Vapi extends VapiEventEmitter { const isVideoRecordingEnabled = webCall?.artifactPlan?.videoRecordingEnabled ?? false; - const isVideoEnabled = webCall?.assistant?.voice?.provider === 'tavus'; - // When video recording is enabled, the server sends a Daily meeting // token that auto-starts the cloud recording on join — more reliable // than calling startRecording() from a weak client network. Older @@ -604,7 +601,6 @@ export default class Vapi extends VapiEventEmitter { audioSource: this.dailyCallObject.audioSource ?? true, videoSource: this.dailyCallObject.videoSource ?? isVideoRecordingEnabled, isVideoRecordingEnabled, - isVideoEnabled } }); @@ -714,12 +710,7 @@ export default class Vapi extends VapiEventEmitter { this.call.on('participant-joined', (e) => { if (!e || !this.call) return; - subscribeToTracks( - e, - this.call, - isVideoRecordingEnabled, - isVideoEnabled, - ); + subscribeToTracks(e, this.call, isVideoRecordingEnabled); }); this.call.on('participant-updated', (e) => { @@ -1543,7 +1534,6 @@ export default class Vapi extends VapiEventEmitter { } const isVideoRecordingEnabled = webCall?.artifactPlan?.videoRecordingEnabled ?? false; - const isVideoEnabled = webCall?.assistant?.voice?.provider === 'tavus'; // Same auto-start token as in start(). Rejoining with it while the // recording is still running is safe; if the recording stopped when the @@ -1559,7 +1549,6 @@ export default class Vapi extends VapiEventEmitter { audioSource: this.dailyCallObject.audioSource ?? true, videoSource: this.dailyCallObject.videoSource ?? isVideoRecordingEnabled, isVideoRecordingEnabled, - isVideoEnabled } }); @@ -1650,12 +1639,7 @@ export default class Vapi extends VapiEventEmitter { this.call.on('participant-joined', (e) => { if (!e || !this.call) return; - subscribeToTracks( - e, - this.call, - isVideoRecordingEnabled, - isVideoEnabled, - ); + subscribeToTracks(e, this.call, isVideoRecordingEnabled); }); this.call.on('participant-updated', (e) => {