fix(whatsapp): detect group @mentions when self is in allowFrom (#49317)

`isBotMentionedFromTargets` derives a "self-chat" flag from
`isSelfChatMode(self.e164, allowFrom)`, which is a config-shaped check
("is the bot's own E.164 in allowFrom?") rather than a conversation-shaped
check. The flag flipped to true for ordinary group conversations whenever
the operator put their own number in allowFrom — the common config — and
the function then took the `hasMentions && isSelfChat` branch, dropping
the identity-overlap check entirely.

Group `@mention` JIDs (including WhatsApp LID mentions like
`216372600647751@lid` that resolve to the bot's E.164 via the LID reverse
mapping) silently failed mention detection. The empty fall-through then
fell back to body-regex / E.164-digit matching, which does not match
WhatsApp's tap-mention markup, so `wasMentioned` stayed false even when
the bot was clearly mentioned.

Confine the implicit `isSelfChat` derivation to non-group conversations.
Real group `@mentions` go through the identity-overlap check regardless of
allowFrom. Explicit `mentionCfg.isSelfChat` overrides from callers
(multi-account / precomputed paths) keep their existing behavior so we do
not regress callers that intentionally set the flag.

Closes #49317
This commit is contained in:
juan-flores077
2026-04-28 11:28:33 +02:00
committed by Marcus Castro
parent 04f6ffd8be
commit ce62bf1c97
3 changed files with 47 additions and 6 deletions

View File

@@ -90,6 +90,7 @@ Docs: https://docs.openclaw.ai
- Agents/context engines: preserve the child agent's configured `agentDir` when subagent cleanup re-resolves a context engine, so `onSubagentEnded` hooks keep operating on the correct per-agent state. (#67243) Thanks @jarimustonen.
- Channels/WhatsApp: restrict pairing verification replies to real inbound user content, preventing unsolicited prompts from receipts, typing indicators, presence updates, and other non-message Baileys upserts. Fixes #73797. (#73823) Thanks @hclsys.
- Configure/Ollama: show the configured Ollama model allowlist after Cloud only or Cloud + Local setup and skip slow per-model cloud metadata fetches. (#73995) Thanks @obviyus.
- Channels/WhatsApp: stop dropping group `@mention` detection when the bot's own E.164 is in `allowFrom`, so LID-style group mentions resolve correctly through the identity-overlap check; the original 1:1 self-DM mention-skip suppression still applies for direct chats and explicit `isSelfChat` overrides. Fixes #49317. Thanks @juan-flores077.
## 2026.4.27

View File

@@ -10,6 +10,7 @@ import {
identitiesOverlap,
type WhatsAppIdentity,
} from "../identity.js";
import { isWhatsAppGroupJid } from "../normalize-target.js";
import { isSelfChatMode, normalizeE164 } from "../text-runtime.js";
import type { WebInboundMsg } from "./types.js";
@@ -44,10 +45,21 @@ export function isBotMentionedFromTargets(
// Remove zero-width and directionality markers WhatsApp injects around display names
normalizeMentionText(text);
const isSelfChat =
typeof mentionCfg.isSelfChat === "boolean"
? mentionCfg.isSelfChat
: isSelfChatMode(targets.self.e164, mentionCfg.allowFrom);
const explicitSelfChatOverride = typeof mentionCfg.isSelfChat === "boolean";
// `isSelfChatMode` is a config-shaped check ("is the bot's own E.164 in
// allowFrom?"), not a conversation-shaped check, so it returns true even
// for group conversations whenever the operator put their own number in
// allowFrom — which is the common config. The original mention-skip path
// was designed to prevent owner-mentioning-self in a true 1:1 self DM
// from falsely triggering the bot, so when we derive the flag implicitly
// from `allowFrom`, confine the suppression to non-group conversations
// and let real group @mentions go through the identity-overlap check
// (#49317). Explicit `mentionCfg.isSelfChat` overrides from the caller
// are honored as-is so multi-account / precomputed paths keep working.
const isGroupConversation = isWhatsAppGroupJid(msg.from);
const isSelfChat = explicitSelfChatOverride
? Boolean(mentionCfg.isSelfChat)
: isSelfChatMode(targets.self.e164, mentionCfg.allowFrom) && !isGroupConversation;
const hasMentions = targets.normalizedMentions.length > 0;
if (hasMentions && !isSelfChat) {
@@ -59,7 +71,7 @@ export function isBotMentionedFromTargets(
// If the message explicitly mentions someone else, do not fall back to regex matches.
return false;
} else if (hasMentions && isSelfChat) {
// Self-chat mode: ignore WhatsApp @mention JIDs, otherwise @mentioning the owner in group chats triggers the bot.
// Self-chat mode: ignore WhatsApp @mention JIDs, otherwise @mentioning the owner in self-chat triggers the bot.
}
const bodyClean = clean(msg.body);
if (mentionCfg.mentionRegexes.some((re) => re.test(bodyClean))) {

View File

@@ -70,9 +70,15 @@ describe("isBotMentionedFromTargets", () => {
expectMentioned(msg, mentionCfg, true);
});
it("ignores JID mentions in self-chat mode", () => {
it("ignores JID mentions in a true 1:1 self-chat (not a group)", () => {
const cfg = { mentionRegexes: [/\bopenclaw\b/i], allowFrom: ["+999"] };
const msg = makeMsg({
// Direct chat with self, not a group — the original "ignore mentions
// in self-chat" suppression still applies here so that mentioning the
// owner in their own DM does not falsely trigger the bot.
from: "999@s.whatsapp.net",
conversationId: "999@s.whatsapp.net",
chatType: "direct",
body: "@owner ping",
mentionedJids: ["999@s.whatsapp.net"],
selfE164: "+999",
@@ -81,6 +87,9 @@ describe("isBotMentionedFromTargets", () => {
expectMentioned(msg, cfg, false);
const msgTextMention = makeMsg({
from: "999@s.whatsapp.net",
conversationId: "999@s.whatsapp.net",
chatType: "direct",
body: "openclaw ping",
selfE164: "+999",
selfJid: "999@s.whatsapp.net",
@@ -88,6 +97,25 @@ describe("isBotMentionedFromTargets", () => {
expectMentioned(msgTextMention, cfg, true);
});
it("detects an explicit group @mention even when self is in allowFrom (#49317)", () => {
// Operator config commonly puts their own E.164 in allowFrom so they can
// run owner-only commands in groups; previously, that flipped the gate
// to "self-chat mode" and silently dropped mention detection in groups,
// including LID-style WhatsApp mentions that resolve to the bot's own
// E.164. After the fix, group conversations honor the identity-overlap
// check regardless of allowFrom.
const cfg = { mentionRegexes: [/\bopenclaw\b/i], allowFrom: ["+15551234567"] };
const msg = makeMsg({
// Default `from` is the @g.us group JID from `makeMsg`.
body: "@216372600647751 can you see this?",
mentionedJids: ["216372600647751@lid"],
selfE164: "+15551234567",
selfJid: "15551234567@s.whatsapp.net",
selfLid: "216372600647751@lid",
});
expectMentioned(msg, cfg, true);
});
it("honors explicit self-chat overrides without recomputing from allowFrom", () => {
const cfg = {
mentionRegexes: [/\bopenclaw\b/i],