From 73e6dc361e27fb469090fae400819d2d0450803c Mon Sep 17 00:00:00 2001 From: scoootscooob Date: Mon, 2 Mar 2026 12:58:55 -0800 Subject: [PATCH] fix(whatsapp): propagate fromMe through inbound message pipeline MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The `fromMe` flag from Baileys' WAMessage.key was only used for access-control filtering and then discarded. This meant agents could not distinguish owner-sent messages from contact messages in DM conversations (everything appeared as from the contact). Add `fromMe` to `WebInboundMessage`, store it during message construction, and thread it through `buildInboundLine` → `formatInboundEnvelope` so DM transcripts prefix owner messages with `(self):`. Closes #32061 Co-Authored-By: Claude Opus 4.6 --- src/auto-reply/envelope.test.ts | 23 ++++++++++++++++++++++ src/auto-reply/envelope.ts | 8 +++++++- src/web/auto-reply/monitor/message-line.ts | 1 + src/web/inbound/monitor.ts | 1 + src/web/inbound/types.ts | 1 + 5 files changed, 33 insertions(+), 1 deletion(-) diff --git a/src/auto-reply/envelope.test.ts b/src/auto-reply/envelope.test.ts index 69571636282..c7929e4eed4 100644 --- a/src/auto-reply/envelope.test.ts +++ b/src/auto-reply/envelope.test.ts @@ -144,6 +144,29 @@ describe("formatInboundEnvelope", () => { expect(body).toBe("[Telegram Alice] follow-up message"); }); + it("prefixes DM body with (self) when fromMe is true", () => { + const body = formatInboundEnvelope({ + channel: "WhatsApp", + from: "+1555", + body: "outbound msg", + chatType: "direct", + fromMe: true, + }); + expect(body).toBe("[WhatsApp +1555] (self): outbound msg"); + }); + + it("does not prefix group messages with (self) when fromMe is true", () => { + const body = formatInboundEnvelope({ + channel: "WhatsApp", + from: "Family Chat", + body: "hello", + chatType: "group", + senderLabel: "Alice", + fromMe: true, + }); + expect(body).toBe("[WhatsApp Family Chat] Alice: hello"); + }); + it("resolves envelope options from config", () => { const options = resolveEnvelopeFormatOptions({ agents: { diff --git a/src/auto-reply/envelope.ts b/src/auto-reply/envelope.ts index 34f4733ec7a..3a2985419dd 100644 --- a/src/auto-reply/envelope.ts +++ b/src/auto-reply/envelope.ts @@ -197,12 +197,18 @@ export function formatInboundEnvelope(params: { sender?: SenderLabelParams; previousTimestamp?: number | Date; envelope?: EnvelopeFormatOptions; + fromMe?: boolean; }): string { const chatType = normalizeChatType(params.chatType); const isDirect = !chatType || chatType === "direct"; const resolvedSenderRaw = params.senderLabel?.trim() || resolveSenderLabel(params.sender ?? {}); const resolvedSender = resolvedSenderRaw ? sanitizeEnvelopeHeaderPart(resolvedSenderRaw) : ""; - const body = !isDirect && resolvedSender ? `${resolvedSender}: ${params.body}` : params.body; + const body = + isDirect && params.fromMe + ? `(self): ${params.body}` + : !isDirect && resolvedSender + ? `${resolvedSender}: ${params.body}` + : params.body; return formatAgentEnvelope({ channel: params.channel, from: params.from, diff --git a/src/web/auto-reply/monitor/message-line.ts b/src/web/auto-reply/monitor/message-line.ts index 1416d8424ee..ba99766aedf 100644 --- a/src/web/auto-reply/monitor/message-line.ts +++ b/src/web/auto-reply/monitor/message-line.ts @@ -43,5 +43,6 @@ export function buildInboundLine(params: { }, previousTimestamp, envelope, + fromMe: msg.fromMe, }); } diff --git a/src/web/inbound/monitor.ts b/src/web/inbound/monitor.ts index 30781122432..e1cd6f2981f 100644 --- a/src/web/inbound/monitor.ts +++ b/src/web/inbound/monitor.ts @@ -323,6 +323,7 @@ export async function monitorWebInbox(options: { mentionedJids: mentionedJids ?? undefined, selfJid, selfE164, + fromMe: Boolean(msg.key?.fromMe), location: location ?? undefined, sendComposing, reply, diff --git a/src/web/inbound/types.ts b/src/web/inbound/types.ts index dfac5a27c50..c9b49e945b5 100644 --- a/src/web/inbound/types.ts +++ b/src/web/inbound/types.ts @@ -31,6 +31,7 @@ export type WebInboundMessage = { mentionedJids?: string[]; selfJid?: string | null; selfE164?: string | null; + fromMe?: boolean; location?: NormalizedLocation; sendComposing: () => Promise; reply: (text: string) => Promise;