fix(whatsapp): pass routing ctx to transcribeFirstAudio so echoTranscript can deliver (#79778) (#79788)

Merged via squash.

Prepared head SHA: b5d2936d52
Co-authored-by: hclsys <7755017+hclsys@users.noreply.github.com>
Co-authored-by: velvet-shark <126378+velvet-shark@users.noreply.github.com>
Reviewed-by: @velvet-shark
This commit is contained in:
hcl
2026-05-10 00:46:54 +08:00
committed by GitHub
parent 8542a7d6c1
commit 55e7f5f27c
5 changed files with 64 additions and 0 deletions

View File

@@ -9,6 +9,7 @@ Docs: https://docs.openclaw.ai
### Fixes
- Feishu: auto-thread `message(action="send")` replies inside the topic when the active session is group_topic or group_topic_sender, and propagate `replyInThread` through text, card, and media outbound adapters so topic-scoped sessions no longer post at the group root. Fixes #74903. (#77151) Thanks @ai-hpc.
- WhatsApp: pass routing context into voice-note transcript echo preflight so echoed transcripts can deliver to the originating chat. Fixes #79778. (#79788) Thanks @hclsys.
## 2026.5.9

View File

@@ -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({

View File

@@ -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;

View File

@@ -219,8 +219,15 @@ describe("processMessage audio preflight transcription", () => {
expect(transcribeFirstAudioMock).toHaveBeenCalledWith(
expect.objectContaining({
ctx: expect.objectContaining({
AccountId: "default",
From: "+15550000002",
MediaPaths: ["/tmp/voice.ogg"],
MediaTypes: ["audio/ogg; codecs=opus"],
OriginatingChannel: "whatsapp",
OriginatingTo: "+15550000002",
Provider: "whatsapp",
Surface: "whatsapp",
To: "+15550000001",
}),
}),
);

View File

@@ -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,
});