From 3a7b969295e01fa617cf830e4842d6b4fa8a7309 Mon Sep 17 00:00:00 2001 From: Steve Date: Fri, 11 Sep 2026 10:49:50 -0700 Subject: [PATCH] Checking in Tools IA draft changes Co-Authored-By: Claude Opus 5 --- fern/assistants/end-call-phrases.mdx | 2 +- .../examples/appointment-scheduling.mdx | 6 +- fern/assistants/examples/inbound-support.mdx | 2 +- .../examples/lead-qualification.mdx | 4 +- .../examples/multilingual-agent.mdx | 2 +- .../examples/support-escalation.mdx | 2 +- fern/assistants/flush-syntax.mdx | 2 +- fern/assistants/keypad-input-settings.mdx | 2 +- fern/assistants/quickstart.mdx | 2 +- fern/assistants/structured-outputs.mdx | 2 +- fern/calls/assistant-based-warm-transfer.mdx | 8 +- fern/calls/call-dynamic-transfers.mdx | 4 +- .../troubleshoot-call-forwarding-drops.mdx | 2 +- fern/chat/session-management.mdx | 2 +- fern/chat/web-widget.mdx | 2 +- fern/docs.yml | 107 ++- fern/knowledge-base/custom-knowledge-base.mdx | 378 +------- .../implement-custom-endpoint.mdx | 380 ++++++++ fern/knowledge-base/knowledge-base.mdx | 4 +- fern/knowledge-base/using-query-tool.mdx | 2 +- fern/observability/simulations-advanced.mdx | 2 +- ...uild-personalized-appointment-campaign.mdx | 2 +- .../voicemail-and-call-screening.mdx | 4 +- fern/prompting-guide.mdx | 2 +- fern/quickstart/web.mdx | 2 +- fern/security-and-privacy/PCI.mdx | 2 +- .../recording-consent-plan.mdx | 4 +- fern/squads.mdx | 2 +- .../clinic-triage-scheduling-handoff-tool.mdx | 2 +- .../examples/clinic-triage-scheduling.mdx | 2 +- fern/squads/handoff.mdx | 897 +----------------- fern/squads/handoff/context-and-variables.mdx | 261 +++++ fern/squads/handoff/destinations.mdx | 407 ++++++++ .../squads/handoff/messages-and-rejection.mdx | 180 ++++ fern/squads/handoff/troubleshooting.mdx | 47 + .../passing-data-between-assistants.mdx | 2 +- fern/tools/api-request-vs-function.mdx | 65 +- fern/tools/api-request.mdx | 6 +- fern/tools/api-request/configuration.mdx | 6 +- fern/tools/api-request/quickstart.mdx | 6 +- fern/tools/api-request/reliability.mdx | 6 +- fern/tools/api-request/response-data.mdx | 4 +- fern/tools/api-request/response-handling.mdx | 6 +- fern/tools/arguments-encryption.mdx | 4 +- fern/tools/client-side-websdk.mdx | 2 +- fern/tools/custom-tools-troubleshooting.mdx | 3 +- fern/tools/custom-tools.mdx | 10 +- fern/tools/default-tools.mdx | 8 +- fern/tools/go-high-level.mdx | 4 +- fern/tools/google-calendar.mdx | 4 +- fern/tools/google-sheets.mdx | 4 +- fern/tools/integrations.mdx | 38 + fern/tools/introduction.mdx | 137 +-- fern/tools/mcp.mdx | 4 +- fern/tools/slack.mdx | 4 +- fern/tools/static-variables-and-aliases.mdx | 638 +------------ .../extract-and-chain.mdx | 262 +++++ .../how-variables-work.mdx | 85 ++ .../static-parameters.mdx | 184 ++++ .../troubleshooting.mdx | 111 +++ fern/tools/tool-rejection-plan.mdx | 2 +- fern/tools/transfer-call.mdx | 8 +- fern/tools/transfer-call/blind-transfer.mdx | 8 +- fern/tools/transfer-call/warm-transfer.mdx | 8 +- fern/tools/voicemail-tool.mdx | 224 +---- fern/tools/voicemail-tool/configure.mdx | 210 ++++ fern/workflows/legacy-migration.mdx | 6 +- 67 files changed, 2474 insertions(+), 2326 deletions(-) create mode 100644 fern/knowledge-base/implement-custom-endpoint.mdx create mode 100644 fern/squads/handoff/context-and-variables.mdx create mode 100644 fern/squads/handoff/destinations.mdx create mode 100644 fern/squads/handoff/messages-and-rejection.mdx create mode 100644 fern/squads/handoff/troubleshooting.mdx create mode 100644 fern/tools/integrations.mdx create mode 100644 fern/tools/static-variables-and-aliases/extract-and-chain.mdx create mode 100644 fern/tools/static-variables-and-aliases/how-variables-work.mdx create mode 100644 fern/tools/static-variables-and-aliases/static-parameters.mdx create mode 100644 fern/tools/static-variables-and-aliases/troubleshooting.mdx create mode 100644 fern/tools/voicemail-tool/configure.mdx diff --git a/fern/assistants/end-call-phrases.mdx b/fern/assistants/end-call-phrases.mdx index 7949abe06..71dd1c27a 100644 --- a/fern/assistants/end-call-phrases.mdx +++ b/fern/assistants/end-call-phrases.mdx @@ -91,6 +91,6 @@ See [call end reasons](/calls/call-ended-reason) for the complete list of ended ## Related -- [Built-in call tools](/tools/default-tools) +- [Built-in tools](/tools/default-tools) - [Call end reasons](/calls/call-ended-reason) - [Troubleshoot call errors](/calls/troubleshoot-call-errors) diff --git a/fern/assistants/examples/appointment-scheduling.mdx b/fern/assistants/examples/appointment-scheduling.mdx index c4a433462..3d215cf3c 100644 --- a/fern/assistants/examples/appointment-scheduling.mdx +++ b/fern/assistants/examples/appointment-scheduling.mdx @@ -101,7 +101,7 @@ Use the Google Calendar integration for availability and booking, or your own AP - See: [Google Calendar Integration](/tools/google-calendar) + See: [Google Calendar](/tools/google-calendar) Configure tools for: - `check_availability(service, date)` @@ -110,7 +110,7 @@ Use the Google Calendar integration for availability and booking, or your own AP - `cancel_appointment(appointmentId)` - See: [Custom Tools](/tools/custom-tools) + See: [Function tools](/tools/custom-tools) Define function tools that call your scheduling backend. Attach CSV knowledge bases (customers/services) if using the sample data above. @@ -271,7 +271,7 @@ Use the Google Calendar integration for availability and booking, or your own AP ## Next steps -- **Tools**: [Google Calendar](/tools/google-calendar), [Custom Tools](/tools/custom-tools) +- **Tools**: [Google Calendar](/tools/google-calendar), [Function tools](/tools/custom-tools) - **Structured outputs**: [Extract structured data](/assistants/structured-outputs-quickstart) - **Multichannel**: [Web integration](/quickstart/web) diff --git a/fern/assistants/examples/inbound-support.mdx b/fern/assistants/examples/inbound-support.mdx index 7ee43619c..4c83c78d4 100644 --- a/fern/assistants/examples/inbound-support.mdx +++ b/fern/assistants/examples/inbound-support.mdx @@ -978,7 +978,7 @@ Just like that, you've built a 24/7 customer support hotline that can handle inb Consider the reading the following guides to further enhance your assistant: -* [**Knowledge Bases**](/knowledge-base) - Learn more about knowledge bases to build knowledge-based agents. +* [**Knowledge bases**](/knowledge-base) - Learn more about knowledge bases to build knowledge-based agents. * [**External Integrations**](../tools/) - Configure integrations with [Google Calendar](../tools/google-calendar), [Google Sheets](../tools/google-sheets), [Slack](../tools/slack), etc. * [**Squads**](/squads) - Learn how to compose multiple assistants and transfer seamlessly for complex use cases. diff --git a/fern/assistants/examples/lead-qualification.mdx b/fern/assistants/examples/lead-qualification.mdx index ff761c360..42f45330c 100644 --- a/fern/assistants/examples/lead-qualification.mdx +++ b/fern/assistants/examples/lead-qualification.mdx @@ -73,7 +73,7 @@ Configure function tools or your CRM API for: - `update_crm(leadId, callOutcome, nextSteps)` - `book_meeting(prospect, time)` -See [Custom Tools](/tools/custom-tools) and [Google Calendar](/tools/google-calendar). +See [Function tools](/tools/custom-tools) and [Google Calendar](/tools/google-calendar). --- @@ -166,7 +166,7 @@ Create a phone number or trigger an outbound call. See [Phone calls](/quickstart ## Next steps -- **CRM integration**: Connect your CRM via [Custom Tools](/tools/custom-tools) +- **CRM integration**: Connect your CRM via [Function tools](/tools/custom-tools) - **Calendar**: [Google Calendar](/tools/google-calendar) - **Escalation**: Use a [Squad](/squads) to hand off to a specialized closer diff --git a/fern/assistants/examples/multilingual-agent.mdx b/fern/assistants/examples/multilingual-agent.mdx index a85e6fe15..50a0e5ab0 100644 --- a/fern/assistants/examples/multilingual-agent.mdx +++ b/fern/assistants/examples/multilingual-agent.mdx @@ -1047,7 +1047,7 @@ Consider reading the following guides to further enhance your multilingual imple * [**Squad-based Multilingual Support**](/squads/examples/multilingual-support) - Compare with structured language selection approach * [**Multilingual Configuration Guide**](/customization/multilingual) - Learn about all multilingual configuration options -* [**Custom Tools**](/tools/custom-tools) - Build advanced multilingual tools and integrations +* [**Function tools**](/tools/custom-tools) - Build advanced multilingual tools and integrations Need help with multilingual implementation? Chat with the team on our [Discord](https://discord.com/invite/pUFNcf2WmH) or mention us on [X/Twitter](https://x.com/Vapi_AI). diff --git a/fern/assistants/examples/support-escalation.mdx b/fern/assistants/examples/support-escalation.mdx index 0dd42f5af..2a664dc37 100644 --- a/fern/assistants/examples/support-escalation.mdx +++ b/fern/assistants/examples/support-escalation.mdx @@ -982,5 +982,5 @@ async function getEscalationWithQueueManagement(context: any) { You've built a sophisticated customer support escalation system using assistants! Consider these enhancements: * **[Call Analysis](/assistants/call-analysis)** - Analyze escalation patterns and optimize routing -* **[Custom Tools](/tools/custom-tools)** - Build additional tools for advanced support logic +* **[Function tools](/tools/custom-tools)** - Build additional tools for advanced support logic * **[Webhooks](/server-url)** - Learn more about webhook security and advanced event handling diff --git a/fern/assistants/flush-syntax.mdx b/fern/assistants/flush-syntax.mdx index dbdea9579..5b4bea5ff 100644 --- a/fern/assistants/flush-syntax.mdx +++ b/fern/assistants/flush-syntax.mdx @@ -232,4 +232,4 @@ Now that you understand flush syntax: - **[Voice formatting plan](/assistants/voice-formatting-plan):** Control voice output formatting and timing - **[Background messages](/assistants/background-messages):** Send messages during conversations -- **[Custom tools](/tools/custom-tools):** Build tools that benefit from flush syntax feedback +- **[Function tools](/tools/custom-tools):** Build tools that benefit from flush syntax feedback diff --git a/fern/assistants/keypad-input-settings.mdx b/fern/assistants/keypad-input-settings.mdx index 0e3f3fdaa..66addfe98 100644 --- a/fern/assistants/keypad-input-settings.mdx +++ b/fern/assistants/keypad-input-settings.mdx @@ -81,5 +81,5 @@ Keypad input does not have a dedicated call-ended reason. Review the call transc ## Related - [PCI compliance](/security-and-privacy/pci) -- [Built-in call tools](/tools/default-tools) +- [Built-in tools](/tools/default-tools) - [IVR navigation](/ivr-navigation) diff --git a/fern/assistants/quickstart.mdx b/fern/assistants/quickstart.mdx index f7f35262b..da31c0dc5 100644 --- a/fern/assistants/quickstart.mdx +++ b/fern/assistants/quickstart.mdx @@ -268,7 +268,7 @@ Call the phone number you created. Your assistant answers with its configured fi ## Next steps -- **Add tools**: [Custom tools](/tools/custom-tools) +- **Add tools**: [Function tools](/tools/custom-tools) - **Tune speech**: [Speech configuration](/customization/speech-configuration) - **Use a preset**: [Model Intelligence presets](/assistants/model-intelligence/presets) bundle a transcriber, model, and voice for common use cases. - **Structure data**: [Structured outputs](/assistants/structured-outputs) diff --git a/fern/assistants/structured-outputs.mdx b/fern/assistants/structured-outputs.mdx index 17e1493df..cb058dfd1 100644 --- a/fern/assistants/structured-outputs.mdx +++ b/fern/assistants/structured-outputs.mdx @@ -849,6 +849,6 @@ if (data.result === null) { ## Related - [Call analysis](/assistants/call-analysis) - Summarize and evaluate calls -- [Custom tools](/tools/custom-tools) - Trigger actions during calls +- [Function tools](/tools/custom-tools) - Trigger actions during calls - [Webhooks](/server-url) - Receive extracted data via webhooks - [Variables](/assistants/dynamic-variables) - Use dynamic data in conversations \ No newline at end of file diff --git a/fern/calls/assistant-based-warm-transfer.mdx b/fern/calls/assistant-based-warm-transfer.mdx index cee04b522..098f2405f 100644 --- a/fern/calls/assistant-based-warm-transfer.mdx +++ b/fern/calls/assistant-based-warm-transfer.mdx @@ -7,7 +7,7 @@ slug: calls/assistant-based-warm-transfer Assistant-based warm transfer places the customer on hold while a transfer assistant calls the destination. The transfer assistant can give the operator context, confirm that a person is ready, and then complete or cancel the transfer. -Use this mode when the destination must accept the call or receive context before speaking with the customer. For a direct transfer without an operator conversation, use the [transfer call tool](/tools/transfer-call) with its default blind-transfer mode. +Use this mode when the destination must accept the call or receive context before speaking with the customer. For a direct transfer without an operator conversation, use the [Transfer Call tool](/tools/transfer-call) with its default blind-transfer mode. ## Prerequisites @@ -202,7 +202,7 @@ In **Logs → Call Logs**, inspect the original call, destination call leg, tran | The customer cannot continue after a failed transfer | `fallbackPlan.endCallEnabled` is `true` | Set it to `false` so the original assistant remains on the call. | | The transfer ends during a long operator interaction | A duration or silence timeout is too short | Increase `maxDurationSeconds` or `silenceTimeoutSeconds` within the supported ranges. | -Check **Logs → API Logs** for validation and transfer errors. If Vapi initiated the transfer but the destination never rings, inspect the telephony provider's call detail records and follow [Troubleshoot call forwarding drops](/calls/troubleshoot-call-forwarding-drops). +Check **Logs → API Logs** for validation and transfer errors. If Vapi initiated the transfer but the destination never rings, inspect the telephony provider's call detail records and follow [Troubleshoot call forwarding drops](/phone-calling/in-call-control/transfer-calls/debug-forwarding-drops). ## API reference @@ -211,7 +211,7 @@ The [Create Tool API reference](/api-reference/tools/create) documents transfer ## Related guides - + Create a transfer call tool and configure its destinations. @@ -220,7 +220,7 @@ The [Create Tool API reference](/api-reference/tools/create) documents transfer Choose a transfer destination at runtime. - + Diagnose failed or incomplete transfers. diff --git a/fern/calls/call-dynamic-transfers.mdx b/fern/calls/call-dynamic-transfers.mdx index 5743acf49..d2211b25d 100644 --- a/fern/calls/call-dynamic-transfers.mdx +++ b/fern/calls/call-dynamic-transfers.mdx @@ -567,6 +567,6 @@ sequenceDiagram ## Related Documentation -* **[Transfer call tool](/tools/transfer-call)** - Static transfer options and transfer plans +* **[Transfer Call tool](/tools/transfer-call)** - Static transfer options and transfer plans * **[Webhooks](/server-url)** - Webhook security and event handling patterns -* **[Custom Tools](/tools/custom-tools)** - Build custom tools for advanced routing logic +* **[Function tools](/tools/custom-tools)** - Build function tools for advanced routing logic diff --git a/fern/calls/troubleshoot-call-forwarding-drops.mdx b/fern/calls/troubleshoot-call-forwarding-drops.mdx index c0c606f38..0b10a9e1d 100644 --- a/fern/calls/troubleshoot-call-forwarding-drops.mdx +++ b/fern/calls/troubleshoot-call-forwarding-drops.mdx @@ -302,7 +302,7 @@ Now that you can debug call forwarding drops: - **Review SIP setup:** Ensure your SIP configuration follows our [advanced SIP guide](https://docs.vapi.ai/advanced/sip/sip-trunk) - + Create a transfer call tool and configure its destinations. diff --git a/fern/chat/session-management.mdx b/fern/chat/session-management.mdx index 1175f4f07..a58c6e672 100644 --- a/fern/chat/session-management.mdx +++ b/fern/chat/session-management.mdx @@ -259,7 +259,7 @@ These webhooks are useful for tracking session lifecycle, managing session state * **[Streaming responses](/chat/streaming)** - Add real-time responses to session-managed chats * **[OpenAI compatibility](/chat/openai-compatibility)** - Use familiar OpenAI patterns with sessions -* **[Custom tools](/tools/custom-tools)** - Give assistants access to external APIs within sessions +* **[Function tools](/tools/custom-tools)** - Give assistants access to external APIs within sessions Need help? Chat with the team on our [Discord](https://discord.com/invite/pUFNcf2WmH) or mention us on [X/Twitter](https://x.com/Vapi_AI). diff --git a/fern/chat/web-widget.mdx b/fern/chat/web-widget.mdx index 4bf010646..43c245d44 100644 --- a/fern/chat/web-widget.mdx +++ b/fern/chat/web-widget.mdx @@ -462,7 +462,7 @@ Enhance your widget integration: * **[Chat API](/chat/quickstart)** - Build custom chat interfaces using the API directly * **[Voice calls](/calls/outbound-calling)** - Add programmatic voice calling capabilities -* **[Custom tools](/tools/custom-tools)** - Give your assistant access to external APIs +* **[Function tools](/tools/custom-tools)** - Give your assistant access to external APIs * **[Assistant customization](/assistants)** - Fine-tune your assistant's behavior diff --git a/fern/docs.yml b/fern/docs.yml index 71eb1d13c..5133db129 100644 --- a/fern/docs.yml +++ b/fern/docs.yml @@ -209,19 +209,19 @@ navigation: collapsed: true icon: fa-light fa-toolbox contents: - - page: API Request vs Function - path: tools/api-request-vs-function.mdx - icon: fa-light fa-code-compare - - page: Built-in call tools + - page: Built-in tools path: tools/default-tools.mdx icon: fa-light fa-gear - - section: API Request Tool + - page: When to use API Request or Function tools + path: tools/api-request-vs-function.mdx + icon: fa-light fa-code-compare + - section: API Request tool path: tools/api-request.mdx icon: fa-light fa-globe contents: - page: Coffee-order quickstart path: tools/api-request/quickstart.mdx - - page: Configure requests + - page: Customize requests path: tools/api-request/configuration.mdx - page: Handle latency and retries path: tools/api-request/reliability.mdx @@ -229,7 +229,10 @@ navigation: path: tools/api-request/response-handling.mdx - page: Use response data path: tools/api-request/response-data.mdx - - section: Transfer call tool + - page: Function tools + path: tools/custom-tools.mdx + icon: fa-light fa-screwdriver-wrench + - section: Transfer Call tool path: tools/transfer-call.mdx icon: fa-solid fa-phone contents: @@ -239,28 +242,45 @@ navigation: path: tools/transfer-call/warm-transfer.mdx - page: Assistant-based warm transfer path: calls/assistant-based-warm-transfer.mdx - - page: Voicemail tool + - section: Handoff tool + path: squads/handoff.mdx + icon: fa-light fa-hand-holding-hand + contents: + - page: Configure handoff destinations + path: squads/handoff/destinations.mdx + - page: Pass context and variables + path: squads/handoff/context-and-variables.mdx + - page: Configure messages and rejection rules + path: squads/handoff/messages-and-rejection.mdx + - page: Troubleshoot handoffs + path: squads/handoff/troubleshooting.mdx + - section: Voicemail tool path: tools/voicemail-tool.mdx icon: fa-light fa-voicemail - - page: Custom (Function) tools - path: tools/custom-tools.mdx - icon: fa-light fa-screwdriver-wrench + contents: + - page: Configure the Voicemail tool + path: tools/voicemail-tool/configure.mdx - page: Client-side tools (Web SDK) path: tools/client-side-websdk.mdx icon: fa-light fa-browser - - page: Tool rejection plan - path: tools/tool-rejection-plan.mdx - icon: fa-light fa-shield-xmark - - page: Static variables and aliases - path: tools/static-variables-and-aliases.mdx - icon: fa-light fa-arrow-right-arrow-left - - page: Custom tools troubleshooting - path: tools/custom-tools-troubleshooting.mdx - icon: fa-light fa-wrench - - link: Handoff tool - href: /squads/handoff - icon: fa-light fa-hand-holding-hand - - section: External tools + - section: Knowledge bases + path: knowledge-base/knowledge-base.mdx + icon: fa-light fa-book + contents: + - page: Query tool + path: knowledge-base/using-query-tool.mdx + icon: fa-light fa-magnifying-glass + - page: Custom knowledge base + path: knowledge-base/custom-knowledge-base.mdx + icon: fa-light fa-server + - page: Implement the custom endpoint + path: knowledge-base/implement-custom-endpoint.mdx + icon: fa-light fa-code + - link: MCP tools + href: /tools/mcp + icon: fa-light fa-network-wired + - section: Integrations + path: tools/integrations.mdx icon: fa-light fa-cubes contents: - page: Google Calendar @@ -275,19 +295,27 @@ navigation: - page: GoHighLevel path: tools/go-high-level.mdx icon: fa-light fa-arrow-up - - section: Knowledge retrieval - path: knowledge-base/knowledge-base.mdx - icon: fa-light fa-book + - section: Static variables and aliases + path: tools/static-variables-and-aliases.mdx + icon: fa-light fa-arrow-right-arrow-left contents: - - page: Query tool - path: knowledge-base/using-query-tool.mdx - icon: fa-light fa-magnifying-glass - - page: Custom knowledge base - path: knowledge-base/custom-knowledge-base.mdx - icon: fa-light fa-server + - page: How tool variables work + path: tools/static-variables-and-aliases/how-variables-work.mdx + - page: Set static parameters + path: tools/static-variables-and-aliases/static-parameters.mdx + - page: Extract and chain values + path: tools/static-variables-and-aliases/extract-and-chain.mdx + - page: Troubleshoot tool variables + path: tools/static-variables-and-aliases/troubleshooting.mdx + - page: Tool rejection plan + path: tools/tool-rejection-plan.mdx + icon: fa-light fa-shield-xmark - page: Argument encryption path: tools/arguments-encryption.mdx icon: fa-light fa-lock + - page: Troubleshoot tools + path: tools/custom-tools-troubleshooting.mdx + icon: fa-light fa-wrench - page: Custom keywords path: customization/custom-keywords.mdx icon: fa-light fa-bullseye @@ -533,9 +561,18 @@ navigation: - page: Overview path: squads.mdx icon: fa-light fa-eye - - page: Handoff tool + - section: Handoff tool path: squads/handoff.mdx icon: fa-light fa-hand-holding-hand + contents: + - page: Configure handoff destinations + path: squads/handoff/destinations.mdx + - page: Pass context and variables + path: squads/handoff/context-and-variables.mdx + - page: Configure messages and rejection rules + path: squads/handoff/messages-and-rejection.mdx + - page: Troubleshoot handoffs + path: squads/handoff/troubleshooting.mdx - page: Passing data between assistants path: squads/passing-data-between-assistants.mdx icon: fa-light fa-share-nodes @@ -1025,6 +1062,8 @@ redirects: destination: "/test/simulations-best-practices#choose-chat-or-voice-deliberately" - source: /tools/code-tool destination: /tools/api-request + - source: /tools/make + destination: /tools/mcp - source: /security-and-privacy/retrieve-call-artifacts destination: /assistants/retrieve-call-artifacts - source: /developer-documentation diff --git a/fern/knowledge-base/custom-knowledge-base.mdx b/fern/knowledge-base/custom-knowledge-base.mdx index c6049d754..8186a062c 100644 --- a/fern/knowledge-base/custom-knowledge-base.mdx +++ b/fern/knowledge-base/custom-knowledge-base.mdx @@ -1,7 +1,8 @@ --- -title: Custom Knowledge Base +title: Custom knowledge base subtitle: Create and implement your own knowledge base server for full control over document retrieval slug: knowledge-base/custom-knowledge-base +description: Build a custom knowledge base in Vapi with your own retrieval server, using your vector database or search logic to control how an assistant finds answers. --- ## Overview @@ -152,383 +153,12 @@ updated_assistant = client.assistants.update( When updating an assistant's model, you must include the **complete model object** including all existing messages and configuration. The API replaces the entire model object and doesn't support partial updates for nested objects. -## Implementing the Custom Endpoint - -Your custom knowledge base server must handle POST requests at the configured URL and return structured responses. - -### Request Structure - -Vapi will send requests to your endpoint with the following structure: - -```json title="Request Format" -{ - "message": { - "type": "knowledge-base-request", - "messages": [ - { - "role": "user", - "content": "What is your return policy?" - }, - { - "role": "assistant", - "content": "I'll help you with information about our return policy." - }, - { - "role": "user", - "content": "How long do I have to return items?" - } - ] - // Additional metadata fields about the call or chat will be included here - } -} -``` - -### Response Options - -Your endpoint can respond in two ways: - -#### Option 1: Return Documents for AI Processing - -Return an array of relevant documents that the AI will use to formulate a response: - -```json title="Document Response" -{ - "documents": [ - { - "content": "Our return policy allows customers to return items within 30 days of purchase for a full refund. Items must be in original condition with tags attached.", - "similarity": 0.92, - "uuid": "doc-return-policy-1" // optional - }, - { - "content": "Extended return periods apply during holiday seasons - customers have up to 60 days to return items purchased between November 1st and December 31st.", - "similarity": 0.78, - "uuid": "doc-return-policy-holiday" // optional - } - ] -} -``` - -#### Option 2: Return Direct Response - -Return a complete response that the assistant will speak directly: - -```json title="Direct Response" -{ - "message": { - "role": "assistant", - "content": "You have 30 days to return items for a full refund. Items must be in original condition with tags attached. During the holiday season (November 1st to December 31st), you get an extended 60-day return period." - } -} -``` - -### Implementation Examples - -Here are complete server implementations in different languages: - - -```typescript title="Node.js/Express" -import express from 'express'; -import crypto from 'crypto'; - -const app = express(); -app.use(express.json()); - -// Your knowledge base data (replace with actual database/vector store) -const documents = [ - { - id: "return-policy-1", - content: "Our return policy allows customers to return items within 30 days of purchase for a full refund. Items must be in original condition with tags attached.", - category: "returns" - }, - { - id: "shipping-info-1", - content: "We offer free shipping on orders over $50. Standard shipping takes 3-5 business days.", - category: "shipping" - } -]; - -app.post('/kb/search', (req, res) => { - try { - // Verify webhook secret (recommended) - const signature = req.headers['x-vapi-signature']; - const secret = process.env.VAPI_WEBHOOK_SECRET; - - if (signature && secret) { - const expectedSignature = crypto - .createHmac('sha256', secret) - .update(JSON.stringify(req.body)) - .digest('hex'); - - if (signature !== `sha256=${expectedSignature}`) { - return res.status(401).json({ error: 'Invalid signature' }); - } - } - - const { message } = req.body; - - if (message.type !== 'knowledge-base-request') { - return res.status(400).json({ error: 'Invalid request type' }); - } - - // Get the latest user message - const userMessages = message.messages.filter(msg => msg.role === 'user'); - const latestQuery = userMessages[userMessages.length - 1]?.content || ''; - - // Simple keyword-based search (replace with vector search) - const relevantDocs = documents - .map(doc => ({ - ...doc, - similarity: calculateSimilarity(latestQuery, doc.content) - })) - .filter(doc => doc.similarity > 0.1) - .sort((a, b) => b.similarity - a.similarity) - .slice(0, 3); - - // Return documents for AI processing - res.json({ - documents: relevantDocs.map(doc => ({ - content: doc.content, - similarity: doc.similarity, - uuid: doc.id - })) - }); - - } catch (error) { - console.error('Knowledge base search error:', error); - res.status(500).json({ error: 'Internal server error' }); - } -}); - -function calculateSimilarity(query: string, content: string): number { - // Simple similarity calculation (replace with proper vector similarity) - const queryWords = query.toLowerCase().split(' '); - const contentWords = content.toLowerCase().split(' '); - const matches = queryWords.filter(word => - contentWords.some(cWord => cWord.includes(word)) - ).length; - - return matches / queryWords.length; -} - -app.listen(3000, () => { - console.log('Custom Knowledge Base server running on port 3000'); -}); -``` - -```python title="Python/FastAPI" -from fastapi import FastAPI, HTTPException, Request -import hashlib -import hmac -import os -from typing import List, Dict, Any -import uvicorn - -app = FastAPI() - -# Your knowledge base data (replace with actual database/vector store) -documents = [ - { - "id": "return-policy-1", - "content": "Our return policy allows customers to return items within 30 days of purchase for a full refund. Items must be in original condition with tags attached.", - "category": "returns" - }, - { - "id": "shipping-info-1", - "content": "We offer free shipping on orders over $50. Standard shipping takes 3-5 business days.", - "category": "shipping" - } -] - -@app.post("/kb/search") -async def knowledge_base_search(request: Request): - try: - body = await request.json() - - # Verify webhook secret (recommended) - signature = request.headers.get('x-vapi-signature') - secret = os.getenv('VAPI_WEBHOOK_SECRET') - - if signature and secret: - body_bytes = await request.body() - expected_signature = f"sha256={hmac.new(secret.encode(), body_bytes, hashlib.sha256).hexdigest()}" - - if signature != expected_signature: - raise HTTPException(status_code=401, detail="Invalid signature") - - message = body.get('message', {}) - - if message.get('type') != 'knowledge-base-request': - raise HTTPException(status_code=400, detail="Invalid request type") - - # Get the latest user message - user_messages = [msg for msg in message.get('messages', []) if msg.get('role') == 'user'] - latest_query = user_messages[-1].get('content', '') if user_messages else '' - - # Simple keyword-based search (replace with vector search) - relevant_docs = [] - for doc in documents: - similarity = calculate_similarity(latest_query, doc['content']) - if similarity > 0.1: - relevant_docs.append({ - **doc, - 'similarity': similarity - }) - - # Sort by similarity and take top 3 - relevant_docs.sort(key=lambda x: x['similarity'], reverse=True) - relevant_docs = relevant_docs[:3] - - # Return documents for AI processing - return { - "documents": [ - { - "content": doc['content'], - "similarity": doc['similarity'], - "uuid": doc['id'] - } - for doc in relevant_docs - ] - } - - except Exception as error: - print(f"Knowledge base search error: {error}") - raise HTTPException(status_code=500, detail="Internal server error") - -def calculate_similarity(query: str, content: str) -> float: - """Simple similarity calculation (replace with proper vector similarity)""" - query_words = query.lower().split() - content_words = content.lower().split() - - matches = sum(1 for word in query_words - if any(word in cword for cword in content_words)) - - return matches / len(query_words) if query_words else 0 - -if __name__ == "__main__": - uvicorn.run(app, host="0.0.0.0", port=8000) -``` - - -## Advanced Implementation Patterns - -### Vector Database Integration - -For production use, integrate with a proper vector database: - - -```typescript title="Pinecone Integration" -import { PineconeClient } from '@pinecone-database/pinecone'; -import OpenAI from 'openai'; - -const pinecone = new PineconeClient(); -const openai = new OpenAI(); - -app.post('/kb/search', async (req, res) => { - try { - const { message } = req.body; - const latestQuery = getLatestUserMessage(message); - - // Generate embedding for the query - const embedding = await openai.embeddings.create({ - model: 'text-embedding-ada-002', - input: latestQuery - }); - - // Search vector database - const index = pinecone.Index('knowledge-base'); - const searchResults = await index.query({ - vector: embedding.data[0].embedding, - topK: 5, - includeMetadata: true - }); - - // Format response - const documents = searchResults.matches.map(match => ({ - content: match.metadata.content, - similarity: match.score, - uuid: match.id - })); - - res.json({ documents }); - } catch (error) { - console.error('Vector search error:', error); - res.status(500).json({ error: 'Search failed' }); - } -}); -``` - -```python title="Weaviate Integration" -import weaviate -from sentence_transformers import SentenceTransformer - -client = weaviate.Client("http://localhost:8080") -model = SentenceTransformer('all-MiniLM-L6-v2') - -@app.post("/kb/search") -async def search_with_weaviate(request: Request): - try: - body = await request.json() - message = body.get('message', {}) - latest_query = get_latest_user_message(message) - - # Search using Weaviate - result = client.query.get("Document", ["content", "title"]) \ - .with_near_text({"concepts": [latest_query]}) \ - .with_limit(5) \ - .with_additional(["certainty"]) \ - .do() - - documents = [] - for doc in result['data']['Get']['Document']: - documents.append({ - "content": doc['content'], - "similarity": doc['_additional']['certainty'], - "uuid": doc.get('title', 'unknown') - }) - - return {"documents": documents} - except Exception as error: - raise HTTPException(status_code=500, detail=str(error)) -``` - - -## Security and Best Practices - -### Performance Optimization - - - **Response time is critical**: Your endpoint should respond in **milliseconds** (ideally under ~50ms) for optimal user experience. While Vapi allows up to 10 seconds timeout, slower responses will significantly affect your assistant's conversational flow and response quality. - - - - **Cache frequently requested documents** and implement request timeouts to ensure fast response times. Consider using in-memory caches, CDNs, or pre-computed embeddings for faster retrieval. - - -### Error Handling - -Always handle errors gracefully and return appropriate HTTP status codes: - -```typescript -app.post('/kb/search', async (req, res) => { - try { - // Your search logic here - } catch (error) { - console.error('Search error:', error); - - // Return empty documents rather than failing - res.json({ - documents: [], - error: "Search temporarily unavailable" - }); - } -}); -``` - ## Next Steps Now that you have a custom knowledge base implementation: -- **[Query Tool Configuration](/knowledge-base/using-query-tool):** Learn advanced query tool configurations +- **[Implement the custom endpoint](/knowledge-base/implement-custom-endpoint):** Handle the retrieval request and return results from your server +- **[Query tool configuration](/knowledge-base/using-query-tool):** Learn advanced Query tool configurations - **[Assistant Configuration](/assistants):** Optimize your assistant's use of knowledge bases diff --git a/fern/knowledge-base/implement-custom-endpoint.mdx b/fern/knowledge-base/implement-custom-endpoint.mdx new file mode 100644 index 000000000..370e9ea3d --- /dev/null +++ b/fern/knowledge-base/implement-custom-endpoint.mdx @@ -0,0 +1,380 @@ +--- +title: Implement the custom endpoint +subtitle: Handle Vapi's retrieval request and return documents or a direct response from your own server +description: Handle the Vapi knowledge base request on your own server, return documents or a direct answer, integrate a vector database, and harden the endpoint. +slug: knowledge-base/implement-custom-endpoint +--- + +Vapi sends your server a request whenever the assistant needs information from the knowledge base. Your endpoint decides what comes back: a set of documents for the model to read, or a finished answer to speak. + +## Implementing the Custom Endpoint + +Your custom knowledge base server must handle POST requests at the configured URL and return structured responses. + +### Request Structure + +Vapi will send requests to your endpoint with the following structure: + +```json title="Request Format" +{ + "message": { + "type": "knowledge-base-request", + "messages": [ + { + "role": "user", + "content": "What is your return policy?" + }, + { + "role": "assistant", + "content": "I'll help you with information about our return policy." + }, + { + "role": "user", + "content": "How long do I have to return items?" + } + ] + // Additional metadata fields about the call or chat will be included here + } +} +``` + +### Response Options + +Your endpoint can respond in two ways: + +#### Option 1: Return Documents for AI Processing + +Return an array of relevant documents that the AI will use to formulate a response: + +```json title="Document Response" +{ + "documents": [ + { + "content": "Our return policy allows customers to return items within 30 days of purchase for a full refund. Items must be in original condition with tags attached.", + "similarity": 0.92, + "uuid": "doc-return-policy-1" // optional + }, + { + "content": "Extended return periods apply during holiday seasons - customers have up to 60 days to return items purchased between November 1st and December 31st.", + "similarity": 0.78, + "uuid": "doc-return-policy-holiday" // optional + } + ] +} +``` + +#### Option 2: Return Direct Response + +Return a complete response that the assistant will speak directly: + +```json title="Direct Response" +{ + "message": { + "role": "assistant", + "content": "You have 30 days to return items for a full refund. Items must be in original condition with tags attached. During the holiday season (November 1st to December 31st), you get an extended 60-day return period." + } +} +``` + +### Implementation Examples + +Here are complete server implementations in different languages: + + +```typescript title="Node.js/Express" +import express from 'express'; +import crypto from 'crypto'; + +const app = express(); +app.use(express.json()); + +// Your knowledge base data (replace with actual database/vector store) +const documents = [ + { + id: "return-policy-1", + content: "Our return policy allows customers to return items within 30 days of purchase for a full refund. Items must be in original condition with tags attached.", + category: "returns" + }, + { + id: "shipping-info-1", + content: "We offer free shipping on orders over $50. Standard shipping takes 3-5 business days.", + category: "shipping" + } +]; + +app.post('/kb/search', (req, res) => { + try { + // Verify webhook secret (recommended) + const signature = req.headers['x-vapi-signature']; + const secret = process.env.VAPI_WEBHOOK_SECRET; + + if (signature && secret) { + const expectedSignature = crypto + .createHmac('sha256', secret) + .update(JSON.stringify(req.body)) + .digest('hex'); + + if (signature !== `sha256=${expectedSignature}`) { + return res.status(401).json({ error: 'Invalid signature' }); + } + } + + const { message } = req.body; + + if (message.type !== 'knowledge-base-request') { + return res.status(400).json({ error: 'Invalid request type' }); + } + + // Get the latest user message + const userMessages = message.messages.filter(msg => msg.role === 'user'); + const latestQuery = userMessages[userMessages.length - 1]?.content || ''; + + // Simple keyword-based search (replace with vector search) + const relevantDocs = documents + .map(doc => ({ + ...doc, + similarity: calculateSimilarity(latestQuery, doc.content) + })) + .filter(doc => doc.similarity > 0.1) + .sort((a, b) => b.similarity - a.similarity) + .slice(0, 3); + + // Return documents for AI processing + res.json({ + documents: relevantDocs.map(doc => ({ + content: doc.content, + similarity: doc.similarity, + uuid: doc.id + })) + }); + + } catch (error) { + console.error('Knowledge base search error:', error); + res.status(500).json({ error: 'Internal server error' }); + } +}); + +function calculateSimilarity(query: string, content: string): number { + // Simple similarity calculation (replace with proper vector similarity) + const queryWords = query.toLowerCase().split(' '); + const contentWords = content.toLowerCase().split(' '); + const matches = queryWords.filter(word => + contentWords.some(cWord => cWord.includes(word)) + ).length; + + return matches / queryWords.length; +} + +app.listen(3000, () => { + console.log('Custom Knowledge Base server running on port 3000'); +}); +``` + +```python title="Python/FastAPI" +from fastapi import FastAPI, HTTPException, Request +import hashlib +import hmac +import os +from typing import List, Dict, Any +import uvicorn + +app = FastAPI() + +# Your knowledge base data (replace with actual database/vector store) +documents = [ + { + "id": "return-policy-1", + "content": "Our return policy allows customers to return items within 30 days of purchase for a full refund. Items must be in original condition with tags attached.", + "category": "returns" + }, + { + "id": "shipping-info-1", + "content": "We offer free shipping on orders over $50. Standard shipping takes 3-5 business days.", + "category": "shipping" + } +] + +@app.post("/kb/search") +async def knowledge_base_search(request: Request): + try: + body = await request.json() + + # Verify webhook secret (recommended) + signature = request.headers.get('x-vapi-signature') + secret = os.getenv('VAPI_WEBHOOK_SECRET') + + if signature and secret: + body_bytes = await request.body() + expected_signature = f"sha256={hmac.new(secret.encode(), body_bytes, hashlib.sha256).hexdigest()}" + + if signature != expected_signature: + raise HTTPException(status_code=401, detail="Invalid signature") + + message = body.get('message', {}) + + if message.get('type') != 'knowledge-base-request': + raise HTTPException(status_code=400, detail="Invalid request type") + + # Get the latest user message + user_messages = [msg for msg in message.get('messages', []) if msg.get('role') == 'user'] + latest_query = user_messages[-1].get('content', '') if user_messages else '' + + # Simple keyword-based search (replace with vector search) + relevant_docs = [] + for doc in documents: + similarity = calculate_similarity(latest_query, doc['content']) + if similarity > 0.1: + relevant_docs.append({ + **doc, + 'similarity': similarity + }) + + # Sort by similarity and take top 3 + relevant_docs.sort(key=lambda x: x['similarity'], reverse=True) + relevant_docs = relevant_docs[:3] + + # Return documents for AI processing + return { + "documents": [ + { + "content": doc['content'], + "similarity": doc['similarity'], + "uuid": doc['id'] + } + for doc in relevant_docs + ] + } + + except Exception as error: + print(f"Knowledge base search error: {error}") + raise HTTPException(status_code=500, detail="Internal server error") + +def calculate_similarity(query: str, content: str) -> float: + """Simple similarity calculation (replace with proper vector similarity)""" + query_words = query.lower().split() + content_words = content.lower().split() + + matches = sum(1 for word in query_words + if any(word in cword for cword in content_words)) + + return matches / len(query_words) if query_words else 0 + +if __name__ == "__main__": + uvicorn.run(app, host="0.0.0.0", port=8000) +``` + + +## Advanced Implementation Patterns + +### Vector Database Integration + +For production use, integrate with a proper vector database: + + +```typescript title="Pinecone Integration" +import { PineconeClient } from '@pinecone-database/pinecone'; +import OpenAI from 'openai'; + +const pinecone = new PineconeClient(); +const openai = new OpenAI(); + +app.post('/kb/search', async (req, res) => { + try { + const { message } = req.body; + const latestQuery = getLatestUserMessage(message); + + // Generate embedding for the query + const embedding = await openai.embeddings.create({ + model: 'text-embedding-ada-002', + input: latestQuery + }); + + // Search vector database + const index = pinecone.Index('knowledge-base'); + const searchResults = await index.query({ + vector: embedding.data[0].embedding, + topK: 5, + includeMetadata: true + }); + + // Format response + const documents = searchResults.matches.map(match => ({ + content: match.metadata.content, + similarity: match.score, + uuid: match.id + })); + + res.json({ documents }); + } catch (error) { + console.error('Vector search error:', error); + res.status(500).json({ error: 'Search failed' }); + } +}); +``` + +```python title="Weaviate Integration" +import weaviate +from sentence_transformers import SentenceTransformer + +client = weaviate.Client("http://localhost:8080") +model = SentenceTransformer('all-MiniLM-L6-v2') + +@app.post("/kb/search") +async def search_with_weaviate(request: Request): + try: + body = await request.json() + message = body.get('message', {}) + latest_query = get_latest_user_message(message) + + # Search using Weaviate + result = client.query.get("Document", ["content", "title"]) \ + .with_near_text({"concepts": [latest_query]}) \ + .with_limit(5) \ + .with_additional(["certainty"]) \ + .do() + + documents = [] + for doc in result['data']['Get']['Document']: + documents.append({ + "content": doc['content'], + "similarity": doc['_additional']['certainty'], + "uuid": doc.get('title', 'unknown') + }) + + return {"documents": documents} + except Exception as error: + raise HTTPException(status_code=500, detail=str(error)) +``` + + +## Security and Best Practices + +### Performance Optimization + + + **Response time is critical**: Your endpoint should respond in **milliseconds** (ideally under ~50ms) for optimal user experience. While Vapi allows up to 10 seconds timeout, slower responses will significantly affect your assistant's conversational flow and response quality. + + + + **Cache frequently requested documents** and implement request timeouts to ensure fast response times. Consider using in-memory caches, CDNs, or pre-computed embeddings for faster retrieval. + + +### Error Handling + +Always handle errors gracefully and return appropriate HTTP status codes: + +```typescript +app.post('/kb/search', async (req, res) => { + try { + // Your search logic here + } catch (error) { + console.error('Search error:', error); + + // Return empty documents rather than failing + res.json({ + documents: [], + error: "Search temporarily unavailable" + }); + } +}); +``` diff --git a/fern/knowledge-base/knowledge-base.mdx b/fern/knowledge-base/knowledge-base.mdx index 43e85ada4..e2157c6a9 100644 --- a/fern/knowledge-base/knowledge-base.mdx +++ b/fern/knowledge-base/knowledge-base.mdx @@ -1,11 +1,13 @@ --- -title: Introduction to Knowledge Bases +title: Knowledge bases subtitle: >- Learn how to create and integrate custom knowledge bases into your AI assistants. slug: knowledge-base --- +A knowledge base is a set of documents an assistant can search during a call to answer questions it was not given in its prompt. This section covers creating a knowledge base, querying it with the query tool, and replacing Vapi's built-in retrieval with a server of your own. +