Skip to content

feat(whatsapp): WhatsApp @mention tagging support - #81208

Open
dhruvkej9 wants to merge 5 commits into
NousResearch:mainfrom
dhruvkej9:feat/whatsapp-mention-tagging
Open

feat(whatsapp): WhatsApp @mention tagging support#81208
dhruvkej9 wants to merge 5 commits into
NousResearch:mainfrom
dhruvkej9:feat/whatsapp-mention-tagging

Conversation

@dhruvkej9

Copy link
Copy Markdown
Contributor

Problem

WhatsApp @mention tagging is missing in Hermes, and the model has no idea who is in a group:

  • Inbound: the bridge already extracts contextInfo.mentionedJid into the event's mentionedIds, but the adapter silently dropped it — the agent never learns who a group message @mentions.
  • Outbound: the bridge send path had no mention support at all, so the bot could not @tag anyone.
  • Context: even with mention support, the model would need to know a member's JID to tag them — it had no group roster, so "tell @ankit X" was impossible.

Fix

Mention pass-through

  • buildTextSendPayload accepts mentions and emits Baileys-native content.mentions
  • /send accepts a mentions array and forwards it
  • adapter.send() accepts mentions and passes them through
  • Adapter surfaces inbound mentionedIds as whatsapp_mentioned_ids in MessageEvent metadata

Group roster + @name resolution

  • Bridge keeps a pushName cache (jid → display name) fed from inbound messages; /chat/:id returns participants as [{id, name}] (falls back to the @username handle, then the bare number)
  • /send resolves @Name tokens in the text against the cached group roster (5-min TTL) into Baileys mentions — the model writes @Ankit, Ankit gets a real tag. Case-insensitive substring match; unknown names stay literal.
  • Adapter prepends a compact [Group members: ...] line to group messages (cached 10 min) so the model always knows who is in the group

No auto-tag on reply — WhatsApp already notifies the replied-to user, so tagging stays the model's explicit choice.

Tests

bridge.native.test.mjs: roster building (pushName → username → number fallback), @name resolution (case-insensitive, unknown ignored), mention pass-through. All 18 native bridge tests + 20 whatsapp pytest pass.

…ssion keys

SessionStore._generate_session_key and the run.py fallback/write paths
read group_sessions_per_user / thread_sessions_per_user only from the
global gateway config, while the adapters' text-batching keys resolve
per-platform extra.* overrides. This divergence means a WhatsApp group
with extra.group_sessions_per_user: false still gets per-user session
keys on the main dispatch path, so each member carries a separate
context even though batching keys say they share one.

Resolve the per-platform extra overrides in the same three places the
session key is built so dispatch, fallback, and shared-session
attribution never diverge from the adapter's batching key.
The shared-key loop in load_gateway_config() only bridged known top-level
keys (dm_policy, group_policy, require_mention, ...) into the platform
extra and silently dropped the platform's own nested ``extra:`` dict. So
``whatsapp.extra.group_sessions_per_user: false`` never reached
PlatformConfig.extra, and the session-key paths (which honor per-platform
extra) fell back to the global default - every group member kept a
separate context even though the config asked for a shared group session.

Preserve the nested ``extra:`` dict before applying bridged keys so
top-level bridged keys keep precedence. Adds a regression test that fails
on main (nested extra dropped) and passes with this fix.
Two halves of the same feature:

INBOUND — the bridge already extracts contextInfo.mentionedJid into the
event's mentionedIds, but the adapter dropped it. Surface it as
whatsapp_mentioned_ids in MessageEvent metadata so the agent can see who
a group message @mentions.

OUTBOUND — the bridge send path had no mention support at all. Add:
- buildTextSendPayload accepts mentions and emits content.mentions
  (Baileys native @tag)
- /send accepts a mentions array and forwards it
- adapter.send() accepts mentions and passes them through
- Auto-tag: when replying to a message in a group, the replied-to
  author is @mentioned automatically (WhatsApp @ behavior), so the user
  knows the reply is addressed to them. DM replies (no key.participant)
  and replies to the bot's own messages are skipped.

Tests: bridge.native.test.mjs covers DM/own-message no-mention, explicit
mentions, and auto-tag merge. All 17 native + 20 whatsapp pytest pass.
Builds on the mention pass-through with the missing half: the model
could tag a member only if it already knew their JID. Now it doesn't
need to.

- Bridge keeps a pushName cache (jid -> display name) fed from inbound
  messages; /chat/:id returns participants as [{id, name}] (name falls
  back to the @username handle, then the bare number).
- /send resolves "@name" tokens in the text against the cached group
  roster (5-min TTL) into Baileys mentions, so the model can write
  "@ankit" and Ankit gets a real tag. Case-insensitive substring match;
  unknown names are left as literal text.
- Adapter prepends a compact "[Group members: ...]" line to group
  messages (cached 10 min) so the model always knows who is in the
  group, and surfaces inbound mentionedIds as whatsapp_mentioned_ids.
- No auto-tag on reply: WhatsApp already notifies the replied-to user,
  so tagging stays the model's explicit choice.

Tests: bridge.native.test.mjs covers roster building, @name resolution
(case-insensitive, unknown ignored), and mention pass-through. All 18
native + 20 whatsapp pytest pass.
@alt-glitch alt-glitch added type/feature New feature or request P3 Low — cosmetic, nice to have comp/gateway Gateway runner, session dispatch, delivery comp/plugins Plugin system and bundled plugins platform/whatsapp WhatsApp Business adapter sweeper:risk-message-delivery Sweeper risk: may drop, duplicate, misroute, or suppress messages sweeper:risk-session-state Sweeper risk: may lose/corrupt/mis-associate session or context state sweeper:risk-compatibility Sweeper risk: may break existing users, config, migrations, defaults, or upgrades labels Aug 7, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comp/gateway Gateway runner, session dispatch, delivery comp/plugins Plugin system and bundled plugins P3 Low — cosmetic, nice to have platform/whatsapp WhatsApp Business adapter sweeper:risk-compatibility Sweeper risk: may break existing users, config, migrations, defaults, or upgrades sweeper:risk-message-delivery Sweeper risk: may drop, duplicate, misroute, or suppress messages sweeper:risk-session-state Sweeper risk: may lose/corrupt/mis-associate session or context state type/feature New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants