mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-06 21:40:44 +00:00
BlueBubbles short message ids (numeric aliases like "1", "5" that agents use instead of full GUIDs to save tokens) are allocated from a single global counter across every account and every chat. Nothing in resolveBlueBubblesMessageId verified that the resolved GUID was actually in the chat the caller was acting on, so any time an agent reused or mis-remembered a short id — especially common after a long group conversation — the id could silently point at a different chat entirely. Symptom Chris observed: reactions/tapbacks and quoted replies authored inside a group would intermittently land in a DM, targeting an old message the user could no longer see. Tool call looks successful, chat archive shows a group reaction appearing in the DM transcript. Add an optional chatContext parameter to resolveBlueBubblesMessageId (chatGuid / chatIdentifier / chatId). When provided, look up the cached reply entry for the resolved GUID and compare. A clear mismatch (same identifier present on both sides, different values) throws with a message that lists both chats and points at "use the full GUID", so the agent fails fast and retries with a disambiguated id. Ambiguous cases (either side missing all identifiers) pass through to preserve existing behavior for callers that cannot supply chat hints. The comparison mirrors resolveReplyContextFromCache so outbound and inbound paths agree on scope. Update every call site that resolves a short id for outbound BB traffic to pass chatContext: - extensions/bluebubbles/src/actions.ts: react, edit, unsend, reply (build context from chat* params, then to/target, then the tool's currentChannelId) - extensions/bluebubbles/src/channel.ts sendText: derive context from the `to` target - extensions/bluebubbles/src/media-send.ts: same - extensions/bluebubbles/src/monitor-processing.ts deliver path: pass the chat already resolved for routing Add buildBlueBubblesChatContextFromTarget to targets.ts so callers can project a raw target string (`chat_guid:...`, `chat_id:42`, `imessage:+1...`, bare handle) into the context shape. Tests: - extensions/bluebubbles/src/monitor-reply-cache.test.ts (new, 8 cases): same-chat resolves, cross-chatGuid throws, ambiguous passes, chatIdentifier fallback, chatId fallback, full GUID input bypasses, error message identifies both chats, unknown short id still errors. - extensions/bluebubbles/src/actions.test.ts: update the react short-id assertion to verify chatContext now flows through. Local patch for upstream consideration — same root cause affects every BB user; plan is to open a separate upstream PR once this bakes locally.
BlueBubbles extension (developer reference)
This package contains the BlueBubbles external channel plugin for OpenClaw.
If you’re 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 viaregisterPluginHttpRoute). - REST helpers:
src/send.ts+src/probe.ts. - Runtime bridge:
src/runtime.ts(set viaapi.runtime). - Catalog entry for setup selection:
src/channels/plugins/catalog.ts.
Internal helpers (use these, not raw API calls)
probeBlueBubblesinsrc/probe.tsfor health checks.sendMessageBlueBubblesinsrc/send.tsfor text delivery.resolveChatGuidForTargetinsrc/send.tsfor chat lookup.sendBlueBubblesReactioninsrc/reactions.tsfor tapbacks.sendBlueBubblesTyping+markBlueBubblesChatReadinsrc/chat.ts.downloadBlueBubblesAttachmentinsrc/attachments.tsfor inbound media.buildBlueBubblesApiUrl+blueBubblesFetchWithTimeoutinsrc/types.tsfor 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) andopenclaw/plugin-sdkhelpers. - For attachments/stickers, use
<media:...>placeholders when text is empty and attach media paths viaMediaUrl(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
reactaction requires atarget(phone number or chat identifier) in addition tomessageId. Example:action=react target=+15551234567 messageId=ABC123 emoji=❤️