状态:已捆绑的插件,通过 HTTP 与 BlueBubbles macOS 服务器通信。由于其 API 更丰富、设置比旧版 imsg 渠道更简单,推荐用于 iMessage 集成。Documentation Index
Fetch the complete documentation index at: https://openclaw.zhcndoc.com/llms.txt
Use this file to discover all available pages before exploring further.
当前 OpenClaw 版本已捆绑 BlueBubbles,因此常规打包构建不需要单独执行
openclaw plugins install 步骤。概览
- 通过 BlueBubbles 辅助应用在 macOS 上运行(bluebubbles.app)。
- 推荐/已测试:macOS Sequoia(15)。macOS Tahoe(26)可用;但当前在 Tahoe 上编辑功能失效,且群组图标更新可能会显示成功但不会同步。
- OpenClaw 通过其 REST API 与之通信(
GET /api/v1/ping、POST /message/text、POST /chat/:id/*)。 - 收到的消息通过 webhook 传入;发出的回复、输入指示、已读回执和 tapback 都是 REST 调用。
- 附件和贴纸会作为入站媒体被接收(并在可能时展示给代理)。
- 自动 TTS 回复生成的 MP3 或 CAF 音频会以 iMessage 语音备忘气泡的形式发送,而不是普通文件附件。
- 配对/允许名单与其他渠道(
/channels/pairing等)一致,使用channels.bluebubbles.allowFrom+ 配对代码。 - 反应会像 Slack/Telegram 一样作为系统事件呈现,因此代理可以在回复前“提及”它们。
- 高级功能:编辑、撤回、回复线程、消息效果、群组管理。
快速开始
安装 BlueBubbles
在你的 Mac 上安装 BlueBubbles 服务器(按照 bluebubbles.app/install 上的说明进行)。
将 webhooks 指向网关
将 BlueBubbles webhooks 指向你的网关(示例:
https://your-gateway-host:3000/bluebubbles-webhook?password=<password>)。保持 Messages.app 存活(VM / 无头部署)
某些 macOS 虚拟机 / 常驻运行环境可能会导致 Messages.app 进入“空闲”状态(传入事件会停止,直到应用被打开/切到前台)。一个简单的解决办法是使用 AppleScript + LaunchAgent 每 5 分钟唤醒一次 Messages。安装 LaunchAgent
将以下内容保存为 这会每 300 秒以及登录时运行。首次运行可能会触发 macOS 的自动化提示(
~/Library/LaunchAgents/com.user.poke-messages.plist:osascript → Messages)。请在运行该 LaunchAgent 的同一用户会话中批准它们。入门配置
BlueBubbles 可在交互式 onboarding 中使用:BlueBubbles 服务器地址(例如
http://192.168.1.100:1234)。来自 BlueBubbles Server 设置的 API 密码。
Webhook 端点路径。
pairing、allowlist、open 或 disabled。电话号码、电子邮件或聊天目标。
访问控制(DM + 群组)
- DM
- Groups
- 默认:
channels.bluebubbles.dmPolicy = "pairing"。 - 未知发送者会收到配对代码;在获得批准前消息会被忽略(代码 1 小时后过期)。
- 通过以下方式批准:
openclaw pairing list bluebubblesopenclaw pairing approve bluebubbles <CODE>
- 配对是默认的令牌交换方式。详情:配对
联系人姓名增强(macOS,可选)
BlueBubbles 群组 webhooks 通常只包含原始参与者地址。如果你希望GroupMembers 上下文显示本地联系人姓名,可以选择在 macOS 上启用本地通讯录增强:
channels.bluebubbles.enrichGroupParticipantsFromContacts = true启用查找。默认:false。- 只有在群组访问、命令授权和提及门控都允许消息通过之后,才会运行查找。
- 仅增强未命名的电话参与者。
- 如果未找到本地匹配,原始电话号码仍会作为回退。
提及门控(群组)
BlueBubbles 支持群聊的提及门控,行为与 iMessage/WhatsApp 一致:- 使用
agents.list[].groupChat.mentionPatterns(或messages.groupChat.mentionPatterns)来检测提及。 - 当群组启用
requireMention时,代理仅在被提及时才会响应。 - 来自已授权发送者的控制命令会绕过提及门控。
命令门控
- 控制命令(例如
/config、/model)需要授权。 - 使用
allowFrom和groupAllowFrom来确定命令授权。 - 已授权发送者即使在群组中未提及也可以运行控制命令。
每群组系统提示词
channels.bluebubbles.groups.* 下的每个条目都接受一个可选的 systemPrompt 字符串。该值会在处理该群组中的消息时注入到代理每一轮的系统提示词中,因此你可以为每个群组设置人格或行为规则,而无需编辑代理提示词:
chatGuid / chatIdentifier / 数字 chatId,而 "*" 通配符条目会为每个没有精确匹配的群组提供默认值(与 requireMention 和每群组工具策略使用相同模式)。精确匹配始终优先于通配符。DM 会忽略此字段;请改用代理级别或账户级别的提示词自定义。
详细示例:线程回复和 tapback 反应(Private API)
启用 BlueBubbles Private API 后,入站消息会带有短消息 ID(例如[[reply_to:5]]),代理可以调用 action=reply 将消息线程回复到特定消息,或者调用 action=react 发出 tapback。每群组的 systemPrompt 是一种可靠方式,可帮助代理始终选择正确的工具:
ACP 对话绑定
BlueBubbles 聊天可以在不更改传输层的情况下转换为持久的 ACP 工作区。 快速操作流程:- 在 DM 或允许的群聊中运行
/acp spawn codex --bind here。 - 同一 BlueBubbles 会话中的后续消息会路由到已生成的 ACP 会话。
/new和/reset会就地重置同一个已绑定的 ACP 会话。/acp close会关闭 ACP 会话并移除绑定。
bindings[] 条目配置持久绑定,使用 type: "acp" 和 match.channel: "bluebubbles"。
match.peer.id 可以使用任何受支持的 BlueBubbles 目标形式:
- 规范化的 DM 句柄,例如
+15555550123或user@example.com chat_id:<id>chat_guid:<guid>chat_identifier:<identifier>
chat_id:* 或 chat_identifier:*。
示例:
输入中提示 + 已读回执
- 输入中指示:在生成回复前和生成过程中会自动发送。
- 已读回执:由
channels.bluebubbles.sendReadReceipts控制(默认:true)。 - 输入中指示:OpenClaw 会发送输入开始事件;BlueBubbles 会在发送或超时后自动清除输入状态(通过 DELETE 手动停止并不可靠)。
高级操作
在配置中启用后,BlueBubbles 支持高级消息操作:可用操作
可用操作
- react:添加/移除 tapback 反应(
messageId、emoji、remove)。iMessage 原生 tapback 集合是love、like、dislike、laugh、emphasize和question。当代理选择了该集合之外的 emoji(例如👀)时,reaction 工具会回退为love,这样 tapback 仍然会显示,而不会导致整个请求失败。已配置的 ack reactions 仍会严格校验,并在未知值上报错。 - edit:编辑已发送消息(
messageId、text)。 - unsend:撤回消息(
messageId)。 - reply:回复特定消息(
messageId、text、to)。 - sendWithEffect:以 iMessage 特效发送(
text、to、effectId)。 - renameGroup:重命名群聊(
chatGuid、displayName)。 - setGroupIcon:设置群聊图标/照片(
chatGuid、media)——在 macOS 26 Tahoe 上不稳定(API 可能返回成功,但图标不会同步)。 - addParticipant:向群组添加某人(
chatGuid、address)。 - removeParticipant:从群组中移除某人(
chatGuid、address)。 - leaveGroup:离开群聊(
chatGuid)。 - upload-file:发送媒体/文件(
to、buffer、filename、asVoice)。- 语音备忘录:将
asVoice: true与 MP3 或 CAF 音频一起使用,可作为 iMessage 语音消息发送。BlueBubbles 在发送语音备忘录时会将 MP3 转换为 CAF。
- 语音备忘录:将
- 旧别名:
sendAttachment仍然可用,但upload-file是规范的操作名称。
消息 ID(短 ID 与完整 ID)
OpenClaw 可能会暴露 短 消息 ID(例如1、2)以节省 token。
MessageSid/ReplyToId可以是短 ID。MessageSidFull/ReplyToIdFull包含提供方的完整 ID。- 短 ID 只存在于内存中;重启或缓存回收后可能过期。
- 操作接受短或完整的
messageId,但如果短 ID 不再可用则会报错。
- 模板:
{{MessageSidFull}}、{{ReplyToIdFull}} - 上下文:入站载荷中的
MessageSidFull/ReplyToIdFull
合并拆分发送的 DM(命令 + URL 在同一条消息中)
当用户在 iMessage 中同时输入命令和 URL——例如Dump https://example.com/article——Apple 会把发送拆成 两个独立的 webhook 投递:
- 一条文本消息(
"Dump")。 - 一个 URL 预览气泡(
"https://..."),并附带 OG 预览图片作为附件。
channels.bluebubbles.coalesceSameSenderDms 会将 DM 中连续来自同一发送者的 webhook 合并为一次代理回合。群聊仍然按每条消息进行标记,因此多用户回合结构会被保留。
- 何时启用
- 启用方式
- 权衡
在以下情况启用:
- 你提供的技能期望在一条消息里同时包含
command + payload(dump、paste、save、queue 等)。 - 用户会在命令旁边粘贴 URL、图片或长内容。
- 你可以接受额外的 DM 回合延迟(见下文)。
- 你需要单词 DM 触发器的最低命令延迟。
- 你的所有流程都是没有后续 payload 的一次性命令。
场景以及代理会看到什么
| 用户输入 | Apple 投递 | 关闭标志(默认) | 开启标志 + 2500 ms 窗口 |
|---|---|---|---|
Dump https://example.com(一次发送) | 2 个 webhook,相隔约 1 秒 | 两个代理回合:“Dump” 单独一条,然后是 URL | 一个回合:合并后的文本 Dump https://example.com |
Save this 📎image.jpg caption(附件 + 文本) | 2 个 webhook | 两个回合 | 一个回合:文本 + 图片 |
/status(独立命令) | 1 个 webhook | 立即分发 | 最多等待窗口,然后分发 |
| 单独粘贴 URL | 1 个 webhook | 立即分发 | 立即分发(桶中只有一项) |
| 文本 + URL 作为两个刻意分开的消息发送,间隔几分钟 | 2 个 webhook,超出窗口 | 两个回合 | 两个回合(窗口之间已过期) |
| 快速洪泛(窗口内超过 10 条小 DM) | N 个 webhook | N 个回合 | 一个回合,输出受限(应用最早 + 最新、文本/附件上限) |
拆分发送合并排查
如果标志已开启但拆分发送仍然作为两个回合到达,请检查各层:配置确实已加载
配置确实已加载
openclaw gateway restart —— 该标志是在 debouncer-registry 创建时读取的。去抖窗口对你的环境足够大
去抖窗口对你的环境足够大
查看 测量
~/Library/Logs/bluebubbles-server/main.log 下的 BlueBubbles 服务器日志:"Dump" 风格文本分发与随后 "https://..."; Attachments: 分发之间的间隔。将 messages.inbound.byChannel.bluebubbles 调大到足以覆盖该间隔。Session JSONL 时间戳 ≠ webhook 到达时间
Session JSONL 时间戳 ≠ webhook 到达时间
Session 事件时间戳(
~/.openclaw/agents/<id>/sessions/*.jsonl)反映的是网关把消息交给代理的时间,不是 webhook 到达的时间。若出现标记为 [Queued messages while agent was busy] 的排队第二条消息,说明第一轮仍在运行时第二个 webhook 就已到达——此时合并桶已经刷新。请根据 BB 服务器日志调整窗口,而不是会话日志。内存压力导致回复分发变慢
内存压力导致回复分发变慢
在较小的机器(8 GB)上,代理回合可能耗时足够长,以至于合并桶会在回复完成前刷新,而 URL 会作为排队的第二轮到达。检查
memory_pressure 和 ps -o rss -p $(pgrep openclaw-gateway);如果网关的 RSS 超过约 500 MB 且压缩器处于活动状态,请关闭其他高负载进程或升级到更大的主机。回复引用发送走的是不同路径
回复引用发送走的是不同路径
如果用户将
Dump 作为对现有 URL 气泡的回复而点击发送(iMessage 会在 Dump 气泡上显示 "1 Reply" 徽标),那么 URL 存在于 replyToBody 中,而不是第二个 webhook 里。合并不适用——这属于技能/提示词问题,而不是去抖器问题。块流式输出
控制回复是作为单条消息发送,还是按块流式输出:媒体 + 限制
- 入站附件会被下载并存储到媒体缓存中。
- 通过
channels.bluebubbles.mediaMaxMb限制入站和出站媒体大小(默认:8 MB)。 - 出站文本会按
channels.bluebubbles.textChunkLimit分块(默认:4000 个字符)。
配置参考
完整配置:Configuration连接和 webhook
连接和 webhook
channels.bluebubbles.enabled: 启用/禁用该通道。channels.bluebubbles.serverUrl: BlueBubbles REST API 基础 URL。channels.bluebubbles.password: API 密码。channels.bluebubbles.webhookPath: Webhook 端点路径(默认:/bluebubbles-webhook)。
访问策略
访问策略
channels.bluebubbles.dmPolicy:pairing | allowlist | open | disabled(默认:pairing)。channels.bluebubbles.allowFrom: DM 允许列表(handles、emails、E.164 numbers、chat_id:*、chat_guid:*)。channels.bluebubbles.groupPolicy:open | allowlist | disabled(默认:allowlist)。channels.bluebubbles.groupAllowFrom: 群组发送者允许列表。channels.bluebubbles.enrichGroupParticipantsFromContacts: 在 macOS 上,在通过门禁后可选地从本地通讯录中补充未命名的群组参与者。默认:false。channels.bluebubbles.groups: 按群组配置(requireMention等)。
发送与分块
发送与分块
channels.bluebubbles.sendReadReceipts: 发送已读回执(默认:true)。channels.bluebubbles.blockStreaming: 启用 block streaming(默认:false;流式回复所必需)。channels.bluebubbles.textChunkLimit: 出站分块大小(字符数,默认:4000)。channels.bluebubbles.sendTimeoutMs: 通过/api/v1/message/text发送出站文本时的单请求超时(毫秒,默认:30000)。在 macOS 26 环境中,如果使用 Private API 发送 iMessage 可能会在 iMessage 框架内卡住 60 秒以上,可将此值调高,例如45000或60000。当前探测、聊天查找、反应、编辑和健康检查仍保持较短的 10 秒默认值;后续计划将覆盖范围扩展到反应和编辑。按账户覆盖:channels.bluebubbles.accounts.<accountId>.sendTimeoutMs。channels.bluebubbles.chunkMode:length(默认)仅在超过textChunkLimit时分块;newline会先按空行(段落边界)分割,再进行长度分块。
媒体和历史
媒体和历史
channels.bluebubbles.mediaMaxMb: 入站/出站媒体上限(MB,默认:8)。channels.bluebubbles.mediaLocalRoots: 明确允许用于出站本地媒体路径的绝对本地目录白名单。未配置时,本地路径发送默认会被拒绝。按账户覆盖:channels.bluebubbles.accounts.<accountId>.mediaLocalRoots。channels.bluebubbles.coalesceSameSenderDms: 将来自同一发送者的连续 DM webhook 合并为一次代理回合,以便 Apple 的文本 + URL 拆分发送作为一条消息到达(默认:false)。有关场景、窗口调优和权衡,请参见 合并拆分发送的 DM。启用后,如果没有显式设置messages.inbound.byChannel.bluebubbles,会将默认入站去抖窗口从 500 ms 扩大到 2500 ms。channels.bluebubbles.historyLimit: 用于上下文的最大群消息数(0 表示禁用)。channels.bluebubbles.dmHistoryLimit: DM 历史限制。channels.bluebubbles.replyContextApiFallback: 当入站回复到达时缺少replyToBody/replyToSender,且内存中的回复上下文缓存未命中时,作为尽力而为的后备方案,从 BlueBubbles HTTP API 拉取原始消息(默认:false)。适用于共享同一 BlueBubbles 账户的多实例部署、进程重启后,或长 TTL/LRU 缓存驱逐后。该拉取受与其他 BlueBubbles 客户端请求相同的 SSRF 防护策略保护,绝不会抛出异常,并会写入缓存以便后续回复复用。按账户覆盖:channels.bluebubbles.accounts.<accountId>.replyContextApiFallback。通道级设置会传播到未显式提供该标志的账户。
操作和账户
操作和账户
channels.bluebubbles.actions: 启用/禁用特定操作。channels.bluebubbles.accounts: 多账户配置。
agents.list[].groupChat.mentionPatterns(或messages.groupChat.mentionPatterns)。messages.responsePrefix。
寻址 / 送达目标
优先使用chat_guid 进行稳定路由:
chat_guid:iMessage;-;+15555550123(群组首选)chat_id:123chat_identifier:...- 直接 handles:
+15555550123、user@example.com- 如果直接 handle 没有现有的 DM 聊天,OpenClaw 会通过
POST /api/v1/chat/new创建一个。这需要启用 BlueBubbles Private API。
- 如果直接 handle 没有现有的 DM 聊天,OpenClaw 会通过
iMessage 与 SMS 路由
当同一个 handle 在 Mac 上同时拥有 iMessage 和 SMS 聊天记录时(例如某个电话号码既已注册 iMessage,但也收到了绿色气泡回退消息),OpenClaw 会优先选择 iMessage 聊天,并且绝不会悄悄降级到 SMS。若要强制使用 SMS 聊天,请使用显式的sms: 目标前缀(例如 sms:+15555550123)。没有匹配 iMessage 聊天的 handle 仍会通过 BlueBubbles 报告的任意聊天发送。
安全
- Webhook 请求通过将
guid/password查询参数或请求头与channels.bluebubbles.password比对来认证。 - 保持 API 密码和 webhook 端点的机密性(将它们视为凭据)。
- BlueBubbles webhook 认证没有 localhost 绕过。如果你代理 webhook 流量,请确保在请求端到端保留 BlueBubbles 密码。这里的
gateway.trustedProxies不能替代channels.bluebubbles.password。参见 Gateway security。 - 如果将 BlueBubbles 服务器暴露到 LAN 之外,请启用 HTTPS + 防火墙规则。
故障排查
- 如果输入/已读事件停止工作,请检查 BlueBubbles webhook 日志并验证网关路径是否与
channels.bluebubbles.webhookPath匹配。 - 配对码一小时后过期;使用
openclaw pairing list bluebubbles和openclaw pairing approve bluebubbles <code>。 - 反应需要 BlueBubbles private API(
POST /api/v1/message/react);请确保服务器版本已暴露该接口。 - 编辑/撤回需要 macOS 13+ 以及兼容的 BlueBubbles 服务器版本。在 macOS 26(Tahoe)上,由于私有 API 变更,编辑功能当前不可用。
- 群组图标更新在 macOS 26(Tahoe)上可能不稳定:API 可能返回成功,但新图标不会同步。
- OpenClaw 会根据 BlueBubbles 服务器的 macOS 版本自动隐藏已知失效的操作。如果在 macOS 26(Tahoe)上编辑仍然显示,请使用
channels.bluebubbles.actions.edit=false手动禁用。 - 已启用
coalesceSameSenderDms但拆分发送(例如Dump+ URL)仍然作为两个回合到达:请参见 拆分发送合并故障排查 清单——常见原因是去抖窗口过紧、会话日志时间戳被误读为 webhook 到达时间,或者是回复引用发送(它使用replyToBody,而不是第二个 webhook)。 - 状态/健康信息:
openclaw status --all或openclaw status --deep。
相关内容
- Channel Routing — 消息的会话路由
- Channels Overview — 所有支持的通道
- Groups — 群聊行为和 mention 门禁
- Pairing — DM 认证和配对流程
- Security — 访问模型和加固