From 6c6c6388bd1aa4fb7f0905d11ff9146ff110bf7b Mon Sep 17 00:00:00 2001 From: Forrest Blount Date: Thu, 12 Mar 2026 21:56:17 +0000 Subject: [PATCH] voice-call: log assistant speech as bot transcript in realtime calls call.speaking events already carry a text field (used by Telnyx) but the manager was discarding it. Wire it through addTranscriptEntry so any call.speaking event with non-empty text records a speaker:"bot" entry. In the realtime handler, emit call.speaking for assistant turns when the transcript is final, mirroring the existing user call.speech path. This restores speaker:"bot" entries in calls.jsonl for realtime calls. Co-Authored-By: Claude Sonnet 4.6 --- extensions/voice-call/src/manager/events.ts | 3 +++ .../voice-call/src/webhook/realtime-handler.ts | 12 +++++++++++- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/extensions/voice-call/src/manager/events.ts b/extensions/voice-call/src/manager/events.ts index 668369e0c35..2ce9de599aa 100644 --- a/extensions/voice-call/src/manager/events.ts +++ b/extensions/voice-call/src/manager/events.ts @@ -204,6 +204,9 @@ export function processEvent(ctx: EventContext, event: NormalizedEvent): void { break; case "call.speaking": + if (event.text) { + addTranscriptEntry(call, "bot", event.text); + } transitionState(call, "speaking"); break; diff --git a/extensions/voice-call/src/webhook/realtime-handler.ts b/extensions/voice-call/src/webhook/realtime-handler.ts index 9eb7d4b2f21..fc911bb2132 100644 --- a/extensions/voice-call/src/webhook/realtime-handler.ts +++ b/extensions/voice-call/src/webhook/realtime-handler.ts @@ -233,7 +233,6 @@ export class RealtimeCallHandler { onTranscript: (role, text, isFinal) => { if (isFinal) { - // Emit user speech through the manager for transcript persistence if (role === "user") { const event: NormalizedEvent = { id: `realtime-speech-${callSid}-${Date.now()}`, @@ -245,6 +244,17 @@ export class RealtimeCallHandler { isFinal: true, }; this.manager.processEvent(event); + } else if (role === "assistant") { + // Log assistant turns via call.speaking so they appear as speaker:"bot" + // in the transcript (same mechanism Telnyx uses for TTS speech). + this.manager.processEvent({ + id: `realtime-bot-${callSid}-${Date.now()}`, + type: "call.speaking", + callId, + providerCallId: callSid, + timestamp: Date.now(), + text, + }); } } },