feat(whatsapp): inbound reaction events (#1)
* feat(whatsapp): subscribe to inbound reaction events Subscribe to Baileys `messages.reaction` events and surface them as system events for the agent session. Follows the same pattern used by Signal and Slack: listen → parse → route → enqueueSystemEvent. - Add `WebInboundReaction` type and `onReaction` callback to monitor - Parse emoji, sender JID, target message ID from Baileys event - Route via `resolveAgentRoute` and enqueue as system event - Handle self-reaction attribution (reactionKey.fromMe → selfJid) - Skip reaction removals (empty emoji) and status/broadcast JIDs - Outer + inner try/catch for resilience against malformed events - 13 unit tests (monitor-level + system event wiring) - Changelog entry and docs updates Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * revert changelog entry to avoid merge conflicts The inbound reaction feature is internal plumbing, not user-facing enough to warrant a changelog entry that will conflict with active PRs. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * feat(whatsapp): handle reaction removals and improve sender detection - Emit reaction events with isRemoval flag instead of skipping them - Fall back to chatJid for DM sender when reaction.key is missing - Add chatType and accountId to reaction logs for observability - Update tests to reflect new removal handling behavior Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * fix(whatsapp): gate reactions by DM/group access controls Address Codex review - reactions now respect the same access controls as messages (dmPolicy, allowlists, etc). Self-reactions bypass the check since they're our own actions, not inbound events. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * chore: remove unused senderName field from reaction type Baileys reaction events don't include push names, so this field was dead interface pollution. (Cursor review) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * fix(whatsapp): update reaction docs + suppress pairing for reactions - Update docs: reaction removals now emit events with isRemoval=true - Pass no-op sendMessage to access control to prevent pairing messages being sent when unknown users react (pairing is for messages, not reactions) (Cursor review) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> --------- Co-authored-by: Nick Sullivan <nick@technick.ai> Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
09be5d45d5
commit
5571967ebd
8 files changed
+844
-3
No files matched your search
@@ -269,6 +269,21 @@ WhatsApp can automatically send emoji reactions to incoming messages immediately
|
||||
- Reaction removal semantics: see [/tools/reactions](/tools/reactions).
|
||||
- Tool gating: `channels.whatsapp.actions.reactions` (default: enabled).
|
||||
|
||||
## Inbound reaction notifications
|
||||
|
||||
When someone reacts to a message in a WhatsApp chat, the gateway emits a system event so the agent sees it in its next prompt. System events appear as lines like:
|
||||
|
||||
```
|
||||
WhatsApp reaction added: 👍 by +1234567890 msg BAE5ABC123
|
||||
WhatsApp reaction removed by +1234567890 msg BAE5ABC123
|
||||
```
|
||||
|
||||
- Reaction removals emit events with `isRemoval: true` and no emoji in the message.
|
||||
- Self-reactions in DMs are correctly attributed to the bot's own JID.
|
||||
- Group reactions include the participant who reacted.
|
||||
- Events are deduplicated by message ID, sender, and emoji to avoid repeat notifications.
|
||||
- No configuration required; inbound reactions are always surfaced when the gateway is running.
|
||||
|
||||
## Limits
|
||||
- Outbound text is chunked to `channels.whatsapp.textChunkLimit` (default 4000).
|
||||
- Optional newline chunking: set `channels.whatsapp.chunkMode="newline"` to split on blank lines (paragraph boundaries) before length chunking.
|
||||
|
||||
@@ -3,6 +3,7 @@ summary: "Reaction semantics shared across channels"
|
||||
read_when:
|
||||
- Working on reactions in any channel
|
||||
---
|
||||
|
||||
# Reaction tooling
|
||||
|
||||
Shared reaction semantics across channels:
|
||||
@@ -18,3 +19,4 @@ Channel notes:
|
||||
- **Telegram**: empty `emoji` removes the bot's reactions; `remove: true` also removes reactions but still requires a non-empty `emoji` for tool validation.
|
||||
- **WhatsApp**: empty `emoji` removes the bot reaction; `remove: true` maps to empty emoji (still requires `emoji`).
|
||||
- **Signal**: inbound reaction notifications emit system events when `channels.signal.reactionNotifications` is enabled.
|
||||
- **WhatsApp**: inbound reaction notifications are always surfaced as system events (no configuration required).
|
||||
Reference in new issue
Block a user