From c88acdb59a4f62a4a6b5f80fa3c94eefcc800280 Mon Sep 17 00:00:00 2001 From: joelnishanth <140015627+joelnishanth@users.noreply.github.com> Date: Wed, 25 Mar 2026 09:46:12 -0700 Subject: [PATCH] fix(whatsapp): drop fromMe echoes in self-chat DMs using outbound ID tracking --- extensions/whatsapp/src/inbound/monitor.ts | 6 ++- ...ssages-from-senders-allowfrom-list.test.ts | 39 +++++++++++++++++++ 2 files changed, 43 insertions(+), 2 deletions(-) diff --git a/extensions/whatsapp/src/inbound/monitor.ts b/extensions/whatsapp/src/inbound/monitor.ts index 5f829d9c4ed..6760cf598cd 100644 --- a/extensions/whatsapp/src/inbound/monitor.ts +++ b/extensions/whatsapp/src/inbound/monitor.ts @@ -218,8 +218,10 @@ export async function monitorWebInbox(options: { } const group = isGroupJid(remoteJid); + // Drop echoes of messages the gateway itself sent (tracked by sendTrackedMessage). + // Applies to both groups and DMs/self-chat — without this, self-chat mode + // re-processes the bot's own replies as new inbound user messages. if ( - group && Boolean(msg.key?.fromMe) && id && isRecentOutboundMessage({ @@ -228,7 +230,7 @@ export async function monitorWebInbox(options: { messageId: id, }) ) { - logVerbose(`Skipping recent outbound WhatsApp group echo ${id} for ${remoteJid}`); + logVerbose(`Skipping recent outbound WhatsApp echo ${id} for ${remoteJid}`); return null; } if (id) { diff --git a/extensions/whatsapp/src/monitor-inbox.allows-messages-from-senders-allowfrom-list.test.ts b/extensions/whatsapp/src/monitor-inbox.allows-messages-from-senders-allowfrom-list.test.ts index e0b022fe82f..99f4e989e11 100644 --- a/extensions/whatsapp/src/monitor-inbox.allows-messages-from-senders-allowfrom-list.test.ts +++ b/extensions/whatsapp/src/monitor-inbox.allows-messages-from-senders-allowfrom-list.test.ts @@ -298,6 +298,45 @@ describe("web monitor inbox", () => { await listener.close(); }); + it("filters self-chat DM fromMe echoes when the gateway sent the matching message id", async () => { + mockLoadConfig.mockReturnValue({ + channels: { + whatsapp: { + selfChatMode: true, + allowFrom: ["+123"], + }, + }, + messages: DEFAULT_MESSAGES_CFG, + }); + + const onMessage = vi.fn(); + const { listener, sock } = await startInboxMonitor(onMessage); + + sock.sendMessage.mockResolvedValueOnce({ key: { id: "bot-dm-echo-1" } }); + await listener.sendMessage("123@s.whatsapp.net", "self-chat reply"); + + sock.ev.emit("messages.upsert", { + type: "notify", + messages: [ + { + key: { + id: "bot-dm-echo-1", + fromMe: true, + remoteJid: "123@s.whatsapp.net", + }, + message: { conversation: "self-chat reply" }, + messageTimestamp: nowSeconds(), + pushName: "Owner", + }, + ], + }); + await settleInboundWork(); + + expect(onMessage).not.toHaveBeenCalled(); + + await listener.close(); + }); + it("handles append messages by marking them read but skipping auto-reply", async () => { const { onMessage, listener, sock } = await openInboxMonitor(); const staleTs = Math.floor(Date.now() / 1000) - 300;