hermes - 💡(How to fix) Fix feat(whatsapp): mirror Discord's message-status reactions (👀 / ✅ / ❌) onto WhatsApp messages

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…

The Discord platform adapter reacts to incoming user messages to surface processing state: 👀 while the agent is thinking, then ✅ on success or ❌ on failure. This gives users an at-a-glance signal that the message was received and is being worked on — particularly valuable when the response takes more than a few seconds.

WhatsApp doesn't have this. There's no signal between "I sent the message" and "the response arrives" — and Baileys (the WhatsApp Web protocol library the bridge uses) supports reactions natively, so the capability exists at the wire level. This is feature parity that would benefit any user running the WhatsApp adapter.

Root Cause

The Discord platform adapter reacts to incoming user messages to surface processing state: 👀 while the agent is thinking, then ✅ on success or ❌ on failure. This gives users an at-a-glance signal that the message was received and is being worked on — particularly valuable when the response takes more than a few seconds.

WhatsApp doesn't have this. There's no signal between "I sent the message" and "the response arrives" — and Baileys (the WhatsApp Web protocol library the bridge uses) supports reactions natively, so the capability exists at the wire level. This is feature parity that would benefit any user running the WhatsApp adapter.

Fix Action

Fix / Workaround

I've been running this as a local plugin for about a week (monkey-patches WhatsAppAdapter.on_processing_start and .on_processing_complete, plus a locally-modified bridge.js with the /react endpoint). It works reliably, and the failure modes are gentle: if the bridge isn't reachable, the reaction call fails silently and message processing proceeds normally.

Workaround until merged

# ~/.hermes/plugins/whatsapp-reactions/__init__.py
from gateway.platforms.whatsapp import WhatsAppAdapter
WhatsAppAdapter.on_processing_start = _on_processing_start  # patched implementation
WhatsAppAdapter.on_processing_complete = _on_processing_complete

Code Example

def _reactions_enabled(self) -> bool:
    return os.getenv("DISCORD_REACTIONS", "true").lower() not in ("false", "0", "no")

async def on_processing_start(self, event: MessageEvent) -> None:
    if not self._reactions_enabled():
        return
    message = event.raw_message
    if hasattr(message, "add_reaction"):
        await self._add_reaction(message, "👀")

async def on_processing_complete(self, event: MessageEvent, outcome: ProcessingOutcome) -> None:
    if not self._reactions_enabled():
        return
    message = event.raw_message
    if hasattr(message, "add_reaction"):
        await self._remove_reaction(message, "👀")
        if outcome == ProcessingOutcome.SUCCESS:
            await self._add_reaction(message, "✅")
        elif outcome == ProcessingOutcome.FAILURE:
            await self._add_reaction(message, "❌")

---

# ~/.hermes/plugins/whatsapp-reactions/__init__.py
from gateway.platforms.whatsapp import WhatsAppAdapter
WhatsAppAdapter.on_processing_start = _on_processing_start  # patched implementation
WhatsAppAdapter.on_processing_complete = _on_processing_complete
RAW_BUFFERClick to expand / collapse

Summary

The Discord platform adapter reacts to incoming user messages to surface processing state: 👀 while the agent is thinking, then ✅ on success or ❌ on failure. This gives users an at-a-glance signal that the message was received and is being worked on — particularly valuable when the response takes more than a few seconds.

WhatsApp doesn't have this. There's no signal between "I sent the message" and "the response arrives" — and Baileys (the WhatsApp Web protocol library the bridge uses) supports reactions natively, so the capability exists at the wire level. This is feature parity that would benefit any user running the WhatsApp adapter.

Where the Discord reference lives

gateway/platforms/discord.py lines 1318-1340:

def _reactions_enabled(self) -> bool:
    return os.getenv("DISCORD_REACTIONS", "true").lower() not in ("false", "0", "no")

async def on_processing_start(self, event: MessageEvent) -> None:
    if not self._reactions_enabled():
        return
    message = event.raw_message
    if hasattr(message, "add_reaction"):
        await self._add_reaction(message, "👀")

async def on_processing_complete(self, event: MessageEvent, outcome: ProcessingOutcome) -> None:
    if not self._reactions_enabled():
        return
    message = event.raw_message
    if hasattr(message, "add_reaction"):
        await self._remove_reaction(message, "👀")
        if outcome == ProcessingOutcome.SUCCESS:
            await self._add_reaction(message, "✅")
        elif outcome == ProcessingOutcome.FAILURE:
            await self._add_reaction(message, "❌")

These override no-op hooks defined on BasePlatformAdapter, which exist specifically for adapter-specific UX like reactions.

What's needed for WhatsApp parity

Two pieces:

  1. scripts/whatsapp-bridge/bridge.js — a new POST /react endpoint that accepts { chatId, messageId, fromMe, emoji } and calls sock.sendMessage(chatId, { react: { text: emoji, key } }). Baileys treats text: "" as a reaction removal, which is needed to clear the in-progress 👀 before posting the final marker.

  2. gateway/platforms/whatsapp.py — override on_processing_start and on_processing_complete to POST to the bridge's new /react endpoint via aiohttp, matching the pattern of existing /send, /edit, /typing calls in the same file. Gated by WHATSAPP_REACTIONS env var (default true), matching DISCORD_REACTIONS.

The implementation is essentially the Discord adapter's reactions logic translated to call the bridge HTTP API instead of using a Python client object's add_reaction method.

Proof of concept

I've been running this as a local plugin for about a week (monkey-patches WhatsAppAdapter.on_processing_start and .on_processing_complete, plus a locally-modified bridge.js with the /react endpoint). It works reliably, and the failure modes are gentle: if the bridge isn't reachable, the reaction call fails silently and message processing proceeds normally.

The plugin code is ~120 lines including comments. The bridge endpoint is ~20 lines. Both straightforward translations of the Discord pattern.

Workaround until merged

Run as a plugin. Sketch:

# ~/.hermes/plugins/whatsapp-reactions/__init__.py
from gateway.platforms.whatsapp import WhatsAppAdapter
WhatsAppAdapter.on_processing_start = _on_processing_start  # patched implementation
WhatsAppAdapter.on_processing_complete = _on_processing_complete

Plus the /react endpoint added to a local copy of bridge.js (which requires pointing whatsapp.bridge_script in config.yaml at the override).

This works but every user has to set it up themselves and re-apply the bridge.js change on each hermes update.

Willing to send a PR

Happy to send a PR with the implementation if welcomed. The code is already proven against my own WhatsApp deployment. Approach:

  1. Add /react endpoint to scripts/whatsapp-bridge/bridge.js.
  2. Add _react() helper + _reactions_enabled() + the two override hooks to WhatsAppAdapter.
  3. Mirror the Discord adapter's env-var gating (WHATSAPP_REACTIONS).

Let me know if the design direction works or if you'd prefer it shaped differently.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING

hermes - 💡(How to fix) Fix feat(whatsapp): mirror Discord's message-status reactions (👀 / ✅ / ❌) onto WhatsApp messages