chore(i18n): refresh zh-CN translations
This commit is contained in:
parent
01d992955c
commit
a610bdbd52
@ -1,18 +1,18 @@
|
||||
---
|
||||
read_when:
|
||||
- 设置 Slack 或调试 Slack socket/HTTP 模式
|
||||
summary: Slack 设置与运行时行为(Socket Mode + HTTP 请求 URL)
|
||||
summary: Slack 设置和运行时行为(Socket Mode + HTTP 请求 URL)
|
||||
title: Slack
|
||||
x-i18n:
|
||||
generated_at: "2026-04-24T17:24:32Z"
|
||||
generated_at: "2026-04-24T23:09:44Z"
|
||||
model: gpt-5.4
|
||||
provider: openai
|
||||
source_hash: 830fe844f1f278062de3c186f2b7865684962c10dfb2740a42bf7b47e342b534
|
||||
source_hash: aef3302e3c535f6e4eaba8460b3a89fcfa7043a8a6da856f4a734c2d997c9374
|
||||
source_path: channels/slack.md
|
||||
workflow: 15
|
||||
---
|
||||
|
||||
适用于通过 Slack 应用集成在私信和渠道中进行生产环境使用。默认模式为 Socket Mode;也支持 HTTP 请求 URL。
|
||||
通过 Slack 应用集成,为私信和渠道提供可用于生产环境的支持。默认模式为 Socket Mode;也支持 HTTP 请求 URL。
|
||||
|
||||
<CardGroup cols={3}>
|
||||
<Card title="配对" icon="link" href="/zh-CN/channels/pairing">
|
||||
@ -26,7 +26,7 @@ x-i18n:
|
||||
</Card>
|
||||
</CardGroup>
|
||||
|
||||
## 快速设置
|
||||
## 快速开始
|
||||
|
||||
<Tabs>
|
||||
<Tab title="Socket Mode(默认)">
|
||||
@ -35,9 +35,9 @@ x-i18n:
|
||||
在 Slack 应用设置中,点击 **[Create New App](https://api.slack.com/apps/new)** 按钮:
|
||||
|
||||
- 选择 **from a manifest**,并为你的应用选择一个工作区
|
||||
- 粘贴下面的[示例清单](#manifest-and-scope-checklist),然后继续创建
|
||||
- 粘贴下面的[示例 manifest](#manifest-and-scope-checklist) 并继续创建
|
||||
- 生成一个带有 `connections:write` 权限的 **App-Level Token**(`xapp-...`)
|
||||
- 安装应用,并复制显示的 **Bot Token**(`xoxb-...`)
|
||||
- 安装应用并复制显示的 **Bot Token**(`xoxb-...`)
|
||||
</Step>
|
||||
|
||||
<Step title="配置 OpenClaw">
|
||||
@ -81,9 +81,9 @@ openclaw gateway
|
||||
在 Slack 应用设置中,点击 **[Create New App](https://api.slack.com/apps/new)** 按钮:
|
||||
|
||||
- 选择 **from a manifest**,并为你的应用选择一个工作区
|
||||
- 粘贴[示例清单](#manifest-and-scope-checklist),并在创建前更新 URL
|
||||
- 粘贴[示例 manifest](#manifest-and-scope-checklist),并在创建前更新 URL
|
||||
- 保存用于请求验证的 **Signing Secret**
|
||||
- 安装应用,并复制显示的 **Bot Token**(`xoxb-...`)
|
||||
- 安装应用并复制显示的 **Bot Token**(`xoxb-...`)
|
||||
|
||||
</Step>
|
||||
|
||||
@ -104,9 +104,9 @@ openclaw gateway
|
||||
```
|
||||
|
||||
<Note>
|
||||
对多账户 HTTP 使用唯一的 webhook 路径
|
||||
为多账户 HTTP 使用唯一的 webhook 路径
|
||||
|
||||
为每个账户指定不同的 `webhookPath`(默认是 `/slack/events`),这样注册就不会发生冲突。
|
||||
为每个账户分配不同的 `webhookPath`(默认是 `/slack/events`),以避免注册冲突。
|
||||
</Note>
|
||||
|
||||
</Step>
|
||||
@ -123,11 +123,11 @@ openclaw gateway
|
||||
</Tab>
|
||||
</Tabs>
|
||||
|
||||
## 清单和作用域检查清单
|
||||
## Manifest 和作用域检查清单
|
||||
|
||||
Socket Mode 和 HTTP 请求 URL 使用相同的基础 Slack 应用清单。只有 `settings` 块(以及斜杠命令的 `url`)不同。
|
||||
基础 Slack 应用 manifest 在 Socket Mode 和 HTTP 请求 URL 中是相同的。只有 `settings` 代码块(以及 slash command 的 `url`)不同。
|
||||
|
||||
基础清单(Socket Mode 默认):
|
||||
基础 manifest(Socket Mode 默认):
|
||||
|
||||
```json
|
||||
{
|
||||
@ -199,7 +199,7 @@ Socket Mode 和 HTTP 请求 URL 使用相同的基础 Slack 应用清单。只
|
||||
}
|
||||
```
|
||||
|
||||
对于 **HTTP 请求 URL 模式**,请将 `settings` 替换为 HTTP 变体,并为每个斜杠命令添加 `url`。需要公共 URL:
|
||||
对于 **HTTP 请求 URL 模式**,请将 `settings` 替换为 HTTP 变体,并为每个 slash command 添加 `url`。需要公开 URL:
|
||||
|
||||
```json
|
||||
{
|
||||
@ -229,19 +229,19 @@ Socket Mode 和 HTTP 请求 URL 使用相同的基础 Slack 应用清单。只
|
||||
}
|
||||
```
|
||||
|
||||
### 其他清单设置
|
||||
### 其他 manifest 设置
|
||||
|
||||
展示扩展上述默认值的不同功能。
|
||||
|
||||
<AccordionGroup>
|
||||
<Accordion title="可选原生斜杠命令">
|
||||
|
||||
可以使用多个[原生斜杠命令](#commands-and-slash-behavior)来代替单个已配置命令,但有一些细微差别:
|
||||
可以使用多个[原生斜杠命令](#commands-and-slash-behavior) 来代替单个已配置命令,但有一些细节需要注意:
|
||||
|
||||
- 使用 `/agentstatus` 而不是 `/status`,因为 `/status` 命令已被保留。
|
||||
- 同时最多只能提供 25 个斜杠命令。
|
||||
- 同时可用的斜杠命令不能超过 25 个。
|
||||
|
||||
用[可用命令](/zh-CN/tools/slash-commands#command-list)的一个子集替换你现有的 `features.slash_commands` 部分:
|
||||
请用 [可用命令](/zh-CN/tools/slash-commands#command-list) 的一个子集替换你现有的 `features.slash_commands` 部分:
|
||||
|
||||
<Tabs>
|
||||
<Tab title="Socket Mode(默认)">
|
||||
@ -361,7 +361,7 @@ Socket Mode 和 HTTP 请求 URL 使用相同的基础 Slack 应用清单。只
|
||||
|
||||
</Tab>
|
||||
<Tab title="HTTP 请求 URL">
|
||||
使用与上方 Socket Mode 相同的 `slash_commands` 列表,并为每一项添加 `"url": "https://gateway-host.example.com/slack/events"`。示例:
|
||||
使用与上方 Socket Mode 相同的 `slash_commands` 列表,并为每个条目添加 `"url": "https://gateway-host.example.com/slack/events"`。示例:
|
||||
|
||||
```json
|
||||
"slash_commands": [
|
||||
@ -385,16 +385,16 @@ Socket Mode 和 HTTP 请求 URL 使用相同的基础 Slack 应用清单。只
|
||||
|
||||
</Accordion>
|
||||
<Accordion title="可选作者身份作用域(写操作)">
|
||||
如果你希望发出的消息使用当前智能体身份(自定义用户名和图标)而不是默认 Slack 应用身份,请添加 `chat:write.customize` bot scope。
|
||||
如果你希望发出的消息使用当前智能体身份(自定义用户名和图标),而不是默认的 Slack 应用身份,请添加 `chat:write.customize` bot scope。
|
||||
|
||||
如果你使用表情符号图标,Slack 需要 `:emoji_name:` 语法。
|
||||
如果你使用 emoji 图标,Slack 要求采用 `:emoji_name:` 语法。
|
||||
|
||||
</Accordion>
|
||||
<Accordion title="可选用户令牌作用域(读操作)">
|
||||
如果你配置了 `channels.slack.userToken`,典型的读取作用域包括:
|
||||
如果你配置了 `channels.slack.userToken`,常见的读取作用域包括:
|
||||
|
||||
- `channels:history`, `groups:history`, `im:history`, `mpim:history`
|
||||
- `channels:read`, `groups:read`, `im:read`, `mpim:read`
|
||||
- `channels:history`、`groups:history`、`im:history`、`mpim:history`
|
||||
- `channels:read`、`groups:read`、`im:read`、`mpim:read`
|
||||
- `users:read`
|
||||
- `reactions:read`
|
||||
- `pins:read`
|
||||
@ -408,35 +408,40 @@ Socket Mode 和 HTTP 请求 URL 使用相同的基础 Slack 应用清单。只
|
||||
|
||||
- Socket Mode 需要 `botToken` + `appToken`。
|
||||
- HTTP 模式需要 `botToken` + `signingSecret`。
|
||||
- `botToken`、`appToken`、`signingSecret` 和 `userToken` 接受明文字符串或 SecretRef 对象。
|
||||
- `botToken`、`appToken`、`signingSecret` 和 `userToken` 接受明文
|
||||
字符串或 SecretRef 对象。
|
||||
- 配置中的令牌会覆盖环境变量回退。
|
||||
- `SLACK_BOT_TOKEN` / `SLACK_APP_TOKEN` 环境变量回退仅适用于默认账户。
|
||||
- `userToken`(`xoxp-...`)仅支持通过配置设置(没有环境变量回退),并且默认是只读行为(`userTokenReadOnly: true`)。
|
||||
- `userToken`(`xoxp-...`)仅可在配置中使用(无环境变量回退),并且默认采用只读行为(`userTokenReadOnly: true`)。
|
||||
|
||||
状态快照行为:
|
||||
|
||||
- Slack 账户检查会跟踪每个凭证的 `*Source` 和 `*Status` 字段(`botToken`、`appToken`、`signingSecret`、`userToken`)。
|
||||
- 状态可以是 `available`、`configured_unavailable` 或 `missing`。
|
||||
- `configured_unavailable` 表示账户是通过 SecretRef 或其他非内联密钥来源配置的,但当前命令/运行时路径无法解析出实际值。
|
||||
- 在 HTTP 模式下,会包含 `signingSecretStatus`;在 Socket Mode 下,所需的字段对是 `botTokenStatus` + `appTokenStatus`。
|
||||
- Slack 账户检查会按凭证跟踪各自的 `*Source` 和 `*Status`
|
||||
字段(`botToken`、`appToken`、`signingSecret`、`userToken`)。
|
||||
- 状态可能是 `available`、`configured_unavailable` 或 `missing`。
|
||||
- `configured_unavailable` 表示该账户通过 SecretRef
|
||||
或其他非内联密钥来源进行配置,但当前命令/运行时路径
|
||||
无法解析出实际值。
|
||||
- 在 HTTP 模式下,会包含 `signingSecretStatus`;在 Socket Mode 下,
|
||||
必需的一对状态字段是 `botTokenStatus` + `appTokenStatus`。
|
||||
|
||||
<Tip>
|
||||
对于操作/目录读取,配置后可以优先使用用户令牌。对于写入,仍然优先使用 bot 令牌;只有在 `userTokenReadOnly: false` 且 bot 令牌不可用时,才允许使用用户令牌写入。
|
||||
对于操作/目录读取,如果已配置 user token,则可以优先使用它。对于写入操作,仍然优先使用 bot token;只有当 `userTokenReadOnly: false` 且 bot token 不可用时,才允许使用 user-token 写入。
|
||||
</Tip>
|
||||
|
||||
## 操作和门控
|
||||
|
||||
Slack 操作由 `channels.slack.actions.*` 控制。
|
||||
|
||||
当前 Slack 工具中可用的操作组:
|
||||
当前 Slack 工具中的可用操作组:
|
||||
|
||||
| 组 | 默认值 |
|
||||
| ---------- | ------- |
|
||||
| messages | 启用 |
|
||||
| reactions | 吂用 |
|
||||
| pins | 启用 |
|
||||
| memberInfo | 启用 |
|
||||
| emojiList | 启用 |
|
||||
| messages | 已启用 |
|
||||
| reactions | 已启用 |
|
||||
| pins | 已启用 |
|
||||
| memberInfo | 已启用 |
|
||||
| emojiList | 已启用 |
|
||||
|
||||
当前 Slack 消息操作包括 `send`、`upload-file`、`download-file`、`read`、`edit`、`delete`、`pin`、`unpin`、`list-pins`、`member-info` 和 `emoji-list`。
|
||||
|
||||
@ -462,29 +467,29 @@ Slack 操作由 `channels.slack.actions.*` 控制。
|
||||
多账户优先级:
|
||||
|
||||
- `channels.slack.accounts.default.allowFrom` 仅适用于 `default` 账户。
|
||||
- 已命名账户在自身 `allowFrom` 未设置时,会继承 `channels.slack.allowFrom`。
|
||||
- 已命名账户不会继承 `channels.slack.accounts.default.allowFrom`。
|
||||
- 当具名账户自身未设置 `allowFrom` 时,会继承 `channels.slack.allowFrom`。
|
||||
- 具名账户不会继承 `channels.slack.accounts.default.allowFrom`。
|
||||
|
||||
私信中的配对使用 `openclaw pairing approve slack <code>`。
|
||||
在私信中进行配对时,使用 `openclaw pairing approve slack <code>`。
|
||||
|
||||
</Tab>
|
||||
|
||||
<Tab title="渠道策略">
|
||||
`channels.slack.groupPolicy` 控制渠道处理:
|
||||
`channels.slack.groupPolicy` 控制渠道处理方式:
|
||||
|
||||
- `open`
|
||||
- `allowlist`
|
||||
- `disabled`
|
||||
|
||||
渠道 allowlist 位于 `channels.slack.channels` 下,并且应使用稳定的渠道 ID。
|
||||
渠道 allowlist 位于 `channels.slack.channels` 下,应使用稳定的渠道 ID。
|
||||
|
||||
运行时说明:如果完全缺少 `channels.slack`(仅环境变量设置),运行时会回退到 `groupPolicy="allowlist"` 并记录一条警告(即使设置了 `channels.defaults.groupPolicy` 也是如此)。
|
||||
运行时说明:如果完全缺少 `channels.slack`(仅环境变量设置),运行时会回退到 `groupPolicy="allowlist"` 并记录警告(即使已设置 `channels.defaults.groupPolicy` 也是如此)。
|
||||
|
||||
名称/ID 解析:
|
||||
|
||||
- 在令牌访问允许的情况下,渠道 allowlist 条目和私信 allowlist 条目会在启动时解析
|
||||
- 无法解析的渠道名称条目会按配置保留,但默认不会用于路由
|
||||
- 入站授权和渠道路由默认优先基于 ID;直接匹配用户名/slug 需要 `channels.slack.dangerouslyAllowNameMatching: true`
|
||||
- 当令牌访问权限允许时,渠道 allowlist 条目和私信 allowlist 条目会在启动时解析
|
||||
- 无法解析的渠道名称条目会按配置原样保留,但默认不会用于路由
|
||||
- 入站授权和渠道路由默认优先使用 ID;直接匹配用户名/slug 需要设置 `channels.slack.dangerouslyAllowNameMatching: true`
|
||||
|
||||
</Tab>
|
||||
|
||||
@ -494,8 +499,8 @@ Slack 操作由 `channels.slack.actions.*` 控制。
|
||||
提及来源:
|
||||
|
||||
- 显式应用提及(`<@botId>`)
|
||||
- 提及正则模式(`agents.list[].groupChat.mentionPatterns`,回退为 `messages.groupChat.mentionPatterns`)
|
||||
- 隐式机器人线程回复行为(当 `thread.requireExplicitMention` 为 `true` 时禁用)
|
||||
- 提及正则模式(`agents.list[].groupChat.mentionPatterns`,回退到 `messages.groupChat.mentionPatterns`)
|
||||
- 隐式回复机器人线程行为(当 `thread.requireExplicitMention` 为 `true` 时禁用)
|
||||
|
||||
每个渠道的控制项(`channels.slack.channels.<id>`;名称仅通过启动时解析或 `dangerouslyAllowNameMatching` 支持):
|
||||
|
||||
@ -504,35 +509,35 @@ Slack 操作由 `channels.slack.actions.*` 控制。
|
||||
- `allowBots`
|
||||
- `skills`
|
||||
- `systemPrompt`
|
||||
- `tools`, `toolsBySender`
|
||||
- `tools`、`toolsBySender`
|
||||
- `toolsBySender` 键格式:`id:`、`e164:`、`username:`、`name:` 或 `"*"` 通配符
|
||||
(旧版无前缀键仍然只会映射到 `id:`)
|
||||
(旧版无前缀键仍只映射到 `id:`)
|
||||
|
||||
</Tab>
|
||||
</Tabs>
|
||||
|
||||
## 线程、会话和回复标签
|
||||
|
||||
- 私信路由为 `direct`;渠道为 `channel`;MPIM 为 `group`。
|
||||
- 使用默认 `session.dmScope=main` 时,Slack 私信会折叠到智能体主会话。
|
||||
- 私信路由为 `direct`;渠道路由为 `channel`;MPIM 路由为 `group`。
|
||||
- 使用默认 `session.dmScope=main` 时,Slack 私信会合并到智能体主会话。
|
||||
- 渠道会话:`agent:<agentId>:slack:channel:<channelId>`。
|
||||
- 在线程回复适用时,可以创建带线程会话后缀的回复(`:thread:<threadTs>`)。
|
||||
- 线程回复在适用时可创建线程会话后缀(`:thread:<threadTs>`)。
|
||||
- `channels.slack.thread.historyScope` 默认为 `thread`;`thread.inheritParent` 默认为 `false`。
|
||||
- `channels.slack.thread.initialHistoryLimit` 控制新线程会话开始时会抓取多少现有线程消息(默认 `20`;设为 `0` 可禁用)。
|
||||
- `channels.slack.thread.requireExplicitMention`(默认 `false`):为 `true` 时,会抑制隐式线程提及,因此机器人只会响应线程内显式的 `@bot` 提及,即使机器人之前已经参与了该线程。若不启用此项,在机器人已参与线程时,该线程中的回复会绕过 `requireMention` 门控。
|
||||
- `channels.slack.thread.initialHistoryLimit` 控制在新线程会话开始时获取多少现有线程消息(默认 `20`;设为 `0` 可禁用)。
|
||||
- `channels.slack.thread.requireExplicitMention`(默认 `false`):当设为 `true` 时,会抑制隐式线程提及,因此机器人即使已经参与该线程,也只会响应线程中的显式 `@bot` 提及。不启用此项时,在机器人已参与的线程中回复会绕过 `requireMention` 门控。
|
||||
|
||||
回复线程控制:
|
||||
|
||||
- `channels.slack.replyToMode`:`off|first|all|batched`(默认 `off`)
|
||||
- `channels.slack.replyToModeByChatType`:按 `direct|group|channel` 分别设置
|
||||
- 旧版私信回退:`channels.slack.dm.replyToMode`
|
||||
- 直接聊天的旧版回退:`channels.slack.dm.replyToMode`
|
||||
|
||||
支持手动回复标签:
|
||||
|
||||
- `[[reply_to_current]]`
|
||||
- `[[reply_to:<id>]]`
|
||||
|
||||
注意:`replyToMode="off"` 会禁用 Slack 中**所有**回复线程功能,包括显式 `[[reply_to_*]]` 标签。这与 Telegram 不同,在 Telegram 中,即使在 `"off"` 模式下也仍然会遵循显式标签——Slack 线程会把消息隐藏在渠道之外,而 Telegram 回复则仍以内联方式可见。
|
||||
注意:`replyToMode="off"` 会禁用 Slack 中**所有**回复线程功能,包括显式 `[[reply_to_*]]` 标签。这与 Telegram 不同,在 Telegram 中显式标签在 `"off"` 模式下仍会生效 —— Slack 线程会将消息隐藏在渠道外,而 Telegram 回复仍以内联方式可见。
|
||||
|
||||
## 确认反应
|
||||
|
||||
@ -543,12 +548,12 @@ Slack 操作由 `channels.slack.actions.*` 控制。
|
||||
- `channels.slack.accounts.<accountId>.ackReaction`
|
||||
- `channels.slack.ackReaction`
|
||||
- `messages.ackReaction`
|
||||
- 智能体身份 emoji 回退(`agents.list[].identity.emoji`,否则为 `"👀"`)
|
||||
- 智能体身份 emoji 回退(`agents.list[].identity.emoji`,否则为 "👀")
|
||||
|
||||
说明:
|
||||
|
||||
- Slack 需要 shortcode(例如 `"eyes"`)。
|
||||
- 使用 `""` 可为 Slack 账户或全局禁用该反应。
|
||||
- 使用 `""` 可为该 Slack 账户或全局禁用此反应。
|
||||
|
||||
## 文本流式传输
|
||||
|
||||
@ -558,18 +563,18 @@ Slack 操作由 `channels.slack.actions.*` 控制。
|
||||
- `partial`(默认):用最新的部分输出替换预览文本。
|
||||
- `block`:追加分块预览更新。
|
||||
- `progress`:生成期间显示进度状态文本,然后发送最终文本。
|
||||
- `streaming.preview.toolProgress`:当草稿预览处于活动状态时,将工具/进度更新路由到同一条被编辑的预览消息中(默认:`true`)。设为 `false` 可保留单独的工具/进度消息。
|
||||
- `streaming.preview.toolProgress`:当草稿预览处于激活状态时,将工具/进度更新路由到同一个被编辑的预览消息中(默认:`true`)。设为 `false` 可保留单独的工具/进度消息。
|
||||
|
||||
当 `channels.slack.streaming.mode` 为 `partial` 时,`channels.slack.streaming.nativeTransport` 控制 Slack 原生文本流式传输(默认:`true`)。
|
||||
|
||||
- 必须有可用的回复线程,原生文本流式传输和 Slack assistant 线程状态才会显示。线程选择仍然遵循 `replyToMode`。
|
||||
- 必须存在回复线程,Slack 原生文本流式传输和 Slack 助手线程状态才会显示。线程选择仍遵循 `replyToMode`。
|
||||
- 当原生流式传输不可用时,渠道和群聊根消息仍可使用普通草稿预览。
|
||||
- 顶层 Slack 私信默认保持在线程之外,因此不会显示线程样式预览;如果你希望在那里看到可见进度,请使用线程回复或 `typingReaction`。
|
||||
- 媒体和非文本负载会回退为普通投递。
|
||||
- 媒体/错误最终消息会取消待处理的预览编辑;符合条件的文本/块最终消息仅会在能够原地编辑预览时才刷新。
|
||||
- 如果流式传输在回复中途失败,OpenClaw 会对剩余负载回退为普通投递。
|
||||
- 顶层 Slack 私信默认保持非线程模式,因此不会显示线程式预览;如果你希望在这种情况下看到可见进度,请使用线程回复或 `typingReaction`。
|
||||
- 媒体和非文本负载会回退到普通投递。
|
||||
- 媒体/错误最终消息会取消待处理的预览编辑;符合条件的文本/块最终消息仅在能够原地编辑预览时才会刷新。
|
||||
- 如果流式传输在回复中途失败,OpenClaw 会对剩余负载回退到普通投递。
|
||||
|
||||
使用草稿预览代替 Slack 原生文本流式传输:
|
||||
使用草稿预览而不是 Slack 原生文本流式传输:
|
||||
|
||||
```json5
|
||||
{
|
||||
@ -586,13 +591,13 @@ Slack 操作由 `channels.slack.actions.*` 控制。
|
||||
|
||||
旧版键:
|
||||
|
||||
- `channels.slack.streamMode`(`replace | status_final | append`)会自动迁移为 `channels.slack.streaming.mode`。
|
||||
- 布尔值 `channels.slack.streaming` 会自动迁移为 `channels.slack.streaming.mode` 和 `channels.slack.streaming.nativeTransport`。
|
||||
- 旧版 `channels.slack.nativeStreaming` 会自动迁移为 `channels.slack.streaming.nativeTransport`。
|
||||
- `channels.slack.streamMode`(`replace | status_final | append`)会自动迁移到 `channels.slack.streaming.mode`。
|
||||
- 布尔值 `channels.slack.streaming` 会自动迁移到 `channels.slack.streaming.mode` 和 `channels.slack.streaming.nativeTransport`。
|
||||
- 旧版 `channels.slack.nativeStreaming` 会自动迁移到 `channels.slack.streaming.nativeTransport`。
|
||||
|
||||
## 输入中反应回退
|
||||
## 输入反应回退
|
||||
|
||||
`typingReaction` 会在 OpenClaw 处理回复期间,给入站 Slack 消息添加一个临时反应,并在运行结束时将其移除。这在非线程回复场景中特别有用,因为线程回复会使用默认的“正在输入...”状态指示器。
|
||||
`typingReaction` 会在 OpenClaw 处理回复期间,为入站 Slack 消息添加一个临时反应,并在运行结束时将其移除。这在非线程回复场景中特别有用,因为线程回复默认会使用“正在输入...”状态指示器。
|
||||
|
||||
解析顺序:
|
||||
|
||||
@ -602,30 +607,30 @@ Slack 操作由 `channels.slack.actions.*` 控制。
|
||||
说明:
|
||||
|
||||
- Slack 需要 shortcode(例如 `"hourglass_flowing_sand"`)。
|
||||
- 该反应是尽力而为的,回复完成或失败路径结束后会自动尝试清理。
|
||||
- 该反应为尽力而为,回复或失败路径完成后会自动尝试清理。
|
||||
|
||||
## 媒体、分块和投递
|
||||
|
||||
<AccordionGroup>
|
||||
<Accordion title="入站附件">
|
||||
Slack 文件附件会从 Slack 托管的私有 URL 下载(基于令牌认证的请求流程),并在抓取成功且大小限制允许时写入媒体存储。
|
||||
Slack 文件附件会从 Slack 托管的私有 URL 下载(使用基于令牌认证的请求流程),当获取成功且满足大小限制时,会写入媒体存储。
|
||||
|
||||
运行时入站大小上限默认是 `20MB`,除非被 `channels.slack.mediaMaxMb` 覆盖。
|
||||
运行时入站大小上限默认为 `20MB`,除非通过 `channels.slack.mediaMaxMb` 覆盖。
|
||||
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="出站文本和文件">
|
||||
- 文本分块使用 `channels.slack.textChunkLimit`(默认 4000)
|
||||
- `channels.slack.chunkMode="newline"` 启用按段落优先拆分
|
||||
- 文件发送使用 Slack 上传 API,并可包含线程回复(`thread_ts`)
|
||||
- 配置了 `channels.slack.mediaMaxMb` 时,出站媒体上限遵循该值;否则渠道发送使用媒体管线中的 MIME 类型默认值
|
||||
- `channels.slack.chunkMode="newline"` 启用优先按段落拆分
|
||||
- 文件发送使用 Slack 上传 API,并且可以包含线程回复(`thread_ts`)
|
||||
- 配置了 `channels.slack.mediaMaxMb` 时,出站媒体上限会遵循该值;否则渠道发送会使用媒体管道中的 MIME 类型默认值
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="投递目标">
|
||||
推荐的显式目标:
|
||||
推荐使用的显式目标:
|
||||
|
||||
- 私信使用 `user:<id>`
|
||||
- 渠道使用 `channel:<id>`
|
||||
- `user:<id>` 用于私信
|
||||
- `channel:<id>` 用于渠道
|
||||
|
||||
发送到用户目标时,Slack 私信会通过 Slack 会话 API 打开。
|
||||
|
||||
@ -634,7 +639,7 @@ Slack 操作由 `channels.slack.actions.*` 控制。
|
||||
|
||||
## 命令和斜杠行为
|
||||
|
||||
斜杠命令在 Slack 中会显示为单个已配置命令或多个原生命令。配置 `channels.slack.slashCommand` 可更改命令默认值:
|
||||
Slash commands 在 Slack 中可以显示为单个已配置命令,或多个原生命令。配置 `channels.slack.slashCommand` 以更改命令默认值:
|
||||
|
||||
- `enabled: false`
|
||||
- `name: "openclaw"`
|
||||
@ -645,30 +650,30 @@ Slack 操作由 `channels.slack.actions.*` 控制。
|
||||
/openclaw /help
|
||||
```
|
||||
|
||||
原生命令要求你在 Slack 应用中设置[其他清单设置](#additional-manifest-settings),并通过 `channels.slack.commands.native: true` 或全局配置中的 `commands.native: true` 启用。
|
||||
原生命令需要你在 Slack 应用中配置[其他 manifest 设置](#additional-manifest-settings),并通过 `channels.slack.commands.native: true` 或全局配置中的 `commands.native: true` 来启用。
|
||||
|
||||
- Slack 的原生命令自动模式默认为**关闭**,因此 `commands.native: "auto"` 不会启用 Slack 原生命令。
|
||||
- 对于 Slack,原生命令自动模式默认是**关闭**的,因此 `commands.native: "auto"` 不会启用 Slack 原生命令。
|
||||
|
||||
```txt
|
||||
/help
|
||||
```
|
||||
|
||||
原生参数菜单使用自适应渲染策略,在分发所选选项值前会先显示确认模态框:
|
||||
原生参数菜单使用自适应渲染策略,在派发所选选项值之前显示确认模态框:
|
||||
|
||||
- 最多 5 个选项:按钮块
|
||||
- 6-100 个选项:静态选择菜单
|
||||
- 超过 100 个选项:当可用 interactivity 选项处理器时,使用带异步选项过滤的外部选择
|
||||
- 超出 Slack 限制:编码后的选项值会回退为按钮
|
||||
- 超过 100 个选项:当可用交互选项处理器时,使用带异步选项过滤的外部选择
|
||||
- 超出 Slack 限制:已编码的选项值会回退为按钮
|
||||
|
||||
```txt
|
||||
/think
|
||||
```
|
||||
|
||||
斜杠会话使用类似 `agent:<agentId>:slack:slash:<userId>` 的隔离键,并且仍会使用 `CommandTargetSessionKey` 将命令执行路由到目标会话。
|
||||
斜杠会话使用类似 `agent:<agentId>:slack:slash:<userId>` 的隔离键,并仍会通过 `CommandTargetSessionKey` 将命令执行路由到目标会话。
|
||||
|
||||
## 交互式回复
|
||||
|
||||
Slack 可以渲染由智能体编写的交互式回复控件,但该功能默认禁用。
|
||||
Slack 可以渲染由智能体编写的交互式回复控件,但此功能默认禁用。
|
||||
|
||||
全局启用:
|
||||
|
||||
@ -702,42 +707,43 @@ Slack 可以渲染由智能体编写的交互式回复控件,但该功能默
|
||||
}
|
||||
```
|
||||
|
||||
启用后,智能体可以发出仅限 Slack 的回复指令:
|
||||
启用后,智能体可以输出仅限 Slack 的回复指令:
|
||||
|
||||
- `[[slack_buttons: Approve:approve, Reject:reject]]`
|
||||
- `[[slack_select: Choose a target | Canary:canary, Production:production]]`
|
||||
|
||||
这些指令会编译为 Slack Block Kit,并将点击或选择通过现有 Slack 交互事件路径路由回来。
|
||||
这些指令会编译为 Slack Block Kit,并通过现有的 Slack 交互事件路径将点击或选择路由回来。
|
||||
|
||||
说明:
|
||||
|
||||
- 这是 Slack 专用 UI。其他渠道不会将 Slack Block Kit 指令转换为它们自己的按钮系统。
|
||||
- 这是 Slack 专属 UI。其他渠道不会将 Slack Block Kit 指令翻译成它们自己的按钮系统。
|
||||
- 交互回调值是 OpenClaw 生成的不透明令牌,而不是智能体原始编写的值。
|
||||
- 如果生成的交互块会超出 Slack Block Kit 限制,OpenClaw 会回退为原始文本回复,而不是发送无效的 blocks 负载。
|
||||
- 如果生成的交互块超出 Slack Block Kit 限制,OpenClaw 会回退为原始文本回复,而不是发送无效的 blocks 负载。
|
||||
|
||||
## Slack 中的 exec 审批
|
||||
## Slack 中的 Exec 审批
|
||||
|
||||
Slack 可以充当原生审批客户端,使用交互式按钮和交互,而不是回退到 Web UI 或终端。
|
||||
Slack 可以作为原生审批客户端,通过交互式按钮和交互来工作,而不是回退到 Web UI 或终端。
|
||||
|
||||
- Exec 审批使用 `channels.slack.execApprovals.*` 进行原生私信/渠道路由。
|
||||
- 当请求已经落在 Slack 中且审批 ID 类型为 `plugin:` 时,插件审批仍然可以通过相同的 Slack 原生按钮界面处理。
|
||||
- 审批人授权仍然会被强制执行:只有被识别为审批人的用户,才能通过 Slack 批准或拒绝请求。
|
||||
- 当请求已经落在 Slack 中且审批 ID 类型为 `plugin:` 时,插件审批仍可通过同一套 Slack 原生按钮界面解析。
|
||||
- 审批人授权仍然会被强制执行:只有被识别为审批人的用户才能通过 Slack 批准或拒绝请求。
|
||||
|
||||
这使用与其他渠道相同的共享审批按钮界面。当你在 Slack 应用设置中启用 `interactivity` 后,审批提示会直接在会话中渲染为 Block Kit 按钮。
|
||||
当这些按钮存在时,它们就是主要的审批 UX;只有当工具结果表明聊天审批不可用,或手动审批是唯一可行路径时,OpenClaw
|
||||
这使用与其他渠道相同的共享审批按钮界面。当你在 Slack 应用设置中启用 `interactivity` 时,审批提示会直接在会话中渲染为 Block Kit 按钮。
|
||||
当这些按钮存在时,它们就是主要的审批 UX;只有当工具结果表明聊天审批不可用,或手动审批是唯一途径时,OpenClaw
|
||||
才应包含手动 `/approve` 命令。
|
||||
|
||||
配置路径:
|
||||
|
||||
- `channels.slack.execApprovals.enabled`
|
||||
- `channels.slack.execApprovals.approvers`(可选;在可能的情况下会回退到 `commands.ownerAllowFrom`)
|
||||
- `channels.slack.execApprovals.approvers`(可选;在可能时会回退到 `commands.ownerAllowFrom`)
|
||||
- `channels.slack.execApprovals.target`(`dm` | `channel` | `both`,默认:`dm`)
|
||||
- `agentFilter`、`sessionFilter`
|
||||
|
||||
当 `enabled` 未设置或为 `"auto"`,并且至少解析出一位审批人时,Slack 会自动启用原生 exec 审批。将 `enabled: false` 设为显式禁用 Slack 作为原生审批客户端。
|
||||
将 `enabled: true` 设为在审批人可解析时强制启用原生审批。
|
||||
当 `enabled` 未设置或为 `"auto"` 且至少解析出一名
|
||||
审批人时,Slack 会自动启用原生 Exec 审批。设置 `enabled: false` 可显式禁用 Slack 作为原生审批客户端。
|
||||
设置 `enabled: true` 可在审批人已解析时强制开启原生审批。
|
||||
|
||||
在没有显式 Slack exec 审批配置时的默认行为:
|
||||
在没有显式 Slack Exec 审批配置时的默认行为:
|
||||
|
||||
```json5
|
||||
{
|
||||
@ -747,7 +753,8 @@ Slack 可以充当原生审批客户端,使用交互式按钮和交互,而
|
||||
}
|
||||
```
|
||||
|
||||
只有当你想覆盖审批人、添加过滤器,或选择启用源聊天投递时,才需要显式的 Slack 原生配置:
|
||||
只有当你想覆盖审批人、添加过滤器,或
|
||||
选择加入源聊天投递时,才需要显式的 Slack 原生配置:
|
||||
|
||||
```json5
|
||||
{
|
||||
@ -763,21 +770,23 @@ Slack 可以充当原生审批客户端,使用交互式按钮和交互,而
|
||||
}
|
||||
```
|
||||
|
||||
共享 `approvals.exec` 转发是独立的。仅当 exec 审批提示还必须路由到其他聊天或明确的带外目标时才使用它。共享 `approvals.plugin` 转发也是独立的;当这些请求已经落在 Slack 中时,Slack 原生按钮仍然可以处理插件审批。
|
||||
共享 `approvals.exec` 转发是独立的。仅当 Exec 审批提示还必须
|
||||
路由到其他聊天或显式的带外目标时才使用它。共享 `approvals.plugin` 转发也同样
|
||||
独立;当这些请求已经落在 Slack 中时,Slack 原生按钮仍然可以解析插件审批。
|
||||
|
||||
同一聊天中的 `/approve` 也可在已支持命令的 Slack 渠道和私信中使用。完整的审批转发模型请参阅 [Exec approvals](/zh-CN/tools/exec-approvals)。
|
||||
同聊天中的 `/approve` 也适用于已支持命令的 Slack 渠道和私信。完整的审批转发模型请参见 [Exec approvals](/zh-CN/tools/exec-approvals)。
|
||||
|
||||
## 事件和运行行为
|
||||
|
||||
- 消息编辑/删除/线程广播会映射为系统事件。
|
||||
- 反应添加/移除事件会映射为系统事件。
|
||||
- 成员加入/离开、渠道创建/重命名,以及固定消息添加/移除事件会映射为系统事件。
|
||||
- 添加/移除反应事件会映射为系统事件。
|
||||
- 成员加入/离开、渠道创建/重命名以及添加/移除置顶事件会映射为系统事件。
|
||||
- 当启用 `configWrites` 时,`channel_id_changed` 可以迁移渠道配置键。
|
||||
- 渠道 topic/purpose 元数据会被视为不可信上下文,并可注入到路由上下文中。
|
||||
- 在线程起始消息和初始线程历史上下文播种时,会在适用情况下按已配置的发送者 allowlist 进行过滤。
|
||||
- Block 操作和模态交互会发出结构化的 `Slack interaction: ...` 系统事件,并带有丰富的负载字段:
|
||||
- block 操作:选中值、标签、选择器值以及 `workflow_*` 元数据
|
||||
- 模态 `view_submission` 和 `view_closed` 事件,包含已路由的渠道元数据和表单输入
|
||||
- 在线程起始消息和初始线程历史上下文预填充时,如适用,会按已配置的发送者 allowlist 进行过滤。
|
||||
- Block actions 和模态交互会发出结构化的 `Slack interaction: ...` 系统事件,并包含丰富的负载字段:
|
||||
- block actions:选定值、标签、选择器值以及 `workflow_*` 元数据
|
||||
- 模态 `view_submission` 和 `view_closed` 事件,带有已路由的渠道元数据和表单输入
|
||||
|
||||
## 配置参考
|
||||
|
||||
@ -785,13 +794,13 @@ Slack 可以充当原生审批客户端,使用交互式按钮和交互,而
|
||||
|
||||
<Accordion title="高信号 Slack 字段">
|
||||
|
||||
- 模式/认证:`mode`、`botToken`、`appToken`、`signingSecret`、`webhookPath`、`accounts.*`
|
||||
- mode/auth:`mode`、`botToken`、`appToken`、`signingSecret`、`webhookPath`、`accounts.*`
|
||||
- 私信访问:`dm.enabled`、`dmPolicy`、`allowFrom`(旧版:`dm.policy`、`dm.allowFrom`)、`dm.groupEnabled`、`dm.groupChannels`
|
||||
- 兼容性开关:`dangerouslyAllowNameMatching`(紧急开关;除非确有需要,否则保持关闭)
|
||||
- 兼容性开关:`dangerouslyAllowNameMatching`(紧急兜底;除非确有需要,否则保持关闭)
|
||||
- 渠道访问:`groupPolicy`、`channels.*`、`channels.*.users`、`channels.*.requireMention`
|
||||
- 线程/历史:`replyToMode`、`replyToModeByChatType`、`thread.*`、`historyLimit`、`dmHistoryLimit`、`dms.*.historyLimit`
|
||||
- 投递:`textChunkLimit`、`chunkMode`、`mediaMaxMb`、`streaming`、`streaming.nativeTransport`、`streaming.preview.toolProgress`
|
||||
- 运维/功能:`configWrites`、`commands.native`、`slashCommand.*`、`actions.*`、`userToken`、`userTokenReadOnly`
|
||||
- 操作/功能:`configWrites`、`commands.native`、`slashCommand.*`、`actions.*`、`userToken`、`userTokenReadOnly`
|
||||
|
||||
</Accordion>
|
||||
|
||||
@ -799,7 +808,7 @@ Slack 可以充当原生审批客户端,使用交互式按钮和交互,而
|
||||
|
||||
<AccordionGroup>
|
||||
<Accordion title="渠道中没有回复">
|
||||
按以下顺序检查:
|
||||
请按顺序检查:
|
||||
|
||||
- `groupPolicy`
|
||||
- 渠道 allowlist(`channels.slack.channels`)
|
||||
@ -822,6 +831,9 @@ openclaw doctor
|
||||
- `channels.slack.dm.enabled`
|
||||
- `channels.slack.dmPolicy`(或旧版 `channels.slack.dm.policy`)
|
||||
- 配对审批 / allowlist 条目
|
||||
- Slack Assistant 私信事件:提到 `drop message_changed` 的详细日志
|
||||
通常表示 Slack 发送了一个已编辑的 Assistant 线程事件,但在消息元数据中
|
||||
没有可恢复的人类发送者
|
||||
|
||||
```bash
|
||||
openclaw pairing list slack
|
||||
@ -830,36 +842,36 @@ openclaw pairing list slack
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="Socket mode 未连接">
|
||||
验证 bot 和 app 令牌,以及 Slack 应用设置中的 Socket Mode 是否已启用。
|
||||
验证 bot 和 app token,以及 Slack 应用设置中的 Socket Mode 是否已启用。
|
||||
|
||||
如果 `openclaw channels status --probe --json` 显示 `botTokenStatus` 或
|
||||
`appTokenStatus: "configured_unavailable"`,则表示 Slack 账户已
|
||||
配置,但当前运行时无法解析由 SecretRef 支持的
|
||||
`appTokenStatus: "configured_unavailable"`,说明该 Slack 账户
|
||||
已配置,但当前运行时无法解析由 SecretRef 支持的
|
||||
值。
|
||||
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="HTTP 模式未收到事件">
|
||||
<Accordion title="HTTP 模式未接收到事件">
|
||||
验证:
|
||||
|
||||
- signing secret
|
||||
- webhook 路径
|
||||
- Slack 请求 URL(Events + Interactivity + Slash Commands)
|
||||
- Slack Request URLs(Events + Interactivity + Slash Commands)
|
||||
- 每个 HTTP 账户使用唯一的 `webhookPath`
|
||||
|
||||
如果账户快照中出现 `signingSecretStatus: "configured_unavailable"`,
|
||||
则表示 HTTP 账户已配置,但当前运行时无法
|
||||
说明该 HTTP 账户已配置,但当前运行时无法
|
||||
解析由 SecretRef 支持的 signing secret。
|
||||
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="原生命令/斜杠命令未触发">
|
||||
验证你期望的是:
|
||||
<Accordion title="原生命令/slash commands 未触发">
|
||||
确认你想要的是:
|
||||
|
||||
- 原生命令模式(`channels.slack.commands.native: true`),并且在 Slack 中注册了匹配的斜杠命令
|
||||
- 或单一斜杠命令模式(`channels.slack.slashCommand.enabled: true`)
|
||||
- 原生命令模式(`channels.slack.commands.native: true`),并且已在 Slack 中注册匹配的 slash commands
|
||||
- 或单 slash command 模式(`channels.slack.slashCommand.enabled: true`)
|
||||
|
||||
还要检查 `commands.useAccessGroups` 以及渠道/用户 allowlist。
|
||||
同时检查 `commands.useAccessGroups` 以及渠道/用户 allowlist。
|
||||
|
||||
</Accordion>
|
||||
</AccordionGroup>
|
||||
|
||||
110
docs/zh-CN/ci.md
110
docs/zh-CN/ci.md
@ -1,27 +1,27 @@
|
||||
---
|
||||
read_when:
|
||||
- 你需要了解某个 CI 作业为什么运行了或没有运行
|
||||
- 你需要了解为什么某个 CI 作业会运行或不会运行
|
||||
- 你正在调试失败的 GitHub Actions 检查
|
||||
summary: CI 作业图、范围门控,以及本地等效命令
|
||||
summary: CI 作业图、范围门禁,以及本地等效命令
|
||||
title: CI 流水线
|
||||
x-i18n:
|
||||
generated_at: "2026-04-24T19:56:24Z"
|
||||
generated_at: "2026-04-24T23:09:47Z"
|
||||
model: gpt-5.4
|
||||
provider: openai
|
||||
source_hash: 8407768803b8d92e03a7fb453307a64cb4f2342ba3894b51d4c928dd434fede6
|
||||
source_hash: bfcd687e6555b15ddebe3c061a814911d4f8a49c0db1c42aff357976a82bbbd5
|
||||
source_path: ci.md
|
||||
workflow: 15
|
||||
---
|
||||
|
||||
CI 会在每次向 `main` 推送以及每个拉取请求时运行。它使用智能范围界定,在仅更改了无关区域时跳过高开销作业。
|
||||
CI 会在每次推送到 `main` 以及每个拉取请求时运行。它使用智能范围控制,在仅更改了无关区域时跳过开销较大的作业。
|
||||
|
||||
QA Lab 在主智能范围界定工作流之外有专用的 CI 通道。`Parity gate` 工作流会在匹配的 PR 变更和手动触发时运行;它会构建私有 QA 运行时,并比较模拟的 GPT-5.4 和 Opus 4.6 agentic pack。`QA-Lab - All Lanes` 工作流会在 `main` 上每晚运行,也可手动触发;它会将模拟 parity gate、实时 Matrix 通道和实时 Telegram 通道拆分为并行作业。实时作业使用 `qa-live-shared` 环境,而 Telegram 通道使用 Convex 租约。`OpenClaw Release Checks` 也会在发布审批前运行同样的 QA Lab 通道。
|
||||
QA Lab 在主智能范围工作流之外有专用的 CI 通道。`Parity gate` 工作流会在匹配的 PR 变更以及手动触发时运行;它会构建私有 QA 运行时,并比较模拟的 GPT-5.4 和 Opus 4.6 agentic packs。`QA-Lab - All Lanes` 工作流会在 `main` 上每晚运行,也支持手动触发;它会将模拟 parity gate、实时 Matrix 通道和实时 Telegram 通道作为并行作业扇出执行。实时作业使用 `qa-live-shared` 环境,而 Telegram 通道使用 Convex 租约。`OpenClaw Release Checks` 也会在发布批准前运行同样的 QA Lab 通道。
|
||||
|
||||
`Duplicate PRs After Merge` 工作流是一个供维护者使用的手动工作流,用于合并后的重复 PR 清理。它默认以 dry-run 模式运行,只有在 `apply=true` 时才会关闭明确列出的 PR。在修改 GitHub 之前,它会验证已落地的 PR 是否已合并,以及每个重复 PR 是否具有共享的引用 issue 或重叠的变更块。
|
||||
`Duplicate PRs After Merge` 工作流是一个供维护者在合并后进行重复项清理的手动工作流。它默认以 dry-run 模式运行,只有在 `apply=true` 时才会关闭明确列出的 PR。在修改 GitHub 之前,它会验证已落地的 PR 确实已合并,并确认每个重复 PR 要么共享同一个被引用的问题,要么存在重叠的变更代码块。
|
||||
|
||||
`Docs Agent` 工作流是一个事件驱动的 Codex 维护通道,用于让现有文档与最近已落地的更改保持一致。它没有纯定时调度:当 `main` 上一次成功的、非机器人触发的 push CI 运行完成后,可以触发它;也可以通过手动触发直接运行。对于由 workflow-run 触发的调用,如果 `main` 已经继续前进,或者在最近一小时内已经创建了另一个未被跳过的 Docs Agent 运行,则会跳过。当它运行时,会审查从上一个未被跳过的 Docs Agent 源 SHA 到当前 `main` 的提交范围,因此每小时的一次运行可以覆盖自上次文档处理以来累计到 `main` 的所有更改。
|
||||
`Docs Agent` 工作流是一个事件驱动的 Codex 维护通道,用于让现有文档与最近已合并的更改保持一致。它没有纯定时调度:当 `main` 上成功完成一次非机器人触发的 push CI 运行后,可以触发它;也可以通过手动触发直接运行。通过 workflow-run 调用时,如果 `main` 已经继续前进,或最近一小时内已经创建了另一个未被跳过的 Docs Agent 运行,它就会跳过。当它运行时,会审查从上一次未被跳过的 Docs Agent 源 SHA 到当前 `main` 的提交范围,因此每小时的一次运行可以覆盖自上次文档处理以来累计在 `main` 上的所有更改。
|
||||
|
||||
`Test Performance Agent` 工作流是一个事件驱动的 Codex 维护通道,用于处理慢测试。它没有纯定时调度:当 `main` 上一次成功的、非机器人触发的 push CI 运行完成后,可以触发它,但如果当天 UTC 内已有另一个 workflow-run 调用已经运行或正在运行,则会跳过。手动触发会绕过这个每日活动门控。该通道会构建完整测试套件分组的 Vitest 性能报告,让 Codex 仅进行小范围、保留覆盖率的测试性能修复,而不是大范围重构,然后重新运行完整测试套件报告,并拒绝会降低通过基线测试数量的更改。如果基线中存在失败测试,Codex 只能修复明显的失败项,并且在提交任何内容之前,agent 处理后的完整测试套件报告必须通过。当 `main` 在机器人推送落地前继续前进时,该通道会对已验证的补丁执行 rebase,重新运行 `pnpm check:changed`,并重试推送;存在冲突的过时补丁会被跳过。它使用 GitHub 托管的 Ubuntu,这样 Codex action 就能与 docs agent 保持相同的 drop-sudo 安全策略。
|
||||
`Test Performance Agent` 工作流是一个事件驱动的 Codex 维护通道,用于处理慢测试。它没有纯定时调度:当 `main` 上成功完成一次非机器人触发的 push CI 运行后,可以触发它,但如果当天 UTC 时间内已有另一个 workflow-run 调用已经运行或正在运行,它就会跳过。手动触发会绕过这个按天的活动门禁。该通道会构建一个完整测试套件分组的 Vitest 性能报告,让 Codex 只进行小范围、保持覆盖率不变的测试性能修复,而不是做大范围重构,然后再次运行完整测试套件报告,并拒绝任何会降低通过基线测试数量的更改。如果基线本身存在失败测试,Codex 只能修复明显的失败项,而且在提交任何内容之前,agent 处理后的完整测试套件报告必须通过。当 `main` 在机器人推送落地之前继续前进时,该通道会对已验证的补丁执行 rebase,重新运行 `pnpm check:changed`,并重试推送;有冲突的过期补丁会被跳过。它使用 GitHub 托管的 Ubuntu,以便 Codex action 能与 docs agent 保持相同的 drop-sudo 安全策略。
|
||||
|
||||
```bash
|
||||
gh workflow run duplicate-after-merge.yml \
|
||||
@ -34,72 +34,72 @@ gh workflow run duplicate-after-merge.yml \
|
||||
|
||||
| 作业 | 用途 | 运行时机 |
|
||||
| -------------------------------- | -------------------------------------------------------------------------------------------- | ------------------------------------ |
|
||||
| `preflight` | 检测是否仅为文档更改、已更改范围、已更改扩展,并构建 CI 清单 | 在所有非草稿 push 和 PR 上始终运行 |
|
||||
| `preflight` | 检测是否仅更改文档、已更改范围、已更改扩展,并构建 CI 清单 | 在所有非草稿 push 和 PR 上始终运行 |
|
||||
| `security-scm-fast` | 通过 `zizmor` 进行私钥检测和工作流审计 | 在所有非草稿 push 和 PR 上始终运行 |
|
||||
| `security-dependency-audit` | 针对 npm advisories 执行无依赖的生产 lockfile 审计 | 在所有非草稿 push 和 PR 上始终运行 |
|
||||
| `security-dependency-audit` | 针对 npm 安全公告执行无依赖的生产 lockfile 审计 | 在所有非草稿 push 和 PR 上始终运行 |
|
||||
| `security-fast` | 快速安全作业的必需聚合作业 | 在所有非草稿 push 和 PR 上始终运行 |
|
||||
| `build-artifacts` | 构建 `dist/`、Control UI、已构建产物检查,以及可复用的下游产物 | 与 Node 相关的更改 |
|
||||
| `build-artifacts` | 构建 `dist/`、Control UI、内置产物检查,以及可复用的下游产物 | 与 Node 相关的更改 |
|
||||
| `checks-fast-core` | 快速 Linux 正确性通道,例如 bundled/plugin-contract/protocol 检查 | 与 Node 相关的更改 |
|
||||
| `checks-fast-contracts-channels` | 分片的 channel contract 检查,并提供稳定的聚合检查结果 | 与 Node 相关的更改 |
|
||||
| `checks-node-extensions` | 面向整个扩展套件的完整 bundled plugin 测试分片 | 与 Node 相关的更改 |
|
||||
| `checks-node-core-test` | 核心 Node 测试分片,不包括 channel、bundled、contract 和 extension 通道 | 与 Node 相关的更改 |
|
||||
| `extension-fast` | 仅针对已更改 bundled plugin 的聚焦测试 | 带有扩展更改的拉取请求 |
|
||||
| `check` | 分片的主本地门控等效项:生产类型、lint、guards、测试类型和严格 smoke | 与 Node 相关的更改 |
|
||||
| `check-additional` | 架构、边界、扩展表面保护、package-boundary 和 gateway-watch 分片 | 与 Node 相关的更改 |
|
||||
| `build-smoke` | 已构建 CLI smoke 测试和启动内存 smoke | 与 Node 相关的更改 |
|
||||
| `checks` | 已构建产物 channel 测试以及仅 push 时的 Node 22 兼容性验证器 | 与 Node 相关的更改 |
|
||||
| `check-docs` | 文档格式、lint 和失效链接检查 | 文档发生更改 |
|
||||
| `skills-python` | 面向 Python 支持 Skills 的 Ruff + pytest | 与 Python Skills 相关的更改 |
|
||||
| `checks-windows` | Windows 专用测试通道 | 与 Windows 相关的更改 |
|
||||
| `macos-node` | 使用共享已构建产物的 macOS TypeScript 测试通道 | 与 macOS 相关的更改 |
|
||||
| `checks-fast-contracts-channels` | 分片渠道契约检查,并提供稳定的聚合检查结果 | 与 Node 相关的更改 |
|
||||
| `checks-node-extensions` | 覆盖整个扩展套件的完整内置插件测试分片 | 与 Node 相关的更改 |
|
||||
| `checks-node-core-test` | Core Node 测试分片,不包括渠道、内置、契约和扩展通道 | 与 Node 相关的更改 |
|
||||
| `extension-fast` | 仅针对已更改的内置插件执行聚焦测试 | 具有扩展更改的拉取请求 |
|
||||
| `check` | 分片后的主本地门禁等效项:生产类型、lint、守卫、测试类型和严格 smoke | 与 Node 相关的更改 |
|
||||
| `check-additional` | 架构、边界、扩展表面守卫、包边界以及 gateway-watch 分片 | 与 Node 相关的更改 |
|
||||
| `build-smoke` | 内置 CLI smoke 测试和启动内存 smoke 测试 | 与 Node 相关的更改 |
|
||||
| `checks` | 用于内置产物渠道测试以及仅 push 的 Node 22 兼容性的校验器 | 与 Node 相关的更改 |
|
||||
| `check-docs` | 文档格式、lint 和失效链接检查 | 文档有更改时 |
|
||||
| `skills-python` | 针对 Python 支持的 Skills 运行 Ruff + pytest | 与 Python Skills 相关的更改 |
|
||||
| `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 成功后或手动触发 |
|
||||
| `android` | 两种 flavor 的 Android 单元测试,以及一个 debug APK 构建 | 与 Android 相关的更改 |
|
||||
| `test-performance-agent` | 在可信活动之后进行每日 Codex 慢测试优化 | 主 CI 成功后或手动触发 |
|
||||
|
||||
## 快速失败顺序
|
||||
|
||||
作业的排列方式是让廉价检查先失败,再运行高开销作业:
|
||||
作业的排序方式是让低成本检查先失败,避免高成本作业启动:
|
||||
|
||||
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`、仅 PR 的 `extension-fast`、`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`、仅 PR 的 `extension-fast`、`checks`、`checks-windows`、`macos-node`、`macos-swift` 和 `android`。
|
||||
|
||||
范围逻辑位于 `scripts/ci-changed-scope.mjs`,并由 `src/scripts/ci-changed-scope.test.ts` 中的单元测试覆盖。
|
||||
CI 工作流编辑会验证 Node CI 作业图以及工作流 lint,但仅凭这些编辑本身并不会强制运行 Windows、Android 或 macOS 原生构建;这些平台通道仍然仅限于平台源码更改。
|
||||
Windows Node 检查的范围仅限于 Windows 专用的进程/路径包装器、npm/pnpm/UI 运行器辅助工具、包管理器配置,以及执行该通道的 CI 工作流表面;无关的源码、plugin、install-smoke 和纯测试更改会继续留在 Linux Node 通道中,因此不会为那些已经由常规测试分片覆盖的内容占用一台 16-vCPU 的 Windows worker。
|
||||
单独的 `install-smoke` 工作流通过其自己的 `preflight` 作业复用同一个范围脚本。它将 smoke 覆盖拆分为 `run_fast_install_smoke` 和 `run_full_install_smoke`。拉取请求会针对 Docker/package 表面、bundled plugin package/manifest 更改,以及 Docker smoke 作业会覆盖的核心 plugin/channel/gateway/插件 SDK 表面运行快速路径。仅源码的 bundled plugin 更改、纯测试编辑和纯文档编辑不会占用 Docker worker。快速路径会构建一次根 Dockerfile 镜像,检查 CLI,运行容器 gateway-network e2e,验证一个 bundled extension 构建参数,并在 120 秒命令超时限制下运行受限的 bundled plugin Docker 配置。完整路径会为每晚定时运行、手动触发、workflow-call 发布检查,以及真正触及 installer/package/Docker 表面的拉取请求,保留 QR package 安装和 installer Docker/update 覆盖。对 `main` 的推送(包括 merge commit)不会强制走完整路径;当 changed-scope 逻辑会在 push 上请求完整覆盖时,工作流仍保留快速 Docker smoke,而将完整安装 smoke 留给每晚或发布验证。较慢的 Bun 全局安装 image-provider smoke 由 `run_bun_global_install_smoke` 单独门控;它会在每晚调度和发布检查工作流中运行,手动触发 `install-smoke` 时也可以选择启用,但拉取请求和对 `main` 的推送不会运行它。QR 和 installer Docker 测试继续保留各自专用的以安装为重点的 Dockerfile。本地 `test:docker:all` 会预构建一个共享 live-test 镜像和一个共享的 `scripts/e2e/Dockerfile` built-app 镜像,然后使用加权调度器和 `OPENCLAW_SKIP_DOCKER_BUILD=1` 运行 live/E2E smoke 通道;默认主池槽位数为 10,可通过 `OPENCLAW_DOCKER_ALL_PARALLELISM` 调整;provider 敏感的尾池槽位数默认为 10,可通过 `OPENCLAW_DOCKER_ALL_TAIL_PARALLELISM` 调整。重型通道上限默认分别为 `OPENCLAW_DOCKER_ALL_LIVE_LIMIT=4`、`OPENCLAW_DOCKER_ALL_NPM_LIMIT=4` 和 `OPENCLAW_DOCKER_ALL_SERVICE_LIMIT=5`,这样 npm install 和多服务通道不会过度占用 Docker,而较轻的通道仍能填满可用槽位。默认会将通道启动错开 2 秒,以避免本地 Docker daemon 出现创建风暴;可通过 `OPENCLAW_DOCKER_ALL_START_STAGGER_MS=0` 或其他毫秒值覆盖。本地聚合器默认在首次失败后停止调度新的池化通道,并且每个通道都有一个 120 分钟的超时,可通过 `OPENCLAW_DOCKER_ALL_LANE_TIMEOUT_MS` 覆盖。可复用的 live/E2E 工作流也沿用了共享镜像模式:在 Docker 矩阵之前先构建并推送一个带 SHA 标签的 GHCR Docker E2E 镜像,然后使用 `OPENCLAW_SKIP_DOCKER_BUILD=1` 运行矩阵。定时的 live/E2E 工作流每天运行完整的发布路径 Docker 套件。完整的 bundled update/channel 矩阵仍然保持为手动/完整套件,因为它会反复执行真实的 npm update 和 Doctor 修复流程。
|
||||
CI 工作流编辑会验证 Node CI 作业图以及工作流 lint,但它们本身不会强制触发 Windows、Android 或 macOS 原生构建;这些平台通道仍然只在平台源码发生更改时才会运行。
|
||||
Windows Node 检查的范围限定在 Windows 特有的进程/路径包装器、npm/pnpm/UI 运行器辅助工具、包管理器配置,以及执行该通道的 CI 工作流表面;无关的源码、插件、install-smoke 和仅测试更改仍然保留在 Linux Node 通道中,因此不会为了已经由常规测试分片覆盖的内容而占用一个 16 vCPU 的 Windows worker。
|
||||
单独的 `install-smoke` 工作流会通过它自己的 `preflight` 作业复用同一个范围脚本。它将 smoke 覆盖拆分为 `run_fast_install_smoke` 和 `run_full_install_smoke`。对于拉取请求,Docker/包表面、内置插件包/manifest 更改,以及 Docker smoke 作业会覆盖到的核心插件/渠道/Gateway 网关/插件 SDK 表面,会运行快速路径。仅源码级的内置插件更改、仅测试更改和仅文档更改不会占用 Docker worker。快速路径会构建一次根 Dockerfile 镜像,检查 CLI,运行容器 gateway-network e2e,验证一个内置扩展 build arg,并在 120 秒命令超时限制下运行受限的 bundled-plugin Docker 配置。完整路径则保留 QR 包安装以及 installer Docker/update 覆盖,用于每晚定时运行、手动触发、workflow-call 发布检查,以及确实涉及 installer/package/Docker 表面的拉取请求。推送到 `main`,包括合并提交,不会强制走完整路径;当 changed-scope 逻辑在一次 push 中本应请求完整覆盖时,该工作流仍只保留快速 Docker smoke,而将完整 install smoke 留给夜间运行或发布验证。较慢的 Bun 全局安装 image-provider smoke 由 `run_bun_global_install_smoke` 单独控制;它会在夜间调度和发布检查工作流中运行,手动触发 `install-smoke` 时也可以选择启用,但拉取请求和推送到 `main` 时不会运行。QR 和 installer Docker 测试保留它们各自专注于安装的 Dockerfile。本地 `test:docker:all` 会预构建一个共享的 live-test 镜像和一个共享的 `scripts/e2e/Dockerfile` built-app 镜像,然后使用加权调度器和 `OPENCLAW_SKIP_DOCKER_BUILD=1` 运行 live/E2E smoke 通道;默认的主池槽位数 10 可通过 `OPENCLAW_DOCKER_ALL_PARALLELISM` 调整,provider 敏感的尾池槽位数 10 可通过 `OPENCLAW_DOCKER_ALL_TAIL_PARALLELISM` 调整。重型通道上限默认分别为 `OPENCLAW_DOCKER_ALL_LIVE_LIMIT=4`、`OPENCLAW_DOCKER_ALL_NPM_LIMIT=4` 和 `OPENCLAW_DOCKER_ALL_SERVICE_LIMIT=5`,以便 npm install 和多服务通道不会让 Docker 过载,同时较轻的通道仍能填满可用槽位。默认情况下,各通道启动会错开 2 秒,以避免本地 Docker 守护进程在创建阶段出现风暴;可通过 `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 通道使用更严格的单通道限制。可复用的 live/E2E 工作流也遵循共享镜像模式:它会在 Docker 矩阵开始前先构建并推送一个带 SHA 标签的 GHCR Docker E2E 镜像,然后在矩阵中使用 `OPENCLAW_SKIP_DOCKER_BUILD=1` 运行。定时的 live/E2E 工作流每天运行完整的发布路径 Docker 套件。内置更新矩阵按更新目标拆分,这样重复的 npm update 和 doctor repair 流程就可以与其他内置检查一起分片执行。
|
||||
|
||||
本地 changed-lane 逻辑位于 `scripts/changed-lanes.mjs`,并由 `scripts/check-changed.mjs` 执行。这个本地门控在架构边界方面比宽泛的 CI 平台范围更严格:核心生产更改会运行核心生产 typecheck 加核心测试,核心仅测试更改只运行核心测试 typecheck/测试,扩展生产更改会运行扩展生产 typecheck 加扩展测试,而扩展仅测试更改只运行扩展测试 typecheck/测试。公共插件 SDK 或 plugin-contract 更改会扩展到扩展验证,因为扩展依赖这些核心契约。仅发布元数据的版本号提升会运行针对性的版本/配置/根依赖检查。未知的根目录/配置更改会以安全优先方式落到所有通道。
|
||||
本地 changed-lane 逻辑位于 `scripts/changed-lanes.mjs`,由 `scripts/check-changed.mjs` 执行。这个本地门禁在架构边界方面比广义的 CI 平台范围更严格:核心生产代码更改会运行 core prod typecheck 加上 core tests,核心仅测试更改只运行 core test typecheck/tests,扩展生产代码更改会运行 extension prod typecheck 加上 extension tests,而扩展仅测试更改只运行 extension test typecheck/tests。公开的插件 SDK 或 plugin-contract 更改会扩大为扩展验证,因为扩展依赖这些核心契约。仅发布元数据的版本号变更会运行有针对性的 version/config/root-dependency 检查。未知的 root/config 更改会以安全优先方式落到所有通道。
|
||||
|
||||
在 push 上,`checks` 矩阵会增加仅 push 的 `compat-node22` 通道。在拉取请求上,该通道会被跳过,矩阵会继续聚焦于常规测试/channel 通道。
|
||||
在 push 上,`checks` 矩阵会增加仅在 push 上运行的 `compat-node22` 通道。在拉取请求上,该通道会被跳过,矩阵仍聚焦于常规的测试/渠道通道。
|
||||
|
||||
最慢的 Node 测试族会被拆分或平衡,以便每个作业都保持较小规模而不额外占用 runner:channel contracts 会作为三个加权分片运行,bundled plugin 测试会在六个扩展 worker 之间平衡,小型核心单元通道会成对组合,auto-reply 会作为三个平衡 worker 运行而不是六个过小的 worker,agentic Gateway 网关/plugin 配置会分布到现有的仅源码 agentic Node 作业中,而不是等待已构建产物。广泛的浏览器、QA、媒体和杂项 plugin 测试会使用各自专用的 Vitest 配置,而不是共享的 plugin 通用兜底配置。扩展分片作业一次最多运行两个 plugin 配置组,每组使用一个 Vitest worker,并配备更大的 Node heap,这样导入开销大的 plugin 批次就不会产生额外的 CI 作业。宽泛的 agents 通道使用共享的 Vitest 文件级并行调度器,因为它主要受导入/调度支配,而不是由某个单独的慢测试文件主导。`runtime-config` 会与 infra core-runtime 分片一起运行,以避免共享运行时分片拖尾。`check-additional` 会将 package-boundary compile/canary 工作保持在一起,并将运行时拓扑架构与 gateway watch 覆盖分开;边界保护分片会在一个作业内部并发运行其较小且彼此独立的保护项。Gateway watch、channel 测试以及核心 support-boundary 分片会在 `build-artifacts` 内部并发运行,此时 `dist/` 和 `dist-runtime/` 已经构建完成,从而在保留原有检查名称作为轻量验证作业的同时,避免额外占用两个 Blacksmith worker 和第二条产物消费者队列。
|
||||
Android CI 会同时运行 `testPlayDebugUnitTest` 和 `testThirdPartyDebugUnitTest`,然后构建 Play debug APK。第三方 flavor 没有单独的源码集或 manifest;它的单元测试通道仍会使用 SMS/通话记录 BuildConfig 标志编译该 flavor,同时避免在每次与 Android 相关的 push 上重复执行 debug APK 打包作业。
|
||||
`extension-fast` 仅用于 PR,因为 push 运行已经会执行完整的 bundled plugin 分片。这样既能为代码审查提供已更改 plugin 的反馈,又不会在 `main` 上额外占用一个 Blacksmith worker 去覆盖 `checks-node-extensions` 中已经存在的内容。
|
||||
最慢的 Node 测试族会被拆分或重新平衡,以便每个作业都保持较小规模而不会过度占用运行器:渠道契约会作为三个加权分片运行,内置插件测试会在六个扩展 worker 之间平衡分配,小型核心单元测试通道会配对执行,自动回复以三个平衡 worker 运行而不是六个很小的 worker,agentic Gateway 网关/插件配置则分散到现有的仅源码 agentic Node 作业中,而不是等待内置产物。广义的浏览器、QA、媒体和杂项插件测试使用它们各自专用的 Vitest 配置,而不是共享的插件兜底配置。扩展分片作业每次最多运行两组插件配置,每组使用一个 Vitest worker,并分配更大的 Node 堆内存,这样导入负载较重的插件批次就不会制造额外的 CI 作业。广义的 agents 通道使用共享的 Vitest 文件并行调度器,因为它的瓶颈主要在导入/调度,而不是某个单独特别慢的测试文件。`runtime-config` 会和 infra core-runtime 分片一起运行,以避免共享运行时分片独自拖尾。`check-additional` 会将 package-boundary compile/canary 工作保持在一起,并把运行时拓扑架构与 gateway watch 覆盖拆开;boundary guard 分片会在一个作业内部并发运行其小型独立守卫。Gateway watch、渠道测试以及 core support-boundary 分片会在 `dist/` 和 `dist-runtime/` 已构建完成后,在 `build-artifacts` 内部并发运行,同时保留它们原有的检查名称作为轻量校验作业,从而避免额外占用两个 Blacksmith worker 和第二条产物消费者队列。
|
||||
Android CI 会同时运行 `testPlayDebugUnitTest` 和 `testThirdPartyDebugUnitTest`,然后构建 Play debug APK。第三方 flavor 没有单独的 source set 或 manifest;它的单元测试通道仍会使用 SMS/call-log `BuildConfig` 标志编译该 flavor,同时避免在每次与 Android 相关的 push 上重复执行 debug APK 打包作业。
|
||||
`extension-fast` 仅在 PR 上运行,因为 push 运行已经会执行完整的内置插件分片。这样既能为代码审查保留已更改插件的反馈,又不会在 `main` 上为 `checks-node-extensions` 已经覆盖的内容额外占用一个 Blacksmith worker。
|
||||
|
||||
当同一个 PR 或 `main` 引用上有新的 push 落地时,GitHub 可能会将被替代的作业标记为 `cancelled`。除非同一引用的最新运行也失败,否则应将其视为 CI 噪声。聚合分片检查使用 `!cancelled() && always()`,因此它们仍会正常报告分片失败,但不会在整个工作流已经被替代后继续排队。
|
||||
CI 并发键是带版本号的(`CI-v7-*`),这样 GitHub 侧旧队列组中的僵尸任务就不会无限期阻塞较新的 `main` 运行。
|
||||
当同一个 PR 或 `main` 引用上有新的 push 落地时,GitHub 可能会将被取代的作业标记为 `cancelled`。除非同一引用上的最新运行也在失败,否则应将其视为 CI 噪声。聚合分片检查使用 `!cancelled() && always()`,因此它们仍会报告正常的分片失败,但不会在整个工作流已经被更新运行取代后继续排队。
|
||||
CI 并发键采用带版本号的形式(`CI-v7-*`),这样 GitHub 端旧队列组中的僵尸任务就不会无限期阻塞更新的 main 运行。
|
||||
|
||||
## Runner
|
||||
## 运行器
|
||||
|
||||
| Runner | 作业 |
|
||||
| 运行器 | 作业 |
|
||||
| -------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `ubuntu-24.04` | `preflight`、快速安全作业及聚合(`security-scm-fast`、`security-dependency-audit`、`security-fast`)、快速 protocol/contract/bundled 检查、分片的 channel contract 检查、除 lint 之外的 `check` 分片、`check-additional` 分片及聚合、Node 测试聚合验证器、文档检查、Python Skills、workflow-sanity、labeler、auto-response;`install-smoke` preflight 也使用 GitHub 托管 Ubuntu,这样 Blacksmith 矩阵就能更早排队 |
|
||||
| `blacksmith-8vcpu-ubuntu-2404` | `build-artifacts`、build-smoke、Linux Node 测试分片、bundled plugin 测试分片、`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`)、快速 protocol/contract/bundled 检查、分片渠道契约检查、除 lint 外的 `check` 分片、`check-additional` 分片和聚合项、Node 测试聚合校验器、文档检查、Python Skills、workflow-sanity、labeler、auto-response;install-smoke preflight 也使用 GitHub 托管的 Ubuntu,这样 Blacksmith 矩阵可以更早开始排队 |
|
||||
| `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 # 检查 origin/main...HEAD 的本地 changed-lane 分类器
|
||||
pnpm check:changed # 智能本地门控:按边界通道运行变更相关的 typecheck/lint/测试
|
||||
pnpm check # 快速本地门控:生产 tsgo + 分片 lint + 并行快速 guards
|
||||
pnpm changed:lanes # 检查针对 origin/main...HEAD 的本地 changed-lane 分类器
|
||||
pnpm check:changed # 智能本地门禁:按边界通道运行变更相关的 typecheck/lint/tests
|
||||
pnpm check # 快速本地门禁:生产 tsgo + 分片 lint + 并行快速守卫
|
||||
pnpm check:test-types
|
||||
pnpm check:timed # 相同门控,但带每个阶段的耗时统计
|
||||
pnpm check:timed # 同样的门禁,但附带各阶段耗时
|
||||
pnpm build:strict-smoke
|
||||
pnpm check:architecture
|
||||
pnpm test:gateway:watch-regression
|
||||
@ -107,9 +107,9 @@ pnpm test # vitest 测试
|
||||
pnpm test:channels
|
||||
pnpm test:contracts:channels
|
||||
pnpm check:docs # 文档格式 + lint + 失效链接
|
||||
pnpm build # 当 CI 产物/build-smoke 通道相关时,构建 dist
|
||||
node scripts/ci-run-timings.mjs <run-id> # 汇总总耗时、排队时间和最慢作业
|
||||
node scripts/ci-run-timings.mjs --recent 10 # 比较最近成功的 `main` CI 运行
|
||||
pnpm build # 当 CI 的 artifact/build-smoke 通道相关时构建 dist
|
||||
node scripts/ci-run-timings.mjs <run-id> # 汇总总耗时、排队耗时和最慢的作业
|
||||
node scripts/ci-run-timings.mjs --recent 10 # 对比最近成功的 main CI 运行
|
||||
pnpm test:perf:groups --full-suite --allow-failures --output .artifacts/test-perf/baseline-before.json
|
||||
pnpm test:perf:groups:compare .artifacts/test-perf/baseline-before.json .artifacts/test-perf/after-agent.json
|
||||
```
|
||||
@ -117,4 +117,4 @@ pnpm test:perf:groups:compare .artifacts/test-perf/baseline-before.json .artifac
|
||||
## 相关内容
|
||||
|
||||
- [安装概览](/zh-CN/install)
|
||||
- [发布渠道](/zh-CN/install/development-channels)
|
||||
- [发布通道](/zh-CN/install/development-channels)
|
||||
|
||||
@ -1,35 +1,35 @@
|
||||
---
|
||||
read_when:
|
||||
- 在本地或 CI 中运行测试
|
||||
- 为模型 / 提供商缺陷添加回归测试
|
||||
- 为模型/提供商缺陷添加回归测试
|
||||
- 调试 Gateway 网关 + 智能体行为
|
||||
summary: 测试工具包:单元 / e2e / 实时测试套件、Docker 运行器,以及每类测试覆盖的内容
|
||||
summary: 测试工具包:unit/e2e/live 测试套件、Docker 运行器,以及每项测试涵盖的内容
|
||||
title: 测试
|
||||
x-i18n:
|
||||
generated_at: "2026-04-24T19:56:43Z"
|
||||
generated_at: "2026-04-24T23:09:47Z"
|
||||
model: gpt-5.4
|
||||
provider: openai
|
||||
source_hash: 437a49f67b775f63670f00efec63e268e02e74e072d92a645d427b975028e8be
|
||||
source_hash: d8d70027f15c4e12198d6e8fa8cb74086c30dd405d6681d78ecb811bd448e838
|
||||
source_path: help/testing.md
|
||||
workflow: 15
|
||||
---
|
||||
|
||||
OpenClaw 有三个 Vitest 测试套件(单元 / 集成、e2e、实时),以及一小组 Docker 运行器。本文档是一份“我们如何测试”的指南:
|
||||
OpenClaw 有三个 Vitest 测试套件(unit/integration、e2e、live)以及一小组 Docker 运行器。本文档是一份“我们如何测试”的指南:
|
||||
|
||||
- 每个测试套件覆盖什么(以及它**有意不**覆盖什么)。
|
||||
- 常见工作流应运行哪些命令(本地、推送前、调试)。
|
||||
- 实时测试如何发现凭证并选择模型 / 提供商。
|
||||
- 如何为真实世界中的模型 / 提供商问题添加回归测试。
|
||||
- 每个测试套件涵盖什么内容(以及它明确 _不_ 涵盖什么)。
|
||||
- 常见工作流(本地、推送前、调试)应运行哪些命令。
|
||||
- live 测试如何发现凭证并选择模型/提供商。
|
||||
- 如何为真实世界中的模型/提供商问题添加回归测试。
|
||||
|
||||
## 快速开始
|
||||
|
||||
大多数情况下:
|
||||
大多数时候:
|
||||
|
||||
- 完整门禁(预期应在推送前运行):`pnpm build && pnpm check && pnpm check:test-types && pnpm test`
|
||||
- 在配置较好的机器上更快地运行本地完整测试套件:`pnpm test:max`
|
||||
- 直接进入 Vitest 监听循环:`pnpm test:watch`
|
||||
- 直接按文件定位现在也支持 extension / channel 路径:`pnpm test extensions/discord/src/monitor/message-handler.preflight.test.ts`
|
||||
- 当你在迭代单个失败用例时,优先使用定向运行。
|
||||
- 完整门禁(推送前的预期要求):`pnpm build && pnpm check && pnpm check:test-types && pnpm test`
|
||||
- 在配置充足的机器上更快地运行本地全套测试:`pnpm test:max`
|
||||
- 直接进入 Vitest watch 循环:`pnpm test:watch`
|
||||
- 现在直接按文件定位也会路由 `extension/channel` 路径:`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`
|
||||
|
||||
@ -38,112 +38,90 @@ OpenClaw 有三个 Vitest 测试套件(单元 / 集成、e2e、实时),以
|
||||
- 覆盖率门禁:`pnpm test:coverage`
|
||||
- E2E 测试套件:`pnpm test:e2e`
|
||||
|
||||
当调试真实提供商 / 模型时(需要真实凭证):
|
||||
当你在调试真实提供商/模型时(需要真实凭证):
|
||||
|
||||
- 实时测试套件(模型 + 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` 禁用这些额外探测。
|
||||
- CI 覆盖:每日的 `OpenClaw Scheduled Live And E2E Checks` 和手动的
|
||||
`OpenClaw Release Checks` 都会调用可复用的实时 / E2E 工作流,并设置
|
||||
`include_live_suites: true`,其中包含按提供商分片的独立 Docker 实时模型
|
||||
矩阵作业。
|
||||
- 如需聚焦的 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` 和其
|
||||
scheduled / release 调用方中。
|
||||
- live 测试套件(模型 + Gateway 网关 工具/图像探测):`pnpm test:live`
|
||||
- 安静地只运行一个 live 文件:`pnpm test:live -- src/agents/models.profiles.live.test.ts`
|
||||
- Docker live 模型扫描:`pnpm test:docker:live-models`
|
||||
- 现在每个选中的模型都会运行一次文本轮次外加一次小型文件读取式探测。元数据声明支持 `image` 输入的模型还会运行一次微型图像轮次。在隔离提供商故障时,可通过 `OPENCLAW_LIVE_MODEL_FILE_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 模型矩阵作业。
|
||||
- 对于聚焦型 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 实时通道,使用 `/codex bind`
|
||||
绑定一个合成的 Slack 私信,会执行 `/codex fast` 和
|
||||
`/codex permissions`,然后验证普通回复和图像附件是通过原生插件绑定路由,
|
||||
而不是通过 ACP。
|
||||
- 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`。
|
||||
- 在 Codex app-server 路径上运行一条 Docker live 通道,使用 `/codex bind` 绑定一个合成的 Slack 私信,执行 `/codex fast` 和 `/codex permissions`,然后验证普通回复和图像附件都通过原生插件绑定路由,而不是 ACP。
|
||||
- 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,并且 assistant transcript 存储了已归一化的 `usage.cost`。
|
||||
|
||||
提示:当你只需要一个失败用例时,优先使用下面描述的 allowlist 环境变量来收窄实时测试范围。
|
||||
提示:当你只需要一个失败用例时,优先通过下面介绍的 allowlist 环境变量来收窄 live 测试范围。
|
||||
|
||||
## QA 专用运行器
|
||||
|
||||
当你需要 QA-lab 级别的真实性时,这些命令与主测试套件并列使用:
|
||||
当你需要 QA-lab 的真实环境时,这些命令与主测试套件并列使用:
|
||||
|
||||
CI 会在专用工作流中运行 QA Lab。`Parity gate` 会在匹配的 PR 上运行,
|
||||
也可通过手动触发配合 mock 提供商运行。`QA-Lab - All Lanes` 会在 `main`
|
||||
上每夜运行,也可通过手动触发运行,其中包含 mock parity gate、实时 Matrix 通道以及由 Convex 管理的实时 Telegram 通道,作为并行作业。`OpenClaw Release Checks`
|
||||
会在发布批准前运行相同的通道。
|
||||
CI 会在专用工作流中运行 QA Lab。`Parity gate` 会在匹配的 PR 上运行,也可通过带 mock 提供商的手动触发运行。`QA-Lab - All Lanes` 会在 `main` 上每晚运行,也可通过手动触发运行,包含 mock parity gate、live Matrix 通道以及由 Convex 管理的 live Telegram 通道,作为并行作业执行。`OpenClaw Release Checks` 会在发布审批前运行相同的通道。
|
||||
|
||||
- `pnpm openclaw qa suite`
|
||||
- 直接在宿主机上运行基于仓库的 QA 场景。
|
||||
- 默认并行运行多个选定场景,并使用隔离的 Gateway 网关 worker。`qa-channel` 默认并发数为 4(受所选场景数量限制)。使用 `--concurrency <count>` 调整 worker 数量,或使用 `--concurrency 1` 运行旧式串行通道。
|
||||
- 任一场景失败时会以非零状态退出。若你想保留产物但不希望以失败退出码结束,可使用 `--allow-failures`。
|
||||
- 直接在主机上运行基于仓库的 QA 场景。
|
||||
- 默认情况下,会使用隔离的 Gateway 网关 worker 并行运行多个选定场景。`qa-channel` 默认并发度为 4(受所选场景数量限制)。使用 `--concurrency <count>` 调整 worker 数量,或使用 `--concurrency 1` 运行旧的串行通道。
|
||||
- 当任一场景失败时,以非零状态退出。若你希望保留产物而不返回失败退出码,请使用 `--allow-failures`。
|
||||
- 支持提供商模式 `live-frontier`、`mock-openai` 和 `aimock`。
|
||||
`aimock` 会启动一个本地的 AIMock 支持的提供商服务器,用于实验性的 fixture 和协议 mock 覆盖,而不会替代具备场景感知能力的 `mock-openai` 通道。
|
||||
`aimock` 会启动一个基于本地 AIMock 的提供商服务器,用于实验性的 fixture 和协议 mock 覆盖,而不会替代具备场景感知能力的 `mock-openai` 通道。
|
||||
- `pnpm openclaw qa suite --runner multipass`
|
||||
- 在一次性的 Multipass Linux VM 中运行相同的 QA 测试套件。
|
||||
- 与宿主机上的 `qa suite` 保持相同的场景选择行为。
|
||||
- 复用与 `qa suite` 相同的提供商 / 模型选择标志。
|
||||
- 实时运行会向访客系统转发支持的、适合访客使用的 QA 认证输入:
|
||||
基于环境变量的提供商密钥、QA 实时提供商配置路径,以及存在时的 `CODEX_HOME`。
|
||||
- 输出目录必须保持在仓库根目录下,以便访客可通过挂载的工作区回写。
|
||||
- 会在 `.artifacts/qa-e2e/...` 下写入常规 QA 报告 + 摘要以及 Multipass 日志。
|
||||
- 在一次性的 Multipass Linux VM 中运行同一套 QA 测试。
|
||||
- 保持与主机上 `qa suite` 相同的场景选择行为。
|
||||
- 复用与 `qa suite` 相同的提供商/模型选择标志。
|
||||
- live 运行会转发适合访客环境使用的受支持 QA 认证输入:基于环境变量的提供商密钥、QA live provider 配置路径,以及存在时的 `CODEX_HOME`。
|
||||
- 输出目录必须位于仓库根目录下,以便访客环境可通过挂载的工作区回写内容。
|
||||
- 会在 `.artifacts/qa-e2e/...` 下写入常规 QA 报告、摘要以及 Multipass 日志。
|
||||
- `pnpm qa:lab:up`
|
||||
- 启动基于 Docker 的 QA 站点,用于操作员风格的 QA 工作。
|
||||
- 启动基于 Docker 的 QA 站点,用于偏操作员风格的 QA 工作。
|
||||
- `pnpm test:docker:npm-onboard-channel-agent`
|
||||
- 从当前 checkout 构建一个 npm tarball,在 Docker 中全局安装,以非交互方式运行 OpenAI API key 新手引导,默认配置 Telegram,验证启用该插件时会按需安装运行时依赖,运行 doctor,然后对一个模拟的 OpenAI 端点执行一次本地智能体轮次。
|
||||
- 使用 `OPENCLAW_NPM_ONBOARD_CHANNEL=discord` 可在 Discord 下运行同样的打包安装通道。
|
||||
- 从当前检出构建一个 npm tarball,在 Docker 中全局安装,执行非交互式 OpenAI API 密钥新手引导,默认配置 Telegram,验证启用插件时会按需安装运行时依赖,运行 doctor,并针对一个模拟的 OpenAI 端点运行一次本地智能体轮次。
|
||||
- 使用 `OPENCLAW_NPM_ONBOARD_CHANNEL=discord` 可在 Discord 上运行同一条打包安装通道。
|
||||
- `pnpm test:docker:npm-telegram-live`
|
||||
- 在 Docker 中安装一个已发布的 OpenClaw 包,运行已安装包的新手引导,通过已安装的 CLI 配置 Telegram,然后复用实时 Telegram QA 通道,将该已安装包作为 SUT Gateway 网关。
|
||||
- 默认值为 `OPENCLAW_NPM_TELEGRAM_PACKAGE_SPEC=openclaw@beta`。
|
||||
- 使用与 `pnpm openclaw qa telegram` 相同的 Telegram 环境变量凭证或 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 凭证租约。
|
||||
- 在 Docker 中安装一个已发布的 OpenClaw 包,运行已安装包的新手引导,通过已安装的 CLI 配置 Telegram,然后复用 live Telegram QA 通道,并将该已安装包作为被测系统的 Gateway 网关。
|
||||
- 默认使用 `OPENCLAW_NPM_TELEGRAM_PACKAGE_SPEC=openclaw@beta`。
|
||||
- 使用与 `pnpm openclaw qa telegram` 相同的 Telegram 环境变量凭证或 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 凭证租约。
|
||||
- `pnpm test:docker:bundled-channel-deps`
|
||||
- 在 Docker 中打包并安装当前 OpenClaw 构建产物,配置 OpenAI 后启动 Gateway 网关,然后通过编辑配置启用内置 channel / plugins。
|
||||
- 验证 setup discovery 会让未配置的插件运行时依赖保持缺失状态,首次配置的 Gateway 网关或 doctor 运行时会按需安装每个内置插件的运行时依赖,而第二次重启不会重新安装已激活的依赖。
|
||||
- 还会安装一个已知的较旧 npm 基线,在运行 `openclaw update --tag <candidate>` 之前启用 Telegram,并验证候选版本的更新后 doctor 会修复内置 channel 运行时依赖,而无需由 harness 侧执行更新后修复。
|
||||
- 在 Docker 中打包并安装当前 OpenClaw 构建,启动已配置 OpenAI 的 Gateway 网关,然后通过编辑配置启用内置的渠道插件。
|
||||
- 验证设置发现流程不会提前安装未配置插件的运行时依赖;首次已配置的 Gateway 网关 或 doctor 运行时,会按需安装每个内置插件的运行时依赖;第二次重启时,不会重新安装已经激活的依赖。
|
||||
- 还会安装一个已知较旧的 npm 基线,在运行 `openclaw update --tag <candidate>` 前启用 Telegram,并验证候选版本的更新后 doctor 会修复内置渠道运行时依赖,而无需由 harness 侧执行 postinstall 修复。
|
||||
- `pnpm openclaw qa aimock`
|
||||
- 仅启动本地 AIMock 提供商服务器,用于直接协议冒烟测试。
|
||||
- `pnpm openclaw qa matrix`
|
||||
- 针对一次性的、基于 Docker 的 Tuwunel homeserver 运行 Matrix 实时 QA 通道。
|
||||
- 此 QA 宿主当前仅供仓库 / 开发使用。打包后的 OpenClaw 安装不附带 `qa-lab`,因此不会暴露 `openclaw qa`。
|
||||
- 仓库 checkout 会直接加载内置运行器;无需单独安装插件。
|
||||
- 会配置三个临时 Matrix 用户(`driver`、`sut`、`observer`)以及一个私有房间,然后启动一个以真实 Matrix 插件作为 SUT 传输层的 QA gateway 子进程。
|
||||
- 默认使用固定稳定版 Tuwunel 镜像 `ghcr.io/matrix-construct/tuwunel:v1.5.1`。如需测试其他镜像,可通过 `OPENCLAW_QA_MATRIX_TUWUNEL_IMAGE` 覆盖。
|
||||
- Matrix 不提供共享凭证源标志,因为该通道会在本地配置一次性用户。
|
||||
- 会在 `.artifacts/qa-e2e/...` 下写入 Matrix QA 报告、摘要、observed-events 产物以及合并后的 stdout / stderr 输出日志。
|
||||
- 默认会输出进度,并通过 `OPENCLAW_QA_MATRIX_TIMEOUT_MS` 强制执行硬性运行超时(默认 30 分钟)。清理由 `OPENCLAW_QA_MATRIX_CLEANUP_TIMEOUT_MS` 限定,失败信息中会包含恢复命令 `docker compose ... down --remove-orphans`。
|
||||
- 针对一个一次性的、基于 Docker 的 Tuwunel homeserver 运行 Matrix live QA 通道。
|
||||
- 该 QA 主机目前仅供仓库/开发使用。打包安装的 OpenClaw 不包含 `qa-lab`,因此不会暴露 `openclaw qa`。
|
||||
- 仓库检出会直接加载内置运行器;不需要单独安装插件。
|
||||
- 会预配三个临时 Matrix 用户(`driver`、`sut`、`observer`)和一个私有房间,然后以真实 Matrix 插件作为被测传输层启动一个 QA gateway 子进程。
|
||||
- 默认使用固定的稳定 Tuwunel 镜像 `ghcr.io/matrix-construct/tuwunel:v1.5.1`。当你需要测试其他镜像时,可使用 `OPENCLAW_QA_MATRIX_TUWUNEL_IMAGE` 覆盖。
|
||||
- 由于该通道会在本地预配一次性用户,Matrix 不暴露共享的凭证源标志。
|
||||
- 会在 `.artifacts/qa-e2e/...` 下写入 Matrix QA 报告、摘要、observed-events 产物以及合并的 stdout/stderr 输出日志。
|
||||
- 默认输出进度,并通过 `OPENCLAW_QA_MATRIX_TIMEOUT_MS`(默认 30 分钟)强制设置硬性运行超时。清理由 `OPENCLAW_QA_MATRIX_CLEANUP_TIMEOUT_MS` 限定,失败时会包含恢复命令 `docker compose ... down --remove-orphans`。
|
||||
- `pnpm openclaw qa telegram`
|
||||
- 使用环境变量中的 driver 和 SUT bot token,针对一个真实私有群组运行 Telegram 实时 QA 通道。
|
||||
- 针对一个真实的私有群组运行 Telegram live QA 通道,使用来自环境变量的 driver 和 SUT bot token。
|
||||
- 需要 `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` 以启用池化租约。
|
||||
- 任一场景失败时会以非零状态退出。若你想保留产物但不希望以失败退出码结束,可使用 `--allow-failures`。
|
||||
- 需要同一私有群组中的两个不同 bot,且 SUT bot 必须暴露 Telegram 用户名。
|
||||
- 为了稳定观察 bot 与 bot 之间的行为,请在 `@BotFather` 中为两个 bot 启用 Bot-to-Bot Communication Mode,并确保 driver bot 可以观察群组中的 bot 流量。
|
||||
- 会在 `.artifacts/qa-e2e/...` 下写入 Telegram QA 报告、摘要和 observed-messages 产物。回复场景会包含从 driver 发送请求到观察到 SUT 回复的 RTT。
|
||||
- 支持 `--credential-source convex` 以使用共享的池化凭证。默认使用环境变量模式,或设置 `OPENCLAW_QA_CREDENTIAL_SOURCE=convex` 以启用池化租约。
|
||||
- 当任一场景失败时,以非零状态退出。若你希望保留产物而不返回失败退出码,请使用 `--allow-failures`。
|
||||
- 需要同一私有群组中的两个不同 bot,且 SUT bot 必须公开 Telegram 用户名。
|
||||
- 为了实现稳定的 bot 对 bot 观察,请在 `@BotFather` 中为两个 bot 启用 Bot-to-Bot Communication Mode,并确保 driver bot 可以观察群组中的 bot 流量。
|
||||
- 会在 `.artifacts/qa-e2e/...` 下写入 Telegram QA 报告、摘要和 observed-messages 产物。回复类场景会包含从 driver 发送请求到观察到 SUT 回复的 RTT。
|
||||
|
||||
实时传输通道共享一个标准约定,因此新传输方式不会发生漂移:
|
||||
live 传输通道共享一份标准契约,以防止新传输逐渐偏离:
|
||||
|
||||
`qa-channel` 仍然是广泛的合成 QA 测试套件,不属于实时传输覆盖矩阵的一部分。
|
||||
`qa-channel` 仍然是更广泛的合成 QA 测试套件,不属于 live 传输覆盖矩阵的一部分。
|
||||
|
||||
| 通道 | Canary | 提及门控 | Allowlist 拦截 | 顶层回复 | 重启恢复 | 线程跟进 | 线程隔离 | Reaction 观察 | 帮助命令 |
|
||||
| ---- | ------ | -------- | -------------- | -------- | -------- | -------- | -------- | --------------- | -------- |
|
||||
| Matrix | x | x | x | x | x | x | x | x | |
|
||||
| Telegram | x | | | | | | | | x |
|
||||
| 通道 | Canary | 提及门控 | allowlist 阻止 | 顶层回复 | 重启恢复 | 线程跟进 | 线程隔离 | 反应观察 | 帮助命令 |
|
||||
| ---- | ------ | -------- | -------------- | -------- | -------- | -------- | -------- | -------- | -------- |
|
||||
| Matrix | x | x | x | x | x | x | x | x | |
|
||||
| Telegram | x | | | | | | | | x |
|
||||
|
||||
### 通过 Convex 共享 Telegram 凭证(v1)
|
||||
|
||||
当为 `openclaw qa telegram` 启用 `--credential-source convex`(或 `OPENCLAW_QA_CREDENTIAL_SOURCE=convex`)时,QA lab 会从一个由 Convex 支持的池中获取独占租约,在该通道运行期间对该租约发送心跳,并在关闭时释放租约。
|
||||
当为 `openclaw qa telegram` 启用 `--credential-source convex`(或 `OPENCLAW_QA_CREDENTIAL_SOURCE=convex`)时,QA lab 会从一个由 Convex 支持的凭证池获取独占租约,在该通道运行期间保持该租约的心跳,并在关闭时释放租约。
|
||||
|
||||
参考的 Convex 项目脚手架:
|
||||
参考用的 Convex 项目脚手架:
|
||||
|
||||
- `qa/convex-credential-broker/`
|
||||
|
||||
@ -155,7 +133,7 @@ CI 会在专用工作流中运行 QA Lab。`Parity gate` 会在匹配的 PR 上
|
||||
- `OPENCLAW_QA_CONVEX_SECRET_CI` 对应 `ci`
|
||||
- 凭证角色选择:
|
||||
- CLI:`--credential-role maintainer|ci`
|
||||
- 环境变量默认值:`OPENCLAW_QA_CREDENTIAL_ROLE`(在 CI 中默认为 `ci`,否则为 `maintainer`)
|
||||
- 默认环境变量:`OPENCLAW_QA_CREDENTIAL_ROLE`(在 CI 中默认是 `ci`,否则是 `maintainer`)
|
||||
|
||||
可选环境变量:
|
||||
|
||||
@ -169,10 +147,10 @@ CI 会在专用工作流中运行 QA Lab。`Parity gate` 会在匹配的 PR 上
|
||||
|
||||
`OPENCLAW_QA_CONVEX_SITE_URL` 在正常运行中应使用 `https://`。
|
||||
|
||||
维护者管理员命令(池添加 / 移除 / 列表)需要专门使用
|
||||
维护者管理命令(池添加/移除/列出)必须特别使用
|
||||
`OPENCLAW_QA_CONVEX_SECRET_MAINTAINER`。
|
||||
|
||||
面向维护者的 CLI 辅助命令:
|
||||
供维护者使用的 CLI 辅助命令:
|
||||
|
||||
```bash
|
||||
pnpm openclaw qa credentials doctor
|
||||
@ -181,89 +159,89 @@ pnpm openclaw qa credentials list --kind telegram
|
||||
pnpm openclaw qa credentials remove --credential-id <credential-id>
|
||||
```
|
||||
|
||||
在实时运行前使用 `doctor`,可检查 Convex 站点 URL、broker 密钥、
|
||||
端点前缀、HTTP 超时,以及管理员 / 列表可达性,同时不会打印密钥值。
|
||||
在脚本和 CI 工具中使用 `--json` 可获得机器可读输出。
|
||||
在 live 运行之前使用 `doctor`,可检查 Convex site URL、broker 密钥、
|
||||
端点前缀、HTTP 超时,以及管理/列表可达性,同时不会打印
|
||||
密钥值。在脚本和 CI 工具中使用 `--json` 可获得机器可读输出。
|
||||
|
||||
默认端点约定(`OPENCLAW_QA_CONVEX_SITE_URL` + `/qa-credentials/v1`):
|
||||
默认端点契约(`OPENCLAW_QA_CONVEX_SITE_URL` + `/qa-credentials/v1`):
|
||||
|
||||
- `POST /acquire`
|
||||
- 请求:`{ kind, ownerId, actorRole, leaseTtlMs, heartbeatIntervalMs }`
|
||||
- 成功:`{ status: "ok", credentialId, leaseToken, payload, leaseTtlMs?, heartbeatIntervalMs? }`
|
||||
- 池耗尽 / 可重试:`{ status: "error", code: "POOL_EXHAUSTED" | "NO_CREDENTIAL_AVAILABLE", ... }`
|
||||
- 资源耗尽/可重试:`{ status: "error", code: "POOL_EXHAUSTED" | "NO_CREDENTIAL_AVAILABLE", ... }`
|
||||
- `POST /heartbeat`
|
||||
- 请求:`{ kind, ownerId, actorRole, credentialId, leaseToken, leaseTtlMs }`
|
||||
- 成功:`{ status: "ok" }`(或空的 `2xx`)
|
||||
- `POST /release`
|
||||
- 请求:`{ kind, ownerId, actorRole, credentialId, leaseToken }`
|
||||
- 成功:`{ status: "ok" }`(或空的 `2xx`)
|
||||
- `POST /admin/add`(仅限 maintainer 密钥)
|
||||
- `POST /admin/add`(仅维护者密钥)
|
||||
- 请求:`{ kind, actorId, payload, note?, status? }`
|
||||
- 成功:`{ status: "ok", credential }`
|
||||
- `POST /admin/remove`(仅限 maintainer 密钥)
|
||||
- `POST /admin/remove`(仅维护者密钥)
|
||||
- 请求:`{ credentialId, actorId }`
|
||||
- 成功:`{ status: "ok", changed, credential }`
|
||||
- 活动租约保护:`{ status: "error", code: "LEASE_ACTIVE", ... }`
|
||||
- `POST /admin/list`(仅限 maintainer 密钥)
|
||||
- 活跃租约保护:`{ status: "error", code: "LEASE_ACTIVE", ... }`
|
||||
- `POST /admin/list`(仅维护者密钥)
|
||||
- 请求:`{ kind?, status?, includePayload?, limit? }`
|
||||
- 成功:`{ status: "ok", credentials, count }`
|
||||
|
||||
Telegram 类型的负载结构:
|
||||
Telegram 类型的 payload 结构:
|
||||
|
||||
- `{ groupId: string, driverToken: string, sutToken: string }`
|
||||
- `groupId` 必须是 Telegram chat id 的数字字符串。
|
||||
- `admin/add` 会对 `kind: "telegram"` 验证此结构,并拒绝格式错误的负载。
|
||||
- `admin/add` 会对 `kind: "telegram"` 的该结构进行校验,并拒绝格式错误的 payload。
|
||||
|
||||
### 向 QA 添加一个渠道
|
||||
|
||||
向 Markdown QA 系统添加一个渠道只需要**严格两个**东西:
|
||||
向 Markdown QA 系统添加一个渠道严格只需要两样东西:
|
||||
|
||||
1. 该渠道的传输适配器。
|
||||
2. 用于验证该渠道约定的场景包。
|
||||
2. 一个用于验证渠道契约的场景包。
|
||||
|
||||
当共享的 `qa-lab` 宿主可以负责整个流程时,不要新增顶层 QA 命令根。
|
||||
当共享的 `qa-lab` 主机可以负责该流程时,不要新增顶层 QA 命令根。
|
||||
|
||||
`qa-lab` 负责共享宿主机制:
|
||||
`qa-lab` 负责共享主机机制:
|
||||
|
||||
- `openclaw qa` 命令根
|
||||
- 测试套件启动和清理
|
||||
- 测试套件启动与拆除
|
||||
- worker 并发
|
||||
- 产物写入
|
||||
- 报告生成
|
||||
- 场景执行
|
||||
- 对旧版 `qa-channel` 场景的兼容别名
|
||||
|
||||
运行器插件负责传输约定:
|
||||
运行器插件负责传输契约:
|
||||
|
||||
- `openclaw qa <runner>` 如何挂载到共享的 `qa` 根命令之下
|
||||
- `openclaw qa <runner>` 如何挂载在共享的 `qa` 根命令下
|
||||
- 如何为该传输配置 Gateway 网关
|
||||
- 如何检查就绪状态
|
||||
- 如何注入入站事件
|
||||
- 如何观察出站消息
|
||||
- 如何暴露转录和标准化的传输状态
|
||||
- 如何暴露 transcript 和归一化后的传输状态
|
||||
- 如何执行由传输支持的操作
|
||||
- 如何处理传输特定的重置或清理
|
||||
|
||||
新渠道的最低接入门槛是:
|
||||
|
||||
1. 保持由 `qa-lab` 负责共享 `qa` 根命令。
|
||||
2. 在共享的 `qa-lab` 宿主接缝上实现传输运行器。
|
||||
1. 保持由 `qa-lab` 作为共享 `qa` 根的所有者。
|
||||
2. 在共享的 `qa-lab` 主机接缝上实现传输运行器。
|
||||
3. 将传输特定机制保留在运行器插件或渠道 harness 内部。
|
||||
4. 将运行器挂载为 `openclaw qa <runner>`,而不是注册一个竞争性的根命令。
|
||||
运行器插件应在 `openclaw.plugin.json` 中声明 `qaRunners`,并从 `runtime-api.ts` 导出匹配的 `qaRunnerCliRegistrations` 数组。
|
||||
保持 `runtime-api.ts` 轻量;延迟 CLI 和运行器执行应保留在独立入口点之后。
|
||||
5. 在按主题组织的 `qa/scenarios/` 目录下编写或改造 Markdown 场景。
|
||||
保持 `runtime-api.ts` 轻量;延迟 CLI 和运行器执行应位于单独的入口点之后。
|
||||
5. 在带主题的 `qa/scenarios/` 目录下编写或改造 Markdown 场景。
|
||||
6. 为新场景使用通用场景辅助函数。
|
||||
7. 除非仓库正在进行有意迁移,否则要保持现有兼容别名继续可用。
|
||||
7. 除非仓库正在进行有意迁移,否则保持现有兼容别名继续可用。
|
||||
|
||||
决策规则是严格的:
|
||||
|
||||
- 如果某种行为可以在 `qa-lab` 中统一表达一次,就放到 `qa-lab`。
|
||||
- 如果某种行为依赖于某一个渠道传输,就将其保留在该运行器插件或插件 harness 中。
|
||||
- 如果某个场景需要一种可被多个渠道复用的新能力,请添加通用辅助函数,而不是在 `suite.ts` 中增加渠道特定分支。
|
||||
- 如果某种行为只对一个传输有意义,就让该场景保持传输特定,并在场景约定中明确说明。
|
||||
- 如果某个行为可以在 `qa-lab` 中统一表达一次,就把它放在 `qa-lab`。
|
||||
- 如果某个行为依赖单一渠道传输,就把它保留在该运行器插件或插件 harness 中。
|
||||
- 如果某个场景需要一个可供多个渠道使用的新能力,应添加通用辅助函数,而不是在 `suite.ts` 中添加渠道特定分支。
|
||||
- 如果某个行为仅对一种传输有意义,就让该场景保持传输特定性,并在场景契约中明确说明。
|
||||
|
||||
新场景推荐使用的通用辅助函数名称:
|
||||
新场景首选的通用辅助函数名称是:
|
||||
|
||||
- `waitForTransportReady`
|
||||
- `waitForChannelReady`
|
||||
@ -287,73 +265,73 @@ Telegram 类型的负载结构:
|
||||
- `resetBus`
|
||||
|
||||
新的渠道工作应使用通用辅助函数名称。
|
||||
兼容别名的存在是为了避免一次性全面迁移,而不是作为新场景编写的范式。
|
||||
兼容别名的存在是为了避免一次性迁移,而不是作为
|
||||
新场景编写的范式。
|
||||
|
||||
## 测试套件(各自在哪里运行)
|
||||
## 测试套件(各自运行位置)
|
||||
|
||||
可以把这些测试套件理解为“真实性逐步提高”(同时脆弱性 / 成本也逐步增加):
|
||||
可以将这些测试套件理解为“真实度逐步提高”(同时不稳定性/成本也逐步提高):
|
||||
|
||||
### 单元 / 集成(默认)
|
||||
### Unit / integration(默认)
|
||||
|
||||
- 命令:`pnpm test`
|
||||
- 配置:未定向运行使用 `vitest.full-*.config.ts` 分片集,并且可能将多项目分片扩展为按项目拆分的配置,以便并行调度
|
||||
- 文件:核心 / 单元清单位于 `src/**/*.test.ts`、`packages/**/*.test.ts`、`test/**/*.test.ts`,以及由 `vitest.unit.config.ts` 覆盖的白名单 `ui` Node 测试
|
||||
- 配置:未定向运行使用 `vitest.full-*.config.ts` 分片集,并且可能会将多项目分片展开为按项目划分的配置,以便并行调度
|
||||
- 文件:核心/unit 清单位于 `src/**/*.test.ts`、`packages/**/*.test.ts`、`test/**/*.test.ts`,以及 `vitest.unit.config.ts` 覆盖的白名单 `ui` Node 测试
|
||||
- 范围:
|
||||
- 纯单元测试
|
||||
- 进程内集成测试(Gateway 网关认证、路由、工具、解析、配置)
|
||||
- 进程内集成测试(Gateway 网关 认证、路由、工具、解析、配置)
|
||||
- 针对已知缺陷的确定性回归测试
|
||||
- 期望:
|
||||
- 预期:
|
||||
- 在 CI 中运行
|
||||
- 不需要真实密钥
|
||||
- 应该快速且稳定
|
||||
|
||||
<AccordionGroup>
|
||||
<Accordion title="项目、分片和作用域通道">
|
||||
<Accordion title="项目、分片和定向通道">
|
||||
|
||||
- 未定向的 `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` 可以避免承担完整根项目启动成本。
|
||||
- 当变更的 git 路径只涉及可路由的源码 / 测试文件时,`pnpm test:changed` 会将这些路径扩展到相同的作用域通道;配置 / setup 编辑仍会回退到广泛的根项目重跑。
|
||||
- `pnpm check:changed` 是窄范围工作时的常规智能本地门禁。它会将 diff 分类为 core、core tests、extensions、extension tests、apps、docs、release metadata 和 tooling,然后运行匹配的 typecheck / lint / test 通道。公共插件 SDK 和插件约定变更会额外包含一次 extension 验证,因为 extensions 依赖这些核心约定。仅涉及发布元数据的版本提升会运行定向的版本 / 配置 / 根依赖检查,而不是完整测试套件,并带有一个保护措施,拒绝顶层版本字段之外的 package 变更。
|
||||
- 来自 agents、commands、plugins、auto-reply helpers、`plugin-sdk` 及类似纯工具区域的轻导入单元测试会路由到 `unit-fast` 通道,该通道会跳过 `test/setup-openclaw-runtime.ts`;有状态 / 运行时较重的文件则仍保留在现有通道中。
|
||||
- 部分选定的 `plugin-sdk` 和 `commands` 辅助源码文件也会在 changed 模式运行中映射到这些轻量通道中的显式同级测试,因此辅助函数编辑不必为该目录重跑完整的重型测试套件。
|
||||
- `auto-reply` 拥有三个专用分桶:顶层 core helpers、顶层 `reply.*` 集成测试,以及 `src/auto-reply/reply/**` 子树。这可以让最重的 reply harness 工作远离廉价的 status / chunk / token 测试。
|
||||
- 未定向的 `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` 不必承担完整根项目启动的成本。
|
||||
- 当 diff 仅涉及可路由的源码/测试文件时,`pnpm test:changed` 会将变更的 git 路径展开到相同的定向通道;配置/设置编辑仍会回退到更广泛的根项目重跑。
|
||||
- `pnpm check:changed` 是窄范围工作时正常的智能本地门禁。它会将 diff 分类为 core、core tests、extensions、extension tests、apps、docs、release metadata 和 tooling,然后运行匹配的 typecheck/lint/test 通道。公开的 插件 SDK 和插件契约变更会额外包含一次 extension 验证,因为 extension 依赖这些核心契约。仅发布元数据的版本提升会运行定向版本/配置/根依赖检查,而不是完整测试套件,并带有一个保护机制,用于拒绝顶层 version 字段之外的包变更。
|
||||
- 来自智能体、命令、插件、auto-reply 辅助函数、`plugin-sdk` 以及类似纯工具区域的轻导入单元测试会路由到 `unit-fast` 通道,该通道会跳过 `test/setup-openclaw-runtime.ts`;有状态/运行时较重的文件则保留在现有通道上。
|
||||
- 某些选定的 `plugin-sdk` 和 `commands` 辅助源码文件,也会在 changed 模式下将运行映射到这些轻量通道中的显式同级测试,因此辅助函数编辑无需为该目录重跑完整的重型测试套件。
|
||||
- `auto-reply` 具有三个专用桶:顶层核心辅助函数、顶层 `reply.*` 集成测试,以及 `src/auto-reply/reply/**` 子树。这使最重的 reply harness 工作不会影响便宜的状态/分块/token 测试。
|
||||
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="嵌入式运行器覆盖">
|
||||
<Accordion title="嵌入式运行器覆盖范围">
|
||||
|
||||
- 当你更改消息工具发现输入或压缩运行时上下文时,要同时保持这两个层级的覆盖。
|
||||
- 为纯路由和标准化边界添加聚焦的辅助函数回归测试。
|
||||
- 当你修改消息工具发现输入或压缩运行时上下文时,需同时保持两个层级的覆盖。
|
||||
- 为纯路由和归一化边界添加聚焦的辅助函数回归测试。
|
||||
- 保持嵌入式运行器集成测试套件健康:
|
||||
`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`。
|
||||
- 这些测试套件会验证作用域 id 和压缩行为仍会通过真实的 `run.ts` / `compact.ts` 路径流动;仅有辅助函数测试不足以替代这些集成路径。
|
||||
- 这些测试套件用于验证作用域 id 和压缩行为仍会流经真实的 `run.ts` / `compact.ts` 路径;仅有辅助函数测试并不足以替代这些集成路径。
|
||||
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="Vitest 池和隔离默认值">
|
||||
|
||||
- 基础 Vitest 配置默认为 `threads`。
|
||||
- 共享 Vitest 配置固定使用 `isolate: false`,并在根项目、e2e 和实时配置中使用非隔离运行器。
|
||||
- 根 UI 通道保留其 `jsdom` setup 和优化器,但也运行在共享的非隔离运行器上。
|
||||
- 每个 `pnpm test` 分片都继承共享 Vitest 配置中的相同 `threads` + `isolate: false` 默认值。
|
||||
- `scripts/run-vitest.mjs` 默认会为 Vitest 子 Node 进程添加 `--no-maglev`,以减少大型本地运行期间的 V8 编译抖动。
|
||||
设置 `OPENCLAW_VITEST_ENABLE_MAGLEV=1` 可与原生 V8 行为进行对比。
|
||||
- 基础 Vitest 配置默认使用 `threads`。
|
||||
- 共享的 Vitest 配置固定 `isolate: false`,并在根项目、e2e 和 live 配置中使用非隔离运行器。
|
||||
- 根 UI 通道保留其 `jsdom` 设置和优化器,但同样运行在共享的非隔离运行器上。
|
||||
- 每个 `pnpm test` 分片都从共享 Vitest 配置继承相同的 `threads` + `isolate: false` 默认值。
|
||||
- `scripts/run-vitest.mjs` 默认会为 Vitest 子 Node 进程添加 `--no-maglev`,以减少大型本地运行期间的 V8 编译抖动。设置 `OPENCLAW_VITEST_ENABLE_MAGLEV=1` 可与标准 V8 行为进行对比。
|
||||
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="快速本地迭代">
|
||||
|
||||
- `pnpm changed:lanes` 会显示某个 diff 触发了哪些架构通道。
|
||||
- pre-commit hook 仅负责格式化。它会重新暂存已格式化文件,不会运行 lint、typecheck 或 tests。
|
||||
- 在交接或推送前,如果你需要智能本地门禁,请显式运行 `pnpm check:changed`。公共插件 SDK 和插件约定变更会包含一次 extension 验证。
|
||||
- 当变更路径可以清晰映射到较小的测试套件时,`pnpm test:changed` 会通过作用域通道进行路由。
|
||||
- `pnpm test:max` 和 `pnpm test:changed:max` 保持相同的路由行为,只是使用更高的 worker 上限。
|
||||
- 本地 worker 自动缩放故意保持保守,当宿主机负载均值已经很高时会回退,因此默认情况下多个并发 Vitest 运行造成的影响更小。
|
||||
- 基础 Vitest 配置会将项目 / 配置文件标记为 `forceRerunTriggers`,以便测试接线变更时,changed 模式重跑仍然正确。
|
||||
- 在受支持的宿主上,该配置会保持 `OPENCLAW_VITEST_FS_MODULE_CACHE` 启用;如果你想为直接分析指定一个明确缓存位置,可设置 `OPENCLAW_VITEST_FS_MODULE_CACHE_PATH=/abs/path`。
|
||||
- pre-commit hook 只负责格式化。它会重新暂存格式化后的文件,不会运行 lint、typecheck 或测试。
|
||||
- 在交接或推送前,如需智能本地门禁,请显式运行 `pnpm check:changed`。公开的 插件 SDK 和插件契约变更会包含一次 extension 验证。
|
||||
- 当变更路径可以清晰映射到更小的测试套件时,`pnpm test:changed` 会通过定向通道进行路由。
|
||||
- `pnpm test:max` 和 `pnpm test:changed:max` 保持相同的路由行为,只是具有更高的 worker 上限。
|
||||
- 本地 worker 自动扩缩容有意保持保守,并会在主机负载平均值已经较高时回退,因此默认情况下多个并发 Vitest 运行造成的影响更小。
|
||||
- 基础 Vitest 配置会将项目/配置文件标记为 `forceRerunTriggers`,以便在测试接线变更时,changed 模式重跑仍然正确。
|
||||
- 该配置会在受支持主机上保持启用 `OPENCLAW_VITEST_FS_MODULE_CACHE`;如果你希望为直接性能分析指定一个明确的缓存位置,请设置 `OPENCLAW_VITEST_FS_MODULE_CACHE_PATH=/abs/path`。
|
||||
|
||||
</Accordion>
|
||||
|
||||
@ -361,14 +339,22 @@ Telegram 类型的负载结构:
|
||||
|
||||
- `pnpm test:perf:imports` 会启用 Vitest 导入耗时报告以及
|
||||
import-breakdown 输出。
|
||||
- `pnpm test:perf:imports:changed` 会将同样的分析视图限定到自 `origin/main` 以来变更的文件。
|
||||
- 当某个热点测试的大部分时间仍然消耗在启动导入上时,应将重型依赖放在一个狭窄的本地 `*.runtime.ts` 接缝之后,并直接 mock 该接缝,而不是为了通过 `vi.mock(...)` 传递它们而深度导入运行时辅助模块。
|
||||
- `pnpm test:perf:changed:bench -- --ref <git-ref>` 会将经路由的
|
||||
`test:changed` 与该已提交 diff 的原生根项目路径进行比较,并输出总耗时以及 macOS 最大 RSS。
|
||||
- `pnpm test:perf:changed:bench -- --worktree` 会通过
|
||||
`scripts/test-projects.mjs` 和根 Vitest 配置,将当前脏工作树的变更文件列表进行路由并执行基准测试。
|
||||
- `pnpm test:perf:profile:main` 会为 Vitest / Vite 启动和转换开销写入主线程 CPU profile。
|
||||
- `pnpm test:perf:profile:runner` 会在禁用文件并行的情况下,为单元测试套件写入运行器 CPU + 堆 profile。
|
||||
- `pnpm test:perf:imports:changed` 会将相同的性能分析视图限定到
|
||||
自 `origin/main` 以来发生变更的文件。
|
||||
- 当某个热点测试的大部分时间仍然消耗在启动导入上时,
|
||||
应将重型依赖放在一个狭窄的本地 `*.runtime.ts` 接缝之后,
|
||||
并直接 mock 该接缝,而不是仅仅为了通过 `vi.mock(...)`
|
||||
传递它们就深度导入运行时辅助函数。
|
||||
- `pnpm test:perf:changed:bench -- --ref <git-ref>` 会将已路由的
|
||||
`test:changed` 与该已提交 diff 的原生根项目路径进行比较,
|
||||
并打印墙钟时间以及 macOS 最大 RSS。
|
||||
- `pnpm test:perf:changed:bench -- --worktree` 会通过将变更文件列表路由到
|
||||
`scripts/test-projects.mjs` 和根 Vitest 配置,
|
||||
对当前未提交工作树进行基准测试。
|
||||
- `pnpm test:perf:profile:main` 会为
|
||||
Vitest/Vite 启动和转换开销写出主线程 CPU profile。
|
||||
- `pnpm test:perf:profile:runner` 会在禁用文件并行的情况下,
|
||||
为 unit 测试套件写出运行器 CPU + 堆 profile。
|
||||
|
||||
</Accordion>
|
||||
</AccordionGroup>
|
||||
@ -378,128 +364,128 @@ Telegram 类型的负载结构:
|
||||
- 命令:`pnpm test:stability:gateway`
|
||||
- 配置:`vitest.gateway.config.ts`,强制使用一个 worker
|
||||
- 范围:
|
||||
- 启动一个真实的 loopback Gateway 网关,并默认启用诊断
|
||||
- 通过诊断事件路径驱动合成的 gateway 消息、内存和大负载 churn
|
||||
- 启动一个真实的 loopback Gateway 网关,默认启用诊断
|
||||
- 通过诊断事件路径驱动合成的 gateway 消息、memory 和大负载 churn
|
||||
- 通过 Gateway 网关 WS RPC 查询 `diagnostics.stability`
|
||||
- 覆盖诊断稳定性 bundle 持久化辅助函数
|
||||
- 断言记录器保持有界、合成 RSS 采样保持在压力预算之下,并且每个会话的队列深度会回落到零
|
||||
- 期望:
|
||||
- 对 CI 安全且不需要密钥
|
||||
- 这是一个用于稳定性回归跟进的窄范围通道,而不是完整 Gateway 网关测试套件的替代品
|
||||
- 断言 recorder 保持有界、合成 RSS 样本保持在压力预算之下,并且每个会话的队列深度都会回落到零
|
||||
- 预期:
|
||||
- 可安全用于 CI,且不需要密钥
|
||||
- 这是一个用于稳定性回归跟进的窄范围通道,而不是完整 Gateway 网关 测试套件的替代品
|
||||
|
||||
### E2E(Gateway 网关冒烟测试)
|
||||
### E2E(Gateway 网关 冒烟测试)
|
||||
|
||||
- 命令:`pnpm test:e2e`
|
||||
- 配置:`vitest.e2e.config.ts`
|
||||
- 文件:`src/**/*.e2e.test.ts`、`test/**/*.e2e.test.ts`,以及 `extensions/` 下的内置插件 E2E 测试
|
||||
- 运行时默认值:
|
||||
- 使用 Vitest `threads` 和 `isolate: false`,与仓库其余部分保持一致。
|
||||
- 使用 Vitest `threads` 并设置 `isolate: false`,与仓库其余部分保持一致。
|
||||
- 使用自适应 worker(CI:最多 2 个,本地:默认 1 个)。
|
||||
- 默认以 silent 模式运行,以减少控制台 I/O 开销。
|
||||
- 默认以静默模式运行,以减少控制台 I/O 开销。
|
||||
- 常用覆盖项:
|
||||
- `OPENCLAW_E2E_WORKERS=<n>` 用于强制指定 worker 数量(上限为 16)。
|
||||
- `OPENCLAW_E2E_VERBOSE=1` 用于重新启用详细控制台输出。
|
||||
- `OPENCLAW_E2E_WORKERS=<n>` 强制指定 worker 数量(上限为 16)。
|
||||
- `OPENCLAW_E2E_VERBOSE=1` 重新启用详细控制台输出。
|
||||
- 范围:
|
||||
- 多实例 Gateway 网关端到端行为
|
||||
- WebSocket / HTTP 接口、节点配对以及更重的网络行为
|
||||
- 期望:
|
||||
- 在 CI 中运行(当流水线启用时)
|
||||
- 多实例 gateway 端到端行为
|
||||
- WebSocket/HTTP 接口、节点配对和更重型的网络行为
|
||||
- 预期:
|
||||
- 会在 CI 中运行(当流水线中启用时)
|
||||
- 不需要真实密钥
|
||||
- 比单元测试有更多活动部件(可能更慢)
|
||||
- 比 unit 测试具有更多活动部件(可能更慢)
|
||||
|
||||
### E2E:OpenShell 后端冒烟测试
|
||||
|
||||
- 命令:`pnpm test:e2e:openshell`
|
||||
- 文件:`extensions/openshell/src/backend.e2e.test.ts`
|
||||
- 范围:
|
||||
- 通过 Docker 在宿主机上启动一个隔离的 OpenShell Gateway 网关
|
||||
- 从临时本地 Dockerfile 创建一个沙箱
|
||||
- 通过真实的 `sandbox ssh-config` + SSH exec 演练 OpenClaw 的 OpenShell 后端
|
||||
- 通过 Docker 在主机上启动一个隔离的 OpenShell gateway
|
||||
- 从一个临时本地 Dockerfile 创建一个沙箱
|
||||
- 通过真实的 `sandbox ssh-config` + SSH exec 对 OpenClaw 的 OpenShell 后端进行测试
|
||||
- 通过沙箱 fs bridge 验证远端规范文件系统行为
|
||||
- 期望:
|
||||
- 仅在显式启用时运行;不是默认 `pnpm test:e2e` 的一部分
|
||||
- 预期:
|
||||
- 仅按需启用;不属于默认 `pnpm test:e2e` 运行的一部分
|
||||
- 需要本地 `openshell` CLI 和可用的 Docker daemon
|
||||
- 使用隔离的 `HOME` / `XDG_CONFIG_HOME`,然后销毁测试 Gateway 网关和沙箱
|
||||
- 使用隔离的 `HOME` / `XDG_CONFIG_HOME`,然后销毁测试 gateway 和沙箱
|
||||
- 常用覆盖项:
|
||||
- `OPENCLAW_E2E_OPENSHELL=1` 可在手动运行更广泛的 e2e 测试套件时启用该测试
|
||||
- `OPENCLAW_E2E_OPENSHELL_COMMAND=/path/to/openshell` 用于指向非默认 CLI 二进制或包装脚本
|
||||
- `OPENCLAW_E2E_OPENSHELL=1`,在手动运行更广泛的 e2e 测试套件时启用该测试
|
||||
- `OPENCLAW_E2E_OPENSHELL_COMMAND=/path/to/openshell`,指向一个非默认 CLI 二进制或包装脚本
|
||||
|
||||
### 实时(真实提供商 + 真实模型)
|
||||
### Live(真实提供商 + 真实模型)
|
||||
|
||||
- 命令:`pnpm test:live`
|
||||
- 配置:`vitest.live.config.ts`
|
||||
- 文件:`src/**/*.live.test.ts`、`test/**/*.live.test.ts`,以及 `extensions/` 下的内置插件实时测试
|
||||
- 默认:由 `pnpm test:live` **启用**(会设置 `OPENCLAW_LIVE_TEST=1`)
|
||||
- 文件:`src/**/*.live.test.ts`、`test/**/*.live.test.ts`,以及 `extensions/` 下的内置插件 live 测试
|
||||
- 默认:由 `pnpm test:live` **启用**(设置 `OPENCLAW_LIVE_TEST=1`)
|
||||
- 范围:
|
||||
- “这个提供商 / 模型在_今天_配合真实凭证是否真的可用?”
|
||||
- 捕获提供商格式变化、工具调用怪癖、认证问题和速率限制行为
|
||||
- 期望:
|
||||
- 按设计不保证 CI 稳定(真实网络、真实提供商策略、配额、故障)
|
||||
- “这个提供商/模型 _今天_ 是否真的能在真实凭证下工作?”
|
||||
- 捕获提供商格式变更、工具调用怪癖、认证问题和速率限制行为
|
||||
- 预期:
|
||||
- 按设计不是 CI 稳定的(真实网络、真实提供商策略、配额、服务中断)
|
||||
- 会花钱 / 消耗速率限制
|
||||
- 优先运行收窄后的子集,而不是“全部”
|
||||
- 实时运行会读取 `~/.profile`,以获取缺失的 API key。
|
||||
- 默认情况下,实时运行仍会隔离 `HOME`,并将配置 / 认证材料复制到一个临时测试 home 中,以便单元测试 fixture 不会修改你的真实 `~/.openclaw`。
|
||||
- 仅在你明确需要实时测试使用真实 home 目录时,才设置 `OPENCLAW_LIVE_USE_REAL_HOME=1`。
|
||||
- `pnpm test:live` 现在默认使用更安静的模式:它会保留 `[live] ...` 进度输出,但会抑制额外的 `~/.profile` 提示,并静默 gateway 引导日志 / Bonjour 噪声。若要恢复完整启动日志,请设置 `OPENCLAW_LIVE_TEST_QUIET=0`。
|
||||
- API key 轮换(按提供商区分):设置 `*_API_KEYS`,使用逗号 / 分号格式,或设置 `*_API_KEY_1`、`*_API_KEY_2`(例如 `OPENAI_API_KEYS`、`ANTHROPIC_API_KEYS`、`GEMINI_API_KEYS`),或通过 `OPENCLAW_LIVE_*_KEY` 进行实时覆盖;测试会在收到速率限制响应时重试。
|
||||
- 进度 / 心跳输出:
|
||||
- 实时测试套件现在会将进度行输出到 stderr,因此即使 Vitest 控制台捕获较安静,长时间的提供商调用也能明显显示为仍在活动中。
|
||||
- `vitest.live.config.ts` 会禁用 Vitest 控制台拦截,因此提供商 / gateway 进度行会在实时运行期间立即流式输出。
|
||||
- 优先运行收窄后的子集,而不是“一切都跑”
|
||||
- live 运行会读取 `~/.profile` 以获取缺失的 API 密钥。
|
||||
- 默认情况下,live 运行仍会隔离 `HOME`,并将配置/认证材料复制到一个临时测试 home 中,这样 unit fixture 就不会改动你真实的 `~/.openclaw`。
|
||||
- 仅当你有意需要 live 测试使用真实 home 目录时,才设置 `OPENCLAW_LIVE_USE_REAL_HOME=1`。
|
||||
- `pnpm test:live` 现在默认采用更安静的模式:会保留 `[live] ...` 进度输出,但会抑制额外的 `~/.profile` 提示,并静默 gateway 启动日志/Bonjour 噪声。如果你想恢复完整启动日志,请设置 `OPENCLAW_LIVE_TEST_QUIET=0`。
|
||||
- API 密钥轮换(按提供商区分):设置 `*_API_KEYS`(逗号/分号格式)或 `*_API_KEY_1`、`*_API_KEY_2`(例如 `OPENAI_API_KEYS`、`ANTHROPIC_API_KEYS`、`GEMINI_API_KEYS`),或通过 `OPENCLAW_LIVE_*_KEY` 进行每次 live 运行覆盖;测试会在收到速率限制响应时重试。
|
||||
- 进度/心跳输出:
|
||||
- live 测试套件现在会将进度行输出到 stderr,因此即使 Vitest 控制台捕获很安静,长时间的提供商调用也能显示为仍在活跃运行。
|
||||
- `vitest.live.config.ts` 会禁用 Vitest 控制台拦截,因此提供商/gateway 进度行会在 live 运行期间立即流式输出。
|
||||
- 使用 `OPENCLAW_LIVE_HEARTBEAT_MS` 调整直接模型心跳。
|
||||
- 使用 `OPENCLAW_LIVE_GATEWAY_HEARTBEAT_MS` 调整 gateway / probe 心跳。
|
||||
- 使用 `OPENCLAW_LIVE_GATEWAY_HEARTBEAT_MS` 调整 Gateway 网关 /探测心跳。
|
||||
|
||||
## 我应该运行哪个测试套件?
|
||||
|
||||
使用下面的决策表:
|
||||
使用这个决策表:
|
||||
|
||||
- 编辑逻辑 / 测试:运行 `pnpm test`(如果改动较多,再运行 `pnpm test:coverage`)
|
||||
- 涉及 Gateway 网关网络 / WS 协议 / 配对:额外运行 `pnpm test:e2e`
|
||||
- 调试“我的 bot 挂了” / 提供商特定故障 / 工具调用:运行收窄后的 `pnpm test:live`
|
||||
- 编辑逻辑/测试:运行 `pnpm test`(如果改动很多,再运行 `pnpm test:coverage`)
|
||||
- 修改 gateway 网络 / WS 协议 / 配对:额外运行 `pnpm test:e2e`
|
||||
- 调试“我的 bot 挂了”/提供商特定故障/工具调用:运行一个收窄的 `pnpm test:live`
|
||||
|
||||
## 实时(触网)测试
|
||||
## Live(触网)测试
|
||||
|
||||
关于实时模型矩阵、CLI 后端冒烟测试、ACP 冒烟测试、Codex app-server
|
||||
harness,以及所有媒体提供商实时测试(Deepgram、BytePlus(国际版)、ComfyUI、image、
|
||||
music、video、media harness)——以及实时运行的凭证处理——请参见
|
||||
[Testing — live suites](/zh-CN/help/testing-live)。
|
||||
关于 live 模型矩阵、CLI 后端冒烟测试、ACP 冒烟测试、Codex app-server
|
||||
harness,以及所有媒体提供商 live 测试(Deepgram、BytePlus(国际版)、ComfyUI、图像、
|
||||
音乐、视频、媒体 harness)——以及 live 运行的凭证处理——请参阅
|
||||
[测试 — live 测试套件](/zh-CN/help/testing-live)。
|
||||
|
||||
## Docker 运行器(可选的“在 Linux 中可用”检查)
|
||||
|
||||
这些 Docker 运行器分为两类:
|
||||
|
||||
- 实时模型运行器:`test:docker:live-models` 和 `test:docker:live-gateway` 仅在仓库 Docker 镜像内运行其对应的 profile-key 实时测试文件(`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`,而
|
||||
`test:docker:live-gateway` 默认为 `OPENCLAW_LIVE_GATEWAY_SMOKE=1`、
|
||||
- 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`),并挂载你的本地配置目录和工作区(若已挂载,也会读取 `~/.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 镜像,然后在实时 Docker 通道中复用它。它还会通过 `test:docker:e2e-build` 构建一个共享的 `scripts/e2e/Dockerfile` 镜像,并将其复用于执行已构建应用的 E2E 容器冒烟运行器。该聚合任务使用加权本地调度器:`OPENCLAW_DOCKER_ALL_PARALLELISM` 控制进程槽位,而资源上限会阻止重型实时、npm 安装以及多服务通道同时全部启动。默认值为 10 个槽位、`OPENCLAW_DOCKER_ALL_LIVE_LIMIT=4`、`OPENCLAW_DOCKER_ALL_NPM_LIMIT=4` 和 `OPENCLAW_DOCKER_ALL_SERVICE_LIMIT=5`;仅当 Docker 宿主有更多余量时,才调整 `OPENCLAW_DOCKER_ALL_WEIGHT_LIMIT` 或 `OPENCLAW_DOCKER_ALL_DOCKER_LIMIT`。
|
||||
`OPENCLAW_LIVE_GATEWAY_MODEL_TIMEOUT_MS=90000`。当你明确想进行更大范围的穷举扫描时,可覆盖这些环境变量。
|
||||
- `test:docker:all` 会先通过 `test:docker:live-build` 构建一次 live Docker 镜像,然后在各 live Docker 通道中复用它。它还会通过 `test:docker:e2e-build` 构建一个共享的 `scripts/e2e/Dockerfile` 镜像,并在用于验证已构建应用的 E2E 容器冒烟运行器中复用它。这个聚合器使用加权本地调度器:`OPENCLAW_DOCKER_ALL_PARALLELISM` 控制进程槽位,而资源上限会避免重型 live、npm 安装和多服务通道同时启动。默认值为 10 个槽位、`OPENCLAW_DOCKER_ALL_LIVE_LIMIT=4`、`OPENCLAW_DOCKER_ALL_NPM_LIMIT=4` 和 `OPENCLAW_DOCKER_ALL_SERVICE_LIMIT=5`;只有当 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 的情况下打印加权通道清单。
|
||||
- 容器冒烟运行器:`test:docker:openwebui`、`test:docker:onboard`、`test:docker:npm-onboard-channel-agent`、`test:docker:gateway-network`、`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 运行器还会仅 bind-mount 所需的 CLI 认证 home(如果运行未收窄,则挂载所有受支持的认证 home),然后在运行前将它们复制到容器 home 中,以便外部 CLI OAuth 可以刷新令牌,而不会修改宿主的认证存储:
|
||||
live 模型 Docker 运行器还会只绑定挂载所需的 CLI 认证 home(如果运行未收窄,则挂载所有受支持的认证 home),然后在运行前将其复制到容器 home 中,这样外部 CLI OAuth 就可以刷新 token,而不会改动主机认证存储:
|
||||
|
||||
- 直接模型:`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`)
|
||||
- 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`)
|
||||
- Gateway 网关 + 开发智能体:`pnpm test:docker:live-gateway`(脚本:`scripts/test-live-gateway-models-docker.sh`)
|
||||
- Open WebUI 实时冒烟测试:`pnpm test:docker:openwebui`(脚本:`scripts/e2e/openwebui-docker.sh`)
|
||||
- onboarding 向导(TTY、完整脚手架):`pnpm test:docker:onboard`(脚本:`scripts/e2e/onboard-docker.sh`)
|
||||
- npm tarball onboarding / 渠道 / 智能体冒烟测试:`pnpm test:docker:npm-onboard-channel-agent` 会在 Docker 中全局安装打包后的 OpenClaw tarball,通过 env-ref onboarding 配置 OpenAI,并默认配置 Telegram,验证 doctor 会修复已激活插件的运行时依赖,并运行一次模拟的 OpenAI 智能体轮次。使用 `OPENCLAW_NPM_ONBOARD_PACKAGE_TGZ=/path/to/openclaw-*.tgz` 可复用预构建 tarball,使用 `OPENCLAW_NPM_ONBOARD_HOST_BUILD=0` 可跳过宿主机构建,或通过 `OPENCLAW_NPM_ONBOARD_CHANNEL=discord` 切换渠道。
|
||||
- Bun 全局安装冒烟测试:`bash scripts/e2e/bun-global-install-smoke.sh` 会打包当前工作树,在隔离的 home 中使用 `bun install -g` 安装,并验证 `openclaw infer image providers --json` 会返回内置 image 提供商,而不是卡住。使用 `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。非 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` 覆盖时,请在本地运行该脚本且不要设置此环境变量。
|
||||
- Gateway 网关网络(两个容器,WS 认证 + 健康检查):`pnpm test:docker:gateway-network`(脚本:`scripts/e2e/gateway-network-docker.sh`)
|
||||
- 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 bridge + 原始 Claude 通知帧冒烟测试):`pnpm test:docker:mcp-channels`(脚本:`scripts/e2e/mcp-channels-docker.sh`)
|
||||
- Pi bundle MCP 工具(真实 stdio MCP 服务器 + 嵌入式 Pi profile 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`)
|
||||
- Gateway 网关 + dev 智能体:`pnpm test:docker:live-gateway`(脚本:`scripts/test-live-gateway-models-docker.sh`)
|
||||
- Open WebUI live 冒烟测试:`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,通过环境变量引用式新手引导配置 OpenAI,并默认配置 Telegram,验证 doctor 会修复已激活插件的运行时依赖,并运行一次模拟的 OpenAI 智能体轮次。可使用 `OPENCLAW_NPM_ONBOARD_PACKAGE_TGZ=/path/to/openclaw-*.tgz` 复用预构建 tarball,使用 `OPENCLAW_NPM_ONBOARD_HOST_BUILD=0` 跳过主机构建,或使用 `OPENCLAW_NPM_ONBOARD_CHANNEL=discord` 切换渠道。
|
||||
- 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。非 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` 时,请在本地不带该环境变量运行脚本。
|
||||
- Gateway 网关 网络(两个容器,WS 认证 + 健康检查):`pnpm test:docker:gateway-network`(脚本:`scripts/e2e/gateway-network-docker.sh`)
|
||||
- OpenAI Responses `web_search` 最小 reasoning 回归测试:`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 bridge + 原始 Claude 通知帧冒烟测试):`pnpm test:docker:mcp-channels`(脚本:`scripts/e2e/mcp-channels-docker.sh`)
|
||||
- Pi bundle MCP 工具(真实 stdio MCP 服务器 + 嵌入式 Pi profile 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`)
|
||||
- 插件(安装冒烟测试 + `/plugin` 别名 + Claude bundle 重启语义):`pnpm test:docker:plugins`(脚本:`scripts/e2e/plugins-docker.sh`)
|
||||
- 插件更新未变更冒烟测试:`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 运行器镜像,在宿主机上构建并打包一次 OpenClaw,然后将该 tarball 挂载到每个 Linux 安装场景中。使用 `OPENCLAW_SKIP_DOCKER_BUILD=1` 可复用该镜像,使用 `OPENCLAW_BUNDLED_CHANNEL_HOST_BUILD=0` 可在本地刚完成构建后跳过宿主机重建,或通过 `OPENCLAW_BUNDLED_CHANNEL_PACKAGE_TGZ=/path/to/openclaw-*.tgz` 指向现有 tarball。完整的 Docker 聚合任务会先预打包该 tarball 一次,然后将内置渠道检查分片到独立通道;直接运行该内置通道时,可使用 `OPENCLAW_BUNDLED_CHANNELS=telegram,slack` 收窄渠道矩阵。该通道还会验证 `channels.<id>.enabled=false` 和 `plugins.entries.<id>.enabled=false` 会抑制 doctor / 运行时依赖修复。
|
||||
- 在迭代时,可通过禁用无关场景来收窄内置插件运行时依赖,例如:
|
||||
- 内置插件运行时依赖:`pnpm test:docker:bundled-channel-deps` 默认会构建一个小型 Docker 运行器镜像,在主机上构建并打包一次 OpenClaw,然后将该 tarball 挂载到每个 Linux 安装场景中。可使用 `OPENCLAW_SKIP_DOCKER_BUILD=1` 复用该镜像,使用 `OPENCLAW_BUNDLED_CHANNEL_HOST_BUILD=0` 在完成一次本地新构建后跳过主机构建,或使用 `OPENCLAW_BUNDLED_CHANNEL_PACKAGE_TGZ=/path/to/openclaw-*.tgz` 指向一个已有 tarball。完整 Docker 聚合器会预先打包一次该 tarball,然后将内置渠道检查分片为独立通道,包括 Telegram、Discord、Slack、Feishu、memory-lancedb 和 ACPX 的独立更新通道。直接运行该内置通道时,使用 `OPENCLAW_BUNDLED_CHANNELS=telegram,slack` 可收窄渠道矩阵,或使用 `OPENCLAW_BUNDLED_CHANNEL_UPDATE_TARGETS=telegram,acpx` 收窄更新场景。该通道还会验证 `channels.<id>.enabled=false` 和 `plugins.entries.<id>.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`。
|
||||
|
||||
如需手动预构建并复用共享的 built-app 镜像:
|
||||
@ -509,141 +495,142 @@ OPENCLAW_DOCKER_E2E_IMAGE=openclaw-docker-e2e:local pnpm test:docker:e2e-build
|
||||
OPENCLAW_DOCKER_E2E_IMAGE=openclaw-docker-e2e:local OPENCLAW_SKIP_DOCKER_BUILD=1 pnpm test:docker:mcp-channels
|
||||
```
|
||||
|
||||
如已设置,特定测试套件的镜像覆盖项(例如 `OPENCLAW_GATEWAY_NETWORK_E2E_IMAGE`)仍然优先生效。当 `OPENCLAW_SKIP_DOCKER_BUILD=1` 指向远程共享镜像时,如果该镜像尚未存在于本地,脚本会先拉取它。QR 和安装器 Docker 测试保留各自的 Dockerfile,因为它们验证的是 package / install 行为,而不是共享的 built-app 运行时。
|
||||
当设置了 suite 专用镜像覆盖项(例如 `OPENCLAW_GATEWAY_NETWORK_E2E_IMAGE`)时,这些覆盖项仍然优先生效。当 `OPENCLAW_SKIP_DOCKER_BUILD=1` 指向远程共享镜像时,如果本地尚不存在,脚本会先拉取它。QR 和安装器 Docker 测试保留各自独立的 Dockerfile,因为它们验证的是包/安装行为,而不是共享 built-app 运行时。
|
||||
|
||||
实时模型 Docker 运行器还会以只读方式 bind-mount 当前 checkout,并将其暂存到容器内的临时 workdir 中。这样可以保持运行时镜像精简,同时仍然针对你精确的本地 source / config 运行 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 实时覆盖时,也请传入 `OPENCLAW_LIVE_GATEWAY_*`。
|
||||
`test:docker:openwebui` 是一个更高层的兼容性冒烟测试:它会启动一个启用了 OpenAI-compatible HTTP 端点的 OpenClaw gateway 容器,再针对该 gateway 启动一个固定版本的 Open WebUI 容器,通过 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":
|
||||
live 模型 Docker 运行器还会以只读方式绑定挂载当前检出内容,并在容器内暂存到一个临时 workdir 中。这样可以保持运行时镜像精简,同时仍能针对你本地精确的源码/配置运行 Vitest。暂存步骤会跳过大型本地专用缓存和应用构建输出,例如 `.pnpm-store`、`.worktrees`、`__openclaw_vitest__`,以及应用本地的 `.build` 或 Gradle 输出目录,因此 Docker live 运行不会花数分钟去复制机器特定产物。
|
||||
它们还会设置 `OPENCLAW_SKIP_CHANNELS=1`,以便 gateway live 探测不会在容器内启动真实的 Telegram/Discord 等渠道 worker。
|
||||
`test:docker:live-models` 仍然运行 `pnpm test:live`,因此当你需要从该 Docker 通道中收窄或排除 gateway live 覆盖时,也应一并传入 `OPENCLAW_LIVE_GATEWAY_*`。
|
||||
`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 也可能需要完成自己的冷启动设置。
|
||||
该通道需要一个可用的 live 模型密钥,而 `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 bridge 验证路由后的会话发现、转录读取、附件元数据、实时事件队列行为、出站发送路由,以及 Claude 风格的渠道 + 权限通知。通知检查会直接检查原始 stdio MCP 帧,因此该冒烟测试验证的是 bridge 实际发出的内容,而不只是某个特定客户端 SDK 恰好暴露出的内容。
|
||||
`test:docker:pi-bundle-mcp-tools` 是确定性的,不需要实时模型密钥。它会构建仓库 Docker 镜像,在容器内启动一个真实的 stdio MCP 探测服务器,通过嵌入式 Pi bundle MCP 运行时实例化该服务器,执行该工具,然后验证 `coding` 和 `messaging` 会保留 `bundle-mcp` 工具,而 `minimal` 和 `tools.deny: ["bundle-mcp"]` 会将其过滤掉。
|
||||
`test:docker:cron-mcp-cleanup` 是确定性的,不需要实时模型密钥。它会启动一个带真实 stdio MCP 探测服务器的预置 Gateway 网关,运行一个隔离的 cron 轮次和一个 `/subagents spawn` 一次性子智能体轮次,然后验证 MCP 子进程会在每次运行后退出。
|
||||
`test:docker:mcp-channels` 有意保持确定性,不需要真实的 Telegram、Discord 或 iMessage 账号。它会启动一个已播种的 Gateway 网关 容器,启动第二个容器来运行 `openclaw mcp serve`,然后通过真实的 stdio MCP bridge 验证路由后的会话发现、transcript 读取、附件元数据、live 事件队列行为、出站发送路由,以及 Claude 风格的渠道 + 权限通知。通知检查会直接检查原始 stdio MCP 帧,因此该冒烟测试验证的是真实 bridge 实际发出的内容,而不仅仅是某个特定客户端 SDK 恰好暴露的内容。
|
||||
`test:docker:pi-bundle-mcp-tools` 保持确定性,不需要 live 模型密钥。它会构建仓库 Docker 镜像,在容器内启动一个真实的 stdio MCP 探测服务器,通过嵌入式 Pi bundle MCP 运行时将该服务器实体化,执行该工具,然后验证 `coding` 和 `messaging` 会保留 `bundle-mcp` 工具,而 `minimal` 和 `tools.deny: ["bundle-mcp"]` 会将它们过滤掉。
|
||||
`test:docker:cron-mcp-cleanup` 保持确定性,不需要 live 模型密钥。它会启动一个带真实 stdio MCP 探测服务器的已播种 Gateway 网关,运行一次隔离的 cron 轮次和一次 `/subagents spawn` 的一次性子智能体轮次,然后验证 MCP 子进程会在每次运行后退出。
|
||||
|
||||
手动 ACP 自然语言线程冒烟测试(非 CI):
|
||||
|
||||
- `bun scripts/dev/discord-acp-plain-language-smoke.ts --channel <discord-channel-id> ...`
|
||||
- 为回归 / 调试工作流保留此脚本。它将来可能还需要再次用于 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`,并在运行测试前读取
|
||||
- `OPENCLAW_DOCKER_PROFILE_ENV_ONLY=1` 用于验证仅来自 `OPENCLAW_PROFILE_FILE` 的环境变量,此时会使用临时 config / workspace 目录,且不挂载外部 CLI 认证
|
||||
- `OPENCLAW_DOCKER_CLI_TOOLS_DIR=...`(默认:`~/.cache/openclaw/docker-cli-tools`)挂载到 `/home/node/.npm-global`,用于在 Docker 内缓存 CLI 安装
|
||||
- `$HOME` 下的外部 CLI 认证目录 / 文件会以只读方式挂载到 `/host-auth...` 下,然后在测试开始前复制到 `/home/node/...`
|
||||
- `OPENCLAW_DOCKER_PROFILE_ENV_ONLY=1` 用于验证仅使用从 `OPENCLAW_PROFILE_FILE` 读取的环境变量,使用临时配置/workspace 目录且不挂载外部 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_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_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 检查提示词
|
||||
- `OPENCLAW_OPENWEBUI_MODEL=...` 用于选择由 gateway 为 Open WebUI 冒烟测试暴露的模型
|
||||
- `OPENCLAW_OPENWEBUI_PROMPT=...` 用于覆盖 Open WebUI 冒烟测试所用的 nonce 检查提示词
|
||||
- `OPENWEBUI_IMAGE=...` 用于覆盖固定的 Open WebUI 镜像标签
|
||||
|
||||
## 文档完整性检查
|
||||
|
||||
编辑文档后运行文档检查:`pnpm check:docs`。
|
||||
当你还需要检查页内标题锚点时,运行完整的 Mintlify 锚点验证:`pnpm docs:check-links:anchors`。
|
||||
当你还需要页内标题检查时,运行完整的 Mintlify 锚点验证:`pnpm docs:check-links:anchors`。
|
||||
|
||||
## 离线回归(对 CI 安全)
|
||||
## 离线回归测试(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`,强制写入 config + auth):`src/gateway/gateway.test.ts`(用例:“runs wizard over ws and writes auth token config”)
|
||||
- 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”)
|
||||
|
||||
## 智能体可靠性评估(Skills)
|
||||
|
||||
我们已经有一些对 CI 安全的测试,行为类似“智能体可靠性评估”:
|
||||
我们已经有一些可安全用于 CI 的测试,它们的行为类似“智能体可靠性评估”:
|
||||
|
||||
- 通过真实 gateway + 智能体循环进行模拟工具调用(`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 文件读取和会话接线。
|
||||
- 一小组以 skill 为重点的场景(使用 vs 避免、门控、prompt 注入)。
|
||||
- 仅在具备 CI 安全测试套件之后,再添加可选的 live 评估(按需启用,由环境变量门控)。
|
||||
|
||||
## 约定测试(插件和渠道形状)
|
||||
## 契约测试(插件和渠道形状)
|
||||
|
||||
约定测试用于验证每个已注册插件和渠道都符合其接口约定。它们会遍历所有已发现的插件,并运行一组形状和行为断言。默认的 `pnpm test` 单元测试通道会有意跳过这些共享接缝和冒烟测试文件;当你修改共享的渠道或提供商接口时,请显式运行约定测试命令。
|
||||
契约测试用于验证每个已注册插件和渠道都符合其
|
||||
接口契约。它们会遍历所有已发现的插件,并运行一套关于形状和行为的断言。默认的 `pnpm test` unit 通道会有意跳过这些共享接缝和冒烟测试文件;当你修改共享渠道或提供商表面时,请显式运行契约命令。
|
||||
|
||||
### 命令
|
||||
|
||||
- 所有约定测试:`pnpm test:contracts`
|
||||
- 仅渠道约定测试:`pnpm test:contracts:channels`
|
||||
- 仅提供商约定测试:`pnpm test:contracts:plugins`
|
||||
- 所有契约:`pnpm test:contracts`
|
||||
- 仅渠道契约:`pnpm test:contracts:channels`
|
||||
- 仅提供商契约:`pnpm test:contracts:plugins`
|
||||
|
||||
### 渠道约定测试
|
||||
### 渠道契约
|
||||
|
||||
位于 `src/channels/plugins/contracts/*.contract.test.ts`:
|
||||
|
||||
- **plugin** - 基本插件形状(id、name、capabilities)
|
||||
- **setup** - 设置向导约定
|
||||
- **setup** - 设置向导契约
|
||||
- **session-binding** - 会话绑定行为
|
||||
- **outbound-payload** - 消息负载结构
|
||||
- **outbound-payload** - 消息 payload 结构
|
||||
- **inbound** - 入站消息处理
|
||||
- **actions** - 渠道动作处理器
|
||||
- **threading** - 线程 ID 处理
|
||||
- **directory** - 目录 / roster API
|
||||
- **directory** - 目录/花名册 API
|
||||
- **group-policy** - 群组策略执行
|
||||
|
||||
### 提供商状态约定测试
|
||||
### 提供商状态契约
|
||||
|
||||
位于 `src/plugins/contracts/*.contract.test.ts`。
|
||||
|
||||
- **status** - 渠道状态探测
|
||||
- **registry** - 插件注册表形状
|
||||
|
||||
### 提供商约定测试
|
||||
### 提供商契约
|
||||
|
||||
位于 `src/plugins/contracts/*.contract.test.ts`:
|
||||
|
||||
- **auth** - 认证流程约定
|
||||
- **auth-choice** - 认证选项 / 选择
|
||||
- **auth** - 认证流程契约
|
||||
- **auth-choice** - 认证选项/选择
|
||||
- **catalog** - 模型目录 API
|
||||
- **discovery** - 插件发现
|
||||
- **loader** - 插件加载
|
||||
- **runtime** - 提供商运行时
|
||||
- **shape** - 插件形状 / 接口
|
||||
- **shape** - 插件形状/接口
|
||||
- **wizard** - 设置向导
|
||||
|
||||
### 何时运行
|
||||
|
||||
- 修改 plugin-sdk 导出或子路径后
|
||||
- 添加或修改渠道或提供商插件后
|
||||
- 重构插件注册或发现逻辑后
|
||||
- 重构插件注册或发现后
|
||||
|
||||
约定测试会在 CI 中运行,不需要真实 API key。
|
||||
契约测试会在 CI 中运行,并且不需要真实 API 密钥。
|
||||
|
||||
## 添加回归测试(指导)
|
||||
|
||||
当你修复一个在实时环境中发现的提供商 / 模型问题时:
|
||||
当你修复在 live 中发现的提供商/模型问题时:
|
||||
|
||||
- 如果可能,添加一个对 CI 安全的回归测试(模拟 / stub 提供商,或捕获确切的请求形状转换)
|
||||
- 如果它本质上只能在实时环境中复现(速率限制、认证策略),则让实时测试保持收窄,并通过环境变量显式启用
|
||||
- 优先瞄准能够捕获该缺陷的最小层级:
|
||||
- 提供商请求转换 / 重放缺陷 → 直接模型测试
|
||||
- Gateway 网关会话 / 历史 / 工具流水线缺陷 → gateway 实时冒烟测试或对 CI 安全的 gateway mock 测试
|
||||
- 如果可能,添加一个 CI 安全的回归测试(模拟/stub 提供商,或捕获精确的请求形状转换)
|
||||
- 如果它本质上只能通过 live 复现(速率限制、认证策略),就让 live 测试保持收窄,并通过环境变量按需启用
|
||||
- 优先定位到能捕获该缺陷的最小层级:
|
||||
- 提供商请求转换/重放缺陷 → 直接模型测试
|
||||
- gateway 会话/历史/工具流水线缺陷 → gateway live 冒烟测试或 CI 安全的 gateway mock 测试
|
||||
- SecretRef 遍历防护:
|
||||
- `src/secrets/exec-secret-ref-id-parity.test.ts` 会从注册表元数据(`listSecretTargetRegistryEntries()`)中为每个 SecretRef 类派生一个采样目标,然后断言遍历片段 exec id 会被拒绝。
|
||||
- 如果你在 `src/secrets/target-registry-data.ts` 中添加了新的 `includeInPlan` SecretRef 目标族,请更新该测试中的 `classifyTargetClass`。该测试会在遇到未分类目标 id 时有意失败,以确保新类别不会被静默跳过。
|
||||
- `src/secrets/exec-secret-ref-id-parity.test.ts` 会从注册表元数据(`listSecretTargetRegistryEntries()`)中为每个 SecretRef 类派生一个采样目标,然后断言遍历段 exec id 会被拒绝。
|
||||
- 如果你在 `src/secrets/target-registry-data.ts` 中添加了新的 `includeInPlan` SecretRef 目标族,请更新该测试中的 `classifyTargetClass`。该测试会在目标 id 未分类时故意失败,以防新类别被悄悄跳过。
|
||||
|
||||
## 相关内容
|
||||
|
||||
|
||||
@ -3,34 +3,35 @@ read_when:
|
||||
- 你希望一个 OpenClaw 智能体加入 Google Meet 通话
|
||||
- 你希望一个 OpenClaw 智能体创建新的 Google Meet 通话
|
||||
- 你正在将 Chrome、Chrome 节点或 Twilio 配置为 Google Meet 传输方式
|
||||
summary: Google Meet 插件:通过 Chrome 或 Twilio 加入显式的 Meet URL,并默认启用实时语音
|
||||
summary: Google Meet 插件:通过 Chrome 或 Twilio 加入指定的 Meet URL,并使用实时语音默认设置
|
||||
title: Google Meet 插件
|
||||
x-i18n:
|
||||
generated_at: "2026-04-24T22:14:45Z"
|
||||
generated_at: "2026-04-24T23:09:48Z"
|
||||
model: gpt-5.4
|
||||
provider: openai
|
||||
source_hash: 2438d52c6a3c98e9d2aa345790b72475bc26c3497580d6af15b6df221705864a
|
||||
source_hash: c12bc2abf8a9bddc56f1fc281e1f7d628ff10d1bcfc99541cd7a085eac017544
|
||||
source_path: plugins/google-meet.md
|
||||
workflow: 15
|
||||
---
|
||||
|
||||
OpenClaw 的 Google Meet 参与支持——该插件在设计上是显式的:
|
||||
OpenClaw 的 Google Meet 参会支持——该插件是按显式设计构建的:
|
||||
|
||||
- 它只会加入显式的 `https://meet.google.com/...` URL。
|
||||
- 它可以通过 Google Meet API 创建新的 Meet 空间,然后加入返回的 URL。
|
||||
- 它只加入显式的 `https://meet.google.com/...` URL。
|
||||
- 它可以通过 Google Meet API 创建一个新的 Meet 空间,然后加入返回的 URL。
|
||||
- `realtime` 语音是默认模式。
|
||||
- 实时语音在需要更深入推理或工具时,可以回调到完整的 OpenClaw 智能体。
|
||||
- 智能体通过 `mode` 选择加入行为:实时收听/回话使用 `realtime`,加入/控制浏览器但不启用实时语音桥接则使用 `transcribe`。
|
||||
- 认证起始方式可以是个人 Google OAuth,或已登录的 Chrome 配置文件。
|
||||
- 不会自动播报同意声明。
|
||||
- 当需要更深层的推理或工具时,实时语音可以回调到完整的 OpenClaw 智能体。
|
||||
- 智能体使用 `mode` 选择加入行为:实时收听/回话使用 `realtime`,加入/控制浏览器但不启用实时语音桥接则使用 `transcribe`。
|
||||
- 认证起始方式可以是个人 Google OAuth,或一个已经登录的 Chrome 配置文件。
|
||||
- 没有自动同意提示公告。
|
||||
- 默认的 Chrome 音频后端是 `BlackHole 2ch`。
|
||||
- Chrome 可以在本地运行,也可以在已配对的节点主机上运行。
|
||||
- Twilio 接受拨入号码以及可选的 PIN 或 DTMF 序列。
|
||||
- CLI 命令是 `googlemeet`;`meet` 保留给更广义的智能体电话会议工作流。
|
||||
- Twilio 接受一个拨入号码,以及可选的 PIN 或 DTMF 序列。
|
||||
- CLI 命令是 `googlemeet`;`meet` 保留给更广泛的智能体电话会议工作流使用。
|
||||
|
||||
## 快速开始
|
||||
|
||||
安装本地音频依赖并配置后端实时语音提供商。OpenAI 是默认项;Google Gemini Live 也可与 `realtime.provider: "google"` 配合使用:
|
||||
安装本地音频依赖,并配置一个后端实时语音提供商。OpenAI 是默认选项;Google Gemini Live 也可用于
|
||||
`realtime.provider: "google"`:
|
||||
|
||||
```bash
|
||||
brew install blackhole-2ch sox
|
||||
@ -45,14 +46,14 @@ export GEMINI_API_KEY=...
|
||||
sudo reboot
|
||||
```
|
||||
|
||||
重启后,验证这两部分都已就绪:
|
||||
重启后,验证这两项是否就绪:
|
||||
|
||||
```bash
|
||||
system_profiler SPAudioDataType | grep -i BlackHole
|
||||
command -v rec play
|
||||
```
|
||||
|
||||
启用插件:
|
||||
启用该插件:
|
||||
|
||||
```json5
|
||||
{
|
||||
@ -73,7 +74,9 @@ command -v rec play
|
||||
openclaw googlemeet setup
|
||||
```
|
||||
|
||||
设置输出旨在供智能体读取。它会报告 Chrome 配置文件、音频桥接、节点固定、延迟的实时介绍,以及在配置了 Twilio 委派时,`voice-call` 插件和 Twilio 凭证是否已就绪。请求智能体加入前,将任何 `ok: false` 检查都视为阻塞项。对脚本或机器可读输出使用 `openclaw googlemeet setup --json`。
|
||||
该设置输出旨在供智能体读取。它会报告 Chrome 配置文件、音频桥接、节点固定、延迟的实时引导,以及在配置了 Twilio 委派时,`voice-call` 插件和 Twilio 凭证是否已就绪。
|
||||
在要求智能体加入之前,将任何 `ok: false` 检查都视为阻塞项。
|
||||
脚本或机器可读输出请使用 `openclaw googlemeet setup --json`。
|
||||
|
||||
加入会议:
|
||||
|
||||
@ -92,7 +95,7 @@ openclaw googlemeet join https://meet.google.com/abc-defg-hij
|
||||
}
|
||||
```
|
||||
|
||||
创建新会议,然后加入:
|
||||
创建一个新会议,然后加入:
|
||||
|
||||
```bash
|
||||
openclaw googlemeet create
|
||||
@ -101,12 +104,12 @@ openclaw googlemeet join https://meet.google.com/new-abcd-xyz --transport chrome
|
||||
|
||||
`googlemeet create` 有两条路径:
|
||||
|
||||
- API 创建:当配置了 Google Meet OAuth 凭证时使用。这是最确定的路径,不依赖浏览器 UI 状态。
|
||||
- 浏览器回退:当 OAuth 凭证缺失时使用。OpenClaw 使用固定的 Chrome 节点,打开 `https://meet.google.com/new`,等待 Google 重定向到真实的会议代码 URL,然后返回该 URL。此路径要求节点上的 OpenClaw Chrome 配置文件已登录 Google。浏览器自动化会处理 Meet 自身的首次运行麦克风提示;该提示不会被视为 Google 登录失败。
|
||||
- API 创建:当已配置 Google Meet OAuth 凭证时使用。这是最确定性的路径,不依赖浏览器 UI 状态。
|
||||
- 浏览器回退:当 OAuth 凭证缺失时使用。OpenClaw 会使用固定的 Chrome 节点,打开 `https://meet.google.com/new`,等待 Google 重定向到真实的会议代码 URL,然后返回该 URL。此路径要求节点上的 OpenClaw Chrome 配置文件已经登录 Google。浏览器自动化会处理 Meet 自身的首次麦克风提示;该提示不会被视为 Google 登录失败。
|
||||
|
||||
命令输出包含 `source` 字段(`api` 或 `browser`),这样智能体就可以说明使用了哪条路径。
|
||||
命令输出包含一个 `source` 字段(`api` 或 `browser`),这样智能体就可以说明使用了哪条路径。
|
||||
|
||||
或者告诉智能体:“创建一个 Google Meet,用实时语音加入,并把链接发给我。” 智能体应先调用 `google_meet` 并使用 `action: "create"`,复制返回的 `meetingUri`,然后再调用 `google_meet` 并使用 `action: "join"` 以及该 URL。
|
||||
或者告诉智能体:“创建一个 Google Meet,用实时语音加入它,然后把链接发给我。” 智能体应先使用 `action: "create"` 调用 `google_meet`,复制返回的 `meetingUri`,然后再使用 `action: "join"` 和该 URL 调用 `google_meet`。
|
||||
|
||||
```json
|
||||
{
|
||||
@ -123,21 +126,21 @@ openclaw googlemeet join https://meet.google.com/new-abcd-xyz --transport chrome
|
||||
}
|
||||
```
|
||||
|
||||
如果只是观察或控制浏览器加入,请设置 `"mode": "transcribe"`。这不会启动双向实时模型桥接,因此不会在会议中回话。
|
||||
如果是仅观察/浏览器控制的加入,请设置 `"mode": "transcribe"`。这不会启动双向实时模型桥接,因此它不会在会议中回话。
|
||||
|
||||
Chrome 会以已登录的 Chrome 配置文件身份加入。在 Meet 中,选择 `BlackHole 2ch` 作为 OpenClaw 使用的麦克风/扬声器路径。为了获得干净的双向音频,请使用独立的虚拟设备或类似 Loopback 的音频图;单个 BlackHole 设备足以完成首次冒烟测试,但可能会产生回声。
|
||||
Chrome 会以已登录的 Chrome 配置文件身份加入。在 Meet 中,为 OpenClaw 使用的麦克风/扬声器路径选择 `BlackHole 2ch`。若要获得干净的双向音频,请使用独立的虚拟设备或类似 Loopback 的音频图;单个 BlackHole 设备足以完成首次冒烟测试,但可能会产生回声。
|
||||
|
||||
### 本地 Gateway 网关 + Parallels Chrome
|
||||
|
||||
你**不**需要在 macOS VM 内运行完整的 OpenClaw Gateway 网关或模型 API 密钥,只是为了让 VM 托管 Chrome。你可以在本地运行 Gateway 网关和智能体,然后在 VM 中运行节点主机。只需在 VM 中启用一次内置插件,这样节点就会通告 Chrome 命令:
|
||||
你**不**需要在 macOS VM 中运行完整的 OpenClaw Gateway 网关或配置模型 API 密钥,仅仅为了让 VM 承载 Chrome。你可以在本地运行 Gateway 网关和智能体,然后在 VM 中运行一个节点主机。只需在 VM 中启用一次内置插件,这样节点就会通告 Chrome 命令:
|
||||
|
||||
各组件运行位置:
|
||||
各部分运行位置:
|
||||
|
||||
- Gateway 网关主机:OpenClaw Gateway 网关、智能体工作区、模型/API 密钥、实时提供商,以及 Google Meet 插件配置。
|
||||
- Parallels macOS VM:OpenClaw CLI/节点主机、Google Chrome、SoX、BlackHole 2ch,以及一个已登录 Google 的 Chrome 配置文件。
|
||||
- VM 中不需要:Gateway 网关服务、智能体配置、OpenAI/GPT 密钥或模型提供商设置。
|
||||
- VM 中不需要:Gateway 网关服务、智能体配置、OpenAI/GPT 密钥,或模型提供商设置。
|
||||
|
||||
安装 VM 依赖项:
|
||||
安装 VM 依赖:
|
||||
|
||||
```bash
|
||||
brew install blackhole-2ch sox
|
||||
@ -168,7 +171,7 @@ openclaw plugins enable google-meet
|
||||
openclaw node run --host <gateway-host> --port 18789 --display-name parallels-macos
|
||||
```
|
||||
|
||||
如果 `<gateway-host>` 是 LAN IP,并且你未使用 TLS,节点会拒绝明文 WebSocket,除非你为该受信任私有网络显式启用:
|
||||
如果 `<gateway-host>` 是局域网 IP,并且你未使用 TLS,那么除非你为该受信任的私有网络显式启用,否则节点会拒绝明文 WebSocket:
|
||||
|
||||
```bash
|
||||
OPENCLAW_ALLOW_INSECURE_PRIVATE_WS=1 \
|
||||
@ -183,7 +186,7 @@ OPENCLAW_ALLOW_INSECURE_PRIVATE_WS=1 \
|
||||
openclaw node restart
|
||||
```
|
||||
|
||||
`OPENCLAW_ALLOW_INSECURE_PRIVATE_WS=1` 是进程环境,不是 `openclaw.json` 设置。`openclaw node install` 会在安装命令中检测到它存在时,将其存储到 LaunchAgent 环境中。
|
||||
`OPENCLAW_ALLOW_INSECURE_PRIVATE_WS=1` 是进程环境,不是 `openclaw.json` 设置。`openclaw node install` 会在安装命令中存在该变量时,将其存储到 LaunchAgent 环境中。
|
||||
|
||||
从 Gateway 网关主机批准该节点:
|
||||
|
||||
@ -192,7 +195,7 @@ openclaw devices list
|
||||
openclaw devices approve <requestId>
|
||||
```
|
||||
|
||||
确认 Gateway 网关能看到该节点,并且它通告了 `googlemeet.chrome` 以及浏览器能力/`browser.proxy`:
|
||||
确认 Gateway 网关能看到该节点,并且它同时通告了 `googlemeet.chrome` 和浏览器能力/`browser.proxy`:
|
||||
|
||||
```bash
|
||||
openclaw nodes status
|
||||
@ -228,62 +231,68 @@ openclaw nodes status
|
||||
}
|
||||
```
|
||||
|
||||
现在可从 Gateway 网关主机正常加入:
|
||||
现在可以像平常一样从 Gateway 网关主机加入:
|
||||
|
||||
```bash
|
||||
openclaw googlemeet join https://meet.google.com/abc-defg-hij
|
||||
```
|
||||
|
||||
或者要求智能体使用 `google_meet` 工具,并设置 `transport: "chrome-node"`。
|
||||
或者让智能体使用 `google_meet` 工具,并设置 `transport: "chrome-node"`。
|
||||
|
||||
如需一个单命令冒烟测试,以创建或复用会话、说出已知短语并打印会话健康状态:
|
||||
如果要运行一个单命令冒烟测试,用于创建或复用会话、说出一段已知短语并打印会话健康状态:
|
||||
|
||||
```bash
|
||||
openclaw googlemeet test-speech https://meet.google.com/abc-defg-hij
|
||||
```
|
||||
|
||||
加入过程中,OpenClaw 浏览器自动化会填写访客姓名、点击加入/请求加入,并在出现时接受 Meet 首次运行的“使用麦克风”选择。在仅通过浏览器创建会议时,如果 Meet 未暴露使用麦克风按钮,它也可以在无麦克风的情况下继续越过同一提示。如果浏览器配置文件未登录、Meet 正在等待主持人准入、Chrome 需要麦克风/摄像头权限,或者 Meet 卡在自动化无法解决的提示上,加入/`test-speech` 结果会报告 `manualActionRequired: true`,并附带 `manualActionReason` 和 `manualActionMessage`。智能体应停止重试加入,报告该确切消息以及当前的 `browserUrl`/`browserTitle`,并且只在手动浏览器操作完成后再重试。
|
||||
在加入过程中,OpenClaw 浏览器自动化会填写访客姓名、点击加入/请求加入,并在出现该提示时接受 Meet 的首次“使用麦克风”选择。在仅通过浏览器创建会议期间,如果 Meet 没有暴露使用麦克风按钮,它也可以在不使用麦克风的情况下继续通过相同提示。
|
||||
如果浏览器配置文件未登录、Meet 正在等待主持人准入、Chrome 需要麦克风/摄像头权限,或 Meet 卡在自动化无法解决的提示上,那么 join/test-speech 结果会报告
|
||||
`manualActionRequired: true`,并附带 `manualActionReason` 和
|
||||
`manualActionMessage`。智能体应停止重试加入,报告该确切消息以及当前的 `browserUrl`/`browserTitle`,并且只在手动浏览器操作完成后再重试。
|
||||
|
||||
如果省略 `chromeNode.node`,只有在恰好存在一个已连接节点同时通告 `googlemeet.chrome` 和浏览器控制时,OpenClaw 才会自动选择。如果连接了多个具备能力的节点,请将 `chromeNode.node` 设置为节点 id、显示名称或远程 IP。
|
||||
如果省略 `chromeNode.node`,只有在恰好有一个已连接节点同时通告 `googlemeet.chrome` 和浏览器控制时,OpenClaw 才会自动选择。
|
||||
如果连接了多个具备能力的节点,请将 `chromeNode.node` 设置为节点 id、显示名称或远程 IP。
|
||||
|
||||
常见故障检查:
|
||||
|
||||
- `No connected Google Meet-capable node`:在 VM 中启动 `openclaw node run`,批准配对,并确保已在 VM 中运行 `openclaw plugins enable google-meet` 和 `openclaw plugins enable browser`。同时确认 Gateway 网关主机允许这两个节点命令:
|
||||
- `No connected Google Meet-capable node`:在 VM 中启动 `openclaw node run`,批准配对,并确保已在 VM 中运行 `openclaw plugins enable google-meet` 和 `openclaw plugins enable browser`。另外还要确认 Gateway 网关主机允许这两个节点命令:
|
||||
`gateway.nodes.allowCommands: ["googlemeet.chrome", "browser.proxy"]`。
|
||||
- `BlackHole 2ch audio device not found on the node`:在 VM 中安装 `blackhole-2ch` 并重启 VM。
|
||||
- Chrome 已打开但无法加入:在 VM 内登录浏览器配置文件,或保持设置 `chrome.guestName` 以访客身份加入。访客自动加入使用 OpenClaw 通过节点浏览器代理进行的浏览器自动化;请确保节点浏览器配置指向你想使用的配置文件,例如 `browser.defaultProfile: "user"` 或已存在会话的命名配置文件。
|
||||
- 重复的 Meet 标签页:保持启用 `chrome.reuseExistingTab: true`。OpenClaw 会在打开新标签页前激活相同 Meet URL 的现有标签页。
|
||||
- 没有音频:在 Meet 中,将麦克风/扬声器路由到 OpenClaw 使用的虚拟音频设备路径;使用独立虚拟设备或类似 Loopback 的路由以获得干净的双向音频。
|
||||
- Chrome 可以打开但无法加入:在 VM 中登录浏览器配置文件,或者保留 `chrome.guestName` 用于访客加入。访客自动加入通过节点浏览器代理使用 OpenClaw 浏览器自动化;请确保节点浏览器配置指向你想使用的配置文件,例如
|
||||
`browser.defaultProfile: "user"` 或某个已命名的 existing-session 配置文件。
|
||||
- 重复的 Meet 标签页:保持启用 `chrome.reuseExistingTab: true`。OpenClaw 会在打开新标签页之前,为相同 Meet URL 激活现有标签页;浏览器创建会议时,也会在打开新标签页之前复用进行中的 `https://meet.google.com/new` 或 Google 账户提示标签页。
|
||||
- 没有音频:在 Meet 中,将麦克风/扬声器路由到 OpenClaw 使用的虚拟音频设备路径;若要获得干净的双向音频,请使用独立的虚拟设备或类似 Loopback 的路由方式。
|
||||
|
||||
## 安装说明
|
||||
|
||||
Chrome 实时默认值使用两个外部工具:
|
||||
Chrome 实时默认配置会使用两个外部工具:
|
||||
|
||||
- `sox`:命令行音频工具。该插件使用它的 `rec` 和 `play` 命令来实现默认的 8 kHz G.711 mu-law 音频桥接。
|
||||
- `blackhole-2ch`:macOS 虚拟音频驱动。它会创建 `BlackHole 2ch` 音频设备,供 Chrome/Meet 通过其进行路由。
|
||||
- `blackhole-2ch`:macOS 虚拟音频驱动。它会创建 `BlackHole 2ch` 音频设备,供 Chrome/Meet 路由使用。
|
||||
|
||||
OpenClaw 不会内置或重新分发这两个软件包。文档要求用户通过 Homebrew 将它们作为主机依赖安装。SoX 采用 `LGPL-2.0-only AND GPL-2.0-only` 许可;BlackHole 采用 GPL-3.0 许可。如果你构建的安装程序或设备将 BlackHole 与 OpenClaw 一起打包,请查看 BlackHole 上游许可条款,或从 Existential Audio 获取单独许可。
|
||||
OpenClaw 不内置,也不重新分发这两个软件包。文档要求用户通过 Homebrew 将它们作为主机依赖安装。SoX 的许可证为
|
||||
`LGPL-2.0-only AND GPL-2.0-only`;BlackHole 为 GPL-3.0。如果你构建的是一个将 BlackHole 与 OpenClaw 一起打包的安装程序或设备,请审查 BlackHole 上游许可证条款,或向 Existential Audio 获取单独许可。
|
||||
|
||||
## 传输方式
|
||||
|
||||
### Chrome
|
||||
|
||||
Chrome 传输方式会在 Google Chrome 中打开 Meet URL,并以已登录的 Chrome 配置文件身份加入。在 macOS 上,插件会在启动前检查 `BlackHole 2ch`。如果已配置,它还会在打开 Chrome 前运行音频桥接健康检查命令和启动命令。当 Chrome/音频位于 Gateway 网关主机上时,请使用 `chrome`;当 Chrome/音频位于已配对节点上(例如 Parallels macOS VM)时,请使用 `chrome-node`。
|
||||
Chrome 传输方式会在 Google Chrome 中打开 Meet URL,并以已登录的 Chrome 配置文件身份加入。在 macOS 上,插件会在启动前检查 `BlackHole 2ch`。如果已配置,它还会在打开 Chrome 前运行音频桥接健康检查命令和启动命令。当 Chrome/音频运行在 Gateway 网关主机上时,请使用 `chrome`;当 Chrome/音频运行在已配对节点上(例如 Parallels macOS VM)时,请使用 `chrome-node`。
|
||||
|
||||
```bash
|
||||
openclaw googlemeet join https://meet.google.com/abc-defg-hij --transport chrome
|
||||
openclaw googlemeet join https://meet.google.com/abc-defg-hij --transport chrome-node
|
||||
```
|
||||
|
||||
将 Chrome 的麦克风和扬声器音频路由到本地 OpenClaw 音频桥接。如果未安装 `BlackHole 2ch`,加入会因设置错误而失败,而不是在没有音频路径的情况下静默加入。
|
||||
通过本地 OpenClaw 音频桥接来路由 Chrome 麦克风和扬声器音频。如果未安装 `BlackHole 2ch`,加入会以设置错误失败,而不是静默地在没有音频路径的情况下加入。
|
||||
|
||||
### Twilio
|
||||
|
||||
Twilio 传输方式是一个严格的拨号计划,委派给 Voice Call 插件。它不会从 Meet 页面解析电话号码。
|
||||
Twilio 传输方式是一个严格的拨号计划,由 Voice Call 插件委派执行。它不会解析 Meet 页面中的电话号码。
|
||||
|
||||
当无法使用 Chrome 参与,或你想要电话拨入回退方案时,请使用此方式。Google Meet 必须为该会议提供电话拨入号码和 PIN;OpenClaw 不会从 Meet 页面中发现这些信息。
|
||||
当无法使用 Chrome 参会,或者你想使用电话拨入作为后备方案时,请使用此方式。Google Meet 必须为该会议暴露电话拨入号码和 PIN;OpenClaw 不会从 Meet 页面中发现这些信息。
|
||||
|
||||
在 Gateway 网关主机上启用 Voice Call 插件,而不是在 Chrome 节点上:
|
||||
请在 Gateway 网关主机上启用 Voice Call 插件,而不是在 Chrome 节点上:
|
||||
|
||||
```json5
|
||||
{
|
||||
@ -294,7 +303,7 @@ Twilio 传输方式是一个严格的拨号计划,委派给 Voice Call 插件
|
||||
enabled: true,
|
||||
config: {
|
||||
defaultTransport: "chrome-node",
|
||||
// 或设置为 "twilio",如果 Twilio 应为默认值
|
||||
// 或者设置为 "twilio",如果应将 Twilio 作为默认选项
|
||||
},
|
||||
},
|
||||
"voice-call": {
|
||||
@ -308,7 +317,7 @@ Twilio 传输方式是一个严格的拨号计划,委派给 Voice Call 插件
|
||||
}
|
||||
```
|
||||
|
||||
通过环境变量或配置提供 Twilio 凭证。使用环境变量可以让密钥不出现在 `openclaw.json` 中:
|
||||
通过环境变量或配置提供 Twilio 凭证。环境变量可以将密钥保留在 `openclaw.json` 之外:
|
||||
|
||||
```bash
|
||||
export TWILIO_ACCOUNT_SID=AC...
|
||||
@ -316,7 +325,7 @@ export TWILIO_AUTH_TOKEN=...
|
||||
export TWILIO_FROM_NUMBER=+15550001234
|
||||
```
|
||||
|
||||
启用 `voice-call` 后,重启或重新加载 Gateway 网关;在 Gateway 网关进程重新加载前,插件配置更改不会出现在已运行的 Gateway 网关进程中。
|
||||
启用 `voice-call` 后,重启或重新加载 Gateway 网关;在 Gateway 网关进程重新加载之前,插件配置更改不会出现在已运行的 Gateway 网关进程中。
|
||||
|
||||
然后验证:
|
||||
|
||||
@ -326,7 +335,8 @@ openclaw plugins list | grep -E 'google-meet|voice-call'
|
||||
openclaw googlemeet setup
|
||||
```
|
||||
|
||||
当 Twilio 委派接线完成后,`googlemeet setup` 会包含成功的 `twilio-voice-call-plugin` 和 `twilio-voice-call-credentials` 检查。
|
||||
当 Twilio 委派接线完成后,`googlemeet setup` 会包含成功的
|
||||
`twilio-voice-call-plugin` 和 `twilio-voice-call-credentials` 检查。
|
||||
|
||||
```bash
|
||||
openclaw googlemeet join https://meet.google.com/abc-defg-hij \
|
||||
@ -335,7 +345,7 @@ openclaw googlemeet join https://meet.google.com/abc-defg-hij \
|
||||
--pin 123456
|
||||
```
|
||||
|
||||
当会议需要自定义序列时,使用 `--dtmf-sequence`:
|
||||
如果会议需要自定义序列,请使用 `--dtmf-sequence`:
|
||||
|
||||
```bash
|
||||
openclaw googlemeet join https://meet.google.com/abc-defg-hij \
|
||||
@ -346,21 +356,22 @@ openclaw googlemeet join https://meet.google.com/abc-defg-hij \
|
||||
|
||||
## OAuth 和预检
|
||||
|
||||
OAuth 对于创建 Meet 链接来说是可选的,因为 `googlemeet create` 可以回退到浏览器自动化。当你需要官方 API 创建、空间解析或 Meet Media API 预检时,请配置 OAuth。
|
||||
OAuth 对于创建 Meet 链接是可选的,因为 `googlemeet create` 可以回退到浏览器自动化。当你需要正式的 API 创建、空间解析或 Meet Media API 预检时,请配置 OAuth。
|
||||
|
||||
Google Meet API 访问首先使用个人 OAuth 客户端。配置 `oauth.clientId`,并可选配置 `oauth.clientSecret`,然后运行:
|
||||
Google Meet API 访问优先使用个人 OAuth 客户端。配置
|
||||
`oauth.clientId`,并可选配置 `oauth.clientSecret`,然后运行:
|
||||
|
||||
```bash
|
||||
openclaw googlemeet auth login --json
|
||||
```
|
||||
|
||||
该命令会打印一个带有刷新令牌的 `oauth` 配置块。它使用 PKCE、`http://localhost:8085/oauth2callback` 上的 localhost 回调,以及通过 `--manual` 进行的手动复制/粘贴流程。
|
||||
该命令会打印一个带刷新令牌的 `oauth` 配置块。它使用 PKCE、本地主机回调 `http://localhost:8085/oauth2callback`,并通过 `--manual` 提供手动复制/粘贴流程。
|
||||
|
||||
OAuth 同意范围包括 Meet 空间创建、Meet 空间读取访问以及 Meet 会议媒体读取访问。如果你在会议创建支持存在之前就已完成认证,请重新运行 `openclaw googlemeet auth login --json`,以便刷新令牌包含 `meetings.space.created` scope。
|
||||
OAuth 同意范围包括 Meet 空间创建、Meet 空间读取权限以及 Meet 会议媒体读取权限。如果你是在支持会议创建之前完成认证的,请重新运行 `openclaw googlemeet auth login --json`,以便刷新令牌具备 `meetings.space.created` scope。
|
||||
|
||||
浏览器回退不需要 OAuth 凭证。在该模式下,Google 认证来自所选节点上已登录的 Chrome 配置文件,而不是来自 OpenClaw 配置。
|
||||
浏览器回退不需要 OAuth 凭证。在该模式下,Google 认证来自所选节点上已登录的 Chrome 配置文件,而不是 OpenClaw 配置。
|
||||
|
||||
接受以下环境变量作为回退:
|
||||
支持以下环境变量作为回退值:
|
||||
|
||||
- `OPENCLAW_GOOGLE_MEET_CLIENT_ID` 或 `GOOGLE_MEET_CLIENT_ID`
|
||||
- `OPENCLAW_GOOGLE_MEET_CLIENT_SECRET` 或 `GOOGLE_MEET_CLIENT_SECRET`
|
||||
@ -377,7 +388,7 @@ OAuth 同意范围包括 Meet 空间创建、Meet 空间读取访问以及 Meet
|
||||
openclaw googlemeet resolve-space --meeting https://meet.google.com/abc-defg-hij
|
||||
```
|
||||
|
||||
在进行媒体工作前运行预检:
|
||||
在媒体工作前运行预检:
|
||||
|
||||
```bash
|
||||
openclaw googlemeet preflight --meeting https://meet.google.com/abc-defg-hij
|
||||
@ -389,7 +400,7 @@ openclaw googlemeet preflight --meeting https://meet.google.com/abc-defg-hij
|
||||
openclaw googlemeet create
|
||||
```
|
||||
|
||||
该命令会打印新的 `meeting uri` 和来源。使用 OAuth 凭证时,它会使用官方 Google Meet API。没有 OAuth 凭证时,它会回退到使用固定的 Chrome 节点上已登录的浏览器配置文件。智能体可以使用 `google_meet` 工具并设置 `action: "create"` 来创建会议,然后使用返回的 `meetingUri` 调用 `action: "join"`。
|
||||
该命令会打印新的 `meeting uri` 和来源。使用 OAuth 凭证时,它会使用正式的 Google Meet API。没有 OAuth 凭证时,它会回退为使用固定 Chrome 节点上已登录的浏览器配置文件。智能体可以使用带 `action: "create"` 的 `google_meet` 工具来创建会议,然后使用返回的 `meetingUri` 通过 `action: "join"` 调用。
|
||||
|
||||
浏览器回退的 JSON 输出示例:
|
||||
|
||||
@ -418,13 +429,15 @@ API 创建的 JSON 输出示例:
|
||||
}
|
||||
```
|
||||
|
||||
创建 Meet 只会创建或发现会议 URL。`chrome` 或 `chrome-node` 传输方式仍然需要一个已登录 Google 的 Chrome 配置文件,才能通过浏览器加入。如果该配置文件已退出登录,OpenClaw 会报告 `manualActionRequired: true` 或浏览器回退错误,并要求操作员在重试前完成 Google 登录。
|
||||
创建 Meet 只会创建或发现会议 URL。`chrome` 或 `chrome-node` 传输方式仍然需要一个已登录 Google 的 Chrome 配置文件,才能通过浏览器加入。如果该配置文件已登出,OpenClaw 会报告
|
||||
`manualActionRequired: true` 或浏览器回退错误,并要求操作员在重试前完成 Google 登录。
|
||||
|
||||
仅在确认你的 Cloud 项目、OAuth principal 和会议参与者都已加入用于 Meet 媒体 API 的 Google Workspace Developer Preview Program 后,才设置 `preview.enrollmentAcknowledged: true`。
|
||||
只有在确认你的 Cloud 项目、OAuth 主体和会议参与者都已加入 Google Workspace Developer Preview Program for Meet media APIs 之后,才设置 `preview.enrollmentAcknowledged: true`。
|
||||
|
||||
## 配置
|
||||
|
||||
常见的 Chrome 实时路径只需要启用插件、安装 BlackHole、SoX,以及配置后端实时语音提供商密钥。OpenAI 是默认值;设置 `realtime.provider: "google"` 可使用 Google Gemini Live:
|
||||
常见的 Chrome 实时路径只需要启用插件、安装 BlackHole、SoX,以及提供一个后端实时语音提供商密钥。OpenAI 是默认选项;设置
|
||||
`realtime.provider: "google"` 可使用 Google Gemini Live:
|
||||
|
||||
```bash
|
||||
brew install blackhole-2ch sox
|
||||
@ -452,17 +465,18 @@ export GEMINI_API_KEY=...
|
||||
|
||||
- `defaultTransport: "chrome"`
|
||||
- `defaultMode: "realtime"`
|
||||
- `chromeNode.node`:`chrome-node` 的可选节点 id/名称/IP
|
||||
- `chromeNode.node`:`chrome-node` 可选的节点 id/名称/IP
|
||||
- `chrome.audioBackend: "blackhole-2ch"`
|
||||
- `chrome.guestName: "OpenClaw Agent"`:在已退出登录的 Meet 访客界面上使用的名称
|
||||
- `chrome.autoJoin: true`:在 `chrome-node` 上通过 OpenClaw 浏览器自动化尽力填写访客名并点击立即加入
|
||||
- `chrome.guestName: "OpenClaw Agent"`:在已登出 Meet 访客界面中使用的名称
|
||||
- `chrome.autoJoin: true`:通过 OpenClaw 浏览器自动化在 `chrome-node` 上尽力填写访客名并点击立即加入
|
||||
- `chrome.reuseExistingTab: true`:激活现有 Meet 标签页,而不是打开重复标签页
|
||||
- `chrome.waitForInCallMs: 20000`:在触发实时介绍前,等待 Meet 标签页报告已在通话中
|
||||
- `chrome.audioInputCommand`:将 8 kHz G.711 mu-law 音频写入 stdout 的 SoX `rec` 命令
|
||||
- `chrome.audioOutputCommand`:从 stdin 读取 8 kHz G.711 mu-law 音频的 SoX `play` 命令
|
||||
- `chrome.waitForInCallMs: 20000`:在触发实时引导前,等待 Meet 标签页报告已在通话中
|
||||
- `chrome.audioInputCommand`:SoX `rec` 命令,将 8 kHz G.711 mu-law 音频写入 stdout
|
||||
- `chrome.audioOutputCommand`:SoX `play` 命令,从 stdin 读取 8 kHz G.711 mu-law 音频
|
||||
- `realtime.provider: "openai"`
|
||||
- `realtime.toolPolicy: "safe-read-only"`
|
||||
- `realtime.instructions`:简短的口头回复,较深入的回答使用 `openclaw_agent_consult`
|
||||
- `realtime.instructions`:简短口头回复,较深入的回答使用
|
||||
`openclaw_agent_consult`
|
||||
- `realtime.introMessage`:实时桥接连接时的简短口头就绪检查;将其设置为 `""` 可静默加入
|
||||
|
||||
可选覆盖项:
|
||||
@ -483,7 +497,7 @@ export GEMINI_API_KEY=...
|
||||
realtime: {
|
||||
provider: "google",
|
||||
toolPolicy: "owner",
|
||||
introMessage: "Say exactly: I'm here.",
|
||||
introMessage: "准确地说:我到了。",
|
||||
providers: {
|
||||
google: {
|
||||
model: "gemini-2.5-flash-native-audio-preview-12-2025",
|
||||
@ -509,7 +523,7 @@ export GEMINI_API_KEY=...
|
||||
}
|
||||
```
|
||||
|
||||
`voiceCall.enabled` 默认为 `true`;使用 Twilio 传输方式时,它会将实际的 PSTN 呼叫和 DTMF 委派给 Voice Call 插件。如果未启用 `voice-call`,Google Meet 仍然可以验证并记录拨号计划,但无法发起 Twilio 呼叫。
|
||||
`voiceCall.enabled` 默认为 `true`;使用 Twilio 传输时,它会将实际的 PSTN 呼叫和 DTMF 委派给 Voice Call 插件。如果未启用 `voice-call`,Google Meet 仍然可以验证并记录拨号计划,但无法发起 Twilio 呼叫。
|
||||
|
||||
## 工具
|
||||
|
||||
@ -524,74 +538,77 @@ export GEMINI_API_KEY=...
|
||||
}
|
||||
```
|
||||
|
||||
当 Chrome 在 Gateway 网关主机上运行时,使用 `transport: "chrome"`。当 Chrome 在已配对节点上运行时,例如 Parallels VM,使用 `transport: "chrome-node"`。在这两种情况下,实时模型和 `openclaw_agent_consult` 都运行在 Gateway 网关主机上,因此模型凭证会保留在那里。
|
||||
当 Chrome 在 Gateway 网关主机上运行时,使用 `transport: "chrome"`。当 Chrome 在已配对节点上运行时,例如 Parallels VM,请使用
|
||||
`transport: "chrome-node"`。在这两种情况下,实时模型和 `openclaw_agent_consult` 都运行在 Gateway 网关主机上,因此模型凭证会保留在那里。
|
||||
|
||||
使用 `action: "status"` 可列出活动会话或检查某个会话 ID。使用带有 `sessionId` 和 `message` 的 `action: "speak"` 可让实时智能体立即发言。使用 `action: "test_speech"` 可创建或复用会话,触发一段已知短语,并在 Chrome 主机可报告时返回 `inCall` 健康状态。使用 `action: "leave"` 可将会话标记为已结束。
|
||||
使用 `action: "status"` 可列出活动会话或检查某个会话 ID。使用带 `sessionId` 和 `message` 的 `action: "speak"` 可让实时智能体立即发言。使用 `action: "test_speech"` 可创建或复用会话、触发一段已知短语,并在 Chrome 主机可报告时返回 `inCall` 健康状态。使用 `action: "leave"` 可将会话标记为已结束。
|
||||
|
||||
`status` 在可用时包含 Chrome 健康状态:
|
||||
`status` 在可用时包含 Chrome 健康信息:
|
||||
|
||||
- `inCall`:Chrome 似乎已进入 Meet 通话
|
||||
- `micMuted`:尽力获取的 Meet 麦克风状态
|
||||
- `manualActionRequired` / `manualActionReason` / `manualActionMessage`:浏览器配置文件需要手动登录、Meet 主持人准入、权限授予或浏览器控制修复后,语音功能才能工作
|
||||
- `inCall`:Chrome 看起来已进入 Meet 通话
|
||||
- `micMuted`:尽力检测的 Meet 麦克风状态
|
||||
- `manualActionRequired` / `manualActionReason` / `manualActionMessage`:浏览器配置文件需要手动登录、Meet 主持人准入、权限授予,或浏览器控制修复,发言功能才能正常工作
|
||||
- `providerConnected` / `realtimeReady`:实时语音桥接状态
|
||||
- `lastInputAt` / `lastOutputAt`:桥接最近一次接收或发送音频的时间
|
||||
- `lastInputAt` / `lastOutputAt`:桥接最近一次收到或发送音频的时间
|
||||
|
||||
```json
|
||||
{
|
||||
"action": "speak",
|
||||
"sessionId": "meet_...",
|
||||
"message": "Say exactly: I'm here and listening."
|
||||
"message": "准确地说:我到了,而且正在听。"
|
||||
}
|
||||
```
|
||||
|
||||
## 实时智能体咨询
|
||||
|
||||
Chrome 实时模式针对实时语音循环进行了优化。实时语音提供商会听取会议音频,并通过已配置的音频桥进行发言。当实时模型需要更深入的推理、最新信息或普通 OpenClaw 工具时,它可以调用 `openclaw_agent_consult`。
|
||||
Chrome 实时模式针对实时语音循环进行了优化。实时语音提供商会听取会议音频,并通过配置的音频桥接发声。当实时模型需要更深入的推理、最新信息或普通 OpenClaw 工具时,它可以调用 `openclaw_agent_consult`。
|
||||
|
||||
该咨询工具会在后台运行常规 OpenClaw 智能体,并附带最近的会议转录上下文,然后向实时语音会话返回简洁的口头回答。随后语音模型可以将该回答说回会议中。它与 Voice Call 共用同一个实时咨询工具。
|
||||
咨询工具会在后台运行常规 OpenClaw 智能体,结合最近的会议转录上下文,并向实时语音会话返回简洁的口头回答。随后语音模型就可以将该回答说回会议中。它与 Voice Call 共用同一个实时咨询工具。
|
||||
|
||||
`realtime.toolPolicy` 控制咨询运行:
|
||||
|
||||
- `safe-read-only`:暴露咨询工具,并将常规智能体限制为使用 `read`、`web_search`、`web_fetch`、`x_search`、`memory_search` 和 `memory_get`。
|
||||
- `safe-read-only`:暴露咨询工具,并将常规智能体限制为
|
||||
`read`、`web_search`、`web_fetch`、`x_search`、`memory_search` 和
|
||||
`memory_get`。
|
||||
- `owner`:暴露咨询工具,并允许常规智能体使用正常的智能体工具策略。
|
||||
- `none`:不向实时语音模型暴露咨询工具。
|
||||
|
||||
咨询会话键按 Meet 会话进行作用域隔离,因此在同一会议期间,后续咨询调用可以复用先前的咨询上下文。
|
||||
咨询会话键按每个 Meet 会话进行作用域划分,因此在同一场会议期间,后续咨询调用可以复用先前的咨询上下文。
|
||||
|
||||
要在 Chrome 已完全加入通话后强制执行一次口头就绪检查:
|
||||
要在 Chrome 完全加入通话后强制执行一次口头就绪检查:
|
||||
|
||||
```bash
|
||||
openclaw googlemeet speak meet_... "Say exactly: I'm here and listening."
|
||||
openclaw googlemeet speak meet_... "准确地说:我到了,而且正在听。"
|
||||
```
|
||||
|
||||
用于完整的加入并发言冒烟测试:
|
||||
如果要执行完整的加入并发言冒烟测试:
|
||||
|
||||
```bash
|
||||
openclaw googlemeet test-speech https://meet.google.com/abc-defg-hij \
|
||||
--transport chrome-node \
|
||||
--message "Say exactly: I'm here and listening."
|
||||
--message "准确地说:我到了,而且正在听。"
|
||||
```
|
||||
|
||||
## 实时测试检查清单
|
||||
|
||||
在将会议交给无人值守智能体前,请使用以下顺序:
|
||||
在将会议交给无人值守智能体之前,请使用以下顺序:
|
||||
|
||||
```bash
|
||||
openclaw googlemeet setup
|
||||
openclaw nodes status
|
||||
openclaw googlemeet test-speech https://meet.google.com/abc-defg-hij \
|
||||
--transport chrome-node \
|
||||
--message "Say exactly: Google Meet speech test complete."
|
||||
--message "准确地说:Google Meet 发言测试完成。"
|
||||
```
|
||||
|
||||
预期的 `chrome-node` 状态:
|
||||
预期的 Chrome-node 状态:
|
||||
|
||||
- `googlemeet setup` 全部为绿色。
|
||||
- `nodes status` 显示所选节点已连接。
|
||||
- 所选节点同时通告了 `googlemeet.chrome` 和 `browser.proxy`。
|
||||
- Meet 标签页加入通话,并且 `test-speech` 返回带有 `inCall: true` 的 Chrome 健康状态。
|
||||
- 所选节点同时通告 `googlemeet.chrome` 和 `browser.proxy`。
|
||||
- Meet 标签页已加入通话,并且 `test-speech` 返回带有 `inCall: true` 的 Chrome 健康状态。
|
||||
|
||||
对于 Twilio 冒烟测试,请使用一个会公开电话拨入详情的会议:
|
||||
如果是 Twilio 冒烟测试,请使用一个会暴露电话拨入详情的会议:
|
||||
|
||||
```bash
|
||||
openclaw googlemeet setup
|
||||
@ -603,10 +620,11 @@ openclaw googlemeet join https://meet.google.com/abc-defg-hij \
|
||||
|
||||
预期的 Twilio 状态:
|
||||
|
||||
- `googlemeet setup` 包含绿色的 `twilio-voice-call-plugin` 和 `twilio-voice-call-credentials` 检查。
|
||||
- `googlemeet setup` 包含绿色的 `twilio-voice-call-plugin` 和
|
||||
`twilio-voice-call-credentials` 检查。
|
||||
- Gateway 网关重新加载后,CLI 中可用 `voicecall`。
|
||||
- 返回的会话带有 `transport: "twilio"` 和 `twilio.voiceCallId`。
|
||||
- `googlemeet leave <sessionId>` 会挂断被委派的语音通话。
|
||||
- 返回的会话具有 `transport: "twilio"` 和一个 `twilio.voiceCallId`。
|
||||
- `googlemeet leave <sessionId>` 会挂断已委派的语音呼叫。
|
||||
|
||||
## 故障排除
|
||||
|
||||
@ -619,9 +637,10 @@ openclaw plugins list | grep google-meet
|
||||
openclaw googlemeet setup
|
||||
```
|
||||
|
||||
如果你刚刚编辑了 `plugins.entries.google-meet`,请重启或重新加载 Gateway 网关。正在运行的智能体只能看到由当前 Gateway 网关进程注册的插件工具。
|
||||
如果你刚刚编辑了 `plugins.entries.google-meet`,请重启或重新加载 Gateway 网关。
|
||||
正在运行的智能体只能看到当前 Gateway 网关进程已注册的插件工具。
|
||||
|
||||
### 没有已连接的 Google Meet 可用节点
|
||||
### 没有已连接的 Google Meet 能力节点
|
||||
|
||||
在节点主机上,运行:
|
||||
|
||||
@ -640,7 +659,8 @@ openclaw devices approve <requestId>
|
||||
openclaw nodes status
|
||||
```
|
||||
|
||||
节点必须已连接,并列出 `googlemeet.chrome` 以及 `browser.proxy`。Gateway 网关配置必须允许这些节点命令:
|
||||
该节点必须处于已连接状态,并列出 `googlemeet.chrome` 以及 `browser.proxy`。
|
||||
Gateway 网关配置必须允许这些节点命令:
|
||||
|
||||
```json5
|
||||
{
|
||||
@ -654,28 +674,32 @@ openclaw nodes status
|
||||
|
||||
### 浏览器已打开,但智能体无法加入
|
||||
|
||||
运行 `googlemeet test-speech` 并检查返回的 Chrome 健康状态。如果它报告 `manualActionRequired: true`,请向操作员显示 `manualActionMessage`,并在浏览器操作完成前停止重试。
|
||||
运行 `googlemeet test-speech` 并检查返回的 Chrome 健康状态。如果它报告
|
||||
`manualActionRequired: true`,请向操作员展示 `manualActionMessage`,并在浏览器操作完成前停止重试。
|
||||
|
||||
常见手动操作:
|
||||
常见的手动操作:
|
||||
|
||||
- 登录 Chrome 配置文件。
|
||||
- 从 Meet 主持人账号准入访客。
|
||||
- 从 Meet 主持人账户准入访客。
|
||||
- 当出现 Chrome 原生权限提示时,授予 Chrome 麦克风/摄像头权限。
|
||||
- 关闭或修复卡住的 Meet 权限对话框。
|
||||
|
||||
如果 Meet 显示“Do you want people to hear you in the meeting?”,不要仅因此就报告“未登录”。这是 Meet 的音频选择过渡页;OpenClaw 会在可用时通过浏览器自动化点击**使用麦克风**,并继续等待真正的会议状态。对于仅创建的浏览器回退,OpenClaw 可能会点击**继续且不使用麦克风**,因为创建 URL 不需要实时音频路径。
|
||||
不要仅因为 Meet 显示“你希望会议中的其他人听到你的声音吗?”就报告“未登录”。那是 Meet 的音频选择过渡界面;OpenClaw 会在可用时通过浏览器自动化点击**使用麦克风**,并继续等待真正的会议状态。对于仅创建的浏览器回退,OpenClaw 可能会点击**不使用麦克风继续**,因为创建 URL 不需要实时音频路径。
|
||||
|
||||
### 会议创建失败
|
||||
|
||||
配置了 OAuth 凭证时,`googlemeet create` 会首先使用 Google Meet API `spaces.create` 端点。没有 OAuth 凭证时,它会回退到固定的 Chrome 节点浏览器。请确认:
|
||||
当配置了 OAuth 凭证时,`googlemeet create` 会首先使用 Google Meet API 的 `spaces.create` 端点。没有 OAuth 凭证时,它会回退到固定的 Chrome 节点浏览器。请确认:
|
||||
|
||||
- 对于 API 创建:已配置 `oauth.clientId` 和 `oauth.refreshToken`,或存在对应的 `OPENCLAW_GOOGLE_MEET_*` 环境变量。
|
||||
- 对于 API 创建:刷新令牌是在添加创建支持之后签发的。旧令牌可能缺少 `meetings.space.created` scope;请重新运行 `openclaw googlemeet auth login --json` 并更新插件配置。
|
||||
- 对于浏览器回退:`defaultTransport: "chrome-node"` 且 `chromeNode.node` 指向一个已连接节点,并且该节点具有 `browser.proxy` 和 `googlemeet.chrome`。
|
||||
- 对于浏览器回退:该节点上的 OpenClaw Chrome 配置文件已登录 Google,并且能够打开 `https://meet.google.com/new`。
|
||||
- 对于浏览器回退:如果 Meet 显示“Do you want people to hear you in the meeting?”,请保持标签页打开。OpenClaw 应通过浏览器自动化点击**使用麦克风**,或者在仅创建回退场景下点击**继续且不使用麦克风**,并继续等待生成的 Meet URL。如果做不到,错误应提到 `meet-audio-choice-required`,而不是 `google-login-required`。
|
||||
- 对于 API 创建:已配置 `oauth.clientId` 和 `oauth.refreshToken`,或存在匹配的 `OPENCLAW_GOOGLE_MEET_*` 环境变量。
|
||||
- 对于 API 创建:刷新令牌是在添加创建支持之后签发的。较旧的令牌可能缺少 `meetings.space.created` scope;请重新运行 `openclaw googlemeet auth login --json` 并更新插件配置。
|
||||
- 对于浏览器回退:`defaultTransport: "chrome-node"` 和
|
||||
`chromeNode.node` 指向一个已连接节点,并且该节点具备 `browser.proxy` 和
|
||||
`googlemeet.chrome`。
|
||||
- 对于浏览器回退:该节点上的 OpenClaw Chrome 配置文件已登录 Google,并且可以打开 `https://meet.google.com/new`。
|
||||
- 对于浏览器回退:重试会在打开新标签页之前复用现有的 `https://meet.google.com/new` 或 Google 账户提示标签页。如果智能体超时,请重试该工具调用,而不是手动再打开一个 Meet 标签页。
|
||||
- 对于浏览器回退:如果 Meet 显示“你希望会议中的其他人听到你的声音吗?”,请保持该标签页打开。OpenClaw 应通过浏览器自动化点击**使用麦克风**,或在仅创建回退场景下点击**不使用麦克风继续**,并继续等待生成的 Meet URL。如果无法继续,错误中应提及 `meet-audio-choice-required`,而不是 `google-login-required`。
|
||||
|
||||
### 智能体已加入但不会说话
|
||||
### 智能体加入了,但没有说话
|
||||
|
||||
检查实时路径:
|
||||
|
||||
@ -684,20 +708,23 @@ openclaw googlemeet setup
|
||||
openclaw googlemeet status
|
||||
```
|
||||
|
||||
使用 `mode: "realtime"` 进行收听/回话。`mode: "transcribe"` 按设计不会启动双向实时语音桥接。
|
||||
若要实现收听/回话,请使用 `mode: "realtime"`。`mode: "transcribe"` 是刻意不启动双向实时语音桥接的。
|
||||
|
||||
另外还要验证:
|
||||
同时还要验证:
|
||||
|
||||
- Gateway 网关主机上有可用的实时提供商密钥,例如 `OPENAI_API_KEY` 或 `GEMINI_API_KEY`。
|
||||
- Chrome 主机上可见 `BlackHole 2ch`。
|
||||
- Gateway 网关主机上有可用的实时提供商密钥,例如
|
||||
`OPENAI_API_KEY` 或 `GEMINI_API_KEY`。
|
||||
- Chrome 主机上可以看到 `BlackHole 2ch`。
|
||||
- Chrome 主机上存在 `rec` 和 `play`。
|
||||
- Meet 的麦克风和扬声器已通过 OpenClaw 使用的虚拟音频路径进行路由。
|
||||
- Meet 麦克风和扬声器通过 OpenClaw 使用的虚拟音频路径进行路由。
|
||||
|
||||
### Twilio 设置检查失败
|
||||
|
||||
当 `voice-call` 未被允许或未启用时,`twilio-voice-call-plugin` 会失败。将其添加到 `plugins.allow`,启用 `plugins.entries.voice-call`,并重新加载 Gateway 网关。
|
||||
当 `voice-call` 未被允许或未启用时,`twilio-voice-call-plugin` 会失败。
|
||||
将它添加到 `plugins.allow`,启用 `plugins.entries.voice-call`,然后重新加载 Gateway 网关。
|
||||
|
||||
当 Twilio 后端缺少 account SID、auth token 或 caller number 时,`twilio-voice-call-credentials` 会失败。在 Gateway 网关主机上设置这些值:
|
||||
当 Twilio 后端缺少 account SID、auth token 或 caller number 时,
|
||||
`twilio-voice-call-credentials` 会失败。在 Gateway 网关主机上设置这些值:
|
||||
|
||||
```bash
|
||||
export TWILIO_ACCOUNT_SID=AC...
|
||||
@ -713,7 +740,7 @@ openclaw googlemeet setup
|
||||
|
||||
### Twilio 呼叫已开始,但始终未进入会议
|
||||
|
||||
确认 Meet 事件公开了电话拨入详情。传入精确的拨入号码和 PIN,或自定义 DTMF 序列:
|
||||
确认 Meet 事件暴露了电话拨入详情。传入准确的拨入号码和 PIN,或自定义 DTMF 序列:
|
||||
|
||||
```bash
|
||||
openclaw googlemeet join https://meet.google.com/abc-defg-hij \
|
||||
@ -726,16 +753,18 @@ openclaw googlemeet join https://meet.google.com/abc-defg-hij \
|
||||
|
||||
## 说明
|
||||
|
||||
Google Meet 的官方媒体 API 偏向接收,因此向 Meet 通话中发言仍然需要一个参与者路径。该插件将这一边界保持为可见状态:Chrome 处理浏览器参与和本地音频路由;Twilio 处理电话拨入参与。
|
||||
Google Meet 的官方媒体 API 偏向接收,因此要在 Meet 通话中发言,仍然需要一个参会路径。该插件让这个边界保持可见:
|
||||
Chrome 处理浏览器参会和本地音频路由;Twilio 处理电话拨入参会。
|
||||
|
||||
Chrome 实时模式需要以下两者之一:
|
||||
Chrome 实时模式需要以下其中之一:
|
||||
|
||||
- `chrome.audioInputCommand` 加 `chrome.audioOutputCommand`:OpenClaw 拥有实时模型桥接,并在这些命令与所选实时语音提供商之间传输 8 kHz G.711 mu-law 音频。
|
||||
- `chrome.audioBridgeCommand`:一个外部桥接命令拥有整个本地音频路径,并且必须在启动或验证其守护进程后退出。
|
||||
- `chrome.audioInputCommand` 加 `chrome.audioOutputCommand`:OpenClaw 接管实时模型桥接,并在这些命令与所选实时语音提供商之间传输 8 kHz G.711 mu-law 音频。
|
||||
- `chrome.audioBridgeCommand`:一个外部桥接命令接管整个本地音频路径,并且必须在启动或验证其守护进程后退出。
|
||||
|
||||
为了获得干净的双向音频,请将 Meet 输出和 Meet 麦克风通过独立虚拟设备或类似 Loopback 的虚拟设备图进行路由。单个共享的 BlackHole 设备可能会把其他参与者的声音回送到通话中。
|
||||
若要获得干净的双向音频,请将 Meet 输出和 Meet 麦克风路由到独立的虚拟设备,或使用类似 Loopback 的虚拟设备图。单个共享的 BlackHole 设备可能会将其他参与者的声音回送进通话中。
|
||||
|
||||
`googlemeet speak` 会触发 Chrome 会话的活动实时音频桥接。`googlemeet leave` 会停止该桥接。对于通过 Voice Call 插件委派的 Twilio 会话,`leave` 还会挂断底层语音通话。
|
||||
`googlemeet speak` 会为一个 Chrome 会话触发活动的实时音频桥接。
|
||||
`googlemeet leave` 会停止该桥接。对于通过 Voice Call 插件委派的 Twilio 会话,`leave` 还会挂断底层语音呼叫。
|
||||
|
||||
## 相关内容
|
||||
|
||||
|
||||
@ -2,28 +2,24 @@
|
||||
read_when:
|
||||
- 你想将 GitHub Copilot 用作模型提供商
|
||||
- 你需要 `openclaw models auth login-github-copilot` 流程
|
||||
summary: 通过设备流程从 OpenClaw 登录 GitHub Copilot
|
||||
summary: 使用设备流程从 OpenClaw 登录 GitHub Copilot
|
||||
title: GitHub Copilot
|
||||
x-i18n:
|
||||
generated_at: "2026-04-23T21:00:11Z"
|
||||
generated_at: "2026-04-24T23:09:48Z"
|
||||
model: gpt-5.4
|
||||
provider: openai
|
||||
source_hash: 8b54a063e30e9202c6b9de35a1a3736ef8c36020296215491fb719afe73a0c3e
|
||||
source_hash: 4b5361f196bbb27ba74f281b4665eaaba770d3532eae2d02f76a14f44d3b4618
|
||||
source_path: providers/github-copilot.md
|
||||
workflow: 15
|
||||
---
|
||||
|
||||
GitHub Copilot 是 GitHub 的 AI 编码助手。它会根据你的 GitHub 账户和订阅计划提供 Copilot
|
||||
模型访问能力。OpenClaw 可以通过两种不同方式将 Copilot 用作模型
|
||||
提供商。
|
||||
GitHub Copilot 是 GitHub 的 AI 编码助手。它为你的 GitHub 账户和套餐提供对 Copilot 模型的访问。OpenClaw 可以通过两种不同方式将 Copilot 用作模型提供商。
|
||||
|
||||
## 在 OpenClaw 中使用 Copilot 的两种方式
|
||||
|
||||
<Tabs>
|
||||
<Tab title="内置提供商(github-copilot)">
|
||||
使用原生设备登录流程获取 GitHub 令牌,然后在 OpenClaw 运行时将其交换为
|
||||
Copilot API 令牌。这是**默认**且最简单的路径,
|
||||
因为它不需要 VS Code。
|
||||
使用原生设备登录流程获取 GitHub token,然后在 OpenClaw 运行时将其交换为 Copilot API token。这是**默认**且最简单的路径,因为它不需要 VS Code。
|
||||
|
||||
<Steps>
|
||||
<Step title="运行登录命令">
|
||||
@ -31,15 +27,14 @@ GitHub Copilot 是 GitHub 的 AI 编码助手。它会根据你的 GitHub 账户
|
||||
openclaw models auth login-github-copilot
|
||||
```
|
||||
|
||||
系统会提示你访问一个 URL 并输入一次性代码。请保持
|
||||
终端打开,直到流程完成。
|
||||
系统会提示你访问一个 URL 并输入一次性代码。在流程完成之前,请保持终端处于打开状态。
|
||||
</Step>
|
||||
<Step title="设置默认模型">
|
||||
```bash
|
||||
openclaw models set github-copilot/claude-opus-4.7
|
||||
```
|
||||
|
||||
或在配置中:
|
||||
或者在配置中设置:
|
||||
|
||||
```json5
|
||||
{
|
||||
@ -54,12 +49,10 @@ GitHub Copilot 是 GitHub 的 AI 编码助手。它会根据你的 GitHub 账户
|
||||
</Tab>
|
||||
|
||||
<Tab title="Copilot Proxy 插件(copilot-proxy)">
|
||||
使用 **Copilot Proxy** VS Code 扩展作为本地桥接。OpenClaw 会连接到
|
||||
该代理的 `/v1` 端点,并使用你在其中配置的模型列表。
|
||||
使用 **Copilot Proxy** VS Code 扩展作为本地桥接。OpenClaw 会与该代理的 `/v1` 端点通信,并使用你在其中配置的模型列表。
|
||||
|
||||
<Note>
|
||||
当你已经在 VS Code 中运行 Copilot Proxy,或者需要通过它进行路由时,
|
||||
请选择这种方式。你必须启用该插件,并保持 VS Code 扩展持续运行。
|
||||
当你已经在 VS Code 中运行 Copilot Proxy,或需要通过它进行路由时,请选择此方式。你必须启用该插件,并保持 VS Code 扩展持续运行。
|
||||
</Note>
|
||||
|
||||
</Tab>
|
||||
@ -67,7 +60,7 @@ GitHub Copilot 是 GitHub 的 AI 编码助手。它会根据你的 GitHub 账户
|
||||
|
||||
## 可选标志
|
||||
|
||||
| 标志 | 描述 |
|
||||
| 标志 | 说明 |
|
||||
| --------------- | --------------------------------------------------- |
|
||||
| `--yes` | 跳过确认提示 |
|
||||
| `--set-default` | 同时应用该提供商推荐的默认模型 |
|
||||
@ -82,60 +75,50 @@ openclaw models auth login --provider github-copilot --method device --set-defau
|
||||
|
||||
<AccordionGroup>
|
||||
<Accordion title="需要交互式 TTY">
|
||||
设备登录流程需要交互式 TTY。请直接在
|
||||
终端中运行,不要在非交互式脚本或 CI 流水线中运行。
|
||||
设备登录流程需要交互式 TTY。请直接在终端中运行,不要在非交互式脚本或 CI 流水线中运行。
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="模型可用性取决于你的订阅计划">
|
||||
Copilot 模型可用性取决于你的 GitHub 订阅计划。如果某个模型
|
||||
被拒绝,请尝试其他 ID(例如 `github-copilot/gpt-4.1`)。
|
||||
<Accordion title="模型可用性取决于你的套餐">
|
||||
Copilot 模型的可用性取决于你的 GitHub 套餐。如果某个模型被拒绝,请尝试另一个 ID(例如 `github-copilot/gpt-4.1`)。
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="传输选择">
|
||||
Claude 模型 ID 会自动使用 Anthropic Messages 传输。GPT、
|
||||
o 系列以及 Gemini 模型则继续使用 OpenAI Responses 传输。OpenClaw
|
||||
会根据模型引用选择正确的传输方式。
|
||||
<Accordion title="传输方式选择">
|
||||
Claude 模型 ID 会自动使用 Anthropic Messages 传输方式。GPT、o-series 和 Gemini 模型会继续使用 OpenAI Responses 传输方式。OpenClaw 会根据模型 ref 选择正确的传输方式。
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="请求兼容性">
|
||||
OpenClaw 会在 Copilot 传输中发送 Copilot IDE 风格的请求头,包括内置压缩、工具结果以及图片后续轮次。除非该行为已经过 Copilot API 验证,否则它不会为 Copilot 启用提供商级别的 Responses continuation。
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="环境变量解析顺序">
|
||||
OpenClaw 会按以下优先级顺序解析 Copilot 认证环境变量:
|
||||
OpenClaw 会按照以下优先级顺序,从环境变量中解析 Copilot 身份验证信息:
|
||||
|
||||
| 优先级 | 变量 | 说明 |
|
||||
| -------- | --------------------- | -------------------------------- |
|
||||
| 1 | `COPILOT_GITHUB_TOKEN` | 最高优先级,Copilot 专用 |
|
||||
| 2 | `GH_TOKEN` | GitHub CLI 令牌(回退) |
|
||||
| 3 | `GITHUB_TOKEN` | 标准 GitHub 令牌(最低) |
|
||||
| 2 | `GH_TOKEN` | GitHub CLI token(回退) |
|
||||
| 3 | `GITHUB_TOKEN` | 标准 GitHub token(最低优先级) |
|
||||
|
||||
当设置了多个变量时,OpenClaw 会使用优先级最高的那个。
|
||||
设备登录流程(`openclaw models auth login-github-copilot`)会将
|
||||
令牌存储到 auth profile store 中,并优先于所有环境
|
||||
变量。
|
||||
当设置了多个变量时,OpenClaw 会使用优先级最高的那个。设备登录流程(`openclaw models auth login-github-copilot`)会将其 token 存储在 auth profile store 中,并优先于所有环境变量。
|
||||
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="令牌存储">
|
||||
登录流程会将 GitHub 令牌存储在 auth profile store 中,并在 OpenClaw 运行时将其交换
|
||||
为 Copilot API 令牌。你无需手动管理该
|
||||
令牌。
|
||||
<Accordion title="Token 存储">
|
||||
登录会将 GitHub token 存储在 auth profile store 中,并在 OpenClaw 运行时将其交换为 Copilot API token。你无需手动管理该 token。
|
||||
</Accordion>
|
||||
</AccordionGroup>
|
||||
|
||||
<Warning>
|
||||
需要交互式 TTY。请直接在终端中运行登录命令,不要
|
||||
在无头脚本或 CI 任务中执行。
|
||||
需要交互式 TTY。请直接在终端中运行登录命令,不要在无头脚本或 CI 任务中运行。
|
||||
</Warning>
|
||||
|
||||
## Memory 搜索嵌入
|
||||
## Memory search 嵌入
|
||||
|
||||
GitHub Copilot 还可以作为
|
||||
[memory 搜索](/zh-CN/concepts/memory-search) 的嵌入提供商。如果你拥有 Copilot 订阅并且
|
||||
已经登录,OpenClaw 就可以在无需额外 API 密钥的情况下将它用于嵌入。
|
||||
GitHub Copilot 还可以作为 [memory search](/zh-CN/concepts/memory-search) 的嵌入提供商。如果你订阅了 Copilot 并且已经登录,OpenClaw 可以在无需单独 API 密钥的情况下将其用于嵌入。
|
||||
|
||||
### 自动检测
|
||||
|
||||
当 `memorySearch.provider` 为 `"auto"`(默认值)时,GitHub Copilot 会在优先级 15 被尝试——位于本地嵌入之后、OpenAI 和其他付费
|
||||
提供商之前。如果存在 GitHub 令牌,OpenClaw 会从 Copilot API 中发现可用的
|
||||
嵌入模型,并自动选择最佳模型。
|
||||
当 `memorySearch.provider` 为 `"auto"`(默认值)时,GitHub Copilot 会以优先级 15 被尝试——位于本地嵌入之后,但在 OpenAI 和其他付费提供商之前。如果有可用的 GitHub token,OpenClaw 会从 Copilot API 发现可用的嵌入模型,并自动选择最佳模型。
|
||||
|
||||
### 显式配置
|
||||
|
||||
@ -155,22 +138,21 @@ GitHub Copilot 还可以作为
|
||||
|
||||
### 工作原理
|
||||
|
||||
1. OpenClaw 解析你的 GitHub 令牌(来自环境变量或 auth profile)。
|
||||
2. 将其交换为一个短期 Copilot API 令牌。
|
||||
1. OpenClaw 解析你的 GitHub token(来自环境变量或 auth profile)。
|
||||
2. 将其交换为短期有效的 Copilot API token。
|
||||
3. 查询 Copilot `/models` 端点以发现可用的嵌入模型。
|
||||
4. 选择最佳模型(优先 `text-embedding-3-small`)。
|
||||
5. 将嵌入请求发送到 Copilot `/embeddings` 端点。
|
||||
|
||||
模型可用性取决于你的 GitHub 订阅计划。如果没有可用的嵌入模型,
|
||||
OpenClaw 会跳过 Copilot 并尝试下一个提供商。
|
||||
模型可用性取决于你的 GitHub 套餐。如果没有可用的嵌入模型,OpenClaw 会跳过 Copilot 并尝试下一个提供商。
|
||||
|
||||
## 相关内容
|
||||
|
||||
<CardGroup cols={2}>
|
||||
<Card title="模型选择" href="/zh-CN/concepts/model-providers" icon="layers">
|
||||
选择提供商、模型引用以及故障切换行为。
|
||||
选择提供商、模型 ref 和故障切换行为。
|
||||
</Card>
|
||||
<Card title="OAuth 与认证" href="/zh-CN/gateway/authentication" icon="key">
|
||||
认证细节与凭证复用规则。
|
||||
<Card title="OAuth 和身份验证" href="/zh-CN/gateway/authentication" icon="key">
|
||||
身份验证细节和凭证复用规则。
|
||||
</Card>
|
||||
</CardGroup>
|
||||
|
||||
@ -1,47 +1,47 @@
|
||||
---
|
||||
read_when:
|
||||
- 运行或修复测试
|
||||
summary: 如何在本地运行测试(Vitest),以及何时使用 force / coverage 模式
|
||||
summary: 如何在本地运行测试(vitest),以及何时使用 force/coverage 模式
|
||||
title: 测试
|
||||
x-i18n:
|
||||
generated_at: "2026-04-24T19:58:03Z"
|
||||
generated_at: "2026-04-24T23:09:45Z"
|
||||
model: gpt-5.4
|
||||
provider: openai
|
||||
source_hash: 4393562f7ab8471d44ab1573bc14b041fb50058bfc61de628e02328793193ed7
|
||||
source_hash: f15e68a95d68dd076862aa168a836c4918876afa1f925ed183f7fde8ec75f24a
|
||||
source_path: reference/test.md
|
||||
workflow: 15
|
||||
---
|
||||
|
||||
- 完整测试工具包(测试套件、live、Docker):[测试](/zh-CN/help/testing)
|
||||
|
||||
- `pnpm test:force`:终止任何仍占用默认控制端口的残留 Gateway 网关进程,然后使用隔离的 Gateway 网关端口运行完整 Vitest 测试套件,以避免服务器测试与正在运行的实例冲突。当之前的 Gateway 网关运行导致端口 `18789` 仍被占用时,请使用此命令。
|
||||
- `pnpm test:coverage`:使用 V8 覆盖率运行单元测试套件(通过 `vitest.unit.config.ts`)。这是一个针对已加载文件的单元覆盖率门禁,不是整个仓库的全文件覆盖率。阈值为 70% 的行数 / 函数 / 语句覆盖率,以及 55% 的分支覆盖率。由于 `coverage.all` 为 false,该门禁只衡量单元覆盖率套件加载到的文件,而不是把所有拆分 lane 中的源文件都视为未覆盖。
|
||||
- `pnpm test:coverage:changed`:仅对相较于 `origin/main` 发生变更的文件运行单元覆盖率。
|
||||
- `pnpm test:changed`:当 diff 仅触及可路由的源文件 / 测试文件时,将变更的 git 路径展开为有范围限定的 Vitest lanes。配置 / setup 变更仍会回退到原生根项目运行方式,因此在需要时,接线类改动仍会触发更广泛的重跑。
|
||||
- `pnpm changed:lanes`:显示相较于 `origin/main` 的 diff 所触发的架构 lanes。
|
||||
- `pnpm check:changed`:针对相较于 `origin/main` 的 diff 运行智能变更门禁。它会对 core 改动运行 core 测试 lanes,对扩展改动运行扩展测试 lanes,对仅测试改动仅运行测试类型检查 / 测试,将公共插件 SDK 或插件契约变更扩展为一次扩展校验,并在仅有发布元数据版本提升时保持针对性的版本 / 配置 / 根依赖检查。
|
||||
- `pnpm test`:通过有范围限定的 Vitest lanes 路由显式的文件 / 目录目标。未指定目标的运行会使用固定分片组,并展开到叶子配置以进行本地并行执行;扩展组始终会展开为每个扩展各自的分片配置,而不是一个巨大的根项目进程。
|
||||
- 完整测试和扩展分片运行会在 `.artifacts/vitest-shard-timings.json` 中更新本地耗时数据;后续运行会使用这些耗时数据来平衡慢分片和快分片。设置 `OPENCLAW_TEST_PROJECTS_TIMINGS=0` 可忽略本地耗时产物。
|
||||
- 选定的 `plugin-sdk` 和 `commands` 测试文件现在会路由到专用的轻量 lanes,这些 lanes 只保留 `test/setup.ts`,而运行时负载较重的用例则保留在原有 lanes 中。
|
||||
- 选定的 `plugin-sdk` 和 `commands` 辅助源文件也会将 `pnpm test:changed` 映射到这些轻量 lanes 中的显式同级测试,因此小规模辅助文件改动无需重跑那些依赖重型运行时的测试套件。
|
||||
- `auto-reply` 现在也拆分为三个专用配置(`core`、`top-level`、`reply`),因此 reply harness 不会主导较轻量的顶层状态 / token / helper 测试。
|
||||
- 基础 Vitest 配置现在默认使用 `pool: "threads"` 和 `isolate: false`,并在整个仓库配置中启用了共享的非隔离 runner。
|
||||
- `pnpm test:force`:终止任何仍在占用默认控制端口的遗留 Gateway 网关进程,然后使用隔离的 Gateway 网关端口运行完整的 Vitest 测试套件,避免服务端测试与正在运行的实例发生冲突。当先前的 Gateway 网关运行使端口 `18789` 仍被占用时,请使用此命令。
|
||||
- `pnpm test:coverage`:使用 V8 覆盖率运行单元测试套件(通过 `vitest.unit.config.ts`)。这是一个“已加载文件”的单元覆盖率门禁,而不是针对整个仓库所有文件的覆盖率。阈值为:行数 / 函数 / 语句 70%,分支 55%。由于 `coverage.all` 为 false,该门禁只统计被单元覆盖率套件加载的文件,而不会将拆分车道中的每个源文件都视为未覆盖。
|
||||
- `pnpm test:coverage:changed`:仅对自 `origin/main` 以来发生变更的文件运行单元覆盖率。
|
||||
- `pnpm test:changed`:当 diff 只涉及可路由的源文件 / 测试文件时,会将变更的 Git 路径展开为有范围限制的 Vitest 车道。配置 / setup 变更仍会回退到原生根项目运行,因此在有接线层编辑时,相关测试仍会按需要广泛重跑。
|
||||
- `pnpm changed:lanes`:显示针对 `origin/main` 的 diff 所触发的架构车道。
|
||||
- `pnpm check:changed`:针对 `origin/main` 的 diff 运行智能变更门禁。它会将核心改动与核心测试车道一起运行,将扩展改动与扩展测试车道一起运行,仅测试改动则只运行测试类型检查 / 测试;对公开的插件 SDK 或插件契约改动,会额外扩展为一次扩展校验;而仅涉及发布元数据的版本提升,则保持在有针对性的版本 / 配置 / 根依赖检查范围内。
|
||||
- `pnpm test`:将显式指定的文件 / 目录目标路由到有范围限制的 Vitest 车道。未指定目标的运行会使用固定的分片组,并展开到叶子配置以便在本地并行执行;扩展组始终会展开为按扩展划分的分片配置,而不是使用一个巨大的根项目进程。
|
||||
- 完整测试和扩展分片运行会在 `.artifacts/vitest-shard-timings.json` 中更新本地耗时数据;后续运行会使用这些数据来平衡慢分片和快分片。设置 `OPENCLAW_TEST_PROJECTS_TIMINGS=0` 可忽略本地耗时产物。
|
||||
- 选定的 `plugin-sdk` 和 `commands` 测试文件现在会路由到专用的轻量车道,这些车道只保留 `test/setup.ts`,而运行时较重的用例仍保留在现有车道中。
|
||||
- 选定的 `plugin-sdk` 和 `commands` 辅助源文件也会将 `pnpm test:changed` 映射到这些轻量车道中的显式同级测试,因此对小型辅助文件的修改不必重跑较重的运行时支撑测试套件。
|
||||
- `auto-reply` 现在也拆分为三个专用配置(`core`、`top-level`、`reply`),因此 reply harness 不会再主导较轻的顶层状态 / token / helper 测试。
|
||||
- 基础 Vitest 配置现在默认使用 `pool: "threads"` 和 `isolate: false`,并且整个仓库配置都启用了共享的非隔离 runner。
|
||||
- `pnpm test:channels` 运行 `vitest.channels.config.ts`。
|
||||
- `pnpm test:extensions` 和 `pnpm test extensions` 会运行所有扩展 / 插件分片。重型渠道插件、浏览器插件和 OpenAI 作为专用分片运行;其他插件组则保持批量运行。对单个内置插件 lane,请使用 `pnpm test extensions/<id>`。
|
||||
- `pnpm test:perf:imports`:启用 Vitest 导入耗时 + 导入明细报告,同时仍对显式文件 / 目录目标使用有范围限定的 lane 路由。
|
||||
- `pnpm test:perf:imports:changed`:同样进行导入分析,但仅针对相较于 `origin/main` 有变更的文件。
|
||||
- `pnpm test:perf:changed:bench -- --ref <git-ref>`:对相同已提交 git diff 下的路由化 changed 模式路径与原生根项目运行进行基准对比。
|
||||
- `pnpm test:perf:changed:bench -- --worktree`:无需先提交,直接对当前工作树变更集进行基准测试。
|
||||
- `pnpm test:extensions` 和 `pnpm test extensions` 会运行所有扩展 / 插件分片。较重的渠道插件、浏览器插件和 OpenAI 会作为专用分片运行;其他插件组仍保持批量运行。对单个内置插件车道,可使用 `pnpm test extensions/<id>`。
|
||||
- `pnpm test:perf:imports`:启用 Vitest 导入耗时和导入明细报告,同时仍对显式文件 / 目录目标使用有范围限制的车道路由。
|
||||
- `pnpm test:perf:imports:changed`:与上面相同的导入分析,但仅针对自 `origin/main` 以来变更的文件。
|
||||
- `pnpm test:perf:changed:bench -- --ref <git-ref>`:针对同一份已提交的 Git diff,对比路由后的 changed 模式路径和原生根项目运行的基准表现。
|
||||
- `pnpm test:perf:changed:bench -- --worktree`:无需先提交,即可对当前工作树变更集进行基准测试。
|
||||
- `pnpm test:perf:profile:main`:为 Vitest 主线程写入 CPU profile(`.artifacts/vitest-main-profile`)。
|
||||
- `pnpm test:perf:profile:runner`:为单元测试 runner 写入 CPU + heap profiles(`.artifacts/vitest-runner-profile`)。
|
||||
- `pnpm test:perf:groups --full-suite --allow-failures --output .artifacts/test-perf/baseline-before.json`:串行运行每个完整测试套件的 Vitest 叶子配置,并写入分组耗时数据以及每个配置对应的 JSON / 日志产物。测试性能智能体会在尝试修复慢测试之前,将其用作基线。
|
||||
- `pnpm test:perf:groups:compare .artifacts/test-perf/baseline-before.json .artifacts/test-perf/after-agent.json`:对比性能相关变更之后的分组报告。
|
||||
- `pnpm test:perf:profile:runner`:为单元测试 runner 写入 CPU + 堆 profile(`.artifacts/vitest-runner-profile`)。
|
||||
- `pnpm test:perf:groups --full-suite --allow-failures --output .artifacts/test-perf/baseline-before.json`:串行运行每个完整测试套件的 Vitest 叶子配置,并写出分组耗时数据以及按配置划分的 JSON / 日志产物。测试性能智能体会将此作为尝试修复慢测试之前的基线。
|
||||
- `pnpm test:perf:groups:compare .artifacts/test-perf/baseline-before.json .artifacts/test-perf/after-agent.json`:对比面向性能的改动前后分组报告。
|
||||
- Gateway 网关集成测试:通过 `OPENCLAW_TEST_INCLUDE_GATEWAY=1 pnpm test` 或 `pnpm test:gateway` 显式启用。
|
||||
- `pnpm test:e2e`:运行 Gateway 网关端到端冒烟测试(多实例 WS/HTTP/节点配对)。在 `vitest.e2e.config.ts` 中默认使用 `threads` + `isolate: false`,并启用自适应 workers;可通过 `OPENCLAW_E2E_WORKERS=<n>` 调整,并设置 `OPENCLAW_E2E_VERBOSE=1` 以输出详细日志。
|
||||
- `pnpm test:live`:运行提供商 live 测试(minimax/zai)。需要 API 密钥,并需要设置 `LIVE=1`(或提供商专属的 `*_LIVE_TEST=1`)才能取消跳过。
|
||||
- `pnpm test:docker:all`:先构建共享的 live-test 镜像和 Docker E2E 镜像各一次,然后通过加权调度器在 `OPENCLAW_SKIP_DOCKER_BUILD=1` 下运行 Docker 冒烟 lanes。`OPENCLAW_DOCKER_ALL_PARALLELISM=<n>` 控制进程槽位,默认值为 10;`OPENCLAW_DOCKER_ALL_TAIL_PARALLELISM=<n>` 控制对提供商敏感的尾部池,默认值也为 10。重型 lane 上限默认分别为 `OPENCLAW_DOCKER_ALL_LIVE_LIMIT=4`、`OPENCLAW_DOCKER_ALL_NPM_LIMIT=4` 和 `OPENCLAW_DOCKER_ALL_SERVICE_LIMIT=5`;更强的主机可使用 `OPENCLAW_DOCKER_ALL_WEIGHT_LIMIT` 或 `OPENCLAW_DOCKER_ALL_DOCKER_LIMIT`。lane 启动默认错开 2 秒,以避免本地 Docker daemon 出现创建风暴;可通过 `OPENCLAW_DOCKER_ALL_START_STAGGER_MS=<ms>` 覆盖。除非设置了 `OPENCLAW_DOCKER_ALL_FAIL_FAST=0`,否则 runner 在首次失败后会停止调度新的池化 lanes;每个 lane 默认有 120 分钟超时,可通过 `OPENCLAW_DOCKER_ALL_LANE_TIMEOUT_MS` 覆盖。每个 lane 的日志会写入 `.artifacts/docker-tests/<run-id>/`。
|
||||
- `pnpm test:docker:openwebui`:启动 Docker 化的 OpenClaw + Open WebUI,通过 Open WebUI 登录,检查 `/api/models`,然后通过 `/api/chat/completions` 运行一次真实的代理聊天。它需要可用的 live 模型密钥(例如在 `~/.profile` 中配置的 OpenAI),会拉取外部 Open WebUI 镜像,并不像常规单元 / e2e 测试套件那样以 CI 稳定性为目标。
|
||||
- `pnpm test:docker:mcp-channels`:启动一个带预置数据的 Gateway 网关容器和第二个客户端容器,后者会启动 `openclaw mcp serve`,然后通过真实的 stdio bridge 验证路由对话发现、转录读取、附件元数据、实时事件队列行为、出站发送路由,以及 Claude 风格的渠道 + 权限通知。Claude 通知断言会直接读取原始 stdio MCP 帧,因此该冒烟测试反映的是 bridge 实际发出的内容。
|
||||
- `pnpm test:e2e`:运行 Gateway 网关端到端 smoke 测试(多实例 WS / HTTP / 节点配对)。在 `vitest.e2e.config.ts` 中默认使用 `threads` + `isolate: false` 和自适应 workers;可用 `OPENCLAW_E2E_WORKERS=<n>` 调整,并设置 `OPENCLAW_E2E_VERBOSE=1` 以输出详细日志。
|
||||
- `pnpm test:live`:运行提供商 live 测试(minimax / zai)。需要 API key,并设置 `LIVE=1`(或提供商专用的 `*_LIVE_TEST=1`)后才会取消 skip。
|
||||
- `pnpm test:docker:all`:先构建一次共享的 live-test 镜像和 Docker E2E 镜像,然后通过加权调度器以 `OPENCLAW_SKIP_DOCKER_BUILD=1` 运行 Docker smoke 车道。`OPENCLAW_DOCKER_ALL_PARALLELISM=<n>` 控制进程槽位,默认值为 10;`OPENCLAW_DOCKER_ALL_TAIL_PARALLELISM=<n>` 控制对 provider 敏感的尾部池,默认值也为 10。重型车道上限默认分别为 `OPENCLAW_DOCKER_ALL_LIVE_LIMIT=4`、`OPENCLAW_DOCKER_ALL_NPM_LIMIT=4` 和 `OPENCLAW_DOCKER_ALL_SERVICE_LIMIT=5`;在更大的主机上,可使用 `OPENCLAW_DOCKER_ALL_WEIGHT_LIMIT` 或 `OPENCLAW_DOCKER_ALL_DOCKER_LIMIT`。默认情况下,车道启动会错开 2 秒,以避免本地 Docker daemon 出现集中创建风暴;可通过 `OPENCLAW_DOCKER_ALL_START_STAGGER_MS=<ms>` 覆盖。runner 默认会预检 Docker、清理陈旧的 OpenClaw E2E 容器、每 30 秒输出一次活动车道状态,并将车道耗时保存在 `.artifacts/docker-tests/lane-timings.json` 中,以便后续运行按“最长优先”排序。使用 `OPENCLAW_DOCKER_ALL_DRY_RUN=1` 可只打印车道清单而不运行 Docker,使用 `OPENCLAW_DOCKER_ALL_STATUS_INTERVAL_MS=<ms>` 可调整状态输出频率,或使用 `OPENCLAW_DOCKER_ALL_TIMINGS=0` 禁用耗时复用。除非设置 `OPENCLAW_DOCKER_ALL_FAIL_FAST=0`,否则 runner 会在第一次失败后停止调度新的池化车道;每个车道都有一个 120 分钟的兜底超时,可通过 `OPENCLAW_DOCKER_ALL_LANE_TIMEOUT_MS` 覆盖;选定的 live / tail 车道使用更紧的每车道上限。每车道日志会写入 `.artifacts/docker-tests/<run-id>/`。
|
||||
- `pnpm test:docker:openwebui`:启动 Docker 化的 OpenClaw + Open WebUI,通过 Open WebUI 登录,检查 `/api/models`,然后通过 `/api/chat/completions` 运行真实的代理聊天。需要可用的 live model key(例如 `~/.profile` 中的 OpenAI),会拉取外部 Open WebUI 镜像,并不像常规的单元 / e2e 测试套件那样以 CI 稳定性为目标。
|
||||
- `pnpm test:docker:mcp-channels`:启动一个带种子数据的 Gateway 网关容器,以及第二个会启动 `openclaw mcp serve` 的客户端容器,然后验证经路由的会话发现、transcript 读取、附件元数据、live 事件队列行为、出站发送路由,以及通过真实 stdio bridge 传递的 Claude 风格渠道 + 权限通知。Claude 通知断言会直接读取原始 stdio MCP 帧,因此该 smoke 测试反映的是 bridge 实际发出的内容。
|
||||
|
||||
## 本地 PR 门禁
|
||||
|
||||
@ -54,12 +54,12 @@ x-i18n:
|
||||
- `pnpm test`
|
||||
- `pnpm check:docs`
|
||||
|
||||
如果 `pnpm test` 在负载较高的主机上出现偶发失败,请先重跑一次,再决定是否将其视为回归,然后用 `pnpm test <path/to/test>` 进行隔离。对于内存受限的主机,请使用:
|
||||
如果 `pnpm test` 在负载较高的主机上出现偶发失败,在将其视为回归之前请先重跑一次,然后使用 `pnpm test <path/to/test>` 进行隔离。对于内存受限的主机,可使用:
|
||||
|
||||
- `OPENCLAW_VITEST_MAX_WORKERS=1 pnpm test`
|
||||
- `OPENCLAW_VITEST_FS_MODULE_CACHE_PATH=/tmp/openclaw-vitest-cache pnpm test:changed`
|
||||
|
||||
## 模型延迟基准(本地密钥)
|
||||
## 模型延迟基准测试(本地 keys)
|
||||
|
||||
脚本:[`scripts/bench-model.ts`](https://github.com/openclaw/openclaw/blob/main/scripts/bench-model.ts)
|
||||
|
||||
@ -71,10 +71,10 @@ x-i18n:
|
||||
|
||||
最近一次运行(2025-12-31,20 次):
|
||||
|
||||
- minimax 中位数 1279ms(最小 1114,最大 2431)
|
||||
- opus 中位数 2454ms(最小 1224,最大 3170)
|
||||
- minimax 中位数 1279 ms(最小 1114,最大 2431)
|
||||
- opus 中位数 2454 ms(最小 1224,最大 3170)
|
||||
|
||||
## CLI 启动基准
|
||||
## CLI 启动基准测试
|
||||
|
||||
脚本:[`scripts/bench-cli-startup.ts`](https://github.com/openclaw/openclaw/blob/main/scripts/bench-cli-startup.ts)
|
||||
|
||||
@ -101,11 +101,11 @@ x-i18n:
|
||||
- `real`:`health`、`status`、`status --json`、`sessions`、`sessions --json`、`agents list --json`、`gateway status`、`gateway status --json`、`gateway health --json`、`config get gateway.port`
|
||||
- `all`:两个预设都包含
|
||||
|
||||
输出会包含每个命令的 `sampleCount`、平均值、p50、p95、最小 / 最大值、exit-code / signal 分布以及最大 RSS 汇总。可选的 `--cpu-prof-dir` / `--heap-prof-dir` 会为每次运行写入 V8 profile,因此计时和 profile 捕获使用的是同一个 harness。
|
||||
输出内容包括每个命令的 `sampleCount`、平均值、p50、p95、最小值 / 最大值、exit code / signal 分布,以及最大 RSS 汇总。可选的 `--cpu-prof-dir` / `--heap-prof-dir` 会为每次运行写入 V8 profile,因此计时和 profile 捕获使用的是同一个 harness。
|
||||
|
||||
保存输出约定:
|
||||
已保存输出约定:
|
||||
|
||||
- `pnpm test:startup:bench:smoke` 会将目标冒烟产物写入 `.artifacts/cli-startup-bench-smoke.json`
|
||||
- `pnpm test:startup:bench:smoke` 会将有针对性的 smoke 产物写入 `.artifacts/cli-startup-bench-smoke.json`
|
||||
- `pnpm test:startup:bench:save` 会使用 `runs=5` 和 `warmup=1` 将完整测试套件产物写入 `.artifacts/cli-startup-bench-all.json`
|
||||
- `pnpm test:startup:bench:update` 会使用 `runs=5` 和 `warmup=1` 刷新已提交的基线 fixture:`test/fixtures/cli-startup-bench.json`
|
||||
|
||||
@ -117,19 +117,19 @@ x-i18n:
|
||||
|
||||
## 新手引导 E2E(Docker)
|
||||
|
||||
Docker 是可选的;只有在进行容器化新手引导冒烟测试时才需要。
|
||||
Docker 是可选的;只有在运行容器化新手引导 smoke 测试时才需要。
|
||||
|
||||
在一个干净的 Linux 容器中运行完整冷启动流程:
|
||||
在干净的 Linux 容器中执行完整冷启动流程:
|
||||
|
||||
```bash
|
||||
scripts/e2e/onboard-docker.sh
|
||||
```
|
||||
|
||||
该脚本会通过伪终端驱动交互式向导,验证配置 / 工作区 / 会话文件,然后启动 Gateway 网关并运行 `openclaw health`。
|
||||
该脚本会通过 pseudo-tty 驱动交互式向导,验证配置 / 工作区 / 会话文件,然后启动 Gateway 网关并运行 `openclaw health`。
|
||||
|
||||
## QR 导入冒烟测试(Docker)
|
||||
## QR 导入 smoke 测试(Docker)
|
||||
|
||||
确保维护中的 QR 运行时 helper 能在受支持的 Docker Node 运行时下正确加载(默认 Node 24,兼容 Node 22):
|
||||
确保受维护的 QR 运行时 helper 能在受支持的 Docker Node 运行时下正确加载(默认 Node 24,兼容 Node 22):
|
||||
|
||||
```bash
|
||||
pnpm test:docker:qr
|
||||
@ -138,4 +138,4 @@ pnpm test:docker:qr
|
||||
## 相关内容
|
||||
|
||||
- [测试](/zh-CN/help/testing)
|
||||
- [Testing live](/zh-CN/help/testing-live)
|
||||
- [live 测试](/zh-CN/help/testing-live)
|
||||
|
||||
@ -7,20 +7,20 @@ sidebarTitle: Install and Configure
|
||||
summary: 安装、配置和管理 OpenClaw 插件
|
||||
title: 插件
|
||||
x-i18n:
|
||||
generated_at: "2026-04-24T16:58:32Z"
|
||||
generated_at: "2026-04-24T23:09:48Z"
|
||||
model: gpt-5.4
|
||||
provider: openai
|
||||
source_hash: 1f4968e70dc215dc50916f2d180121ce2afbe90e6bb2a85d3fe0bd8d989244fd
|
||||
source_hash: 7d962119bcb2bf94da08fcd48d4da8be76618104ea3c37ce60e2fcf397b05c98
|
||||
source_path: tools/plugin.md
|
||||
workflow: 15
|
||||
---
|
||||
|
||||
插件通过新增功能来扩展 OpenClaw:渠道、模型提供商、智能体 harness、工具、Skills、语音、实时转写、实时语音、媒体理解、图像生成、视频生成、网页抓取、网页搜索等。有些插件是**核心**插件(随 OpenClaw 一起发布),另一些则是**外部**插件(由社区发布到 npm)。
|
||||
插件通过新增能力来扩展 OpenClaw:渠道、模型提供商、智能体 harness、工具、Skills、语音、实时转写、实时语音、媒体理解、图像生成、视频生成、网页抓取、网页搜索等。有些插件是**核心**插件(随 OpenClaw 一起发布),另一些则是**外部**插件(由社区在 npm 上发布)。
|
||||
|
||||
## 快速开始
|
||||
|
||||
<Steps>
|
||||
<Step title="查看已加载内容">
|
||||
<Step title="查看已加载的内容">
|
||||
```bash
|
||||
openclaw plugins list
|
||||
```
|
||||
@ -28,10 +28,10 @@ x-i18n:
|
||||
|
||||
<Step title="安装插件">
|
||||
```bash
|
||||
# 来自 npm
|
||||
# 从 npm
|
||||
openclaw plugins install @openclaw/voice-call
|
||||
|
||||
# 来自本地目录或归档文件
|
||||
# 从本地目录或归档文件
|
||||
openclaw plugins install ./my-plugin
|
||||
openclaw plugins install ./my-plugin.tgz
|
||||
```
|
||||
@ -43,12 +43,12 @@ x-i18n:
|
||||
openclaw gateway restart
|
||||
```
|
||||
|
||||
然后在你的配置文件中的 `plugins.entries.\<id\>.config` 下进行配置。
|
||||
然后在你的配置文件中,通过 `plugins.entries.\<id\>.config` 进行配置。
|
||||
|
||||
</Step>
|
||||
</Steps>
|
||||
|
||||
如果你更喜欢聊天原生的控制方式,请启用 `commands.plugins: true` 并使用:
|
||||
如果你更喜欢使用聊天原生控制方式,请启用 `commands.plugins: true` 并使用:
|
||||
|
||||
```text
|
||||
/plugin install clawhub:@openclaw/voice-call
|
||||
@ -56,11 +56,11 @@ x-i18n:
|
||||
/plugin enable voice-call
|
||||
```
|
||||
|
||||
安装路径使用与 CLI 相同的解析器:本地路径/归档文件、显式 `clawhub:<pkg>`,或裸包规范(优先 ClawHub,其次回退到 npm)。
|
||||
安装路径使用与 CLI 相同的解析器:本地路径/归档、显式 `clawhub:<pkg>`,或裸包规范(优先 ClawHub,然后回退到 npm)。
|
||||
|
||||
如果配置无效,安装通常会以安全失败的方式终止,并提示你使用 `openclaw doctor --fix`。唯一的恢复例外是一个较窄的内置插件重装路径,适用于选择加入 `openclaw.install.allowInvalidConfigRecovery` 的插件。
|
||||
如果配置无效,安装通常会以失败关闭的方式结束,并提示你运行 `openclaw doctor --fix`。唯一的恢复例外是一个有限的内置插件重装路径,适用于选择启用 `openclaw.install.allowInvalidConfigRecovery` 的插件。
|
||||
|
||||
打包发布的 OpenClaw 安装不会急切安装每个内置插件的全部运行时依赖树。当某个由 OpenClaw 拥有的内置插件因插件配置、旧版渠道配置或默认启用的清单而处于活动状态时,启动过程只会在导入该插件前修复该插件声明的运行时依赖。显式禁用仍然优先生效:`plugins.entries.<id>.enabled: false`、`plugins.deny`、`plugins.enabled: false` 和 `channels.<id>.enabled: false` 会阻止该插件/渠道的自动内置运行时依赖修复。外部插件和自定义加载路径仍然必须通过 `openclaw plugins install` 安装。
|
||||
打包后的 OpenClaw 安装不会急切地安装每个内置插件的运行时依赖树。当一个由 OpenClaw 拥有的内置插件通过插件配置、旧版渠道配置或默认启用的清单处于激活状态时,启动修复只会在导入该插件之前修复该插件声明的运行时依赖。显式禁用仍然优先:`plugins.entries.<id>.enabled: false`、`plugins.deny`、`plugins.enabled: false` 和 `channels.<id>.enabled: false` 会阻止为该插件/渠道自动修复内置运行时依赖。外部插件和自定义加载路径仍然必须通过 `openclaw plugins install` 安装。
|
||||
|
||||
## 插件类型
|
||||
|
||||
@ -68,12 +68,12 @@ OpenClaw 可识别两种插件格式:
|
||||
|
||||
| 格式 | 工作方式 | 示例 |
|
||||
| ---------- | ------------------------------------------------------------------ | ------------------------------------------------------ |
|
||||
| **Native** | `openclaw.plugin.json` + 运行时模块;在进程内执行 | 官方插件、社区 npm 包 |
|
||||
| **原生** | `openclaw.plugin.json` + 运行时模块;在进程内执行 | 官方插件、社区 npm 包 |
|
||||
| **Bundle** | 与 Codex/Claude/Cursor 兼容的布局;映射到 OpenClaw 功能 | `.codex-plugin/`、`.claude-plugin/`、`.cursor-plugin/` |
|
||||
|
||||
这两种格式都会显示在 `openclaw plugins list` 中。有关 Bundle 的详细信息,请参阅 [Plugin Bundles](/zh-CN/plugins/bundles)。
|
||||
两者都会显示在 `openclaw plugins list` 中。有关 bundle 的详细信息,请参阅 [Plugin Bundles](/zh-CN/plugins/bundles)。
|
||||
|
||||
如果你正在编写原生插件,请从 [Building Plugins](/zh-CN/plugins/building-plugins) 和 [插件 SDK 概览](/zh-CN/plugins/sdk-overview) 开始。
|
||||
如果你要编写原生插件,请从 [构建插件](/zh-CN/plugins/building-plugins) 和 [插件 SDK 概览](/zh-CN/plugins/sdk-overview) 开始。
|
||||
|
||||
## 官方插件
|
||||
|
||||
@ -99,9 +99,9 @@ OpenClaw 可识别两种插件格式:
|
||||
`vercel-ai-gateway`, `volcengine`, `xiaomi`, `zai`
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="Memory 插件">
|
||||
- `memory-core` — 内置的内存搜索(通过 `plugins.slots.memory` 默认启用)
|
||||
- `memory-lancedb` — 按需安装的长期记忆,带自动回忆/捕获功能(设置 `plugins.slots.memory = "memory-lancedb"`)
|
||||
<Accordion title="记忆插件">
|
||||
- `memory-core` — 内置的记忆搜索(默认通过 `plugins.slots.memory` 使用)
|
||||
- `memory-lancedb` — 按需安装的长期记忆,支持自动召回/捕获(设置 `plugins.slots.memory = "memory-lancedb"`)
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="语音提供商(默认启用)">
|
||||
@ -109,12 +109,12 @@ OpenClaw 可识别两种插件格式:
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="其他">
|
||||
- `browser` — 用于浏览器工具、`openclaw browser` CLI、`browser.request` Gateway 网关方法、浏览器运行时以及默认浏览器控制服务的内置浏览器插件(默认启用;替换前请先禁用)
|
||||
- `copilot-proxy` — VS Code Copilot Proxy 桥接器(默认禁用)
|
||||
- `browser` — 用于浏览器工具、`openclaw browser` CLI、`browser.request` Gateway 网关方法、浏览器运行时以及默认浏览器控制服务的内置浏览器插件(默认启用;在替换它之前请先禁用)
|
||||
- `copilot-proxy` — VS Code Copilot Proxy 桥接(默认禁用)
|
||||
</Accordion>
|
||||
</AccordionGroup>
|
||||
|
||||
在找第三方插件?请参阅 [Community Plugins](/zh-CN/plugins/community)。
|
||||
在寻找第三方插件?请参阅 [Community Plugins](/zh-CN/plugins/community)。
|
||||
|
||||
## 配置
|
||||
|
||||
@ -134,24 +134,24 @@ OpenClaw 可识别两种插件格式:
|
||||
|
||||
| 字段 | 说明 |
|
||||
| ---------------- | --------------------------------------------------------- |
|
||||
| `enabled` | 主开关(默认:`true`) |
|
||||
| `enabled` | 总开关(默认:`true`) |
|
||||
| `allow` | 插件允许列表(可选) |
|
||||
| `deny` | 插件拒绝列表(可选;拒绝优先) |
|
||||
| `load.paths` | 额外的插件文件/目录 |
|
||||
| `slots` | 独占槽位选择器(例如 `memory`、`contextEngine`) |
|
||||
| `entries.\<id\>` | 每个插件的开关 + 配置 |
|
||||
| `slots` | 独占插槽选择器(例如 `memory`、`contextEngine`) |
|
||||
| `entries.\<id\>` | 按插件分别设置的开关 + 配置 |
|
||||
|
||||
配置更改**需要重启 Gateway 网关**。如果 Gateway 网关正在以启用配置监视和进程内重启的方式运行(默认的 `openclaw gateway` 路径),那么在配置写入后不久,这个重启通常会自动执行。对于原生插件运行时代码或生命周期钩子,不存在受支持的热重载路径;在期望更新后的 `register(api)` 代码、`api.on(...)` 钩子、工具、服务或提供商/运行时钩子生效之前,请重启正在服务实时渠道的 Gateway 网关进程。
|
||||
配置更改**需要重启 Gateway 网关**。如果 Gateway 网关正在以启用配置监听和进程内重启的方式运行(默认的 `openclaw gateway` 路径),通常会在配置写入完成后不久自动执行重启。对于原生插件运行时代码或生命周期钩子,没有受支持的热重载路径;在你期望更新后的 `register(api)` 代码、`api.on(...)` 钩子、工具、服务或提供商/运行时钩子生效之前,请重启正在服务实时渠道的 Gateway 网关进程。
|
||||
|
||||
`openclaw plugins list` 是本地 CLI/配置快照。其中某个插件显示为 `loaded`,表示从该次 CLI 调用所看到的配置/文件来看,这个插件可被发现且可被加载。这并不能证明一个已经运行中的远程 Gateway 网关子进程已重启并载入同一份插件代码。在 VPS/容器部署中,如果存在包装进程,请将重启信号发送给实际的 `openclaw gateway run` 进程,或对正在运行的 Gateway 网关使用 `openclaw gateway restart`。
|
||||
`openclaw plugins list` 是本地 CLI/配置快照。那里显示为 `loaded` 的插件,表示从该次 CLI 调用所看到的配置/文件中,该插件可被发现且可被加载。这并不能证明一个已在运行的远程 Gateway 网关子进程已经重启并使用了相同的插件代码。在 VPS/容器部署中,如果有包装进程,请将重启发送到实际的 `openclaw gateway run` 进程,或对正在运行的 Gateway 网关使用 `openclaw gateway restart`。
|
||||
|
||||
<Accordion title="插件状态:disabled、missing 与 invalid">
|
||||
- **Disabled**:插件存在,但被启用规则关闭。配置会被保留。
|
||||
- **Missing**:配置引用了某个插件 id,但设备发现未找到该插件。
|
||||
- **Invalid**:插件存在,但其配置与声明的 schema 不匹配。
|
||||
<Accordion title="插件状态:已禁用 vs 缺失 vs 无效">
|
||||
- **已禁用**:插件存在,但启用规则将其关闭。配置会被保留。
|
||||
- **缺失**:配置引用了某个插件 id,但在发现过程中未找到它。
|
||||
- **无效**:插件存在,但其配置与声明的 schema 不匹配。
|
||||
</Accordion>
|
||||
|
||||
## 设备发现和优先级
|
||||
## 发现顺序和优先级
|
||||
|
||||
OpenClaw 按以下顺序扫描插件(先匹配者优先):
|
||||
|
||||
@ -169,7 +169,7 @@ OpenClaw 按以下顺序扫描插件(先匹配者优先):
|
||||
</Step>
|
||||
|
||||
<Step title="内置插件">
|
||||
随 OpenClaw 一起发布。许多插件默认启用(模型提供商、语音)。
|
||||
随 OpenClaw 一起发布。其中许多默认启用(模型提供商、语音)。
|
||||
其他插件则需要显式启用。
|
||||
</Step>
|
||||
</Steps>
|
||||
@ -177,31 +177,28 @@ OpenClaw 按以下顺序扫描插件(先匹配者优先):
|
||||
### 启用规则
|
||||
|
||||
- `plugins.enabled: false` 会禁用所有插件
|
||||
- `plugins.deny` 始终优先于 allow
|
||||
- `plugins.deny` 总是优先于 allow
|
||||
- `plugins.entries.\<id\>.enabled: false` 会禁用该插件
|
||||
- 来自工作区的插件**默认禁用**(必须显式启用)
|
||||
- 内置插件遵循内建的默认启用集合,除非被覆盖
|
||||
- 独占槽位可以为该槽位强制启用所选插件
|
||||
- 某些内置的选择加入型插件会在配置命名了某个由插件拥有的表面时自动启用,例如提供商模型引用、渠道配置或 harness 运行时
|
||||
- OpenAI 系列的 Codex 路由保持独立的插件边界:
|
||||
`openai-codex/*` 属于 OpenAI 插件,而内置的 Codex
|
||||
app-server 插件则通过 `embeddedHarness.runtime: "codex"` 或旧版
|
||||
`codex/*` 模型引用来选择
|
||||
- 独占插槽可以强制启用该插槽中被选中的插件
|
||||
- 某些内置的可选启用插件会在配置命名了某个插件拥有的表面时自动启用,例如提供商模型引用、渠道配置或 harness 运行时
|
||||
- OpenAI 家族的 Codex 路由保持独立的插件边界:
|
||||
`openai-codex/*` 属于 OpenAI 插件,而内置 Codex app-server 插件则通过 `embeddedHarness.runtime: "codex"` 或旧版 `codex/*` 模型引用来选择
|
||||
|
||||
## 运行时钩子故障排除
|
||||
|
||||
如果某个插件出现在 `plugins list` 中,但 `register(api)` 副作用或钩子没有在实时聊天流量中运行,请先检查以下内容:
|
||||
|
||||
- 运行 `openclaw gateway status --deep --require-rpc`,并确认当前活动的 Gateway 网关 URL、profile、配置路径和进程,就是你正在编辑的那些。
|
||||
- 在插件安装/配置/代码变更后重启实时 Gateway 网关。在包装容器中,PID 1 可能只是一个 supervisor;请重启或向子进程 `openclaw gateway run` 发送信号。
|
||||
- 使用 `openclaw plugins inspect <id> --json` 确认钩子注册和诊断信息。像 `llm_input`、`llm_output` 和 `agent_end` 这类非内置的会话钩子,需要
|
||||
`plugins.entries.<id>.hooks.allowConversationAccess=true`。
|
||||
- 对于模型切换,优先使用 `before_model_resolve`。它会在智能体轮次的模型解析之前运行;`llm_output` 仅会在某次模型尝试产生 assistant 输出之后运行。
|
||||
- 若要证明会话实际使用的模型,请使用 `openclaw sessions` 或 Gateway 网关的会话/状态表面;在调试提供商负载时,请使用 `--raw-stream --raw-stream-path <path>` 启动 Gateway 网关。
|
||||
- 运行 `openclaw gateway status --deep --require-rpc`,确认活动的 Gateway 网关 URL、配置文件、配置路径和进程就是你正在编辑的那些。
|
||||
- 在插件安装/配置/代码更改后重启实时 Gateway 网关。在包装容器中,PID 1 可能只是一个 supervisor;请重启或向子 `openclaw gateway run` 进程发送信号。
|
||||
- 使用 `openclaw plugins inspect <id> --json` 确认钩子注册和诊断信息。非内置的会话钩子,如 `llm_input`、`llm_output` 和 `agent_end`,需要设置 `plugins.entries.<id>.hooks.allowConversationAccess=true`。
|
||||
- 对于模型切换,优先使用 `before_model_resolve`。它会在智能体轮次进行模型解析之前运行;`llm_output` 只会在某次模型尝试生成 assistant 输出之后运行。
|
||||
- 若要证明会话实际使用的模型,请使用 `openclaw sessions` 或 Gateway 网关的会话/状态表面;调试提供商负载时,请使用 `--raw-stream --raw-stream-path <path>` 启动 Gateway 网关。
|
||||
|
||||
## 插件槽位(独占类别)
|
||||
## 插件插槽(独占类别)
|
||||
|
||||
某些类别是独占的(一次只能激活一个):
|
||||
某些类别是独占的(同一时间只能激活一个):
|
||||
|
||||
```json5
|
||||
{
|
||||
@ -214,32 +211,32 @@ OpenClaw 按以下顺序扫描插件(先匹配者优先):
|
||||
}
|
||||
```
|
||||
|
||||
| 槽位 | 控制内容 | 默认值 |
|
||||
| 插槽 | 控制内容 | 默认值 |
|
||||
| --------------- | --------------------- | ------------------- |
|
||||
| `memory` | 当前活动的 Memory 插件 | `memory-core` |
|
||||
| `contextEngine` | 当前活动的上下文引擎 | `legacy`(内建) |
|
||||
| `memory` | 当前激活的记忆插件 | `memory-core` |
|
||||
| `contextEngine` | 当前激活的上下文引擎 | `legacy`(内建) |
|
||||
|
||||
## CLI 参考
|
||||
|
||||
```bash
|
||||
openclaw plugins list # 精简清单
|
||||
openclaw plugins list --enabled # 仅显示已加载插件
|
||||
openclaw plugins list --enabled # 仅显示已加载的插件
|
||||
openclaw plugins list --verbose # 每个插件的详细信息行
|
||||
openclaw plugins list --json # 机器可读清单
|
||||
openclaw plugins inspect <id> # 深度详情
|
||||
openclaw plugins inspect <id> --json # 机器可读格式
|
||||
openclaw plugins inspect --all # 全局表格
|
||||
openclaw plugins inspect <id> --json # 机器可读
|
||||
openclaw plugins inspect --all # 全量范围表格
|
||||
openclaw plugins info <id> # inspect 别名
|
||||
openclaw plugins doctor # 诊断
|
||||
|
||||
openclaw plugins install <package> # 安装(优先 ClawHub,其次 npm)
|
||||
openclaw plugins install <package> # 安装(优先 ClawHub,然后回退到 npm)
|
||||
openclaw plugins install clawhub:<pkg> # 仅从 ClawHub 安装
|
||||
openclaw plugins install <spec> --force # 覆盖现有安装
|
||||
openclaw plugins install <path> # 从本地路径安装
|
||||
openclaw plugins install -l <path> # 链接(不复制),用于开发
|
||||
openclaw plugins install <plugin> --marketplace <source>
|
||||
openclaw plugins install <plugin> --marketplace https://github.com/<owner>/<repo>
|
||||
openclaw plugins install <spec> --pin # 记录精确解析出的 npm spec
|
||||
openclaw plugins install <spec> --pin # 记录精确解析后的 npm spec
|
||||
openclaw plugins install <spec> --dangerously-force-unsafe-install
|
||||
openclaw plugins update <id-or-npm-spec> # 更新单个插件
|
||||
openclaw plugins update <id-or-npm-spec> --dangerously-force-unsafe-install
|
||||
@ -253,31 +250,31 @@ openclaw plugins enable <id>
|
||||
openclaw plugins disable <id>
|
||||
```
|
||||
|
||||
内置插件随 OpenClaw 一起发布。许多插件默认启用(例如内置模型提供商、内置语音提供商以及内置浏览器插件)。其他内置插件仍然需要执行 `openclaw plugins enable <id>`。
|
||||
内置插件随 OpenClaw 一起发布。许多插件默认启用(例如内置模型提供商、内置语音提供商,以及内置浏览器插件)。其他内置插件仍然需要运行 `openclaw plugins enable <id>`。
|
||||
|
||||
`--force` 会就地覆盖现有已安装的插件或 hook pack。对于已跟踪的 npm 插件的常规升级,请使用 `openclaw plugins update <id-or-npm-spec>`。该选项不支持与 `--link` 一起使用,因为后者会复用源路径,而不是复制到受管理的安装目标。
|
||||
`--force` 会就地覆盖现有已安装的插件或 hook 包。对于已跟踪 npm 插件的常规升级,请使用 `openclaw plugins update <id-or-npm-spec>`。它不支持与 `--link` 一起使用,因为后者会复用源路径,而不是复制到受管理的安装目标中。
|
||||
|
||||
当已经设置了 `plugins.allow` 时,`openclaw plugins install` 会在启用插件之前,将已安装的插件 id 添加到该允许列表中,因此重启后安装的插件会立即可加载。
|
||||
当 `plugins.allow` 已设置时,`openclaw plugins install` 会先把已安装插件的 id 添加到该允许列表中,然后再启用它,因此插件在重启后可以立即被加载。
|
||||
|
||||
`openclaw plugins update <id-or-npm-spec>` 适用于已跟踪的安装。传入带有 dist-tag 或精确版本的 npm 包 spec 时,会将包名解析回已跟踪的插件记录,并记录新的 spec 以供后续更新使用。传入不带版本的包名时,则会将一个精确固定版本的安装切回注册表的默认发布线。如果已安装的 npm 插件已经与解析出的版本和记录的制品标识匹配,OpenClaw 会跳过更新,不会下载、重装或重写配置。
|
||||
`openclaw plugins update <id-or-npm-spec>` 适用于已跟踪的安装。传入带有 dist-tag 或精确版本的 npm 包 spec 时,会将包名解析回已跟踪的插件记录,并记录新的 spec 以供后续更新使用。传入不带版本的包名时,会将一个精确固定版本的安装恢复到注册表的默认发布线。如果已安装的 npm 插件已经与解析出的版本和记录的工件标识一致,OpenClaw 会跳过更新,不会下载、重新安装或重写配置。
|
||||
|
||||
`--pin` 仅适用于 npm。它不支持与 `--marketplace` 一起使用,因为 marketplace 安装会持久化 marketplace 来源元数据,而不是 npm spec。
|
||||
`--pin` 仅适用于 npm。它不支持与 `--marketplace` 一起使用,因为 marketplace 安装会持久化 marketplace 源元数据,而不是 npm spec。
|
||||
|
||||
`--dangerously-force-unsafe-install` 是一个紧急兜底覆盖项,用于处理内置危险代码扫描器的误报。它允许插件安装和插件更新在遇到内置 `critical` 发现后继续进行,但仍不会绕过插件 `before_install` 策略阻止或扫描失败阻止。
|
||||
`--dangerously-force-unsafe-install` 是一个紧急破玻璃式覆盖选项,用于处理内置危险代码扫描器的误报。它允许插件安装和插件更新在遇到内置 `critical` 发现后继续执行,但仍不会绕过插件 `before_install` 策略阻止或扫描失败阻止。
|
||||
|
||||
这个 CLI 标志仅适用于插件安装/更新流程。由 Gateway 网关支持的 Skills 依赖安装则使用对应的 `dangerouslyForceUnsafeInstall` 请求覆盖项,而 `openclaw skills install` 仍然是独立的 ClawHub Skills 下载/安装流程。
|
||||
这个 CLI 标志只适用于插件安装/更新流程。由 Gateway 网关支持的 Skills 依赖安装则改用对应的 `dangerouslyForceUnsafeInstall` 请求覆盖,而 `openclaw skills install` 仍然是独立的 ClawHub Skills 下载/安装流程。
|
||||
|
||||
兼容的 Bundle 会参与相同的插件 list/inspect/enable/disable 流程。当前运行时支持包括 Bundle Skills、Claude command-skills、Claude `settings.json` 默认值、Claude `.lsp.json` 和清单声明的 `lspServers` 默认值、Cursor command-skills,以及兼容的 Codex hook 目录。
|
||||
兼容的 bundle 会参与同样的插件 list/inspect/enable/disable 流程。当前运行时支持包括 bundle Skills、Claude command-skills、Claude `settings.json` 默认值、Claude `.lsp.json` 和 manifest 声明的 `lspServers` 默认值、Cursor command-skills,以及兼容的 Codex hook 目录。
|
||||
|
||||
`openclaw plugins inspect <id>` 还会报告检测到的 Bundle 能力,以及由 Bundle 支持的或不受支持的 MCP 和 LSP 服务器条目。
|
||||
`openclaw plugins inspect <id>` 还会报告检测到的 bundle 能力,以及由 bundle 支持或不支持的 MCP 和 LSP 服务器条目。
|
||||
|
||||
Marketplace 来源可以是来自 `~/.claude/plugins/known_marketplaces.json` 的 Claude 已知 marketplace 名称、本地 marketplace 根目录或 `marketplace.json` 路径、类似 `owner/repo` 的 GitHub 简写、GitHub 仓库 URL,或 git URL。对于远程 marketplace,插件条目必须保持在克隆的 marketplace 仓库内部,并且只能使用相对路径来源。
|
||||
Marketplace 源可以是 `~/.claude/plugins/known_marketplaces.json` 中的 Claude 已知 marketplace 名称、本地 marketplace 根目录或 `marketplace.json` 路径、类似 `owner/repo` 的 GitHub 简写、GitHub 仓库 URL,或 git URL。对于远程 marketplace,插件条目必须保持在克隆的 marketplace 仓库内,并且只能使用相对路径源。
|
||||
|
||||
完整详情请参阅 [`openclaw plugins` CLI 参考](/zh-CN/cli/plugins)。
|
||||
有关完整详情,请参阅 [`openclaw plugins` CLI 参考](/zh-CN/cli/plugins)。
|
||||
|
||||
## 插件 API 概览
|
||||
|
||||
原生插件会导出一个入口对象,并暴露 `register(api)`。较旧的插件仍可能使用 `activate(api)` 作为旧版别名,但新插件应使用 `register`。
|
||||
原生插件会导出一个入口对象,该对象暴露 `register(api)`。旧版插件仍可能使用 `activate(api)` 作为旧版别名,但新插件应使用 `register`。
|
||||
|
||||
```typescript
|
||||
export default definePluginEntry({
|
||||
@ -297,7 +294,19 @@ export default definePluginEntry({
|
||||
});
|
||||
```
|
||||
|
||||
OpenClaw 会加载该入口对象,并在插件激活期间调用 `register(api)`。对于旧插件,加载器仍会回退到 `activate(api)`,但内置插件和新的外部插件都应将 `register` 视为公共契约。
|
||||
OpenClaw 会加载该入口对象,并在插件激活期间调用 `register(api)`。加载器仍会为旧版插件回退到 `activate(api)`,但内置插件和新的外部插件应将 `register` 视为公开契约。
|
||||
|
||||
`api.registrationMode` 会告诉插件其入口正在因何种原因被加载:
|
||||
|
||||
| 模式 | 含义 |
|
||||
| --------------- | ------------------------------------------------------------------------------------------------------ |
|
||||
| `full` | 运行时激活。注册工具、钩子、服务、命令、路由和其他实时副作用。 |
|
||||
| `discovery` | 只读能力发现。注册提供商和元数据,但跳过高成本的实时副作用。 |
|
||||
| `setup-only` | 通过轻量设置入口加载渠道设置元数据。 |
|
||||
| `setup-runtime` | 加载渠道设置,同时也需要运行时入口。 |
|
||||
| `cli-metadata` | 仅收集 CLI 命令元数据。 |
|
||||
|
||||
如果插件入口会打开 socket、数据库、后台 worker 或长生命周期客户端,应使用 `api.registrationMode === "full"` 来保护这些副作用。发现加载会与激活加载分开缓存,并且不会替换正在运行的 Gateway 网关注册表。
|
||||
|
||||
常见注册方法:
|
||||
|
||||
@ -309,7 +318,7 @@ OpenClaw 会加载该入口对象,并在插件激活期间调用 `register(api
|
||||
| `registerHook` / `on(...)` | 生命周期钩子 |
|
||||
| `registerSpeechProvider` | 文本转语音 / STT |
|
||||
| `registerRealtimeTranscriptionProvider` | 流式 STT |
|
||||
| `registerRealtimeVoiceProvider` | 双向实时语音 |
|
||||
| `registerRealtimeVoiceProvider` | 双工实时语音 |
|
||||
| `registerMediaUnderstandingProvider` | 图像/音频分析 |
|
||||
| `registerImageGenerationProvider` | 图像生成 |
|
||||
| `registerMusicGenerationProvider` | 音乐生成 |
|
||||
@ -321,24 +330,24 @@ OpenClaw 会加载该入口对象,并在插件激活期间调用 `register(api
|
||||
| `registerContextEngine` | 上下文引擎 |
|
||||
| `registerService` | 后台服务 |
|
||||
|
||||
类型化生命周期钩子的守卫行为:
|
||||
类型化生命周期钩子的钩子保护行为:
|
||||
|
||||
- `before_tool_call`:`{ block: true }` 为终结结果;会跳过更低优先级的处理程序。
|
||||
- `before_tool_call`:`{ block: false }` 为无操作,不会清除更早的阻止。
|
||||
- `before_install`:`{ block: true }` 为终结结果;会跳过更低优先级的处理程序。
|
||||
- `before_install`:`{ block: false }` 为无操作,不会清除更早的阻止。
|
||||
- `message_sending`:`{ cancel: true }` 为终结结果;会跳过更低优先级的处理程序。
|
||||
- `message_sending`:`{ cancel: false }` 为无操作,不会清除更早的取消。
|
||||
- `before_tool_call`:`{ block: true }` 是终止性的;更低优先级的处理器会被跳过。
|
||||
- `before_tool_call`:`{ block: false }` 不执行任何操作,也不会清除之前的阻止。
|
||||
- `before_install`:`{ block: true }` 是终止性的;更低优先级的处理器会被跳过。
|
||||
- `before_install`:`{ block: false }` 不执行任何操作,也不会清除之前的阻止。
|
||||
- `message_sending`:`{ cancel: true }` 是终止性的;更低优先级的处理器会被跳过。
|
||||
- `message_sending`:`{ cancel: false }` 不执行任何操作,也不会清除之前的取消。
|
||||
|
||||
原生 Codex app-server 会将桥接的 Codex 原生工具事件回传到这个 hook 表面中。插件可以通过 `before_tool_call` 阻止原生 Codex 工具,通过 `after_tool_call` 观察结果,并参与 Codex `PermissionRequest` 批准流程。该桥接目前还不会重写 Codex 原生工具参数。
|
||||
原生 Codex app-server 会将桥接的 Codex 原生工具事件回传到这个钩子表面。插件可以通过 `before_tool_call` 阻止原生 Codex 工具,通过 `after_tool_call` 观察结果,并参与 Codex `PermissionRequest` 批准。该桥接目前尚不会重写 Codex 原生工具参数。
|
||||
|
||||
有关完整的类型化 hook 行为,请参阅 [SDK 概览](/zh-CN/plugins/sdk-overview#hook-decision-semantics)。
|
||||
有关完整的类型化钩子行为,请参阅 [SDK 概览](/zh-CN/plugins/sdk-overview#hook-decision-semantics)。
|
||||
|
||||
## 相关内容
|
||||
|
||||
- [Building Plugins](/zh-CN/plugins/building-plugins) — 创建你自己的插件
|
||||
- [Plugin Bundles](/zh-CN/plugins/bundles) — 与 Codex/Claude/Cursor 的 Bundle 兼容性
|
||||
- [Plugin Manifest](/zh-CN/plugins/manifest) — 清单 schema
|
||||
- [Registering Tools](/zh-CN/plugins/building-plugins#registering-agent-tools) — 在插件中添加智能体工具
|
||||
- [Plugin Internals](/zh-CN/plugins/architecture) — 能力模型和加载管线
|
||||
- [构建插件](/zh-CN/plugins/building-plugins) — 创建你自己的插件
|
||||
- [Plugin Bundles](/zh-CN/plugins/bundles) — Codex/Claude/Cursor bundle 兼容性
|
||||
- [Plugin Manifest](/zh-CN/plugins/manifest) — manifest schema
|
||||
- [注册工具](/zh-CN/plugins/building-plugins#registering-agent-tools) — 在插件中添加智能体工具
|
||||
- [Plugin Internals](/zh-CN/plugins/architecture) — 能力模型和加载流水线
|
||||
- [Community Plugins](/zh-CN/plugins/community) — 第三方列表
|
||||
|
||||
Loading…
Reference in New Issue
Block a user