diff --git a/docs/zh-CN/channels/qa-channel.md b/docs/zh-CN/channels/qa-channel.md index b2d51cc63..5aa3782a2 100644 --- a/docs/zh-CN/channels/qa-channel.md +++ b/docs/zh-CN/channels/qa-channel.md @@ -1,38 +1,29 @@ --- read_when: - 你正在将合成 QA 传输接入本地或 CI 测试运行中 - - 你需要内置 qa-channel 的配置界面 + - 你需要内置的 QA channel 配置界面 - 你正在迭代端到端 QA 自动化 -summary: 用于确定性 OpenClaw QA 场景的 Slack 类合成渠道插件 -title: QA 渠道 +summary: 用于确定性 OpenClaw QA 场景的合成 Slack 类渠道插件 +title: QA channel x-i18n: - generated_at: "2026-04-23T22:55:54Z" + generated_at: "2026-04-27T17:44:10Z" model: gpt-5.4 provider: openai - source_hash: 195312376ce8815af44169505b66314eb287ede19e40d27db5b4f256edaa0b46 + source_hash: e1de1f52da1a14c845cf2a536ddc6f36ab52ed6364f68d9ece32ce272e2a2f96 source_path: channels/qa-channel.md workflow: 15 --- -`qa-channel` 是一个内置的合成消息传输,用于自动化 OpenClaw QA。 +`qa-channel` 是用于自动化 OpenClaw QA 的内置合成消息传输。它不是生产渠道——它的存在是为了在保持状态确定且完全可检查的同时,演练真实传输所使用的同一渠道插件边界。 -它不是生产渠道。它的存在是为了在保持状态确定且完全可检查的前提下,演练真实传输所使用的同一渠道插件边界。 - -## 当前功能 +## 它的作用 - Slack 类目标语法: - `dm:` - `channel:` - `thread:/` -- 基于 HTTP 的合成总线,用于: - - 注入入站消息 - - 捕获出站记录 - - 创建线程 - - reactions - - 编辑 - - 删除 - - 搜索和读取操作 -- 内置的宿主端自检运行器,可写出 Markdown 报告 +- 基于 HTTP 的合成总线,用于入站消息注入、出站消息记录捕获、线程创建、反应、编辑、删除,以及搜索/读取操作。 +- 主机侧自检运行器,会将 Markdown 报告写入 `.artifacts/qa-e2e/`。 ## 配置 @@ -50,63 +41,53 @@ x-i18n: } ``` -支持的账户键名: +账户键名: -- `baseUrl` -- `botUserId` -- `botDisplayName` -- `pollTimeoutMs` -- `allowFrom` -- `defaultTo` -- `actions.messages` -- `actions.reactions` -- `actions.search` -- `actions.threads` +- `enabled` — 此账户的主开关。 +- `name` — 可选显示标签。 +- `baseUrl` — 合成总线 URL。 +- `botUserId` — 目标语法中使用的 Matrix 风格机器人用户 id。 +- `botDisplayName` — 出站消息的显示名称。 +- `pollTimeoutMs` — 长轮询等待窗口。取值为 100 到 30000 之间的整数。 +- `allowFrom` — 发送者允许列表(用户 id 或 `"*"`)。 +- `defaultTo` — 未提供目标时使用的回退目标。 +- `actions.messages` / `actions.reactions` / `actions.search` / `actions.threads` — 按操作划分的工具门控。 + +顶层多账户键名: + +- `accounts` — 以账户 id 为键、包含具名逐账户覆盖项的记录。 +- `defaultAccount` — 配置了多个账户时的首选账户 id。 ## 运行器 -当前的纵向切片: +主机侧自检(会在 `.artifacts/qa-e2e/` 下写入 Markdown 报告): ```bash pnpm qa:e2e ``` -现在会通过内置的 `qa-lab` 插件路由。它会启动仓库内的 QA 总线,启动内置的 `qa-channel` 运行时切片,运行确定性的自检,并将 Markdown 报告写入 `.artifacts/qa-e2e/`。 +这会通过 `qa-lab` 路由,启动仓库内 QA 总线,引导内置的 `qa-channel` 运行时切片,并运行确定性的自检。 -私有调试器 UI: - -```bash -pnpm qa:lab:up -``` - -这一条命令会构建 QA 站点,启动基于 Docker 的 Gateway 网关 + QA Lab 堆栈,并打印 QA Lab URL。你可以在该站点中选择场景、选择模型通道、启动单次运行,并实时查看结果。 - -完整的基于仓库的 QA 套件: +完整的仓库支持场景套件: ```bash pnpm openclaw qa suite ``` -这会在本地 URL 启动私有 QA 调试器,与随产品发布的 Control UI bundle 分开。 +并行运行针对 QA gateway 通道的场景。关于场景、配置文件和提供商模式,请参阅 [QA overview](/zh-CN/concepts/qa-e2e-automation)。 -## 范围 +Docker 支持的 QA 站点(Gateway 网关 + QA Lab 调试器 UI 集成在同一个栈中): -当前范围有意保持精简: +```bash +pnpm qa:lab:up +``` -- 总线 + 插件传输 -- 线程化路由语法 -- 渠道自有的消息操作 -- Markdown 报告 -- 带运行控制的基于 Docker 的 QA 站点 - -后续工作将添加: - -- 提供商/模型矩阵执行 -- 更丰富的场景发现 -- 后续加入 OpenClaw 原生编排 +这会构建 QA 站点,启动由 Docker 支持的 Gateway 网关 + QA Lab 栈,并输出 QA Lab URL。之后你可以在其中选择场景、选择模型通道、启动单次运行,并实时查看结果。QA Lab 调试器独立于已发布的 Control UI 打包内容。 ## 相关内容 +- [QA overview](/zh-CN/concepts/qa-e2e-automation) — 整体栈、传输适配器、场景编写 +- [Matrix QA](/zh-CN/concepts/qa-matrix) — 驱动真实渠道的示例实时传输运行器 - [配对](/zh-CN/channels/pairing) - [群组](/zh-CN/channels/groups) - [渠道概览](/zh-CN/channels) diff --git a/docs/zh-CN/concepts/qa-e2e-automation.md b/docs/zh-CN/concepts/qa-e2e-automation.md index d097942e4..c0e515293 100644 --- a/docs/zh-CN/concepts/qa-e2e-automation.md +++ b/docs/zh-CN/concepts/qa-e2e-automation.md @@ -1,48 +1,68 @@ --- read_when: - - 扩展 qa-lab 或 qa-channel - - 添加由仓库支持的 QA 场景 - - 围绕 Gateway 网关仪表盘构建更高真实度的 QA 自动化 -summary: qa-lab、qa-channel、带种子场景和协议报告的私有 QA 自动化形态 -title: QA E2E 自动化 + - 理解 QA 栈如何协同工作 + - 扩展 qa-lab、QA channel 或传输适配器 + - 添加仓库支持的 QA 场景 + - 围绕 Gateway 网关仪表板构建更高拟真度的 QA 自动化 +summary: QA 栈概览:qa-lab、QA channel、仓库支持的场景、实时传输通道、传输适配器和报告。 +title: QA overview x-i18n: - generated_at: "2026-04-27T06:03:54Z" + generated_at: "2026-04-27T17:44:11Z" model: gpt-5.4 provider: openai - source_hash: d439b460967ea8386e079059db73b709174bfaae7160212e7a1d5ff981c0cd3c + source_hash: 75c47dc9a430d54c2a701a70efbe098a3ddecef74afe91c4e594f5eea9e57bbb source_path: concepts/qa-e2e-automation.md workflow: 15 --- -私有 QA 栈旨在以比单个单元测试更贴近真实、 -更具渠道形态的方式来验证 OpenClaw。 +私有 QA 栈旨在以比单个单元测试更真实、更贴近渠道形态的方式来演练 OpenClaw。 当前组成部分: -- `extensions/qa-channel`:合成消息渠道,支持私信、频道、线程、 - reaction、编辑和删除等界面。 -- `extensions/qa-lab`:调试器 UI 和 QA 总线,用于观察对话记录、 - 注入入站消息以及导出 Markdown 报告。 -- `qa/`:由仓库支持的种子资源,用于启动任务和基线 QA - 场景。 +- `extensions/qa-channel`:合成消息渠道,提供私信、渠道、线程、表情回应、编辑和删除等交互面。 +- `extensions/qa-lab`:调试器 UI 和 QA 总线,用于观察转录内容、注入入站消息以及导出 Markdown 报告。 +- `extensions/qa-matrix`、未来的运行器插件:实时传输适配器,在子 QA Gateway 网关内驱动真实渠道。 +- `qa/`:为启动任务和基线 QA 场景提供仓库支持的种子资源。 + +## 命令界面 + +每个 QA 流程都在 `pnpm openclaw qa ` 下运行。许多命令也有 `pnpm qa:*` 脚本别名;两种形式都受支持。 + +| Command | Purpose | +| --------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `qa run` | 内置 QA 自检;会写入一份 Markdown 报告。 | +| `qa suite` | 针对 QA Gateway 网关通道运行仓库支持的场景。别名:`pnpm openclaw qa suite --runner multipass` 用于一次性 Linux VM。 | +| `qa coverage` | 打印 Markdown 场景覆盖清单(使用 `--json` 可获得机器可读输出)。 | +| `qa parity-report` | 比较两个 `qa-suite-summary.json` 文件并写入 agentic parity-gate 报告。 | +| `qa character-eval` | 在多个实时模型上运行角色 QA 场景,并生成带评判结果的报告。参见[报告](#reporting)。 | +| `qa manual` | 针对所选提供商/模型通道运行一次性提示词。 | +| `qa ui` | 启动 QA 调试器 UI 和本地 QA 总线(别名:`pnpm qa:lab:ui`)。 | +| `qa docker-build-image` | 构建预烘焙的 QA Docker 镜像。 | +| `qa docker-scaffold` | 为 QA 仪表板 + Gateway 网关通道写入 docker-compose 脚手架。 | +| `qa up` | 构建 QA 站点,启动基于 Docker 的栈,并打印 URL(别名:`pnpm qa:lab:up`;`:fast` 变体会添加 `--use-prebuilt-image --bind-ui-dist --skip-ui-build`)。 | +| `qa aimock` | 仅启动 AIMock provider 服务器。 | +| `qa mock-openai` | 仅启动支持场景感知的 `mock-openai` provider 服务器。 | +| `qa credentials doctor` / `add` / `list` / `remove` | 管理共享的 Convex 凭证池。 | +| `qa matrix` | 针对一次性 Tuwunel homeserver 的实时传输通道。参见 [Matrix QA](/zh-CN/concepts/qa-matrix)。 | +| `qa telegram` | 针对真实私有 Telegram 群组的实时传输通道。 | +| `qa discord` | 针对真实私有 Discord guild 渠道的实时传输通道。 | + +## 操作流程 当前的 QA 操作流程是一个双窗格 QA 站点: -- 左侧:带有智能体的 Gateway 网关仪表盘(Control UI)。 -- 右侧:QA Lab,显示类 Slack 的对话记录和场景计划。 +- 左侧:带有智能体的 Gateway 网关仪表板(Control UI)。 +- 右侧:QA Lab,显示类似 Slack 的转录内容和场景计划。 -运行方式: +运行方式如下: ```bash pnpm qa:lab:up ``` -该命令会构建 QA 站点、启动由 Docker 支持的 gateway lane,并暴露 -QA Lab 页面,供操作员或自动化循环向智能体下发 QA -任务、观察真实渠道行为,并记录哪些内容有效、失败或仍被阻塞。 +这会构建 QA 站点,启动基于 Docker 的 Gateway 网关通道,并暴露 QA Lab 页面,操作员或自动化循环可以在其中给智能体分配 QA 任务、观察真实渠道行为,并记录哪些内容正常、失败或仍被阻塞。 -为了更快地迭代 QA Lab UI,而不必每次都重建 Docker 镜像, -可以使用 bind-mount 的 QA Lab bundle 启动栈: +如果你希望更快地迭代 QA Lab UI,而不必每次都重新构建 Docker 镜像,请使用带有绑定挂载 QA Lab bundle 的方式启动该栈: ```bash pnpm openclaw qa docker-build-image @@ -51,9 +71,7 @@ pnpm qa:lab:up:fast pnpm qa:lab:watch ``` -`qa:lab:up:fast` 会让 Docker 服务基于预构建镜像运行,并将 -`extensions/qa-lab/web/dist` bind-mount 到 `qa-lab` 容器中。`qa:lab:watch` -会在变更时重建该 bundle,而当 QA Lab 资源哈希变化时浏览器会自动重载。 +`qa:lab:up:fast` 让 Docker 服务保持在预构建镜像上运行,并将 `extensions/qa-lab/web/dist` 绑定挂载到 `qa-lab` 容器中。`qa:lab:watch` 会在变更时重新构建该 bundle,当 QA Lab 资源哈希发生变化时,浏览器会自动重新加载。 若要运行本地 OpenTelemetry trace 冒烟测试,请执行: @@ -61,204 +79,202 @@ pnpm qa:lab:watch pnpm qa:otel:smoke ``` -该脚本会启动本地 OTLP/HTTP trace 接收器,运行 -启用了 `diagnostics-otel` 插件的 `otel-trace-smoke` QA 场景,然后 -解码导出的 protobuf span,并断言关键发布形态: -必须存在 `openclaw.run`、`openclaw.harness.run`、`openclaw.model.call`、 -`openclaw.context.assembled` 和 `openclaw.message.delivery`; -成功轮次中的模型调用不得导出 `StreamAbandoned`;原始诊断 ID 和 -`openclaw.content.*` 属性不得进入 trace。它会在 -QA 套件工件旁写入 `otel-smoke-summary.json`。 +该脚本会启动本地 OTLP/HTTP trace 接收器,启用 `diagnostics-otel` 插件运行 `otel-trace-smoke` QA 场景,然后解码导出的 protobuf spans,并断言发布关键形态:必须存在 `openclaw.run`、`openclaw.harness.run`、`openclaw.model.call`、`openclaw.context.assembled` 和 `openclaw.message.delivery`;成功轮次中的模型调用不得导出 `StreamAbandoned`;原始诊断 ID 和 `openclaw.content.*` 属性不得出现在 trace 中。它会在 QA suite 产物旁边写入 `otel-smoke-summary.json`。 -可观测性 QA 仅限源代码检出使用。npm tarball 有意省略了 -QA Lab,因此软件包 Docker 发布 lane 不会运行 `qa` 命令。更改诊断 -埋点时,请在已构建的源代码检出中使用 `pnpm qa:otel:smoke`。 +可观测性 QA 仅支持源码检出环境。npm tarball 会刻意省略 QA Lab,因此软件包 Docker 发布通道不会运行 `qa` 命令。修改诊断埋点时,请在已构建的源码检出环境中使用 `pnpm qa:otel:smoke`。 -若要运行基于真实传输的 Matrix 冒烟 lane,请执行: +若要运行一个真实传输的 Matrix 冒烟通道,请执行: ```bash pnpm openclaw qa matrix --profile fast --fail-fast ``` -该 lane 会在 Docker 中配置一次性的 Tuwunel homeserver,注册 -临时的 driver、SUT 和 observer 用户,创建一个私有房间,然后在 QA gateway 子进程中 -运行真实 Matrix 插件。实时传输 lane 会将子进程配置限定在待测传输范围内, -因此 Matrix 会在子进程配置中不启用 `qa-channel` 的情况下运行。它会将结构化报告工件和 -合并后的 stdout/stderr 日志写入所选的 Matrix QA 输出目录。若要同时捕获外层 -`scripts/run-node.mjs` 的构建/启动器输出,请将 -`OPENCLAW_RUN_NODE_OUTPUT_LOG=` 设置为仓库内的日志文件。 -默认会打印 Matrix 进度。CLI 默认 profile 为 `all`,因此 -直接运行 `pnpm openclaw qa matrix` 仍会执行完整目录。对于发布关键的传输契约, -请使用 `--profile fast`;或使用 `transport`、`media`、`e2ee-smoke`、 -`e2ee-deep` 和 `e2ee-cli` 对完整覆盖进行分片。`--fail-fast` -会在第一个场景失败后停止,适合用作发布门禁而不是 -完整清单。`OPENCLAW_QA_MATRIX_TIMEOUT_MS` 用于限制整个运行时间, -`OPENCLAW_QA_MATRIX_NO_REPLY_WINDOW_MS` 可为 CI 缩短无回复静默窗口, -`OPENCLAW_QA_MATRIX_CLEANUP_TIMEOUT_MS` 用于限制清理时间,以便卡住的 -Docker 拆除流程报告精确的恢复命令,而不是一直挂起。 +此通道的完整 CLI 参考、配置文件/场景目录、环境变量和产物布局见 [Matrix QA](/zh-CN/concepts/qa-matrix)。简而言之:它会在 Docker 中配置一个一次性的 Tuwunel homeserver,注册临时 driver/SUT/observer 用户,在限定于该传输协议的子 QA Gateway 网关内运行真实 Matrix 插件(不使用 `qa-channel`),然后在 `.artifacts/qa-e2e/matrix-/` 下写入 Markdown 报告、JSON 摘要、observed-events 产物和组合输出日志。 -若要运行基于真实传输的 Telegram 冒烟 lane,请执行: +若要运行一个真实传输的 Telegram 冒烟通道,请执行: ```bash pnpm openclaw qa telegram ``` -该 lane 面向一个真实的私有 Telegram 群组,而不是配置 -一次性服务器。它需要 `OPENCLAW_QA_TELEGRAM_GROUP_ID`、 -`OPENCLAW_QA_TELEGRAM_DRIVER_BOT_TOKEN` 和 -`OPENCLAW_QA_TELEGRAM_SUT_BOT_TOKEN`,并且需要两个位于同一 -私有群组中的不同机器人。SUT 机器人必须拥有 Telegram 用户名, -并且当两个机器人都在 `@BotFather` 中启用了 -Bot-to-Bot Communication Mode 时,机器人到机器人的观察效果最佳。 -任何场景失败时,命令都会以非零状态退出。若你 -想保留工件但不使用失败退出码,请使用 `--allow-failures`。 -Telegram 报告和摘要包含每次回复的 RTT,范围从 driver 消息 -发送请求到观察到的 SUT 回复,从 canary 开始。 +该通道会以一个真实私有 Telegram 群组为目标,而不是配置一次性服务器。它需要 `OPENCLAW_QA_TELEGRAM_GROUP_ID`、`OPENCLAW_QA_TELEGRAM_DRIVER_BOT_TOKEN` 和 `OPENCLAW_QA_TELEGRAM_SUT_BOT_TOKEN`,并要求两个不同的机器人位于同一个私有群组中。SUT 机器人必须具有 Telegram 用户名,并且当两个机器人都在 `@BotFather` 中启用 Bot-to-Bot Communication Mode 时,机器人到机器人的观察效果最佳。设置 `OPENCLAW_QA_TELEGRAM_CAPTURE_CONTENT=1` 可以在 observed-message 产物中保留消息正文(默认会脱敏)。 +当任一场景失败时,该命令会以非零状态退出。若你希望在不触发失败退出码的情况下保留产物,请使用 `--allow-failures`。 +Telegram 报告和摘要包含每条回复的 RTT,计算范围从 driver 消息发送请求到观察到的 SUT 回复,从金丝雀场景开始。 -在使用池化的实时凭证之前,请运行: +在使用池化的实时凭证前,请执行: ```bash pnpm openclaw qa credentials doctor ``` -该 doctor 会检查 Convex broker 环境、验证端点设置,并在存在 -维护者密钥时验证 admin/list 可达性。它只会报告密钥是已设置还是缺失。 +Doctor 会检查 Convex broker 环境变量、验证端点设置,并在存在维护者密钥时验证 admin/list 可达性。它只会报告密钥是已设置还是缺失,不会显示具体内容。 -若要运行基于真实传输的 Discord 冒烟 lane,请执行: +若要运行一个真实传输的 Discord 冒烟通道,请执行: ```bash pnpm openclaw qa discord ``` -该 lane 面向一个真实的私有 Discord guild 渠道,包含两个机器人: -一个由 harness 控制的 driver 机器人,以及一个由子 OpenClaw gateway -通过内置 Discord 插件启动的 SUT 机器人。使用环境凭证时, -它需要 `OPENCLAW_QA_DISCORD_GUILD_ID`、`OPENCLAW_QA_DISCORD_CHANNEL_ID`、 -`OPENCLAW_QA_DISCORD_DRIVER_BOT_TOKEN`、`OPENCLAW_QA_DISCORD_SUT_BOT_TOKEN`, -以及 `OPENCLAW_QA_DISCORD_SUT_APPLICATION_ID`。 -该 lane 会验证渠道提及处理,并检查 SUT 机器人是否已经 -向 Discord 注册原生 `/help` 命令。 -任何场景失败时,命令都会以非零状态退出。若你 -想保留工件但不使用失败退出码,请使用 `--allow-failures`。 +该通道会以一个真实私有 Discord guild 渠道为目标,并使用两个机器人:一个由 harness 控制的 driver 机器人,以及一个由子 OpenClaw Gateway 网关通过内置 Discord 插件启动的 SUT 机器人。使用环境变量凭证时,它需要 `OPENCLAW_QA_DISCORD_GUILD_ID`、`OPENCLAW_QA_DISCORD_CHANNEL_ID`、`OPENCLAW_QA_DISCORD_DRIVER_BOT_TOKEN`、`OPENCLAW_QA_DISCORD_SUT_BOT_TOKEN` 和 `OPENCLAW_QA_DISCORD_SUT_APPLICATION_ID`。设置 `OPENCLAW_QA_DISCORD_CAPTURE_CONTENT=1` 可以在 observed-message 产物中保留消息正文(默认会脱敏)。 +该通道会验证渠道提及处理,并检查 SUT 机器人是否已向 Discord 注册原生 `/help` 命令。 +当任一场景失败时,该命令会以非零状态退出。若你希望在不触发失败退出码的情况下保留产物,请使用 `--allow-failures`。 -实时传输 lane 现在共享同一套较小的契约,而不是各自发明 -自己的场景列表形状: +## 实时传输覆盖范围 -`qa-channel` 仍然是覆盖范围广的合成产品行为套件,不属于 -实时传输覆盖矩阵的一部分。 +实时传输通道共享同一套契约,而不是各自发明自己的场景列表结构。`qa-channel` 是覆盖面更广的合成产品行为套件,不属于实时传输覆盖矩阵的一部分。 -| Lane | Canary | 提及门控 | allowlist 阻止 | 顶层回复 | 重启恢复 | 线程后续跟进 | 线程隔离 | reaction 观察 | help 命令 | 原生命令注册 | -| -------- | ------ | -------- | -------------- | -------- | -------- | ------------ | -------- | --------------- | --------- | ------------ | -| Matrix | x | x | x | x | x | x | x | x | | | -| Telegram | x | x | | | | | | | x | | -| Discord | x | x | | | | | | | | x | +| Lane | Canary | Mention gating | Allowlist block | Top-level reply | Restart resume | Thread follow-up | Thread isolation | Reaction observation | Help command | Native command registration | +| -------- | ------ | -------------- | --------------- | --------------- | -------------- | ---------------- | ---------------- | -------------------- | ------------ | --------------------------- | +| Matrix | x | x | x | x | x | x | x | x | | | +| Telegram | x | x | | | | | | | x | | +| Discord | x | x | | | | | | | | x | -这样可以让 `qa-channel` 继续作为覆盖广泛的产品行为套件,而 Matrix、 -Telegram 和未来的实时传输则共享一份明确的传输契约检查清单。 +这样可以让 `qa-channel` 保持为覆盖面广泛的产品行为套件,同时让 Matrix、Telegram 和未来的实时传输协议共享一份明确的传输契约检查清单。 -若要在不将 Docker 引入 QA 路径的情况下运行一次性 Linux VM lane,请执行: +若要在不将 Docker 引入 QA 路径的情况下运行一次性 Linux VM 通道,请执行: ```bash pnpm openclaw qa suite --runner multipass --scenario channel-chat-baseline ``` -这会启动一个全新的 Multipass guest,在 guest 内安装依赖、 -构建 OpenClaw、运行 `qa suite`,然后将常规 QA 报告和 -摘要复制回主机上的 `.artifacts/qa-e2e/...`。 -它复用了与主机上 `qa suite` 相同的场景选择行为。 -主机和 Multipass 套件运行默认都会并行执行多个已选场景, -并使用隔离的 gateway worker。`qa-channel` 默认并发数为 4, -上限受所选场景数量限制。使用 `--concurrency ` 可调整 -worker 数量,或使用 `--concurrency 1` 串行执行。 -任何场景失败时,命令都会以非零状态退出。若你 -想保留工件但不使用失败退出码,请使用 `--allow-failures`。 -实时运行会转发那些适合 guest 使用的受支持 QA 认证输入: -基于环境变量的 provider 密钥、QA 实时 provider 配置路径, -以及存在时的 `CODEX_HOME`。请将 `--output-dir` 保持在仓库根目录下, -以便 guest 能通过挂载的工作区回写结果。 +这会启动一个全新的 Multipass guest,在 guest 内安装依赖、构建 OpenClaw、运行 `qa suite`,然后将常规 QA 报告和摘要复制回宿主机上的 `.artifacts/qa-e2e/...`。 +它复用了与宿主机上 `qa suite` 相同的场景选择行为。 +默认情况下,宿主机和 Multipass suite 运行都会并行执行多个已选场景,并使用隔离的 Gateway 网关工作进程。`qa-channel` 默认并发度为 4,并受所选场景数量限制。使用 `--concurrency ` 可调整工作进程数量,或使用 `--concurrency 1` 进行串行执行。 +当任一场景失败时,该命令会以非零状态退出。若你希望在不触发失败退出码的情况下保留产物,请使用 `--allow-failures`。 +实时运行会转发适合 guest 使用的受支持 QA 认证输入:基于环境变量的 provider 密钥、QA 实时 provider 配置路径,以及存在时的 `CODEX_HOME`。请将 `--output-dir` 保持在仓库根目录下,以便 guest 能通过挂载的工作区回写结果。 -## 由仓库支持的种子 +## 仓库支持的种子资源 种子资源位于 `qa/`: - `qa/scenarios/index.md` - `qa/scenarios//*.md` -这些内容有意保存在 git 中,以便 QA 计划对人类和 -智能体都可见。 +这些内容被有意保存在 git 中,这样人类和智能体都能看到 QA 计划。 -`qa-lab` 应保持为通用的 Markdown 运行器。每个场景 Markdown 文件 -都是单次测试运行的事实来源,并应定义: +`qa-lab` 应保持为通用 Markdown 运行器。每个场景 Markdown 文件都是一次测试运行的事实来源,并且应定义: - 场景元数据 -- 可选的类别、能力、lane 和风险元数据 +- 可选的 category、capability、lane 和 risk 元数据 - 文档和代码引用 -- 可选的插件要求 +- 可选的插件需求 - 可选的 Gateway 网关配置补丁 - 可执行的 `qa-flow` -支撑 `qa-flow` 的可复用运行时表面可以保持通用和跨领域。 -例如,Markdown 场景可以组合传输侧辅助工具与浏览器侧辅助工具, -通过 Gateway 网关的 `browser.request` seam 驱动嵌入式 Control UI,而无需添加专门的运行器。 +支撑 `qa-flow` 的可复用运行时界面可以继续保持通用和跨领域。例如,Markdown 场景可以将传输侧辅助工具与浏览器侧辅助工具组合起来,通过 Gateway 网关 `browser.request` 接口驱动嵌入式 Control UI,而无需新增一个特殊用途的运行器。 -场景文件应按产品能力分组,而不是按源代码树文件夹分组。文件移动时保持 -场景 ID 稳定;通过 `docsRefs` 和 `codeRefs` 实现实现层面的可追溯性。 +场景文件应按产品能力分组,而不是按源码树目录分组。文件移动时请保持场景 ID 稳定;使用 `docsRefs` 和 `codeRefs` 来追踪实现对应关系。 -基线列表应足够广,以覆盖: +基线列表应保持足够广泛,以覆盖: -- 私信和频道聊天 +- 私信和渠道聊天 - 线程行为 - 消息操作生命周期 - cron 回调 -- 记忆召回 +- Memory Wiki 召回 - 模型切换 - 子智能体交接 - 读取仓库和读取文档 - 一个小型构建任务,例如 Lobster Invaders -## Provider mock lanes +## 提供商 mock 通道 -`qa suite` 有两个本地 provider mock lane: +`qa suite` 有两个本地提供商 mock 通道: -- `mock-openai` 是具备场景感知能力的 OpenClaw mock。它仍然是 - 由仓库支持的 QA 和一致性门禁的默认确定性 mock lane。 -- `aimock` 会启动由 AIMock 支持的 provider 服务器,用于实验性的协议、 - 夹具、录制/回放和混沌覆盖。它是增量补充,不会替代 `mock-openai` - 场景分发器。 +- `mock-openai` 是支持场景感知的 OpenClaw mock。它仍然是仓库支持的 QA 和 parity gate 的默认确定性 mock 通道。 +- `aimock` 会启动一个基于 AIMock 的 provider 服务器,用于实验性协议、夹具、录制/回放和混沌覆盖。它是补充性的,不会替代 `mock-openai` 场景分发器。 -Provider lane 实现位于 `extensions/qa-lab/src/providers/` 下。 -每个 provider 负责自己的默认值、本地服务器启动、Gateway 网关模型配置、 -auth-profile 暂存需求以及实时/mock 能力标志。共享的 suite 和 -gateway 代码应通过 provider 注册表进行路由,而不是基于 provider 名称分支。 +提供商通道实现位于 `extensions/qa-lab/src/providers/` 下。每个提供商负责自己的默认值、本地服务器启动、Gateway 网关模型配置、auth-profile 暂存需求以及实时/mock 能力标记。共享的 suite 和 Gateway 网关代码应通过 provider 注册表进行路由,而不是根据 provider 名称分支。 ## 传输适配器 -`qa-lab` 拥有面向 Markdown QA 场景的通用传输 seam。 -`qa-channel` 是该 seam 上的第一个适配器,但设计目标更广: -未来的真实或合成渠道应接入同一个 suite 运行器, -而不是新增特定于传输的 QA 运行器。 +`qa-lab` 为 Markdown QA 场景提供了一个通用传输接口。`qa-channel` 是该接口上的第一个适配器,但设计目标更广:未来真实或合成的渠道都应接入同一个 suite 运行器,而不是新增一个特定于传输的 QA 运行器。 -在架构层面,分工如下: +在架构层面,划分如下: -- `qa-lab` 负责通用场景执行、worker 并发、工件写入和报告。 -- 传输适配器负责 Gateway 网关配置、就绪性、入站与出站观察、传输操作以及标准化传输状态。 -- `qa/scenarios/` 下的 Markdown 场景文件定义测试运行;`qa-lab` 提供执行它们的可复用运行时表面。 +- `qa-lab` 负责通用场景执行、工作进程并发、产物写入和报告。 +- 传输适配器负责 Gateway 网关配置、就绪性、入站和出站观测、传输操作以及标准化传输状态。 +- `qa/scenarios/` 下的 Markdown 场景文件定义测试运行;`qa-lab` 提供执行它们的可复用运行时界面。 -面向维护者的新渠道适配器接入指南位于 -[测试](/zh-CN/help/testing#adding-a-channel-to-qa)。 +### 添加一个渠道 + +将一个渠道添加到 Markdown QA 系统中只需要两样东西: + +1. 该渠道的传输适配器。 +2. 一个用于演练该渠道契约的场景包。 + +当共享的 `qa-lab` 主机可以承载流程时,不要新增顶层 QA 命令根。 + +`qa-lab` 负责共享主机机制: + +- `openclaw qa` 命令根 +- suite 启动和拆除 +- 工作进程并发 +- 产物写入 +- 报告生成 +- 场景执行 +- 对旧版 `qa-channel` 场景的兼容别名 + +运行器插件负责传输契约: + +- `openclaw qa ` 如何挂载到共享 `qa` 根命令之下 +- 如何为该传输配置 Gateway 网关 +- 如何检查就绪性 +- 如何注入入站事件 +- 如何观察出站消息 +- 如何暴露转录内容和标准化传输状态 +- 如何执行由传输支持的操作 +- 如何处理特定于传输的重置或清理 + +新渠道的最低接入门槛: + +1. 保持 `qa-lab` 作为共享 `qa` 根的所有者。 +2. 在共享的 `qa-lab` 主机接口上实现传输运行器。 +3. 将特定于传输的机制保留在运行器插件或渠道 harness 内部。 +4. 将运行器挂载为 `openclaw qa `,而不是注册一个竞争性的根命令。运行器插件应在 `openclaw.plugin.json` 中声明 `qaRunners`,并从 `runtime-api.ts` 导出匹配的 `qaRunnerCliRegistrations` 数组。保持 `runtime-api.ts` 轻量;惰性 CLI 和运行器执行应继续放在单独的入口点之后。 +5. 在按主题划分的 `qa/scenarios/` 目录下编写或改造 Markdown 场景。 +6. 为新场景使用通用场景辅助工具。 +7. 除非仓库正在进行有意迁移,否则保持现有兼容别名继续可用。 + +决策规则很严格: + +- 如果某个行为可以在 `qa-lab` 中统一表达一次,就把它放进 `qa-lab`。 +- 如果某个行为依赖单一渠道传输,就把它保留在该运行器插件或插件 harness 中。 +- 如果某个场景需要一个可供多个渠道使用的新能力,应添加一个通用辅助工具,而不是在 `suite.ts` 中加入特定于渠道的分支。 +- 如果某个行为仅对一种传输有意义,就让该场景保持传输专用,并在场景契约中明确说明。 + +### 场景辅助工具名称 + +新场景推荐使用的通用辅助工具: + +- `waitForTransportReady` +- `waitForChannelReady` +- `injectInboundMessage` +- `injectOutboundMessage` +- `waitForTransportOutboundMessage` +- `waitForChannelOutboundMessage` +- `waitForNoTransportOutbound` +- `getTransportSnapshot` +- `readTransportMessage` +- `readTransportTranscript` +- `formatTransportTranscript` +- `resetTransport` + +现有场景仍可使用兼容别名——`waitForQaChannelReady`、`waitForOutboundMessage`、`waitForNoOutbound`、`formatConversationTranscript`、`resetBus`——但新场景编写应使用这些通用名称。这些别名的存在是为了避免一次性迁移日,而不是未来的模式。 ## 报告 -`qa-lab` 会根据观察到的总线时间线导出 Markdown 协议报告。 +`qa-lab` 会基于观察到的总线时间线导出一份 Markdown 协议报告。 该报告应回答: -- 什么有效 -- 什么失败 -- 什么仍被阻塞 +- 哪些内容正常工作 +- 哪些内容失败了 +- 哪些内容仍然受阻 - 值得补充哪些后续场景 -对于角色与风格检查,可在多个实时模型引用上运行同一场景, -并写出经评审的 Markdown 报告: +若要查看可用场景清单——这在评估后续工作规模或接入新传输时很有用——请运行 `pnpm openclaw qa coverage`(加上 `--json` 可获得机器可读输出)。 + +对于角色和风格检查,可在多个实时模型引用上运行同一场景,并写入带评判结果的 Markdown 报告: ```bash pnpm openclaw qa character-eval \ @@ -277,42 +293,17 @@ pnpm openclaw qa character-eval \ --judge-concurrency 16 ``` -该命令运行的是本地 QA gateway 子进程,而不是 Docker。Character eval -场景应通过 `SOUL.md` 设置 persona,然后运行普通用户轮次, -例如聊天、工作区帮助和小型文件任务。不应告诉候选模型 -它正在接受评估。该命令会保留每份完整对话记录、记录基础运行统计, -然后让 judge 模型在 fast 模式下、并在支持时使用 `xhigh` 推理, -按自然度、氛围和幽默感对各次运行进行排序。 -在比较不同 provider 时使用 `--blind-judge-models`:judge 提示词仍会收到 -每份对话记录和运行状态,但候选引用会被替换为中性标签, -例如 `candidate-01`;报告会在解析后将排序结果映射回真实引用。 - -候选运行默认使用 `high` thinking,对 GPT-5.5 使用 `medium`,对支持的旧版 OpenAI eval 引用使用 `xhigh`。 -可通过 `--model provider/model,thinking=` 为特定候选模型内联覆盖。 -`--thinking ` 仍用于设置全局回退值,而旧格式 -`--model-thinking ` 也会保留以兼容旧用法。 - -OpenAI 候选引用默认启用 fast 模式,以便在 provider 支持时使用优先处理。 -当某个单独的候选或 judge 需要覆盖时,可内联添加 `,fast`、`,no-fast` 或 `,fast=false`。 -仅当你想为每个候选模型强制开启 fast 模式时,才传入 `--fast`。 -候选和 judge 的时长都会记录到报告中用于基准分析,但 judge 提示词会明确说明 -不要按速度排名。 - -候选和 judge 模型运行默认都使用 16 的并发度。当 provider 限制 -或本地 Gateway 网关压力使运行噪声过大时,可降低 -`--concurrency` 或 `--judge-concurrency`。 - -当未传入任何候选 `--model` 时,character eval 默认使用 -`openai/gpt-5.5`、`openai/gpt-5.2`、`openai/gpt-5`、`anthropic/claude-opus-4-6`、 -`anthropic/claude-sonnet-4-6`、`zai/glm-5.1`、 -`moonshot/kimi-k2.5` 和 -`google/gemini-3.1-pro-preview`。 -当未传入任何 `--judge-model` 时,judge 默认使用 -`openai/gpt-5.5,thinking=xhigh,fast` 和 -`anthropic/claude-opus-4-6,thinking=high`。 +该命令运行的是本地 QA Gateway 网关子进程,而不是 Docker。角色评估场景应通过 `SOUL.md` 设置 persona,然后运行普通用户轮次,例如聊天、工作区帮助和小型文件任务。不应告知候选模型它正在被评估。该命令会保留每份完整转录、记录基本运行统计,然后请求评审模型在快速模式下、在支持时使用 `xhigh` 推理,按自然度、氛围和幽默感对各次运行进行排序。 +在比较不同提供商时,请使用 `--blind-judge-models`:评判提示词仍会获取每份转录和运行状态,但候选引用会被替换为诸如 `candidate-01` 之类的中性标签;报告会在解析后再将排名映射回真实引用。 +候选运行默认使用 `high` thinking;GPT-5.5 使用 `medium`,支持的较旧 OpenAI 评估引用则使用 `xhigh`。可以使用 `--model provider/model,thinking=` 内联覆盖特定候选。`--thinking ` 仍可设置全局后备值,较旧的 `--model-thinking ` 形式也会为兼容性保留。 +OpenAI 候选引用默认启用快速模式,以便在提供商支持时使用优先处理。若单个候选或评审需要覆盖,请内联添加 `,fast`、`,no-fast` 或 `,fast=false`。仅当你想为每个候选模型都强制启用快速模式时,才传入 `--fast`。报告中会记录候选和评审的耗时,以供基准分析,但评审提示词会明确说明不要按速度进行排名。 +候选和评审模型运行的默认并发度都是 16。当提供商限制或本地 Gateway 网关压力导致运行噪声过大时,请降低 `--concurrency` 或 `--judge-concurrency`。 +当未传入候选 `--model` 时,角色评估默认使用 `openai/gpt-5.5`、`openai/gpt-5.2`、`openai/gpt-5`、`anthropic/claude-opus-4-6`、`anthropic/claude-sonnet-4-6`、`zai/glm-5.1`、`moonshot/kimi-k2.5` 和 `google/gemini-3.1-pro-preview`。 +当未传入 `--judge-model` 时,评审默认使用 `openai/gpt-5.5,thinking=xhigh,fast` 和 `anthropic/claude-opus-4-6,thinking=high`。 ## 相关文档 -- [测试](/zh-CN/help/testing) +- [Matrix QA](/zh-CN/concepts/qa-matrix) - [QA Channel](/zh-CN/channels/qa-channel) -- [仪表盘](/zh-CN/web/dashboard) +- [Testing](/zh-CN/help/testing) +- [Dashboard](/zh-CN/web/dashboard) diff --git a/docs/zh-CN/concepts/qa-matrix.md b/docs/zh-CN/concepts/qa-matrix.md new file mode 100644 index 000000000..09786e365 --- /dev/null +++ b/docs/zh-CN/concepts/qa-matrix.md @@ -0,0 +1,143 @@ +--- +read_when: + - 在本地运行 `pnpm openclaw qa matrix` + - 添加或选择 Matrix QA 场景 + - 排查 Matrix QA 失败、超时或清理卡住的问题 +summary: Docker 支持的 Matrix 实时 QA 通道维护者参考:CLI、配置文件、环境变量、场景和输出工件。 +title: Matrix QA +x-i18n: + generated_at: "2026-04-27T17:44:05Z" + model: gpt-5.4 + provider: openai + source_hash: 6b49528cafbdc1b3ca52b6dce9f5d98e806032c1d8fea49e1c49190982dd5767 + source_path: concepts/qa-matrix.md + workflow: 15 +--- + +Matrix QA 通道会在 Docker 中针对一次性 Tuwunel homeserver 运行内置的 `@openclaw/matrix` 插件,并使用临时的 driver、SUT 和 observer 账号以及预置房间。它为 Matrix 提供基于真实传输的实时覆盖。 + +这是仅供维护者使用的工具。打包后的 OpenClaw 发布版本会刻意省略 `qa-lab`,因此 `openclaw qa` 只能在源码检出中使用。源码检出会直接加载内置运行器——不需要安装插件。 + +有关更广泛的 QA 框架背景,请参阅 [QA overview](/zh-CN/concepts/qa-e2e-automation)。 + +## 快速开始 + +```bash +pnpm openclaw qa matrix --profile fast --fail-fast +``` + +直接运行 `pnpm openclaw qa matrix` 会执行 `--profile all`,并且不会在首次失败时停止。将 `--profile fast --fail-fast` 用作发布门禁;在并行运行完整清单时,可使用 `--profile transport|media|e2ee-smoke|e2ee-deep|e2ee-cli` 对目录进行分片。 + +## 该通道会执行什么 + +1. 在 Docker 中配置一次性的 Tuwunel homeserver(默认镜像为 `ghcr.io/matrix-construct/tuwunel:v1.5.1`,服务器名称为 `matrix-qa.test`,端口为 `28008`)。 +2. 注册三个临时用户——`driver`(发送入站流量)、`sut`(被测的 OpenClaw Matrix 账号)、`observer`(第三方流量捕获)。 +3. 为所选场景预置所需房间(主房间、线程房间、媒体房间、重启房间、次要房间、allowlist 房间、E2EE 房间、验证私信等)。 +4. 启动一个子 OpenClaw Gateway 网关,并将真实 Matrix 插件限定在 SUT 账号上;子进程中不会加载 `qa-channel`。 +5. 按顺序运行场景,并通过 driver/observer Matrix 客户端观测事件。 +6. 拆除 homeserver,写入报告和摘要工件,然后退出。 + +## CLI + +```text +pnpm openclaw qa matrix [options] +``` + +### 常用标志 + +| 标志 | 默认值 | 说明 | +| --------------------- | --------------------------------------------- | -------------------------------------------------------------------- | +| `--profile ` | `all` | 场景配置文件。参见 [Profiles](#profiles)。 | +| `--fail-fast` | 关闭 | 在第一个失败的检查或场景后停止。 | +| `--scenario ` | — | 仅运行此场景。可重复使用。参见 [Scenarios](#scenarios)。 | +| `--output-dir ` | `/.artifacts/qa-e2e/matrix-` | 报告、摘要、观测事件和输出日志的写入位置。相对路径会基于 `--repo-root` 解析。 | +| `--repo-root ` | `process.cwd()` | 当你从中立工作目录调用时使用的仓库根目录。 | +| `--sut-account ` | `sut` | QA Gateway 网关配置中的 Matrix 账号 id。 | + +### 提供商标志 + +该通道使用真实的 Matrix 传输,但模型提供商可配置: + +| 标志 | 默认值 | 说明 | +| ------------------------ | ---------------- | ---------------------------------------------------------------------------------------------------------------------------------------- | +| `--provider-mode ` | `live-frontier` | 对于确定性的 mock 分发使用 `mock-openai`,或对实时 frontier 提供商使用 `live-frontier`。旧别名 `live-openai` 仍然可用。 | +| `--model ` | provider 默认值 | 主 `provider/model` 引用。 | +| `--alt-model ` | provider 默认值 | 在场景运行中切换时使用的备用 `provider/model` 引用。 | +| `--fast` | 关闭 | 在支持的情况下启用提供商快速模式。 | + +Matrix QA 不接受 `--credential-source` 或 `--credential-role`。该通道会在本地配置一次性用户;没有可供租用的共享凭证池。 + +## Profiles + +所选配置文件决定运行哪些场景。 + +| 配置文件 | 用途 | +| ---------------- | -------------------------------------------------------------------------------------------------------------------------------------------- | +| `all`(默认) | 完整目录。较慢,但最全面。 | +| `fast` | 用于发布门禁的子集,覆盖实时传输契约:canary、mention gating、allowlist 拦截、回复形态、重启恢复、线程跟进、线程隔离、reaction 观测。 | +| `transport` | 传输层级的线程、私信、房间、自动加入、mention/allowlist 场景。 | +| `media` | 图片、音频、视频、PDF、EPUB 附件覆盖。 | +| `e2ee-smoke` | 最小 E2EE 覆盖——基础加密回复、线程跟进、bootstrap 成功。 | +| `e2ee-deep` | 全面的 E2EE 状态丢失、备份、密钥和恢复场景。 | +| `e2ee-cli` | 通过 QA harness 驱动的 `openclaw matrix encryption setup` 和 `verify *` CLI 场景。 | + +精确映射位于 `extensions/qa-matrix/src/runners/contract/scenario-catalog.ts`。 + +## Scenarios + +完整场景 id 列表是 `extensions/qa-matrix/src/runners/contract/scenario-catalog.ts:15` 中的 `MatrixQaScenarioId` 联合类型。类别包括: + +- threading —— `matrix-thread-*`、`matrix-subagent-thread-spawn` +- 顶层 / 私信 / 房间 —— `matrix-top-level-reply-shape`、`matrix-room-*`、`matrix-dm-*` +- media —— `matrix-media-type-coverage`、`matrix-room-image-understanding-attachment`、`matrix-attachment-only-ignored`、`matrix-unsupported-media-safe` +- routing —— `matrix-room-autojoin-invite`、`matrix-secondary-room-*` +- reactions —— `matrix-reaction-*` +- restart 和 replay —— `matrix-restart-*`、`matrix-stale-sync-replay-dedupe`、`matrix-room-membership-loss`、`matrix-homeserver-restart-resume`、`matrix-initial-catchup-then-incremental` +- mention gating 和 allowlists —— `matrix-mention-*`、`matrix-allowlist-*`、`matrix-multi-actor-ordering`、`matrix-inbound-edit-*`、`matrix-mxid-prefixed-command-block`、`matrix-observer-allowlist-override` +- E2EE —— `matrix-e2ee-*`(基础回复、线程跟进、bootstrap、recovery key 生命周期、状态丢失变体、服务器备份行为、设备清理、SAS / QR / 私信验证、重启、工件脱敏) +- E2EE CLI —— `matrix-e2ee-cli-*`(encryption setup、幂等 setup、bootstrap 失败、recovery-key 生命周期、多账号、gateway-reply 往返、自验证) + +传入 `--scenario `(可重复)可运行手动挑选的一组场景;与 `--profile all` 组合使用可忽略配置文件限制。 + +## 环境变量 + +| 变量 | 默认值 | 作用 | +| --------------------------------------- | ----------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------- | +| `OPENCLAW_QA_MATRIX_TIMEOUT_MS` | `1800000`(30 分钟) | 整个运行过程的硬性上限。 | +| `OPENCLAW_QA_MATRIX_NO_REPLY_WINDOW_MS` | `8000` | 用于负向“无回复”断言的静默窗口。会被限制为 `≤` 运行超时时间。 | +| `OPENCLAW_QA_MATRIX_CLEANUP_TIMEOUT_MS` | `90000` | Docker 拆除的时间上限。失败时暴露的信息包括恢复用的 `docker compose ... down --remove-orphans` 命令。 | +| `OPENCLAW_QA_MATRIX_TUWUNEL_IMAGE` | `ghcr.io/matrix-construct/tuwunel:v1.5.1` | 在针对其他 Tuwunel 版本进行验证时覆盖 homeserver 镜像。 | +| `OPENCLAW_QA_MATRIX_PROGRESS` | 开启 | `0` 会关闭 stderr 上的 `[matrix-qa] ...` 进度行。`1` 会强制开启。 | +| `OPENCLAW_QA_MATRIX_CAPTURE_CONTENT` | 已脱敏 | `1` 会在 `matrix-qa-observed-events.json` 中保留消息正文和 `formatted_body`。默认会脱敏,以保证 CI 工件安全。 | +| `OPENCLAW_QA_MATRIX_DISABLE_FORCE_EXIT` | 关闭 | `1` 会跳过写入工件后的确定性 `process.exit`。默认会强制退出,因为 `matrix-js-sdk` 的原生加密句柄可能会在工件写入完成后仍让事件循环保持活动。 | +| `OPENCLAW_RUN_NODE_OUTPUT_LOG` | 未设置 | 当由外部启动器设置时(例如 `scripts/run-node.mjs`),Matrix QA 会复用该日志路径,而不是启动自己的 tee。 | + +## 输出工件 + +写入到 `--output-dir`: + +- `matrix-qa-report.md` —— Markdown 协议报告(哪些通过、失败、跳过,以及原因)。 +- `matrix-qa-summary.json` —— 适合 CI 解析和仪表板使用的结构化摘要。 +- `matrix-qa-observed-events.json` —— 来自 driver 和 observer 客户端观测到的 Matrix 事件。除非设置 `OPENCLAW_QA_MATRIX_CAPTURE_CONTENT=1`,否则正文会被脱敏。 +- `matrix-qa-output.log` —— 运行期间合并的 stdout/stderr。如果设置了 `OPENCLAW_RUN_NODE_OUTPUT_LOG`,则会改为复用外部启动器的日志。 + +默认输出目录为 `/.artifacts/qa-e2e/matrix-`,因此连续运行不会互相覆盖。 + +## 排查提示 + +- **运行接近结束时卡住:** `matrix-js-sdk` 的原生加密句柄可能会在 harness 结束后仍然存活。默认行为是在写入工件后强制执行一次干净的 `process.exit`;如果你取消设置了 `OPENCLAW_QA_MATRIX_DISABLE_FORCE_EXIT=1`,预计进程会继续挂起。 +- **清理错误:** 查找打印出来的恢复命令(一个 `docker compose ... down --remove-orphans` 调用),并手动运行它以释放 homeserver 端口。 +- **CI 中负向断言窗口不稳定:** 当 CI 较快时,调低 `OPENCLAW_QA_MATRIX_NO_REPLY_WINDOW_MS`(默认 8 秒);在较慢的共享 runner 上则调高。 +- **需要为缺陷报告保留未脱敏正文:** 使用 `OPENCLAW_QA_MATRIX_CAPTURE_CONTENT=1` 重新运行,并附上 `matrix-qa-observed-events.json`。请将生成的工件视为敏感内容。 +- **不同的 Tuwunel 版本:** 将 `OPENCLAW_QA_MATRIX_TUWUNEL_IMAGE` 指向待测版本。该通道仓库中只检入了固定的默认镜像。 + +## 实时传输契约 + +Matrix 是三个实时传输通道之一(Matrix、Telegram、Discord),它们共享同一个契约检查清单,定义见 [QA overview → Live transport coverage](/zh-CN/concepts/qa-e2e-automation#live-transport-coverage)。`qa-channel` 仍然是覆盖范围更广的合成测试套件,并且有意不属于该矩阵的一部分。 + +## 相关内容 + +- [QA overview](/zh-CN/concepts/qa-e2e-automation) —— 整体 QA 栈和实时传输契约 +- [QA channel](/zh-CN/channels/qa-channel) —— 用于基于仓库场景的合成渠道适配器 +- [Testing](/zh-CN/help/testing) —— 运行测试和添加 QA 覆盖 +- [Matrix](/zh-CN/channels/matrix) —— 被测的渠道插件 diff --git a/docs/zh-CN/help/testing.md b/docs/zh-CN/help/testing.md index 41d51f6c5..e72ac999b 100644 --- a/docs/zh-CN/help/testing.md +++ b/docs/zh-CN/help/testing.md @@ -3,37 +3,47 @@ read_when: - 在本地或 CI 中运行测试 - 为模型 / 提供商缺陷添加回归测试 - 调试 Gateway 网关 + 智能体行为 -summary: 测试工具包:单元 / e2e / 实时测试套件、Docker 运行器,以及各项测试所覆盖的内容 +summary: 测试工具包:单元 / e2e / 实时测试套件、Docker 运行器,以及每类测试涵盖的内容 title: 测试 x-i18n: - generated_at: "2026-04-27T12:52:57Z" + generated_at: "2026-04-27T17:44:01Z" model: gpt-5.4 provider: openai - source_hash: f91deebbf835100826f77e36cba64ae0b35dc0c6a5b4cad0b8f360099c4259bf + source_hash: 37dbd2dd294a4a97850cd9a3ff13bb680e612380115fc660d0b8e0d8dbf1c5e0 source_path: help/testing.md workflow: 15 --- -OpenClaw 有三个 Vitest 测试套件(单元 / 集成、e2e、实时)以及一小组 Docker 运行器。本文档是一份“我们如何测试”的指南: +OpenClaw 有三个 Vitest 测试套件(单元 / 集成、e2e、实时)和一小组 Docker 运行器。本文档是一份“我们如何测试”的指南: -- 每个测试套件覆盖什么(以及它刻意**不**覆盖什么)。 -- 常见工作流该运行哪些命令(本地、推送前、调试)。 +- 每个测试套件涵盖什么内容(以及它刻意**不**涵盖什么)。 +- 常见工作流(本地、推送前、调试)应运行哪些命令。 - 实时测试如何发现凭证并选择模型 / 提供商。 - 如何为真实世界中的模型 / 提供商问题添加回归测试。 + +**QA stack(qa-lab、qa-channel、实时传输通道)**另有单独文档: + +- [QA overview](/zh-CN/concepts/qa-e2e-automation) — 架构、命令入口、场景编写。 +- [Matrix QA](/zh-CN/concepts/qa-matrix) — `pnpm openclaw qa matrix` 的参考文档。 +- [QA channel](/zh-CN/channels/qa-channel) — 仓库场景使用的合成传输插件。 + +本页介绍如何运行常规测试套件以及 Docker / Parallels 运行器。下面的 QA 专用运行器部分([QA 专用运行器](#qa-specific-runners))列出了具体的 `qa` 调用方式,并回指以上参考文档。 + + ## 快速开始 大多数时候: -- 完整门禁(推送前预期执行):`pnpm build && pnpm check && pnpm check:test-types && pnpm test` -- 在配置充裕的机器上更快地运行本地全套测试:`pnpm test:max` +- 完整门禁(推送前的预期要求):`pnpm build && pnpm check && pnpm check:test-types && pnpm test` +- 在资源充足的机器上进行更快的本地全套测试:`pnpm test:max` - 直接进入 Vitest 监听循环:`pnpm test:watch` -- 直接按文件定位现在也会路由扩展 / 渠道路径:`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` +- 现在直接按文件定位也会路由扩展 / 渠道路径:`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` -当你改动测试或想获得更多信心时: +当你修改了测试,或者想获得更多信心时: - 覆盖率门禁:`pnpm test:coverage` - E2E 测试套件:`pnpm test:e2e` @@ -43,60 +53,61 @@ OpenClaw 有三个 Vitest 测试套件(单元 / 集成、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` 及其定时 / 发布调用方中。 + - 现在每个选中的模型都会运行一次文本轮次,再加上一个小型文件读取风格的探测。元数据声明支持 `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` 及其定时 / 发布调用工作流中。 - 原生 Codex 绑定聊天冒烟测试:`pnpm test:docker:live-codex-bind` - - 对 Codex app-server 路径运行一条 Docker 实时通道,使用 `/codex bind` 绑定一个合成 Slack 私信,执行 `/codex fast` 和 `/codex permissions`,然后验证普通回复和图像附件都通过原生插件绑定路由,而不是 ACP。 + - 在 Docker 中针对 Codex app-server 路径运行实时测试通道,绑定一个合成 Slack 私信 `/codex bind`,执行 `/codex fast` 和 `/codex permissions`,然后验证普通回复和图像附件都通过原生插件绑定路由,而不是 ACP。 - Codex app-server harness 冒烟测试:`pnpm test:docker:live-codex-harness` - - 通过插件拥有的 Codex app-server harness 运行 Gateway 网关智能体轮次,验证 `/codex status` 和 `/codex models`,并且默认执行图像、cron MCP、子智能体和 Guardian 探测。调试其他 Codex app-server 故障时,可使用 `OPENCLAW_LIVE_CODEX_HARNESS_SUBAGENT_PROBE=0` 禁用子智能体探测。若要聚焦检查子智能体,请禁用其他探测:`OPENCLAW_LIVE_CODEX_HARNESS_IMAGE_PROBE=0 OPENCLAW_LIVE_CODEX_HARNESS_MCP_PROBE=0 OPENCLAW_LIVE_CODEX_HARNESS_GUARDIAN_PROBE=0 OPENCLAW_LIVE_CODEX_HARNESS_SUBAGENT_PROBE=1 pnpm test:docker:live-codex-harness`。 - 除非设置 `OPENCLAW_LIVE_CODEX_HARNESS_SUBAGENT_ONLY=0`,否则该命令会在子智能体探测后退出。 + - 通过插件拥有的 Codex app-server harness 运行 Gateway 网关智能体轮次,验证 `/codex status` 和 `/codex models`,并默认执行图像、cron MCP、子智能体和 Guardian 探测。排查其他 Codex app-server 故障时,可使用 `OPENCLAW_LIVE_CODEX_HARNESS_SUBAGENT_PROBE=0` 禁用子智能体探测。若只想聚焦子智能体检查,请禁用其他探测:`OPENCLAW_LIVE_CODEX_HARNESS_IMAGE_PROBE=0 OPENCLAW_LIVE_CODEX_HARNESS_MCP_PROBE=0 OPENCLAW_LIVE_CODEX_HARNESS_GUARDIAN_PROBE=0 OPENCLAW_LIVE_CODEX_HARNESS_SUBAGENT_PROBE=1 pnpm test:docker:live-codex-harness`。 + 除非设置了 `OPENCLAW_LIVE_CODEX_HARNESS_SUBAGENT_ONLY=0`,否则该命令会在子智能体探测后退出。 - Crestodian 救援命令冒烟测试:`pnpm test:live:crestodian-rescue-channel` - - 针对消息渠道救援命令表面的选择启用型双保险检查。它会执行 `/crestodian status`,排队一个持久模型变更,回复 `/crestodian yes`,并验证审计 / 配置写入路径。 -- Crestodian planner Docker 冒烟测试:`pnpm test:docker:crestodian-planner` - - 在无配置容器中、并在 `PATH` 上提供一个伪造的 Claude CLI 来运行 Crestodian,并验证模糊规划器回退会转换为带审计的类型化配置写入。 + - 对消息渠道救援命令入口面的可选双重保险检查。它会执行 `/crestodian status`、排队一个持久化模型变更、回复 `/crestodian yes`,并验证审计 / 配置写入路径。 +- Crestodian 规划器 Docker 冒烟测试:`pnpm test:docker:crestodian-planner` + - 在无配置容器中运行 Crestodian,并在 `PATH` 上放置一个假的 Claude CLI,验证模糊规划器回退会转换为带审计记录的类型化配置写入。 - Crestodian 首次运行 Docker 冒烟测试:`pnpm test:docker:crestodian-first-run` - - 从空的 OpenClaw 状态目录启动,将裸 `openclaw` 路由到 Crestodian,应用 setup / model / agent / Discord 插件 + SecretRef 写入,验证配置,并检查审计条目。同样的 Ring 0 设置路径也在 QA Lab 中通过 `pnpm openclaw qa suite --scenario crestodian-ring-zero-setup` 覆盖。 -- Moonshot / Kimi 成本冒烟测试:设置 `MOONSHOT_API_KEY` 后,运行 `openclaw models list --provider moonshot --json`,然后针对 `moonshot/kimi-k2.6` 运行独立命令 `openclaw agent --local --session-id live-kimi-cost --message 'Reply exactly: KIMI_LIVE_OK' --thinking off --json`。验证 JSON 报告的是 Moonshot / K2.6,且助手会话记录中保存了规范化的 `usage.cost`。 + - 从空的 OpenClaw 状态目录启动,将裸 `openclaw` 路由到 Crestodian,应用 setup / model / agent / Discord 插件 + SecretRef 写入,验证配置,并检查审计条目。同一 Ring 0 设置路径也在 QA Lab 中由 `pnpm openclaw qa suite --scenario crestodian-ring-zero-setup` 覆盖。 +- Moonshot / Kimi 成本冒烟测试:设置 `MOONSHOT_API_KEY` 后,运行 `openclaw models list --provider moonshot --json`,然后针对 `moonshot/kimi-k2.6` 运行隔离的 `openclaw agent --local --session-id live-kimi-cost --message 'Reply exactly: KIMI_LIVE_OK' --thinking off --json` + 。验证 JSON 报告的是 Moonshot / K2.6,并且助手转录中存储了规范化的 `usage.cost`。 -当你只需要处理一个失败用例时,优先使用下面描述的允许列表环境变量来缩小实时测试范围。 +当你只需要一个失败用例时,优先使用下面描述的 allowlist 环境变量来缩小实时测试范围。 ## QA 专用运行器 -当你需要 QA-lab 级别的真实性时,这些命令与主测试套件并列使用: +当你需要 qa-lab 级别的真实环境时,这些命令与主测试套件并列存在: -CI 会在专用工作流中运行 QA Lab。`Parity gate` 会在匹配的 PR 上运行,也可通过手动触发使用模拟提供商运行。`QA-Lab - All Lanes` 会在 `main` 上每晚运行,也可通过手动触发,以并行作业方式运行模拟 parity gate、实时 Matrix 通道、由 Convex 管理的实时 Telegram 通道,以及由 Convex 管理的实时 Discord 通道。定时 QA 和发布检查会显式传入 Matrix `--profile fast`,而 Matrix CLI 和手动工作流输入默认仍为 `all`;手动触发可将 `all` 分片为 `transport`、`media`、`e2ee-smoke`、`e2ee-deep` 和 `e2ee-cli` 作业。`OpenClaw Release Checks` 会在发布批准前运行 parity,以及快速 Matrix 和 Telegram 通道。 +CI 会在专用工作流中运行 QA Lab。`Parity gate` 会在匹配的 PR 上运行,也可通过手动触发使用模拟提供商运行。`QA-Lab - All Lanes` 会在 `main` 上每晚运行,也可通过手动触发,以并行任务方式运行模拟 parity gate、实时 Matrix 通道、Convex 托管的实时 Telegram 通道和 Convex 托管的实时 Discord 通道。定时 QA 和发布检查会显式传递 Matrix `--profile fast`,而 Matrix CLI 和手动工作流输入的默认值仍是 `all`;手动触发可以将 `all` 分片为 `transport`、`media`、`e2ee-smoke`、`e2ee-deep` 和 `e2ee-cli` 作业。`OpenClaw Release Checks` 会在发布批准前运行 parity 以及快速 Matrix 和 Telegram 通道。 - `pnpm openclaw qa suite` - 直接在主机上运行基于仓库的 QA 场景。 - - 默认以隔离的 Gateway 网关 worker 并行运行多个所选场景。`qa-channel` 默认并发数为 4(受所选场景数量限制)。可使用 `--concurrency ` 调整 worker 数量,或使用 `--concurrency 1` 切换为旧的串行通道。 - - 任一场景失败时以非零退出。若你想获取工件但不希望退出码失败,可使用 `--allow-failures`。 - - 支持 `live-frontier`、`mock-openai` 和 `aimock` 三种提供商模式。`aimock` 会启动一个本地 AIMock 支持的提供商服务器,用于实验性夹具和协议模拟覆盖,而不会替代具备场景感知能力的 `mock-openai` 通道。 + - 默认会以隔离的 Gateway 网关工作进程并行运行多个已选场景。`qa-channel` 默认并发度为 4(受所选场景数量限制)。使用 `--concurrency ` 调整工作进程数量,或使用 `--concurrency 1` 切换回旧的串行通道。 + - 当任一场景失败时,以非零状态退出。如果你想要产物但不希望以失败退出码结束,请使用 `--allow-failures`。 + - 支持提供商模式 `live-frontier`、`mock-openai` 和 `aimock`。`aimock` 会启动一个本地 AIMock 支持的提供商服务器,用于实验性的夹具和协议模拟覆盖,但不会替代具备场景感知能力的 `mock-openai` 通道。 - `pnpm openclaw qa suite --runner multipass` - - 在一次性 Multipass Linux VM 中运行同样的 QA 套件。 + - 在一次性 Multipass Linux VM 中运行相同的 QA 套件。 - 保持与主机上 `qa suite` 相同的场景选择行为。 - 复用与 `qa suite` 相同的提供商 / 模型选择标志。 - - 实时运行会转发适合访客环境的受支持 QA 认证输入:基于环境变量的提供商密钥、QA 实时提供商配置路径,以及存在时的 `CODEX_HOME`。 - - 输出目录必须保持在仓库根目录下,以便访客通过挂载的工作区回写。 + - 实时运行会转发适合访客机使用的受支持 QA 认证输入:基于环境变量的提供商密钥、QA 实时提供商配置路径,以及存在时的 `CODEX_HOME`。 + - 输出目录必须保留在仓库根目录下,以便访客机能够通过挂载的工作区回写。 - 会将常规 QA 报告 + 摘要以及 Multipass 日志写入 `.artifacts/qa-e2e/...`。 - `pnpm qa:lab:up` - - 启动基于 Docker 的 QA 站点,用于面向操作员风格的 QA 工作。 + - 启动 Docker 支持的 QA 站点,用于面向操作员风格的 QA 工作。 - `pnpm test:docker:npm-onboard-channel-agent` - - 从当前检出构建一个 npm tarball,在 Docker 中全局安装,运行非交互式 OpenAI API 密钥新手引导,默认配置 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:session-runtime-context` - - 运行一个确定性的、基于已构建应用的 Docker 冒烟测试,用于嵌入式运行时上下文会话记录。它会验证隐藏的 OpenClaw 运行时上下文会作为非显示自定义消息持久化,而不是泄露到可见的用户轮次中;然后种入一份受影响的损坏 session JSONL,并验证 `openclaw doctor --fix` 会将其重写到当前活跃分支并保留备份。 + - 运行一个确定性的、基于已构建应用的 Docker 冒烟测试,用于嵌入式运行时上下文转录。它会验证隐藏的 OpenClaw 运行时上下文被保存为非显示的自定义消息,而不是泄漏到可见的用户轮次中;随后注入一个受影响的损坏会话 JSONL,并验证 `openclaw doctor --fix` 会将其重写到当前分支并生成备份。 - `pnpm test:docker:npm-telegram-live` - - 在 Docker 中安装一个 OpenClaw 候选包,运行已安装包的新手引导,通过已安装 CLI 配置 Telegram,然后复用实时 Telegram QA 通道,并将该已安装包作为被测 Gateway 网关。 + - 在 Docker 中安装一个 OpenClaw 候选包,运行已安装包的新手引导,通过已安装的 CLI 配置 Telegram,然后复用实时 Telegram QA 通道,并将该已安装包作为 SUT Gateway 网关。 - 默认使用 `OPENCLAW_NPM_TELEGRAM_PACKAGE_SPEC=openclaw@beta`;设置 `OPENCLAW_NPM_TELEGRAM_PACKAGE_TGZ=/path/to/openclaw-current.tgz` 或 `OPENCLAW_CURRENT_PACKAGE_TGZ` 可测试已解析的本地 tarball,而不是从注册表安装。 - - 使用与 `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` environment 和 Convex CI 凭证租约。 -- GitHub Actions 还提供 `Package Acceptance`,用于针对单个候选包进行旁路产品证明。它接受受信任的 ref、已发布的 npm 规格、带 SHA-256 的 HTTPS tarball URL,或来自其他运行的 tarball 工件,上传规范化后的 `openclaw-current.tgz` 作为 `package-under-test`,然后运行现有的 Docker E2E 调度器,支持 smoke、package、product、full 或 custom 通道配置。设置 `telegram_mode=mock-openai` 或 `live-frontier` 可让 Telegram QA 工作流针对同一个 `package-under-test` 工件运行。 - - 最新 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 凭证租约。 +- GitHub Actions 还提供 `Package Acceptance`,用于针对单个候选包进行旁路产品验证。它接受受信任的 ref、已发布的 npm 规范、带 SHA-256 的 HTTPS tarball URL,或来自另一个运行的 tarball 产物;然后将规范化后的 `openclaw-current.tgz` 上传为 `package-under-test`,再运行现有 Docker E2E 调度器,支持 smoke、package、product、full 或自定义通道配置。设置 `telegram_mode=mock-openai` 或 `live-frontier`,即可让 Telegram QA 工作流针对相同的 `package-under-test` 产物运行。 + - 最新 beta 产品验证: ```bash gh workflow run package-acceptance.yml --ref main \ @@ -106,7 +117,7 @@ gh workflow run package-acceptance.yml --ref main \ -f telegram_mode=mock-openai ``` -- 精确 tarball URL 证明需要摘要: +- 精确 tarball URL 验证需要摘要: ```bash gh workflow run package-acceptance.yml --ref main \ @@ -116,7 +127,7 @@ gh workflow run package-acceptance.yml --ref main \ -f suite_profile=package ``` -- 工件证明会从另一个 Actions 运行中下载 tarball 工件: +- 产物验证会从另一个 Actions 运行中下载 tarball 产物: ```bash gh workflow run package-acceptance.yml --ref main \ @@ -127,73 +138,58 @@ gh workflow run package-acceptance.yml --ref main \ ``` - `pnpm test:docker:bundled-channel-deps` - - 在 Docker 中打包并安装当前的 OpenClaw 构建,使用已配置的 OpenAI 启动 Gateway 网关,然后通过配置编辑启用内置渠道 / 插件。 - - 验证设置发现会让未配置插件的运行时依赖保持未安装状态,第一次配置后的 Gateway 网关或 doctor 运行会按需安装每个内置插件的运行时依赖,而第二次重启不会重新安装已经激活过的依赖。 - - 还会安装一个已知的较旧 npm 基线版本,在运行 `openclaw update --tag ` 之前启用 Telegram,并验证候选版本在更新后的 doctor 中会修复内置渠道运行时依赖,而无需 harness 侧的 postinstall 修复。 + - 在 Docker 中打包并安装当前 OpenClaw 构建,使用已配置的 OpenAI 启动 Gateway 网关,然后通过配置编辑启用内置渠道 / 插件。 + - 验证设置发现流程会让未配置插件的运行时依赖保持缺失状态;首次已配置的 Gateway 网关或 doctor 运行会按需安装每个内置插件的运行时依赖;第二次重启不会重新安装已经激活过的依赖。 + - 还会安装一个已知的较旧 npm 基线版本,在运行 `openclaw update --tag ` 之前启用 Telegram,并验证候选版本更新后的 doctor 会修复内置渠道运行时依赖,而不依赖 harness 侧的 postinstall 修复。 - `pnpm test:parallels:npm-update` - - 在 Parallels 虚拟机中运行原生打包安装更新冒烟测试。每个选定平台都会先安装指定的基线包,然后在同一访客系统中运行已安装的 `openclaw update` 命令,并验证已安装版本、更新状态、Gateway 网关就绪情况以及一次本地智能体轮次。 - - 在针对单一访客系统迭代时,使用 `--platform macos`、`--platform windows` 或 `--platform linux`。使用 `--json` 获取摘要工件路径和每条通道的状态。 - - OpenAI 通道默认使用 `openai/gpt-5.5` 作为实时智能体轮次证明。若你是有意验证其他 OpenAI 模型,请传入 `--model ` 或设置 `OPENCLAW_PARALLELS_OPENAI_MODEL`。 - - 将较长的本地运行包裹在宿主机超时控制中,以避免 Parallels 传输卡住耗尽剩余测试窗口: + - 在 Parallels 来宾机上运行原生打包安装更新冒烟测试。每个选定平台都会先安装指定的基线包,然后在同一个来宾机中运行已安装的 `openclaw update` 命令,并验证已安装版本、更新状态、gateway 就绪情况以及一次本地智能体轮次。 + - 在针对单个来宾机迭代时,使用 `--platform macos`、`--platform windows` 或 `--platform linux`。使用 `--json` 可获取摘要产物路径和每个通道状态。 + - OpenAI 通道默认使用 `openai/gpt-5.5` 作为实时智能体轮次验证模型。如需有意验证其他 OpenAI 模型,请传入 `--model ` 或设置 `OPENCLAW_PARALLELS_OPENAI_MODEL`。 + - 将较长的本地运行包装在主机超时中,以避免 Parallels 传输停滞耗尽剩余测试窗口: ```bash timeout --foreground 150m pnpm test:parallels:npm-update -- --json timeout --foreground 90m pnpm test:parallels:npm-update -- --platform windows --json ``` - - 该脚本会将嵌套通道日志写入 `/tmp/openclaw-parallels-npm-update.*`。在假设外层包装器卡住之前,请先检查 `windows-update.log`、`macos-update.log` 或 `linux-update.log`。 - - 在冷启动访客系统上,Windows 更新可能会在更新后的 doctor / 运行时依赖修复阶段耗费 10 到 15 分钟;只要嵌套的 npm 调试日志仍在推进,这仍然是健康状态。 - - 不要将这个聚合包装器与单独的 Parallels macOS、Windows 或 Linux 冒烟通道并行运行。它们共享 VM 状态,可能会在快照恢复、包分发或访客 Gateway 网关状态上发生冲突。 - - 更新后的证明会运行正常的内置插件表面,因为像语音、图像生成和媒体理解这样的能力门面,即使在智能体轮次本身只检查简单文本响应时,也会通过内置运行时 API 加载。 + - 脚本会将嵌套通道日志写入 `/tmp/openclaw-parallels-npm-update.*`。在认定外层包装器卡住之前,请先检查 `windows-update.log`、`macos-update.log` 或 `linux-update.log`。 + - 在冷启动来宾机上,Windows 更新后的 doctor / 运行时依赖修复可能需要 10 到 15 分钟;只要嵌套的 npm 调试日志仍在推进,这仍属正常。 + - 不要将这个聚合包装器与单独的 Parallels macOS、Windows 或 Linux 冒烟通道并行运行。它们共享 VM 状态,可能会在快照恢复、包提供或来宾 gateway 状态上发生冲突。 + - 更新后的验证会运行常规内置插件入口面,因为语音、图像生成和媒体理解等能力外观层即使在智能体轮次本身只检查简单文本响应时,也仍然通过内置运行时 API 加载。 - `pnpm openclaw qa aimock` - - 仅启动本地 AIMock provider 服务器,用于直接协议冒烟测试。 + - 仅启动本地 AIMock 提供商服务器,用于直接协议冒烟测试。 - `pnpm openclaw qa matrix` - - 针对一次性的、由 Docker 支持的 Tuwunel homeserver 运行 Matrix 实时 QA 通道。 - - 这个 QA 宿主目前仅用于仓库 / 开发环境。打包后的 OpenClaw 安装不包含 `qa-lab`,因此不会暴露 `openclaw qa`。 - - 仓库检出会直接加载内置运行器,无需单独安装插件。 - - 会预配三个临时 Matrix 用户(`driver`、`sut`、`observer`)以及一个私有房间,然后启动一个 QA Gateway 网关子进程,并将真实 Matrix 插件作为 SUT 传输。 - - 默认使用 `--profile all`。对于发布关键的传输证明,请使用 `--profile fast --fail-fast`;在对完整目录进行分片时,可使用 `--profile transport|media|e2ee-smoke|e2ee-deep|e2ee-cli`。 - - 默认使用固定的稳定版 Tuwunel 镜像 `ghcr.io/matrix-construct/tuwunel:v1.5.1`。如果需要测试其他镜像,可使用 `OPENCLAW_QA_MATRIX_TUWUNEL_IMAGE` 覆盖。 - - Matrix 不暴露共享凭证源标志,因为该通道会在本地预配一次性用户。 - - 会将 Matrix QA 报告、摘要、observed-events 工件以及合并的 stdout / stderr 输出日志写入 `.artifacts/qa-e2e/...`。 - - 默认会输出进度,并通过 `OPENCLAW_QA_MATRIX_TIMEOUT_MS`(默认 30 分钟)强制执行硬运行超时。`OPENCLAW_QA_MATRIX_NO_REPLY_WINDOW_MS` 用于调整负向无回复静默窗口,清理操作受 `OPENCLAW_QA_MATRIX_CLEANUP_TIMEOUT_MS` 限制;失败时会包含用于恢复的 `docker compose ... down --remove-orphans` 命令。 + - 针对一次性 Docker 支持的 Tuwunel homeserver 运行 Matrix 实时 QA 通道。仅支持源码检出——打包安装不附带 `qa-lab`。 + - 完整 CLI、profile / 场景目录、环境变量和产物布局:参见 [Matrix QA](/zh-CN/concepts/qa-matrix)。 - `pnpm openclaw qa telegram` - 使用来自环境变量的 driver 和 SUT 机器人令牌,针对真实私有群组运行 Telegram 实时 QA 通道。 - - 需要 `OPENCLAW_QA_TELEGRAM_GROUP_ID`、`OPENCLAW_QA_TELEGRAM_DRIVER_BOT_TOKEN` 和 `OPENCLAW_QA_TELEGRAM_SUT_BOT_TOKEN`。群组 ID 必须是 Telegram 聊天的数字 ID。 - - 支持 `--credential-source convex` 用于共享的凭证池。默认使用环境变量模式,或设置 `OPENCLAW_QA_CREDENTIAL_SOURCE=convex` 以启用池化租约。 - - 任一场景失败时以非零退出。若你想获取工件但不希望退出码失败,可使用 `--allow-failures`。 - - 需要同一私有群组中的两个不同机器人,并且 SUT 机器人需要暴露 Telegram 用户名。 - - 为了稳定的机器人对机器人观察,请在 `@BotFather` 中为两个机器人都启用 Bot-to-Bot Communication Mode,并确保 driver 机器人能够观察群组中的机器人流量。 - - 会将 Telegram QA 报告、摘要和 observed-messages 工件写入 `.artifacts/qa-e2e/...`。回复场景中会包含从 driver 发送请求到观察到 SUT 回复的 RTT。 + - 需要 `OPENCLAW_QA_TELEGRAM_GROUP_ID`、`OPENCLAW_QA_TELEGRAM_DRIVER_BOT_TOKEN` 和 `OPENCLAW_QA_TELEGRAM_SUT_BOT_TOKEN`。群组 id 必须是 Telegram 聊天的数字 id。 + - 支持 `--credential-source convex` 使用共享凭证池。默认使用环境变量模式,或设置 `OPENCLAW_QA_CREDENTIAL_SOURCE=convex` 以启用池化租约。 + - 任一场景失败时,以非零状态退出。如果你希望保留产物但不以失败退出码结束,请使用 `--allow-failures`。 + - 需要同一私有群组中的两个不同机器人,并且 SUT 机器人需要公开 Telegram 用户名。 + - 为了实现稳定的机器人对机器人观测,请在 `@BotFather` 中为两个机器人启用 Bot-to-Bot Communication Mode,并确保 driver 机器人能够观测群组中的机器人流量。 + - 会在 `.artifacts/qa-e2e/...` 下写入 Telegram QA 报告、摘要和 observed-messages 产物。回复类场景包含从 driver 发送请求到观测到 SUT 回复的 RTT。 -实时传输通道共享一个标准契约,以防新传输发生漂移: - -`qa-channel` 仍然是广泛的合成 QA 套件,不属于实时传输覆盖矩阵的一部分。 - -| 通道 | Canary | 提及门控 | 允许列表阻止 | 顶层回复 | 重启恢复 | 线程后续 | 线程隔离 | Reaction 观察 | 帮助命令 | 原生命令注册 | -| ---- | ------ | -------- | ------------ | -------- | -------- | -------- | -------- | -------------- | -------- | ------------ | -| Matrix | x | x | x | x | x | x | x | x | | | -| Telegram | x | x | | | | | | | x | | -| Discord | x | x | | | | | | | | x | +实时传输通道共享一套标准契约,以避免新传输协议出现偏移;每个通道的覆盖矩阵位于 [QA overview → Live transport coverage](/zh-CN/concepts/qa-e2e-automation#live-transport-coverage)。`qa-channel` 是覆盖范围更广的合成测试套件,不属于该矩阵的一部分。 ### 通过 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 项目脚手架: - `qa/convex-credential-broker/` -必需的环境变量: +必需环境变量: - `OPENCLAW_QA_CONVEX_SITE_URL`(例如 `https://your-deployment.convex.site`) -- 为所选角色提供一个机密: +- 所选角色对应的一个密钥: - `maintainer` 使用 `OPENCLAW_QA_CONVEX_SECRET_MAINTAINER` - `ci` 使用 `OPENCLAW_QA_CONVEX_SECRET_CI` - 凭证角色选择: - CLI:`--credential-role maintainer|ci` - - 环境变量默认值:`OPENCLAW_QA_CREDENTIAL_ROLE`(在 CI 中默认为 `ci`,否则为 `maintainer`) + - 环境变量默认值:`OPENCLAW_QA_CREDENTIAL_ROLE`(在 CI 中默认是 `ci`,否则默认是 `maintainer`) 可选环境变量: @@ -202,15 +198,15 @@ gh workflow run package-acceptance.yml --ref main \ - `OPENCLAW_QA_CREDENTIAL_ACQUIRE_TIMEOUT_MS`(默认 `90000`) - `OPENCLAW_QA_CREDENTIAL_HTTP_TIMEOUT_MS`(默认 `15000`) - `OPENCLAW_QA_CONVEX_ENDPOINT_PREFIX`(默认 `/qa-credentials/v1`) -- `OPENCLAW_QA_CREDENTIAL_OWNER_ID`(可选的追踪 ID) -- `OPENCLAW_QA_ALLOW_INSECURE_HTTP=1` 允许在仅限本地开发时使用回环 `http://` Convex URL。 +- `OPENCLAW_QA_CREDENTIAL_OWNER_ID`(可选追踪 id) +- `OPENCLAW_QA_ALLOW_INSECURE_HTTP=1` 允许在仅限本地开发时使用 loopback `http://` Convex URL。 正常运行时,`OPENCLAW_QA_CONVEX_SITE_URL` 应使用 `https://`。 -维护者管理命令(池添加 / 删除 / 列表)必须专门使用 +维护者管理命令(池添加 / 删除 / 列表)必须明确使用 `OPENCLAW_QA_CONVEX_SECRET_MAINTAINER`。 -供维护者使用的 CLI 辅助命令: +面向维护者的 CLI 辅助命令: ```bash pnpm openclaw qa credentials doctor @@ -219,7 +215,7 @@ pnpm openclaw qa credentials list --kind telegram pnpm openclaw qa credentials remove --credential-id ``` -在实时运行前使用 `doctor` 可检查 Convex 站点 URL、broker 机密、端点前缀、HTTP 超时以及 admin / list 可达性,而不会打印机密值。在脚本和 CI 工具中可使用 `--json` 获取机器可读输出。 +在实时运行前使用 `doctor`,可检查 Convex 站点 URL、broker 密钥、端点前缀、HTTP 超时和管理 / 列表可达性,同时不会打印密钥值。在脚本和 CI 工具中使用 `--json` 可获得机器可读输出。 默认端点契约(`OPENCLAW_QA_CONVEX_SITE_URL` + `/qa-credentials/v1`): @@ -229,112 +225,40 @@ pnpm openclaw qa credentials remove --credential-id - 池耗尽 / 可重试:`{ status: "error", code: "POOL_EXHAUSTED" | "NO_CREDENTIAL_AVAILABLE", ... }` - `POST /heartbeat` - 请求:`{ kind, ownerId, actorRole, credentialId, leaseToken, leaseTtlMs }` - - 成功:`{ status: "ok" }`(或空 `2xx`) + - 成功:`{ status: "ok" }`(或空的 `2xx`) - `POST /release` - 请求:`{ kind, ownerId, actorRole, credentialId, leaseToken }` - - 成功:`{ status: "ok" }`(或空 `2xx`) -- `POST /admin/add`(仅维护者机密) + - 成功:`{ status: "ok" }`(或空的 `2xx`) +- `POST /admin/add`(仅 maintainer 密钥) - 请求:`{ kind, actorId, payload, note?, status? }` - 成功:`{ status: "ok", credential }` -- `POST /admin/remove`(仅维护者机密) +- `POST /admin/remove`(仅 maintainer 密钥) - 请求:`{ credentialId, actorId }` - 成功:`{ status: "ok", changed, credential }` - 活跃租约保护:`{ status: "error", code: "LEASE_ACTIVE", ... }` -- `POST /admin/list`(仅维护者机密) +- `POST /admin/list`(仅 maintainer 密钥) - 请求:`{ kind?, status?, includePayload?, limit? }` - 成功:`{ status: "ok", credentials, count }` -Telegram 类型的 payload 结构: +Telegram 类型的负载结构: - `{ groupId: string, driverToken: string, sutToken: string }` -- `groupId` 必须是 Telegram 聊天数字 ID 字符串。 -- `admin/add` 会对 `kind: "telegram"` 验证此结构,并拒绝格式错误的 payload。 +- `groupId` 必须是 Telegram 聊天数字 id 字符串。 +- `admin/add` 会在 `kind: "telegram"` 时验证此结构,并拒绝格式错误的负载。 ### 向 QA 添加一个渠道 -向 Markdown QA 系统添加一个渠道,严格来说只需要两样东西: - -1. 该渠道的传输适配器。 -2. 一组用于执行该渠道契约的场景包。 - -当共享的 `qa-lab` 宿主可以拥有整个流程时,不要新增顶层 QA 命令根。 - -`qa-lab` 负责共享宿主机制: - -- `openclaw qa` 命令根 -- 套件启动和清理 -- worker 并发 -- 工件写入 -- 报告生成 -- 场景执行 -- 旧版 `qa-channel` 场景的兼容性别名 - -运行器插件负责传输契约: - -- 如何将 `openclaw qa ` 挂载到共享的 `qa` 根命令下 -- 如何为该传输配置 gateway -- 如何检查就绪状态 -- 如何注入入站事件 -- 如何观察出站消息 -- 如何暴露会话记录和规范化后的传输状态 -- 如何执行由传输支持的操作 -- 如何处理传输特定的重置或清理 - -新渠道的最低采用门槛是: - -1. 继续由 `qa-lab` 拥有共享的 `qa` 根命令。 -2. 在共享的 `qa-lab` 宿主接缝上实现传输运行器。 -3. 将传输特定机制保留在运行器插件或渠道 harness 内部。 -4. 将运行器挂载为 `openclaw qa `,而不是注册一个竞争的根命令。 - 运行器插件应在 `openclaw.plugin.json` 中声明 `qaRunners`,并从 `runtime-api.ts` 导出匹配的 `qaRunnerCliRegistrations` 数组。 - 保持 `runtime-api.ts` 轻量;惰性 CLI 和运行器执行应位于独立入口点之后。 -5. 在带主题的 `qa/scenarios/` 目录下编写或改造 Markdown 场景。 -6. 为新场景使用通用场景辅助工具。 -7. 除非仓库正在进行有意迁移,否则保持现有兼容性别名继续工作。 - -决策规则很严格: - -- 如果某个行为可以在 `qa-lab` 中统一表达一次,就放到 `qa-lab` 中。 -- 如果某个行为依赖于某一种渠道传输,就将其保留在该运行器插件或插件 harness 中。 -- 如果某个场景需要多个渠道都能使用的新能力,请添加通用辅助工具,而不是在 `suite.ts` 中添加渠道特定分支。 -- 如果某个行为仅对一种传输有意义,就让该场景保持传输特定,并在场景契约中明确说明。 - -新场景优先使用的通用辅助函数名称是: - -- `waitForTransportReady` -- `waitForChannelReady` -- `injectInboundMessage` -- `injectOutboundMessage` -- `waitForTransportOutboundMessage` -- `waitForChannelOutboundMessage` -- `waitForNoTransportOutbound` -- `getTransportSnapshot` -- `readTransportMessage` -- `readTransportTranscript` -- `formatTransportTranscript` -- `resetTransport` - -现有场景仍可使用兼容性别名,包括: - -- `waitForQaChannelReady` -- `waitForOutboundMessage` -- `waitForNoOutbound` -- `formatConversationTranscript` -- `resetBus` - -新的渠道工作应使用通用辅助函数名称。 -兼容性别名的存在是为了避免一次性迁移,而不是作为 -新场景编写的范式。 +新渠道适配器的架构和场景辅助函数名称位于 [QA overview → Adding a channel](/zh-CN/concepts/qa-e2e-automation#adding-a-channel)。最低要求是:在共享的 `qa-lab` 主机接缝上实现传输运行器、在插件清单中声明 `qaRunners`、挂载为 `openclaw qa `,并在 `qa/scenarios/` 下编写场景。 ## 测试套件(各自运行位置) -可以把这些套件理解为“真实性逐步增加”(同时不稳定性 / 成本也逐步增加): +可以把这些测试套件理解为“真实度逐步增加”(同时波动性 / 成本也逐步增加): ### 单元 / 集成(默认) - 命令:`pnpm test` -- 配置:非定向运行使用 `vitest.full-*.config.ts` 分片集合,并且可能会将多项目分片展开为每项目配置,以便并行调度 -- 文件:核心 / 单元测试清单位于 `src/**/*.test.ts`、`packages/**/*.test.ts` 和 `test/**/*.test.ts`;UI 单元测试在专用 `unit-ui` 分片中运行 +- 配置:非定向运行使用 `vitest.full-*.config.ts` 分片集,并且可以将多项目分片展开为按项目划分的配置,以便并行调度 +- 文件:核心 / 单元清单位于 `src/**/*.test.ts`、`packages/**/*.test.ts` 和 `test/**/*.test.ts`;UI 单元测试在专用的 `unit-ui` 分片中运行 - 范围: - 纯单元测试 - 进程内集成测试(gateway 认证、路由、工具、解析、配置) @@ -342,69 +266,68 @@ Telegram 类型的 payload 结构: - 预期: - 在 CI 中运行 - 不需要真实密钥 - - 应当快速且稳定 + - 应该快速且稳定 - + - - 非定向的 `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` 项目图,因为多分片监听循环并不现实。 - - `pnpm test`、`pnpm test:watch` 和 `pnpm test:perf:imports` 会优先通过定向通道来路由显式文件 / 目录目标,因此 `pnpm test extensions/discord/src/monitor/message-handler.preflight.test.ts` 不必承担完整根项目启动成本。 - - `pnpm test:changed` 默认会将变更的 git 路径展开为低成本定向通道:直接测试编辑、同级 `*.test.ts` 文件、显式源文件映射以及本地导入图依赖项。除非你显式使用 `OPENCLAW_TEST_CHANGED_BROAD=1 pnpm test:changed`,否则配置 / setup / package 编辑不会触发大范围测试。 - - `pnpm check:changed` 是针对小范围工作的标准智能本地检查门禁。它会将 diff 分类为核心、核心测试、扩展、扩展测试、应用、文档、发布元数据、实时 Docker 工具和工具链,然后运行匹配的类型检查、lint 和保护命令。它不会运行 Vitest 测试;测试证明请调用 `pnpm test:changed` 或显式 `pnpm test `。仅涉及发布元数据的版本提升会运行定向版本 / 配置 / 根依赖检查,并带有一个保护机制,拒绝顶层 version 字段之外的 package 变更。 - - 对实时 Docker ACP harness 的编辑会运行聚焦检查:实时 Docker 认证脚本的 shell 语法检查,以及实时 Docker 调度器的 dry-run。仅当 diff 仅限于 `scripts["test:docker:live-*"]` 时才会包含 `package.json` 变更;依赖、导出、版本及其他 package 表面编辑仍使用更广泛的保护措施。 - - 来自 agents、commands、plugins、auto-reply helpers、`plugin-sdk` 及类似纯工具区域的轻导入单元测试会路由到 `unit-fast` 通道,该通道会跳过 `test/setup-openclaw-runtime.ts`;有状态 / 运行时负担较重的文件则保留在现有通道上。 - - 部分选定的 `plugin-sdk` 和 `commands` 辅助源文件也会在 changed 模式下,将运行映射到这些轻量通道中的显式同级测试,因此辅助文件编辑不会为该目录重跑整个重型套件。 - - `auto-reply` 为顶层核心辅助工具、顶层 `reply.*` 集成测试以及 `src/auto-reply/reply/**` 子树提供了专门的分桶。CI 还会将 reply 子树进一步拆分为智能体运行器、分发以及命令 / 状态路由分片,从而避免单个导入负担较重的桶占据整个 Node 收尾时间。 + - 非定向的 `pnpm test` 会运行十二个较小的分片配置(`core-unit-fast`、`core-unit-src`、`core-unit-security`、`core-unit-ui`、`core-unit-support`、`core-support-boundary`、`core-contracts`、`core-bundled`、`core-runtime`、`agentic`、`auto-reply`、`extensions`),而不是一个巨大的原生根项目进程。这样可以降低高负载机器上的 RSS 峰值,并避免 auto-reply / 扩展工作饿死无关套件。 + - `pnpm test --watch` 仍然使用原生根 `vitest.config.ts` 项目图,因为多分片监听循环并不现实。 + - `pnpm test`、`pnpm test:watch` 和 `pnpm test:perf:imports` 会优先通过带作用域的通道处理显式文件 / 目录目标,因此 `pnpm test extensions/discord/src/monitor/message-handler.preflight.test.ts` 不必承担完整根项目启动开销。 + - `pnpm test:changed` 默认会将 Git 变更路径展开为低成本的带作用域通道:直接测试编辑、同级 `*.test.ts` 文件、显式源码映射和本地导入图依赖方。除非你显式使用 `OPENCLAW_TEST_CHANGED_BROAD=1 pnpm test:changed`,否则配置 / setup / package 编辑不会广泛运行测试。 + - `pnpm check:changed` 是针对窄范围工作的标准智能本地检查门禁。它会将 diff 分类为核心、核心测试、扩展、扩展测试、应用、文档、发布元数据、实时 Docker 工具和工具链,然后运行匹配的类型检查、lint 和守卫命令。它不会运行 Vitest 测试;测试证明请调用 `pnpm test:changed` 或显式 `pnpm test `。仅发布元数据的版本升级会运行有针对性的版本 / 配置 / 根依赖检查,并带有一个守卫,用于拒绝顶层版本字段以外的 package 变更。 + - 实时 Docker ACP harness 编辑会运行聚焦检查:对实时 Docker 认证脚本进行 shell 语法检查,以及实时 Docker 调度器 dry-run。只有当 diff 仅限于 `scripts["test:docker:live-*"]` 时才包含 `package.json` 变更;依赖、导出、版本和其他 package 入口面编辑仍然使用更广泛的守卫。 + - 来自 agents、commands、plugins、auto-reply helpers、`plugin-sdk` 以及类似纯工具区域的轻量导入单元测试会路由到 `unit-fast` 通道,该通道会跳过 `test/setup-openclaw-runtime.ts`;有状态 / 运行时较重的文件仍保留在现有通道上。 + - 选定的 `plugin-sdk` 和 `commands` 辅助源码文件也会将 changed 模式运行映射到这些轻量通道中的显式同级测试,因此辅助函数编辑无需重新运行该目录下完整的重型套件。 + - `auto-reply` 为顶层核心辅助函数、顶层 `reply.*` 集成测试以及 `src/auto-reply/reply/**` 子树设置了专用分桶。CI 还会进一步将 reply 子树拆分为 agent-runner、dispatch 和 commands / state-routing 分片,以避免某个导入较重的分桶独占整个 Node 尾部时间。 - + - - 当你修改消息工具发现输入或压缩运行时上下文时,请同时保持两层覆盖。 - - 为纯路由和规范化边界添加聚焦的辅助函数回归测试。 - - 保持嵌入式运行器集成套件健康: + - 当你修改消息工具发现输入或压缩运行时上下文时,要同时保留这两个层级的覆盖。 + - 为纯路由和归一化边界添加聚焦的辅助函数回归测试。 + - 保持嵌入式运行器集成套件处于健康状态: `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` 路径流动;仅有辅助函数测试并不能充分替代这些集成路径。 - 基础 Vitest 配置默认使用 `threads`。 - - 共享 Vitest 配置固定 `isolate: false`,并在根项目、e2e 和实时配置中使用非隔离运行器。 - - 根 UI 通道保留其 `jsdom` setup 和优化器,但也运行在共享的非隔离运行器上。 + - 共享 Vitest 配置固定为 `isolate: false`,并在根项目、e2e 和实时配置中使用非隔离运行器。 + - 根 UI 通道保留其 `jsdom` 设置和优化器,但也运行在共享的非隔离运行器上。 - 每个 `pnpm test` 分片都从共享 Vitest 配置继承相同的 `threads` + `isolate: false` 默认值。 - - `scripts/run-vitest.mjs` 默认会为 Vitest 子 Node 进程添加 `--no-maglev`,以减少大型本地运行期间的 V8 编译抖动。设置 `OPENCLAW_VITEST_ENABLE_MAGLEV=1` 可与原生 V8 行为进行比较。 + - `scripts/run-vitest.mjs` 默认会为 Vitest 子 Node 进程添加 `--no-maglev`,以减少大型本地运行期间的 V8 编译抖动。设置 `OPENCLAW_VITEST_ENABLE_MAGLEV=1` 可与原生 V8 行为进行对比。 - `pnpm changed:lanes` 会显示某个 diff 会触发哪些架构通道。 - - pre-commit 钩子仅负责格式化。它会重新暂存格式化后的文件,不会运行 lint、类型检查或测试。 - - 在交接或推送前,当你需要智能本地检查门禁时,请显式运行 `pnpm check:changed`。 - - `pnpm test:changed` 默认通过低成本定向通道进行路由。只有当智能体判断 harness、配置、package 或契约编辑确实需要更广的 Vitest 覆盖时,才使用 `OPENCLAW_TEST_CHANGED_BROAD=1 pnpm test:changed`。 + - pre-commit 钩子只负责格式化。它会重新暂存格式化后的文件,不会运行 lint、类型检查或测试。 + - 在你需要智能本地检查门禁时,请在交接或推送前显式运行 `pnpm check:changed`。 + - `pnpm test:changed` 默认通过低成本的带作用域通道运行。只有当智能体判断 harness、配置、package 或契约编辑确实需要更广泛的 Vitest 覆盖时,才使用 `OPENCLAW_TEST_CHANGED_BROAD=1 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`。 + - 本地 worker 自动缩放有意采取保守策略;当主机平均负载已经较高时会自动回退,因此默认情况下多个并发 Vitest 运行造成的影响更小。 + - 基础 Vitest 配置会将项目 / 配置文件标记为 `forceRerunTriggers`,以便在测试接线发生变化时,changed 模式重跑仍然正确。 + - 该配置会在受支持主机上保持 `OPENCLAW_VITEST_FS_MODULE_CACHE` 启用;如果你希望为直接分析指定一个明确的缓存位置,请设置 `OPENCLAW_VITEST_FS_MODULE_CACHE_PATH=/abs/path`。 - - `pnpm test:perf:imports` 会启用 Vitest 导入耗时报告和导入拆分输出。 - - `pnpm test:perf:imports:changed` 会将同样的分析视图限定到自 `origin/main` 以来发生变更的文件。 - - 分片耗时数据会写入 `.artifacts/vitest-shard-timings.json`。 - 整个配置运行使用配置路径作为键;带 include-pattern 的 CI 分片会附加分片名称,以便单独跟踪经过过滤的分片。 - - 当某个热点测试的大部分时间仍然耗在启动导入上时,请将重依赖放在狭窄的本地 `*.runtime.ts` 接缝之后,并直接 mock 这个接缝,而不是为了传给 `vi.mock(...)` 就深度导入运行时辅助工具。 - - `pnpm test:perf:changed:bench -- --ref ` 会针对该已提交 diff,对比路由后的 `test:changed` 与原生根项目路径,并输出总耗时以及 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` 会启用 Vitest 导入时长报告以及导入拆解输出。 + - `pnpm test:perf:imports:changed` 会将相同的分析视图限定到自 `origin/main` 以来变更的文件。 + - 分片计时数据会写入 `.artifacts/vitest-shard-timings.json`。整套配置运行使用配置路径作为键;基于 include-pattern 的 CI 分片会追加分片名,以便分别跟踪过滤后的分片。 + - 当某个热点测试仍然把大部分时间花在启动导入上时,应将重型依赖放在狭窄的本地 `*.runtime.ts` 接缝后面,并直接 mock 该接缝,而不是为了通过 `vi.mock(...)` 传递它们就深度导入运行时辅助函数。 + - `pnpm test:perf:changed:bench -- --ref ` 会将定向的 `test:changed` 与该已提交 diff 的原生根项目路径进行对比,并打印墙钟时间及 macOS 最大 RSS。 + - `pnpm test:perf:changed:bench -- --worktree` 会通过 `scripts/test-projects.mjs` 和根 Vitest 配置,将当前脏工作树中的变更文件列表进行路由并基准测试。 + - `pnpm test:perf:profile:main` 会为 Vitest / Vite 启动和 transform 开销写入主线程 CPU profile。 + - `pnpm test:perf:profile:runner` 会在禁用文件并行的情况下,为单元测试套件写入运行器 CPU + 堆 profile。 @@ -412,16 +335,16 @@ Telegram 类型的 payload 结构: ### 稳定性(gateway) - 命令:`pnpm test:stability:gateway` -- 配置:`vitest.gateway.config.ts`,强制使用一个 worker +- 配置:`vitest.gateway.config.ts`,强制单 worker - 范围: - - 启动一个真实的 local loopback Gateway 网关,默认启用诊断 - - 通过诊断事件路径驱动合成的 gateway 消息、记忆和大负载抖动 + - 启动一个默认启用诊断的真实 loopback Gateway 网关 + - 通过诊断事件路径驱动合成的 gateway 消息、memory 和大负载抖动 - 通过 Gateway 网关 WS RPC 查询 `diagnostics.stability` - - 覆盖诊断稳定性包持久化辅助工具 - - 断言记录器保持有界、合成 RSS 样本保持在压力预算之下,并且每个会话队列深度都会回落到零 + - 覆盖诊断稳定性 bundle 持久化辅助函数 + - 断言记录器保持有界、合成 RSS 采样保持在压力预算以内,并且每个会话的队列深度会回落到零 - 预期: - - 对 CI 安全且不需要密钥 - - 这是用于稳定性回归跟进的窄通道,而不是完整 Gateway 网关套件的替代品 + - 对 CI 安全且无需密钥 + - 这是用于稳定性回归跟进的窄范围通道,不可替代完整 Gateway 网关套件 ### E2E(gateway 冒烟) @@ -429,17 +352,17 @@ Telegram 类型的 payload 结构: - 配置:`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 开销。 -- 常用覆盖项: - - `OPENCLAW_E2E_WORKERS=`:强制指定 worker 数量(上限 16)。 - - `OPENCLAW_E2E_VERBOSE=1`:重新启用详细控制台输出。 + - 默认以静默模式运行,以减少控制台 I/O 开销。 +- 常用覆盖方式: + - `OPENCLAW_E2E_WORKERS=` 强制指定 worker 数量(上限为 16)。 + - `OPENCLAW_E2E_VERBOSE=1` 重新启用详细控制台输出。 - 范围: - 多实例 gateway 端到端行为 - - WebSocket / HTTP 表面、节点配对,以及更重的网络场景 + - WebSocket / HTTP 入口面、节点配对和更重的网络行为 - 预期: - - 在 CI 中运行(当流水线启用时) + - 在 CI 中运行(当管道中启用时) - 不需要真实密钥 - 比单元测试包含更多活动部件(可能更慢) @@ -448,101 +371,102 @@ Telegram 类型的 payload 结构: - 命令:`pnpm test:e2e:openshell` - 文件:`extensions/openshell/src/backend.e2e.test.ts` - 范围: - - 通过 Docker 在宿主机上启动一个隔离的 OpenShell gateway + - 通过 Docker 在主机上启动一个隔离的 OpenShell gateway - 从临时本地 Dockerfile 创建一个沙箱 - 通过真实的 `sandbox ssh-config` + SSH exec 运行 OpenClaw 的 OpenShell 后端 - - 通过沙箱 fs bridge 验证远端规范文件系统行为 + - 通过沙箱 fs bridge 验证远程规范化文件系统行为 - 预期: - - 仅在选择启用时运行;不属于默认 `pnpm test:e2e` 执行的一部分 + - 仅显式启用;不属于默认 `pnpm test:e2e` 运行的一部分 - 需要本地 `openshell` CLI 和可用的 Docker daemon - 使用隔离的 `HOME` / `XDG_CONFIG_HOME`,然后销毁测试 gateway 和沙箱 -- 常用覆盖项: - - `OPENCLAW_E2E_OPENSHELL=1`:在手动运行更广泛 e2e 套件时启用该测试 - - `OPENCLAW_E2E_OPENSHELL_COMMAND=/path/to/openshell`:指向非默认的 CLI 二进制或包装脚本 +- 常用覆盖方式: + - `OPENCLAW_E2E_OPENSHELL=1`,在手动运行更广泛的 e2e 套件时启用该测试 + - `OPENCLAW_E2E_OPENSHELL_COMMAND=/path/to/openshell`,指向非默认 CLI 二进制文件或包装脚本 ### 实时(真实提供商 + 真实模型) - 命令:`pnpm test:live` - 配置:`vitest.live.config.ts` - 文件:`src/**/*.live.test.ts`、`test/**/*.live.test.ts`,以及 `extensions/` 下的内置插件实时测试 -- 默认:由 `pnpm test:live` **启用**(会设置 `OPENCLAW_LIVE_TEST=1`) +- 默认:由 `pnpm test:live` **启用**(设置 `OPENCLAW_LIVE_TEST=1`) - 范围: - - “这个提供商 / 模型在今天使用真实凭证时是否真的可用?” - - 捕捉提供商格式变化、工具调用怪癖、认证问题和速率限制行为 + - “这个提供商 / 模型在今天、使用真实凭证时,是否真的能工作?” + - 捕获提供商格式变化、工具调用怪癖、认证问题和速率限制行为 - 预期: - - 设计上并非 CI 稳定(真实网络、真实提供商策略、配额、故障) - - 会花钱 / 消耗速率限制 - - 优先运行缩小范围的子集,而不是“全部跑一遍” + - 按设计不具备 CI 稳定性(真实网络、真实提供商策略、配额、故障) + - 会花钱 / 消耗速率限制额度 + - 更适合运行收窄后的子集,而不是“全部” - 实时运行会读取 `~/.profile` 以获取缺失的 API 密钥。 -- 默认情况下,实时运行仍会隔离 `HOME`,并将配置 / 认证材料复制到临时测试 home 中,以便单元测试夹具不会修改你真实的 `~/.openclaw`。 -- 仅当你确实有意让实时测试使用真实 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` 提供单个实时覆盖值;测试在遇到速率限制响应时会重试。 +- 默认情况下,实时运行仍会隔离 `HOME`,并将配置 / 认证材料复制到临时测试 home 中,这样单元夹具就不会修改你真实的 `~/.openclaw`。 +- 只有当你有意需要实时测试使用真实 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` 做每次实时运行覆盖;测试在遇到速率限制响应时会重试。 - 进度 / 心跳输出: - - 实时套件现在会将进度行输出到 stderr,因此即使 Vitest 控制台捕获处于安静模式,长时间的提供商调用也能显示为仍在活动中。 - - `vitest.live.config.ts` 会禁用 Vitest 控制台拦截,因此提供商 / gateway 进度行会在实时运行期间立即流出。 + - 实时套件现在会把进度行输出到 stderr,因此即使 Vitest 控制台捕获处于安静状态,长时间的提供商调用也能显示为仍在活动。 + - `vitest.live.config.ts` 会禁用 Vitest 控制台拦截,因此提供商 / gateway 进度行会在实时运行期间立即流式输出。 - 使用 `OPENCLAW_LIVE_HEARTBEAT_MS` 调整直接模型心跳。 - - 使用 `OPENCLAW_LIVE_GATEWAY_HEARTBEAT_MS` 调整 Gateway 网关 / 探测心跳。 + - 使用 `OPENCLAW_LIVE_GATEWAY_HEARTBEAT_MS` 调整 gateway / 探测心跳。 -## 我该运行哪个套件? +## 我应该运行哪个测试套件? -使用这个决策表: +使用下面这个决策表: -- 编辑逻辑 / 测试:运行 `pnpm test`(如果你改动很多,再加上 `pnpm test:coverage`) -- 修改 gateway 网络 / WS 协议 / 配对:增加 `pnpm test:e2e` -- 调试“我的机器人挂了” / 提供商特定故障 / 工具调用:运行缩小范围的 `pnpm test:live` +- 编辑逻辑 / 测试:运行 `pnpm test`(如果你改动很多,也运行 `pnpm test:coverage`) +- 修改 gateway 网络 / WS 协议 / 配对:再加上 `pnpm test:e2e` +- 调试“我的机器人挂了” / 提供商特定故障 / 工具调用:运行收窄后的 `pnpm test:live` ## 实时(触网)测试 -关于实时模型矩阵、CLI 后端冒烟、ACP 冒烟、Codex app-server harness,以及所有媒体提供商实时测试(Deepgram、BytePlus(国际版)、ComfyUI、图像、音乐、视频、媒体 harness)——以及实时运行的凭证处理——请参见 -[测试——实时套件](/zh-CN/help/testing-live)。 +关于实时模型矩阵、CLI 后端冒烟、ACP 冒烟、Codex app-server +harness,以及所有媒体提供商实时测试(Deepgram、BytePlus(国际版)、ComfyUI、图像、音乐、视频、媒体 harness)——以及实时运行的凭证处理——请参见 +[Testing — live suites](/zh-CN/help/testing-live)。 -## Docker 运行器(可选的“在 Linux 中能工作”检查) +## Docker 运行器(可选的“在 Linux 上能工作”检查) 这些 Docker 运行器分为两类: -- 实时模型运行器:`test:docker:live-models` 和 `test:docker:live-gateway` 仅在仓库 Docker 镜像内运行与各自配置键匹配的实时测试文件(`src/agents/models.profiles.live.test.ts` 和 `src/gateway/gateway-models.profiles.live.test.ts`),挂载你的本地配置目录和工作区(如果挂载了,也会读取 `~/.profile`)。对应的本地入口是 `test:live:models-profiles` 和 `test:live:gateway-profiles`。 +- 实时模型运行器:`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`、 + `test:docker:live-models` 默认设置 `OPENCLAW_LIVE_MAX_MODELS=12`,而 + `test:docker:live-gateway` 默认设置 `OPENCLAW_LIVE_GATEWAY_SMOKE=1`、 `OPENCLAW_LIVE_GATEWAY_MAX_MODELS=8`、 - `OPENCLAW_LIVE_GATEWAY_STEP_TIMEOUT_MS=45000` 以及 - `OPENCLAW_LIVE_GATEWAY_MODEL_TIMEOUT_MS=90000`。当你明确需要更大范围的穷尽扫描时,可覆盖这些环境变量。 -- `test:docker:all` 会先通过 `test:docker:live-build` 构建一次实时 Docker 镜像,再通过 `scripts/package-openclaw-for-docker.mjs` 将 OpenClaw 打包为一个 npm tarball,接着构建 / 复用两个 `scripts/e2e/Dockerfile` 镜像。裸镜像只包含用于安装 / 更新 / 插件依赖通道的 Node / Git 运行器;这些通道会挂载预构建 tarball。功能镜像则会将同一个 tarball 安装到 `/app`,用于已构建应用的功能通道。Docker 通道定义位于 `scripts/lib/docker-e2e-scenarios.mjs`;规划逻辑位于 `scripts/lib/docker-e2e-plan.mjs`;`scripts/test-docker-all.mjs` 会执行所选计划。这个聚合运行器使用加权本地调度器:`OPENCLAW_DOCKER_ALL_PARALLELISM` 控制进程槽位,而资源上限会阻止重型实时、npm-install 和多服务通道同时启动。如果某个单独通道比当前上限更重,调度器仍可在池为空时启动它,然后让它单独运行,直到再次有可用容量为止。默认值为 10 个槽位、`OPENCLAW_DOCKER_ALL_LIVE_LIMIT=9`、`OPENCLAW_DOCKER_ALL_NPM_LIMIT=10` 和 `OPENCLAW_DOCKER_ALL_SERVICE_LIMIT=7`;仅当 Docker 宿主还有更多余量时,才调整 `OPENCLAW_DOCKER_ALL_WEIGHT_LIMIT` 或 `OPENCLAW_DOCKER_ALL_DOCKER_LIMIT`。该运行器默认会执行 Docker 预检,移除陈旧的 OpenClaw E2E 容器,每 30 秒打印一次状态,将成功通道的耗时存储到 `.artifacts/docker-tests/lane-timings.json`,并在后续运行中利用这些耗时优先启动更长的通道。使用 `OPENCLAW_DOCKER_ALL_DRY_RUN=1` 可在不构建或运行 Docker 的情况下打印加权通道清单,或使用 `node scripts/test-docker-all.mjs --plan-json` 打印所选通道的 CI 计划、package / image 需求和凭证。 -- `Package Acceptance` 是 GitHub 原生的包级门禁,用于回答“这个可安装的 tarball 作为产品是否可用?”。它会从 `source=npm`、`source=ref`、`source=url` 或 `source=artifact` 解析一个候选包,将其作为 `package-under-test` 上传,然后针对这个精确 tarball 运行可复用的 Docker E2E 通道,而不是重新打包所选 ref。`workflow_ref` 选择受信任的工作流 / harness 脚本,而 `package_ref` 则在 `source=ref` 时选择要打包的源提交 / 分支 / 标签;这使得当前的 acceptance 逻辑也能验证较旧但受信任的提交。配置档案按覆盖范围排序:`smoke` 是快速的安装 / 渠道 / 智能体加 gateway / 配置检查,`package` 是 package / update / plugin 契约,也是大多数 Parallels package / update 覆盖的默认原生替代项,`product` 额外加入 MCP 渠道、cron / 子智能体清理、OpenAI web 搜索和 OpenWebUI,而 `full` 则运行带 OpenWebUI 的发布路径 Docker 分块。发布验证会运行一个自定义 package 增量(`bundled-channel-deps-compat plugins-offline`)外加 Telegram package QA,因为发布路径 Docker 分块已经覆盖了重叠的 package / update / plugin 通道。由工件生成的定向 GitHub Docker 重跑命令,在可用时会包含先前的 package 工件和已准备的镜像输入,因此失败通道可避免重复构建 package 和镜像。 -- 构建和发布检查会在 tsdown 之后运行 `scripts/check-cli-bootstrap-imports.mjs`。该保护会从 `dist/entry.js` 和 `dist/cli/run-main.js` 遍历静态已构建图,并在命令分发前的启动导入提前引入 Commander、提示 UI、undici 或日志等 package 依赖时失败。打包 CLI 冒烟测试还覆盖根 help、onboard help、doctor help、status、config schema 以及一个 model-list 命令。 -- Package Acceptance 的旧版兼容性上限为 `2026.4.25`(包括 `2026.4.25-beta.*`)。在该截止版本之前,harness 只容忍已发布包元数据缺口:缺失的私有 QA inventory 条目、缺失的 `gateway install --wrapper`、从 tarball 派生的 git fixture 中缺失的 patch 文件、缺失的持久化 `update.channel`、旧版插件安装记录位置、缺失的 marketplace 安装记录持久化,以及 `plugins update` 期间的配置元数据迁移。对于 `2026.4.25` 之后的包,这些路径都会被视为严格失败。 + `OPENCLAW_LIVE_GATEWAY_STEP_TIMEOUT_MS=45000` 和 + `OPENCLAW_LIVE_GATEWAY_MODEL_TIMEOUT_MS=90000`。当你明确需要更大的穷举扫描时,可覆盖这些环境变量。 +- `test:docker:all` 会先通过 `test:docker:live-build` 构建一次实时 Docker 镜像,再通过 `scripts/package-openclaw-for-docker.mjs` 将 OpenClaw 打包为一个 npm tarball,然后构建 / 复用两个 `scripts/e2e/Dockerfile` 镜像。基础镜像仅包含用于安装 / 更新 / 插件依赖通道的 Node / Git 运行器;这些通道会挂载预构建 tarball。功能镜像则会把同一个 tarball 安装到 `/app`,供基于已构建应用的功能通道使用。Docker 通道定义位于 `scripts/lib/docker-e2e-scenarios.mjs`;规划逻辑位于 `scripts/lib/docker-e2e-plan.mjs`;`scripts/test-docker-all.mjs` 负责执行选定计划。该聚合器使用加权本地调度器:`OPENCLAW_DOCKER_ALL_PARALLELISM` 控制进程槽位,而资源上限会阻止重型实时、npm 安装和多服务通道同时全部启动。如果某个单独通道比当前上限还重,调度器在池为空时仍可启动它,然后让它单独运行,直到再次有可用容量。默认值为 10 个槽位、`OPENCLAW_DOCKER_ALL_LIVE_LIMIT=9`、`OPENCLAW_DOCKER_ALL_NPM_LIMIT=10` 和 `OPENCLAW_DOCKER_ALL_SERVICE_LIMIT=7`;只有当 Docker 主机有更多余量时,才调整 `OPENCLAW_DOCKER_ALL_WEIGHT_LIMIT` 或 `OPENCLAW_DOCKER_ALL_DOCKER_LIMIT`。该运行器默认执行 Docker 预检,移除陈旧的 OpenClaw E2E 容器,每 30 秒打印一次状态,将成功通道的耗时存储到 `.artifacts/docker-tests/lane-timings.json`,并在后续运行中利用这些耗时优先启动更长的通道。使用 `OPENCLAW_DOCKER_ALL_DRY_RUN=1` 可在不构建或运行 Docker 的情况下打印加权通道清单,或者使用 `node scripts/test-docker-all.mjs --plan-json` 打印所选通道、包 / 镜像需求和凭证的 CI 计划。 +- `Package Acceptance` 是 GitHub 原生的包门禁,用于回答“这个可安装 tarball 作为产品是否可用?”。它会从 `source=npm`、`source=ref`、`source=url` 或 `source=artifact` 解析出一个候选包,将其上传为 `package-under-test`,然后针对这个精确 tarball 运行可复用的 Docker E2E 通道,而不是重新打包所选 ref。`workflow_ref` 用于选择受信任的工作流 / harness 脚本,而 `package_ref` 用于在 `source=ref` 时选择要打包的源提交 / 分支 / 标签;这样当前的验收逻辑也能验证较旧的受信任提交。各 profile 按覆盖范围排序:`smoke` 是快速安装 / 渠道 / 智能体加 gateway / 配置,`package` 是包 / 更新 / 插件契约,也是大多数 Parallels 包 / 更新覆盖的默认原生替代方案,`product` 会增加 MCP 渠道、cron / 子智能体清理、OpenAI Web 搜索和 OpenWebUI,而 `full` 会运行包含 OpenWebUI 的发布路径 Docker 分块。发布验证会运行一个自定义包差异集(`bundled-channel-deps-compat plugins-offline`)加 Telegram 包 QA,因为发布路径 Docker 分块已经覆盖了重叠的包 / 更新 / 插件通道。由产物生成的定向 GitHub Docker 重跑命令在可用时会包含先前的包产物和准备好的镜像输入,因此失败通道可以避免重新构建包和镜像。 +- 构建和发布检查会在 tsdown 之后运行 `scripts/check-cli-bootstrap-imports.mjs`。该守卫会从 `dist/entry.js` 和 `dist/cli/run-main.js` 遍历静态构建图,如果在命令分发之前的启动导入阶段就引入了 Commander、提示 UI、undici 或日志等包依赖,则会失败。打包后的 CLI 冒烟测试还会覆盖根帮助、onboard 帮助、doctor 帮助、status、配置 schema 和模型列表命令。 +- `Package Acceptance` 的旧版兼容性上限为 `2026.4.25`(包含 `2026.4.25-beta.*`)。在该截止版本及之前,harness 仅容忍已发布包元数据缺口:省略的私有 QA 清单条目、缺失的 `gateway install --wrapper`、tarball 派生 git 夹具中缺失的补丁文件、缺失的持久化 `update.channel`、旧版插件安装记录位置、缺失的 marketplace 安装记录持久化,以及 `plugins update` 期间的配置元数据迁移。对于 `2026.4.25` 之后的包,这些路径都会被视为严格失败。 - 容器冒烟运行器:`test:docker:openwebui`、`test:docker:onboard`、`test:docker:npm-onboard-channel-agent`、`test:docker:update-channel-switch`、`test:docker:session-runtime-context`、`test:docker:agents-delete-shared-workspace`、`test:docker:gateway-network`、`test:docker:browser-cdp-snapshot`、`test:docker:mcp-channels`、`test:docker:pi-bundle-mcp-tools`、`test:docker:cron-mcp-cleanup`、`test:docker:plugins`、`test:docker:plugin-update` 和 `test:docker:config-reload` 会启动一个或多个真实容器,并验证更高层级的集成路径。 -实时模型 Docker 运行器还会只绑定挂载所需的 CLI 认证 home(如果运行未缩小范围,则挂载所有受支持的 home),然后在运行前将它们复制到容器 home 中,以便外部 CLI OAuth 可以刷新令牌,而不会修改宿主机认证存储: +实时模型 Docker 运行器还会只绑定挂载所需的 CLI 认证 home(若运行未缩小范围,则挂载所有受支持的认证 home),然后在运行前将它们复制到容器 home 中,这样外部 CLI OAuth 就可以刷新令牌,而不会修改主机认证存储: - 直接模型:`pnpm test:docker:live-models`(脚本:`scripts/test-live-models-docker.sh`) -- ACP 绑定冒烟测试:`pnpm test:docker:live-acp-bind`(脚本:`scripts/test-live-acp-bind-docker.sh`;默认覆盖 Claude、Codex 和 Gemini,而更严格的 Droid / OpenCode 覆盖可通过 `pnpm test:docker:live-acp-bind:droid` 和 `pnpm test:docker:live-acp-bind:opencode` 启用) -- CLI 后端冒烟测试:`pnpm test:docker:live-cli-backend`(脚本:`scripts/test-live-cli-backend-docker.sh`) -- Codex app-server harness 冒烟测试:`pnpm test:docker:live-codex-harness`(脚本:`scripts/test-live-codex-harness-docker.sh`) +- ACP 绑定冒烟:`pnpm test:docker:live-acp-bind`(脚本:`scripts/test-live-acp-bind-docker.sh`;默认覆盖 Claude、Codex 和 Gemini,并可通过 `pnpm test:docker:live-acp-bind:droid` 和 `pnpm test:docker:live-acp-bind:opencode` 启用严格的 Droid / OpenCode 覆盖) +- CLI 后端冒烟:`pnpm test:docker:live-cli-backend`(脚本:`scripts/test-live-cli-backend-docker.sh`) +- Codex app-server harness 冒烟:`pnpm test:docker:live-codex-harness`(脚本:`scripts/test-live-codex-harness-docker.sh`) - Gateway 网关 + 开发智能体:`pnpm test:docker:live-gateway`(脚本:`scripts/test-live-gateway-models-docker.sh`) -- 可观测性冒烟测试:`pnpm qa:otel:smoke` 是一个私有 QA 源码检出通道。它刻意不属于 package Docker 发布通道的一部分,因为 npm tarball 不包含 QA Lab。 -- Open WebUI 实时冒烟测试:`pnpm test:docker:openwebui`(脚本:`scripts/e2e/openwebui-docker.sh`) +- 可观测性冒烟:`pnpm qa:otel:smoke` 是一个私有 QA 源码检出通道。它刻意不属于包级 Docker 发布通道的一部分,因为 npm tarball 不包含 QA Lab。 +- Open WebUI 实时冒烟:`pnpm test:docker:openwebui`(脚本:`scripts/e2e/openwebui-docker.sh`) - 新手引导向导(TTY,完整脚手架):`pnpm test:docker:onboard`(脚本:`scripts/e2e/onboard-docker.sh`) -- Npm tarball 新手引导 / 渠道 / 智能体冒烟测试:`pnpm test:docker:npm-onboard-channel-agent` 会在 Docker 中全局安装打包后的 OpenClaw tarball,通过环境变量引用新手引导配置 OpenAI,并默认配置 Telegram,验证 doctor 会修复已激活插件的运行时依赖,然后运行一次模拟 OpenAI 智能体轮次。可通过 `OPENCLAW_CURRENT_PACKAGE_TGZ=/path/to/openclaw-*.tgz` 复用预构建 tarball,通过 `OPENCLAW_NPM_ONBOARD_HOST_BUILD=0` 跳过宿主机构建,或通过 `OPENCLAW_NPM_ONBOARD_CHANNEL=discord` 切换渠道。 -- 更新渠道切换冒烟测试:`pnpm test:docker:update-channel-switch` 会在 Docker 中全局安装打包后的 OpenClaw tarball,从 package `stable` 切换到 git `dev`,验证持久化的渠道和插件在更新后仍可工作,然后切换回 package `stable` 并检查更新状态。 -- 会话运行时上下文冒烟测试:`pnpm test:docker:session-runtime-context` 会验证隐藏运行时上下文的会话记录持久化,以及 doctor 对受影响的重复 prompt-rewrite 分支的修复。 -- Bun 全局安装冒烟测试:`bash scripts/e2e/bun-global-install-smoke.sh` 会打包当前树,在隔离的 home 中使用 `bun install -g` 安装,并验证 `openclaw infer image providers --json` 会返回内置图像提供商而不是挂起。可通过 `OPENCLAW_BUN_GLOBAL_SMOKE_PACKAGE_TGZ=/path/to/openclaw-*.tgz` 复用预构建 tarball,通过 `OPENCLAW_BUN_GLOBAL_SMOKE_HOST_BUILD=0` 跳过宿主机构建,或通过 `OPENCLAW_BUN_GLOBAL_SMOKE_DIST_IMAGE=openclaw-dockerfile-smoke:local` 从已构建的 Docker 镜像复制 `dist/`。 -- 安装器 Docker 冒烟测试:`bash scripts/test-install-sh-docker.sh` 会在其 root、update 和 direct-npm 容器之间共享同一个 npm 缓存。更新冒烟测试默认使用 npm `latest` 作为稳定基线,然后升级到候选 tarball。你可以在本地通过 `OPENCLAW_INSTALL_SMOKE_UPDATE_BASELINE=2026.4.22` 覆盖,或在 GitHub 上通过 Install Smoke 工作流的 `update_baseline_version` 输入覆盖。非 root 安装器检查会保留隔离的 npm 缓存,以避免 root 拥有的缓存条目掩盖用户本地安装行为。设置 `OPENCLAW_INSTALL_SMOKE_NPM_CACHE_DIR=/path/to/cache` 可在本地重跑之间复用 root / update / direct-npm 缓存。 -- Install Smoke CI 会通过 `OPENCLAW_INSTALL_SMOKE_SKIP_NPM_GLOBAL=1` 跳过重复的 direct-npm 全局更新;如需覆盖直接 `npm install -g`,请在本地不带该环境变量运行脚本。 -- Agents 删除共享工作区 CLI 冒烟测试:`pnpm test:docker:agents-delete-shared-workspace`(脚本:`scripts/e2e/agents-delete-shared-workspace-docker.sh`)默认会构建根 Dockerfile 镜像,在隔离的容器 home 中为两个智能体种入一个工作区,运行 `agents delete --json`,并验证 JSON 有效以及工作区保留行为。可通过 `OPENCLAW_AGENTS_DELETE_SHARED_WORKSPACE_E2E_IMAGE=openclaw-dockerfile-smoke:local OPENCLAW_AGENTS_DELETE_SHARED_WORKSPACE_E2E_SKIP_BUILD=1` 复用 install-smoke 镜像。 +- npm tarball 新手引导 / 渠道 / 智能体冒烟:`pnpm test:docker:npm-onboard-channel-agent` 会在 Docker 中全局安装打包好的 OpenClaw tarball,通过 env-ref 新手引导配置 OpenAI,并默认配置 Telegram,验证 doctor 会修复已激活插件的运行时依赖,然后运行一次模拟的 OpenAI 智能体轮次。可使用 `OPENCLAW_CURRENT_PACKAGE_TGZ=/path/to/openclaw-*.tgz` 复用预构建 tarball,使用 `OPENCLAW_NPM_ONBOARD_HOST_BUILD=0` 跳过主机构建,或使用 `OPENCLAW_NPM_ONBOARD_CHANNEL=discord` 切换渠道。 +- 更新渠道切换冒烟:`pnpm test:docker:update-channel-switch` 会在 Docker 中全局安装打包好的 OpenClaw tarball,从 package `stable` 切换到 git `dev`,验证持久化渠道和插件在更新后可正常工作,然后再切回 package `stable` 并检查更新状态。 +- 会话运行时上下文冒烟:`pnpm test:docker:session-runtime-context` 会验证隐藏运行时上下文转录的持久化,以及 doctor 对受影响的重复 prompt-rewrite 分支的修复。 +- Bun 全局安装冒烟:`bash scripts/e2e/bun-global-install-smoke.sh` 会打包当前树,在隔离 home 中使用 `bun install -g` 安装,并验证 `openclaw infer image providers --json` 返回的是内置图像提供商,而不是挂起。可使用 `OPENCLAW_BUN_GLOBAL_SMOKE_PACKAGE_TGZ=/path/to/openclaw-*.tgz` 复用预构建 tarball,使用 `OPENCLAW_BUN_GLOBAL_SMOKE_HOST_BUILD=0` 跳过主机构建,或使用 `OPENCLAW_BUN_GLOBAL_SMOKE_DIST_IMAGE=openclaw-dockerfile-smoke:local` 从已构建 Docker 镜像复制 `dist/`。 +- 安装器 Docker 冒烟:`bash scripts/test-install-sh-docker.sh` 会在其 root、update 和 direct-npm 容器之间共享一个 npm 缓存。更新冒烟默认使用 npm `latest` 作为稳定基线,然后再升级到候选 tarball。本地可通过 `OPENCLAW_INSTALL_SMOKE_UPDATE_BASELINE=2026.4.22` 覆盖,或在 GitHub 上通过 Install Smoke 工作流的 `update_baseline_version` 输入覆盖。非 root 安装器检查会保持隔离的 npm 缓存,这样 root 拥有的缓存条目就不会掩盖用户本地安装行为。设置 `OPENCLAW_INSTALL_SMOKE_NPM_CACHE_DIR=/path/to/cache` 可在本地重跑之间复用 root / update / direct-npm 缓存。 +- Install Smoke CI 会通过 `OPENCLAW_INSTALL_SMOKE_SKIP_NPM_GLOBAL=1` 跳过重复的 direct-npm 全局更新;如果需要直接 `npm install -g` 覆盖,请在本地运行该脚本时不要设置这个环境变量。 +- Agents 删除共享工作区 CLI 冒烟:`pnpm test:docker:agents-delete-shared-workspace`(脚本:`scripts/e2e/agents-delete-shared-workspace-docker.sh`)默认构建根 Dockerfile 镜像,在隔离容器 home 中注入两个共享同一工作区的智能体,运行 `agents delete --json`,并验证 JSON 合法以及工作区保留行为。可使用 `OPENCLAW_AGENTS_DELETE_SHARED_WORKSPACE_E2E_IMAGE=openclaw-dockerfile-smoke:local OPENCLAW_AGENTS_DELETE_SHARED_WORKSPACE_E2E_SKIP_BUILD=1` 复用 install-smoke 镜像。 - Gateway 网关网络(两个容器,WS 认证 + 健康检查):`pnpm test:docker:gateway-network`(脚本:`scripts/e2e/gateway-network-docker.sh`) -- Browser CDP 快照冒烟测试:`pnpm test:docker:browser-cdp-snapshot`(脚本:`scripts/e2e/browser-cdp-snapshot-docker.sh`)会构建源码 E2E 镜像和一个 Chromium 层,以原始 CDP 模式启动 Chromium,运行 `browser doctor --deep`,并验证 CDP 角色快照覆盖链接 URL、由光标提升的可点击元素、iframe 引用以及 frame 元数据。 -- OpenAI Responses `web_search` 最小 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 配置档案 allow / deny 冒烟测试):`pnpm test:docker:pi-bundle-mcp-tools`(脚本:`scripts/e2e/pi-bundle-mcp-tools-docker.sh`) -- Cron / 子智能体 MCP 清理(真实 Gateway 网关 + 在隔离 cron 和一次性子智能体运行后关闭 stdio MCP 子进程):`pnpm test:docker:cron-mcp-cleanup`(脚本:`scripts/e2e/cron-mcp-cleanup-docker.sh`) -- 插件(安装冒烟测试、ClawHub 安装 / 卸载、marketplace 更新,以及 Claude bundle 启用 / 检查):`pnpm test:docker:plugins`(脚本:`scripts/e2e/plugins-docker.sh`) - 设置 `OPENCLAW_PLUGINS_E2E_CLAWHUB=0` 可跳过实时 ClawHub 区块,或通过 `OPENCLAW_PLUGINS_E2E_CLAWHUB_SPEC` 和 `OPENCLAW_PLUGINS_E2E_CLAWHUB_ID` 覆盖默认 package。 -- 插件更新不变冒烟测试:`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_CURRENT_PACKAGE_TGZ=/path/to/openclaw-*.tgz` 指向一个现有 tarball。完整 Docker 聚合以及发布路径的 `bundled-channels` 分块会先预打包一次该 tarball,然后将内置渠道检查分片为独立通道,其中包括 Telegram、Discord、Slack、Feishu、memory-lancedb 和 ACPX 的单独更新通道。旧版 `plugins-integrations` 分块仍然保留为手动重跑用的聚合别名。直接运行内置通道时,可使用 `OPENCLAW_BUNDLED_CHANNELS=telegram,slack` 缩小渠道矩阵,或使用 `OPENCLAW_BUNDLED_CHANNEL_UPDATE_TARGETS=telegram,acpx` 缩小更新场景。该通道还会验证 `channels..enabled=false` 和 `plugins.entries..enabled=false` 会抑制 doctor / 运行时依赖修复。 -- 在迭代时,如需缩小内置插件运行时依赖范围,可禁用无关场景,例如: +- 浏览器 CDP 快照冒烟:`pnpm test:docker:browser-cdp-snapshot`(脚本:`scripts/e2e/browser-cdp-snapshot-docker.sh`)会构建源码 E2E 镜像和一个 Chromium 层,以原始 CDP 启动 Chromium,运行 `browser doctor --deep`,并验证 CDP 角色快照覆盖链接 URL、由光标提升的可点击元素、iframe 引用和 frame 元数据。 +- OpenAI Responses `web_search` 最小 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 / 子智能体 MCP 清理(真实 Gateway 网关 + 在隔离 cron 和一次性子智能体运行后回收 stdio MCP 子进程):`pnpm test:docker:cron-mcp-cleanup`(脚本:`scripts/e2e/cron-mcp-cleanup-docker.sh`) +- 插件(安装冒烟、ClawHub 安装 / 卸载、marketplace 更新,以及 Claude bundle 启用 / 检查):`pnpm test:docker:plugins`(脚本:`scripts/e2e/plugins-docker.sh`) + 设置 `OPENCLAW_PLUGINS_E2E_CLAWHUB=0` 可跳过实时 ClawHub 模块,或通过 `OPENCLAW_PLUGINS_E2E_CLAWHUB_SPEC` 和 `OPENCLAW_PLUGINS_E2E_CLAWHUB_ID` 覆盖默认包。 +- 插件更新未变化冒烟:`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_CURRENT_PACKAGE_TGZ=/path/to/openclaw-*.tgz` 指向现有 tarball。完整 Docker 聚合和发布路径 `bundled-channels` 分块会先统一预打包一次这个 tarball,然后将内置渠道检查切分为独立通道,包括 Telegram、Discord、Slack、Feishu、memory-lancedb 和 ACPX 的独立更新通道。旧版 `plugins-integrations` 分块仍保留为手动重跑时的聚合别名。直接运行内置通道时,可使用 `OPENCLAW_BUNDLED_CHANNELS=telegram,slack` 缩小渠道矩阵,或使用 `OPENCLAW_BUNDLED_CHANNEL_UPDATE_TARGETS=telegram,acpx` 缩小更新场景。该通道还会验证 `channels..enabled=false` 和 `plugins.entries..enabled=false` 会抑制 doctor / 运行时依赖修复。 +- 迭代时可通过禁用无关场景来缩小内置插件运行时依赖范围,例如: `OPENCLAW_BUNDLED_CHANNEL_SCENARIOS=0 OPENCLAW_BUNDLED_CHANNEL_UPDATE_SCENARIO=0 OPENCLAW_BUNDLED_CHANNEL_ROOT_OWNED_SCENARIO=0 OPENCLAW_BUNDLED_CHANNEL_SETUP_ENTRY_SCENARIO=0 pnpm test:docker:bundled-channel-deps`。 如需手动预构建并复用共享功能镜像: @@ -552,78 +476,113 @@ OPENCLAW_DOCKER_E2E_IMAGE=openclaw-docker-e2e-functional:local pnpm test:docker: OPENCLAW_DOCKER_E2E_IMAGE=openclaw-docker-e2e-functional:local OPENCLAW_SKIP_DOCKER_BUILD=1 pnpm test:docker:mcp-channels ``` -当设置了诸如 `OPENCLAW_GATEWAY_NETWORK_E2E_IMAGE` 之类的套件特定镜像覆盖项时,它们仍然优先。当 `OPENCLAW_SKIP_DOCKER_BUILD=1` 指向远程共享镜像时,如果本地尚不存在,脚本会先拉取。QR 和安装器 Docker 测试继续保留各自的 Dockerfile,因为它们验证的是 package / 安装行为,而不是共享的已构建应用运行时。 +设置后,诸如 `OPENCLAW_GATEWAY_NETWORK_E2E_IMAGE` 这样的套件专用镜像覆盖仍会优先生效。当 `OPENCLAW_SKIP_DOCKER_BUILD=1` 指向远程共享镜像时,如果镜像尚未在本地存在,这些脚本会先拉取它。QR 和安装器 Docker 测试仍保留各自独立的 Dockerfile,因为它们验证的是包 / 安装行为,而不是共享的已构建应用运行时。 -实时模型 Docker 运行器还会以只读方式绑定挂载当前检出,并将其暂存到容器内的临时工作目录中。这样既能保持运行时镜像精简,又能让 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 兼容 HTTP 端点的 OpenClaw gateway 容器,启动一个固定版本的 Open WebUI 容器连接到该 gateway,通过 Open WebUI 登录,验证 `/api/models` 暴露 `openclaw/default`,然后通过 Open WebUI 的 `/api/chat/completions` 代理发送一次真实聊天请求。 -首次运行可能明显更慢,因为 Docker 可能需要拉取 Open WebUI 镜像,而 Open WebUI 也可能需要完成自己的冷启动设置。 -该通道需要一个可用的实时模型密钥,而 `OPENCLAW_PROFILE_FILE`(默认为 `~/.profile`)是在 Docker 化运行中提供该密钥的主要方式。 -成功运行会打印一个小型 JSON 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 子进程会在每次运行后退出。 +实时模型 Docker 运行器还会以只读方式绑定挂载当前检出内容, +并将其注入到容器内的临时工作目录中。这样既能保持运行时 +镜像精简,又仍可针对你当前本地的源码 / 配置运行 Vitest。 +注入步骤会跳过大型本地专用缓存和应用构建输出,例如 +`.pnpm-store`、`.worktrees`、`__openclaw_vitest__`,以及应用本地 `.build` 或 +Gradle 输出目录,因此 Docker 实时运行不会花数分钟复制 +机器特定产物。 +它们还会设置 `OPENCLAW_SKIP_CHANNELS=1`,这样 gateway 实时探测就不会在容器内 +启动真实的 Telegram / Discord / 等渠道工作进程。 +`test:docker:live-models` 仍然运行 `pnpm test:live`,因此当你需要缩小或排除该 Docker 通道中的 gateway +实时覆盖范围时,也要一并传入 +`OPENCLAW_LIVE_GATEWAY_*`。 +`test:docker:openwebui` 是更高层级的兼容性冒烟测试:它会启动一个 +启用了 OpenAI 兼容 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": +"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 子进程会在每次运行后退出。 手动 ACP 自然语言线程冒烟测试(非 CI): - `bun scripts/dev/discord-acp-plain-language-smoke.ts --channel ...` -- 请保留此脚本用于回归 / 调试工作流。它未来可能仍会用于 ACP 线程路由验证,因此不要删除它。 +- 将此脚本保留用于回归 / 调试工作流。它未来可能仍会在 ACP 线程路由验证中再次需要,因此不要删除它。 常用环境变量: - `OPENCLAW_CONFIG_DIR=...`(默认:`~/.openclaw`)挂载到 `/home/node/.openclaw` - `OPENCLAW_WORKSPACE_DIR=...`(默认:`~/.openclaw/workspace`)挂载到 `/home/node/.openclaw/workspace` - `OPENCLAW_PROFILE_FILE=...`(默认:`~/.profile`)挂载到 `/home/node/.profile`,并在运行测试前读取 -- `OPENCLAW_DOCKER_PROFILE_ENV_ONLY=1`:仅验证从 `OPENCLAW_PROFILE_FILE` 读取的环境变量,使用临时配置 / 工作区目录,且不挂载外部 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` 读取的环境变量,使用临时配置 / 工作区目录,并且不挂载外部 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_LIVE_PROVIDERS` / `OPENCLAW_LIVE_GATEWAY_PROVIDERS` 推断出的所需目录 / 文件 - 可通过 `OPENCLAW_DOCKER_AUTH_DIRS=all`、`OPENCLAW_DOCKER_AUTH_DIRS=none` 或逗号列表(如 `OPENCLAW_DOCKER_AUTH_DIRS=.claude,.codex`)手动覆盖 -- `OPENCLAW_LIVE_GATEWAY_MODELS=...` / `OPENCLAW_LIVE_MODELS=...`:缩小运行范围 -- `OPENCLAW_LIVE_GATEWAY_PROVIDERS=...` / `OPENCLAW_LIVE_PROVIDERS=...`:在容器内过滤提供商 -- `OPENCLAW_SKIP_DOCKER_BUILD=1`:复用现有的 `openclaw:local-live` 镜像,用于无需重建的重跑 -- `OPENCLAW_LIVE_REQUIRE_PROFILE_KEYS=1`:确保凭证来自 profile 存储(而不是环境变量) -- `OPENCLAW_OPENWEBUI_MODEL=...`:选择 Gateway 网关为 Open WebUI 冒烟测试暴露的模型 -- `OPENCLAW_OPENWEBUI_PROMPT=...`:覆盖 Open WebUI 冒烟测试使用的 nonce 检查提示词 -- `OPENWEBUI_IMAGE=...`:覆盖固定的 Open WebUI 镜像标签 +- `OPENCLAW_LIVE_GATEWAY_MODELS=...` / `OPENCLAW_LIVE_MODELS=...` 用于缩小运行范围 +- `OPENCLAW_LIVE_GATEWAY_PROVIDERS=...` / `OPENCLAW_LIVE_PROVIDERS=...` 用于在容器内筛选提供商 +- `OPENCLAW_SKIP_DOCKER_BUILD=1` 用于复用现有 `openclaw:local-live` 镜像,以便在无需重建的情况下重跑 +- `OPENCLAW_LIVE_REQUIRE_PROFILE_KEYS=1` 用于确保凭证来自 profile 存储(而不是环境变量) +- `OPENCLAW_OPENWEBUI_MODEL=...` 用于选择 Gateway 网关为 Open WebUI 冒烟测试暴露的模型 +- `OPENCLAW_OPENWEBUI_PROMPT=...` 用于覆盖 Open WebUI 冒烟测试使用的 nonce 检查提示词 +- `OPENWEBUI_IMAGE=...` 用于覆盖固定的 Open WebUI 镜像标签 ## 文档完整性检查 -在编辑文档后运行文档检查:`pnpm check:docs`。 -当你还需要检查页内标题时,运行完整的 Mintlify 锚点校验:`pnpm docs:check-links:anchors`。 +修改文档后运行文档检查:`pnpm check:docs`。 +当你还需要检查页内标题锚点时,运行完整的 Mintlify 锚点校验:`pnpm docs:check-links:anchors`。 -## 离线回归(对 CI 安全) +## 离线回归测试(对 CI 安全) -这些是在没有真实提供商情况下的“真实流水线”回归测试: +这些是在没有真实提供商的情况下运行的“真实流水线”回归测试: -- Gateway 网关工具调用(模拟 OpenAI,真实 gateway + agent loop):`src/gateway/gateway.test.ts`(用例:“runs a mock OpenAI tool call end-to-end via gateway agent loop”) +- Gateway 网关工具调用(模拟 OpenAI,真实 gateway + Agent loop):`src/gateway/gateway.test.ts`(用例:“runs a mock OpenAI tool call end-to-end via gateway agent loop”) - Gateway 网关向导(WS `wizard.start` / `wizard.next`,强制写入配置 + 认证):`src/gateway/gateway.test.ts`(用例:“runs wizard over ws and writes auth token config”) ## 智能体可靠性评估(Skills) -我们已经有一些对 CI 安全、行为类似“智能体可靠性评估”的测试: +我们已经有一些对 CI 安全的测试,它们的行为类似于“智能体可靠性评估”: -- 通过真实 gateway + agent loop 进行模拟工具调用(`src/gateway/gateway.test.ts`)。 +- 通过真实 gateway + Agent loop 的模拟工具调用(`src/gateway/gateway.test.ts`)。 - 验证会话接线和配置效果的端到端向导流程(`src/gateway/gateway.test.ts`)。 -对于 Skills(参见 [Skills](/zh-CN/tools/skills))仍然缺少的部分: +对于 Skills(见 [Skills](/zh-CN/tools/skills)),目前仍缺少的内容: -- **决策能力:** 当提示中列出 Skills 时,智能体是否会选择正确的 Skill(或避免选择无关的 Skill)? -- **遵循性:** 智能体是否会在使用前读取 `SKILL.md`,并遵守所需步骤 / 参数? -- **工作流契约:** 多轮场景,用于断言工具顺序、会话历史继承以及沙箱边界。 +- **决策能力:** 当提示词中列出 Skills 时,智能体是否会选择正确的 skill(或避免选择无关 skill)? +- **合规性:** 智能体在使用前是否会读取 `SKILL.md`,并遵循要求的步骤 / 参数? +- **工作流契约:** 断言工具顺序、会话历史延续和沙箱边界的多轮场景。 未来的评估应优先保持确定性: -- 一个使用模拟提供商的场景运行器,用于断言工具调用及顺序、Skill 文件读取和会话接线。 -- 一小套以 Skill 为中心的场景(使用与避免、门控、提示注入)。 -- 仅在 CI 安全套件就位后,再添加可选的实时评估(选择启用、由环境变量门控)。 +- 一个使用模拟提供商的场景运行器,用于断言工具调用 + 顺序、skill 文件读取和会话接线。 +- 一小组聚焦 skill 的场景(使用 vs 避免、门禁、提示注入)。 +- 只有在对 CI 安全的测试套件就位之后,才添加可选的实时评估(显式启用、受环境变量控制)。 ## 契约测试(插件和渠道形状) -契约测试验证每个已注册的插件和渠道都符合其接口契约。它们会遍历所有发现的插件,并运行一组形状和行为断言。默认的 `pnpm test` 单元通道会刻意跳过这些共享接缝和冒烟文件;当你修改共享渠道或提供商表面时,请显式运行契约命令。 +契约测试用于验证每个已注册插件和渠道都符合其 +接口契约。它们会遍历所有已发现的插件,并运行一套 +形状和行为断言。默认的 `pnpm test` 单元通道会刻意 +跳过这些共享接缝和冒烟文件;当你修改共享渠道或提供商入口面时, +请显式运行契约命令。 ### 命令 @@ -635,21 +594,21 @@ OPENCLAW_DOCKER_E2E_IMAGE=openclaw-docker-e2e-functional:local OPENCLAW_SKIP_DOC 位于 `src/channels/plugins/contracts/*.contract.test.ts`: -- **plugin** - 基本插件形状(id、name、capabilities) +- **plugin** - 基本插件形状(id、名称、能力) - **setup** - 设置向导契约 - **session-binding** - 会话绑定行为 -- **outbound-payload** - 消息载荷结构 +- **outbound-payload** - 消息负载结构 - **inbound** - 入站消息处理 - **actions** - 渠道操作处理器 - **threading** - 线程 ID 处理 -- **directory** - 目录 / roster API +- **directory** - 目录 / 成员列表 API - **group-policy** - 群组策略强制执行 -### 提供商状态契约 +### 提供商 Status 契约 位于 `src/plugins/contracts/*.contract.test.ts`。 -- **status** - 渠道状态探测 +- **status** - 渠道 Status 探测 - **registry** - 插件注册表形状 ### 提供商契约 @@ -657,7 +616,7 @@ OPENCLAW_DOCKER_E2E_IMAGE=openclaw-docker-e2e-functional:local OPENCLAW_SKIP_DOC 位于 `src/plugins/contracts/*.contract.test.ts`: - **auth** - 认证流程契约 -- **auth-choice** - 认证选项 / 选择 +- **auth-choice** - 认证选择 / 选择逻辑 - **catalog** - 模型目录 API - **discovery** - 插件发现 - **loader** - 插件加载 @@ -667,26 +626,26 @@ OPENCLAW_DOCKER_E2E_IMAGE=openclaw-docker-e2e-functional:local OPENCLAW_SKIP_DOC ### 何时运行 -- 修改 plugin-sdk 导出或子路径之后 +- 修改 `plugin-sdk` 导出或子路径之后 - 添加或修改渠道或提供商插件之后 - 重构插件注册或发现逻辑之后 -契约测试会在 CI 中运行,不需要真实 API 密钥。 +契约测试会在 CI 中运行,并且不需要真实 API 密钥。 ## 添加回归测试(指南) -当你修复了在实时环境中发现的提供商 / 模型问题时: +当你修复一个在实时环境中发现的提供商 / 模型问题时: - 如果可能,添加一个对 CI 安全的回归测试(模拟 / stub 提供商,或捕获精确的请求形状转换) -- 如果它天生只能在实时环境中复现(速率限制、认证策略),就让实时测试保持范围狭小,并通过环境变量选择启用 -- 优先瞄准能捕获该缺陷的最小层级: +- 如果它天生只能在实时环境中复现(速率限制、认证策略),则保持实时测试范围狭窄,并通过环境变量显式启用 +- 优先针对能捕获该缺陷的最小层: - 提供商请求转换 / 重放缺陷 → 直接模型测试 - - gateway 会话 / 历史 / 工具流水线缺陷 → gateway 实时冒烟测试或对 CI 安全的 gateway 模拟测试 -- SecretRef 遍历保护栏: - - `src/secrets/exec-secret-ref-id-parity.test.ts` 会从注册表元数据(`listSecretTargetRegistryEntries()`)中为每个 SecretRef 类派生一个采样目标,然后断言遍历段 exec ID 会被拒绝。 - - 如果你在 `src/secrets/target-registry-data.ts` 中添加了新的 `includeInPlan` SecretRef 目标族,请更新该测试中的 `classifyTargetClass`。该测试会在目标 ID 未分类时故意失败,以防新类别被悄悄跳过。 + - gateway 会话 / 历史 / 工具流水线缺陷 → gateway 实时冒烟或对 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 时故意失败,以确保新类别不会被静默跳过。 -## 相关 +## 相关内容 -- [实时测试](/zh-CN/help/testing-live) +- [Testing live](/zh-CN/help/testing-live) - [CI](/zh-CN/ci)