From 1feff5b2b6d6f14f228161c9feda9bc5b8cf312a Mon Sep 17 00:00:00 2001 From: "chenglun.hu" Date: Thu, 29 Jan 2026 13:17:13 +0800 Subject: [PATCH] fix(voice-call): include intro message in AI context for outbound calls Fixes #3256 When initiating an outbound call with an intro message (e.g., "Henrik asked me to call about your mother"), the AI now receives this as explicit context in its system prompt under "Purpose of this call". Previously, the intro was played via TTS but the AI didn't understand the call's objective, leading to generic follow-up questions instead of staying on topic. Changes: - manager.ts: Store callPurpose in metadata at call creation time - response-generator.ts: Accept callPurpose param and include in system prompt - webhook.ts: Pass callPurpose to generateVoiceResponse Co-Authored-By: Claude Opus 4.5 --- extensions/voice-call/src/manager.ts | 3 +++ .../voice-call/src/response-generator.ts | 23 ++++++++++++++++--- extensions/voice-call/src/webhook.ts | 1 + 3 files changed, 24 insertions(+), 3 deletions(-) diff --git a/extensions/voice-call/src/manager.ts b/extensions/voice-call/src/manager.ts index 2e2e4661b..118971f60 100644 --- a/extensions/voice-call/src/manager.ts +++ b/extensions/voice-call/src/manager.ts @@ -132,6 +132,9 @@ export class CallManager { processedEventIds: [], metadata: { ...(initialMessage && { initialMessage }), + // Store callPurpose immediately so it's available for AI context + // before speakInitialMessage runs (avoids race with early user speech) + ...(initialMessage && { callPurpose: initialMessage }), mode, }, }; diff --git a/extensions/voice-call/src/response-generator.ts b/extensions/voice-call/src/response-generator.ts index f60215a5f..b46230db3 100644 --- a/extensions/voice-call/src/response-generator.ts +++ b/extensions/voice-call/src/response-generator.ts @@ -22,6 +22,8 @@ export type VoiceResponseParams = { transcript: Array<{ speaker: "user" | "bot"; text: string }>; /** Latest user message */ userMessage: string; + /** Optional: Purpose of this call (from intro message for outbound calls) */ + callPurpose?: string; }; export type VoiceResponseResult = { @@ -41,8 +43,15 @@ type SessionEntry = { export async function generateVoiceResponse( params: VoiceResponseParams, ): Promise { - const { voiceConfig, callId, from, transcript, userMessage, coreConfig } = - params; + const { + voiceConfig, + callId, + from, + transcript, + userMessage, + coreConfig, + callPurpose, + } = params; if (!coreConfig) { return { text: null, error: "Core config unavailable for voice response" }; @@ -116,6 +125,14 @@ export async function generateVoiceResponse( `You are ${agentName}, a helpful voice assistant on a phone call. Keep responses brief and conversational (1-2 sentences max). Be natural and friendly. The caller's phone number is ${from}. You have access to tools - use them when helpful.`; let extraSystemPrompt = basePrompt; + + // If we have an explicit call purpose (from outbound intro message), + // include it so the AI knows the objective of this call + if (callPurpose) { + extraSystemPrompt += `\n\nPurpose of this call: ${callPurpose}`; + extraSystemPrompt += `\nYou started the call with this message. Stay focused on this topic.`; + } + if (transcript.length > 0) { const history = transcript .map( @@ -123,7 +140,7 @@ export async function generateVoiceResponse( `${entry.speaker === "bot" ? "You" : "Caller"}: ${entry.text}`, ) .join("\n"); - extraSystemPrompt = `${basePrompt}\n\nConversation so far:\n${history}`; + extraSystemPrompt += `\n\nConversation so far:\n${history}`; } // Resolve timeout diff --git a/extensions/voice-call/src/webhook.ts b/extensions/voice-call/src/webhook.ts index 09e96ffed..14c6c9c3e 100644 --- a/extensions/voice-call/src/webhook.ts +++ b/extensions/voice-call/src/webhook.ts @@ -341,6 +341,7 @@ export class VoiceCallWebhookServer { from: call.from, transcript: call.transcript, userMessage, + callPurpose: call.metadata?.callPurpose as string | undefined, }); if (result.error) {