From f9b89aed4ff8a71fb2f57761758ba20cf4fc6354 Mon Sep 17 00:00:00 2001 From: hclsys Date: Sat, 9 May 2026 19:21:56 +0800 Subject: [PATCH] fix(whatsapp): pass routing ctx to transcribeFirstAudio so echoTranscript can deliver (#79778) sendTranscriptEcho requires Provider/OriginatingTo/From on ctx to resolve the delivery target. Both on-message and process-message passed a minimal ctx with only MediaPaths/MediaTypes, causing sendTranscriptEcho to silently bail (no channel/to resolved). Added routing fields from msg and route at both call sites. --- .../on-message.audio-preflight.test.ts | 42 +++++++++++++++++++ .../src/auto-reply/monitor/on-message.ts | 7 ++++ .../src/auto-reply/monitor/process-message.ts | 7 ++++ 3 files changed, 56 insertions(+) diff --git a/extensions/whatsapp/src/auto-reply/monitor/on-message.audio-preflight.test.ts b/extensions/whatsapp/src/auto-reply/monitor/on-message.audio-preflight.test.ts index 2fbadc7b034..114acd5b54f 100644 --- a/extensions/whatsapp/src/auto-reply/monitor/on-message.audio-preflight.test.ts +++ b/extensions/whatsapp/src/auto-reply/monitor/on-message.audio-preflight.test.ts @@ -316,6 +316,48 @@ describe("createWebOnMessageHandler audio preflight", () => { ); }); + it("passes routing ctx fields to transcribeFirstAudio so echoTranscript can deliver (#79778)", async () => { + let capturedCtx: unknown; + transcribeFirstAudioMock.mockImplementation(async ({ ctx }: { ctx: unknown }) => { + capturedCtx = ctx; + return "transcribed voice note"; + }); + const handler = createWebOnMessageHandler({ + cfg: { + channels: { + whatsapp: { + ackReaction: { enabled: true }, + }, + }, + } as never, + verbose: false, + connectionId: "conn-1", + maxMediaBytes: 1024 * 1024, + groupHistoryLimit: 20, + groupHistories: new Map(), + groupMemberNames: new Map(), + echoTracker: makeEchoTracker() as never, + backgroundTasks: new Set(), + replyResolver: vi.fn() as never, + replyLogger: { + info: () => {}, + warn: () => {}, + debug: () => {}, + error: () => {}, + } as never, + baseMentionConfig: {} as never, + account: { authDir: "/tmp/auth", accountId: "default" }, + }); + + await handler(makeAudioMsg()); + + expect(capturedCtx).toMatchObject({ + Provider: "whatsapp", + OriginatingTo: "+15550000002", + From: "+15550000002", + }); + }); + it("does not transcribe group voice when policy gating rejects before mention", async () => { applyGroupGatingMock.mockResolvedValueOnce({ shouldProcess: false }); const handler = createWebOnMessageHandler({ diff --git a/extensions/whatsapp/src/auto-reply/monitor/on-message.ts b/extensions/whatsapp/src/auto-reply/monitor/on-message.ts index 64eea5bf425..3ca364201c8 100644 --- a/extensions/whatsapp/src/auto-reply/monitor/on-message.ts +++ b/extensions/whatsapp/src/auto-reply/monitor/on-message.ts @@ -162,6 +162,13 @@ export function createWebOnMessageHandler(params: { ctx: { MediaPaths: [msg.mediaPath], MediaTypes: msg.mediaType ? [msg.mediaType] : undefined, + From: msg.from, + To: msg.to, + Provider: "whatsapp", + Surface: "whatsapp", + OriginatingChannel: "whatsapp", + OriginatingTo: conversationId, + AccountId: route.accountId, }, cfg: params.cfg, })) ?? null; diff --git a/extensions/whatsapp/src/auto-reply/monitor/process-message.ts b/extensions/whatsapp/src/auto-reply/monitor/process-message.ts index 61e6c4920df..7c321f3f379 100644 --- a/extensions/whatsapp/src/auto-reply/monitor/process-message.ts +++ b/extensions/whatsapp/src/auto-reply/monitor/process-message.ts @@ -243,6 +243,13 @@ export async function processMessage(params: { ctx: { MediaPaths: [params.msg.mediaPath], MediaTypes: params.msg.mediaType ? [params.msg.mediaType] : undefined, + From: params.msg.from, + To: params.msg.to, + Provider: "whatsapp", + Surface: "whatsapp", + OriginatingChannel: "whatsapp", + OriginatingTo: conversationId, + AccountId: params.route.accountId, }, cfg: params.cfg, });