Example: Function calling

View as MarkdownOpen in Claude

This example answers an inbound Voximplant call, connects it to Deepgram Voice Agent, and handles function calls (tool requests) from the agent inside VoxEngine.

⬇️ Jump to the Full VoxEngine scenario.

Prerequisites

Session setup

The Voice Agent session is configured via a settingsOptions object passed to Deepgram.createVoiceAgentClient(...).

For function calling, the key part is SETTINGS_OPTIONS.agent.think.functions:

  • name, description, parameters: define the tool schema the LLM can call
  • client_side: true: ensures VoxEngine receives FunctionCallRequest and can respond

Connect call audio

Once the Deepgram.VoiceAgentClient is created, bridge audio both ways:

Connect call audio
1VoxEngine.sendMediaBetween(call, voiceAgentClient);

Function calling

In the scenario, Deepgram.VoiceAgentEvents.FunctionCallRequest delivers one or more function calls requested by the agent.

Each call includes an id, a name, and JSON string arguments. Respond using voiceAgentClient.sendFunctionCallResponse(...) with a FunctionCallResponse message containing the same id:

Handle FunctionCallRequest and respond
1voiceAgentClient.addEventListener(Deepgram.VoiceAgentEvents.FunctionCallRequest, (event) => {
2 const { functions } = event?.data?.payload || {};
3 if (!Array.isArray(functions)) return;
4
5 functions.forEach(({ id, name, arguments: rawArguments }) => {
6 // ...perform the function...
7 voiceAgentClient.sendFunctionCallResponse({
8 type: "FunctionCallResponse",
9 id,
10 name,
11 content: JSON.stringify({ ok: true }),
12 });
13 });
14});

Barge-in

As in the other examples, keep the experience interruption-friendly by clearing buffered audio on UserStartedSpeaking:

Barge-in
1voiceAgentClient.addEventListener(Deepgram.VoiceAgentEvents.UserStartedSpeaking, () => {
2 voiceAgentClient.clearMediaBuffer();
3});

Events

The function calling flow is driven by:

  • Deepgram.VoiceAgentEvents.FunctionCallRequest: agent requests a client-side function execution
  • Deepgram.VoiceAgentEvents.FunctionCallResponse: emitted when a function call response is processed

For the complete list of supported events:

Notes

See the VoxEngine API Reference for more details.

Full VoxEngine scenario

voxeengine-deepgram-function-calling.js
1/**
2 * Voximplant + Deepgram Voice Agent connector demo
3 * Scenario: answer an incoming call and handle Deepgram function calling.
4 */
5
6require(Modules.Deepgram);
7require(Modules.ApplicationStorage);
8
9const SYSTEM_PROMPT = `
10You are a helpful English-speaking voice assistant for phone callers.
11Keep your turns short and telephony-friendly (usually 1–2 sentences).
12
13If the caller asks about the weather, call the "get_weather" function.
14`;
15
16// -------------------- Deepgram Voice Agent settings --------------------
17const SETTINGS_OPTIONS = {
18 tags: ["voximplant", "deepgram", "voice_agent_connector", "function_calling_demo"],
19 agent: {
20 language: "en",
21 greeting: "Hi! I'm Voxi. How can I help today?",
22 listen: {
23 provider: {
24 type: "deepgram",
25 model: "flux-general-en",
26 },
27 },
28 think: {
29 provider: {
30 type: "open_ai",
31 model: "gpt-4o-mini",
32 },
33 prompt: SYSTEM_PROMPT,
34 functions: [
35 {
36 name: "get_weather",
37 description: "Get current weather for a location (demo stub)",
38 parameters: {
39 type: "object",
40 properties: {
41 location: {
42 type: "string",
43 description: "City name, for example: San Francisco",
44 },
45 },
46 required: ["location"],
47 },
48 // Mark as client-side so VoxEngine receives FunctionCallRequest and can respond.
49 client_side: true,
50 },
51 ],
52 },
53 speak: {
54 provider: {
55 type: "deepgram",
56 model: "aura-2-cordelia-en",
57 },
58 },
59 },
60};
61
62VoxEngine.addEventListener(AppEvents.CallAlerting, async ({call}) => {
63 let voiceAIClient;
64
65 // Termination functions - add cleanup and logging as needed
66 call.addEventListener(CallEvents.Disconnected, ()=>VoxEngine.terminate());
67 call.addEventListener(CallEvents.Failed, ()=>VoxEngine.terminate());
68
69 try {
70 call.answer();
71 // call.record({hd_audio: true, stereo: true}); // optional: call recording
72
73 // Create client and wire media
74 voiceAIClient = await Deepgram.createVoiceAgentClient({
75 apiKey: (await ApplicationStorage.get("DEEPGRAM_API_KEY")).value,
76 settingsOptions: SETTINGS_OPTIONS,
77 });
78 VoxEngine.sendMediaBetween(call, voiceAIClient);
79
80 // ---------------------- Event handlers -----------------------
81 // Barge-in: keep conversation responsive
82 voiceAIClient.addEventListener(Deepgram.VoiceAgentEvents.UserStartedSpeaking, () => {
83 Logger.write("===BARGE-IN: Deepgram.VoiceAgentEvents.UserStartedSpeaking===");
84 voiceAIClient.clearMediaBuffer();
85 });
86
87 // Function calling: handle tool requests and send back responses
88 voiceAIClient.addEventListener(Deepgram.VoiceAgentEvents.FunctionCallRequest, (event) => {
89 const {functions} = event?.data?.payload || {};
90 if (!Array.isArray(functions) || functions.length === 0) return;
91
92 functions.forEach((fn) => {
93 const {id, name, arguments: rawArguments} = fn || {};
94 if (!id || !name) return;
95
96 if (name !== "get_weather") {
97 voiceAIClient.sendFunctionCallResponse({
98 type: "FunctionCallResponse",
99 id,
100 name,
101 content: JSON.stringify({error: `Unhandled function: ${name}`}),
102 });
103 return;
104 }
105
106 let args = {};
107 try {
108 args = rawArguments ? JSON.parse(rawArguments) : {};
109 } catch (error) {
110 Logger.write(`===FUNCTION_ARGS_PARSE_ERROR=== ${rawArguments}`);
111 Logger.write(error);
112 }
113
114 const location = args.location || "Unknown";
115
116 // Demo response (no external API call)
117 const result = {
118 location,
119 temperature_f: 72,
120 condition: "sunny",
121 };
122
123 voiceAIClient.sendFunctionCallResponse({
124 type: "FunctionCallResponse",
125 id,
126 name,
127 content: JSON.stringify(result),
128 });
129 });
130 });
131
132 } catch (error) {
133 Logger.write("===UNHANDLED_ERROR===");
134 Logger.write(error);
135 VoxEngine.terminate();
136 }
137});