Files
openclaw/extensions/bluebubbles
zqchris 77b424b15e BlueBubbles/reactions: fall back unsupported reactions to love (#64693)
* bluebubbles: fall back unsupported reactions to love

iMessage tapback only supports love/like/dislike/laugh/emphasize/question.
Previously, `normalizeBlueBubblesReactionInput` threw when the input did
not map to one of those (e.g. a non-standard unicode emoji like 👀 used
to mean "seen, working on it"), which aborted the whole reaction request
and left the user with no feedback.

This splits the normalizer into a strict and lenient variant:

- `normalizeBlueBubblesReactionInputStrict` throws on unsupported input
  and is used by validator-style callers (e.g. `resolveBlueBubblesAckReaction`
  in monitor-processing.ts) that rely on the throw to detect misconfigured
  ack reactions and skip them cleanly. This preserves the previous silent-skip
  + warn-once behavior for ack reactions configured with an unsupported
  emoji.
- `normalizeBlueBubblesReactionInput` stays lenient and falls back to
  `love` (or `-love` when removing) on unsupported input, so agent-driven
  `sendBlueBubblesReaction` still produces a visible tapback instead of
  failing the whole reaction request. Contract errors (empty input)
  continue to bubble up.

`love` is chosen over `like` as the neutral default: `❤️` reads as a
general acknowledgment across chat norms, while `👍` carries an
agreement connotation that does not match the "seen, working on it"
semantic.

* CHANGELOG: note BlueBubbles reaction fallback

---------

Co-authored-by: Omar Shahine <10343873+omarshahine@users.noreply.github.com>
2026-04-19 20:52:36 -07:00
..

BlueBubbles extension (developer reference)

This package contains the BlueBubbles external channel plugin for OpenClaw.

If youre looking for how to use BlueBubbles as an agent/tool user, see:

  • skills/bluebubbles/SKILL.md

Layout

  • Package entry: index.ts.
  • Channel implementation: src/channel.ts.
  • Webhook handling: src/monitor.ts (register per-account route via registerPluginHttpRoute).
  • REST helpers: src/send.ts + src/probe.ts.
  • Runtime bridge: src/runtime.ts (set via api.runtime).
  • Catalog entry for setup selection: src/channels/plugins/catalog.ts.

Internal helpers (use these, not raw API calls)

  • probeBlueBubbles in src/probe.ts for health checks.
  • sendMessageBlueBubbles in src/send.ts for text delivery.
  • resolveChatGuidForTarget in src/send.ts for chat lookup.
  • sendBlueBubblesReaction in src/reactions.ts for tapbacks.
  • sendBlueBubblesTyping + markBlueBubblesChatRead in src/chat.ts.
  • downloadBlueBubblesAttachment in src/attachments.ts for inbound media.
  • buildBlueBubblesApiUrl + blueBubblesFetchWithTimeout in src/types.ts for shared REST plumbing.

Webhooks

  • BlueBubbles posts JSON to the gateway HTTP server.
  • Normalize sender/chat IDs defensively (payloads vary by version).
  • Skip messages marked as from self.
  • Route into core reply pipeline via the plugin runtime (api.runtime) and openclaw/plugin-sdk helpers.
  • For attachments/stickers, use <media:...> placeholders when text is empty and attach media paths via MediaUrl(s) in the inbound context.

Config (core)

  • channels.bluebubbles.serverUrl (base URL), channels.bluebubbles.password, channels.bluebubbles.webhookPath.
  • Action gating: channels.bluebubbles.actions.reactions (default true).

Message tool notes

  • Reactions: the react action requires a target (phone number or chat identifier) in addition to messageId. Example: action=react target=+15551234567 messageId=ABC123 emoji=❤️