chore(i18n): refresh zh-CN translations
This commit is contained in:
parent
a6c895d61d
commit
75d9afa73f
@ -1,42 +1,42 @@
|
||||
---
|
||||
read_when:
|
||||
- 设置 BlueBubbles 渠道
|
||||
- 故障排除 webhook 配对
|
||||
- Webhook 配对故障排除
|
||||
- 在 macOS 上配置 iMessage
|
||||
summary: 通过 BlueBubbles macOS 服务器接入 iMessage(REST 发送/接收、正在输入、表情回应、配对、高级操作)。
|
||||
title: BlueBubbles
|
||||
x-i18n:
|
||||
generated_at: "2026-04-21T08:44:48Z"
|
||||
generated_at: "2026-04-21T20:11:29Z"
|
||||
model: gpt-5.4
|
||||
provider: openai
|
||||
source_hash: 30ce50ae8a17140b42fa410647c367e0eefdffb1646b1ff92d8e1af63f2e1155
|
||||
source_hash: db2e193db3fbcea22748187c21d0493037f59d4f1af163725530d5572b06e8b4
|
||||
source_path: channels/bluebubbles.md
|
||||
workflow: 15
|
||||
---
|
||||
|
||||
# BlueBubbles(macOS REST)
|
||||
|
||||
状态:这是一个通过 HTTP 与 BlueBubbles macOS 服务器通信的内置插件。由于相比旧版 `imsg` 渠道拥有更丰富的 API 和更简单的设置方式,**推荐用于 iMessage 集成**。
|
||||
状态:一个通过 HTTP 与 BlueBubbles macOS 服务器通信的内置插件。由于其 API 更丰富、设置也比旧版 `imsg` 渠道更简单,**推荐用于 iMessage 集成**。
|
||||
|
||||
## 内置插件
|
||||
|
||||
当前的 OpenClaw 发布版本已内置 BlueBubbles,因此普通的打包构建**不需要**单独执行 `openclaw plugins install` 步骤。
|
||||
当前的 OpenClaw 版本内置了 BlueBubbles,因此常规打包构建**不需要**单独执行 `openclaw plugins install` 步骤。
|
||||
|
||||
## 概览
|
||||
|
||||
- 通过 BlueBubbles 辅助应用在 macOS 上运行([bluebubbles.app](https://bluebubbles.app))。
|
||||
- 推荐/已测试:macOS Sequoia(15)。macOS Tahoe(26)可用;目前在 Tahoe 上编辑功能失效,群组图标更新也可能显示成功但不会同步。
|
||||
- OpenClaw 通过其 REST API 与之通信(`GET /api/v1/ping`、`POST /message/text`、`POST /chat/:id/*`)。
|
||||
- 推荐/已测试:macOS Sequoia(15)。macOS Tahoe(26)可用;但当前在 Tahoe 上编辑功能不可用,群组图标更新也可能显示成功但不会同步。
|
||||
- OpenClaw 通过它的 REST API 与其通信(`GET /api/v1/ping`、`POST /message/text`、`POST /chat/:id/*`)。
|
||||
- 传入消息通过 webhook 到达;传出回复、正在输入指示、已读回执和 tapback 都通过 REST 调用完成。
|
||||
- 附件和贴纸会作为入站媒体接收(并在可能时展示给智能体)。
|
||||
- 附件和贴纸会作为入站媒体摄取(并在可能时暴露给智能体)。
|
||||
- 配对/允许列表的工作方式与其他渠道相同(`/channels/pairing` 等),使用 `channels.bluebubbles.allowFrom` + 配对码。
|
||||
- 表情回应会像 Slack/Telegram 一样作为系统事件呈现,因此智能体可以在回复前“提到”它们。
|
||||
- 表情回应会像 Slack/Telegram 一样作为系统事件暴露,因此智能体可以在回复前“提及”它们。
|
||||
- 高级功能:编辑、撤回、回复线程、消息效果、群组管理。
|
||||
|
||||
## 快速开始
|
||||
|
||||
1. 在你的 Mac 上安装 BlueBubbles 服务器(按照 [bluebubbles.app/install](https://bluebubbles.app/install) 上的说明操作)。
|
||||
2. 在 BlueBubbles 配置中,启用 Web API 并设置密码。
|
||||
2. 在 BlueBubbles 配置中,启用 web API 并设置密码。
|
||||
3. 运行 `openclaw onboard` 并选择 BlueBubbles,或手动配置:
|
||||
|
||||
```json5
|
||||
@ -57,17 +57,17 @@ x-i18n:
|
||||
|
||||
安全说明:
|
||||
|
||||
- 始终设置一个 webhook 密码。
|
||||
- webhook 身份验证始终是必需的。无论 local loopback/代理拓扑如何,OpenClaw 都会拒绝 BlueBubbles webhook 请求,除非它们包含与 `channels.bluebubbles.password` 匹配的密码/guid(例如 `?password=<password>` 或 `x-password`)。
|
||||
- 密码验证会在读取/解析完整 webhook 请求体之前进行。
|
||||
- 始终设置 webhook 密码。
|
||||
- 始终要求进行 webhook 身份验证。无论 loopback/代理拓扑如何,除非 BlueBubbles webhook 请求包含与 `channels.bluebubbles.password` 匹配的 password/guid(例如 `?password=<password>` 或 `x-password`),否则 OpenClaw 会拒绝该请求。
|
||||
- 在读取/解析完整 webhook 请求体之前,会先检查密码认证。
|
||||
|
||||
## 保持 Messages.app 处于活跃状态(VM / 无头设置)
|
||||
## 保持 Messages.app 处于活动状态(VM / 无头设置)
|
||||
|
||||
某些 macOS VM / 常开设置中,Messages.app 可能会进入“空闲”状态(传入事件会停止,直到应用被打开/切到前台)。一个简单的解决方法是使用 AppleScript + LaunchAgent **每 5 分钟轻触一次 Messages**。
|
||||
某些 macOS VM / 常开环境可能会出现 Messages.app 进入“空闲”状态的情况(传入事件会停止,直到应用被打开/切到前台)。一个简单的变通办法是使用 AppleScript + LaunchAgent **每 5 分钟轻触一次 Messages**。
|
||||
|
||||
### 1)保存 AppleScript
|
||||
|
||||
将以下内容保存为:
|
||||
将其保存为:
|
||||
|
||||
- `~/Scripts/poke-messages.scpt`
|
||||
|
||||
@ -90,7 +90,7 @@ end try
|
||||
|
||||
### 2)安装 LaunchAgent
|
||||
|
||||
将以下内容保存为:
|
||||
将其保存为:
|
||||
|
||||
- `~/Library/LaunchAgents/com.user.poke-messages.plist`
|
||||
|
||||
@ -125,8 +125,8 @@ end try
|
||||
|
||||
说明:
|
||||
|
||||
- 这会**每 300 秒**运行一次,并且**在登录时**运行。
|
||||
- 首次运行时,可能会触发 macOS 的**自动化**提示(`osascript` → Messages)。请在运行该 LaunchAgent 的同一用户会话中批准它们。
|
||||
- 该任务会**每 300 秒**运行一次,并且会**在登录时**运行。
|
||||
- 首次运行时可能会触发 macOS 的**自动化**提示(`osascript` → Messages)。请在运行该 LaunchAgent 的同一用户会话中批准这些提示。
|
||||
|
||||
加载它:
|
||||
|
||||
@ -143,13 +143,13 @@ BlueBubbles 可在交互式新手引导中使用:
|
||||
openclaw onboard
|
||||
```
|
||||
|
||||
向导会提示输入:
|
||||
向导会提示你输入:
|
||||
|
||||
- **Server URL**(必填):BlueBubbles 服务器地址(例如 `http://192.168.1.100:1234`)
|
||||
- **Password**(必填):BlueBubbles Server 设置中的 API 密码
|
||||
- **Password**(必填):来自 BlueBubbles Server 设置的 API 密码
|
||||
- **Webhook path**(可选):默认为 `/bluebubbles-webhook`
|
||||
- **私信 policy**:pairing、allowlist、open 或 disabled
|
||||
- **Allow list**:电话号码、电子邮件地址或聊天目标
|
||||
- **DM policy**:pairing、allowlist、open 或 disabled
|
||||
- **Allow list**:电话号码、电子邮件或聊天目标
|
||||
|
||||
你也可以通过 CLI 添加 BlueBubbles:
|
||||
|
||||
@ -161,26 +161,26 @@ openclaw channels add bluebubbles --http-url http://192.168.1.100:1234 --passwor
|
||||
|
||||
私信:
|
||||
|
||||
- 默认:`channels.bluebubbles.dmPolicy = "pairing"`。
|
||||
- 未知发件人会收到一个配对码;在获得批准前,消息会被忽略(配对码 1 小时后过期)。
|
||||
- 批准方式:
|
||||
- 默认值:`channels.bluebubbles.dmPolicy = "pairing"`。
|
||||
- 未知发送者会收到一个配对码;在获得批准之前,消息会被忽略(配对码 1 小时后过期)。
|
||||
- 通过以下方式批准:
|
||||
- `openclaw pairing list bluebubbles`
|
||||
- `openclaw pairing approve bluebubbles <CODE>`
|
||||
- 配对是默认的令牌交换方式。详情见:[Pairing](/zh-CN/channels/pairing)
|
||||
- 配对是默认的令牌交换方式。详情参见:[Pairing](/zh-CN/channels/pairing)
|
||||
|
||||
群组:
|
||||
|
||||
- `channels.bluebubbles.groupPolicy = open | allowlist | disabled`(默认:`allowlist`)。
|
||||
- 当设置为 `allowlist` 时,`channels.bluebubbles.groupAllowFrom` 用于控制群组中谁可以触发。
|
||||
- 当设置为 `allowlist` 时,`channels.bluebubbles.groupAllowFrom` 控制谁可以在群组中触发。
|
||||
|
||||
### 联系人姓名增强(macOS,可选)
|
||||
|
||||
BlueBubbles 的群组 webhook 通常只包含原始参与者地址。如果你希望 `GroupMembers` 上下文显示本地联系人姓名而不是这些地址,可以选择在 macOS 上启用本地通讯录增强:
|
||||
BlueBubbles 的群组 webhook 通常只包含原始参与者地址。如果你希望 `GroupMembers` 上下文改为显示本地联系人姓名,可以选择在 macOS 上启用本地通讯录增强:
|
||||
|
||||
- `channels.bluebubbles.enrichGroupParticipantsFromContacts = true` 启用查找。默认值:`false`。
|
||||
- 只有在群组访问、命令授权和提及门控都已允许消息通过后,才会执行查找。
|
||||
- 仅增强未命名的电话参与者。
|
||||
- 如果找不到本地匹配项,仍会回退为原始电话号码。
|
||||
- `channels.bluebubbles.enrichGroupParticipantsFromContacts = true` 启用该查找。默认值:`false`。
|
||||
- 只有在群组访问、命令授权和提及门控都允许该消息通过之后,才会执行查找。
|
||||
- 只有未命名的电话参与者会被增强。
|
||||
- 如果未找到本地匹配项,则原始电话号码仍会作为回退值保留。
|
||||
|
||||
```json5
|
||||
{
|
||||
@ -194,10 +194,10 @@ BlueBubbles 的群组 webhook 通常只包含原始参与者地址。如果你
|
||||
|
||||
### 提及门控(群组)
|
||||
|
||||
BlueBubbles 支持群聊提及门控,与 iMessage/WhatsApp 行为一致:
|
||||
BlueBubbles 支持群聊的提及门控,与 iMessage/WhatsApp 的行为一致:
|
||||
|
||||
- 使用 `agents.list[].groupChat.mentionPatterns`(或 `messages.groupChat.mentionPatterns`)来检测提及。
|
||||
- 当某个群组启用了 `requireMention` 时,智能体仅在被提及时才会响应。
|
||||
- 使用 `agents.list[].groupChat.mentionPatterns`(或 `messages.groupChat.mentionPatterns`)检测提及。
|
||||
- 当为某个群组启用 `requireMention` 时,智能体只有在被提及时才会响应。
|
||||
- 来自已授权发送者的控制命令会绕过提及门控。
|
||||
|
||||
按群组配置:
|
||||
@ -210,7 +210,7 @@ BlueBubbles 支持群聊提及门控,与 iMessage/WhatsApp 行为一致:
|
||||
groupAllowFrom: ["+15555550123"],
|
||||
groups: {
|
||||
"*": { requireMention: true }, // 所有群组的默认值
|
||||
"iMessage;-;chat123": { requireMention: false }, // 对特定群组的覆盖
|
||||
"iMessage;-;chat123": { requireMention: false }, // 特定群组的覆盖值
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -225,7 +225,7 @@ BlueBubbles 支持群聊提及门控,与 iMessage/WhatsApp 行为一致:
|
||||
|
||||
### 按群组设置 system prompt
|
||||
|
||||
`channels.bluebubbles.groups.*` 下的每个条目都接受一个可选的 `systemPrompt` 字符串。对于该群组中的每一轮消息处理,这个值都会注入到智能体的 system prompt 中,因此你可以为不同群组设置不同的人设或行为规则,而无需编辑智能体提示词:
|
||||
`channels.bluebubbles.groups.*` 下的每个条目都接受一个可选的 `systemPrompt` 字符串。每当处理该群组中的消息时,该值都会注入到智能体的 system prompt 中,因此你可以为每个群组设置特定人格或行为规则,而无需编辑智能体提示词:
|
||||
|
||||
```json5
|
||||
{
|
||||
@ -233,7 +233,7 @@ BlueBubbles 支持群聊提及门控,与 iMessage/WhatsApp 行为一致:
|
||||
bluebubbles: {
|
||||
groups: {
|
||||
"iMessage;-;chat123": {
|
||||
systemPrompt: "将回复控制在 3 句话以内。模仿这个群组的随意语气。",
|
||||
systemPrompt: "将回复控制在 3 句话以内。模仿群组的随意语气。",
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -241,11 +241,11 @@ BlueBubbles 支持群聊提及门控,与 iMessage/WhatsApp 行为一致:
|
||||
}
|
||||
```
|
||||
|
||||
该键会匹配 BlueBubbles 上报的群组 `chatGuid` / `chatIdentifier` / 数字 `chatId`,而 `"*"` 通配符条目会为每个没有精确匹配的群组提供默认值(与 `requireMention` 和按群组工具策略使用相同的模式)。精确匹配始终优先于通配符。私信会忽略此字段;请改用智能体级别或账户级别的提示词自定义。
|
||||
该键与 BlueBubbles 为该群组报告的 `chatGuid` / `chatIdentifier` / 数字 `chatId` 相匹配,而 `"*"` 通配符条目则为每个没有精确匹配的群组提供默认值(与 `requireMention` 和按群组工具策略使用的模式相同)。精确匹配始终优先于通配符。私信会忽略此字段;请改用智能体级或账户级提示词自定义。
|
||||
|
||||
#### 示例:线程回复与 tapback 表情回应(Private API)
|
||||
#### 示例:线程回复和 tapback 表情回应(Private API)
|
||||
|
||||
启用 BlueBubbles Private API 后,入站消息会带有短消息 ID(例如 `[[reply_to:5]]`),智能体可以调用 `action=reply` 将回复串到特定消息下,或者调用 `action=react` 添加一个 tapback。按群组设置 `systemPrompt` 是让智能体始终选择正确工具的可靠方式:
|
||||
启用 BlueBubbles Private API 后,传入消息会带有简短消息 ID(例如 `[[reply_to:5]]`),智能体可以调用 `action=reply` 将回复串接到特定消息,或调用 `action=react` 添加 tapback。按群组设置 `systemPrompt` 是让智能体稳定选择正确工具的可靠方法:
|
||||
|
||||
```json5
|
||||
{
|
||||
@ -254,13 +254,12 @@ BlueBubbles 支持群聊提及门控,与 iMessage/WhatsApp 行为一致:
|
||||
groups: {
|
||||
"iMessage;+;chat-family": {
|
||||
systemPrompt: [
|
||||
"在这个群组中回复时,始终使用上下文中的",
|
||||
"[[reply_to:N]] messageId 调用 action=reply,",
|
||||
"这样你的回复会串在线程中并位于触发消息下方。",
|
||||
"绝不要发送一条新的未关联消息。",
|
||||
"在此群组中回复时,始终使用上下文中的",
|
||||
"[[reply_to:N]] messageId 调用 action=reply,这样你的回复会串接到",
|
||||
"触发消息下方。绝不要发送新的未关联消息。",
|
||||
"",
|
||||
"对于简短确认(“好的”“收到”“在处理了”),请使用",
|
||||
"action=react 并配合合适的 tapback emoji(❤️、👍、😂、‼️、❓),",
|
||||
"对于简短确认('ok'、'got it'、'on it'),请使用",
|
||||
"action=react 并选择合适的 tapback 表情(❤️、👍、😂、‼️、❓),",
|
||||
"而不是发送文本回复。",
|
||||
].join(" "),
|
||||
},
|
||||
@ -270,24 +269,24 @@ BlueBubbles 支持群聊提及门控,与 iMessage/WhatsApp 行为一致:
|
||||
}
|
||||
```
|
||||
|
||||
tapback 表情回应和线程回复都需要 BlueBubbles Private API;底层机制请参见 [Advanced actions](#advanced-actions) 和 [Message IDs](#message-ids-short-vs-full)。
|
||||
tapback 表情回应和线程回复都需要 BlueBubbles Private API;相关底层机制参见 [Advanced actions](#advanced-actions) 和 [Message IDs](#message-ids-short-vs-full)。
|
||||
|
||||
## ACP 会话绑定
|
||||
|
||||
BlueBubbles 聊天可以转为持久化的 ACP 工作区,而无需更改传输层。
|
||||
BlueBubbles 聊天可以在不改变传输层的情况下转变为持久 ACP 工作区。
|
||||
|
||||
快速操作流程:
|
||||
|
||||
- 在私信或允许的群聊中运行 `/acp spawn codex --bind here`。
|
||||
- 同一个 BlueBubbles 会话中的后续消息会路由到所创建的 ACP 会话。
|
||||
- `/new` 和 `/reset` 会就地重置同一个已绑定的 ACP 会话。
|
||||
- 在同一个 BlueBubbles 会话中,后续消息会路由到生成的 ACP 会话。
|
||||
- `/new` 和 `/reset` 会在原地重置同一个已绑定 ACP 会话。
|
||||
- `/acp close` 会关闭 ACP 会话并移除绑定。
|
||||
|
||||
也支持通过顶层 `bindings[]` 条目配置持久绑定,使用 `type: "acp"` 和 `match.channel: "bluebubbles"`。
|
||||
|
||||
`match.peer.id` 可以使用任何受支持的 BlueBubbles 目标形式:
|
||||
`match.peer.id` 可以使用任意受支持的 BlueBubbles 目标形式:
|
||||
|
||||
- 标准化的私信句柄,例如 `+15555550123` 或 `user@example.com`
|
||||
- 标准化私信句柄,例如 `+15555550123` 或 `user@example.com`
|
||||
- `chat_id:<id>`
|
||||
- `chat_guid:<guid>`
|
||||
- `chat_identifier:<identifier>`
|
||||
@ -324,13 +323,13 @@ BlueBubbles 聊天可以转为持久化的 ACP 工作区,而无需更改传输
|
||||
}
|
||||
```
|
||||
|
||||
共享的 ACP 绑定行为请参见 [ACP Agents](/zh-CN/tools/acp-agents)。
|
||||
共享的 ACP 绑定行为参见 [ACP Agents](/zh-CN/tools/acp-agents)。
|
||||
|
||||
## 正在输入 + 已读回执
|
||||
|
||||
- **正在输入指示**:会在生成回复之前和生成过程中自动发送。
|
||||
- **正在输入指示**:会在生成回复之前和期间自动发送。
|
||||
- **已读回执**:由 `channels.bluebubbles.sendReadReceipts` 控制(默认:`true`)。
|
||||
- **正在输入指示**:OpenClaw 会发送开始输入事件;BlueBubbles 会在发送消息后或超时后自动清除输入状态(通过 DELETE 手动停止并不可靠)。
|
||||
- **正在输入指示**:OpenClaw 会发送开始输入事件;BlueBubbles 会在发送后或超时后自动清除输入状态(通过 DELETE 手动停止并不可靠)。
|
||||
|
||||
```json5
|
||||
{
|
||||
@ -351,8 +350,8 @@ BlueBubbles 聊天可以转为持久化的 ACP 工作区,而无需更改传输
|
||||
channels: {
|
||||
bluebubbles: {
|
||||
actions: {
|
||||
reactions: true, // tapback(默认:true)
|
||||
edit: true, // 编辑已发送消息(macOS 13+,在 macOS 26 Tahoe 上失效)
|
||||
reactions: true, // tapback 表情回应(默认:true)
|
||||
edit: true, // 编辑已发送消息(macOS 13+,在 macOS 26 Tahoe 上不可用)
|
||||
unsend: true, // 撤回消息(macOS 13+)
|
||||
reply: true, // 按消息 GUID 进行线程回复
|
||||
sendWithEffect: true, // 消息效果(slam、loud 等)
|
||||
@ -370,10 +369,10 @@ BlueBubbles 聊天可以转为持久化的 ACP 工作区,而无需更改传输
|
||||
|
||||
可用操作:
|
||||
|
||||
- **react**:添加/移除 tapback 表情回应(`messageId`、`emoji`、`remove`)
|
||||
- **react**:添加/移除 tapback 表情回应(`messageId`、`emoji`、`remove`)。iMessage 原生的 tapback 集合是 `love`、`like`、`dislike`、`laugh`、`emphasize` 和 `question`。当智能体选择了该集合之外的 emoji(例如 `👀`)时,reaction 工具会回退为 `love`,这样 tapback 仍然会渲染,而不会导致整个请求失败。已配置的确认表情回应仍会严格校验,遇到未知值时会报错。
|
||||
- **edit**:编辑已发送消息(`messageId`、`text`)
|
||||
- **unsend**:撤回消息(`messageId`)
|
||||
- **reply**:回复指定消息(`messageId`、`text`、`to`)
|
||||
- **reply**:回复特定消息(`messageId`、`text`、`to`)
|
||||
- **sendWithEffect**:使用 iMessage 效果发送(`text`、`to`、`effectId`)
|
||||
- **renameGroup**:重命名群聊(`chatGuid`、`displayName`)
|
||||
- **setGroupIcon**:设置群聊图标/照片(`chatGuid`、`media`)—— 在 macOS 26 Tahoe 上不稳定(API 可能返回成功,但图标不会同步)。
|
||||
@ -381,48 +380,48 @@ BlueBubbles 聊天可以转为持久化的 ACP 工作区,而无需更改传输
|
||||
- **removeParticipant**:从群组移除成员(`chatGuid`、`address`)
|
||||
- **leaveGroup**:退出群聊(`chatGuid`)
|
||||
- **upload-file**:发送媒体/文件(`to`、`buffer`、`filename`、`asVoice`)
|
||||
- 语音备忘录:将 **MP3** 或 **CAF** 音频与 `asVoice: true` 一起使用,即可作为 iMessage 语音消息发送。BlueBubbles 在发送语音备忘录时会将 MP3 转换为 CAF。
|
||||
- 旧别名:`sendAttachment` 仍然可用,但 `upload-file` 是规范操作名。
|
||||
- 语音备忘录:将 **MP3** 或 **CAF** 音频与 `asVoice: true` 一起设置,即可作为 iMessage 语音消息发送。BlueBubbles 在发送语音备忘录时会将 MP3 转换为 CAF。
|
||||
- 旧别名:`sendAttachment` 仍然可用,但 `upload-file` 才是规范操作名称。
|
||||
|
||||
### 消息 ID(短 ID 与完整 ID)
|
||||
|
||||
OpenClaw 可能会显示_短_消息 ID(例如 `1`、`2`)以节省 token。
|
||||
OpenClaw 可能会暴露_短_消息 ID(例如 `1`、`2`)以节省 token。
|
||||
|
||||
- `MessageSid` / `ReplyToId` 可以是短 ID。
|
||||
- `MessageSidFull` / `ReplyToIdFull` 包含提供商的完整 ID。
|
||||
- 短 ID 存储在内存中;在重启或缓存清除后可能失效。
|
||||
- 操作可以接受短或完整的 `messageId`,但如果短 ID 已不可用,将会报错。
|
||||
- 短 ID 保存在内存中;重启或缓存清除后可能失效。
|
||||
- 操作接受短 ID 或完整 `messageId`,但如果短 ID 已不可用,就会报错。
|
||||
|
||||
对于持久化自动化和存储,请使用完整 ID:
|
||||
对于持久自动化和存储,请使用完整 ID:
|
||||
|
||||
- 模板:`{{MessageSidFull}}`、`{{ReplyToIdFull}}`
|
||||
- 上下文:入站负载中的 `MessageSidFull` / `ReplyToIdFull`
|
||||
- 上下文:入站载荷中的 `MessageSidFull` / `ReplyToIdFull`
|
||||
|
||||
模板变量请参见 [Configuration](/zh-CN/gateway/configuration)。
|
||||
模板变量参见 [Configuration](/zh-CN/gateway/configuration)。
|
||||
|
||||
## 合并拆分发送的私信(一次输入中的命令 + URL)
|
||||
## 合并拆分发送的私信(一次编辑中同时包含命令 + URL)
|
||||
|
||||
当用户在 iMessage 中将命令和 URL 一起输入时——例如 `Dump https://example.com/article`——Apple 会将这次发送拆成**两次独立的 webhook 投递**:
|
||||
当用户在 iMessage 中同时输入命令和 URL 时——例如 `Dump https://example.com/article`——Apple 会把这次发送拆成**两个独立的 webhook 投递**:
|
||||
|
||||
1. 一条文本消息(`"Dump"`)。
|
||||
2. 一个 URL 预览气泡(`"https://..."`),并附带 OG 预览图片作为附件。
|
||||
2. 一个 URL 预览气泡(`"https://..."`),并带有 OG 预览图片作为附件。
|
||||
|
||||
在大多数设置中,这两个 webhook 会相隔约 0.8–2.0 秒到达 OpenClaw。如果不进行合并,智能体在第 1 轮只会收到命令本身并回复(通常是“把 URL 发给我”),直到第 2 轮才看到 URL——而此时命令上下文已经丢失。
|
||||
在大多数环境中,这两个 webhook 会相隔约 0.8 - 2.0 秒到达 OpenClaw。如果不进行合并,智能体会在第 1 轮只收到命令本身,然后回复(通常是“把 URL 发给我”),等到第 2 轮才看到 URL——此时命令上下文已经丢失。
|
||||
|
||||
`channels.bluebubbles.coalesceSameSenderDms` 会让私信启用同一发送者连续 webhook 的合并,从而在一轮智能体处理内统一处理。群聊仍然按单条消息分组,以保留多用户会话结构。
|
||||
`channels.bluebubbles.coalesceSameSenderDms` 可让私信选择启用:将同一发送者连续发来的 webhook 合并为一次智能体轮次。群聊则继续按单条消息作为键,以保留多用户轮次结构。
|
||||
|
||||
### 何时启用
|
||||
|
||||
在以下情况下启用:
|
||||
|
||||
- 你提供的 Skills 期望在一条消息中收到 `命令 + 负载`(dump、paste、save、queue 等)。
|
||||
- 你提供的 Skills 期望在一条消息中接收 `命令 + 负载`(dump、paste、save、queue 等)。
|
||||
- 你的用户会把 URL、图片或长内容与命令一起粘贴发送。
|
||||
- 你可以接受私信轮次的额外延迟(见下文)。
|
||||
- 你可以接受额外增加的私信轮次延迟(见下文)。
|
||||
|
||||
在以下情况下保持禁用:
|
||||
在以下情况下保持关闭:
|
||||
|
||||
- 你需要最小化单词私信命令触发的延迟。
|
||||
- 你的所有流程都是无需后续负载的一次性命令。
|
||||
- 你需要单词私信触发命令的最低延迟。
|
||||
- 你的所有流程都是不带后续负载的一次性命令。
|
||||
|
||||
### 启用方式
|
||||
|
||||
@ -436,17 +435,17 @@ OpenClaw 可能会显示_短_消息 ID(例如 `1`、`2`)以节省 token。
|
||||
}
|
||||
```
|
||||
|
||||
启用此标志后,如果没有显式设置 `messages.inbound.byChannel.bluebubbles`,防抖窗口会扩大到 **2500 ms**(不进行合并时默认是 500 ms)。之所以需要更宽的窗口,是因为 Apple 的拆分发送节奏为 0.8–2.0 秒,无法适配更紧的默认值。
|
||||
当此标志开启,且未显式设置 `messages.inbound.byChannel.bluebubbles` 时,去抖窗口会扩大到 **2500 ms**(未启用合并时默认是 500 ms)。必须使用更宽的窗口——Apple 0.8 - 2.0 秒的拆分发送节奏无法落入更紧的默认窗口中。
|
||||
|
||||
若要自行调整窗口:
|
||||
如果你要自行调整窗口:
|
||||
|
||||
```json5
|
||||
{
|
||||
messages: {
|
||||
inbound: {
|
||||
byChannel: {
|
||||
// 2500 ms 对大多数设置都适用;如果你的 Mac 较慢
|
||||
// 或存在内存压力(观察到的间隔可能会超过 2 秒),可提高到 4000 ms。
|
||||
// 2500 ms 适用于大多数环境;如果你的 Mac 较慢
|
||||
// 或存在内存压力(观察到的间隔可能超过 2 秒),可提高到 4000 ms。
|
||||
bluebubbles: 2500,
|
||||
},
|
||||
},
|
||||
@ -456,70 +455,60 @@ OpenClaw 可能会显示_短_消息 ID(例如 `1`、`2`)以节省 token。
|
||||
|
||||
### 权衡
|
||||
|
||||
- **私信控制命令会增加延迟。** 启用此标志后,私信控制命令消息(如 `Dump`、`Save` 等)现在会在分发前最多等待一个防抖窗口,以防后续还有负载 webhook 到来。群聊命令仍然是即时分发。
|
||||
- **合并输出有边界限制**——合并后的文本上限为 4000 个字符,并会明确添加 `…[truncated]` 标记;附件上限为 20 个;来源条目上限为 10 个(超过后保留第一条和最新条目)。每个来源 `messageId` 仍会进入入站去重逻辑,因此稍后如果 MessagePoller 重放其中任意单个事件,也会被识别为重复。
|
||||
- **按渠道选择启用。** 其他渠道(Telegram、WhatsApp、Slack、…)不受影响。
|
||||
- **私信控制命令会增加延迟。** 启用该标志后,私信控制命令消息(如 `Dump`、`Save` 等)现在会在分发前最多等待整个去抖窗口,以防后续还有负载 webhook 到来。群聊命令仍然会立即分发。
|
||||
- **合并输出有上限**——合并文本最多 4000 个字符,超出时会带有显式的 `…[truncated]` 标记;附件上限为 20;来源条目上限为 10(超过后保留“第一条 + 最新条目”)。每个来源 `messageId` 仍然会进入入站去重,因此如果之后 MessagePoller 重放其中任意单个事件,系统仍会识别它是重复事件。
|
||||
- **按渠道选择启用。** 其他渠道(Telegram、WhatsApp、Slack、……)不受影响。
|
||||
|
||||
### 场景与智能体实际看到的内容
|
||||
|
||||
| 用户输入内容 | 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 条小私信) | N 个 webhook | N 轮处理 | 一轮处理,输出有边界限制(保留首条 + 最新条,应用文本/附件上限) |
|
||||
| ------------------------------------------------------------------ | ------------------------- | --------------------------------------- | ----------------------------------------------------------------------- |
|
||||
| `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 | 立即分发 | 立即分发(bucket 中只有一个条目) |
|
||||
| 文本 + URL 分几分钟作为两条独立消息刻意发送 | 窗口之外的 2 个 webhook | 两轮 | 两轮(窗口在两者之间到期) |
|
||||
| 快速洪泛(窗口内 >10 条小型私信) | N 个 webhook | N 轮 | 一轮,带有上限输出(应用“第一条 + 最新条目”、文本/附件上限) |
|
||||
|
||||
### 拆分发送合并的故障排除
|
||||
|
||||
如果该标志已开启,但拆分发送仍然表现为两轮处理,请逐层检查:
|
||||
如果标志已开启,但拆分发送仍然作为两轮到达,请逐层检查:
|
||||
|
||||
1. **确认配置已实际加载。**
|
||||
1. **配置是否实际已加载。**
|
||||
|
||||
```
|
||||
grep coalesceSameSenderDms ~/.openclaw/openclaw.json
|
||||
```
|
||||
|
||||
然后执行 `openclaw gateway restart`——该标志会在防抖器注册表创建时读取。
|
||||
然后执行 `openclaw gateway restart`——该标志会在 debouncer 注册表创建时读取。
|
||||
|
||||
2. **确认你的设置有足够宽的防抖窗口。** 查看位于 `~/Library/Logs/bluebubbles-server/main.log` 的 BlueBubbles 服务器日志:
|
||||
2. **你的环境的去抖窗口是否足够宽。** 查看 BlueBubbles 服务器日志 `~/Library/Logs/bluebubbles-server/main.log`:
|
||||
|
||||
```
|
||||
grep -E "Dispatching event to webhook" main.log | tail -20
|
||||
```
|
||||
|
||||
测量 `"Dump"` 这类文本分发与后续 `"https://..."; Attachments:` 分发之间的时间间隔。将 `messages.inbound.byChannel.bluebubbles` 提高到足以覆盖这个间隔。
|
||||
测量 `"Dump"` 这类文本分发与后续 `"https://..."`; Attachments:` 分发之间的间隔。将 `messages.inbound.byChannel.bluebubbles` 提高到足以覆盖该间隔。
|
||||
|
||||
3. **会话 JSONL 时间戳 ≠ webhook 到达时间。** 会话事件时间戳(`~/.openclaw/agents/<id>/sessions/*.jsonl`)反映的是 Gateway 网关将消息交给智能体的时间,**不是** webhook 到达时间。带有 `[Queued messages while agent was busy]` 标签的排队第二条消息,意味着第二个 webhook 到达时第一轮仍在运行——此时合并桶已经刷新。应根据 BB 服务器日志来调整窗口,而不是根据会话日志。
|
||||
3. **会话 JSONL 时间戳 ≠ webhook 到达时间。** 会话事件时间戳(`~/.openclaw/agents/<id>/sessions/*.jsonl`)反映的是 Gateway 网关何时将消息交给智能体,**不是** webhook 何时到达。如果排队中的第二条消息被标记为 `[Queued messages while agent was busy]`,说明第二个 webhook 到达时,第一轮仍在运行——合并 bucket 已经刷新。请根据 BB 服务器日志而不是会话日志来调整窗口。
|
||||
|
||||
4. **内存压力拖慢了回复分发。** 在较小的机器(8 GB)上,智能体轮次可能耗时很长,以至于在回复完成前合并桶就已刷新,URL 因而作为排队的第二轮到达。检查 `memory_pressure` 和 `ps -o rss -p $(pgrep openclaw-gateway)`;如果 Gateway 网关的 RSS 超过约 500 MB 且压缩器处于活动状态,请关闭其他高负载进程,或升级到更大的主机。
|
||||
4. **内存压力拖慢了回复分发。** 在较小的机器(8 GB)上,智能体轮次可能耗时较长,以至于在回复完成前合并 bucket 就已刷新,结果 URL 作为排队的第二轮到达。检查 `memory_pressure` 和 `ps -o rss -p $(pgrep openclaw-gateway)`;如果 Gateway 网关的 RSS 超过约 500 MB 且压缩器处于活跃状态,请关闭其他重型进程或升级到更大的主机。
|
||||
|
||||
5. **回复引用发送走的是另一条路径。** 如果用户是将 `Dump` 作为对现有 URL 气泡的**回复**发送的(iMessage 会在 `Dump` 气泡上显示 “1 Reply” 徽标),那么 URL 位于 `replyToBody` 中,而不是位于第二个 webhook 中。此时合并逻辑不适用——这是 Skills/提示词层面的问题,不是防抖器的问题。
|
||||
5. **回复引用发送走的是另一条路径。** 如果用户把 `Dump` 作为对现有 URL 预览气泡的**回复**发出(iMessage 会在 Dump 气泡上显示 “1 Reply” 标记),那么 URL 位于 `replyToBody` 中,而不是第二个 webhook 中。这时不适用合并——这是 Skills/提示词层面的问题,而不是 debouncer 层面的问题。
|
||||
|
||||
## 分块流式传输
|
||||
|
||||
控制响应是作为单条消息发送,还是按块流式发送:
|
||||
|
||||
```json5
|
||||
{
|
||||
channels: {
|
||||
bluebubbles: {
|
||||
blockStreaming: true, // 启用分块流式传输(默认关闭)
|
||||
},
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
控制是将回复作为单条消息发送,还是按块流式发送:
|
||||
__OC_I18N_900017__
|
||||
## 媒体 + 限制
|
||||
|
||||
- 入站附件会被下载并存储到媒体缓存中。
|
||||
- 入站和出站媒体都可通过 `channels.bluebubbles.mediaMaxMb` 设置媒体上限(默认:8 MB)。
|
||||
- 入站附件会被下载并存储在媒体缓存中。
|
||||
- 入站和出站媒体的大小上限由 `channels.bluebubbles.mediaMaxMb` 控制(默认:8 MB)。
|
||||
- 出站文本会按 `channels.bluebubbles.textChunkLimit` 分块(默认:4000 个字符)。
|
||||
|
||||
## 配置参考
|
||||
|
||||
完整配置: [Configuration](/zh-CN/gateway/configuration)
|
||||
完整配置: [Configuration](/gateway/configuration)
|
||||
|
||||
提供商选项:
|
||||
|
||||
@ -531,17 +520,17 @@ OpenClaw 可能会显示_短_消息 ID(例如 `1`、`2`)以节省 token。
|
||||
- `channels.bluebubbles.allowFrom`:私信允许列表(handles、电子邮件、E.164 号码、`chat_id:*`、`chat_guid:*`)。
|
||||
- `channels.bluebubbles.groupPolicy`:`open | allowlist | disabled`(默认:`allowlist`)。
|
||||
- `channels.bluebubbles.groupAllowFrom`:群组发送者允许列表。
|
||||
- `channels.bluebubbles.enrichGroupParticipantsFromContacts`:在 macOS 上,在门控通过后,可选择从本地“通讯录”中增强未命名的群组参与者。默认:`false`。
|
||||
- `channels.bluebubbles.enrichGroupParticipantsFromContacts`:在 macOS 上,在门控通过后,可选择从本地通讯录增强未命名的群组参与者。默认:`false`。
|
||||
- `channels.bluebubbles.groups`:按群组配置(`requireMention` 等)。
|
||||
- `channels.bluebubbles.sendReadReceipts`:发送已读回执(默认:`true`)。
|
||||
- `channels.bluebubbles.blockStreaming`:启用分块流式传输(默认:`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.blockStreaming`:启用分块流式传输(默认:`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`:将同一发送者连续的私信 webhook 合并为一轮智能体处理,使 Apple 的“文本 + URL”拆分发送能作为单条消息到达(默认:`false`)。场景、窗口调优和权衡请参见[合并拆分发送的私信](#coalescing-split-send-dms-command--url-in-one-composition)。启用后,如果未显式设置 `messages.inbound.byChannel.bluebubbles`,默认入站防抖窗口会从 500 ms 扩大到 2500 ms。
|
||||
- `channels.bluebubbles.historyLimit`:用于上下文的群组消息最大数量(设为 0 则禁用)。
|
||||
- `channels.bluebubbles.mediaMaxMb`:入站/出站媒体大小上限(MB)(默认:8)。
|
||||
- `channels.bluebubbles.mediaLocalRoots`:允许用于出站本地媒体路径的绝对本地目录显式允许列表。默认会拒绝发送本地路径,除非配置了此项。按账户覆盖:`channels.bluebubbles.accounts.<accountId>.mediaLocalRoots`。
|
||||
- `channels.bluebubbles.coalesceSameSenderDms`:将同一发送者连续发来的私信 webhook 合并为一次智能体轮次,使 Apple 拆分的“文本 + URL”发送能够作为一条消息到达(默认:`false`)。场景、窗口调优和权衡取舍参见 [合并拆分发送的私信](#coalescing-split-send-dms-command--url-in-one-composition)。当启用且未显式设置 `messages.inbound.byChannel.bluebubbles` 时,会将默认入站去抖窗口从 500 ms 扩大到 2500 ms。
|
||||
- `channels.bluebubbles.historyLimit`:用于上下文的群组消息最大数量(0 表示禁用)。
|
||||
- `channels.bluebubbles.dmHistoryLimit`:私信历史记录上限。
|
||||
- `channels.bluebubbles.actions`:启用/禁用特定操作。
|
||||
- `channels.bluebubbles.accounts`:多账户配置。
|
||||
@ -555,36 +544,40 @@ OpenClaw 可能会显示_短_消息 ID(例如 `1`、`2`)以节省 token。
|
||||
|
||||
为了获得稳定路由,优先使用 `chat_guid`:
|
||||
|
||||
- `chat_guid:iMessage;-;+15555550123`(群组推荐)
|
||||
- `chat_guid:iMessage;-;+15555550123`(群组首选)
|
||||
- `chat_id:123`
|
||||
- `chat_identifier:...`
|
||||
- 直接句柄:`+15555550123`、`user@example.com`
|
||||
- 如果某个直接句柄没有现有私信聊天,OpenClaw 会通过 `POST /api/v1/chat/new` 创建一个。这要求启用 BlueBubbles Private API。
|
||||
- 直接 handle:`+15555550123`、`user@example.com`
|
||||
- 如果某个直接 handle 没有现有的私信聊天,OpenClaw 会通过 `POST /api/v1/chat/new` 创建一个。这要求启用 BlueBubbles Private API。
|
||||
|
||||
### iMessage 与 SMS 路由
|
||||
|
||||
当同一个 handle 在 Mac 上同时存在 iMessage 聊天和 SMS 聊天时(例如某个已注册 iMessage 的电话号码,同时也收过绿色气泡的回退消息),OpenClaw 会优先选择 iMessage 聊天,绝不会静默降级到 SMS。要强制使用 SMS 聊天,请使用显式的 `sms:` 目标前缀(例如 `sms:+15555550123`)。如果某个 handle 没有匹配的 iMessage 聊天,则仍会通过 BlueBubbles 报告的相应聊天发送。
|
||||
|
||||
## 安全
|
||||
|
||||
- webhook 请求通过比较查询参数或请求头中的 `guid`/`password` 与 `channels.bluebubbles.password` 来进行身份验证。
|
||||
- 请妥善保管 API 密码和 webhook 端点(将其视为凭证)。
|
||||
- BlueBubbles webhook 身份验证没有 localhost 旁路。如果你代理 webhook 流量,请在整个请求链路中保留 BlueBubbles 密码。这里的 `gateway.trustedProxies` 不能替代 `channels.bluebubbles.password`。参见 [Gateway 网关安全](/zh-CN/gateway/security#reverse-proxy-configuration)。
|
||||
- 如果要将 BlueBubbles 服务器暴露到你的局域网之外,请启用 HTTPS + 防火墙规则。
|
||||
- webhook 请求通过将查询参数或请求头中的 `guid`/`password` 与 `channels.bluebubbles.password` 进行比较来完成身份验证。
|
||||
- 请妥善保管 API 密码和 webhook 端点(将它们视为凭据)。
|
||||
- BlueBubbles webhook 身份验证没有 localhost 绕过。如果你代理 webhook 流量,请在整个请求链路中保留 BlueBubbles 密码。这里的 `gateway.trustedProxies` 不能替代 `channels.bluebubbles.password`。参见 [Gateway 网关安全](/gateway/security#reverse-proxy-configuration)。
|
||||
- 如果要在局域网之外暴露 BlueBubbles 服务器,请启用 HTTPS 和防火墙规则。
|
||||
|
||||
## 故障排除
|
||||
|
||||
- 如果正在输入/已读事件停止工作,请检查 BlueBubbles webhook 日志,并确认 Gateway 网关路径与 `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)上,由于 private API 变更,编辑功能目前失效。
|
||||
- 如果“正在输入”/已读事件停止工作,请检查 BlueBubbles webhook 日志,并验证 Gateway 网关路径与 `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)上,由于 private API 变更,编辑当前不可用。
|
||||
- 群组图标更新在 macOS 26(Tahoe)上可能不稳定:API 可能返回成功,但新图标不会同步。
|
||||
- OpenClaw 会根据 BlueBubbles 服务器的 macOS 版本自动隐藏已知失效的操作。如果在 macOS 26(Tahoe)上仍然显示 edit,请手动通过 `channels.bluebubbles.actions.edit=false` 禁用它。
|
||||
- 已启用 `coalesceSameSenderDms`,但拆分发送(例如 `Dump` + URL)仍然作为两轮到达:请查看[拆分发送合并的故障排除](#split-send-coalescing-troubleshooting)清单——常见原因包括防抖窗口过窄、误将会话日志时间戳当作 webhook 到达时间,或使用了回复引用发送(其使用 `replyToBody`,而不是第二个 webhook)。
|
||||
- OpenClaw 会根据 BlueBubbles 服务器的 macOS 版本自动隐藏已知有问题的操作。如果在 macOS 26(Tahoe)上仍然显示 edit,请手动使用 `channels.bluebubbles.actions.edit=false` 禁用它。
|
||||
- 已启用 `coalesceSameSenderDms`,但拆分发送(例如 `Dump` + URL)仍然作为两轮到达:请参阅[拆分发送合并的故障排除](#split-send-coalescing-troubleshooting)检查清单——常见原因包括去抖窗口过窄、将会话日志时间戳误读为 webhook 到达时间,或发送的是回复引用(它使用的是 `replyToBody`,而不是第二个 webhook)。
|
||||
- 查看状态/健康信息:`openclaw status --all` 或 `openclaw status --deep`。
|
||||
|
||||
有关渠道工作流的一般参考,请参见 [Channels](/zh-CN/channels) 和 [Plugins](/zh-CN/tools/plugin) 指南。
|
||||
有关通用渠道工作流的参考,请参见 [Channels](/zh-CN/channels) 和 [Plugins](/zh-CN/tools/plugin) 指南。
|
||||
|
||||
## 相关内容
|
||||
|
||||
- [Channels 概览](/zh-CN/channels) —— 所有支持的渠道
|
||||
- [Pairing](/zh-CN/channels/pairing) —— 私信身份验证与配对流程
|
||||
- [Groups](/zh-CN/channels/groups) —— 群聊行为与提及门控
|
||||
- [Channels Overview](/zh-CN/channels) —— 所有受支持的渠道
|
||||
- [Pairing](/zh-CN/channels/pairing) —— 私信认证和配对流程
|
||||
- [Groups](/zh-CN/channels/groups) —— 群聊行为和提及门控
|
||||
- [Channel Routing](/zh-CN/channels/channel-routing) —— 消息的会话路由
|
||||
- [Security](/zh-CN/gateway/security) —— 访问模型与加固措施
|
||||
- [Security](/zh-CN/gateway/security) —— 访问模型与加固
|
||||
|
||||
@ -5,24 +5,24 @@ read_when:
|
||||
summary: Matrix 支持状态、设置和配置示例
|
||||
title: Matrix
|
||||
x-i18n:
|
||||
generated_at: "2026-04-20T12:12:13Z"
|
||||
generated_at: "2026-04-21T20:11:29Z"
|
||||
model: gpt-5.4
|
||||
provider: openai
|
||||
source_hash: 00fa6201d2ee4ac4ae5be3eb18ff687c5c2c9ef70cff12af1413b4c311484b24
|
||||
source_hash: 5e78d85096ea84361951935a0daf34966c575d822f8581277eb384276c7c706a
|
||||
source_path: channels/matrix.md
|
||||
workflow: 15
|
||||
---
|
||||
|
||||
# Matrix
|
||||
|
||||
Matrix 是 OpenClaw 的内置渠道插件。
|
||||
Matrix 是 OpenClaw 的一个内置渠道插件。
|
||||
它使用官方的 `matrix-js-sdk`,并支持私信、房间、线程、媒体、回应、投票、位置和 E2EE。
|
||||
|
||||
## 内置插件
|
||||
|
||||
Matrix 作为内置插件随当前的 OpenClaw 版本一起提供,因此常规打包构建不需要单独安装。
|
||||
Matrix 作为内置插件随当前的 OpenClaw 版本发布,因此常规的打包构建不需要单独安装。
|
||||
|
||||
如果你使用的是较旧的构建版本,或者排除了 Matrix 的自定义安装,请手动安装:
|
||||
如果你使用的是较旧的构建版本,或排除了 Matrix 的自定义安装,请手动安装:
|
||||
|
||||
从 npm 安装:
|
||||
|
||||
@ -36,20 +36,20 @@ openclaw plugins install @openclaw/matrix
|
||||
openclaw plugins install ./path/to/local/matrix-plugin
|
||||
```
|
||||
|
||||
有关插件行为和安装规则,请参阅 [Plugins](/zh-CN/tools/plugin)。
|
||||
有关插件行为和安装规则,请参见 [Plugins](/zh-CN/tools/plugin)。
|
||||
|
||||
## 设置
|
||||
|
||||
1. 确保 Matrix 插件可用。
|
||||
- 当前打包发布的 OpenClaw 版本已内置该插件。
|
||||
- 较旧版本或自定义安装可使用上述命令手动添加。
|
||||
- 当前打包的 OpenClaw 版本已内置该插件。
|
||||
- 较旧或自定义安装可以使用上面的命令手动添加。
|
||||
2. 在你的 homeserver 上创建一个 Matrix 账户。
|
||||
3. 使用以下任一方式配置 `channels.matrix`:
|
||||
- `homeserver` + `accessToken`,或
|
||||
- `homeserver` + `userId` + `password`。
|
||||
4. 重启 Gateway 网关。
|
||||
5. 与机器人开始一个私信,或邀请它加入一个房间。
|
||||
- 只有当 `channels.matrix.autoJoin` 允许时,新的 Matrix 邀请才会生效。
|
||||
5. 与机器人发起私信,或邀请它加入房间。
|
||||
- 只有当 `channels.matrix.autoJoin` 允许时,新发出的 Matrix 邀请才会生效。
|
||||
|
||||
交互式设置路径:
|
||||
|
||||
@ -61,27 +61,27 @@ openclaw configure --section channels
|
||||
Matrix 向导会询问以下内容:
|
||||
|
||||
- homeserver URL
|
||||
- 认证方式:访问令牌或密码
|
||||
- 认证方式:access token 或密码
|
||||
- 用户 ID(仅密码认证)
|
||||
- 可选的设备名称
|
||||
- 可选设备名称
|
||||
- 是否启用 E2EE
|
||||
- 是否配置房间访问和邀请自动加入
|
||||
|
||||
向导的关键行为:
|
||||
|
||||
- 如果 Matrix 认证环境变量已存在,并且该账户的凭证尚未保存在配置中,向导会提供一个环境变量快捷选项,以便将凭证保存在环境变量中。
|
||||
- 如果 Matrix 认证环境变量已存在,且该账户尚未在配置中保存认证信息,则向导会提供一个环境变量快捷选项,以便将认证信息保留在环境变量中。
|
||||
- 账户名称会规范化为账户 ID。例如,`Ops Bot` 会变成 `ops-bot`。
|
||||
- 私信允许列表条目可直接接受 `@user:server`;显示名称只有在实时目录查找找到唯一精确匹配时才可用。
|
||||
- 房间允许列表条目可直接接受房间 ID 和别名。优先使用 `!room:server` 或 `#alias:server`;未解析的名称会在运行时的允许列表解析中被忽略。
|
||||
- 在邀请自动加入允许列表模式下,只能使用稳定的邀请目标:`!roomId:server`、`#alias:server` 或 `*`。纯房间名称会被拒绝。
|
||||
- 若要在保存前解析房间名称,请使用 `openclaw channels resolve --channel matrix "Project Room"`。
|
||||
- 私信允许列表条目可直接接受 `@user:server`;显示名称只有在实时目录查找找到一个精确匹配时才有效。
|
||||
- 房间允许列表条目可直接接受房间 ID 和别名。优先使用 `!room:server` 或 `#alias:server`;未解析的名称会在运行时被允许列表解析忽略。
|
||||
- 在邀请自动加入的允许列表模式下,只使用稳定的邀请目标:`!roomId:server`、`#alias:server` 或 `*`。普通房间名称会被拒绝。
|
||||
- 如需在保存前解析房间名称,请使用 `openclaw channels resolve --channel matrix "Project Room"`。
|
||||
|
||||
<Warning>
|
||||
`channels.matrix.autoJoin` 的默认值为 `off`。
|
||||
`channels.matrix.autoJoin` 默认值为 `off`。
|
||||
|
||||
如果你不设置它,机器人将不会加入受邀房间或新的私信式邀请,因此除非你先手动加入,否则它不会出现在新的群组或受邀私信中。
|
||||
如果你不设置它,机器人将不会加入被邀请的房间或新的私信式邀请,因此除非你先手动加入,否则它不会出现在新群组或被邀请的私信中。
|
||||
|
||||
将 `autoJoin: "allowlist"` 与 `autoJoinAllowlist` 一起设置,可限制它接受哪些邀请;或者设置 `autoJoin: "always"`,让它加入所有邀请。
|
||||
将 `autoJoin: "allowlist"` 与 `autoJoinAllowlist` 一起设置,可限制它接受哪些邀请;如果你希望它加入所有邀请,可设置 `autoJoin: "always"`。
|
||||
|
||||
在 `allowlist` 模式下,`autoJoinAllowlist` 只接受 `!roomId:server`、`#alias:server` 或 `*`。
|
||||
</Warning>
|
||||
@ -116,7 +116,7 @@ Matrix 向导会询问以下内容:
|
||||
}
|
||||
```
|
||||
|
||||
基于令牌的最小设置:
|
||||
基于 token 的最小设置:
|
||||
|
||||
```json5
|
||||
{
|
||||
@ -131,7 +131,7 @@ Matrix 向导会询问以下内容:
|
||||
}
|
||||
```
|
||||
|
||||
基于密码的设置(登录后会缓存令牌):
|
||||
基于密码的设置(登录后会缓存 token):
|
||||
|
||||
```json5
|
||||
{
|
||||
@ -149,7 +149,7 @@ Matrix 向导会询问以下内容:
|
||||
|
||||
Matrix 会将缓存的凭证存储在 `~/.openclaw/credentials/matrix/` 中。
|
||||
默认账户使用 `credentials.json`;命名账户使用 `credentials-<account>.json`。
|
||||
当该处存在缓存凭证时,即使当前凭证未直接在配置中设置,OpenClaw 也会在设置、Doctor 和渠道状态发现中将 Matrix 视为已配置。
|
||||
当该位置存在缓存凭证时,即使当前认证未直接在配置中设置,OpenClaw 仍会在设置、Doctor 和渠道状态发现中将 Matrix 视为已配置。
|
||||
|
||||
对应的环境变量(当未设置配置键时使用):
|
||||
|
||||
@ -169,7 +169,7 @@ Matrix 会将缓存的凭证存储在 `~/.openclaw/credentials/matrix/` 中。
|
||||
- `MATRIX_<ACCOUNT_ID>_DEVICE_ID`
|
||||
- `MATRIX_<ACCOUNT_ID>_DEVICE_NAME`
|
||||
|
||||
账户 `ops` 的示例:
|
||||
以账户 `ops` 为例:
|
||||
|
||||
- `MATRIX_OPS_HOMESERVER`
|
||||
- `MATRIX_OPS_ACCESS_TOKEN`
|
||||
@ -179,10 +179,10 @@ Matrix 会将缓存的凭证存储在 `~/.openclaw/credentials/matrix/` 中。
|
||||
- `MATRIX_OPS_X2D_BOT_HOMESERVER`
|
||||
- `MATRIX_OPS_X2D_BOT_ACCESS_TOKEN`
|
||||
|
||||
Matrix 会对账户 ID 中的标点进行转义,以避免带作用域的环境变量发生冲突。
|
||||
例如,`-` 会变成 `_X2D_`,因此 `ops-prod` 会映射为 `MATRIX_OPS_X2D_PROD_*`。
|
||||
Matrix 会对账户 ID 中的标点进行转义,以确保带作用域的环境变量不会发生冲突。
|
||||
例如,`-` 会变为 `_X2D_`,因此 `ops-prod` 会映射为 `MATRIX_OPS_X2D_PROD_*`。
|
||||
|
||||
只有在这些认证环境变量已经存在,且所选账户尚未在配置中保存 Matrix 凭证时,交互式向导才会提供环境变量快捷选项。
|
||||
只有在这些认证环境变量已存在,且所选账户尚未在配置中保存 Matrix 认证信息时,交互式向导才会提供环境变量快捷选项。
|
||||
|
||||
## 配置示例
|
||||
|
||||
@ -221,13 +221,13 @@ Matrix 会对账户 ID 中的标点进行转义,以避免带作用域的环境
|
||||
}
|
||||
```
|
||||
|
||||
`autoJoin` 适用于所有 Matrix 邀请,包括私信式邀请。OpenClaw 无法在邀请时可靠地将受邀房间分类为私信或群组,因此所有邀请都会先经过 `autoJoin`。`dm.policy` 会在机器人加入并且房间被分类为私信后再生效。
|
||||
`autoJoin` 适用于所有 Matrix 邀请,包括私信式邀请。OpenClaw 无法在邀请发生时可靠地将受邀房间分类为私信或群组,因此所有邀请都会先经过 `autoJoin`。`dm.policy` 会在机器人加入后、房间被分类为私信之后再生效。
|
||||
|
||||
## 流式预览
|
||||
|
||||
Matrix 回复流式传输为可选启用。
|
||||
Matrix 回复流式传输是可选启用的。
|
||||
|
||||
当你希望 OpenClaw 发送一条实时预览回复、在模型生成文本时原地编辑该预览,并在回复完成时将其最终定稿,请将 `channels.matrix.streaming` 设置为 `"partial"`:
|
||||
当你希望 OpenClaw 发送一条实时预览回复、在模型生成文本时原地编辑该预览,并在回复完成后将其定稿时,请将 `channels.matrix.streaming` 设置为 `"partial"`:
|
||||
|
||||
```json5
|
||||
{
|
||||
@ -239,37 +239,37 @@ Matrix 回复流式传输为可选启用。
|
||||
}
|
||||
```
|
||||
|
||||
- `streaming: "off"` 是默认值。OpenClaw 会等待最终回复并只发送一次。
|
||||
- `streaming: "partial"` 会为当前智能体块创建一条可编辑的预览消息,使用普通 Matrix 文本消息。这会保留 Matrix 旧有的“先预览后完成”通知行为,因此标准客户端可能会对第一段流式预览文本发出通知,而不是对完成后的最终块发出通知。
|
||||
- `streaming: "quiet"` 会为当前智能体块创建一条可编辑的静默预览通知。仅当你还为最终定稿的预览编辑配置了收件人推送规则时才使用此选项。
|
||||
- `blockStreaming: true` 会启用单独的 Matrix 进度消息。启用预览流式传输后,Matrix 会为当前块保留实时草稿,并将已完成的块保留为单独消息。
|
||||
- 当启用了预览流式传输且 `blockStreaming` 为 off 时,Matrix 会原地编辑实时草稿,并在块或轮次结束时将同一事件最终定稿。
|
||||
- 如果预览不再适合放入单个 Matrix 事件中,OpenClaw 会停止预览流式传输并回退到普通的最终投递方式。
|
||||
- 媒体回复仍会正常发送附件。如果过期的预览已无法安全复用,OpenClaw 会在发送最终媒体回复前将其删隐。
|
||||
- 预览编辑会增加额外的 Matrix API 调用。如果你希望采用最保守的速率限制行为,请保持关闭流式传输。
|
||||
- `streaming: "off"` 是默认值。OpenClaw 会等待最终回复并一次性发送。
|
||||
- `streaming: "partial"` 会为当前助手块创建一条可编辑的预览消息,并使用普通 Matrix 文本消息。这会保留 Matrix 传统的“预览优先”通知行为,因此标准客户端可能会针对首次流式预览文本发送通知,而不是在完整块完成时通知。
|
||||
- `streaming: "quiet"` 会为当前助手块创建一条可编辑的静默预览通知。只有当你也为已完成的预览编辑配置了接收方 push 规则时,才应使用此模式。
|
||||
- `blockStreaming: true` 会启用单独的 Matrix 进度消息。启用预览流式传输后,Matrix 会保留当前块的实时草稿,并将已完成的块保留为单独消息。
|
||||
- 当启用预览流式传输且 `blockStreaming` 为 off 时,Matrix 会原地编辑实时草稿,并在块或轮次结束时将同一事件定稿。
|
||||
- 如果预览内容不再适合放入单个 Matrix 事件中,OpenClaw 会停止预览流式传输,并回退到普通的最终发送方式。
|
||||
- 媒体回复仍会正常发送附件。如果过期预览已无法安全复用,OpenClaw 会在发送最终媒体回复前将其撤回。
|
||||
- 预览编辑会带来额外的 Matrix API 调用。如果你希望采用最保守的限流行为,请保持关闭流式传输。
|
||||
|
||||
`blockStreaming` 本身不会启用草稿预览。
|
||||
请使用 `streaming: "partial"` 或 `streaming: "quiet"` 来启用预览编辑;如果你还希望已完成的智能体块作为单独的进度消息保持可见,再额外添加 `blockStreaming: true`。
|
||||
使用 `streaming: "partial"` 或 `streaming: "quiet"` 来启用预览编辑;如果你还希望已完成的助手块作为独立进度消息保留可见,再额外添加 `blockStreaming: true`。
|
||||
|
||||
如果你需要标准 Matrix 通知而不使用自定义推送规则,请使用 `streaming: "partial"` 以获得“先预览后完成”的行为,或保持 `streaming` 为关闭以仅投递最终结果。在 `streaming: "off"` 时:
|
||||
如果你需要标准 Matrix 通知,而不想配置自定义 push 规则,请使用 `streaming: "partial"` 获得“预览优先”行为,或保持 `streaming` 为 off 以仅在最终完成时发送。使用 `streaming: "off"` 时:
|
||||
|
||||
- `blockStreaming: true` 会将每个已完成块作为普通且会通知的 Matrix 消息发送。
|
||||
- `blockStreaming: false` 只会将最终完成的回复作为普通且会通知的 Matrix 消息发送。
|
||||
- `blockStreaming: true` 会将每个已完成块作为普通的可通知 Matrix 消息发送。
|
||||
- `blockStreaming: false` 只会将最终完成的回复作为普通的可通知 Matrix 消息发送。
|
||||
|
||||
### 自托管静默最终预览的推送规则
|
||||
### 自托管环境中用于静默已定稿预览的 push 规则
|
||||
|
||||
如果你运行自己的 Matrix 基础设施,并希望静默预览仅在某个块或最终回复完成时触发通知,请设置 `streaming: "quiet"`,并为最终定稿的预览编辑添加每用户推送规则。
|
||||
如果你运行的是自己的 Matrix 基础设施,并希望静默预览只在某个块或最终回复完成时触发通知,请设置 `streaming: "quiet"`,并为每个用户添加一条用于已定稿预览编辑的 push 规则。
|
||||
|
||||
这通常是收件用户的设置,而不是 homeserver 全局配置变更:
|
||||
这通常是接收方用户级别的设置,而不是 homeserver 全局配置变更:
|
||||
|
||||
开始前的快速对应说明:
|
||||
开始前的快速说明:
|
||||
|
||||
- 收件用户 = 应该接收通知的人
|
||||
- 机器人用户 = 发送回复的 OpenClaw Matrix 账户
|
||||
- 下面的 API 调用请使用收件用户的访问令牌
|
||||
- 在推送规则中,将 `sender` 与机器人用户的完整 MXID 匹配
|
||||
- recipient user = 应收到通知的人
|
||||
- bot user = 发送回复的 OpenClaw Matrix 账户
|
||||
- 下方 API 调用请使用 recipient user 的 access token
|
||||
- 在 push 规则中,将 `sender` 匹配为 bot user 的完整 MXID
|
||||
|
||||
1. 将 OpenClaw 配置为使用静默预览:
|
||||
1. 配置 OpenClaw 使用静默预览:
|
||||
|
||||
```json5
|
||||
{
|
||||
@ -281,12 +281,12 @@ Matrix 回复流式传输为可选启用。
|
||||
}
|
||||
```
|
||||
|
||||
2. 确保收件账户已经可以接收普通 Matrix 推送通知。静默预览规则只有在该用户已经拥有正常工作的推送器/设备时才会生效。
|
||||
2. 确保接收方账户已经能够接收普通 Matrix push 通知。静默预览规则只有在该用户已有可用的 pusher 或设备时才会生效。
|
||||
|
||||
3. 获取收件用户的访问令牌。
|
||||
- 使用接收用户的令牌,而不是机器人的令牌。
|
||||
- 复用现有客户端会话令牌通常最简单。
|
||||
- 如果你需要签发一个新的令牌,可以通过标准 Matrix Client-Server API 登录:
|
||||
3. 获取接收方用户的 access token。
|
||||
- 使用接收消息用户的 token,而不是机器人的 token。
|
||||
- 复用现有客户端会话 token 通常是最简单的方式。
|
||||
- 如果你需要签发一个新的 token,可以通过标准 Matrix Client-Server API 登录:
|
||||
|
||||
```bash
|
||||
curl -sS -X POST \
|
||||
@ -302,7 +302,7 @@ curl -sS -X POST \
|
||||
}'
|
||||
```
|
||||
|
||||
4. 验证收件账户是否已经拥有推送器:
|
||||
4. 验证接收方账户已存在 pusher:
|
||||
|
||||
```bash
|
||||
curl -sS \
|
||||
@ -310,9 +310,9 @@ curl -sS \
|
||||
"https://matrix.example.org/_matrix/client/v3/pushers"
|
||||
```
|
||||
|
||||
如果这里没有返回活动的推送器/设备,请先修复普通 Matrix 通知,再添加下面的 OpenClaw 规则。
|
||||
如果这里返回没有活动 pusher 或设备,请先修复普通 Matrix 通知,再添加下方的 OpenClaw 规则。
|
||||
|
||||
OpenClaw 会使用以下标记来标识已最终定稿的纯文本预览编辑:
|
||||
OpenClaw 会使用以下标记来标识已定稿的纯文本预览编辑:
|
||||
|
||||
```json
|
||||
{
|
||||
@ -320,7 +320,7 @@ OpenClaw 会使用以下标记来标识已最终定稿的纯文本预览编辑
|
||||
}
|
||||
```
|
||||
|
||||
5. 为每个需要接收这些通知的收件账户创建一条 override 推送规则:
|
||||
5. 为每个应接收此类通知的接收方账户创建一条 override push 规则:
|
||||
|
||||
```bash
|
||||
curl -sS -X PUT \
|
||||
@ -350,23 +350,23 @@ curl -sS -X PUT \
|
||||
}'
|
||||
```
|
||||
|
||||
在运行该命令前,请替换以下值:
|
||||
运行命令前,请替换以下值:
|
||||
|
||||
- `https://matrix.example.org`:你的 homeserver 基础 URL
|
||||
- `$USER_ACCESS_TOKEN`:接收用户的访问令牌
|
||||
- `openclaw-finalized-preview-botname`:对此接收用户而言,该机器人的唯一规则 ID
|
||||
- `@bot:example.org`:你的 OpenClaw Matrix 机器人 MXID,不是接收用户的 MXID
|
||||
- `$USER_ACCESS_TOKEN`:接收方用户的 access token
|
||||
- `openclaw-finalized-preview-botname`:对此接收方用户和此机器人的唯一规则 ID
|
||||
- `@bot:example.org`:你的 OpenClaw Matrix 机器人 MXID,而不是接收方用户的 MXID
|
||||
|
||||
多机器人设置的重要说明:
|
||||
对于多机器人部署,重要说明:
|
||||
|
||||
- 推送规则以 `ruleId` 为键。对相同规则 ID 再次执行 `PUT` 会更新该条规则。
|
||||
- Push 规则以 `ruleId` 为键。对同一个规则 ID 重复执行 `PUT` 会更新该条规则。
|
||||
- 如果同一个接收用户需要对多个 OpenClaw Matrix 机器人账户触发通知,请为每个机器人分别创建一条规则,并为每个 `sender` 匹配使用唯一的规则 ID。
|
||||
- 一个简单的命名模式是 `openclaw-finalized-preview-<botname>`,例如 `openclaw-finalized-preview-ops` 或 `openclaw-finalized-preview-support`。
|
||||
|
||||
该规则会根据事件发送者进行评估:
|
||||
该规则会针对事件发送者进行匹配:
|
||||
|
||||
- 使用接收用户的令牌进行认证
|
||||
- 将 `sender` 与 OpenClaw 机器人 MXID 进行匹配
|
||||
- 使用接收用户的 token 进行认证
|
||||
- 将 `sender` 与 OpenClaw 机器人的 MXID 进行匹配
|
||||
|
||||
6. 验证规则是否存在:
|
||||
|
||||
@ -376,9 +376,9 @@ curl -sS \
|
||||
"https://matrix.example.org/_matrix/client/v3/pushrules/global/override/openclaw-finalized-preview-botname"
|
||||
```
|
||||
|
||||
7. 测试一次流式回复。在静默模式下,房间应显示一条静默的草稿预览,并且当块或轮次结束时,最终的原地编辑应触发一次通知。
|
||||
7. 测试一次流式回复。在 quiet 模式下,房间中应显示一条静默草稿预览,并且当块或轮次结束时,最终的原地编辑应触发一次通知。
|
||||
|
||||
如果你之后需要移除该规则,请使用接收用户的令牌删除相同的规则 ID:
|
||||
如果你之后需要移除该规则,请使用接收用户的 token 删除同一个规则 ID:
|
||||
|
||||
```bash
|
||||
curl -sS -X DELETE \
|
||||
@ -388,33 +388,33 @@ curl -sS -X DELETE \
|
||||
|
||||
说明:
|
||||
|
||||
- 请使用接收用户的访问令牌创建该规则,而不是机器人的令牌。
|
||||
- 新的用户自定义 `override` 规则会插入到默认抑制规则之前,因此不需要额外的排序参数。
|
||||
- 这只影响 OpenClaw 能够安全地原地最终定稿的纯文本预览编辑。媒体回退和过期预览回退仍使用普通 Matrix 投递。
|
||||
- 如果 `GET /_matrix/client/v3/pushers` 显示没有推送器,则表示该用户在此账户/设备上尚未具备正常工作的 Matrix 推送投递。
|
||||
- 创建规则时请使用接收用户的 access token,而不是机器人的。
|
||||
- 新建的用户自定义 `override` 规则会插入到默认抑制规则之前,因此不需要额外的排序参数。
|
||||
- 这只影响 OpenClaw 能够安全原地定稿的纯文本预览编辑。媒体回退和过期预览回退仍会使用普通 Matrix 发送方式。
|
||||
- 如果 `GET /_matrix/client/v3/pushers` 显示没有 pusher,说明该用户在此账户或设备上还没有可用的 Matrix push 投递。
|
||||
|
||||
#### Synapse
|
||||
|
||||
对于 Synapse,上述设置通常已经足够:
|
||||
对于 Synapse,通常只需完成上述设置即可:
|
||||
|
||||
- 不需要为 OpenClaw 最终预览通知做任何特殊的 `homeserver.yaml` 修改。
|
||||
- 如果你的 Synapse 部署已经能发送普通 Matrix 推送通知,那么上面的用户令牌 + `pushrules` 调用就是主要设置步骤。
|
||||
- 如果你在反向代理或 workers 后面运行 Synapse,请确保 `/_matrix/client/.../pushrules/` 能正确到达 Synapse。
|
||||
- 如果你使用 Synapse workers,请确保 pushers 状态正常。推送投递由主进程或 `synapse.app.pusher` / 已配置的 pusher workers 处理。
|
||||
- 不需要为 OpenClaw 已定稿预览通知专门修改 `homeserver.yaml`。
|
||||
- 如果你的 Synapse 部署已经能够发送普通 Matrix push 通知,那么上面的用户 token + `pushrules` 调用就是主要设置步骤。
|
||||
- 如果你的 Synapse 运行在反向代理或 workers 后面,请确保 `/_matrix/client/.../pushrules/` 能正确到达 Synapse。
|
||||
- 如果你使用 Synapse workers,请确保 pushers 状态健康。Push 投递由主进程或 `synapse.app.pusher` / 已配置的 pusher workers 处理。
|
||||
|
||||
#### Tuwunel
|
||||
|
||||
对于 Tuwunel,请使用与上文相同的设置流程和 `push-rule` API 调用:
|
||||
对于 Tuwunel,使用与上方相同的设置流程和 push-rule API 调用:
|
||||
|
||||
- 对于最终预览标记本身,不需要任何 Tuwunel 专属配置。
|
||||
- 如果该用户的普通 Matrix 通知已经正常工作,那么上面的用户令牌 + `pushrules` 调用就是主要设置步骤。
|
||||
- 如果用户在另一台设备上处于活跃状态时通知似乎消失了,请检查是否启用了 `suppress_push_when_active`。Tuwunel 在 2025 年 9 月 12 日发布的 Tuwunel 1.4.2 中加入了此选项,它可能会在某一台设备活跃时有意抑制向其他设备发送推送。
|
||||
- 对于已定稿预览标记本身,不需要任何 Tuwunel 特定配置。
|
||||
- 如果该用户的普通 Matrix 通知已经正常工作,那么上面的用户 token + `pushrules` 调用就是主要设置步骤。
|
||||
- 如果用户在另一台设备活跃时通知似乎消失了,请检查是否启用了 `suppress_push_when_active`。Tuwunel 在 2025 年 9 月 12 日发布的 Tuwunel 1.4.2 中加入了该选项,它可能会在一台设备活跃时故意抑制发往其他设备的 push。
|
||||
|
||||
## 机器人到机器人的房间
|
||||
|
||||
默认情况下,来自其他已配置 OpenClaw Matrix 账户的 Matrix 消息会被忽略。
|
||||
|
||||
当你有意启用智能体之间的 Matrix 通信时,请使用 `allowBots`:
|
||||
如果你有意启用智能体之间的 Matrix 通信,请使用 `allowBots`:
|
||||
|
||||
```json5
|
||||
{
|
||||
@ -432,16 +432,16 @@ curl -sS -X DELETE \
|
||||
```
|
||||
|
||||
- `allowBots: true` 会在允许的房间和私信中接受来自其他已配置 Matrix 机器人账户的消息。
|
||||
- `allowBots: "mentions"` 仅在这些消息在房间中显式提及该机器人时接受它们。私信仍然允许。
|
||||
- `groups.<room>.allowBots` 会覆盖账户级别对单个房间的设置。
|
||||
- `allowBots: "mentions"` 仅在这些消息在房间中明确提及此机器人时接受。私信仍然允许。
|
||||
- `groups.<room>.allowBots` 会覆盖账户级设置,仅对某一个房间生效。
|
||||
- OpenClaw 仍会忽略来自同一个 Matrix 用户 ID 的消息,以避免自回复循环。
|
||||
- Matrix 在这里不会暴露原生机器人标记;OpenClaw 将“由机器人撰写”视为“由此 OpenClaw Gateway 网关上另一个已配置 Matrix 账户发送”。
|
||||
- Matrix 在这里不提供原生的机器人标记;OpenClaw 将“机器人发送”定义为“由此 OpenClaw Gateway 网关上另一个已配置的 Matrix 账户发送”。
|
||||
|
||||
在共享房间中启用机器人到机器人通信时,请使用严格的房间允许列表和提及要求。
|
||||
|
||||
## 加密和验证
|
||||
|
||||
在加密的(E2EE)房间中,出站图片事件使用 `thumbnail_file`,因此图片预览会与完整附件一起加密。未加密房间仍使用普通的 `thumbnail_url`。无需任何配置——插件会自动检测 E2EE 状态。
|
||||
在加密的(E2EE)房间中,出站图片事件使用 `thumbnail_file`,因此图片预览会与完整附件一起被加密。未加密房间仍使用普通的 `thumbnail_url`。无需额外配置——该插件会自动检测 E2EE 状态。
|
||||
|
||||
启用加密:
|
||||
|
||||
@ -477,19 +477,19 @@ openclaw matrix verify status --verbose
|
||||
openclaw matrix verify status --include-recovery-key --json
|
||||
```
|
||||
|
||||
引导 cross-signing 和验证状态:
|
||||
初始化 cross-signing 和验证状态:
|
||||
|
||||
```bash
|
||||
openclaw matrix verify bootstrap
|
||||
```
|
||||
|
||||
详细的引导诊断:
|
||||
详细的初始化诊断:
|
||||
|
||||
```bash
|
||||
openclaw matrix verify bootstrap --verbose
|
||||
```
|
||||
|
||||
在引导前强制重置为全新的 cross-signing 身份:
|
||||
在初始化之前强制重置为全新的 cross-signing 身份:
|
||||
|
||||
```bash
|
||||
openclaw matrix verify bootstrap --force-reset-cross-signing
|
||||
@ -531,17 +531,17 @@ openclaw matrix verify backup restore
|
||||
openclaw matrix verify backup restore --verbose
|
||||
```
|
||||
|
||||
删除当前服务器备份并创建一个全新的备份基线。如果无法正常加载已存储的备份密钥,此重置还可以重新创建 secret storage,以便未来冷启动时能够加载新的备份密钥:
|
||||
删除当前服务器备份并创建一个全新的备份基线。如果已存储的备份密钥无法被干净地加载,此重置也可以重新创建 secret storage,以便未来冷启动时能够加载新的备份密钥:
|
||||
|
||||
```bash
|
||||
openclaw matrix verify backup reset --yes
|
||||
```
|
||||
|
||||
所有 `verify` 命令默认都保持简洁(包括安静的内部 SDK 日志),仅在使用 `--verbose` 时显示详细诊断信息。
|
||||
在编写脚本时,请使用 `--json` 获取完整的机器可读输出。
|
||||
所有 `verify` 命令默认都保持简洁(包括安静的内部 SDK 日志),只有在使用 `--verbose` 时才显示详细诊断信息。
|
||||
编写脚本时,请使用 `--json` 获取完整的机器可读输出。
|
||||
|
||||
在多账户设置中,除非你传入 `--account <id>`,否则 Matrix CLI 命令会使用隐式的 Matrix 默认账户。
|
||||
如果你配置了多个命名账户,请先设置 `channels.matrix.defaultAccount`,否则这些隐式 CLI 操作会停止并要求你显式选择一个账户。
|
||||
在多账户设置中,Matrix CLI 命令会使用隐式的 Matrix 默认账户,除非你传入 `--account <id>`。
|
||||
如果你配置了多个命名账户,请先设置 `channels.matrix.defaultAccount`,否则这些隐式 CLI 操作会停止并要求你显式选择账户。
|
||||
当你希望验证或设备操作明确针对某个命名账户时,请使用 `--account`:
|
||||
|
||||
```bash
|
||||
@ -552,38 +552,38 @@ openclaw matrix devices list --account assistant
|
||||
|
||||
当某个命名账户的加密被禁用或不可用时,Matrix 警告和验证错误会指向该账户的配置键,例如 `channels.matrix.accounts.assistant.encryption`。
|
||||
|
||||
### “已验证” 的含义
|
||||
### “已验证”的含义
|
||||
|
||||
只有当该 Matrix 设备已由你自己的 cross-signing 身份验证时,OpenClaw 才会将其视为已验证。
|
||||
在实际中,`openclaw matrix verify status --verbose` 会暴露三个信任信号:
|
||||
只有当这个 Matrix 设备已被你自己的 cross-signing 身份验证时,OpenClaw 才会将其视为已验证。
|
||||
在实践中,`openclaw matrix verify status --verbose` 会暴露三个信任信号:
|
||||
|
||||
- `Locally trusted`:该设备仅被当前客户端信任
|
||||
- `Locally trusted`:该设备仅被当前客户端本地信任
|
||||
- `Cross-signing verified`:SDK 报告该设备已通过 cross-signing 验证
|
||||
- `Signed by owner`:该设备已由你自己的 self-signing 密钥签名
|
||||
|
||||
只有当存在 cross-signing 验证或所有者签名时,`Verified by owner` 才会变为 `yes`。
|
||||
仅有本地信任还不足以让 OpenClaw 将该设备视为完全已验证。
|
||||
只有在存在 cross-signing 验证或 owner-signing 时,`Verified by owner` 才会变为 `yes`。
|
||||
仅有本地信任并不足以让 OpenClaw 将该设备视为完全已验证。
|
||||
|
||||
### bootstrap 会做什么
|
||||
|
||||
`openclaw matrix verify bootstrap` 是针对加密 Matrix 账户的修复和设置命令。
|
||||
它会依次执行以下所有操作:
|
||||
`openclaw matrix verify bootstrap` 是加密 Matrix 账户的修复和设置命令。
|
||||
它会按顺序执行以下所有操作:
|
||||
|
||||
- 引导 secret storage,并在可能时复用现有恢复密钥
|
||||
- 引导 cross-signing,并上传缺失的公开 cross-signing 密钥
|
||||
- 初始化 secret storage,并尽可能复用现有恢复密钥
|
||||
- 初始化 cross-signing,并上传缺失的公开 cross-signing 密钥
|
||||
- 尝试标记并 cross-sign 当前设备
|
||||
- 如果服务器端尚不存在房间密钥备份,则创建一个新的服务器端房间密钥备份
|
||||
- 如果服务器端尚不存在房间密钥备份,则创建一个新的备份
|
||||
|
||||
如果 homeserver 需要交互式认证才能上传 cross-signing 密钥,OpenClaw 会先尝试不带认证上传,然后使用 `m.login.dummy`,再在配置了 `channels.matrix.password` 时使用 `m.login.password`。
|
||||
如果 homeserver 在上传 cross-signing 密钥时要求交互式认证,OpenClaw 会先尝试无认证上传,然后尝试 `m.login.dummy`,最后在配置了 `channels.matrix.password` 时尝试 `m.login.password`。
|
||||
|
||||
仅当你明确希望丢弃当前 cross-signing 身份并创建新的身份时,才使用 `--force-reset-cross-signing`。
|
||||
只有在你明确希望丢弃当前 cross-signing 身份并创建新身份时,才使用 `--force-reset-cross-signing`。
|
||||
|
||||
如果你明确希望丢弃当前房间密钥备份,并为未来消息重新开始新的备份基线,请使用 `openclaw matrix verify backup reset --yes`。
|
||||
只有当你接受无法恢复的旧加密历史将继续不可用,并且 OpenClaw 可能会在当前备份密钥无法安全加载时重新创建 secret storage,才应这样做。
|
||||
如果你明确希望丢弃当前房间密钥备份,并为未来消息建立一个新的备份基线,请使用 `openclaw matrix verify backup reset --yes`。
|
||||
只有在你接受无法恢复的旧加密历史将继续不可用,并且 OpenClaw 可能会在当前备份密钥无法安全加载时重新创建 secret storage 的情况下,才这样做。
|
||||
|
||||
### 全新备份基线
|
||||
### 全新的备份基线
|
||||
|
||||
如果你希望确保未来的加密消息继续正常工作,并接受丢失无法恢复的旧历史,请按顺序运行以下命令:
|
||||
如果你希望未来的加密消息继续可用,并接受失去无法恢复的旧历史,请按顺序运行以下命令:
|
||||
|
||||
```bash
|
||||
openclaw matrix verify backup reset --yes
|
||||
@ -591,47 +591,47 @@ openclaw matrix verify backup status --verbose
|
||||
openclaw matrix verify status
|
||||
```
|
||||
|
||||
当你希望明确针对某个命名 Matrix 账户时,请为每条命令添加 `--account <id>`。
|
||||
如果你希望明确指定某个命名 Matrix 账户,请为每个命令添加 `--account <id>`。
|
||||
|
||||
### 启动行为
|
||||
|
||||
当 `encryption: true` 时,Matrix 会将 `startupVerification` 默认设为 `"if-unverified"`。
|
||||
启动时,如果此设备仍未验证,Matrix 会在另一个 Matrix 客户端中请求自验证,在已有请求待处理时跳过重复请求,并在重启后重试前应用本地冷却时间。
|
||||
默认情况下,失败的请求尝试会比成功创建请求后的重试更早进行。
|
||||
如果你想禁用自动启动请求,请设置 `startupVerification: "off"`;如果你希望更短或更长的重试窗口,可调整 `startupVerificationCooldownHours`。
|
||||
启动时,如果该设备仍未验证,Matrix 会在另一个 Matrix 客户端中请求自我验证;如果已有一个请求处于待处理状态,则跳过重复请求;并在重启后重试前应用本地冷却时间。
|
||||
默认情况下,失败的请求尝试会比成功创建请求后更早重试。
|
||||
如果你想禁用自动启动请求,请设置 `startupVerification: "off"`;如果你希望缩短或延长重试窗口,请调整 `startupVerificationCooldownHours`。
|
||||
|
||||
启动时还会自动执行一次保守的加密 bootstrap 检查。
|
||||
该检查会优先尝试复用当前的 secret storage 和 cross-signing 身份,并且除非你运行显式的 bootstrap 修复流程,否则不会重置 cross-signing。
|
||||
启动时也会自动执行一次保守的加密 bootstrap 检查。
|
||||
该检查会优先尝试复用当前的 secret storage 和 cross-signing 身份,并避免重置 cross-signing,除非你运行了显式的 bootstrap 修复流程。
|
||||
|
||||
如果启动时仍发现 bootstrap 状态损坏,即使未配置 `channels.matrix.password`,OpenClaw 也可以尝试一条受保护的修复路径。
|
||||
如果 homeserver 要求基于密码的 UIA 才能完成该修复,OpenClaw 会记录一条警告,并保持启动为非致命状态,而不是中止机器人。
|
||||
如果当前设备已经由所有者签名,OpenClaw 会保留该身份,而不是自动重置它。
|
||||
如果启动时仍发现 bootstrap 状态损坏,即使未配置 `channels.matrix.password`,OpenClaw 也可以尝试受保护的修复路径。
|
||||
如果 homeserver 要求密码型 UIA 才能完成该修复,OpenClaw 会记录一条警告,并保持启动为非致命错误,而不是中止机器人。
|
||||
如果当前设备已经由 owner 签名,OpenClaw 会保留该身份,而不会自动重置它。
|
||||
|
||||
有关完整的升级流程、限制、恢复命令和常见迁移消息,请参阅 [Matrix migration](/zh-CN/install/migrating-matrix)。
|
||||
完整的升级流程、限制、恢复命令和常见迁移消息,请参见 [Matrix migration](/zh-CN/install/migrating-matrix)。
|
||||
|
||||
### 验证通知
|
||||
|
||||
Matrix 会将验证生命周期通知直接作为 `m.notice` 消息发布到严格的私信验证房间中。
|
||||
其中包括:
|
||||
包括:
|
||||
|
||||
- 验证请求通知
|
||||
- 验证就绪通知(带有明确的“通过表情符号验证”指引)
|
||||
- 验证就绪通知(包含明确的“通过表情符号验证”指引)
|
||||
- 验证开始和完成通知
|
||||
- SAS 详情(如果可用,则包括表情符号和十进制数字)
|
||||
- SAS 详情(如果可用,包括表情符号和十进制数字)
|
||||
|
||||
来自另一个 Matrix 客户端的入站验证请求会被 OpenClaw 跟踪并自动接受。
|
||||
对于自验证流程,OpenClaw 还会在表情符号验证可用时自动启动 SAS 流程,并确认自身这一侧。
|
||||
对于来自其他 Matrix 用户/设备的验证请求,OpenClaw 会自动接受请求,然后等待 SAS 流程正常推进。
|
||||
你仍需要在你的 Matrix 客户端中比较表情符号或十进制 SAS,并在那里确认“它们匹配”,以完成验证。
|
||||
来自其他 Matrix 客户端的传入验证请求会被 OpenClaw 跟踪并自动接受。
|
||||
对于自我验证流程,当表情符号验证可用时,OpenClaw 也会自动启动 SAS 流程并确认自己这一侧。
|
||||
对于来自其他 Matrix 用户或设备的验证请求,OpenClaw 会自动接受请求,然后等待 SAS 流程正常继续。
|
||||
你仍然需要在你的 Matrix 客户端中比对表情符号或十进制 SAS,并在那里确认“它们匹配”,才能完成验证。
|
||||
|
||||
OpenClaw 不会盲目自动接受自发起的重复流程。当已有自验证请求待处理时,启动过程会跳过创建新请求。
|
||||
OpenClaw 不会盲目自动接受由自己发起的重复流程。当已有自我验证请求处于待处理状态时,启动过程会跳过创建新请求。
|
||||
|
||||
验证协议/系统通知不会被转发到智能体聊天流水线,因此不会产生 `NO_REPLY`。
|
||||
验证协议或系统通知不会转发到智能体聊天管道,因此不会产生 `NO_REPLY`。
|
||||
|
||||
### 设备清理
|
||||
|
||||
由 OpenClaw 管理的旧 Matrix 设备可能会在账户中逐渐累积,使加密房间的信任状态更难判断。
|
||||
可使用以下命令列出它们:
|
||||
旧的由 OpenClaw 管理的 Matrix 设备可能会在账户中不断累积,使加密房间的信任状态更难判断。
|
||||
使用以下命令列出它们:
|
||||
|
||||
```bash
|
||||
openclaw matrix devices list
|
||||
@ -645,67 +645,67 @@ openclaw matrix devices prune-stale
|
||||
|
||||
### 加密存储
|
||||
|
||||
Matrix E2EE 在 Node 中使用官方 `matrix-js-sdk` 的 Rust 加密路径,并使用 `fake-indexeddb` 作为 IndexedDB shim。加密状态会持久化到快照文件(`crypto-idb-snapshot.json`)并在启动时恢复。该快照文件属于敏感运行时状态,采用严格的文件权限存储。
|
||||
Matrix E2EE 在 Node 中使用官方 `matrix-js-sdk` 的 Rust 加密路径,并以 `fake-indexeddb` 作为 IndexedDB shim。加密状态会持久化到一个快照文件(`crypto-idb-snapshot.json`)并在启动时恢复。该快照文件属于敏感运行时状态,使用严格的文件权限存储。
|
||||
|
||||
加密运行时状态位于按账户、按用户令牌哈希划分的根目录下:
|
||||
加密运行时状态位于按账户、按用户 token 哈希划分的根目录下:
|
||||
`~/.openclaw/matrix/accounts/<account>/<homeserver>__<user>/<token-hash>/`。
|
||||
该目录包含同步存储(`bot-storage.json`)、加密存储(`crypto/`)、
|
||||
恢复密钥文件(`recovery-key.json`)、IndexedDB 快照(`crypto-idb-snapshot.json`)、
|
||||
线程绑定(`thread-bindings.json`)以及启动验证状态(`startup-verification.json`)。
|
||||
当令牌发生变化但账户身份保持不变时,OpenClaw 会为该 account/homeserver/user 元组复用最佳现有根目录,这样先前的同步状态、加密状态、线程绑定和启动验证状态仍然可见。
|
||||
当 token 发生变化但账户身份保持不变时,OpenClaw 会为该账户 / homeserver / 用户元组复用最合适的现有根目录,以便先前的同步状态、加密状态、线程绑定和启动验证状态仍然可见。
|
||||
|
||||
## 资料管理
|
||||
## 配置文件管理
|
||||
|
||||
使用以下命令更新所选账户的 Matrix 自身资料:
|
||||
使用以下命令为所选账户更新 Matrix 自身配置文件:
|
||||
|
||||
```bash
|
||||
openclaw matrix profile set --name "OpenClaw Assistant"
|
||||
openclaw matrix profile set --avatar-url https://cdn.example.org/avatar.png
|
||||
```
|
||||
|
||||
当你想显式指定某个命名 Matrix 账户时,请添加 `--account <id>`。
|
||||
如果你想显式指定某个命名 Matrix 账户,请添加 `--account <id>`。
|
||||
|
||||
Matrix 可直接接受 `mxc://` 头像 URL。当你传入 `http://` 或 `https://` 头像 URL 时,OpenClaw 会先将其上传到 Matrix,然后将解析后的 `mxc://` URL 回写到 `channels.matrix.avatarUrl`(或所选账户的覆盖项)中。
|
||||
Matrix 可直接接受 `mxc://` 头像 URL。当你传入 `http://` 或 `https://` 头像 URL 时,OpenClaw 会先将其上传到 Matrix,然后将解析后的 `mxc://` URL 回写到 `channels.matrix.avatarUrl`(或所选账户的覆盖配置)中。
|
||||
|
||||
## 线程
|
||||
|
||||
Matrix 同时支持自动回复和消息工具发送时使用原生 Matrix 线程。
|
||||
Matrix 同时支持自动回复和消息工具发送使用原生 Matrix 线程。
|
||||
|
||||
- `dm.sessionScope: "per-user"`(默认)会让 Matrix 私信路由保持按发送者划分作用域,因此多个私信房间在解析到同一对端时可以共享一个会话。
|
||||
- `dm.sessionScope: "per-room"` 会将每个 Matrix 私信房间隔离到各自独立的会话键中,同时仍使用普通私信认证和允许列表检查。
|
||||
- 显式的 Matrix 会话绑定仍优先于 `dm.sessionScope`,因此已绑定的房间和线程会继续保留其选定的目标会话。
|
||||
- `threadReplies: "off"` 会让回复保持在顶层,并将入站线程消息保留在父会话中。
|
||||
- `threadReplies: "inbound"` 仅当入站消息原本就在该线程中时,才会在线程内回复。
|
||||
- `threadReplies: "always"` 会让房间回复保持在线程中,以触发消息为根,并从第一次触发消息开始,通过匹配的线程作用域会话来路由该会话。
|
||||
- `dm.threadReplies` 仅覆盖私信的顶层设置。例如,你可以保持房间线程隔离,同时让私信保持扁平。
|
||||
- 入站线程消息会将线程根消息作为额外的智能体上下文包含进来。
|
||||
- 当目标是同一房间或同一私信用户目标时,消息工具发送会自动继承当前 Matrix 线程,除非显式提供了 `threadId`。
|
||||
- 仅当当前会话元数据能够证明是同一 Matrix 账户上的同一私信对端时,才会启用同会话私信用户目标复用;否则 OpenClaw 会回退到普通的按用户划分作用域的路由。
|
||||
- 当 OpenClaw 发现某个 Matrix 私信房间与同一个共享 Matrix 私信会话中的另一个私信房间发生冲突时,如果启用了线程绑定并存在 `dm.sessionScope` 提示,它会在该房间中发布一次性的 `m.notice`,其中包含 `/focus` 逃生口。
|
||||
- Matrix 支持运行时线程绑定。`/focus`、`/unfocus`、`/agents`、`/session idle`、`/session max-age` 和线程绑定的 `/acp spawn` 都可在 Matrix 房间和私信中使用。
|
||||
- 当 `threadBindings.spawnSubagentSessions=true` 时,顶层 Matrix 房间/私信中的 `/focus` 会创建一个新的 Matrix 线程,并将其绑定到目标会话。
|
||||
- 在现有 Matrix 线程中运行 `/focus` 或 `/acp spawn --thread here` 时,则会绑定当前线程本身。
|
||||
- `dm.sessionScope: "per-user"`(默认)会将 Matrix 私信路由保持为发送者作用域,因此多个私信房间在解析为同一对端时可以共享一个会话。
|
||||
- `dm.sessionScope: "per-room"` 会将每个 Matrix 私信房间隔离到各自的会话键中,同时仍使用普通私信认证和允许列表检查。
|
||||
- 显式的 Matrix 会话绑定仍然优先于 `dm.sessionScope`,因此已绑定的房间和线程会保留它们选择的目标会话。
|
||||
- `threadReplies: "off"` 会让回复保持在顶层,并将传入的线程消息保留在父会话上。
|
||||
- `threadReplies: "inbound"` 仅当传入消息本身已经在该线程中时,才在线程内回复。
|
||||
- `threadReplies: "always"` 会将房间回复保持在线程中,该线程以触发消息为根,并从第一条触发消息开始通过匹配的线程作用域会话路由该会话。
|
||||
- `dm.threadReplies` 仅对私信覆盖顶层设置。例如,你可以让房间线程保持隔离,同时让私信保持扁平。
|
||||
- 传入的线程消息会将线程根消息作为额外的智能体上下文一并包含。
|
||||
- 当目标是同一房间,或同一私信用户目标时,消息工具发送会自动继承当前 Matrix 线程,除非显式提供了 `threadId`。
|
||||
- 只有当当前会话元数据能够证明是在同一个 Matrix 账户下与同一个私信对端通信时,才会复用同会话的私信用户目标;否则 OpenClaw 会回退到普通的用户作用域路由。
|
||||
- 当 OpenClaw 发现某个 Matrix 私信房间与同一个共享 Matrix 私信会话中的另一个私信房间冲突时,如果启用了线程绑定并设置了 `dm.sessionScope` 提示,它会在该房间中发布一次性 `m.notice`,提示可使用 `/focus` 作为跳出方案。
|
||||
- Matrix 支持运行时线程绑定。`/focus`、`/unfocus`、`/agents`、`/session idle`、`/session max-age` 以及线程绑定的 `/acp spawn` 都可在 Matrix 房间和私信中使用。
|
||||
- 当 `threadBindings.spawnSubagentSessions=true` 时,在顶层 Matrix 房间 / 私信中执行 `/focus` 会创建一个新的 Matrix 线程,并将其绑定到目标会话。
|
||||
- 在现有 Matrix 线程中执行 `/focus` 或 `/acp spawn --thread here` 时,则会改为绑定当前线程本身。
|
||||
|
||||
## ACP 会话绑定
|
||||
|
||||
Matrix 房间、私信和现有 Matrix 线程都可以在不改变聊天界面的情况下转换为持久化 ACP 工作区。
|
||||
|
||||
快捷操作流程:
|
||||
快速操作流程:
|
||||
|
||||
- 在你希望继续使用的 Matrix 私信、房间或现有线程中运行 `/acp spawn codex --bind here`。
|
||||
- 在顶层 Matrix 私信或房间中,当前私信/房间会继续作为聊天界面,后续消息将路由到新创建的 ACP 会话。
|
||||
- 在现有 Matrix 线程中,`--bind here` 会将当前线程原地绑定。
|
||||
- `/new` 和 `/reset` 会原地重置同一个已绑定 ACP 会话。
|
||||
- 在顶层 Matrix 私信或房间中,当前私信 / 房间会继续作为聊天界面,后续消息会路由到新创建的 ACP 会话。
|
||||
- 在现有 Matrix 线程中,`--bind here` 会直接原位绑定当前线程。
|
||||
- `/new` 和 `/reset` 会原位重置同一个已绑定 ACP 会话。
|
||||
- `/acp close` 会关闭 ACP 会话并移除绑定。
|
||||
|
||||
说明:
|
||||
|
||||
- `--bind here` 不会创建子 Matrix 线程。
|
||||
- `threadBindings.spawnAcpSessions` 仅在使用 `/acp spawn --thread auto|here` 时需要启用,因为此时 OpenClaw 需要创建或绑定一个子 Matrix 线程。
|
||||
- `threadBindings.spawnAcpSessions` 只在 `/acp spawn --thread auto|here` 时需要,因为此时 OpenClaw 需要创建或绑定一个子 Matrix 线程。
|
||||
|
||||
### 线程绑定配置
|
||||
|
||||
Matrix 会继承来自 `session.threadBindings` 的全局默认值,同时也支持按渠道覆盖:
|
||||
Matrix 会继承 `session.threadBindings` 中的全局默认值,同时也支持按渠道覆盖:
|
||||
|
||||
- `threadBindings.enabled`
|
||||
- `threadBindings.idleHours`
|
||||
@ -713,27 +713,27 @@ Matrix 会继承来自 `session.threadBindings` 的全局默认值,同时也
|
||||
- `threadBindings.spawnSubagentSessions`
|
||||
- `threadBindings.spawnAcpSessions`
|
||||
|
||||
Matrix 线程绑定的 spawn 标志为选择启用:
|
||||
Matrix 的线程绑定 spawn 标志为可选启用:
|
||||
|
||||
- 设置 `threadBindings.spawnSubagentSessions: true`,以允许顶层 `/focus` 创建并绑定新的 Matrix 线程。
|
||||
- 设置 `threadBindings.spawnAcpSessions: true`,以允许 `/acp spawn --thread auto|here` 将 ACP 会话绑定到 Matrix 线程。
|
||||
|
||||
## 回应
|
||||
|
||||
Matrix 支持出站回应操作、入站回应通知以及入站 ack 回应。
|
||||
Matrix 支持出站回应操作、入站回应通知和入站 ack 回应。
|
||||
|
||||
- 出站回应工具受 `channels["matrix"].actions.reactions` 控制。
|
||||
- 出站回应工具由 `channels["matrix"].actions.reactions` 控制。
|
||||
- `react` 会向特定 Matrix 事件添加一个回应。
|
||||
- `reactions` 会列出特定 Matrix 事件当前的回应摘要。
|
||||
- `reactions` 会列出特定 Matrix 事件的当前回应汇总。
|
||||
- `emoji=""` 会移除机器人账户在该事件上的所有自身回应。
|
||||
- `remove: true` 仅移除机器人账户对该表情符号的回应。
|
||||
- `remove: true` 只会移除机器人账户上的指定 emoji 回应。
|
||||
|
||||
ack 回应使用标准 OpenClaw 解析顺序:
|
||||
|
||||
- `channels["matrix"].accounts.<accountId>.ackReaction`
|
||||
- `channels["matrix"].ackReaction`
|
||||
- `messages.ackReaction`
|
||||
- 智能体身份 emoji 回退
|
||||
- 智能体身份 emoji 回退值
|
||||
|
||||
ack 回应作用域按以下顺序解析:
|
||||
|
||||
@ -745,32 +745,32 @@ ack 回应作用域按以下顺序解析:
|
||||
|
||||
- `channels["matrix"].accounts.<accountId>.reactionNotifications`
|
||||
- `channels["matrix"].reactionNotifications`
|
||||
- 默认值:`own`
|
||||
- 默认:`own`
|
||||
|
||||
行为如下:
|
||||
行为:
|
||||
|
||||
- `reactionNotifications: "own"` 会在目标是机器人撰写的 Matrix 消息时,转发新增的 `m.reaction` 事件。
|
||||
- `reactionNotifications: "own"` 会在新增的 `m.reaction` 事件目标是机器人发送的 Matrix 消息时转发这些事件。
|
||||
- `reactionNotifications: "off"` 会禁用回应系统事件。
|
||||
- 回应移除不会被合成为系统事件,因为 Matrix 将其表现为删隐,而不是独立的 `m.reaction` 移除事件。
|
||||
- 回应移除不会被合成为系统事件,因为 Matrix 将它们表现为 redaction,而不是独立的 `m.reaction` 移除事件。
|
||||
|
||||
## 历史上下文
|
||||
|
||||
- `channels.matrix.historyLimit` 控制当 Matrix 房间消息触发智能体时,会有多少条最近的房间消息作为 `InboundHistory` 包含进来。若未设置,则回退到 `messages.groupChat.historyLimit`;如果两者都未设置,则有效默认值为 `0`。设置为 `0` 可禁用。
|
||||
- `channels.matrix.historyLimit` 控制当 Matrix 房间消息触发智能体时,作为 `InboundHistory` 包含多少条最近的房间消息。它会回退到 `messages.groupChat.historyLimit`;如果两者都未设置,则有效默认值为 `0`。设置为 `0` 可禁用。
|
||||
- Matrix 房间历史仅限房间。私信仍使用普通会话历史。
|
||||
- Matrix 房间历史为“仅待处理”模式:OpenClaw 会缓冲尚未触发回复的房间消息,然后在提及或其他触发条件到来时对该窗口拍摄快照。
|
||||
- 当前触发消息不会包含在 `InboundHistory` 中;它会在该轮的主入站正文中保留。
|
||||
- 对同一个 Matrix 事件的重试会复用原始历史快照,而不会漂移到更新的房间消息。
|
||||
- Matrix 房间历史是仅待处理的:OpenClaw 会缓冲那些尚未触发回复的房间消息,然后在提及或其他触发条件到来时对该窗口进行快照。
|
||||
- 当前触发消息不会包含在 `InboundHistory` 中;它会保留在该轮次的主入站消息体中。
|
||||
- 同一个 Matrix 事件的重试会复用原始历史快照,而不是漂移到更新的房间消息。
|
||||
|
||||
## 上下文可见性
|
||||
|
||||
Matrix 支持共享的 `contextVisibility` 控制,用于补充房间上下文,例如获取到的回复文本、线程根消息和待处理历史。
|
||||
|
||||
- `contextVisibility: "all"` 为默认值。补充上下文会按接收到的内容保留。
|
||||
- `contextVisibility: "allowlist"` 会将补充上下文过滤为仅保留通过当前房间/用户允许列表检查的发送者内容。
|
||||
- `contextVisibility: "allowlist_quote"` 的行为与 `allowlist` 相同,但仍会保留一条显式引用的回复。
|
||||
- `contextVisibility: "allowlist"` 会根据当前房间 / 用户允许列表检查,过滤补充上下文中的发送者。
|
||||
- `contextVisibility: "allowlist_quote"` 的行为与 `allowlist` 类似,但仍会保留一条显式引用回复。
|
||||
|
||||
此设置影响的是补充上下文的可见性,而不是入站消息本身是否可以触发回复。
|
||||
触发授权仍来自 `groupPolicy`、`groups`、`groupAllowFrom` 和私信策略设置。
|
||||
触发授权仍由 `groupPolicy`、`groups`、`groupAllowFrom` 和私信策略设置决定。
|
||||
|
||||
## 私信和房间策略
|
||||
|
||||
@ -795,7 +795,7 @@ Matrix 支持共享的 `contextVisibility` 控制,用于补充房间上下文
|
||||
}
|
||||
```
|
||||
|
||||
有关提及门控和允许列表行为,请参阅 [Groups](/zh-CN/channels/groups)。
|
||||
有关提及门控和允许列表行为,请参见 [Groups](/zh-CN/channels/groups)。
|
||||
|
||||
Matrix 私信的配对示例:
|
||||
|
||||
@ -804,13 +804,13 @@ openclaw pairing list matrix
|
||||
openclaw pairing approve matrix <CODE>
|
||||
```
|
||||
|
||||
如果某个尚未获批的 Matrix 用户在批准前持续向你发送消息,OpenClaw 会复用相同的待处理配对码,并且可能会在短暂冷却后再次发送提醒回复,而不是生成新的配对码。
|
||||
如果某个尚未批准的 Matrix 用户在获批前持续给你发消息,OpenClaw 会复用同一个待处理配对码,并可能在短暂冷却后再次发送提醒回复,而不是签发一个新代码。
|
||||
|
||||
有关共享的私信配对流程和存储布局,请参阅 [Pairing](/zh-CN/channels/pairing)。
|
||||
有关共享的私信配对流程和存储布局,请参见 [Pairing](/zh-CN/channels/pairing)。
|
||||
|
||||
## 直接房间修复
|
||||
|
||||
如果私信状态不同步,OpenClaw 可能会留下过期的 `m.direct` 映射,使其指向旧的单人房间,而不是当前有效的私信。可使用以下命令检查某个对端当前的映射:
|
||||
如果私信状态不同步,OpenClaw 可能会残留过期的 `m.direct` 映射,使其指向旧的一对一房间而不是当前活跃私信。使用以下命令检查某个对端的当前映射:
|
||||
|
||||
```bash
|
||||
openclaw matrix direct inspect --user-id @alice:example.org
|
||||
@ -825,27 +825,26 @@ openclaw matrix direct repair --user-id @alice:example.org
|
||||
修复流程会:
|
||||
|
||||
- 优先选择已经在 `m.direct` 中映射的严格 1:1 私信
|
||||
- 否则回退到与该用户当前已加入的任意严格 1:1 私信
|
||||
- 如果不存在健康的私信,则创建一个新的直接房间并重写 `m.direct`
|
||||
- 如果没有,则回退到与该用户当前已加入的任意严格 1:1 私信
|
||||
- 如果仍不存在健康的私信,则创建一个新的直连房间并重写 `m.direct`
|
||||
|
||||
修复流程不会自动删除旧房间。它只会选择健康的私信并更新映射,以便新的 Matrix 发送、验证通知和其他私信流程再次指向正确的房间。
|
||||
修复流程不会自动删除旧房间。它只会选择健康的私信并更新映射,使新的 Matrix 发送、验证通知和其他私信流程重新指向正确的房间。
|
||||
|
||||
## Exec 审批
|
||||
|
||||
Matrix 可以作为某个 Matrix 账户的原生审批客户端。原生
|
||||
私信/渠道路由控制项仍位于 exec 审批配置下:
|
||||
Matrix 可以作为某个 Matrix 账户的原生审批客户端。原生私信 / 渠道路由控制项仍位于 exec 审批配置下:
|
||||
|
||||
- `channels.matrix.execApprovals.enabled`
|
||||
- `channels.matrix.execApprovals.approvers`(可选;回退到 `channels.matrix.dm.allowFrom`)
|
||||
- `channels.matrix.execApprovals.target`(`dm` | `channel` | `both`,默认值:`dm`)
|
||||
- `channels.matrix.execApprovals.approvers`(可选;会回退到 `channels.matrix.dm.allowFrom`)
|
||||
- `channels.matrix.execApprovals.target`(`dm` | `channel` | `both`,默认:`dm`)
|
||||
- `channels.matrix.execApprovals.agentFilter`
|
||||
- `channels.matrix.execApprovals.sessionFilter`
|
||||
|
||||
审批人必须是 Matrix 用户 ID,例如 `@owner:example.org`。当 `enabled` 未设置或为 `"auto"`,并且至少能解析出一个审批人时,Matrix 会自动启用原生审批。Exec 审批优先使用 `execApprovals.approvers`,并可回退到 `channels.matrix.dm.allowFrom`。插件审批通过 `channels.matrix.dm.allowFrom` 进行授权。若要显式禁用 Matrix 作为原生审批客户端,请设置 `enabled: false`。否则,审批请求会回退到其他已配置的审批路由或审批回退策略。
|
||||
审批人必须是 Matrix 用户 ID,例如 `@owner:example.org`。当 `enabled` 未设置或为 `"auto"`,且至少能解析出一位审批人时,Matrix 会自动启用原生审批。Exec 审批会优先使用 `execApprovals.approvers`,并可回退到 `channels.matrix.dm.allowFrom`。插件审批则通过 `channels.matrix.dm.allowFrom` 进行授权。将 `enabled: false` 设为显式禁用 Matrix 作为原生审批客户端。否则,审批请求会回退到其他已配置的审批路径或审批回退策略。
|
||||
|
||||
Matrix 原生路由同时支持两种审批类型:
|
||||
Matrix 原生路由支持两种审批类型:
|
||||
|
||||
- `channels.matrix.execApprovals.*` 控制 Matrix 审批提示的原生私信/渠道扇出模式。
|
||||
- `channels.matrix.execApprovals.*` 控制 Matrix 审批提示的原生私信 / 渠道扇出模式。
|
||||
- Exec 审批使用来自 `execApprovals.approvers` 或 `channels.matrix.dm.allowFrom` 的 exec 审批人集合。
|
||||
- 插件审批使用来自 `channels.matrix.dm.allowFrom` 的 Matrix 私信允许列表。
|
||||
- Matrix 回应快捷方式和消息更新同时适用于 exec 审批和插件审批。
|
||||
@ -853,18 +852,18 @@ Matrix 原生路由同时支持两种审批类型:
|
||||
投递规则:
|
||||
|
||||
- `target: "dm"` 会将审批提示发送到审批人的私信
|
||||
- `target: "channel"` 会将提示回发到原始 Matrix 房间或私信
|
||||
- `target: "channel"` 会将提示发回原始 Matrix 房间或私信
|
||||
- `target: "both"` 会同时发送到审批人的私信以及原始 Matrix 房间或私信
|
||||
|
||||
Matrix 审批提示会在主审批消息上植入回应快捷方式:
|
||||
Matrix 审批提示会在主审批消息上添加回应快捷方式:
|
||||
|
||||
- `✅` = 允许一次
|
||||
- `❌` = 拒绝
|
||||
- `♾️` = 在有效 exec 策略允许该决定时,始终允许
|
||||
- `♾️` = 始终允许,前提是有效 exec 策略允许该决定
|
||||
|
||||
审批人可以对该消息添加回应,或使用回退斜杠命令:`/approve <id> allow-once`、`/approve <id> allow-always` 或 `/approve <id> deny`。
|
||||
审批人可以对该消息添加回应,也可以使用回退斜杠命令:`/approve <id> allow-once`、`/approve <id> allow-always` 或 `/approve <id> deny`。
|
||||
|
||||
只有已解析出的审批人才能执行批准或拒绝。对于 exec 审批,渠道投递会包含命令文本,因此只有在受信任房间中才应启用 `channel` 或 `both`。
|
||||
只有已解析出的审批人才能执行批准或拒绝。对于 exec 审批,渠道投递会包含命令文本,因此仅应在可信房间中启用 `channel` 或 `both`。
|
||||
|
||||
按账户覆盖:
|
||||
|
||||
@ -872,6 +871,12 @@ Matrix 审批提示会在主审批消息上植入回应快捷方式:
|
||||
|
||||
相关文档:[Exec approvals](/zh-CN/tools/exec-approvals)
|
||||
|
||||
## 斜杠命令
|
||||
|
||||
Matrix 斜杠命令(例如 `/new`、`/reset`、`/model`)可直接在私信中使用。在房间中,OpenClaw 也会识别以机器人自身 Matrix 提及为前缀的斜杠命令,因此 `@bot:server /new` 会触发命令路径,而不需要自定义提及正则。这使机器人能够响应 Element 及类似客户端发出的房间式 `@mention /command` 消息:用户先通过补全输入机器人,再输入命令即可。
|
||||
|
||||
授权规则仍然适用:命令发送者必须像普通消息一样满足私信或房间允许列表 / owner 策略。
|
||||
|
||||
## 多账户
|
||||
|
||||
```json5
|
||||
@ -903,22 +908,23 @@ Matrix 审批提示会在主审批消息上植入回应快捷方式:
|
||||
```
|
||||
|
||||
顶层 `channels.matrix` 值会作为命名账户的默认值,除非某个账户进行了覆盖。
|
||||
你可以使用 `groups.<room>.account` 将继承的房间条目限定到某一个 Matrix 账户。
|
||||
未设置 `account` 的条目会在所有 Matrix 账户之间共享,而设置了 `account: "default"` 的条目在默认账户直接配置于顶层 `channels.matrix.*` 时仍然有效。
|
||||
部分共享认证默认值本身不会单独创建一个隐式默认账户。只有当该默认账户具备新的认证信息(`homeserver` 加 `accessToken`,或 `homeserver` 加 `userId` 和 `password`)时,OpenClaw 才会合成顶层 `default` 账户;命名账户仍然可以仅凭 `homeserver` 加 `userId` 保持可发现状态,并在之后缓存凭证满足认证时生效。
|
||||
如果 Matrix 已经恰好有一个命名账户,或者 `defaultAccount` 指向一个现有命名账户键,则单账户到多账户的修复/设置升级会保留该账户,而不是创建一个新的 `accounts.default` 条目。只有 Matrix 认证/bootstrap 键会迁移到该升级后的账户中;共享投递策略键会保留在顶层。
|
||||
你可以通过 `groups.<room>.account` 将继承的房间条目限定到某一个 Matrix 账户。
|
||||
未设置 `account` 的条目会在所有 Matrix 账户之间共享,而设置了 `account: "default"` 的条目在默认账户直接配置于顶层 `channels.matrix.*` 时也仍然有效。
|
||||
部分共享认证默认值本身不会创建一个单独的隐式默认账户。只有当该默认账户拥有新的认证信息(`homeserver` 加 `accessToken`,或 `homeserver` 加 `userId` 和 `password`)时,OpenClaw 才会合成顶层 `default` 账户;命名账户仍可在稍后通过缓存凭证满足认证时,仅凭 `homeserver` 加 `userId` 保持可发现。
|
||||
如果 Matrix 已经恰好有一个命名账户,或者 `defaultAccount` 指向一个现有命名账户键,则从单账户到多账户的修复 / 设置提升会保留该账户,而不是新建一个 `accounts.default` 条目。只有 Matrix 的认证 / bootstrap 键会移入被提升的账户;共享的投递策略键会保留在顶层。
|
||||
当你希望 OpenClaw 在隐式路由、探测和 CLI 操作中优先使用某个命名 Matrix 账户时,请设置 `defaultAccount`。
|
||||
如果配置了多个 Matrix 账户,并且其中一个账户 ID 是 `default`,那么即使未设置 `defaultAccount`,OpenClaw 也会隐式使用该账户。
|
||||
如果你配置了多个命名账户,请设置 `defaultAccount`,或为依赖隐式账户选择的 CLI 命令传入 `--account <id>`。
|
||||
当你希望仅对某一条命令覆盖该隐式选择时,请为 `openclaw matrix verify ...` 和 `openclaw matrix devices ...` 传入 `--account <id>`。
|
||||
如果配置了多个 Matrix 账户,且其中一个账户 ID 是 `default`,即使 `defaultAccount` 未设置,OpenClaw 也会隐式使用该账户。
|
||||
如果你配置了多个命名账户,请设置 `defaultAccount`,或在依赖隐式账户选择的 CLI 命令中传入 `--account <id>`。
|
||||
当你希望为某一条命令覆盖该隐式选择时,请向 `openclaw matrix verify ...` 和 `openclaw matrix devices ...` 传入 `--account <id>`。
|
||||
|
||||
有关共享的多账户模式,请参阅 [Configuration reference](/zh-CN/gateway/configuration-reference#multi-account-all-channels)。
|
||||
共享多账户模式请参见 [Configuration reference](/zh-CN/gateway/configuration-reference#multi-account-all-channels)。
|
||||
|
||||
## 私有/LAN homeserver
|
||||
## 私有 / LAN homeserver
|
||||
|
||||
默认情况下,出于 SSRF 防护,OpenClaw 会阻止连接私有/内部 Matrix homeserver,除非你为每个账户显式选择启用。
|
||||
默认情况下,出于 SSRF 防护,OpenClaw 会阻止连接私有 / 内部 Matrix homeserver,除非你为某个账户显式选择加入。
|
||||
|
||||
如果你的 homeserver 运行在 localhost、LAN/Tailscale IP 或内部主机名上,请为该 Matrix 账户启用 `network.dangerouslyAllowPrivateNetwork`:
|
||||
如果你的 homeserver 运行在 localhost、LAN/Tailscale IP 或内部主机名上,请为该 Matrix 账户启用
|
||||
`network.dangerouslyAllowPrivateNetwork`:
|
||||
|
||||
```json5
|
||||
{
|
||||
@ -944,8 +950,8 @@ openclaw matrix account add \
|
||||
--access-token syt_ops_xxx
|
||||
```
|
||||
|
||||
此选择启用仅允许受信任的私有/内部目标。诸如
|
||||
`http://matrix.example.org:8008` 这样的公共明文 homeserver 仍会被阻止。请尽可能优先使用 `https://`。
|
||||
此选择加入仅允许受信任的私有 / 内部目标。公共明文 homeserver,例如
|
||||
`http://matrix.example.org:8008`,仍会被阻止。尽可能优先使用 `https://`。
|
||||
|
||||
## 代理 Matrix 流量
|
||||
|
||||
@ -963,86 +969,86 @@ openclaw matrix account add \
|
||||
}
|
||||
```
|
||||
|
||||
命名账户可以使用 `channels.matrix.accounts.<id>.proxy` 覆盖顶层默认值。
|
||||
命名账户可以通过 `channels.matrix.accounts.<id>.proxy` 覆盖顶层默认值。
|
||||
OpenClaw 会对运行时 Matrix 流量和账户状态探测使用相同的代理设置。
|
||||
|
||||
## 目标解析
|
||||
|
||||
在 OpenClaw 要求你提供房间或用户目标的任何位置,Matrix 都接受以下目标形式:
|
||||
在 OpenClaw 任何要求你提供房间或用户目标的地方,Matrix 都接受以下目标格式:
|
||||
|
||||
- 用户:`@user:server`、`user:@user:server` 或 `matrix:user:@user:server`
|
||||
- 房间:`!room:server`、`room:!room:server` 或 `matrix:room:!room:server`
|
||||
- 别名:`#alias:server`、`channel:#alias:server` 或 `matrix:channel:#alias:server`
|
||||
|
||||
实时目录查找会使用已登录的 Matrix 账户:
|
||||
实时目录查找使用已登录的 Matrix 账户:
|
||||
|
||||
- 用户查找会查询该 homeserver 上的 Matrix 用户目录。
|
||||
- 房间查找会直接接受显式房间 ID 和别名,然后回退为搜索该账户已加入的房间名称。
|
||||
- 已加入房间名称查找是尽力而为的。如果某个房间名称无法解析为 ID 或别名,它会在运行时允许列表解析中被忽略。
|
||||
- 房间查找会直接接受显式房间 ID 和别名,然后回退到搜索该账户已加入房间的名称。
|
||||
- 已加入房间名称查找属于尽力而为。如果某个房间名称无法解析为 ID 或别名,它会在运行时允许列表解析中被忽略。
|
||||
|
||||
## 配置参考
|
||||
|
||||
- `enabled`:启用或禁用该渠道。
|
||||
- `name`:账户的可选标签。
|
||||
- `defaultAccount`:配置了多个 Matrix 账户时的首选账户 ID。
|
||||
- `defaultAccount`:当配置多个 Matrix 账户时的首选账户 ID。
|
||||
- `homeserver`:homeserver URL,例如 `https://matrix.example.org`。
|
||||
- `network.dangerouslyAllowPrivateNetwork`:允许该 Matrix 账户连接到私有/内部 homeserver。当 homeserver 解析为 `localhost`、LAN/Tailscale IP 或诸如 `matrix-synapse` 的内部主机时,请启用此项。
|
||||
- `proxy`:Matrix 流量的可选 HTTP(S) 代理 URL。命名账户可以用自己的 `proxy` 覆盖顶层默认值。
|
||||
- `network.dangerouslyAllowPrivateNetwork`:允许该 Matrix 账户连接到私有 / 内部 homeserver。当 homeserver 解析到 `localhost`、LAN/Tailscale IP 或内部主机(如 `matrix-synapse`)时启用此项。
|
||||
- `proxy`:Matrix 流量的可选 HTTP(S) 代理 URL。命名账户可用其自己的 `proxy` 覆盖顶层默认值。
|
||||
- `userId`:完整 Matrix 用户 ID,例如 `@bot:example.org`。
|
||||
- `accessToken`:基于令牌认证的访问令牌。`channels.matrix.accessToken` 和 `channels.matrix.accounts.<id>.accessToken` 支持明文值和 SecretRef 值,适用于 env/file/exec 提供商。请参阅 [Secrets Management](/zh-CN/gateway/secrets)。
|
||||
- `password`:基于密码登录的密码。支持明文值和 SecretRef 值。
|
||||
- `accessToken`:基于 token 的认证所用 access token。`channels.matrix.accessToken` 和 `channels.matrix.accounts.<id>.accessToken` 支持明文值和 SecretRef 值,适用于 env/file/exec 提供商。参见 [Secrets Management](/zh-CN/gateway/secrets)。
|
||||
- `password`:基于密码登录所用密码。支持明文值和 SecretRef 值。
|
||||
- `deviceId`:显式 Matrix 设备 ID。
|
||||
- `deviceName`:密码登录使用的设备显示名称。
|
||||
- `avatarUrl`:用于资料同步和 `profile set` 更新的已存储自身头像 URL。
|
||||
- `initialSyncLimit`:启动同步期间获取的最大事件数。
|
||||
- `deviceName`:用于密码登录的设备显示名称。
|
||||
- `avatarUrl`:用于配置文件同步和 `profile set` 更新的已存储自身头像 URL。
|
||||
- `initialSyncLimit`:启动同步期间抓取的最大事件数。
|
||||
- `encryption`:启用 E2EE。
|
||||
- `allowlistOnly`:当为 `true` 时,会将 `open` 房间策略升级为 `allowlist`,并强制所有活动私信策略(除了 `disabled`,包括 `pairing` 和 `open`)变为 `allowlist`。不会影响 `disabled` 策略。
|
||||
- `allowlistOnly`:当为 `true` 时,会将 `open` 房间策略升级为 `allowlist`,并强制所有活动私信策略(除 `disabled` 外,包括 `pairing` 和 `open`)变为 `allowlist`。不影响 `disabled` 策略。
|
||||
- `allowBots`:允许来自其他已配置 OpenClaw Matrix 账户的消息(`true` 或 `"mentions"`)。
|
||||
- `groupPolicy`:`open`、`allowlist` 或 `disabled`。
|
||||
- `contextVisibility`:补充房间上下文的可见性模式(`all`、`allowlist`、`allowlist_quote`)。
|
||||
- `groupAllowFrom`:房间流量的允许列表用户 ID。完整 Matrix 用户 ID 最安全;精确目录匹配会在启动时以及监视器运行期间允许列表变更时解析。未解析的名称会被忽略。
|
||||
- `historyLimit`:作为群组历史上下文包含的最大房间消息数。回退到 `messages.groupChat.historyLimit`;如果两者都未设置,则有效默认值为 `0`。设置为 `0` 可禁用。
|
||||
- `contextVisibility`:补充房间上下文可见性模式(`all`、`allowlist`、`allowlist_quote`)。
|
||||
- `groupAllowFrom`:用于房间流量的允许列表用户 ID。完整 Matrix 用户 ID 最安全;当监视器运行时,在启动时以及允许列表变化时会解析精确目录匹配。未解析的名称会被忽略。
|
||||
- `historyLimit`:作为群组历史上下文包含的最大房间消息数。会回退到 `messages.groupChat.historyLimit`;如果两者都未设置,则有效默认值为 `0`。设置为 `0` 可禁用。
|
||||
- `replyToMode`:`off`、`first`、`all` 或 `batched`。
|
||||
- `markdown`:出站 Matrix 文本的可选 Markdown 渲染配置。
|
||||
- `streaming`:`off`(默认)、`"partial"`、`"quiet"`、`true` 或 `false`。`"partial"` 和 `true` 会启用“先预览后完成”的草稿更新,使用普通 Matrix 文本消息。`"quiet"` 为自托管推送规则设置使用不通知的预览通知。`false` 等同于 `"off"`。
|
||||
- `blockStreaming`:当草稿预览流式传输处于活动状态时,`true` 会为已完成的智能体块启用单独的进度消息。
|
||||
- `markdown`:用于出站 Matrix 文本的可选 Markdown 渲染配置。
|
||||
- `streaming`:`off`(默认)、`"partial"`、`"quiet"`、`true` 或 `false`。`"partial"` 和 `true` 会使用普通 Matrix 文本消息启用“预览优先”的草稿更新。`"quiet"` 会为自托管 push 规则设置使用静默预览通知。`false` 等同于 `"off"`。
|
||||
- `blockStreaming`:`true` 会在草稿预览流式传输处于活动状态时,为已完成的助手块启用单独的进度消息。
|
||||
- `threadReplies`:`off`、`inbound` 或 `always`。
|
||||
- `threadBindings`:线程绑定会话路由和生命周期的按渠道覆盖。
|
||||
- `startupVerification`:启动时自动自验证请求模式(`if-unverified`、`off`)。
|
||||
- `startupVerificationCooldownHours`:自动启动验证请求重试前的冷却时间。
|
||||
- `textChunkLimit`:按字符数分块时的出站消息分块大小(当 `chunkMode` 为 `length` 时适用)。
|
||||
- `threadBindings`:用于线程绑定会话路由和生命周期的按渠道覆盖。
|
||||
- `startupVerification`:启动时的自动自我验证请求模式(`if-unverified`、`off`)。
|
||||
- `startupVerificationCooldownHours`:重试自动启动验证请求前的冷却时间。
|
||||
- `textChunkLimit`:出站消息按字符数分块时的字符块大小(当 `chunkMode` 为 `length` 时生效)。
|
||||
- `chunkMode`:`length` 按字符数拆分消息;`newline` 按行边界拆分。
|
||||
- `responsePrefix`:为该渠道所有出站回复添加的可选前缀字符串。
|
||||
- `ackReaction`:该渠道/账户的可选 ack 回应覆盖。
|
||||
- `responsePrefix`:可选字符串,会添加到该渠道的所有出站回复前。
|
||||
- `ackReaction`:该渠道 / 账户的可选 ack 回应覆盖值。
|
||||
- `ackReactionScope`:可选 ack 回应作用域覆盖(`group-mentions`、`group-all`、`direct`、`all`、`none`、`off`)。
|
||||
- `reactionNotifications`:入站回应通知模式(`own`、`off`)。
|
||||
- `mediaMaxMb`:出站发送和入站媒体处理的媒体大小上限(MB)。
|
||||
- `autoJoin`:邀请自动加入策略(`always`、`allowlist`、`off`)。默认值:`off`。适用于所有 Matrix 邀请,包括私信式邀请。
|
||||
- `autoJoinAllowlist`:当 `autoJoin` 为 `allowlist` 时允许的房间/别名。别名条目会在处理邀请时解析为房间 ID;OpenClaw 不信任受邀房间声明的别名状态。
|
||||
- `autoJoin`:邀请自动加入策略(`always`、`allowlist`、`off`)。默认:`off`。适用于所有 Matrix 邀请,包括私信式邀请。
|
||||
- `autoJoinAllowlist`:当 `autoJoin` 为 `allowlist` 时允许的房间 / 别名。别名条目会在处理邀请时解析为房间 ID;OpenClaw 不会信任受邀房间声称的别名状态。
|
||||
- `dm`:私信策略块(`enabled`、`policy`、`allowFrom`、`sessionScope`、`threadReplies`)。
|
||||
- `dm.policy`:控制 OpenClaw 加入房间并将其分类为私信后,私信访问如何处理。它不会改变邀请是否自动加入。
|
||||
- `dm.allowFrom`:私信流量的允许列表用户 ID。完整 Matrix 用户 ID 最安全;精确目录匹配会在启动时以及监视器运行期间允许列表变更时解析。未解析的名称会被忽略。
|
||||
- `dm.sessionScope`:`per-user`(默认)或 `per-room`。当你希望即使对端相同,每个 Matrix 私信房间仍保持独立上下文时,请使用 `per-room`。
|
||||
- `dm.threadReplies`:仅私信的线程策略覆盖(`off`、`inbound`、`always`)。它会同时覆盖私信中的回复放置和会话隔离的顶层 `threadReplies` 设置。
|
||||
- `dm.policy`:控制 OpenClaw 加入房间并将其分类为私信之后的私信访问策略。它不会改变邀请是否会被自动加入。
|
||||
- `dm.allowFrom`:用于私信流量的允许列表用户 ID。完整 Matrix 用户 ID 最安全;当监视器运行时,在启动时以及允许列表变化时会解析精确目录匹配。未解析的名称会被忽略。
|
||||
- `dm.sessionScope`:`per-user`(默认)或 `per-room`。如果你希望即使对端相同,每个 Matrix 私信房间也保持独立上下文,请使用 `per-room`。
|
||||
- `dm.threadReplies`:仅私信的线程策略覆盖(`off`、`inbound`、`always`)。它会覆盖顶层 `threadReplies` 设置,影响私信中的回复位置和会话隔离。
|
||||
- `execApprovals`:Matrix 原生 exec 审批投递(`enabled`、`approvers`、`target`、`agentFilter`、`sessionFilter`)。
|
||||
- `execApprovals.approvers`:允许批准 exec 请求的 Matrix 用户 ID。当 `dm.allowFrom` 已经标识出审批人时,此项可选。
|
||||
- `execApprovals.target`:`dm | channel | both`(默认值:`dm`)。
|
||||
- `accounts`:按名称划分的每账户覆盖。顶层 `channels.matrix` 值会作为这些条目的默认值。
|
||||
- `groups`:按房间划分的策略映射。优先使用房间 ID 或别名;未解析的房间名称会在运行时被忽略。解析后,会话/群组身份使用稳定的房间 ID。
|
||||
- `groups.<room>.account`:在多账户设置中,将某一个继承的房间条目限制到特定 Matrix 账户。
|
||||
- `execApprovals.approvers`:允许审批 exec 请求的 Matrix 用户 ID。如果 `dm.allowFrom` 已经标识了审批人,则此项可选。
|
||||
- `execApprovals.target`:`dm | channel | both`(默认:`dm`)。
|
||||
- `accounts`:按账户命名的覆盖项。顶层 `channels.matrix` 值会作为这些条目的默认值。
|
||||
- `groups`:按房间的策略映射。优先使用房间 ID 或别名;未解析的房间名称会在运行时被忽略。会话 / 群组身份在解析后使用稳定的房间 ID。
|
||||
- `groups.<room>.account`:在多账户设置中,将某个继承的房间条目限制到特定 Matrix 账户。
|
||||
- `groups.<room>.allowBots`:针对已配置机器人发送者的房间级覆盖(`true` 或 `"mentions"`)。
|
||||
- `groups.<room>.users`:按房间划分的发送者允许列表。
|
||||
- `groups.<room>.tools`:按房间划分的工具允许/拒绝覆盖。
|
||||
- `groups.<room>.autoReply`:房间级提及门控覆盖。`true` 会禁用该房间的提及要求;`false` 会强制重新启用。
|
||||
- `groups.<room>.skills`:可选的房间级技能过滤器。
|
||||
- `groups.<room>.users`:按房间的发送者允许列表。
|
||||
- `groups.<room>.tools`:按房间的工具允许 / 拒绝覆盖。
|
||||
- `groups.<room>.autoReply`:房间级提及门控覆盖。`true` 会为该房间禁用提及要求;`false` 会强制重新启用。
|
||||
- `groups.<room>.skills`:可选的房间级 Skills 过滤器。
|
||||
- `groups.<room>.systemPrompt`:可选的房间级系统提示片段。
|
||||
- `rooms`:`groups` 的旧别名。
|
||||
- `actions`:按操作划分的工具门控(`messages`、`reactions`、`pins`、`profile`、`memberInfo`、`channelInfo`、`verification`)。
|
||||
- `actions`:按操作的工具门控(`messages`、`reactions`、`pins`、`profile`、`memberInfo`、`channelInfo`、`verification`)。
|
||||
|
||||
## 相关内容
|
||||
## 相关
|
||||
|
||||
- [Channels Overview](/zh-CN/channels) — 所有受支持的渠道
|
||||
- [Pairing](/zh-CN/channels/pairing) — 私信认证和配对流程
|
||||
- [Groups](/zh-CN/channels/groups) — 群聊行为和提及门控
|
||||
- [Channel Routing](/zh-CN/channels/channel-routing) — 消息的会话路由
|
||||
- [Security](/zh-CN/gateway/security) — 访问模型和加固
|
||||
- [Security](/zh-CN/gateway/security) — 访问模型和安全加固
|
||||
|
||||
@ -5,27 +5,28 @@ read_when:
|
||||
summary: Mattermost 机器人设置和 OpenClaw 配置
|
||||
title: Mattermost
|
||||
x-i18n:
|
||||
generated_at: "2026-04-05T08:16:22Z"
|
||||
generated_at: "2026-04-21T20:11:32Z"
|
||||
model: gpt-5.4
|
||||
provider: openai
|
||||
source_hash: f21dc7543176fda0b38b00fab60f0daae38dffcf68fa1cf7930a9f14ec57cb5a
|
||||
source_hash: 76a182ad26199f435de64edc27c888672964b711a7346f3ca539fba666695222
|
||||
source_path: channels/mattermost.md
|
||||
workflow: 15
|
||||
---
|
||||
|
||||
# Mattermost
|
||||
|
||||
状态:内置插件(bot token + WebSocket 事件)。支持频道、群组和私信。
|
||||
Mattermost 是一个可自行托管的团队消息平台;产品详情和下载请参见官网
|
||||
状态:内置插件(机器人令牌 + WebSocket 事件)。支持渠道、群组和私信。
|
||||
Mattermost 是一个可自托管的团队消息平台;产品详情和下载请参见官方网站
|
||||
[mattermost.com](https://mattermost.com)。
|
||||
|
||||
## 内置插件
|
||||
|
||||
Mattermost 在当前 OpenClaw 版本中作为内置插件提供,因此普通的打包构建不需要单独安装。
|
||||
Mattermost 在当前的 OpenClaw 版本中作为内置插件提供,因此普通的打包构建不需要单独安装。
|
||||
|
||||
如果你使用的是较旧版本或排除了 Mattermost 的自定义安装,请手动安装:
|
||||
如果你使用的是较旧版本,或者使用了不包含 Mattermost 的自定义安装,
|
||||
请手动安装:
|
||||
|
||||
通过 CLI 安装(npm registry):
|
||||
通过 CLI 安装(npm 注册表):
|
||||
|
||||
```bash
|
||||
openclaw plugins install @openclaw/mattermost
|
||||
@ -37,16 +38,16 @@ openclaw plugins install @openclaw/mattermost
|
||||
openclaw plugins install ./path/to/local/mattermost-plugin
|
||||
```
|
||||
|
||||
详情参见:[插件](/tools/plugin)
|
||||
详情: [Plugins](/zh-CN/tools/plugin)
|
||||
|
||||
## 快速设置
|
||||
|
||||
1. 确保 Mattermost 插件可用。
|
||||
- 当前打包的 OpenClaw 版本已内置该插件。
|
||||
- 较旧/自定义安装可使用上述命令手动添加。
|
||||
2. 创建一个 Mattermost 机器人账号,并复制 **bot token**。
|
||||
3. 复制 Mattermost 的 **base URL**(例如 `https://chat.example.com`)。
|
||||
4. 配置 OpenClaw 并启动 gateway。
|
||||
- 当前打包发布的 OpenClaw 版本已内置该插件。
|
||||
- 较旧版本/自定义安装可使用上面的命令手动添加。
|
||||
2. 创建一个 Mattermost 机器人账户并复制 **bot token**。
|
||||
3. 复制 Mattermost **base URL**(例如 `https://chat.example.com`)。
|
||||
4. 配置 OpenClaw 并启动 Gateway 网关。
|
||||
|
||||
最小配置:
|
||||
|
||||
@ -65,7 +66,8 @@ openclaw plugins install ./path/to/local/mattermost-plugin
|
||||
|
||||
## 原生斜杠命令
|
||||
|
||||
原生斜杠命令为可选启用。启用后,OpenClaw 会通过 Mattermost API 注册 `oc_*` 斜杠命令,并在 gateway HTTP 服务器上接收回调 POST 请求。
|
||||
原生斜杠命令为可选启用。启用后,OpenClaw 会通过
|
||||
Mattermost API 注册 `oc_*` 斜杠命令,并在 Gateway 网关 HTTP 服务器上接收回调 POST 请求。
|
||||
|
||||
```json5
|
||||
{
|
||||
@ -75,7 +77,7 @@ openclaw plugins install ./path/to/local/mattermost-plugin
|
||||
native: true,
|
||||
nativeSkills: true,
|
||||
callbackPath: "/api/channels/mattermost/command",
|
||||
// 当 Mattermost 无法直接访问 gateway 时使用(反向代理/公网 URL)。
|
||||
// 当 Mattermost 无法直接访问 Gateway 网关时使用(反向代理/公共 URL)。
|
||||
callbackUrl: "https://gateway.example.com/api/channels/mattermost/command",
|
||||
},
|
||||
},
|
||||
@ -85,39 +87,41 @@ openclaw plugins install ./path/to/local/mattermost-plugin
|
||||
|
||||
说明:
|
||||
|
||||
- `native: "auto"` 在 Mattermost 中默认是禁用的。设置 `native: true` 可启用。
|
||||
- 如果省略 `callbackUrl`,OpenClaw 会根据 gateway host/port 和 `callbackPath` 推导一个地址。
|
||||
- 对于多账号设置,`commands` 可设置在顶层,也可设置在
|
||||
`channels.mattermost.accounts.<id>.commands` 下(账号值会覆盖顶层字段)。
|
||||
- 命令回调会使用 Mattermost 在 OpenClaw 注册 `oc_*` 命令时返回的逐命令 token 进行验证。
|
||||
- 如果注册失败、启动不完整,或回调 token 与任一已注册命令都不匹配,斜杠回调会以失败即关闭方式处理。
|
||||
- 可达性要求:Mattermost 服务器必须能够访问回调端点。
|
||||
- 除非 Mattermost 与 OpenClaw 运行在同一主机/网络命名空间,否则不要把 `callbackUrl` 设为 `localhost`。
|
||||
- 除非该 URL 会将 `/api/channels/mattermost/command` 反向代理到 OpenClaw,否则不要把 `callbackUrl` 设为你的 Mattermost base URL。
|
||||
- 一个快速检查方法是运行 `curl https://<gateway-host>/api/channels/mattermost/command`;GET 应返回来自 OpenClaw 的 `405 Method Not Allowed`,而不是 `404`。
|
||||
- Mattermost 出站 allowlist 要求:
|
||||
- 如果你的回调目标使用私有/tailnet/内部地址,请将回调 host/domain 加入 Mattermost 的
|
||||
`ServiceSettings.AllowedUntrustedInternalConnections`。
|
||||
- 使用 host/domain 条目,而不是完整 URL。
|
||||
- `native: "auto"` 在 Mattermost 中默认禁用。设置 `native: true` 以启用。
|
||||
- 如果省略 `callbackUrl`,OpenClaw 会根据 Gateway 网关主机/端口 + `callbackPath` 自动推导。
|
||||
- 对于多账户设置,`commands` 可以设置在顶层,也可以设置在
|
||||
`channels.mattermost.accounts.<id>.commands` 下(账户级值会覆盖顶层字段)。
|
||||
- 命令回调会使用 OpenClaw 注册 `oc_*` 命令时
|
||||
Mattermost 返回的每个命令专属令牌进行校验。
|
||||
- 当注册失败、启动不完整,或
|
||||
回调令牌与任何已注册命令都不匹配时,斜杠命令回调会以失败关闭的方式处理。
|
||||
- 可达性要求:回调端点必须可从 Mattermost 服务器访问。
|
||||
- 除非 Mattermost 与 OpenClaw 运行在同一主机/网络命名空间中,否则不要将 `callbackUrl` 设置为 `localhost`。
|
||||
- 除非该 URL 已将 `/api/channels/mattermost/command` 反向代理到 OpenClaw,否则不要将 `callbackUrl` 设置为你的 Mattermost base URL。
|
||||
- 一个快速检查方法是执行 `curl https://<gateway-host>/api/channels/mattermost/command`;GET 请求应从 OpenClaw 返回 `405 Method Not Allowed`,而不是 `404`。
|
||||
- Mattermost 出站允许列表要求:
|
||||
- 如果你的回调目标是私有/tailnet/内部地址,请设置 Mattermost
|
||||
`ServiceSettings.AllowedUntrustedInternalConnections` 以包含回调主机/域名。
|
||||
- 请使用主机/域名条目,而不是完整 URL。
|
||||
- 正确:`gateway.tailnet-name.ts.net`
|
||||
- 错误:`https://gateway.tailnet-name.ts.net`
|
||||
|
||||
## 环境变量(默认账号)
|
||||
## 环境变量(默认账户)
|
||||
|
||||
如果你更喜欢使用环境变量,请在 gateway 主机上设置以下变量:
|
||||
如果你更喜欢使用环境变量,请在 Gateway 网关主机上设置这些值:
|
||||
|
||||
- `MATTERMOST_BOT_TOKEN=...`
|
||||
- `MATTERMOST_URL=https://chat.example.com`
|
||||
|
||||
环境变量仅适用于**默认**账号(`default`)。其他账号必须使用配置值。
|
||||
环境变量仅适用于**默认**账户(`default`)。其他账户必须使用配置值。
|
||||
|
||||
## 聊天模式
|
||||
|
||||
Mattermost 会自动回复私信。频道行为由 `chatmode` 控制:
|
||||
Mattermost 会自动响应私信。渠道行为由 `chatmode` 控制:
|
||||
|
||||
- `oncall`(默认):仅在频道中被 @ 提及时回复。
|
||||
- `onmessage`:回复每一条频道消息。
|
||||
- `onchar`:当消息以触发前缀开头时回复。
|
||||
- `oncall`(默认):仅在渠道中被 @提及时响应。
|
||||
- `onmessage`:响应每条渠道消息。
|
||||
- `onchar`:当消息以前缀触发符开头时响应。
|
||||
|
||||
配置示例:
|
||||
|
||||
@ -134,17 +138,19 @@ Mattermost 会自动回复私信。频道行为由 `chatmode` 控制:
|
||||
|
||||
说明:
|
||||
|
||||
- `onchar` 仍会对显式 @ 提及进行回复。
|
||||
- 对于旧配置,`channels.mattermost.requireMention` 仍会生效,但更推荐使用 `chatmode`。
|
||||
- `onchar` 仍会响应显式的 @提及。
|
||||
- `channels.mattermost.requireMention` 会兼容旧配置,但更推荐使用 `chatmode`。
|
||||
|
||||
## 线程与会话
|
||||
## 线程和会话
|
||||
|
||||
使用 `channels.mattermost.replyToMode` 控制频道和群组回复是保留在主频道中,还是在触发消息下方开启一个线程。
|
||||
使用 `channels.mattermost.replyToMode` 控制渠道和群组回复是保留在主渠道中,
|
||||
还是在触发消息下开启线程。
|
||||
|
||||
- `off`(默认):只有当入站消息本身已在线程中时,才在线程中回复。
|
||||
- `first`:对于频道/群组中的顶层消息,在该消息下开启线程,并将对话路由到线程作用域的会话。
|
||||
- `all`:对于当前 Mattermost,与 `first` 的行为相同。
|
||||
- 私信会忽略此设置,并保持非线程化。
|
||||
- `off`(默认):仅当传入消息本身已在线程中时,才在线程中回复。
|
||||
- `first`:对于渠道/群组中的顶级消息,在该消息下启动线程,并将
|
||||
对话路由到线程作用域的会话。
|
||||
- `all`:在当前 Mattermost 中,行为与 `first` 相同。
|
||||
- 私信会忽略此设置,并保持为非线程形式。
|
||||
|
||||
配置示例:
|
||||
|
||||
@ -160,26 +166,27 @@ Mattermost 会自动回复私信。频道行为由 `chatmode` 控制:
|
||||
|
||||
说明:
|
||||
|
||||
- 线程作用域的会话会使用触发消息的 post id 作为线程根。
|
||||
- `first` 和 `all` 当前是等价的,因为一旦 Mattermost 有了线程根,后续的分块和媒体都会继续进入同一个线程。
|
||||
- 线程作用域会话使用触发消息的 post id 作为线程根。
|
||||
- `first` 和 `all` 当前等价,因为一旦 Mattermost 已有线程根,
|
||||
后续分块和媒体都会继续发送到同一线程中。
|
||||
|
||||
## 访问控制(私信)
|
||||
|
||||
- 默认:`channels.mattermost.dmPolicy = "pairing"`(未知发送者会收到配对码)。
|
||||
- 批准方式:
|
||||
- 默认:`channels.mattermost.dmPolicy = "pairing"`(未知发送者会收到一个配对码)。
|
||||
- 通过以下命令批准:
|
||||
- `openclaw pairing list mattermost`
|
||||
- `openclaw pairing approve mattermost <CODE>`
|
||||
- 公开私信:`channels.mattermost.dmPolicy="open"` 加 `channels.mattermost.allowFrom=["*"]`。
|
||||
- 公开私信:`channels.mattermost.dmPolicy="open"` 加上 `channels.mattermost.allowFrom=["*"]`。
|
||||
|
||||
## 频道(群组)
|
||||
## 渠道(群组)
|
||||
|
||||
- 默认:`channels.mattermost.groupPolicy = "allowlist"`(提及门控)。
|
||||
- 使用 `channels.mattermost.groupAllowFrom` 对发送者加入 allowlist(推荐使用用户 ID)。
|
||||
- 按频道的提及覆盖位于 `channels.mattermost.groups.<channelId>.requireMention`
|
||||
或 `channels.mattermost.groups["*"].requireMention`(用作默认值)。
|
||||
- `@username` 匹配是可变的,且仅在 `channels.mattermost.dangerouslyAllowNameMatching: true` 时启用。
|
||||
- 开放频道:`channels.mattermost.groupPolicy="open"`(提及门控)。
|
||||
- 运行时说明:如果 `channels.mattermost` 完全缺失,运行时在进行群组检查时会回退到 `groupPolicy="allowlist"`(即使设置了 `channels.defaults.groupPolicy` 也是如此)。
|
||||
- 使用 `channels.mattermost.groupAllowFrom` 将发送者加入允许列表(推荐使用用户 ID)。
|
||||
- 每个渠道的提及覆盖项位于 `channels.mattermost.groups.<channelId>.requireMention`
|
||||
或 `channels.mattermost.groups["*"].requireMention`(作为默认值)。
|
||||
- `@username` 匹配是可变的,并且仅在 `channels.mattermost.dangerouslyAllowNameMatching: true` 时启用。
|
||||
- 公开渠道:`channels.mattermost.groupPolicy="open"`(提及门控)。
|
||||
- 运行时说明:如果 `channels.mattermost` 完全缺失,运行时在群组检查时会回退到 `groupPolicy="allowlist"`(即使已设置 `channels.defaults.groupPolicy`)。
|
||||
|
||||
示例:
|
||||
|
||||
@ -197,29 +204,31 @@ Mattermost 会自动回复私信。频道行为由 `chatmode` 控制:
|
||||
}
|
||||
```
|
||||
|
||||
## 出站交付目标
|
||||
## 出站投递的目标格式
|
||||
|
||||
将以下目标格式与 `openclaw message send` 或 cron/webhook 一起使用:
|
||||
将以下目标格式与 `openclaw message send` 或 cron/webhooks 一起使用:
|
||||
|
||||
- `channel:<id>` 表示频道
|
||||
- `channel:<id>` 表示渠道
|
||||
- `user:<id>` 表示私信
|
||||
- `@username` 表示私信(通过 Mattermost API 解析)
|
||||
|
||||
裸的不透明 ID(例如 `64ifufp...`)在 Mattermost 中是**有歧义的**(用户 ID 或频道 ID)。
|
||||
裸的不透明 ID(例如 `64ifufp...`)在 Mattermost 中是**有歧义的**
|
||||
(用户 ID 与渠道 ID 无法区分)。
|
||||
|
||||
OpenClaw 会按**用户优先**顺序解析:
|
||||
OpenClaw 会按**优先用户**的顺序解析:
|
||||
|
||||
- 如果该 ID 作为用户存在(`GET /api/v4/users/<id>` 成功),OpenClaw 会先通过 `/api/v4/channels/direct` 解析直连频道,然后发送**私信**。
|
||||
- 否则,该 ID 会被视为**频道 ID**。
|
||||
- 如果该 ID 作为用户存在(`GET /api/v4/users/<id>` 成功),OpenClaw 会通过 `/api/v4/channels/direct` 解析直连渠道后发送**私信**。
|
||||
- 否则,该 ID 会被视为**渠道 ID**。
|
||||
|
||||
如果你需要确定性行为,请始终使用显式前缀(`user:<id>` / `channel:<id>`)。
|
||||
|
||||
## 私信频道重试
|
||||
## 私信渠道重试
|
||||
|
||||
当 OpenClaw 向 Mattermost 私信目标发送消息且需要先解析直连频道时,默认会对瞬时的直连频道创建失败进行重试。
|
||||
当 OpenClaw 向 Mattermost 私信目标发送消息且需要先解析直连渠道时,
|
||||
默认会对临时性的直连渠道创建失败进行重试。
|
||||
|
||||
使用 `channels.mattermost.dmChannelRetry` 可为整个 Mattermost 插件全局调优此行为,
|
||||
或使用 `channels.mattermost.accounts.<id>.dmChannelRetry` 为单个账号调优。
|
||||
使用 `channels.mattermost.dmChannelRetry` 为 Mattermost 插件全局调整该行为,
|
||||
或使用 `channels.mattermost.accounts.<id>.dmChannelRetry` 为单个账户调整。
|
||||
|
||||
```json5
|
||||
{
|
||||
@ -238,17 +247,42 @@ OpenClaw 会按**用户优先**顺序解析:
|
||||
|
||||
说明:
|
||||
|
||||
- 这仅适用于私信频道创建(`/api/v4/channels/direct`),而不是所有 Mattermost API 调用。
|
||||
- 重试适用于限流、5xx 响应以及网络或超时错误等瞬时故障。
|
||||
- 除 `429` 之外的 4xx 客户端错误会被视为永久性错误,不会重试。
|
||||
- 这仅适用于私信渠道创建(`/api/v4/channels/direct`),不适用于每一次 Mattermost API 调用。
|
||||
- 重试适用于限流、5xx 响应以及网络或超时错误等瞬时失败。
|
||||
- 除 `429` 外的 4xx 客户端错误会被视为永久性错误,不会重试。
|
||||
|
||||
## 表情回应(message 工具)
|
||||
## 预览流式传输
|
||||
|
||||
Mattermost 会将思考过程、工具活动和部分回复文本流式写入同一个**草稿预览消息**中,当最终答案可以安全发送时,就地完成该消息。预览会在同一个 post id 上更新,而不是用每个分块消息刷屏整个渠道。
|
||||
|
||||
通过 `channels.mattermost.streaming` 启用:
|
||||
|
||||
```json5
|
||||
{
|
||||
channels: {
|
||||
mattermost: {
|
||||
streaming: "partial", // off | partial | block | progress
|
||||
},
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
说明:
|
||||
|
||||
- `partial` 是通常的选择:一个预览消息会随着回复增长不断编辑,然后用完整答案完成。
|
||||
- `block` 会在预览消息中使用追加式草稿分块。
|
||||
- `progress` 会在生成过程中显示状态预览,并仅在完成时发送最终答案。
|
||||
- `off` 会禁用预览流式传输。
|
||||
- 如果流无法就地完成(例如消息在流式过程中被删除),OpenClaw 会回退为发送一个新的最终消息,以确保回复不会丢失。
|
||||
- 渠道映射矩阵请参见 [Streaming](/zh-CN/concepts/streaming#preview-streaming-modes)。
|
||||
|
||||
## Reactions(消息工具)
|
||||
|
||||
- 使用 `message action=react`,并设置 `channel=mattermost`。
|
||||
- `messageId` 是 Mattermost 的 post id。
|
||||
- `emoji` 接受 `thumbsup` 或 `:+1:` 这样的名称(冒号可选)。
|
||||
- 设置 `remove=true`(boolean)可移除表情回应。
|
||||
- 表情回应的添加/移除事件会作为系统事件转发到已路由的智能体会话。
|
||||
- `emoji` 接受如 `thumbsup` 或 `:+1:` 这样的名称(冒号可省略)。
|
||||
- 设置 `remove=true`(布尔值)以移除一个 reaction。
|
||||
- Reaction 添加/移除事件会作为系统事件转发到已路由的智能体会话。
|
||||
|
||||
示例:
|
||||
|
||||
@ -259,14 +293,15 @@ message action=react channel=mattermost target=channel:<channelId> messageId=<po
|
||||
|
||||
配置:
|
||||
|
||||
- `channels.mattermost.actions.reactions`:启用/禁用表情回应操作(默认 true)。
|
||||
- 按账号覆盖:`channels.mattermost.accounts.<id>.actions.reactions`。
|
||||
- `channels.mattermost.actions.reactions`:启用/禁用 reaction 操作(默认 true)。
|
||||
- 每账户覆盖:`channels.mattermost.accounts.<id>.actions.reactions`。
|
||||
|
||||
## 交互按钮(message 工具)
|
||||
## 交互式按钮(消息工具)
|
||||
|
||||
发送带可点击按钮的消息。用户点击按钮后,智能体会收到所选内容并作出响应。
|
||||
发送带有可点击按钮的消息。当用户点击按钮时,智能体会收到该选择,
|
||||
并可以作出响应。
|
||||
|
||||
通过将 `inlineButtons` 添加到渠道 capabilities 中来启用按钮:
|
||||
通过将 `inlineButtons` 添加到渠道能力中来启用按钮:
|
||||
|
||||
```json5
|
||||
{
|
||||
@ -278,7 +313,7 @@ message action=react channel=mattermost target=channel:<channelId> messageId=<po
|
||||
}
|
||||
```
|
||||
|
||||
使用 `message action=send` 并附带 `buttons` 参数。按钮是二维数组(按钮行):
|
||||
使用 `message action=send` 并带上 `buttons` 参数。按钮是一个二维数组(按钮行):
|
||||
|
||||
```
|
||||
message action=send channel=mattermost target=channel:<channelId> buttons=[[{"text":"Yes","callback_data":"yes"},{"text":"No","callback_data":"no"}]]
|
||||
@ -286,39 +321,43 @@ message action=send channel=mattermost target=channel:<channelId> buttons=[[{"te
|
||||
|
||||
按钮字段:
|
||||
|
||||
- `text`(必需):显示标签。
|
||||
- `callback_data`(必需):点击时回传的值(用作操作 ID)。
|
||||
- `text`(必填):显示标签。
|
||||
- `callback_data`(必填):点击后回传的值(用作 action ID)。
|
||||
- `style`(可选):`"default"`、`"primary"` 或 `"danger"`。
|
||||
|
||||
当用户点击按钮时:
|
||||
|
||||
1. 所有按钮都会被替换为一行确认信息(例如 “✓ **Yes** selected by @user”)。
|
||||
2. 智能体会将该选择作为入站消息接收并作出回复。
|
||||
1. 所有按钮都会被替换为一行确认文本(例如,“✓ **Yes** selected by @user”)。
|
||||
2. 智能体会将该选择作为一条入站消息接收,并作出响应。
|
||||
|
||||
说明:
|
||||
|
||||
- 按钮回调使用 HMAC-SHA256 验证(自动完成,无需配置)。
|
||||
- Mattermost 会从其 API 响应中剥离 callback data(安全特性),因此按钮点击后会移除所有按钮——无法只部分移除。
|
||||
- 包含连字符或下划线的操作 ID 会被自动清理
|
||||
- 按钮回调使用 HMAC-SHA256 校验(自动完成,无需配置)。
|
||||
- Mattermost 会从其 API 响应中剥离 callback data(安全特性),因此点击后所有按钮
|
||||
都会被移除——无法只移除其中一部分。
|
||||
- 包含连字符或下划线的 action ID 会自动清理
|
||||
(Mattermost 路由限制)。
|
||||
|
||||
配置:
|
||||
|
||||
- `channels.mattermost.capabilities`:能力字符串数组。添加 `"inlineButtons"` 以在智能体系统提示中启用按钮工具说明。
|
||||
- `channels.mattermost.interactions.callbackBaseUrl`:按钮回调的可选外部基础 URL(例如 `https://gateway.example.com`)。当 Mattermost 无法直接访问 gateway 绑定主机时使用。
|
||||
- 在多账号设置中,你也可以在
|
||||
- `channels.mattermost.capabilities`:能力字符串数组。添加 `"inlineButtons"` 以
|
||||
在智能体系统提示词中启用按钮工具说明。
|
||||
- `channels.mattermost.interactions.callbackBaseUrl`:可选的按钮回调外部基础 URL
|
||||
(例如 `https://gateway.example.com`)。当 Mattermost 无法
|
||||
直接通过 Gateway 网关绑定主机访问它时,请使用此项。
|
||||
- 在多账户设置中,你也可以在
|
||||
`channels.mattermost.accounts.<id>.interactions.callbackBaseUrl` 下设置同一字段。
|
||||
- 如果省略 `interactions.callbackBaseUrl`,OpenClaw 会根据
|
||||
`gateway.customBindHost` + `gateway.port` 推导回调 URL,然后回退到 `http://localhost:<port>`。
|
||||
- 可达性规则:按钮回调 URL 必须能被 Mattermost 服务器访问。
|
||||
只有当 Mattermost 与 OpenClaw 运行在同一主机/网络命名空间时,`localhost` 才可用。
|
||||
- 如果你的回调目标是私有/tailnet/内部地址,请将其 host/domain 添加到 Mattermost 的
|
||||
- 可达性规则:按钮回调 URL 必须可从 Mattermost 服务器访问。
|
||||
`localhost` 仅在 Mattermost 和 OpenClaw 运行于同一主机/网络命名空间时有效。
|
||||
- 如果你的回调目标是私有/tailnet/内部地址,请将其主机/域名添加到 Mattermost 的
|
||||
`ServiceSettings.AllowedUntrustedInternalConnections` 中。
|
||||
|
||||
### 直接 API 集成(外部脚本)
|
||||
|
||||
外部脚本和 webhook 可以直接通过 Mattermost REST API 发送按钮,而不是通过智能体的 `message` 工具。
|
||||
尽可能使用扩展中的 `buildButtonAttachments()`;如果发送原始 JSON,请遵循以下规则:
|
||||
外部脚本和 webhook 可以直接通过 Mattermost REST API 发送按钮,
|
||||
而不必经过智能体的 `message` 工具。如果可能,请使用扩展中的 `buildButtonAttachments()`;如果发送原始 JSON,请遵循以下规则:
|
||||
|
||||
**负载结构:**
|
||||
|
||||
@ -331,17 +370,17 @@ message action=send channel=mattermost target=channel:<channelId> buttons=[[{"te
|
||||
{
|
||||
actions: [
|
||||
{
|
||||
id: "mybutton01", // 仅限字母数字 —— 见下文
|
||||
type: "button", // 必需,否则点击会被静默忽略
|
||||
name: "Approve", // 显示标签
|
||||
style: "primary", // 可选:"default"、"primary"、"danger"
|
||||
id: "mybutton01", // alphanumeric only — see below
|
||||
type: "button", // required, or clicks are silently ignored
|
||||
name: "Approve", // display label
|
||||
style: "primary", // optional: "default", "primary", "danger"
|
||||
integration: {
|
||||
url: "https://gateway.example.com/mattermost/interactions/default",
|
||||
context: {
|
||||
action_id: "mybutton01", // 必须与按钮 id 匹配(用于名称查找)
|
||||
action_id: "mybutton01", // must match button id (for name lookup)
|
||||
action: "approve",
|
||||
// ... 任意自定义字段 ...
|
||||
_token: "<hmac>", // 参见下方 HMAC 部分
|
||||
// ... any custom fields ...
|
||||
_token: "<hmac>", // see HMAC section below
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -354,24 +393,25 @@ message action=send channel=mattermost target=channel:<channelId> buttons=[[{"te
|
||||
|
||||
**关键规则:**
|
||||
|
||||
1. Attachments 要放在 `props.attachments` 中,而不是顶层 `attachments`(否则会被静默忽略)。
|
||||
2. 每个 action 都需要 `type: "button"` —— 没有它,点击会被静默吞掉。
|
||||
3. 每个 action 都需要 `id` 字段 —— Mattermost 会忽略没有 ID 的 action。
|
||||
4. Action `id` 必须**仅包含字母数字**(`[a-zA-Z0-9]`)。连字符和下划线会破坏
|
||||
Mattermost 服务端的 action 路由(返回 404)。使用前请先移除它们。
|
||||
5. `context.action_id` 必须与按钮的 `id` 匹配,这样确认消息才会显示按钮名称
|
||||
(例如 “Approve”),而不是原始 ID。
|
||||
1. 附件应放在 `props.attachments` 中,而不是顶层的 `attachments`(否则会被静默忽略)。
|
||||
2. 每个 action 都需要 `type: "button"` —— 缺少它时,点击会被静默吞掉。
|
||||
3. 每个 action 都需要一个 `id` 字段 —— 没有 ID 的 action 会被 Mattermost 忽略。
|
||||
4. Action 的 `id` 必须是**纯字母数字**(`[a-zA-Z0-9]`)。连字符和下划线会破坏
|
||||
Mattermost 服务端的 action 路由(返回 404)。使用前请将它们移除。
|
||||
5. `context.action_id` 必须与按钮的 `id` 匹配,这样确认消息才会显示
|
||||
按钮名称(例如 “Approve”),而不是原始 ID。
|
||||
6. `context.action_id` 是必需的 —— 没有它,交互处理器会返回 400。
|
||||
|
||||
**HMAC token 生成:**
|
||||
|
||||
gateway 会使用 HMAC-SHA256 验证按钮点击。外部脚本必须生成与 gateway 验证逻辑匹配的 token:
|
||||
Gateway 网关使用 HMAC-SHA256 校验按钮点击。外部脚本必须生成
|
||||
与 Gateway 网关校验逻辑匹配的 token:
|
||||
|
||||
1. 从 bot token 派生密钥:
|
||||
1. 从 bot token 派生 secret:
|
||||
`HMAC-SHA256(key="openclaw-mattermost-interactions", data=botToken)`
|
||||
2. 构建包含所有字段但**不包含** `_token` 的 context 对象。
|
||||
3. 使用**排序后的键**和**无空格**格式进行序列化(gateway 使用带排序键的 `JSON.stringify`,
|
||||
其输出是紧凑格式)。
|
||||
2. 构建包含所有字段但**不包括** `_token` 的 context 对象。
|
||||
3. 使用**排序后的键**和**无空格**进行序列化(Gateway 网关使用带排序键的 `JSON.stringify`,
|
||||
其输出为紧凑格式)。
|
||||
4. 签名:`HMAC-SHA256(key=secret, data=serializedContext)`
|
||||
5. 将生成的十六进制摘要作为 `_token` 添加到 context 中。
|
||||
|
||||
@ -396,23 +436,24 @@ context = {**ctx, "_token": token}
|
||||
|
||||
- Python 的 `json.dumps` 默认会添加空格(`{"key": "val"}`)。请使用
|
||||
`separators=(",", ":")` 以匹配 JavaScript 的紧凑输出(`{"key":"val"}`)。
|
||||
- 始终对**所有** context 字段(除 `_token` 外)进行签名。gateway 会先移除 `_token`,
|
||||
然后对剩余所有内容签名。只对部分字段签名会导致静默验证失败。
|
||||
- 使用 `sort_keys=True` —— gateway 在签名前会对键排序,而 Mattermost 在存储负载时
|
||||
可能会重新排列 context 字段。
|
||||
- 从 bot token 派生密钥(确定性),而不是使用随机字节。创建按钮的进程与执行验证的 gateway
|
||||
必须使用相同的密钥。
|
||||
- 始终对**所有** context 字段(除 `_token` 外)进行签名。Gateway 网关会先移除 `_token`,
|
||||
然后对其余所有内容签名。只签名子集会导致静默校验失败。
|
||||
- 使用 `sort_keys=True` —— Gateway 网关会在签名前对键排序,而 Mattermost 在存储负载时
|
||||
可能会重排 context 字段顺序。
|
||||
- 从 bot token 派生 secret(确定性),而不是使用随机字节。这个 secret
|
||||
必须在创建按钮的进程和执行校验的 Gateway 网关之间保持一致。
|
||||
|
||||
## 目录适配器
|
||||
|
||||
Mattermost 插件包含一个目录适配器,可通过 Mattermost API 解析频道名和用户名。
|
||||
这使得你可以在 `openclaw message send` 和 cron/webhook 交付中使用 `#channel-name` 和 `@username` 目标。
|
||||
Mattermost 插件包含一个目录适配器,可通过 Mattermost API 解析渠道和用户名称。
|
||||
这使得你可以在
|
||||
`openclaw message send` 和 cron/webhook 投递中使用 `#channel-name` 和 `@username` 目标。
|
||||
|
||||
无需额外配置——该适配器会使用账号配置中的 bot token。
|
||||
无需额外配置 —— 该适配器会使用账户配置中的 bot token。
|
||||
|
||||
## 多账号
|
||||
## 多账户
|
||||
|
||||
Mattermost 支持在 `channels.mattermost.accounts` 下配置多个账号:
|
||||
Mattermost 支持在 `channels.mattermost.accounts` 下配置多个账户:
|
||||
|
||||
```json5
|
||||
{
|
||||
@ -429,33 +470,34 @@ Mattermost 支持在 `channels.mattermost.accounts` 下配置多个账号:
|
||||
|
||||
## 故障排除
|
||||
|
||||
- 频道中没有回复:确保机器人已加入该频道,并 @ 提及它(oncall),使用触发前缀(onchar),或设置 `chatmode: "onmessage"`。
|
||||
- 认证错误:检查 bot token、base URL,以及该账号是否已启用。
|
||||
- 多账号问题:环境变量仅适用于 `default` 账号。
|
||||
- 渠道中没有回复:确认机器人已加入该渠道,并 @提及它(oncall),使用触发前缀(onchar),或设置 `chatmode: "onmessage"`。
|
||||
- 认证错误:检查 bot token、base URL,以及账户是否已启用。
|
||||
- 多账户问题:环境变量仅适用于 `default` 账户。
|
||||
- 原生斜杠命令返回 `Unauthorized: invalid command token.`:OpenClaw
|
||||
未接受该回调 token。常见原因包括:
|
||||
- 斜杠命令注册失败,或启动时仅部分完成
|
||||
- 回调命中了错误的 gateway/账号
|
||||
- Mattermost 仍保留旧命令,指向之前的回调目标
|
||||
- gateway 重启后未重新激活斜杠命令
|
||||
未接受回调 token。常见原因包括:
|
||||
- 启动时斜杠命令注册失败,或只完成了部分注册
|
||||
- 回调打到了错误的 Gateway 网关/账户
|
||||
- Mattermost 仍保留指向旧回调目标的旧命令
|
||||
- Gateway 网关重启后未重新激活斜杠命令
|
||||
- 如果原生斜杠命令停止工作,请检查日志中是否有
|
||||
`mattermost: failed to register slash commands` 或
|
||||
`mattermost: native slash commands enabled but no commands could be registered`。
|
||||
- 如果省略了 `callbackUrl` 且日志警告回调解析为
|
||||
`http://127.0.0.1:18789/...`,该 URL 很可能只有在
|
||||
Mattermost 与 OpenClaw 运行在同一主机/网络命名空间时才可访问。请改为显式设置一个外部可访问的 `commands.callbackUrl`。
|
||||
- 按钮显示为空白方块:智能体发送的按钮数据可能格式不正确。请检查每个按钮是否同时包含 `text` 和 `callback_data` 字段。
|
||||
- 按钮可以渲染但点击无反应:请验证 Mattermost 服务器配置中的 `AllowedUntrustedInternalConnections` 包含 `127.0.0.1 localhost`,并且 `ServiceSettings` 中的 `EnablePostActionIntegration` 为 `true`。
|
||||
- 点击按钮返回 404:按钮 `id` 很可能包含连字符或下划线。Mattermost 的 action 路由器在非字母数字 ID 上会失效。仅使用 `[a-zA-Z0-9]`。
|
||||
- Gateway 网关日志显示 `invalid _token`:HMAC 不匹配。请检查是否对所有 context 字段(而非子集)进行了签名、使用了排序后的键,以及使用了紧凑 JSON(无空格)。参见上文 HMAC 部分。
|
||||
- Gateway 网关日志显示 `missing _token in context`:按钮的 context 中没有 `_token` 字段。请确保在构建 integration 负载时包含它。
|
||||
- 确认消息显示的是原始 ID 而不是按钮名称:`context.action_id` 与按钮的 `id` 不匹配。请将两者设置为同一个清理后的值。
|
||||
- 智能体不了解按钮:在 Mattermost 渠道配置中添加 `capabilities: ["inlineButtons"]`。
|
||||
- 如果省略 `callbackUrl`,且日志警告回调被解析为
|
||||
`http://127.0.0.1:18789/...`,那么该 URL 很可能只有在
|
||||
Mattermost 与 OpenClaw 运行于同一主机/网络命名空间时才可达。请改为设置一个
|
||||
显式的、外部可达的 `commands.callbackUrl`。
|
||||
- 按钮显示为空白方块:智能体可能发送了格式错误的按钮数据。检查每个按钮是否同时具有 `text` 和 `callback_data` 字段。
|
||||
- 按钮能渲染但点击无反应:确认 Mattermost 服务器配置中的 `AllowedUntrustedInternalConnections` 包含 `127.0.0.1 localhost`,并且 ServiceSettings 中的 `EnablePostActionIntegration` 为 `true`。
|
||||
- 点击按钮返回 404:按钮的 `id` 很可能包含连字符或下划线。Mattermost 的 action 路由器无法处理非字母数字 ID。请仅使用 `[a-zA-Z0-9]`。
|
||||
- Gateway 网关日志显示 `invalid _token`:HMAC 不匹配。请检查你是否对所有 context 字段(而非其中一部分)进行了签名、使用了排序后的键,并使用紧凑 JSON(无空格)。请参见上面的 HMAC 部分。
|
||||
- Gateway 网关日志显示 `missing _token in context`:按钮的 context 中没有 `_token` 字段。请确保在构建 integration 负载时包含该字段。
|
||||
- 确认消息显示的是原始 ID 而不是按钮名称:`context.action_id` 与按钮的 `id` 不匹配。请将二者设为相同的清理后值。
|
||||
- 智能体不知道按钮功能:在 Mattermost 渠道配置中添加 `capabilities: ["inlineButtons"]`。
|
||||
|
||||
## 相关
|
||||
## 相关内容
|
||||
|
||||
- [渠道概览](/channels) — 所有支持的渠道
|
||||
- [配对](/channels/pairing) — 私信身份验证和配对流程
|
||||
- [群组](/channels/groups) — 群聊行为和提及门控
|
||||
- [渠道路由](/channels/channel-routing) — 消息的会话路由
|
||||
- [安全性](/gateway/security) — 访问模型和加固
|
||||
- [Channels Overview](/zh-CN/channels) — 所有支持的渠道
|
||||
- [Pairing](/zh-CN/channels/pairing) — 私信认证与配对流程
|
||||
- [Groups](/zh-CN/channels/groups) — 群聊行为和提及门控
|
||||
- [Channel Routing](/zh-CN/channels/channel-routing) — 消息的会话路由
|
||||
- [Security](/zh-CN/gateway/security) — 访问模型与加固
|
||||
|
||||
@ -1,31 +1,31 @@
|
||||
---
|
||||
read_when:
|
||||
- 说明流式传输或分块在各渠道中的工作方式
|
||||
- 更改分块流式传输或渠道分块行为
|
||||
- 解释渠道上的流式传输或分块处理如何工作
|
||||
- 更改分块流式传输或渠道分块处理行为
|
||||
- 调试重复/过早的分块回复或渠道预览流式传输
|
||||
summary: 流式传输 + 分块行为(分块回复、渠道预览流式传输、模式映射)
|
||||
title: 流式传输和分块
|
||||
summary: 流式传输 + 分块处理行为(分块回复、渠道预览流式传输、模式映射)
|
||||
title: 流式传输与分块处理
|
||||
x-i18n:
|
||||
generated_at: "2026-04-08T04:59:54Z"
|
||||
generated_at: "2026-04-21T20:11:34Z"
|
||||
model: gpt-5.4
|
||||
provider: openai
|
||||
source_hash: a8e847bb7da890818cd79dec7777f6ae488e6d6c0468e948e56b6b6c598e0000
|
||||
source_hash: ca91815fb44c0d0283dcfbcec44fb016e07a841e538b5cb4baab18d441a86730
|
||||
source_path: concepts/streaming.md
|
||||
workflow: 15
|
||||
---
|
||||
|
||||
# 流式传输 + 分块
|
||||
# 流式传输 + 分块处理
|
||||
|
||||
OpenClaw 有两层彼此独立的流式传输:
|
||||
OpenClaw 有两个彼此独立的流式传输层:
|
||||
|
||||
- **分块流式传输(渠道):** 在助手写作时发送已完成的**块**。这些是正常的渠道消息(不是 token 增量)。
|
||||
- **预览流式传输(Telegram/Discord/Slack):** 在生成过程中更新一个临时的**预览消息**。
|
||||
- **分块流式传输(渠道):** 在助手写入时,输出已完成的**块**。这些是普通的渠道消息(不是 token 增量)。
|
||||
- **预览流式传输(Telegram/Discord/Slack):** 在生成过程中更新一条临时的**预览消息**。
|
||||
|
||||
目前还**没有真正的 token 增量流式传输**发送到渠道消息。预览流式传输是基于消息的(发送 + 编辑/追加)。
|
||||
目前**没有真正的 token 增量流式传输**发送到渠道消息。预览流式传输是基于消息的(发送 + 编辑/追加)。
|
||||
|
||||
## 分块流式传输(渠道消息)
|
||||
|
||||
分块流式传输会在助手输出可用时,以较粗粒度的块发送。
|
||||
分块流式传输会在助手输出可用时,以较粗粒度的分段发送。
|
||||
|
||||
```
|
||||
Model output
|
||||
@ -39,76 +39,75 @@ Model output
|
||||
|
||||
图例:
|
||||
|
||||
- `text_delta/events`:模型流事件(对于非流式模型,这些事件可能很稀疏)。
|
||||
- `chunker`:应用最小/最大边界和断点偏好的 `EmbeddedBlockChunker`。
|
||||
- `channel send`:实际发出的出站消息(分块回复)。
|
||||
- `text_delta/events`:模型流事件(对于非流式模型,事件可能很稀疏)。
|
||||
- `chunker`:`EmbeddedBlockChunker`,应用最小/最大边界 + 断点偏好。
|
||||
- `channel send`:实际发出的消息(分块回复)。
|
||||
|
||||
**控制项:**
|
||||
|
||||
- `agents.defaults.blockStreamingDefault`:`"on"`/`"off"`(默认关闭)。
|
||||
- 渠道覆盖:`*.blockStreaming`(以及每账号变体)可为每个渠道强制设为 `"on"`/`"off"`。
|
||||
- 渠道覆盖:`*.blockStreaming`(以及按账户划分的变体),可按渠道强制设为 `"on"`/`"off"`。
|
||||
- `agents.defaults.blockStreamingBreak`:`"text_end"` 或 `"message_end"`。
|
||||
- `agents.defaults.blockStreamingChunk`:`{ minChars, maxChars, breakPreference? }`。
|
||||
- `agents.defaults.blockStreamingCoalesce`:`{ minChars?, maxChars?, idleMs? }`(在发送前合并流式块)。
|
||||
- 渠道硬上限:`*.textChunkLimit`(例如 `channels.whatsapp.textChunkLimit`)。
|
||||
- 渠道分块模式:`*.chunkMode`(默认 `length`,`newline` 会先按空行即段落边界拆分,再按长度分块)。
|
||||
- Discord 软上限:`channels.discord.maxLinesPerMessage`(默认 17)会拆分过高的回复,以避免 UI 裁剪。
|
||||
- 渠道分块模式:`*.chunkMode`(默认 `length`,`newline` 会先按空行〔段落边界〕拆分,再按长度分块)。
|
||||
- Discord 软上限:`channels.discord.maxLinesPerMessage`(默认 17),会拆分过高的回复以避免 UI 截断。
|
||||
|
||||
**边界语义:**
|
||||
|
||||
- `text_end`:一旦 chunker 产生块就立即流式发送;在每个 `text_end` 时刷新。
|
||||
- `text_end`:一旦 chunker 输出块就立即流式发送;在每个 `text_end` 时刷新。
|
||||
- `message_end`:等待助手消息完成后,再刷新缓冲输出。
|
||||
|
||||
`message_end` 仍然会在缓冲文本超过 `maxChars` 时使用 chunker,因此它可以在结尾发出多个块。
|
||||
即使是 `message_end`,如果缓冲文本超过 `maxChars`,仍然会使用 chunker,因此它可能在结尾输出多个分块。
|
||||
|
||||
## 分块算法(低/高边界)
|
||||
|
||||
分块由 `EmbeddedBlockChunker` 实现:
|
||||
分块处理由 `EmbeddedBlockChunker` 实现:
|
||||
|
||||
- **低边界:** 在缓冲区达到 `minChars` 之前不发送(除非被强制发送)。
|
||||
- **高边界:** 优先在 `maxChars` 之前拆分;如果必须强制拆分,就在 `maxChars` 处拆分。
|
||||
- **低边界:** 在缓冲区达到 `minChars` 之前不输出(除非被强制输出)。
|
||||
- **高边界:** 优先在 `maxChars` 之前拆分;如果必须强制拆分,就在 `maxChars` 处切分。
|
||||
- **断点偏好:** `paragraph` → `newline` → `sentence` → `whitespace` → 硬拆分。
|
||||
- **代码围栏:** 绝不在围栏内部拆分;如果被迫在 `maxChars` 处拆分,会先关闭再重新打开围栏,以保持 Markdown 有效。
|
||||
- **代码围栏:** 绝不在围栏内部拆分;如果必须在 `maxChars` 处强制拆分,会先闭合再重新打开围栏,以保持 Markdown 有效。
|
||||
|
||||
`maxChars` 会被限制到渠道的 `textChunkLimit`,因此你无法超过各渠道的上限。
|
||||
`maxChars` 会被限制在渠道的 `textChunkLimit` 以内,因此你不能超过各渠道的上限。
|
||||
|
||||
## 合并(合并流式块)
|
||||
|
||||
启用分块流式传输时,OpenClaw 可以在发送前**合并连续的分块**。
|
||||
这样既能提供渐进式输出,又能减少“单行刷屏”。
|
||||
这样既能保留渐进式输出,又能减少“单行刷屏”。
|
||||
|
||||
- 合并会等待**空闲间隔**(`idleMs`)后再刷新。
|
||||
- 缓冲区受 `maxChars` 限制,超过时会刷新。
|
||||
- `minChars` 会阻止过小的片段被提前发送,直到积累足够文本
|
||||
(最终刷新始终会发送剩余文本)。
|
||||
- 连接符由 `blockStreamingChunk.breakPreference`
|
||||
决定(`paragraph` → `\n\n`,`newline` → `\n`,`sentence` → 空格)。
|
||||
- 可通过 `*.blockStreamingCoalesce` 进行渠道级覆盖(包括每账号配置)。
|
||||
- 对于 Signal/Slack/Discord,默认合并 `minChars` 会提升到 1500,除非被覆盖。
|
||||
- 缓冲区受 `maxChars` 限制,超过时会立即刷新。
|
||||
- `minChars` 会阻止过小的片段过早发送,直到累积足够文本
|
||||
(最终刷新时始终会发送剩余文本)。
|
||||
- 连接符由 `blockStreamingChunk.breakPreference` 推导而来
|
||||
(`paragraph` → `\n\n`,`newline` → `\n`,`sentence` → 空格)。
|
||||
- 可通过 `*.blockStreamingCoalesce` 提供渠道级覆盖(包括按账户配置)。
|
||||
- 除非另有覆盖,对于 Signal/Slack/Discord,默认合并 `minChars` 会提升到 1500。
|
||||
|
||||
## 块之间的类人节奏
|
||||
## 块之间的人类式节奏
|
||||
|
||||
启用分块流式传输时,你可以在分块回复之间加入**随机暂停**
|
||||
(第一个块之后)。这会让多气泡回复显得更自然。
|
||||
启用分块流式传输时,你可以在各个分块回复之间加入**随机暂停**
|
||||
(首个分块之后)。这会让多气泡回复显得更自然。
|
||||
|
||||
- 配置:`agents.defaults.humanDelay`(可通过 `agents.list[].humanDelay` 按智能体覆盖)。
|
||||
- 模式:`off`(默认)、`natural`(800–2500ms)、`custom`(`minMs`/`maxMs`)。
|
||||
- 仅适用于**分块回复**,不适用于最终回复或工具摘要。
|
||||
|
||||
## “流式发送分块,还是一次性全部发送”
|
||||
## “流式输出分块”还是“最后一次性输出”
|
||||
|
||||
它对应为:
|
||||
这对应到:
|
||||
|
||||
- **流式发送分块:** `blockStreamingDefault: "on"` + `blockStreamingBreak: "text_end"`(边生成边发送)。非 Telegram 渠道还需要将 `*.blockStreaming` 设为 `true`。
|
||||
- **在结尾一次性发送全部内容:** `blockStreamingBreak: "message_end"`(刷新一次;如果内容很长,可能仍会拆成多个块)。
|
||||
- **流式输出分块:** `blockStreamingDefault: "on"` + `blockStreamingBreak: "text_end"`(边生成边输出)。非 Telegram 渠道还需要 `*.blockStreaming: true`。
|
||||
- **在结尾一次性输出全部:** `blockStreamingBreak: "message_end"`(只在最后刷新一次;如果内容很长,可能仍会拆成多个分块)。
|
||||
- **不使用分块流式传输:** `blockStreamingDefault: "off"`(只发送最终回复)。
|
||||
|
||||
**渠道说明:** 除非显式将
|
||||
`*.blockStreaming` 设为 `true`,否则分块流式传输**默认关闭**。渠道仍然可以启用实时预览
|
||||
(`channels.<channel>.streaming`),而不发送分块回复。
|
||||
**渠道说明:** 只有在明确设置
|
||||
`*.blockStreaming: true` 时,才会启用分块流式传输。渠道可以在没有分块回复的情况下启用实时预览
|
||||
(`channels.<channel>.streaming`)。
|
||||
|
||||
配置位置提醒:`blockStreaming*` 默认值位于
|
||||
`agents.defaults` 下,而不是根配置下。
|
||||
配置位置提醒:`blockStreaming*` 默认值位于 `agents.defaults` 下,而不是根配置。
|
||||
|
||||
## 预览流式传输模式
|
||||
|
||||
@ -117,51 +116,57 @@ Model output
|
||||
模式:
|
||||
|
||||
- `off`:禁用预览流式传输。
|
||||
- `partial`:使用单个预览,并用最新文本替换。
|
||||
- `partial`:使用单个预览,用最新文本替换其内容。
|
||||
- `block`:以分块/追加的方式更新预览。
|
||||
- `progress`:在生成期间显示进度/状态预览,完成后给出最终答案。
|
||||
- `progress`:生成期间显示进度/状态预览,完成时输出最终答案。
|
||||
|
||||
### 渠道映射
|
||||
|
||||
| 渠道 | `off` | `partial` | `block` | `progress` |
|
||||
| ---- | ----- | --------- | ------- | ---------- |
|
||||
| Telegram | ✅ | ✅ | ✅ | 映射为 `partial` |
|
||||
| Discord | ✅ | ✅ | ✅ | 映射为 `partial` |
|
||||
| Slack | ✅ | ✅ | ✅ | ✅ |
|
||||
| ---------- | ----- | --------- | ------- | ----------------- |
|
||||
| Telegram | ✅ | ✅ | ✅ | 映射为 `partial` |
|
||||
| Discord | ✅ | ✅ | ✅ | 映射为 `partial` |
|
||||
| Slack | ✅ | ✅ | ✅ | ✅ |
|
||||
| Mattermost | ✅ | ✅ | ✅ | ✅ |
|
||||
|
||||
仅限 Slack:
|
||||
|
||||
- `channels.slack.streaming.nativeTransport` 在 `channels.slack.streaming.mode="partial"` 时切换 Slack 原生流式 API 调用(默认:`true`)。
|
||||
- Slack 原生流式传输和 Slack 助手线程状态都需要回复线程目标;顶层私信不会显示这种线程式预览。
|
||||
- 当 `channels.slack.streaming.mode="partial"` 时,`channels.slack.streaming.nativeTransport` 用于切换 Slack 原生流式 API 调用(默认:`true`)。
|
||||
- Slack 原生流式传输以及 Slack 助手线程状态都需要一个回复线程目标;顶层私信不会显示这种线程式预览。
|
||||
|
||||
旧键迁移:
|
||||
|
||||
- Telegram:`streamMode` 和布尔值 `streaming` 会自动迁移到枚举 `streaming`。
|
||||
- Discord:`streamMode` 和布尔值 `streaming` 会自动迁移到枚举 `streaming`。
|
||||
- Slack:`streamMode` 会自动迁移到 `streaming.mode`;布尔值 `streaming` 会自动迁移到 `streaming.mode` 加 `streaming.nativeTransport`;旧版 `nativeStreaming` 会自动迁移到 `streaming.nativeTransport`。
|
||||
- Telegram:`streamMode` + 布尔值 `streaming` 会自动迁移到 `streaming` 枚举。
|
||||
- Discord:`streamMode` + 布尔值 `streaming` 会自动迁移到 `streaming` 枚举。
|
||||
- Slack:`streamMode` 会自动迁移到 `streaming.mode`;布尔值 `streaming` 会自动迁移到 `streaming.mode` + `streaming.nativeTransport`;旧版 `nativeStreaming` 会自动迁移到 `streaming.nativeTransport`。
|
||||
|
||||
### 运行时行为
|
||||
|
||||
Telegram:
|
||||
|
||||
- 在私信和群组/话题中使用 `sendMessage` + `editMessageText` 更新预览。
|
||||
- 当 Telegram 分块流式传输被显式启用时,会跳过预览流式传输(以避免双重流式传输)。
|
||||
- `/reasoning stream` 可以将 reasoning 写入预览。
|
||||
- 在私信和群组/话题中,使用 `sendMessage` + `editMessageText` 更新预览。
|
||||
- 当明确启用了 Telegram 分块流式传输时,会跳过预览流式传输(以避免双重流式传输)。
|
||||
- `/reasoning stream` 可以将推理内容写入预览。
|
||||
|
||||
Discord:
|
||||
|
||||
- 使用发送 + 编辑预览消息。
|
||||
- `block` 模式使用草稿分块(`draftChunk`)。
|
||||
- 当 Discord 分块流式传输被显式启用时,会跳过预览流式传输。
|
||||
- 当明确启用了 Discord 分块流式传输时,会跳过预览流式传输。
|
||||
|
||||
Slack:
|
||||
|
||||
- `partial` 在可用时可以使用 Slack 原生流式传输(`chat.startStream`/`append`/`stop`)。
|
||||
- `partial` 在可用时可使用 Slack 原生流式传输(`chat.startStream`/`append`/`stop`)。
|
||||
- `block` 使用追加式草稿预览。
|
||||
- `progress` 使用状态预览文本,然后发送最终答案。
|
||||
- `progress` 使用状态预览文本,然后输出最终答案。
|
||||
|
||||
Mattermost:
|
||||
|
||||
- 将思考、工具活动和部分回复文本流式写入单条草稿预览帖子,并在最终答案可安全发送时原地完成该帖子。
|
||||
- 如果预览帖子已被删除或在最终完成时不可用,则回退为发送一条新的最终帖子。
|
||||
|
||||
## 相关内容
|
||||
|
||||
- [消息](/zh-CN/concepts/messages) — 消息生命周期和投递
|
||||
- [重试](/zh-CN/concepts/retry) — 投递失败时的重试行为
|
||||
- [渠道](/zh-CN/channels) — 各渠道的流式传输支持
|
||||
- [Messages](/zh-CN/concepts/messages) —— 消息生命周期与投递
|
||||
- [Retry](/zh-CN/concepts/retry) —— 投递失败时的重试行为
|
||||
- [Channels](/zh-CN/channels) —— 各渠道的流式传输支持
|
||||
|
||||
Loading…
Reference in New Issue
Block a user