fix(messaging): route WhatsApp group JIDs to the target, not the home DM - #46622
fix(messaging): route WhatsApp group JIDs to the target, not the home DM#46622kmccammon wants to merge 1 commit into
Conversation
send_message(target="whatsapp:<group-jid>") silently delivered to the configured home DM instead of the requested group. Two gaps: 1. _parse_target_ref had no WhatsApp branch. Group JIDs (<id>@g.us), user JIDs (<id>@s.whatsapp.net), linked-identity JIDs (<id>@lid), and broadcast/newsletter JIDs matched no pattern and fell through to `return None, None, False`, so the caller treated them as unresolvable and used the home channel. The bridge's /send endpoint accepts any chatId, so only the tool-side target parsing was at fault. Add a whatsapp branch that recognizes native JIDs as explicit targets. The pre-existing '+'-prefixed E.164 path is preserved. 2. WhatsApp groups have no human-friendly name — the channel directory is regenerated from session data on a timer, so a group shows up as its raw 18-digit JID and any hand-edit to channel_directory.json is clobbered on the next rebuild. Add a user-maintained alias overlay (~/.hermes/channel_aliases.json) re-applied on every build AND every load, giving durable friendly names and letting a freshly-created group be pre-named before its first message. Tests: TestParseTargetRefWhatsAppJID (7 cases) for the parser; TestChannelAliases (7 cases) for the overlay, plus an autouse fixture isolating CHANNEL_ALIASES_PATH so a real alias file can't leak into the existing directory tests.
|
Related: #41407 (bug), #20718 / #41415 / #18646 (open cluster) all fix the same _parse_target_ref WhatsApp-JID gap that routes group sends to the home channel. This PR adds that same core fix PLUS a user-maintained alias overlay (~/.hermes/channel_aliases.json in channel_directory.py) that the cluster lacks — so it's a superset/competing approach, not a strict duplicate. Maintainer should pick one core fix. |
|
Your commit was cherry-picked onto current Thanks for the fix — the raw WhatsApp group JID path now routes to the requested target instead of the configured home DM. |
Symptom
send_message(target="whatsapp:<group-jid>")silently delivers to the configured home DM instead of the requested group. The tool reports success with aSent to whatsapp home channelnote, so it looks like it worked — the message just lands in the wrong chat. Reproduced on a real gateway: a group message round-trips inbound fine (the gateway auto-replies in-context), but every outbound send addressed to the group JID falls back to the DM.Root cause
Two independent gaps, both tool-side (the Node bridge's
/sendendpoint already accepts anychatId):1.
_parse_target_refhas no WhatsApp branch (tools/send_message_tool.py).WhatsApp is in
_PHONE_PLATFORMS, but the only pattern that matches there is+-prefixed E.164. A group JID120363…@g.us, user JID…@s.whatsapp.net, linked-identity…@lid, or broadcast/newsletter JID matches no branch and hits the finalreturn None, None, False. The caller reads that as "not an explicit target" and substitutes the home channel.Fix: add a
whatsappbranch recognizing native JIDs as explicit. The existing+-E.164 path is untouched.2. WhatsApp groups have no friendly name (
gateway/channel_directory.py).The directory is regenerated from session data on a timer, so a group surfaces only as its raw 18-digit JID, and any hand-edit to
channel_directory.jsonis clobbered on the next rebuild. There's no way to give a group a stable name.Fix: add a user-maintained alias overlay at
~/.hermes/channel_aliases.json, re-applied on every build (persisted) and every load (immediate, survives between rebuilds). Format:{ "whatsapp": { "120363408391911677@g.us": "general" } }Aliases rename matching entries in place and inject a placeholder for an aliased id not yet discovered — so a freshly-created group is addressable by name before its first message.
Tests
TestParseTargetRefWhatsAppJID(7 cases): group/user/lid/broadcast/newsletter JIDs are explicit; E.164 still works; JID suffixes are not explicit on other platforms; bare friendly names fall through to directory resolution.TestChannelAliases(7 cases): rename-on-load, resolve-by-name (case-insensitive), inject-undiscovered-group, no-file no-op, corrupt-file ignored, persist-through-rebuild, malformed-map safety.CHANNEL_ALIASES_PATHin the directory test module so a real~/.hermes/channel_aliases.jsoncan't leak into existing tests.All 110 tests in the touched areas pass locally (
tests/gateway/test_channel_directory.py,tests/tools/test_send_message_target_parse.py,tests/gateway/test_weixin.py). The maintest_send_message_tool.pymoduleimportorskipspython-telegram-bot(not installed in this env); the new parser assertions were verified directly against the patched function.Cache / invariant safety
No change to the system prompt, message alternation, or per-conversation caching. Pure target-resolution + directory-overlay logic. Alias config lives in a JSON file under
~/.hermes/, not in.envand not a newHERMES_*env var.