*** title: 'Example: Using Grok features' subtitle: Connect an inbound call to a Grok voice agent ------------------------------------------------------- ## Overview This inbound example showcases Grok tools (function calling, file\_search, web\_search, x\_search) with barge-in for telephony use. The same tool configuration applies to outbound calls—reuse the tools and prompt in your outbound scenario and swap the call entrypoint. **⬇️ Jump to the [Full VoxEngine scenario](#full-voxengine-scenario).** ## Prerequisites * Set up an inbound entrypoint for the caller: * Phone number: [https://voximplant.com/docs/getting-started/basic-concepts/phone-numbers](https://voximplant.com/docs/getting-started/basic-concepts/phone-numbers) * WhatsApp: [https://voximplant.com/docs/guides/integrations/whatsapp](https://voximplant.com/docs/guides/integrations/whatsapp) * SIP user / SIP registration: [https://voximplant.com/docs/guides/calls/sip](https://voximplant.com/docs/guides/calls/sip) * Voximplant user: [https://voximplant.com/docs/getting-started/basic-concepts/users](https://voximplant.com/docs/getting-started/basic-concepts/users) (see also [https://voximplant.com/docs/guides/calls/scenarios#how-to-call-a-voximplant-user](https://voximplant.com/docs/guides/calls/scenarios#how-to-call-a-voximplant-user)) * Create a routing rule that points the destination to this scenario: [https://voximplant.com/docs/getting-started/basic-concepts/routing-rules](https://voximplant.com/docs/getting-started/basic-concepts/routing-rules) * Store your Grok API key in `ApplicationStorage` under `XAI_API_KEY`. * If you use `file_search`, upload documents and set `COLLECTION_ID` accordingly. ## Usage highlights * Create a `VoiceAgentAPIClient` with `Grok.createVoiceAgentAPIClient(...)`. * Configure the session with `voice`, `turn_detection`, `instructions`, and tools. * Bridge audio with `VoxEngine.sendMediaBetween(call, client)`. * Handle function calls with `ResponseFunctionCallArgumentsDone`. ### Feature summary * **Function calling**: Let Grok request server-side actions, then respond with structured outputs. See [Function calling](#function-calling). Also see Grok docs: [https://docs.x.ai/docs/guides/tools/overview#function-calling](https://docs.x.ai/docs/guides/tools/overview#function-calling) * **RAG with file\_search**: Ground responses in your uploaded documents using vector search. See [RAG with file\_search](#rag-with-file_search). Also see Grok docs: [https://docs.x.ai/docs/guides/tools/overview#file-search](https://docs.x.ai/docs/guides/tools/overview#file-search) * **Web search**: Allow Grok to fetch current public information when needed. See [Web search](#web-search). Also see Grok docs: [https://docs.x.ai/docs/guides/tools/overview#web-search](https://docs.x.ai/docs/guides/tools/overview#web-search) * **X/Twitter search**: Constrain Grok to specific X handles for social lookups. See [X/Twitter search](#xtwitter-search). Also see Grok docs: [https://docs.x.ai/docs/guides/tools/overview#x-search](https://docs.x.ai/docs/guides/tools/overview#x-search) ### Turn detection & barge-in When `InputAudioBufferSpeechStarted` fires, clear the media buffer so the caller can interrupt the agent: ```js voiceAgentAPIClient.addEventListener( Grok.VoiceAgentAPIEvents.InputAudioBufferSpeechStarted, () => voiceAgentAPIClient.clearMediaBuffer() ); ``` ## Function calling Function calling lets Grok request actions from VoxEngine (transfer, hang up, fetch data) and receive a structured response. For official Grok tool guidance, see [https://docs.x.ai/docs/guides/tools/overview#function-calling](https://docs.x.ai/docs/guides/tools/overview#function-calling). ```js { type: "function", name: "forward_to_agent", description: "Forward the user to a live agent", parameters: { type: "object", properties: {}, required: [], }, } ``` Handle tool calls and return outputs to the agent: ```js voiceAgentAPIClient.addEventListener( Grok.VoiceAgentAPIEvents.ResponseFunctionCallArgumentsDone, (event) => { const { name, call_id } = event?.data?.payload || {}; if (name !== "forward_to_agent" && name !== "hangup_call") return; const output = name === "forward_to_agent" ? { result: "Forwarding your call to a live agent. Please hold on." } : { result: "Have a great day, goodbye!" }; voiceAgentAPIClient.conversationItemCreate({ item: { type: "function_call_output", call_id, output: JSON.stringify(output), }, }); voiceAgentAPIClient.responseCreate({}); } ); ``` ## RAG with file\_search Use `file_search` to ground responses in your documents. Upload files to Grok, then reference the collection (vector store) ID in your session tools. For official Grok tool guidance, see [https://docs.x.ai/docs/guides/tools/overview#file-search](https://docs.x.ai/docs/guides/tools/overview#file-search). ```js { type: "file_search", vector_store_ids: [COLLECTION_ID], max_num_results: 5, } ``` * Keep your collection focused on the topics the agent should answer. * Tune `max_num_results` to balance relevance and speed. ## Web search Enable `web_search` when you want Grok to fetch public web information at runtime. For official Grok tool guidance, see [https://docs.x.ai/docs/guides/tools/overview#web-search](https://docs.x.ai/docs/guides/tools/overview#web-search). ```js { type: "web_search" } ``` ## X/Twitter search Use `x_search` to limit Grok's social search to specific X handles. For official Grok tool guidance, see [https://docs.x.ai/docs/guides/tools/overview#x-search](https://docs.x.ai/docs/guides/tools/overview#x-search). ```js { type: "x_search", allowed_x_handles: ["voximplant", "aylarov"], } ``` ## Configure before you run * Set `XAI_API_KEY` in `ApplicationStorage`. * Update `COLLECTION_ID` to point at your uploaded documents (or remove `file_search`). * Adjust the `SYSTEM_PROMPT` to match your brand voice and escalation rules. ## Try it ## Notes [See the VoxEngine API Reference for more details](https://voximplant.com/docs/references/voxengine/grok). ## Full VoxEngine scenario This scenario includes barge-in handling, function calling, file search, web search, and X search. ```javascript title={"voxeengine-grok-features.js"} maxLines={0} require(Modules.Grok); require(Modules.ApplicationStorage); const SYSTEM_PROMPT = ` Your name is Voxi. You are a helpful voice assistant for phone callers representing the company Voximplant (pronounced VOX-im-plant). You can answer questions about the company, its voice AI integrations, and X/Twitter posts from the "voximplant" and "aylarov" handles. "aylarov" is the X handle for Alexey Aylarov, Voximplant's CEO. Keep responses short and telephony-friendly (usually 1-2 sentences). If the user asks for a live agent or an operator, call the "forward_to_agent" function. If the user says goodbye, call the "hangup_call" function. When answering a company/product question, prefer searching the knowledge base first. `; const COLLECTION_ID = "collection_4c5a63ab-f739-4c13-93d2-05b74095c34a"; // uploaded documents to show RAG // -------------------- Grok Voice Agent settings -------------------- const SESSION_PARAMETERS = { session: { voice: "Ara", turn_detection: {type: "server_vad"}, instructions: SYSTEM_PROMPT, tools: [ {type: "web_search"}, { type: "file_search", vector_store_ids: [COLLECTION_ID], max_num_results: 5, }, { type: "x_search", allowed_x_handles: ["voximplant", "aylarov"], }, { type: "function", name: "forward_to_agent", description: "Forward the user to a live agent", parameters: { type: "object", properties: {}, required: [], }, }, { type: "function", name: "hangup_call", description: "Hangup the call", parameters: { type: "object", properties: {}, required: [], }, }, ], }, }; VoxEngine.addEventListener(AppEvents.CallAlerting, async ({call}) => { let voiceAIClient = undefined; let hangupCall = false, forwardToLiveAgent = false; call.answer(); call.record({hd_audio: true, stereo: true}); // optional: call recording const callCloseHandler = () => { voiceAIClient?.close(); VoxEngine.terminate(); }; call.addEventListener(CallEvents.Disconnected, callCloseHandler); call.addEventListener(CallEvents.Failed, callCloseHandler); try { voiceAIClient = await Grok.createVoiceAgentAPIClient({ xAIApiKey: (await ApplicationStorage.get("XAI_API_KEY")).value, onWebSocketClose: (event) => { Logger.write(`===${event.name}===>${JSON.stringify(event.data)}`); VoxEngine.terminate(); }, }); voiceAIClient.addEventListener(Grok.VoiceAgentAPIEvents.ConversationCreated, (event) => { Logger.write(`===${event.name}===>${JSON.stringify(event.data)}`); voiceAIClient.sessionUpdate(SESSION_PARAMETERS); }); voiceAIClient.addEventListener(Grok.VoiceAgentAPIEvents.SessionUpdated, (event) => { Logger.write(`===${event.name}===>${JSON.stringify(event.data)}`); VoxEngine.sendMediaBetween(call, voiceAIClient); voiceAIClient.responseCreate({instructions: "Hello."}); }); // -------------------- Barge-in (keep it interruption-friendly) -------------------- voiceAIClient.addEventListener(Grok.VoiceAgentAPIEvents.InputAudioBufferSpeechStarted, (event) => { Logger.write(`===${event.name}===>${JSON.stringify(event.data)}`); voiceAIClient.clearMediaBuffer(); }); // -------------------- Function calling -------------------- voiceAIClient.addEventListener(Grok.VoiceAgentAPIEvents.ResponseFunctionCallArgumentsDone, (event) => { Logger.write(`===${event.name}===>${JSON.stringify(event.data)}`); const {name, call_id} = event?.data?.payload || {}; let output; // Ignore server-side tools like collections_search / web_search / x_search if (name !== "forward_to_agent" && name !== "hangup_call") { Logger.write(`===Ignoring unhandled function call: ${name}===`); return; } if (name === "forward_to_agent") { forwardToLiveAgent = true; output = {result: "Forwarding your call to a live agent. Please hold on."}; } else if (name === "hangup_call") { hangupCall = true; output = {result: "Have a great day, goodbye!"}; } // Create a conversationItem and send it voiceAIClient.conversationItemCreate({ item: { type: "function_call_output", call_id, output: JSON.stringify(output), }, }); voiceAIClient.responseCreate({}); }); // -------------------- Log Other Events -------------------- [ CallEvents.FirstAudioPacketReceived, Grok.Events.WebSocketMediaStarted, Grok.VoiceAgentAPIEvents.InputAudioBufferSpeechStopped, Grok.VoiceAgentAPIEvents.ConversationItemInputAudioTranscriptionCompleted, Grok.VoiceAgentAPIEvents.ConversationItemAdded, Grok.VoiceAgentAPIEvents.ResponseCreated, Grok.VoiceAgentAPIEvents.ResponseOutputItemAdded, Grok.VoiceAgentAPIEvents.ResponseDone, Grok.VoiceAgentAPIEvents.ResponseOutputAudioTranscriptDelta, Grok.VoiceAgentAPIEvents.ResponseOutputAudioTranscriptDone, Grok.VoiceAgentAPIEvents.ResponseOutputAudioDelta, // Not in enum Grok.VoiceAgentAPIEvents.ResponseOutputAudioDone, Grok.VoiceAgentAPIEvents.ResponseOutputItemDone, Grok.VoiceAgentAPIEvents.ConnectorInformation, Grok.VoiceAgentAPIEvents.InputAudioBufferCommitted, Grok.VoiceAgentAPIEvents.WebSocketError, Grok.VoiceAgentAPIEvents.Unknown, ].forEach((evtName) => { voiceAIClient.addEventListener(evtName, (e) => { Logger.write(`===${e.name}===>${JSON.stringify(e)}`); }); }); voiceAIClient.addEventListener(Grok.Events.WebSocketMediaEnded, (event) => { Logger.write(`===${event.name}===>${JSON.stringify(event.data)}`); if (hangupCall) callCloseHandler(); else if (forwardToLiveAgent) { call.say("Here is where I would forward the call via the phone network, SIP, or WhatsApp."); // See the forwardCallToPSTN, forwardCallToSIP, forwardCallToUser, and handleBlindTransfer call methods // For this simple demo, we will just close and hang-up call.addEventListener(CallEvents.PlaybackFinished, callCloseHandler); } }); } catch (error) { Logger.write("===SOMETHING_WENT_WRONG==="); Logger.write(error); VoxEngine.terminate(); } }); ```