From dfbb0529cc2fde14036e0ed5ea2b05debb3f72b9 Mon Sep 17 00:00:00 2001 From: "openclaw-docs-i18n[bot]" Date: Wed, 29 Apr 2026 06:00:37 +0000 Subject: [PATCH] chore(i18n): refresh zh-CN translations --- docs/zh-CN/channels/feishu.md | 154 +++--- docs/zh-CN/channels/pairing.md | 91 ++-- docs/zh-CN/channels/synology-chat.md | 116 ++--- docs/zh-CN/channels/telegram.md | 379 +++++++------- docs/zh-CN/ci.md | 191 ++++---- docs/zh-CN/help/testing.md | 709 +++++++++++++-------------- 6 files changed, 810 insertions(+), 830 deletions(-) diff --git a/docs/zh-CN/channels/feishu.md b/docs/zh-CN/channels/feishu.md index fcbe5628a..7f19ec1c2 100644 --- a/docs/zh-CN/channels/feishu.md +++ b/docs/zh-CN/channels/feishu.md @@ -1,30 +1,30 @@ --- read_when: - - 你想要连接一个 Feishu/Lark 机器人 + - 你想连接一个 Feishu/Lark 机器人 - 你正在配置 Feishu 渠道 summary: Feishu 机器人概览、功能和配置 title: Feishu x-i18n: - generated_at: "2026-04-27T22:37:15Z" - model: gpt-5.4 + generated_at: "2026-04-29T05:57:39Z" + model: gpt-5.5 provider: openai - source_hash: 54db77a6bb05d862fe8eb5dfc97d04e4252b20e2b0ccbf204eb49d9d7256b026 + source_hash: 37de7cbb12821f119ca1a06fcdb8e80a07752e1cbfc462344d24750fbf13147a source_path: channels/feishu.md - workflow: 15 + workflow: 16 --- # Feishu / Lark -Feishu/Lark 是一个一体化协作平台,团队可以在其中聊天、共享文档、管理日历并协同完成工作。 +Feishu/Lark 是一体化协作平台,团队可在其中聊天、共享文档、管理日历并协同完成工作。 -**Status:** 适用于机器人私信和群聊的生产就绪状态。WebSocket 是默认模式;webhook 模式为可选。 +**Status:** 已可用于生产环境中的机器人私信 + 群聊。WebSocket 是默认模式;webhook 模式是可选项。 --- ## 快速开始 -需要 OpenClaw 2026.4.25 或更高版本。运行 `openclaw --version` 进行检查。使用 `openclaw update` 升级。 +需要 OpenClaw 2026.4.25 或更高版本。运行 `openclaw --version` 检查。使用 `openclaw update` 升级。 @@ -32,7 +32,7 @@ Feishu/Lark 是一个一体化协作平台,团队可以在其中聊天、共 ```bash openclaw channels login --channel feishu ``` - 使用你的 Feishu/Lark 移动应用扫描二维码,以自动创建一个 Feishu/Lark 机器人。 + 使用你的 Feishu/Lark 移动应用扫描二维码,即可自动创建 Feishu/Lark 机器人。 @@ -48,11 +48,11 @@ Feishu/Lark 是一个一体化协作平台,团队可以在其中聊天、共 ### 私信 -配置 `dmPolicy` 以控制谁可以向机器人发送私信: +配置 `dmPolicy` 来控制谁可以向机器人发送私信: - `"pairing"` — 未知用户会收到配对码;通过 CLI 批准 -- `"allowlist"` — 只有 `allowFrom` 中列出的用户可以聊天(默认:仅机器人所有者) -- `"open"` — 允许所有用户 +- `"allowlist"` — 只有列在 `allowFrom` 中的用户可以聊天(默认:仅机器人所有者) +- `"open"` — 仅当 `allowFrom` 包含 `"*"` 时允许公开私信;如果使用限制性条目,只有匹配的用户可以聊天 - `"disabled"` — 禁用所有私信 **批准配对请求:** @@ -68,24 +68,24 @@ openclaw pairing approve feishu | 值 | 行为 | | ------------- | -------------------------------------------------------------------------------------------- | -| `"open"` | 响应群组中的所有消息 | -| `"allowlist"` | 仅响应 `groupAllowFrom` 中的群组,或在 `groups.` 下显式配置的群组 | -| `"disabled"` | 禁用所有群组消息;显式的 `groups.` 条目不会覆盖此设置 | +| `"open"` | 回复群组中的所有消息 | +| `"allowlist"` | 只回复 `groupAllowFrom` 中的群组,或在 `groups.` 下显式配置的群组 | +| `"disabled"` | 禁用所有群组消息;显式的 `groups.` 条目不会覆盖此设置 | 默认值:`allowlist` **提及要求**(`channels.feishu.requireMention`): -- `true` — 需要 @提及(默认) -- `false` — 无需 @提及也会响应 +- `true` — 要求 @提及(默认) +- `false` — 无需 @提及也会回复 - 按群组覆盖:`channels.feishu.groups..requireMention` -- 仅广播用的 `@all` 和 `@_all` 不会被视为对机器人的提及。如果一条消息同时提及 `@all` 和机器人本身,仍然算作提及了机器人。 +- 仅用于广播的 `@all` 和 `@_all` 不会被视为机器人提及。同时提及 `@all` 和机器人本身的消息仍会算作机器人提及。 --- ## 群组配置示例 -### 允许所有群组,不需要 @提及 +### 允许所有群组,无需 @提及 ```json5 { @@ -97,7 +97,7 @@ openclaw pairing approve feishu } ``` -### 允许所有群组,但仍需要 @提及 +### 允许所有群组,仍然要求 @提及 ```json5 { @@ -110,21 +110,21 @@ openclaw pairing approve feishu } ``` -### 仅允许特定群组 +### 仅允许指定群组 ```json5 { channels: { feishu: { groupPolicy: "allowlist", - // 群组 ID 类似于:oc_xxx + // Group IDs look like: oc_xxx groupAllowFrom: ["oc_xxx", "oc_yyy"], }, }, } ``` -在 `allowlist` 模式下,你也可以通过添加显式的 `groups.` 条目来准入某个群组。显式条目不会覆盖 `groupPolicy: "disabled"`。`groups.*` 下的通配符默认项会配置匹配的群组,但它们本身不会让群组获得准入。 +在 `allowlist` 模式下,你也可以通过添加显式的 `groups.` 条目来接纳某个群组。显式条目不会覆盖 `groupPolicy: "disabled"`。`groups.*` 下的通配符默认值会配置匹配的群组,但它们本身不会接纳群组。 ```json5 { @@ -151,7 +151,7 @@ openclaw pairing approve feishu groupAllowFrom: ["oc_xxx"], groups: { oc_xxx: { - // 用户 open_id 类似于:ou_xxx + // User open_ids look like: ou_xxx allowFrom: ["ou_user1", "ou_user2"], }, }, @@ -168,19 +168,19 @@ openclaw pairing approve feishu ### 群组 ID(`chat_id`,格式:`oc_xxx`) -在 Feishu/Lark 中打开群组,点击右上角的菜单图标,然后进入**设置**。群组 ID(`chat_id`)会显示在设置页面中。 +在 Feishu/Lark 中打开群组,点击右上角的菜单图标,然后进入**设置**。群组 ID(`chat_id`)会列在设置页面上。 -![Get Group ID](/images/feishu-get-group-id.png) +![获取群组 ID](/images/feishu-get-group-id.png) ### 用户 ID(`open_id`,格式:`ou_xxx`) -启动 Gateway 网关,向机器人发送一条私信,然后查看日志: +启动 Gateway 网关,向机器人发送私信,然后检查日志: ```bash openclaw logs --follow ``` -在日志输出中查找 `open_id`。你也可以查看待处理的配对请求: +在日志输出中查找 `open_id`。你也可以检查待处理的配对请求: ```bash openclaw pairing list feishu @@ -190,14 +190,14 @@ openclaw pairing list feishu ## 常用命令 -| 命令 | 说明 | -| --------- | ------------------------ | -| `/status` | 显示机器人状态 | -| `/reset` | 重置当前会话 | -| `/model` | 显示或切换 AI 模型 | +| 命令 | 描述 | +| --------- | -------------------- | +| `/status` | 显示机器人状态 | +| `/reset` | 重置当前会话 | +| `/model` | 显示或切换 AI 模型 | -Feishu/Lark 不支持原生斜杠命令菜单,因此请将这些命令作为纯文本消息发送。 +Feishu/Lark 不支持原生斜杠菜单,因此请将这些命令作为纯文本消息发送。 --- @@ -206,12 +206,12 @@ Feishu/Lark 不支持原生斜杠命令菜单,因此请将这些命令作为 ### 机器人在群聊中没有响应 -1. 确保机器人已加入群组 -2. 确保你 @提及了机器人(默认必需) -3. 确认 `groupPolicy` 不是 `"disabled"` +1. 确保机器人已添加到群组 +2. 确保你 @提及了机器人(默认要求) +3. 验证 `groupPolicy` 不是 `"disabled"` 4. 检查日志:`openclaw logs --follow` -### 机器人未收到消息 +### 机器人没有收到消息 1. 确保机器人已在 Feishu Open Platform / Lark Developer 中发布并获批 2. 确保事件订阅包含 `im.message.receive_v1` @@ -223,7 +223,7 @@ Feishu/Lark 不支持原生斜杠命令菜单,因此请将这些命令作为 ### App Secret 泄露 1. 在 Feishu Open Platform / Lark Developer 中重置 App Secret -2. 更新你配置中的值 +2. 在你的配置中更新该值 3. 重启 Gateway 网关:`openclaw gateway restart` --- @@ -261,7 +261,7 @@ Feishu/Lark 不支持原生斜杠命令菜单,因此请将这些命令作为 ``` `defaultAccount` 控制在出站 API 未指定 `accountId` 时使用哪个账户。 -`accounts..tts` 使用与 `messages.tts` 相同的结构,并会在全局 TTS 配置之上进行深度合并,因此多机器人 Feishu 部署可以在全局保留共享的提供商凭证,同时仅按账户覆盖语音、模型、角色设定或自动模式。 +`accounts..tts` 使用与 `messages.tts` 相同的形状,并会深度合并到全局 TTS 配置之上,因此多机器人 Feishu 设置可以在全局保留共享的提供商凭证,同时仅按账户覆盖语音、模型、角色或自动模式。 ### 消息限制 @@ -270,14 +270,14 @@ Feishu/Lark 不支持原生斜杠命令菜单,因此请将这些命令作为 ### 流式传输 -Feishu/Lark 通过交互式卡片支持流式回复。启用后,机器人会在生成文本时实时更新卡片。 +Feishu/Lark 支持通过交互式卡片进行流式回复。启用后,机器人会在生成文本时实时更新卡片。 ```json5 { channels: { feishu: { - streaming: true, // 启用流式卡片输出(默认:true) - blockStreaming: true, // 启用分块流式传输(默认:true) + streaming: true, // enable streaming card output (default: true) + blockStreaming: true, // enable block-level streaming (default: true) }, }, } @@ -287,10 +287,10 @@ Feishu/Lark 通过交互式卡片支持流式回复。启用后,机器人会 ### 配额优化 -使用两个可选标志来减少 Feishu/Lark API 调用次数: +使用两个可选标志减少 Feishu/Lark API 调用次数: -- `typingIndicator`(默认 `true`):设为 `false` 以跳过“正在输入”反应调用 -- `resolveSenderNames`(默认 `true`):设为 `false` 以跳过发送者资料查询 +- `typingIndicator`(默认 `true`):设置为 `false` 可跳过输入中反应调用 +- `resolveSenderNames`(默认 `true`):设置为 `false` 可跳过发送者资料查询 ```json5 { @@ -305,7 +305,7 @@ Feishu/Lark 通过交互式卡片支持流式回复。启用后,机器人会 ### ACP 会话 -Feishu/Lark 支持用于私信和群组话题消息的 ACP。Feishu/Lark ACP 由文本命令驱动——没有原生斜杠命令菜单,因此请直接在对话中使用 `/acp ...` 消息。 +Feishu/Lark 支持用于私信和群组线程消息的 ACP。Feishu/Lark ACP 由文本命令驱动,没有原生斜杠菜单,因此请直接在对话中使用 `/acp ...` 消息。 #### 持久 ACP 绑定 @@ -351,19 +351,19 @@ Feishu/Lark 支持用于私信和群组话题消息的 ACP。Feishu/Lark ACP 由 } ``` -#### 从聊天中启动 ACP +#### 从聊天中生成 ACP -在 Feishu/Lark 私信或话题中: +在 Feishu/Lark 私信或线程中: ```text /acp spawn codex --thread here ``` -`--thread here` 适用于私信和 Feishu/Lark 话题消息。后续在已绑定对话中的消息会直接路由到该 ACP 会话。 +`--thread here` 适用于私信和 Feishu/Lark 线程消息。绑定对话中的后续消息会直接路由到该 ACP 会话。 ### 多智能体路由 -使用 `bindings` 将 Feishu/Lark 私信或群组路由到不同的智能体。 +使用 `bindings` 将 Feishu/Lark 私信或群组路由到不同智能体。 ```json5 { @@ -399,41 +399,41 @@ Feishu/Lark 支持用于私信和群组话题消息的 ACP。Feishu/Lark ACP 由 - `match.peer.kind`:`"direct"`(私信)或 `"group"`(群聊) - `match.peer.id`:用户 Open ID(`ou_xxx`)或群组 ID(`oc_xxx`) -查找提示请参见[获取群组/用户 ID](#get-groupuser-ids)。 +请参阅[获取群组/用户 ID](#get-groupuser-ids)了解查找提示。 --- ## 配置参考 -完整配置: [Gateway 网关配置](/zh-CN/gateway/configuration) +完整配置:[Gateway 网关配置](/zh-CN/gateway/configuration) -| 设置 | 说明 | 默认值 | +| 设置 | 描述 | 默认值 | | ------------------------------------------------- | -------------------------------------------------------------------------------- | ---------------- | -| `channels.feishu.enabled` | 启用/禁用该渠道 | `true` | +| `channels.feishu.enabled` | 启用/停用该渠道 | `true` | | `channels.feishu.domain` | API 域名(`feishu` 或 `lark`) | `feishu` | | `channels.feishu.connectionMode` | 事件传输方式(`websocket` 或 `webhook`) | `websocket` | | `channels.feishu.defaultAccount` | 用于出站路由的默认账户 | `default` | | `channels.feishu.verificationToken` | webhook 模式必需 | — | | `channels.feishu.encryptKey` | webhook 模式必需 | — | -| `channels.feishu.webhookPath` | webhook 路由路径 | `/feishu/events` | -| `channels.feishu.webhookHost` | webhook 绑定主机 | `127.0.0.1` | -| `channels.feishu.webhookPort` | webhook 绑定端口 | `3000` | +| `channels.feishu.webhookPath` | Webhook 路由路径 | `/feishu/events` | +| `channels.feishu.webhookHost` | Webhook 绑定主机 | `127.0.0.1` | +| `channels.feishu.webhookPort` | Webhook 绑定端口 | `3000` | | `channels.feishu.accounts..appId` | App ID | — | | `channels.feishu.accounts..appSecret` | App Secret | — | -| `channels.feishu.accounts..domain` | 按账户覆盖域名 | `feishu` | -| `channels.feishu.accounts..tts` | 按账户覆盖 TTS | `messages.tts` | +| `channels.feishu.accounts..domain` | 每个账户的域名覆盖设置 | `feishu` | +| `channels.feishu.accounts..tts` | 每个账户的 TTS 覆盖设置 | `messages.tts` | | `channels.feishu.dmPolicy` | 私信策略 | `allowlist` | -| `channels.feishu.allowFrom` | 私信白名单(`open_id` 列表) | [BotOwnerId] | +| `channels.feishu.allowFrom` | 私信允许列表(open_id 列表) | [BotOwnerId] | | `channels.feishu.groupPolicy` | 群组策略 | `allowlist` | -| `channels.feishu.groupAllowFrom` | 群组白名单 | — | -| `channels.feishu.requireMention` | 在群组中要求 @提及 | `true` | -| `channels.feishu.groups..requireMention` | 按群组覆盖 @提及要求;显式 ID 在 allowlist 模式下也会让该群组获得准入 | inherited | -| `channels.feishu.groups..enabled` | 启用/禁用特定群组 | `true` | +| `channels.feishu.groupAllowFrom` | 群组允许列表 | — | +| `channels.feishu.requireMention` | 群组中要求 @mention | `true` | +| `channels.feishu.groups..requireMention` | 每个群组的 @mention 覆盖设置;显式 ID 在允许列表模式下也会准入该群组 | inherited | +| `channels.feishu.groups..enabled` | 启用/停用特定群组 | `true` | | `channels.feishu.textChunkLimit` | 消息分块大小 | `2000` | | `channels.feishu.mediaMaxMb` | 媒体大小限制 | `30` | | `channels.feishu.streaming` | 流式卡片输出 | `true` | -| `channels.feishu.blockStreaming` | 分块流式传输 | `true` | -| `channels.feishu.typingIndicator` | 发送“正在输入”反应 | `true` | +| `channels.feishu.blockStreaming` | 块级流式传输 | `true` | +| `channels.feishu.typingIndicator` | 发送正在输入反应 | `true` | | `channels.feishu.resolveSenderNames` | 解析发送者显示名称 | `true` | --- @@ -450,7 +450,7 @@ Feishu/Lark 支持用于私信和群组话题消息的 ACP。Feishu/Lark ACP 由 - ✅ 视频/媒体 - ✅ 表情贴纸 -Feishu/Lark 的入站音频消息会被标准化为媒体占位符,而不是原始 `file_key` JSON。当配置了 `tools.media.audio` 时,OpenClaw 会下载语音消息资源,并在智能体轮次开始前运行共享音频转写,因此智能体接收到的是语音转写文本。如果 Feishu 在音频负载中直接包含转写文本,则会直接使用该文本,而不会再发起一次 ASR 调用。如果没有音频转写提供商,智能体仍会接收到一个 `` 占位符以及已保存的附件,而不是原始的 Feishu 资源负载。 +入站 Feishu/Lark 音频消息会被规范化为媒体占位符,而不是原始 `file_key` JSON。当配置了 `tools.media.audio` 时,OpenClaw 会下载语音留言资源,并在智能体轮次开始前运行共享音频转写,因此智能体会收到语音转写文本。如果 Feishu 在音频载荷中直接包含转写文本,则会直接使用该文本,不再进行另一次 ASR 调用。如果没有音频转写提供商,智能体仍会收到一个 `` 占位符和已保存的附件,而不是原始 Feishu 资源载荷。 ### 发送 @@ -460,24 +460,24 @@ Feishu/Lark 的入站音频消息会被标准化为媒体占位符,而不是 - ✅ 音频 - ✅ 视频/媒体 - ✅ 交互式卡片(包括流式更新) -- ⚠️ 富文本(post 风格格式;不支持完整的 Feishu/Lark 原生编辑能力) +- ⚠️ 富文本(post 风格格式;不支持完整 Feishu/Lark 创作能力) -原生 Feishu/Lark 音频气泡使用 Feishu `audio` 消息类型,并要求上传 Ogg/Opus 媒体(`file_type: "opus"`)。现有的 `.opus` 和 `.ogg` 媒体会直接作为原生音频发送。MP3/WAV/M4A 和其他常见音频格式,仅会在回复请求语音投递时转码为 48 kHz Ogg/Opus(使用 `ffmpeg`),例如 `audioAsVoice` / 消息工具 `asVoice`,包括 TTS 语音便笺回复。普通 MP3 附件会保持为常规文件。如果缺少 `ffmpeg` 或转换失败,OpenClaw 会回退为文件附件并记录原因。 +原生 Feishu/Lark 音频气泡使用 Feishu `audio` 消息类型,并要求上传 Ogg/Opus 媒体(`file_type: "opus"`)。已有的 `.opus` 和 `.ogg` 媒体会直接作为原生音频发送。只有当回复请求语音递送(`audioAsVoice` / 消息工具 `asVoice`,包括 TTS 语音留言回复)时,MP3/WAV/M4A 和其他可能的音频格式才会通过 `ffmpeg` 转码为 48kHz Ogg/Opus。普通 MP3 附件仍作为常规文件发送。如果缺少 `ffmpeg` 或转换失败,OpenClaw 会回退为文件附件并记录原因。 -### 话题和回复 +### 线程和回复 -- ✅ 内联回复 -- ✅ 话题回复 -- ✅ 回复话题消息时,媒体回复会保持话题感知 +- ✅ 行内回复 +- ✅ 线程回复 +- ✅ 回复线程消息时,媒体回复会保持线程感知 -对于 `groupSessionScope: "group_topic"` 和 `"group_topic_sender"`,原生 Feishu/Lark 话题群组使用事件中的 `thread_id`(`omt_*`)作为规范的话题会话键。对于 OpenClaw 转换为话题的普通群组回复,仍继续使用回复根消息 ID(`om_*`),这样首轮消息和后续消息会保持在同一个会话中。 +对于 `groupSessionScope: "group_topic"` 和 `"group_topic_sender"`,原生 Feishu/Lark 话题群使用事件 `thread_id`(`omt_*`)作为规范的话题会话键。OpenClaw 转换成线程的普通群组回复会继续使用回复根消息 ID(`om_*`),因此第一轮和后续轮次会保持在同一会话中。 --- ## 相关内容 - [渠道概览](/zh-CN/channels) — 所有支持的渠道 -- [配对](/zh-CN/channels/pairing) — 私信身份验证与配对流程 +- [配对](/zh-CN/channels/pairing) — 私信认证和配对流程 - [群组](/zh-CN/channels/groups) — 群聊行为和提及门控 - [渠道路由](/zh-CN/channels/channel-routing) — 消息的会话路由 -- [安全](/zh-CN/gateway/security) — 访问模型与加固措施 +- [安全](/zh-CN/gateway/security) — 访问模型和加固 diff --git a/docs/zh-CN/channels/pairing.md b/docs/zh-CN/channels/pairing.md index 84d527c1c..415ede258 100644 --- a/docs/zh-CN/channels/pairing.md +++ b/docs/zh-CN/channels/pairing.md @@ -2,20 +2,20 @@ read_when: - 设置私信访问控制 - 配对新的 iOS/Android 节点 - - 审查 OpenClaw 的安全态势 -summary: 配对概览:批准谁可以私信你 + 哪些节点可以加入 + - 审查 OpenClaw 安全态势 +summary: 配对概览:批准谁可以给你发私信 + 哪些节点可以加入 title: 配对 x-i18n: - generated_at: "2026-04-28T22:44:28Z" + generated_at: "2026-04-29T05:57:51Z" model: gpt-5.5 provider: openai - source_hash: 123d1dccfab0a2ed8a415934eb508e373c4fe85e3d07adb5eb8aa9f3cf8a3fc9 + source_hash: cfdcaf831aedb122ea85200518b8dc1c6f42eff365444dee6c4b740050b1ce26 source_path: channels/pairing.md workflow: 16 --- “配对”是 OpenClaw 的显式访问批准步骤。 -它用于两个位置: +它用于两个地方: 1. **私信配对**(谁可以与机器人对话) 2. **节点配对**(哪些设备/节点可以加入 Gateway 网关网络) @@ -24,15 +24,20 @@ x-i18n: ## 1) 私信配对(入站聊天访问) -当某个渠道配置了私信策略 `pairing` 时,未知发送者会收到一个短代码,并且他们的消息在你批准前**不会被处理**。 +当某个渠道配置了私信策略 `pairing` 时,未知发送者会收到一个短代码,并且在你批准之前,他们的消息**不会被处理**。 默认私信策略记录在:[安全](/zh-CN/gateway/security) +只有当生效的私信允许列表包含 `"*"` 时,`dmPolicy: "open"` 才是公开的。 +设置和验证要求公开开放配置必须包含该通配符。如果现有 +状态包含带有具体 `allowFrom` 条目的 `open`,运行时仍然只允许 +这些发送者,并且配对存储的批准不会扩大 `open` 访问范围。 + 配对代码: -- 8 个字符,大写,不包含易混淆字符(`0O1I`)。 +- 8 个字符,大写,不含易混淆字符(`0O1I`)。 - **1 小时后过期**。机器人只会在创建新请求时发送配对消息(大约每个发送者每小时一次)。 -- 待处理的私信配对请求默认每个渠道最多 **3 个**;额外请求会被忽略,直到其中一个过期或获批。 +- 待处理的私信配对请求默认限制为**每个渠道 3 个**;额外请求会被忽略,直到其中一个过期或被批准。 ### 批准发送者 @@ -41,47 +46,47 @@ openclaw pairing list telegram openclaw pairing approve telegram ``` -如果尚未配置命令所有者,批准私信配对代码也会将 -`commands.ownerAllowFrom` 引导设置为获批发送者,例如 `telegram:123456789`。 -这会为首次设置提供一个显式所有者,用于特权命令和 exec +如果尚未配置命令所有者,批准私信配对代码还会将 +`commands.ownerAllowFrom` 引导设置为已批准的发送者,例如 `telegram:123456789`。 +这会为首次设置提供一个明确的所有者,用于特权命令和 exec 批准提示。所有者存在后,后续配对批准只会授予私信 -访问权限;它们不会添加更多所有者。 +访问权限;不会添加更多所有者。 支持的渠道:`bluebubbles`、`discord`、`feishu`、`googlechat`、`imessage`、`irc`、`line`、`matrix`、`mattermost`、`msteams`、`nextcloud-talk`、`nostr`、`openclaw-weixin`、`signal`、`slack`、`synology-chat`、`telegram`、`twitch`、`whatsapp`、`zalo`、`zalouser`。 -### 状态存放位置 +### 状态存储位置 存储在 `~/.openclaw/credentials/` 下: - 待处理请求:`-pairing.json` - 已批准允许列表存储: - - 默认账号:`-allowFrom.json` - - 非默认账号:`--allowFrom.json` + - 默认账户:`-allowFrom.json` + - 非默认账户:`--allowFrom.json` -账号作用域行为: +账户作用域行为: -- 非默认账号只读写其作用域化的允许列表文件。 -- 默认账号使用渠道作用域的非作用域化允许列表文件。 +- 非默认账户只读写其作用域内的允许列表文件。 +- 默认账户使用渠道作用域的非作用域允许列表文件。 -请将这些文件视为敏感信息(它们控制对你的助手的访问)。 +请将这些内容视为敏感信息(它们控制对你的助手的访问)。 -配对允许列表存储用于私信访问。群组授权是单独的。 +配对允许列表存储用于私信访问。群组授权是独立的。 批准私信配对代码不会自动允许该发送者运行群组 -命令或在群组中控制机器人。首个所有者引导是 `commands.ownerAllowFrom` -中的单独配置状态,而群聊投递仍遵循该 -渠道的群组允许列表(例如 `groupAllowFrom`、`groups`,或根据渠道而定的按群组 -或按话题覆盖项)。 +命令或在群组中控制机器人。首次所有者引导是 `commands.ownerAllowFrom` +中的独立配置状态,群聊投递仍遵循该 +渠道的群组允许列表(例如 `groupAllowFrom`、`groups`,或取决于渠道的按群组 +或按主题覆盖)。 ## 2) 节点设备配对(iOS/Android/macOS/无头节点) 节点以 `role: node` 的**设备**身份连接到 Gateway 网关。Gateway 网关 -会创建设备配对请求,且该请求必须获批。 +会创建设备配对请求,必须批准该请求。 ### 通过 Telegram 配对(推荐用于 iOS) -如果使用 `device-pair` 插件,你可以完全通过 Telegram 完成首次设备配对: +如果你使用 `device-pair` 插件,可以完全通过 Telegram 完成首次设备配对: 1. 在 Telegram 中,向你的机器人发送消息:`/pair` 2. 机器人会回复两条消息:一条说明消息,以及一条单独的**设置代码**消息(便于在 Telegram 中复制/粘贴)。 @@ -89,23 +94,23 @@ openclaw pairing approve telegram 4. 粘贴设置代码并连接。 5. 回到 Telegram:`/pair pending`(查看请求 ID、角色和作用域),然后批准。 -设置代码是一个 base64 编码的 JSON 载荷,包含: +设置代码是一个 base64 编码的 JSON 载荷,其中包含: - `url`:Gateway 网关 WebSocket URL(`ws://...` 或 `wss://...`) - `bootstrapToken`:用于初始配对握手的短期单设备引导令牌 -该引导令牌携带内置配对引导配置文件: +该引导令牌携带内置的配对引导配置文件: - 主要移交的 `node` 令牌保持 `scopes: []` -- 任何移交的 `operator` 令牌都保持受限于引导允许列表: +- 任何移交的 `operator` 令牌都受引导允许列表限制: `operator.approvals`、`operator.read`、`operator.talk.secrets`、`operator.write` -- 引导作用域检查按角色前缀划分,而不是一个扁平作用域池: +- 引导作用域检查按角色前缀区分,而不是一个扁平的作用域池: operator 作用域条目只满足 operator 请求,非 operator 角色 - 仍必须在它们自己的角色前缀下请求作用域 + 仍必须在其自身角色前缀下请求作用域 - 后续令牌轮换/撤销仍同时受设备已批准的 - 角色合约和调用方会话的 operator 作用域限制 + 角色契约和调用方会话的 operator 作用域限制 -在设置代码有效期间,请像对待密码一样对待它。 +设置代码在有效期内应像密码一样对待。 ### 批准节点设备 @@ -115,17 +120,17 @@ openclaw devices approve openclaw devices reject ``` -如果同一设备使用不同认证详情重试(例如不同 -角色/作用域/公钥),之前待处理的请求会被取代,并创建新的 +如果同一设备使用不同的认证详情重试(例如不同的 +角色/作用域/公钥),之前的待处理请求会被取代,并创建新的 `requestId`。 -已配对的设备不会静默获得更宽泛的访问权限。如果它重新连接并请求更多作用域或更宽泛角色,OpenClaw 会保持现有批准不变,并创建一个新的待处理升级请求。在批准前,使用 `openclaw devices list` 比较当前已批准访问权限与新请求的访问权限。 +已配对设备不会静默获得更广泛的访问权限。如果它重新连接并请求更多作用域或更广泛的角色,OpenClaw 会保持现有批准不变,并创建一个新的待处理升级请求。在批准前,使用 `openclaw devices list` 比较当前已批准的访问权限与新请求的访问权限。 -### 可选的受信任 CIDR 节点自动批准 +### 可选的可信 CIDR 节点自动批准 -默认情况下,设备配对仍为手动。对于严格受控的节点网络, +设备配对默认仍为手动。对于严格受控的节点网络, 你可以通过显式 CIDR 或精确 IP 选择启用首次节点自动批准: ```json5 @@ -141,7 +146,7 @@ openclaw devices reject ``` 这只适用于没有请求 -作用域的新 `role: node` 配对请求。Operator、浏览器、Control UI 和 WebChat 客户端仍需要手动 +作用域的全新 `role: node` 配对请求。Operator、浏览器、Control UI 和 WebChat 客户端仍需要手动 批准。角色、作用域、元数据和公钥变更仍需要手动 批准。 @@ -152,12 +157,12 @@ openclaw devices reject - `pending.json`(短期;待处理请求会过期) - `paired.json`(已配对设备 + 令牌) -### 注意事项 +### 备注 - 旧版 `node.pair.*` API(CLI:`openclaw nodes pending|approve|reject|remove|rename`)是一个 - 单独的 Gateway 网关自有配对存储。WS 节点仍需要设备配对。 -- 配对记录是已批准角色的持久事实来源。活动 - 设备令牌仍受限于该已批准角色集;已批准角色之外的零散令牌条目 + 独立的 Gateway 网关拥有的配对存储。WS 节点仍需要设备配对。 +- 配对记录是已批准角色的持久事实来源。活跃的 + 设备令牌仍受该已批准角色集限制;已批准角色之外的意外令牌条目 不会创建新的访问权限。 ## 相关文档 diff --git a/docs/zh-CN/channels/synology-chat.md b/docs/zh-CN/channels/synology-chat.md index 7d5935296..629748989 100644 --- a/docs/zh-CN/channels/synology-chat.md +++ b/docs/zh-CN/channels/synology-chat.md @@ -1,26 +1,26 @@ --- read_when: - - 设置 Synology Chat 与 OpenClaw 的集成 - - 调试 Synology Chat webhook 路由 -summary: Synology Chat webhook 设置和 OpenClaw 配置 + - 设置 Synology Chat 与 OpenClaw 配合使用 + - 调试 Synology Chat 网络钩子路由 +summary: Synology Chat 网络钩子设置和 OpenClaw 配置 title: Synology Chat x-i18n: - generated_at: "2026-04-23T20:42:03Z" - model: gpt-5.4 + generated_at: "2026-04-29T05:57:46Z" + model: gpt-5.5 provider: openai - source_hash: 5135e9aa1fd86437a635378dfbbde321bbd2e5f6fef7a3cc740ea54ebf4b76d5 + source_hash: c3d6d7a56bd15d29de38c6ae29ae496b491c2e75df5e0a0a15410b0fbdc55a00 source_path: channels/synology-chat.md - workflow: 15 + workflow: 16 --- -状态:内置插件的私信渠道,使用 Synology Chat webhooks。 -该插件接收来自 Synology Chat 出站 webhook 的入站消息,并通过 Synology Chat 入站 webhook 发送回复。 +Status:使用 Synology Chat webhook 的内置插件私信渠道。 +该插件接受来自 Synology Chat outgoing webhook 的入站消息,并通过 Synology Chat incoming webhook 发送回复。 ## 内置插件 -在当前 OpenClaw 版本中,Synology Chat 作为内置插件提供,因此常规打包构建不需要单独安装。 +Synology Chat 在当前 OpenClaw 版本中作为内置插件随附,因此正常的打包构建不需要单独安装。 -如果你使用的是较旧的构建版本,或是不包含 Synology Chat 的自定义安装,请手动安装: +如果你使用的是较旧构建,或排除了 Synology Chat 的自定义安装,请手动安装: 从本地检出安装: @@ -28,35 +28,35 @@ x-i18n: openclaw plugins install ./path/to/local/synology-chat-plugin ``` -详情参见:[Plugins](/zh-CN/tools/plugin) +详情:[插件](/zh-CN/tools/plugin) ## 快速设置 1. 确保 Synology Chat 插件可用。 - 当前打包的 OpenClaw 版本已内置该插件。 - - 较旧/自定义安装可通过上面的命令,从源码检出中手动添加。 + - 较旧/自定义安装可以使用上面的命令从源码检出手动添加。 - `openclaw onboard` 现在会在与 `openclaw channels add` 相同的渠道设置列表中显示 Synology Chat。 - 非交互式设置:`openclaw channels add --channel synology-chat --token --url ` 2. 在 Synology Chat 集成中: - - 创建一个入站 webhook 并复制其 URL。 - - 创建一个带有你的 secret token 的出站 webhook。 -3. 将出站 webhook URL 指向你的 OpenClaw Gateway 网关: + - 创建一个 incoming webhook 并复制其 URL。 + - 使用你的 secret token 创建一个 outgoing webhook。 +3. 将 outgoing webhook URL 指向你的 OpenClaw Gateway 网关: - 默认是 `https://gateway-host/webhook/synology`。 - - 或者使用你自定义的 `channels.synology-chat.webhookPath`。 + - 或使用你的自定义 `channels.synology-chat.webhookPath`。 4. 在 OpenClaw 中完成设置。 - 引导式:`openclaw onboard` - - 直接设置:`openclaw channels add --channel synology-chat --token --url ` -5. 重启 Gateway 网关,并向 Synology Chat bot 发送一条私信。 + - 直接:`openclaw channels add --channel synology-chat --token --url ` +5. 重启 Gateway 网关,并向 Synology Chat 机器人发送私信。 -Webhook 身份验证详情: +Webhook 认证详情: -- OpenClaw 按顺序从 `body.token`、然后 `?token=...`、再然后 headers 中接受出站 webhook token。 +- OpenClaw 会先从 `body.token` 接受 outgoing webhook token,然后是 `?token=...`,最后是 headers。 - 接受的 header 形式: - `x-synology-token` - `x-webhook-token` - `x-openclaw-token` - `Authorization: Bearer ` -- 空 token 或缺失 token 会以失败关闭方式处理。 +- 空 token 或缺失 token 会失败关闭。 最小配置: @@ -90,23 +90,23 @@ Webhook 身份验证详情: 配置值会覆盖环境变量。 -`SYNOLOGY_CHAT_INCOMING_URL` 不能通过工作区 `.env` 设置;参见 [工作区 `.env` 文件](/zh-CN/gateway/security)。 +`SYNOLOGY_CHAT_INCOMING_URL` 不能从工作区 `.env` 设置;请参阅[工作区 `.env` 文件](/zh-CN/gateway/security)。 -## 私信策略与访问控制 +## 私信策略和访问控制 -- 推荐默认使用 `dmPolicy: "allowlist"`。 +- `dmPolicy: "allowlist"` 是推荐的默认值。 - `allowedUserIds` 接受 Synology 用户 ID 列表(或逗号分隔字符串)。 -- 在 `allowlist` 模式下,空的 `allowedUserIds` 列表会被视为配置错误,webhook 路由不会启动(如需允许所有人,请使用 `dmPolicy: "open"`)。 -- `dmPolicy: "open"` 允许任意发送者。 -- `dmPolicy: "disabled"` 阻止私信。 -- 回复接收方绑定默认保持基于稳定的数字 `user_id`。`channels.synology-chat.dangerouslyAllowNameMatching: true` 是紧急兼容模式,会重新启用基于可变用户名/昵称查找的回复投递。 -- 配对批准可配合以下命令使用: +- 在 `allowlist` 模式下,空的 `allowedUserIds` 列表会被视为配置错误,webhook 路由不会启动(如需允许所有用户,请使用 `dmPolicy: "open"` 与 `allowedUserIds: ["*"]`)。 +- 只有当 `allowedUserIds` 包含 `"*"` 时,`dmPolicy: "open"` 才允许公开私信;如果是限制性条目,则只有匹配的用户可以聊天。 +- `dmPolicy: "disabled"` 会阻止私信。 +- 默认情况下,回复收件人绑定保持在稳定的数字 `user_id` 上。`channels.synology-chat.dangerouslyAllowNameMatching: true` 是应急兼容模式,会重新启用可变用户名/昵称查找来投递回复。 +- 配对批准可使用: - `openclaw pairing list synology-chat` - `openclaw pairing approve synology-chat ` ## 出站投递 -请使用数字 Synology Chat 用户 ID 作为目标。 +使用数字 Synology Chat 用户 ID 作为目标。 示例: @@ -115,16 +115,16 @@ openclaw message send --channel synology-chat --target 123456 --text "Hello from openclaw message send --channel synology-chat --target synology-chat:123456 --text "Hello again" ``` -支持通过基于 URL 的文件投递发送媒体。 -出站文件 URL 必须使用 `http` 或 `https`,私有网络或其他被阻止的网络目标会在 OpenClaw 将 URL 转发给 NAS webhook 之前被拒绝。 +支持通过基于 URL 的文件投递发送媒体。 +出站文件 URL 必须使用 `http` 或 `https`,并且在 OpenClaw 将该 URL 转发到 NAS webhook 之前,会拒绝私有或其他被阻止的网络目标。 ## 多账户 -支持在 `channels.synology-chat.accounts` 下配置多个 Synology Chat 账户。 -每个账户都可以覆盖 token、入站 URL、webhook 路径、私信策略和限制。 -私信会话会按账户和用户隔离,因此两个不同 Synology 账户上的同一个数字 `user_id` 不会共享转录状态。 -请为每个已启用账户提供不同的 `webhookPath`。OpenClaw 现在会拒绝重复的精确路径,并在多账户设置中拒绝启动那些仅继承共享 webhook 路径的具名账户。 -如果你确实需要为具名账户保留旧版继承行为,请在该账户或 `channels.synology-chat` 上设置 `dangerouslyAllowInheritedWebhookPath: true`,但重复的精确路径仍会以失败关闭方式被拒绝。推荐为每个账户显式配置路径。 +`channels.synology-chat.accounts` 下支持多个 Synology Chat 账户。 +每个账户都可以覆盖 token、incoming URL、webhook path、私信策略和限制。 +私信会话按账户和用户隔离,因此两个不同 Synology 账户上的相同数字 `user_id` 不会共享对话状态。 +为每个已启用账户指定不同的 `webhookPath`。OpenClaw 现在会拒绝重复的精确路径,并且在多账户设置中会拒绝启动仅继承共享 webhook path 的命名账户。 +如果你有意需要为某个命名账户使用旧版继承,请在该账户上或在 `channels.synology-chat` 设置 `dangerouslyAllowInheritedWebhookPath: true`,但重复的精确路径仍会失败关闭。优先使用显式的按账户路径。 ```json5 { @@ -151,35 +151,35 @@ openclaw message send --channel synology-chat --target synology-chat:123456 --te ## 安全说明 -- 请妥善保管 `token`,如有泄露请轮换。 -- 除非你明确信任使用自签名本地 NAS 证书,否则请保持 `allowInsecureSsl: false`。 -- 入站 webhook 请求会进行 token 验证,并按发送者进行速率限制。 -- 无效 token 检查使用常量时间 secret 比较,并以失败关闭方式处理。 -- 在生产环境中,优先使用 `dmPolicy: "allowlist"`。 -- 除非你明确需要旧版基于用户名的回复投递,否则请保持 `dangerouslyAllowNameMatching` 关闭。 -- 除非你明确接受多账户设置中共享路径路由的风险,否则请保持 `dangerouslyAllowInheritedWebhookPath` 关闭。 +- 保持 `token` 机密,如果泄露请轮换。 +- 除非你明确信任自签名的本地 NAS 证书,否则保持 `allowInsecureSsl: false`。 +- 入站 webhook 请求会按发送者进行 token 验证和限速。 +- 无效 token 检查使用常量时间 secret 比较,并失败关闭。 +- 生产环境优先使用 `dmPolicy: "allowlist"`。 +- 除非你明确需要基于旧版用户名的回复投递,否则保持 `dangerouslyAllowNameMatching` 关闭。 +- 除非你明确接受多账户设置中的共享路径路由风险,否则保持 `dangerouslyAllowInheritedWebhookPath` 关闭。 ## 故障排除 - `Missing required fields (token, user_id, text)`: - - 出站 webhook 负载缺少所需字段之一 + - outgoing webhook payload 缺少某个必填字段 - 如果 Synology 通过 headers 发送 token,请确保 Gateway 网关/代理保留这些 headers - `Invalid token`: - - 出站 webhook secret 与 `channels.synology-chat.token` 不匹配 - - 请求命中了错误的账户/webhook 路径 - - 反向代理在请求到达 OpenClaw 前剥离了 token header + - outgoing webhook secret 与 `channels.synology-chat.token` 不匹配 + - 请求命中了错误的账户/webhook path + - 反向代理在请求到达 OpenClaw 之前剥离了 token header - `Rate limit exceeded`: - - 来自同一来源的过多无效 token 尝试,可能会暂时将该来源锁定 - - 已认证发送者也会受到单独的按用户消息速率限制 -- `Allowlist is empty. Configure allowedUserIds or use dmPolicy=open.`: - - 已启用 `dmPolicy="allowlist"`,但未配置任何用户 + - 来自同一来源的无效 token 尝试过多,可能会暂时锁定该来源 + - 已认证发送者也有单独的按用户消息速率限制 +- `Allowlist is empty. Configure allowedUserIds or use dmPolicy=open with allowedUserIds=["*"].`: + - `dmPolicy="allowlist"` 已启用,但未配置用户 - `User not authorized`: - 发送者的数字 `user_id` 不在 `allowedUserIds` 中 -## 相关内容 +## 相关 -- [渠道概览](/zh-CN/channels) — 所有受支持的渠道 -- [配对](/zh-CN/channels/pairing) — 私信身份验证与配对流程 -- [群组](/zh-CN/channels/groups) — 群聊行为与提及门控 +- [渠道概览](/zh-CN/channels) — 所有支持的渠道 +- [配对](/zh-CN/channels/pairing) — 私信认证和配对流程 +- [群组](/zh-CN/channels/groups) — 群聊行为和提及门控 - [渠道路由](/zh-CN/channels/channel-routing) — 消息的会话路由 -- [安全](/zh-CN/gateway/security) — 访问模型与安全加固 +- [安全](/zh-CN/gateway/security) — 访问模型和加固 diff --git a/docs/zh-CN/channels/telegram.md b/docs/zh-CN/channels/telegram.md index 94e794c29..960fd23de 100644 --- a/docs/zh-CN/channels/telegram.md +++ b/docs/zh-CN/channels/telegram.md @@ -4,15 +4,15 @@ read_when: summary: Telegram 机器人支持状态、能力和配置 title: Telegram x-i18n: - generated_at: "2026-04-28T23:40:09Z" + generated_at: "2026-04-29T05:57:36Z" model: gpt-5.5 provider: openai - source_hash: aecd9edba56d0689a5823536a92171fa6e0c3ef56656f4699bb1e5793e248751 + source_hash: 0bf75d82f21658a1ca547b2e4ab229f7b6e47537a2379bf52bd7a18f0677664b source_path: channels/telegram.md workflow: 16 --- -通过 grammY 可用于生产环境中的机器人私信和群组。长轮询是默认模式;webhook 模式是可选的。 +可用于生产环境的机器人私信和群组,基于 grammY。长轮询是默认模式;webhook 模式可选。 @@ -30,9 +30,9 @@ x-i18n: - 打开 Telegram 并与 **@BotFather** 聊天(确认用户名正好是 `@BotFather`)。 + 打开 Telegram 并与 **@BotFather** 聊天(确认用户名正是 `@BotFather`)。 - 运行 `/newbot`,按照提示操作,并保存令牌。 + 运行 `/newbot`,按提示操作,并保存令牌。 @@ -52,7 +52,7 @@ x-i18n: ``` 环境变量回退:`TELEGRAM_BOT_TOKEN=...`(仅默认账号)。 - Telegram **不**使用 `openclaw channels login telegram`;请在配置/环境变量中配置令牌,然后启动 Gateway 网关。 + Telegram **不**使用 `openclaw channels login telegram`;在配置/环境变量中配置令牌,然后启动 Gateway 网关。 @@ -64,38 +64,38 @@ openclaw pairing list telegram openclaw pairing approve telegram ``` - 配对码会在 1 小时后过期。 + 配对代码会在 1 小时后过期。 - 将机器人添加到你的群组,然后设置 `channels.telegram.groups` 和 `groupPolicy`,以匹配你的访问模型。 + 将机器人添加到你的群组,然后设置 `channels.telegram.groups` 和 `groupPolicy` 以匹配你的访问模型。 -令牌解析顺序支持账号感知。实际使用中,配置值优先于环境变量回退,并且 `TELEGRAM_BOT_TOKEN` 仅适用于默认账号。 +令牌解析顺序支持账号感知。实际使用中,配置值优先于环境变量回退,且 `TELEGRAM_BOT_TOKEN` 仅适用于默认账号。 -## Telegram 端设置 +## Telegram 侧设置 - Telegram 机器人默认启用**隐私模式**,这会限制它们能接收哪些群组消息。 + Telegram 机器人默认使用**隐私模式**,这会限制它们能接收的群组消息。 如果机器人必须看到所有群组消息,可以: - 通过 `/setprivacy` 禁用隐私模式,或 - 将机器人设为群组管理员。 - 切换隐私模式后,请在每个群组中移除并重新添加机器人,以便 Telegram 应用该更改。 + 切换隐私模式时,请在每个群组中移除并重新添加机器人,以便 Telegram 应用该变更。 管理员状态在 Telegram 群组设置中控制。 - 管理员机器人会接收所有群组消息,这对常驻群组行为很有用。 + 管理员机器人会接收所有群组消息,这对始终在线的群组行为很有用。 @@ -111,27 +111,28 @@ openclaw pairing approve telegram - `channels.telegram.dmPolicy` 控制直接消息访问: + `channels.telegram.dmPolicy` 控制私信访问: - `pairing`(默认) - `allowlist`(要求 `allowFrom` 中至少有一个发送者 ID) - `open`(要求 `allowFrom` 包含 `"*"`) - `disabled` - 使用 `dmPolicy: "open"` 且 `allowFrom: ["*"]` 时,任何找到或猜到机器人用户名的 Telegram 账号都可以向机器人发出命令。只应将它用于有意公开、且工具受到严格限制的机器人;单所有者机器人应使用带数字用户 ID 的 `allowlist`。 + `dmPolicy: "open"` 搭配 `allowFrom: ["*"]` 会让任何找到或猜到机器人用户名的 Telegram 账号都能命令机器人。仅在有意公开且工具权限严格受限的机器人上使用;单所有者机器人应使用带数字用户 ID 的 `allowlist`。 - `channels.telegram.allowFrom` 接受数字 Telegram 用户 ID。`telegram:` / `tg:` 前缀会被接受并规范化。 - `dmPolicy: "allowlist"` 搭配空的 `allowFrom` 会阻止所有私信,并会被配置验证拒绝。 - 设置过程只会要求输入数字用户 ID。 - 如果你已升级且配置中包含 `@username` 允许列表条目,请运行 `openclaw doctor --fix` 解析它们(尽力而为;需要 Telegram 机器人令牌)。 - 如果你之前依赖配对存储中的允许列表文件,`openclaw doctor --fix` 可以在 allowlist 流程中将条目恢复到 `channels.telegram.allowFrom`(例如当 `dmPolicy: "allowlist"` 还没有显式 ID 时)。 + `channels.telegram.allowFrom` 接受数字 Telegram 用户 ID。接受并规范化 `telegram:` / `tg:` 前缀。 + 在多账号配置中,限制性的顶层 `channels.telegram.allowFrom` 会被视为安全边界:账号级 `allowFrom: ["*"]` 条目不会让该账号公开,除非合并后的有效账号允许列表仍包含显式通配符。 + `dmPolicy: "allowlist"` 搭配空 `allowFrom` 会阻止所有私信,并会被配置验证拒绝。 + 设置只会询问数字用户 ID。 + 如果你升级后配置中包含 `@username` 允许列表条目,请运行 `openclaw doctor --fix` 来解析它们(尽力处理;需要 Telegram 机器人令牌)。 + 如果你以前依赖配对存储允许列表文件,`openclaw doctor --fix` 可以在允许列表流程中将条目恢复到 `channels.telegram.allowFrom`(例如 `dmPolicy: "allowlist"` 还没有显式 ID 时)。 - 对于单所有者机器人,建议使用 `dmPolicy: "allowlist"` 并配置显式的数字 `allowFrom` ID,以便让访问策略在配置中保持持久(而不是依赖之前的配对批准)。 + 对于单所有者机器人,优先使用带显式数字 `allowFrom` ID 的 `dmPolicy: "allowlist"`,以便在配置中保持访问策略持久化(而不是依赖之前的配对批准)。 - 常见混淆:批准私信配对并不意味着“这个发送者在所有地方都已授权”。 - 配对授予私信访问权限。如果还没有命令所有者,第一次获批的配对也会设置 `commands.ownerAllowFrom`,让仅所有者命令和执行批准拥有显式操作员账号。 - 群组发送者授权仍然来自显式配置允许列表。 - 如果你希望“我授权一次后,私信和群组命令都能使用”,请将你的数字 Telegram 用户 ID 放入 `channels.telegram.allowFrom`;对于仅所有者命令,请确保 `commands.ownerAllowFrom` 包含 `telegram:`。 + 常见误解:私信配对批准并不意味着“此发送者在所有地方都已授权”。 + 配对授予私信访问权限。如果还没有命令所有者,首次获批的配对也会设置 `commands.ownerAllowFrom`,让仅所有者命令和 exec 批准拥有显式操作员账号。 + 群组发送者授权仍来自显式配置允许列表。 + 如果你想要“我授权一次后,私信和群组命令都可用”,请将你的数字 Telegram 用户 ID 放入 `channels.telegram.allowFrom`;对于仅所有者命令,请确保 `commands.ownerAllowFrom` 包含 `telegram:`。 ### 查找你的 Telegram 用户 ID @@ -147,7 +148,7 @@ openclaw pairing approve telegram curl "https://api.telegram.org/bot/getUpdates" ``` - 第三方方法(隐私性较低):`@userinfobot` 或 `@getidsbot`。 + 第三方方法(隐私性较弱):`@userinfobot` 或 `@getidsbot`。 @@ -155,9 +156,9 @@ curl "https://api.telegram.org/bot/getUpdates" 两个控制项会共同生效: 1. **允许哪些群组**(`channels.telegram.groups`) - - 没有 `groups` 配置: - - 使用 `groupPolicy: "open"`:任何群组都可以通过群组 ID 检查 - - 使用 `groupPolicy: "allowlist"`(默认):群组会被阻止,直到你添加 `groups` 条目(或 `"*"`) + - 无 `groups` 配置: + - 搭配 `groupPolicy: "open"`:任何群组都可以通过群组 ID 检查 + - 搭配 `groupPolicy: "allowlist"`(默认):群组会被阻止,直到你添加 `groups` 条目(或 `"*"`) - 已配置 `groups`:作为允许列表(显式 ID 或 `"*"`) 2. **群组中允许哪些发送者**(`channels.telegram.groupPolicy`) @@ -167,13 +168,13 @@ curl "https://api.telegram.org/bot/getUpdates" `groupAllowFrom` 用于群组发送者过滤。如果未设置,Telegram 会回退到 `allowFrom`。 `groupAllowFrom` 条目应为数字 Telegram 用户 ID(`telegram:` / `tg:` 前缀会被规范化)。 - 不要将 Telegram 群组或超级群组聊天 ID 放入 `groupAllowFrom`。负数聊天 ID 属于 `channels.telegram.groups`。 - 非数字条目会被发送者授权忽略。 - 安全边界(`2026.2.25+`):群组发送者认证**不会**继承私信配对存储批准。 - 配对只适用于私信。对于群组,请设置 `groupAllowFrom` 或按群组/按话题设置 `allowFrom`。 + 不要将 Telegram 群组或超级群组聊天 ID 放入 `groupAllowFrom`。负数聊天 ID 应放在 `channels.telegram.groups` 下。 + 非数字条目会在发送者授权中被忽略。 + 安全边界(`2026.2.25+`):群组发送者身份验证**不会**继承私信配对存储批准。 + 配对仅用于私信。对于群组,请设置 `groupAllowFrom` 或按群组/主题设置 `allowFrom`。 如果未设置 `groupAllowFrom`,Telegram 会回退到配置中的 `allowFrom`,而不是配对存储。 单所有者机器人的实用模式:在 `channels.telegram.allowFrom` 中设置你的用户 ID,保持 `groupAllowFrom` 未设置,并在 `channels.telegram.groups` 下允许目标群组。 - 运行时说明:如果完全缺少 `channels.telegram`,运行时默认会以失败关闭方式使用 `groupPolicy="allowlist"`,除非显式设置了 `channels.defaults.groupPolicy`。 + 运行时注意事项:如果完全缺少 `channels.telegram`,运行时会默认以失败关闭方式使用 `groupPolicy="allowlist"`,除非显式设置了 `channels.defaults.groupPolicy`。 示例:允许一个特定群组中的任何成员: @@ -192,7 +193,7 @@ curl "https://api.telegram.org/bot/getUpdates" } ``` - 示例:只允许一个特定群组内的特定用户: + 示例:仅允许一个特定群组中的特定用户: ```json5 { @@ -212,9 +213,9 @@ curl "https://api.telegram.org/bot/getUpdates" 常见错误:`groupAllowFrom` 不是 Telegram 群组允许列表。 - - 将像 `-1001234567890` 这样的负数 Telegram 群组或超级群组聊天 ID 放到 `channels.telegram.groups` 下。 - - 当你想限制允许群组内哪些人可以触发机器人时,将像 `8734062810` 这样的 Telegram 用户 ID 放到 `groupAllowFrom` 下。 - - 仅当你希望允许群组中的任何成员都能与机器人交谈时,才使用 `groupAllowFrom: ["*"]`。 + - 将类似 `-1001234567890` 的负数 Telegram 群组或超级群组聊天 ID 放在 `channels.telegram.groups` 下。 + - 当你想限制允许群组中哪些人可以触发机器人时,将类似 `8734062810` 的 Telegram 用户 ID 放在 `groupAllowFrom` 下。 + - 仅当你希望允许群组中的任何成员都能与机器人对话时,才使用 `groupAllowFrom: ["*"]`。 @@ -235,9 +236,9 @@ curl "https://api.telegram.org/bot/getUpdates" - `/activation always` - `/activation mention` - 这些只会更新会话状态。使用配置实现持久化。 + 这些只会更新会话状态。使用配置来持久化。 - 持久配置示例: + 持久化配置示例: ```json5 { @@ -254,7 +255,7 @@ curl "https://api.telegram.org/bot/getUpdates" 获取群组聊天 ID: - 将群组消息转发给 `@userinfobot` / `@getidsbot` - - 或从 `openclaw logs --follow` 中读取 `chat.id` + - 或从 `openclaw logs --follow` 读取 `chat.id` - 或检查 Bot API `getUpdates` @@ -264,12 +265,12 @@ curl "https://api.telegram.org/bot/getUpdates" - Telegram 由 Gateway 网关进程拥有。 - 路由是确定性的:Telegram 入站消息会回复到 Telegram(模型不会选择渠道)。 -- 入站消息会规范化为共享渠道信封,并包含回复元数据和媒体占位符。 -- 群组会话按群组 ID 隔离。论坛话题会追加 `:topic:`,以保持话题隔离。 -- 私信消息可以携带 `message_thread_id`;OpenClaw 会使用支持线程感知的会话键路由,并在回复中保留线程 ID。 -- 长轮询使用 grammY runner,并按聊天/按线程排序。整体 runner sink 并发使用 `agents.defaults.maxConcurrent`。 -- 长轮询在每个 Gateway 网关进程内受到保护,因此一次只能有一个活跃 poller 使用某个机器人令牌。如果你仍然看到 `getUpdates` 409 冲突,可能是另一个 OpenClaw Gateway 网关、脚本或外部 poller 正在使用同一个令牌。 -- 默认情况下,长轮询看门狗会在 120 秒内没有完成的 `getUpdates` 活性信号后触发重启。只有当你的部署在长时间运行工作期间仍然看到误报的轮询停滞重启时,才增加 `channels.telegram.pollingStallThresholdMs`。该值以毫秒为单位,允许范围为 `30000` 到 `600000`;支持按账号覆盖。 +- 入站消息会规范化为共享渠道信封,并带有回复元数据和媒体占位符。 +- 群组会话按群组 ID 隔离。论坛主题会追加 `:topic:` 以保持主题隔离。 +- 私信消息可以携带 `message_thread_id`;OpenClaw 会使用线程感知的会话键路由它们,并为回复保留线程 ID。 +- 长轮询使用 grammY runner,并按聊天/线程排序。总体 runner sink 并发使用 `agents.defaults.maxConcurrent`。 +- 每个 Gateway 网关进程内部都会保护长轮询,因此同一时间只有一个活跃轮询器可以使用一个机器人令牌。如果你仍然看到 `getUpdates` 409 冲突,可能是另一个 OpenClaw Gateway 网关、脚本或外部轮询器正在使用同一个令牌。 +- 长轮询看门狗默认会在 120 秒内没有完成的 `getUpdates` 活跃性后触发重启。仅当你的部署在长时间运行工作期间仍看到误判的轮询停滞重启时,才增加 `channels.telegram.pollingStallThresholdMs`。该值以毫秒为单位,允许范围为 `30000` 到 `600000`;支持按账号覆盖。 - Telegram Bot API 不支持已读回执(`sendReadReceipts` 不适用)。 ## 功能参考 @@ -279,16 +280,16 @@ curl "https://api.telegram.org/bot/getUpdates" OpenClaw 可以实时流式传输部分回复: - 直接聊天:预览消息 + `editMessageText` - - 群组/话题:预览消息 + `editMessageText` + - 群组/主题:预览消息 + `editMessageText` 要求: - `channels.telegram.streaming` 为 `off | partial | block | progress`(默认:`partial`) - - `progress` 在 Telegram 上映射为 `partial`(与跨渠道命名兼容) - - `streaming.preview.toolProgress` 控制工具/进度更新是否复用同一条已编辑的预览消息(默认:预览流式传输处于活动状态时为 `true`) - - 会检测旧版 `channels.telegram.streamMode` 和布尔 `streaming` 值;运行 `openclaw doctor --fix` 将它们迁移到 `channels.telegram.streaming.mode` + - `progress` 在 Telegram 上映射为 `partial`(兼容跨渠道命名) + - `streaming.preview.toolProgress` 控制工具/进度更新是否复用同一条已编辑的预览消息(预览流式传输处于活跃状态时默认为 `true`) + - 会检测旧版 `channels.telegram.streamMode` 和布尔值 `streaming`;运行 `openclaw doctor --fix` 将它们迁移到 `channels.telegram.streaming.mode` - 工具进度预览更新是在工具运行时显示的简短“Working...”行,例如命令执行、文件读取、规划更新或补丁摘要。Telegram 默认保持启用这些内容,以匹配 `v2026.4.22` 及更高版本发布的 OpenClaw 行为。若要保留答案文本的编辑预览但隐藏工具进度行,请设置: + 工具进度预览更新是在工具运行时显示的短“Working...”行,例如命令执行、文件读取、规划更新或补丁摘要。Telegram 默认保持启用这些更新,以匹配 `v2026.4.22` 及更高版本中已发布的 OpenClaw 行为。若要为回答文本保留已编辑预览,但隐藏工具进度行,请设置: ```json { @@ -305,39 +306,39 @@ curl "https://api.telegram.org/bot/getUpdates" } ``` - 仅当你想要只投递最终结果时,才使用 `streaming.mode: "off"`:Telegram 预览编辑会被禁用,通用工具/进度闲聊会被抑制,而不是作为独立的“Working...”消息发送。批准提示、媒体载荷和错误仍然会通过正常的最终投递路由。仅当你只想保留答案预览编辑、同时隐藏工具进度状态行时,才使用 `streaming.preview.toolProgress: false`。 + 仅当你希望只交付最终结果时,才使用 `streaming.mode: "off"`:Telegram 预览编辑会被禁用,通用工具/进度杂讯会被抑制,而不是作为独立“Working...”消息发送。批准提示、媒体载荷和错误仍会通过正常的最终交付路由。仅当你只想保留回答预览编辑,同时隐藏工具进度状态行时,才使用 `streaming.preview.toolProgress: false`。 对于纯文本回复: - - 简短的私信/群组/话题预览:OpenClaw 会保留同一条预览消息,并在原处执行最终编辑 - - 早于约一分钟的预览:OpenClaw 会将完整回复作为新的最终消息发送,然后清理预览,因此 Telegram 的可见时间戳会反映完成时间,而不是预览创建时间 + - 短私信/群组/topic 预览:OpenClaw 保留同一条预览消息,并在原处执行最终编辑 + - 超过约一分钟的预览:OpenClaw 会将完成的回复作为一条新的最终消息发送,然后清理预览,因此 Telegram 可见时间戳会反映完成时间,而不是预览创建时间 - 对于复杂回复(例如媒体负载),OpenClaw 会回退到正常的最终交付,然后清理预览消息。 + 对于复杂回复(例如媒体载荷),OpenClaw 会回退到普通的最终投递,然后清理预览消息。 - 预览流式传输与分块流式传输是分开的。当 Telegram 显式启用分块流式传输时,OpenClaw 会跳过预览流,避免重复流式传输。 + 预览流式传输独立于分块流式传输。当为 Telegram 显式启用分块流式传输时,OpenClaw 会跳过预览流,避免双重流式传输。 - 如果原生草稿传输不可用或被拒绝,OpenClaw 会自动回退到 `sendMessage` + `editMessageText`。 + 如果原生草稿传输不可用/被拒绝,OpenClaw 会自动回退到 `sendMessage` + `editMessageText`。 - 仅限 Telegram 的推理流: + 仅 Telegram 的推理流: - - `/reasoning stream` 在生成时将推理发送到实时预览 + - `/reasoning stream` 会在生成时将推理发送到实时预览 - 最终答案发送时不包含推理文本 - + 出站文本使用 Telegram `parse_mode: "HTML"`。 - 类 Markdown 文本会渲染为 Telegram 安全的 HTML。 - 原始模型 HTML 会被转义,以减少 Telegram 解析失败。 - 如果 Telegram 拒绝解析后的 HTML,OpenClaw 会以纯文本重试。 - 链接预览默认启用,可以通过 `channels.telegram.linkPreview: false` 禁用。 + 链接预览默认启用,可通过 `channels.telegram.linkPreview: false` 禁用。 - Telegram 命令菜单注册在启动时通过 `setMyCommands` 处理。 + Telegram 命令菜单注册会在启动时通过 `setMyCommands` 处理。 原生命令默认值: @@ -368,39 +369,39 @@ curl "https://api.telegram.org/bot/getUpdates" 注意: - 自定义命令只是菜单项;它们不会自动实现行为 - - 即使未显示在 Telegram 菜单中,插件/skill 命令在输入时仍然可以工作 + - 插件/skill 命令即使未显示在 Telegram 菜单中,输入时仍可工作 - 如果禁用原生命令,内置命令会被移除。自定义/插件命令在已配置时仍可注册。 + 如果禁用原生命令,内置命令会被移除。自定义/插件命令在配置后仍可能注册。 常见设置失败: - - `setMyCommands failed` 带有 `BOT_COMMANDS_TOO_MUCH` 表示 Telegram 菜单在裁剪后仍然超出限制;减少插件/skill/自定义命令,或禁用 `channels.telegram.commands.native`。 - - 当直接的 Bot API curl 命令可用,但 `deleteWebhook`、`deleteMyCommands` 或 `setMyCommands` 失败并出现 `404: Not Found`,可能表示 `channels.telegram.apiRoot` 被设置成了完整的 `/bot` 端点。`apiRoot` 必须只是 Bot API 根地址,并且 `openclaw doctor --fix` 会移除意外尾随的 `/bot`。 - - `getMe returned 401` 表示 Telegram 拒绝了已配置的 bot token。使用当前 BotFather token 更新 `botToken`、`tokenFile` 或 `TELEGRAM_BOT_TOKEN`;OpenClaw 会在轮询前停止,因此这不会被报告为 webhook 清理失败。 - - `setMyCommands failed` 带有 network/fetch 错误通常表示到 `api.telegram.org` 的出站 DNS/HTTPS 被阻断。 + - `setMyCommands failed` 搭配 `BOT_COMMANDS_TOO_MUCH` 表示 Telegram 菜单在裁剪后仍然溢出;减少插件/skill/自定义命令,或禁用 `channels.telegram.commands.native`。 + - 当直接 Bot API curl 命令可用,但 `deleteWebhook`、`deleteMyCommands` 或 `setMyCommands` 失败并显示 `404: Not Found` 时,可能表示 `channels.telegram.apiRoot` 被设置为了完整的 `/bot` 端点。`apiRoot` 必须只是 Bot API 根地址,并且 `openclaw doctor --fix` 会移除意外尾随的 `/bot`。 + - `getMe returned 401` 表示 Telegram 拒绝了配置的 bot token。使用当前 BotFather token 更新 `botToken`、`tokenFile` 或 `TELEGRAM_BOT_TOKEN`;OpenClaw 会在轮询前停止,因此这不会报告为 webhook 清理失败。 + - `setMyCommands failed` 搭配网络/fetch 错误通常表示到 `api.telegram.org` 的出站 DNS/HTTPS 被阻止。 ### 设备配对命令(`device-pair` 插件) - 安装 `device-pair` 插件后: + 当安装了 `device-pair` 插件时: 1. `/pair` 生成设置代码 2. 在 iOS 应用中粘贴代码 - 3. `/pair pending` 列出待处理请求(包括角色/作用域) + 3. `/pair pending` 列出待处理请求(包括角色/范围) 4. 批准请求: - `/pair approve ` 用于显式批准 - - 只有一个待处理请求时使用 `/pair approve` + - 当只有一个待处理请求时使用 `/pair approve` - `/pair approve latest` 用于最近的请求 - 设置代码携带一个短期 bootstrap token。内置 bootstrap handoff 会将主节点 token 保持在 `scopes: []`;任何交接的 operator token 都会被限制在 `operator.approvals`、`operator.read`、`operator.talk.secrets` 和 `operator.write`。Bootstrap 作用域检查带有角色前缀,因此该 operator allowlist 只满足 operator 请求;非 operator 角色仍然需要其自身角色前缀下的作用域。 + 设置代码携带一个短期 bootstrap token。内置 bootstrap 交接会将主节点 token 保持在 `scopes: []`;任何被交接的操作员 token 都限制在 `operator.approvals`、`operator.read`、`operator.talk.secrets` 和 `operator.write`。Bootstrap 范围检查带有角色前缀,因此该操作员允许列表只满足操作员请求;非操作员角色仍需要其自身角色前缀下的范围。 - 如果设备使用已更改的认证详情重试(例如角色/作用域/公钥),之前的待处理请求会被取代,新请求会使用不同的 `requestId`。批准前请重新运行 `/pair pending`。 + 如果设备使用更改后的认证详情重试(例如角色/范围/公钥),之前的待处理请求会被取代,新请求会使用不同的 `requestId`。批准前请重新运行 `/pair pending`。 更多详情:[配对](/zh-CN/channels/pairing#pair-via-telegram-recommended-for-ios)。 - 配置内联键盘作用域: + 配置内联键盘范围: ```json5 { @@ -414,7 +415,7 @@ curl "https://api.telegram.org/bot/getUpdates" } ``` - 按账号覆盖: + 按账户覆盖: ```json5 { @@ -432,7 +433,7 @@ curl "https://api.telegram.org/bot/getUpdates" } ``` - 作用域: + 范围: - `off` - `dm` @@ -442,7 +443,7 @@ curl "https://api.telegram.org/bot/getUpdates" 旧版 `capabilities: ["inlineButtons"]` 映射到 `inlineButtons: "all"`。 - 消息动作示例: + 消息操作示例: ```json5 { @@ -465,8 +466,8 @@ curl "https://api.telegram.org/bot/getUpdates" - - Telegram 工具动作包括: + + Telegram 工具操作包括: - `sendMessage`(`to`、`content`、可选 `mediaUrl`、`replyToMessageId`、`messageThreadId`) - `react`(`chatId`、`messageId`、`emoji`) @@ -474,7 +475,7 @@ curl "https://api.telegram.org/bot/getUpdates" - `editMessage`(`chatId`、`messageId`、`content`) - `createForumTopic`(`chatId`、`name`、可选 `iconColor`、`iconCustomEmojiId`) - 渠道消息动作提供符合人体工学的别名(`send`、`react`、`delete`、`edit`、`sticker`、`sticker-search`、`topic-create`)。 + 渠道消息操作公开了符合人体工学的别名(`send`、`react`、`delete`、`edit`、`sticker`、`sticker-search`、`topic-create`)。 门控控制: @@ -484,9 +485,9 @@ curl "https://api.telegram.org/bot/getUpdates" - `channels.telegram.actions.sticker`(默认:禁用) 注意:`edit` 和 `topic-create` 目前默认启用,并且没有单独的 `channels.telegram.actions.*` 开关。 - 运行时发送使用活动的配置/secret 快照(启动/重载),因此动作路径不会在每次发送时执行临时 SecretRef 重新解析。 + 运行时发送使用活动的配置/密钥快照(启动/重载),因此操作路径不会在每次发送时执行临时 SecretRef 重新解析。 - Reaction 移除语义:[/tools/reactions](/zh-CN/tools/reactions) + 反应移除语义:[/tools/reactions](/zh-CN/tools/reactions) @@ -494,7 +495,7 @@ curl "https://api.telegram.org/bot/getUpdates" Telegram 支持在生成输出中使用显式回复线程标签: - `[[reply_to_current]]` 回复触发消息 - - `[[reply_to:]]` 回复指定的 Telegram 消息 ID + - `[[reply_to:]]` 回复特定 Telegram 消息 ID `channels.telegram.replyToMode` 控制处理方式: @@ -502,29 +503,29 @@ curl "https://api.telegram.org/bot/getUpdates" - `first` - `all` - 启用回复线程且原始 Telegram 文本或说明可用时,OpenClaw 会自动包含一段原生 Telegram 引用摘录。Telegram 将原生引用文本限制为 1024 个 UTF-16 代码单元,因此较长消息会从开头引用;如果 Telegram 拒绝该引用,则回退为普通回复。 + 当启用回复线程,并且原始 Telegram 文本或标题可用时,OpenClaw 会自动包含原生 Telegram 引用摘录。Telegram 将原生引用文本限制为 1024 个 UTF-16 代码单元,因此较长消息会从开头引用,并在 Telegram 拒绝引用时回退到普通回复。 - 注意:`off` 会禁用隐式回复线程。显式 `[[reply_to_*]]` 标签仍会被遵循。 + 注意:`off` 禁用隐式回复线程。显式 `[[reply_to_*]]` 标签仍会被遵循。 - + 论坛超级群组: - - 话题会话键追加 `:topic:` - - 回复和正在输入状态会指向话题线程 - - 话题配置路径: + - topic 会话键追加 `:topic:` + - 回复和正在输入目标为 topic 线程 + - topic 配置路径: `channels.telegram.groups..topics.` - 常规话题(`threadId=1`)特殊情况: + 通用 topic(`threadId=1`)特殊情况: - - 消息发送会省略 `message_thread_id`(Telegram 会拒绝 `sendMessage(...thread_id=1)`) - - 正在输入动作仍会包含 `message_thread_id` + - 消息发送会省略 `message_thread_id`(Telegram 拒绝 `sendMessage(...thread_id=1)`) + - 正在输入操作仍包含 `message_thread_id` - 话题继承:除非被覆盖,话题条目会继承群组设置(`requireMention`、`allowFrom`、`skills`、`systemPrompt`、`enabled`、`groupPolicy`)。 - `agentId` 仅属于话题,不会从群组默认值继承。 + Topic 继承:topic 条目会继承群组设置,除非被覆盖(`requireMention`、`allowFrom`、`skills`、`systemPrompt`、`enabled`、`groupPolicy`)。 + `agentId` 仅属于 topic,不会从群组默认值继承。 - **按话题的智能体路由**:每个话题都可以通过在话题配置中设置 `agentId` 路由到不同的智能体。这让每个话题都拥有自己隔离的工作区、记忆和会话。示例: + **按 topic 的智能体路由**:每个 topic 都可以通过在 topic 配置中设置 `agentId` 路由到不同智能体。这会让每个 topic 拥有自己隔离的工作区、记忆和会话。示例: ```json5 { @@ -544,26 +545,26 @@ curl "https://api.telegram.org/bot/getUpdates" } ``` - 然后每个话题都有自己的会话键:`agent:zu:telegram:group:-1001234567890:topic:3` + 然后每个 topic 都有自己的会话键:`agent:zu:telegram:group:-1001234567890:topic:3` - **持久 ACP 话题绑定**:论坛话题可以通过顶层类型化 ACP 绑定固定 ACP harness 会话(`bindings[]`,带有 `type: "acp"` 和 `match.channel: "telegram"`、`peer.kind: "group"`,以及像 `-1001234567890:topic:42` 这样的带话题限定的 id)。目前限定于群组/超级群组中的论坛话题。参见 [ACP 智能体](/zh-CN/tools/acp-agents)。 + **持久 ACP topic 绑定**:论坛 topic 可以通过顶层类型化 ACP 绑定固定 ACP harness 会话(`bindings[]` 搭配 `type: "acp"` 和 `match.channel: "telegram"`、`peer.kind: "group"`,以及类似 `-1001234567890:topic:42` 的 topic 限定 ID)。目前范围限定为群组/超级群组中的论坛 topic。参见 [ACP 智能体](/zh-CN/tools/acp-agents)。 - **从聊天启动线程绑定的 ACP**:`/acp spawn --thread here|auto` 将当前话题绑定到新的 ACP 会话;后续消息会直接路由到那里。OpenClaw 会在话题内固定启动确认。需要 `channels.telegram.threadBindings.spawnAcpSessions=true`。 + **从聊天发起线程绑定的 ACP spawn**:`/acp spawn --thread here|auto` 会将当前 topic 绑定到新的 ACP 会话;后续消息会直接路由到那里。OpenClaw 会在 topic 内固定 spawn 确认。需要 `channels.telegram.threadBindings.spawnAcpSessions=true`。 - 模板上下文公开 `MessageThreadId` 和 `IsForum`。带有 `message_thread_id` 的 DM 聊天会保留 DM 路由,但使用线程感知的会话键。 + 模板上下文公开 `MessageThreadId` 和 `IsForum`。带有 `message_thread_id` 的私信聊天会保持私信路由,但使用线程感知的会话键。 ### 音频消息 - Telegram 区分语音留言和音频文件。 + Telegram 区分语音消息和音频文件。 - 默认:音频文件行为 - - 在智能体回复中使用标签 `[[audio_as_voice]]` 强制作为语音留言发送 - - 入站语音留言转录会在智能体上下文中被框定为机器生成的非可信文本;提及检测仍使用原始转录,因此受提及门控的语音消息会继续工作。 + - 在智能体回复中使用标签 `[[audio_as_voice]]` 强制作为语音消息发送 + - 入站语音消息转写会在智能体上下文中被框定为机器生成的、不受信任文本;提及检测仍使用原始转写,因此提及门控的语音消息会继续工作。 - 消息动作示例: + 消息操作示例: ```json5 { @@ -577,9 +578,9 @@ curl "https://api.telegram.org/bot/getUpdates" ### 视频消息 - Telegram 区分视频文件和视频留言。 + Telegram 区分视频文件和视频消息。 - 消息动作示例: + 消息操作示例: ```json5 { @@ -591,7 +592,7 @@ curl "https://api.telegram.org/bot/getUpdates" } ``` - 视频留言不支持说明;提供的消息文本会单独发送。 + 视频消息不支持标题;提供的消息文本会单独发送。 ### 贴纸 @@ -613,9 +614,9 @@ curl "https://api.telegram.org/bot/getUpdates" - `~/.openclaw/telegram/sticker-cache.json` - 贴纸会被描述一次(如果可能)并缓存,以减少重复视觉调用。 + 贴纸会被描述一次(尽可能),并缓存以减少重复视觉调用。 - 启用贴纸动作: + 启用贴纸操作: ```json5 { @@ -629,7 +630,7 @@ curl "https://api.telegram.org/bot/getUpdates" } ``` - 发送贴纸动作: + 发送贴纸操作: ```json5 { @@ -653,31 +654,31 @@ curl "https://api.telegram.org/bot/getUpdates" - - Telegram reaction 会作为 `message_reaction` 更新到达(独立于消息负载)。 + + Telegram 反应以 `message_reaction` 更新到达(独立于消息载荷)。 - 启用后,OpenClaw 会将如下系统事件加入队列: + 启用后,OpenClaw 会将如下系统事件入队: - `Telegram reaction added: 👍 by Alice (@alice) on msg 42` 配置: - - `channels.telegram.reactionNotifications`:`off | own | all`(默认:`own`) - - `channels.telegram.reactionLevel`:`off | ack | minimal | extensive`(默认:`minimal`) + - `channels.telegram.reactionNotifications`: `off | own | all`(默认:`own`) + - `channels.telegram.reactionLevel`: `off | ack | minimal | extensive`(默认:`minimal`) 注意: - - `own` 表示仅用户对机器人发送消息的反应(通过已发送消息缓存尽力处理)。 - - 反应事件仍遵循 Telegram 访问控制(`dmPolicy`、`allowFrom`、`groupPolicy`、`groupAllowFrom`);未授权发送者会被丢弃。 - - Telegram 不会在反应更新中提供话题 ID。 - - 非论坛群组路由到群聊会话 - - 论坛群组路由到群组通用话题会话(`:topic:1`),而不是精确的原始话题 + - `own` 表示仅对机器人发送消息的用户回应生效(通过已发送消息缓存尽力而为)。 + - 回应事件仍会遵守 Telegram 访问控制(`dmPolicy`、`allowFrom`、`groupPolicy`、`groupAllowFrom`);未授权发送者会被丢弃。 + - Telegram 不会在回应更新中提供话题 ID。 + - 非论坛群组会路由到群聊会话 + - 论坛群组会路由到群组常规话题会话(`:topic:1`),而不是确切的原始话题 轮询/webhook 的 `allowed_updates` 会自动包含 `message_reaction`。 - + `ackReaction` 会在 OpenClaw 处理入站消息时发送一个确认表情符号。 解析顺序: @@ -689,8 +690,8 @@ curl "https://api.telegram.org/bot/getUpdates" 注意: - - Telegram 需要 unicode 表情符号(例如 "👀")。 - - 使用 `""` 可为某个渠道或账号禁用反应。 + - Telegram 需要 Unicode 表情符号(例如 "👀")。 + - 使用 `""` 可禁用某个渠道或账号的回应。 @@ -717,28 +718,28 @@ curl "https://api.telegram.org/bot/getUpdates" - 默认使用长轮询。对于 webhook 模式,请设置 `channels.telegram.webhookUrl` 和 `channels.telegram.webhookSecret`;可选 `webhookPath`、`webhookHost`、`webhookPort`(默认值为 `/telegram-webhook`、`127.0.0.1`、`8787`)。 + 默认使用长轮询。若使用 webhook 模式,请设置 `channels.telegram.webhookUrl` 和 `channels.telegram.webhookSecret`;可选设置 `webhookPath`、`webhookHost`、`webhookPort`(默认值为 `/telegram-webhook`、`127.0.0.1`、`8787`)。 - 本地监听器绑定到 `127.0.0.1:8787`。对于公共入口,可以在本地端口前放置反向代理,或有意设置 `webhookHost: "0.0.0.0"`。 + 本地监听器绑定到 `127.0.0.1:8787`。对于公网入口,请在本地端口前放置反向代理,或有意设置 `webhookHost: "0.0.0.0"`。 - Webhook 模式会在向 Telegram 返回 `200` 前验证请求防护、Telegram 密钥令牌和 JSON 正文。 - 随后 OpenClaw 会通过与长轮询相同的按聊天/按话题机器人通道异步处理该更新,因此缓慢的智能体轮次不会阻塞 Telegram 的投递 ACK。 + webhook 模式会先验证请求保护、Telegram secret token 和 JSON 正文,然后才向 Telegram 返回 `200`。 + 随后 OpenClaw 会通过长轮询使用的同一组按聊天/按话题划分的机器人通道异步处理更新,因此较慢的智能体回合不会阻塞 Telegram 的投递确认。 - `channels.telegram.textChunkLimit` 默认值为 4000。 - - `channels.telegram.chunkMode="newline"` 会在按长度拆分前优先使用段落边界(空行)。 - - `channels.telegram.mediaMaxMb`(默认 100)限制入站和出站 Telegram 媒体大小。 - - `channels.telegram.timeoutSeconds` 会覆盖 Telegram API 客户端超时时间(未设置时,使用 grammY 默认值)。 - - `channels.telegram.pollingStallThresholdMs` 默认为 `120000`;仅在误报轮询停滞重启时,才在 `30000` 到 `600000` 之间调整。 + - `channels.telegram.chunkMode="newline"` 会优先按段落边界(空行)分割,再按长度分割。 + - `channels.telegram.mediaMaxMb`(默认 100)会限制入站和出站 Telegram 媒体大小。 + - `channels.telegram.timeoutSeconds` 会覆盖 Telegram API 客户端超时(若未设置,则使用 grammY 默认值)。 + - `channels.telegram.pollingStallThresholdMs` 默认为 `120000`;仅在轮询停滞重启误报时,调整到 `30000` 到 `600000` 之间。 - 群组上下文历史使用 `channels.telegram.historyLimit` 或 `messages.groupChat.historyLimit`(默认 50);`0` 表示禁用。 - 回复/引用/转发的补充上下文目前会按接收内容传递。 - - Telegram 允许列表主要限制谁可以触发智能体,而不是完整的补充上下文删改边界。 - - 私信历史控制项: + - Telegram 允许列表主要用于控制谁可以触发智能体,并不是完整的补充上下文脱敏边界。 + - 私信历史控制: - `channels.telegram.dmHistoryLimit` - `channels.telegram.dms[""].historyLimit` - - `channels.telegram.retry` 配置适用于 Telegram 发送辅助函数(CLI/工具/动作)中的可恢复出站 API 错误。 + - `channels.telegram.retry` 配置适用于 Telegram 发送辅助逻辑(CLI/工具/actions),用于可恢复的出站 API 错误。 CLI 发送目标可以是数字聊天 ID 或用户名: @@ -757,12 +758,12 @@ openclaw message poll --channel telegram --target -1001234567890:topic:42 \ --poll-duration-seconds 300 --poll-public ``` - 仅限 Telegram 的投票标志: + 仅 Telegram 可用的投票标志: - `--poll-duration-seconds` (5-600) - `--poll-anonymous` - `--poll-public` - - `--thread-id` 用于论坛话题(或使用 `:topic:` 目标) + - 用于论坛话题的 `--thread-id`(也可以使用 `:topic:` 目标) Telegram 发送还支持: @@ -770,42 +771,42 @@ openclaw message poll --channel telegram --target -1001234567890:topic:42 \ - 当机器人可以在该聊天中置顶时,使用 `--pin` 或 `--delivery '{"pin":true}'` 请求置顶投递 - 使用 `--force-document` 将出站图片和 GIF 作为文档发送,而不是压缩照片或动画媒体上传 - 动作门控: + Action gating: - `channels.telegram.actions.sendMessage=false` 会禁用出站 Telegram 消息,包括投票 - - `channels.telegram.actions.poll=false` 会禁用 Telegram 投票创建,同时保留常规发送启用状态 + - `channels.telegram.actions.poll=false` 会禁用 Telegram 投票创建,同时保留常规发送功能 - - Telegram 支持在审批者私信中进行执行审批,并可选择在原始聊天或话题中发布提示。审批者必须是数字 Telegram 用户 ID。 + + Telegram 支持在审批者私信中进行 exec 审批,也可以选择在原始聊天或话题中发布提示。审批者必须是数字 Telegram 用户 ID。 配置路径: - `channels.telegram.execApprovals.enabled`(当至少一个审批者可解析时自动启用) - - `channels.telegram.execApprovals.approvers`(回退到来自 `commands.ownerAllowFrom` 的数字 owner ID) + - `channels.telegram.execApprovals.approvers`(回退到 `commands.ownerAllowFrom` 中的数字所有者 ID) - `channels.telegram.execApprovals.target`: `dm`(默认)| `channel` | `both` - `agentFilter`、`sessionFilter` - `channels.telegram.allowFrom`、`groupAllowFrom` 和 `defaultTo` 控制谁可以与机器人对话,以及机器人在哪里发送正常回复。它们不会让某人成为执行审批者。当尚不存在命令 owner 时,首次批准的私信配对会引导创建 `commands.ownerAllowFrom`,因此单 owner 设置仍可工作,而无需在 `execApprovals.approvers` 下重复 ID。 + `channels.telegram.allowFrom`、`groupAllowFrom` 和 `defaultTo` 控制谁可以与机器人对话,以及机器人将普通回复发送到哪里。它们不会让某人成为 exec 审批者。当还没有命令所有者时,第一次获批的私信配对会引导生成 `commands.ownerAllowFrom`,因此单所有者设置仍可工作,而无需在 `execApprovals.approvers` 下重复 ID。 - 渠道投递会在聊天中显示命令文本;仅在受信任的群组/话题中启用 `channel` 或 `both`。当提示落在论坛话题中时,OpenClaw 会为审批提示和后续消息保留该话题。执行审批默认在 30 分钟后过期。 + 渠道投递会在聊天中显示命令文本;只应在受信任的群组/话题中启用 `channel` 或 `both`。当提示落在论坛话题中时,OpenClaw 会为审批提示和后续消息保留该话题。exec 审批默认在 30 分钟后过期。 - 内联审批按钮还要求 `channels.telegram.capabilities.inlineButtons` 允许目标表面(`dm`、`group` 或 `all`)。带有 `plugin:` 前缀的审批 ID 会通过插件审批解析;其他 ID 会先通过执行审批解析。 + 内联审批按钮还要求 `channels.telegram.capabilities.inlineButtons` 允许目标表面(`dm`、`group` 或 `all`)。以 `plugin:` 为前缀的审批 ID 会通过插件审批解析;其他 ID 会先通过 exec 审批解析。 - 参见 [执行审批](/zh-CN/tools/exec-approvals)。 + 参见 [Exec 审批](/zh-CN/tools/exec-approvals)。 ## 错误回复控制 -当智能体遇到投递或提供商错误时,Telegram 可以回复错误文本,也可以抑制该错误。两个配置键控制此行为: +当智能体遇到投递或提供商错误时,Telegram 可以回复错误文本,也可以抑制它。两个配置键控制此行为: | 键 | 值 | 默认值 | 描述 | | ----------------------------------- | ----------------- | ------- | -------------------------------------------------------------------------------------------- | | `channels.telegram.errorPolicy` | `reply`, `silent` | `reply` | `reply` 会向聊天发送友好的错误消息。`silent` 会完全抑制错误回复。 | -| `channels.telegram.errorCooldownMs` | number (ms) | `60000` | 向同一聊天发送错误回复的最小间隔时间。防止故障期间出现错误刷屏。 | +| `channels.telegram.errorCooldownMs` | number (ms) | `60000` | 向同一聊天发送错误回复的最小间隔。可防止中断期间产生错误消息轰炸。 | 支持按账号、按群组和按话题覆盖(继承方式与其他 Telegram 配置键相同)。 @@ -828,50 +829,50 @@ openclaw message poll --channel telegram --target -1001234567890:topic:42 \ ## 故障排除 - + - 如果 `requireMention=false`,Telegram 隐私模式必须允许完整可见性。 - BotFather:`/setprivacy` -> Disable - - 然后将机器人从群组中移除并重新添加 - - 当配置预期处理未提及的群组消息时,`openclaw channels status` 会发出警告。 - - `openclaw channels status --probe` 可以检查显式数字群组 ID;通配符 `"*"` 无法进行成员探测。 + - 然后将机器人从群组移除并重新添加 + - 当配置期望未提及的群组消息时,`openclaw channels status` 会发出警告。 + - `openclaw channels status --probe` 可以检查明确的数字群组 ID;通配符 `"*"` 无法探测成员关系。 - 快速会话测试:`/activation always`。 - - 当存在 `channels.telegram.groups` 时,群组必须被列出(或包含 `"*"`) + - 当存在 `channels.telegram.groups` 时,群组必须列在其中(或包含 `"*"`) - 验证机器人是否为群组成员 - - 查看日志:`openclaw logs --follow` 以了解跳过原因 + - 查看日志:`openclaw logs --follow`,了解跳过原因 - 授权你的发送者身份(配对和/或数字 `allowFrom`) - - 即使群组策略为 `open`,命令授权仍然适用 - - `setMyCommands failed` 伴随 `BOT_COMMANDS_TOO_MUCH` 表示原生命令菜单条目过多;减少插件/skill/自定义命令,或禁用原生菜单 - - `setMyCommands failed` 伴随网络/fetch 错误通常表示到 `api.telegram.org` 的 DNS/HTTPS 可达性存在问题 + - 即使群组策略为 `open`,仍会应用命令授权 + - `setMyCommands failed` 且包含 `BOT_COMMANDS_TOO_MUCH` 表示原生命令菜单条目过多;减少插件/skill/自定义命令,或禁用原生命令菜单 + - `setMyCommands failed` 且包含网络/fetch 错误,通常表示到 `api.telegram.org` 的 DNS/HTTPS 可达性存在问题 - + - - `getMe returned 401` 是为已配置机器人令牌返回的 Telegram 身份验证失败。 - - 在 BotFather 中重新复制或重新生成机器人令牌,然后更新默认账号的 `channels.telegram.botToken`、`channels.telegram.tokenFile`、`channels.telegram.accounts..botToken` 或 `TELEGRAM_BOT_TOKEN`。 - - 启动期间的 `deleteWebhook 401 Unauthorized` 也是身份验证失败;将其视为“没有 webhook 存在”只会把同一个错误令牌失败推迟到后续 API 调用。 + - `getMe returned 401` 是所配置机器人 token 的 Telegram 身份验证失败。 + - 在 BotFather 中重新复制或重新生成机器人 token,然后为默认账号更新 `channels.telegram.botToken`、`channels.telegram.tokenFile`、`channels.telegram.accounts..botToken` 或 `TELEGRAM_BOT_TOKEN`。 + - 启动期间的 `deleteWebhook 401 Unauthorized` 也是身份验证失败;将其视为“没有 webhook 存在”只会把同一个错误 token 失败推迟到后续 API 调用。 - - Node 22+ 加自定义 fetch/proxy 在 AbortSignal 类型不匹配时可能触发立即中止行为。 - - 某些主机会优先将 `api.telegram.org` 解析到 IPv6;损坏的 IPv6 出站可能导致间歇性 Telegram API 失败。 - - 如果日志包含 `TypeError: fetch failed` 或 `Network request for 'getUpdates' failed!`,OpenClaw 现在会将这些作为可恢复网络错误进行重试。 - - 如果日志包含 `Polling stall detected`,OpenClaw 默认会在 120 秒内没有完成长轮询活性检查后重启轮询并重建 Telegram 传输。 - - 仅当长时间运行的 `getUpdates` 调用是健康的,但你的主机仍报告误报轮询停滞重启时,才增加 `channels.telegram.pollingStallThresholdMs`。持续停滞通常指向主机与 `api.telegram.org` 之间的 proxy、DNS、IPv6 或 TLS 出站问题。 - - 在直接出站/TLS 不稳定的 VPS 主机上,通过 `channels.telegram.proxy` 路由 Telegram API 调用: + - Node 22+ 加自定义 fetch/proxy 时,如果 AbortSignal 类型不匹配,可能触发立即中止行为。 + - 某些主机会优先将 `api.telegram.org` 解析为 IPv6;损坏的 IPv6 出站可能导致间歇性 Telegram API 失败。 + - 如果日志包含 `TypeError: fetch failed` 或 `Network request for 'getUpdates' failed!`,OpenClaw 现在会将这些错误作为可恢复网络错误重试。 + - 如果日志包含 `Polling stall detected`,默认情况下,OpenClaw 会在 120 秒内没有完成的长轮询存活信号后重启轮询并重建 Telegram 传输。 + - 只有当长时间运行的 `getUpdates` 调用健康,但你的主机仍报告轮询停滞重启误报时,才增加 `channels.telegram.pollingStallThresholdMs`。持续停滞通常指向主机与 `api.telegram.org` 之间的代理、DNS、IPv6 或 TLS 出站问题。 + - 在直连出站/TLS 不稳定的 VPS 主机上,通过 `channels.telegram.proxy` 路由 Telegram API 调用: ```yaml channels: @@ -880,7 +881,7 @@ channels: ``` - Node 22+ 默认使用 `autoSelectFamily=true`(WSL2 除外)和 `dnsResultOrder=ipv4first`。 - - 如果你的主机是 WSL2,或明确在仅 IPv4 行为下工作得更好,请强制选择地址族: + - 如果你的主机是 WSL2,或明确在仅 IPv4 行为下效果更好,请强制选择地址族: ```yaml channels: @@ -889,7 +890,7 @@ channels: autoSelectFamily: false ``` - - RFC 2544 基准范围应答(`198.18.0.0/15`)默认已允许用于 Telegram 媒体下载。如果受信任的 fake-IP 或透明代理在媒体下载期间将 `api.telegram.org` 重写为其他 private/internal/special-use 地址,你可以选择启用仅限 Telegram 的绕过: + - RFC 2544 基准范围响应(`198.18.0.0/15`)默认已允许用于 Telegram 媒体下载。如果受信任的 fake-IP 或透明代理在媒体下载期间将 `api.telegram.org` 重写到其他私有/内部/特殊用途地址,你可以选择启用仅限 Telegram 的绕过: ```yaml channels: @@ -898,15 +899,19 @@ channels: dangerouslyAllowPrivateNetwork: true ``` - - 同样的选择启用也可按账号在 `channels.telegram.accounts..network.dangerouslyAllowPrivateNetwork` 中使用。 - - 如果你的代理将 Telegram 媒体主机解析为 `198.18.x.x`,请先保持危险标志关闭。Telegram 媒体默认已允许 RFC 2544 基准范围。 + - 同一个选择加入项也可按账号配置在 + `channels.telegram.accounts..network.dangerouslyAllowPrivateNetwork`。 + - 如果你的代理将 Telegram 媒体主机解析到 `198.18.x.x`,请先保持危险标志关闭。Telegram 媒体已默认允许 RFC 2544 基准范围。 `channels.telegram.network.dangerouslyAllowPrivateNetwork` 会削弱 Telegram - 媒体 SSRF 防护。仅在可信、由操作员控制的代理环境中使用它,例如 Clash、Mihomo 或 Surge fake-IP 路由,并且这些环境会在 RFC 2544 基准测试范围之外合成私有或特殊用途应答。正常的公共互联网 Telegram 访问应保持关闭。 + 媒体 SSRF 防护。仅在受信任、由运维控制的代理环境中使用它, + 例如 Clash、Mihomo 或 Surge fake-IP 路由,且这些环境会在 + RFC 2544 基准范围之外合成私有或特殊用途应答。普通公网 + Telegram 访问请保持关闭。 - - 环境覆盖(临时): + - 环境变量覆盖(临时): - `OPENCLAW_TELEGRAM_DISABLE_AUTO_SELECT_FAMILY=1` - `OPENCLAW_TELEGRAM_ENABLE_AUTO_SELECT_FAMILY=1` - `OPENCLAW_TELEGRAM_DNS_RESULT_ORDER=ipv4first` @@ -926,48 +931,48 @@ dig +short api.telegram.org AAAA 主要参考:[配置参考 - Telegram](/zh-CN/gateway/config-channels#telegram)。 - + -- 启动/凭证:`enabled`、`botToken`、`tokenFile`、`accounts.*`(`tokenFile` 必须指向常规文件;符号链接会被拒绝) +- 启动/鉴权:`enabled`、`botToken`、`tokenFile`、`accounts.*`(`tokenFile` 必须指向普通文件;符号链接会被拒绝) - 访问控制:`dmPolicy`、`allowFrom`、`groupPolicy`、`groupAllowFrom`、`groups`、`groups.*.topics.*`、顶层 `bindings[]`(`type: "acp"`) -- 执行批准:`execApprovals`、`accounts.*.execApprovals` +- exec 审批:`execApprovals`、`accounts.*.execApprovals` - 命令/菜单:`commands.native`、`commands.nativeSkills`、`customCommands` -- 话题/回复:`replyToMode` +- 线程/回复:`replyToMode` - 流式传输:`streaming`(预览)、`streaming.preview.toolProgress`、`blockStreaming` -- 格式/投递:`textChunkLimit`、`chunkMode`、`linkPreview`、`responsePrefix` +- 格式化/投递:`textChunkLimit`、`chunkMode`、`linkPreview`、`responsePrefix` - 媒体/网络:`mediaMaxMb`、`timeoutSeconds`、`pollingStallThresholdMs`、`retry`、`network.autoSelectFamily`、`network.dangerouslyAllowPrivateNetwork`、`proxy` - 自定义 API 根路径:`apiRoot`(仅限 Bot API 根路径;不要包含 `/bot`) - webhook:`webhookUrl`、`webhookSecret`、`webhookPath`、`webhookHost` - 操作/能力:`capabilities.inlineButtons`、`actions.sendMessage|editMessage|deleteMessage|reactions|sticker` -- 表情回应:`reactionNotifications`、`reactionLevel` +- reactions:`reactionNotifications`、`reactionLevel` - 错误:`errorPolicy`、`errorCooldownMs` - 写入/历史记录:`configWrites`、`historyLimit`、`dmHistoryLimit`、`dms.*.historyLimit` -多账号优先级:配置两个或更多账号 ID 时,设置 `channels.telegram.defaultAccount`(或包含 `channels.telegram.accounts.default`)以显式指定默认路由。否则 OpenClaw 会回退到第一个规范化账号 ID,且 `openclaw doctor` 会发出警告。命名账号会继承 `channels.telegram.allowFrom` / `groupAllowFrom`,但不会继承 `accounts.default.*` 值。 +多账号优先级:配置两个或更多账号 ID 时,请设置 `channels.telegram.defaultAccount`(或包含 `channels.telegram.accounts.default`),以明确默认路由。否则 OpenClaw 会回退到第一个规范化后的账号 ID,并且 `openclaw doctor` 会发出警告。命名账号会继承 `channels.telegram.allowFrom` / `groupAllowFrom`,但不会继承 `accounts.default.*` 值。 -## 相关内容 +## 相关 - - 将 Telegram 用户配对到 Gateway 网关。 + + 将 Telegram 用户与 Gateway 网关配对。 - + 群组和话题允许列表行为。 - + 将入站消息路由到智能体。 - + 威胁模型和加固。 - + 将群组和话题映射到智能体。 - + 跨渠道诊断。 diff --git a/docs/zh-CN/ci.md b/docs/zh-CN/ci.md index 00e611d26..9ebeb3eed 100644 --- a/docs/zh-CN/ci.md +++ b/docs/zh-CN/ci.md @@ -1,65 +1,66 @@ --- read_when: - - 你需要了解 CI 作业为什么运行或没有运行 + - 你需要了解某个 CI 作业为什么运行或未运行 - 你正在调试失败的 GitHub Actions 检查 summary: CI 作业图、范围门禁和本地命令等效项 title: CI 流水线 x-i18n: - generated_at: "2026-04-29T05:39:22Z" + generated_at: "2026-04-29T05:57:42Z" model: gpt-5.5 provider: openai - source_hash: 07839136693d9bfa72da1bb24a2839e0b249882795fa939dbc79a35436572b01 + source_hash: 67d20b149b2b294646652ff412a8e1c611af812a33cc4b95acef6073370f7388 source_path: ci.md workflow: 16 --- -CI 会在每次推送到 `main` 和每个拉取请求时运行。它使用智能范围限定,在只有无关区域发生变化时跳过昂贵的作业。手动 `workflow_dispatch` 运行会有意绕过智能范围限定,并为候选发布版本或广泛验证展开完整的常规 CI 图。仅发布用的插件预发布通道保持关闭,除非 `Full Release Validation` 以 `full_release_validation=true` 调度 CI。 +CI 会在每次推送到 `main` 和每个拉取请求时运行。它使用智能范围界定,在只有无关区域发生更改时跳过昂贵的作业。手动 `workflow_dispatch` 运行会有意绕过智能范围界定,并展开完整的常规 CI 图,用于发布候选版本或广泛验证。仅发布用的插件预发布通道默认保持关闭,除非 `Full Release Validation` 以 `full_release_validation=true` 调度 CI。 -`Full Release Validation` 是“发布前运行所有内容”的手动总括工作流。它接受分支、标签或完整提交 SHA,使用该目标调度手动 `CI` 工作流,并调度 `OpenClaw Release Checks` 来覆盖安装冒烟、包验收、Docker 发布路径套件、实时/E2E、OpenWebUI、QA Lab parity、Matrix 和 Telegram 通道。提供已发布的包规范时,它还可以运行发布后的 `NPM Telegram Beta E2E` 工作流。`release_profile=minimum|stable|full` 控制传入发布检查的实时/提供商覆盖范围:`minimum` 保留最快的 OpenAI/核心发布关键通道,`stable` 添加稳定的提供商/后端集合,`full` 运行广泛的建议提供商/媒体矩阵。总括工作流会记录已调度的子运行 ID,最终的 `Verify full validation` 作业会重新检查当前子运行结论,并为每个子运行附加最慢作业表。如果某个子工作流重新运行后转绿,只需重新运行父验证器作业,以刷新总括结果和耗时摘要。 +`Full Release Validation` 是用于“发布前运行所有内容”的手动总控工作流。它接受分支、标签或完整提交 SHA,使用该目标调度手动 `CI` 工作流,并为安装烟测、包验收、Docker 发布路径套件、实时/E2E、OpenWebUI、QA Lab parity、Matrix 和 Telegram 通道调度 `OpenClaw Release Checks`。当提供已发布的包规格时,它还可以运行发布后的 `NPM Telegram Beta E2E` 工作流。`release_profile=minimum|stable|full` 控制传递给发布检查的实时/提供商覆盖范围:`minimum` 保留最快的 OpenAI/核心发布关键通道,`stable` 添加稳定的提供商/后端集合,`full` 运行广泛的建议提供商/媒体矩阵。总控会记录被调度的子运行 ID,最终的 `Verify full validation` 作业会重新检查当前子运行结论,并为每个子运行追加最慢作业表。如果某个子工作流重新运行后变绿,只需重新运行父级验证作业,即可刷新总控结果和耗时摘要。 -为了恢复,`Full Release Validation` 和 `OpenClaw Release Checks` 都接受 `rerun_group`。对候选发布版本使用 `all`,只重跑常规完整 CI 子项使用 `ci`,重跑每个发布子项使用 `release-checks`,或者在总括工作流上使用更窄的发布组:`install-smoke`、`cross-os`、`live-e2e`、`package`、`qa`、`qa-parity`、`qa-live` 或 `npm-telegram`。这样在进行聚焦修复后,可以把失败的发布环境重跑范围限制住。 +对于恢复,`Full Release Validation` 和 `OpenClaw Release Checks` 都接受 `rerun_group`。发布候选版本使用 `all`,仅常规完整 CI 子项使用 `ci`,每个发布子项使用 `release-checks`,或在总控上使用更窄的发布组:`install-smoke`、`cross-os`、`live-e2e`、`package`、`qa`、`qa-parity`、`qa-live` 或 `npm-telegram`。这样可以在针对性修复后,将失败的发布环境重跑限制在有界范围内。 -发布实时/E2E 子项保留广泛的原生 `pnpm test:live` 覆盖,但会通过 `scripts/test-live-shard.mjs` 作为命名分片运行(`native-live-src-agents`、`native-live-src-gateway-core`、按提供商过滤的 `native-live-src-gateway-profiles` 作业、`native-live-src-gateway-backends`、`native-live-test`、`native-live-extensions-a-k`、`native-live-extensions-l-n`、`native-live-extensions-openai`、`native-live-extensions-o-z-other`、`native-live-extensions-xai`、拆分后的媒体音频/视频分片,以及按提供商过滤的音乐分片),而不是一个串行作业。这样在保持相同文件覆盖的同时,也让慢速实时提供商失败更容易重跑和诊断。聚合的 `native-live-extensions-o-z`、`native-live-extensions-media` 和 `native-live-extensions-media-music` 分片名称仍可用于手动一次性重跑。 +发布实时/E2E 子项保留广泛的原生 `pnpm test:live` 覆盖范围,但它通过 `scripts/test-live-shard.mjs` 以命名分片运行(`native-live-src-agents`、`native-live-src-gateway-core`、按提供商筛选的 `native-live-src-gateway-profiles` 作业、`native-live-src-gateway-backends`、`native-live-test`、`native-live-extensions-a-k`、`native-live-extensions-l-n`、`native-live-extensions-openai`、`native-live-extensions-o-z-other`、`native-live-extensions-xai`、拆分的媒体音频/视频分片,以及按提供商筛选的音乐分片),而不是作为一个串行作业运行。这在保持相同文件覆盖范围的同时,让较慢的实时提供商失败更容易重跑和诊断。聚合的 `native-live-extensions-o-z`、`native-live-extensions-media` 和 `native-live-extensions-media-music` 分片名称仍可用于手动一次性重跑。 -原生实时媒体分片运行在 `ghcr.io/openclaw/openclaw-live-media-runner:ubuntu-24.04` 中,该镜像由 `Live Media Runner Image` 工作流构建。该镜像预安装 `ffmpeg` 和 `ffprobe`;媒体作业只会在设置前验证这些二进制文件。将 Docker 支撑的实时套件保留在常规 Blacksmith runner 上,因为容器作业不适合启动嵌套 Docker 测试。 +原生实时媒体分片在 `ghcr.io/openclaw/openclaw-live-media-runner:ubuntu-24.04` 中运行,该镜像由 `Live Media Runner Image` 工作流构建。该镜像预装了 `ffmpeg` 和 `ffprobe`;媒体作业只会在设置前验证这些二进制文件。将 Docker 支持的实时套件保留在常规 Blacksmith runner 上,因为容器作业并不适合启动嵌套 Docker 测试。 -Docker 支撑的实时模型/后端分片会为所选提交使用单独的共享 `ghcr.io/openclaw/openclaw-live-test:` 镜像。实时发布工作流会构建并推送该镜像一次,然后 Docker 实时模型、Gateway 网关、CLI 后端、ACP bind 和 Codex harness 分片会带着 `OPENCLAW_SKIP_DOCKER_BUILD=1` 运行。如果这些分片独立重建完整源代码 Docker 目标,则说明发布运行配置有误,并会把墙钟时间浪费在重复镜像构建上。 +Docker 支持的实时模型/后端分片会为每个选定提交使用单独的共享 `ghcr.io/openclaw/openclaw-live-test:` 镜像。实时发布工作流会构建并推送该镜像一次,然后 Docker 实时模型、Gateway 网关、CLI 后端、ACP 绑定和 Codex harness 分片会使用 `OPENCLAW_SKIP_DOCKER_BUILD=1` 运行。如果这些分片各自独立重建完整的源 Docker 目标,则说明发布运行配置错误,并会把耗时浪费在重复镜像构建上。 -`OpenClaw Release Checks` 使用受信任的工作流 ref 将所选 ref 一次性解析为 `release-package-under-test` tarball,然后将该工件传给实时/E2E 发布路径 Docker 工作流和包验收分片。这会让发布环境之间的包字节保持一致,并避免在多个子作业中重新打包同一个候选版本。 +`OpenClaw Release Checks` 使用受信任的工作流引用将选定引用解析一次为 `release-package-under-test` tarball,然后将该构件传递给实时/E2E 发布路径 Docker 工作流和包验收分片。这会让发布环境之间的包字节保持一致,并避免在多个子作业中重复打包同一个候选版本。 -`Package Acceptance` 是用于验证包工件且不会阻塞发布工作流的旁路运行工作流。它会从已发布的 npm 规范、使用所选 `workflow_ref` harness 构建的受信任 `package_ref`、带 SHA-256 的 HTTPS tarball URL,或另一个 GitHub Actions 运行中的 tarball 工件解析一个候选包,将其上传为 `package-under-test`,然后复用 Docker 发布/E2E 调度器,以该 tarball 代替重新打包工作流 checkout。Profile 覆盖 smoke、package、product、full 和自定义 Docker 通道选择。`package` profile 使用离线插件覆盖,因此已发布包验证不会受实时 ClawHub 可用性阻塞。可选 Telegram 通道会在 `NPM Telegram Beta E2E` 工作流中复用 `package-under-test` 工件,同时保留已发布 npm 规范路径用于独立调度。 +`Package Acceptance` 是用于验证包构件且不阻塞发布工作流的旁路运行工作流。它会从已发布的 npm 规格、使用选定 `workflow_ref` harness 构建的受信任 `package_ref`、带 SHA-256 的 HTTPS tarball URL,或另一个 GitHub Actions 运行中的 tarball 构件解析一个候选包,将其作为 `package-under-test` 上传,然后复用 Docker 发布/E2E 调度器,并使用该 tarball,而不是重新打包工作流检出内容。配置文件覆盖烟测、包、产品、完整和自定义 Docker 通道选择。`package` 配置文件使用离线插件覆盖范围,因此已发布包验证不会被实时 ClawHub 可用性阻塞。可选的 Telegram 通道会在 `NPM Telegram Beta E2E` 工作流中复用 `package-under-test` 构件,同时保留已发布 npm 规格路径以支持独立调度。 ## 包验收 -当问题是“这个可安装的 OpenClaw 包是否能作为产品正常工作?”时,使用 `Package Acceptance`。它不同于常规 CI:常规 CI 验证源代码树,而包验收会通过用户安装或更新后实际使用的同一个 Docker E2E harness 验证单个 tarball。 +当问题是“这个可安装的 OpenClaw 包是否能作为产品正常工作?”时,使用 `Package Acceptance`。它不同于常规 CI:常规 CI 验证源代码树,而包验收通过用户在安装或更新后实际使用的同一个 Docker E2E harness 验证单个 tarball。 该工作流有四个作业: -1. `resolve_package` checkout `workflow_ref`,解析一个包候选项,写入 `.artifacts/docker-e2e-package/openclaw-current.tgz`,写入 `.artifacts/docker-e2e-package/package-candidate.json`,将两者作为 `package-under-test` 工件上传,并在 GitHub 步骤摘要中打印来源、工作流 ref、包 ref、版本、SHA-256 和 profile。 -2. `docker_acceptance` 使用 `ref=workflow_ref` 和 `package_artifact_name=package-under-test` 调用 `openclaw-live-and-e2e-checks-reusable.yml`。可复用工作流会下载该工件,验证 tarball 清单,在需要时准备 package-digest Docker 镜像,并针对该包运行所选 Docker 通道,而不是打包工作流 checkout。当某个 profile 选择多个目标 `docker_lanes` 时,可复用工作流会先准备一次包和共享镜像,然后将这些通道展开为并行目标 Docker 作业,并生成唯一工件。 -3. `package_telegram` 可选调用 `NPM Telegram Beta E2E`。当 `telegram_mode` 不是 `none` 时它会运行,并在 Package Acceptance 已解析包时安装同一个 `package-under-test` 工件;独立 Telegram 调度仍可安装已发布的 npm 规范。 -4. `summary` 会在包解析、Docker 验收或可选 Telegram 通道失败时让工作流失败。 +1. `resolve_package` 检出 `workflow_ref`,解析一个包候选项,写入 `.artifacts/docker-e2e-package/openclaw-current.tgz`,写入 `.artifacts/docker-e2e-package/package-candidate.json`,将两者作为 `package-under-test` 构件上传,并在 GitHub 步骤摘要中打印来源、工作流引用、包引用、版本、SHA-256 和配置文件。 +2. `docker_acceptance` 使用 `ref=workflow_ref` 和 `package_artifact_name=package-under-test` 调用 `openclaw-live-and-e2e-checks-reusable.yml`。可复用工作流会下载该构件,验证 tarball 清单,在需要时准备包摘要 Docker 镜像,并针对该包运行选定的 Docker 通道,而不是打包工作流检出内容。当某个配置文件选择多个目标 `docker_lanes` 时,可复用工作流会准备一次包和共享镜像,然后将这些通道展开为具有唯一构件的并行目标 Docker 作业。 +3. `package_telegram` 可选调用 `NPM Telegram Beta E2E`。当 `telegram_mode` 不是 `none` 时,它会运行,并在 Package Acceptance 已解析包时安装同一个 `package-under-test` 构件;独立 Telegram 调度仍然可以安装已发布的 npm 规格。 +4. `summary` 会在包解析、Docker 验收或可选 Telegram 通道失败时使工作流失败。 候选来源: -- `source=npm`:只接受 `openclaw@beta`、`openclaw@latest`,或精确的 OpenClaw 发布版本,例如 `openclaw@2026.4.27-beta.2`。用于已发布 beta/stable 验收。 -- `source=ref`:打包受信任的 `package_ref` 分支、标签或完整提交 SHA。解析器会获取 OpenClaw 分支/标签,验证所选提交可从仓库分支历史或发布标签到达,在分离 worktree 中安装依赖,并用 `scripts/package-openclaw-for-docker.mjs` 打包。 +- `source=npm`:只接受 `openclaw@beta`、`openclaw@latest`,或精确的 OpenClaw 发布版本,例如 `openclaw@2026.4.27-beta.2`。将其用于已发布 beta/稳定版验收。 +- `source=ref`:打包受信任的 `package_ref` 分支、标签或完整提交 SHA。解析器会获取 OpenClaw 分支/标签,验证选定提交可从仓库分支历史或发布标签访问,在分离 worktree 中安装依赖,并使用 `scripts/package-openclaw-for-docker.mjs` 打包。 - `source=url`:下载 HTTPS `.tgz`;必须提供 `package_sha256`。 -- `source=artifact`:从 `artifact_run_id` 和 `artifact_name` 下载一个 `.tgz`;`package_sha256` 是可选项,但对于外部共享的工件应提供。 +- `source=artifact`:从 `artifact_run_id` 和 `artifact_name` 下载一个 `.tgz`;`package_sha256` 可选,但对于外部共享的构件应提供。 保持 `workflow_ref` 和 `package_ref` 分离。`workflow_ref` 是运行测试的受信任工作流/harness 代码。`package_ref` 是在 `source=ref` 时被打包的源提交。这样当前测试 harness 可以验证较旧的受信任源提交,而无需运行旧的工作流逻辑。 -Profile 映射到 Docker 覆盖范围: +配置文件映射到 Docker 覆盖范围: - `smoke`:`npm-onboard-channel-agent`、`gateway-network`、`config-reload` - `package`:`npm-onboard-channel-agent`、`doctor-switch`、`update-channel-switch`、`bundled-channel-deps-compat`、`plugins-offline`、`plugin-update` - `product`:`package` 加上 `mcp-channels`、`cron-mcp-cleanup`、`openai-web-search-minimal`、`openwebui` -- `full`:带 OpenWebUI 的完整 Docker 发布路径分块 -- `custom`:精确的 `docker_lanes`;当 `suite_profile=custom` 时必需 +- `full`:包含 OpenWebUI 的完整 Docker 发布路径分块 +- `custom`:精确的 `docker_lanes`;当 `suite_profile=custom` 时必填 -发布检查会以 `source=ref`、`package_ref=`、`workflow_ref=`、`suite_profile=custom`、`docker_lanes='bundled-channel-deps-compat plugins-offline'` 和 `telegram_mode=mock-openai` 调用 Package Acceptance。发布路径 Docker 分块覆盖重叠的包/更新/插件通道,而 Package Acceptance 保留针对同一个已解析包 tarball 的工件原生内置渠道兼容性、离线插件和 Telegram 证明。跨 OS 发布检查仍覆盖特定 OS 的新手引导、安装器和平台行为;包/更新产品验证应从 Package Acceptance 开始。Windows 打包和安装器全新安装通道还会验证已安装包可以从原始绝对 Windows 路径导入 browser-control override。 +发布检查会使用 `source=ref`、`package_ref=`、`workflow_ref=`、`suite_profile=custom`、`docker_lanes='bundled-channel-deps-compat plugins-offline'` 和 `telegram_mode=mock-openai` 调用 Package Acceptance。发布路径 Docker 分块覆盖重叠的包/更新/插件通道,而 Package Acceptance 会针对同一个已解析包 tarball 保留构件原生的内置渠道兼容、离线插件和 Telegram 证明。 +跨 OS 发布检查仍然覆盖 OS 特定的新手引导、安装器和平台行为;包/更新产品验证应从 Package Acceptance 开始。Windows 打包版和安装器全新安装通道还会验证已安装包能否从原始绝对 Windows 路径导入浏览器控制覆盖。 -Package Acceptance 对已经发布的包有有限的旧版兼容窗口。到 `2026.4.25` 为止的包,包括 `2026.4.25-beta.*`,可以对 `dist/postinstall-inventory.json` 中指向 tarball 省略文件的已知私有 QA 条目使用兼容路径;当包未暴露 `gateway install --wrapper` 标志时,`doctor-switch` 可以跳过该持久化子用例;`update-channel-switch` 可以从 tarball 派生的假 git fixture 中裁剪缺失的 `pnpm.patchedDependencies`,并可以记录缺失的持久化 `update.channel`;插件冒烟可以读取旧版安装记录位置,或接受缺失的 marketplace 安装记录持久化;`plugin-update` 可以允许配置元数据迁移,同时仍要求安装记录和不重装行为保持不变。已发布的 `2026.4.26` 包也可以对已经发布出去的本地构建元数据戳文件发出警告。之后的包必须满足现代契约;相同条件会失败,而不是警告或跳过。 +Package Acceptance 对已发布包有有界的旧版兼容窗口。直到 `2026.4.25` 的包,包括 `2026.4.25-beta.*`,可以对 `dist/postinstall-inventory.json` 中指向 tarball 省略文件的已知私有 QA 条目使用兼容路径;当包未暴露 `gateway install --wrapper` 标志时,`doctor-switch` 可以跳过该持久化子用例;`update-channel-switch` 可以从 tarball 派生的假 git fixture 中修剪缺失的 `pnpm.patchedDependencies`,并可以记录缺失的持久化 `update.channel`;插件烟测可以读取旧版安装记录位置,或接受缺失的 marketplace 安装记录持久化;`plugin-update` 可以允许配置元数据迁移,同时仍要求安装记录和不重装行为保持不变。已发布的 `2026.4.26` 包也可以对已经发布的本地构建元数据戳文件发出警告。更晚的包必须满足现代契约;相同条件会失败,而不是警告或跳过。 示例: @@ -102,24 +103,24 @@ gh workflow run package-acceptance.yml \ -f docker_lanes='install-e2e plugin-update' ``` -调试失败的包验收运行时,从 `resolve_package` 摘要开始,确认包来源、版本和 SHA-256。然后检查 `docker_acceptance` 子运行及其 Docker 工件:`.artifacts/docker-tests/**/summary.json`、`failures.json`、通道日志、阶段耗时和重跑命令。优先重跑失败的包 profile 或精确 Docker 通道,而不是重跑完整发布验证。 +调试失败的包验收运行时,先查看 `resolve_package` 摘要,以确认包来源、版本和 SHA-256。然后检查 `docker_acceptance` 子运行及其 Docker 构件:`.artifacts/docker-tests/**/summary.json`、`failures.json`、通道日志、阶段耗时和重跑命令。优先重跑失败的包配置文件或精确 Docker 通道,而不是重新运行完整发布验证。 -QA Lab 在主智能范围工作流之外有专用的 CI 通道。`Parity gate` 工作流会在匹配的 PR 变更和手动派发时运行;它会构建私有 QA 运行时,并比较模拟 GPT-5.5 和 Opus 4.6 智能体包。`QA-Lab - All Lanes` 工作流每晚在 `main` 上运行,也可手动派发;它会将模拟奇偶校验门、实时 Matrix 通道,以及实时 Telegram 和 Discord 通道展开为并行作业。实时作业使用 `qa-live-shared` 环境,Telegram/Discord 使用 Convex 租约。发布检查会使用确定性的模拟提供商和模拟限定模型(`mock-openai/gpt-5.5` 和 `mock-openai/gpt-5.5-alt`)运行 Matrix 和 Telegram 实时传输通道,从而将渠道契约与实时模型延迟和正常提供商插件启动隔离开。实时传输 Gateway 网关还会禁用内存搜索,因为 QA 奇偶校验会单独覆盖内存行为;提供商连通性由单独的实时模型、原生提供商和 Docker 提供商套件覆盖。Matrix 会对计划任务和发布门使用 `--profile fast`,仅在检出的 CLI 支持时添加 `--fail-fast`。CLI 默认值和手动工作流输入仍为 `all`;手动 `matrix_profile=all` 派发始终会将完整 Matrix 覆盖分片为 `transport`、`media`、`e2ee-smoke`、`e2ee-deep` 和 `e2ee-cli` 作业。`OpenClaw Release Checks` 也会在发布批准前运行发布关键的 QA Lab 通道;其 QA 奇偶校验门会将候选包和基线包作为并行通道作业运行,然后把两个工件下载到一个小型报告作业中,以执行最终奇偶校验比较。 -除非变更确实触及 QA 运行时、模型包奇偶校验,或奇偶校验工作流拥有的表面,否则不要把 PR 落地路径放在 `Parity gate` 后面。对于普通的渠道、配置、文档或单元测试修复,应将其视为可选信号,并遵循范围化 CI/检查证据。 +QA Lab 有专用的 CI 通道,位于主智能作用域工作流之外。`Parity gate` 工作流会在匹配的 PR 变更和手动触发时运行;它会构建私有 QA 运行时,并比较模拟 GPT-5.5 和 Opus 4.6 智能体包。`QA-Lab - All Lanes` 工作流每晚在 `main` 上运行,也可手动触发;它会将模拟一致性门禁、实时 Matrix 通道,以及实时 Telegram 和 Discord 通道分散为并行作业。实时作业使用 `qa-live-shared` 环境,Telegram/Discord 使用 Convex 租约。发布检查会使用确定性的模拟提供商和带 mock 限定的模型(`mock-openai/gpt-5.5` 和 `mock-openai/gpt-5.5-alt`)运行 Matrix 和 Telegram 实时传输通道,因此渠道契约会与实时模型延迟和常规提供商插件启动隔离开来。实时传输 Gateway 网关还会禁用内存搜索,因为 QA 一致性会单独覆盖内存行为;提供商连通性由单独的实时模型、原生提供商和 Docker 提供商套件覆盖。Matrix 在计划任务和发布门禁中使用 `--profile fast`,仅在检出的 CLI 支持时才添加 `--fail-fast`。CLI 默认值和手动工作流输入仍为 `all`;手动 `matrix_profile=all` 触发始终会将完整 Matrix 覆盖范围分片到 `transport`、`media`、`e2ee-smoke`、`e2ee-deep` 和 `e2ee-cli` 作业。`OpenClaw Release Checks` 也会在发布批准前运行发布关键的 QA Lab 通道;其 QA 一致性门禁会将候选包和基线包作为并行通道作业运行,然后把两个构件下载到一个小型报告作业中,用于最终一致性比较。 +不要把 PR 落地路径放到 `Parity gate` 后面,除非变更确实触及 QA 运行时、模型包一致性,或一致性工作流拥有的表面。对于常规渠道、配置、文档或单元测试修复,把它视为可选信号,并遵循作用域化 CI/检查证据。 -`Duplicate PRs After Merge` 工作流是一个手动维护者工作流,用于落地后的重复项清理。它默认 dry-run,只有在 `apply=true` 时才会关闭明确列出的 PR。在变更 GitHub 之前,它会验证已落地 PR 已合并,并且每个重复项要么共享引用的问题,要么有重叠的变更 hunks。 +`Duplicate PRs After Merge` 工作流是用于落地后重复项清理的手动维护者工作流。它默认 dry-run,且仅在 `apply=true` 时关闭显式列出的 PR。在修改 GitHub 前,它会验证已落地 PR 已合并,并且每个重复项要么有共享的引用 issue,要么有重叠的变更 hunk。 -`CodeQL` 工作流有意作为窄范围的第一轮安全扫描器,而不是完整仓库扫描。每日和手动运行会使用高精度安全查询扫描 Actions 工作流代码,以及风险最高的 JavaScript/TypeScript 凭证、密钥、沙箱、cron 和 Gateway 网关表面。channel-runtime-boundary 作业会在 `/codeql-critical-security/channel-runtime-boundary` 类别下单独扫描核心渠道实现契约,以及渠道插件运行时、Gateway 网关、插件 SDK、密钥和审计接触点,这样渠道安全信号就能扩展,而无需扩大基线 JS/TS 类别。 +`CodeQL` 工作流有意作为窄范围第一遍安全扫描器,而不是完整仓库扫描。每日和手动运行会使用高精度安全查询扫描 Actions 工作流代码,以及最高风险的 JavaScript/TypeScript 凭证、密钥、沙箱、cron 和 Gateway 网关表面。channel-runtime-boundary 作业会单独扫描核心渠道实现契约,以及渠道插件运行时、Gateway 网关、插件 SDK、密钥和审计触点,分类为 `/codeql-critical-security/channel-runtime-boundary`,因此渠道安全信号可以扩展,而不必扩大基线 JS/TS 分类。 -`CodeQL Android Critical Security` 工作流是计划运行的 Android 安全分片。它会在工作流完整性检查接受的最小 Blacksmith Linux runner 标签上为 CodeQL 手动构建 Android 应用,并在 `/codeql-critical-security/android` 类别下上传结果。 +`CodeQL Android Critical Security` 工作流是计划执行的 Android 安全分片。它会在 workflow sanity 接受的最小 Blacksmith Linux runner 标签上为 CodeQL 手动构建 Android 应用,并将结果上传到 `/codeql-critical-security/android` 分类下。 -`CodeQL macOS Critical Security` 工作流是每周/手动 macOS 安全分片。它会在 Blacksmith macOS 上为 CodeQL 手动构建 macOS 应用,从上传的 SARIF 中过滤掉依赖构建结果,并在 `/codeql-critical-security/macos` 类别下上传结果。保持它在每日默认工作流之外,因为即使干净通过,macOS 构建也会主导运行时间。 +`CodeQL macOS Critical Security` 工作流是每周/手动的 macOS 安全分片。它会在 Blacksmith macOS 上为 CodeQL 手动构建 macOS 应用,从上传的 SARIF 中过滤掉依赖构建结果,并将结果上传到 `/codeql-critical-security/macos` 分类下。保持它在每日默认工作流之外,因为即使干净通过,macOS 构建也会主导运行时间。 -`CodeQL Critical Quality` 工作流是匹配的非安全分片。它只在较小的 Blacksmith Linux runner 上,对窄范围高价值表面运行错误严重级别、非安全 JavaScript/TypeScript 质量查询。它的基线作业扫描与安全工作流相同的凭证、密钥、沙箱、cron 和 Gateway 网关表面。config-boundary 作业在单独的 `/codeql-critical-quality/config-boundary` 类别下扫描配置 schema、迁移、规范化和 IO 契约。gateway-runtime-boundary 作业在单独的 `/codeql-critical-quality/gateway-runtime-boundary` 类别下扫描 Gateway 网关协议 schema 和服务器方法契约。channel-runtime-boundary 作业在单独的 `/codeql-critical-quality/channel-runtime-boundary` 类别下扫描核心渠道实现契约。agent-runtime-boundary 作业在单独的 `/codeql-critical-quality/agent-runtime-boundary` 类别下扫描命令执行、模型/提供商分发、自动回复分发和队列,以及 ACP 控制平面运行时契约。ui-control-plane 作业在单独的 `/codeql-critical-quality/ui-control-plane` 类别下扫描 Control UI 引导、本地持久化、Gateway 网关控制流和任务控制平面运行时契约。web-media-runtime-boundary 作业在单独的 `/codeql-critical-quality/web-media-runtime-boundary` 类别下扫描核心网页抓取/搜索、媒体 IO、媒体理解、图像生成和媒体生成运行时契约。plugin-boundary 作业在单独的 `/codeql-critical-quality/plugin-boundary` 类别下扫描加载器、注册表、公共表面和插件 SDK 入口点契约。保持该工作流与安全工作流分离,这样质量发现就可以被计划运行、度量、禁用或扩展,而不会掩盖安全信号。Swift、Python 和内置插件的 CodeQL 扩展应只在窄范围配置文件拥有稳定运行时间和信号之后,作为范围化或分片的后续工作加回。 +`CodeQL Critical Quality` 工作流是对应的非安全分片。它只在较小的 Blacksmith Linux runner 上,对窄范围高价值表面运行错误严重级别的非安全 JavaScript/TypeScript 质量查询。其 core-auth-secrets 作业会在单独的 `/codeql-critical-quality/core-auth-secrets` 分类下扫描凭证、密钥、沙箱、cron 和 Gateway 网关安全边界代码。config-boundary 作业会在单独的 `/codeql-critical-quality/config-boundary` 分类下扫描配置 schema、迁移、规范化和 IO 契约。gateway-runtime-boundary 作业会在单独的 `/codeql-critical-quality/gateway-runtime-boundary` 分类下扫描 Gateway 网关协议 schema 和服务器方法契约。channel-runtime-boundary 作业会在单独的 `/codeql-critical-quality/channel-runtime-boundary` 分类下扫描核心渠道实现契约。agent-runtime-boundary 作业会在单独的 `/codeql-critical-quality/agent-runtime-boundary` 分类下扫描命令执行、模型/提供商分发、自动回复分发和队列,以及 ACP 控制平面运行时契约。ui-control-plane 作业会在单独的 `/codeql-critical-quality/ui-control-plane` 分类下扫描 Control UI 引导、本地持久化、Gateway 网关控制流和任务控制平面运行时契约。web-media-runtime-boundary 作业会在单独的 `/codeql-critical-quality/web-media-runtime-boundary` 分类下扫描核心 Web 获取/搜索、媒体 IO、媒体理解、图像生成和媒体生成运行时契约。plugin-boundary 作业会在单独的 `/codeql-critical-quality/plugin-boundary` 分类下扫描加载器、注册表、公共表面和插件 SDK 入口点契约。保持该工作流与安全工作流分离,这样质量发现就可以被计划执行、度量、禁用或扩展,而不会掩盖安全信号。Swift、Python 和内置插件的 CodeQL 扩展只有在窄范围配置具备稳定运行时间和信号后,才应作为作用域化或分片化后续工作添加回来。 -`Docs Agent` 工作流是事件驱动的 Codex 维护通道,用于让现有文档与最近落地的变更保持一致。它没有纯计划任务:`main` 上成功的非机器人 push CI 运行可以触发它,手动派发也可以直接运行它。当 `main` 已经前移,或过去一小时内已创建另一个未跳过的 Docs Agent 运行时,workflow-run 调用会跳过。运行时,它会审查从上一个未跳过 Docs Agent 源 SHA 到当前 `main` 的提交范围,因此一次每小时运行可以覆盖自上次文档处理以来累积的所有 main 变更。 +`Docs Agent` 工作流是一个事件驱动的 Codex 维护通道,用于保持现有文档与最近落地的变更对齐。它没有纯计划任务:`main` 上成功的非机器人 push CI 运行可以触发它,手动触发也可以直接运行它。当 `main` 已经前移,或过去一小时内已创建另一个未跳过的 Docs Agent 运行时,workflow-run 调用会跳过。运行时,它会审查从上一个未跳过 Docs Agent 源 SHA 到当前 `main` 的提交范围,因此一次每小时运行可以覆盖自上次文档检查以来累积的所有 main 变更。 -`Test Performance Agent` 工作流是事件驱动的 Codex 维护通道,用于慢测试。它没有纯计划任务:`main` 上成功的非机器人 push CI 运行可以触发它,但如果当天 UTC 已经有另一个 workflow-run 调用运行过或正在运行,它会跳过。手动派发会绕过该每日活动门。该通道会构建完整套件分组 Vitest 性能报告,让 Codex 只进行小型、保留覆盖率的测试性能修复,而不是大范围重构,然后重新运行完整套件报告,并拒绝会降低通过基线测试数量的变更。如果基线有失败测试,Codex 只能修复明显失败项,并且 agent 之后的完整套件报告必须通过,才能提交任何内容。当 `main` 在机器人 push 落地前前移时,该通道会 rebase 已验证补丁,重新运行 `pnpm check:changed`,并重试 push;有冲突的陈旧补丁会被跳过。它使用 GitHub 托管的 Ubuntu,因此 Codex action 可以保持与 docs agent 相同的 drop-sudo 安全姿态。 +`Test Performance Agent` 工作流是一个事件驱动的 Codex 维护通道,用于慢测试。它没有纯计划任务:`main` 上成功的非机器人 push CI 运行可以触发它,但如果当天 UTC 已经有另一个 workflow-run 调用运行过或正在运行,它会跳过。手动触发会绕过该每日活动门禁。该通道会构建完整套件分组 Vitest 性能报告,让 Codex 只做保留覆盖率的小型测试性能修复,而不是大范围重构,然后重新运行完整套件报告,并拒绝会降低通过基线测试数量的变更。如果基线存在失败测试,Codex 只能修复明显失败,并且智能体后完整套件报告必须通过后才能提交任何内容。当 `main` 在机器人 push 落地前前移时,该通道会 rebase 已验证补丁,重新运行 `pnpm check:changed`,并重试 push;有冲突的过期补丁会跳过。它使用 GitHub 托管的 Ubuntu,因此 Codex action 可以保持与文档智能体相同的 drop-sudo 安全姿态。 ```bash gh workflow run duplicate-after-merge.yml \ @@ -130,32 +131,38 @@ gh workflow run duplicate-after-merge.yml \ ## 作业概览 -| 作业 | 目的 | 运行时机 | -| -------------------------------- | -------------------------------------------------------------------------------------------- | ---------------------------------- | -| `preflight` | 检测仅文档变更、变更范围、变更插件,并构建 CI 清单 | 始终在非草稿 push 和 PR 上运行 | -| `security-scm-fast` | 通过 `zizmor` 进行私钥检测和工作流审计 | 始终在非草稿 push 和 PR 上运行 | -| `security-dependency-audit` | 针对 npm advisories 执行无依赖的生产 lockfile 审计 | 始终在非草稿 push 和 PR 上运行 | -| `security-fast` | 快速安全作业的必需聚合项 | 始终在非草稿 push 和 PR 上运行 | -| `build-artifacts` | 构建 `dist/`、Control UI、构建工件检查,以及可复用下游工件 | Node 相关变更 | -| `checks-fast-core` | 快速 Linux 正确性通道,例如内置/插件契约/协议检查 | Node 相关变更 | -| `checks-fast-contracts-channels` | 分片渠道契约检查,并提供稳定的聚合检查结果 | Node 相关变更 | -| `checks-node-extensions` | 跨插件套件的完整内置插件测试分片 | Node 相关变更 | -| `checks-node-core-test` | 核心 Node 测试分片,不包括渠道、内置、契约和插件通道 | Node 相关变更 | -| `check` | 分片后的主本地门等价项:生产类型、lint、守卫、测试类型和严格 smoke | Node 相关变更 | -| `check-additional` | 架构、边界、插件表面守卫、包边界和 gateway-watch 分片 | Node 相关变更 | -| `build-smoke` | 已构建 CLI smoke 测试和启动内存 smoke | Node 相关变更 | -| `checks` | 已构建工件渠道测试的验证器 | Node 相关变更 | -| `checks-node-compat-node22` | Node 22 兼容性构建和 smoke 通道 | 发布的手动 CI 派发 | -| `plugin-prerelease-suite` | 插件预发布静态检查和 Docker 产品通道的聚合项 | Full Release Validation CI 子项 | -| `check-docs` | 文档格式、lint 和断链检查 | 文档已变更 | -| `skills-python` | Python 支持的 Skills 的 Ruff + pytest | Python 技能相关变更 | -| `checks-windows` | Windows 特定进程/路径测试,以及共享运行时导入说明符回归 | Windows 相关变更 | -| `macos-node` | 使用共享构建工件的 macOS TypeScript 测试通道 | macOS 相关变更 | -| `macos-swift` | macOS 应用的 Swift lint、构建和测试 | macOS 相关变更 | -| `android` | 两种 flavor 的 Android 单元测试,加一个 debug APK 构建 | Android 相关变更 | -| `test-performance-agent` | 受信任活动后每日 Codex 慢测试优化 | Main CI 成功或手动派发 | +| 作业 | 目的 | 运行时机 | +| -------------------------------- | -------------------------------------------------------------------------------------------- | -------------------------------- | +| `preflight` | 检测仅文档变更、变更作用域、变更插件,并构建 CI manifest | 始终在非草稿 push 和 PR 上运行 | +| `security-scm-fast` | 通过 `zizmor` 执行私钥检测和工作流审计 | 始终在非草稿 push 和 PR 上运行 | +| `security-dependency-audit` | 根据 npm advisories 对无依赖生产 lockfile 执行审计 | 始终在非草稿 push 和 PR 上运行 | +| `security-fast` | 快速安全作业的必需聚合作业 | 始终在非草稿 push 和 PR 上运行 | +| `build-artifacts` | 构建 `dist/`、Control UI、构建构件检查,以及可复用下游构件 | Node 相关变更 | +| `checks-fast-core` | 快速 Linux 正确性通道,例如内置/插件契约/协议检查 | Node 相关变更 | +| `checks-fast-contracts-channels` | 分片的渠道契约检查,带稳定的聚合检查结果 | Node 相关变更 | +| `checks-node-extensions` | 覆盖插件套件的完整内置插件测试分片 | Node 相关变更 | +| `checks-node-core-test` | 核心 Node 测试分片,不包括渠道、内置、契约和插件通道 | Node 相关变更 | +| `check` | 分片的主本地门禁等价项:生产类型、lint、guard、测试类型和严格 smoke | Node 相关变更 | +| `check-additional` | 架构、边界、插件表面 guard、包边界和 gateway-watch 分片 | Node 相关变更 | +| `build-smoke` | 已构建 CLI smoke 测试和启动内存 smoke | Node 相关变更 | +| `checks` | 已构建构件渠道测试的验证器 | Node 相关变更 | +| `checks-node-compat-node22` | Node 22 兼容性构建和 smoke 通道 | 用于发布的手动 CI 触发 | +| `plugin-prerelease-suite` | 插件预发布静态检查和 Docker 产品通道的聚合作业 | Full Release Validation CI 子项 | +| `check-docs` | 文档格式、lint 和断链检查 | 文档已变更 | +| `skills-python` | 针对 Python 支持的 Skills 执行 Ruff + pytest | Python Skill 相关变更 | +| `checks-windows` | Windows 专用进程/路径测试,以及共享运行时 import specifier 回归测试 | Windows 相关变更 | +| `macos-node` | 使用共享构建构件的 macOS TypeScript 测试通道 | macOS 相关变更 | +| `macos-swift` | macOS 应用的 Swift lint、构建和测试 | macOS 相关变更 | +| `android` | 两种 flavor 的 Android 单元测试,以及一次 debug APK 构建 | Android 相关变更 | +| `test-performance-agent` | 可信活动后的每日 Codex 慢测试优化 | Main CI 成功或手动触发 | -手动 CI 调度运行与普通 CI 相同的作业图,但会强制开启每个范围化检查通道:Linux Node 分片、内置插件分片、渠道契约、Node 22 兼容性、`check`、`check-additional`、构建冒烟、文档检查、Python Skills、Windows、macOS、Android,以及 Control UI i18n。插件预发布套件会从独立手动 CI 中排除,只有完整发布总控流程通过 `full_release_validation=true` 时才会启用。手动运行使用唯一的并发组,因此发布候选完整套件不会被同一 ref 上的另一次推送或 PR 运行取消。可选的 `target_ref` 输入允许受信任的调用方使用所选调度 ref 中的工作流文件,针对分支、标签或完整提交 SHA 运行该作业图。 +手动 CI 调度运行与普通 CI 相同的作业图,但会强制启用每个 +作用域化通道:Linux Node 分片、内置插件分片、渠道契约、 +Node 22 兼容性、`check`、`check-additional`、构建冒烟测试、文档检查、 +Python Skills、Windows、macOS、Android,以及 Control UI i18n。插件 +预发布套件会从独立手动 CI 中排除,只有在完整发布总控流程通过 +`full_release_validation=true` 时才会启用。手动运行使用唯一的 +并发组,因此同一 ref 上的其他推送或 PR 运行不会取消发布候选的完整套件。可选的 `target_ref` 输入允许受信任的调用方针对某个分支、标签或完整提交 SHA 运行该图,同时使用所选调度 ref 中的工作流文件。 ```bash gh workflow run ci.yml --ref release/YYYY.M.D @@ -165,63 +172,47 @@ gh workflow run full-release-validation.yml --ref main -f ref= ## 快速失败顺序 -作业按顺序排列,让低成本检查先于高成本检查失败: +作业按顺序排列,使低成本检查先于高成本检查失败: -1. `preflight` 决定哪些检查通道实际存在。`docs-scope` 和 `changed-scope` 逻辑是此作业内的步骤,不是独立作业。 -2. `security-scm-fast`、`security-dependency-audit`、`security-fast`、`check`、`check-additional`、`check-docs` 和 `skills-python` 会快速失败,而不等待更重的产物和平台矩阵作业。 -3. `build-artifacts` 会与快速 Linux 检查通道重叠运行,使下游消费者能在共享构建就绪后立即开始。 -4. 更重的平台和运行时检查通道随后展开:`checks-fast-core`、`checks-fast-contracts-channels`、`checks-node-extensions`、`checks-node-core-test`、`checks`、`checks-windows`、`macos-node`、`macos-swift` 和 `android`。 +1. `preflight` 决定哪些通道实际存在。`docs-scope` 和 `changed-scope` 逻辑是此作业中的步骤,而不是独立作业。 +2. `security-scm-fast`、`security-dependency-audit`、`security-fast`、`check`、`check-additional`、`check-docs` 和 `skills-python` 会快速失败,不等待更重的产物和平台矩阵作业。 +3. `build-artifacts` 与快速 Linux 通道重叠运行,因此下游消费者可以在共享构建就绪后立即开始。 +4. 更重的平台和运行时通道随后展开:`checks-fast-core`、`checks-fast-contracts-channels`、`checks-node-extensions`、`checks-node-core-test`、`checks`、`checks-windows`、`macos-node`、`macos-swift` 和 `android`。 -范围逻辑位于 `scripts/ci-changed-scope.mjs`,并由 `src/scripts/ci-changed-scope.test.ts` 中的单元测试覆盖。 -手动调度会跳过 changed-scope 检测,并让预检清单表现得像每个范围化区域都已更改。 -CI 工作流编辑会验证 Node CI 作业图以及工作流 lint,但它们本身不会强制运行 Windows、Android 或 macOS 原生构建;这些平台检查通道仍然只限定于平台源码变更。 -仅 CI 路由编辑、选定的低成本 core-test fixture 编辑,以及窄范围插件契约辅助/测试路由编辑,会使用快速的仅 Node 清单路径:preflight、security 和单个 `checks-fast-core` 任务。当变更文件仅限于该快速任务直接覆盖的路由或辅助表面时,此路径会避开构建产物、Node 22 兼容性、渠道契约、完整核心分片、内置插件分片和额外防护矩阵。 -Windows Node 检查限定于 Windows 特定的进程/路径封装、npm/pnpm/UI runner 辅助、包管理器配置,以及执行该检查通道的 CI 工作流表面;无关源码、插件、install-smoke 和仅测试变更仍留在 Linux Node 检查通道上,因此不会为已由常规测试分片覆盖的内容占用 16-vCPU Windows worker。 -独立的 `install-smoke` 工作流通过自己的 `preflight` 作业复用同一范围脚本。它将冒烟覆盖拆分为 `run_fast_install_smoke` 和 `run_full_install_smoke`。Pull request 会针对 Docker/包表面、内置插件包/清单变更,以及 Docker 冒烟作业会覆盖的核心插件/渠道/Gateway 网关/插件 SDK 表面运行快速路径。仅源码的内置插件变更、仅测试编辑和仅文档编辑不会占用 Docker worker。快速路径会构建一次根 Dockerfile 镜像,检查 CLI,运行 agents delete shared-workspace CLI 冒烟,运行容器 gateway-network e2e,验证一个内置扩展构建参数,并在 240 秒聚合命令超时内运行有界内置插件 Docker 配置文件,每个场景的 Docker 运行也会分别封顶。完整路径保留 QR 包安装和安装器 Docker/更新覆盖,用于夜间计划运行、手动调度、workflow-call 发布检查,以及真正触及安装器/包/Docker 表面的 pull request。`main` 推送(包括 merge commit)不会强制完整路径;当 changed-scope 逻辑会在推送上请求完整覆盖时,工作流保留快速 Docker 冒烟,并将完整安装冒烟留给夜间或发布验证。较慢的 Bun 全局安装 image-provider 冒烟由 `run_bun_global_install_smoke` 单独门控;它会在夜间计划和发布检查工作流中运行,手动 `install-smoke` 调度可以选择加入,但 pull request 和 `main` 推送不会运行它。QR 和安装器 Docker 测试保留各自聚焦安装的 Dockerfile。本地 `test:docker:all` 会预构建一个共享 live-test 镜像,将 OpenClaw 作为 npm tarball 打包一次,并构建两个共享 `scripts/e2e/Dockerfile` 镜像:一个用于安装器/更新/插件依赖检查通道的裸 Node/Git runner,以及一个将同一 tarball 安装到 `/app` 中、用于常规功能检查通道的功能镜像。Docker 检查通道定义位于 `scripts/lib/docker-e2e-scenarios.mjs`,规划器逻辑位于 `scripts/lib/docker-e2e-plan.mjs`,runner 只执行选定的计划。调度器按检查通道使用 `OPENCLAW_DOCKER_E2E_BARE_IMAGE` 和 `OPENCLAW_DOCKER_E2E_FUNCTIONAL_IMAGE` 选择镜像,然后使用 `OPENCLAW_SKIP_DOCKER_BUILD=1` 运行检查通道;使用 `OPENCLAW_DOCKER_ALL_PARALLELISM` 调整默认主池槽位数 10,使用 `OPENCLAW_DOCKER_ALL_TAIL_PARALLELISM` 调整对提供商敏感的尾池槽位数 10。重型检查通道上限默认为 `OPENCLAW_DOCKER_ALL_LIVE_LIMIT=9`、`OPENCLAW_DOCKER_ALL_NPM_LIMIT=10` 和 `OPENCLAW_DOCKER_ALL_SERVICE_LIMIT=7`,这样 npm install 和多服务检查通道不会过度占用 Docker,而较轻的检查通道仍能填满可用槽位。单个比有效上限更重的检查通道仍可从空池启动,然后独占运行直到释放容量。检查通道启动默认错开 2 秒,以避免本地 Docker daemon 创建风暴;可用 `OPENCLAW_DOCKER_ALL_START_STAGGER_MS=0` 或其他毫秒值覆盖。本地聚合会预检 Docker,移除过时的 OpenClaw E2E 容器,输出活动检查通道状态,持久化检查通道耗时以便最长优先排序,并支持 `OPENCLAW_DOCKER_ALL_DRY_RUN=1` 用于调度器检查。默认情况下,它会在首次失败后停止调度新的池化检查通道,每个检查通道都有 120 分钟后备超时,可用 `OPENCLAW_DOCKER_ALL_LANE_TIMEOUT_MS` 覆盖;选定的 live/tail 检查通道使用更严格的单检查通道上限。`OPENCLAW_DOCKER_ALL_LANES=` 会运行精确的调度器检查通道,包括仅发布检查通道(如 `install-e2e`)和拆分的内置更新检查通道(如 `bundled-channel-update-acpx`),同时跳过清理冒烟,使智能体可以复现单个失败检查通道。可复用 live/E2E 工作流会询问 `scripts/test-docker-all.mjs --plan-json` 需要哪些包、镜像种类、live 镜像、检查通道和凭据覆盖,然后 `scripts/docker-e2e.mjs` 将该计划转换为 GitHub 输出和摘要。它会通过 `scripts/package-openclaw-for-docker.mjs` 打包 OpenClaw,或下载当前运行的包产物,或从 `package_artifact_run_id` 下载包产物;验证 tarball 清单;当计划需要已安装包的检查通道时,通过 Blacksmith 的 Docker layer cache 构建并推送以包摘要标记的裸/功能 GHCR Docker E2E 镜像;并复用提供的 `docker_e2e_bare_image`/`docker_e2e_functional_image` 输入或现有包摘要镜像,而不是重新构建。`Package Acceptance` 工作流是高级包门禁:它从 npm、受信任的 `package_ref`、HTTPS tarball 加 SHA-256,或先前工作流产物解析候选包,然后将该单个 `package-under-test` 产物传入可复用 Docker E2E 工作流。它将 `workflow_ref` 与 `package_ref` 分开,使当前验收逻辑能验证较旧的受信任提交,而不必签出旧工作流代码。发布检查会针对目标 ref 运行自定义 Package Acceptance 差异:内置渠道兼容性、离线插件 fixture,以及针对解析出的 tarball 的 Telegram 包 QA。发布路径 Docker 套件运行更小的分块作业,并使用 `OPENCLAW_SKIP_DOCKER_BUILD=1`,因此每个分块只拉取所需的镜像种类,并通过同一加权调度器执行多个检查通道(`OPENCLAW_DOCKER_ALL_PROFILE=release-path`、`OPENCLAW_DOCKER_ALL_CHUNK=core|package-update-openai|package-update-anthropic|package-update-core|plugins-runtime-plugins|plugins-runtime-services|plugins-runtime-install-a|plugins-runtime-install-b|plugins-runtime-install-c|plugins-runtime-install-d|bundled-channels`)。当完整 release-path 覆盖请求 OpenWebUI 时,OpenWebUI 会并入 `plugins-runtime-services`,并且仅对 OpenWebUI-only 调度保留独立的 `openwebui` 分块。旧版聚合分块名称 `package-update`、`plugins-runtime-core`、`plugins-runtime` 和 `plugins-integrations` 仍可用于手动重跑,但发布工作流使用拆分分块,因此安装器 E2E 和内置插件安装/卸载扫描不会主导关键路径。`install-e2e` 检查通道别名仍是两个提供商安装器检查通道的聚合手动重跑别名。`bundled-channels` 分块运行拆分的 `bundled-channel-*` 和 `bundled-channel-update-*` 检查通道,而不是串行的一体式 `bundled-channel-deps` 检查通道。每个分块都会上传 `.artifacts/docker-tests/`,其中包含检查通道日志、耗时、`summary.json`、`failures.json`、阶段耗时、调度器计划 JSON、慢检查通道表,以及每检查通道重跑命令。工作流 `docker_lanes` 输入会针对准备好的镜像运行选定检查通道,而不是分块作业,这使失败检查通道调试被限定在一个目标 Docker 作业内,并为该运行准备、下载或复用包产物;如果选定检查通道是 live Docker 检查通道,目标作业会为该重跑在本地构建 live-test 镜像。生成的每检查通道 GitHub 重跑命令会在这些值存在时包含 `package_artifact_run_id`、`package_artifact_name` 和已准备镜像输入,因此失败检查通道可以复用失败运行中的精确包和镜像。使用 `pnpm test:docker:rerun ` 从 GitHub 运行下载 Docker 产物并打印组合/每检查通道目标重跑命令;使用 `pnpm test:docker:timings ` 查看慢检查通道和阶段关键路径摘要。计划 live/E2E 工作流每天运行完整 release-path Docker 套件。内置更新矩阵按更新目标拆分,使重复的 npm update 和 Doctor 修复流程可以与其他内置检查一起分片。 +作用域逻辑位于 `scripts/ci-changed-scope.mjs`,并由 `src/scripts/ci-changed-scope.test.ts` 中的单元测试覆盖。 +手动调度会跳过 changed-scope 检测,并让 preflight 清单表现得像每个作用域区域都已变更。 +CI 工作流编辑会验证 Node CI 图和工作流 lint,但不会单独强制运行 Windows、Android 或 macOS 原生构建;这些平台通道仍然只针对平台源代码变更启用。 +仅 CI 路由的编辑、部分低成本 core-test fixture 编辑,以及窄范围的插件契约辅助/测试路由编辑,会使用快速的仅 Node 清单路径:preflight、安全检查和单个 `checks-fast-core` 任务。当变更文件仅限于路由或辅助表面,并且快速任务会直接覆盖这些表面时,该路径会避开构建产物、Node 22 兼容性、渠道契约、完整核心分片、内置插件分片和额外防护矩阵。 +Windows Node 检查的作用域限定为 Windows 特定的进程/路径封装、npm/pnpm/UI runner 辅助、包管理器配置,以及执行该通道的 CI 工作流表面;无关的源代码、插件、install-smoke 和仅测试变更会留在 Linux Node 通道上,因此它们不会占用 16-vCPU Windows worker 去覆盖普通测试分片已经覆盖的内容。 +独立的 `install-smoke` 工作流通过自己的 `preflight` 作业复用相同的作用域脚本。它把冒烟覆盖拆分为 `run_fast_install_smoke` 和 `run_full_install_smoke`。拉取请求会针对 Docker/包表面、内置插件包/清单变更,以及 Docker 冒烟作业覆盖的核心插件/渠道/Gateway 网关/插件 SDK 表面运行快速路径。仅源代码的内置插件变更、仅测试编辑和仅文档编辑不会占用 Docker worker。快速路径会构建一次根 Dockerfile 镜像,检查 CLI,运行 agents delete shared-workspace CLI 冒烟测试,运行容器 gateway-network e2e,验证内置插件构建参数,并在 240 秒聚合命令超时内运行受限的内置插件 Docker profile,其中每个场景的 Docker 运行都会单独限制。完整路径保留 QR 包安装和 installer Docker/update 覆盖,用于夜间计划运行、手动调度、workflow-call 发布检查,以及确实触及 installer/package/Docker 表面的拉取请求。`main` 推送(包括合并提交)不会强制完整路径;当 changed-scope 逻辑会在推送上请求完整覆盖时,工作流会保留快速 Docker 冒烟测试,并把完整 install smoke 留给夜间或发布验证。较慢的 Bun 全局安装 image-provider 冒烟测试由 `run_bun_global_install_smoke` 单独控制;它会在夜间计划和发布检查工作流中运行,手动 `install-smoke` 调度可以选择启用它,但拉取请求和 `main` 推送不会运行它。QR 和 installer Docker 测试保留各自面向安装的 Dockerfile。本地 `test:docker:all` 会预构建一个共享 live-test 镜像,将 OpenClaw 打包一次为 npm tarball,并构建两个共享的 `scripts/e2e/Dockerfile` 镜像:一个用于 installer/update/plugin-dependency 通道的裸 Node/Git runner,以及一个把同一个 tarball 安装到 `/app` 的功能镜像,用于普通功能通道。Docker 通道定义位于 `scripts/lib/docker-e2e-scenarios.mjs`,规划器逻辑位于 `scripts/lib/docker-e2e-plan.mjs`,runner 只执行所选计划。调度器通过 `OPENCLAW_DOCKER_E2E_BARE_IMAGE` 和 `OPENCLAW_DOCKER_E2E_FUNCTIONAL_IMAGE` 为每个通道选择镜像,然后用 `OPENCLAW_SKIP_DOCKER_BUILD=1` 运行通道;用 `OPENCLAW_DOCKER_ALL_PARALLELISM` 调整默认主池插槽数 10,用 `OPENCLAW_DOCKER_ALL_TAIL_PARALLELISM` 调整对提供商敏感的尾部池插槽数 10。重型通道上限默认为 `OPENCLAW_DOCKER_ALL_LIVE_LIMIT=9`、`OPENCLAW_DOCKER_ALL_NPM_LIMIT=10` 和 `OPENCLAW_DOCKER_ALL_SERVICE_LIMIT=7`,因此 npm install 和多服务通道不会让 Docker 过载,而较轻通道仍会填满可用插槽。即使单个通道重于有效上限,也仍可从空池启动,然后单独运行直到释放容量。通道启动默认错开 2 秒,以避免本地 Docker daemon 创建风暴;可用 `OPENCLAW_DOCKER_ALL_START_STAGGER_MS=0` 或其他毫秒值覆盖。本地聚合会预检 Docker,移除过期的 OpenClaw E2E 容器,输出活动通道 Status,持久化通道耗时以便按最长优先排序,并支持用 `OPENCLAW_DOCKER_ALL_DRY_RUN=1` 检查调度器。默认情况下,它会在第一次失败后停止调度新的池化通道,每个通道都有 120 分钟的后备超时,可用 `OPENCLAW_DOCKER_ALL_LANE_TIMEOUT_MS` 覆盖;所选 live/tail 通道使用更严格的逐通道上限。`OPENCLAW_DOCKER_ALL_LANES=` 会运行精确的调度器通道,包括 `install-e2e` 等仅发布通道,以及 `bundled-channel-update-acpx` 等拆分的内置更新通道,同时跳过清理冒烟测试,以便智能体复现一个失败通道。可复用 live/E2E 工作流会向 `scripts/test-docker-all.mjs --plan-json` 查询所需的包、镜像类型、live 镜像、通道和凭证覆盖,然后 `scripts/docker-e2e.mjs` 会把该计划转换为 GitHub 输出和摘要。它要么通过 `scripts/package-openclaw-for-docker.mjs` 打包 OpenClaw,要么下载当前运行的包产物,要么从 `package_artifact_run_id` 下载包产物;验证 tarball 清单;当计划需要已安装包的通道时,通过 Blacksmith 的 Docker layer cache 构建并推送带包摘要标签的裸/功能 GHCR Docker E2E 镜像;并复用提供的 `docker_e2e_bare_image`/`docker_e2e_functional_image` 输入或现有包摘要镜像,而不是重新构建。`Package Acceptance` 工作流是高级包门禁:它从 npm、受信任的 `package_ref`、HTTPS tarball 加 SHA-256,或先前的工作流产物解析候选项,然后把该单个 `package-under-test` 产物传给可复用 Docker E2E 工作流。它把 `workflow_ref` 与 `package_ref` 分开,因此当前验收逻辑可以验证较旧的受信任提交,而无需检出旧工作流代码。发布检查会针对目标 ref 运行自定义 Package Acceptance 增量:内置渠道兼容性、离线插件 fixture,以及针对解析出的 tarball 的 Telegram 包 QA。发布路径 Docker 套件会运行更小的分块作业,并使用 `OPENCLAW_SKIP_DOCKER_BUILD=1`,因此每个分块只拉取自己需要的镜像类型,并通过同一个加权调度器执行多个通道(`OPENCLAW_DOCKER_ALL_PROFILE=release-path`、`OPENCLAW_DOCKER_ALL_CHUNK=core|package-update-openai|package-update-anthropic|package-update-core|plugins-runtime-plugins|plugins-runtime-services|plugins-runtime-install-a|plugins-runtime-install-b|plugins-runtime-install-c|plugins-runtime-install-d|bundled-channels`)。当完整 release-path 覆盖请求 OpenWebUI 时,OpenWebUI 会合并到 `plugins-runtime-services`,并且只为仅 OpenWebUI 调度保留独立的 `openwebui` 分块。旧的聚合分块名称 `package-update`、`plugins-runtime-core`、`plugins-runtime` 和 `plugins-integrations` 仍可用于手动重跑,但发布工作流使用拆分分块,这样 installer E2E 和内置插件安装/卸载扫描不会主导关键路径。`install-e2e` 通道别名仍是两个提供商 installer 通道的聚合手动重跑别名。`bundled-channels` 分块运行拆分的 `bundled-channel-*` 和 `bundled-channel-update-*` 通道,而不是串行的全量 `bundled-channel-deps` 通道。每个分块都会上传 `.artifacts/docker-tests/`,其中包含通道日志、耗时、`summary.json`、`failures.json`、阶段耗时、调度器计划 JSON、慢通道表,以及逐通道重跑命令。工作流 `docker_lanes` 输入会针对已准备的镜像运行所选通道,而不是分块作业,这会把失败通道调试限制在一个目标 Docker 作业内,并为该运行准备、下载或复用包产物;如果所选通道是 live Docker 通道,则目标作业会为该重跑在本地构建 live-test 镜像。生成的逐通道 GitHub 重跑命令会在这些值存在时包含 `package_artifact_run_id`、`package_artifact_name` 和已准备镜像输入,因此失败通道可以复用失败运行中的精确包和镜像。使用 `pnpm test:docker:rerun ` 可从 GitHub 运行下载 Docker 产物并打印组合/逐通道目标重跑命令;使用 `pnpm test:docker:timings ` 可查看慢通道和阶段关键路径摘要。计划 live/E2E 工作流每天运行完整 release-path Docker 套件。内置更新矩阵按更新目标拆分,因此重复的 npm update 和 Doctor 修复轮次可以与其他内置检查一起分片。 -当前发布 Docker 分块为 `core`、`package-update-openai`、`package-update-anthropic`、`package-update-core`、`plugins-runtime-plugins`、`plugins-runtime-services`、`plugins-runtime-install-a`、`plugins-runtime-install-b`、`plugins-runtime-install-c`、`plugins-runtime-install-d`、`bundled-channels-core`、`bundled-channels-update-a`、`bundled-channels-update-b` 和 `bundled-channels-contracts`。聚合 `bundled-channels` 分块仍可用于手动一次性重跑,`plugins-runtime-core`、`plugins-runtime` 和 `plugins-integrations` 仍是聚合插件/运行时别名,但发布工作流使用拆分分块,使渠道冒烟、更新目标、插件运行时检查以及内置插件安装/卸载扫描可以并行运行。目标 `docker_lanes` 调度也会在一次共享包/镜像准备步骤之后,将多个选定检查通道拆分为并行作业,并且内置渠道更新检查通道会针对临时 npm 网络故障重试一次。 +当前发布 Docker 分块是 `core`、`package-update-openai`、`package-update-anthropic`、`package-update-core`、`plugins-runtime-plugins`、`plugins-runtime-services`、`plugins-runtime-install-a`、`plugins-runtime-install-b`、`plugins-runtime-install-c`、`plugins-runtime-install-d`、`bundled-channels-core`、`bundled-channels-update-a`、`bundled-channels-update-b` 和 `bundled-channels-contracts`。聚合 `bundled-channels` 分块仍可用于手动一次性重跑,`plugins-runtime-core`、`plugins-runtime` 和 `plugins-integrations` 也仍是聚合插件/运行时别名,但发布工作流使用拆分分块,因此渠道冒烟测试、更新目标、插件运行时检查和内置插件安装/卸载扫描可以并行运行。目标化 `docker_lanes` 调度也会在一次共享包/镜像准备步骤之后,把多个选定通道拆分为并行作业,并且内置渠道更新通道会针对临时 npm 网络失败重试一次。 -本地 changed-lane 逻辑位于 `scripts/changed-lanes.mjs`,并由 `scripts/check-changed.mjs` 执行。这个本地检查门禁在架构边界上比宽泛的 CI 平台范围更严格:核心生产变更会运行核心生产和核心测试类型检查,以及核心 lint/守卫;仅核心测试变更只运行核心测试类型检查和核心 lint;插件生产变更会运行插件生产和插件测试类型检查,以及插件 lint;仅插件测试变更会运行插件测试类型检查和插件 lint。公共插件 SDK 或插件契约变更会扩展到插件类型检查,因为插件依赖这些核心契约,但 Vitest 插件扫描属于显式测试工作。仅发布元数据的版本号变更会运行针对版本、配置和根依赖的检查。未知的根目录/配置变更会故障安全地回退到所有检查通道。 -本地 changed-test 路由位于 `scripts/test-projects.test-support.mjs`,并且 -有意比 `check:changed` 更轻量:直接测试编辑会运行自身, -源代码编辑会优先使用显式映射,然后是同级测试和导入图 -依赖项。共享群组房间投递配置是显式映射之一: -对群组可见回复配置、源回复投递模式或 -message-tool 系统提示词的更改,会路由到核心回复测试以及 Discord 和 -Slack 投递回归测试,这样共享默认值变更会在首次 PR -推送前失败。仅当变更覆盖整个 harness,导致廉价映射集合不能作为可信代理时, -才使用 `OPENCLAW_TEST_CHANGED_BROAD=1 pnpm test:changed`。 +本地变更车道逻辑位于 `scripts/changed-lanes.mjs`,并由 `scripts/check-changed.mjs` 执行。该本地检查关卡对架构边界的要求比广泛的 CI 平台范围更严格:核心生产更改会运行核心生产和核心测试类型检查,以及核心 lint/守卫;仅核心测试更改只运行核心测试类型检查以及核心 lint;插件生产更改会运行插件生产和插件测试类型检查,以及插件 lint;仅插件测试更改会运行插件测试类型检查以及插件 lint。公共插件 SDK 或插件契约更改会扩展到插件类型检查,因为插件依赖这些核心契约,但 Vitest 插件扫描是显式测试工作。仅发布元数据的版本号变更会运行定向版本/配置/根依赖检查。未知的根目录/配置更改会以故障安全方式进入所有检查车道。 +本地变更测试路由位于 `scripts/test-projects.test-support.mjs`,并且有意比 `check:changed` 更轻量:直接测试编辑会运行自身,源码编辑优先使用显式映射,然后是同级测试和导入图依赖项。共享群组房间投递配置是显式映射之一:对群组可见回复配置、源码回复投递模式或消息工具系统提示词的更改,会路由到核心回复测试以及 Discord 和 Slack 投递回归测试,因此共享默认值更改会在第一次 PR 推送前失败。只有当更改在 harness 范围内足够广,以至于廉价映射集合不能作为可信代理时,才使用 `OPENCLAW_TEST_CHANGED_BROAD=1 pnpm test:changed`。 -对于 Testbox 验证,请从仓库根目录运行,并优先使用新预热的 box 来获取 -宽泛证明。在把慢速门禁花在一个被复用、已过期或 -刚报告异常大量同步的 box 上之前,先在该 -box 内运行 `pnpm testbox:sanity`。当所需根文件(例如 -`pnpm-lock.yaml`)消失,或 `git status --short` 显示至少 200 个 -已跟踪删除时,完整性检查会快速失败。这通常意味着远程同步状态不是 -PR 的可信副本。停止该 box 并预热一个新的,而不是调试 -产品测试失败。对于有意的大规模删除 PR,请为该完整性检查运行设置 -`OPENCLAW_TESTBOX_ALLOW_MASS_DELETIONS=1`。 +对于 Testbox 验证,请从仓库根目录运行,并优先为广泛证明使用新预热的 box。在把较慢的关卡花到一个被复用、已过期或刚报告异常大同步量的 box 上之前,先在该 box 内运行 `pnpm testbox:sanity`。当所需根目录文件(例如 `pnpm-lock.yaml`)消失,或者 `git status --short` 显示至少 200 个已跟踪文件删除时,完整性检查会快速失败。这通常意味着远程同步状态不是 PR 的可信副本。请停止该 box 并预热一个新的,而不是调试产品测试失败。对于有意进行大量删除的 PR,请为该完整性检查设置 `OPENCLAW_TESTBOX_ALLOW_MASS_DELETIONS=1`。 -手动 CI 分派会运行 `checks-node-compat-node22` 作为宽泛兼容性覆盖。`plugin-prerelease-suite` 是成本更高的产品/包覆盖,因此只在 `Full Release Validation` 以 `full_release_validation=true` 分派 CI 时运行。普通拉取请求、`main` 推送和独立手动 CI 分派会保持该套件关闭。 +手动 CI 分派会运行 `checks-node-compat-node22` 作为广泛兼容性覆盖。`plugin-prerelease-suite` 是更昂贵的产品/包覆盖,因此只在 `Full Release Validation` 使用 `full_release_validation=true` 分派 CI 时运行。普通拉取请求、`main` 推送和独立手动 CI 分派都会保持该套件关闭。 -最慢的 Node 测试族已拆分或均衡,使每个作业保持较小规模且不过度预留 runner:渠道契约作为三个加权分片运行,内置插件测试在六个插件 worker 间均衡,小型核心单元通道会成对运行,自动回复作为四个均衡 worker 运行,并将回复子树拆分为 agent-runner、dispatch 和 commands/state-routing 分片,agentic Gateway 网关/插件配置分布在现有仅源码 agentic Node 作业中,而不是等待构建产物。宽泛浏览器、QA、媒体和杂项插件测试使用它们专用的 Vitest 配置,而不是共享插件兜底配置。插件分片作业一次最多运行两个插件配置组,每组一个 Vitest worker,并使用更大的 Node 堆,这样导入密集的插件批次不会创建额外 CI 作业。宽泛 agents 通道使用共享 Vitest 文件并行调度器,因为它主要受导入/调度影响,而不是由单个慢测试文件主导。`runtime-config` 与 infra core-runtime 分片一起运行,避免共享运行时分片承担尾部耗时。include-pattern 分片使用 CI 分片名称记录计时条目,因此 `.artifacts/vitest-shard-timings.json` 可以区分整个配置和过滤后的分片。`check-additional` 将包边界编译/canary 工作保持在一起,并将运行时拓扑架构与 Gateway 网关 watch 覆盖分离;boundary guard 分片会在一个作业内并发运行其小型独立守卫。Gateway 网关 watch、渠道测试和核心 support-boundary 分片在 `dist/` 和 `dist-runtime/` 已经构建后,在 `build-artifacts` 内并发运行,保留它们旧有的检查名称作为轻量验证作业,同时避免两个额外的 Blacksmith worker 和第二个产物消费队列。 -Android CI 会同时运行 `testPlayDebugUnitTest` 和 `testThirdPartyDebugUnitTest`,然后构建 Play debug APK。第三方 flavor 没有单独的 source set 或 manifest;它的单元测试通道仍会使用短信/通话记录 BuildConfig 标志编译该 flavor,同时避免在每次 Android 相关推送时重复执行 debug APK 打包作业。 -当同一 PR 或 `main` ref 上有更新推送落地时,GitHub 可能会将被取代的作业标记为 `cancelled`。除非同一 ref 的最新运行也失败,否则将其视为 CI 噪声。聚合分片检查使用 `!cancelled() && always()`,因此它们仍会报告正常的分片失败,但不会在整个 workflow 已经被取代后继续排队。 -自动 CI 并发键带有版本号(`CI-v7-*`),这样 GitHub 端旧队列组中的僵尸项无法无限期阻塞较新的 main 运行。手动全套件运行使用 `CI-manual-v1-*`,且不会取消进行中的运行。 +最慢的 Node 测试族会被拆分或均衡,使每个作业保持较小,同时不会过度预留 runner:渠道契约作为三个加权分片运行,内置插件测试在六个插件 worker 之间均衡,小型核心单元车道会配对运行,自动回复作为四个均衡 worker 运行且回复子树拆分为 agent-runner、dispatch 和 commands/state-routing 分片,agentic gateway/插件配置分散到现有的仅源码 agentic Node 作业中,而不是等待构建产物。广泛浏览器、QA、媒体和杂项插件测试使用它们专用的 Vitest 配置,而不是共享插件兜底配置。插件分片作业一次最多运行两个插件配置组,每组一个 Vitest worker,并使用更大的 Node 堆,因此导入密集的插件批次不会创建额外 CI 作业。广泛 agents 车道使用共享 Vitest 文件并行调度器,因为它主要受导入/调度影响,而不是由单个慢测试文件主导。`runtime-config` 与 infra core-runtime 分片一起运行,避免共享运行时分片承担尾部耗时。包含模式分片使用 CI 分片名称记录计时条目,因此 `.artifacts/vitest-shard-timings.json` 可以区分整个配置与过滤后的分片。`check-additional` 将包边界编译/canary 工作放在一起,并将运行时拓扑架构与 Gateway 网关 watch 覆盖分开;边界守卫分片会在一个作业内并发运行其小型独立守卫。Gateway 网关 watch、渠道测试和核心 support-boundary 分片会在 `dist/` 与 `dist-runtime/` 已构建后,在 `build-artifacts` 内并发运行,保留它们旧的检查名称作为轻量验证作业,同时避免两个额外 Blacksmith worker 和第二个产物消费者队列。 +Android CI 会同时运行 `testPlayDebugUnitTest` 和 `testThirdPartyDebugUnitTest`,然后构建 Play debug APK。第三方 flavor 没有单独的源码集或 manifest;它的单元测试车道仍会使用 SMS/通话记录 BuildConfig 标志编译该 flavor,同时避免在每次 Android 相关推送上重复执行 debug APK 打包作业。 +当较新的推送落在同一个 PR 或 `main` ref 上时,GitHub 可能会将被取代的作业标记为 `cancelled`。除非同一 ref 的最新运行也在失败,否则将其视为 CI 噪声。聚合分片检查使用 `!cancelled() && always()`,因此它们仍会报告正常分片失败,但不会在整个工作流已被取代后继续排队。 +自动 CI 并发键带有版本(`CI-v7-*`),因此 GitHub 侧旧队列组中的僵尸项不能无限期阻塞较新的 main 运行。手动完整套件运行使用 `CI-manual-v1-*`,并且不会取消进行中的运行。 ## Runner | Runner | 作业 | | -------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `ubuntu-24.04` | `preflight`,快速安全作业和聚合(`security-scm-fast`、`security-dependency-audit`、`security-fast`),快速协议/契约/内置检查,分片渠道契约检查,除 lint 外的 `check` 分片,`check-additional` 分片和聚合,Node 测试聚合验证器,文档检查,Python Skills,workflow-sanity,labeler,auto-response;install-smoke preflight 也使用 GitHub 托管 Ubuntu,这样 Blacksmith 矩阵可以更早排队 | -| `blacksmith-4vcpu-ubuntu-2404` | `CodeQL Critical Quality`,较低权重的插件分片,`checks-fast-core`,`checks-node-compat-node22`,`check-prod-types` 和 `check-test-types` | -| `blacksmith-8vcpu-ubuntu-2404` | `build-artifacts`,build-smoke,Linux Node 测试分片,内置插件测试分片,`android` | -| `blacksmith-16vcpu-ubuntu-2404` | `check-lint`,它对 CPU 仍足够敏感,使 8 vCPU 带来的成本高于节省;install-smoke Docker 构建中,32-vCPU 排队时间成本高于节省 | +| `ubuntu-24.04` | `preflight`,快速安全作业和聚合(`security-scm-fast`、`security-dependency-audit`、`security-fast`)、快速协议/契约/内置检查、分片渠道契约检查、除 lint 外的 `check` 分片、`check-additional` 分片和聚合、Node 测试聚合验证器、文档检查、Python Skills、workflow-sanity、labeler、auto-response;install-smoke preflight 也使用 GitHub 托管的 Ubuntu,以便 Blacksmith 矩阵可以更早排队 | +| `blacksmith-4vcpu-ubuntu-2404` | `CodeQL Critical Quality`、较低权重的插件分片、`checks-fast-core`、`checks-node-compat-node22`、`check-prod-types` 和 `check-test-types` | +| `blacksmith-8vcpu-ubuntu-2404` | `build-artifacts`、build-smoke、Linux Node 测试分片、内置插件测试分片、`android` | +| `blacksmith-16vcpu-ubuntu-2404` | `check-lint`,它仍然对 CPU 足够敏感,以至于 8 vCPU 的成本高于节省;install-smoke Docker 构建,其中 32-vCPU 队列时间的成本高于节省 | | `blacksmith-16vcpu-windows-2025` | `checks-windows` | | `blacksmith-6vcpu-macos-latest` | `openclaw/openclaw` 上的 `macos-node`;fork 回退到 `macos-latest` | | `blacksmith-12vcpu-macos-latest` | `openclaw/openclaw` 上的 `macos-swift`;fork 回退到 `macos-latest` | -## 本地等效命令 +## 本地等价命令 ```bash pnpm changed:lanes # inspect the local changed-lane classifier for origin/main...HEAD diff --git a/docs/zh-CN/help/testing.md b/docs/zh-CN/help/testing.md index 459ff9de4..f4aa327f5 100644 --- a/docs/zh-CN/help/testing.md +++ b/docs/zh-CN/help/testing.md @@ -3,33 +3,32 @@ read_when: - 在本地或 CI 中运行测试 - 为模型/提供商缺陷添加回归测试 - 调试 Gateway 网关 + 智能体行为 -summary: 测试工具包:单元/e2e/live 套件、Docker 运行器,以及每项测试覆盖的内容 +summary: 测试工具包:单元/端到端/实时套件、Docker 运行器,以及每个测试覆盖的内容 title: 测试 x-i18n: - generated_at: "2026-04-29T05:40:33Z" + generated_at: "2026-04-29T05:57:51Z" model: gpt-5.5 provider: openai - source_hash: 883840f97ca94a4e6b64cfce414da59ad3710ddd8e5e2e3ba04e33a83e96d407 + source_hash: 9b06c2e7905ca930f0cac92d43c5902d38b9513968a68d2077ff4ef7a5a345ce source_path: help/testing.md workflow: 16 --- -OpenClaw 有三个 Vitest 套件(单元/集成、e2e、live)和一小组 -Docker 运行器。本文档是一份“我们如何测试”的指南: +OpenClaw 有三个 Vitest 套件(单元/集成、端到端、真实服务测试)和少量 Docker 运行器。本文是“我们如何测试”的指南: -- 每个套件覆盖什么(以及它有意_不_覆盖什么)。 -- 常见工作流(本地、推送前、调试)应该运行哪些命令。 -- live 测试如何发现凭证并选择模型/提供商。 -- 如何为真实世界的模型/提供商问题添加回归测试。 +- 每个套件覆盖什么(以及它有意 _不_ 覆盖什么)。 +- 常见工作流(本地、推送前、调试)应运行哪些命令。 +- 真实服务测试如何发现凭证并选择模型/提供商。 +- 如何为真实的模型/提供商问题添加回归测试。 -**QA 栈(qa-lab、qa-channel、live 传输通道)** 单独记录在以下文档中: +**QA 栈(qa-lab、qa-channel、真实传输通道)** 已单独记录: -- [QA overview](/zh-CN/concepts/qa-e2e-automation) — 架构、命令界面、场景编写。 +- [QA overview](/zh-CN/concepts/qa-e2e-automation) — 架构、命令表面、场景编写。 - [Matrix QA](/zh-CN/concepts/qa-matrix) — `pnpm openclaw qa matrix` 的参考。 - [QA channel](/zh-CN/channels/qa-channel) — 由仓库支持的场景使用的合成传输插件。 -本页介绍如何运行常规测试套件和 Docker/Parallels 运行器。下面的 QA 专用运行器部分([QA 专用运行器](#qa-specific-runners))列出了具体的 `qa` 调用,并指回上面的参考文档。 +本页覆盖常规测试套件以及 Docker/Parallels 运行器的运行方式。下面的 QA 专用运行器部分([QA 专用运行器](#qa-specific-runners))列出具体的 `qa` 调用,并指回上面的参考文档。 ## 快速开始 @@ -37,166 +36,145 @@ Docker 运行器。本文档是一份“我们如何测试”的指南: 大多数时候: - 完整门禁(推送前预期执行):`pnpm build && pnpm check && pnpm check:test-types && pnpm test` -- 在资源充足的机器上更快地运行本地完整套件:`pnpm test:max` +- 在资源充足的机器上更快运行本地完整套件:`pnpm test:max` - 直接 Vitest 监听循环:`pnpm test:watch` -- 直接按文件定位现在也会路由扩展/渠道路径:`pnpm test extensions/discord/src/monitor/message-handler.preflight.test.ts` -- 在针对单个失败迭代时,优先先运行目标测试。 +- 直接文件定位现在也会路由插件/渠道路径:`pnpm test extensions/discord/src/monitor/message-handler.preflight.test.ts` +- 在迭代单个失败时,优先使用定向运行。 - Docker 支持的 QA 站点:`pnpm qa:lab:up` -- Linux VM 支持的 QA 通道:`pnpm openclaw qa suite --runner multipass --scenario channel-chat-baseline` +- Linux 虚拟机支持的 QA 通道:`pnpm openclaw qa suite --runner multipass --scenario channel-chat-baseline` 当你修改测试或想获得额外信心时: - 覆盖率门禁:`pnpm test:coverage` -- E2E 套件:`pnpm test:e2e` +- 端到端套件:`pnpm test:e2e` 调试真实提供商/模型时(需要真实凭证): -- Live 套件(模型 + Gateway 网关工具/图片探测):`pnpm test:live` -- 安静地定位一个 live 文件:`pnpm test:live -- src/agents/models.profiles.live.test.ts` -- Docker live 模型扫描:`pnpm test:docker:live-models` - - 每个选中的模型现在会运行一次文本回合外加一个小型文件读取式探测。 - 元数据声明支持 `image` 输入的模型也会运行一次微型图片回合。 +- 真实服务套件(模型 + Gateway 网关工具/图片探针):`pnpm test:live` +- 静默定位一个真实服务文件:`pnpm test:live -- src/agents/models.profiles.live.test.ts` +- Docker 真实模型扫描:`pnpm test:docker:live-models` + - 每个选中的模型现在都会运行一次文本轮次和一个小型文件读取风格探针。 + 元数据声明支持 `image` 输入的模型还会运行一个小型图片轮次。 在隔离提供商失败时,可用 `OPENCLAW_LIVE_MODEL_FILE_PROBE=0` 或 - `OPENCLAW_LIVE_MODEL_IMAGE_PROBE=0` 禁用这些额外探测。 + `OPENCLAW_LIVE_MODEL_IMAGE_PROBE=0` 禁用额外探针。 - CI 覆盖:每日 `OpenClaw Scheduled Live And E2E Checks` 和手动 - `OpenClaw Release Checks` 都会调用可复用的 live/E2E 工作流,并设置 - `include_live_suites: true`,其中包含按提供商分片的独立 Docker live 模型 + `OpenClaw Release Checks` 都会调用可复用的真实服务/端到端工作流,并设置 + `include_live_suites: true`,其中包括按提供商分片的独立 Docker 真实模型 矩阵任务。 - - 对于聚焦的 CI 重跑,分发 `OpenClaw Live And E2E Checks (Reusable)`, + - 对于聚焦的 CI 重跑,分派 `OpenClaw Live And E2E Checks (Reusable)`, 并设置 `include_live_suites: true` 和 `live_models_only: true`。 - 将新的高信号提供商密钥添加到 `scripts/ci-hydrate-live-auth.sh`, 以及 `.github/workflows/openclaw-live-and-e2e-checks-reusable.yml` 和它的 - 定时/发布调用方中。 + 定时/发布调用方。 - 原生 Codex 绑定聊天冒烟测试:`pnpm test:docker:live-codex-bind` - - 针对 Codex app-server 路径运行 Docker live 通道,使用 `/codex bind` + - 针对 Codex app-server 路径运行 Docker 真实服务通道,使用 `/codex bind` 绑定一个合成 Slack 私信,执行 `/codex fast` 和 - `/codex permissions`,然后验证一条纯文本回复和一个图片附件通过原生插件绑定 - 路由,而不是通过 ACP。 + `/codex permissions`,然后验证普通回复和图片附件通过原生插件绑定路由, + 而不是通过 ACP。 - Codex app-server harness 冒烟测试:`pnpm test:docker:live-codex-harness` - - 通过插件拥有的 Codex app-server harness 运行 Gateway 网关智能体回合, - 验证 `/codex status` 和 `/codex models`,并默认执行图片、cron MCP、子智能体和 Guardian 探测。在隔离其他 Codex - app-server 失败时,可用 - `OPENCLAW_LIVE_CODEX_HARNESS_SUBAGENT_PROBE=0` 禁用子智能体探测。对于聚焦的子智能体检查,禁用其他探测: + - 通过插件拥有的 Codex app-server harness 运行 Gateway 网关智能体轮次, + 验证 `/codex status` 和 `/codex models`,并默认执行图片、cron MCP、 + 子智能体和 Guardian 探针。在隔离其他 Codex app-server 失败时,可用 + `OPENCLAW_LIVE_CODEX_HARNESS_SUBAGENT_PROBE=0` 禁用子智能体探针。 + 对于聚焦的子智能体检查,禁用其他探针: `OPENCLAW_LIVE_CODEX_HARNESS_IMAGE_PROBE=0 OPENCLAW_LIVE_CODEX_HARNESS_MCP_PROBE=0 OPENCLAW_LIVE_CODEX_HARNESS_GUARDIAN_PROBE=0 OPENCLAW_LIVE_CODEX_HARNESS_SUBAGENT_PROBE=1 pnpm test:docker:live-codex-harness`。 - 除非设置了 - `OPENCLAW_LIVE_CODEX_HARNESS_SUBAGENT_ONLY=0`,否则这会在子智能体探测后退出。 + 除非设置了 `OPENCLAW_LIVE_CODEX_HARNESS_SUBAGENT_ONLY=0`, + 否则这会在子智能体探针后退出。 - Crestodian 救援命令冒烟测试:`pnpm test:live:crestodian-rescue-channel` - - 对消息渠道救援命令界面的可选双保险检查。 - 它会执行 `/crestodian status`,排队一个持久模型 - 变更,回复 `/crestodian yes`,并验证审计/配置写入路径。 -- Crestodian 规划器 Docker 冒烟测试:`pnpm test:docker:crestodian-planner` - - 在无配置容器中运行 Crestodian,`PATH` 上有一个假的 Claude CLI, - 并验证模糊规划器回退会转换为经过审计的类型化 - 配置写入。 + - 面向消息渠道救援命令表面的选择性双保险检查。它会执行 `/crestodian status`, + 排队一个持久模型变更,回复 `/crestodian yes`,并验证审计/配置写入路径。 +- Crestodian planner Docker 冒烟测试:`pnpm test:docker:crestodian-planner` + - 在无配置容器中运行 Crestodian,并在 `PATH` 上放置一个假的 Claude CLI, + 然后验证模糊 planner 回退会转化为已审计的类型化配置写入。 - Crestodian 首次运行 Docker 冒烟测试:`pnpm test:docker:crestodian-first-run` - 从空的 OpenClaw 状态目录开始,将裸 `openclaw` 路由到 Crestodian,应用设置/模型/智能体/Discord 插件 + SecretRef 写入, - 验证配置,并验证审计条目。同一条 Ring 0 设置路径 - 也在 QA Lab 中通过 + 验证配置,并检查审计条目。同一个 Ring 0 设置路径也由 QA Lab 中的 `pnpm openclaw qa suite --scenario crestodian-ring-zero-setup` 覆盖。 - Moonshot/Kimi 成本冒烟测试:设置 `MOONSHOT_API_KEY` 后,运行 `openclaw models list --provider moonshot --json`,然后针对 `moonshot/kimi-k2.6` 运行一个隔离的 `openclaw agent --local --session-id live-kimi-cost --message 'Reply exactly: KIMI_LIVE_OK' --thinking off --json`。 - 验证 JSON 报告 Moonshot/K2.6,并且助手转录保存了规范化的 `usage.cost`。 + 验证 JSON 报告 Moonshot/K2.6,且助手转录记录存储了规范化的 `usage.cost`。 -当你只需要一个失败用例时,优先通过下面描述的 allowlist 环境变量缩小 live 测试范围。 +当你只需要一个失败用例时,优先通过下面描述的 allowlist 环境变量缩小真实服务测试范围。 ## QA 专用运行器 -当你需要 QA-lab 的真实度时,这些命令与主测试套件并列: +当你需要 QA-lab 真实度时,这些命令与主测试套件并列使用: -CI 在专用工作流中运行 QA Lab。`Parity gate` 在匹配的 PR 上运行,并且 -可通过使用模拟提供商的手动分发运行。`QA-Lab - All Lanes` 每晚在 -`main` 上运行,也可通过手动分发运行,其中包含模拟奇偶门禁、live Matrix 通道、 -Convex 管理的 live Telegram 通道,以及 Convex 管理的 live Discord 通道, -这些都作为并行任务运行。定时 QA 和发布检查会显式传入 Matrix `--profile fast`, -而 Matrix CLI 和手动工作流输入的默认值仍为 -`all`;手动分发可以将 `all` 分片为 `transport`、`media`、`e2ee-smoke`、 -`e2ee-deep` 和 `e2ee-cli` 任务。`OpenClaw Release Checks` 在发布批准前运行奇偶检查以及 -快速 Matrix 和 Telegram 通道,发布传输检查使用 -`mock-openai/gpt-5.5`,以保持确定性并避免常规提供商插件启动。这些 live 传输 Gateway 网关会禁用 -memory 搜索;memory 行为仍由 QA 奇偶套件覆盖。 +CI 在专用工作流中运行 QA Lab。`Parity gate` 在匹配的 PR 上运行,也可通过手动分派使用模拟提供商运行。`QA-Lab - All Lanes` 每晚在 `main` 上运行,也可通过手动分派运行,使用模拟一致性门禁、真实 Matrix 通道、Convex 托管的真实 Telegram 通道,以及 Convex 托管的真实 Discord 通道作为并行任务。定时 QA 和发布检查会显式传入 Matrix `--profile fast`,而 Matrix CLI 和手动工作流输入默认仍为 `all`;手动分派可以将 `all` 分片为 `transport`、`media`、`e2ee-smoke`、`e2ee-deep` 和 `e2ee-cli` 任务。`OpenClaw Release Checks` 在发布批准前运行一致性门禁以及快速 Matrix 和 Telegram 通道,并使用 `mock-openai/gpt-5.5` 进行发布传输检查,从而保持确定性并避免普通提供商插件启动。这些真实传输 Gateway 网关会禁用记忆搜索;记忆行为仍由 QA 一致性套件覆盖。 -完整发布 live 媒体分片使用 -`ghcr.io/openclaw/openclaw-live-media-runner:ubuntu-24.04`,其中已经有 -`ffmpeg` 和 `ffprobe`。Docker live 模型/后端分片使用共享的 -`ghcr.io/openclaw/openclaw-live-test:` 镜像,该镜像会为每个选定的 -提交构建一次,然后用 `OPENCLAW_SKIP_DOCKER_BUILD=1` 拉取它,而不是在 -每个分片内部重新构建。 +完整发布真实媒体分片使用 +`ghcr.io/openclaw/openclaw-live-media-runner:ubuntu-24.04`,其中已经包含 +`ffmpeg` 和 `ffprobe`。Docker 真实模型/后端分片使用共享的 +`ghcr.io/openclaw/openclaw-live-test:` 镜像,该镜像会为选中的 +commit 构建一次,然后通过 `OPENCLAW_SKIP_DOCKER_BUILD=1` 拉取,而不是在每个分片内重新构建。 - `pnpm openclaw qa suite` - 直接在主机上运行由仓库支持的 QA 场景。 - - 默认使用隔离的 Gateway 网关工作器并行运行多个选定场景。 - `qa-channel` 默认并发为 4(受选定场景数量限制)。使用 `--concurrency ` 调整工作器 - 数量,或使用 `--concurrency 1` 运行较旧的串行通道。 - - 任一场景失败时以非零状态退出。当你 - 想要产物但不想要失败退出码时,使用 `--allow-failures`。 + - 默认使用隔离的 Gateway 网关 worker 并行运行多个选中的场景。 + `qa-channel` 默认并发为 4(受选中场景数量限制)。使用 + `--concurrency ` 调整 worker 数量,或使用 `--concurrency 1` + 运行较旧的串行通道。 + - 当任何场景失败时以非零状态退出。若你想获取产物但不希望失败退出码, + 请使用 `--allow-failures`。 - 支持提供商模式 `live-frontier`、`mock-openai` 和 `aimock`。 - `aimock` 会启动一个本地 AIMock 支持的提供商服务器,用于实验性 - fixture 和协议模拟覆盖,而不会替代场景感知的 - `mock-openai` 通道。 + `aimock` 会启动一个本地 AIMock 支持的提供商服务器,用于实验性的 + fixture 和协议模拟覆盖,而不会替代具备场景感知能力的 `mock-openai` 通道。 - `pnpm test:gateway:cpu-scenarios` - - 运行 Gateway 网关启动基准测试,以及一个小型模拟 QA Lab 场景包 + - 运行 Gateway 网关启动基准以及一个小型模拟 QA Lab 场景包 (`channel-chat-baseline`、`memory-failure-fallback`、 `gateway-restart-inflight-run`),并在 `.artifacts/gateway-cpu-scenarios/` - 下写入合并的 CPU 观察 - 摘要。 - - 默认只标记持续的高 CPU 观察(`--cpu-core-warn` - 加 `--hot-wall-warn-ms`),因此短暂的启动突发会被记录为指标, - 而不会看起来像持续数分钟的 Gateway 网关占满回归。 - - 使用构建好的 `dist` 产物;当检出内容中还没有新的运行时输出时, - 先运行构建。 + 下写入合并的 CPU 观测摘要。 + - 默认只标记持续的高 CPU 观测(`--cpu-core-warn` 加 + `--hot-wall-warn-ms`),因此短暂的启动峰值会被记录为指标,而不会看起来像持续数分钟的 + Gateway 网关占满 CPU 回归。 + - 使用已构建的 `dist` 产物;当检出目录中还没有新鲜运行时输出时,请先运行构建。 - `pnpm openclaw qa suite --runner multipass` - - 在一次性 Multipass Linux VM 中运行同一个 QA 套件。 + - 在一次性 Multipass Linux 虚拟机内运行相同的 QA 套件。 - 保持与主机上的 `qa suite` 相同的场景选择行为。 - 复用与 `qa suite` 相同的提供商/模型选择标志。 - - Live 运行会转发对 guest 实用的受支持 QA auth 输入: - 基于环境变量的提供商 key、QA live 提供商配置路径,以及存在时的 `CODEX_HOME`。 - - 输出目录必须保留在仓库根目录下,以便 guest 能通过 - 挂载的工作区写回。 + - 真实服务运行会转发对 guest 可行的受支持 QA 认证输入: + 基于 env 的提供商密钥、QA 真实服务提供商配置路径,以及存在时的 `CODEX_HOME`。 + - 输出目录必须保留在仓库根目录下,以便 guest 能通过挂载的工作区写回。 - 在 `.artifacts/qa-e2e/...` 下写入常规 QA 报告 + 摘要以及 Multipass 日志。 - `pnpm qa:lab:up` - - 启动 Docker 支持的 QA 站点,用于操作员风格的 QA 工作。 + - 启动 Docker 支持的 QA 站点,用于操作者风格的 QA 工作。 - `pnpm test:docker:npm-onboard-channel-agent` - - 从当前检出内容构建一个 npm tarball,在 - Docker 中全局安装它,运行非交互式 OpenAI API key 新手引导,默认配置 Telegram, - 验证启用插件会按需安装运行时依赖,运行 Doctor,并针对模拟的 OpenAI - 端点运行一个本地智能体回合。 - - 使用 `OPENCLAW_NPM_ONBOARD_CHANNEL=discord` 通过 Discord 运行同一个打包安装 - 通道。 + - 从当前检出构建 npm tarball,在 Docker 中全局安装它,运行非交互式 OpenAI + API key 新手引导,默认配置 Telegram,验证启用插件会按需安装运行时依赖, + 运行 Doctor,并针对模拟的 OpenAI 端点运行一次本地智能体轮次。 + - 使用 `OPENCLAW_NPM_ONBOARD_CHANNEL=discord` 可用 Discord 运行相同的打包安装通道。 - `pnpm test:docker:session-runtime-context` - - 为嵌入式运行时上下文转录运行确定性的已构建应用 Docker 冒烟测试。 - 它会验证隐藏的 OpenClaw 运行时上下文会作为非展示的自定义消息持久化, - 而不是泄露到可见用户回合中,然后植入一个受影响的损坏会话 JSONL,并验证 - `openclaw doctor --fix` 会将其重写到活动分支并创建备份。 + - 针对嵌入式运行时上下文转录记录,运行一个确定性的已构建应用 Docker 冒烟测试。 + 它会验证隐藏的 OpenClaw 运行时上下文以非展示的自定义消息持久化, + 而不是泄漏到可见的用户轮次中,然后植入一个受影响的损坏会话 JSONL, + 并验证 `openclaw doctor --fix` 会将其重写到当前分支且创建备份。 - `pnpm test:docker:npm-telegram-live` - - 在 Docker 中安装 OpenClaw 候选包,运行已安装包的 - 新手引导,通过已安装的 CLI 配置 Telegram,然后复用 - live Telegram QA 通道,并将该已安装包作为 SUT Gateway 网关。 - - 默认值为 `OPENCLAW_NPM_TELEGRAM_PACKAGE_SPEC=openclaw@beta`;设置 + - 在 Docker 中安装一个 OpenClaw 包候选版本,运行已安装包的新手引导, + 通过已安装的 CLI 配置 Telegram,然后复用真实 Telegram QA 通道, + 并将该已安装包作为被测系统 Gateway 网关。 + - 默认使用 `OPENCLAW_NPM_TELEGRAM_PACKAGE_SPEC=openclaw@beta`;设置 `OPENCLAW_NPM_TELEGRAM_PACKAGE_TGZ=/path/to/openclaw-current.tgz` 或 - `OPENCLAW_CURRENT_PACKAGE_TGZ` 可测试已解析的本地 tarball,而不是 - 从 registry 安装。 - - 使用与 `pnpm openclaw qa telegram` 相同的 Telegram 环境变量凭证或 Convex 凭证源。 - 对于 CI/发布自动化,设置 - `OPENCLAW_NPM_TELEGRAM_CREDENTIAL_SOURCE=convex`,以及 - `OPENCLAW_QA_CONVEX_SITE_URL` 和角色密钥。如果 - `OPENCLAW_QA_CONVEX_SITE_URL` 和一个 Convex 角色密钥存在于 CI 中, - Docker 包装器会自动选择 Convex。 + `OPENCLAW_CURRENT_PACKAGE_TGZ` 可测试已解析的本地 tarball,而不是从注册表安装。 + - 使用与 `pnpm openclaw qa telegram` 相同的 Telegram env 凭证或 Convex + 凭证来源。对于 CI/发布自动化,请设置 + `OPENCLAW_NPM_TELEGRAM_CREDENTIAL_SOURCE=convex`,再加上 + `OPENCLAW_QA_CONVEX_SITE_URL` 和角色密钥。如果 CI 中存在 + `OPENCLAW_QA_CONVEX_SITE_URL` 和一个 Convex 角色密钥,Docker 包装器会自动选择 Convex。 - `OPENCLAW_NPM_TELEGRAM_CREDENTIAL_ROLE=ci|maintainer` 只为此通道覆盖共享的 `OPENCLAW_QA_CREDENTIAL_ROLE`。 - - GitHub Actions 将此通道暴露为手动维护者工作流 - `NPM Telegram Beta E2E`。它不会在合并时运行。该工作流使用 - `qa-live-shared` 环境和 Convex CI 凭证租约。 -- GitHub Actions 还暴露了 `Package Acceptance`,用于针对一个候选包进行旁路产品证明。 - 它接受可信 ref、已发布的 npm spec、 - HTTPS tarball URL 加 SHA-256,或来自另一次运行的 tarball 产物,上传 - 规范化的 `openclaw-current.tgz` 作为 `package-under-test`,然后使用 smoke、package、product、full 或 custom - 通道 profile 运行现有 Docker E2E 调度器。设置 `telegram_mode=mock-openai` 或 `live-frontier` 可让 - Telegram QA 工作流针对同一个 `package-under-test` 产物运行。 + - GitHub Actions 将此通道作为手动维护者工作流 `NPM Telegram Beta E2E` 暴露。 + 它不会在合并时运行。该工作流使用 `qa-live-shared` 环境和 Convex CI 凭证租约。 +- GitHub Actions 还暴露 `Package Acceptance`,用于针对一个候选包进行旁路产品证明。 + 它接受可信 ref、已发布 npm spec、HTTPS tarball URL 加 SHA-256, + 或来自另一次运行的 tarball 产物,将规范化的 `openclaw-current.tgz` 上传为 + `package-under-test`,然后使用 smoke、package、product、full 或自定义通道配置文件运行现有的 + Docker E2E 调度器。设置 `telegram_mode=mock-openai` 或 `live-frontier` + 可让 Telegram QA 工作流针对相同的 `package-under-test` 产物运行。 - 最新 beta 产品证明: ```bash @@ -217,7 +195,7 @@ gh workflow run package-acceptance.yml --ref main \ -f suite_profile=package ``` -- 工件证明会从另一个 Actions 运行下载 tarball 工件: +- 构件证明会从另一个 Actions 运行下载 tarball 构件: ```bash gh workflow run package-acceptance.yml --ref main \ @@ -228,44 +206,44 @@ gh workflow run package-acceptance.yml --ref main \ ``` - `pnpm test:docker:bundled-channel-deps` - - 在 Docker 中打包并安装当前 OpenClaw 构建,使用已配置的 OpenAI 启动 Gateway 网关,然后通过配置编辑启用内置渠道/插件。 - - 验证设置发现会让未配置的插件运行时依赖保持缺失,首次配置的 Gateway 网关或 Doctor 运行会按需安装每个内置插件的运行时依赖,并且第二次重启不会重新安装已激活的依赖。 - - 还会安装一个已知的较旧 npm 基线,在运行 `openclaw update --tag ` 前启用 Telegram,并验证候选版本的更新后 Doctor 会修复内置渠道运行时依赖,无需 harness 侧 postinstall 修复。 + - 在 Docker 中打包并安装当前 OpenClaw 构建,启动已配置 OpenAI 的 Gateway 网关,然后通过配置编辑启用内置渠道/插件。 + - 验证设置发现会让未配置的插件运行时依赖保持缺失,首次配置的 Gateway 网关或 doctor 运行会按需安装每个内置插件的运行时依赖,并且第二次重启不会重新安装已经激活的依赖。 + - 还会安装一个已知的旧 npm 基线,在运行 `openclaw update --tag ` 前启用 Telegram,并验证候选版本的更新后 doctor 能修复内置渠道运行时依赖,而不需要 harness 侧的 postinstall 修复。 - `pnpm test:parallels:npm-update` - - 跨 Parallels 客户机运行原生打包安装更新冒烟测试。每个选中的平台先安装请求的基线包,然后在同一个客户机中运行已安装的 `openclaw update` 命令,并验证已安装版本、更新 Status、Gateway 网关就绪状态,以及一次本地智能体回合。 - - 在迭代单个客户机时使用 `--platform macos`、`--platform windows` 或 `--platform linux`。使用 `--json` 获取摘要工件路径和每条 lane 的 Status。 - - OpenAI lane 默认使用 `openai/gpt-5.5` 作为实时智能体回合证明。若要刻意验证另一个 OpenAI 模型,请传入 `--model ` 或设置 `OPENCLAW_PARALLELS_OPENAI_MODEL`。 - - 用主机超时包装长时间本地运行,避免 Parallels 传输停滞耗尽剩余测试窗口: + - 跨 Parallels guest 运行原生打包安装更新 smoke。每个选中的平台会先安装请求的基线包,然后在同一个 guest 中运行已安装的 `openclaw update` 命令,并验证已安装版本、更新 Status、Gateway 网关就绪状态,以及一次本地智能体轮次。 + - 在迭代单个 guest 时使用 `--platform macos`、`--platform windows` 或 `--platform linux`。使用 `--json` 获取摘要构件路径和每个 lane 的 Status。 + - OpenAI lane 默认使用 `openai/gpt-5.5` 作为实时智能体轮次证明。需要有意验证另一个 OpenAI 模型时,传入 `--model ` 或设置 `OPENCLAW_PARALLELS_OPENAI_MODEL`。 + - 用宿主机 timeout 包裹较长的本地运行,避免 Parallels 传输停滞耗尽剩余测试窗口: ```bash timeout --foreground 150m pnpm test:parallels:npm-update -- --json timeout --foreground 90m pnpm test:parallels:npm-update -- --platform windows --json ``` - - 脚本会在 `/tmp/openclaw-parallels-npm-update.*` 下写入嵌套 lane 日志。在假定外层包装器挂起之前,先检查 `windows-update.log`、`macos-update.log` 或 `linux-update.log`。 - - 在冷启动客户机上,Windows 更新可能会在更新后 Doctor/运行时依赖修复中花费 10 到 15 分钟;只要嵌套 npm 调试日志仍在推进,这仍然是正常的。 - - 不要将这个聚合包装器与单独的 Parallels macOS、Windows 或 Linux 冒烟 lane 并行运行。它们共享虚拟机状态,可能在快照恢复、包服务或客户机 Gateway 网关状态上发生冲突。 - - 更新后证明会运行常规内置插件表面,因为语音、图像生成和媒体理解等能力 facade 是通过内置运行时 API 加载的,即使智能体回合本身只检查一个简单文本响应。 + - 脚本会在 `/tmp/openclaw-parallels-npm-update.*` 下写入嵌套 lane 日志。在假定外层 wrapper 挂起之前,先检查 `windows-update.log`、`macos-update.log` 或 `linux-update.log`。 + - 在冷 guest 上,Windows 更新可能会在更新后 doctor/运行时依赖修复中花费 10 到 15 分钟;只要嵌套 npm debug 日志还在推进,这仍然是正常状态。 + - 不要将此聚合 wrapper 与单独的 Parallels macOS、Windows 或 Linux smoke lane 并行运行。它们共享 VM 状态,可能在快照还原、包服务或 guest Gateway 网关状态上发生冲突。 + - 更新后证明会运行常规的内置插件表面,因为即使智能体轮次本身只检查简单文本响应,语音、图像生成和媒体理解等能力 facade 也是通过内置运行时 API 加载的。 - `pnpm openclaw qa aimock` - - 仅启动本地 AIMock provider 服务器,用于直接协议冒烟测试。 + - 只启动本地 AIMock 提供商服务器,用于直接协议 smoke 测试。 - `pnpm openclaw qa matrix` - - 针对一次性 Docker 支持的 Tuwunel homeserver 运行 Matrix 实时 QA lane。仅源代码检出可用 — 打包安装不会发布 `qa-lab`。 - - 完整 CLI、profile/场景目录、环境变量和工件布局:[Matrix QA](/zh-CN/concepts/qa-matrix)。 + - 针对一次性 Docker 后端 Tuwunel homeserver 运行 Matrix 实时 QA lane。仅限源代码检出 — 打包安装不会随附 `qa-lab`。 + - 完整 CLI、profile/scenario 目录、环境变量和构件布局:[Matrix QA](/zh-CN/concepts/qa-matrix)。 - `pnpm openclaw qa telegram` - 使用来自环境变量的 driver 和 SUT bot token,针对真实私有群组运行 Telegram 实时 QA lane。 - - 需要 `OPENCLAW_QA_TELEGRAM_GROUP_ID`、`OPENCLAW_QA_TELEGRAM_DRIVER_BOT_TOKEN` 和 `OPENCLAW_QA_TELEGRAM_SUT_BOT_TOKEN`。群组 ID 必须是数字 Telegram 聊天 ID。 - - 支持 `--credential-source convex` 来使用共享池化凭据。默认使用环境变量模式,或设置 `OPENCLAW_QA_CREDENTIAL_SOURCE=convex` 以选择使用池化租约。 - - 任一场景失败时会以非零状态退出。当你想要工件但不想要失败退出码时,使用 `--allow-failures`。 - - 需要同一私有群组中的两个不同 bot,并且 SUT bot 需要公开 Telegram 用户名。 - - 为获得稳定的 bot 到 bot 观察,在两个 bot 的 `@BotFather` 中启用机器人到机器人通信模式,并确保 driver bot 可以观察群组 bot 流量。 - - 在 `.artifacts/qa-e2e/...` 下写入 Telegram QA 报告、摘要和 observed-messages 工件。回复场景包含从 driver 发送请求到观察到 SUT 回复的 RTT。 + - 需要 `OPENCLAW_QA_TELEGRAM_GROUP_ID`、`OPENCLAW_QA_TELEGRAM_DRIVER_BOT_TOKEN` 和 `OPENCLAW_QA_TELEGRAM_SUT_BOT_TOKEN`。群组 id 必须是数字 Telegram chat id。 + - 支持 `--credential-source convex` 使用共享池化凭证。默认使用 env 模式,或设置 `OPENCLAW_QA_CREDENTIAL_SOURCE=convex` 以选择加入池化租约。 + - 任一 scenario 失败时会以非零退出。如果你想获取构件但不产生失败退出码,请使用 `--allow-failures`。 + - 需要同一私有群组中的两个不同 bot,且 SUT bot 公开 Telegram username。 + - 为了获得稳定的 bot 到 bot 观测,请在 `@BotFather` 中为两个 bot 启用 Bot-to-Bot Communication Mode,并确保 driver bot 可以观察群组 bot 流量。 + - 在 `.artifacts/qa-e2e/...` 下写入 Telegram QA 报告、摘要和 observed-messages 构件。回复 scenario 包含从 driver 发送请求到观测到 SUT 回复的 RTT。 -实时传输 lane 共享一个标准契约,避免新传输漂移;每条 lane 的覆盖矩阵位于 [QA overview → 实时传输覆盖范围](/zh-CN/concepts/qa-e2e-automation#live-transport-coverage)。`qa-channel` 是广泛的合成套件,不属于该矩阵。 +实时传输 lane 共享一个标准契约,这样新传输不会漂移;每个 lane 的覆盖矩阵位于 [QA overview → 实时传输覆盖](/zh-CN/concepts/qa-e2e-automation#live-transport-coverage)。`qa-channel` 是广义合成套件,不属于该矩阵。 -### 通过 Convex 共享 Telegram 凭据(v1) +### 通过 Convex 共享 Telegram 凭证(v1) -为 `openclaw qa telegram` 启用 `--credential-source convex`(或 `OPENCLAW_QA_CREDENTIAL_SOURCE=convex`)后,QA lab 会从 Convex 支持的池中获取独占租约,在 lane 运行期间对该租约发送心跳,并在关闭时释放租约。 +为 `openclaw qa telegram` 启用 `--credential-source convex`(或 `OPENCLAW_QA_CREDENTIAL_SOURCE=convex`)时,QA lab 会从 Convex 后端池中获取独占租约,在 lane 运行期间对该租约进行心跳,并在关闭时释放租约。 参考 Convex 项目脚手架: @@ -274,12 +252,12 @@ gh workflow run package-acceptance.yml --ref main \ 必需环境变量: - `OPENCLAW_QA_CONVEX_SITE_URL`(例如 `https://your-deployment.convex.site`) -- 所选角色的一个密钥: +- 所选角色的一个 secret: - `OPENCLAW_QA_CONVEX_SECRET_MAINTAINER` 用于 `maintainer` - `OPENCLAW_QA_CONVEX_SECRET_CI` 用于 `ci` -- 凭据角色选择: +- 凭证角色选择: - CLI:`--credential-role maintainer|ci` - - 环境变量默认值:`OPENCLAW_QA_CREDENTIAL_ROLE`(CI 中默认为 `ci`,否则为 `maintainer`) + - Env 默认值:`OPENCLAW_QA_CREDENTIAL_ROLE`(CI 中默认为 `ci`,否则为 `maintainer`) 可选环境变量: @@ -288,14 +266,14 @@ gh workflow run package-acceptance.yml --ref main \ - `OPENCLAW_QA_CREDENTIAL_ACQUIRE_TIMEOUT_MS`(默认 `90000`) - `OPENCLAW_QA_CREDENTIAL_HTTP_TIMEOUT_MS`(默认 `15000`) - `OPENCLAW_QA_CONVEX_ENDPOINT_PREFIX`(默认 `/qa-credentials/v1`) -- `OPENCLAW_QA_CREDENTIAL_OWNER_ID`(可选跟踪 ID) -- `OPENCLAW_QA_ALLOW_INSECURE_HTTP=1` 允许仅本地开发使用环回 `http://` Convex URL。 +- `OPENCLAW_QA_CREDENTIAL_OWNER_ID`(可选 trace id) +- `OPENCLAW_QA_ALLOW_INSECURE_HTTP=1` 允许用于仅本地开发的 loopback `http://` Convex URL。 -`OPENCLAW_QA_CONVEX_SITE_URL` 在正常运行中应使用 `https://`。 +正常操作中,`OPENCLAW_QA_CONVEX_SITE_URL` 应使用 `https://`。 -维护者管理命令(池 add/remove/list)专门需要 `OPENCLAW_QA_CONVEX_SECRET_MAINTAINER`。 +Maintainer admin 命令(池添加/移除/列出)特别需要 `OPENCLAW_QA_CONVEX_SECRET_MAINTAINER`。 -维护者 CLI 辅助命令: +供 maintainer 使用的 CLI 辅助命令: ```bash pnpm openclaw qa credentials doctor @@ -304,9 +282,9 @@ pnpm openclaw qa credentials list --kind telegram pnpm openclaw qa credentials remove --credential-id ``` -在实时运行前使用 `doctor` 检查 Convex 站点 URL、broker 密钥、端点前缀、HTTP 超时和 admin/list 可达性,且不会打印密钥值。在脚本和 CI 工具中使用 `--json` 获取机器可读输出。 +在实时运行前使用 `doctor` 检查 Convex site URL、broker secret、endpoint prefix、HTTP timeout 和 admin/list 可达性,而不打印 secret 值。在脚本和 CI 工具中使用 `--json` 获取机器可读输出。 -默认端点契约(`OPENCLAW_QA_CONVEX_SITE_URL` + `/qa-credentials/v1`): +默认 endpoint 契约(`OPENCLAW_QA_CONVEX_SITE_URL` + `/qa-credentials/v1`): - `POST /acquire` - 请求:`{ kind, ownerId, actorRole, leaseTtlMs, heartbeatIntervalMs }` @@ -318,72 +296,74 @@ pnpm openclaw qa credentials remove --credential-id - `POST /release` - 请求:`{ kind, ownerId, actorRole, credentialId, leaseToken }` - 成功:`{ status: "ok" }`(或空 `2xx`) -- `POST /admin/add`(仅维护者密钥) +- `POST /admin/add`(仅 maintainer secret) - 请求:`{ kind, actorId, payload, note?, status? }` - 成功:`{ status: "ok", credential }` -- `POST /admin/remove`(仅维护者密钥) +- `POST /admin/remove`(仅 maintainer secret) - 请求:`{ credentialId, actorId }` - 成功:`{ status: "ok", changed, credential }` - 活跃租约保护:`{ status: "error", code: "LEASE_ACTIVE", ... }` -- `POST /admin/list`(仅维护者密钥) +- `POST /admin/list`(仅 maintainer secret) - 请求:`{ kind?, status?, includePayload?, limit? }` - 成功:`{ status: "ok", credentials, count }` -Telegram 类型的 payload 形状: +Telegram kind 的 payload 形状: - `{ groupId: string, driverToken: string, sutToken: string }` -- `groupId` 必须是数字 Telegram 聊天 ID 字符串。 -- `admin/add` 会针对 `kind: "telegram"` 验证此形状,并拒绝格式错误的 payload。 +- `groupId` 必须是数字 Telegram chat id 字符串。 +- `admin/add` 会为 `kind: "telegram"` 验证此形状,并拒绝格式错误的 payload。 ### 向 QA 添加渠道 -新渠道适配器的架构和场景辅助函数名称位于 [QA overview → 添加渠道](/zh-CN/concepts/qa-e2e-automation#adding-a-channel)。最低要求:在共享 `qa-lab` host seam 上实现传输 runner,在插件 manifest 中声明 `qaRunners`,挂载为 `openclaw qa `,并在 `qa/scenarios/` 下编写场景。 +新渠道适配器的架构和 scenario-helper 名称位于 [QA overview → 添加渠道](/zh-CN/concepts/qa-e2e-automation#adding-a-channel)。最低要求:在共享 `qa-lab` host seam 上实现传输 runner,在插件 manifest 中声明 `qaRunners`,挂载为 `openclaw qa `,并在 `qa/scenarios/` 下编写 scenario。 ## 测试套件(在哪里运行什么) -可以把这些套件理解为“逐步提高真实性”(同时也提高不稳定性/成本): +将这些套件视为“逐渐提高真实度”(同时也增加不稳定性/成本): ### 单元 / 集成(默认) - 命令:`pnpm test` -- 配置:未定向运行使用 `vitest.full-*.config.ts` 分片集,并可能将多项目分片展开为按项目配置以进行并行调度 -- 文件:`src/**/*.test.ts`、`packages/**/*.test.ts` 和 `test/**/*.test.ts` 下的核心/单元清单;UI 单元测试在专用 `unit-ui` 分片中运行 +- 配置:非定向运行使用 `vitest.full-*.config.ts` shard 集,并且可能将多项目 shard 展开为按项目配置以进行并行调度 +- 文件:`src/**/*.test.ts`、`packages/**/*.test.ts` 和 `test/**/*.test.ts` 下的 core/unit 清单;UI 单元测试在专用 `unit-ui` shard 中运行 - 范围: - 纯单元测试 - - 进程内集成测试(Gateway 网关鉴权、路由、工具调用、解析、配置) + - 进程内集成测试(Gateway 网关 auth、路由、工具、解析、配置) - 已知 bug 的确定性回归 - 预期: - 在 CI 中运行 - - 不需要真实密钥 + - 不需要真实 key - 应该快速且稳定 + - Resolver 和公共表面 loader 测试必须用生成的微型插件 fixture 证明广义 `api.js` 和 `runtime-api.js` fallback 行为,而不是使用真实内置插件源 API。真实插件 API 加载属于插件拥有的契约/集成套件。 - + - - 未指定目标的 `pnpm test` 会运行十二个更小的分片配置(`core-unit-fast`、`core-unit-src`、`core-unit-security`、`core-unit-ui`、`core-unit-support`、`core-support-boundary`、`core-contracts`、`core-bundled`、`core-runtime`、`agentic`、`auto-reply`、`extensions`),而不是一个巨大的原生根项目进程。这会降低负载较高机器上的峰值 RSS,并避免 auto-reply/extension 工作让无关套件资源不足。 - - `pnpm test --watch` 仍然使用原生根 `vitest.config.ts` 项目图,因为多分片 watch 循环并不实用。 - - `pnpm test`、`pnpm test:watch` 和 `pnpm test:perf:imports` 会先通过作用域车道分派显式文件/目录目标,因此 `pnpm test extensions/discord/src/monitor/message-handler.preflight.test.ts` 可以避免承担完整根项目启动成本。 - - `pnpm test:changed` 默认会把已变更的 git 路径展开为低成本的作用域车道:直接测试编辑、相邻 `*.test.ts` 文件、显式源码映射,以及本地导入图依赖项。Config/Setup/package 编辑不会广泛运行测试,除非你显式使用 `OPENCLAW_TEST_CHANGED_BROAD=1 pnpm test:changed`。 - - `pnpm check:changed` 是窄范围工作的常规智能本地检查门禁。它会把 diff 分类为 core、core tests、extensions、extension tests、apps、docs、release metadata、live Docker tooling 和 tooling,然后运行匹配的 typecheck、lint 和 guard 命令。它不会运行 Vitest 测试;如需测试证明,请调用 `pnpm test:changed` 或显式 `pnpm test `。仅 release metadata 的版本号提升会运行定向 version/config/root-dependency 检查,并带有一个 guard,用来拒绝顶层 version 字段以外的 package 变更。 - - Live Docker ACP harness 编辑会运行聚焦检查:live Docker auth 脚本的 shell 语法检查,以及 live Docker scheduler dry-run。只有当 diff 限定在 `scripts["test:docker:live-*"]` 时才包含 `package.json` 变更;dependency、export、version 和其他 package 表面编辑仍然使用更广的 guard。 - - 来自 agents、commands、plugins、auto-reply helpers、`plugin-sdk` 以及类似纯工具区域的轻导入单元测试会走 `unit-fast` 车道,该车道会跳过 `test/setup-openclaw-runtime.ts`;有状态或运行时较重的文件仍保留在现有车道。 - - 选定的 `plugin-sdk` 和 `commands` helper 源文件也会把 changed-mode 运行映射到这些轻量车道中的显式相邻测试,因此 helper 编辑可以避免为该目录重新运行完整重型套件。 - - `auto-reply` 为顶层 core helpers、顶层 `reply.*` 集成测试以及 `src/auto-reply/reply/**` 子树设置了专用桶。CI 还会进一步把 reply 子树拆分为 agent-runner、dispatch 和 commands/state-routing 分片,避免一个导入较重的桶占用完整 Node 尾部时间。 + - 非定向的 `pnpm test` 会运行十二个较小的分片配置(`core-unit-fast`、`core-unit-src`、`core-unit-security`、`core-unit-ui`、`core-unit-support`、`core-support-boundary`、`core-contracts`、`core-bundled`、`core-runtime`、`agentic`、`auto-reply`、`extensions`),而不是一个巨大的原生根项目进程。这会降低负载较高机器上的峰值 RSS,并避免 auto-reply/extension 工作让无关套件饥饿。 + - `pnpm test --watch` 仍使用原生根 `vitest.config.ts` 项目图,因为多分片 watch 循环并不实用。 + - `pnpm test`、`pnpm test:watch` 和 `pnpm test:perf:imports` 会先把显式文件/目录目标路由到作用域化 lane,因此 `pnpm test extensions/discord/src/monitor/message-handler.preflight.test.ts` 可以避免支付完整根项目启动成本。 + - `pnpm test:changed` 默认会把变更的 git 路径展开为低成本的作用域化 lane:直接测试编辑、同级 `*.test.ts` 文件、显式源映射,以及本地导入图依赖项。配置/setup/package 编辑不会广泛运行测试,除非你显式使用 `OPENCLAW_TEST_CHANGED_BROAD=1 pnpm test:changed`。 + - `pnpm check:changed` 是窄范围工作的常规智能本地检查门禁。它会把 diff 分类为 core、core tests、extensions、extension tests、apps、docs、release metadata、live Docker tooling 和 tooling,然后运行匹配的 typecheck、lint 和 guard 命令。它不会运行 Vitest 测试;如需测试证明,请调用 `pnpm test:changed` 或显式的 `pnpm test `。仅发布元数据的版本 bump 会运行定向版本/config/root-dependency 检查,并带有一个 guard,用于拒绝顶层 version 字段之外的 package 变更。 + - Live Docker ACP harness 编辑会运行聚焦检查:live Docker auth 脚本的 shell 语法,以及 live Docker 调度器 dry-run。仅当 diff 限定在 `scripts["test:docker:live-*"]` 时,才会包含 `package.json` 变更;dependency、export、version 和其他 package 表面编辑仍使用更广泛的 guard。 + - 来自 agents、commands、plugins、auto-reply helpers、`plugin-sdk` 以及类似纯工具区域的轻量导入单元测试会路由到 `unit-fast` lane,该 lane 会跳过 `test/setup-openclaw-runtime.ts`;有状态/运行时较重的文件仍保留在现有 lane 上。 + - 选定的 `plugin-sdk` 和 `commands` 辅助源文件也会把 changed-mode 运行映射到这些轻量 lane 中的显式同级测试,因此辅助文件编辑可以避免重新运行该目录的完整重型套件。 + - `auto-reply` 为顶层 core helpers、顶层 `reply.*` 集成测试以及 `src/auto-reply/reply/**` 子树提供专用 bucket。CI 还会进一步把 reply 子树拆分为 agent-runner、dispatch 和 commands/state-routing 分片,因此不会让一个导入较重的 bucket 独占完整 Node 尾部。 + - 常规 PR/main CI 有意跳过 extension 批量 sweep 和仅发布使用的 `agentic-plugins` 分片。完整 Release Validation 会以 `full_release_validation=true` 分发 CI 子流程,从而为发布候选版本重新启用这些 plugin/extension 重型套件。 - + - - 当你更改 message-tool 发现输入或 compaction 运行时 - 上下文时,请保留两层覆盖。 - - 为纯 routing 和 normalization - 边界添加聚焦 helper 回归测试。 - - 保持嵌入式运行器集成套件健康: + - 当你更改 message-tool 设备发现输入或 compaction 运行时 + 上下文时,请保留两层覆盖率。 + - 为纯路由和规范化 + 边界添加聚焦的辅助回归测试。 + - 保持嵌入式 runner 集成套件健康: `src/agents/pi-embedded-runner/compact.hooks.test.ts`、 `src/agents/pi-embedded-runner/run.overflow-compaction.test.ts` 和 `src/agents/pi-embedded-runner/run.overflow-compaction.loop.test.ts`。 - - 这些套件会验证 scoped ids 和 compaction 行为仍然通过真实的 - `run.ts` / `compact.ts` 路径流动;仅 helper 的测试 + - 这些套件会验证作用域化 id 和 compaction 行为仍然流经真实 + `run.ts` / `compact.ts` 路径;仅辅助函数测试 不能充分替代这些集成路径。 @@ -391,66 +371,65 @@ Telegram 类型的 payload 形状: - 基础 Vitest 配置默认使用 `threads`。 - - 共享 Vitest 配置固定 `isolate: false`,并在根项目、e2e 和 live 配置中使用 - 非隔离运行器。 - - 根 UI 车道保留其 `jsdom` 设置和优化器,但也运行在 - 共享的非隔离运行器上。 - - 每个 `pnpm test` 分片都从共享 Vitest 配置继承相同的 `threads` + `isolate: false` + - 共享 Vitest 配置固定为 `isolate: false`,并在根项目、e2e 和 live 配置中使用 + 非隔离 runner。 + - 根 UI lane 保留其 `jsdom` setup 和 optimizer,但也运行在 + 共享的非隔离 runner 上。 + - 每个 `pnpm test` 分片都会从共享 Vitest 配置继承相同的 `threads` + `isolate: false` 默认值。 - `scripts/run-vitest.mjs` 默认会为 Vitest 子 Node - 进程添加 `--no-maglev`,以减少大型本地运行期间的 V8 编译抖动。 - 设置 `OPENCLAW_VITEST_ENABLE_MAGLEV=1` 可与原始 V8 - 行为对比。 + 进程添加 `--no-maglev`,以减少大型本地运行期间的 V8 编译 churn。 + 设置 `OPENCLAW_VITEST_ENABLE_MAGLEV=1` 可与原生 V8 + 行为进行比较。 - - `pnpm changed:lanes` 会显示一个 diff 触发了哪些架构车道。 - - pre-commit hook 仅负责格式化。它会重新暂存已格式化文件, + - `pnpm changed:lanes` 会显示一个 diff 触发哪些架构 lane。 + - pre-commit hook 仅执行格式化。它会重新暂存已格式化的文件, 不会运行 lint、typecheck 或测试。 - - 在交接或 push 之前,当你需要智能本地检查门禁时, - 显式运行 `pnpm check:changed`。 - - `pnpm test:changed` 默认会通过低成本作用域车道分派。只有当 agent - 判断 harness、config、package 或 contract 编辑确实需要更广的 - Vitest 覆盖时,才使用 + - 当你需要智能本地检查门禁时,在 handoff 或 push 前显式运行 + `pnpm check:changed`。 + - `pnpm test:changed` 默认通过低成本的作用域化 lane 路由。仅当智能体 + 判断 harness、config、package 或 contract 编辑确实需要更广泛的 + Vitest 覆盖率时,才使用 `OPENCLAW_TEST_CHANGED_BROAD=1 pnpm test:changed`。 - `pnpm test:max` 和 `pnpm test:changed:max` 保持相同的路由 行为,只是使用更高的 worker 上限。 - - 本地 worker 自动扩缩容有意保持保守,并会在主机负载平均值已经很高时退避, - 因此默认情况下多个并发 - Vitest 运行造成的影响更小。 - - 基础 Vitest 配置会把 projects/config 文件标记为 + - 本地 worker 自动扩缩有意保持保守,并会在主机负载平均值已经较高时 + 退避,因此多个并发 + Vitest 运行默认造成的影响更小。 + - 基础 Vitest 配置会把项目/config 文件标记为 `forceRerunTriggers`,因此当测试 - 线路变更时,changed-mode 重新运行仍能保持正确。 + wiring 变更时,changed-mode 重跑仍保持正确。 - 该配置会在受支持的主机上保持启用 `OPENCLAW_VITEST_FS_MODULE_CACHE`; - 如果你希望直接性能分析使用一个显式缓存位置,请设置 `OPENCLAW_VITEST_FS_MODULE_CACHE_PATH=/abs/path`。 + 如果你想为直接 profiling 使用一个显式缓存位置,请设置 `OPENCLAW_VITEST_FS_MODULE_CACHE_PATH=/abs/path`。 - - `pnpm test:perf:imports` 会启用 Vitest import-duration 报告以及 + - `pnpm test:perf:imports` 会启用 Vitest 导入耗时报告以及 import-breakdown 输出。 - - `pnpm test:perf:imports:changed` 会把同一性能分析视图限定到 + - `pnpm test:perf:imports:changed` 会把同一个 profiling 视图限定到 自 `origin/main` 以来变更的文件。 - 分片计时数据会写入 `.artifacts/vitest-shard-timings.json`。 - 全配置运行使用配置路径作为键;include-pattern CI + 整个配置运行使用配置路径作为 key;include-pattern CI 分片会追加分片名称,以便单独跟踪过滤后的分片。 - - 当某个热点测试仍把大部分时间花在启动导入上时, - 请把重型依赖放在狭窄的本地 `*.runtime.ts` 接缝之后,并 - 直接 mock 该接缝,而不是深度导入运行时 helper,只为了 - 把它们传给 `vi.mock(...)`。 - - `pnpm test:perf:changed:bench -- --ref ` 会将已提交 - diff 的路由后 `test:changed` 与原生根项目路径进行对比, - 并打印 wall time 与 macOS max RSS。 - - `pnpm test:perf:changed:bench -- --worktree` 会通过把 changed file list 路由到 - `scripts/test-projects.mjs` 和根 Vitest 配置来对当前 - dirty tree 做基准测试。 + - 当某个热点测试仍然把大部分时间花在启动导入上时, + 请把重型依赖放在窄的本地 `*.runtime.ts` seam 后面,并 + 直接 mock 该 seam,而不是仅为了传给 `vi.mock(...)` 就深度导入运行时 helpers。 + - `pnpm test:perf:changed:bench -- --ref ` 会把路由后的 + `test:changed` 与该已提交 diff 的原生根项目路径进行比较, + 并打印 wall time 以及 macOS max RSS。 + - `pnpm test:perf:changed:bench -- --worktree` 会对当前 + dirty tree 进行 benchmark,方式是把 changed file list 通过 + `scripts/test-projects.mjs` 和根 Vitest 配置进行路由。 - `pnpm test:perf:profile:main` 会为 Vitest/Vite 启动和 transform 开销写入主线程 CPU profile。 - - `pnpm test:perf:profile:runner` 会在禁用文件并行时为 - 单元套件写入 runner CPU+heap profiles。 + - `pnpm test:perf:profile:runner` 会为 + unit 套件写入 runner CPU+heap profiles,并禁用文件并行。 @@ -460,136 +439,133 @@ Telegram 类型的 payload 形状: - 命令:`pnpm test:stability:gateway` - 配置:`vitest.gateway.config.ts`,强制使用一个 worker - 范围: - - 默认启动一个启用诊断的真实 loopback Gateway 网关 - - 通过诊断事件路径驱动合成 gateway 消息、内存和大载荷 churn + - 默认启动一个启用 diagnostics 的真实 loopback Gateway 网关 + - 通过 diagnostic event path 驱动 synthetic gateway message、memory 和 large-payload churn - 通过 Gateway 网关 WS RPC 查询 `diagnostics.stability` - - 覆盖诊断稳定性 bundle 持久化 helpers - - 断言 recorder 保持有界、合成 RSS 样本保持低于 pressure budget,并且每个会话队列深度回落到零 + - 覆盖 diagnostic stability bundle 持久化 helpers + - 断言 recorder 保持有界,synthetic RSS samples 保持在 pressure budget 以下,并且每会话队列深度回落为零 - 预期: - - CI 安全且不需要密钥 - - 这是用于 stability-regression 跟进的窄车道,不是完整 Gateway 网关套件的替代品 + - CI-safe 且不需要 key + - 用于稳定性回归跟进的窄 lane,而不是完整 Gateway 网关套件的替代品 ### E2E(Gateway 网关 smoke) - 命令:`pnpm test:e2e` - 配置:`vitest.e2e.config.ts` -- 文件:`src/**/*.e2e.test.ts`、`test/**/*.e2e.test.ts`,以及 `extensions/` 下的内置插件 E2E 测试 +- 文件:`src/**/*.e2e.test.ts`、`test/**/*.e2e.test.ts`,以及 `extensions/` 下的 bundled-plugin E2E 测试 - 运行时默认值: - - 使用 Vitest `threads` 和 `isolate: false`,与仓库其余部分一致。 - - 使用自适应 workers(CI:最多 2 个,本地:默认 1 个)。 - - 默认以 silent 模式运行,以减少 console I/O 开销。 -- 实用覆盖: - - `OPENCLAW_E2E_WORKERS=` 强制 worker 数量(上限 16)。 - - `OPENCLAW_E2E_VERBOSE=1` 重新启用详细 console 输出。 + - 使用 Vitest `threads` 并设置 `isolate: false`,与仓库其余部分一致。 + - 使用 adaptive workers(CI:最多 2 个,本地:默认 1 个)。 + - 默认以 silent mode 运行,以减少 console I/O 开销。 +- 有用的覆盖项: + - `OPENCLAW_E2E_WORKERS=` 用于强制 worker 数量(上限为 16)。 + - `OPENCLAW_E2E_VERBOSE=1` 用于重新启用详细 console 输出。 - 范围: - - 多实例 gateway 端到端行为 - - WebSocket/HTTP 表面、node 配对以及更重的网络 + - 多实例 Gateway 网关端到端行为 + - WebSocket/HTTP 表面、node pairing 以及更重的 networking - 预期: - 在 CI 中运行(当 pipeline 中启用时) - - 不需要真实密钥 - - 比单元测试有更多移动部件(可能更慢) + - 不需要真实 key + - 比单元测试有更多活动部件(可能更慢) ### E2E:OpenShell 后端 smoke - 命令:`pnpm test:e2e:openshell` - 文件:`extensions/openshell/src/backend.e2e.test.ts` - 范围: - - 通过 Docker 在主机上启动隔离的 OpenShell gateway + - 通过 Docker 在主机上启动一个隔离的 OpenShell Gateway 网关 - 从临时本地 Dockerfile 创建沙箱 - - 通过真实的 `sandbox ssh-config` + SSH exec 运行 OpenClaw 的 OpenShell 后端 - - 通过沙箱 fs bridge 验证 remote-canonical 文件系统行为 + - 通过真实的 `sandbox ssh-config` + SSH exec 演练 OpenClaw 的 OpenShell 后端 + - 通过沙箱 fs bridge 验证 remote-canonical filesystem 行为 - 预期: - - 仅 opt-in;不属于默认 `pnpm test:e2e` 运行的一部分 + - 仅 opt-in;不是默认 `pnpm test:e2e` 运行的一部分 - 需要本地 `openshell` CLI 以及可工作的 Docker daemon - - 使用隔离的 `HOME` / `XDG_CONFIG_HOME`,然后销毁测试 gateway 和沙箱 -- 实用覆盖: - - `OPENCLAW_E2E_OPENSHELL=1` 在手动运行更广的 e2e 套件时启用该测试 - - `OPENCLAW_E2E_OPENSHELL_COMMAND=/path/to/openshell` 指向非默认 CLI binary 或 wrapper script + - 使用隔离的 `HOME` / `XDG_CONFIG_HOME`,然后销毁测试 Gateway 网关和沙箱 +- 有用的覆盖项: + - `OPENCLAW_E2E_OPENSHELL=1` 用于在手动运行更广泛的 e2e 套件时启用该测试 + - `OPENCLAW_E2E_OPENSHELL_COMMAND=/path/to/openshell` 用于指向非默认 CLI binary 或 wrapper script ### Live(真实提供商 + 真实模型) - 命令:`pnpm test:live` - 配置:`vitest.live.config.ts` -- 文件:`src/**/*.live.test.ts`、`test/**/*.live.test.ts`,以及 `extensions/` 下的内置插件 live 测试 +- 文件:`src/**/*.live.test.ts`、`test/**/*.live.test.ts`,以及 `extensions/` 下的 bundled-plugin live 测试 - 默认:由 `pnpm test:live` **启用**(设置 `OPENCLAW_LIVE_TEST=1`) - 范围: - - “这个提供商/模型在 _今天_ 使用真实凭证是否确实可用?” - - 捕获提供商格式变更、tool-calling 特性差异、auth 问题和 rate limit 行为 + - “这个提供商/模型在 _今天_ 使用真实凭据是否真的可用?” + - 捕获提供商格式变更、工具调用差异、auth 问题和 rate limit 行为 - 预期: - - 设计上不具备 CI 稳定性(真实网络、真实提供商策略、配额、故障) - - 会产生费用 / 使用 rate limits - - 优先运行缩窄后的子集,而不是“全部” + - 按设计并非 CI-stable(真实网络、真实提供商策略、配额、故障) + - 会花钱 / 使用 rate limits + - 优先运行缩小后的子集,而不是“全部” - Live 运行会 source `~/.profile` 以获取缺失的 API keys。 -- 默认情况下,live 运行仍会隔离 `HOME`,并把 config/auth material 复制到临时测试 home,这样单元 fixture 就不能改变你的真实 `~/.openclaw`。 -- 仅当你有意需要 live tests 使用你的真实 home directory 时,才设置 `OPENCLAW_LIVE_USE_REAL_HOME=1`。 -- `pnpm test:live` 现在默认使用更安静的模式:它保留 `[live] ...` 进度输出,但会抑制额外的 `~/.profile` notice,并静音 gateway bootstrap logs/Bonjour chatter。如果你想恢复完整 startup logs,请设置 `OPENCLAW_LIVE_TEST_QUIET=0`。 -- API key rotation(特定提供商):设置 `*_API_KEYS`,格式为逗号/分号分隔,或设置 `*_API_KEY_1`、`*_API_KEY_2`(例如 `OPENAI_API_KEYS`、`ANTHROPIC_API_KEYS`、`GEMINI_API_KEYS`),也可以通过 `OPENCLAW_LIVE_*_KEY` 进行 per-live override;测试会在 rate limit responses 时重试。 -- 进度/heartbeat 输出: - - Live 套件现在会向 stderr 发出进度行,因此即使 Vitest console capture 较安静,长时间提供商调用也能明显显示仍在活跃。 - - `vitest.live.config.ts` 禁用 Vitest console interception,因此提供商/gateway 进度行会在 live 运行期间立即流式输出。 +- 默认情况下,live 运行仍会隔离 `HOME`,并把 config/auth material 复制到临时测试 home,因此单元 fixture 无法修改你的真实 `~/.openclaw`。 +- 仅当你有意需要 live 测试使用你的真实 home directory 时,才设置 `OPENCLAW_LIVE_USE_REAL_HOME=1`。 +- `pnpm test:live` 现在默认使用更安静的模式:它保留 `[live] ...` progress 输出,但会抑制额外的 `~/.profile` notice,并静音 Gateway 网关 bootstrap 日志/Bonjour chatter。如果你想恢复完整 startup 日志,请设置 `OPENCLAW_LIVE_TEST_QUIET=0`。 +- API key rotation(特定于提供商):使用 comma/semicolon format 设置 `*_API_KEYS` 或 `*_API_KEY_1`、`*_API_KEY_2`(例如 `OPENAI_API_KEYS`、`ANTHROPIC_API_KEYS`、`GEMINI_API_KEYS`),或通过 `OPENCLAW_LIVE_*_KEY` 设置每个 live 覆盖项;测试会在 rate limit 响应时重试。 +- Progress/heartbeat 输出: + - Live 套件现在会把 progress lines 输出到 stderr,因此即使 Vitest console capture 很安静,长时间的提供商调用也能显示为仍在活动。 + - `vitest.live.config.ts` 会禁用 Vitest console interception,因此提供商/Gateway 网关 progress lines 会在 live 运行期间立即流式输出。 - 使用 `OPENCLAW_LIVE_HEARTBEAT_MS` 调整 direct-model heartbeats。 - - 使用 `OPENCLAW_LIVE_GATEWAY_HEARTBEAT_MS` 调整 gateway/probe heartbeats。 + - 使用 `OPENCLAW_LIVE_GATEWAY_HEARTBEAT_MS` 调整 Gateway 网关/probe heartbeats。 ## 我应该运行哪个套件? 使用这个决策表: -- 编辑逻辑/测试:运行 `pnpm test`(如果你改动很多,也运行 `pnpm test:coverage`) -- 触及 gateway networking / WS protocol / pairing:添加 `pnpm test:e2e` -- 调试“我的 bot 宕机了” / 特定提供商失败 / tool calling:运行缩窄后的 `pnpm test:live` +- 编辑逻辑/测试:运行 `pnpm test`(如果改动很多,也运行 `pnpm test:coverage`) +- 涉及 Gateway 网关网络 / WS 协议 / 配对:添加 `pnpm test:e2e` +- 调试“我的机器人掉线了”/ 提供商特定故障 / 工具调用:运行缩窄范围的 `pnpm test:live` ## Live(触网)测试 -有关真实模型矩阵、CLI 后端冒烟测试、ACP 冒烟测试、Codex 应用服务器 -harness,以及所有媒体提供商真实服务测试(Deepgram、BytePlus、ComfyUI、图像、 -音乐、视频、媒体 harness),以及真实运行的凭证处理,请参阅 -[测试 —— 真实服务套件](/zh-CN/help/testing-live)。 +关于 live 模型矩阵、CLI 后端冒烟测试、ACP 冒烟测试、Codex 应用服务器 harness,以及所有媒体提供商 live 测试(Deepgram、BytePlus、ComfyUI、图像、音乐、视频、媒体 harness)以及 live 运行的凭证处理,请参阅 [测试 — live 套件](/zh-CN/help/testing-live)。 -## Docker 运行器(可选的“可在 Linux 中工作”检查) +## Docker 运行器(可选的“在 Linux 中可运行”检查) 这些 Docker 运行器分为两类: -- 真实模型运行器:`test:docker:live-models` 和 `test:docker:live-gateway` 只在仓库 Docker 镜像内运行对应的配置键真实服务文件(`src/agents/models.profiles.live.test.ts` 和 `src/gateway/gateway-models.profiles.live.test.ts`),并挂载你的本地配置目录和工作区(如果已挂载,也会读取 `~/.profile`)。对应的本地入口点是 `test:live:models-profiles` 和 `test:live:gateway-profiles`。 -- Docker 真实服务运行器默认使用较小的冒烟上限,以便完整 Docker 扫描保持可行: - `test:docker:live-models` 默认使用 `OPENCLAW_LIVE_MAX_MODELS=12`,而 +- Live 模型运行器:`test:docker:live-models` 和 `test:docker:live-gateway` 仅在仓库 Docker 镜像内运行与其匹配的 profile-key live 文件(`src/agents/models.profiles.live.test.ts` 和 `src/gateway/gateway-models.profiles.live.test.ts`),并挂载你的本地配置目录和工作区(如果已挂载,也会 source `~/.profile`)。对应的本地入口点是 `test:live:models-profiles` 和 `test:live:gateway-profiles`。 +- Docker live 运行器默认使用较小的冒烟上限,以便完整 Docker 扫描保持可行: + `test:docker:live-models` 默认使用 `OPENCLAW_LIVE_MAX_MODELS=12`,并且 `test:docker:live-gateway` 默认使用 `OPENCLAW_LIVE_GATEWAY_SMOKE=1`、 `OPENCLAW_LIVE_GATEWAY_MAX_MODELS=8`、 - `OPENCLAW_LIVE_GATEWAY_STEP_TIMEOUT_MS=45000`,以及 - `OPENCLAW_LIVE_GATEWAY_MODEL_TIMEOUT_MS=90000`。只有在你明确需要更大的穷尽式扫描时,才覆盖这些环境变量。 -- `test:docker:all` 会先通过 `test:docker:live-build` 构建一次真实服务 Docker 镜像,再通过 `scripts/package-openclaw-for-docker.mjs` 将 OpenClaw 打包一次为 npm tarball,然后构建/复用两个 `scripts/e2e/Dockerfile` 镜像。裸镜像只是用于安装/更新/插件依赖通道的 Node/Git 运行器;这些通道会挂载预构建的 tarball。功能镜像会把同一个 tarball 安装到 `/app`,用于已构建应用功能通道。Docker 通道定义位于 `scripts/lib/docker-e2e-scenarios.mjs`;规划器逻辑位于 `scripts/lib/docker-e2e-plan.mjs`;`scripts/test-docker-all.mjs` 执行选定计划。聚合流程使用加权本地调度器:`OPENCLAW_DOCKER_ALL_PARALLELISM` 控制进程槽位,而资源上限会避免繁重的真实服务、npm 安装和多服务通道同时全部启动。如果单个通道比当前上限更重,调度器仍可在池为空时启动它,并让它单独运行,直到容量再次可用。默认值为 10 个槽位、`OPENCLAW_DOCKER_ALL_LIVE_LIMIT=9`、`OPENCLAW_DOCKER_ALL_NPM_LIMIT=10` 和 `OPENCLAW_DOCKER_ALL_SERVICE_LIMIT=7`;只有当 Docker 主机有更多余量时,才调整 `OPENCLAW_DOCKER_ALL_WEIGHT_LIMIT` 或 `OPENCLAW_DOCKER_ALL_DOCKER_LIMIT`。运行器默认执行 Docker 预检,移除陈旧的 OpenClaw E2E 容器,每 30 秒打印一次状态,将成功通道耗时存储在 `.artifacts/docker-tests/lane-timings.json`,并在后续运行中使用这些耗时优先启动更长的通道。使用 `OPENCLAW_DOCKER_ALL_DRY_RUN=1` 可在不构建或运行 Docker 的情况下打印加权通道清单,或使用 `node scripts/test-docker-all.mjs --plan-json` 打印选定通道、包/镜像需求和凭证的 CI 计划。 -- `Package Acceptance` 是 GitHub 原生的包门禁,用于验证“这个可安装的 tarball 作为产品是否可用?”它会从 `source=npm`、`source=ref`、`source=url` 或 `source=artifact` 解析一个候选包,将其上传为 `package-under-test`,然后针对这个精确的 tarball 运行可复用的 Docker E2E 通道,而不是重新打包所选 ref。`workflow_ref` 选择受信任的工作流/harness 脚本,而 `package_ref` 在 `source=ref` 时选择要打包的源提交/分支/标签;这使当前验收逻辑能够验证较旧的受信任提交。配置按覆盖面排序:`smoke` 是快速安装/渠道/智能体加 Gateway 网关/配置,`package` 是包/更新/插件契约,也是大多数 Parallels 包/更新覆盖的默认原生替代,`product` 添加 MCP 渠道、cron/子智能体清理、OpenAI Web 搜索和 OpenWebUI,`full` 使用 OpenWebUI 运行发布路径 Docker 分块。发布验证运行一个自定义包差异(`bundled-channel-deps-compat plugins-offline`),外加 Telegram 包 QA,因为发布路径 Docker 分块已经覆盖重叠的包/更新/插件通道。从构件生成的定向 GitHub Docker 重跑命令会在可用时包含先前的包构件和已准备镜像输入,因此失败通道可以避免重新构建包和镜像。 -- 构建和发布检查会在 tsdown 后运行 `scripts/check-cli-bootstrap-imports.mjs`。该守卫从 `dist/entry.js` 和 `dist/cli/run-main.js` 遍历静态构建图,如果命令分派前的启动阶段导入了 Commander、提示 UI、undici 或日志等包依赖,就会失败;它还会让打包的 Gateway 网关运行分块保持在预算内,并拒绝对已知冷 Gateway 网关路径的静态导入。打包 CLI 冒烟测试还覆盖根帮助、onboard 帮助、doctor 帮助、Status、配置架构,以及模型列表命令。 -- Package Acceptance 旧版兼容性上限为 `2026.4.25`(包括 `2026.4.25-beta.*`)。在该截止版本之前,harness 只容忍已发布包的元数据缺口:省略的私有 QA 清单条目、缺失的 `gateway install --wrapper`、tarball 派生 git fixture 中缺失的补丁文件、缺失的持久化 `update.channel`、旧版插件安装记录位置、缺失的 marketplace 安装记录持久化,以及 `plugins update` 期间的配置元数据迁移。对于 `2026.4.25` 之后的包,这些路径都是严格失败。 -- 容器冒烟运行器:`test:docker:openwebui`、`test:docker:onboard`、`test:docker:npm-onboard-channel-agent`、`test:docker:update-channel-switch`、`test:docker:session-runtime-context`、`test:docker:agents-delete-shared-workspace`、`test:docker:gateway-network`、`test:docker:browser-cdp-snapshot`、`test:docker:mcp-channels`、`test:docker:pi-bundle-mcp-tools`、`test:docker:cron-mcp-cleanup`、`test:docker:plugins`、`test:docker:plugin-update` 和 `test:docker:config-reload` 会启动一个或多个真实容器,并验证更高层级的集成路径。 + `OPENCLAW_LIVE_GATEWAY_STEP_TIMEOUT_MS=45000` 和 + `OPENCLAW_LIVE_GATEWAY_MODEL_TIMEOUT_MS=90000`。当你明确需要更大的穷尽扫描时,可以覆盖这些环境变量。 +- `test:docker:all` 先通过 `test:docker:live-build` 构建一次 live Docker 镜像,再通过 `scripts/package-openclaw-for-docker.mjs` 将 OpenClaw 打包一次为 npm tarball,然后构建/复用两个 `scripts/e2e/Dockerfile` 镜像。裸镜像只是用于安装/更新/插件依赖车道的 Node/Git 运行器;这些车道会挂载预构建的 tarball。功能镜像会把同一个 tarball 安装到 `/app`,用于已构建应用功能车道。Docker 车道定义位于 `scripts/lib/docker-e2e-scenarios.mjs`;规划器逻辑位于 `scripts/lib/docker-e2e-plan.mjs`;`scripts/test-docker-all.mjs` 执行选中的计划。聚合运行器使用加权本地调度器:`OPENCLAW_DOCKER_ALL_PARALLELISM` 控制进程槽位,而资源上限会避免重型 live、npm 安装和多服务车道同时启动。如果单个车道比当前上限更重,调度器仍可在池为空时启动它,然后让它单独运行,直到容量再次可用。默认值为 10 个槽位、`OPENCLAW_DOCKER_ALL_LIVE_LIMIT=9`、`OPENCLAW_DOCKER_ALL_NPM_LIMIT=10` 和 `OPENCLAW_DOCKER_ALL_SERVICE_LIMIT=7`;只有当 Docker 主机有更多余量时,才调整 `OPENCLAW_DOCKER_ALL_WEIGHT_LIMIT` 或 `OPENCLAW_DOCKER_ALL_DOCKER_LIMIT`。运行器默认执行 Docker 预检,移除陈旧的 OpenClaw E2E 容器,每 30 秒打印一次状态,将成功车道的耗时存储在 `.artifacts/docker-tests/lane-timings.json`,并在后续运行中使用这些耗时优先启动更长的车道。使用 `OPENCLAW_DOCKER_ALL_DRY_RUN=1` 可以在不构建或运行 Docker 的情况下打印加权车道清单,或者使用 `node scripts/test-docker-all.mjs --plan-json` 打印所选车道、包/镜像需求和凭证的 CI 计划。 +- `Package Acceptance` 是 GitHub 原生的包闸门,用于验证“这个可安装 tarball 是否能作为产品正常工作?”它会从 `source=npm`、`source=ref`、`source=url` 或 `source=artifact` 解析一个候选包,将其上传为 `package-under-test`,然后针对这个确切的 tarball 运行可复用的 Docker E2E 车道,而不是重新打包选中的 ref。`workflow_ref` 选择受信任的 workflow/harness 脚本,而 `package_ref` 在 `source=ref` 时选择要打包的源提交/分支/标签;这让当前验收逻辑可以验证较旧的受信任提交。Profile 按覆盖范围排序:`smoke` 是快速安装/渠道/智能体加 Gateway 网关/配置,`package` 是包/更新/插件契约,也是大多数 Parallels 包/更新覆盖的默认原生替代项,`product` 添加 MCP 渠道、cron/子智能体清理、OpenAI Web 搜索和 OpenWebUI,`full` 则运行包含 OpenWebUI 的发布路径 Docker 分块。发布验证会运行自定义包增量(`bundled-channel-deps-compat plugins-offline`)以及 Telegram 包 QA,因为发布路径 Docker 分块已经覆盖了重叠的包/更新/插件车道。从工件生成的定向 GitHub Docker 重新运行命令会在可用时包含先前的包工件和已准备镜像输入,因此失败车道可以避免重新构建包和镜像。 +- 构建和发布检查会在 tsdown 之后运行 `scripts/check-cli-bootstrap-imports.mjs`。该守卫会从 `dist/entry.js` 和 `dist/cli/run-main.js` 遍历静态构建图;如果命令分发前的启动阶段导入了 Commander、prompt UI、undici 或 logging 等包依赖,它会失败;它还会让打包的 Gateway 网关运行分块保持在预算内,并拒绝静态导入已知的冷启动 Gateway 网关路径。打包 CLI 冒烟测试也覆盖根帮助、onboard 帮助、doctor 帮助、Status、配置 schema 和模型列表命令。 +- Package Acceptance 旧版兼容性上限为 `2026.4.25`(包含 `2026.4.25-beta.*`)。在该截止点之前,harness 只容忍已发布包的元数据缺口:省略的私有 QA 清单条目、缺失的 `gateway install --wrapper`、从 tarball 派生的 git fixture 中缺失的 patch 文件、缺失的持久化 `update.channel`、旧版插件安装记录位置、缺失的 marketplace 安装记录持久化,以及 `plugins update` 期间的配置元数据迁移。对于 `2026.4.25` 之后的包,这些路径都是严格失败。 +- 容器冒烟运行器:`test:docker:openwebui`、`test:docker:onboard`、`test:docker:npm-onboard-channel-agent`、`test:docker:update-channel-switch`、`test:docker:session-runtime-context`、`test:docker:agents-delete-shared-workspace`、`test:docker:gateway-network`、`test:docker:browser-cdp-snapshot`、`test:docker:mcp-channels`、`test:docker:pi-bundle-mcp-tools`、`test:docker:cron-mcp-cleanup`、`test:docker:plugins`、`test:docker:plugin-update` 和 `test:docker:config-reload` 会启动一个或多个真实容器,并验证更高层的集成路径。 -真实模型 Docker 运行器还只会绑定挂载所需的 CLI 认证主目录(或在运行未缩小时挂载所有支持的主目录),然后在运行前将其复制到容器主目录,使外部 CLI OAuth 可以刷新令牌,而不改变主机认证存储: +Live 模型 Docker 运行器还会仅 bind-mount 所需的 CLI 认证 home(或者在未缩窄运行范围时挂载所有受支持的认证 home),然后在运行前将它们复制到容器 home 中,使外部 CLI OAuth 可以刷新令牌而不会改变宿主机认证存储: - 直接模型:`pnpm test:docker:live-models`(脚本:`scripts/test-live-models-docker.sh`) -- ACP 绑定冒烟测试:`pnpm test:docker:live-acp-bind`(脚本:`scripts/test-live-acp-bind-docker.sh`;默认覆盖 Claude、Codex 和 Gemini,并通过 `pnpm test:docker:live-acp-bind:droid` 和 `pnpm test:docker:live-acp-bind:opencode` 对 Droid/OpenCode 做严格覆盖) +- ACP 绑定冒烟测试:`pnpm test:docker:live-acp-bind`(脚本:`scripts/test-live-acp-bind-docker.sh`;默认覆盖 Claude、Codex 和 Gemini,并通过 `pnpm test:docker:live-acp-bind:droid` 和 `pnpm test:docker:live-acp-bind:opencode` 严格覆盖 Droid/OpenCode) - CLI 后端冒烟测试:`pnpm test:docker:live-cli-backend`(脚本:`scripts/test-live-cli-backend-docker.sh`) -- Codex app-server harness 冒烟测试:`pnpm test:docker:live-codex-harness`(脚本:`scripts/test-live-codex-harness-docker.sh`) +- Codex app-server 测试框架冒烟测试:`pnpm test:docker:live-codex-harness`(脚本:`scripts/test-live-codex-harness-docker.sh`) - Gateway 网关 + 开发智能体:`pnpm test:docker:live-gateway`(脚本:`scripts/test-live-gateway-models-docker.sh`) -- 可观测性冒烟测试:`pnpm qa:otel:smoke` 是私有 QA 源码检出通道。它有意不属于软件包 Docker 发布通道,因为 npm tarball 会省略 QA Lab。 +- 可观测性冒烟测试:`pnpm qa:otel:smoke` 是私有 QA 源码检出通道。它有意不属于包 Docker 发布通道,因为 npm tarball 省略了 QA Lab。 - Open WebUI 实时冒烟测试:`pnpm test:docker:openwebui`(脚本:`scripts/e2e/openwebui-docker.sh`) - 新手引导向导(TTY,完整脚手架):`pnpm test:docker:onboard`(脚本:`scripts/e2e/onboard-docker.sh`) -- Npm tarball 新手引导/渠道/智能体冒烟测试:`pnpm test:docker:npm-onboard-channel-agent` 会在 Docker 中全局安装打包好的 OpenClaw tarball,通过 env-ref 新手引导配置 OpenAI,并默认配置 Telegram,验证 Doctor 是否修复已启用插件的运行时依赖,并运行一次模拟的 OpenAI 智能体轮次。使用 `OPENCLAW_CURRENT_PACKAGE_TGZ=/path/to/openclaw-*.tgz` 复用预构建 tarball,用 `OPENCLAW_NPM_ONBOARD_HOST_BUILD=0` 跳过主机重建,或用 `OPENCLAW_NPM_ONBOARD_CHANNEL=discord` 切换渠道。 -- 更新渠道切换冒烟测试:`pnpm test:docker:update-channel-switch` 会在 Docker 中全局安装打包好的 OpenClaw tarball,从软件包 `stable` 切换到 git `dev`,验证持久化的渠道和插件更新后工作正常,然后切回软件包 `stable` 并检查更新 Status。 +- Npm tarball 新手引导/渠道/智能体冒烟测试:`pnpm test:docker:npm-onboard-channel-agent` 会在 Docker 中全局安装打包后的 OpenClaw tarball,通过 env-ref 新手引导配置 OpenAI 并默认配置 Telegram,验证 Doctor 已修复激活的插件运行时依赖,并运行一次模拟的 OpenAI 智能体轮次。使用 `OPENCLAW_CURRENT_PACKAGE_TGZ=/path/to/openclaw-*.tgz` 复用预构建 tarball,使用 `OPENCLAW_NPM_ONBOARD_HOST_BUILD=0` 跳过主机构建,或使用 `OPENCLAW_NPM_ONBOARD_CHANNEL=discord` 切换渠道。 +- 更新渠道切换冒烟测试:`pnpm test:docker:update-channel-switch` 会在 Docker 中全局安装打包后的 OpenClaw tarball,从包 `stable` 切换到 git `dev`,验证持久化的渠道和插件更新后工作正常,然后切回包 `stable` 并检查更新 Status。 - 会话运行时上下文冒烟测试:`pnpm test:docker:session-runtime-context` 会验证隐藏运行时上下文转录持久化,以及 Doctor 对受影响的重复提示词重写分支的修复。 -- Bun 全局安装冒烟测试:`bash scripts/e2e/bun-global-install-smoke.sh` 会打包当前树,在隔离的 home 中用 `bun install -g` 安装它,并验证 `openclaw infer image providers --json` 返回内置图像提供商而不是挂起。使用 `OPENCLAW_BUN_GLOBAL_SMOKE_PACKAGE_TGZ=/path/to/openclaw-*.tgz` 复用预构建 tarball,用 `OPENCLAW_BUN_GLOBAL_SMOKE_HOST_BUILD=0` 跳过主机构建,或用 `OPENCLAW_BUN_GLOBAL_SMOKE_DIST_IMAGE=openclaw-dockerfile-smoke:local` 从已构建的 Docker 镜像复制 `dist/`。 -- 安装器 Docker 冒烟测试:`bash scripts/test-install-sh-docker.sh` 会在它的 root、update 和 direct-npm 容器之间共享一个 npm 缓存。更新冒烟测试默认以 npm `latest` 作为升级到候选 tarball 之前的 stable 基线。本地可用 `OPENCLAW_INSTALL_SMOKE_UPDATE_BASELINE=2026.4.22` 覆盖,或在 GitHub 上用 Install Smoke 工作流的 `update_baseline_version` 输入覆盖。非 root 安装器检查会保留隔离的 npm 缓存,避免 root 拥有的缓存条目掩盖用户本地安装行为。设置 `OPENCLAW_INSTALL_SMOKE_NPM_CACHE_DIR=/path/to/cache` 可在本地重复运行时复用 root/update/direct-npm 缓存。 -- Install Smoke CI 会用 `OPENCLAW_INSTALL_SMOKE_SKIP_NPM_GLOBAL=1` 跳过重复的 direct-npm 全局更新;需要覆盖直接 `npm install -g` 时,在本地运行脚本且不带该环境变量。 -- 智能体删除共享工作区 CLI 冒烟测试:`pnpm test:docker:agents-delete-shared-workspace`(脚本:`scripts/e2e/agents-delete-shared-workspace-docker.sh`)默认构建根 Dockerfile 镜像,在隔离容器 home 中为两个智能体填充一个工作区,运行 `agents delete --json`,并验证有效 JSON 以及保留工作区的行为。使用 `OPENCLAW_AGENTS_DELETE_SHARED_WORKSPACE_E2E_IMAGE=openclaw-dockerfile-smoke:local OPENCLAW_AGENTS_DELETE_SHARED_WORKSPACE_E2E_SKIP_BUILD=1` 复用 install-smoke 镜像。 -- Gateway 网关网络(两个容器,WS 身份验证 + 健康检查):`pnpm test:docker:gateway-network`(脚本:`scripts/e2e/gateway-network-docker.sh`) -- 浏览器 CDP 快照冒烟测试:`pnpm test:docker:browser-cdp-snapshot`(脚本:`scripts/e2e/browser-cdp-snapshot-docker.sh`)会构建源码 E2E 镜像以及一个 Chromium 层,使用原始 CDP 启动 Chromium,运行 `browser doctor --deep`,并验证 CDP 角色快照覆盖链接 URL、游标提升的可点击项、iframe 引用和框架元数据。 -- OpenAI Responses `web_search` minimal 推理回归:`pnpm test:docker:openai-web-search-minimal`(脚本:`scripts/e2e/openai-web-search-minimal-docker.sh`)会通过 Gateway 网关运行一个模拟 OpenAI 服务器,验证 `web_search` 将 `reasoning.effort` 从 `minimal` 提升到 `low`,然后强制提供商 schema 拒绝,并检查原始详情出现在 Gateway 网关日志中。 -- MCP 渠道桥接(已填充的 Gateway 网关 + stdio 桥接 + 原始 Claude 通知帧冒烟测试):`pnpm test:docker:mcp-channels`(脚本:`scripts/e2e/mcp-channels-docker.sh`) -- Pi bundle MCP 工具(真实 stdio MCP 服务器 + 嵌入式 Pi 配置文件 allow/deny 冒烟测试):`pnpm test:docker:pi-bundle-mcp-tools`(脚本:`scripts/e2e/pi-bundle-mcp-tools-docker.sh`) -- Cron/subagent MCP 清理(真实 Gateway 网关 + 在隔离 cron 和一次性 subagent 运行后拆卸 stdio MCP 子进程):`pnpm test:docker:cron-mcp-cleanup`(脚本:`scripts/e2e/cron-mcp-cleanup-docker.sh`) +- Bun 全局安装冒烟测试:`bash scripts/e2e/bun-global-install-smoke.sh` 会打包当前目录树,在隔离的 home 中用 `bun install -g` 安装它,并验证 `openclaw infer image providers --json` 返回内置图像提供商而不是挂起。使用 `OPENCLAW_BUN_GLOBAL_SMOKE_PACKAGE_TGZ=/path/to/openclaw-*.tgz` 复用预构建 tarball,使用 `OPENCLAW_BUN_GLOBAL_SMOKE_HOST_BUILD=0` 跳过主机构建,或使用 `OPENCLAW_BUN_GLOBAL_SMOKE_DIST_IMAGE=openclaw-dockerfile-smoke:local` 从已构建的 Docker 镜像复制 `dist/`。 +- 安装器 Docker 冒烟测试:`bash scripts/test-install-sh-docker.sh` 在其 root、update 和 direct-npm 容器之间共享一个 npm 缓存。更新冒烟测试默认以 npm `latest` 作为升级到候选 tarball 之前的稳定基线。可在本地用 `OPENCLAW_INSTALL_SMOKE_UPDATE_BASELINE=2026.4.22` 覆盖,或在 GitHub 上用 Install Smoke 工作流的 `update_baseline_version` 输入覆盖。非 root 安装器检查会保留隔离的 npm 缓存,避免 root 拥有的缓存条目掩盖用户本地安装行为。设置 `OPENCLAW_INSTALL_SMOKE_NPM_CACHE_DIR=/path/to/cache` 可在本地重跑时复用 root/update/direct-npm 缓存。 +- Install Smoke CI 使用 `OPENCLAW_INSTALL_SMOKE_SKIP_NPM_GLOBAL=1` 跳过重复的 direct-npm 全局更新;需要覆盖直接 `npm install -g` 时,在本地运行该脚本且不带这个环境变量。 +- 智能体删除共享工作区 CLI 冒烟测试:`pnpm test:docker:agents-delete-shared-workspace`(脚本:`scripts/e2e/agents-delete-shared-workspace-docker.sh`)默认构建根 Dockerfile 镜像,在隔离的容器 home 中为两个智能体种子化一个工作区,运行 `agents delete --json`,并验证有效 JSON 以及保留工作区行为。使用 `OPENCLAW_AGENTS_DELETE_SHARED_WORKSPACE_E2E_IMAGE=openclaw-dockerfile-smoke:local OPENCLAW_AGENTS_DELETE_SHARED_WORKSPACE_E2E_SKIP_BUILD=1` 复用 install-smoke 镜像。 +- Gateway 网关网络(两个容器,WS 认证 + 健康检查):`pnpm test:docker:gateway-network`(脚本:`scripts/e2e/gateway-network-docker.sh`) +- 浏览器 CDP 快照冒烟测试:`pnpm test:docker:browser-cdp-snapshot`(脚本:`scripts/e2e/browser-cdp-snapshot-docker.sh`)会构建源码 E2E 镜像和一个 Chromium 层,用原始 CDP 启动 Chromium,运行 `browser doctor --deep`,并验证 CDP 角色快照覆盖链接 URL、光标提升的可点击元素、iframe 引用和 frame 元数据。 +- OpenAI Responses web_search 最小推理回归:`pnpm test:docker:openai-web-search-minimal`(脚本:`scripts/e2e/openai-web-search-minimal-docker.sh`)通过 Gateway 网关运行一个模拟的 OpenAI 服务器,验证 `web_search` 将 `reasoning.effort` 从 `minimal` 提升到 `low`,然后强制提供商 schema 拒绝并检查原始细节是否出现在 Gateway 网关日志中。 +- MCP 渠道桥接(种子化 Gateway 网关 + stdio 桥接 + 原始 Claude notification-frame 冒烟测试):`pnpm test:docker:mcp-channels`(脚本:`scripts/e2e/mcp-channels-docker.sh`) +- Pi 捆绑 MCP 工具(真实 stdio MCP 服务器 + 嵌入式 Pi 配置文件 allow/deny 冒烟测试):`pnpm test:docker:pi-bundle-mcp-tools`(脚本:`scripts/e2e/pi-bundle-mcp-tools-docker.sh`) +- Cron/subagent MCP 清理(真实 Gateway 网关 + stdio MCP 子进程在隔离 cron 和一次性 subagent 运行后的清理):`pnpm test:docker:cron-mcp-cleanup`(脚本:`scripts/e2e/cron-mcp-cleanup-docker.sh`) - 插件(安装冒烟测试、ClawHub kitchen-sink 安装/卸载、marketplace 更新,以及 Claude-bundle 启用/检查):`pnpm test:docker:plugins`(脚本:`scripts/e2e/plugins-docker.sh`) - 设置 `OPENCLAW_PLUGINS_E2E_CLAWHUB=0` 可跳过 ClawHub 块,或用 `OPENCLAW_PLUGINS_E2E_CLAWHUB_SPEC` 和 `OPENCLAW_PLUGINS_E2E_CLAWHUB_ID` 覆盖默认的 kitchen-sink 软件包/运行时组合。没有 `OPENCLAW_CLAWHUB_URL`/`CLAWHUB_URL` 时,测试会使用封闭的本地 ClawHub fixture 服务器。 -- 插件更新未变化冒烟测试:`pnpm test:docker:plugin-update`(脚本:`scripts/e2e/plugin-update-unchanged-docker.sh`) + 设置 `OPENCLAW_PLUGINS_E2E_CLAWHUB=0` 可跳过 ClawHub 块,或用 `OPENCLAW_PLUGINS_E2E_CLAWHUB_SPEC` 和 `OPENCLAW_PLUGINS_E2E_CLAWHUB_ID` 覆盖默认的 kitchen-sink 包/运行时组合。没有 `OPENCLAW_CLAWHUB_URL`/`CLAWHUB_URL` 时,该测试使用封闭的本地 ClawHub fixture 服务器。 +- 插件更新未变更冒烟测试:`pnpm test:docker:plugin-update`(脚本:`scripts/e2e/plugin-update-unchanged-docker.sh`) - 配置重载元数据冒烟测试:`pnpm test:docker:config-reload`(脚本:`scripts/e2e/config-reload-source-docker.sh`) -- 内置插件运行时依赖:`pnpm test:docker:bundled-channel-deps` 默认构建一个小型 Docker runner 镜像,在主机上构建并打包一次 OpenClaw,然后把该 tarball 挂载到每个 Linux 安装场景中。用 `OPENCLAW_SKIP_DOCKER_BUILD=1` 复用镜像,在一次新的本地构建后用 `OPENCLAW_BUNDLED_CHANNEL_HOST_BUILD=0` 跳过主机重建,或用 `OPENCLAW_CURRENT_PACKAGE_TGZ=/path/to/openclaw-*.tgz` 指向现有 tarball。完整 Docker 聚合和发布路径内置渠道分块会先预打包一次该 tarball,然后将内置渠道检查拆分到独立通道,包括 Telegram、Discord、Slack、Feishu、memory-lancedb 和 ACPX 的单独更新通道。发布分块会把渠道冒烟测试、更新目标以及设置/运行时契约拆分为 `bundled-channels-core`、`bundled-channels-update-a`、`bundled-channels-update-b` 和 `bundled-channels-contracts`;聚合的 `bundled-channels` 分块仍可用于手动重跑。发布工作流还会拆分提供商安装器分块和内置插件安装/卸载分块;旧版 `package-update`、`plugins-runtime` 和 `plugins-integrations` 分块仍作为手动重跑的聚合别名保留。直接运行内置通道时,用 `OPENCLAW_BUNDLED_CHANNELS=telegram,slack` 缩小渠道矩阵,或用 `OPENCLAW_BUNDLED_CHANNEL_UPDATE_TARGETS=telegram,acpx` 缩小更新场景。每场景 Docker 运行默认使用 `OPENCLAW_BUNDLED_CHANNEL_DOCKER_RUN_TIMEOUT=900s`;多目标更新场景默认使用 `OPENCLAW_BUNDLED_CHANNEL_UPDATE_DOCKER_RUN_TIMEOUT=2400s`。该通道还会验证 `channels..enabled=false` 和 `plugins.entries..enabled=false` 会抑制 Doctor/运行时依赖修复。 +- 内置插件运行时依赖:`pnpm test:docker:bundled-channel-deps` 默认构建一个小型 Docker runner 镜像,在主机上构建并打包 OpenClaw 一次,然后将该 tarball 挂载到每个 Linux 安装场景中。使用 `OPENCLAW_SKIP_DOCKER_BUILD=1` 复用镜像,在新近本地构建后使用 `OPENCLAW_BUNDLED_CHANNEL_HOST_BUILD=0` 跳过主机重建,或用 `OPENCLAW_CURRENT_PACKAGE_TGZ=/path/to/openclaw-*.tgz` 指向现有 tarball。完整 Docker 聚合和发布路径 bundled-channel 分块会先预打包这个 tarball 一次,然后将内置渠道检查分片到独立通道中,包括 Telegram、Discord、Slack、Feishu、memory-lancedb 和 ACPX 的单独更新通道。发布分块将渠道冒烟测试、更新目标和设置/运行时契约拆分到 `bundled-channels-core`、`bundled-channels-update-a`、`bundled-channels-update-b` 和 `bundled-channels-contracts`;聚合 `bundled-channels` 分块仍可用于手动重跑。发布工作流还会拆分提供商安装器分块以及内置插件安装/卸载分块;旧版 `package-update`、`plugins-runtime` 和 `plugins-integrations` 分块仍作为手动重跑的聚合别名保留。直接运行内置通道时,用 `OPENCLAW_BUNDLED_CHANNELS=telegram,slack` 缩小渠道矩阵,或用 `OPENCLAW_BUNDLED_CHANNEL_UPDATE_TARGETS=telegram,acpx` 缩小更新场景。每个场景的 Docker 运行默认使用 `OPENCLAW_BUNDLED_CHANNEL_DOCKER_RUN_TIMEOUT=900s`;多目标更新场景默认使用 `OPENCLAW_BUNDLED_CHANNEL_UPDATE_DOCKER_RUN_TIMEOUT=2400s`。该通道还会验证 `channels..enabled=false` 和 `plugins.entries..enabled=false` 会抑制 Doctor/运行时依赖修复。 - 迭代时可通过禁用无关场景来缩小内置插件运行时依赖,例如: `OPENCLAW_BUNDLED_CHANNEL_SCENARIOS=0 OPENCLAW_BUNDLED_CHANNEL_UPDATE_SCENARIO=0 OPENCLAW_BUNDLED_CHANNEL_ROOT_OWNED_SCENARIO=0 OPENCLAW_BUNDLED_CHANNEL_SETUP_ENTRY_SCENARIO=0 pnpm test:docker:bundled-channel-deps`。 @@ -600,108 +576,111 @@ OPENCLAW_DOCKER_E2E_IMAGE=openclaw-docker-e2e-functional:local pnpm test:docker: OPENCLAW_DOCKER_E2E_IMAGE=openclaw-docker-e2e-functional:local OPENCLAW_SKIP_DOCKER_BUILD=1 pnpm test:docker:mcp-channels ``` -设置后,像 `OPENCLAW_GATEWAY_NETWORK_E2E_IMAGE` 这样的套件专用镜像覆盖仍然优先生效。当 `OPENCLAW_SKIP_DOCKER_BUILD=1` 指向远程共享镜像时,如果本地尚不存在,脚本会拉取它。QR 和安装器 Docker 测试保留自己的 Dockerfile,因为它们验证的是软件包/安装行为,而不是共享的已构建应用运行时。 +设置后,诸如 `OPENCLAW_GATEWAY_NETWORK_E2E_IMAGE` 这样的套件专用镜像覆盖仍会优先生效。当 `OPENCLAW_SKIP_DOCKER_BUILD=1` 指向远程共享镜像时,如果它尚未在本地存在,脚本会拉取该镜像。QR 和安装器 Docker 测试保留各自的 Dockerfile,因为它们验证的是包/安装行为,而不是共享的已构建应用运行时。 -实时模型 Docker runner 还会以只读方式 bind-mount 当前检出, -并在容器内将它暂存到临时 workdir。这会让运行时 -镜像保持精简,同时仍然针对你确切的本地源码/配置运行 Vitest。 +实时模型 Docker runner 还会以只读方式绑定挂载当前检出, +并将其暂存到容器内的临时工作目录。这让运行时 +镜像保持精简,同时仍针对你的精确本地源码/配置运行 Vitest。 暂存步骤会跳过大型本地专用缓存和应用构建输出,例如 `.pnpm-store`、`.worktrees`、`__openclaw_vitest__`,以及应用本地 `.build` 或 -Gradle 输出目录,这样 Docker 实时运行就不会花费数分钟复制 -机器专用产物。 -它们还会设置 `OPENCLAW_SKIP_CHANNELS=1`,这样 Gateway 网关实时探测就不会在 -容器内启动真实的 Telegram/Discord 等渠道 worker。 -`test:docker:live-models` 仍然运行 `pnpm test:live`,因此当你需要从该 Docker 通道 -缩小或排除 Gateway 网关实时覆盖时,也要传入 +Gradle 输出目录,使 Docker 实时运行不会花数分钟复制 +机器专用构件。 +它们还会设置 `OPENCLAW_SKIP_CHANNELS=1`,使 Gateway 网关实时探针不会在容器内启动 +真正的 Telegram/Discord 等渠道 worker。 +`test:docker:live-models` 仍会运行 `pnpm test:live`,因此当你需要缩小或排除该 Docker 通道中的 Gateway 网关 +实时覆盖时,也要透传 `OPENCLAW_LIVE_GATEWAY_*`。 -`test:docker:openwebui` 是更高层的兼容性冒烟测试:它会启动一个启用了 -OpenAI 兼容 HTTP 端点的 OpenClaw Gateway 网关容器, -再启动一个 pinned Open WebUI 容器连接该 Gateway 网关, -通过 Open WebUI 登录,验证 `/api/models` 暴露 `openclaw/default`, -然后通过 Open WebUI 的 `/api/chat/completions` 代理发送一个 +`test:docker:openwebui` 是更高层的兼容性冒烟测试:它会启动一个 +启用了 OpenAI 兼容 HTTP 端点的 OpenClaw Gateway 网关容器, +启动一个固定版本的 Open WebUI 容器并指向该 Gateway 网关,通过 +Open WebUI 登录,验证 `/api/models` 暴露 `openclaw/default`,然后通过 Open WebUI 的 `/api/chat/completions` 代理发送 真实聊天请求。 首次运行可能明显更慢,因为 Docker 可能需要拉取 -Open WebUI 镜像,Open WebUI 也可能需要完成自己的冷启动设置。 -该通道需要可用的实时模型密钥,而 `OPENCLAW_PROFILE_FILE` -(默认是 `~/.profile`)是在 Docker 化运行中提供它的主要方式。 -成功运行会打印一个小型 JSON 负载,例如 `{ "ok": true, "model": +Open WebUI 镜像,而 Open WebUI 可能也需要完成自己的冷启动设置。 +该通道需要可用的实时模型密钥,`OPENCLAW_PROFILE_FILE` +(默认 `~/.profile`)是在 Docker 化运行中提供它的主要方式。 +成功运行会打印一个小型 JSON payload,例如 `{ "ok": true, "model": "openclaw/default", ... }`。 -`test:docker:mcp-channels` 有意保持确定性,不需要真实的 -Telegram、Discord 或 iMessage 账号。它会启动一个已填充的 Gateway 网关 -容器,启动第二个容器并生成 `openclaw mcp serve`,然后 -验证路由会话发现、转录读取、附件元数据、 -实时事件队列行为、出站发送路由,以及通过真实 stdio MCP 桥接发出的 Claude 风格渠道 + -权限通知。通知检查会直接检查原始 stdio MCP 帧, -因此该冒烟测试验证的是桥接实际发出的内容,而不只是某个特定客户端 SDK 恰好暴露的内容。 +`test:docker:mcp-channels` 有意保持确定性,不需要 +真正的 Telegram、Discord 或 iMessage 账号。它会启动一个种子化 Gateway 网关 +容器,启动第二个容器生成 `openclaw mcp serve`,然后 +验证路由后的对话发现、转录读取、附件元数据、 +实时事件队列行为、出站发送路由,以及通过真实 stdio MCP 桥接发送的 Claude 风格渠道 + +权限通知。通知检查会直接检查原始 stdio MCP frame, +因此该冒烟测试验证的是桥接实际发出的内容,而不只是某个特定客户端 SDK 碰巧暴露的内容。 `test:docker:pi-bundle-mcp-tools` 是确定性的,不需要实时 -模型密钥。它会构建仓库 Docker 镜像,在容器内启动一个真实 stdio MCP 探测服务器, -通过嵌入式 Pi bundle MCP 运行时物化该服务器, -执行工具,然后验证 `coding` 和 `messaging` 保留 +模型密钥。它会构建仓库 Docker 镜像,在容器内启动一个真实的 stdio MCP 探针服务器, +通过嵌入式 Pi bundle +MCP 运行时物化该服务器,执行该工具,然后验证 `coding` 和 `messaging` 保留 `bundle-mcp` 工具,而 `minimal` 和 `tools.deny: ["bundle-mcp"]` 会过滤它们。 `test:docker:cron-mcp-cleanup` 是确定性的,不需要实时模型 -密钥。它会启动一个已填充的 Gateway 网关和真实 stdio MCP 探测服务器,运行一个 -隔离 cron 轮次和一个 `/subagents spawn` 一次性子轮次,然后验证 -MCP 子进程在每次运行后退出。 +密钥。它会启动一个带真实 stdio MCP 探针服务器的种子化 Gateway 网关,运行一个 +隔离的 cron 轮次和一个 `/subagents spawn` 一次性子轮次,然后验证 +每次运行后 MCP 子进程都会退出。 -手动 ACP 自然语言线程冒烟测试(非 CI): +手动 ACP 自然语言线程冒烟测试(不在 CI 中): - `bun scripts/dev/discord-acp-plain-language-smoke.ts --channel ...` -- 保留此脚本用于回归/调试工作流。ACP 线程路由验证可能还会再次需要它,所以不要删除它。 +- 保留此脚本用于回归/调试工作流。ACP 线程路由验证可能还会再次需要它,因此不要删除。 有用的环境变量: - `OPENCLAW_CONFIG_DIR=...`(默认值:`~/.openclaw`)挂载到 `/home/node/.openclaw` - `OPENCLAW_WORKSPACE_DIR=...`(默认值:`~/.openclaw/workspace`)挂载到 `/home/node/.openclaw/workspace` - `OPENCLAW_PROFILE_FILE=...`(默认值:`~/.profile`)挂载到 `/home/node/.profile`,并在运行测试前 source -- `OPENCLAW_DOCKER_PROFILE_ENV_ONLY=1` 仅验证从 `OPENCLAW_PROFILE_FILE` source 的环境变量,使用临时配置/工作区目录,且不挂载外部 CLI 凭证 -- `OPENCLAW_DOCKER_CLI_TOOLS_DIR=...`(默认值:`~/.cache/openclaw/docker-cli-tools`)挂载到 `/home/node/.npm-global`,用于 Docker 内缓存 CLI 安装 +- `OPENCLAW_DOCKER_PROFILE_ENV_ONLY=1` 仅验证从 `OPENCLAW_PROFILE_FILE` source 的环境变量,使用临时配置/工作区目录,并且不挂载外部 CLI 凭证 +- `OPENCLAW_DOCKER_CLI_TOOLS_DIR=...`(默认值:`~/.cache/openclaw/docker-cli-tools`)挂载到 `/home/node/.npm-global`,用于 Docker 内缓存的 CLI 安装 - `$HOME` 下的外部 CLI 凭证目录/文件会以只读方式挂载到 `/host-auth...` 下,然后在测试开始前复制到 `/home/node/...` - 默认目录:`.minimax` - 默认文件:`~/.codex/auth.json`、`~/.codex/config.toml`、`.claude.json`、`~/.claude/.credentials.json`、`~/.claude/settings.json`、`~/.claude/settings.local.json` - - 收窄的提供商运行只会挂载从 `OPENCLAW_LIVE_PROVIDERS` / `OPENCLAW_LIVE_GATEWAY_PROVIDERS` 推断出的所需目录/文件 - - 可用 `OPENCLAW_DOCKER_AUTH_DIRS=all`、`OPENCLAW_DOCKER_AUTH_DIRS=none` 或类似 `OPENCLAW_DOCKER_AUTH_DIRS=.claude,.codex` 的逗号列表手动覆盖 -- `OPENCLAW_LIVE_GATEWAY_MODELS=...` / `OPENCLAW_LIVE_MODELS=...` 用于收窄运行范围 -- `OPENCLAW_LIVE_GATEWAY_PROVIDERS=...` / `OPENCLAW_LIVE_PROVIDERS=...` 用于在容器内筛选提供商 -- `OPENCLAW_SKIP_DOCKER_BUILD=1` 用于在不需要重新构建的重复运行中复用现有 `openclaw:local-live` 镜像 -- `OPENCLAW_LIVE_REQUIRE_PROFILE_KEYS=1` 用于确保凭证来自配置文件存储(而不是环境变量) -- `OPENCLAW_OPENWEBUI_MODEL=...` 用于选择 Gateway 网关向 Open WebUI 冒烟测试暴露的模型 -- `OPENCLAW_OPENWEBUI_PROMPT=...` 用于覆盖 Open WebUI 冒烟测试使用的 nonce 检查提示词 + - 缩窄后的提供商运行只会挂载根据 `OPENCLAW_LIVE_PROVIDERS` / `OPENCLAW_LIVE_GATEWAY_PROVIDERS` 推断出的所需目录/文件 + - 可使用 `OPENCLAW_DOCKER_AUTH_DIRS=all`、`OPENCLAW_DOCKER_AUTH_DIRS=none`,或像 `OPENCLAW_DOCKER_AUTH_DIRS=.claude,.codex` 这样的逗号列表手动覆盖 +- `OPENCLAW_LIVE_GATEWAY_MODELS=...` / `OPENCLAW_LIVE_MODELS=...` 用于缩窄运行范围 +- `OPENCLAW_LIVE_GATEWAY_PROVIDERS=...` / `OPENCLAW_LIVE_PROVIDERS=...` 用于在容器内过滤提供商 +- `OPENCLAW_SKIP_DOCKER_BUILD=1` 用于在不需要重建的重复运行中复用现有 `openclaw:local-live` 镜像 +- `OPENCLAW_LIVE_REQUIRE_PROFILE_KEYS=1` 用于确保凭证来自 profile 存储(而不是环境变量) +- `OPENCLAW_OPENWEBUI_MODEL=...` 用于选择 Gateway 网关为 Open WebUI 冒烟测试暴露的模型 +- `OPENCLAW_OPENWEBUI_PROMPT=...` 用于覆盖 Open WebUI 冒烟测试使用的 nonce 检查 prompt - `OPENWEBUI_IMAGE=...` 用于覆盖固定的 Open WebUI 镜像标签 ## 文档完整性检查 文档编辑后运行文档检查:`pnpm check:docs`。 -如果还需要检查页内标题,请运行完整的 Mintlify 锚点验证:`pnpm docs:check-links:anchors`。 +当还需要页内标题检查时,运行完整的 Mintlify 锚点验证:`pnpm docs:check-links:anchors`。 ## 离线回归(CI 安全) 这些是不使用真实提供商的“真实流水线”回归: -- Gateway 网关工具调用(模拟 OpenAI,真实 Gateway 网关 + 智能体循环):`src/gateway/gateway.test.ts`(用例:"runs a mock OpenAI tool call end-to-end via gateway agent loop") -- Gateway 网关向导(WS `wizard.start`/`wizard.next`,写入配置 + 强制执行凭证):`src/gateway/gateway.test.ts`(用例:"runs wizard over ws and writes auth token config") +- Gateway 网关工具调用(模拟 OpenAI,真实 Gateway 网关 + Agent loop):`src/gateway/gateway.test.ts`(用例:"runs a mock OpenAI tool call end-to-end via gateway agent loop") +- Gateway 网关向导(WS `wizard.start`/`wizard.next`,写入配置 + 强制执行鉴权):`src/gateway/gateway.test.ts`(用例:"runs wizard over ws and writes auth token config") ## 智能体可靠性评估(Skills) -我们已经有一些 CI 安全测试,其行为类似“智能体可靠性评估”: +我们已经有一些 CI 安全测试,行为类似“智能体可靠性评估”: -- 通过真实 Gateway 网关 + 智能体循环进行模拟工具调用(`src/gateway/gateway.test.ts`)。 +- 通过真实 Gateway 网关 + Agent loop 进行模拟工具调用(`src/gateway/gateway.test.ts`)。 - 端到端向导流程,用于验证会话接线和配置效果(`src/gateway/gateway.test.ts`)。 -Skills 仍然缺少的内容(见 [Skills](/zh-CN/tools/skills)): +Skills 仍缺少的内容(见 [Skills](/zh-CN/tools/skills)): -- **决策:** 当提示词中列出 Skills 时,智能体是否会选择正确的 skill(或避开不相关的 skill)? -- **合规:** 智能体在使用前是否读取 `SKILL.md`,并遵循必需的步骤/参数? +- **决策:** 当 prompt 中列出 Skills 时,智能体是否会选择正确的 skill(或避开无关的 skill)? +- **合规性:** 智能体是否会在使用前读取 `SKILL.md`,并遵循所需步骤/参数? - **工作流契约:** 断言工具顺序、会话历史延续和沙箱边界的多轮场景。 未来评估应首先保持确定性: -- 使用模拟提供商的场景运行器,用于断言工具调用 + 顺序、skill 文件读取和会话接线。 -- 一小套以 skill 为中心的场景(使用 vs 避免、门控、提示词注入)。 -- 可选实时评估(可选启用,通过环境变量门控)仅在 CI 安全套件到位后再添加。 +- 使用模拟提供商的场景运行器,用于断言工具调用及其顺序、skill 文件读取和会话接线。 +- 一小组聚焦 Skills 的场景(使用与避开、门控、prompt 注入)。 +- 可选的 live 评估(选择加入、通过环境变量门控)仅在 CI 安全套件就位后再添加。 ## 契约测试(插件和渠道形状) -契约测试验证每个已注册插件和渠道是否符合其接口契约。它们会遍历所有已发现的插件,并运行一套形状和行为断言。默认的 `pnpm test` 单元测试通道会有意跳过这些共享接口和冒烟文件;当你触碰共享渠道或提供商表面时,请显式运行契约命令。 +契约测试会验证每个已注册插件和渠道都符合其 +接口契约。它们会遍历所有发现的插件,并运行一组 +形状和行为断言。默认的 `pnpm test` 单元测试 lane 会有意 +跳过这些共享边界和冒烟文件;当你触及共享渠道或提供商表面时, +请显式运行契约命令。 ### 命令 @@ -716,11 +695,11 @@ Skills 仍然缺少的内容(见 [Skills](/zh-CN/tools/skills)): - **plugin** - 基本插件形状(id、名称、能力) - **setup** - 设置向导契约 - **session-binding** - 会话绑定行为 -- **outbound-payload** - 消息载荷结构 +- **outbound-payload** - 消息 payload 结构 - **inbound** - 入站消息处理 -- **actions** - 渠道操作处理器 +- **actions** - 渠道 action 处理器 - **threading** - 线程 ID 处理 -- **directory** - 目录/花名册 API +- **directory** - 目录/成员名册 API - **group-policy** - 群组策略强制执行 ### 提供商 Status 契约 @@ -734,8 +713,8 @@ Skills 仍然缺少的内容(见 [Skills](/zh-CN/tools/skills)): 位于 `src/plugins/contracts/*.contract.test.ts`: -- **auth** - 凭证流程契约 -- **auth-choice** - 凭证选择/选取 +- **auth** - 鉴权流程契约 +- **auth-choice** - 鉴权选择/选取 - **catalog** - 模型目录 API - **discovery** - 插件发现 - **loader** - 插件加载 @@ -753,18 +732,18 @@ Skills 仍然缺少的内容(见 [Skills](/zh-CN/tools/skills)): ## 添加回归(指南) -当你修复实时运行中发现的提供商/模型问题时: +当你修复 live 中发现的提供商/模型问题时: -- 尽可能添加 CI 安全回归(模拟/stub 提供商,或捕获确切的请求形状转换) -- 如果它本质上只能实时验证(速率限制、凭证策略),请保持实时测试范围狭窄,并通过环境变量可选启用 -- 优先针对能捕获该 bug 的最小层级: - - 提供商请求转换/重放 bug → 直接模型测试 - - Gateway 网关会话/历史/工具流水线 bug → Gateway 网关实时冒烟测试或 CI 安全的 Gateway 网关模拟测试 -- SecretRef 遍历护栏: - - `src/secrets/exec-secret-ref-id-parity.test.ts` 会从注册表元数据(`listSecretTargetRegistryEntries()`)为每个 SecretRef 类派生一个采样目标,然后断言包含遍历段的 exec id 会被拒绝。 - - 如果你在 `src/secrets/target-registry-data.ts` 中添加新的 `includeInPlan` SecretRef 目标族,请更新该测试中的 `classifyTargetClass`。该测试会故意在未分类的目标 id 上失败,以便新类别不能被静默跳过。 +- 尽可能添加 CI 安全回归(模拟/存根提供商,或捕获精确的请求形状转换) +- 如果它本质上只能 live 复现(速率限制、鉴权策略),请让 live 测试保持窄范围,并通过环境变量选择加入 +- 优先针对能捕获该 bug 的最小层: + - 提供商请求转换/回放 bug → 直接模型测试 + - Gateway 网关会话/历史/工具流水线 bug → Gateway 网关 live 冒烟测试或 CI 安全的 Gateway 网关模拟测试 +- SecretRef 遍历防护栏: + - `src/secrets/exec-secret-ref-id-parity.test.ts` 会从注册表元数据(`listSecretTargetRegistryEntries()`)为每个 SecretRef 类派生一个抽样目标,然后断言 traversal-segment exec ids 会被拒绝。 + - 如果你在 `src/secrets/target-registry-data.ts` 中添加新的 `includeInPlan` SecretRef 目标族,请更新该测试中的 `classifyTargetClass`。该测试会故意在未分类的目标 ID 上失败,以免新类别被静默跳过。 ## 相关 -- [实时测试](/zh-CN/help/testing-live) +- [Testing live](/zh-CN/help/testing-live) - [CI](/zh-CN/ci)