diff --git a/extensions/whatsapp/src/auto-reply/monitor/inbound-dispatch.test.ts b/extensions/whatsapp/src/auto-reply/monitor/inbound-dispatch.test.ts index b698cf72b4b..50ee424ec39 100644 --- a/extensions/whatsapp/src/auto-reply/monitor/inbound-dispatch.test.ts +++ b/extensions/whatsapp/src/auto-reply/monitor/inbound-dispatch.test.ts @@ -378,7 +378,7 @@ describe("whatsapp inbound dispatch", () => { expect(groupHistories.get("whatsapp:default:group:123@g.us") ?? []).toHaveLength(0); }); - it("delivers block and final WhatsApp payloads; suppresses text-only tool payloads but delivers tool media", async () => { + it("delivers block and final WhatsApp payloads; suppresses text-only tool payloads but delivers media", async () => { const deliverReply = vi.fn(async () => undefined); const rememberSentText = vi.fn(); @@ -411,10 +411,27 @@ describe("whatsapp inbound dispatch", () => { }), ); + await deliver?.( + { text: "generated image", mediaUrls: ["/tmp/generated.jpg"] }, + { + kind: "block", + }, + ); + expect(deliverReply).toHaveBeenCalledTimes(2); + expect(rememberSentText).toHaveBeenCalledTimes(2); + expect(deliverReply).toHaveBeenLastCalledWith( + expect.objectContaining({ + replyResult: expect.objectContaining({ + mediaUrls: ["/tmp/generated.jpg"], + text: "generated image", + }), + }), + ); + await deliver?.({ text: "block payload" }, { kind: "block" }); await deliver?.({ text: "final payload" }, { kind: "final" }); - expect(deliverReply).toHaveBeenCalledTimes(3); - expect(rememberSentText).toHaveBeenCalledTimes(3); + expect(deliverReply).toHaveBeenCalledTimes(4); + expect(rememberSentText).toHaveBeenCalledTimes(4); }); it("suppresses reasoning and compaction payloads before WhatsApp delivery", async () => { diff --git a/src/auto-reply/reply/dispatch-from-config.test.ts b/src/auto-reply/reply/dispatch-from-config.test.ts index d62a34b5e49..5a9ef665e09 100644 --- a/src/auto-reply/reply/dispatch-from-config.test.ts +++ b/src/auto-reply/reply/dispatch-from-config.test.ts @@ -3241,6 +3241,37 @@ describe("dispatchReplyFromConfig", () => { expect(blockReplySentTexts).toContain("The answer is 42"); }); + it("forwards generated-media block replies in WhatsApp group sessions", async () => { + setNoAbort(); + const dispatcher = createDispatcher(); + const ctx = buildTestCtx({ + Provider: "whatsapp", + Surface: "whatsapp", + ChatType: "group", + From: "whatsapp:120363111111111@g.us", + To: "whatsapp:120363111111111@g.us", + SessionKey: "agent:main:whatsapp:group:120363111111111@g.us", + }); + const replyResolver = async ( + _ctx: MsgContext, + opts?: GetReplyOptions, + ): Promise => { + await opts?.onBlockReply?.({ + text: "generated", + mediaUrls: ["https://example.com/generated.png"], + }); + return { text: "NO_REPLY" }; + }; + + await dispatchReplyFromConfig({ ctx, cfg: emptyConfig, dispatcher, replyResolver }); + + expect(dispatcher.sendBlockReply).toHaveBeenCalledTimes(1); + expect(dispatcher.sendBlockReply).toHaveBeenCalledWith({ + text: "generated", + mediaUrls: ["https://example.com/generated.png"], + }); + }); + it("signals block boundaries before async block delivery is queued", async () => { setNoAbort(); const dispatcher = createDispatcher();