Affected component
channel
Severity
S1 - workflow blocked
Current behavior
When a user in a WhatsApp group sends a message that @-mentions the bot by tapping the contact (the proper WhatsApp mention UI), the bot silently drops the message instead of processing it. The message never reaches the LLM and never gets persisted to session history — as if it never arrived.
This happens because the mention_only filter in src/channels/whatsapp_web.rs:1313-1342 only runs a substring check against the configured mention_name text fallback via contains_mention():
// whatsapp_web.rs:1313
if mention_only && is_group && !is_contact {
let text = msg.text_content().unwrap_or("");
let mentioned = mention_name.as_deref().map_or(false, |name| {
Self::contains_mention(text, name) // simple substring on mention_name
});
if !mentioned {
// passive-observe, log debug, return ← silent drop
return;
}
}
And contains_mention (whatsapp_web.rs:337-339) is just:
fn contains_mention(text: &str, mention_name: &str) -> bool {
text.to_lowercase().contains(&mention_name.to_lowercase())
}
It does NOT consult the message's structural mentions — even though extract_mentioned_jids() + contains_bot_mention() exist in the same file (lines 604-655) and do exactly that. Those helpers are wired into the downstream normalization block at lines 1465-1527, but only AFTER the upstream filter has already dropped the message.
The WhatsApp protocol replaces the visible display name in a tap-mention with the raw phone digits in the text body. So when a user taps @<bot-name> in the UI, the text_content() arrives as:
Ok, @<bot-phone-digits> Can you check if you have access to obsidian cli?
That string does NOT contain the substring "<bot-name>" (configured mention_name), so contains_mention() returns false and the message is silently discarded at line 1340. The message is written to observe_store for passive scanning but never enters session history, so subsequent turns in the same conversation have no record of it and the bot loses conversational context.
Confirmed via Langfuse traces from a production daemon on 2026-04-09:
- T+0: user sends
@<bot> Can you check if you have access to obsidian cli? → no trace recorded, no LLM call made
- T+5min: user asks a follow-up → the model's
input.messages[] contains zero trace of the obsidian question; the conversation jumps straight from the prior turn to the follow-up, with the dropped message entirely absent.
Expected behavior
Group messages where the bot is structurally mentioned (via context_info.mentioned_jid containing the bot's phone digits) should pass the mention_only filter, be added to session history, and be processed by the LLM — regardless of whether the text body coincidentally contains the configured mention_name substring.
Both signals should be OR'd at the filter:
- Text fallback:
contains_mention(text, mention_name) (existing)
- Structural:
contains_bot_mention(text, extract_mentioned_jids(&msg), bot_phone) (existing helper, just not wired into this filter)
Suggested fix sketch — replace lines 1313-1317 of src/channels/whatsapp_web.rs:
if mention_only && is_group && !is_contact {
let text = msg.text_content().unwrap_or("");
let text_mention = mention_name.as_deref()
.map_or(false, |name| Self::contains_mention(text, name));
let structural_mention = {
let bot_phone = bot_phone_inner.lock();
bot_phone.as_ref().map_or(false, |bp| {
let jids = Self::extract_mentioned_jids(&msg);
Self::contains_bot_mention(text, &jids, bp)
})
};
let mentioned = text_mention || structural_mention;
if !mentioned {
// existing passive-observe + return
}
}
This mirrors the same check already performed at lines 1465-1527 for content normalization — it just needs to happen upstream at the filter too, so structural mentions don't get dropped before entering session history.
Steps to reproduce
# 1. Configure whatsapp_web channel with:
# mention_only = true
# mention_name = "<bot-name>"
# mode = "business"
# group_policy = "allowlist"
# allowed_groups = ["<group-jid>@g.us"]
# 2. Start daemon:
zeroclaw daemon
# 3. In the allowed WhatsApp group, tap-to-mention the bot via the WhatsApp UI
# (do NOT type the bot-name anywhere else in the message) and ask a question:
# "@<bot-name> can you check if you have access to obsidian cli?"
# 4. Observe: no reply, no LLM call in langfuse/tracing, debug log shows:
# "WhatsApp Web: mention_only=true, no mention found in group message from ..., skipping"
# 5. The message exists in observe_store but is absent from session history.
Impact
Affected users: anyone running the WhatsApp Web channel with mention_only = true in groups where the mention_name substring does not appear verbatim in the message text — i.e. most users who rely on structural @-mentions, which is the normal WhatsApp UX.
Frequency: every group message that uses a tap-mention without the bot name also typed in the body.
Consequence: bot appears broken/unresponsive in groups; conversation history silently loses turns, causing the LLM to lose context on subsequent addressed turns. The only workaround is typing the mention_name in the message body, which defeats the purpose of WhatsApp's structural mentions.
Logs / stack traces
WhatsApp Web: mention_only=true, no mention found in group message from <user>, skipping
Langfuse trace pattern (redacted):
- Trace A @ T+0: user turn "@ cmon" → LLM reply ✓
- (T+2min: obsidian-cli tap-mention: NO TRACE, message dropped at filter)
- Trace B @ T+7min: next user turn;
input.messages[] array contains zero trace of the dropped T+2min obsidian question.
ZeroClaw version
commit 1291196 (fork branch based on upstream ~v0.5.0)
Rust version
rustc 1.93.1 (01f6ddf75 2026-02-11)
Operating system
macOS 26.3.1 (Darwin 25.3.0 arm64)
Regression?
Unknown
Pre-flight checks
Affected component
channel
Severity
S1 - workflow blocked
Current behavior
When a user in a WhatsApp group sends a message that @-mentions the bot by tapping the contact (the proper WhatsApp mention UI), the bot silently drops the message instead of processing it. The message never reaches the LLM and never gets persisted to session history — as if it never arrived.
This happens because the
mention_onlyfilter insrc/channels/whatsapp_web.rs:1313-1342only runs a substring check against the configuredmention_nametext fallback viacontains_mention():And
contains_mention(whatsapp_web.rs:337-339) is just:It does NOT consult the message's structural mentions — even though
extract_mentioned_jids()+contains_bot_mention()exist in the same file (lines 604-655) and do exactly that. Those helpers are wired into the downstream normalization block at lines 1465-1527, but only AFTER the upstream filter has already dropped the message.The WhatsApp protocol replaces the visible display name in a tap-mention with the raw phone digits in the text body. So when a user taps
@<bot-name>in the UI, thetext_content()arrives as:That string does NOT contain the substring
"<bot-name>"(configuredmention_name), socontains_mention()returns false and the message is silently discarded at line 1340. The message is written toobserve_storefor passive scanning but never enters session history, so subsequent turns in the same conversation have no record of it and the bot loses conversational context.Confirmed via Langfuse traces from a production daemon on 2026-04-09:
@<bot> Can you check if you have access to obsidian cli?→ no trace recorded, no LLM call madeinput.messages[]contains zero trace of the obsidian question; the conversation jumps straight from the prior turn to the follow-up, with the dropped message entirely absent.Expected behavior
Group messages where the bot is structurally mentioned (via
context_info.mentioned_jidcontaining the bot's phone digits) should pass themention_onlyfilter, be added to session history, and be processed by the LLM — regardless of whether the text body coincidentally contains the configuredmention_namesubstring.Both signals should be OR'd at the filter:
contains_mention(text, mention_name)(existing)contains_bot_mention(text, extract_mentioned_jids(&msg), bot_phone)(existing helper, just not wired into this filter)Suggested fix sketch — replace lines 1313-1317 of
src/channels/whatsapp_web.rs:This mirrors the same check already performed at lines 1465-1527 for content normalization — it just needs to happen upstream at the filter too, so structural mentions don't get dropped before entering session history.
Steps to reproduce
Impact
Affected users: anyone running the WhatsApp Web channel with
mention_only = truein groups where themention_namesubstring does not appear verbatim in the message text — i.e. most users who rely on structural @-mentions, which is the normal WhatsApp UX.Frequency: every group message that uses a tap-mention without the bot name also typed in the body.
Consequence: bot appears broken/unresponsive in groups; conversation history silently loses turns, causing the LLM to lose context on subsequent addressed turns. The only workaround is typing the
mention_namein the message body, which defeats the purpose of WhatsApp's structural mentions.Logs / stack traces
Langfuse trace pattern (redacted):
input.messages[]array contains zero trace of the dropped T+2min obsidian question.ZeroClaw version
commit 1291196 (fork branch based on upstream ~v0.5.0)
Rust version
rustc 1.93.1 (01f6ddf75 2026-02-11)
Operating system
macOS 26.3.1 (Darwin 25.3.0 arm64)
Regression?
Unknown
Pre-flight checks