hermes-agent/scripts/whatsapp-bridge
keiravoss94 84f350efe0 feat(whatsapp): opt-in forwarding of owner-typed messages in bot mode
In `WHATSAPP_MODE=bot` the bridge currently drops every fromMe inbound
message — they are all assumed to be echoes of our own /send calls.
That makes it impossible for plugins / agents to detect when a human
owner has typed directly into a customer chat from the same WhatsApp
Business account (e.g. via a linked phone or WhatsApp Web).

This adds an opt-in `WHATSAPP_FORWARD_OWNER_MESSAGES` env var.  When
true, the bridge classifies fromMe inbound by looking up `key.id` in a
bounded LRU of recently-sent message IDs (the existing 50-entry echo
suppressor, bumped to 512 and extracted to a testable
`outbound_ids.js` helper).  Hits in the LRU are still dropped (echoes);
misses are forwarded to the Python adapter with `fromOwner: true`.

The Python adapter lifts that flag onto
`MessageEvent.metadata["whatsapp_from_owner"]`.  `metadata` is a new
free-form dict on the event so future per-platform signals don't each
need their own field.  Default behaviour is unchanged: with the env
flag unset, bot mode still drops every fromMe message exactly as
before.

Use cases for downstream consumers:
- Implicit handover activation when the owner replies manually
- Sliding TTL on owner activity (keep an active session alive while
  the owner is engaged)
- Audit trails of owner interventions
- Analytics on human-vs-bot reply ratios

Heuristic limitation (documented in code): the LRU is in-memory.  After
a bridge restart, in-flight delivery receipts of pre-restart sends will
briefly look like owner-typed for a few seconds until the set is
repopulated.  Persisting isn't worth the disk churn — downstream
consumers should treat the flag as best-effort.

Tests:
- tests/gateway/test_whatsapp_from_owner.py (new): adapter sets the
  metadata flag iff the bridge payload has `fromOwner: true`; absent
  otherwise.
- scripts/whatsapp-bridge/outbound_ids.test.mjs (new): LRU bounds,
  eviction order, falsy-id handling.

Backwards compatibility: with the env flag unset, every code path is
identical to before.  No existing deployment is affected.
2026-06-30 03:41:43 -07:00
..
allowlist.js fix(whatsapp): reject strangers by default, never respond in self-chat (#8389) (#21291) 2026-05-07 06:53:04 -07:00
allowlist.test.mjs fix(whatsapp): reject strangers by default, never respond in self-chat (#8389) (#21291) 2026-05-07 06:53:04 -07:00
bridge.js feat(whatsapp): opt-in forwarding of owner-typed messages in bot mode 2026-06-30 03:41:43 -07:00
bridge.sendqueue.test.mjs fix(whatsapp-bridge): serialize sendMessage to prevent cross-chat contamination (#33360) 2026-06-28 01:10:14 -07:00
outbound_ids.js feat(whatsapp): opt-in forwarding of owner-typed messages in bot mode 2026-06-30 03:41:43 -07:00
outbound_ids.test.mjs feat(whatsapp): opt-in forwarding of owner-typed messages in bot mode 2026-06-30 03:41:43 -07:00
package-lock.json Add Hermes desktop app (#20059) 2026-05-31 17:46:56 -05:00
package.json fix(whatsapp): pin protobufjs >=7.5.5 via npm overrides to clear 3 critical vulns (#19204) 2026-05-03 05:22:30 -07:00