diff --git a/docs/zh-CN/ci.md b/docs/zh-CN/ci.md index 71254740a..92d6a9890 100644 --- a/docs/zh-CN/ci.md +++ b/docs/zh-CN/ci.md @@ -1,55 +1,55 @@ --- read_when: - - 你需要了解某个 CI 作业为什么运行或没有运行 + - 你需要了解为什么某个 CI 作业运行了或没有运行 - 你正在调试失败的 GitHub Actions 检查 -summary: CI 作业图、范围门禁和本地对应命令 +summary: CI 作业图、范围门禁,以及本地等效命令 title: CI 流水线 x-i18n: - generated_at: "2026-04-27T07:11:15Z" + generated_at: "2026-04-27T08:00:03Z" model: gpt-5.4 provider: openai - source_hash: 197ca6bd69f47fc26f8bee3f10c90fab75536cc46c0ca2350a02342d7a3a030c + source_hash: 997474e178b4a9195e4a421c81bbeb0f625ded48f015bc87c4406ddb28aec912 source_path: ci.md workflow: 15 --- -CI 在每次推送到 `main` 以及每个拉取请求时都会运行。它使用智能范围界定,在只更改了不相关区域时跳过高开销作业。手动 `workflow_dispatch` 运行会有意绕过智能范围界定,并展开完整的常规 CI 作业图,用于发布候选版本或广泛验证。 +CI 会在每次向 `main` 推送以及每个拉取请求时运行。它使用智能范围控制,在仅有不相关区域发生变更时跳过昂贵作业。手动 `workflow_dispatch` 运行会有意绕过智能范围控制,并展开完整的常规 CI 作业图,用于发布候选版本或大范围验证。 -`Full Release Validation` 是“发布前运行所有内容”的手动总工作流。它接受分支、标签或完整提交 SHA,使用该目标派发手动 `CI` 工作流,并派发 `OpenClaw Release Checks`,用于安装冒烟测试、包验收、Docker 发布路径测试套件、live/E2E、OpenWebUI、QA Lab 一致性、Matrix 和 Telegram 相关流程。当提供已发布的包规范时,它还可以运行发布后的 `NPM Telegram Beta E2E` 工作流。 +`Full Release Validation` 是“发布前运行全部内容”的手动总控工作流。它接受分支、标签或完整提交 SHA,使用该目标分发手动 `CI` 工作流,并分发 `OpenClaw Release Checks`,用于安装冒烟测试、包验收、Docker 发布路径测试套件、实时 / E2E、OpenWebUI、QA Lab 对等验证、Matrix 和 Telegram 通道测试。提供已发布的软件包规范时,它还可以运行发布后的 `NPM Telegram Beta E2E` 工作流。 -`Package Acceptance` 是用于验证包产物的旁路工作流,不会阻塞发布工作流。它可从以下来源解析单个候选项:已发布的 npm 规范、使用所选 `workflow_ref` harness 构建的可信 `package_ref`、带有 SHA-256 的 HTTPS tarball URL,或来自其他 GitHub Actions 运行的 tarball 产物;然后将其上传为 `package-under-test`,并复用 Docker 发布 / E2E 调度器,使用该 tarball 而不是重新打包工作流检出内容。其配置文件涵盖 smoke、package、product、full 以及自定义 Docker 流程选择。`package` 配置文件使用离线插件覆盖,因此已发布包的验证不依赖 live ClawHub 可用性。可选的 Telegram 流程会在 `NPM Telegram Beta E2E` 工作流中复用 `package-under-test` 产物,而已发布 npm 规范路径仍保留给独立派发使用。 +`Package Acceptance` 是一个旁路运行工作流,用于验证软件包构件,而不会阻塞发布工作流。它会从已发布的 npm 规范、使用所选 `workflow_ref` harness 构建的受信任 `package_ref`、带 SHA-256 的 HTTPS tarball URL,或来自其他 GitHub Actions 运行的 tarball 构件中解析出一个候选项,将其上传为 `package-under-test`,然后复用 Docker 发布 / E2E 调度器,针对该 tarball 运行,而不是重新打包工作流检出的内容。配置文件覆盖 smoke、package、product、full 和自定义 Docker 通道选择。`package` 配置文件使用离线插件覆盖,因此已发布软件包的验证不依赖实时 ClawHub 可用性。可选的 Telegram 通道会在 `NPM Telegram Beta E2E` 工作流中复用 `package-under-test` 构件,而已发布 npm 规范路径则保留给独立分发使用。 ## 包验收 -当问题是“这个可安装的 OpenClaw 包作为产品是否可用?”时,请使用 `Package Acceptance`。它与常规 CI 不同:常规 CI 验证源码树,而包验收则通过用户在安装或更新后实际经历的同一套 Docker E2E harness 来验证单个 tarball。 +当问题是“这个可安装的 OpenClaw 软件包作为产品是否可用?”时,请使用 `Package Acceptance`。它不同于常规 CI:常规 CI 验证源码树,而包验收则通过用户在安装或更新后会实际使用的同一套 Docker E2E harness 来验证单个 tarball。 -该工作流有四个作业: +该工作流包含四个作业: -1. `resolve_package` 检出 `workflow_ref`,解析单个包候选项,写入 `.artifacts/docker-e2e-package/openclaw-current.tgz`,写入 `.artifacts/docker-e2e-package/package-candidate.json`,将二者作为 `package-under-test` 产物上传,并在 GitHub 步骤摘要中打印来源、工作流 ref、包 ref、版本、SHA-256 和配置文件。 -2. `docker_acceptance` 使用 `ref=workflow_ref` 和 `package_artifact_name=package-under-test` 调用 `openclaw-live-and-e2e-checks-reusable.yml`。该可复用工作流会下载该产物,验证 tarball 清单,按需准备 package-digest Docker 镜像,并针对该包运行所选 Docker 流程,而不是打包工作流检出内容。 -3. `package_telegram` 可选调用 `NPM Telegram Beta E2E`。当 `telegram_mode` 不为 `none` 时它会运行;如果 Package Acceptance 已解析出包,它会安装相同的 `package-under-test` 产物;独立的 Telegram 派发仍然可以安装已发布的 npm 规范。 -4. `summary` 会在包解析、Docker 验收或可选的 Telegram 流程失败时使整个工作流失败。 +1. `resolve_package` 会检出 `workflow_ref`,解析一个软件包候选项,写入 `.artifacts/docker-e2e-package/openclaw-current.tgz`,写入 `.artifacts/docker-e2e-package/package-candidate.json`,将两者作为 `package-under-test` 构件上传,并在 GitHub 步骤摘要中输出来源、工作流引用、软件包引用、版本、SHA-256 和配置文件。 +2. `docker_acceptance` 调用 `openclaw-live-and-e2e-checks-reusable.yml`,并传入 `ref=workflow_ref` 与 `package_artifact_name=package-under-test`。该可复用工作流会下载该构件、验证 tarball 清单、在需要时准备 package-digest Docker 镜像,并针对该软件包运行所选 Docker 通道,而不是打包工作流检出的内容。 +3. `package_telegram` 可选调用 `NPM Telegram Beta E2E`。当 `telegram_mode` 不为 `none` 时运行;如果 `Package Acceptance` 已解析出一个候选项,它会安装相同的 `package-under-test` 构件;独立的 Telegram 分发仍可安装已发布的 npm 规范。 +4. `summary` 会在软件包解析、Docker 验收或可选的 Telegram 通道失败时使工作流失败。 候选来源: -- `source=npm`:仅接受 `openclaw@beta`、`openclaw@latest` 或精确的 OpenClaw 发布版本,例如 `openclaw@2026.4.27-beta.2`。用于已发布 beta / stable 的验收。 -- `source=ref`:打包可信的 `package_ref` 分支、标签或完整提交 SHA。解析器会获取 OpenClaw 分支 / 标签,验证所选提交可从仓库分支历史或发布标签到达,在分离工作树中安装依赖,并使用 `scripts/package-openclaw-for-docker.mjs` 进行打包。 +- `source=npm`:仅接受 `openclaw@beta`、`openclaw@latest`,或确切的 OpenClaw 发布版本,例如 `openclaw@2026.4.27-beta.2`。用于已发布 beta / stable 的验收。 +- `source=ref`:打包受信任的 `package_ref` 分支、标签或完整提交 SHA。解析器会获取 OpenClaw 分支 / 标签,验证所选提交可从仓库分支历史或发布标签到达,在分离的工作树中安装依赖,并使用 `scripts/package-openclaw-for-docker.mjs` 进行打包。 - `source=url`:下载 HTTPS `.tgz`;必须提供 `package_sha256`。 -- `source=artifact`:从 `artifact_run_id` 和 `artifact_name` 下载一个 `.tgz`;`package_sha256` 可选,但对于外部共享产物应当提供。 +- `source=artifact`:从 `artifact_run_id` 和 `artifact_name` 下载一个 `.tgz`;`package_sha256` 是可选的,但对于外部共享构件应当提供。 -请将 `workflow_ref` 和 `package_ref` 分开理解。`workflow_ref` 是运行测试的可信工作流 / harness 代码。`package_ref` 是在 `source=ref` 时要被打包的源提交。这样可以让当前测试 harness 验证较旧但可信的源提交,而不必运行旧的工作流逻辑。 +请将 `workflow_ref` 和 `package_ref` 分开。`workflow_ref` 是运行测试的受信任工作流 / harness 代码。`package_ref` 是在 `source=ref` 时被打包的源码提交。这样,当前测试 harness 就可以验证较旧但受信任的源码提交,而无需运行旧的工作流逻辑。 -配置文件映射到 Docker 覆盖范围: +配置文件与 Docker 覆盖的映射如下: - `smoke`:`npm-onboard-channel-agent`、`gateway-network`、`config-reload` - `package`:`npm-onboard-channel-agent`、`doctor-switch`、`update-channel-switch`、`bundled-channel-deps-compat`、`plugins-offline`、`plugin-update` -- `product`:在 `package` 基础上增加 `mcp-channels`、`cron-mcp-cleanup`、`openai-web-search-minimal`、`openwebui` +- `product`:`package` 加上 `mcp-channels`、`cron-mcp-cleanup`、`openai-web-search-minimal`、`openwebui` - `full`:带 OpenWebUI 的完整 Docker 发布路径分片 -- `custom`:精确的 `docker_lanes`;当 `suite_profile=custom` 时为必填 +- `custom`:精确的 `docker_lanes`;当 `suite_profile=custom` 时必须提供 -发布检查会以 `source=ref`、`package_ref=`、`workflow_ref=`、`suite_profile=package` 和 `telegram_mode=mock-openai` 调用 Package Acceptance。该配置文件是大多数 Parallels 包 / 更新验证的 GitHub 原生替代方案,而 Telegram 会通过 QA live 传输证明同一个包产物。跨 OS 的发布检查仍覆盖 OS 特定的新手引导、安装器和平台行为;包 / 更新产品验证应从 Package Acceptance 开始。 +发布检查会以 `source=ref`、`package_ref=`、`workflow_ref=`、`suite_profile=package` 和 `telegram_mode=mock-openai` 调用 `Package Acceptance`。该配置文件是大多数 Parallels 软件包 / 更新验证在 GitHub 原生环境中的替代方案,其中 Telegram 会通过 QA 实时传输验证同一软件包构件。跨操作系统发布检查仍然覆盖特定于操作系统的新手引导、安装器和平台行为;而软件包 / 更新的产品级验证应从 `Package Acceptance` 开始。Windows 打包版和安装器全新安装通道还会验证:已安装的软件包是否可以从原始绝对 Windows 路径导入浏览器控制覆盖项。 -Package Acceptance 为已发布且截至 `2026.4.25` 的包提供了一个有边界的旧版兼容窗口,包括 `2026.4.25-beta.*`。这些宽限规则在此记录,以避免它们变成永久性的静默跳过:如果 tarball 省略了已知的私有 QA 文件,`dist/postinstall-inventory.json` 中已知的私有 QA 条目可能会发出警告;当包未暴露该标志时,`doctor-switch` 可能会跳过 `gateway install --wrapper` 持久化子场景;`update-channel-switch` 可能会从 tarball 派生的伪 git fixture 中裁剪缺失的 `pnpm.patchedDependencies`,并且可能记录缺失的持久化 `update.channel`;插件冒烟测试可能会读取旧版安装记录位置,或接受缺失的 marketplace 安装记录持久化;而 `plugin-update` 可能允许配置元数据迁移,同时仍要求安装记录及无重复安装行为保持不变。`2026.4.25` 之后的包必须满足现代契约;相同条件将不再警告或跳过,而是直接失败。 +`Package Acceptance` 对已发布软件包提供一个有界的旧版兼容窗口,截止到 `2026.4.25`,包括 `2026.4.25-beta.*`。这些兼容规则在此处记录,以防它们变成永久性的静默跳过:如果 tarball 省略了这些文件,`dist/postinstall-inventory.json` 中已知的私有 QA 条目可能会发出警告;当软件包未暴露该标志时,`doctor-switch` 可能会跳过 `gateway install --wrapper` 持久化子用例;`update-channel-switch` 可能会从 tarball 派生的伪 git 固件中裁剪缺失的 `pnpm.patchedDependencies`,并可能记录缺失的持久化 `update.channel`;插件冒烟测试可能会读取旧版安装记录位置,或接受缺失的 marketplace 安装记录持久化;而 `plugin-update` 可能会允许配置元数据迁移,同时仍要求安装记录以及“不重新安装”行为保持不变。`2026.4.25` 之后的软件包必须满足现代契约;相同条件届时会失败,而不是警告或跳过。 示例: @@ -92,15 +92,15 @@ gh workflow run package-acceptance.yml \ -f docker_lanes='install-e2e plugin-update' ``` -在调试失败的包验收运行时,先查看 `resolve_package` 摘要,以确认包来源、版本和 SHA-256。然后检查 `docker_acceptance` 子运行及其 Docker 产物:`.artifacts/docker-tests/**/summary.json`、`failures.json`、流程日志、阶段耗时以及重跑命令。优先重跑失败的包配置文件或精确的 Docker 流程,而不是重跑完整发布验证。 +调试失败的包验收运行时,先查看 `resolve_package` 摘要,以确认软件包来源、版本和 SHA-256。然后检查 `docker_acceptance` 子运行及其 Docker 构件:`.artifacts/docker-tests/**/summary.json`、`failures.json`、通道日志、阶段耗时以及重新运行命令。优先重新运行失败的软件包配置文件或精确的 Docker 通道,而不是重新运行完整发布验证。 -QA Lab 在主智能范围工作流之外有专门的 CI 流程。`Parity gate` 工作流会在匹配的 PR 更改和手动派发时运行;它会构建私有 QA 运行时,并比较 mock GPT-5.5 和 Opus 4.6 agentic packs。`QA-Lab - All Lanes` 工作流会在 `main` 上每晚运行,并支持手动派发;它会将 mock parity gate、live Matrix 流程以及 live Telegram 和 Discord 流程作为并行作业展开。live 作业使用 `qa-live-shared` 环境,而 Telegram / Discord 使用 Convex leases。对于定时和发布门禁,Matrix 使用 `--profile fast --fail-fast`;而 CLI 默认值和手动工作流输入仍为 `all`;手动 `matrix_profile=all` 派发总是会将完整 Matrix 覆盖拆分为 `transport`、`media`、`e2ee-smoke`、`e2ee-deep` 和 `e2ee-cli` 作业。`OpenClaw Release Checks` 也会在发布批准前运行关键发布所需的 QA Lab 流程。 +QA Lab 在主智能范围工作流之外拥有专门的 CI 通道。`Parity gate` 工作流会在匹配的 PR 变更和手动分发时运行;它会构建私有 QA 运行时,并比较 mock GPT-5.5 与 Opus 4.6 智能体打包。`QA-Lab - All Lanes` 工作流会在 `main` 上按夜间计划运行,也可手动分发;它会将 mock parity gate、实时 Matrix 通道,以及实时 Telegram 和 Discord 通道并行展开为多个作业。实时作业使用 `qa-live-shared` 环境,而 Telegram / Discord 使用 Convex 租约。对于计划任务和发布门禁,Matrix 使用 `--profile fast --fail-fast`,而 CLI 默认值和手动工作流输入仍为 `all`;手动 `matrix_profile=all` 分发始终会将完整 Matrix 覆盖拆分为 `transport`、`media`、`e2ee-smoke`、`e2ee-deep` 和 `e2ee-cli` 作业。`OpenClaw Release Checks` 也会在发布批准前运行关键的 QA Lab 通道。 -`Duplicate PRs After Merge` 工作流是一个供维护者使用的手动工作流,用于落地后的重复 PR 清理。它默认以 dry-run 方式运行,只有在 `apply=true` 时才会关闭明确列出的 PR。在修改 GitHub 之前,它会验证已落地 PR 已被合并,并验证每个重复 PR 都具有共享的引用 issue,或存在重叠的已修改代码块。 +`Duplicate PRs After Merge` 工作流是一个供维护者使用的手动工作流,用于合并后的重复项清理。它默认执行 dry-run,且仅当 `apply=true` 时才会关闭显式列出的 PR。在修改 GitHub 之前,它会验证已合并的 PR 确实已合并,并验证每个重复 PR 要么共享同一个被引用 issue,要么存在重叠的变更代码块。 -`Docs Agent` 工作流是一个事件驱动的 Codex 维护流程,用于让现有文档与最近已落地的更改保持一致。它没有纯定时调度:`main` 上成功的、非机器人推送 CI 运行可以触发它,也可以通过手动派发直接运行。工作流运行触发的调用会在 `main` 已继续前进,或最近一小时内已创建另一个未被跳过的 Docs Agent 运行时跳过。实际运行时,它会审查从上一个未被跳过的 Docs Agent 源 SHA 到当前 `main` 的提交范围,因此每小时一次的运行可以覆盖自上次文档处理以来累积在 `main` 上的所有更改。 +`Docs Agent` 工作流是一个事件驱动的 Codex 维护通道,用于让现有文档与最近已合并的变更保持一致。它没有纯定时计划:`main` 上成功的非机器人 push CI 运行可以触发它,手动分发也可以直接运行它。若 `main` 已继续前进,或过去一小时内已创建了另一个未被跳过的 Docs Agent 运行,则基于 workflow-run 的调用会跳过。运行时,它会审查从上一个未被跳过的 Docs Agent 源 SHA 到当前 `main` 的提交范围,因此每小时一次运行即可覆盖自上次文档处理以来累积到 `main` 的全部变更。 -`Test Performance Agent` 工作流是一个事件驱动的 Codex 维护流程,用于处理慢测试。它没有纯定时调度:`main` 上成功的、非机器人推送 CI 运行可以触发它,但如果同一 UTC 日期已有另一个由工作流运行触发的调用已运行或正在运行,它会跳过。手动派发会绕过这一按日活动门禁。该流程会构建完整测试套件的分组 Vitest 性能报告,让 Codex 只进行小范围、保持覆盖率的测试性能修复,而不是大范围重构;随后重跑完整测试套件报告,并拒绝任何会降低基线通过测试数的更改。如果基线存在失败测试,Codex 只能修复明显的失败项,且 agent 处理后的完整测试套件报告必须通过,之后才会提交任何内容。当 `main` 在机器人推送落地前继续前进时,该流程会对已验证补丁执行 rebase、重跑 `pnpm check:changed` 并重试推送;有冲突的过期补丁会被跳过。它使用 GitHub 托管的 Ubuntu,因此 Codex action 可以与 docs agent 保持相同的 drop-sudo 安全姿态。 +`Test Performance Agent` 工作流是一个事件驱动的 Codex 维护通道,用于处理慢测试。它没有纯定时计划:`main` 上成功的非机器人 push CI 运行可以触发它,但如果当天 UTC 已有另一个基于 workflow-run 的调用已经运行或正在运行,它就会跳过。手动分发会绕过这一按天的活动门禁。该通道会构建一个完整测试套件的分组 Vitest 性能报告,让 Codex 仅进行小规模、保持覆盖率的测试性能修复,而不是大范围重构,然后重新运行完整测试套件报告,并拒绝任何导致通过基线测试数下降的变更。如果基线中有失败测试,Codex 只能修复明显失败项,并且代理运行后的完整测试套件报告必须通过,才会提交任何内容。当 `main` 在机器人推送落地前继续前进时,该通道会对已验证补丁进行变基,重新运行 `pnpm check:changed`,并重试推送;存在冲突的过时补丁会被跳过。它使用 GitHub 托管的 Ubuntu,以便 Codex action 能与 docs agent 保持相同的 drop-sudo 安全策略。 ```bash gh workflow run duplicate-after-merge.yml \ @@ -111,31 +111,31 @@ gh workflow run duplicate-after-merge.yml \ ## 作业概览 -| 作业 | 用途 | 运行时机 | +| 作业 | 目的 | 运行时机 | | -------------------------------- | -------------------------------------------------------------------------------------------- | ---------------------------------- | -| `preflight` | 检测是否仅为文档更改、已更改范围、已更改扩展,并构建 CI 清单 | 在所有非草稿推送和 PR 上始终运行 | -| `security-scm-fast` | 通过 `zizmor` 进行私钥检测和工作流审计 | 在所有非草稿推送和 PR 上始终运行 | -| `security-dependency-audit` | 针对 npm advisories 执行无依赖的生产 lockfile 审计 | 在所有非草稿推送和 PR 上始终运行 | -| `security-fast` | 快速安全作业所需的聚合作业 | 在所有非草稿推送和 PR 上始终运行 | -| `build-artifacts` | 构建 `dist/`、Control UI、构建产物检查以及可复用的下游产物 | 与 Node 相关的更改 | -| `checks-fast-core` | 快速 Linux 正确性流程,例如 bundled / plugin-contract / protocol 检查 | 与 Node 相关的更改 | -| `checks-fast-contracts-channels` | 分片的渠道契约检查,并提供稳定的聚合检查结果 | 与 Node 相关的更改 | -| `checks-node-extensions` | 覆盖整个扩展套件的完整内置插件测试分片 | 与 Node 相关的更改 | -| `checks-node-core-test` | Core Node 测试分片,不包括渠道、内置、契约和扩展流程 | 与 Node 相关的更改 | -| `check` | 分片后的主要本地门禁对应项:生产类型、lint、防护检查、测试类型和严格冒烟测试 | 与 Node 相关的更改 | -| `check-additional` | 架构、边界、扩展表面防护、包边界和 gateway-watch 分片 | 与 Node 相关的更改 | -| `build-smoke` | 已构建 CLI 冒烟测试和启动内存冒烟测试 | 与 Node 相关的更改 | -| `checks` | 已构建产物渠道测试的验证作业 | 与 Node 相关的更改 | -| `checks-node-compat-node22` | Node 22 兼容性构建和冒烟流程 | 用于发布的手动 CI 派发 | -| `check-docs` | 文档格式、lint 和断链检查 | 文档发生更改时 | -| `skills-python` | 面向 Python 支持的 Skills 的 Ruff + pytest | 与 Python Skills 相关的更改 | -| `checks-windows` | Windows 特定测试流程 | 与 Windows 相关的更改 | -| `macos-node` | 使用共享构建产物的 macOS TypeScript 测试流程 | 与 macOS 相关的更改 | -| `macos-swift` | macOS 应用的 Swift lint、构建和测试 | 与 macOS 相关的更改 | -| `android` | 两个 flavor 的 Android 单元测试,以及一个 debug APK 构建 | 与 Android 相关的更改 | -| `test-performance-agent` | 在可信活动之后进行每日 Codex 慢测试优化 | `main` 上的 CI 成功后或手动派发 | +| `preflight` | 检测是否仅有文档变更、已变更的范围、已变更的扩展,并构建 CI 清单 | 在所有非草稿 push 和 PR 上始终运行 | +| `security-scm-fast` | 通过 `zizmor` 进行私钥检测和工作流审计 | 在所有非草稿 push 和 PR 上始终运行 | +| `security-dependency-audit` | 针对 npm advisories 进行无依赖的生产 lockfile 审计 | 在所有非草稿 push 和 PR 上始终运行 | +| `security-fast` | 快速安全作业所需的聚合作业 | 在所有非草稿 push 和 PR 上始终运行 | +| `build-artifacts` | 构建 `dist/`、Control UI、构建产物检查,以及可复用的下游构件 | 与 Node 相关的变更 | +| `checks-fast-core` | 快速 Linux 正确性通道,例如 bundled / plugin-contract / protocol 检查 | 与 Node 相关的变更 | +| `checks-fast-contracts-channels` | 分片的渠道契约检查,并提供稳定的聚合检查结果 | 与 Node 相关的变更 | +| `checks-node-extensions` | 针对整个扩展套件的完整内置插件测试分片 | 与 Node 相关的变更 | +| `checks-node-core-test` | Core Node 测试分片,不包括渠道、内置、契约和扩展通道 | 与 Node 相关的变更 | +| `check` | 分片后的主要本地门禁等效项:生产类型、lint、防护项、测试类型和严格冒烟测试 | 与 Node 相关的变更 | +| `check-additional` | 架构、边界、扩展表面防护、包边界和 gateway-watch 分片 | 与 Node 相关的变更 | +| `build-smoke` | 已构建 CLI 冒烟测试和启动内存冒烟测试 | 与 Node 相关的变更 | +| `checks` | 已构建产物渠道测试的验证器 | 与 Node 相关的变更 | +| `checks-node-compat-node22` | Node 22 兼容性构建和冒烟通道 | 用于发布的手动 CI 分发 | +| `check-docs` | 文档格式、lint 和失效链接检查 | 文档发生变更时 | +| `skills-python` | 针对 Python 支持的 Skills 运行 Ruff + pytest | 与 Python Skills 相关的变更 | +| `checks-windows` | Windows 特定测试通道 | 与 Windows 相关的变更 | +| `macos-node` | 使用共享构建产物的 macOS TypeScript 测试通道 | 与 macOS 相关的变更 | +| `macos-swift` | macOS 应用的 Swift lint、构建和测试 | 与 macOS 相关的变更 | +| `android` | 两个 flavor 的 Android 单元测试,以及一个 debug APK 构建 | 与 Android 相关的变更 | +| `test-performance-agent` | 在受信任活动之后,每日由 Codex 执行慢测试优化 | `main` 上 CI 成功后或手动分发 | -手动 CI 派发运行的作业图与常规 CI 相同,但会强制开启所有范围流程:Linux Node 分片、内置插件分片、渠道契约、Node 22 兼容性、`check`、`check-additional`、构建冒烟、文档检查、Python Skills、Windows、macOS、Android 和 Control UI i18n。手动运行使用唯一的并发组,因此发布候选版本的完整测试套件不会因同一 ref 上的另一次推送或 PR 运行而被取消。可选的 `target_ref` 输入允许可信调用者在使用所选派发 ref 的工作流文件的同时,针对某个分支、标签或完整提交 SHA 运行该作业图。 +手动 CI 分发会运行与常规 CI 相同的作业图,但会强制开启所有受范围控制的通道:Linux Node 分片、内置插件分片、渠道契约、Node 22 兼容性、`check`、`check-additional`、构建冒烟测试、文档检查、Python Skills、Windows、macOS、Android,以及 Control UI i18n。手动运行使用唯一的并发组,因此某个发布候选版本的完整测试套件不会因为同一 ref 上的另一次 push 或 PR 运行而被取消。可选的 `target_ref` 输入允许受信任的调用方在所选分发 ref 的工作流文件基础上,针对某个分支、标签或完整提交 SHA 运行该作业图。 ```bash gh workflow run ci.yml --ref release/YYYY.M.D @@ -145,55 +145,54 @@ gh workflow run full-release-validation.yml --ref main -f ref= ## 快速失败顺序 -作业的排序方式是让低成本检查先失败,再决定是否运行高成本作业: +作业的排列顺序经过设计,以便让低成本检查先失败,再决定是否运行高成本作业: -1. `preflight` 决定哪些流程实际存在。`docs-scope` 和 `changed-scope` 逻辑是这个作业中的步骤,不是独立作业。 -2. `security-scm-fast`、`security-dependency-audit`、`security-fast`、`check`、`check-additional`、`check-docs` 和 `skills-python` 会快速失败,而不会等待更重的构建产物和平台矩阵作业。 -3. `build-artifacts` 会与快速 Linux 流程并行进行,这样下游消费者就能在共享构建准备好后立即开始。 -4. 更重的平台和运行时流程会在之后展开:`checks-fast-core`、`checks-fast-contracts-channels`、`checks-node-extensions`、`checks-node-core-test`、`checks`、`checks-windows`、`macos-node`、`macos-swift` 和 `android`。 +1. `preflight` 决定究竟存在哪些通道。`docs-scope` 和 `changed-scope` 逻辑是该作业内部的步骤,而不是独立作业。 +2. `security-scm-fast`、`security-dependency-audit`、`security-fast`、`check`、`check-additional`、`check-docs` 和 `skills-python` 会快速失败,而无需等待更重的构件和平台矩阵作业。 +3. `build-artifacts` 会与快速 Linux 通道并行运行,这样下游消费者就能在共享构建准备好后立刻开始。 +4. 之后会展开更重的平台和运行时通道:`checks-fast-core`、`checks-fast-contracts-channels`、`checks-node-extensions`、`checks-node-core-test`、`checks`、`checks-windows`、`macos-node`、`macos-swift` 和 `android`。 -范围逻辑位于 `scripts/ci-changed-scope.mjs`,并由 `src/scripts/ci-changed-scope.test.ts` 中的单元测试覆盖。 -手动派发会跳过 changed-scope 检测,并让 preflight 清单表现得像所有有范围限制的区域都发生了更改。 +范围逻辑位于 `scripts/ci-changed-scope.mjs`,并由 `src/scripts/ci-changed-scope.test.ts` 中的单元测试覆盖。手动分发会跳过 changed-scope 检测,并让 preflight 清单表现得像所有受范围控制的区域都发生了变更。 -CI 工作流编辑会验证 Node CI 作业图以及工作流 lint,但不会仅因自身更改就强制运行 Windows、Android 或 macOS 原生构建;这些平台流程仍然只针对对应平台源码更改运行。 +CI 工作流编辑会验证 Node CI 作业图以及工作流 lint,但不会仅因这些编辑就强制运行 Windows、Android 或 macOS 原生构建;这些平台通道仍然仅在对应平台源码发生变更时才会运行。 -仅涉及 CI 路由的编辑、特定的低成本 core-test fixture 编辑,以及范围很窄的插件契约辅助函数 / 测试路由编辑,会使用快速的仅 Node 清单路径:preflight、安全检查,以及单个 `checks-fast-core` 任务。当更改文件仅限于快速任务可直接覆盖的路由或辅助函数表面时,这一路径会避免运行 build artifacts、Node 22 兼容性、渠道契约、完整 core 分片、内置插件分片以及额外的防护矩阵。 +仅涉及 CI 路由的编辑、部分低成本 core-test 固件编辑,以及狭窄的插件契约辅助工具 / 测试路由编辑,会使用快速的仅 Node 清单路径:preflight、安全检查,以及单个 `checks-fast-core` 任务。当前变更文件仅限于该快速任务可直接覆盖的路由或辅助表面时,这一路径会跳过构建产物、Node 22 兼容性、渠道契约、完整 core 分片、内置插件分片,以及额外的防护矩阵。 -Windows Node 检查的范围仅限于 Windows 特定的进程 / 路径包装器、npm / pnpm / UI 运行器辅助函数、包管理器配置,以及执行该流程的 CI 工作流表面;不相关的源码、插件、install-smoke 和仅测试更改仍会留在 Linux Node 流程上,这样就不会为了已经由常规测试分片覆盖的内容去占用一个 16 vCPU 的 Windows worker。 +Windows Node 检查的范围仅限于 Windows 特定的进程 / 路径包装器、npm / pnpm / UI 运行器辅助工具、包管理器配置,以及执行该通道的 CI 工作流表面;不相关的源码、插件、install-smoke 和纯测试变更会保留在 Linux Node 通道上,这样就不会为了已被常规测试分片覆盖的内容而占用一个 16 vCPU 的 Windows worker。 -独立的 `install-smoke` 工作流通过其自身的 `preflight` 作业复用同一个范围脚本。它将冒烟覆盖拆分为 `run_fast_install_smoke` 和 `run_full_install_smoke`。对于拉取请求,Docker / package 表面、内置插件 package / manifest 更改,以及 Docker 冒烟作业所覆盖的 core 插件 / 渠道 / Gateway 网关 / Plugin SDK 表面,会运行快速路径。仅源码的内置插件更改、仅测试编辑以及仅文档编辑不会占用 Docker workers。快速路径会构建一次根 Dockerfile 镜像,检查 CLI,运行 agents delete shared-workspace CLI 冒烟测试,运行容器 `gateway-network` e2e,验证一个内置扩展 build arg,并在总命令超时 240 秒的限制下运行有边界的内置插件 Docker 配置文件,同时每个场景的 Docker 运行也分别受限。完整路径则保留 QR 包安装以及 installer Docker / update 覆盖,用于每晚定时运行、手动派发、工作流调用的发布检查,以及确实触及 installer / package / Docker 表面的拉取请求。推送到 `main`,包括合并提交,不会强制完整路径;当 changed-scope 逻辑在推送时请求完整覆盖,该工作流仍会保留快速 Docker 冒烟,而将完整 install smoke 留给每晚运行或发布验证。较慢的 Bun 全局安装 image-provider 冒烟由 `run_bun_global_install_smoke` 单独控制;它会在每晚调度以及发布检查工作流中运行,手动 `install-smoke` 派发也可以选择启用它,但拉取请求和 `main` 推送不会运行它。QR 和 installer Docker 测试保留各自面向安装的 Dockerfile。本地 `test:docker:all` 会预构建一个共享的 live-test 镜像,将 OpenClaw 仅打包一次为 npm tarball,并构建两个共享的 `scripts/e2e/Dockerfile` 镜像:一个是用于 installer / update / plugin-dependency 流程的裸 Node / Git 运行器,另一个是功能镜像,会将相同 tarball 安装到 `/app` 中,供常规功能流程使用。Docker 流程定义位于 `scripts/lib/docker-e2e-scenarios.mjs`,规划器逻辑位于 `scripts/lib/docker-e2e-plan.mjs`,运行器只执行所选计划。调度器会通过 `OPENCLAW_DOCKER_E2E_BARE_IMAGE` 和 `OPENCLAW_DOCKER_E2E_FUNCTIONAL_IMAGE` 为每个流程选择镜像,然后以 `OPENCLAW_SKIP_DOCKER_BUILD=1` 运行流程;可用 `OPENCLAW_DOCKER_ALL_PARALLELISM` 调整默认 main-pool 槽位数 10,用 `OPENCLAW_DOCKER_ALL_TAIL_PARALLELISM` 调整 provider 敏感的 tail-pool 槽位数 10。重型流程上限默认分别为 `OPENCLAW_DOCKER_ALL_LIVE_LIMIT=9`、`OPENCLAW_DOCKER_ALL_NPM_LIMIT=10` 和 `OPENCLAW_DOCKER_ALL_SERVICE_LIMIT=7`,这样 npm 安装和多服务流程就不会让 Docker 过度提交,而较轻流程仍能填满可用槽位。单个比实际限制更重的流程仍然可以从空池启动,然后在释放容量前独占运行。默认会将流程启动错开 2 秒,以避免本地 Docker daemon 出现 create storm;可通过 `OPENCLAW_DOCKER_ALL_START_STAGGER_MS=0` 或其他毫秒值覆盖。本地聚合流程会预检 Docker、移除过期的 OpenClaw E2E 容器、输出活跃流程状态、持久化流程耗时用于最长优先排序,并支持 `OPENCLAW_DOCKER_ALL_DRY_RUN=1` 以检查调度器。默认情况下,它会在首次失败后停止调度新的池化流程,并且每个流程都有一个 120 分钟的后备超时,可通过 `OPENCLAW_DOCKER_ALL_LANE_TIMEOUT_MS` 覆盖;选定的 live / tail 流程使用更严格的逐流程上限。`OPENCLAW_DOCKER_ALL_LANES=` 会运行精确的调度器流程,包括仅发布使用的流程如 `install-e2e`,以及拆分后的内置更新流程如 `bundled-channel-update-acpx`,同时跳过 cleanup smoke,以便智能体复现单个失败流程。可复用的 live / E2E 工作流会调用 `scripts/test-docker-all.mjs --plan-json`,以确定所需的 package、镜像类型、live 镜像、流程和凭证覆盖,然后由 `scripts/docker-e2e.mjs` 将该计划转换为 GitHub 输出和摘要。它会通过 `scripts/package-openclaw-for-docker.mjs` 打包 OpenClaw、下载当前运行的包产物,或从 `package_artifact_run_id` 下载包产物;验证 tarball 清单;当计划需要包安装型流程时,通过 Blacksmith 的 Docker layer cache 构建并推送带 package-digest 标签的 bare / functional GHCR Docker E2E 镜像;并复用提供的 `docker_e2e_bare_image` / `docker_e2e_functional_image` 输入或已有的 package-digest 镜像,而不是重新构建。`Package Acceptance` 工作流是高层级的包门禁:它从 npm、可信 `package_ref`、附带 SHA-256 的 HTTPS tarball,或之前的工作流产物中解析一个候选项,然后将这个单独的 `package-under-test` 产物传入可复用的 Docker E2E 工作流。它将 `workflow_ref` 与 `package_ref` 分开,以便当前验收逻辑可以验证较旧但可信的提交,而不必检出旧工作流代码。发布检查会针对目标 ref 运行 `package` 验收配置文件;该配置文件覆盖 package / update / plugin 契约,是大多数 Parallels package / update 覆盖的默认 GitHub 原生替代方案。发布路径 Docker 套件最多运行三个分块作业,并设置 `OPENCLAW_SKIP_DOCKER_BUILD=1`,这样每个分块只拉取自己所需的镜像类型,并通过同一个带权重的调度器执行多个流程(`OPENCLAW_DOCKER_ALL_PROFILE=release-path`、`OPENCLAW_DOCKER_ALL_CHUNK=core|package-update|plugins-integrations`)。当请求完整发布路径覆盖时,OpenWebUI 会并入 `plugins-integrations`,只有在仅派发 OpenWebUI 时才保留独立的 `openwebui` 分块。`plugins-integrations` 分块运行拆分后的 `bundled-channel-*` 和 `bundled-channel-update-*` 流程,而不是串行的一体化 `bundled-channel-deps` 流程。每个分块都会上传 `.artifacts/docker-tests/`,其中包含流程日志、耗时、`summary.json`、`failures.json`、阶段耗时、调度器计划 JSON、慢流程表,以及逐流程重跑命令。工作流的 `docker_lanes` 输入会针对准备好的镜像运行所选流程,而不是运行分块作业,这样失败流程的调试就被限制在一个有针对性的 Docker 作业内,并会为该次运行准备、下载或复用包产物;如果所选流程是 live Docker 流程,有针对性的作业会在本地为该次重跑构建 live-test 镜像。生成的每流程 GitHub 重跑命令在相关值存在时会包含 `package_artifact_run_id`、`package_artifact_name` 和准备好的镜像输入,因此失败流程可以复用失败运行中的完全相同的包和镜像。使用 `pnpm test:docker:rerun ` 可从 GitHub 运行下载 Docker 产物,并打印组合 / 每流程的定向重跑命令;使用 `pnpm test:docker:timings ` 可查看慢流程和阶段关键路径摘要。定时的 live / E2E 工作流每天运行完整的发布路径 Docker 套件。内置更新矩阵按更新目标拆分,以便重复的 npm update 和 Doctor 修复过程可以与其他内置检查一起分片运行。 +独立的 `install-smoke` 工作流也通过其自身的 `preflight` 作业复用同一个范围脚本。它将冒烟测试覆盖拆分为 `run_fast_install_smoke` 和 `run_full_install_smoke`。对于拉取请求,Docker / package 表面、内置插件 package / manifest 变更,以及 Docker 冒烟作业所覆盖的 core 插件 / 渠道 / Gateway 网关 / 插件 SDK 表面,会运行快速路径。仅源码级的内置插件变更、纯测试编辑和纯文档编辑不会占用 Docker worker。快速路径会构建一次根 Dockerfile 镜像、检查 CLI、运行 agents delete shared-workspace CLI 冒烟测试、运行 container gateway-network e2e、验证一个内置扩展 build arg,并在 240 秒的总命令超时限制内运行有界的内置插件 Docker 配置文件,同时对每个场景的 Docker 运行分别设置上限。完整路径会为夜间计划运行、手动分发、workflow-call 发布检查,以及真正触及 installer / package / Docker 表面的拉取请求保留 QR package install 和 installer Docker / update 覆盖。推送到 `main`,包括合并提交,不会强制走完整路径;当 changed-scope 逻辑会在 push 上请求完整覆盖时,该工作流会保留快速 Docker 冒烟测试,并将完整 install smoke 留给夜间任务或发布验证。较慢的 Bun 全局安装 image-provider 冒烟测试由 `run_bun_global_install_smoke` 单独控制;它会在夜间计划中运行,也会从发布检查工作流中运行,手动 `install-smoke` 分发也可以选择启用,但拉取请求和 `main` 推送不会运行它。QR 和 installer Docker 测试保留各自以安装为重点的 Dockerfile。本地 `test:docker:all` 会预构建一个共享的 live-test 镜像,将 OpenClaw 作为 npm tarball 打包一次,并构建两个共享的 `scripts/e2e/Dockerfile` 镜像:一个是裸 Node / Git 运行器,用于 installer / update / plugin-dependency 通道;另一个是功能镜像,会将同一个 tarball 安装到 `/app`,用于常规功能通道。Docker 通道定义位于 `scripts/lib/docker-e2e-scenarios.mjs`,规划逻辑位于 `scripts/lib/docker-e2e-plan.mjs`,运行器只执行所选计划。调度器会通过 `OPENCLAW_DOCKER_E2E_BARE_IMAGE` 和 `OPENCLAW_DOCKER_E2E_FUNCTIONAL_IMAGE` 为每个通道选择镜像,然后在 `OPENCLAW_SKIP_DOCKER_BUILD=1` 下运行通道;默认主池槽位数为 10,可通过 `OPENCLAW_DOCKER_ALL_PARALLELISM` 调整;对 provider 敏感的尾部池槽位数默认也是 10,可通过 `OPENCLAW_DOCKER_ALL_TAIL_PARALLELISM` 调整。重型通道上限默认分别为 `OPENCLAW_DOCKER_ALL_LIVE_LIMIT=9`、`OPENCLAW_DOCKER_ALL_NPM_LIMIT=10` 和 `OPENCLAW_DOCKER_ALL_SERVICE_LIMIT=7`,以避免 npm install 和多服务通道过度占用 Docker,同时让较轻的通道继续填满可用槽位。单个比有效上限更重的通道仍可在空池中启动,然后独占运行直到释放容量。默认情况下,通道启动会错开 2 秒,以避免本地 Docker 守护进程在创建阶段发生风暴;可通过 `OPENCLAW_DOCKER_ALL_START_STAGGER_MS=0` 或其他毫秒值覆盖。本地聚合运行会先执行 Docker 预检查、移除陈旧的 OpenClaw E2E 容器、输出活动通道状态、持久化通道耗时以便按最长优先排序,并支持使用 `OPENCLAW_DOCKER_ALL_DRY_RUN=1` 检查调度器。默认情况下,在首次失败后它会停止调度新的池化通道,并且每个通道都有一个 120 分钟的回退超时,可通过 `OPENCLAW_DOCKER_ALL_LANE_TIMEOUT_MS` 覆盖;部分选定的 live / tail 通道使用更紧的单通道上限。`OPENCLAW_DOCKER_ALL_LANES=` 会运行精确的调度器通道,包括仅发布使用的通道,例如 `install-e2e`,以及拆分后的内置更新通道,例如 `bundled-channel-update-acpx`,同时跳过清理冒烟步骤,以便智能体复现某个失败通道。可复用的 live / E2E 工作流会先通过 `scripts/test-docker-all.mjs --plan-json` 询问所需的软件包、镜像类型、live 镜像、通道以及凭证覆盖,然后 `scripts/docker-e2e.mjs` 会将该计划转换为 GitHub 输出和摘要。它会通过 `scripts/package-openclaw-for-docker.mjs` 打包 OpenClaw、下载当前运行的软件包构件,或从 `package_artifact_run_id` 下载软件包构件;验证 tarball 清单;在计划需要 package-installed 通道时,通过 Blacksmith 的 Docker 层缓存构建并推送带 package-digest 标签的 bare / functional GHCR Docker E2E 镜像;并在提供了 `docker_e2e_bare_image` / `docker_e2e_functional_image` 输入或已存在 package-digest 镜像时复用它们,而不是重新构建。`Package Acceptance` 工作流是高级包门禁:它会从 npm、受信任的 `package_ref`、带 SHA-256 的 HTTPS tarball,或先前工作流构件中解析一个候选项,然后将这个单一的 `package-under-test` 构件传递给可复用的 Docker E2E 工作流。它将 `workflow_ref` 与 `package_ref` 分离,以便当前验收逻辑可以验证较旧但受信任的提交,而无需检出旧的工作流代码。发布检查会针对目标 ref 运行 `package` 验收配置文件;该配置文件覆盖 package / update / 插件契约,是大多数 Parallels package / update 覆盖在 GitHub 原生环境中的默认替代方案。发布路径 Docker 套件最多运行三个分块作业,并设置 `OPENCLAW_SKIP_DOCKER_BUILD=1`,因此每个分块只会拉取其所需的镜像类型,并通过同一个加权调度器执行多个通道(`OPENCLAW_DOCKER_ALL_PROFILE=release-path`、`OPENCLAW_DOCKER_ALL_CHUNK=core|package-update|plugins-integrations`)。当完整发布路径覆盖请求包含 OpenWebUI 时,它会被合并进 `plugins-integrations`;只有在仅分发 OpenWebUI 时,才会保留独立的 `openwebui` 分块。`plugins-integrations` 分块运行拆分后的 `bundled-channel-*` 和 `bundled-channel-update-*` 通道,而不是串行的一体化 `bundled-channel-deps` 通道。每个分块都会上传 `.artifacts/docker-tests/`,其中包含通道日志、耗时、`summary.json`、`failures.json`、阶段耗时、调度器计划 JSON、慢通道表格,以及每个通道的重新运行命令。工作流的 `docker_lanes` 输入会针对已准备好的镜像运行所选通道,而不是运行这些分块作业,这样失败通道的调试就能限制在一个有针对性的 Docker 作业内,并为该次运行准备、下载或复用软件包构件;如果所选通道是 live Docker 通道,则该定向作业会为此次重跑在本地构建 live-test 镜像。生成的按通道 GitHub 重跑命令会在这些值存在时包含 `package_artifact_run_id`、`package_artifact_name` 和已准备镜像输入,因此失败通道可以复用失败运行中的完全相同的软件包和镜像。使用 `pnpm test:docker:rerun ` 可以从某个 GitHub 运行中下载 Docker 构件,并输出组合式 / 按通道的定向重跑命令;使用 `pnpm test:docker:timings ` 可以查看慢通道和阶段关键路径摘要。定时的 live / E2E 工作流每天运行完整的发布路径 Docker 套件。内置更新矩阵按更新目标拆分,以便重复的 npm update 和 doctor 修复过程可以与其他内置检查一起分片执行。 -本地 changed-lane 逻辑位于 `scripts/changed-lanes.mjs`,由 `scripts/check-changed.mjs` 执行。这个本地检查门禁在架构边界方面比宽泛的 CI 平台范围更严格:core 生产更改会运行 core prod 和 core test typecheck,以及 core lint / guards;core 仅测试更改只运行 core test typecheck 和 core lint;扩展生产更改会运行 extension prod 和 extension test typecheck,以及 extension lint;扩展仅测试更改会运行 extension test typecheck 和 extension lint。公共 Plugin SDK 或插件契约更改会扩展到 extension typecheck,因为扩展依赖这些 core 契约,但 Vitest 扩展全量测试仍然是显式的测试工作。仅发布元数据的版本提升会运行有针对性的版本 / 配置 / 根依赖检查。未知的根目录 / 配置更改会安全地回退到所有检查流程。 +本地 changed-lane 逻辑位于 `scripts/changed-lanes.mjs`,由 `scripts/check-changed.mjs` 执行。该本地检查门禁在架构边界方面比广义的 CI 平台范围更严格:core 生产变更会运行 core 生产和 core 测试 typecheck,以及 core lint / guards;core 纯测试变更仅运行 core 测试 typecheck 和 core lint;扩展生产变更会运行扩展生产和扩展测试 typecheck,以及扩展 lint;扩展纯测试变更会运行扩展测试 typecheck 和扩展 lint。公共插件 SDK 或插件契约变更会扩展到扩展 typecheck,因为扩展依赖这些 core 契约,但 Vitest 扩展全量测试属于显式测试工作。仅发布元数据的版本升级会运行定向的版本 / 配置 / 根依赖检查。未知的根目录 / 配置变更会以安全优先方式回退为运行所有检查通道。 -手动 CI 派发会运行 `checks-node-compat-node22` 作为发布候选版本的兼容性覆盖。常规拉取请求和 `main` 推送会跳过该流程,并让矩阵继续聚焦于 Node 24 测试 / 渠道流程。 +手动 CI 分发会运行 `checks-node-compat-node22`,作为发布候选版本的兼容性覆盖。常规拉取请求和 `main` 推送会跳过该通道,并让矩阵专注于 Node 24 测试 / 渠道通道。 -最慢的 Node 测试族已被拆分或重新平衡,以便每个作业都保持较小规模,同时不至于过度预留 runners:渠道契约以三个带权重的分片运行,内置插件测试在六个扩展 workers 之间做负载均衡,小型 core 单元流程被成对组合,auto-reply 作为四个平衡 worker 运行,并将 reply 子树拆分为 agent-runner、dispatch 以及 commands / state-routing 分片,而 agentic Gateway 网关 / 插件配置则分布到现有的仅源码 agentic Node 作业中,而不是等待构建产物。广泛的浏览器、QA、媒体和杂项插件测试使用各自专用的 Vitest 配置,而不是共享的插件兜底配置。扩展分片作业一次最多运行两个插件配置组,每组使用一个 Vitest worker,并配备更大的 Node heap,这样导入密集型的插件批次就不会产生额外的 CI 作业。广泛的 agents 流程使用共享的 Vitest 文件并行调度器,因为它主要受导入 / 调度限制,而不是由某个单独的慢测试文件主导。`runtime-config` 与 infra core-runtime 分片一起运行,以避免共享运行时分片承担尾部负载。包含模式分片会使用 CI 分片名称记录耗时条目,因此 `.artifacts/vitest-shard-timings.json` 可以区分整个配置和过滤后的分片。`check-additional` 将 package-boundary 的 compile / canary 工作保持在一起,并将运行时拓扑架构与 gateway watch 覆盖分开;边界防护分片会在一个作业内部并发运行其规模较小且彼此独立的防护检查。Gateway 网关 watch、渠道测试和 core support-boundary 分片会在 `dist/` 和 `dist-runtime/` 已构建完成后,于 `build-artifacts` 内部并发运行,保留它们原有的检查名称作为轻量验证作业,同时避免额外占用两个 Blacksmith workers 和第二条产物消费者队列。 +最慢的 Node 测试族会被拆分或平衡,以便每个作业都保持较小规模,同时避免过度预留运行器:渠道契约会作为三个加权分片运行,内置插件测试会在六个扩展 worker 之间平衡,小型 core 单元通道会成对组合,auto-reply 会作为四个平衡 worker 运行,其中 reply 子树会拆分为 agent-runner、dispatch 和 commands / state-routing 分片,而 agentic Gateway 网关 / 插件配置则会分布到现有的仅源码 agentic Node 作业中,而不是等待构建产物。广泛的浏览器、QA、媒体和杂项插件测试会使用它们各自专用的 Vitest 配置,而不是共享的插件兜底配置。扩展分片作业一次最多运行两个插件配置组,每组使用一个 Vitest worker,并配合更大的 Node 堆,这样导入密集的插件批次就不会产生额外的 CI 作业。广泛的 agents 通道使用共享的 Vitest 文件并行调度器,因为它主要受导入 / 调度支配,而不是由某个单独的慢测试文件主导。`runtime-config` 会与 infra core-runtime 分片一起运行,以避免共享运行时分片成为尾部瓶颈。include-pattern 分片会使用 CI 分片名称记录耗时条目,因此 `.artifacts/vitest-shard-timings.json` 可以区分完整配置和经过筛选的分片。`check-additional` 会将 package-boundary compile / canary 工作放在一起,并将运行时拓扑架构与 gateway watch 覆盖拆分开;boundary guard 分片会在同一个作业内并发运行其小型独立防护项。Gateway watch、渠道测试以及 core support-boundary 分片会在 `dist/` 和 `dist-runtime/` 已经构建完成后,于 `build-artifacts` 内部并发运行,保留它们原有的检查名称作为轻量验证作业,同时避免额外占用两个 Blacksmith worker 和第二个构件消费者队列。 -Android CI 会同时运行 `testPlayDebugUnitTest` 和 `testThirdPartyDebugUnitTest`,然后构建 Play debug APK。第三方 flavor 没有单独的源码集或 manifest;它的单元测试流程仍会在启用 SMS / call-log BuildConfig 标志的情况下编译该 flavor,同时避免在每次与 Android 相关的推送中重复打包 debug APK 作业。 +Android CI 会同时运行 `testPlayDebugUnitTest` 和 `testThirdPartyDebugUnitTest`,然后构建 Play debug APK。第三方 flavor 没有单独的源码集或 manifest;它的单元测试通道仍会使用 SMS / call-log BuildConfig 标志编译该 flavor,同时避免在每次与 Android 相关的推送中重复执行 debug APK 打包作业。 -当同一个 PR 或 `main` ref 上有新的推送到达时,GitHub 可能会将被取代的作业标记为 `cancelled`。除非同一 ref 的最新运行也失败,否则应将其视为 CI 噪声。聚合分片检查使用 `!cancelled() && always()`,因此它们仍会报告正常的分片失败,但不会在整个工作流已被取代后继续排队。 +当同一个 PR 或 `main` ref 上有更新的推送到达时,GitHub 可能会将被取代的作业标记为 `cancelled`。除非同一 ref 的最新运行也失败,否则应将其视为 CI 噪声。聚合分片检查使用 `!cancelled() && always()`,因此它们仍会正常报告分片失败,但不会在整个工作流已经被取代后继续排队。 -自动 CI 并发键已做版本化处理(`CI-v7-*`),这样 GitHub 端旧队列组中的僵尸任务就不会无限期阻塞较新的 main 运行。手动完整测试套件运行使用 `CI-manual-v1-*`,并且不会取消进行中的运行。 +自动 CI 并发键采用版本化形式(`CI-v7-*`),这样 GitHub 端旧队列组中的僵尸任务就不会无限期阻塞较新的 main 运行。手动完整套件运行使用 `CI-manual-v1-*`,并且不会取消正在进行中的运行。 ## 运行器 | 运行器 | 作业 | | -------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `ubuntu-24.04` | `preflight`、快速安全作业及其聚合(`security-scm-fast`、`security-dependency-audit`、`security-fast`)、快速 protocol / contract / bundled 检查、分片渠道契约检查、除 lint 外的 `check` 分片、`check-additional` 分片及聚合、Node 测试聚合验证作业、文档检查、Python Skills、workflow-sanity、labeler、auto-response;install-smoke 的 preflight 也使用 GitHub 托管 Ubuntu,这样 Blacksmith 矩阵就能更早排队 | +| `ubuntu-24.04` | `preflight`、快速安全作业及其聚合(`security-scm-fast`、`security-dependency-audit`、`security-fast`)、快速 protocol / contract / bundled 检查、分片渠道契约检查、除 lint 外的 `check` 分片、`check-additional` 分片及聚合、Node 测试聚合验证器、文档检查、Python Skills、workflow-sanity、labeler、auto-response;install-smoke preflight 也使用 GitHub 托管的 Ubuntu,以便 Blacksmith 矩阵能更早进入队列 | | `blacksmith-8vcpu-ubuntu-2404` | `build-artifacts`、build-smoke、Linux Node 测试分片、内置插件测试分片、`android` | -| `blacksmith-16vcpu-ubuntu-2404` | `check-lint`,它对 CPU 的敏感度仍然高到让 8 vCPU 得不偿失;install-smoke Docker 构建,此处 32 vCPU 的排队时间得不偿失 | +| `blacksmith-16vcpu-ubuntu-2404` | `check-lint`,它仍然对 CPU 足够敏感,以至于 8 vCPU 的成本高于节省;install-smoke Docker 构建,在那里 32 vCPU 的排队时间成本高于节省 | | `blacksmith-16vcpu-windows-2025` | `checks-windows` | | `blacksmith-6vcpu-macos-latest` | `openclaw/openclaw` 上的 `macos-node`;fork 会回退到 `macos-latest` | | `blacksmith-12vcpu-macos-latest` | `openclaw/openclaw` 上的 `macos-swift`;fork 会回退到 `macos-latest` | -## 本地对应命令 +## 本地等效命令 ```bash pnpm changed:lanes # 检查 origin/main...HEAD 的本地 changed-lane 分类器 -pnpm check:changed # 智能本地检查门禁:按边界流程运行 changed typecheck/lint/guards -pnpm check # 快速本地门禁:production tsgo + 分片 lint + 并行快速 guards +pnpm check:changed # 智能本地检查门禁:按边界通道运行 changed typecheck/lint/guards +pnpm check # 快速本地门禁:生产 tsgo + 分片 lint + 并行快速 guards pnpm check:test-types -pnpm check:timed # 同一门禁,但带各阶段耗时 +pnpm check:timed # 相同门禁,但包含各阶段耗时 pnpm build:strict-smoke pnpm check:architecture pnpm test:gateway:watch-regression @@ -201,12 +200,12 @@ pnpm test # Vitest 测试 pnpm test:changed # 低成本的智能 changed Vitest 目标 pnpm test:channels pnpm test:contracts:channels -pnpm check:docs # 文档格式 + lint + 断链检查 -pnpm build # 当 CI 的 artifact / build-smoke 流程相关时,构建 dist -pnpm ci:timings # 汇总最近一次 origin/main 推送 CI 运行 +pnpm check:docs # 文档格式 + lint + 失效链接 +pnpm build # 当 CI 构建产物 / build-smoke 通道相关时,构建 dist +pnpm ci:timings # 汇总最近一次 origin/main push CI 运行 pnpm ci:timings:recent # 比较最近成功的 main CI 运行 node scripts/ci-run-timings.mjs # 汇总总耗时、排队时间和最慢作业 -node scripts/ci-run-timings.mjs --latest-main # 忽略 issue / comment 噪声并选择 origin/main 推送 CI +node scripts/ci-run-timings.mjs --latest-main # 忽略 issue / comment 噪声并选择 origin/main push CI node scripts/ci-run-timings.mjs --recent 10 # 比较最近成功的 main CI 运行 pnpm test:perf:groups --full-suite --allow-failures --output .artifacts/test-perf/baseline-before.json pnpm test:perf:groups:compare .artifacts/test-perf/baseline-before.json .artifacts/test-perf/after-agent.json diff --git a/docs/zh-CN/cli/gateway.md b/docs/zh-CN/cli/gateway.md index 0dcf93e27..62caae0d4 100644 --- a/docs/zh-CN/cli/gateway.md +++ b/docs/zh-CN/cli/gateway.md @@ -1,28 +1,28 @@ --- read_when: - 从 CLI 运行 Gateway 网关(开发环境或服务器) - - 调试 Gateway 网关认证、绑定模式和连接性 + - 调试 Gateway 网关身份验证、绑定模式和连接性 - 通过 Bonjour 发现 Gateway 网关(本地 + 广域 DNS-SD) sidebarTitle: Gateway -summary: OpenClaw Gateway 网关 CLI(`openclaw gateway`)——运行、查询并发现 Gateway 网关 +summary: OpenClaw Gateway 网关 CLI(`openclaw gateway`)——运行、查询和发现 Gateway 网关 title: Gateway 网关 x-i18n: - generated_at: "2026-04-27T04:26:19Z" + generated_at: "2026-04-27T08:00:05Z" model: gpt-5.4 provider: openai - source_hash: 795d30511ad7a98093edfcfb862869349e1454d3e01f18dec7912cc2128934de + source_hash: 9c909e8f6e1fb56b612eb1a0826cd993626c9f65b1736924b33c95a37dc60d14 source_path: cli/gateway.md workflow: 15 --- -Gateway 网关是 OpenClaw 的 WebSocket 服务器(渠道、节点、会话、钩子)。本页中的子命令位于 `openclaw gateway …` 之下。 +Gateway 网关是 OpenClaw 的 WebSocket 服务器(渠道、节点、会话、钩子)。本页中的子命令都位于 `openclaw gateway …` 之下。 本地 mDNS + 广域 DNS-SD 设置。 - OpenClaw 如何通告和发现 Gateway 网关。 + OpenClaw 如何通告并发现 Gateway 网关。 顶层 Gateway 网关配置键。 @@ -45,31 +45,31 @@ openclaw gateway run - - 默认情况下,除非在 `~/.openclaw/openclaw.json` 中设置了 `gateway.mode=local`,否则 Gateway 网关会拒绝启动。对于临时 / 开发运行,请使用 `--allow-unconfigured`。 - - `openclaw onboard --mode local` 和 `openclaw setup` 预期会写入 `gateway.mode=local`。如果文件已存在但缺少 `gateway.mode`,应将其视为损坏或被覆盖的配置,并修复它,而不是隐式假定为本地模式。 - - 如果文件已存在且缺少 `gateway.mode`,Gateway 网关会将其视为可疑的配置损坏,并拒绝为你“猜测为 local”。 - - 未启用认证时,禁止绑定到 loopback 之外的地址(安全护栏)。 - - 在获得授权时,`SIGUSR1` 会触发进程内重启(`commands.restart` 默认启用;设置 `commands.restart: false` 可阻止手动重启,但 gateway 工具 / config apply / update 仍然允许)。 - - `SIGINT` / `SIGTERM` 处理程序会停止 gateway 进程,但不会恢复任何自定义终端状态。如果你使用 TUI 或 raw-mode 输入包装 CLI,请在退出前恢复终端。 + - 默认情况下,除非在 `~/.openclaw/openclaw.json` 中设置了 `gateway.mode=local`,否则 Gateway 网关会拒绝启动。临时 / 开发运行可使用 `--allow-unconfigured`。 + - `openclaw onboard --mode local` 和 `openclaw setup` 预期会写入 `gateway.mode=local`。如果文件存在但缺少 `gateway.mode`,应将其视为损坏或被覆盖的配置,并修复它,而不是默认隐式假定为本地模式。 + - 如果文件存在且缺少 `gateway.mode`,Gateway 网关会将其视为可疑的配置损坏,并拒绝为你“猜测为本地”。 + - 未启用身份验证时,禁止绑定到 loopback 之外的地址(安全护栏)。 + - 在获得授权时,`SIGUSR1` 会触发进程内重启(`commands.restart` 默认启用;设置 `commands.restart: false` 可阻止手动重启,但 gateway 工具 / 配置 apply/update 仍然允许)。 + - `SIGINT` / `SIGTERM` 处理器会停止 gateway 进程,但不会恢复任何自定义终端状态。如果你用 TUI 或 raw-mode 输入封装 CLI,请在退出前恢复终端。 ### 选项 - WebSocket 端口(默认值来自 config / env;通常为 `18789`)。 + WebSocket 端口(默认值来自配置 / 环境变量;通常为 `18789`)。 监听器绑定模式。 - 认证模式覆盖。 + 身份验证模式覆盖值。 - Token 覆盖(也会为该进程设置 `OPENCLAW_GATEWAY_TOKEN`)。 + 令牌覆盖值(也会为当前进程设置 `OPENCLAW_GATEWAY_TOKEN`)。 - 密码覆盖。 + 密码覆盖值。 从文件读取 gateway 密码。 @@ -81,10 +81,10 @@ openclaw gateway run 在关闭时重置 Tailscale serve / funnel 配置。 - 允许在配置中没有 `gateway.mode=local` 的情况下启动 gateway。仅绕过临时 / 开发引导的启动保护;不会写入或修复配置文件。 + 允许在配置中没有 `gateway.mode=local` 的情况下启动 gateway。仅用于临时 / 开发引导,绕过启动保护;不会写入或修复配置文件。 - 如果缺失,则创建开发配置 + 工作区(跳过 `BOOTSTRAP.md`)。 + 如果缺失,则创建开发配置 + 工作区(跳过 BOOTSTRAP.md)。 重置开发配置 + 凭证 + 会话 + 工作区(需要 `--dev`)。 @@ -99,7 +99,7 @@ openclaw gateway run 仅在控制台中显示 CLI 后端日志(并启用 stdout / stderr)。 - Websocket 日志样式。 + WebSocket 日志样式。 `--ws-log compact` 的别名。 @@ -117,8 +117,8 @@ openclaw gateway run ### 启动性能分析 -- 设置 `OPENCLAW_GATEWAY_STARTUP_TRACE=1`,以在 Gateway 网关启动期间记录各阶段耗时。 -- 运行 `pnpm test:startup:gateway -- --runs 5 --warmup 1` 以对 Gateway 网关启动进行基准测试。该基准测试会记录首次进程输出、`/healthz`、`/readyz` 和启动跟踪耗时。 +- 设置 `OPENCLAW_GATEWAY_STARTUP_TRACE=1`,可在 Gateway 网关启动期间记录各阶段耗时,包括每个阶段的 `eventLoopMax` 延迟,以及 installed-index、manifest registry、startup planning 和 owner-map 工作中的插件查找表耗时。 +- 运行 `pnpm test:startup:gateway -- --runs 5 --warmup 1` 以对 Gateway 网关启动进行基准测试。该基准会记录首个进程输出、`/healthz`、`/readyz`、启动跟踪耗时、事件循环延迟,以及插件查找表耗时详情。 ## 查询正在运行的 Gateway 网关 @@ -127,12 +127,12 @@ openclaw gateway run - 默认:人类可读(在 TTY 中带颜色)。 - - `--json`:机器可读的 JSON(无样式 / 无 spinner)。 + - `--json`:机器可读 JSON(无样式 / 无 spinner)。 - `--no-color`(或 `NO_COLOR=1`):禁用 ANSI,同时保留人类可读布局。 - `--url `:Gateway 网关 WebSocket URL。 - - `--token `:Gateway 网关 token。 + - `--token `:Gateway 网关令牌。 - `--password `:Gateway 网关密码。 - `--timeout `:超时 / 预算(因命令而异)。 - `--expect-final`:等待“final”响应(智能体调用)。 @@ -140,7 +140,7 @@ openclaw gateway run -当你设置 `--url` 时,CLI 不会回退到配置或环境凭证。请显式传递 `--token` 或 `--password`。缺少显式凭证会报错。 +设置 `--url` 时,CLI 不会回退使用配置或环境变量中的凭证。请显式传入 `--token` 或 `--password`。缺少显式凭证会报错。 ### `gateway health` @@ -149,11 +149,11 @@ openclaw gateway run openclaw gateway health --url ws://127.0.0.1:18789 ``` -HTTP `/healthz` 端点是存活探针:一旦服务器可以响应 HTTP,它就会返回。HTTP `/readyz` 端点更严格,在启动 sidecar、渠道或已配置钩子仍在稳定之前会一直保持红色状态。 +HTTP `/healthz` 端点是存活探针:一旦服务器可以响应 HTTP,它就会返回。HTTP `/readyz` 端点更严格,在启动 sidecar、渠道或已配置钩子仍在稳定期间会持续显示为未就绪。 ### `gateway usage-cost` -从会话日志中获取 usage-cost 摘要。 +从会话日志中获取 usage-cost 汇总。 ```bash openclaw gateway usage-cost @@ -167,7 +167,7 @@ openclaw gateway usage-cost --json ### `gateway stability` -从正在运行的 Gateway 网关获取最近的诊断稳定性记录器数据。 +从正在运行的 Gateway 网关获取最近的诊断稳定性记录器内容。 ```bash openclaw gateway stability @@ -178,7 +178,7 @@ openclaw gateway stability --json ``` - 要包含的最近事件最大数量(最大为 `1000`)。 + 要包含的最近事件的最大数量(最大为 `1000`)。 按诊断事件类型筛选,例如 `payload.large` 或 `diagnostic.memory.pressure`。 @@ -187,7 +187,7 @@ openclaw gateway stability --json 仅包含某个诊断序列号之后的事件。 - 读取持久化的稳定性 bundle,而不是调用正在运行的 Gateway 网关。对状态目录下最新的 bundle 使用 `--bundle latest`(或直接 `--bundle`),或者直接传入 bundle JSON 路径。 + 读取持久化的稳定性 bundle,而不是调用正在运行的 Gateway 网关。对状态目录下最新的 bundle 使用 `--bundle latest`(或仅 `--bundle`),或直接传入 bundle JSON 路径。 写出一个可共享的支持诊断 zip,而不是打印稳定性详情。 @@ -198,14 +198,14 @@ openclaw gateway stability --json - - 记录会保留运维元数据:事件名称、计数、字节大小、内存读数、队列 / 会话状态、渠道 / 插件名称,以及已脱敏的会话摘要。它们不会保留聊天文本、webhook 正文、工具输出、原始请求或响应正文、token、cookie、secret 值、主机名或原始会话 id。设置 `diagnostics.enabled: false` 可完全禁用记录器。 - - 在 Gateway 网关发生致命退出、关闭超时和重启启动失败时,如果记录器中有事件,OpenClaw 会将相同的诊断快照写入 `~/.openclaw/logs/stability/openclaw-stability-*.json`。使用 `openclaw gateway stability --bundle latest` 检查最新 bundle;`--limit`、`--type` 和 `--since-seq` 也适用于 bundle 输出。 + - 记录会保留运维元数据:事件名称、计数、字节大小、内存读数、队列 / 会话状态、渠道 / 插件名称以及已脱敏的会话摘要。它们不会保留聊天文本、webhook 正文、工具输出、原始请求或响应正文、令牌、cookie、秘密值、主机名或原始会话 ID。将 `diagnostics.enabled: false` 设为关闭,可完全禁用该记录器。 + - 在 Gateway 网关发生致命退出、关闭超时和重启启动失败时,如果记录器中有事件,OpenClaw 会将相同的诊断快照写入 `~/.openclaw/logs/stability/openclaw-stability-*.json`。可使用 `openclaw gateway stability --bundle latest` 检查最新 bundle;`--limit`、`--type` 和 `--since-seq` 同样适用于 bundle 输出。 ### `gateway diagnostics export` -写出一个本地诊断 zip,专门用于附加到 bug 报告。有关隐私模型和 bundle 内容,请参阅 [Diagnostics Export](/zh-CN/gateway/diagnostics)。 +写出一个本地诊断 zip,设计用于附加到 bug 报告。有关隐私模型和 bundle 内容,请参见 [Diagnostics Export](/zh-CN/gateway/diagnostics)。 ```bash openclaw gateway diagnostics export @@ -214,10 +214,10 @@ openclaw gateway diagnostics export --json ``` - 输出 zip 路径。默认是在状态目录下生成一个支持导出文件。 + 输出 zip 路径。默认为状态目录下的支持导出文件。 - 要包含的最大已脱敏日志行数。 + 要包含的已脱敏日志行最大数量。 要检查的最大日志字节数。 @@ -226,28 +226,28 @@ openclaw gateway diagnostics export --json 用于健康快照的 Gateway 网关 WebSocket URL。 - 用于健康快照的 Gateway 网关 token。 + 用于健康快照的 Gateway 网关令牌。 用于健康快照的 Gateway 网关密码。 - Status / health 快照超时。 + Status / 健康快照超时。 跳过持久化稳定性 bundle 查找。 - 以 JSON 格式打印写入路径、大小和清单。 + 以 JSON 打印写入路径、大小和清单。 -导出内容包括清单、Markdown 摘要、配置形状、已脱敏的配置详情、已脱敏的日志摘要、已脱敏的 Gateway 网关 status / health 快照,以及存在时的最新稳定性 bundle。 +该导出包含清单、Markdown 摘要、配置结构、已脱敏配置详情、已脱敏日志摘要、已脱敏 Gateway 网关状态 / 健康快照,以及存在时的最新稳定性 bundle。 -它旨在用于共享。它会保留有助于调试的运维细节,例如安全的 OpenClaw 日志字段、子系统名称、状态码、持续时间、已配置模式、端口、插件 id、提供商 id、非 secret 功能设置,以及已脱敏的运维日志消息。它会省略或脱敏聊天文本、webhook 正文、工具输出、凭证、cookie、账户 / 消息标识符、提示 / 指令文本、主机名和 secret 值。当类似 LogTape 风格的消息看起来像用户 / 聊天 / 工具负载文本时,导出仅保留“某条消息已省略”及其字节数。 +它旨在被共享。它会保留有助于调试的运维细节,例如安全的 OpenClaw 日志字段、子系统名称、状态码、持续时间、已配置模式、端口、插件 ID、提供商 ID、非机密功能设置以及已脱敏的运维日志消息。它会省略或脱敏聊天文本、webhook 正文、工具输出、凭证、cookie、账户 / 消息标识符、提示 / 指令文本、主机名和秘密值。当 LogTape 风格消息看起来像用户 / 聊天 / 工具负载文本时,导出只会保留“某条消息已被省略”及其字节计数。 ### `gateway status` -`gateway status` 显示 Gateway 网关服务(launchd / systemd / schtasks)以及可选的连接性 / 认证能力探测。 +`gateway status` 会显示 Gateway 网关服务(launchd / systemd / schtasks),以及可选的连接性 / 身份验证能力探测。 ```bash openclaw gateway status @@ -256,13 +256,13 @@ openclaw gateway status --require-rpc ``` - 添加一个显式探测目标。仍会探测已配置的远程目标和 localhost。 + 添加显式探测目标。仍会探测已配置的远程地址和 localhost。 - 用于探测的 token 认证。 + 用于探测的令牌身份验证。 - 用于探测的密码认证。 + 用于探测的密码身份验证。 探测超时。 @@ -280,19 +280,19 @@ openclaw gateway status --require-rpc - 即使本地 CLI 配置缺失或无效,`gateway status` 仍可用于诊断。 - - 默认的 `gateway status` 可证明服务状态、WebSocket 连接,以及握手时可见的认证能力。它不能证明读 / 写 / 管理操作。 - - 对于首次设备认证,诊断探针不会产生变更:如果已有缓存的设备 token,它会复用;但不会仅为了检查状态而创建新的 CLI 设备身份或只读设备配对记录。 - - `gateway status` 会在可能的情况下解析已配置的认证 SecretRef 以用于探测认证。 - - 如果在此命令路径中某个必需的认证 SecretRef 无法解析,当探测连接 / 认证失败时,`gateway status --json` 会报告 `rpc.authWarning`;请显式传递 `--token` / `--password`,或先解析 secret 来源。 - - 如果探测成功,则会抑制未解析的 auth-ref 警告,以避免误报。 - - 当监听中的服务本身还不够、你还需要读范围 RPC 调用也保持健康时,请在脚本和自动化中使用 `--require-rpc`。 - - `--deep` 会尽力扫描额外的 launchd / systemd / schtasks 安装。当检测到多个类似 gateway 的服务时,人类可读输出会打印清理提示,并警告大多数部署应当每台机器只运行一个 gateway。 - - 人类可读输出包含已解析的文件日志路径,以及 CLI 与服务的配置路径 / 有效性快照,以帮助诊断 profile 或状态目录漂移。 + - 默认的 `gateway status` 可证明服务状态、WebSocket 连接以及握手时可见的身份验证能力。它不能证明读 / 写 / 管理操作。 + - 对于首次设备身份验证,诊断探针不会产生变更:如果已有缓存的设备令牌,它会复用该令牌,但不会仅为了检查状态而创建新的 CLI 设备身份或只读设备配对记录。 + - `gateway status` 会在可能的情况下解析已配置的身份验证 SecretRef,用于探针身份验证。 + - 如果此命令路径中某个必需的身份验证 SecretRef 无法解析,且探针连接 / 身份验证失败,`gateway status --json` 会报告 `rpc.authWarning`;请显式传入 `--token` / `--password`,或先解析对应的 secret 来源。 + - 如果探针成功,为避免误报,未解析的 auth-ref 警告会被抑制。 + - 当仅有监听服务还不够、你还需要读作用域的 RPC 调用也保持健康时,请在脚本和自动化中使用 `--require-rpc`。 + - `--deep` 会尽力扫描额外的 launchd / systemd / schtasks 安装项。当检测到多个类似 gateway 的服务时,人类可读输出会打印清理提示,并警告大多数环境应每台机器仅运行一个 gateway。 + - 人类可读输出会包含解析后的文件日志路径,以及 CLI 与服务配置路径 / 有效性快照,以帮助诊断 profile 或状态目录漂移。 - - - 在 Linux systemd 安装中,服务认证漂移检查会同时读取 unit 中的 `Environment=` 和 `EnvironmentFile=` 值(包括 `%h`、带引号的路径、多个文件和可选的 `-` 文件)。 - - 漂移检查会使用合并后的运行时环境变量解析 `gateway.auth.token` SecretRef(优先使用服务命令环境变量,然后回退到进程环境变量)。 - - 如果 token 认证实际上未激活(显式 `gateway.auth.mode` 为 `password` / `none` / `trusted-proxy`,或 mode 未设置且 password 可能优先、并且没有任何 token 候选能胜出),则 token 漂移检查会跳过配置 token 解析。 + + - 在 Linux systemd 安装中,服务身份验证漂移检查会同时读取单元中的 `Environment=` 和 `EnvironmentFile=` 值(包括 `%h`、带引号的路径、多个文件以及可选的 `-` 文件)。 + - 漂移检查会使用合并后的运行时环境变量解析 `gateway.auth.token` SecretRef(优先使用服务命令环境变量,其次回退到进程环境变量)。 + - 如果令牌身份验证实际上未启用(显式 `gateway.auth.mode` 为 `password` / `none` / `trusted-proxy`,或 mode 未设置且 password 可能胜出,同时没有任何可能胜出的令牌候选值),则令牌漂移检查会跳过配置中的令牌解析。 @@ -301,16 +301,16 @@ openclaw gateway status --require-rpc `gateway probe` 是“调试一切”的命令。它始终会探测: - 你已配置的远程 gateway(如果已设置),以及 -- localhost(local loopback),**即使已配置远程地址也是如此**。 +- localhost(local loopback),**即使已配置远程地址**。 -如果你传递 `--url`,则会在这两者之前添加该显式目标。人类可读输出会将目标标记为: +如果你传入 `--url`,该显式目标会被添加到两者之前。人类可读输出会将目标标记为: - `URL(显式)` - `Remote(已配置)` 或 `Remote(已配置,未激活)` - `Local loopback` -如果有多个 gateway 可达,它会全部打印出来。当你使用隔离的 profile / 端口(例如 rescue bot)时支持多个 gateway,但大多数安装仍然只运行单个 gateway。 +如果有多个 gateway 可达,它会全部打印出来。当你使用隔离的 profile / 端口时,支持多个 gateway(例如 rescue bot),但大多数安装仍然只运行单个 gateway。 ```bash @@ -321,49 +321,49 @@ openclaw gateway probe --json - `Reachable: yes` 表示至少有一个目标接受了 WebSocket 连接。 - - `Capability: read-only|write-capable|admin-capable|pairing-pending|connect-only` 表示探针能够证明的认证能力。它与可达性是分开的。 - - `Read probe: ok` 表示读范围详情 RPC 调用(`health` / `status` / `system-presence` / `config.get`)也成功了。 - - `Read probe: limited - missing scope: operator.read` 表示连接成功,但读范围 RPC 受限。这会被报告为**降级**可达性,而不是完全失败。 - - 与 `gateway status` 一样,probe 会复用现有缓存的设备认证,但不会创建首次设备身份或配对状态。 - - 只有在所有被探测目标都不可达时,退出码才为非零。 + - `Capability: read-only|write-capable|admin-capable|pairing-pending|connect-only` 表示探针能够证明的身份验证能力。它与可达性是分开的。 + - `Read probe: ok` 表示读作用域的详情 RPC 调用(`health` / `status` / `system-presence` / `config.get`)也成功了。 + - `Read probe: limited - missing scope: operator.read` 表示连接成功,但读作用域 RPC 受限。它会被报告为**降级**可达性,而不是完全失败。 + - 与 `gateway status` 一样,probe 会复用现有缓存的设备身份验证,但不会创建首次设备身份或配对状态。 + - 仅当所有被探测目标都不可达时,退出码才为非零。 顶层: - `ok`:至少有一个目标可达。 - - `degraded`:至少有一个目标的详情 RPC 受到范围限制。 - - `capability`:在所有可达目标中观察到的最佳能力(`read_only`、`write_capable`、`admin_capable`、`pairing_pending`、`connected_no_operator_scope` 或 `unknown`)。 - - `primaryTargetId`:按以下顺序作为活动优胜者处理的最佳目标:显式 URL、SSH 隧道、已配置远程目标,然后是本地 loopback。 - - `warnings[]`:尽力而为的警告记录,包含 `code`、`message` 和可选的 `targetIds`。 - - `network`:从当前配置和主机网络派生出的本地 loopback / tailnet URL 提示。 - - `discovery.timeoutMs` 和 `discovery.count`:本次探测实际使用的设备发现预算 / 结果计数。 + - `degraded`:至少有一个目标的详情 RPC 因作用域限制而受限。 + - `capability`:所有可达目标中观测到的最佳能力(`read_only`、`write_capable`、`admin_capable`、`pairing_pending`、`connected_no_operator_scope` 或 `unknown`)。 + - `primaryTargetId`:按以下顺序选出的最佳活跃目标:显式 URL、SSH 隧道、已配置的远程目标,然后是 local loopback。 + - `warnings[]`:尽力生成的警告记录,包含 `code`、`message` 和可选的 `targetIds`。 + - `network`:根据当前配置和主机网络推导出的 local loopback / tailnet URL 提示。 + - `discovery.timeoutMs` 和 `discovery.count`:此次探测过程实际使用的设备发现预算 / 结果数量。 每个目标(`targets[].connect`): - - `ok`:在连接以及降级分类之后的可达性。 + - `ok`:连接后并经过降级分类后的可达性。 - `rpcOk`:完整详情 RPC 成功。 - - `scopeLimited`:由于缺少 operator 范围,详情 RPC 失败。 + - `scopeLimited`:详情 RPC 因缺少 operator 作用域而失败。 每个目标(`targets[].auth`): - - `role`:可用时,在 `hello-ok` 中报告的认证角色。 - - `scopes`:可用时,在 `hello-ok` 中报告的已授予范围。 - - `capability`:为该目标呈现的认证能力分类。 + - `role`:在可用时,由 `hello-ok` 报告的身份验证角色。 + - `scopes`:在可用时,由 `hello-ok` 报告的已授予作用域。 + - `capability`:该目标暴露出的身份验证能力分类。 - - `ssh_tunnel_failed`:SSH 隧道设置失败;命令已回退为直接探测。 - - `multiple_gateways`:有多个目标可达;除非你有意运行隔离的 profile(例如 rescue bot),否则这并不常见。 - - `auth_secretref_unresolved`:某个已配置的认证 SecretRef 无法为失败目标解析。 - - `probe_scope_limited`:WebSocket 连接成功,但读取探针因缺少 `operator.read` 而受限。 + - `ssh_tunnel_failed`:SSH 隧道建立失败;命令已回退为直接探测。 + - `multiple_gateways`:可达目标不止一个;除非你有意运行隔离的 profile(例如 rescue bot),否则这并不常见。 + - `auth_secretref_unresolved`:某个失败目标的已配置身份验证 SecretRef 无法解析。 + - `probe_scope_limited`:WebSocket 连接成功,但读探针因缺少 `operator.read` 而受限。 -#### 通过 SSH 连接远程目标(与 Mac 应用一致) +#### 通过 SSH 连接远程端(与 Mac 应用一致) -macOS 应用中的“Remote over SSH”模式使用本地端口转发,使远程 gateway(它可能仅绑定到 loopback)可以通过 `ws://127.0.0.1:` 访问。 +macOS 应用的“Remote over SSH”模式使用本地端口转发,使远程 gateway(其绑定地址可能仅为 loopback)可以通过 `ws://127.0.0.1:` 访问。 -等效的 CLI: +等效 CLI: ```bash openclaw gateway probe --ssh user@gateway-host @@ -376,7 +376,7 @@ openclaw gateway probe --ssh user@gateway-host 身份文件。 - 从已解析的设备发现端点中选择第一个发现的 gateway 主机作为 SSH 目标(`local.` 加上已配置的广域域名(如果有))。仅 TXT 的提示会被忽略。 + 从解析后的设备发现端点(`local.` 加上已配置的广域域名(如果有))中,选择第一个发现到的 gateway 主机作为 SSH 目标。仅 TXT 的提示会被忽略。 配置(可选,用作默认值): @@ -386,7 +386,7 @@ openclaw gateway probe --ssh user@gateway-host ### `gateway call ` -底层 RPC 辅助命令。 +底层 RPC 帮助工具。 ```bash openclaw gateway call status @@ -394,13 +394,13 @@ openclaw gateway call logs.tail --params '{"sinceMs": 60000}' ``` - 用于 params 的 JSON 对象字符串。 + 参数的 JSON 对象字符串。 Gateway 网关 WebSocket URL。 - Gateway 网关 token。 + Gateway 网关令牌。 Gateway 网关密码。 @@ -409,7 +409,7 @@ openclaw gateway call logs.tail --params '{"sinceMs": 60000}' 超时预算。 - 主要用于智能体风格的 RPC,这类 RPC 会在最终负载之前流式传输中间事件。 + 主要用于智能体风格的 RPC:在最终负载之前会先流式传输中间事件。 机器可读的 JSON 输出。 @@ -432,8 +432,7 @@ openclaw gateway uninstall ### 使用 wrapper 安装 当托管服务必须通过另一个可执行文件启动时,请使用 `--wrapper`,例如 -secret 管理器 shim 或 run-as 辅助程序。wrapper 会接收正常的 Gateway 网关参数,并 -负责最终使用这些参数执行 `openclaw` 或 Node。 +secret 管理器 shim 或 run-as helper。wrapper 会接收正常的 Gateway 网关参数,并负责最终使用这些参数执行 `openclaw` 或 Node。 ```bash cat > ~/.local/bin/openclaw-doppler <<'EOF' @@ -448,9 +447,8 @@ openclaw gateway restart ``` 你也可以通过环境变量设置 wrapper。`gateway install` 会验证该路径是 -一个可执行文件,将 wrapper 写入服务 `ProgramArguments`,并在服务环境中持久化 -`OPENCLAW_WRAPPER`,供后续强制重新安装、更新和 Doctor -修复使用。 +可执行文件,将 wrapper 写入服务的 `ProgramArguments`,并在服务环境中持久化 +`OPENCLAW_WRAPPER`,供后续强制重装、更新和 Doctor 修复使用。 ```bash OPENCLAW_WRAPPER="$HOME/.local/bin/openclaw-doppler" openclaw gateway install --force @@ -471,36 +469,36 @@ openclaw gateway restart - `gateway uninstall|start|stop|restart`:`--json` - - 使用 `gateway restart` 重启托管服务。不要将 `gateway stop` 和 `gateway start` 串联起来替代重启;在 macOS 上,`gateway stop` 会在停止之前有意禁用 LaunchAgent。 - - 生命周期命令接受 `--json` 以供脚本使用。 + - 使用 `gateway restart` 重启托管服务。不要把 `gateway stop` 和 `gateway start` 串联起来作为重启替代方案;在 macOS 上,`gateway stop` 会先有意禁用 LaunchAgent,然后再停止它。 + - 生命周期命令接受 `--json`,便于脚本调用。 - - - 当 token 认证需要 token 且 `gateway.auth.token` 由 SecretRef 管理时,`gateway install` 会验证 SecretRef 可解析,但不会将解析后的 token 持久化到服务环境元数据中。 - - 如果 token 认证需要 token,而已配置的 token SecretRef 无法解析,则安装会以封闭失败的方式终止,而不是持久化回退明文。 - - 对于 `gateway run` 的密码认证,优先使用 `OPENCLAW_GATEWAY_PASSWORD`、`--password-file` 或由 SecretRef 支持的 `gateway.auth.password`,而不是内联 `--password`。 - - 在推断认证模式下,仅 shell 中的 `OPENCLAW_GATEWAY_PASSWORD` 不会放宽安装的 token 要求;安装托管服务时,请使用持久配置(`gateway.auth.password` 或 config `env`)。 - - 如果同时配置了 `gateway.auth.token` 和 `gateway.auth.password`,而 `gateway.auth.mode` 未设置,则在显式设置 mode 之前会阻止安装。 + + - 当令牌身份验证需要令牌且 `gateway.auth.token` 由 SecretRef 管理时,`gateway install` 会验证 SecretRef 可解析,但不会将解析后的令牌持久化到服务环境元数据中。 + - 如果令牌身份验证需要令牌且已配置的令牌 SecretRef 无法解析,安装会以安全失败方式中止,而不是持久化回退的明文。 + - 对于 `gateway run` 的密码身份验证,优先使用 `OPENCLAW_GATEWAY_PASSWORD`、`--password-file` 或由 SecretRef 支持的 `gateway.auth.password`,不要使用内联 `--password`。 + - 在推断身份验证模式下,仅 shell 中的 `OPENCLAW_GATEWAY_PASSWORD` 不会放宽安装时的令牌要求;安装托管服务时,请使用持久配置(`gateway.auth.password` 或配置中的 `env`)。 + - 如果同时配置了 `gateway.auth.token` 和 `gateway.auth.password`,且 `gateway.auth.mode` 未设置,则在显式设置 mode 之前会阻止安装。 -## 发现 gateway(Bonjour) +## 发现 Gateway 网关(Bonjour) -`gateway discover` 会扫描 Gateway 网关 beacon(`_openclaw-gw._tcp`)。 +`gateway discover` 会扫描 Gateway 网关信标(`_openclaw-gw._tcp`)。 -- Multicast DNS-SD:`local.` -- Unicast DNS-SD(广域 Bonjour):选择一个域名(例如:`openclaw.internal.`),并设置 split DNS + DNS 服务器;参见 [Bonjour](/zh-CN/gateway/bonjour)。 +- 组播 DNS-SD:`local.` +- 单播 DNS-SD(广域 Bonjour):选择一个域名(例如:`openclaw.internal.`),并设置 split DNS + DNS 服务器;参见 [Bonjour](/zh-CN/gateway/bonjour)。 -只有启用了 Bonjour 设备发现(默认启用)的 gateway 才会通告该 beacon。 +只有启用了 Bonjour 设备发现的 gateway(默认启用)才会通告该信标。 -广域发现记录包括(TXT): +广域发现记录包含(TXT): - `role`(gateway 角色提示) - `transport`(传输提示,例如 `gateway`) - `gatewayPort`(WebSocket 端口,通常为 `18789`) -- `sshPort`(可选;缺失时,客户端默认 SSH 目标端口为 `22`) +- `sshPort`(可选;缺失时客户端默认 SSH 目标端口为 `22`) - `tailnetDns`(可用时的 MagicDNS 主机名) -- `gatewayTls` / `gatewayTlsSha256`(TLS 是否启用 + 证书指纹) -- `cliPath`(写入广域区域的远程安装提示) +- `gatewayTls` / `gatewayTlsSha256`(是否启用 TLS + 证书指纹) +- `cliPath`(写入广域 zone 的远程安装提示) ### `gateway discover` @@ -523,9 +521,9 @@ openclaw gateway discover --json | jq '.beacons[].wsUrl' ``` -- CLI 会扫描 `local.` 以及已配置的广域域名(如果已启用)。 -- JSON 输出中的 `wsUrl` 派生自已解析的服务端点,而不是 `lanHost` 或 `tailnetDns` 之类仅 TXT 的提示。 -- 在 `local.` mDNS 上,只有当 `discovery.mdns.mode` 为 `full` 时,才会广播 `sshPort` 和 `cliPath`。广域 DNS-SD 仍会写入 `cliPath`;`sshPort` 在那里同样保持可选。 +- CLI 会扫描 `local.`,以及启用时已配置的广域域名。 +- JSON 输出中的 `wsUrl` 是从解析后的服务端点推导出来的,而不是来自仅 TXT 的提示,例如 `lanHost` 或 `tailnetDns`。 +- 在 `local.` mDNS 上,仅当 `discovery.mdns.mode` 为 `full` 时,才会广播 `sshPort` 和 `cliPath`。广域 DNS-SD 仍会写入 `cliPath`;`sshPort` 在那里也仍然是可选的。 ## 相关内容 diff --git a/docs/zh-CN/cli/migrate.md b/docs/zh-CN/cli/migrate.md new file mode 100644 index 000000000..39b4fe6a6 --- /dev/null +++ b/docs/zh-CN/cli/migrate.md @@ -0,0 +1,82 @@ +--- +read_when: + - 你想从 Hermes 或另一个智能体系统迁移到 OpenClaw】【。 + - 你正在添加一个由插件拥有的迁移提供商】【。 +summary: 从另一个智能体系统导入状态的 CLI 参考 +title: 迁移 +x-i18n: + generated_at: "2026-04-27T08:00:10Z" + model: gpt-5.4 + provider: openai + source_hash: 3efe1f29ae0e7832b7a349f2260e6934990d09ca74a16b73b31350613e2f77aa + source_path: cli/migrate.md + workflow: 15 +--- + +# `openclaw migrate` + +通过由插件拥有的迁移提供商,从另一个智能体系统导入状态。 + +```bash +openclaw migrate list +openclaw migrate hermes --dry-run +openclaw migrate hermes +openclaw migrate apply hermes --yes +openclaw migrate apply hermes --include-secrets --yes +openclaw onboard --flow import +openclaw onboard --import-from hermes --import-source ~/.hermes +``` + +## 安全模型 + +`openclaw migrate` 采用“预览优先”模式。提供商会在任何更改发生前返回一份逐项列出的计划,其中包括冲突、已跳过的项以及敏感项。JSON 计划、应用输出和迁移报告会对嵌套的疑似密钥字段进行脱敏,例如 API 密钥、令牌、授权头、cookie 和密码。 + +`openclaw migrate apply ` 会先预览计划,并在更改状态之前提示确认,除非设置了 `--yes`。在非交互模式下,apply 需要 `--yes`。使用 `--json` 且未设置 `--yes` 时,apply 会打印 JSON 计划,并且不会修改状态。 + +Apply 会在执行迁移之前创建并验证一个 OpenClaw 备份。如果本地尚不存在 OpenClaw 状态,则会跳过备份步骤,迁移仍可继续。若在状态已存在时跳过备份,请同时传入 `--no-backup` 和 `--force`。 + +当计划中存在冲突时,Apply 模式会拒绝继续执行。请先查看计划,然后在确实有意替换现有目标时,使用 `--overwrite` 重新运行。对于被覆盖的文件,提供商仍可能在迁移报告目录中写入逐项备份。 + +默认情况下绝不会导入密钥。使用 `--include-secrets` 以导入受支持的凭证。 + +## Hermes + +内置的 Hermes 提供商默认会在 `~/.hermes` 检测 Hermes 状态。如果 Hermes 位于其他位置,请使用 `--from `。 + +Hermes 迁移可导入: + +- `config.yaml` 中的默认模型配置 +- `providers` 和 `custom_providers` 中已配置的模型提供商及自定义 OpenAI 兼容端点 +- `mcp_servers` 或 `mcp.servers` 中的 MCP 服务器定义 +- 将 `SOUL.md` 和 `AGENTS.md` 导入到 OpenClaw 智能体工作区 +- 通过追加到工作区 memory 文件,导入 `memories/MEMORY.md` 和 `memories/USER.md` +- OpenClaw 文件 memory 的 memory 配置默认值,以及针对 Honcho 等外部 memory 提供商的仅归档 / 需手动审核项 +- 来自 `skills//` 且带有 `SKILL.md` 文件的 Skills +- 来自 `skills.config` 的按 Skill 划分的配置值 +- 来自 `.env` 的受支持 API 密钥,仅在使用 `--include-secrets` 时导入 + +仅归档的 Hermes 状态会被复制到迁移报告中,供手动审核,但不会载入到在线的 OpenClaw 配置或凭证中。这会保留不透明或不安全的状态,例如 `plugins/`、`sessions/`、`logs/`、`cron/`、`mcp-tokens/`、`auth.json` 和 `state.db`,而不会假装 OpenClaw 可以自动执行或信任它们。 + +受支持的 Hermes `.env` 键包括 `OPENAI_API_KEY`、`ANTHROPIC_API_KEY`、`OPENROUTER_API_KEY`、`GOOGLE_API_KEY`、`GEMINI_API_KEY`、`GROQ_API_KEY`、`XAI_API_KEY`、`MISTRAL_API_KEY` 和 `DEEPSEEK_API_KEY`。 + +应用迁移后,请运行: + +```bash +openclaw doctor +``` + +## 插件契约 + +迁移源是插件。插件会在 `openclaw.plugin.json` 中声明其提供商 id: + +```json +{ + "contracts": { + "migrationProviders": ["hermes"] + } +} +``` + +在运行时,插件会调用 `api.registerMigrationProvider(...)`。该提供商实现 `detect`、`plan` 和 `apply`;核心负责 CLI 编排、备份策略、提示、JSON 输出和冲突预检。核心会将审核后的计划传入 `apply(ctx, plan)`,而提供商仅可在该参数缺失时重新构建计划,以保持兼容性。提供商插件可以使用 `openclaw/plugin-sdk/migration` 进行条目构造和汇总计数,也可以使用 `openclaw/plugin-sdk/migration-runtime` 进行具备冲突感知的文件复制、仅归档报告复制和迁移报告处理。 + +当某个提供商检测到已知来源时,新手引导也可以提供迁移。`openclaw onboard --flow import` 和 `openclaw setup --wizard --import-from hermes` 使用相同的插件迁移提供商,并且在应用前仍会显示预览。新手引导导入要求使用全新的 OpenClaw 设置;如果你已经有本地状态,请先重置配置、凭证、会话和工作区。对于现有设置,带备份以及覆盖或合并的导入目前受功能开关控制。 diff --git a/docs/zh-CN/cli/onboard.md b/docs/zh-CN/cli/onboard.md index e1e4e7216..ecef830a0 100644 --- a/docs/zh-CN/cli/onboard.md +++ b/docs/zh-CN/cli/onboard.md @@ -1,13 +1,13 @@ --- read_when: - - 你想通过引导式设置来配置网关、工作区、凭证、渠道和 Skills -summary: '`openclaw onboard` 的 CLI 参考(交互式新手引导)' + - 你希望通过引导式设置来配置 Gateway 网关、工作区、凭证、渠道和 Skills。 +summary: '`openclaw onboard`(交互式新手引导)的 CLI 参考' title: 新手引导 x-i18n: - generated_at: "2026-04-27T04:37:31Z" + generated_at: "2026-04-27T08:00:02Z" model: gpt-5.4 provider: openai - source_hash: 98985c119f64ba41ed1a74fbb0bf1feb78b3c5daa4844e66f3aa1ae73ef6d0f5 + source_hash: 041063bce6616ed32225cb411f385dcbfd750c0bb2779ec17bc58e1aa9ada254 source_path: cli/onboard.md workflow: 15 --- @@ -23,10 +23,10 @@ x-i18n: 交互式 CLI 流程的演练说明。 - OpenClaw 新手引导如何协同工作。 + OpenClaw 的新手引导如何协同工作。 - 输出、内部机制以及每一步的行为。 + 输出、内部机制和各步骤行为。 非交互式标志和脚本化设置。 @@ -43,13 +43,20 @@ openclaw onboard openclaw onboard --modern openclaw onboard --flow quickstart openclaw onboard --flow manual +openclaw onboard --flow import +openclaw onboard --import-from hermes --import-source ~/.hermes openclaw onboard --skip-bootstrap openclaw onboard --mode remote --remote-url wss://gateway-host:18789 ``` -`--modern` 会启动 Crestodian 对话式新手引导预览。若不使用 `--modern`,`openclaw onboard` 将继续使用经典新手引导流程。 +`--flow import` 使用由插件拥有的迁移提供商,例如 Hermes。它仅适用于全新的 OpenClaw 设置;如果已存在配置、凭证、会话或工作区内存/身份文件,请在导入前重置或选择一个全新的设置。 -对于明文私有网络 `ws://` 目标(仅限受信任网络),请在新手引导进程环境中设置 `OPENCLAW_ALLOW_INSECURE_PRIVATE_WS=1`。此客户端传输层的紧急兜底选项没有对应的 `openclaw.json` 配置方式。 +`--modern` 会启动 Crestodian 对话式新手引导预览。不使用 +`--modern` 时,`openclaw onboard` 会保留经典的新手引导流程。 + +对于明文私有网络 `ws://` 目标(仅限受信任网络),请在新手引导进程环境中设置 +`OPENCLAW_ALLOW_INSECURE_PRIVATE_WS=1`。 +这种客户端传输层的紧急开关没有对应的 `openclaw.json` 配置项。 非交互式自定义提供商: @@ -65,7 +72,7 @@ openclaw onboard --non-interactive \ 在非交互式模式下,`--custom-api-key` 是可选的。如果省略,新手引导会检查 `CUSTOM_API_KEY`。 -LM Studio 在非交互式模式下也支持提供商专用的密钥标志: +LM Studio 在非交互式模式下也支持特定于提供商的密钥标志: ```bash openclaw onboard --non-interactive \ @@ -86,7 +93,7 @@ openclaw onboard --non-interactive \ --accept-risk ``` -`--custom-base-url` 默认为 `http://127.0.0.1:11434`。`--custom-model-id` 是可选的;如果省略,新手引导会使用 Ollama 建议的默认值。像 `kimi-k2.5:cloud` 这样的云端模型 ID 在这里也可用。 +`--custom-base-url` 默认值为 `http://127.0.0.1:11434`。`--custom-model-id` 是可选的;如果省略,新手引导会使用 Ollama 建议的默认值。诸如 `kimi-k2.5:cloud` 之类的云模型 ID 在这里也可用。 将提供商密钥存储为引用而不是明文: @@ -97,26 +104,26 @@ openclaw onboard --non-interactive \ --accept-risk ``` -使用 `--secret-input-mode ref` 时,新手引导会写入基于环境变量的引用,而不是明文密钥值。 -对于基于 auth-profile 的提供商,这会写入 `keyRef` 条目;对于自定义提供商,这会将 `models.providers..apiKey` 写为环境变量引用(例如 `{ source: "env", provider: "default", id: "CUSTOM_API_KEY" }`)。 +使用 `--secret-input-mode ref` 时,新手引导会写入由环境变量支持的引用,而不是明文密钥值。 +对于由 auth-profile 支持的提供商,这会写入 `keyRef` 条目;对于自定义提供商,这会将 `models.providers..apiKey` 写为环境变量引用(例如 `{ source: "env", provider: "default", id: "CUSTOM_API_KEY" }`)。 非交互式 `ref` 模式约定: - 在新手引导进程环境中设置提供商环境变量(例如 `OPENAI_API_KEY`)。 -- 不要传递内联密钥标志(例如 `--openai-api-key`),除非同时也设置了该环境变量。 -- 如果传递了内联密钥标志,但未设置所需的环境变量,新手引导会快速失败并提供指引。 +- 不要传递内联密钥标志(例如 `--openai-api-key`),除非该环境变量也已设置。 +- 如果传递了内联密钥标志但所需环境变量未设置,新手引导会快速失败并给出指引。 非交互式模式下的 Gateway 网关令牌选项: -- `--gateway-auth token --gateway-token ` 会存储明文令牌。 -- `--gateway-auth token --gateway-token-ref-env ` 会将 `gateway.auth.token` 存储为环境变量 SecretRef。 +- `--gateway-auth token --gateway-token ` 存储明文令牌。 +- `--gateway-auth token --gateway-token-ref-env ` 将 `gateway.auth.token` 存储为环境变量 SecretRef。 - `--gateway-token` 和 `--gateway-token-ref-env` 互斥。 -- `--gateway-token-ref-env` 要求在新手引导进程环境中存在非空环境变量。 -- 使用 `--install-daemon` 时,当令牌认证需要令牌时,由 SecretRef 管理的 Gateway 网关令牌会被验证,但不会以解析后的明文形式持久化到监督服务环境元数据中。 -- 使用 `--install-daemon` 时,如果令牌模式需要令牌,而已配置的令牌 SecretRef 无法解析,新手引导会以关闭失败的方式终止,并提供修复指引。 -- 使用 `--install-daemon` 时,如果同时配置了 `gateway.auth.token` 和 `gateway.auth.password`,且未设置 `gateway.auth.mode`,新手引导会阻止安装,直到显式设置 mode。 -- 本地新手引导会将 `gateway.mode="local"` 写入配置。如果后续某个配置文件缺少 `gateway.mode`,应将其视为配置损坏或不完整的手动编辑,而不是有效的本地模式快捷方式。 -- `--allow-unconfigured` 是单独的 Gateway 网关运行时紧急兜底选项。它并不表示新手引导可以省略 `gateway.mode`。 +- `--gateway-token-ref-env` 要求在新手引导进程环境中存在一个非空环境变量。 +- 使用 `--install-daemon` 时,当令牌认证需要令牌时,由 SecretRef 管理的 Gateway 网关令牌会被验证,但不会以已解析的明文形式持久化到 supervisor 服务环境元数据中。 +- 使用 `--install-daemon` 时,如果令牌模式需要令牌,而配置的令牌 SecretRef 未解析,新手引导会以安全关闭方式失败,并给出修复指引。 +- 使用 `--install-daemon` 时,如果同时配置了 `gateway.auth.token` 和 `gateway.auth.password`,但未设置 `gateway.auth.mode`,则在显式设置模式之前,新手引导会阻止安装。 +- 本地新手引导会将 `gateway.mode="local"` 写入配置。如果后续配置文件缺少 `gateway.mode`,应将其视为配置损坏或不完整的手动编辑,而不是有效的本地模式捷径。 +- `--allow-unconfigured` 是单独的 Gateway 网关运行时紧急开关。它并不表示新手引导可以省略 `gateway.mode`。 示例: @@ -132,25 +139,25 @@ openclaw onboard --non-interactive \ 非交互式本地 Gateway 网关健康检查: -- 除非你传入 `--skip-health`,否则新手引导会等待本地 Gateway 网关可访问后,才会成功退出。 -- `--install-daemon` 会先启动受管 Gateway 网关安装路径。不使用它时,你必须已经有一个正在运行的本地 Gateway 网关,例如 `openclaw gateway run`。 -- 如果你在自动化中只想写入 config/workspace/bootstrap,请使用 `--skip-health`。 -- 如果你自行管理工作区文件,请传入 `--skip-bootstrap` 以设置 `agents.defaults.skipBootstrap: true`,并跳过创建 `AGENTS.md`、`SOUL.md`、`TOOLS.md`、`IDENTITY.md`、`USER.md`、`HEARTBEAT.md` 和 `BOOTSTRAP.md`。 -- 在原生 Windows 上,`--install-daemon` 会先尝试 Scheduled Tasks;如果任务创建被拒绝,则回退到每用户 Startup 文件夹登录项。 +- 除非你传递 `--skip-health`,否则新手引导会在成功退出前等待本地 Gateway 网关可连接。 +- `--install-daemon` 会先启动受管的 Gateway 网关安装路径。如果不使用它,你必须已经有一个正在运行的本地 Gateway 网关,例如 `openclaw gateway run`。 +- 如果你只想在自动化中写入配置/工作区/bootstrap,请使用 `--skip-health`。 +- 如果你自行管理工作区文件,请传递 `--skip-bootstrap` 以设置 `agents.defaults.skipBootstrap: true`,并跳过创建 `AGENTS.md`、`SOUL.md`、`TOOLS.md`、`IDENTITY.md`、`USER.md`、`HEARTBEAT.md` 和 `BOOTSTRAP.md`。 +- 在原生 Windows 上,`--install-daemon` 会先尝试 Scheduled Tasks;如果任务创建被拒绝,则回退到按用户的 Startup 文件夹登录项。 使用引用模式时的交互式新手引导行为: -- 出现提示时,选择 **Use secret reference**。 -- 然后选择以下之一: - - Environment variable - - Configured secret provider (`file` 或 `exec`) -- 新手引导会在保存引用前执行快速预检验证。 +- 出现提示时,选择 **使用秘密引用**。 +- 然后选择以下其中之一: + - 环境变量 + - 已配置的秘密提供商(`file` 或 `exec`) +- 在保存该引用前,新手引导会执行快速预检验证。 - 如果验证失败,新手引导会显示错误并允许你重试。 ### 非交互式 Z.AI 端点选择 -`--auth-choice zai-api-key` 会为你的密钥自动检测最佳 Z.AI 端点(优先选择通用 API 和 `zai/glm-5.1`)。如果你明确想使用 GLM Coding Plan 端点,请选择 `zai-coding-global` 或 `zai-coding-cn`。 +`--auth-choice zai-api-key` 会自动为你的密钥检测最佳 Z.AI 端点(优先使用通用 API 和 `zai/glm-5.1`)。如果你明确想使用 GLM Coding Plan 端点,请选择 `zai-coding-global` 或 `zai-coding-cn`。 ```bash @@ -178,25 +185,27 @@ openclaw onboard --non-interactive \ - `quickstart`:最少提示,自动生成 Gateway 网关令牌。 - - `manual`:针对端口、绑定和认证的完整提示(`advanced` 的别名)。 + - `manual`:完整提示端口、绑定和认证(`advanced` 的别名)。 + - `import`:运行检测到的迁移提供商,预览计划,然后在确认后应用。 - 当某个认证选项意味着优先提供商时,新手引导会将默认模型和 allowlist 选择器预筛选到该提供商。对于 Volcengine 和 BytePlus(国际版),这也会匹配 coding-plan 变体(`volcengine-plan/*`、`byteplus-plan/*`)。 + 当某个认证选择暗示了首选提供商时,新手引导会将默认模型和 allowlist 选择器预筛选到该提供商。对于 Volcengine 和 BytePlus(国际版),这也会匹配 coding-plan 变体(`volcengine-plan/*`、`byteplus-plan/*`)。 - 如果优先提供商过滤后尚未得到任何已加载模型,新手引导会回退到未筛选的目录,而不是让选择器保持空白。 + 如果首选提供商筛选后尚未产生任何已加载模型,新手引导会回退到未筛选的目录,而不是让选择器保持为空。 - - 某些 Web 搜索提供商会触发提供商专用的后续提示: + + 某些 Web 搜索提供商会触发特定于提供商的后续提示: - - **Grok** 可以提供可选的 `x_search` 设置,使用相同的 `XAI_API_KEY` 和一个 `x_search` 模型选择。 - - **Kimi** 可以询问 Moonshot API 区域(`api.moonshot.ai` 与 `api.moonshot.cn`)以及默认的 Kimi Web 搜索模型。 + - **Grok** 可能会提供可选的 `x_search` 设置,使用相同的 `XAI_API_KEY` 和一个 `x_search` 模型选择。 + - **Kimi** 可能会询问 Moonshot API 区域(`api.moonshot.ai` 还是 `api.moonshot.cn`)以及默认的 Kimi Web 搜索模型。 - 本地新手引导的私信 范围行为:[CLI 设置参考](/zh-CN/start/wizard-cli-reference#outputs-and-internals)。 - - 最快开始首次聊天:`openclaw dashboard`(Control UI,无需渠道设置)。 + - 最快开始首次聊天:`openclaw dashboard`(Control UI,无需设置渠道)。 - 自定义提供商:连接任何兼容 OpenAI 或 Anthropic 的端点,包括未列出的托管提供商。使用 Unknown 可自动检测。 + - 如果检测到 Hermes 状态,新手引导会提供迁移流程。使用 [迁移](/zh-CN/cli/migrate) 获取 dry-run 计划、覆盖模式、报告和精确映射。 @@ -208,5 +217,5 @@ openclaw agents add ``` -`--json` 并不意味着非交互式模式。脚本中请使用 `--non-interactive`。 +`--json` 并不表示非交互式模式。脚本中请使用 `--non-interactive`。 diff --git a/docs/zh-CN/cli/setup.md b/docs/zh-CN/cli/setup.md index 8a8c3d6ae..ed9c58074 100644 --- a/docs/zh-CN/cli/setup.md +++ b/docs/zh-CN/cli/setup.md @@ -1,14 +1,14 @@ --- read_when: - - 你正在进行首次运行设置,而不执行完整的 CLI 新手引导 + - 你正在进行首次运行设置,但不使用完整的 CLI 新手引导 - 你想设置默认工作区路径 summary: '`openclaw setup` 的 CLI 参考(初始化配置 + 工作区)' title: 设置 x-i18n: - generated_at: "2026-04-24T04:01:28Z" + generated_at: "2026-04-27T08:00:03Z" model: gpt-5.4 provider: openai - source_hash: 650b0faf99ef1bc24ec6514661093a9a2ba7edead2e2622b863d51553c44f267 + source_hash: 68e5c07a6b1769420c2125677f3eda9bd4841c938b4fc62583c5bed2a2596250 source_path: cli/setup.md workflow: 15 --- @@ -28,6 +28,7 @@ x-i18n: openclaw setup openclaw setup --workspace ~/.openclaw/workspace openclaw setup --wizard +openclaw setup --wizard --import-from hermes --import-source ~/.hermes openclaw setup --non-interactive --mode remote --remote-url wss://gateway-host:18789 --remote-token ``` @@ -35,12 +36,15 @@ openclaw setup --non-interactive --mode remote --remote-url wss://gateway-host:1 - `--workspace `:智能体工作区目录(存储为 `agents.defaults.workspace`) - `--wizard`:运行新手引导 -- `--non-interactive`:无提示运行新手引导 +- `--non-interactive`:在无提示的情况下运行新手引导 - `--mode `:新手引导模式 +- `--import-from `:在新手引导期间运行的迁移提供商 +- `--import-source `:用于 `--import-from` 的源智能体主目录 +- `--import-secrets`:在新手引导迁移期间导入受支持的密钥 - `--remote-url `:远程 Gateway 网关 WebSocket URL - `--remote-token `:远程 Gateway 网关令牌 -通过 setup 运行新手引导: +要通过 setup 运行新手引导: ```bash openclaw setup --wizard @@ -49,9 +53,10 @@ openclaw setup --wizard 说明: - 普通的 `openclaw setup` 会初始化配置 + 工作区,而不会运行完整的新手引导流程。 -- 当存在任一新手引导标志时,会自动运行新手引导(`--wizard`、`--non-interactive`、`--mode`、`--remote-url`、`--remote-token`)。 +- 当存在任一新手引导标志时,会自动运行新手引导(`--wizard`、`--non-interactive`、`--mode`、`--import-from`、`--import-source`、`--import-secrets`、`--remote-url`、`--remote-token`)。 +- 如果检测到 Hermes 状态,交互式新手引导可以自动提供迁移选项。导入新手引导需要全新的设置;如需在新手引导之外使用试运行计划、备份和覆盖模式,请使用 [迁移](/zh-CN/cli/migrate)。 -## 相关内容 +## 相关 - [CLI 参考](/zh-CN/cli) - [安装概览](/zh-CN/install) diff --git a/docs/zh-CN/gateway/local-models.md b/docs/zh-CN/gateway/local-models.md index be5fdd3c1..a69da14e2 100644 --- a/docs/zh-CN/gateway/local-models.md +++ b/docs/zh-CN/gateway/local-models.md @@ -1,26 +1,26 @@ --- read_when: - - 你希望从自己的 GPU 主机提供模型服务 - - 你正在连接 LM Studio 或兼容 OpenAI 的代理 + - 你想从你自己的 GPU 机器提供模型服务 + - 你正在配置 LM Studio 或兼容 OpenAI 的代理 - 你需要最安全的本地模型使用指南 summary: 在本地 LLM 上运行 OpenClaw(LM Studio、vLLM、LiteLLM、自定义 OpenAI 端点) title: 本地模型 x-i18n: - generated_at: "2026-04-27T06:04:15Z" + generated_at: "2026-04-27T08:00:04Z" model: gpt-5.4 provider: openai - source_hash: 1fe9f5f7e3fc4f5660769fddef1f524b303d309f77551880cd74f3395286816c + source_hash: 4a42076e542448018eaf8633c18dfd290c822be502d78a135d03d138e9713668 source_path: gateway/local-models.md workflow: 15 --- -本地部署是可行的,但 OpenClaw 需要大上下文窗口以及针对提示注入的强防护。小显存显卡会截断上下文并削弱安全性。目标应尽量高:**至少 2 台满配 Mac Studio 或同等 GPU 主机(约 3 万美元以上)**。单张 **24 GB** GPU 仅适用于较轻的提示,并且延迟更高。请使用你能运行的**最大 / 完整尺寸模型变体**;激进量化或“小型”检查点会提高提示注入风险(参见[安全](/zh-CN/gateway/security))。 +本地部署是可行的,但 OpenClaw 需要大上下文窗口,并且要对提示注入有较强防御。小显卡会截断上下文,并削弱安全性。尽量提高配置:**至少 2 台满配 Mac Studio 或同等级 GPU 设备(约 3 万美元以上)**。单张 **24 GB** GPU 仅适用于较轻量的提示,且延迟更高。请使用**你能运行的最大 / 完整尺寸模型变体**;激进量化或“small”检查点会提高提示注入风险(参见 [Security](/zh-CN/gateway/security))。 -如果你想要最低摩擦的本地设置,请从 [LM Studio](/zh-CN/providers/lmstudio) 或 [Ollama](/zh-CN/providers/ollama) 和 `openclaw onboard` 开始。本页是面向更高端本地堆栈和自定义 OpenAI 兼容本地服务器的建议性指南。 +如果你想要摩擦最小的本地部署方式,先从 [LM Studio](/zh-CN/providers/lmstudio) 或 [Ollama](/zh-CN/providers/ollama) 和 `openclaw onboard` 开始。本页是面向更高端本地方案和自定义兼容 OpenAI 的本地服务器的带有明确倾向性的指南。 ## 推荐:LM Studio + 大型本地模型(Responses API) -当前最佳的本地堆栈。将大型模型加载到 LM Studio 中(例如完整尺寸的 Qwen、DeepSeek 或 Llama 构建),启用本地服务器(默认 `http://127.0.0.1:1234`),并使用 Responses API 将推理与最终文本分离。 +这是当前最佳的本地方案。在 LM Studio 中加载一个大型模型(例如完整尺寸的 Qwen、DeepSeek 或 Llama 构建),启用本地服务器(默认 `http://127.0.0.1:1234`),并使用 Responses API 以将推理过程与最终文本分离。 ```json5 { @@ -60,15 +60,15 @@ x-i18n: **设置检查清单** - 安装 LM Studio:[https://lmstudio.ai](https://lmstudio.ai) -- 在 LM Studio 中,下载**可用的最大模型构建**(避免 “small” / 重度量化变体),启动服务器,并确认 `http://127.0.0.1:1234/v1/models` 列出了该模型。 +- 在 LM Studio 中,下载**可用的最大模型构建**(避免使用 “small”/重度量化变体),启动服务器,并确认 `http://127.0.0.1:1234/v1/models` 能列出该模型。 - 将 `my-local-model` 替换为 LM Studio 中显示的实际模型 ID。 -- 保持模型已加载;冷加载会增加启动延迟。 -- 如果你的 LM Studio 构建不同,请调整 `contextWindow` / `maxTokens`。 +- 保持模型处于已加载状态;冷加载会增加启动延迟。 +- 如果你的 LM Studio 构建不同,请调整 `contextWindow`/`maxTokens`。 - 对于 WhatsApp,请坚持使用 Responses API,这样只会发送最终文本。 -即使在本地运行,也请保留托管模型配置;使用 `models.mode: "merge"`,这样回退模型仍然可用。 +即使在本地运行,也请保留已配置的托管模型;使用 `models.mode: "merge"` 以便回退模型仍然可用。 -### 混合配置:托管主模型,本地回退 +### 混合配置:托管模型为主,本地模型为回退 ```json5 { @@ -109,18 +109,18 @@ x-i18n: } ``` -### 本地优先,托管安全兜底 +### 本地优先,并保留托管安全兜底 -交换主模型和回退模型的顺序;保留相同的 provider 块和 `models.mode: "merge"`,这样当本地主机宕机时,你仍可回退到 Sonnet 或 Opus。 +交换主模型与回退模型的顺序;保留相同的 provider 配置块和 `models.mode: "merge"`,这样当本地设备宕机时,你仍可回退到 Sonnet 或 Opus。 ### 区域托管 / 数据路由 -- 托管的 MiniMax / Kimi / GLM 变体也存在于 OpenRouter 上,并提供区域固定端点(例如美国托管)。在那里选择对应区域变体,即可将流量保留在你选择的司法辖区内,同时仍使用 `models.mode: "merge"` 为 Anthropic / OpenAI 回退保留能力。 -- 纯本地仍然是最强的隐私路径;当你需要 provider 功能但又希望控制数据流向时,托管区域路由是中间方案。 +- 托管的 MiniMax/Kimi/GLM 变体在 OpenRouter 上也可用,并提供区域固定端点(例如托管于美国)。你可以在那里选择区域变体,以便在所选司法辖区内保留流量,同时仍然使用 `models.mode: "merge"` 为 Anthropic/OpenAI 回退保留支持。 +- 纯本地仍然是隐私性最强的路径;当你需要提供商功能但又希望控制数据流向时,托管的区域路由是折中方案。 -## 其他 OpenAI 兼容本地代理 +## 其他兼容 OpenAI 的本地代理 -如果 vLLM、LiteLLM、OAI-proxy 或自定义 Gateway 网关暴露的是 OpenAI 风格的 `/v1` 端点,它们就可以工作。将上面的 provider 块替换为你的端点和模型 ID: +vLLM、LiteLLM、OAI-proxy 或自定义 Gateway 网关 只要暴露出兼容 OpenAI 风格的 `/v1` 端点即可使用。将上面的 provider 配置块替换为你的端点和模型 ID: ```json5 { @@ -149,55 +149,36 @@ x-i18n: } ``` -保留 `models.mode: "merge"`,这样托管模型仍可作为回退使用。 -对于较慢的本地或远程模型 -服务器,请先使用 `models.providers..timeoutSeconds`,再考虑提高 `agents.defaults.timeoutSeconds`。provider 超时 -仅适用于模型 HTTP 请求,包括连接、响应头、正文流式传输 -以及整个受保护 fetch 的中止。 +请保留 `models.mode: "merge"`,这样托管模型仍可作为回退使用。 +对于较慢的本地或远程模型服务器,请使用 `models.providers..timeoutSeconds`,再考虑提高 `agents.defaults.timeoutSeconds`。provider 超时仅适用于模型 HTTP 请求,包括连接、响应头、正文流式传输,以及整个受保护抓取的中止超时。 关于本地 / 代理 `/v1` 后端的行为说明: -- OpenClaw 会将这些视为代理风格的 OpenAI 兼容路由,而不是原生 - OpenAI 端点 -- 原生 OpenAI 专用的请求整形不会在这里生效:没有 - `service_tier`、没有 Responses `store`、没有 OpenAI 推理兼容负载 - 整形,也没有提示缓存提示 -- 隐藏的 OpenClaw 归因请求头(`originator`、`version`、`User-Agent`) - 不会注入到这些自定义代理 URL 中 +- OpenClaw 会将这些视为代理风格的兼容 OpenAI 路由,而不是原生 OpenAI 端点 +- 仅适用于原生 OpenAI 的请求整形不会在这里生效:没有 `service_tier`,没有 Responses `store`,没有 OpenAI 推理兼容负载整形,也没有提示缓存提示 +- 隐藏的 OpenClaw 归因请求头(`originator`、`version`、`User-Agent`)不会注入到这些自定义代理 URL 中 -针对更严格的 OpenAI 兼容后端的兼容性说明: +针对更严格的兼容 OpenAI 后端的兼容性说明: -- 某些服务器在 Chat Completions 中只接受字符串形式的 `messages[].content`,而不接受 - 结构化内容分片数组。对于这些端点,请设置 - `models.providers..models[].compat.requiresStringContent: true`。 -- 某些较小或更严格的本地后端在面对 OpenClaw 完整的 - agent 运行时提示形态时不稳定,尤其是在包含工具 schema 时。如果后端 - 对极小的直接 `/v1/chat/completions` 调用可用,但在正常的 - OpenClaw 智能体轮次中失败,请先尝试 - `agents.defaults.experimental.localModelLean: true`,以移除重量级的 - 默认工具,如 `browser`、`cron` 和 `message`;这是一个实验性 - 标志,不是稳定的默认模式设置。参见 - [Experimental Features](/zh-CN/concepts/experimental-features)。如果这样仍然失败,再尝试 - `models.providers..models[].compat.supportsTools: false`。 -- 如果后端仍然只在更大的 OpenClaw 运行中失败,那么剩余问题 - 通常是上游模型 / 服务器容量不足或后端 bug,而不是 OpenClaw 的 - 传输层问题。 +- 某些服务器在 Chat Completions 中只接受字符串形式的 `messages[].content`,不接受结构化的内容片段数组。对于这些端点,请设置 `models.providers..models[].compat.requiresStringContent: true`。 +- 某些本地模型会以文本形式输出独立的方括号工具请求,例如 `[tool_name]`,后跟 JSON,再跟 `[END_TOOL_REQUEST]`。只有当该名称与当前轮次已注册工具完全匹配时,OpenClaw 才会将其提升为真实工具调用;否则该块会被视为不受支持的文本,并从面向用户的回复中隐藏。 +- 某些较小或更严格的本地后端在面对 OpenClaw 完整的智能体运行时提示结构时不稳定,尤其是在包含工具 schema 时。如果该后端可以处理极小的直接 `/v1/chat/completions` 调用,但在正常的 OpenClaw 智能体轮次中失败,请先尝试设置 `agents.defaults.experimental.localModelLean: true`,以移除像 `browser`、`cron` 和 `message` 这类重量级默认工具;这是一个实验性标志,不是稳定的默认模式设置。参见 [Experimental Features](/zh-CN/concepts/experimental-features)。如果这样仍然失败,再尝试 `models.providers..models[].compat.supportsTools: false`。 +- 如果后端仅在较大的 OpenClaw 运行中仍然失败,剩余问题通常是上游模型/服务器容量限制或后端 bug,而不是 OpenClaw 的传输层问题。 ## 故障排除 -- Gateway 网关能访问代理吗?`curl http://127.0.0.1:1234/v1/models`。 -- LM Studio 模型未加载?重新加载;冷启动是常见的“卡住”原因。 -- 当检测到的上下文窗口低于 **32k** 时,OpenClaw 会发出警告;低于 **16k** 时会阻止运行。如果你遇到这个预检,请提高服务器 / 模型的上下文限制,或选择更大的模型。 -- 上下文错误?降低 `contextWindow` 或提高你的服务器限制。 -- OpenAI 兼容服务器返回 `messages[].content ... expected a string`? - 在该模型条目上添加 `compat.requiresStringContent: true`。 -- 直接的小型 `/v1/chat/completions` 调用可用,但 `openclaw infer model run` - 在 Gemma 或其他本地模型上失败?先通过 - `compat.supportsTools: false` 禁用工具 schema,然后重新测试。如果服务器 - 仍然只在更大的 OpenClaw 提示上崩溃,请将其视为上游服务器 / 模型限制。 -- 安全性:本地模型会跳过 provider 侧过滤;请保持智能体范围收窄,并启用 compact,以限制提示注入的影响范围。 +- Gateway 网关 能连到代理吗?`curl http://127.0.0.1:1234/v1/models` +- LM Studio 模型已卸载?重新加载;冷启动是常见的“卡住”原因。 +- 当检测到的上下文窗口低于 **32k** 时,OpenClaw 会发出警告;低于 **16k** 时会阻止运行。如果你遇到这个预检,请提高服务器/模型的上下文限制,或选择更大的模型。 +- 出现上下文错误?降低 `contextWindow` 或提高你的服务器限制。 +- 兼容 OpenAI 的服务器返回 `messages[].content ... expected a string`? + 在该模型条目中添加 `compat.requiresStringContent: true`。 +- 直接的小型 `/v1/chat/completions` 调用可以工作,但 `openclaw infer model run` + 在 Gemma 或其他本地模型上失败?先用 + `compat.supportsTools: false` 禁用工具 schema,然后重新测试。如果服务器仍然只在更大的 OpenClaw 提示下崩溃,请将其视为上游服务器/模型限制。 +- 安全性:本地模型会跳过提供商侧过滤;请让智能体范围保持狭窄,并开启压缩,以限制提示注入的影响半径。 ## 相关内容 -- [配置参考](/zh-CN/gateway/configuration-reference) -- [模型故障转移](/zh-CN/concepts/model-failover) +- [Configuration reference](/zh-CN/gateway/configuration-reference) +- [Model failover](/zh-CN/concepts/model-failover) diff --git a/docs/zh-CN/help/testing.md b/docs/zh-CN/help/testing.md index 377bd7e34..f89bbeb61 100644 --- a/docs/zh-CN/help/testing.md +++ b/docs/zh-CN/help/testing.md @@ -3,22 +3,22 @@ read_when: - 在本地或 CI 中运行测试 - 为模型 / 提供商缺陷添加回归测试 - 调试 Gateway 网关 + 智能体行为 -summary: 测试工具包:单元 / e2e / 实时测试套件、Docker 运行器,以及每类测试涵盖的内容 +summary: 测试工具包:单元 / e2e / live 测试套件、Docker 运行器,以及各项测试的覆盖范围 title: 测试 x-i18n: - generated_at: "2026-04-27T06:21:51Z" + generated_at: "2026-04-27T08:00:04Z" model: gpt-5.4 provider: openai - source_hash: bcd7c0413e52f11486ffd06a6fb4d25f12ca79fb605fec114076a179b01f6c42 + source_hash: dfc4d1044ddaf1adfdcdde4f018156d36d5874f9be507a53bdc637dc3a772f2f source_path: help/testing.md workflow: 15 --- -OpenClaw 有三套 Vitest 测试套件(单元 / 集成、e2e、实时),以及一小组 Docker 运行器。本文档是一份“我们如何测试”的指南: +OpenClaw 有三个 Vitest 测试套件(unit/integration、e2e、live)以及一小组 Docker 运行器。本文档是一份“我们的测试方式”指南: -- 每个测试套件涵盖什么(以及它明确**不**涵盖什么)。 +- 每个测试套件覆盖什么(以及它有意 _不_ 覆盖什么)。 - 常见工作流应运行哪些命令(本地、推送前、调试)。 -- 实时测试如何发现凭证并选择模型 / 提供商。 +- live 测试如何发现凭证以及如何选择模型 / 提供商。 - 如何为真实世界中的模型 / 提供商问题添加回归测试。 ## 快速开始 @@ -26,76 +26,77 @@ OpenClaw 有三套 Vitest 测试套件(单元 / 集成、e2e、实时),以 大多数时候: - 完整门禁(预期在推送前运行):`pnpm build && pnpm check && pnpm check:test-types && pnpm test` -- 在资源充足的机器上更快地运行本地全套测试:`pnpm test:max` +- 在配置较好的机器上更快地运行本地完整测试套件:`pnpm test:max` - 直接进入 Vitest 监听循环:`pnpm test:watch` -- 现在可直接按文件定位,扩展 / 渠道路径也会正确路由:`pnpm test extensions/discord/src/monitor/message-handler.preflight.test.ts` -- 当你在迭代修复单个失败用例时,优先选择定向运行。 -- 基于 Docker 的 QA 站点:`pnpm qa:lab:up` +- 现在直接指定文件路径也会路由 extension/channel 路径:`pnpm test extensions/discord/src/monitor/message-handler.preflight.test.ts` +- 当你在迭代处理单个失败时,优先使用定向运行。 +- Docker 支持的 QA 站点:`pnpm qa:lab:up` - 基于 Linux VM 的 QA 通道:`pnpm openclaw qa suite --runner multipass --scenario channel-chat-baseline` -当你修改了测试,或希望获得额外信心时: +当你修改测试或希望获得更多信心时: - 覆盖率门禁:`pnpm test:coverage` -- E2E 套件:`pnpm test:e2e` +- E2E 测试套件:`pnpm test:e2e` -当你在调试真实的提供商 / 模型时(需要真实凭证): +当你在调试真实提供商 / 模型时(需要真实凭证): -- 实时套件(模型 + Gateway 网关工具 / 图像探测):`pnpm test:live` -- 安静地只跑一个实时测试文件:`pnpm test:live -- src/agents/models.profiles.live.test.ts` -- Docker 实时模型扫测:`pnpm test:docker:live-models` - - 现在,每个选中的模型都会运行一次文本轮次,再加一次小型的文件读取风格探测。元数据声明支持 `image` 输入的模型还会运行一次微型图像轮次。排查提供商故障时,可用 `OPENCLAW_LIVE_MODEL_FILE_PROBE=0` 或 `OPENCLAW_LIVE_MODEL_IMAGE_PROBE=0` 关闭这些额外探测。 - - CI 覆盖范围:每日的 `OpenClaw Scheduled Live And E2E Checks` 和手动触发的 `OpenClaw Release Checks` 都会调用可复用的实时 / E2E 工作流,并设置 `include_live_suites: true`,其中包括按提供商分片的独立 Docker 实时模型矩阵作业。 - - 若要聚焦重跑 CI,可手动触发 `OpenClaw Live And E2E Checks (Reusable)`,并设置 `include_live_suites: true` 与 `live_models_only: true`。 - - 把新的高信号提供商密钥添加到 `scripts/ci-hydrate-live-auth.sh`,以及 `.github/workflows/openclaw-live-and-e2e-checks-reusable.yml` 和它的定时 / 发布调用方中。 +- Live 测试套件(模型 + Gateway 网关工具 / 图像探测):`pnpm test:live` +- 安静地只运行一个 live 文件:`pnpm test:live -- src/agents/models.profiles.live.test.ts` +- Docker live 模型扫描:`pnpm test:docker:live-models` + - 每个选定模型现在都会运行一次文本轮次外加一个小型文件读取式探测。元数据声明支持 `image` 输入的模型还会运行一个微型图像轮次。隔离提供商故障时,可通过 `OPENCLAW_LIVE_MODEL_FILE_PROBE=0` 或 `OPENCLAW_LIVE_MODEL_IMAGE_PROBE=0` 禁用这些额外探测。 + - CI 覆盖:每日的 `OpenClaw Scheduled Live And E2E Checks` 和手动触发的 `OpenClaw Release Checks` 都会调用可复用的 live/E2E 工作流,并设置 `include_live_suites: true`,其中包含按提供商分片的独立 Docker live 模型矩阵作业。 + - 若需有针对性的 CI 重跑,可触发 `OpenClaw Live And E2E Checks (Reusable)`,并设置 `include_live_suites: true` 与 `live_models_only: true`。 + - 将新的高信号提供商密钥添加到 `scripts/ci-hydrate-live-auth.sh`,以及 `.github/workflows/openclaw-live-and-e2e-checks-reusable.yml` 和其计划 / 发布调用方中。 - 原生 Codex 绑定聊天冒烟测试:`pnpm test:docker:live-codex-bind` - - 在 Codex app-server 路径上运行一个 Docker 实时测试通道,绑定一个合成的 Slack 私信并执行 `/codex bind`,测试 `/codex fast` 和 `/codex permissions`,然后验证普通回复和图像附件都会通过原生插件绑定路由,而不是 ACP。 + - 在 Codex app-server 路径上运行一个 Docker live 通道,绑定一个通过 `/codex bind` 的合成 Slack 私信,会执行 `/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` - - 在无配置容器中运行 Crestodian,并在 `PATH` 上提供一个假的 Claude CLI,验证模糊 planner 回退会被转换为经过审计的类型化配置写入。 + - 这是针对消息渠道救援命令界面的可选双保险检查。它会执行 `/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 plugin + 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,并且 assistant transcript 存储了已归一化的 `usage.cost`。 -当你只需要一个失败用例时,优先使用下面介绍的 allowlist 环境变量来收窄实时测试范围。 +当你只需要一个失败用例时,优先使用下文介绍的 allowlist 环境变量来收窄 live 测试范围。 ## 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 上运行,也可通过手动触发在 mock 提供商下运行。`QA-Lab - All Lanes` 会在 `main` 上每晚运行,也可手动触发;它会并行运行 mock parity gate、live Matrix 通道、由 Convex 管理的 live Telegram 通道,以及由 Convex 管理的 live Discord 通道。计划中的 QA 和发布检查会显式传递 Matrix `--profile fast`,而 Matrix CLI 和手动工作流输入的默认值仍是 `all`;手动触发可将 `all` 分片为 `transport`、`media`、`e2ee-smoke`、`e2ee-deep` 和 `e2ee-cli` 作业。`OpenClaw Release Checks` 会在发布批准前运行 parity,加上快速 Matrix 和 Telegram 通道。 - `pnpm openclaw qa suite` - - 直接在宿主机上运行基于仓库的 QA 场景。 - - 默认会并行运行多个选中的场景,并使用隔离的 Gateway 网关工作进程。`qa-channel` 默认并发数为 4(受选中场景数量限制)。使用 `--concurrency ` 调整工作进程数量,或使用 `--concurrency 1` 启用旧的串行通道。 - - 任一场景失败时以非零状态退出。若你希望保留产物但不以失败退出码结束,请使用 `--allow-failures`。 - - 支持 `live-frontier`、`mock-openai` 和 `aimock` 三种提供商模式。`aimock` 会启动一个本地的 AIMock 支持的提供商服务器,用于实验性的 fixture 和协议模拟覆盖,而不会替代具备场景感知能力的 `mock-openai` 通道。 + - 直接在主机上运行由仓库支持的 QA 场景。 + - 默认会使用隔离的 Gateway 网关工作进程并行运行多个选定场景。`qa-channel` 默认并发数为 4(受选定场景数量限制)。使用 `--concurrency ` 调整工作进程数量,或使用 `--concurrency 1` 运行旧的串行通道。 + - 任一场景失败时会以非零状态退出。若你想获取工件但不希望退出码失败,可使用 `--allow-failures`。 + - 支持 `live-frontier`、`mock-openai` 和 `aimock` 提供商模式。`aimock` 会启动一个本地的 AIMock 支持的 provider 服务器,用于实验性 fixture 和协议 mock 覆盖,而不会替代具备场景感知能力的 `mock-openai` 通道。 - `pnpm openclaw qa suite --runner multipass` - - 在一次性 Multipass Linux VM 中运行相同的 QA 套件。 - - 场景选择行为与宿主机上的 `qa suite` 保持一致。 - - 复用与 `qa suite` 相同的提供商 / 模型选择参数。 - - 实时运行会转发来宾环境中可实际使用的受支持 QA 认证输入:基于环境变量的提供商密钥、QA 实时提供商配置路径,以及存在时的 `CODEX_HOME`。 - - 输出目录必须位于仓库根目录下,以便来宾可通过挂载的工作区回写。 - - 会把常规 QA 报告 + 摘要,以及 Multipass 日志写入 `.artifacts/qa-e2e/...`。 + - 在一个临时的 Multipass Linux VM 中运行相同的 QA 测试套件。 + - 保持与主机上 `qa suite` 相同的场景选择行为。 + - 复用与 `qa suite` 相同的 provider / model 选择标志。 + - Live 运行会转发对来宾系统实际可用的受支持 QA 凭证输入:基于环境变量的提供商密钥、QA live provider 配置路径,以及存在时的 `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 密钥 onboarding,默认配置 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 运行时上下文被持久化为一条不展示的自定义消息,而不是泄漏进可见的用户轮次;随后会注入一个受影响的损坏会话 JSONL,并验证 `openclaw doctor --fix` 会将其重写到当前分支并保留备份。 + - 运行一个确定性的内置应用 Docker 冒烟测试,用于嵌入式运行时上下文 transcript。它会验证隐藏的 OpenClaw 运行时上下文被持久化为一个非展示型自定义消息,而不是泄露到可见的用户轮次中;然后它会植入一个受影响的损坏 session JSONL,并验证 `openclaw doctor --fix` 会将其重写到当前分支并生成备份。 - `pnpm test:docker:npm-telegram-live` - - 在 Docker 中安装一个 OpenClaw 候选包,运行已安装包的 onboarding,通过已安装的 CLI 配置 Telegram,然后复用实时 Telegram QA 通道,并把该已安装包作为被测 Gateway 网关。 - - 默认使用 `OPENCLAW_NPM_TELEGRAM_PACKAGE_SPEC=openclaw@beta`;设置 `OPENCLAW_NPM_TELEGRAM_PACKAGE_TGZ=/path/to/openclaw-current.tgz` 或 `OPENCLAW_CURRENT_PACKAGE_TGZ`,即可测试一个已解析的本地 tarball,而不是从注册表安装。 - - 它使用与 `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。 + - 在 Docker 中安装一个 OpenClaw 包候选版本,运行已安装包的新手引导,通过已安装的 CLI 配置 Telegram,然后复用 live Telegram QA 通道,并将该已安装包作为被测 Gateway 网关。 + - 默认使用 `OPENCLAW_NPM_TELEGRAM_PACKAGE_SPEC=openclaw@beta`;设置 `OPENCLAW_NPM_TELEGRAM_PACKAGE_TGZ=/path/to/openclaw-current.tgz` 或 `OPENCLAW_CURRENT_PACKAGE_TGZ` 可测试一个已解析的本地 tarball,而不是从注册表安装。 + - 使用与 `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` 产物运行。 + - GitHub Actions 也将此通道公开为手动维护者工作流 `NPM Telegram Beta E2E`。它不会在合并时运行。该工作流使用 `qa-live-shared` environment 和 Convex CI credential leases。 +- GitHub Actions 还公开了 `Package Acceptance`,用于针对单个候选包进行旁路产品验证。它接受受信任的 ref、已发布的 npm spec、带 SHA-256 的 HTTPS tarball URL,或来自另一个运行的 tarball artifact,上传归一化后的 `openclaw-current.tgz` 作为 `package-under-test`,然后使用现有的 Docker E2E 调度器运行 smoke、package、product、full 或 custom 通道配置。设置 `telegram_mode=mock-openai` 或 `live-frontier`,即可针对同一个 `package-under-test` artifact 运行 Telegram QA 工作流。 - 最新 beta 产品验证: ```bash @@ -116,7 +117,7 @@ gh workflow run package-acceptance.yml --ref main \ -f suite_profile=package ``` -- 产物验证会从另一个 Actions 运行下载一个 tarball 产物: +- Artifact 验证会从另一个 Actions 运行中下载 tarball artifact: ```bash gh workflow run package-acceptance.yml --ref main \ @@ -127,14 +128,14 @@ gh workflow run package-acceptance.yml --ref main \ ``` - `pnpm test:docker:bundled-channel-deps` - - 在 Docker 中打包并安装当前的 OpenClaw 构建,使用已配置的 OpenAI 启动 Gateway 网关,然后通过配置编辑启用内置渠道 / 插件。 - - 验证 setup 发现阶段不会预装未配置插件的运行时依赖;第一次已配置的 Gateway 网关或 doctor 运行会按需安装每个内置插件的运行时依赖;第二次重启不会重新安装已经激活过的依赖。 - - 还会安装一个已知的较旧 npm 基线版本,在运行 `openclaw update --tag ` 之前启用 Telegram,并验证候选版本在更新后的 doctor 会修复内置渠道运行时依赖,而不需要 harness 侧的 postinstall 修复。 + - 在 Docker 中打包并安装当前的 OpenClaw 构建版本,以配置好的 OpenAI 启动 Gateway 网关,然后通过编辑配置启用内置的渠道 / 插件。 + - 验证 setup 发现阶段不会预先安装未配置插件的运行时依赖;首次配置好的 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` 获取摘要 artifact 路径和每个通道状态。 + - OpenAI 通道默认使用 `openai/gpt-5.5` 进行 live 智能体轮次验证。若要有意验证其他 OpenAI 模型,请传入 `--model ` 或设置 `OPENCLAW_PARALLELS_OPENAI_MODEL`。 + - 将较长的本地运行包裹在主机超时中,以免 Parallels 传输卡顿耗尽剩余测试窗口: ```bash timeout --foreground 150m pnpm test:parallels:npm-update -- --json @@ -142,58 +143,58 @@ gh workflow run package-acceptance.yml --ref main \ ``` - 该脚本会将嵌套通道日志写入 `/tmp/openclaw-parallels-npm-update.*`。在认定外层包装器卡住之前,请先检查 `windows-update.log`、`macos-update.log` 或 `linux-update.log`。 - - 在冷启动来宾系统上,Windows 更新可能会在更新后的 doctor / 运行时依赖修复阶段耗时 10 到 15 分钟;只要嵌套的 npm 调试日志仍在推进,这仍属于正常情况。 + - 在冷启动来宾系统上,Windows 更新可能会在更新后的 doctor / 运行时依赖修复阶段耗时 10 到 15 分钟;只要嵌套的 npm 调试日志仍在推进,这仍属于健康状态。 - 不要将这个聚合包装器与单独的 Parallels macOS、Windows 或 Linux 冒烟通道并行运行。它们共享 VM 状态,可能会在快照恢复、包服务或来宾 Gateway 网关状态上发生冲突。 - - 更新后的验证会运行常规的内置插件表面,因为像语音、图像生成和媒体理解这样的能力外观层,即使在智能体轮次本身只检查简单文本回复时,也仍然通过内置运行时 API 加载。 + - 更新后的验证会运行常规的内置插件界面,因为像语音、图像生成和媒体理解这样的能力外观层,即使智能体轮次本身只检查简单文本响应,也会通过内置运行时 API 加载。 - `pnpm openclaw qa aimock` - - 仅启动本地 AIMock 提供商服务器,用于直接协议冒烟测试。 + - 仅启动本地 AIMock provider 服务器,用于直接协议冒烟测试。 - `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 不提供共享的凭证来源标志,因为该通道会在本地预置一次性用户。 - - 会在 `.artifacts/qa-e2e/...` 下写入 Matrix QA 报告、摘要、observed-events 产物,以及合并后的 stdout / stderr 输出日志。 - - 默认会输出进度,并通过 `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 live 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 artifact,以及合并的 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`。 - `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 机器人能够观察群组中的机器人流量。 - - 会在 `.artifacts/qa-e2e/...` 下写入 Telegram QA 报告、摘要和 observed-messages 产物。回复类场景会包含从 driver 发送请求到观察到 SUT 回复之间的 RTT。 + - 使用环境变量中的 driver 和 SUT bot token,针对一个真实私有群组运行 Telegram live QA 通道。 + - 需要 `OPENCLAW_QA_TELEGRAM_GROUP_ID`、`OPENCLAW_QA_TELEGRAM_DRIVER_BOT_TOKEN` 和 `OPENCLAW_QA_TELEGRAM_SUT_BOT_TOKEN`。群组 id 必须是数字形式的 Telegram chat id。 + - 支持 `--credential-source convex` 以使用共享凭证池。默认使用环境变量模式,或设置 `OPENCLAW_QA_CREDENTIAL_SOURCE=convex` 以启用池化租约。 + - 任一场景失败时会以非零状态退出。若你想获取 artifact 但不希望退出码失败,可使用 `--allow-failures`。 + - 需要同一私有群组中的两个不同 bot,并且 SUT bot 需要公开 Telegram 用户名。 + - 为了稳定地进行 bot 对 bot 观测,请在 `@BotFather` 中为两个 bot 启用 Bot-to-Bot Communication Mode,并确保 driver bot 能观测群组内 bot 流量。 + - 将 Telegram QA 报告、摘要和 observed-messages artifact 写入 `.artifacts/qa-e2e/...`。回复场景会包含从 driver 发送请求到观测到 SUT 回复的 RTT。 -实时传输通道共享一份标准契约,这样新传输不会发生漂移: +Live 传输通道共享一份标准契约,这样新增传输层时就不会发生漂移: -`qa-channel` 仍然是广义的合成 QA 套件,不属于实时传输覆盖矩阵的一部分。 +`qa-channel` 仍然是覆盖范围更广的合成 QA 测试套件,不属于 live 传输覆盖矩阵的一部分。 -| 通道 | Canary | Mention gating | Allowlist block | 顶层回复 | 重启恢复 | 线程后续回复 | 线程隔离 | 反应观察 | 帮助命令 | 原生命令注册 | -| ---- | ------ | -------------- | --------------- | -------- | -------- | ------------ | -------- | -------- | -------- | ------------ | +| 通道 | Canary | 提及门控 | Allowlist 阻止 | 顶层回复 | 重启恢复 | 线程跟进 | 线程隔离 | 反应观测 | 帮助命令 | 原生命令注册 | +| ---- | ------ | -------- | -------------- | -------- | -------- | -------- | -------- | -------- | -------- | ------------ | | Matrix | x | x | x | x | x | x | x | x | | | | Telegram | x | x | | | | | | | x | | | Discord | x | x | | | | | | | | x | ### 通过 Convex 共享 Telegram 凭证(v1) -当为 `openclaw qa telegram` 启用 `--credential-source convex`(或 `OPENCLAW_QA_CREDENTIAL_SOURCE=convex`)时,QA lab 会从 Convex 支持的凭证池中获取一个独占租约,在通道运行期间为该租约发送心跳,并在关闭时释放租约。 +当为 `openclaw qa telegram` 启用 `--credential-source convex`(或 `OPENCLAW_QA_CREDENTIAL_SOURCE=convex`)时,QA lab 会从一个由 Convex 支持的池中获取独占租约,在通道运行期间为该租约持续发送心跳,并在关闭时释放租约。 -参考用 Convex 项目脚手架: +参考用的 Convex 项目脚手架: - `qa/convex-credential-broker/` 必需的环境变量: - `OPENCLAW_QA_CONVEX_SITE_URL`(例如 `https://your-deployment.convex.site`) -- 为所选角色提供一个密钥: - - `maintainer` 使用 `OPENCLAW_QA_CONVEX_SECRET_MAINTAINER` - - `ci` 使用 `OPENCLAW_QA_CONVEX_SECRET_CI` +- 所选角色对应的一个密钥: + - `OPENCLAW_QA_CONVEX_SECRET_MAINTAINER` 用于 `maintainer` + - `OPENCLAW_QA_CONVEX_SECRET_CI` 用于 `ci` - 凭证角色选择: - CLI:`--credential-role maintainer|ci` - - 环境变量默认值:`OPENCLAW_QA_CREDENTIAL_ROLE`(在 CI 中默认是 `ci`,否则默认是 `maintainer`) + - 环境变量默认值:`OPENCLAW_QA_CREDENTIAL_ROLE`(在 CI 中默认 `ci`,否则默认 `maintainer`) 可选环境变量: @@ -202,14 +203,14 @@ gh workflow run package-acceptance.yml --ref main \ - `OPENCLAW_QA_CREDENTIAL_ACQUIRE_TIMEOUT_MS`(默认 `90000`) - `OPENCLAW_QA_CREDENTIAL_HTTP_TIMEOUT_MS`(默认 `15000`) - `OPENCLAW_QA_CONVEX_ENDPOINT_PREFIX`(默认 `/qa-credentials/v1`) -- `OPENCLAW_QA_CREDENTIAL_OWNER_ID`(可选追踪 ID) -- `OPENCLAW_QA_ALLOW_INSECURE_HTTP=1` 允许仅用于本地开发的 loopback `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`。 +维护者管理员命令(池添加 / 删除 / 列表)需要明确使用 `OPENCLAW_QA_CONVEX_SECRET_MAINTAINER`。 -供维护者使用的 CLI 辅助命令: +面向维护者的 CLI 辅助命令: ```bash pnpm openclaw qa credentials doctor @@ -218,87 +219,87 @@ pnpm openclaw qa credentials list --kind telegram pnpm openclaw qa credentials remove --credential-id ``` -在实时运行前使用 `doctor`,以检查 Convex 站点 URL、broker 密钥、端点前缀、HTTP 超时,以及 admin / list 可达性,同时不会打印密钥值。在脚本和 CI 工具中使用 `--json` 可获得机器可读输出。 +在 live 运行前使用 `doctor` 检查 Convex site URL、broker 密钥、endpoint prefix、HTTP 超时和管理员 / 列表可达性,同时不会打印密钥值。在脚本和 CI 工具中可使用 `--json` 获取机器可读输出。 -默认端点契约(`OPENCLAW_QA_CONVEX_SITE_URL` + `/qa-credentials/v1`): +默认 endpoint 契约(`OPENCLAW_QA_CONVEX_SITE_URL` + `/qa-credentials/v1`): - `POST /acquire` - 请求:`{ kind, ownerId, actorRole, leaseTtlMs, heartbeatIntervalMs }` - 成功:`{ status: "ok", credentialId, leaseToken, payload, leaseTtlMs?, heartbeatIntervalMs? }` - - 耗尽 / 可重试:`{ status: "error", code: "POOL_EXHAUSTED" | "NO_CREDENTIAL_AVAILABLE", ... }` + - 资源耗尽 / 可重试:`{ status: "error", code: "POOL_EXHAUSTED" | "NO_CREDENTIAL_AVAILABLE", ... }` - `POST /heartbeat` - 请求:`{ kind, ownerId, actorRole, credentialId, leaseToken, leaseTtlMs }` - 成功:`{ status: "ok" }`(或空的 `2xx`) - `POST /release` - 请求:`{ kind, ownerId, actorRole, credentialId, leaseToken }` - 成功:`{ status: "ok" }`(或空的 `2xx`) -- `POST /admin/add`(仅限 maintainer 密钥) +- `POST /admin/add`(仅维护者密钥) - 请求:`{ kind, actorId, payload, note?, status? }` - 成功:`{ status: "ok", credential }` -- `POST /admin/remove`(仅限 maintainer 密钥) +- `POST /admin/remove`(仅维护者密钥) - 请求:`{ credentialId, actorId }` - 成功:`{ status: "ok", changed, credential }` - 活跃租约保护:`{ status: "error", code: "LEASE_ACTIVE", ... }` -- `POST /admin/list`(仅限 maintainer 密钥) +- `POST /admin/list`(仅维护者密钥) - 请求:`{ kind?, status?, includePayload?, limit? }` - 成功:`{ status: "ok", credentials, count }` Telegram 类型的 payload 结构: - `{ groupId: string, driverToken: string, sutToken: string }` -- `groupId` 必须是 Telegram 聊天数字 ID 字符串。 +- `groupId` 必须是数字形式的 Telegram chat id 字符串。 - 对于 `kind: "telegram"`,`admin/add` 会校验该结构,并拒绝格式错误的 payload。 ### 向 QA 添加一个渠道 -向 Markdown QA 系统添加一个渠道,严格只需要两样东西: +向 Markdown QA 系统添加一个渠道只需要两样东西: 1. 该渠道的传输适配器。 -2. 一个用于测试该渠道契约的场景包。 +2. 一个用于验证渠道契约的场景包。 -当共享的 `qa-lab` 宿主可以负责整个流程时,不要新增一个顶层 QA 命令根。 +当共享 `qa-lab` 主机可以承载该流程时,不要新增顶层 QA 命令根。 -`qa-lab` 负责共享宿主机制: +`qa-lab` 负责共享主机机制: - `openclaw qa` 命令根 -- 套件启动与关闭 +- 套件启动和拆除 - 工作进程并发 -- 产物写入 +- artifact 写入 - 报告生成 - 场景执行 -- 旧 `qa-channel` 场景的兼容别名 +- 对旧版 `qa-channel` 场景的兼容别名 运行器插件负责传输契约: -- `openclaw qa ` 如何挂载在共享 `qa` 根命令下 -- Gateway 网关如何为该传输进行配置 +- 如何将 `openclaw qa ` 挂载到共享 `qa` 根之下 +- 如何为该传输层配置 gateway - 如何检查就绪状态 - 如何注入入站事件 -- 如何观察出站消息 -- 如何暴露转录和标准化的传输状态 -- 如何执行由传输支持的动作 -- 如何处理传输特定的重置或清理 +- 如何观测出站消息 +- 如何暴露 transcript 和归一化后的传输状态 +- 如何执行由传输层支持的操作 +- 如何处理传输层特定的重置或清理 -新渠道的最低采用门槛是: +新渠道的最低接入门槛是: -1. 保持 `qa-lab` 作为共享 `qa` 根命令的所有者。 -2. 在共享的 `qa-lab` 宿主接缝上实现传输运行器。 -3. 将传输特定机制保留在运行器插件或渠道 harness 内部。 -4. 将运行器挂载为 `openclaw qa `,而不是注册一个竞争性的根命令。 +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. 除非仓库正在进行有意迁移,否则应保持现有兼容别名继续可用。 + 保持 `runtime-api.ts` 轻量;惰性 CLI 和运行器执行应放在独立入口点之后。 +5. 在带主题的 `qa/scenarios/` 目录下编写或适配 Markdown 场景。 +6. 对新场景使用通用场景辅助函数。 +7. 除非仓库正在进行有意迁移,否则要保持现有兼容别名继续可用。 -决策规则是严格的: +决策规则很严格: -- 如果某个行为可以在 `qa-lab` 中统一表达一次,就把它放进 `qa-lab`。 -- 如果某个行为依赖单一渠道传输,就把它保留在该运行器插件或插件 harness 中。 -- 如果某个场景需要一个可被多个渠道复用的新能力,就添加一个通用辅助工具,而不是在 `suite.ts` 中添加渠道特定分支。 -- 如果某个行为只对一种传输有意义,就让该场景保持传输特定,并在场景契约中明确说明。 +- 如果某个行为可以在 `qa-lab` 中统一表达一次,就把它放到 `qa-lab` 中。 +- 如果某个行为依赖单一渠道传输层,就把它保留在对应的运行器插件或插件 harness 中。 +- 如果某个场景需要一个可供多个渠道复用的新能力,就添加一个通用 helper,而不是在 `suite.ts` 中加入渠道专用分支。 +- 如果某个行为只对单一传输层有意义,就让该场景保持传输层专用,并在场景契约中明确说明。 -新场景推荐使用的通用辅助函数名有: +新场景推荐使用的通用 helper 名称: - `waitForTransportReady` - `waitForChannelReady` @@ -321,21 +322,22 @@ Telegram 类型的 payload 结构: - `formatConversationTranscript` - `resetBus` -新的渠道开发应使用这些通用辅助函数名。 -兼容别名的存在是为了避免一次性全面迁移,而不是作为新场景编写的范式。 +新的渠道开发应使用通用 helper 名称。 +兼容别名的存在是为了避免一次性迁移,不应作为 +新场景编写的范式。 -## 测试套件(各自运行位置) +## 测试套件(各自在哪里运行) -可以把这些测试套件理解为“真实度逐步提升”(同时也会增加不稳定性 / 成本): +可以把这些测试套件理解为“真实度逐步增加”(以及不稳定性 / 成本也逐步增加): -### 单元 / 集成(默认) +### Unit / integration(默认) - 命令:`pnpm test` -- 配置:未定向运行使用 `vitest.full-*.config.ts` 分片集合,并且可能会将多项目分片展开为按项目拆分的配置,以便并行调度 -- 文件:核心 / 单元测试清单位于 `src/**/*.test.ts`、`packages/**/*.test.ts`、`test/**/*.test.ts`,以及由 `vitest.unit.config.ts` 覆盖的白名单 `ui` Node 测试 +- 配置:未指定目标的运行使用 `vitest.full-*.config.ts` 分片集合,并且可能会将多项目分片展开为按项目拆分的配置,以便并行调度 +- 文件:核心 / 单元测试清单位于 `src/**/*.test.ts`、`packages/**/*.test.ts` 和 `test/**/*.test.ts`;UI 单元测试在专用的 `unit-ui` 分片中运行 - 范围: - 纯单元测试 - - 进程内集成测试(gateway 认证、路由、工具、解析、配置) + - 进程内集成测试(gateway 凭证、路由、工具、解析、配置) - 针对已知缺陷的确定性回归测试 - 预期: - 在 CI 中运行 @@ -343,294 +345,295 @@ Telegram 类型的 payload 结构: - 应该快速且稳定 - + - - 未定向的 `pnpm test` 会运行 12 个较小的分片配置(`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` 项目图,因为多分片 watch 循环并不现实。 - - `pnpm test`、`pnpm test:watch` 和 `pnpm test:perf:imports` 会先通过限定通道来路由显式的文件 / 目录目标,因此 `pnpm test extensions/discord/src/monitor/message-handler.preflight.test.ts` 无需承担完整根项目启动成本。 - - `pnpm test:changed` 默认会把变更的 git 路径展开为低成本的限定通道:直接测试编辑、同级 `*.test.ts` 文件、显式源码映射,以及本地导入图依赖项。配置 / setup / package 编辑不会广泛运行测试,除非你显式使用 `OPENCLAW_TEST_CHANGED_BROAD=1 pnpm test:changed`。 - - `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 辅助工具、`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 尾部时间。 + - 未指定目标的 `pnpm test` 会运行 12 个较小的分片配置(`core-unit-fast`、`core-unit-src`、`core-unit-security`、`core-unit-ui`、`core-unit-support`、`core-support-boundary`、`core-contracts`、`core-bundled`、`core-runtime`、`agentic`、`auto-reply`、`extensions`),而不是启动一个巨大的原生根项目进程。这样可以降低高负载机器上的峰值 RSS,并避免 auto-reply / extension 工作拖累无关套件。 + - `pnpm test --watch` 仍然使用原生根 `vitest.config.ts` 项目图,因为多分片 watch 循环并不现实。 + - `pnpm test`、`pnpm test:watch` 和 `pnpm test:perf:imports` 会先通过作用域通道路由显式文件 / 目录目标,因此 `pnpm test extensions/discord/src/monitor/message-handler.preflight.test.ts` 不需要承担完整根项目启动的代价。 + - `pnpm test:changed` 默认会将变更的 git 路径展开为低成本的作用域通道:直接修改的测试、相邻的 `*.test.ts` 文件、显式源码映射,以及本地导入图的依赖方。除非你显式使用 `OPENCLAW_TEST_CHANGED_BROAD=1 pnpm test:changed`,否则配置 / setup / package 修改不会触发大范围测试。 + - `pnpm check:changed` 是窄范围工作时常规的智能本地检查门禁。它会将差异分类为 core、core tests、extensions、extension tests、apps、docs、release metadata、live Docker tooling 和 tooling,然后运行匹配的 typecheck、lint 与保护命令。它不会运行 Vitest 测试;如需测试证明,请调用 `pnpm test:changed` 或显式的 `pnpm test `。仅发布元数据的版本号更新会运行定向的版本 / 配置 / 根依赖检查,并带有一个保护,拒绝顶层版本字段之外的 package 变更。 + - 对 live Docker ACP harness 的修改会运行聚焦检查:针对 live Docker 认证脚本的 shell 语法检查,以及 live Docker 调度器 dry-run。只有当差异仅限于 `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` helper 源文件也会在 changed 模式运行中映射到这些轻量通道中的显式相邻测试,因此 helper 修改无需重新运行该目录下完整的重型套件。 + - `auto-reply` 拥有针对顶层 core helpers、顶层 `reply.*` 集成测试以及 `src/auto-reply/reply/**` 子树的专用桶。CI 还会将 reply 子树进一步拆分为 agent-runner、dispatch 以及 commands / state-routing 分片,这样某个导入开销较重的桶就不会独占整个 Node 尾部时长。 - + - - 当你修改消息工具发现输入或压缩运行时上下文时,要同时保留两层覆盖。 - - 为纯路由和标准化边界添加聚焦的辅助函数回归测试。 - - 保持嵌入式运行器集成套件健康: + - 当你修改 message-tool 发现输入或 compaction 运行时上下文时,要同时保留这两个层级的覆盖。 + - 为纯路由和归一化边界添加聚焦的 helper 回归测试。 + - 保持嵌入式运行器集成测试套件健康: `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 和 compaction 行为仍会流经真实的 `run.ts` / `compact.ts` 路径;仅有 helper 测试并不足以替代这些集成路径。 - 基础 Vitest 配置默认使用 `threads`。 - - 共享 Vitest 配置固定使用 `isolate: false`,并在根项目、e2e 和实时配置中使用非隔离运行器。 - - 根 UI 通道保留其 `jsdom` setup 和优化器,但也运行在共享的非隔离运行器上。 - - 每个 `pnpm test` 分片都继承自共享 Vitest 配置中的相同 `threads` + `isolate: false` 默认值。 - - `scripts/run-vitest.mjs` 默认会为 Vitest 子 Node 进程添加 `--no-maglev`,以减少大型本地运行期间的 V8 编译抖动。设置 `OPENCLAW_VITEST_ENABLE_MAGLEV=1` 可与原生 V8 行为进行比较。 + - 共享的 Vitest 配置固定 `isolate: false`,并在根项目、e2e 和 live 配置中使用非隔离运行器。 + - 根 UI 通道保留其 `jsdom` setup 和优化器,但同样运行在共享的非隔离运行器上。 + - 每个 `pnpm test` 分片都继承共享 Vitest 配置中的相同 `threads` + `isolate: false` 默认值。 + - `scripts/run-vitest.mjs` 默认会为 Vitest 子 Node 进程添加 `--no-maglev`,以减少大型本地运行期间 V8 编译抖动。设置 `OPENCLAW_VITEST_ENABLE_MAGLEV=1` 可与默认 V8 行为进行对比。 - - `pnpm changed:lanes` 会显示某个 diff 会触发哪些架构通道。 - - pre-commit hook 仅负责格式化。它会重新暂存已格式化文件,不会运行 lint、类型检查或测试。 - - 当你需要智能本地检查门禁时,请在交接或推送前显式运行 `pnpm check:changed`。 - - `pnpm test:changed` 默认会通过低成本的限定通道路由。只有在智能体判断 harness、配置、package 或契约编辑确实需要更广泛的 Vitest 覆盖时,才使用 `OPENCLAW_TEST_CHANGED_BROAD=1 pnpm test:changed`。 + - `pnpm changed:lanes` 会显示某个差异会触发哪些架构通道。 + - pre-commit hook 仅处理格式化。它会重新暂存格式化后的文件,不会运行 lint、typecheck 或测试。 + - 在你需要智能本地检查门禁时,请在交接或 push 前显式运行 `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(...)` 就深层导入运行时 helper。 + - `pnpm test:perf:changed:bench -- --ref ` 会将路由后的 `test:changed` 与该已提交差异对应的原生根项目路径进行比较,并打印 wall time 和 macOS 最大 RSS。 + - `pnpm test:perf:changed:bench -- --worktree` 会通过将当前脏工作树中的变更文件列表路由到 `scripts/test-projects.mjs` 和根 Vitest 配置,对其进行基准测试。 + - `pnpm test:perf:profile:main` 会为 Vitest / Vite 启动与转换开销写出主线程 CPU profile。 + - `pnpm test:perf:profile:runner` 会在禁用文件级并行的情况下,为 unit 测试套件写出运行器 CPU + heap profile。 -### 稳定性(gateway) +### Stability(gateway) - 命令:`pnpm test:stability:gateway` - 配置:`vitest.gateway.config.ts`,强制单 worker - 范围: - - 默认启动一个启用诊断的真实 loopback Gateway 网关 - - 通过诊断事件路径驱动合成的 gateway 消息、内存和大负载抖动 + - 启动一个真实的 loopback Gateway 网关,默认启用诊断 + - 通过诊断事件路径驱动合成的 gateway 消息、memory 和大负载抖动 - 通过 Gateway 网关 WS RPC 查询 `diagnostics.stability` - - 覆盖诊断稳定性包持久化辅助工具 - - 断言记录器保持有界、合成 RSS 样本保持在压力预算之下,并且每个会话队列深度都会回落到零 + - 覆盖诊断稳定性 bundle 持久化 helper + - 断言 recorder 保持有界、合成 RSS 样本保持在压力预算之下,并且每个 session 的队列深度会回落为零 - 预期: - - 可安全运行于 CI,且不需要密钥 - - 这是一个用于稳定性回归跟进的窄通道,不是完整 Gateway 网关套件的替代品 + - 对 CI 安全且无需密钥 + - 这是用于稳定性回归跟进的窄通道,不可替代完整的 Gateway 网关测试套件 -### E2E(gateway 冒烟) +### E2E(gateway 冒烟测试) - 命令:`pnpm test:e2e` - 配置:`vitest.e2e.config.ts` - 文件:`src/**/*.e2e.test.ts`、`test/**/*.e2e.test.ts`,以及 `extensions/` 下内置插件的 E2E 测试 - 运行时默认值: - - 使用 Vitest `threads` 并设置 `isolate: false`,与仓库其余部分保持一致。 + - 使用 Vitest `threads` 和 `isolate: false`,与仓库其余部分保持一致。 - 使用自适应 worker(CI:最多 2 个,本地:默认 1 个)。 - 默认以 silent 模式运行,以减少控制台 I/O 开销。 -- 常用覆盖项: - - `OPENCLAW_E2E_WORKERS=` 用于强制设置 worker 数量(上限 16)。 - - `OPENCLAW_E2E_VERBOSE=1` 用于重新启用详细控制台输出。 +- 常用覆盖方式: + - `OPENCLAW_E2E_WORKERS=` 可强制指定 worker 数量(上限为 16)。 + - `OPENCLAW_E2E_VERBOSE=1` 可重新启用详细控制台输出。 - 范围: - 多实例 gateway 端到端行为 - - WebSocket / HTTP 表面、节点配对和更重的网络交互 + - WebSocket / HTTP 界面、节点配对,以及更重的网络行为 - 预期: - 在 CI 中运行(当流水线启用时) - 不需要真实密钥 - - 比单元测试涉及更多活动部件(可能更慢) + - 比单元测试涉及更多可变因素(可能更慢) -### E2E:OpenShell 后端冒烟 +### E2E:OpenShell 后端冒烟测试 - 命令:`pnpm test:e2e:openshell` - 文件:`extensions/openshell/src/backend.e2e.test.ts` - 范围: - - 通过 Docker 在宿主机上启动一个隔离的 OpenShell gateway - - 通过临时本地 Dockerfile 创建一个沙箱 - - 通过真实的 `sandbox ssh-config` + SSH exec 测试 OpenClaw 的 OpenShell 后端 - - 通过 sandbox 文件系统桥接验证远端规范化文件系统行为 + - 通过 Docker 在主机上启动一个隔离的 OpenShell gateway + - 从一个临时本地 Dockerfile 创建沙箱 + - 通过真实的 `sandbox ssh-config` + SSH 执行来验证 OpenClaw 的 OpenShell 后端 + - 通过沙箱文件系统桥接验证远端规范文件系统行为 - 预期: - - 仅按需启用;不属于默认的 `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 二进制或包装脚本 + - 使用隔离的 `HOME` / `XDG_CONFIG_HOME`,随后销毁测试 gateway 和沙箱 +- 常用覆盖方式: + - 运行更广泛的 e2e 套件时,设置 `OPENCLAW_E2E_OPENSHELL=1` 以启用该测试 + - 设置 `OPENCLAW_E2E_OPENSHELL_COMMAND=/path/to/openshell` 以指向非默认的 CLI 二进制或包装脚本 -### 实时(真实提供商 + 真实模型) +### Live(真实提供商 + 真实模型) - 命令:`pnpm test:live` - 配置:`vitest.live.config.ts` -- 文件:`src/**/*.live.test.ts`、`test/**/*.live.test.ts`,以及 `extensions/` 下内置插件的实时测试 +- 文件:`src/**/*.live.test.ts`、`test/**/*.live.test.ts`,以及 `extensions/` 下内置插件的 live 测试 - 默认:由 `pnpm test:live` **启用**(会设置 `OPENCLAW_LIVE_TEST=1`) - 范围: - - “这个提供商 / 模型今天在真实凭证下是否真的可用?” - - 捕获提供商格式变更、工具调用怪癖、认证问题和速率限制行为 + - “这个提供商 / 模型在 _今天_ 使用真实凭证时是否真的可用?” + - 捕获提供商格式变更、工具调用怪癖、认证问题以及速率限制行为 - 预期: - - 按设计不具备 CI 稳定性(真实网络、真实提供商策略、配额、故障) + - 设计上不保证在 CI 中稳定(真实网络、真实提供商策略、配额、故障) - 会花钱 / 消耗速率限制 - - 优先运行缩小范围的子集,而不是“全部” -- 实时运行会 source `~/.profile`,以获取缺失的 API 密钥。 -- 默认情况下,实时运行仍会隔离 `HOME`,并将配置 / 认证材料复制到一个临时测试 home 中,这样单元测试 fixture 就不会改动你真实的 `~/.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` 进行每次实时运行覆盖;测试会在收到速率限制响应时重试。 + - 优先运行收窄后的子集,而不是“全部都跑” +- Live 运行会 source `~/.profile` 以补齐缺失的 API 密钥。 +- 默认情况下,live 运行仍会隔离 `HOME`,并将配置 / 认证材料复制到临时测试 home 中,这样单元测试 fixture 就不会修改你真实的 `~/.openclaw`。 +- 仅当你明确需要 live 测试使用真实 home 目录时,才设置 `OPENCLAW_LIVE_USE_REAL_HOME=1`。 +- `pnpm test:live` 现在默认使用更安静的模式:它会保留 `[live] ...` 进度输出,但会抑制额外的 `~/.profile` 提示,并静默 gateway 启动日志 / Bonjour 噪声。若你希望恢复完整启动日志,请设置 `OPENCLAW_LIVE_TEST_QUIET=0`。 +- API 密钥轮换(按提供商区分):设置逗号 / 分号格式的 `*_API_KEYS`,或设置 `*_API_KEY_1`、`*_API_KEY_2`(例如 `OPENAI_API_KEYS`、`ANTHROPIC_API_KEYS`、`GEMINI_API_KEYS`),也可通过 `OPENCLAW_LIVE_*_KEY` 为单次 live 运行覆盖;测试在遇到速率限制响应时会重试。 - 进度 / 心跳输出: - - 实时套件现在会向 stderr 输出进度行,因此即使 Vitest 控制台捕获处于安静模式,长时间的提供商调用也能显示为正在活动。 - - `vitest.live.config.ts` 禁用了 Vitest 控制台拦截,因此在实时运行期间,提供商 / gateway 进度行会立即流式输出。 - - 使用 `OPENCLAW_LIVE_HEARTBEAT_MS` 调整直接模型心跳。 - - 使用 `OPENCLAW_LIVE_GATEWAY_HEARTBEAT_MS` 调整 gateway / 探测心跳。 + - Live 测试套件现在会将进度行输出到 stderr,因此即使 Vitest 控制台捕获处于安静模式,长时间的 provider 调用也能明显显示仍在运行。 + - `vitest.live.config.ts` 会禁用 Vitest 控制台拦截,因此 provider / gateway 进度行会在 live 运行期间立即流式输出。 + - 使用 `OPENCLAW_LIVE_HEARTBEAT_MS` 调整 direct-model 心跳。 + - 使用 `OPENCLAW_LIVE_GATEWAY_HEARTBEAT_MS` 调整 gateway / probe 心跳。 -## 我应该运行哪套测试? +## 我应该运行哪个测试套件? -使用下面这张决策表: +使用这个决策表: -- 编辑逻辑 / 测试:运行 `pnpm test`(如果你改动很多,也运行 `pnpm test:coverage`) -- 涉及 gateway 网络 / WS 协议 / 配对:额外运行 `pnpm test:e2e` -- 调试“我的机器人挂了” / 提供商特定故障 / 工具调用:运行缩小范围的 `pnpm test:live` +- 编辑逻辑 / 测试:运行 `pnpm test`(如果你改动很多,再加上 `pnpm test:coverage`) +- 修改 gateway 网络 / WS 协议 / 配对:额外运行 `pnpm test:e2e` +- 调试“我的 bot 挂了” / provider 专属故障 / 工具调用:运行一个收窄后的 `pnpm test:live` -## 实时(会触网)测试 +## Live(触网)测试 -有关实时模型矩阵、CLI 后端冒烟测试、ACP 冒烟测试、Codex app-server harness,以及所有媒体提供商实时测试(Deepgram、BytePlus(国际版)、ComfyUI、图像、音乐、视频、媒体 harness)——以及实时运行的凭证处理——请参见 [测试——实时套件](/zh-CN/help/testing-live)。 +关于 live 模型矩阵、CLI 后端冒烟测试、ACP 冒烟测试、Codex app-server harness,以及所有媒体 provider live 测试(Deepgram、BytePlus(国际版)、ComfyUI、图像、音乐、视频、媒体 harness)——外加 live 运行的凭证处理——请参阅 [测试 — live suites](/zh-CN/help/testing-live)。 ## Docker 运行器(可选的“在 Linux 中可用”检查) 这些 Docker 运行器分为两类: -- 实时模型运行器:`test:docker:live-models` 和 `test:docker:live-gateway` 仅在仓库 Docker 镜像中运行与其匹配的 profile-key 实时测试文件(`src/agents/models.profiles.live.test.ts` 和 `src/gateway/gateway-models.profiles.live.test.ts`),并挂载你的本地配置目录和工作区(如果已挂载,也会 source `~/.profile`)。对应的本地入口点是 `test:live:models-profiles` 和 `test:live:gateway-profiles`。 -- Docker 实时运行器默认使用较小的冒烟上限,以便完整 Docker 扫测仍然可行: +- Live 模型运行器:`test:docker:live-models` 和 `test:docker:live-gateway` 仅在仓库 Docker 镜像中运行各自匹配 profile-key 的 live 文件(`src/agents/models.profiles.live.test.ts` 和 `src/gateway/gateway-models.profiles.live.test.ts`),会挂载你的本地配置目录和工作区(如果已挂载,也会 source `~/.profile`)。对应的本地入口点是 `test:live:models-profiles` 和 `test:live:gateway-profiles`。 +- Docker live 运行器默认采用更小的冒烟上限,以便完整 Docker 扫描保持可行: `test:docker:live-models` 默认使用 `OPENCLAW_LIVE_MAX_MODELS=12`,而 `test:docker:live-gateway` 默认使用 `OPENCLAW_LIVE_GATEWAY_SMOKE=1`、 `OPENCLAW_LIVE_GATEWAY_MAX_MODELS=8`、 `OPENCLAW_LIVE_GATEWAY_STEP_TIMEOUT_MS=45000` 和 - `OPENCLAW_LIVE_GATEWAY_MODEL_TIMEOUT_MS=90000`。当你明确需要更大的穷举扫描时,可覆盖这些环境变量。 -- `test:docker:all` 会先通过 `test:docker:live-build` 构建一次实时 Docker 镜像,再通过 `scripts/package-openclaw-for-docker.mjs` 将 OpenClaw 打包成一个 npm tarball,然后构建 / 复用两个 `scripts/e2e/Dockerfile` 镜像。裸镜像仅包含用于安装 / 更新 / 插件依赖通道的 Node / Git 运行器;这些通道会挂载预构建的 tarball。功能镜像则将同一个 tarball 安装到 `/app`,用于已构建应用的功能通道。Docker 通道定义位于 `scripts/lib/docker-e2e-scenarios.mjs`;规划逻辑位于 `scripts/lib/docker-e2e-plan.mjs`;`scripts/test-docker-all.mjs` 负责执行选定计划。这个聚合运行器使用加权的本地调度器:`OPENCLAW_DOCKER_ALL_PARALLELISM` 控制进程槽位,同时资源上限会阻止重型实时、npm 安装和多服务通道同时全部启动。如果某个单独通道比当前上限还重,调度器仍可以在池为空时启动它,然后让它单独运行,直到再次有可用容量。默认值是 10 个槽位、`OPENCLAW_DOCKER_ALL_LIVE_LIMIT=9`、`OPENCLAW_DOCKER_ALL_NPM_LIMIT=10` 和 `OPENCLAW_DOCKER_ALL_SERVICE_LIMIT=7`;仅当 Docker 宿主有更多余量时,才调整 `OPENCLAW_DOCKER_ALL_WEIGHT_LIMIT` 或 `OPENCLAW_DOCKER_ALL_DOCKER_LIMIT`。该运行器默认会执行 Docker 预检,移除陈旧的 OpenClaw E2E 容器,每 30 秒打印一次状态,将成功通道的计时写入 `.artifacts/docker-tests/lane-timings.json`,并利用这些计时在后续运行中优先启动更长的通道。使用 `OPENCLAW_DOCKER_ALL_DRY_RUN=1` 可仅打印加权通道清单,而不构建或运行 Docker;也可以使用 `node scripts/test-docker-all.mjs --plan-json` 打印所选通道、package / 镜像需求和凭证的 CI 计划。 -- `Package Acceptance` 是 GitHub 原生的 package 门禁,用于回答“这个可安装 tarball 作为产品是否可用?”这个问题。它会从 `source=npm`、`source=ref`、`source=url` 或 `source=artifact` 解析出一个候选 package,将其上传为 `package-under-test`,然后针对这个精确 tarball 运行可复用的 Docker E2E 通道,而不是重新打包所选 ref。`workflow_ref` 选择受信任的工作流 / harness 脚本,而 `package_ref` 则在 `source=ref` 时选择要打包的源提交 / 分支 / 标签;这样当前的 acceptance 逻辑就可以验证较早的受信任提交。各配置文件按覆盖广度排序:`smoke` 是快速的安装 / 渠道 / 智能体,加上 gateway / 配置;`package` 涵盖 package / 更新 / 插件契约,并且是大多数 Parallels package / 更新覆盖的默认原生替代方案;`product` 额外包含 MCP 渠道、cron / 子智能体清理、OpenAI Web 搜索 和 OpenWebUI;`full` 则运行带 OpenWebUI 的发布路径 Docker 分块。发布验证会针对目标 ref 运行 `package` 配置文件,并启用 Telegram package QA。基于产物生成的定向 GitHub Docker 重跑命令,在可用时会附带先前的 package 产物和已准备好的镜像输入,因此失败通道可以避免重新构建 package 和镜像。 -- `Package Acceptance` 的旧兼容性上限为 `2026.4.25`(含 `2026.4.25-beta.*`)。在这个截止点之前,harness 只容忍已发布 package 的元数据缺口:缺失的私有 QA 清单条目、缺失的 `gateway install --wrapper`、从 tarball 派生的 git fixture 中缺失的 patch 文件、缺失的持久化 `update.channel`、旧版插件安装记录位置、缺失的 marketplace 安装记录持久化,以及在 `plugins update` 期间的配置元数据迁移。对于 `2026.4.25` 之后的 package,这些路径都会被视为严格失败。 + `OPENCLAW_LIVE_GATEWAY_MODEL_TIMEOUT_MS=90000`。当你明确希望进行更大范围的穷尽扫描时,可覆盖这些环境变量。 +- `test:docker:all` 会先通过 `test:docker:live-build` 构建一次 live Docker 镜像,再通过 `scripts/package-openclaw-for-docker.mjs` 将 OpenClaw 打包一次为 npm tarball,然后构建 / 复用两个 `scripts/e2e/Dockerfile` 镜像。裸镜像仅包含用于 install/update/plugin-dependency 通道的 Node/Git 运行器;这些通道会挂载预构建的 tarball。功能镜像则将同一个 tarball 安装到 `/app` 中,用于已构建应用的功能通道。Docker 通道定义位于 `scripts/lib/docker-e2e-scenarios.mjs`;规划逻辑位于 `scripts/lib/docker-e2e-plan.mjs`;`scripts/test-docker-all.mjs` 负责执行选定的计划。这个聚合运行器使用加权本地调度器:`OPENCLAW_DOCKER_ALL_PARALLELISM` 控制进程槽位数,而资源上限会防止重型 live、npm-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` 打印选定通道、package / image 需求和凭证对应的 CI 计划。 +- `Package Acceptance` 是 GitHub 原生的 package 门禁,用于回答“这个可安装 tarball 作为产品是否可用?”它会从 `source=npm`、`source=ref`、`source=url` 或 `source=artifact` 中解析一个候选 package,将其上传为 `package-under-test`,然后针对这个确切 tarball 运行可复用的 Docker E2E 通道,而不是重新打包选定的 ref。`workflow_ref` 选择受信任的 workflow / harness 脚本,而 `package_ref` 选择在 `source=ref` 时用于打包的源 commit / branch / tag;这使当前的 acceptance 逻辑能够验证较旧的受信任提交。各 profile 按覆盖范围排序:`smoke` 是快速的 install/channel/agent 加 gateway/config,`package` 是 package/update/plugin 契约,也是大多数 Parallels package/update 覆盖的默认原生替代,`product` 会额外加入 MCP 渠道、cron/subagent 清理、OpenAI Web 搜索和 OpenWebUI,`full` 则运行包含 OpenWebUI 的发布路径 Docker 分块。发布验证会针对目标 ref 运行 `package` profile,并启用 Telegram package QA。由 artifact 生成的定向 GitHub Docker 重跑命令在可用时会包含之前的 package artifact 和准备好的 image 输入,因此失败通道可以避免重新构建 package 和镜像。 +- Package Acceptance 旧版兼容性上限为 `2026.4.25`(包括 `2026.4.25-beta.*`)。在该截止版本之前,harness 仅容忍已发布 package 的元数据缺口:省略的私有 QA inventory 条目、缺失的 `gateway install --wrapper`、来自 tarball 派生 git fixture 中缺失的 patch 文件、缺失的持久化 `update.channel`、旧版插件 install-record 位置、缺失的 marketplace install-record 持久化,以及 `plugins update` 期间的配置元数据迁移。对于 `2026.4.25` 之后的 package,这些路径都会视为严格失败。 - 容器冒烟运行器:`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 中,这样外部 CLI OAuth 就可以刷新令牌,而不会改动宿主机认证存储: +Live 模型 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`) +- 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`) -- 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`) -- onboarding 向导(TTY,完整脚手架):`pnpm test:docker:onboard`(脚本:`scripts/e2e/onboard-docker.sh`) -- Npm tarball onboarding / 渠道 / 智能体冒烟测试:`pnpm test:docker:npm-onboard-channel-agent` 会在 Docker 中全局安装打包好的 OpenClaw tarball,通过 env-ref onboarding 配置 OpenAI,默认还会配置 Telegram,验证 doctor 会修复已激活插件的运行时依赖,并运行一次模拟的 OpenAI 智能体轮次。可通过 `OPENCLAW_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 全局更新;如果你需要 direct `npm install -g` 覆盖,请在本地运行脚本时不要设置这个环境变量。 -- 智能体删除共享工作区 CLI 冒烟测试:`pnpm test:docker:agents-delete-shared-workspace`(脚本:`scripts/e2e/agents-delete-shared-workspace-docker.sh`)默认会构建根 Dockerfile 镜像,在隔离的容器 home 中为两个智能体注入一个共享工作区,运行 `agents delete --json`,并验证 JSON 有效且工作区保留行为正确。可通过 `OPENCLAW_AGENTS_DELETE_SHARED_WORKSPACE_E2E_IMAGE=openclaw-dockerfile-smoke:local OPENCLAW_AGENTS_DELETE_SHARED_WORKSPACE_E2E_SKIP_BUILD=1` 复用 install-smoke 镜像。 -- Gateway 网关网络(两个容器,WS 认证 + 健康检查):`pnpm test:docker:gateway-network`(脚本:`scripts/e2e/gateway-network-docker.sh`) -- 浏览器 CDP 快照冒烟测试:`pnpm test:docker:browser-cdp-snapshot`(脚本:`scripts/e2e/browser-cdp-snapshot-docker.sh`)会构建源码 E2E 镜像以及一个 Chromium 层,使用原始 CDP 启动 Chromium,运行 `browser doctor --deep`,并验证 CDP 角色快照覆盖链接 URL、由光标提升的可点击元素、iframe 引用和 frame 元数据。 -- OpenAI Responses `web_search` 最小推理回归测试:`pnpm test:docker:openai-web-search-minimal`(脚本:`scripts/e2e/openai-web-search-minimal-docker.sh`)会通过 Gateway 网关运行一个模拟的 OpenAI 服务器,验证 `web_search` 会将 `reasoning.effort` 从 `minimal` 提升到 `low`,然后强制提供商 schema 拒绝,并检查原始细节是否出现在 Gateway 网关日志中。 -- MCP 渠道桥接(预置 Gateway 网关 + stdio bridge + 原始 Claude 通知帧冒烟测试):`pnpm test:docker:mcp-channels`(脚本:`scripts/e2e/mcp-channels-docker.sh`) -- Pi 内置 MCP 工具(真实 stdio MCP 服务器 + 嵌入式 Pi 配置文件允许 / 拒绝冒烟测试):`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。 +- Gateway 网关 + dev 智能体:`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 live 冒烟测试:`pnpm test:docker:openwebui`(脚本:`scripts/e2e/openwebui-docker.sh`) +- 新手引导向导(TTY、完整脚手架):`pnpm test:docker:onboard`(脚本:`scripts/e2e/onboard-docker.sh`) +- Npm tarball 新手引导 / 渠道 / 智能体冒烟测试:`pnpm test:docker:npm-onboard-channel-agent` 会在 Docker 中全局安装打包后的 OpenClaw tarball,通过 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` 并检查更新状态。 +- Session 运行时上下文冒烟测试:`pnpm test:docker:session-runtime-context` 会验证隐藏运行时上下文 transcript 的持久化,以及 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` 覆盖时,请在本地运行该脚本且不要设置此环境变量。 +- 智能体删除共享工作区 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 auth + health):`pnpm test:docker:gateway-network`(脚本:`scripts/e2e/gateway-network-docker.sh`) +- 浏览器 CDP 快照冒烟测试:`pnpm test:docker:browser-cdp-snapshot`(脚本:`scripts/e2e/browser-cdp-snapshot-docker.sh`)会构建源码 E2E 镜像加一个 Chromium 层,以原始 CDP 启动 Chromium,运行 `browser doctor --deep`,并验证 CDP 角色快照覆盖链接 URL、被光标提升的可点击元素、iframe 引用以及 frame 元数据。 +- OpenAI Responses `web_search` 最小 reasoning 回归测试:`pnpm test:docker:openai-web-search-minimal`(脚本:`scripts/e2e/openai-web-search-minimal-docker.sh`)会让一个模拟 OpenAI 服务器通过 Gateway 网关运行,验证 `web_search` 会将 `reasoning.effort` 从 `minimal` 提升为 `low`,然后强制 provider 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` 可跳过 live 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 聚合运行器和发布路径 `plugins-integrations` 分块会先预打包一次这个 tarball,然后将内置渠道检查拆分为独立通道,包括 Telegram、Discord、Slack、Feishu、memory-lancedb 和 ACPX 的独立更新通道。直接运行该内置通道时,可通过 `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` +- 内置插件运行时依赖:`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 聚合运行器和发布路径 `plugins-integrations` 分块会预先打包一次这个 tarball,然后将内置渠道检查分片为独立通道,包括针对 Telegram、Discord、Slack、Feishu、memory-lancedb 和 ACPX 的独立更新通道。直接运行该内置通道时,可用 `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`。 -如需手动预构建并复用共享功能镜像: +若要手动预构建并复用共享功能镜像: ```bash OPENCLAW_DOCKER_E2E_IMAGE=openclaw-docker-e2e-functional:local pnpm test:docker:e2e-build 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,因为它们验证的是 package / install 行为,而不是共享的已构建应用运行时。 -实时模型 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 内置 MCP 运行时将该服务器实例化,执行工具,然后验证 `coding` 和 `messaging` 会保留 `bundle-mcp` 工具,而 `minimal` 和 `tools.deny: ["bundle-mcp"]` 会将其过滤掉。 -`test:docker:cron-mcp-cleanup` 是确定性的,不需要实时模型密钥。它会使用一个真实的 stdio MCP 探测服务器启动预置 Gateway 网关,运行一次隔离的 cron 轮次和一次 `/subagents spawn` 的一次性子智能体轮次,然后验证 MCP 子进程会在每次运行后退出。 +Live 模型 Docker 运行器还会将当前检出以只读方式绑定挂载,并在容器内暂存到一个临时工作目录中。这样既能保持运行时镜像轻量,又能让 Vitest 针对你精确的本地源码 / 配置运行。暂存步骤会跳过大型本地专用缓存和应用构建输出,例如 `.pnpm-store`、`.worktrees`、`__openclaw_vitest__`,以及应用本地 `.build` 或 Gradle 输出目录,这样 Docker live 运行就不会花数分钟复制机器专属 artifact。 +它们还会设置 `OPENCLAW_SKIP_CHANNELS=1`,因此 gateway live 探测不会在容器内启动真实的 Telegram/Discord 等渠道工作进程。 +`test:docker:live-models` 仍会运行 `pnpm test:live`,因此当你需要收窄或排除该 Docker 通道中的 gateway live 覆盖时,也要一并传入 `OPENCLAW_LIVE_GATEWAY_*`。 +`test:docker:openwebui` 是一个更高层级的兼容性冒烟测试:它会启动一个启用了 OpenAI 兼容 HTTP 端点的 OpenClaw gateway 容器,启动一个固定版本的 Open WebUI 容器并将其指向该 gateway,通过 Open WebUI 完成登录,验证 `/api/models` 暴露 `openclaw/default`,然后通过 Open WebUI 的 `/api/chat/completions` 代理发送一条真实聊天请求。 +第一次运行可能会明显更慢,因为 Docker 可能需要拉取 Open WebUI 镜像,而 Open WebUI 也可能需要完成自身的冷启动设置。 +该通道需要一个可用的 live 模型密钥,而 `OPENCLAW_PROFILE_FILE`(默认是 `~/.profile`)是在 Docker 化运行中提供该密钥的主要方式。 +成功运行会打印一个小型 JSON 负载,例如 `{ "ok": true, "model": "openclaw/default", ... }`。 +`test:docker:mcp-channels` 是刻意设计为确定性的,不需要真实的 Telegram、Discord 或 iMessage 账号。它会启动一个植入好的 Gateway 网关容器,启动第二个容器来生成 `openclaw mcp serve`,然后通过真实的 stdio MCP bridge 验证路由后的对话发现、transcript 读取、附件元数据、live 事件队列行为、出站发送路由,以及 Claude 风格的渠道 + 权限通知。通知检查会直接检查原始 stdio MCP 帧,因此该冒烟测试验证的是 bridge 实际发出的内容,而不只是某个客户端 SDK 恰好暴露出来的内容。 +`test:docker:pi-bundle-mcp-tools` 是确定性的,不需要 live 模型密钥。它会构建仓库 Docker 镜像,在容器内启动一个真实的 stdio MCP 探测服务器,通过嵌入式 Pi bundle MCP 运行时将该服务器实例化,执行工具,然后验证 `coding` 和 `messaging` 会保留 `bundle-mcp` 工具,而 `minimal` 和 `tools.deny: ["bundle-mcp"]` 会将其过滤掉。 +`test:docker:cron-mcp-cleanup` 是确定性的,不需要 live 模型密钥。它会启动一个带真实 stdio MCP 探测服务器的植入式 Gateway 网关,运行一个隔离的 cron 轮次和一个 `/subagents spawn` 一次性子智能体轮次,然后验证每次运行后 MCP 子进程都会退出。 -手动 ACP 自然语言线程冒烟测试(非 CI): +手动 ACP 自然语言线程冒烟测试(不在 CI 中运行): - `bun scripts/dev/discord-acp-plain-language-smoke.ts --channel ...` -- 保留此脚本用于回归 / 调试工作流。它未来仍可能再次用于 ACP 线程路由验证,因此不要删除。 +- 为回归 / 调试工作流保留此脚本。后续进行 ACP 线程路由验证时可能还需要它,因此不要删除它。 常用环境变量: -- `OPENCLAW_CONFIG_DIR=...`(默认:`~/.openclaw`)挂载到 `/home/node/.openclaw` -- `OPENCLAW_WORKSPACE_DIR=...`(默认:`~/.openclaw/workspace`)挂载到 `/home/node/.openclaw/workspace` -- `OPENCLAW_PROFILE_FILE=...`(默认:`~/.profile`)挂载到 `/home/node/.profile`,并在运行测试前 source -- `OPENCLAW_DOCKER_PROFILE_ENV_ONLY=1` 用于验证只使用从 `OPENCLAW_PROFILE_FILE` source 的环境变量,使用临时配置 / 工作区目录,并且不挂载外部 CLI 认证 -- `OPENCLAW_DOCKER_CLI_TOOLS_DIR=...`(默认:`~/.cache/openclaw/docker-cli-tools`)挂载到 `/home/node/.npm-global`,用于 Docker 内缓存 CLI 安装 +- `OPENCLAW_CONFIG_DIR=...`(默认:`~/.openclaw`)会挂载到 `/home/node/.openclaw` +- `OPENCLAW_WORKSPACE_DIR=...`(默认:`~/.openclaw/workspace`)会挂载到 `/home/node/.openclaw/workspace` +- `OPENCLAW_PROFILE_FILE=...`(默认:`~/.profile`)会挂载到 `/home/node/.profile`,并在运行测试前 source +- `OPENCLAW_DOCKER_PROFILE_ENV_ONLY=1` 用于仅验证从 `OPENCLAW_PROFILE_FILE` source 的环境变量,使用临时的配置 / 工作区目录,并且不挂载外部 CLI 认证 +- `OPENCLAW_DOCKER_CLI_TOOLS_DIR=...`(默认:`~/.cache/openclaw/docker-cli-tools`)会挂载到 `/home/node/.npm-global`,用于 Docker 内缓存 CLI 安装 - `$HOME` 下的外部 CLI 认证目录 / 文件会以只读方式挂载到 `/host-auth...` 下,然后在测试开始前复制到 `/home/node/...` - 默认目录:`.minimax` - 默认文件:`~/.codex/auth.json`、`~/.codex/config.toml`、`.claude.json`、`~/.claude/.credentials.json`、`~/.claude/settings.json`、`~/.claude/settings.local.json` - - 缩小提供商范围的运行只会挂载从 `OPENCLAW_LIVE_PROVIDERS` / `OPENCLAW_LIVE_GATEWAY_PROVIDERS` 推断出的所需目录 / 文件 - - 可通过 `OPENCLAW_DOCKER_AUTH_DIRS=all`、`OPENCLAW_DOCKER_AUTH_DIRS=none` 或逗号列表(例如 `OPENCLAW_DOCKER_AUTH_DIRS=.claude,.codex`)手动覆盖 -- `OPENCLAW_LIVE_GATEWAY_MODELS=...` / `OPENCLAW_LIVE_MODELS=...` 用于缩小运行范围 + - 收窄提供商的运行只会挂载从 `OPENCLAW_LIVE_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_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 anchor 验证:`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 网关向导(WS `wizard.start` / `wizard.next`,强制写入 config + auth):`src/gateway/gateway.test.ts`(用例:“runs wizard over ws and writes auth token config”) +- Gateway 网关向导(WS `wizard.start` / `wizard.next`,强制写入配置 + auth):`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.md`,并遵循要求的步骤 / 参数? -- **工作流契约:** 断言工具顺序、会话历史延续和沙箱边界的多轮场景。 +- **决策**:当 Skills 列在提示词中时,智能体是否会选择正确的 Skills(或避开无关项)? +- **合规性**:智能体在使用前是否会读取 `SKILL.md`,并遵循所需步骤 / 参数? +- **工作流契约**:用于断言工具顺序、会话历史延续和沙箱边界的多轮场景。 -未来的评估应首先保持确定性: +未来的评估应优先保持确定性: -- 一个使用模拟提供商的场景运行器,用于断言工具调用 + 顺序、技能文件读取以及会话接线。 -- 一小套面向技能的场景(使用 vs 避免、门禁、提示注入)。 -- 仅在 CI 安全套件就绪之后,再添加可选的实时评估(需显式启用,并受环境变量控制)。 +- 一个使用模拟提供商的场景运行器,用于断言工具调用 + 顺序、skill 文件读取和会话接线。 +- 一小组面向 skill 的场景(使用 vs 避免、门控、提示注入)。 +- 仅在对 CI 安全的测试套件就位之后,再添加可选的 live 评估(选择加入、由环境变量门控)。 -## 契约测试(插件和渠道形状) +## 契约测试(plugin 和 channel 形状) -契约测试用于验证每个已注册的插件和渠道都符合其接口契约。它们会遍历所有已发现的插件,并运行一组关于形状和行为的断言。默认的 `pnpm test` 单元通道会有意跳过这些共享接缝和冒烟文件;当你修改共享渠道或提供商表面时,请显式运行这些契约命令。 +契约测试用于验证每个已注册的插件和渠道都符合其接口契约。它们会遍历所有已发现的插件,并运行一组关于结构与行为的断言。默认的 `pnpm test` 单元测试通道会有意跳过这些共享接缝和冒烟文件;当你修改共享 channel 或 provider 界面时,请显式运行契约命令。 ### 命令 -- 所有契约:`pnpm test:contracts` -- 仅渠道契约:`pnpm test:contracts:channels` -- 仅提供商契约:`pnpm test:contracts:plugins` +- 所有契约测试:`pnpm test:contracts` +- 仅 channel 契约测试:`pnpm test:contracts:channels` +- 仅 provider 契约测试:`pnpm test:contracts:plugins` -### 渠道契约 +### Channel 契约测试 位于 `src/channels/plugins/contracts/*.contract.test.ts`: -- **plugin** - 基本插件形状(id、name、capabilities) +- **plugin** - 基本插件结构(id、name、capabilities) - **setup** - 设置向导契约 - **session-binding** - 会话绑定行为 - **outbound-payload** - 消息负载结构 @@ -640,48 +643,48 @@ OPENCLAW_DOCKER_E2E_IMAGE=openclaw-docker-e2e-functional:local OPENCLAW_SKIP_DOC - **directory** - 目录 / roster API - **group-policy** - 群组策略强制执行 -### 提供商 Status 契约 +### Provider Status 契约测试 位于 `src/plugins/contracts/*.contract.test.ts`。 - **status** - 渠道 Status 探测 -- **registry** - 插件注册表形状 +- **registry** - 插件注册表结构 -### 提供商契约 +### Provider 契约测试 位于 `src/plugins/contracts/*.contract.test.ts`: -- **auth** - 认证流程契约 -- **auth-choice** - 认证选择 / 选择逻辑 +- **auth** - 凭证流程契约 +- **auth-choice** - 凭证选择 / 选择器 - **catalog** - 模型目录 API - **discovery** - 插件发现 - **loader** - 插件加载 -- **runtime** - 提供商运行时 -- **shape** - 插件形状 / 接口 +- **runtime** - provider 运行时 +- **shape** - 插件结构 / 接口 - **wizard** - 设置向导 ### 何时运行 - 修改 `plugin-sdk` 导出或子路径之后 -- 添加或修改渠道或提供商插件之后 -- 重构插件注册或发现逻辑之后 +- 添加或修改 channel 或 provider 插件之后 +- 重构插件注册或发现机制之后 契约测试会在 CI 中运行,不需要真实 API 密钥。 ## 添加回归测试(指南) -当你修复了一个在实时环境中发现的提供商 / 模型问题时: +当你修复一个在 live 中发现的 provider / model 问题时: -- 如果可能,添加一个 CI 安全的回归测试(模拟 / stub 提供商,或捕获精确的请求形状转换) -- 如果问题天然只能在实时环境复现(速率限制、认证策略),就让实时测试保持窄范围,并通过环境变量显式启用 +- 如果可能,添加一个对 CI 安全的回归测试(模拟 / 存根 provider,或捕获精确的请求形状转换) +- 如果它天生只能在 live 中复现(速率限制、认证策略),就保持该 live 测试范围收窄,并通过环境变量选择启用 - 优先瞄准能捕获该缺陷的最小层级: - - 提供商请求转换 / 重放缺陷 → 直接模型测试 - - gateway 会话 / 历史 / 工具流水线缺陷 → gateway 实时冒烟测试或 CI 安全的 gateway 模拟测试 -- SecretRef 遍历防护栏: - - `src/secrets/exec-secret-ref-id-parity.test.ts` 会从注册表元数据(`listSecretTargetRegistryEntries()`)中为每个 SecretRef 类派生一个采样目标,然后断言遍历段执行 ID 会被拒绝。 - - 如果你在 `src/secrets/target-registry-data.ts` 中新增了一个 `includeInPlan` SecretRef 目标族,请更新该测试中的 `classifyTargetClass`。该测试会在目标 ID 未分类时故意失败,这样新类别就不会被悄悄跳过。 + - provider 请求转换 / 重放问题 → 直接模型测试 + - gateway 会话 / 历史 / 工具管道问题 → gateway live 冒烟测试或对 CI 安全的 gateway mock 测试 +- SecretRef 遍历护栏: + - `src/secrets/exec-secret-ref-id-parity.test.ts` 会从注册表元数据(`listSecretTargetRegistryEntries()`)中为每个 SecretRef 类派生一个采样目标,然后断言遍历段 exec id 会被拒绝。 + - 如果你在 `src/secrets/target-registry-data.ts` 中新增一个 `includeInPlan` SecretRef 目标家族,请更新该测试中的 `classifyTargetClass`。该测试会在遇到未分类目标 id 时故意失败,因此新类别不能被静默跳过。 ## 相关内容 -- [测试——实时套件](/zh-CN/help/testing-live) +- [Testing live](/zh-CN/help/testing-live) - [CI](/zh-CN/ci) diff --git a/docs/zh-CN/install/docker.md b/docs/zh-CN/install/docker.md index 63e06d267..9ba7b6ee7 100644 --- a/docs/zh-CN/install/docker.md +++ b/docs/zh-CN/install/docker.md @@ -1,34 +1,34 @@ --- read_when: - - 你想使用容器化的 Gateway 网关,而不是本地安装 + - 你想要一个容器化的 Gateway 网关,而不是本地安装版本 - 你正在验证 Docker 流程 -summary: OpenClaw 的可选 Docker 安装与新手引导 +summary: OpenClaw 的基于 Docker 的可选设置和新手引导 title: Docker x-i18n: - generated_at: "2026-04-27T07:11:35Z" + generated_at: "2026-04-27T08:00:10Z" model: gpt-5.4 provider: openai - source_hash: 56766c90b2751d186b0e9a7b55241fb45f05a37c2e8d7c0d0155b41eefc2177a + source_hash: 434d11db92060c20902db626f48e79077d24446450dd186af820c0a08a773c47 source_path: install/docker.md workflow: 15 --- -Docker **是可选的**。仅当你想使用容器化的 Gateway 网关,或验证 Docker 流程时才使用它。 +Docker **是可选的**。只有当你想要一个容器化的 Gateway 网关,或想验证 Docker 流程时,才使用它。 ## Docker 适合我吗? -- **是**:你想要一个隔离的、可随时丢弃的 Gateway 网关环境,或者想在没有本地安装的主机上运行 OpenClaw。 -- **否**:你是在自己的机器上运行,只想获得最快的开发循环。请改用常规安装流程。 -- **沙箱注意事项**:启用沙箱隔离时,默认的沙箱后端会使用 Docker,但沙箱隔离默认是关闭的,并且**不**要求整个 Gateway 网关都运行在 Docker 中。也可以使用 SSH 和 OpenShell 沙箱后端。参见 [沙箱隔离](/zh-CN/gateway/sandboxing)。 +- **是**:你想要一个隔离的、可随时丢弃的 Gateway 网关环境,或者想在一台不进行本地安装的主机上运行 OpenClaw。 +- **否**:你是在自己的机器上运行,并且只想要最快的开发循环。请改用常规安装流程。 +- **沙箱注意事项**:启用沙箱隔离时,默认的沙箱后端会使用 Docker,但默认情况下沙箱隔离是关闭的,并且**不**要求整个 Gateway 网关都在 Docker 中运行。也可使用 SSH 和 OpenShell 沙箱后端。参见 [沙箱隔离](/zh-CN/gateway/sandboxing)。 -## 前置条件 +## 前提条件 - Docker Desktop(或 Docker Engine)+ Docker Compose v2 -- 至少 2 GB 内存用于构建镜像(在 1 GB 主机上,`pnpm install` 可能因 OOM 被杀死并以 137 退出) -- 足够的磁盘空间用于镜像和日志 +- 镜像构建至少需要 2 GB 内存(在 1 GB 主机上,`pnpm install` 可能会因 OOM 被终止,并以退出码 137 结束) +- 足够的磁盘空间用于存储镜像和日志 - 如果在 VPS/公网主机上运行,请查看 [网络暴露的安全加固](/zh-CN/gateway/security), - 尤其是 Docker `DOCKER-USER` 防火墙策略。 + 特别是 Docker `DOCKER-USER` 防火墙策略。 ## 容器化 Gateway 网关 @@ -40,7 +40,7 @@ Docker **是可选的**。仅当你想使用容器化的 Gateway 网关,或验 ./scripts/docker/setup.sh ``` - 这会在本地构建 Gateway 网关镜像。若要改用预构建镜像,请使用: + 这会在本地构建 Gateway 网关镜像。若要改用预构建镜像,请执行: ```bash export OPENCLAW_IMAGE="ghcr.io/openclaw/openclaw:latest" @@ -57,17 +57,18 @@ Docker **是可选的**。仅当你想使用容器化的 Gateway 网关,或验 设置脚本会自动运行新手引导。它将会: - 提示你输入提供商 API 密钥 - - 生成一个 Gateway 网关令牌并写入 `.env` + - 生成一个 Gateway 网关令牌并将其写入 `.env` - 通过 Docker Compose 启动 Gateway 网关 在设置过程中,启动前的新手引导和配置写入会直接通过 - `openclaw-gateway` 完成。`openclaw-cli` 用于在 - Gateway 网关容器已经存在之后再运行的命令。 + `openclaw-gateway` 执行。`openclaw-cli` 用于在 + Gateway 网关容器已经存在之后再执行的命令。 - 在浏览器中打开 `http://127.0.0.1:18789/`,然后将已配置的共享密钥粘贴到设置中。设置脚本默认会将令牌写入 `.env`;如果你把容器配置切换为密码认证,请改用该密码。 + 在浏览器中打开 `http://127.0.0.1:18789/`,然后将已配置的 + 共享密钥粘贴到 Settings 中。设置脚本默认会把令牌写入 `.env`;如果你把容器配置切换为密码认证,请改用该密码。 需要再次获取 URL 吗? @@ -91,14 +92,14 @@ Docker **是可选的**。仅当你想使用容器化的 Gateway 网关,或验 docker compose run --rm openclaw-cli channels add --channel discord --token "" ``` - 文档: [WhatsApp](/zh-CN/channels/whatsapp)、[Telegram](/zh-CN/channels/telegram)、[Discord](/zh-CN/channels/discord) + 文档:[WhatsApp](/zh-CN/channels/whatsapp)、[Telegram](/zh-CN/channels/telegram)、[Discord](/zh-CN/channels/discord) ### 手动流程 -如果你更喜欢自己逐步执行每一步,而不是使用设置脚本: +如果你更喜欢自己逐步执行,而不是使用设置脚本: ```bash docker build -t openclaw:local -f Dockerfile . @@ -116,41 +117,43 @@ docker compose up -d openclaw-gateway -由于 `openclaw-cli` 与 `openclaw-gateway` 共享网络命名空间,它是一个启动后的工具。在 `docker compose up -d openclaw-gateway` 之前,请通过带有 -`--no-deps --entrypoint node` 的 `openclaw-gateway` 运行新手引导和设置期间的配置写入。 +由于 `openclaw-cli` 与 `openclaw-gateway` 共享网络命名空间,因此它是一个 +启动后的工具。在执行 `docker compose up -d openclaw-gateway` 之前,请通过 +`openclaw-gateway` 配合 `--no-deps --entrypoint node` +来运行新手引导和设置期间的配置写入。 ### 环境变量 -设置脚本支持以下可选环境变量: +设置脚本接受以下可选环境变量: -| Variable | Purpose | +| 变量 | 用途 | | ------------------------------------------ | --------------------------------------------------------------- | -| `OPENCLAW_IMAGE` | 使用远程镜像而不是在本地构建 | -| `OPENCLAW_DOCKER_APT_PACKAGES` | 在构建期间安装额外的 apt 软件包(以空格分隔) | -| `OPENCLAW_EXTENSIONS` | 在构建时预安装插件依赖(以空格分隔名称) | -| `OPENCLAW_EXTRA_MOUNTS` | 额外的主机绑定挂载(以逗号分隔的 `source:target[:opts]`) | -| `OPENCLAW_HOME_VOLUME` | 在具名 Docker 卷中持久化 `/home/node` | -| `OPENCLAW_SANDBOX` | 选择启用沙箱引导(`1`、`true`、`yes`、`on`) | -| `OPENCLAW_DOCKER_SOCKET` | 覆盖 Docker socket 路径 | -| `OPENCLAW_DISABLE_BONJOUR` | 禁用 Bonjour/mDNS 广播(Docker 默认值为 `1`) | +| `OPENCLAW_IMAGE` | 使用远程镜像,而不是在本地构建 | +| `OPENCLAW_DOCKER_APT_PACKAGES` | 在构建期间安装额外的 apt 软件包(以空格分隔) | +| `OPENCLAW_EXTENSIONS` | 在构建时预安装插件依赖(以空格分隔的名称) | +| `OPENCLAW_EXTRA_MOUNTS` | 额外的主机绑定挂载(以逗号分隔的 `source:target[:opts]`) | +| `OPENCLAW_HOME_VOLUME` | 将 `/home/node` 持久化到一个命名的 Docker 卷 | +| `OPENCLAW_SANDBOX` | 选择启用沙箱引导初始化(`1`、`true`、`yes`、`on`) | +| `OPENCLAW_DOCKER_SOCKET` | 覆盖 Docker socket 路径 | +| `OPENCLAW_DISABLE_BONJOUR` | 禁用 Bonjour/mDNS 广播(Docker 默认值为 `1`) | | `OPENCLAW_DISABLE_BUNDLED_SOURCE_OVERLAYS` | 禁用内置插件源码绑定挂载覆盖 | -| `OTEL_EXPORTER_OTLP_ENDPOINT` | 用于 OpenTelemetry 导出的共享 OTLP/HTTP 收集器端点 | -| `OTEL_EXPORTER_OTLP_*_ENDPOINT` | 用于 traces、metrics 或 logs 的各信号专用 OTLP 端点 | -| `OTEL_EXPORTER_OTLP_PROTOCOL` | OTLP 协议覆盖。当前仅支持 `http/protobuf` | -| `OTEL_SERVICE_NAME` | 用于 OpenTelemetry 资源的服务名称 | -| `OTEL_SEMCONV_STABILITY_OPT_IN` | 选择启用最新的实验性 GenAI 语义属性 | -| `OPENCLAW_OTEL_PRELOADED` | 当已预加载一个 OpenTelemetry SDK 时,跳过启动第二个 | +| `OTEL_EXPORTER_OTLP_ENDPOINT` | 用于 OpenTelemetry 导出的共享 OTLP/HTTP 收集器端点 | +| `OTEL_EXPORTER_OTLP_*_ENDPOINT` | 用于 traces、metrics 或 logs 的按信号划分的 OTLP 端点 | +| `OTEL_EXPORTER_OTLP_PROTOCOL` | OTLP 协议覆盖。目前仅支持 `http/protobuf` | +| `OTEL_SERVICE_NAME` | 用于 OpenTelemetry 资源的服务名称 | +| `OTEL_SEMCONV_STABILITY_OPT_IN` | 选择启用最新的实验性 GenAI 语义属性 | +| `OPENCLAW_OTEL_PRELOADED` | 当已有预加载实例时,跳过启动第二个 OpenTelemetry SDK | -维护者可以通过把某个插件源码目录挂载到其打包后的源码路径之上,来针对打包镜像测试内置插件源码,例如 +维护者可以通过将某个插件源码目录挂载到其打包后的源码路径之上,在打包镜像中测试内置插件源码,例如 `OPENCLAW_EXTRA_MOUNTS=/path/to/fork/extensions/synology-chat:/app/extensions/synology-chat:ro`。 -该已挂载的源码目录会覆盖相同插件 id 对应的已编译 -`/app/dist/extensions/synology-chat` 包。 +该挂载的源码目录会覆盖同一插件 id 对应的已编译 +`/app/dist/extensions/synology-chat` bundle。 ### 可观测性 OpenTelemetry 导出是从 Gateway 网关容器向你的 OTLP -collector 发起的出站连接。它不需要发布 Docker 端口。如果你在本地构建镜像,并希望镜像中包含可用的内置 OpenTelemetry exporter,请加入其运行时依赖: +收集器发起的出站连接。它不需要发布 Docker 端口。如果你在本地构建镜像,并希望镜像中包含可用的内置 OpenTelemetry 导出器,请加入其运行时依赖: ```bash export OPENCLAW_EXTENSIONS="diagnostics-otel" @@ -160,24 +163,27 @@ export OTEL_SERVICE_NAME="openclaw-gateway" ``` 官方 OpenClaw Docker 发布镜像包含内置的 -`diagnostics-otel` 插件源码。根据镜像和缓存状态,Gateway 网关在首次启用该插件时,可能仍需暂存插件本地的 OpenTelemetry 运行时依赖,因此请确保首次启动时可以访问软件包注册表,或在你的发布流程中预热镜像。要启用导出,请在配置中允许并启用 `diagnostics-otel` 插件,然后设置 +`diagnostics-otel` 插件源码。根据镜像和缓存状态的不同, +在首次启用该插件时,Gateway 网关仍可能需要暂存插件本地的 OpenTelemetry 运行时依赖,因此请确保首次启动时能够访问软件包注册表,或在你的发布流程中预热镜像。要启用导出,请先在配置中允许并启用 +`diagnostics-otel` 插件,然后设置 `diagnostics.otel.enabled=true`,或使用 -[OpenTelemetry 导出](/zh-CN/gateway/opentelemetry) 中的配置示例。collector 认证头通过 +[OpenTelemetry 导出](/zh-CN/gateway/opentelemetry) 中的配置示例。收集器认证头通过 `diagnostics.otel.headers` 配置,而不是通过 Docker 环境变量配置。 Prometheus 指标使用已经发布的 Gateway 网关端口。启用 -`diagnostics-prometheus` 插件后,抓取: +`diagnostics-prometheus` 插件后,抓取以下地址: ```text http://:18789/api/diagnostics/prometheus ``` -该路由受 Gateway 网关认证保护。不要暴露单独的公共 `/metrics` 端口,也不要暴露未认证的反向代理路径。参见 +该路由受 Gateway 网关认证保护。不要暴露单独的公共 +`/metrics` 端口,也不要提供未经认证的反向代理路径。参见 [Prometheus 指标](/zh-CN/gateway/prometheus)。 ### 健康检查 -容器探针端点(无需认证): +容器探测端点(无需认证): ```bash curl -fsS http://127.0.0.1:18789/healthz # 存活检查 @@ -188,7 +194,7 @@ Docker 镜像内置了一个 `HEALTHCHECK`,会探测 `/healthz`。 如果检查持续失败,Docker 会将容器标记为 `unhealthy`, 编排系统即可重启或替换它。 -需要认证的深度健康状态快照: +需要认证的深度健康快照: ```bash docker compose exec openclaw-gateway node dist/index.js health --token "$OPENCLAW_GATEWAY_TOKEN" @@ -196,8 +202,8 @@ docker compose exec openclaw-gateway node dist/index.js health --token "$OPENCLA ### LAN 与 loopback -`scripts/docker/setup.sh` 默认设置 `OPENCLAW_GATEWAY_BIND=lan`,因此通过 Docker 端口发布时,主机可以访问 -`http://127.0.0.1:18789`。 +`scripts/docker/setup.sh` 默认将 `OPENCLAW_GATEWAY_BIND=lan`,以便主机可以通过 +Docker 端口发布访问 `http://127.0.0.1:18789`。 - `lan`(默认):主机浏览器和主机 CLI 都可以访问已发布的 Gateway 网关端口。 - `loopback`:只有容器网络命名空间内的进程可以直接访问 @@ -205,50 +211,76 @@ docker compose exec openclaw-gateway node dist/index.js health --token "$OPENCLA 请在 `gateway.bind` 中使用绑定模式值(`lan` / `loopback` / `custom` / -`tailnet` / `auto`),不要使用主机别名,例如 `0.0.0.0` 或 `127.0.0.1`。 +`tailnet` / `auto`),不要使用主机别名,如 `0.0.0.0` 或 `127.0.0.1`。 +### 主机本地提供商 + +当 OpenClaw 在 Docker 中运行时,容器内的 `127.0.0.1` 指向的是容器自身, +而不是你的主机。对于运行在主机上的 AI 提供商,请使用 `host.docker.internal`: + +| Provider | 主机默认 URL | Docker 设置 URL | +| --------- | ------------------------ | ----------------------------------- | +| LM Studio | `http://127.0.0.1:1234` | `http://host.docker.internal:1234` | +| Ollama | `http://127.0.0.1:11434` | `http://host.docker.internal:11434` | + +内置的 Docker 设置会将这些主机 URL 用作 LM Studio 和 Ollama +在新手引导期间的默认值,并且 `docker-compose.yml` 会在 Linux Docker Engine 上将 +`host.docker.internal` 映射到 Docker 的 host gateway。Docker Desktop 在 macOS 和 Windows 上已默认提供同名主机名。 + +主机服务还必须监听一个 Docker 可访问的地址: + +```bash +lms server start --port 1234 --bind 0.0.0.0 +OLLAMA_HOST=0.0.0.0:11434 ollama serve +``` + +如果你使用自己的 Compose 文件或 `docker run` 命令,请自行添加相同的主机映射,例如 +`--add-host=host.docker.internal:host-gateway`。 + ### Bonjour / mDNS -Docker bridge 网络通常无法可靠地转发 Bonjour/mDNS 多播 -(`224.0.0.251:5353`)。因此,内置的 Compose 设置默认使用 -`OPENCLAW_DISABLE_BONJOUR=1`,以避免 Gateway 网关因桥接网络丢弃多播流量而崩溃循环或反复重启广播。 +Docker bridge 网络通常无法可靠地转发 Bonjour/mDNS 组播 +(`224.0.0.251:5353`)。因此,内置的 Compose 设置默认启用 +`OPENCLAW_DISABLE_BONJOUR=1`,这样 Gateway 网关就不会因为 bridge 丢失组播流量而崩溃重启或反复重新启动广播。 -对于 Docker 主机,请使用已发布的 Gateway 网关 URL、Tailscale 或广域 DNS-SD。仅当你运行在 host networking、macvlan 或其他已知支持 mDNS 多播的网络中时,才将 `OPENCLAW_DISABLE_BONJOUR=0`。 +对于 Docker 主机,请使用已发布的 Gateway 网关 URL、Tailscale 或广域 DNS-SD。 +只有在使用 host networking、macvlan +或其他已知支持 mDNS 组播的网络时,才将 `OPENCLAW_DISABLE_BONJOUR=0`。 -有关注意事项和故障排除,请参见 [Bonjour 设备发现](/zh-CN/gateway/bonjour)。 +如需了解常见问题和故障排除,请参见 [Bonjour 设备发现](/zh-CN/gateway/bonjour)。 ### 存储与持久化 -Docker Compose 会将 `OPENCLAW_CONFIG_DIR` 绑定挂载到 `/home/node/.openclaw`,并将 -`OPENCLAW_WORKSPACE_DIR` 绑定挂载到 `/home/node/.openclaw/workspace`,因此这些路径在容器被替换后仍会保留。 +Docker Compose 会将 `OPENCLAW_CONFIG_DIR` 绑定挂载到 `/home/node/.openclaw`, +并将 `OPENCLAW_WORKSPACE_DIR` 绑定挂载到 `/home/node/.openclaw/workspace`,因此这些路径在容器替换后仍会保留。 -这个已挂载的配置目录是 OpenClaw 存储以下内容的位置: +该挂载的配置目录是 OpenClaw 存储以下内容的位置: - 用于行为配置的 `openclaw.json` -- 用于已存储提供商 OAuth/API 密钥认证的 `agents//agent/auth-profiles.json` -- 用于基于环境变量的运行时密钥(例如 `OPENCLAW_GATEWAY_TOKEN`)的 `.env` +- 用于存储提供商 OAuth/API-key 认证的 `agents//agent/auth-profiles.json` +- 用于存储基于环境变量的运行时密钥(如 `OPENCLAW_GATEWAY_TOKEN`)的 `.env` -关于 VM 部署中持久化细节的完整说明,请参见 -[Docker VM Runtime - What persists where](/zh-CN/install/docker-vm-runtime#what-persists-where)。 +如需了解 VM 部署中的完整持久化细节,请参见 +[Docker VM Runtime - 持久化内容及其位置](/zh-CN/install/docker-vm-runtime#what-persists-where)。 **磁盘增长热点:** 请关注 `media/`、会话 JSONL 文件、`cron/runs/*.jsonl`, 以及 `/tmp/openclaw/` 下的滚动文件日志。 -### Shell 助手(可选) +### Shell 辅助工具(可选) -为了更轻松地进行日常 Docker 管理,请安装 `ClawDock`: +为了更方便地进行日常 Docker 管理,请安装 `ClawDock`: ```bash mkdir -p ~/.clawdock && curl -sL https://raw.githubusercontent.com/openclaw/openclaw/main/scripts/clawdock/clawdock-helpers.sh -o ~/.clawdock/clawdock-helpers.sh echo 'source ~/.clawdock/clawdock-helpers.sh' >> ~/.zshrc && source ~/.zshrc ``` -如果你之前是通过旧的 `scripts/shell-helpers/clawdock-helpers.sh` 原始路径安装 ClawDock 的,请重新运行上面的安装命令,以便你的本地 helper 文件跟踪新位置。 +如果你是通过较旧的原始路径 `scripts/shell-helpers/clawdock-helpers.sh` 安装的 ClawDock,请重新运行上面的安装命令,以便你的本地辅助文件跟踪新位置。 -然后你就可以使用 `clawdock-start`、`clawdock-stop`、`clawdock-dashboard` 等命令。 -运行 `clawdock-help` 查看全部命令。 -完整 helper 指南请参见 [ClawDock](/zh-CN/install/clawdock)。 +然后使用 `clawdock-start`、`clawdock-stop`、`clawdock-dashboard` 等命令。运行 +`clawdock-help` 可查看所有命令。 +完整的辅助工具指南请参见 [ClawDock](/zh-CN/install/clawdock)。 @@ -265,7 +297,8 @@ echo 'source ~/.clawdock/clawdock-helpers.sh' >> ~/.zshrc && source ~/.zshrc ./scripts/docker/setup.sh ``` - 只有在沙箱前置条件检查通过后,脚本才会挂载 `docker.sock`。如果沙箱设置无法完成,脚本会将 `agents.defaults.sandbox.mode` + 该脚本只有在沙箱前提条件通过后才会挂载 `docker.sock`。如果 + 沙箱设置无法完成,脚本会将 `agents.defaults.sandbox.mode` 重置为 `off`。 @@ -281,9 +314,10 @@ echo 'source ~/.clawdock/clawdock-helpers.sh' >> ~/.zshrc && source ~/.zshrc - `openclaw-cli` 使用 `network_mode: "service:openclaw-gateway"`,这样 CLI - 命令就可以通过 `127.0.0.1` 访问 Gateway 网关。请将其视为一个共享信任边界。Compose 配置在 `openclaw-cli` 上移除了 `NET_RAW`/`NET_ADMIN`,并启用了 - `no-new-privileges`。 + `openclaw-cli` 使用 `network_mode: "service:openclaw-gateway"`,因此 CLI + 命令可以通过 `127.0.0.1` 访问 Gateway 网关。请将此视为一个共享的 + 信任边界。compose 配置会移除 `NET_RAW`/`NET_ADMIN`,并在 + `openclaw-cli` 上启用 `no-new-privileges`。 @@ -297,8 +331,8 @@ echo 'source ~/.clawdock/clawdock-helpers.sh' >> ~/.zshrc && source ~/.zshrc - 请按依赖层可缓存的方式组织你的 Dockerfile。这样可以避免在 lockfile 未变化时重复运行 - `pnpm install`: + 请按依赖层可缓存的方式安排你的 Dockerfile。这可避免在锁文件未变化时 + 重新运行 `pnpm install`: ```dockerfile FROM node:24-bookworm @@ -331,42 +365,48 @@ echo 'source ~/.clawdock/clawdock-helpers.sh' >> ~/.zshrc && source ~/.zshrc node /app/node_modules/playwright-core/cli.js install chromium ``` 4. **持久化浏览器下载内容**:设置 - `PLAYWRIGHT_BROWSERS_PATH=/home/node/.cache/ms-playwright` 并使用 + `PLAYWRIGHT_BROWSERS_PATH=/home/node/.cache/ms-playwright`,并使用 `OPENCLAW_HOME_VOLUME` 或 `OPENCLAW_EXTRA_MOUNTS`。 如果你在向导中选择 OpenAI Codex OAuth,它会打开一个浏览器 URL。在 - Docker 或无头环境中,请复制你最终跳转到的完整重定向 URL,并将其粘贴回向导中以完成认证。 + Docker 或无头环境中,请复制你最终跳转到的完整重定向 URL,并将其粘贴回 + 向导中以完成认证。 主 Docker 运行时镜像使用 `node:24-bookworm-slim`,并发布 OCI 基础镜像注解,包括 `org.opencontainers.image.base.name`、 - `org.opencontainers.image.source` 等。Node 基础镜像摘要会通过 Dependabot 的 Docker 基础镜像 PR 刷新;发布构建不会运行发行版升级层。参见 - [OCI image annotations](https://github.com/opencontainers/image-spec/blob/main/annotations.md)。 + `org.opencontainers.image.source` 等。Node 基础镜像摘要 + 会通过 Dependabot 的 Docker 基础镜像 PR 刷新;发布构建不会运行 + 发行版升级层。参见 + [OCI 镜像注解](https://github.com/opencontainers/image-spec/blob/main/annotations.md)。 ### 在 VPS 上运行? -共享 VM 部署步骤(包括二进制预置、持久化和更新)请参见 +有关共享 VM 部署步骤,包括二进制预烘焙、持久化和更新,请参见 [Hetzner(Docker VPS)](/zh-CN/install/hetzner) 和 [Docker VM Runtime](/zh-CN/install/docker-vm-runtime)。 ## 智能体沙箱 -当使用 Docker 后端启用 `agents.defaults.sandbox` 时,Gateway 网关会在隔离的 Docker -容器中运行智能体工具执行(shell、文件读写等),而 Gateway 网关本身仍保留在主机上运行。这能在不将整个 Gateway 网关容器化的情况下,为不受信任或多租户智能体会话提供一道强隔离边界。 +当通过 Docker 后端启用 `agents.defaults.sandbox` 时,Gateway 网关会在隔离的 Docker +容器中运行智能体工具执行(shell、文件读写等),而 Gateway 网关本身仍运行在主机上。这为不受信任或多租户的智能体会话提供了一道硬隔离边界,而无需将整个 +Gateway 网关都容器化。 -沙箱作用域可以是每个智能体(默认)、每个会话,或共享。每种作用域都会获得其自己的工作区,并挂载到 `/workspace`。你还可以配置工具允许/拒绝策略、网络隔离、资源限制和浏览器容器。 +沙箱范围可以按智能体(默认)、按会话,或共享。每种范围 +都会获得自己挂载到 `/workspace` 的工作区。你还可以配置 +工具允许/拒绝策略、网络隔离、资源限制以及浏览器容器。 -有关完整配置、镜像、安全说明和多智能体配置文件,请参见: +完整配置、镜像、安全说明和多智能体配置文件请参见: - [沙箱隔离](/zh-CN/gateway/sandboxing) -- 完整的沙箱参考 - [OpenShell](/zh-CN/gateway/openshell) -- 对沙箱容器的交互式 shell 访问 -- [Multi-Agent Sandbox and Tools](/zh-CN/tools/multi-agent-sandbox-tools) -- 每个智能体的覆盖配置 +- [Multi-Agent Sandbox and Tools](/zh-CN/tools/multi-agent-sandbox-tools) -- 按智能体覆盖 ### 快速启用 @@ -392,11 +432,11 @@ scripts/sandbox-setup.sh ## 故障排除 - + 使用 [`scripts/sandbox-setup.sh`](https://github.com/openclaw/openclaw/blob/main/scripts/sandbox-setup.sh) 构建沙箱镜像,或将 `agents.defaults.sandbox.docker.image` 设置为你的自定义镜像。 - 容器会按需为每个会话自动创建。 + 容器会在会话按需创建时自动生成。 @@ -404,17 +444,18 @@ scripts/sandbox-setup.sh 或对工作区文件夹执行 chown。 - - OpenClaw 使用 `sh -lc`(登录 shell)运行命令,这会加载 - `/etc/profile` 并且可能重置 PATH。请设置 `docker.env.PATH` 以预先添加你的自定义工具路径,或在你的 Dockerfile 中向 `/etc/profile.d/` 添加脚本。 + + OpenClaw 使用 `sh -lc`(登录 shell)运行命令,它会加载 + `/etc/profile`,并且可能重置 PATH。请设置 `docker.env.PATH` 以预先加入你的 + 自定义工具路径,或在 Dockerfile 中向 `/etc/profile.d/` 添加脚本。 - - VM 至少需要 2 GB 内存。请使用更大的机器规格后重试。 + + VM 至少需要 2 GB 内存。请使用更大规格的机器后重试。 - - 获取新的 dashboard 链接并批准浏览器设备: + + 获取一个新的仪表盘链接并批准该浏览器设备: ```bash docker compose run --rm openclaw-cli dashboard --no-open @@ -422,11 +463,11 @@ scripts/sandbox-setup.sh docker compose run --rm openclaw-cli devices approve ``` - 更多详情: [Dashboard](/zh-CN/web/dashboard)、[Devices](/zh-CN/cli/devices)。 + 更多细节: [Dashboard](/zh-CN/web/dashboard)、[Devices](/zh-CN/cli/devices)。 - + 重置 Gateway 网关模式和绑定: ```bash diff --git a/docs/zh-CN/plugins/architecture.md b/docs/zh-CN/plugins/architecture.md index 936859bbc..588c8c324 100644 --- a/docs/zh-CN/plugins/architecture.md +++ b/docs/zh-CN/plugins/architecture.md @@ -6,24 +6,24 @@ read_when: - 实现提供商运行时钩子或渠道插件 sidebarTitle: Internals summary: 插件内部机制:能力模型、归属、契约、加载管线和运行时辅助工具 -title: 插件架构内部机制 +title: 插件内部机制 x-i18n: - generated_at: "2026-04-26T07:50:09Z" + generated_at: "2026-04-27T08:00:17Z" model: gpt-5.4 provider: openai - source_hash: 16664d284a8bfbfcb9914bb012d1f36dfdd60406636d6bf4b011f76e886cb518 + source_hash: 5b7622b361c6d19069106785f2b80cb3155e58f9a27a2fac9733e976d7c27f13 source_path: plugins/architecture.md workflow: 15 --- -这是 OpenClaw 插件系统的**深度架构参考**。如果你想看实用指南,请先从下面这些聚焦页面之一开始。 +这是 OpenClaw 插件系统的**深度架构参考**。如需实用指南,请先从下面其中一个聚焦页面开始。 - 面向最终用户的指南,介绍如何添加、启用以及排查插件问题。 + 面向终端用户的指南,介绍如何添加、启用和故障排除插件。 - 第一个插件教程,包含最小可工作的 manifest。 + 使用最小可运行 manifest 的首个插件教程。 构建一个消息渠道插件。 @@ -31,46 +31,46 @@ x-i18n: 构建一个模型提供商插件。 - - 导入映射和注册 API 参考。 + + import map 和注册 API 参考。 -## 公共能力模型 +## 公开能力模型 -能力是 OpenClaw 内部公共的**原生插件**模型。每个原生 OpenClaw 插件都会针对一种或多种能力类型进行注册: +能力是 OpenClaw 内部公开的**原生插件**模型。每个原生 OpenClaw 插件都会针对一种或多种能力类型进行注册: | 能力 | 注册方法 | 示例插件 | | ---------------------- | ------------------------------------------------ | ------------------------------------ | -| 文本推理 | `api.registerProvider(...)` | `openai`、`anthropic` | -| CLI 推理后端 | `api.registerCliBackend(...)` | `openai`、`anthropic` | -| 语音 | `api.registerSpeechProvider(...)` | `elevenlabs`、`microsoft` | -| 实时转写 | `api.registerRealtimeTranscriptionProvider(...)` | `openai` | +| 文本推理 | `api.registerProvider(...)` | `openai`, `anthropic` | +| CLI 推理后端 | `api.registerCliBackend(...)` | `openai`, `anthropic` | +| 语音 | `api.registerSpeechProvider(...)` | `elevenlabs`, `microsoft` | +| 实时转录 | `api.registerRealtimeTranscriptionProvider(...)` | `openai` | | 实时语音 | `api.registerRealtimeVoiceProvider(...)` | `openai` | -| 媒体理解 | `api.registerMediaUnderstandingProvider(...)` | `openai`、`google` | -| 图像生成 | `api.registerImageGenerationProvider(...)` | `openai`、`google`、`fal`、`minimax` | -| 音乐生成 | `api.registerMusicGenerationProvider(...)` | `google`、`minimax` | +| 媒体理解 | `api.registerMediaUnderstandingProvider(...)` | `openai`, `google` | +| 图像生成 | `api.registerImageGenerationProvider(...)` | `openai`, `google`, `fal`, `minimax` | +| 音乐生成 | `api.registerMusicGenerationProvider(...)` | `google`, `minimax` | | 视频生成 | `api.registerVideoGenerationProvider(...)` | `qwen` | | Web 抓取 | `api.registerWebFetchProvider(...)` | `firecrawl` | | Web 搜索 | `api.registerWebSearchProvider(...)` | `google` | -| 渠道 / 消息传递 | `api.registerChannel(...)` | `msteams`、`matrix` | +| 渠道 / 消息 | `api.registerChannel(...)` | `msteams`, `matrix` | | Gateway 网关发现 | `api.registerGatewayDiscoveryService(...)` | `bonjour` | -一个注册了零能力、但提供钩子、工具、发现服务或后台服务的插件,属于**旧式纯钩子**插件。该模式目前仍然被完全支持。 +一个注册了零能力、但提供钩子、工具、发现服务或后台服务的插件,属于**旧版仅钩子**插件。这种模式仍然得到完整支持。 ### 外部兼容性立场 -能力模型已经落地到核心中,并已被今天的内置 / 原生插件使用,但外部插件兼容性仍然需要比“它已导出,因此它已冻结”更严格的标准。 +能力模型已经在核心中落地,并已被当前内置/原生插件使用,但外部插件兼容性仍需要比“它已导出,因此它已冻结”更严格的标准。 -| 插件情况 | 指导原则 | +| 插件情况 | 指导建议 | | ------------------------------------------------- | ------------------------------------------------------------------------------------------------ | -| 现有外部插件 | 保持基于钩子的集成可用;这是兼容性的基线。 | -| 新的内置 / 原生插件 | 优先使用显式能力注册,而不是针对特定厂商的深入调用或新的纯钩子设计。 | -| 采用能力注册的外部插件 | 允许,但除非文档将其标记为稳定,否则应将特定能力的辅助表面视为仍在演进中。 | +| 现有外部插件 | 保持基于钩子的集成继续工作;这是兼容性的基线。 | +| 新的内置/原生插件 | 优先选择显式能力注册,而不是特定厂商的深层接入或新的仅钩子设计。 | +| 采用能力注册的外部插件 | 允许,但除非文档将能力专用辅助接口标记为稳定,否则应将其视为仍在演进中。 | -能力注册是预期的发展方向。在过渡期间,旧式钩子仍然是对外部插件最安全、最不易破坏的路径。已导出的辅助子路径并不都同样稳定——应优先使用范围收窄、且有文档说明的契约,而不是偶然暴露出来的辅助导出。 +能力注册是预期的发展方向。在过渡期间,对于外部插件,旧版钩子仍然是最安全、最不容易破坏兼容性的路径。导出的辅助子路径并不都具有同等稳定性——请优先使用文档化的窄接口契约,而不是偶然暴露的辅助导出。 ### 插件形态 @@ -78,32 +78,32 @@ OpenClaw 会根据每个已加载插件的实际注册行为(而不只是静 - 只注册一种能力类型(例如像 `mistral` 这样的仅提供商插件)。 + 仅注册一种能力类型(例如仅提供商插件 `mistral`)。 注册多种能力类型(例如 `openai` 同时拥有文本推理、语音、媒体理解和图像生成)。 - 只注册钩子(类型化或自定义),不注册任何能力、工具、命令或服务。 + 仅注册钩子(类型化或自定义),不注册能力、工具、命令或服务。 注册工具、命令、服务或路由,但不注册能力。 -使用 `openclaw plugins inspect ` 可以查看插件的形态和能力拆分。详情请参见 [CLI 参考](/zh-CN/cli/plugins#inspect)。 +使用 `openclaw plugins inspect ` 可查看插件的形态和能力明细。详见 [CLI 参考](/zh-CN/cli/plugins#inspect)。 -### 旧式钩子 +### 旧版钩子 -`before_agent_start` 钩子仍然作为纯钩子插件的兼容路径被支持。现实中的旧插件仍然依赖它。 +`before_agent_start` 钩子仍然作为仅钩子插件的兼容路径受到支持。现有真实插件仍然依赖它。 方向如下: - 保持其可用 -- 在文档中标记为旧式 -- 涉及模型 / 提供商覆盖工作时,优先使用 `before_model_resolve` -- 涉及提示词变更工作时,优先使用 `before_prompt_build` -- 仅在真实使用下降,且 fixture 覆盖证明迁移安全之后,才移除 +- 在文档中将其标记为旧版 +- 对于模型/提供商覆盖工作,优先使用 `before_model_resolve` +- 对于提示词变更工作,优先使用 `before_prompt_build` +- 仅在真实使用量下降且夹具覆盖证明迁移安全后再移除 ### 兼容性信号 @@ -111,76 +111,90 @@ OpenClaw 会根据每个已加载插件的实际注册行为(而不只是静 | 信号 | 含义 | | -------------------------- | ------------------------------------------------------------ | -| **config valid** | 配置解析正常,插件可解析 | -| **compatibility advisory** | 插件使用了受支持但较旧的模式(例如 `hook-only`) | -| **legacy warning** | 插件使用了 `before_agent_start`,该功能已弃用 | -| **hard error** | 配置无效,或插件加载失败 | +| **配置有效** | 配置解析正常,且插件解析成功 | +| **兼容性提示** | 插件使用受支持但较旧的模式(例如 `hook-only`) | +| **旧版警告** | 插件使用 `before_agent_start`,该机制已弃用 | +| **硬错误** | 配置无效或插件加载失败 | -如今,`hook-only` 和 `before_agent_start` 都不会破坏你的插件:`hook-only` 只是提示信息,而 `before_agent_start` 只会触发警告。这些信号也会出现在 `openclaw status --all` 和 `openclaw plugins doctor` 中。 +`hook-only` 和 `before_agent_start` 目前都不会导致你的插件失效:`hook-only` 只是提示信息,而 `before_agent_start` 只会触发警告。这些信号也会显示在 `openclaw status --all` 和 `openclaw plugins doctor` 中。 ## 架构概览 -OpenClaw 的插件系统有四层: +OpenClaw 的插件系统分为四层: - OpenClaw 会从已配置路径、工作区根目录、全局插件根目录以及内置插件中查找候选插件。设备发现会优先读取原生 `openclaw.plugin.json` manifest 以及受支持的 bundle manifest。 + OpenClaw 会从已配置路径、工作区根目录、全局插件根目录以及内置插件中查找候选插件。设备发现会先读取原生 `openclaw.plugin.json` manifest 以及受支持 bundle 的 manifest。 - 核心决定某个已发现插件是启用、禁用、阻止,还是被选中用于某个独占插槽,例如 memory。 + 核心决定已发现的插件是启用、禁用、阻止,还是被选入某个独占槽位(例如 memory)。 - 原生 OpenClaw 插件会通过 jiti 在进程内加载,并将能力注册到中央注册表中。兼容的 bundle 会被标准化为注册表记录,而无需导入运行时代码。 + 原生 OpenClaw 插件通过 jiti 在进程内加载,并将能力注册到中央注册表中。兼容 bundle 会被规范化为注册表记录,而无需导入运行时代码。 OpenClaw 的其余部分会读取注册表,以暴露工具、渠道、提供商设置、钩子、HTTP 路由、CLI 命令和服务。 -就插件 CLI 而言,根命令发现分为两个阶段: +具体到插件 CLI,根命令发现分为两个阶段: - 解析时元数据来自 `registerCli(..., { descriptors: [...] })` -- 真正的插件 CLI 模块可以保持懒加载,并在第一次调用时注册 +- 实际的插件 CLI 模块可以保持惰性,并在首次调用时注册 -这样既能让插件自有的 CLI 代码保留在插件内部,又能让 OpenClaw 在解析前预留根命令名称。 +这样既能将插件拥有的 CLI 代码保留在插件内部,又能让 OpenClaw 在解析之前预留根命令名称。 重要的设计边界是: -- manifest / 配置验证应仅根据 **manifest / schema 元数据** 即可完成,而无需执行插件代码 -- 原生能力发现可以加载受信任的插件入口代码,以构建一个不激活的注册表快照 -- 原生运行时行为来自插件模块的 `register(api)` 路径,并带有 `api.registrationMode === "full"` +- manifest/配置验证应当仅依据**manifest/schema 元数据**完成,而不执行插件代码 +- 原生能力发现可以加载受信任的插件入口代码,以构建一个不会激活的注册表快照 +- 原生运行时行为来自插件模块的 `register(api)` 路径,其中 `api.registrationMode === "full"` -这种拆分让 OpenClaw 能够在完整运行时尚未激活前,验证配置、解释缺失 / 禁用的插件,并构建 UI / schema 提示。 +这种拆分让 OpenClaw 能在完整运行时尚未激活前,就验证配置、解释缺失/禁用的插件,并构建 UI/schema 提示。 + +### 插件查找表 + +Gateway 网关启动时,会基于当前配置快照中的已安装插件索引和 manifest 注册表构建一个 `PluginLookUpTable`。该表仅包含元数据:存储插件 id、manifest 记录、诊断信息、所有者映射、插件 id 规范化器以及启动插件计划。它不持有已加载的插件模块、提供商 SDK、包内容或运行时导出。 + +查找表使重复启动决策能够走快速路径: + +- 渠道归属 +- 延迟渠道启动 +- 启动插件 id +- 提供商和 CLI 后端归属 +- setup provider、命令别名、模型目录提供商以及 manifest 契约归属 + +安全边界在于快照替换,而不是变更。配置、插件清单、安装记录或持久化索引策略发生变化时,应重新构建该表。不要将其视为一个可广泛变更的全局注册表,也不要保留无限制的历史表。运行时插件加载仍然独立于查找表元数据,因此过期的运行时状态不会被元数据缓存掩盖。 ### 激活规划 -激活规划是控制平面的一部分。调用方可以在加载更广泛的运行时注册表之前,先询问哪些插件与某个具体命令、提供商、渠道、路由、智能体 harness 或能力相关。 +激活规划是控制平面的一部分。调用方可以在加载更广泛的运行时注册表之前,询问哪些插件与具体命令、提供商、渠道、路由、Agent harness 或能力相关。 -规划器会保持当前 manifest 行为兼容: +规划器保持当前 manifest 行为兼容: -- `activation.*` 字段是显式的规划器提示 -- `providers`、`channels`、`commandAliases`、`setup.providers`、`contracts.tools` 和钩子仍然保留为 manifest 归属回退 -- 仅返回 id 的规划器 API 仍然可供现有调用方使用 -- plan API 会报告原因标签,以便诊断信息区分显式提示与归属回退 +- `activation.*` 字段是显式的规划提示 +- `providers`、`channels`、`commandAliases`、`setup.providers`、`contracts.tools` 和钩子仍然是 manifest 归属的回退来源 +- 仅返回 id 的规划器 API 仍对现有调用方可用 +- 计划 API 会报告原因标签,以便诊断能够区分显式提示和归属回退 -不要把 `activation` 当作生命周期钩子,或当作 `register(...)` 的替代品。它只是用于缩小加载范围的元数据。当归属字段已经能够描述该关系时,应优先使用归属字段;只有在需要额外规划器提示时才使用 `activation`。 +不要把 `activation` 当作生命周期钩子或 `register(...)` 的替代品。它是用于缩小加载范围的元数据。若归属字段已经能描述该关系,请优先使用归属字段;仅在需要额外规划提示时使用 `activation`。 -### 渠道插件和共享 message 工具 +### 渠道插件与共享消息工具 -对于普通聊天动作,渠道插件不需要单独注册发送 / 编辑 / 反应工具。OpenClaw 在核心中保留了一个共享的 `message` 工具,而渠道插件负责其背后的渠道特定发现与执行。 +对于普通聊天操作,渠道插件无需单独注册发送/编辑/回应工具。OpenClaw 在核心中保留一个共享的 `message` 工具,而渠道插件负责其背后的渠道专属发现与执行。 当前边界如下: -- 核心拥有共享 `message` 工具宿主、提示词接线、会话 / 线程簿记以及执行分发 -- 渠道插件拥有带作用域的动作发现、能力发现以及任何渠道特定的 schema 片段 -- 渠道插件拥有提供商特定的会话对话语法,例如对话 id 如何编码线程 id,或如何从父对话继承 -- 渠道插件通过其动作适配器执行最终动作 +- 核心拥有共享 `message` 工具宿主、提示词接线、会话/线程记账以及执行分发 +- 渠道插件拥有作用域操作发现、能力发现以及任何渠道专属 schema 片段 +- 渠道插件拥有提供商专属的会话对话语法,例如对话 id 如何编码线程 id,或如何继承父对话 +- 渠道插件通过其 action adapter 执行最终操作 -对于渠道插件,SDK 表面是 `ChannelMessageActionAdapter.describeMessageTool(...)`。这种统一的发现调用让插件可以把可见动作、能力和 schema 贡献一起返回,从而避免这些部分彼此漂移。 +对于渠道插件,SDK 接口是 `ChannelMessageActionAdapter.describeMessageTool(...)`。该统一发现调用允许插件同时返回其可见操作、能力和 schema 贡献,从而避免这些部分发生漂移。 -当某个渠道特定的 message-tool 参数携带媒体源(例如本地路径或远程媒体 URL)时,插件还应从 `describeMessageTool(...)` 返回 `mediaSourceParams`。核心会使用这个显式列表来应用沙箱路径规范化以及出站媒体访问提示,而不是对插件自有参数名进行硬编码。这里应优先使用按动作划分的映射,而不是整个渠道范围的扁平列表,这样某个仅用于 profile 的媒体参数就不会在 `send` 这类无关动作上被规范化。 +当某个渠道专属消息工具参数携带媒体源(例如本地路径或远程媒体 URL)时,插件还应从 `describeMessageTool(...)` 返回 `mediaSourceParams`。核心使用这个显式列表来应用沙箱路径规范化和出站媒体访问提示,而无需硬编码插件拥有的参数名。这里应优先使用按操作划分的映射,而不是整个渠道共用的扁平列表,这样仅用于 profile 的媒体参数就不会在 `send` 这类无关操作上被规范化。 核心会将运行时作用域传入该发现步骤。重要字段包括: @@ -193,57 +207,57 @@ OpenClaw 的插件系统有四层: - `agentId` - 受信任的入站 `requesterSenderId` -这对于依赖上下文的插件很重要。渠道可以根据当前活跃账号、当前房间 / 线程 / 消息,或受信任的请求者身份,隐藏或暴露消息动作,而无需在核心 `message` 工具中硬编码渠道特定分支。 +这对上下文敏感型插件很重要。渠道可以根据活动账号、当前房间/线程/消息,或受信任的请求方身份,隐藏或暴露消息操作,而无需在核心 `message` 工具中硬编码渠道专属分支。 -这也是为什么嵌入式运行器路由变更仍然属于插件工作:运行器负责将当前聊天 / 会话身份转发到插件发现边界,从而让共享 `message` 工具为当前轮次暴露正确的渠道自有表面。 +这也是为什么嵌入式 runner 路由变更仍然属于插件工作:runner 负责将当前聊天/会话身份转发到插件发现边界,以便共享的 `message` 工具为当前轮次暴露正确的渠道拥有表面。 -对于渠道自有的执行辅助工具,内置插件应将执行运行时保留在各自的扩展模块内部。核心不再拥有位于 `src/agents/tools` 下的 Discord、Slack、Telegram 或 WhatsApp 消息动作运行时。我们不会发布单独的 `plugin-sdk/*-action-runtime` 子路径,内置插件应直接从各自扩展自有模块导入本地运行时代码。 +对于渠道拥有的执行辅助工具,内置插件应将执行运行时保留在它们自己的扩展模块中。核心不再拥有位于 `src/agents/tools` 下的 Discord、Slack、Telegram 或 WhatsApp 消息操作运行时。我们不会发布单独的 `plugin-sdk/*-action-runtime` 子路径,内置插件应直接从其扩展自有模块导入本地运行时代码。 -同样的边界原则也适用于一般性的、以提供商命名的 SDK 接缝:核心不应导入 Slack、Discord、Signal、WhatsApp 或类似扩展的渠道专用便捷 barrel。如果核心需要某种行为,要么使用内置插件自己的 `api.ts` / `runtime-api.ts` barrel,要么将该需求提升为共享 SDK 中一个范围收窄的通用能力。 +相同的边界通常也适用于带提供商名称的 SDK 接缝:核心不应导入针对 Slack、Discord、Signal、WhatsApp 或类似扩展的渠道专用便捷 barrel。如果核心需要某种行为,要么消费内置插件自己的 `api.ts` / `runtime-api.ts` barrel,要么将该需求提升为共享 SDK 中一个狭义的通用能力。 对于投票,具体有两条执行路径: -- `outbound.sendPoll` 是适用于符合通用投票模型的渠道的共享基线 -- `actions.handleAction("poll")` 是处理渠道特定投票语义或额外投票参数的首选路径 +- `outbound.sendPoll` 是适用于符合通用投票模型渠道的共享基线 +- `actions.handleAction("poll")` 是处理渠道专属投票语义或额外投票参数的首选路径 -现在,核心会在插件投票分发拒绝该动作之后,才延后执行共享投票解析,因此插件自有的投票处理器可以接受渠道特定的投票字段,而不会先被通用投票解析器拦住。 +现在,核心会在插件投票分发拒绝该操作之后,才延迟执行共享投票解析,因此插件自有的投票处理器可以接受渠道专属投票字段,而不会先被通用投票解析器拦住。 -完整启动顺序请参见 [插件架构内部机制](/zh-CN/plugins/architecture-internals)。 +完整启动序列请参见 [插件架构内部机制](/zh-CN/plugins/architecture-internals)。 ## 能力归属模型 -OpenClaw 将一个原生插件视为某个**公司**或某项**功能**的归属边界,而不是一堆彼此无关集成的杂物袋。 +OpenClaw 将原生插件视为**公司**或**功能**的归属边界,而不是一堆彼此无关集成的杂物袋。 这意味着: -- 一个公司插件通常应拥有该公司的所有 OpenClaw 对外表面 -- 一个功能插件通常应拥有它所引入的完整功能表面 -- 渠道应消费共享的核心能力,而不是临时性地重复实现提供商行为 +- 公司插件通常应拥有该公司的所有 OpenClaw 对外表面 +- 功能插件通常应拥有其引入的完整功能表面 +- 渠道应消费共享核心能力,而不是临时重复实现提供商行为 - + `openai` 拥有文本推理、语音、实时语音、媒体理解和图像生成。`google` 拥有文本推理,以及媒体理解、图像生成和 Web 搜索。`qwen` 拥有文本推理,以及媒体理解和视频生成。 - + `elevenlabs` 和 `microsoft` 拥有语音;`firecrawl` 拥有 Web 抓取;`minimax` / `mistral` / `moonshot` / `zai` 拥有媒体理解后端。 - - `voice-call` 拥有呼叫传输、工具、CLI、路由和 Twilio 媒体流桥接,但它会消费共享的语音、实时转写和实时语音能力,而不是直接导入厂商插件。 + + `voice-call` 拥有通话传输、工具、CLI、路由和 Twilio 媒体流桥接,但会消费共享的语音、实时转录和实时语音能力,而不是直接导入供应商插件。 预期的最终状态是: -- OpenAI 即使横跨文本模型、语音、图像以及未来的视频,也仍然驻留在一个插件中 -- 其他厂商也可以对自己的表面区域采取同样做法 -- 渠道并不关心是哪一个厂商插件拥有该提供商;它们消费的是核心暴露出的共享能力契约 +- OpenAI 即使同时涵盖文本模型、语音、图像和未来的视频,也仍位于一个插件中 +- 其他供应商也可以为其自身的表面采用同样方式 +- 渠道不关心哪个供应商插件拥有该提供商;它们消费的是核心暴露的共享能力契约 -这里的关键区别是: +这是关键区别: - **plugin** = 归属边界 - **capability** = 可由多个插件实现或消费的核心契约 -因此,如果 OpenClaw 新增了一个像视频这样的领域,第一个问题不应该是“哪个提供商应该硬编码视频处理?”第一个问题应该是“核心的视频能力契约是什么?”一旦这个契约存在,厂商插件就可以针对它注册,而渠道 / 功能插件也可以消费它。 +因此,如果 OpenClaw 增加像视频这样的新领域,第一个问题不应是“哪个提供商应该硬编码视频处理?”第一个问题应是“核心视频能力契约是什么?”一旦该契约存在,供应商插件就可以针对它注册,渠道/功能插件也可以消费它。 如果该能力尚不存在,通常正确的做法是: @@ -252,45 +266,45 @@ OpenClaw 将一个原生插件视为某个**公司**或某项**功能**的归属 在核心中定义缺失的能力。 - 以类型化方式通过插件 API / 运行时将其暴露出来。 + 通过插件 API/运行时以类型化方式暴露它。 - - 将渠道 / 功能接入该能力。 + + 让渠道/功能接入该能力。 - - 让厂商插件注册其实现。 + + 让供应商插件注册具体实现。 -这样既能保持归属清晰,又能避免核心行为依赖于单一厂商或某条一次性的插件专用代码路径。 +这样既能保持归属明确,又能避免核心行为依赖单一供应商或某个一次性插件专用代码路径。 ### 能力分层 -当你决定代码应该放在哪里时,请使用这个思维模型: +在判断代码应放在哪里时,可使用以下思维模型: - 共享的编排、策略、回退、配置合并规则、投递语义和类型化契约。 + 共享的编排、策略、回退、配置合并规则、交付语义和类型化契约。 - - 厂商特定 API、认证、模型目录、语音合成、图像生成、未来的视频后端、用量端点。 + + 供应商专属 API、认证、模型目录、语音合成、图像生成、未来视频后端、用量端点。 - Slack / Discord / voice-call / 等集成,它们消费核心能力并在某个表面上呈现出来。 + Slack/Discord/voice-call 等集成,它们消费核心能力并将其呈现在某个表面上。 -例如,TTS 遵循这种结构: +例如,TTS 遵循这种形态: -- 核心拥有回复时 TTS 策略、回退顺序、偏好设置和渠道投递 -- `openai`、`elevenlabs` 和 `microsoft` 拥有语音合成实现 +- 核心拥有回复时 TTS 策略、回退顺序、偏好设置和渠道交付 +- `openai`、`elevenlabs` 和 `microsoft` 拥有合成实现 - `voice-call` 消费电话 TTS 运行时辅助工具 -对于未来能力,也应优先采用同样的模式。 +未来的能力也应优先采用同样模式。 ### 多能力公司插件示例 -从外部看,一个公司插件应当具有一致性。如果 OpenClaw 拥有针对模型、语音、实时转写、实时语音、媒体理解、图像生成、视频生成、Web 抓取和 Web 搜索的共享契约,那么一个厂商就可以在一个地方拥有其所有表面: +从外部看,公司插件应具备一致性。如果 OpenClaw 具有针对模型、语音、实时转录、实时语音、媒体理解、图像生成、视频生成、Web 抓取和 Web 搜索的共享契约,那么供应商可以在一个地方拥有其全部表面: ```ts import type { OpenClawPluginDefinition } from "openclaw/plugin-sdk/plugin-entry"; @@ -344,125 +358,125 @@ const plugin: OpenClawPluginDefinition = { export default plugin; ``` -重要的不是确切的辅助函数名,而是这种结构: +重要的不是确切的辅助函数名称,而是整体形态: -- 一个插件拥有厂商表面 +- 一个插件拥有供应商表面 - 核心仍然拥有能力契约 -- 渠道和功能插件消费 `api.runtime.*` 辅助工具,而不是厂商代码 -- 契约测试可以断言该插件确实注册了它声称拥有的能力 +- 渠道和功能插件消费 `api.runtime.*` 辅助工具,而不是供应商代码 +- 契约测试可以断言该插件已注册其声称拥有的能力 ### 能力示例:视频理解 -OpenClaw 已经将图像 / 音频 / 视频理解视为一个共享能力。这里同样适用相同的归属模型: +OpenClaw 已经将图像/音频/视频理解视为一个共享能力。相同的归属模型也适用于这里: 核心定义媒体理解契约。 - - 厂商插件按需注册 `describeImage`、`transcribeAudio` 和 `describeVideo`。 + + 供应商插件按适用情况注册 `describeImage`、`transcribeAudio` 和 `describeVideo`。 - 渠道和功能插件消费共享的核心行为,而不是直接接线到厂商代码。 + 渠道和功能插件消费共享核心行为,而不是直接连接到供应商代码。 -这避免了把某个提供商对视频的假设烘焙进核心。插件拥有厂商表面;核心拥有能力契约和回退行为。 +这样可以避免将某一提供商的视频假设固化进核心。插件拥有供应商表面;核心拥有能力契约和回退行为。 -视频生成已经采用了同样的顺序:核心拥有类型化能力契约和运行时辅助工具,而厂商插件则针对其注册 `api.registerVideoGenerationProvider(...)` 实现。 +视频生成已经使用同样的顺序:核心拥有类型化能力契约和运行时辅助工具,而供应商插件则针对其注册 `api.registerVideoGenerationProvider(...)` 实现。 -需要一个具体的发布清单吗?请参见 [能力扩展手册](/zh-CN/plugins/architecture)。 +需要具体的发布检查清单?请参见 [能力扩展手册](/zh-CN/plugins/architecture)。 -## 契约与约束执行 +## 契约与强制执行 -插件 API 表面有意在 `OpenClawPluginApi` 中集中并做了类型化。该契约定义了受支持的注册点,以及插件可以依赖的运行时辅助工具。 +插件 API 表面被有意设计为类型化,并集中在 `OpenClawPluginApi` 中。该契约定义了受支持的注册点,以及插件可依赖的运行时辅助工具。 -这很重要,因为: +这之所以重要,是因为: -- 插件作者可以得到一套稳定的内部标准 +- 插件作者可获得一个稳定的内部标准 - 核心可以拒绝重复归属,例如两个插件注册相同的提供商 id -- 启动过程可以为格式错误的注册暴露可执行的诊断信息 -- 契约测试可以强制执行内置插件的归属,并防止静默漂移 +- 启动过程可以为格式错误的注册暴露可操作的诊断信息 +- 契约测试可以强制约束内置插件归属并防止无声漂移 -这里有两层约束执行: +存在两层强制执行: - - 插件注册表会在插件加载时验证注册。例如:重复的提供商 id、重复的语音提供商 id,以及格式错误的注册,都会产生插件诊断信息,而不是导致未定义行为。 + + 插件注册表会在插件加载时验证注册内容。示例:重复的提供商 id、重复的语音提供商 id 以及格式错误的注册,不会产生未定义行为,而会生成插件诊断信息。 - 在测试运行期间,内置插件会被捕获到契约注册表中,这样 OpenClaw 就可以显式断言归属。当前这用于模型提供商、语音提供商、Web 搜索提供商和内置注册归属。 + 在测试运行期间,内置插件会被捕获到契约注册表中,以便 OpenClaw 明确断言归属。当前这用于模型提供商、语音提供商、Web 搜索提供商以及内置注册归属。 -实际效果是,OpenClaw 可以预先知道哪个插件拥有哪个表面。这使得核心和渠道能够无缝组合,因为归属是被声明、被类型化且可测试的,而不是隐式的。 +实际效果是,OpenClaw 能在一开始就知道哪个插件拥有哪些表面。这使核心和渠道能够无缝组合,因为归属是声明式、类型化且可测试的,而不是隐式的。 ### 什么应该属于契约 - + - 类型化 - 小而精 - - 能力特定 + - 能力专属 - 由核心拥有 - 可被多个插件复用 - - 可在不了解厂商细节的情况下被渠道 / 功能消费 + - 渠道/功能无需了解供应商即可消费 - - - 隐藏在核心中的厂商特定策略 + + - 隐藏在核心中的供应商专属策略 - 绕过注册表的一次性插件逃生口 - - 直接深入调用厂商实现的渠道代码 + - 直接深入某个供应商实现的渠道代码 - 不属于 `OpenClawPluginApi` 或 `api.runtime` 的临时运行时对象 -拿不准时,就提升抽象层级:先定义能力,再让插件接入它。 +如有疑问,请提升抽象层级:先定义能力,再让插件接入该能力。 ## 执行模型 -原生 OpenClaw 插件与 Gateway 网关**在同一进程中**运行。它们没有沙箱隔离。一个已加载的原生插件与核心代码具有相同的进程级信任边界。 +原生 OpenClaw 插件与 Gateway 网关**在同一进程内**运行。它们没有经过沙箱隔离。已加载的原生插件与核心代码具有相同的进程级信任边界。 影响包括: - 原生插件可以注册工具、网络处理器、钩子和服务 -- 原生插件的 bug 可能导致 Gateway 网关崩溃或不稳定 -- 恶意原生插件等同于在 OpenClaw 进程内部执行任意代码 +- 原生插件中的 bug 可能导致 gateway 崩溃或不稳定 +- 恶意原生插件等同于在 OpenClaw 进程内执行任意代码 -兼容的 bundle 默认情况下更安全,因为 OpenClaw 当前将其视为元数据 / 内容包。在当前版本中,这主要指内置 Skills。 +兼容 bundle 默认更安全,因为 OpenClaw 当前将其视为元数据/内容包。在当前版本中,这主要意味着内置的 Skills。 -对于非内置插件,请使用允许列表和显式安装 / 加载路径。应将工作区插件视为开发时代码,而不是生产默认值。 +对于非内置插件,请使用 allowlist 和显式的安装/加载路径。应将工作区插件视为开发阶段代码,而不是生产默认值。 -对于内置工作区 package 名称,请让插件 id 锚定在 npm 名称中:默认使用 `@openclaw/`,或者在该 package 有意暴露更窄的插件角色时,使用经批准的类型化后缀,例如 `-provider`、`-plugin`、`-speech`、`-sandbox` 或 `-media-understanding`。 +对于内置工作区包名,请让插件 id 锚定在 npm 名称中:默认使用 `@openclaw/`,或者在包有意暴露更窄的插件角色时,使用批准的类型化后缀,例如 `-provider`、`-plugin`、`-speech`、`-sandbox` 或 `-media-understanding`。 **信任说明:** - `plugins.allow` 信任的是**插件 id**,而不是来源出处。 -- 当启用 / 加入允许列表的工作区插件与某个内置插件具有相同 id 时,它会有意遮蔽该内置副本。 -- 这在本地开发、补丁测试和热修复中是正常且有用的。 -- 内置插件信任是根据源快照解析的——也就是加载时磁盘上的 manifest 和代码——而不是根据安装元数据。一个被破坏或被替换的安装记录,不能在实际源代码未声明的情况下,静默扩大某个内置插件的信任表面。 +- 当工作区插件已启用/加入 allowlist,且其 id 与某个内置插件相同时,它会有意覆盖该内置副本。 +- 这属于正常行为,并且对本地开发、补丁测试和热修复很有用。 +- 内置插件信任是根据源快照解析的——也就是加载时磁盘上的 manifest 和代码——而不是根据安装元数据解析。损坏或被替换的安装记录不能在实际源码声明范围之外,悄悄扩大内置插件的信任表面。 ## 导出边界 -OpenClaw 导出的是能力,而不是实现层面的便捷工具。 +OpenClaw 导出的是能力,而不是实现层面的便捷接口。 -保持能力注册为公共接口。收紧非契约辅助导出: +保持能力注册公开。收紧非契约辅助导出: - 内置插件专用的辅助子路径 -- 不打算作为公共 API 的运行时管线子路径 -- 厂商特定的便捷辅助工具 -- 属于实现细节的设置 / 新手引导辅助工具 +- 不打算作为公开 API 的运行时管线子路径 +- 供应商专属的便捷辅助函数 +- 属于实现细节的 setup/新手引导辅助函数 -为了兼容性和内置插件维护,一些内置插件辅助子路径仍然保留在生成的 SDK 导出映射中。当前示例包括 `plugin-sdk/feishu`、`plugin-sdk/feishu-setup`、`plugin-sdk/zalo`、`plugin-sdk/zalo-setup` 以及若干 `plugin-sdk/matrix*` 接缝。应将这些视为保留的实现细节导出,而不是为新的第三方插件推荐的 SDK 模式。 +出于兼容性和内置插件维护原因,一些内置插件辅助子路径仍然保留在生成的 SDK 导出映射中。当前示例包括 `plugin-sdk/feishu`、`plugin-sdk/feishu-setup`、`plugin-sdk/zalo`、`plugin-sdk/zalo-setup` 以及若干 `plugin-sdk/matrix*` 接缝。应将这些视为保留的实现细节导出,而不是新第三方插件推荐采用的 SDK 模式。 ## 内部机制与参考 -关于加载管线、注册表模型、提供商运行时钩子、Gateway 网关 HTTP 路由、消息工具 schema、渠道目标解析、提供商目录、上下文引擎插件以及添加新能力的指南,请参见 [插件架构内部机制](/zh-CN/plugins/architecture-internals)。 +关于加载管线、注册表模型、提供商运行时钩子、Gateway 网关 HTTP 路由、消息工具 schema、渠道目标解析、提供商目录、上下文引擎插件,以及新增能力的指南,请参见 [插件架构内部机制](/zh-CN/plugins/architecture-internals)。 -## 相关内容 +## 相关 - [构建插件](/zh-CN/plugins/building-plugins) - [插件 manifest](/zh-CN/plugins/manifest) diff --git a/docs/zh-CN/plugins/google-meet.md b/docs/zh-CN/plugins/google-meet.md index ea6cdb489..c94edf7a9 100644 --- a/docs/zh-CN/plugins/google-meet.md +++ b/docs/zh-CN/plugins/google-meet.md @@ -1,36 +1,38 @@ --- read_when: - - 你想让一个 OpenClaw 智能体加入一个 Google Meet 通话 - - 你想让一个 OpenClaw 智能体创建一个新的 Google Meet 通话 - - 你正在将 Chrome、Chrome 节点或 Twilio 配置为 Google Meet 传输方式 + - 你希望一个 OpenClaw 智能体加入 Google Meet 通话。 + - 你希望一个 OpenClaw 智能体创建一个新的 Google Meet 通话。 + - 你正在将 Chrome、Chrome 节点或 Twilio 配置为 Google Meet 传输方式。 summary: Google Meet 插件:通过 Chrome 或 Twilio 加入显式的 Meet URL,并使用实时语音默认设置 title: Google Meet 插件 x-i18n: - generated_at: "2026-04-26T11:10:54Z" + generated_at: "2026-04-27T08:00:38Z" model: gpt-5.4 provider: openai - source_hash: 1bd53db711e4729a9a7b18f7aaa3eedffd71a1e19349fc858537652b5d17cfcb + source_hash: 4b0196c35c06ce884bf14f8e6c94e49ae17e309527854b4e17d3ce01d57ee6be source_path: plugins/google-meet.md workflow: 15 --- -OpenClaw 的 Google Meet 参与者支持——该插件在设计上是显式的: +适用于 OpenClaw 的 Google Meet 参与者支持——该插件在设计上是显式的: - 它只会加入显式的 `https://meet.google.com/...` URL。 - 它可以通过 Google Meet API 创建一个新的 Meet 空间,然后加入返回的 URL。 - `realtime` 语音是默认模式。 - 当需要更深入的推理或工具时,实时语音可以回调到完整的 OpenClaw 智能体。 -- 智能体通过 `mode` 选择加入行为:实时收听/回话请使用 `realtime`,若要在不启用实时语音桥接的情况下加入/控制浏览器,则使用 `transcribe`。 -- 身份验证从个人 Google OAuth 或已登录的 Chrome 配置文件开始。 -- 不会自动播报同意声明。 +- 智能体通过 `mode` 选择加入行为:实时监听/回话使用 `realtime`,加入/控制浏览器但不启用实时语音桥接则使用 `transcribe`。 +- 认证从个人 Google OAuth 或已登录的 Chrome 配置文件开始。 +- 不会自动播报同意提示。 - 默认的 Chrome 音频后端是 `BlackHole 2ch`。 - Chrome 可以在本地运行,也可以在已配对的节点主机上运行。 -- Twilio 接受拨入号码,以及可选的 PIN 或 DTMF 序列。 -- CLI 命令是 `googlemeet`;`meet` 保留给更广义的智能体电话会议工作流。 +- Twilio 接受拨入号码以及可选的 PIN 或 DTMF 序列。 +- CLI 命令是 `googlemeet`;`meet` 保留给更广泛的智能体电话会议工作流。 ## 快速开始 -安装本地音频依赖,并配置一个后端实时语音提供商。OpenAI 是默认选项;Google Gemini Live 也可配合 `realtime.provider: "google"` 使用: +安装本地音频依赖,并配置一个后端实时语音提供商。 +OpenAI 是默认选项;Google Gemini Live 也可与 +`realtime.provider: "google"` 一起使用: ```bash brew install blackhole-2ch sox @@ -39,7 +41,7 @@ export OPENAI_API_KEY=sk-... export GEMINI_API_KEY=... ``` -`blackhole-2ch` 会安装 `BlackHole 2ch` 虚拟音频设备。Homebrew 的安装程序要求重启后,macOS 才会暴露该设备: +`blackhole-2ch` 会安装 `BlackHole 2ch` 虚拟音频设备。Homebrew 的安装程序需要重启后,macOS 才会暴露该设备: ```bash sudo reboot @@ -73,7 +75,13 @@ command -v rec play openclaw googlemeet setup ``` -设置输出旨在供智能体读取。它会报告 Chrome 配置文件、音频桥接、节点固定、延迟的实时介绍,以及在配置了 Twilio 委派时,`voice-call` 插件和 Twilio 凭证是否已就绪。把任何 `ok: false` 检查都视为阻塞项,在要求智能体加入之前先解决。脚本或机器可读输出请使用 `openclaw googlemeet setup --json`。使用 `--transport chrome`、`--transport chrome-node` 或 `--transport twilio`,可在智能体尝试前预检特定传输方式。 +该设置输出旨在让智能体可读。它会报告 Chrome 配置文件、 +音频桥接、节点固定、延迟实时介绍,以及在配置了 Twilio 委派时, +`voice-call` 插件和 Twilio 凭证是否已就绪。 +将任何 `ok: false` 检查都视为在要求智能体加入前必须解决的阻塞项。 +脚本或机器可读输出请使用 `openclaw googlemeet setup --json`。 +使用 `--transport chrome`、`--transport chrome-node` 或 `--transport twilio` +可在智能体尝试前对特定传输方式执行预检。 加入会议: @@ -92,7 +100,7 @@ openclaw googlemeet join https://meet.google.com/abc-defg-hij } ``` -创建新会议并加入: +创建一个新会议并加入: ```bash openclaw googlemeet create --transport chrome-node --mode realtime @@ -106,13 +114,19 @@ openclaw googlemeet create --no-join `googlemeet create` 有两条路径: -- API 创建:当已配置 Google Meet OAuth 凭证时使用。这是最确定的路径,不依赖浏览器 UI 状态。 -- 浏览器回退:当 OAuth 凭证不存在时使用。OpenClaw 会使用固定的 Chrome 节点,打开 `https://meet.google.com/new`,等待 Google 重定向到真实的会议代码 URL,然后返回该 URL。这一路径要求节点上的 OpenClaw Chrome 配置文件已登录 Google。浏览器自动化会处理 Meet 自身的首次运行麦克风提示;该提示不会被视为 Google 登录失败。 - 加入和创建流程也会尽量复用现有的 Meet 标签页,而不是打开新标签页。匹配时会忽略无害的 URL 查询字符串,例如 `authuser`,因此智能体重试时应聚焦到已打开的会议,而不是创建第二个 Chrome 标签页。 +- API 创建:当配置了 Google Meet OAuth 凭证时使用。 + 这是最确定的路径,不依赖浏览器 UI 状态。 +- 浏览器回退:当 OAuth 凭证缺失时使用。OpenClaw 使用固定的 Chrome 节点,打开 `https://meet.google.com/new`,等待 Google 重定向到真实的会议代码 URL,然后返回该 URL。此路径要求节点上的 OpenClaw Chrome 配置文件已经登录 Google。 + 浏览器自动化会处理 Meet 自身的首次运行麦克风提示;该提示不会被视为 Google 登录失败。 + 加入和创建流程还会在打开新标签页前尝试复用现有的 Meet 标签页。匹配时会忽略无害的 URL 查询字符串,例如 `authuser`,因此智能体重试时应聚焦已打开的会议,而不是创建第二个 Chrome 标签页。 -命令/工具输出包含 `source` 字段(`api` 或 `browser`),这样智能体就能说明使用了哪条路径。`create` 默认会加入新会议,并返回 `joined: true` 以及加入会话。若只想生成 URL,请在 CLI 中使用 `create --no-join`,或向工具传入 `"join": false`。 +命令/工具输出包含一个 `source` 字段(`api` 或 `browser`),这样智能体就可以解释使用了哪条路径。 +默认情况下,`create` 会加入新会议,并返回 `joined: true` 以及加入会话。 +如果只想生成 URL,可在 CLI 中使用 `create --no-join`,或者向工具传入 `"join": false`。 -或者你也可以告诉智能体:“创建一个 Google Meet,用实时语音加入它,并把链接发给我。” 智能体应调用 `google_meet`,使用 `action: "create"`,然后分享返回的 `meetingUri`。 +或者告诉智能体:“创建一个 Google Meet,用实时语音加入它,并把链接发给我。” +智能体应调用 `google_meet`,使用 `action: "create"`, +然后分享返回的 `meetingUri`。 ```json { @@ -122,61 +136,63 @@ openclaw googlemeet create --no-join } ``` -如果要进行仅观察/浏览器控制的加入,请设置 `"mode": "transcribe"`。这不会启动双工实时模型桥接,因此它不会在会议中回话。 +如果只想观察/控制浏览器地加入,请设置 `"mode": "transcribe"`。这样不会启动双向实时模型桥接,因此它不会在会议中回话。 -在实时会话期间,`google_meet` 状态会包含浏览器和音频桥接健康信息,例如 `inCall`、`manualActionRequired`、`providerConnected`、`realtimeReady`、`audioInputActive`、`audioOutputActive`、最近输入/输出时间戳、字节计数以及桥接关闭状态。如果出现安全的 Meet 页面提示,浏览器自动化会在可能时处理它。登录、主持人准入以及浏览器/操作系统权限提示会被报告为手动操作,并附带原因和消息,供智能体转达。 +在实时会话期间,`google_meet` 状态会包含浏览器和音频桥接健康信息,例如 `inCall`、`manualActionRequired`、`providerConnected`、`realtimeReady`、`audioInputActive`、`audioOutputActive`、最近输入/输出时间戳、字节计数以及桥接关闭状态。 +如果出现安全的 Meet 页面提示,浏览器自动化会在可处理时进行处理。 +登录、主持人准入以及浏览器/操作系统权限提示会作为手动操作报告,并附带原因和消息,供智能体转述。 -Chrome 会以已登录的 Chrome 配置文件身份加入。在 Meet 中,为 OpenClaw 使用的麦克风/扬声器路径选择 `BlackHole 2ch`。为了获得干净的双工音频,请使用独立的虚拟设备或类似 Loopback 的音频图;单个 BlackHole 设备足以完成首次冒烟测试,但可能会产生回声。 +Chrome 会以已登录的 Chrome 配置文件身份加入。在 Meet 中,为 OpenClaw 使用的麦克风/扬声器路径选择 `BlackHole 2ch`。为了获得干净的双工音频,请使用独立的虚拟设备或类似 Loopback 的图形路由;单个 BlackHole 设备足以完成首次冒烟测试,但可能会产生回声。 ### 本地 Gateway 网关 + Parallels Chrome -你**不**需要在 macOS 虚拟机中部署完整的 OpenClaw Gateway 网关或模型 API 密钥,只是为了让虚拟机承载 Chrome。可以在本地运行 Gateway 网关和智能体,然后在虚拟机中运行一个节点主机。只需在虚拟机中启用一次内置插件,让节点宣告 Chrome 命令即可: +你**不**需要在 macOS VM 内运行完整的 OpenClaw Gateway 网关或模型 API 密钥,只为了让 VM 托管 Chrome。可以在本地运行 Gateway 网关和智能体,然后在 VM 中运行节点主机。只需在 VM 中启用一次内置插件,这样节点就会广播 Chrome 命令: -各部分运行位置: +各组件运行位置: - Gateway 网关主机:OpenClaw Gateway 网关、智能体工作区、模型/API 密钥、实时提供商,以及 Google Meet 插件配置。 -- Parallels macOS 虚拟机:OpenClaw CLI/节点主机、Google Chrome、SoX、BlackHole 2ch,以及一个已登录 Google 的 Chrome 配置文件。 -- 虚拟机中不需要:Gateway 网关服务、智能体配置、OpenAI/GPT 密钥或模型提供商设置。 +- Parallels macOS VM:OpenClaw CLI/节点主机、Google Chrome、SoX、BlackHole 2ch,以及一个已登录 Google 的 Chrome 配置文件。 +- VM 中不需要:Gateway 网关服务、智能体配置、OpenAI/GPT 密钥或模型提供商设置。 -安装虚拟机依赖: +安装 VM 依赖: ```bash brew install blackhole-2ch sox ``` -安装 BlackHole 后重启虚拟机,让 macOS 暴露 `BlackHole 2ch`: +安装 BlackHole 后请重启 VM,以便 macOS 暴露 `BlackHole 2ch`: ```bash sudo reboot ``` -重启后,验证虚拟机可以看到该音频设备和 SoX 命令: +重启后,验证 VM 能看到音频设备和 SoX 命令: ```bash system_profiler SPAudioDataType | grep -i BlackHole command -v rec play ``` -在虚拟机中安装或更新 OpenClaw,然后在那里启用内置插件: +在 VM 中安装或更新 OpenClaw,然后在那里启用内置插件: ```bash openclaw plugins enable google-meet ``` -在虚拟机中启动节点主机: +在 VM 中启动节点主机: ```bash openclaw node run --host --port 18789 --display-name parallels-macos ``` -如果 `` 是局域网 IP,并且你没有使用 TLS,除非你为这个受信任的私有网络显式启用明文 WebSocket,否则节点会拒绝它: +如果 `` 是局域网 IP 且你未使用 TLS,除非你为这个受信任的私有网络显式启用,否则节点会拒绝明文 WebSocket: ```bash OPENCLAW_ALLOW_INSECURE_PRIVATE_WS=1 \ openclaw node run --host --port 18789 --display-name parallels-macos ``` -将节点安装为 LaunchAgent 时,也要使用同一个环境变量: +将节点安装为 LaunchAgent 时,也请使用相同的环境变量: ```bash OPENCLAW_ALLOW_INSECURE_PRIVATE_WS=1 \ @@ -184,7 +200,8 @@ OPENCLAW_ALLOW_INSECURE_PRIVATE_WS=1 \ openclaw node restart ``` -`OPENCLAW_ALLOW_INSECURE_PRIVATE_WS=1` 是进程环境,而不是 `openclaw.json` 设置。当 `openclaw node install` 执行安装命令时,如果该变量存在,就会将其存储到 LaunchAgent 环境中。 +`OPENCLAW_ALLOW_INSECURE_PRIVATE_WS=1` 是进程环境变量,不是 +`openclaw.json` 设置。如果在执行安装命令时该变量存在,`openclaw node install` 会将其存储到 LaunchAgent 环境中。 在 Gateway 网关主机上批准该节点: @@ -193,13 +210,14 @@ openclaw devices list openclaw devices approve ``` -确认 Gateway 网关能看到该节点,并且它同时宣告了 `googlemeet.chrome` 和浏览器能力/`browser.proxy`: +确认 Gateway 网关能看到该节点,并且它同时广播 `googlemeet.chrome` +和浏览器能力/`browser.proxy`: ```bash openclaw nodes status ``` -在 Gateway 网关主机上将 Meet 路由到该节点: +在 Gateway 网关主机上通过该节点路由 Meet: ```json5 { @@ -229,62 +247,82 @@ openclaw nodes status } ``` -现在你可以像平常一样从 Gateway 网关主机加入: +现在就可以从 Gateway 网关主机正常加入: ```bash openclaw googlemeet join https://meet.google.com/abc-defg-hij ``` -或者要求智能体使用 `google_meet` 工具,并设置 `transport: "chrome-node"`。 +或者要求智能体使用 `google_meet` 工具并指定 `transport: "chrome-node"`。 -要进行单命令冒烟测试,以创建或复用会话、说出一段已知短语并打印会话健康状态,请运行: +如果你想执行一个单命令冒烟测试,它会创建或复用会话、说出一个已知短语,并打印会话健康状态: ```bash openclaw googlemeet test-speech https://meet.google.com/abc-defg-hij ``` -在加入过程中,OpenClaw 浏览器自动化会填写访客名称,点击 Join/Ask to join,并在出现提示时接受 Meet 首次运行的 “Use microphone” 选项。在仅浏览器会议创建期间,如果 Meet 没有暴露使用麦克风按钮,它也可以在不使用麦克风的情况下继续通过相同提示。如果浏览器配置文件未登录、Meet 正在等待主持人准入、Chrome 需要麦克风/摄像头权限,或者 Meet 卡在自动化无法解决的提示上,则 join/test-speech 结果会报告 `manualActionRequired: true`,并附带 `manualActionReason` 和 `manualActionMessage`。智能体应停止重试加入,报告该确切消息以及当前的 `browserUrl`/`browserTitle`,并且只在手动浏览器操作完成后再重试。 +在加入过程中,OpenClaw 浏览器自动化会填写访客名、点击“加入”/“请求加入”,并在该提示出现时接受 Meet 首次运行的“使用麦克风”选项。 +在仅浏览器的会议创建过程中,如果 Meet 没有暴露使用麦克风按钮,它也可以在不使用麦克风的情况下继续越过同一提示。 +如果浏览器配置文件未登录、Meet 正在等待主持人准入、Chrome 需要麦克风/摄像头权限,或者 Meet 卡在自动化无法解决的提示上,join/test-speech 结果会报告 +`manualActionRequired: true`,并带有 `manualActionReason` 和 +`manualActionMessage`。智能体应停止重试加入,报告该精确消息以及当前的 `browserUrl`/`browserTitle`,并且只在手动浏览器操作完成后再重试。 -如果省略了 `chromeNode.node`,只有在恰好有一个已连接节点同时宣告 `googlemeet.chrome` 和浏览器控制时,OpenClaw 才会自动选择。如果连接了多个具备能力的节点,请将 `chromeNode.node` 设置为节点 id、显示名称或远程 IP。 +如果省略 `chromeNode.node`,OpenClaw 只会在恰好有一个已连接节点同时广播 `googlemeet.chrome` 和浏览器控制能力时自动选择它。 +如果连接了多个可用节点,请将 `chromeNode.node` 设置为节点 ID、显示名称或远程 IP。 常见故障检查: -- `Configured Google Meet node ... is not usable: offline`:固定的节点已被 Gateway 网关识别,但当前不可用。智能体应将该节点视为诊断状态,而不是可用的 Chrome 主机,并报告设置阻塞项,而不是回退到其他传输方式,除非用户明确要求这样做。 -- `No connected Google Meet-capable node`:在虚拟机中启动 `openclaw node run`,批准配对,并确保已在虚拟机中运行 `openclaw plugins enable google-meet` 和 `openclaw plugins enable browser`。另外还要确认 Gateway 网关主机允许这两个节点命令,配置如下: - `gateway.nodes.allowCommands: ["googlemeet.chrome", "browser.proxy"]`。 +- `Configured Google Meet node ... is not usable: offline`:固定节点已被 Gateway 网关识别,但当前不可用。智能体应将该节点视为诊断状态,而不是可用的 Chrome 主机,并报告设置阻塞项,而不是回退到其他传输方式,除非用户要求这样做。 +- `No connected Google Meet-capable node`:在 VM 中启动 `openclaw node run`,批准配对,并确保已在 VM 中运行 `openclaw plugins enable google-meet` 和 `openclaw plugins enable browser`。同时确认 Gateway 网关主机通过 + `gateway.nodes.allowCommands: ["googlemeet.chrome", "browser.proxy"]` + 允许这两个节点命令。 - `BlackHole 2ch audio device not found`:在被检查的主机上安装 `blackhole-2ch`,并在使用本地 Chrome 音频前重启。 -- `BlackHole 2ch audio device not found on the node`:在虚拟机中安装 `blackhole-2ch` 并重启虚拟机。 -- Chrome 打开但无法加入:在虚拟机内登录浏览器配置文件,或保持设置 `chrome.guestName` 以进行访客加入。访客自动加入会通过节点浏览器代理使用 OpenClaw 浏览器自动化;请确保节点浏览器配置指向你希望使用的配置文件,例如 `browser.defaultProfile: "user"` 或一个已命名的现有会话配置文件。 -- 重复的 Meet 标签页:保持启用 `chrome.reuseExistingTab: true`。OpenClaw 会在打开新标签页前激活相同 Meet URL 的现有标签页,而浏览器会议创建也会复用进行中的 `https://meet.google.com/new` 或 Google 账号提示标签页,而不是再打开一个。 -- 没有音频:在 Meet 中,将麦克风/扬声器路由到 OpenClaw 使用的虚拟音频设备路径;为了获得干净的双工音频,请使用独立的虚拟设备或类似 Loopback 的路由。 +- `BlackHole 2ch audio device not found on the node`:在 VM 中安装 `blackhole-2ch` 并重启 VM。 +- Chrome 已打开但无法加入:在 VM 内登录浏览器配置文件,或者保持设置 `chrome.guestName` 以进行访客加入。访客自动加入通过节点浏览器代理使用 OpenClaw 浏览器自动化;请确保节点浏览器配置指向你想使用的配置文件,例如 + `browser.defaultProfile: "user"` 或某个已存在会话的命名配置文件。 +- 重复的 Meet 标签页:保持 `chrome.reuseExistingTab: true` 启用。OpenClaw 会在打开新标签页前激活相同 Meet URL 的现有标签页,而浏览器会议创建也会在打开新标签页前复用进行中的 `https://meet.google.com/new` 或 Google 账号提示标签页。 +- 没有音频:在 Meet 中,将麦克风/扬声器路由到 OpenClaw 使用的虚拟音频设备路径;如需干净的双工音频,请使用独立的虚拟设备或类似 Loopback 的路由。 ## 安装说明 -Chrome 的 `realtime` 默认设置使用两个外部工具: +Chrome 实时默认设置会使用两个外部工具: -- `sox`:命令行音频工具。该插件使用它的 `rec` 和 `play` 命令来实现默认的 8 kHz G.711 mu-law 音频桥接。 -- `blackhole-2ch`:macOS 虚拟音频驱动。它会创建 `BlackHole 2ch` 音频设备,供 Chrome/Meet 路由使用。 +- `sox`:命令行音频工具。插件使用它的 `rec` 和 `play` + 命令来实现默认的 8 kHz G.711 mu-law 音频桥接。 +- `blackhole-2ch`:macOS 虚拟音频驱动。它会创建 `BlackHole 2ch` + 音频设备,供 Chrome/Meet 路由使用。 -OpenClaw 不捆绑也不重新分发这两个软件包。文档要求用户通过 Homebrew 将它们作为主机依赖安装。SoX 的许可证为 `LGPL-2.0-only AND GPL-2.0-only`;BlackHole 为 GPL-3.0。如果你要构建一个将 BlackHole 与 OpenClaw 一起捆绑的安装程序或设备,请审查 BlackHole 上游许可条款,或从 Existential Audio 获取单独许可证。 +OpenClaw 不会捆绑或再分发这两个包。文档要求用户通过 Homebrew 将它们作为主机依赖安装。 +SoX 采用 `LGPL-2.0-only AND GPL-2.0-only` 许可;BlackHole 采用 GPL-3.0。 +如果你构建了一个将 BlackHole 与 OpenClaw 一起打包的安装程序或设备,请审查 BlackHole 上游许可条款,或向 Existential Audio 获取单独许可。 ## 传输方式 ### Chrome -Chrome 传输方式会在 Google Chrome 中打开 Meet URL,并以已登录的 Chrome 配置文件身份加入。在 macOS 上,插件会在启动前检查 `BlackHole 2ch`。如果已配置,它还会在打开 Chrome 之前运行音频桥接健康检查命令和启动命令。当 Chrome/音频运行在 Gateway 网关主机上时,请使用 `chrome`;当 Chrome/音频运行在已配对节点(例如 Parallels macOS 虚拟机)上时,请使用 `chrome-node`。 +Chrome 传输方式会在 Google Chrome 中打开 Meet URL,并以已登录的 +Chrome 配置文件身份加入。在 macOS 上,插件会在启动前检查 `BlackHole 2ch`。 +如果已配置,它还会在打开 Chrome 之前运行音频桥接健康检查命令和启动命令。 +当 Chrome/音频运行在 Gateway 网关主机上时,请使用 `chrome`; +当 Chrome/音频运行在已配对节点(例如 Parallels macOS VM)上时,请使用 `chrome-node`。 ```bash openclaw googlemeet join https://meet.google.com/abc-defg-hij --transport chrome openclaw googlemeet join https://meet.google.com/abc-defg-hij --transport chrome-node ``` -将 Chrome 的麦克风和扬声器音频通过本地 OpenClaw 音频桥接进行路由。如果未安装 `BlackHole 2ch`,加入会因设置错误而失败,而不是在没有音频路径的情况下静默加入。 +将 Chrome 的麦克风和扬声器音频通过本地 OpenClaw 音频桥接进行路由。 +如果未安装 `BlackHole 2ch`,加入会因设置错误而失败, +而不是在没有音频路径的情况下静默加入。 ### Twilio -Twilio 传输方式是一个严格的拨号计划,委派给 Voice Call 插件。它不会从 Meet 页面解析电话号码。 +Twilio 传输方式是一个严格的拨号计划,委派给 Voice Call 插件。 +它不会解析 Meet 页面来提取电话号码。 -当 Chrome 参与不可用,或者你想使用电话拨入作为回退方案时,请使用此方式。Google Meet 必须为该会议提供电话拨入号码和 PIN;OpenClaw 不会从 Meet 页面发现这些信息。 +当 Chrome 参与方式不可用,或者你想要一个电话拨入回退方案时,请使用它。 +Google Meet 必须为该会议提供电话拨入号码和 PIN; +OpenClaw 不会从 Meet 页面中发现这些信息。 在 Gateway 网关主机上启用 Voice Call 插件,而不是在 Chrome 节点上: @@ -311,7 +349,8 @@ Twilio 传输方式是一个严格的拨号计划,委派给 Voice Call 插件 } ``` -通过环境变量或配置提供 Twilio 凭证。环境变量可以让密钥不出现在 `openclaw.json` 中: +通过环境变量或配置提供 Twilio 凭证。环境变量可以让秘密信息保留在 +`openclaw.json` 之外: ```bash export TWILIO_ACCOUNT_SID=AC... @@ -319,7 +358,7 @@ export TWILIO_AUTH_TOKEN=... export TWILIO_FROM_NUMBER=+15550001234 ``` -启用 `voice-call` 后,重新启动或重新加载 Gateway 网关;插件配置更改在 Gateway 网关进程重新加载之前,不会出现在已运行的进程中。 +启用 `voice-call` 后请重启或重新加载 Gateway 网关;在已运行的 Gateway 网关进程重新加载之前,插件配置更改不会生效。 然后验证: @@ -329,7 +368,8 @@ openclaw plugins list | grep -E 'google-meet|voice-call' openclaw googlemeet setup ``` -当 Twilio 委派连通后,`googlemeet setup` 会包含成功的 `twilio-voice-call-plugin` 和 `twilio-voice-call-credentials` 检查项。 +当 Twilio 委派连接完成后,`googlemeet setup` 会包含成功的 +`twilio-voice-call-plugin` 和 `twilio-voice-call-credentials` 检查项。 ```bash openclaw googlemeet join https://meet.google.com/abc-defg-hij \ @@ -338,7 +378,7 @@ openclaw googlemeet join https://meet.google.com/abc-defg-hij \ --pin 123456 ``` -当会议需要自定义序列时,使用 `--dtmf-sequence`: +当会议需要自定义序列时,请使用 `--dtmf-sequence`: ```bash openclaw googlemeet join https://meet.google.com/abc-defg-hij \ @@ -349,11 +389,19 @@ openclaw googlemeet join https://meet.google.com/abc-defg-hij \ ## OAuth 和预检 -OAuth 对于创建 Meet 链接来说是可选的,因为 `googlemeet create` 可以回退到浏览器自动化。当你想使用官方 API 创建、空间解析或 Meet Media API 预检时,请配置 OAuth。 +OAuth 对于创建 Meet 链接来说是可选的,因为 `googlemeet create` 可以回退到浏览器自动化。 +如果你想使用官方 API 创建、空间解析或 Meet Media API 预检检查,请配置 OAuth。 -Google Meet API 访问使用用户 OAuth:创建一个 Google Cloud OAuth 客户端,请求所需作用域,授权一个 Google 账号,然后将生成的刷新令牌存储在 Google Meet 插件配置中,或者提供 `OPENCLAW_GOOGLE_MEET_*` 环境变量。 +Google Meet API 访问使用用户 OAuth:创建一个 Google Cloud OAuth 客户端, +请求所需作用域,授权一个 Google 账号,然后将生成的刷新令牌存储在 +Google Meet 插件配置中,或提供 +`OPENCLAW_GOOGLE_MEET_*` 环境变量。 -OAuth 不会取代 Chrome 加入路径。当你使用浏览器参与时,Chrome 和 chrome-node 传输方式仍然通过已登录的 Chrome 配置文件、BlackHole/SoX 以及一个已连接节点来加入。OAuth 仅用于官方 Google Meet API 路径:创建会议空间、解析空间,以及运行 Meet Media API 预检。 +OAuth 不会替代 Chrome 加入路径。使用浏览器参与时, +Chrome 和 chrome-node 传输方式仍然通过已登录的 Chrome 配置文件、 +BlackHole/SoX,以及一个已连接节点来加入。 +OAuth 仅用于官方 Google Meet API 路径:创建会议空间、解析空间, +以及运行 Meet Media API 预检检查。 ### 创建 Google 凭证 @@ -362,33 +410,40 @@ OAuth 不会取代 Chrome 加入路径。当你使用浏览器参与时,Chrome 1. 创建或选择一个 Google Cloud 项目。 2. 为该项目启用 **Google Meet REST API**。 3. 配置 OAuth 同意屏幕。 - - **Internal** 对 Google Workspace 组织来说最简单。 - - **External** 适用于个人/测试设置;当应用处于 Testing 状态时,将每个会授权该应用的 Google 账号添加为测试用户。 + - 对于 Google Workspace 组织,**Internal** 最简单。 + - **External** 适用于个人/测试设置;当应用处于 Testing 状态时, + 将每个会授权该应用的 Google 账号添加为测试用户。 4. 添加 OpenClaw 请求的作用域: - `https://www.googleapis.com/auth/meetings.space.created` - `https://www.googleapis.com/auth/meetings.space.readonly` - `https://www.googleapis.com/auth/meetings.conference.media.readonly` -5. 创建一个 OAuth client ID。 - - Application type:**Web application**。 - - Authorized redirect URI: +5. 创建 OAuth 客户端 ID。 + - 应用类型:**Web application**。 + - 已授权重定向 URI: ```text http://localhost:8085/oauth2callback ``` -6. 复制 client ID 和 client secret。 +6. 复制客户端 ID 和客户端密钥。 -`meetings.space.created` 是 Google Meet `spaces.create` 所必需的。`meetings.space.readonly` 允许 OpenClaw 将 Meet URL/代码解析为空间。`meetings.conference.media.readonly` 用于 Meet Media API 预检和媒体相关工作;Google 可能要求加入 Developer Preview 才能实际使用 Media API。如果你只需要基于浏览器的 Chrome 加入,可以完全跳过 OAuth。 +Google Meet `spaces.create` 需要 `meetings.space.created`。 +`meetings.space.readonly` 允许 OpenClaw 将 Meet URL/代码解析为空间。 +`meetings.conference.media.readonly` 用于 Meet Media API 预检和媒体相关工作; +Google 可能要求加入 Developer Preview 才能实际使用 Media API。 +如果你只需要基于浏览器的 Chrome 加入,可完全跳过 OAuth。 ### 生成刷新令牌 -配置 `oauth.clientId`,并可选配置 `oauth.clientSecret`,或者将它们作为环境变量传入,然后运行: +配置 `oauth.clientId` 和可选的 `oauth.clientSecret`,或者将它们作为 +环境变量传入,然后运行: ```bash openclaw googlemeet auth login --json ``` -该命令会输出一个带有刷新令牌的 `oauth` 配置块。它使用 PKCE、本地回调 `http://localhost:8085/oauth2callback`,以及带 `--manual` 的手动复制/粘贴流程。 +该命令会打印一个带有刷新令牌的 `oauth` 配置块。它使用 PKCE、 +位于 `http://localhost:8085/oauth2callback` 的 localhost 回调,以及带 `--manual` 的手动复制/粘贴流程。 示例: @@ -442,37 +497,49 @@ JSON 输出包括: } ``` -如果你不想将刷新令牌放在配置中,优先使用环境变量。如果同时存在配置值和环境变量值,插件会优先解析配置,然后回退到环境变量。 +如果你不希望将刷新令牌放入配置中,优先使用环境变量。 +如果配置值和环境变量值同时存在,插件会优先解析配置值, +然后再回退到环境变量。 -OAuth 同意内容包括 Meet 空间创建、Meet 空间读取访问以及 Meet 会议媒体读取访问。如果你在支持会议创建之前就已经完成认证,请重新运行 `openclaw googlemeet auth login --json`,以便刷新令牌具备 `meetings.space.created` 作用域。 +OAuth 同意内容包括 Meet 空间创建、Meet 空间读取访问,以及 Meet +会议媒体读取访问。如果你在支持会议创建之前就已完成认证, +请重新运行 `openclaw googlemeet auth login --json`,以便刷新令牌具备 +`meetings.space.created` 作用域。 -### 使用 doctor 验证 OAuth +### 用 Doctor 验证 OAuth -当你需要快速、无密钥的健康检查时,请运行 OAuth Doctor: +当你想进行快速、无秘密信息的健康检查时,请运行 OAuth Doctor: ```bash openclaw googlemeet doctor --oauth --json ``` -这不会加载 Chrome 运行时,也不需要已连接的 Chrome 节点。它会检查 OAuth 配置是否存在,以及刷新令牌是否能够生成访问令牌。JSON 报告仅包含状态字段,例如 `ok`、`configured`、`tokenSource`、`expiresAt` 和检查消息;不会打印访问令牌、刷新令牌或 client secret。 +这不会加载 Chrome 运行时,也不要求有已连接的 Chrome 节点。 +它会检查 OAuth 配置是否存在,以及刷新令牌是否能生成访问令牌。 +JSON 报告仅包含 `ok`、`configured`、 +`tokenSource`、`expiresAt` 和检查消息等状态字段; +不会打印访问令牌、刷新令牌或客户端密钥。 常见结果: -| 检查项 | 含义 | -| --------------------- | -------------------------------------------------------------------- | -| `oauth-config` | 存在 `oauth.clientId` 加 `oauth.refreshToken`,或存在缓存的访问令牌。 | -| `oauth-token` | 缓存的访问令牌仍然有效,或者刷新令牌已生成新的访问令牌。 | -| `meet-spaces-get` | 可选的 `--meeting` 检查已解析一个现有 Meet 空间。 | -| `meet-spaces-create` | 可选的 `--create-space` 检查已创建一个新的 Meet 空间。 | +| 检查项 | 含义 | +| --------------------- | ---------------------------------------------------------------------------------------- | +| `oauth-config` | 存在 `oauth.clientId` 加 `oauth.refreshToken`,或存在缓存的访问令牌。 | +| `oauth-token` | 缓存的访问令牌仍然有效,或刷新令牌已生成新的访问令牌。 | +| `meet-spaces-get` | 可选的 `--meeting` 检查已解析现有 Meet 空间。 | +| `meet-spaces-create` | 可选的 `--create-space` 检查已创建新的 Meet 空间。 | -如果还要证明 Google Meet API 已启用以及具备 `spaces.create` 作用域,请运行带副作用的创建检查: +如果还要证明 Google Meet API 已启用以及 `spaces.create` 作用域也已具备, +请运行带副作用的创建检查: ```bash openclaw googlemeet doctor --oauth --create-space --json openclaw googlemeet create --no-join --json ``` -`--create-space` 会创建一个一次性的 Meet URL。当你需要确认 Google Cloud 项目已启用 Meet API,并且已授权账号具备 `meetings.space.created` 作用域时,请使用它。 +`--create-space` 会创建一个一次性的 Meet URL。 +当你需要确认 Google Cloud 项目已启用 Meet API, +并且获授权账号具备 `meetings.space.created` 作用域时,请使用它。 要证明对现有会议空间的读取访问权限: @@ -481,11 +548,18 @@ openclaw googlemeet doctor --oauth --meeting https://meet.google.com/abc-defg-hi openclaw googlemeet resolve-space --meeting https://meet.google.com/abc-defg-hij ``` -`doctor --oauth --meeting` 和 `resolve-space` 可证明已授权的 Google 账号对其可访问的现有空间具有读取权限。这些检查返回 `403` 通常意味着 Google Meet REST API 已禁用、已同意的刷新令牌缺少所需作用域,或者该 Google 账号无法访问该 Meet 空间。刷新令牌错误则表示需要重新运行 `openclaw googlemeet auth login --json` 并存储新的 `oauth` 配置块。 +`doctor --oauth --meeting` 和 `resolve-space` 可证明获授权 Google +账号对其可访问的现有空间具有读取权限。 +这些检查返回 `403` 通常意味着 Google Meet REST API 已被禁用、 +已同意的刷新令牌缺少所需作用域,或者该 Google 账号无法访问该 Meet +空间。刷新令牌错误则意味着需要重新运行 `openclaw googlemeet auth login +--json` 并存储新的 `oauth` 块。 -浏览器回退不需要 OAuth 凭证。在该模式下,Google 身份验证来自所选节点上已登录的 Chrome 配置文件,而不是 OpenClaw 配置。 +浏览器回退模式不需要 OAuth 凭证。 +在这种模式下,Google 认证来自所选节点上已登录的 Chrome 配置文件, +而不是 OpenClaw 配置。 -以下环境变量可作为回退值: +接受以下环境变量作为回退值: - `OPENCLAW_GOOGLE_MEET_CLIENT_ID` 或 `GOOGLE_MEET_CLIENT_ID` - `OPENCLAW_GOOGLE_MEET_CLIENT_SECRET` 或 `GOOGLE_MEET_CLIENT_SECRET` @@ -502,7 +576,7 @@ openclaw googlemeet resolve-space --meeting https://meet.google.com/abc-defg-hij openclaw googlemeet resolve-space --meeting https://meet.google.com/abc-defg-hij ``` -在进行媒体相关工作前运行预检: +在进行媒体工作之前运行预检: ```bash openclaw googlemeet preflight --meeting https://meet.google.com/abc-defg-hij @@ -516,9 +590,10 @@ openclaw googlemeet attendance --meeting https://meet.google.com/abc-defg-hij openclaw googlemeet export --meeting https://meet.google.com/abc-defg-hij --output ./meet-export ``` -带上 `--meeting` 时,`artifacts` 和 `attendance` 默认使用最新的会议记录。如果你希望获取该会议的所有保留记录,请传入 `--all-conference-records`。 +使用 `--meeting` 时,`artifacts` 和 `attendance` 默认使用最新的会议记录。 +如果你想要该会议的所有保留记录,请传递 `--all-conference-records`。 -Calendar 查找可以先从 Google Calendar 解析会议 URL,再读取 Meet 工件: +日历查找可以先从 Google Calendar 解析会议 URL,然后再读取 Meet 工件: ```bash openclaw googlemeet latest --today @@ -527,10 +602,15 @@ openclaw googlemeet artifacts --event "Weekly sync" openclaw googlemeet attendance --today --format csv --output attendance.csv ``` -`--today` 会在今天的 `primary` 日历中搜索带有 Google Meet 链接的 Calendar 事件。使用 `--event ` 搜索匹配的事件文本,使用 `--calendar ` 指定非主日历。Calendar 查找需要一次新的 OAuth 登录,并包含 Calendar events readonly 作用域。 -`calendar-events` 会预览匹配的 Meet 事件,并标记 `latest`、`artifacts`、`attendance` 或 `export` 将会选择的事件。 +`--today` 会在今天的 `primary` 日历中搜索带有 +Google Meet 链接的 Calendar 事件。 +使用 `--event ` 搜索匹配的事件文本, +使用 `--calendar ` 指定非主日历。 +日历查找需要一次新的 OAuth 登录,并且该登录包含 Calendar events readonly 作用域。 +`calendar-events` 会预览匹配的 Meet 事件,并标记 `latest`、 +`artifacts`、`attendance` 或 `export` 将选择的那个事件。 -如果你已经知道 conference record id,可以直接指定它: +如果你已经知道会议记录 ID,可以直接指定它: ```bash openclaw googlemeet latest --meeting https://meet.google.com/abc-defg-hij @@ -553,10 +633,23 @@ openclaw googlemeet export --conference-record conferenceRecords/abc123 \ --include-doc-bodies --dry-run ``` -`artifacts` 会返回会议记录元数据,以及当 Google 为该会议提供这些数据时的参与者、录制、转录、结构化 transcript-entry 和智能笔记资源元数据。对大型会议可使用 `--no-transcript-entries` 跳过条目查找。`attendance` 会将参与者展开为 participant-session 行,包含首次/最后出现时间、总会话时长、迟到/提前离开标记,并按已登录用户或显示名称合并重复的参与者资源。传入 `--no-merge-duplicates` 可保持原始参与者资源彼此分离,传入 `--late-after-minutes` 可调整迟到判定,传入 `--early-before-minutes` 可调整提前离开判定。 +`artifacts` 会返回会议记录元数据,以及 Google 为该会议公开时的参与者、 +录音、转录、结构化 transcript-entry 和智能笔记资源元数据。 +对于大型会议,使用 `--no-transcript-entries` 可跳过条目查找。 +`attendance` 会将参与者展开为 participant-session 行,包含首次/最后出现时间、总会话时长、迟到/提前离开标记,以及按已登录用户或显示名称合并的重复参与者资源。 +传递 `--no-merge-duplicates` 可保持原始参与者资源彼此分离,传递 `--late-after-minutes` 可调整迟到判定,传递 `--early-before-minutes` 可调整提前离开判定。 -`export` 会写出一个文件夹,其中包含 `summary.md`、`attendance.csv`、`transcript.md`、`artifacts.json`、`attendance.json` 和 `manifest.json`。`manifest.json` 会记录所选输入、导出选项、会议记录、输出文件、计数、令牌来源、使用到的 Calendar 事件,以及任何部分检索警告。传入 `--zip` 可在该文件夹旁边额外写出一个可移植归档文件。传入 `--include-doc-bodies` 可通过 Google Drive `files.export` 导出已链接的 transcript 和智能笔记 Google Docs 文本;这需要一次新的 OAuth 登录,并包含 Drive Meet readonly 作用域。不使用 `--include-doc-bodies` 时,导出内容只包含 Meet 元数据和结构化 transcript-entry。如果 Google 返回部分工件失败,例如智能笔记列表、transcript-entry 或 Drive 文档正文错误,摘要和清单会保留该警告,而不会让整个导出失败。 -使用 `--dry-run` 可获取同样的工件/出席数据,并打印 manifest JSON,而不会创建文件夹或 ZIP。这在写出大型导出之前,或者当智能体只需要计数、所选记录和警告时很有用。 +`export` 会写出一个文件夹,其中包含 `summary.md`、`attendance.csv`、 +`transcript.md`、`artifacts.json`、`attendance.json` 和 `manifest.json`。 +`manifest.json` 会记录所选输入、导出选项、会议记录、输出文件、计数、 +令牌来源、使用到的 Calendar 事件,以及任何部分检索警告。 +传递 `--zip` 可在该文件夹旁边额外写出一个可移植归档文件。 +传递 `--include-doc-bodies` 可通过 Google Drive `files.export` 导出已链接的 transcript 和智能笔记 Google Docs 文本;这需要一次新的 OAuth 登录,并包含 Drive Meet readonly 作用域。 +如果不使用 `--include-doc-bodies`,导出内容只包含 Meet 元数据和结构化 transcript-entry。 +如果 Google 返回部分工件失败,例如智能笔记列表、transcript-entry 或 Drive 文档正文错误,摘要和清单会保留该警告,而不会让整个导出失败。 +使用 `--dry-run` 可获取相同的工件/出席数据,并打印 +manifest JSON,而不创建文件夹或 ZIP。 +这在写入大型导出之前,或者当智能体只需要计数、已选记录和警告时非常有用。 智能体也可以通过 `google_meet` 工具创建同样的打包结果: @@ -570,9 +663,9 @@ openclaw googlemeet export --conference-record conferenceRecords/abc123 \ } ``` -将 `"dryRun": true` 设置为只返回导出清单并跳过文件写入。 +设置 `"dryRun": true` 可只返回导出清单并跳过文件写入。 -对真实保留会议运行受保护的实时冒烟测试: +对一个真实保留的会议运行受保护的实时冒烟测试: ```bash OPENCLAW_LIVE_TEST=1 \ @@ -582,15 +675,23 @@ pnpm test:live -- extensions/google-meet/google-meet.live.test.ts 实时冒烟测试环境: -- `OPENCLAW_LIVE_TEST=1` 启用受保护的实时测试。 -- `OPENCLAW_GOOGLE_MEET_LIVE_MEETING` 指向一个保留的 Meet URL、代码或 `spaces/{id}`。 -- `OPENCLAW_GOOGLE_MEET_CLIENT_ID` 或 `GOOGLE_MEET_CLIENT_ID` 提供 OAuth client id。 -- `OPENCLAW_GOOGLE_MEET_REFRESH_TOKEN` 或 `GOOGLE_MEET_REFRESH_TOKEN` 提供刷新令牌。 -- 可选:`OPENCLAW_GOOGLE_MEET_CLIENT_SECRET`、`OPENCLAW_GOOGLE_MEET_ACCESS_TOKEN` 和 `OPENCLAW_GOOGLE_MEET_ACCESS_TOKEN_EXPIRES_AT` 使用相同的回退名称,只是不带 `OPENCLAW_` 前缀。 +- `OPENCLAW_LIVE_TEST=1` 会启用受保护的实时测试。 +- `OPENCLAW_GOOGLE_MEET_LIVE_MEETING` 指向一个保留的 Meet URL、代码或 + `spaces/{id}`。 +- `OPENCLAW_GOOGLE_MEET_CLIENT_ID` 或 `GOOGLE_MEET_CLIENT_ID` 提供 OAuth + client id。 +- `OPENCLAW_GOOGLE_MEET_REFRESH_TOKEN` 或 `GOOGLE_MEET_REFRESH_TOKEN` 提供 + refresh token。 +- 可选:`OPENCLAW_GOOGLE_MEET_CLIENT_SECRET`、 + `OPENCLAW_GOOGLE_MEET_ACCESS_TOKEN` 和 + `OPENCLAW_GOOGLE_MEET_ACCESS_TOKEN_EXPIRES_AT` 使用相同的回退名称, + 只是没有 `OPENCLAW_` 前缀。 -基础的工件/出席实时冒烟测试需要 +基础工件/出席实时冒烟测试需要 `https://www.googleapis.com/auth/meetings.space.readonly` 和 -`https://www.googleapis.com/auth/meetings.conference.media.readonly`。Calendar 查找需要 `https://www.googleapis.com/auth/calendar.events.readonly`。Drive 文档正文导出需要 +`https://www.googleapis.com/auth/meetings.conference.media.readonly`。 +Calendar 查找需要 `https://www.googleapis.com/auth/calendar.events.readonly`。 +Drive 文档正文导出需要 `https://www.googleapis.com/auth/drive.meet.readonly`。 创建一个新的 Meet 空间: @@ -599,9 +700,14 @@ pnpm test:live -- extensions/google-meet/google-meet.live.test.ts openclaw googlemeet create ``` -该命令会打印新的 `meeting uri`、来源和加入会话。有 OAuth 凭证时,它会使用官方 Google Meet API。没有 OAuth 凭证时,它会使用固定 Chrome 节点上已登录的浏览器配置文件作为回退。智能体可以使用 `google_meet` 工具并设置 `action: "create"`,一步完成创建和加入。若只创建 URL,请传入 `"join": false`。 +该命令会打印新的 `meeting uri`、来源和加入会话。 +如果有 OAuth 凭证,它会使用官方 Google Meet API。 +如果没有 OAuth 凭证,它会回退为使用固定 Chrome 节点上已登录的浏览器配置文件。 +智能体可以使用 `google_meet` 工具并设置 `action: "create"`, +一次性完成创建并加入。 +若只创建 URL,请传递 `"join": false`。 -来自浏览器回退的 JSON 输出示例: +浏览器回退的 JSON 输出示例: ```json { @@ -621,7 +727,8 @@ openclaw googlemeet create } ``` -如果浏览器回退在创建 URL 之前遇到 Google 登录或 Meet 权限阻塞,Gateway 网关方法会返回失败响应,而 `google_meet` 工具会返回结构化详情,而不是普通字符串: +如果浏览器回退在创建 URL 之前就遇到 Google 登录或 Meet 权限阻塞, +Gateway 网关方法会返回失败响应,而 `google_meet` 工具会返回结构化详情,而不是普通字符串: ```json { @@ -639,9 +746,11 @@ openclaw googlemeet create } ``` -当智能体看到 `manualActionRequired: true` 时,它应报告 `manualActionMessage`,再加上浏览器节点/标签页上下文,并停止打开新的 Meet 标签页,直到操作员完成浏览器步骤。 +当智能体看到 `manualActionRequired: true` 时,它应报告 +`manualActionMessage` 以及浏览器节点/标签页上下文,并停止继续打开新的 +Meet 标签页,直到操作员完成浏览器步骤。 -来自 API 创建的 JSON 输出示例: +API 创建的 JSON 输出示例: ```json { @@ -662,13 +771,18 @@ openclaw googlemeet create } ``` -创建 Meet 默认会加入会议。Chrome 或 chrome-node 传输方式仍然需要一个已登录 Google 的 Chrome 配置文件,才能通过浏览器加入。如果该配置文件已退出登录,OpenClaw 会报告 `manualActionRequired: true` 或浏览器回退错误,并要求操作员先完成 Google 登录再重试。 +默认情况下,创建 Meet 后会立即加入。 +Chrome 或 chrome-node 传输方式仍然需要一个已登录 Google 的 Chrome 配置文件,才能通过浏览器加入。 +如果该配置文件已退出登录,OpenClaw 会报告 `manualActionRequired: true` 或浏览器回退错误,并要求操作员先完成 Google 登录,再重试。 -仅在确认你的 Cloud 项目、OAuth principal 和会议参与者都已加入用于 Meet 媒体 API 的 Google Workspace Developer Preview Program 后,再设置 `preview.enrollmentAcknowledged: true`。 +只有在确认你的 Cloud 项目、OAuth principal 和会议参与者都已加入 +Google Workspace Developer Preview Program for Meet media APIs 之后,才设置 `preview.enrollmentAcknowledged: true`。 ## 配置 -常见的 Chrome `realtime` 路径只需要启用插件、BlackHole、SoX,以及一个后端实时语音提供商密钥。OpenAI 是默认选项;设置 `realtime.provider: "google"` 可使用 Google Gemini Live: +常见的 Chrome 实时路径只需要启用插件、BlackHole、SoX,以及一个后端实时语音提供商密钥。 +OpenAI 是默认选项;设置 +`realtime.provider: "google"` 可使用 Google Gemini Live: ```bash brew install blackhole-2ch sox @@ -696,18 +810,20 @@ export GEMINI_API_KEY=... - `defaultTransport: "chrome"` - `defaultMode: "realtime"` -- `chromeNode.node`:`chrome-node` 的可选节点 id/名称/IP +- `chromeNode.node`:`chrome-node` 的可选节点 id/name/IP - `chrome.audioBackend: "blackhole-2ch"` - `chrome.guestName: "OpenClaw Agent"`:在已退出登录的 Meet 访客界面上使用的名称 -- `chrome.autoJoin: true`:通过 OpenClaw 浏览器自动化在 `chrome-node` 上尽力完成访客名填写并点击 Join Now +- `chrome.autoJoin: true`:在 `chrome-node` 上通过 OpenClaw 浏览器自动化尽力填写访客名并点击 Join Now - `chrome.reuseExistingTab: true`:激活现有 Meet 标签页,而不是打开重复标签页 -- `chrome.waitForInCallMs: 20000`:等待 Meet 标签页报告已在通话中,然后才触发实时介绍 -- `chrome.audioInputCommand`:将 8 kHz G.711 mu-law 音频写入 stdout 的 SoX `rec` 命令 -- `chrome.audioOutputCommand`:从 stdin 读取 8 kHz G.711 mu-law 音频的 SoX `play` 命令 +- `chrome.waitForInCallMs: 20000`:等待 Meet 标签页报告已在通话中,然后再触发实时介绍 +- `chrome.audioInputCommand`:SoX `rec` 命令,将 8 kHz G.711 mu-law 音频写入 stdout +- `chrome.audioOutputCommand`:SoX `play` 命令,从 stdin 读取 8 kHz G.711 mu-law 音频 - `realtime.provider: "openai"` - `realtime.toolPolicy: "safe-read-only"` -- `realtime.instructions`:简短口头回复,并在需要更深入回答时使用 `openclaw_agent_consult` +- `realtime.instructions`:简短口头回复,较深入的回答使用 + `openclaw_agent_consult` - `realtime.introMessage`:实时桥接连接时的简短口头就绪检查;将其设为 `""` 可静默加入 +- `realtime.agentId`:用于 `openclaw_agent_consult` 的可选 OpenClaw 智能体 id;默认值为 `main` 可选覆盖项: @@ -726,6 +842,7 @@ export GEMINI_API_KEY=... }, realtime: { provider: "google", + agentId: "jay", toolPolicy: "owner", introMessage: "Say exactly: I'm here.", providers: { @@ -753,7 +870,8 @@ export GEMINI_API_KEY=... } ``` -`voiceCall.enabled` 默认为 `true`;使用 Twilio 传输方式时,它会将实际的 PSTN 呼叫和 DTMF 委派给 Voice Call 插件。如果未启用 `voice-call`,Google Meet 仍然可以验证并记录拨号计划,但无法发起 Twilio 呼叫。 +`voiceCall.enabled` 默认值为 `true`;使用 Twilio 传输方式时,它会将实际的 PSTN 呼叫和 DTMF 委派给 Voice Call 插件。 +如果 `voice-call` 未启用,Google Meet 仍然可以验证并记录拨号计划,但无法发起 Twilio 呼叫。 ## 工具 @@ -768,17 +886,24 @@ export GEMINI_API_KEY=... } ``` -当 Chrome 运行在 Gateway 网关主机上时,请使用 `transport: "chrome"`。当 Chrome 运行在已配对节点(例如 Parallels 虚拟机)上时,请使用 `transport: "chrome-node"`。在这两种情况下,实时模型和 `openclaw_agent_consult` 都运行在 Gateway 网关主机上,因此模型凭证也保留在那里。 +当 Chrome 运行在 Gateway 网关主机上时,请使用 `transport: "chrome"`。 +当 Chrome 运行在已配对节点(例如 Parallels VM)上时,请使用 +`transport: "chrome-node"`。 +在这两种情况下,实时模型和 `openclaw_agent_consult` 都运行在 +Gateway 网关主机上,因此模型凭证会保留在那里。 -使用 `action: "status"` 可列出活跃会话或检查某个会话 ID。使用带有 `sessionId` 和 `message` 的 `action: "speak"` 可让实时智能体立即发言。使用 `action: "test_speech"` 可创建或复用会话、触发一段已知短语,并在 Chrome 主机可报告时返回 `inCall` 健康状态。使用 `action: "leave"` 可将会话标记为已结束。 +使用 `action: "status"` 可列出活动会话或检查某个会话 ID。 +使用 `action: "speak"` 并传入 `sessionId` 和 `message`,可让实时智能体立即发声。 +使用 `action: "test_speech"` 可创建或复用会话、触发一段已知短语,并在 Chrome 主机可报告时返回 `inCall` 健康状态。 +使用 `action: "leave"` 可将某个会话标记为已结束。 `status` 在可用时包含 Chrome 健康信息: - `inCall`:Chrome 看起来已在 Meet 通话中 -- `micMuted`:尽力推断的 Meet 麦克风状态 -- `manualActionRequired` / `manualActionReason` / `manualActionMessage`:浏览器配置文件需要手动登录、Meet 主持人准入、权限处理或浏览器控制修复,之后语音才能工作 +- `micMuted`:尽力获取的 Meet 麦克风状态 +- `manualActionRequired` / `manualActionReason` / `manualActionMessage`:浏览器配置文件需要手动登录、Meet 主持人准入、权限授予或浏览器控制修复,语音功能才能工作 - `providerConnected` / `realtimeReady`:实时语音桥接状态 -- `lastInputAt` / `lastOutputAt`:最近一次从桥接收到或发送到桥接的音频时间 +- `lastInputAt` / `lastOutputAt`:最近一次从桥接接收或发送音频的时间 ```json { @@ -790,17 +915,26 @@ export GEMINI_API_KEY=... ## 实时智能体咨询 -Chrome `realtime` 模式针对实时语音循环进行了优化。实时语音提供商会听取会议音频,并通过已配置的音频桥接发声。当实时模型需要更深入的推理、当前信息或普通 OpenClaw 工具时,它可以调用 `openclaw_agent_consult`。 +Chrome 实时模式针对实时语音循环进行了优化。 +实时语音提供商会听取会议音频,并通过已配置的音频桥接发声。 +当实时模型需要更深入的推理、最新信息或常规 OpenClaw 工具时,它可以调用 `openclaw_agent_consult`。 -咨询工具会在后台运行常规 OpenClaw 智能体,附带最近的会议转录上下文,并向实时语音会话返回一个简洁的口头回答。随后语音模型就可以将该回答说回会议中。它与 Voice Call 共用同一个实时咨询工具。 +咨询工具会在后台运行常规 OpenClaw 智能体,携带最近的会议转录上下文,并向实时语音会话返回简洁的口头回答。 +然后语音模型就可以把该回答说回会议中。 +它与 Voice Call 共用同一个实时咨询工具。 + +默认情况下,咨询会针对 `main` 智能体运行。 +当某个 Meet 通道应咨询一个专用的 OpenClaw 智能体工作区、模型默认值、工具策略、内存和会话历史时,请设置 `realtime.agentId`。 `realtime.toolPolicy` 控制咨询运行方式: -- `safe-read-only`:暴露咨询工具,并将常规智能体限制为使用 `read`、`web_search`、`web_fetch`、`x_search`、`memory_search` 和 `memory_get`。 -- `owner`:暴露咨询工具,并允许常规智能体使用正常的智能体工具策略。 -- `none`:不向实时语音模型暴露咨询工具。 +- `safe-read-only`:暴露咨询工具,并将常规智能体限制为使用 + `read`、`web_search`、`web_fetch`、`x_search`、`memory_search` 和 + `memory_get`。 +- `owner`:暴露咨询工具,并让常规智能体使用正常的智能体工具策略。 +- `none`:不要向实时语音模型暴露咨询工具。 -咨询会话键按 Meet 会话分别限定,因此后续咨询调用可以在同一场会议期间复用先前的咨询上下文。 +咨询会话键按每个 Meet 会话分别设定作用域,因此在同一场会议期间,后续咨询调用可以复用之前的咨询上下文。 要在 Chrome 完全加入通话后强制执行一次口头就绪检查: @@ -808,7 +942,7 @@ Chrome `realtime` 模式针对实时语音循环进行了优化。实时语音 openclaw googlemeet speak meet_... "Say exactly: I'm here and listening." ``` -用于完整的加入并发言冒烟测试: +要执行完整的“加入并发声”冒烟测试: ```bash openclaw googlemeet test-speech https://meet.google.com/abc-defg-hij \ @@ -816,9 +950,9 @@ openclaw googlemeet test-speech https://meet.google.com/abc-defg-hij \ --message "Say exactly: I'm here and listening." ``` -## 实时测试检查清单 +## 实时测试清单 -在把会议交给无人值守的智能体之前,使用以下顺序: +在将会议交给无人值守的智能体之前,请使用以下顺序: ```bash openclaw googlemeet setup @@ -831,12 +965,12 @@ openclaw googlemeet test-speech https://meet.google.com/abc-defg-hij \ 预期的 chrome-node 状态: - `googlemeet setup` 全部为绿色。 -- 当 chrome-node 是默认传输方式或已固定某个节点时,`googlemeet setup` 会包含 `chrome-node-connected`。 +- 当 chrome-node 是默认传输方式或某个节点已被固定时,`googlemeet setup` 会包含 `chrome-node-connected`。 - `nodes status` 显示所选节点已连接。 -- 所选节点同时宣告 `googlemeet.chrome` 和 `browser.proxy`。 -- Meet 标签页加入通话,且 `test-speech` 返回的 Chrome 健康状态中 `inCall: true`。 +- 所选节点同时广播 `googlemeet.chrome` 和 `browser.proxy`。 +- Meet 标签页已加入通话,并且 `test-speech` 返回的 Chrome 健康状态中包含 `inCall: true`。 -对于远程 Chrome 主机(例如 Parallels macOS 虚拟机),这是在更新 Gateway 网关或虚拟机之后最短且安全的检查方式: +对于远程 Chrome 主机(例如 Parallels macOS VM),在更新 Gateway 网关或 VM 之后,这是最简短且安全的检查方式: ```bash openclaw googlemeet setup @@ -847,9 +981,9 @@ openclaw nodes invoke \ --params '{"action":"setup"}' ``` -这可以证明 Gateway 网关插件已加载、虚拟机节点使用当前令牌已连接,并且在智能体打开真实会议标签页之前,Meet 音频桥接已可用。 +这可以证明 Gateway 网关插件已加载、VM 节点已使用当前令牌连接,并且在智能体打开真实会议标签页之前,Meet 音频桥接已可用。 -对于 Twilio 冒烟测试,请使用一个会暴露电话拨入详情的会议: +对于 Twilio 冒烟测试,请使用一个会公开电话拨入详情的会议: ```bash openclaw googlemeet setup @@ -861,25 +995,27 @@ openclaw googlemeet join https://meet.google.com/abc-defg-hij \ 预期的 Twilio 状态: -- `googlemeet setup` 包含绿色的 `twilio-voice-call-plugin` 和 `twilio-voice-call-credentials` 检查项。 -- Gateway 网关重新加载后,CLI 中可用 `voicecall`。 -- 返回的会话具有 `transport: "twilio"` 和一个 `twilio.voiceCallId`。 -- `googlemeet leave ` 会挂断已委派的语音呼叫。 +- `googlemeet setup` 包含绿色的 `twilio-voice-call-plugin` 和 + `twilio-voice-call-credentials` 检查项。 +- 在 Gateway 网关重新加载后,CLI 中可用 `voicecall`。 +- 返回的会话带有 `transport: "twilio"` 和一个 `twilio.voiceCallId`。 +- `googlemeet leave ` 会挂断被委派的语音呼叫。 ## 故障排除 ### 智能体看不到 Google Meet 工具 -确认插件已在 Gateway 网关配置中启用,并重新加载 Gateway 网关: +确认该插件已在 Gateway 网关配置中启用,并重新加载 Gateway 网关: ```bash openclaw plugins list | grep google-meet openclaw googlemeet setup ``` -如果你刚刚编辑了 `plugins.entries.google-meet`,请重启或重新加载 Gateway 网关。正在运行的智能体只能看到当前 Gateway 网关进程已注册的插件工具。 +如果你刚刚编辑了 `plugins.entries.google-meet`,请重启或重新加载 Gateway 网关。 +正在运行的智能体只能看到由当前 Gateway 网关进程注册的插件工具。 -### 没有已连接的具备 Google Meet 能力的节点 +### 没有已连接的 Google Meet 可用节点 在节点主机上运行: @@ -890,7 +1026,7 @@ OPENCLAW_ALLOW_INSECURE_PRIVATE_WS=1 \ openclaw node run --host --port 18789 --display-name parallels-macos ``` -在 Gateway 网关主机上,批准该节点并验证命令: +在 Gateway 网关主机上,批准节点并验证命令: ```bash openclaw devices list @@ -898,7 +1034,7 @@ openclaw devices approve openclaw nodes status ``` -该节点必须已连接,并列出 `googlemeet.chrome` 和 `browser.proxy`。 +该节点必须已连接,并列出 `googlemeet.chrome` 以及 `browser.proxy`。 Gateway 网关配置必须允许这些节点命令: ```json5 @@ -911,7 +1047,8 @@ Gateway 网关配置必须允许这些节点命令: } ``` -如果 `googlemeet setup` 的 `chrome-node-connected` 检查失败,或 Gateway 网关日志报告 `gateway token mismatch`,请使用当前 Gateway 网关令牌重新安装或重启该节点。对于局域网 Gateway 网关,这通常意味着: +如果 `googlemeet setup` 的 `chrome-node-connected` 检查失败,或者 Gateway 网关日志报告 +`gateway token mismatch`,请使用当前 Gateway 网关令牌重新安装或重启该节点。对于局域网 Gateway 网关,这通常意味着: ```bash OPENCLAW_ALLOW_INSECURE_PRIVATE_WS=1 \ @@ -929,65 +1066,80 @@ openclaw googlemeet setup openclaw nodes status --connected ``` -### 浏览器打开了,但智能体无法加入 +### 浏览器已打开,但智能体无法加入 -运行 `googlemeet test-speech` 并检查返回的 Chrome 健康状态。如果其中报告 `manualActionRequired: true`,请向操作员显示 `manualActionMessage`,并在浏览器操作完成前停止重试。 +运行 `googlemeet test-speech` 并检查返回的 Chrome 健康状态。 +如果它报告 `manualActionRequired: true`,请将 `manualActionMessage` 展示给操作员,并在浏览器操作完成前停止重试。 -常见的手动操作: +常见手动操作: -- 登录 Chrome 配置文件。 -- 通过 Meet 主持账号批准访客加入。 -- 当出现 Chrome 原生权限提示时,授予 Chrome 麦克风/摄像头权限。 +- 登录到 Chrome 配置文件。 +- 通过 Meet 主持账号准入访客。 +- 当出现 Chrome 原生权限提示时,为 Chrome 授予麦克风/摄像头权限。 - 关闭或修复卡住的 Meet 权限对话框。 -不要仅因为 Meet 显示 “Do you want people to hear you in the meeting?” 就报告“未登录”。这是 Meet 的音频选择过渡页;OpenClaw 会在可用时通过浏览器自动化点击 **Use microphone**,并继续等待真实的会议状态。对于仅创建 URL 的浏览器回退,由于创建 URL 不需要 `realtime` 音频路径,OpenClaw 可能会点击 **Continue without microphone**。 +不要仅因为 Meet 显示“Do you want people to hear you in the meeting?” 就报告“未登录”。 +这是 Meet 的音频选择过渡页面;OpenClaw 会在可用时通过浏览器自动化点击 **Use microphone**,并继续等待真正的会议状态。 +对于仅创建的浏览器回退,OpenClaw 可能会点击 **Continue without microphone**,因为创建 URL 不需要实时音频路径。 ### 会议创建失败 -配置了 OAuth 凭证时,`googlemeet create` 会首先使用 Google Meet API 的 `spaces.create` 端点。没有 OAuth 凭证时,它会回退到固定的 Chrome 节点浏览器。请确认: +配置了 OAuth 凭证时,`googlemeet create` 会首先使用 Google Meet API 的 `spaces.create` 端点。 +如果没有 OAuth 凭证,它会回退到固定的 Chrome 节点浏览器。请确认: - 对于 API 创建:已配置 `oauth.clientId` 和 `oauth.refreshToken`,或者存在匹配的 `OPENCLAW_GOOGLE_MEET_*` 环境变量。 -- 对于 API 创建:刷新令牌是在支持创建功能之后生成的。较旧的令牌可能缺少 `meetings.space.created` 作用域;请重新运行 `openclaw googlemeet auth login --json` 并更新插件配置。 -- 对于浏览器回退:`defaultTransport: "chrome-node"` 且 `chromeNode.node` 指向一个已连接、具备 `browser.proxy` 和 `googlemeet.chrome` 的节点。 +- 对于 API 创建:刷新令牌是在添加创建支持之后生成的。较旧的令牌可能缺少 `meetings.space.created` 作用域;请重新运行 `openclaw googlemeet auth login --json` 并更新插件配置。 +- 对于浏览器回退:`defaultTransport: "chrome-node"` 和 `chromeNode.node` 指向一个已连接的节点,并且该节点具备 `browser.proxy` 和 `googlemeet.chrome`。 - 对于浏览器回退:该节点上的 OpenClaw Chrome 配置文件已登录 Google,并且可以打开 `https://meet.google.com/new`。 -- 对于浏览器回退:重试会复用现有的 `https://meet.google.com/new` 或 Google 账号提示标签页,而不是打开新标签页。如果智能体超时,请重试工具调用,而不是手动再打开一个 Meet 标签页。 -- 对于浏览器回退:如果工具返回 `manualActionRequired: true`,请使用返回的 `browser.nodeId`、`browser.targetId`、`browserUrl` 和 `manualActionMessage` 来指导操作员。在该操作完成前,不要循环重试。 -- 对于浏览器回退:如果 Meet 显示 “Do you want people to hear you in the meeting?”,请保持该标签页打开。OpenClaw 应通过浏览器自动化点击 **Use microphone**,或者在仅创建的回退场景中点击 **Continue without microphone**,然后继续等待生成的 Meet URL。如果无法做到,错误中应提到 `meet-audio-choice-required`,而不是 `google-login-required`。 +- 对于浏览器回退:重试时会复用现有的 `https://meet.google.com/new` 或 Google 账号提示标签页,而不是打开新标签页。如果智能体超时,请重试工具调用,而不是手动再打开一个 Meet 标签页。 +- 对于浏览器回退:如果工具返回 `manualActionRequired: true`,请使用返回的 `browser.nodeId`、`browser.targetId`、`browserUrl` 和 `manualActionMessage` 指导操作员。在该操作完成前,不要循环重试。 +- 对于浏览器回退:如果 Meet 显示 “Do you want people to hear you in the meeting?”,请保持标签页打开。OpenClaw 应通过浏览器自动化点击 **Use microphone**,或者在仅创建回退中点击 **Continue without microphone**,然后继续等待生成的 Meet URL。如果做不到,错误信息应提到 `meet-audio-choice-required`,而不是 `google-login-required`。 -### 智能体加入了,但不说话 +### 智能体已加入但不说话 -检查 `realtime` 路径: +检查实时路径: ```bash openclaw googlemeet setup openclaw googlemeet doctor ``` -使用 `mode: "realtime"` 进行收听/回话。`mode: "transcribe"` 会有意不启动双工实时语音桥接。 +使用 `mode: "realtime"` 进行监听/回话。 +`mode: "transcribe"` 则会按设计不启动双向实时语音桥接。 -还要验证: +另外还要验证: -- Gateway 网关主机上有可用的实时提供商密钥,例如 `OPENAI_API_KEY` 或 `GEMINI_API_KEY`。 -- `BlackHole 2ch` 在 Chrome 主机上可见。 -- `rec` 和 `play` 在 Chrome 主机上存在。 +- Gateway 网关主机上有可用的实时提供商密钥,例如 + `OPENAI_API_KEY` 或 `GEMINI_API_KEY`。 +- Chrome 主机上可以看到 `BlackHole 2ch`。 +- Chrome 主机上存在 `rec` 和 `play`。 - Meet 的麦克风和扬声器已通过 OpenClaw 使用的虚拟音频路径进行路由。 -`googlemeet doctor [session-id]` 会打印会话、节点、通话中状态、手动操作原因、实时提供商连接、`realtimeReady`、音频输入/输出活动、最近音频时间戳、字节计数和浏览器 URL。当你需要原始 JSON 时,请使用 `googlemeet status [session-id]`。当你需要在不暴露令牌的情况下验证 Google Meet OAuth 刷新时,请使用 `googlemeet doctor --oauth`;当你还需要 Google Meet API 证明时,可额外加上 `--meeting` 或 `--create-space`。 +`googlemeet doctor [session-id]` 会打印会话、节点、通话内状态、手动操作原因、实时提供商连接、`realtimeReady`、音频输入/输出活动、最近音频时间戳、字节计数以及浏览器 URL。 +当你需要原始 JSON 时,请使用 `googlemeet status [session-id]`。 +当你需要验证 Google Meet OAuth 刷新而不暴露令牌时,请使用 `googlemeet doctor --oauth`;当你还需要 Google Meet API 证明时,可加上 `--meeting` 或 `--create-space`。 -如果智能体已超时,而你能看到一个已经打开的 Meet 标签页,请在不再打开新标签页的情况下检查该标签页: +如果某个智能体已超时,而你能看到一个 Meet 标签页已经打开,请在不再打开新标签页的情况下检查该标签页: ```bash openclaw googlemeet recover-tab openclaw googlemeet recover-tab https://meet.google.com/abc-defg-hij ``` -对应的工具动作是 `recover_current_tab`。它会为所选传输方式聚焦并检查现有的 Meet 标签页。使用 `chrome` 时,它通过 Gateway 网关进行本地浏览器控制;使用 `chrome-node` 时,它使用已配置的 Chrome 节点。它不会打开新标签页,也不会创建新会话;它会报告当前阻塞项,例如登录、准入、权限或音频选择状态。CLI 命令会与已配置的 Gateway 网关通信,因此 Gateway 网关必须正在运行;`chrome-node` 还要求 Chrome 节点已连接。 +对应的工具动作是 `recover_current_tab`。 +它会针对所选传输方式聚焦并检查现有 Meet 标签页。 +对于 `chrome`,它通过 Gateway 网关使用本地浏览器控制; +对于 `chrome-node`,它使用已配置的 Chrome 节点。 +它不会打开新标签页,也不会创建新会话;它会报告当前阻塞项,例如登录、准入、权限或音频选择状态。 +该 CLI 命令会与已配置的 Gateway 网关通信,因此 Gateway 网关必须处于运行状态;`chrome-node` 还要求 Chrome 节点已连接。 ### Twilio 设置检查失败 -当 `voice-call` 未被允许或未启用时,`twilio-voice-call-plugin` 会失败。请将其添加到 `plugins.allow`,启用 `plugins.entries.voice-call`,然后重新加载 Gateway 网关。 +当 `voice-call` 未被允许或未启用时,`twilio-voice-call-plugin` 会失败。 +请将其添加到 `plugins.allow`,启用 `plugins.entries.voice-call`,并重新加载 Gateway 网关。 -当 Twilio 后端缺少 account SID、auth token 或主叫号码时,`twilio-voice-call-credentials` 会失败。请在 Gateway 网关主机上设置以下内容: +当 Twilio 后端缺少 account SID、auth token 或 caller number 时,`twilio-voice-call-credentials` 会失败。 +请在 Gateway 网关主机上设置这些值: ```bash export TWILIO_ACCOUNT_SID=AC... @@ -1003,21 +1155,23 @@ openclaw voicecall setup openclaw voicecall smoke ``` -`voicecall smoke` 默认仅进行就绪性检查。若要对特定号码执行 dry-run: +默认情况下,`voicecall smoke` 仅执行就绪性检查。 +要对某个特定号码执行 dry-run: ```bash openclaw voicecall smoke --to "+15555550123" ``` -只有在你明确想发起一次真实的外呼通知电话时,才添加 `--yes`: +只有在你明确要发起真实的外拨通知呼叫时,才添加 `--yes`: ```bash openclaw voicecall smoke --to "+15555550123" --yes ``` -### Twilio 呼叫已开始,但始终未进入会议 +### Twilio 呼叫开始了,但始终未进入会议 -确认 Meet 事件暴露了电话拨入详情。请传入精确的拨入号码和 PIN,或一个自定义 DTMF 序列: +确认 Meet 事件公开了电话拨入详情。 +传入精确的拨入号码和 PIN,或者自定义 DTMF 序列: ```bash openclaw googlemeet join https://meet.google.com/abc-defg-hij \ @@ -1026,23 +1180,28 @@ openclaw googlemeet join https://meet.google.com/abc-defg-hij \ --dtmf-sequence ww123456# ``` -如果提供商在输入 PIN 前需要暂停,请在 `--dtmf-sequence` 中使用前导 `w` 或逗号。 +如果提供商在输入 PIN 之前需要暂停,请在 `--dtmf-sequence` 中使用前导 `w` 或逗号。 ## 说明 -Google Meet 的官方媒体 API 偏向接收,因此要向 Meet 通话中发言,仍然需要一个参与者路径。该插件明确保留了这条边界:Chrome 负责浏览器参与和本地音频路由;Twilio 负责电话拨入参与。 +Google Meet 的官方媒体 API 偏向接收,因此要向 Meet 通话中发声,仍然需要一个参与者路径。 +该插件会保持这一边界清晰可见: +Chrome 负责浏览器参与和本地音频路由;Twilio 负责电话拨入参与。 -Chrome `realtime` 模式需要以下其一: +Chrome 实时模式需要以下之一: - `chrome.audioInputCommand` 加 `chrome.audioOutputCommand`:OpenClaw 拥有实时模型桥接,并在这些命令与所选实时语音提供商之间传输 8 kHz G.711 mu-law 音频。 - `chrome.audioBridgeCommand`:一个外部桥接命令拥有整个本地音频路径,并且必须在启动或验证其守护进程后退出。 -为了获得干净的双工音频,请将 Meet 输出和 Meet 麦克风通过独立的虚拟设备,或类似 Loopback 的虚拟设备图来路由。单个共享的 BlackHole 设备可能会将其他参与者的声音回送到通话中。 +为了获得干净的双工音频,请将 Meet 输出和 Meet 麦克风分别路由到独立的虚拟设备,或使用类似 Loopback 的虚拟设备图。 +单个共享的 BlackHole 设备可能会把其他参与者的声音回送进通话中。 -`googlemeet speak` 会触发某个 Chrome 会话当前活跃的实时音频桥接。`googlemeet leave` 会停止该桥接。对于通过 Voice Call 插件委派的 Twilio 会话,`leave` 还会挂断底层语音呼叫。 +`googlemeet speak` 会触发 Chrome 会话的活动实时音频桥接。 +`googlemeet leave` 会停止该桥接。 +对于通过 Voice Call 插件委派的 Twilio 会话,`leave` 还会挂断底层语音呼叫。 ## 相关内容 -- [Voice call 插件](/zh-CN/plugins/voice-call) -- [Talk 模式](/zh-CN/nodes/talk) +- [Voice call plugin](/zh-CN/plugins/voice-call) +- [Talk mode](/zh-CN/nodes/talk) - [构建插件](/zh-CN/plugins/building-plugins) diff --git a/docs/zh-CN/plugins/manifest.md b/docs/zh-CN/plugins/manifest.md index 1e3d0e38a..f8a7d2e38 100644 --- a/docs/zh-CN/plugins/manifest.md +++ b/docs/zh-CN/plugins/manifest.md @@ -1,53 +1,53 @@ --- read_when: - - 你正在构建一个 OpenClaw 插件 - - 你需要发布一个插件配置 schema,或调试插件验证错误 + - 你正在构建一个 OpenClaw 插件】【。 + - 你需要发布一个插件配置 schema,或调试插件验证错误】【。 summary: 插件清单 + JSON schema 要求(严格配置验证) title: 插件清单 x-i18n: - generated_at: "2026-04-26T08:13:19Z" + generated_at: "2026-04-27T08:00:40Z" model: gpt-5.4 provider: openai - source_hash: b86920ad774c5ef4ace7b546ef44e5b087a8ca694dea622ddb440258ffff4237 + source_hash: 9d6e1da1cc57f6ba89ef511b01636439dd34f0b847a306b96271ccf9c2b878d4 source_path: plugins/manifest.md workflow: 15 --- 此页面仅适用于**原生 OpenClaw 插件清单**。 -关于兼容的 bundle 布局,请参阅 [Plugin bundles](/zh-CN/plugins/bundles)。 +关于兼容的 bundle 布局,请参见 [Plugin bundles](/zh-CN/plugins/bundles)。 兼容的 bundle 格式使用不同的清单文件: - Codex bundle:`.codex-plugin/plugin.json` -- Claude bundle:`.claude-plugin/plugin.json` 或不带清单的默认 Claude 组件布局 +- Claude bundle:`.claude-plugin/plugin.json`,或不带清单的默认 Claude 组件布局 - Cursor bundle:`.cursor-plugin/plugin.json` -OpenClaw 也会自动检测这些 bundle 布局,但不会根据此处描述的 `openclaw.plugin.json` schema 对它们进行验证。 +OpenClaw 也会自动检测这些 bundle 布局,但它们不会根据此处描述的 `openclaw.plugin.json` schema 进行验证。 -对于兼容 bundle,当其布局符合 OpenClaw 运行时预期时,OpenClaw 目前会读取 bundle 元数据、已声明的 skill 根目录、Claude 命令根目录、Claude bundle 的 `settings.json` 默认值、Claude bundle 的 LSP 默认值,以及受支持的 hook 包。 +对于兼容 bundle,OpenClaw 当前会在布局符合 OpenClaw 运行时期望时,读取 bundle 元数据、已声明的 Skill 根目录、Claude 命令根目录、Claude bundle `settings.json` 默认值、Claude bundle LSP 默认值以及受支持的 hook pack。 -每个原生 OpenClaw 插件都**必须**在**插件根目录**中提供一个 `openclaw.plugin.json` 文件。OpenClaw 使用此清单在**不执行插件代码的情况下**验证配置。缺失或无效的清单会被视为插件错误,并阻止配置验证。 +每个原生 OpenClaw 插件**都必须**在**插件根目录**中提供一个 `openclaw.plugin.json` 文件。OpenClaw 使用这个清单在**不执行插件代码的情况下**验证配置。缺失或无效的清单会被视为插件错误,并阻止配置验证。 请参阅完整的插件系统指南:[Plugins](/zh-CN/tools/plugin)。 -关于原生能力模型和当前外部兼容性指南,请参阅: +关于原生能力模型和当前外部兼容性指导,请参见: [能力模型](/zh-CN/plugins/architecture#public-capability-model)。 -## 此文件的作用 +## 这个文件的作用 -`openclaw.plugin.json` 是 OpenClaw 在**加载你的插件代码之前**读取的元数据。以下所有内容都必须足够轻量,能够在不启动插件运行时的情况下进行检查。 +`openclaw.plugin.json` 是 OpenClaw 在**加载你的插件代码之前**读取的元数据。下面的所有内容都必须足够轻量,以便在不启动插件运行时的情况下进行检查。 -**用于:** +**将它用于:** -- 插件标识、配置验证,以及配置 UI 提示 -- 认证、新手引导和设置元数据(别名、自动启用、provider 环境变量、认证选项) -- control-plane 表面的激活提示 -- 简写的模型家族归属 +- 插件标识、配置验证和配置 UI 提示 +- 认证、新手引导和设置元数据(别名、自动启用、提供商环境变量、认证选项) +- 控制平面界面的激活提示 +- 简写模型族归属 - 静态能力归属快照(`contracts`) -- 共享 `openclaw qa` 宿主可检查的 QA 运行器元数据 -- 合并到目录和验证表面的渠道专用配置元数据 +- 共享 `openclaw qa` 主机可检查的 QA 运行器元数据 +- 合并到目录和验证界面中的渠道专用配置元数据 -**不要用于:** 注册运行时行为、声明代码入口点,或 npm 安装元数据。这些应放在你的插件代码和 `package.json` 中。 +**不要将它用于:** 注册运行时行为、声明代码入口点或 npm 安装元数据。这些属于你的插件代码和 `package.json`。 ## 最小示例 @@ -131,64 +131,67 @@ OpenClaw 也会自动检测这些 bundle 布局,但不会根据此处描述的 | ------------------------------------ | -------- | -------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `id` | 是 | `string` | 规范插件 id。这是在 `plugins.entries.` 中使用的 id。 | | `configSchema` | 是 | `object` | 此插件配置的内联 JSON Schema。 | -| `enabledByDefault` | 否 | `true` | 将内置插件标记为默认启用。省略此字段,或设置为任何非 `true` 的值,以使该插件默认保持禁用。 | +| `enabledByDefault` | 否 | `true` | 将内置插件标记为默认启用。省略此项,或设置为任何非 `true` 的值,以使该插件默认禁用。 | | `legacyPluginIds` | 否 | `string[]` | 会规范化为此规范插件 id 的旧版 id。 | -| `autoEnableWhenConfiguredProviders` | 否 | `string[]` | 当认证、配置或模型引用提到这些 provider id 时,应自动启用此插件。 | -| `kind` | 否 | `"memory"` \| `"context-engine"` | 声明由 `plugins.slots.*` 使用的独占插件类型。 | +| `autoEnableWhenConfiguredProviders` | 否 | `string[]` | 当认证、配置或模型引用提到这些提供商 id 时,应自动启用此插件。 | +| `kind` | 否 | `"memory"` \| `"context-engine"` | 声明一个由 `plugins.slots.*` 使用的互斥插件种类。 | | `channels` | 否 | `string[]` | 由此插件拥有的渠道 id。用于发现和配置验证。 | -| `providers` | 否 | `string[]` | 由此插件拥有的 provider id。 | -| `providerDiscoveryEntry` | 否 | `string` | 轻量级 provider 发现模块路径,相对于插件根目录,用于可在不激活完整插件运行时的情况下加载的、作用域限定于清单的 provider 目录元数据。 | -| `modelSupport` | 否 | `object` | 由清单拥有的简写模型家族元数据,用于在运行时之前自动加载插件。 | -| `modelCatalog` | 否 | `object` | 由声明式方式定义的、适用于此插件所拥有 providers 的模型目录元数据。这是未来只读列表、onboarding、模型选择器、别名和抑制功能在不加载插件运行时情况下使用的 control-plane 合约。 | -| `providerEndpoints` | 否 | `object[]` | 由清单拥有的 endpoint 主机 / `baseUrl` 元数据,用于核心在 provider 运行时加载之前必须分类的 provider 路由。 | +| `providers` | 否 | `string[]` | 由此插件拥有的提供商 id。 | +| `providerDiscoveryEntry` | 否 | `string` | 轻量级 provider 发现模块路径,相对于插件根目录,用于可在不激活完整插件运行时的情况下加载的、限定于清单范围内的 provider 目录元数据。 | +| `modelSupport` | 否 | `object` | 由清单拥有的简写模型族元数据,用于在运行时之前自动加载插件。 | +| `modelCatalog` | 否 | `object` | 适用于由此插件拥有的提供商的声明式模型目录元数据。这是未来只读列表、新手引导、模型选择器、别名和抑制功能在不加载插件运行时情况下的控制平面契约。 | +| `providerEndpoints` | 否 | `object[]` | 由清单拥有的端点 host / `baseUrl` 元数据,用于核心在 provider 运行时加载前必须分类的 provider 路由。 | | `cliBackends` | 否 | `string[]` | 由此插件拥有的 CLI 推理后端 id。用于根据显式配置引用在启动时自动激活。 | -| `syntheticAuthRefs` | 否 | `string[]` | 在运行时加载之前、冷启动模型发现期间,应探测其插件自有 synthetic auth hook 的 provider 或 CLI 后端引用。 | -| `nonSecretAuthMarkers` | 否 | `string[]` | 由内置插件拥有的占位 API key 值,表示非机密的本地、OAuth 或环境凭证状态。 | -| `commandAliases` | 否 | `object[]` | 由此插件拥有的命令名称,应在运行时加载之前生成带有插件感知能力的配置和 CLI 诊断信息。 | -| `providerAuthEnvVars` | 否 | `Record` | 用于 provider 认证 / Status 查找的已弃用兼容性环境变量元数据。对于新插件,优先使用 `setup.providers[].envVars`;OpenClaw 在弃用窗口期内仍会读取此字段。 | -| `providerAuthAliases` | 否 | `Record` | 应复用另一个 provider id 进行认证查找的 provider id,例如与基础 provider 共享 API key 和认证配置文件的编码 provider。 | -| `channelEnvVars` | 否 | `Record` | OpenClaw 可在不加载插件代码的情况下检查的轻量级渠道环境变量元数据。将其用于通用启动 / 配置辅助工具应可见的、由环境变量驱动的渠道设置或认证表面。 | -| `providerAuthChoices` | 否 | `object[]` | 用于 onboarding 选择器、首选 provider 解析和简单 CLI 标志接线的轻量级认证选项元数据。 | -| `activation` | 否 | `object` | 轻量级激活规划器元数据,用于由 provider、命令、渠道、路由和能力触发的加载。仅包含元数据;插件运行时仍拥有实际行为。 | -| `setup` | 否 | `object` | 轻量级设置 / onboarding 描述符,供发现和设置表面在不加载插件运行时的情况下检查。 | -| `qaRunners` | 否 | `object[]` | 由共享 `openclaw qa` 宿主在插件运行时加载前使用的轻量级 QA 运行器描述符。 | -| `contracts` | 否 | `object` | 静态内置能力快照,涵盖外部认证 hook、speech、实时转录、实时语音、媒体理解、图像生成、音乐生成、视频生成、网页抓取、网页搜索和工具归属。 | -| `mediaUnderstandingProviderMetadata` | 否 | `Record` | 为 `contracts.mediaUnderstandingProviders` 中声明的 provider id 提供的轻量级媒体理解默认元数据。 | -| `channelConfigs` | 否 | `Record` | 由清单拥有的渠道配置元数据,在运行时加载前合并到发现和验证表面中。 | +| `syntheticAuthRefs` | 否 | `string[]` | provider 或 CLI 后端引用;在运行时加载前的冷启动模型发现期间,应探测其由插件拥有的合成认证钩子。 | +| `nonSecretAuthMarkers` | 否 | `string[]` | 由内置插件拥有的占位 API 密钥值,表示非密钥的本地、OAuth 或环境凭证状态。 | +| `commandAliases` | 否 | `object[]` | 由此插件拥有的命令名称;在运行时加载前,这些命令应产生具备插件感知的配置和 CLI 诊断信息。 | +| `providerAuthEnvVars` | 否 | `Record` | 已弃用的兼容性环境变量元数据,用于 provider 认证 / Status 查询。对于新插件,优先使用 `setup.providers[].envVars`;OpenClaw 在弃用窗口期内仍会读取此项。 | +| `providerAuthAliases` | 否 | `Record` | 应复用另一个 provider id 进行认证查询的 provider id,例如共享基础 provider API 密钥和 auth profile 的编码 provider。 | +| `channelEnvVars` | 否 | `Record` | OpenClaw 可在不加载插件代码的情况下检查的轻量级渠道环境变量元数据。将其用于通用启动 / 配置辅助工具应可见的、由环境变量驱动的渠道设置或认证界面。 | +| `providerAuthChoices` | 否 | `object[]` | 适用于新手引导选择器、首选 provider 解析和简单 CLI 标志接线的轻量级认证选项元数据。 | +| `activation` | 否 | `object` | 适用于由 provider、命令、渠道、路由和能力触发加载的轻量级激活规划器元数据。仅为元数据;实际行为仍由插件运行时负责。 | +| `setup` | 否 | `object` | 可供发现和设置界面在不加载插件运行时情况下检查的轻量级设置 / 新手引导描述符。 | +| `qaRunners` | 否 | `object[]` | 共享 `openclaw qa` 主机在插件运行时加载前使用的轻量级 QA 运行器描述符。 | +| `contracts` | 否 | `object` | 外部认证钩子、语音、实时转写、实时语音、媒体理解、图像生成、音乐生成、视频生成、网页抓取、Ollama Web 搜索 和工具归属的静态内置能力快照。 | +| `mediaUnderstandingProviderMetadata` | 否 | `Record` | 适用于在 `contracts.mediaUnderstandingProviders` 中声明的 provider id 的轻量级媒体理解默认值。 | +| `channelConfigs` | 否 | `Record` | 由清单拥有的渠道配置元数据,在运行时加载前合并到发现和验证界面中。 | | `skills` | 否 | `string[]` | 要加载的 Skills 目录,相对于插件根目录。 | | `name` | 否 | `string` | 人类可读的插件名称。 | -| `description` | 否 | `string` | 显示在插件表面中的简短摘要。 | +| `description` | 否 | `string` | 显示在插件界面中的简短摘要。 | | `version` | 否 | `string` | 信息性插件版本。 | | `uiHints` | 否 | `Record` | 配置字段的 UI 标签、占位符和敏感性提示。 | ## `providerAuthChoices` 参考 -每个 `providerAuthChoices` 条目描述一个 onboarding 或认证选项。 -OpenClaw 会在 provider 运行时加载之前读取这些内容。 -provider 设置列表会使用这些清单选项、从描述符派生的设置选项,以及安装目录元数据,而无需加载 provider 运行时。 +每个 `providerAuthChoices` 条目描述一个新手引导或认证选项。 +OpenClaw 会在 provider 运行时加载前读取它。 +provider 设置列表会使用这些清单选项、由描述符派生的设置选项, +以及安装目录元数据,而无需加载 provider 运行时。 | 字段 | 必填 | 类型 | 含义 | | --------------------- | -------- | ----------------------------------------------- | -------------------------------------------------------------------------------------------------------- | | `provider` | 是 | `string` | 此选项所属的 provider id。 | -| `method` | 是 | `string` | 要分发到的认证方法 id。 | -| `choiceId` | 是 | `string` | onboarding 和 CLI 流程使用的稳定认证选项 id。 | -| `choiceLabel` | 否 | `string` | 面向用户的标签。如果省略,OpenClaw 会回退到 `choiceId`。 | -| `choiceHint` | 否 | `string` | 选择器的简短辅助文本。 | +| `method` | 是 | `string` | 要分派到的认证方法 id。 | +| `choiceId` | 是 | `string` | 新手引导和 CLI 流程使用的稳定认证选项 id。 | +| `choiceLabel` | 否 | `string` | 面向用户的标签。如果省略,OpenClaw 会回退为 `choiceId`。 | +| `choiceHint` | 否 | `string` | 选择器中的简短帮助文本。 | | `assistantPriority` | 否 | `number` | 在由助手驱动的交互式选择器中,值越小排序越靠前。 | -| `assistantVisibility` | 否 | `"visible"` \| `"manual-only"` | 在助手选择器中隐藏该选项,但仍允许手动通过 CLI 选择。 | -| `deprecatedChoiceIds` | 否 | `string[]` | 应将用户重定向到此替代选项的旧版选项 id。 | -| `groupId` | 否 | `string` | 用于对相关选项进行分组的可选分组 id。 | -| `groupLabel` | 否 | `string` | 该分组面向用户的标签。 | -| `groupHint` | 否 | `string` | 该分组的简短辅助文本。 | +| `assistantVisibility` | 否 | `"visible"` \| `"manual-only"` | 在助手选择器中隐藏该选项,但仍允许通过手动 CLI 选择。 | +| `deprecatedChoiceIds` | 否 | `string[]` | 旧版选项 id,应该将用户重定向到这个替代选项。 | +| `groupId` | 否 | `string` | 用于对相关选项分组的可选分组 id。 | +| `groupLabel` | 否 | `string` | 该分组的面向用户标签。 | +| `groupHint` | 否 | `string` | 该分组的简短帮助文本。 | | `optionKey` | 否 | `string` | 用于简单单标志认证流程的内部选项键。 | | `cliFlag` | 否 | `string` | CLI 标志名称,例如 `--openrouter-api-key`。 | | `cliOption` | 否 | `string` | 完整的 CLI 选项形式,例如 `--openrouter-api-key `。 | -| `cliDescription` | 否 | `string` | CLI 帮助中使用的说明。 | -| `onboardingScopes` | 否 | `Array<"text-inference" \| "image-generation">` | 此选项应出现在哪些 onboarding 表面中。如果省略,默认值为 `["text-inference"]`。 | +| `cliDescription` | 否 | `string` | 用于 CLI 帮助中的说明。 | +| `onboardingScopes` | 否 | `Array<"text-inference" \| "image-generation">` | 该选项应出现在哪些新手引导界面中。如果省略,默认值为 `["text-inference"]`。 | ## `commandAliases` 参考 -当插件拥有某个运行时命令名称,而用户可能会误将其放入 `plugins.allow`,或尝试将其作为根 CLI 命令运行时,请使用 `commandAliases`。OpenClaw 使用此元数据在不导入插件运行时代码的情况下提供诊断信息。 +当插件拥有一个运行时命令名称,而用户可能误将其放入 `plugins.allow`, +或尝试将其作为根 CLI 命令运行时,请使用 `commandAliases`。OpenClaw +使用这些元数据来提供诊断,而无需导入插件运行时代码。 ```json { @@ -206,18 +209,33 @@ provider 设置列表会使用这些清单选项、从描述符派生的设置 | ------------ | -------- | ----------------- | ----------------------------------------------------------------------- | | `name` | 是 | `string` | 属于此插件的命令名称。 | | `kind` | 否 | `"runtime-slash"` | 将该别名标记为聊天斜杠命令,而不是根 CLI 命令。 | -| `cliCommand` | 否 | `string` | 若存在,可为 CLI 操作建议的相关根 CLI 命令。 | +| `cliCommand` | 否 | `string` | 若存在,用于建议 CLI 操作的相关根 CLI 命令。 | ## `activation` 参考 -当插件可以以低成本声明哪些 control-plane 事件应将其纳入激活 / 加载计划时,请使用 `activation`。 +当插件可以以低成本声明哪些控制平面事件 +应将其包含在激活 / 加载计划中时,请使用 `activation`。 -此代码块是规划器元数据,而不是生命周期 API。它不会注册运行时行为,不会替代 `register(...)`,也不保证插件代码已经执行。激活规划器会使用这些字段缩小候选插件范围,然后再回退到现有的清单归属元数据,例如 `providers`、`channels`、`commandAliases`、`setup.providers`、`contracts.tools` 和 hooks。 +此块是规划器元数据,而不是生命周期 API。它不会注册 +运行时行为,不会替代 `register(...)`,也不保证 +插件代码已执行。激活规划器使用这些字段来 +缩小候选插件范围,然后才回退到现有的清单归属 +元数据,例如 `providers`、`channels`、`commandAliases`、`setup.providers`、 +`contracts.tools` 和 hooks。 -优先使用已经描述归属关系的最窄元数据。如果这些字段已经能够表达这种关系,请使用 `providers`、`channels`、`commandAliases`、设置描述符或 `contracts`。当这些归属字段无法表示所需关系时,再使用 `activation` 作为额外的规划器提示。 -对于 `claude-cli`、`codex-cli` 或 `google-gemini-cli` 之类的 CLI 运行时别名,请使用顶层 `cliBackends`;`activation.onAgentHarnesses` 仅适用于尚无归属字段的嵌入式 Agent harness id。 +优先使用已经能够描述归属关系的最窄元数据。能用 +`providers`、`channels`、`commandAliases`、setup 描述符或 `contracts` +表达关系时,就使用这些字段。对于无法由这些归属字段表示的额外规划器 +提示,再使用 `activation`。 +对于 `claude-cli`、`codex-cli` 或 `google-gemini-cli` 这类 CLI 运行时别名, +请使用顶层 `cliBackends`;`activation.onAgentHarnesses` 仅适用于 +那些尚无归属字段的嵌入式 Agent harness id。 -此代码块仅包含元数据。它不会注册运行时行为,也不会替代 `register(...)`、`setupEntry` 或其他运行时 / 插件入口点。当前使用方会在更广泛的插件加载之前将其作为缩小范围的提示,因此缺少激活元数据通常只会带来性能损耗;在旧版清单归属回退仍然存在的情况下,它不应影响正确性。 +此块仅为元数据。它不会注册运行时行为,也不会 +替代 `register(...)`、`setupEntry` 或其他运行时 / 插件入口点。 +当前使用方会在更广泛的插件加载之前将其作为缩小范围的提示,因此 +缺少激活元数据通常只会带来性能成本; +只要旧版清单归属回退仍然存在,就不应影响正确性。 ```json { @@ -233,27 +251,39 @@ provider 设置列表会使用这些清单选项、从描述符派生的设置 | 字段 | 必填 | 类型 | 含义 | | ------------------ | -------- | ---------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- | -| `onProviders` | 否 | `string[]` | 在激活 / 加载计划中应包含此插件的 provider id。 | -| `onAgentHarnesses` | 否 | `string[]` | 在激活 / 加载计划中应包含此插件的嵌入式 Agent harness 运行时 id。对于 CLI 后端别名,请使用顶层 `cliBackends`。 | -| `onCommands` | 否 | `string[]` | 在激活 / 加载计划中应包含此插件的命令 id。 | -| `onChannels` | 否 | `string[]` | 在激活 / 加载计划中应包含此插件的渠道 id。 | -| `onRoutes` | 否 | `string[]` | 在激活 / 加载计划中应包含此插件的路由类型。 | -| `onCapabilities` | 否 | `Array<"provider" \| "channel" \| "tool" \| "hook">` | control-plane 激活规划使用的宽泛能力提示。可能的话,优先使用更窄的字段。 | +| `onProviders` | 否 | `string[]` | 应将此插件包含在激活 / 加载计划中的 provider id。 | +| `onAgentHarnesses` | 否 | `string[]` | 应将此插件包含在激活 / 加载计划中的嵌入式 Agent harness 运行时 id。对于 CLI 后端别名,请使用顶层 `cliBackends`。 | +| `onCommands` | 否 | `string[]` | 应将此插件包含在激活 / 加载计划中的命令 id。 | +| `onChannels` | 否 | `string[]` | 应将此插件包含在激活 / 加载计划中的渠道 id。 | +| `onRoutes` | 否 | `string[]` | 应将此插件包含在激活 / 加载计划中的路由类型。 | +| `onCapabilities` | 否 | `Array<"provider" \| "channel" \| "tool" \| "hook">` | 用于控制平面激活规划的宽泛能力提示。可以的话,优先使用更窄的字段。 | 当前在线使用方: - 由命令触发的 CLI 规划会回退到旧版 `commandAliases[].cliCommand` 或 `commandAliases[].name` -- 智能体运行时启动规划对嵌入式 harness 使用 `activation.onAgentHarnesses`,对 CLI 运行时别名使用顶层 `cliBackends[]` -- 由渠道触发的设置 / 渠道规划在缺少显式渠道激活元数据时,会回退到旧版 `channels[]` 归属 -- 由 provider 触发的设置 / 运行时规划在缺少显式 provider 激活元数据时,会回退到旧版 +- 智能体运行时启动规划对嵌入式 harness 使用 `activation.onAgentHarnesses`, + 对 CLI 运行时别名使用顶层 `cliBackends[]` +- 由渠道触发的设置 / 渠道规划在缺少显式渠道激活元数据时, + 会回退到旧版 `channels[]` + 归属 +- 由 provider 触发的设置 / 运行时规划在缺少显式 provider + 激活元数据时,会回退到旧版 `providers[]` 和顶层 `cliBackends[]` 归属 -规划器诊断可以区分显式激活提示和清单归属回退。例如,`activation-command-hint` 表示匹配了 `activation.onCommands`,而 `manifest-command-alias` 表示规划器改为使用 `commandAliases` 归属。这些原因标签用于宿主诊断和测试;插件作者应继续声明最能描述归属关系的元数据。 +规划器诊断可以区分显式激活提示和清单 +归属回退。例如,`activation-command-hint` 表示 +匹配了 `activation.onCommands`,而 `manifest-command-alias` 表示 +规划器改用了 `commandAliases` 归属。这些原因标签 +用于宿主诊断和测试;插件作者应继续声明最能描述 +归属关系的元数据。 ## `qaRunners` 参考 -当插件在共享 `openclaw qa` 根命令下贡献一个或多个传输运行器时,请使用 `qaRunners`。请保持此元数据轻量且静态;实际的 CLI 注册仍由插件运行时通过导出 `qaRunnerCliRegistrations` 的轻量级 `runtime-api.ts` 表面来负责。 +当插件在共享的 `openclaw qa` 根命令下贡献一个或多个传输运行器时, +请使用 `qaRunners`。请保持这些元数据轻量且静态; +实际的 CLI 注册仍由插件运行时通过一个轻量级 +`runtime-api.ts` 接口负责,该接口导出 `qaRunnerCliRegistrations`。 ```json { @@ -269,11 +299,12 @@ provider 设置列表会使用这些清单选项、从描述符派生的设置 | 字段 | 必填 | 类型 | 含义 | | ------------- | -------- | -------- | ------------------------------------------------------------------ | | `commandName` | 是 | `string` | 挂载在 `openclaw qa` 下的子命令,例如 `matrix`。 | -| `description` | 否 | `string` | 当共享宿主需要一个占位命令时使用的回退帮助文本。 | +| `description` | 否 | `string` | 当共享宿主需要一个桩命令时使用的回退帮助文本。 | ## `setup` 参考 -当设置和 onboarding 表面需要在运行时加载前读取由插件拥有的低成本元数据时,请使用 `setup`。 +当设置和新手引导界面需要在运行时加载前获取由插件拥有的轻量级元数据时, +请使用 `setup`。 ```json { @@ -292,40 +323,65 @@ provider 设置列表会使用这些清单选项、从描述符派生的设置 } ``` -顶层 `cliBackends` 仍然有效,并继续描述 CLI 推理后端。`setup.cliBackends` 是面向 control-plane / 设置流程的、应保持仅元数据形式的 setup 专用描述符表面。 +顶层 `cliBackends` 仍然有效,并继续描述 CLI 推理 +后端。`setup.cliBackends` 是面向 +应保持仅元数据化的控制平面 / 设置流程的、设置专用描述符界面。 -存在时,`setup.providers` 和 `setup.cliBackends` 是设置发现的首选“descriptor-first”查找表面。如果描述符只能缩小候选插件范围,而设置仍需要更丰富的设置期运行时 hooks,请设置 `requiresRuntime: true`,并保留 `setup-api` 作为回退执行路径。 +存在 `setup.providers` 和 `setup.cliBackends` 时,它们是 +设置发现中优先使用的描述符优先查询界面。如果该描述符仅用于 +缩小候选插件范围,而设置仍需要更丰富的设置期运行时钩子, +请将 `requiresRuntime` 设为 `true`,并保留 `setup-api` +作为回退执行路径。 -OpenClaw 还会将 `setup.providers[].envVars` 纳入通用 provider 认证和环境变量查找。`providerAuthEnvVars` 在弃用窗口期内仍通过兼容适配器受支持,但仍在使用它的非内置插件会收到清单诊断。新插件应将设置 / Status 环境变量元数据放在 `setup.providers[].envVars` 上。 +OpenClaw 还会将 `setup.providers[].envVars` 包含在通用 provider 认证和 +环境变量查询中。`providerAuthEnvVars` 在弃用窗口期内仍通过兼容适配器 +继续受支持,但仍在使用它的非内置插件 +会收到清单诊断。新插件应将设置 / Status 环境变量元数据 +放在 `setup.providers[].envVars` 上。 -当没有 setup 条目可用,或 `setup.requiresRuntime: false` 声明设置运行时不是必需时,OpenClaw 还可以从 `setup.providers[].authMethods` 派生简单的设置选项。对于自定义标签、CLI 标志、onboarding 范围和助手元数据,显式的 `providerAuthChoices` 条目仍然是首选。 +在没有 setup 入口时,或者当 +`setup.requiresRuntime: false` 声明设置运行时不必要时,OpenClaw 也可以从 `setup.providers[].authMethods` +派生出简单的设置选项。对于自定义标签、CLI 标志、新手引导范围 +和助手元数据,显式的 `providerAuthChoices` 条目仍然是首选。 -仅当这些描述符对于设置表面已经足够时,才设置 `requiresRuntime: false`。OpenClaw 将显式的 `false` 视为仅描述符合约,并且不会为设置查找执行 `setup-api` 或 `openclaw.setupEntry`。如果仅描述符插件仍然提供了这些设置运行时入口之一,OpenClaw 会报告一条附加诊断,并继续忽略它。省略 `requiresRuntime` 会保留旧版回退行为,这样那些在未设置该标志的情况下添加了描述符的现有插件就不会出问题。 +仅当这些描述符已足以满足 +设置界面时,才将 `requiresRuntime: false`。OpenClaw 将显式的 `false` 视为仅描述符契约, +并且不会为设置查询执行 `setup-api` 或 `openclaw.setupEntry`。如果 +一个仅描述符插件仍然提供了其中某个设置运行时入口, +OpenClaw 会报告一条附加诊断,并继续忽略它。省略 +`requiresRuntime` 会保留旧版回退行为,因此现有那些在未设置该标志的情况下添加了 +描述符的插件不会失效。 -由于设置查找可能会执行由插件拥有的 `setup-api` 代码,规范化后的 `setup.providers[].id` 和 `setup.cliBackends[]` 值必须在已发现插件之间保持唯一。归属不明确时会采用失败即关闭的方式,而不是根据发现顺序挑选一个“胜出者”。 +由于设置查询可能会执行由插件拥有的 `setup-api` 代码, +规范化后的 `setup.providers[].id` 和 `setup.cliBackends[]` 值必须在所有已发现插件中 +保持唯一。归属不明确时会采取失败即关闭的方式,而不是按发现顺序选一个 +“赢家”。 -当设置运行时确实执行时,如果 `setup-api` 注册了清单描述符未声明的 provider 或 CLI 后端,或者某个描述符没有对应的运行时注册,设置注册表诊断就会报告描述符漂移。这些诊断是附加性的,不会拒绝旧版插件。 +当设置运行时确实执行时,如果 `setup-api` 注册了一个提供商或 CLI 后端, +但清单描述符没有声明它,或者某个描述符没有匹配的运行时 +注册,设置注册表诊断就会报告描述符漂移。 +这些诊断是附加性的,不会拒绝旧版插件。 ### `setup.providers` 参考 | 字段 | 必填 | 类型 | 含义 | | ------------- | -------- | ---------- | ------------------------------------------------------------------------------------ | -| `id` | 是 | `string` | 在设置或 onboarding 期间公开的 provider id。保持规范化 id 在全局范围内唯一。 | +| `id` | 是 | `string` | 在设置或新手引导期间暴露的 provider id。请保持规范化 id 在全局范围内唯一。 | | `authMethods` | 否 | `string[]` | 此 provider 在不加载完整运行时的情况下支持的设置 / 认证方法 id。 | -| `envVars` | 否 | `string[]` | 通用设置 / Status 表面可在插件运行时加载前检查的环境变量。 | +| `envVars` | 否 | `string[]` | 通用设置 / Status 界面可在插件运行时加载前检查的环境变量。 | ### `setup` 字段 | 字段 | 必填 | 类型 | 含义 | | ------------------ | -------- | ---------- | --------------------------------------------------------------------------------------------------- | -| `providers` | 否 | `object[]` | 在设置和 onboarding 期间公开的 provider 设置描述符。 | -| `cliBackends` | 否 | `string[]` | 用于 descriptor-first 设置查找的设置期后端 id。保持规范化 id 在全局范围内唯一。 | -| `configMigrations` | 否 | `string[]` | 由此插件的设置表面拥有的配置迁移 id。 | -| `requiresRuntime` | 否 | `boolean` | 在描述符查找之后,设置是否仍需要执行 `setup-api`。 | +| `providers` | 否 | `object[]` | 在设置和新手引导期间暴露的 provider 设置描述符。 | +| `cliBackends` | 否 | `string[]` | 用于描述符优先设置查询的设置期后端 id。请保持规范化 id 在全局范围内唯一。 | +| `configMigrations` | 否 | `string[]` | 由此插件的设置界面拥有的配置迁移 id。 | +| `requiresRuntime` | 否 | `boolean` | 描述符查询后,设置是否仍需要执行 `setup-api`。 | ## `uiHints` 参考 -`uiHints` 是从配置字段名称到小型渲染提示的映射。 +`uiHints` 是一个从配置字段名映射到小型渲染提示的映射表。 ```json { @@ -345,15 +401,16 @@ OpenClaw 还会将 `setup.providers[].envVars` 纳入通用 provider 认证和 | 字段 | 类型 | 含义 | | ------------- | ---------- | --------------------------------------- | | `label` | `string` | 面向用户的字段标签。 | -| `help` | `string` | 简短辅助文本。 | -| `tags` | `string[]` | 可选 UI 标签。 | +| `help` | `string` | 简短帮助文本。 | +| `tags` | `string[]` | 可选的 UI 标签。 | | `advanced` | `boolean` | 将该字段标记为高级项。 | -| `sensitive` | `boolean` | 将该字段标记为机密或敏感项。 | +| `sensitive` | `boolean` | 将该字段标记为密钥或敏感项。 | | `placeholder` | `string` | 表单输入的占位文本。 | ## `contracts` 参考 -仅将 `contracts` 用于 OpenClaw 能够在不导入插件运行时的情况下读取的静态能力归属元数据。 +仅当 OpenClaw 可以在不导入插件运行时的情况下读取静态能力归属元数据时, +才使用 `contracts`。 ```json { @@ -369,6 +426,7 @@ OpenClaw 还会将 `setup.providers[].envVars` 纳入通用 provider 认证和 "videoGenerationProviders": ["qwen"], "webFetchProviders": ["firecrawl"], "webSearchProviders": ["gemini"], + "migrationProviders": ["hermes"], "tools": ["firecrawl_search", "firecrawl_scrape"] } } @@ -380,27 +438,43 @@ OpenClaw 还会将 `setup.providers[].envVars` 纳入通用 provider 认证和 | -------------------------------- | ---------- | --------------------------------------------------------------------- | | `embeddedExtensionFactories` | `string[]` | Codex app-server 扩展工厂 id,目前为 `codex-app-server`。 | | `agentToolResultMiddleware` | `string[]` | 内置插件可为其注册工具结果中间件的运行时 id。 | -| `externalAuthProviders` | `string[]` | 此插件拥有其外部认证配置文件 hook 的 provider id。 | -| `speechProviders` | `string[]` | 此插件拥有的 speech provider id。 | -| `realtimeTranscriptionProviders` | `string[]` | 此插件拥有的实时转录 provider id。 | -| `realtimeVoiceProviders` | `string[]` | 此插件拥有的实时语音 provider id。 | -| `memoryEmbeddingProviders` | `string[]` | 此插件拥有的 Memory 嵌入 provider id。 | -| `mediaUnderstandingProviders` | `string[]` | 此插件拥有的媒体理解 provider id。 | -| `imageGenerationProviders` | `string[]` | 此插件拥有的图像生成 provider id。 | -| `videoGenerationProviders` | `string[]` | 此插件拥有的视频生成 provider id。 | -| `webFetchProviders` | `string[]` | 此插件拥有的网页抓取 provider id。 | -| `webSearchProviders` | `string[]` | 此插件拥有的网页搜索 provider id。 | -| `tools` | `string[]` | 此插件拥有的智能体工具名称,用于内置合约检查。 | +| `externalAuthProviders` | `string[]` | 其外部 auth profile 钩子由该插件拥有的 provider id。 | +| `speechProviders` | `string[]` | 该插件拥有的语音 provider id。 | +| `realtimeTranscriptionProviders` | `string[]` | 该插件拥有的实时转写 provider id。 | +| `realtimeVoiceProviders` | `string[]` | 该插件拥有的实时语音 provider id。 | +| `memoryEmbeddingProviders` | `string[]` | 该插件拥有的 memory embedding provider id。 | +| `mediaUnderstandingProviders` | `string[]` | 该插件拥有的媒体理解 provider id。 | +| `imageGenerationProviders` | `string[]` | 该插件拥有的图像生成 provider id。 | +| `videoGenerationProviders` | `string[]` | 该插件拥有的视频生成 provider id。 | +| `webFetchProviders` | `string[]` | 该插件拥有的网页抓取 provider id。 | +| `webSearchProviders` | `string[]` | 该插件拥有的网页搜索 provider id。 | +| `migrationProviders` | `string[]` | 该插件为 `openclaw migrate` 拥有的导入 provider id。 | +| `tools` | `string[]` | 该插件为内置契约检查拥有的智能体工具名称。 | -`contracts.embeddedExtensionFactories` 保留用于内置、仅限 Codex app-server 的扩展工厂。内置工具结果转换应声明 `contracts.agentToolResultMiddleware`,并改为使用 `api.registerAgentToolResultMiddleware(...)` 进行注册。外部插件不能注册工具结果中间件,因为该接缝可以在模型看到之前重写高信任度工具输出。 +`contracts.embeddedExtensionFactories` 被保留用于内置的、仅适用于 Codex +app-server 的扩展工厂。内置工具结果转换应 +声明 `contracts.agentToolResultMiddleware`,并使用 +`api.registerAgentToolResultMiddleware(...)` 进行注册。外部插件不能 +注册工具结果中间件,因为该接口可以在模型看到高信任度工具输出之前 +改写它。 -实现了 `resolveExternalAuthProfiles` 的 provider 插件应声明 `contracts.externalAuthProviders`。未声明该字段的插件仍会通过已弃用的兼容性回退运行,但这种回退更慢,并将在迁移窗口结束后移除。 +实现了 `resolveExternalAuthProfiles` 的 provider 插件 +应声明 `contracts.externalAuthProviders`。未声明该项的插件仍会通过 +已弃用的兼容性回退运行,但该回退更慢, +并将在迁移窗口结束后移除。 -内置 Memory 嵌入 providers 应为其公开的每个适配器 id 声明 `contracts.memoryEmbeddingProviders`,包括诸如 `local` 之类的内置适配器。独立 CLI 路径会使用此清单合约,仅在完整 Gateway 网关运行时完成 provider 注册之前加载其所属插件。 +内置 memory embedding provider 应为其暴露的每个适配器 id 声明 +`contracts.memoryEmbeddingProviders`, +包括诸如 `local` 之类的内置适配器。独立 CLI 路径使用这个清单 +契约,在完整 Gateway 网关运行时尚未 +注册 provider 之前,仅加载拥有该能力的插件。 ## `mediaUnderstandingProviderMetadata` 参考 -当媒体理解 provider 具有默认模型、自动认证回退优先级,或通用核心辅助工具在运行时加载前所需的原生文档支持时,请使用 `mediaUnderstandingProviderMetadata`。其键也必须在 `contracts.mediaUnderstandingProviders` 中声明。 +当某个媒体理解 provider 具有默认模型、自动认证回退优先级 +或原生文档支持,并且通用核心辅助工具需要在运行时加载前获取这些信息时, +请使用 `mediaUnderstandingProviderMetadata`。其键也必须在 +`contracts.mediaUnderstandingProviders` 中声明。 ```json { @@ -427,25 +501,39 @@ OpenClaw 还会将 `setup.providers[].envVars` 纳入通用 provider 认证和 | 字段 | 类型 | 含义 | | ---------------------- | ----------------------------------- | ---------------------------------------------------------------------------- | -| `capabilities` | `("image" \| "audio" \| "video")[]` | 该 provider 公开的媒体能力。 | -| `defaultModels` | `Record` | 当配置未指定模型时使用的“能力到模型”默认值。 | -| `autoPriority` | `Record` | 对于基于凭证的自动 provider 回退,数字越小排序越靠前。 | +| `capabilities` | `("image" \| "audio" \| "video")[]` | 该 provider 暴露的媒体能力。 | +| `defaultModels` | `Record` | 当配置未指定模型时,按能力映射到模型的默认值。 | +| `autoPriority` | `Record` | 用于基于凭证自动回退 provider 时,数字越小排序越靠前。 | | `nativeDocumentInputs` | `"pdf"[]` | 该 provider 支持的原生文档输入。 | ## `channelConfigs` 参考 -当渠道插件在运行时加载前需要低成本配置元数据时,请使用 `channelConfigs`。当没有可用的 setup 条目,或 `setup.requiresRuntime: false` 声明设置运行时不是必需时,只读的渠道设置 / Status 发现可以直接使用这些元数据来处理已配置的外部渠道。 +当某个渠道插件需要在运行时加载前获取低成本配置元数据时, +请使用 `channelConfigs`。只读的渠道设置 / Status 发现可以 +在没有 setup 入口时直接使用这些元数据来处理已配置的外部渠道, +或者在 `setup.requiresRuntime: false` 声明设置运行时不必要时使用它们。 -`channelConfigs` 是插件清单元数据,而不是新的顶层用户配置部分。用户仍然在 `channels.` 下配置渠道实例。OpenClaw 读取清单元数据,以便在插件运行时代码执行之前决定哪个插件拥有该已配置渠道。 +`channelConfigs` 是插件清单元数据,而不是新的顶层用户配置 +区段。用户仍然在 `channels.` 下配置渠道实例。 +OpenClaw 会读取清单元数据,以决定哪个插件拥有该已配置的 +渠道,然后才执行插件运行时代码。 -对于渠道插件,`configSchema` 和 `channelConfigs` 描述的是不同路径: +对于渠道插件,`configSchema` 和 `channelConfigs` 描述的是不同 +路径: -- `configSchema` 验证 `plugins.entries..config` -- `channelConfigs..schema` 验证 `channels.` +- `configSchema` 用于验证 `plugins.entries..config` +- `channelConfigs..schema` 用于验证 `channels.` -声明了 `channels[]` 的非内置插件,也应声明匹配的 `channelConfigs` 条目。没有这些条目时,OpenClaw 仍然可以加载该插件,但冷路径配置 schema、设置和 Control UI 表面在插件运行时执行之前无法获知渠道自有选项的形状。 +声明了 `channels[]` 的非内置插件也应声明匹配的 +`channelConfigs` 条目。若没有它们,OpenClaw 仍然可以加载该插件, +但冷路径配置 schema、设置和 Control UI 界面在插件运行时执行前 +无法知道该渠道拥有的选项结构。 -`channelConfigs..commands.nativeCommandsAutoEnabled` 和 `nativeSkillsAutoEnabled` 可以为在渠道运行时加载前执行的命令配置检查声明静态 `auto` 默认值。内置渠道也可以通过 `package.json#openclaw.channel.commands` 发布相同的默认值,并与其其他由包拥有的渠道目录元数据一起提供。 +`channelConfigs..commands.nativeCommandsAutoEnabled` 和 +`nativeSkillsAutoEnabled` 可以为在渠道运行时加载前执行的命令配置检查 +声明静态 `auto` 默认值。内置渠道也可以通过 +`package.json#openclaw.channel.commands` 发布相同默认值,并与其他由 package 拥有的 +渠道目录元数据一起提供。 ```json { @@ -481,15 +569,18 @@ OpenClaw 还会将 `setup.providers[].envVars` 纳入通用 provider 认证和 | 字段 | 类型 | 含义 | | ------------- | ------------------------ | ----------------------------------------------------------------------------------------- | | `schema` | `object` | `channels.` 的 JSON Schema。每个已声明的渠道配置条目都必须提供。 | -| `uiHints` | `Record` | 该渠道配置部分的可选 UI 标签 / 占位符 / 敏感性提示。 | -| `label` | `string` | 当运行时元数据尚未就绪时,合并到选择器和检查表面中的渠道标签。 | -| `description` | `string` | 用于检查和目录表面的简短渠道描述。 | +| `uiHints` | `Record` | 该渠道配置区段的可选 UI 标签 / 占位符 / 敏感性提示。 | +| `label` | `string` | 当运行时元数据尚未就绪时,合并到选择器和检查界面中的渠道标签。 | +| `description` | `string` | 用于检查和目录界面的简短渠道描述。 | | `commands` | `object` | 用于运行时前配置检查的静态原生命令和原生 Skills 自动默认值。 | -| `preferOver` | `string[]` | 在选择表面中,此渠道应优先于的旧版或较低优先级插件 id。 | +| `preferOver` | `string[]` | 在选择界面中,此渠道应优先于其之上的旧版或低优先级插件 id。 | ### 替换另一个渠道插件 -当你的插件是某个渠道 id 的首选归属方,而另一个插件也能提供该渠道时,请使用 `preferOver`。常见情况包括:插件 id 已重命名、某个独立插件取代了内置插件,或者某个维护中的分支为了保持配置兼容性而沿用相同的渠道 id。 +当你的插件是某个渠道 id 的首选拥有者,而另一个插件 +也可以提供该渠道时,请使用 `preferOver`。常见情况包括:插件 id 已重命名、 +独立插件取代了内置插件,或者维护中的分支为了配置兼容性 +保留了相同的渠道 id。 ```json { @@ -510,13 +601,22 @@ OpenClaw 还会将 `setup.providers[].envVars` 纳入通用 provider 认证和 } ``` -当配置了 `channels.chat` 时,OpenClaw 会同时考虑渠道 id 和首选插件 id。如果低优先级插件之所以被选中,仅仅是因为它是内置的或默认启用的,OpenClaw 就会在有效运行时配置中将其禁用,以便由一个插件拥有该渠道及其工具。显式用户选择仍然优先:如果用户显式启用了这两个插件,OpenClaw 会保留该选择,并报告重复渠道 / 工具诊断,而不是静默更改所请求的插件集。 +当配置了 `channels.chat` 时,OpenClaw 会同时考虑渠道 id 和 +首选插件 id。如果低优先级插件之所以被选中 +只是因为它是内置的或默认启用的, +OpenClaw 会在生效运行时配置中禁用它,以便由一个插件统一拥有该渠道 +及其工具。显式的用户选择仍然优先:如果用户明确启用了两个插件, +OpenClaw 会保留该选择,并报告重复渠道 / 工具诊断, +而不是静默更改用户请求的插件集合。 -请将 `preferOver` 的范围限定在确实能够提供同一渠道的插件 id 上。它不是一个通用优先级字段,也不会重命名用户配置键。 +请将 `preferOver` 限定在那些确实能提供相同渠道的插件 id 上。 +它不是一个通用优先级字段,也不会重命名用户配置键。 ## `modelSupport` 参考 -当 OpenClaw 应在插件运行时加载之前,根据 `gpt-5.5` 或 `claude-sonnet-4.6` 之类的简写模型 id 推断你的 provider 插件时,请使用 `modelSupport`。 +当 OpenClaw 应在插件运行时加载前,根据简写模型 id +如 `gpt-5.5` 或 `claude-sonnet-4.6` 推断你的 provider 插件时, +请使用 `modelSupport`。 ```json { @@ -527,23 +627,28 @@ OpenClaw 还会将 `setup.providers[].envVars` 纳入通用 provider 认证和 } ``` -OpenClaw 按以下优先级处理: +OpenClaw 按以下优先级应用: -- 显式 `provider/model` 引用使用所属 `providers` 清单元数据 +- 显式的 `provider/model` 引用使用拥有该项的 `providers` 清单元数据 - `modelPatterns` 优先于 `modelPrefixes` -- 如果一个非内置插件和一个内置插件都匹配,则非内置插件胜出 -- 对于其余歧义,在用户或配置指定 provider 之前会被忽略 +- 如果一个非内置插件和一个内置插件都匹配,则非内置 + 插件优先 +- 其余歧义会被忽略,直到用户或配置指定某个 provider 字段: | 字段 | 类型 | 含义 | | --------------- | ---------- | ------------------------------------------------------------------------------- | -| `modelPrefixes` | `string[]` | 使用 `startsWith` 与简写模型 id 匹配的前缀。 | -| `modelPatterns` | `string[]` | 在移除配置文件后缀后,与简写模型 id 匹配的正则表达式源码。 | +| `modelPrefixes` | `string[]` | 通过 `startsWith` 与简写模型 id 匹配的前缀。 | +| `modelPatterns` | `string[]` | 在移除 profile 后缀后,与简写模型 id 匹配的正则表达式源码。 | ## `modelCatalog` 参考 -当 OpenClaw 应在加载插件运行时之前了解 provider 模型元数据时,请使用 `modelCatalog`。这是固定目录行、provider 别名、抑制规则和发现模式的清单归属来源。运行时刷新仍属于 provider 运行时代码,但清单会告知核心何时需要运行时。 +当 OpenClaw 应在加载插件运行时之前了解 provider 模型元数据时, +请使用 `modelCatalog`。这是由清单拥有的固定目录 +条目、provider 别名、抑制规则和发现模式的数据源。 +运行时刷新仍属于 provider 运行时代码负责,但清单会告知核心 +何时需要运行时。 ```json { @@ -596,19 +701,19 @@ OpenClaw 按以下优先级处理: | 字段 | 类型 | 含义 | | -------------- | -------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------- | -| `providers` | `Record` | 此插件拥有的 provider id 的目录行。键也应出现在顶层 `providers` 中。 | -| `aliases` | `Record` | 应解析为某个已拥有 provider 的 provider 别名,用于目录或抑制规划。 | -| `suppressions` | `object[]` | 此插件因 provider 专用原因而抑制的、来自其他来源的模型行。 | +| `providers` | `Record` | 由此插件拥有的 provider id 的目录条目。键也应出现在顶层 `providers` 中。 | +| `aliases` | `Record` | 在目录或抑制规划中应解析到某个已拥有 provider 的 provider 别名。 | +| `suppressions` | `object[]` | 因特定 provider 原因而被此插件抑制的、来自其他来源的模型条目。 | | `discovery` | `Record` | 该 provider 目录是可从清单元数据读取、可刷新到缓存,还是需要运行时。 | provider 字段: | 字段 | 类型 | 含义 | | --------- | ------------------------ | ----------------------------------------------------------------- | -| `baseUrl` | `string` | 此 provider 目录中模型的可选默认 `baseUrl`。 | +| `baseUrl` | `string` | 此 provider 目录中模型的可选默认 base URL。 | | `api` | `ModelApi` | 此 provider 目录中模型的可选默认 API 适配器。 | -| `headers` | `Record` | 适用于此 provider 目录的可选静态头。 | -| `models` | `object[]` | 必需的模型行。没有 `id` 的行会被忽略。 | +| `headers` | `Record` | 适用于此 provider 目录的可选静态请求头。 | +| `models` | `object[]` | 必填模型条目。没有 `id` 的条目会被忽略。 | 模型字段: @@ -616,93 +721,143 @@ provider 字段: | --------------- | -------------------------------------------------------------- | --------------------------------------------------------------------------- | | `id` | `string` | provider 本地模型 id,不含 `provider/` 前缀。 | | `name` | `string` | 可选显示名称。 | -| `api` | `ModelApi` | 可选的逐模型 API 覆盖。 | -| `baseUrl` | `string` | 可选的逐模型 `baseUrl` 覆盖。 | -| `headers` | `Record` | 可选的逐模型静态头。 | +| `api` | `ModelApi` | 可选的逐模型 API 覆盖值。 | +| `baseUrl` | `string` | 可选的逐模型 base URL 覆盖值。 | +| `headers` | `Record` | 可选的逐模型静态请求头。 | | `input` | `Array<"text" \| "image" \| "document" \| "audio" \| "video">` | 该模型接受的模态。 | -| `reasoning` | `boolean` | 该模型是否公开推理行为。 | +| `reasoning` | `boolean` | 该模型是否暴露推理行为。 | | `contextWindow` | `number` | provider 原生上下文窗口。 | -| `contextTokens` | `number` | 当与 `contextWindow` 不同时,可选的有效运行时上下文上限。 | +| `contextTokens` | `number` | 当与 `contextWindow` 不同时,可选的实际运行时上下文上限。 | | `maxTokens` | `number` | 已知时的最大输出 token 数。 | | `cost` | `object` | 可选的每百万 token 美元定价,包括可选的 `tieredPricing`。 | | `compat` | `object` | 与 OpenClaw 模型配置兼容性匹配的可选兼容性标志。 | -| `status` | `"available"` \| `"preview"` \| `"deprecated"` \| `"disabled"` | 列表状态。仅当该行完全不应出现时才使用 suppress。 | -| `statusReason` | `string` | 与不可用状态一同显示的可选原因。 | -| `replaces` | `string[]` | 此模型所取代的旧 provider 本地模型 id。 | -| `replacedBy` | `string` | 已弃用行的替代 provider 本地模型 id。 | -| `tags` | `string[]` | 供选择器和筛选器使用的稳定标签。 | +| `status` | `"available"` \| `"preview"` \| `"deprecated"` \| `"disabled"` | 列表状态。仅当某条目绝不能出现时才使用 suppress。 | +| `statusReason` | `string` | 在非可用状态下显示的可选原因。 | +| `replaces` | `string[]` | 该模型取代的旧 provider 本地模型 id。 | +| `replacedBy` | `string` | 已弃用条目的替代 provider 本地模型 id。 | +| `tags` | `string[]` | 供选择器和过滤器使用的稳定标签。 | -不要将仅运行时数据放入 `modelCatalog`。如果某个 provider 需要账户状态、API 请求或本地进程发现才能得知完整模型集,请在 `discovery` 中将该 provider 声明为 `refreshable` 或 `runtime`。 +不要将仅运行时数据放入 `modelCatalog`。如果某个 provider 需要账户 +状态、API 请求或本地进程发现才能得知完整模型集合, +请在 `discovery` 中将该 provider 声明为 `refreshable` 或 `runtime`。 ### OpenClaw Provider Index -OpenClaw Provider Index 是由 OpenClaw 拥有的预览元数据,用于那些插件可能尚未安装的 providers。它不是插件清单的一部分。插件清单仍然是已安装插件的权威来源。Provider Index 是未来可安装 provider 和安装前模型选择器表面在 provider 插件尚未安装时所使用的内部回退合约。 +OpenClaw Provider Index 是由 OpenClaw 拥有的预览元数据,适用于那些 +插件可能尚未安装的 provider。它不是插件清单的一部分。 +插件清单仍然是已安装插件的权威来源。Provider Index 是内部回退契约, +未来可安装 provider 和安装前模型选择器界面将在未安装 provider 插件时 +使用它。 目录权威顺序: 1. 用户配置。 2. 已安装插件清单中的 `modelCatalog`。 -3. 通过显式刷新获得的模型目录缓存。 -4. OpenClaw Provider Index 预览行。 +3. 通过显式刷新得到的模型目录缓存。 +4. OpenClaw Provider Index 预览条目。 -Provider Index 不得包含机密、启用状态、运行时 hooks,或实时的账户专属模型数据。其预览目录使用与插件清单相同的 `modelCatalog` provider 行形状,但除非有意与已安装插件清单保持一致,否则应限制为稳定显示元数据,而不要包含诸如 `api`、`baseUrl`、定价或兼容性标志之类的运行时适配器字段。对于带有实时 `/models` 发现的 providers,应通过显式模型目录缓存路径写入刷新后的行,而不是让常规列表或 onboarding 去调用 provider API。 +Provider Index 不得包含密钥、启用状态、运行时钩子 +或与实际账户相关的在线模型数据。它的预览目录使用与插件清单 +相同的 `modelCatalog` provider 条目结构,但应仅限于稳定显示元数据, +除非有意让 `api`、 +`baseUrl`、定价或兼容性标志等运行时适配器字段与已安装插件清单保持一致。 +对于具有在线 `/models` 发现能力的 provider,应通过显式模型目录缓存路径 +写入刷新后的条目,而不是在常规列表或新手引导期间调用 provider API。 -对于那些其插件已移出核心或尚未安装的 providers,Provider Index 条目也可以携带可安装插件元数据。此元数据遵循与渠道目录相同的模式:包名、npm 安装规范、预期完整性以及轻量级认证选项标签,足以展示一个可安装的设置选项。一旦插件安装完成,其清单即成为权威,Provider Index 中对应 provider 的条目将被忽略。 +Provider Index 条目还可以携带适用于那些插件已移出核心 +或尚未安装的 provider 的可安装插件元数据。此元数据遵循渠道目录模式: +package 名称、npm 安装规格、预期完整性以及轻量级认证选项标签 +足以展示一个可安装的设置选项。一旦插件安装完成, +其清单将优先生效,而该 provider 的 Provider Index 条目会被忽略。 -旧版顶层能力键已弃用。使用 `openclaw doctor --fix` 将 `speechProviders`、`realtimeTranscriptionProviders`、`realtimeVoiceProviders`、`mediaUnderstandingProviders`、`imageGenerationProviders`、`videoGenerationProviders`、`webFetchProviders` 和 `webSearchProviders` 移动到 `contracts` 下;常规清单加载不再将这些顶层字段视为能力归属。 +旧版顶层能力键已弃用。使用 `openclaw doctor --fix` 将 +`speechProviders`、`realtimeTranscriptionProviders`、 +`realtimeVoiceProviders`、`mediaUnderstandingProviders`、 +`imageGenerationProviders`、`videoGenerationProviders`、 +`webFetchProviders` 和 `webSearchProviders` +移动到 `contracts` 下;常规 +清单加载不再将这些顶层字段视为能力 +归属。 -## Manifest 与 `package.json` +## 清单与 package.json 的区别 这两个文件承担不同职责: | 文件 | 用途 | | ---------------------- | -------------------------------------------------------------------------------------------------------------------------------- | -| `openclaw.plugin.json` | 发现、配置验证、认证选项元数据,以及在插件代码运行前必须存在的 UI 提示 | -| `package.json` | npm 元数据、依赖安装,以及用于入口点、安装门控、设置或目录元数据的 `openclaw` 代码块 | +| `openclaw.plugin.json` | 在插件代码运行前必须存在的设备发现、配置验证、认证选项元数据和 UI 提示 | +| `package.json` | npm 元数据、依赖安装,以及用于入口点、安装门控、设置或目录元数据的 `openclaw` 区块 | -如果你不确定某段元数据应放在哪里,请使用以下规则: +如果你不确定某项元数据应该放在哪里,请使用以下规则: -- 如果 OpenClaw 必须在加载插件代码之前知道它,就将其放在 `openclaw.plugin.json` 中 -- 如果它与打包、入口文件或 npm 安装行为有关,就将其放在 `package.json` 中 +- 如果 OpenClaw 必须在加载插件代码之前知道它,就将其放在 `openclaw.plugin.json` +- 如果它与打包、入口文件或 npm 安装行为有关,就将其放在 `package.json` -### 影响发现的 `package.json` 字段 +### 影响设备发现的 package.json 字段 -一些运行时前插件元数据有意放在 `package.json` 的 `openclaw` 代码块下,而不是 `openclaw.plugin.json` 中。 +一些运行时前插件元数据会有意放在 `package.json` 的 +`openclaw` 区块下,而不是 `openclaw.plugin.json` 中。 重要示例: | 字段 | 含义 | | ----------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -| `openclaw.extensions` | 声明原生插件入口点。必须保留在插件包目录内。 | -| `openclaw.runtimeExtensions` | 为已安装包声明构建后的 JavaScript 运行时入口点。必须保留在插件包目录内。 | -| `openclaw.setupEntry` | 轻量级、仅设置用的入口点,用于 onboarding、延迟渠道启动以及只读的渠道 Status / SecretRef 发现。必须保留在插件包目录内。 | -| `openclaw.runtimeSetupEntry` | 为已安装包声明构建后的 JavaScript 设置入口点。必须保留在插件包目录内。 | -| `openclaw.channel` | 轻量级渠道目录元数据,例如标签、文档路径、别名和选择文案。 | -| `openclaw.channel.commands` | 在渠道运行时加载前,由配置、审计和命令列表表面使用的静态原生命令和原生 Skills 自动默认元数据。 | -| `openclaw.channel.configuredState` | 轻量级已配置状态检查器元数据,可在不加载完整渠道运行时的情况下回答“是否已经存在仅环境变量的设置?”。 | -| `openclaw.channel.persistedAuthState` | 轻量级持久化认证状态检查器元数据,可在不加载完整渠道运行时的情况下回答“是否已经有任何登录状态?”。 | -| `openclaw.install.npmSpec` / `openclaw.install.localPath` | 面向内置和外部发布插件的安装 / 更新提示。 | -| `openclaw.install.defaultChoice` | 当存在多个安装来源时的首选安装路径。 | +| `openclaw.extensions` | 声明原生插件入口点。必须保留在插件 package 目录内。 | +| `openclaw.runtimeExtensions` | 为已安装 package 声明已构建的 JavaScript 运行时入口点。必须保留在插件 package 目录内。 | +| `openclaw.setupEntry` | 在新手引导、延迟渠道启动和只读渠道 Status / SecretRef 设备发现期间使用的轻量级仅设置入口点。必须保留在插件 package 目录内。 | +| `openclaw.runtimeSetupEntry` | 为已安装 package 声明已构建的 JavaScript 设置入口点。必须保留在插件 package 目录内。 | +| `openclaw.channel` | 轻量级渠道目录元数据,例如标签、文档路径、别名和选择说明文本。 | +| `openclaw.channel.commands` | 在渠道运行时加载前,由配置、审计和命令列表界面使用的静态原生命令和原生 Skills 自动默认元数据。 | +| `openclaw.channel.configuredState` | 轻量级 configured-state 检查器元数据,可在不加载完整渠道运行时的情况下回答“是否已存在仅环境变量的设置?”。 | +| `openclaw.channel.persistedAuthState` | 轻量级持久化认证状态检查器元数据,可在不加载完整渠道运行时的情况下回答“是否已登录任何内容?”。 | +| `openclaw.install.npmSpec` / `openclaw.install.localPath` | 内置插件和外部发布插件的安装 / 更新提示。 | +| `openclaw.install.defaultChoice` | 当有多个安装来源可用时的首选安装路径。 | | `openclaw.install.minHostVersion` | 最低支持的 OpenClaw 宿主版本,使用类似 `>=2026.3.22` 的 semver 下限。 | -| `openclaw.install.expectedIntegrity` | 预期的 npm 分发完整性字符串,例如 `sha512-...`;安装和更新流程会据此校验获取到的工件。 | -| `openclaw.install.allowInvalidConfigRecovery` | 当配置无效时,允许一条范围很窄的内置插件重新安装恢复路径。 | -| `openclaw.startup.deferConfiguredChannelFullLoadUntilAfterListen` | 允许在启动期间于完整渠道插件之前加载仅设置用的渠道表面。 | +| `openclaw.install.expectedIntegrity` | 预期的 npm 分发完整性字符串,例如 `sha512-...`;安装和更新流程会据此校验获取的制品。 | +| `openclaw.install.allowInvalidConfigRecovery` | 当配置无效时,允许狭义的内置插件重新安装恢复路径。 | +| `openclaw.startup.deferConfiguredChannelFullLoadUntilAfterListen` | 允许仅设置用途的渠道界面在启动期间于完整渠道插件之前加载。 | -清单元数据决定在运行时加载前,onboarding 中会出现哪些 provider / 渠道 / 设置选项。`package.json#openclaw.install` 则告诉 onboarding:当用户选择这些选项之一时,应如何获取或启用该插件。不要将安装提示移入 `openclaw.plugin.json`。 +清单元数据决定了在运行时加载前, +哪些 provider / channel / setup 选项会出现在新手引导中。`package.json#openclaw.install` 则告诉 +新手引导,当用户选择其中某个选项时, +应如何获取或启用该插件。不要将安装提示移到 `openclaw.plugin.json` 中。 -`openclaw.install.minHostVersion` 会在安装期间和清单注册表加载期间强制执行。无效值会被拒绝;较新的但有效的值会使该插件在旧宿主上被跳过。 +`openclaw.install.minHostVersion` 会在安装和清单 +注册表加载期间强制执行。无效值会被拒绝;较新但有效的值会在旧宿主上跳过该 +插件。 精确的 npm 版本固定已经存在于 `npmSpec` 中,例如 -`"npmSpec": "@wecom/wecom-openclaw-plugin@1.2.3"`。官方外部目录条目应将精确 spec 与 `expectedIntegrity` 配对使用,这样如果获取到的 npm 工件不再匹配已固定的发布版本,更新流程就会以失败即关闭的方式终止。为了兼容性,交互式 onboarding 仍会提供受信任注册表的 npm spec,包括裸包名和 dist-tag。目录诊断可以区分精确、浮动、带完整性固定、缺少完整性、包名不匹配以及无效默认选项来源。它们还会在存在 `expectedIntegrity` 但没有可用于固定的有效 npm 来源时发出警告。 -当存在 `expectedIntegrity` 时,安装 / 更新流程会强制执行它;当省略时,注册表解析会被记录下来,但不会附带完整性固定。 +`"npmSpec": "@wecom/wecom-openclaw-plugin@1.2.3"`。官方外部目录 +条目应将精确 spec 与 `expectedIntegrity` 配对,这样如果获取到的 npm 制品 +不再匹配固定版本,更新流程就会失败即关闭。 +出于兼容性考虑,交互式新手引导仍会提供受信任注册表的 npm spec, +包括裸 package 名称和 dist-tag。目录诊断可以 +区分精确、浮动、带完整性固定、缺少完整性、package 名称不匹配 +以及无效默认选项来源。它们还会在 +存在 `expectedIntegrity` 但没有可用于固定它的有效 npm 来源时发出警告。 +当存在 `expectedIntegrity` 时, +安装 / 更新流程会强制校验它;省略时,注册表解析结果 +会被记录下来,但不带完整性固定。 -当 Status、渠道列表或 SecretRef 扫描需要在不加载完整运行时的情况下识别已配置账户时,渠道插件应提供 `openclaw.setupEntry`。该设置入口应公开渠道元数据以及适用于设置的配置、Status 和密钥适配器;请将网络客户端、Gateway 网关监听器和传输运行时保留在主扩展入口点中。 +当 Status、渠道列表 +或 SecretRef 扫描需要在不加载完整运行时的情况下识别已配置账户时,渠道插件应提供 `openclaw.setupEntry`。 +该设置入口点应暴露渠道元数据以及适用于设置场景的配置、 +Status 和密钥适配器;请将网络客户端、Gateway 网关监听器 +和传输运行时保留在主扩展入口点中。 -运行时入口点字段不会覆盖源入口点字段的包边界检查。例如,`openclaw.runtimeExtensions` 不能让一个越界的 `openclaw.extensions` 路径变得可加载。 +运行时入口点字段不会覆盖针对源代码 +入口点字段的 package 边界检查。例如,`openclaw.runtimeExtensions` 不能让一个 +越界的 `openclaw.extensions` 路径变得可加载。 -`openclaw.install.allowInvalidConfigRecovery` 的设计范围是有意收窄的。它不会让任意损坏的配置都能被安装。当前它仅允许安装流程从特定的陈旧内置插件升级失败中恢复,例如缺失的内置插件路径,或该同一内置插件的陈旧 `channels.` 条目。无关的配置错误仍会阻止安装,并将操作员引导至 `openclaw doctor --fix`。 +`openclaw.install.allowInvalidConfigRecovery` 被有意保持为狭义能力。它 +不会让任意损坏配置都变得可安装。目前它只允许安装流程 +从特定的过期内置插件升级失败中恢复,例如 +缺失的内置插件路径,或同一个内置插件对应的陈旧 `channels.` 条目。 +无关的配置错误仍会阻止安装,并引导操作人员 +运行 `openclaw doctor --fix`。 -`openclaw.channel.persistedAuthState` 是一个微型检查器模块的包元数据: +`openclaw.channel.persistedAuthState` 是一个微型检查器 +模块的 package 元数据: ```json { @@ -718,9 +873,13 @@ Provider Index 不得包含机密、启用状态、运行时 hooks,或实时 } ``` -当设置、Doctor 或已配置状态流程需要在完整渠道插件加载前执行轻量级的“是 / 否”认证探测时,请使用它。目标导出应是一个仅读取持久化状态的小函数;不要通过完整渠道运行时 barrel 来路由它。 +当设置、Doctor 或 configured-state 流程需要在完整渠道插件加载前进行一个 +低成本的是否已认证探测时,请使用它。目标导出应是一个仅 +读取持久化状态的小函数;不要通过完整的 +渠道运行时 barrel 转发它。 -`openclaw.channel.configuredState` 对轻量级的仅环境变量已配置检查采用相同结构: +`openclaw.channel.configuredState` 采用相同结构,用于低成本的仅环境变量 +configured 检查: ```json { @@ -736,51 +895,57 @@ Provider Index 不得包含机密、启用状态、运行时 hooks,或实时 } ``` -当某个渠道可以根据环境变量或其他微型的非运行时输入来判断已配置状态时,请使用它。如果检查需要完整配置解析或真实的渠道运行时,请将该逻辑保留在插件 `config.hasConfiguredState` hook 中。 +当某个渠道可以通过环境变量或其他微型 +非运行时输入来回答 configured-state 时,请使用它。如果检查需要完整配置解析或真实 +渠道运行时,请将该逻辑保留在插件 `config.hasConfiguredState` +钩子中。 -## 发现优先级(重复插件 id) +## 设备发现优先级(重复插件 id) -OpenClaw 会从多个根位置发现插件(内置、全局安装、工作区、配置中显式选择的路径)。如果两个发现结果共享同一个 `id`,则只保留**优先级最高**的清单;较低优先级的重复项会被丢弃,而不是与其并列加载。 +OpenClaw 会从多个根目录发现插件(内置、全局安装、工作区、显式由配置选择的路径)。如果两个发现结果共享相同的 `id`,则只保留**优先级最高**的清单;优先级较低的重复项会被丢弃,而不是与其一起加载。 -优先级从高到低如下: +优先级从高到低: -1. **配置选定** —— 在 `plugins.entries.` 中显式固定的路径 -2. **内置** —— 随 OpenClaw 一同提供的插件 +1. **由配置选择** —— 在 `plugins.entries.` 中显式固定的路径 +2. **内置** —— 随 OpenClaw 一起提供的插件 3. **全局安装** —— 安装到全局 OpenClaw 插件根目录中的插件 4. **工作区** —— 相对于当前工作区发现的插件 影响: -- 位于工作区中的某个内置插件的分支或陈旧副本,不会遮蔽内置构建版本。 -- 若要真正用本地插件覆盖内置插件,请通过 `plugins.entries.` 固定它,使其按优先级获胜,而不是依赖工作区发现。 -- 被丢弃的重复项会被记录,以便 Doctor 和启动诊断能够指向被舍弃的副本。 +- 位于工作区中的某个内置插件分支或过期副本不会遮蔽内置构建。 +- 如果你确实要用本地插件覆盖内置插件,请通过 `plugins.entries.` 固定它,让它凭优先级获胜,而不是依赖工作区发现。 +- 被丢弃的重复项会记录到日志中,以便 Doctor 和启动诊断指出被舍弃的副本。 ## JSON Schema 要求 - **每个插件都必须提供一个 JSON Schema**,即使它不接受任何配置。 -- 空 schema 是可接受的(例如,`{ "type": "object", "additionalProperties": false }`)。 -- schema 在配置读取 / 写入时验证,而不是在运行时验证。 +- 可以接受空 schema(例如 `{ "type": "object", "additionalProperties": false }`)。 +- Schema 会在配置读写时验证,而不是在运行时验证。 ## 验证行为 -- 未知的 `channels.*` 键是**错误**,除非该渠道 id 由某个插件清单声明。 +- 未知的 `channels.*` 键是**错误**,除非该渠道 id 已由 + 某个插件清单声明。 - `plugins.entries.`、`plugins.allow`、`plugins.deny` 和 `plugins.slots.*` 必须引用**可发现的**插件 id。未知 id 是**错误**。 -- 如果某个插件已安装,但其清单或 schema 缺失或损坏,验证会失败,Doctor 会报告该插件错误。 -- 如果插件配置存在,但插件被**禁用**,该配置会被保留,并且在 Doctor + 日志中显示**警告**。 +- 如果某个插件已安装,但其清单或 schema 损坏或缺失, + 验证会失败,Doctor 会报告该插件错误。 +- 如果插件配置存在,但插件已**禁用**,则配置会被保留,并且 + Doctor + 日志中会显示一条**警告**。 -完整的 `plugins.*` schema 请参阅 [配置参考](/zh-CN/gateway/configuration)。 +有关完整 `plugins.*` schema,请参见 [配置参考](/zh-CN/gateway/configuration)。 -## 说明 +## 注意事项 -- 对于**原生 OpenClaw 插件**,清单是**必需的**,包括本地文件系统加载。运行时仍会单独加载插件模块;清单仅用于发现 + 验证。 -- 原生清单使用 JSON5 解析,因此接受注释、尾随逗号和未加引号的键,只要最终值仍然是对象即可。 -- 清单加载器只会读取已记录的清单字段。避免使用自定义顶层键。 -- 当插件不需要它们时,`channels`、`providers`、`cliBackends` 和 `skills` 都可以省略。 -- `providerDiscoveryEntry` 必须保持轻量,不应导入宽泛的运行时代码;请将其用于静态 provider 目录元数据或狭窄的发现描述符,而不是请求时执行。 -- 独占插件类型通过 `plugins.slots.*` 选择:`kind: "memory"` 通过 `plugins.slots.memory`,`kind: "context-engine"` 通过 `plugins.slots.contextEngine`(默认 `legacy`)。 -- 环境变量元数据(`setup.providers[].envVars`、已弃用的 `providerAuthEnvVars` 和 `channelEnvVars`)仅为声明式。Status、审计、cron 投递验证和其他只读表面在将某个环境变量视为已配置之前,仍会应用插件信任和有效激活策略。 -- 关于需要 provider 代码的运行时向导元数据,请参阅 [Provider runtime hooks](/zh-CN/plugins/architecture-internals#provider-runtime-hooks)。 +- 对于原生 OpenClaw 插件,清单是**必需的**,包括从本地文件系统加载的插件。运行时仍会单独加载插件模块;清单仅用于设备发现 + 验证。 +- 原生清单使用 JSON5 解析,因此支持注释、尾随逗号和未加引号的键,只要最终值仍然是一个对象即可。 +- 清单加载器只会读取已文档化的清单字段。避免使用自定义顶层键。 +- 当插件不需要它们时,可以省略 `channels`、`providers`、`cliBackends` 和 `skills`。 +- `providerDiscoveryEntry` 必须保持轻量,不应导入宽泛的运行时代码;应将其用于静态 provider 目录元数据或窄范围发现描述符,而不是请求时执行。 +- 互斥插件种类通过 `plugins.slots.*` 选择:`kind: "memory"` 通过 `plugins.slots.memory` 选择,`kind: "context-engine"` 通过 `plugins.slots.contextEngine` 选择(默认值为 `legacy`)。 +- 环境变量元数据(`setup.providers[].envVars`、已弃用的 `providerAuthEnvVars` 以及 `channelEnvVars`)仅是声明式信息。Status、审计、cron 投递验证和其他只读界面在将某个环境变量视为已配置之前,仍会应用插件信任和生效激活策略。 +- 关于需要 provider 代码的运行时向导元数据,请参见 [Provider 运行时钩子](/zh-CN/plugins/architecture-internals#provider-runtime-hooks)。 - 如果你的插件依赖原生模块,请记录构建步骤以及任何包管理器允许列表要求(例如 pnpm `allow-build-scripts` + `pnpm rebuild `)。 ## 相关内容 @@ -792,7 +957,7 @@ OpenClaw 会从多个根位置发现插件(内置、全局安装、工作区 内部架构和能力模型。 - + 插件 SDK 参考和子路径导入。 diff --git a/docs/zh-CN/plugins/sdk-subpaths.md b/docs/zh-CN/plugins/sdk-subpaths.md index 8cb61946b..5a075f2f0 100644 --- a/docs/zh-CN/plugins/sdk-subpaths.md +++ b/docs/zh-CN/plugins/sdk-subpaths.md @@ -1,31 +1,34 @@ --- read_when: - 为插件导入选择正确的 plugin-sdk 子路径 - - 审查 bundled-plugin 子路径和辅助接口 surface -summary: 插件 SDK 子路径目录:按领域分组说明各导入位于何处 + - 审查内置插件子路径和辅助接口 +summary: 插件 SDK 子路径目录:按领域分组说明各导入分别位于何处 title: 插件 SDK 子路径 x-i18n: - generated_at: "2026-04-26T09:19:32Z" + generated_at: "2026-04-27T08:00:45Z" model: gpt-5.4 provider: openai - source_hash: fcb49ee51301b79985d43470cd8c149c858e79d685908605317de253121d4736 + source_hash: 7ab23b42341d981e4ad85027682be603048a0a57d19604fe9024767ffbb78c50 source_path: plugins/sdk-subpaths.md workflow: 15 --- - 插件 SDK 通过 `openclaw/plugin-sdk/` 下的一组精简子路径公开。 - 本页按用途对常用子路径进行归类。生成的完整列表包含 200 多个子路径,位于 `scripts/lib/plugin-sdk-entrypoints.json`;其中也会出现保留的 bundled-plugin 辅助子路径,但除非某个文档页面明确将其作为公开能力介绍,否则它们都属于实现细节。 + 插件 SDK 通过 `openclaw/plugin-sdk/` 下的一组精简子路径暴露。 + 本页按用途分组整理了常用子路径。完整的 200+ 子路径生成列表位于 `scripts/lib/plugin-sdk-entrypoints.json`; + 其中也包含保留给内置插件辅助接口的子路径,但除非某个文档页面明确将其作为公开能力介绍,否则它们都属于实现细节。 - 关于插件编写指南,请参阅 [插件 SDK 概览](/zh-CN/plugins/sdk-overview)。 + 关于插件编写指南,参见 [插件 SDK 概览](/zh-CN/plugins/sdk-overview)。 ## 插件入口 - | 子路径 | 关键导出 | - | --------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------- | - | `plugin-sdk/plugin-entry` | `definePluginEntry` | - | `plugin-sdk/core` | `defineChannelPluginEntry`, `createChatChannelPlugin`, `createChannelPluginBase`, `defineSetupPluginEntry`, `buildChannelConfigSchema` | - | `plugin-sdk/config-schema` | `OpenClawSchema` | - | `plugin-sdk/provider-entry` | `defineSingleProviderPluginEntry` | + | 子路径 | 关键导出 | + | ------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------ | + | `plugin-sdk/plugin-entry` | `definePluginEntry` | + | `plugin-sdk/core` | `defineChannelPluginEntry`, `createChatChannelPlugin`, `createChannelPluginBase`, `defineSetupPluginEntry`, `buildChannelConfigSchema` | + | `plugin-sdk/config-schema` | `OpenClawSchema` | + | `plugin-sdk/provider-entry` | `defineSingleProviderPluginEntry` | + | `plugin-sdk/migration` | 迁移 provider 条目辅助函数,例如 `createMigrationItem`、原因常量、条目状态标记、脱敏辅助函数,以及 `summarizeMigrationItems` | + | `plugin-sdk/migration-runtime` | 运行时迁移辅助函数,例如 `copyMigrationFileItem` 和 `writeMigrationReport` | @@ -34,83 +37,83 @@ x-i18n: | `plugin-sdk/channel-core` | `defineChannelPluginEntry`, `defineSetupPluginEntry`, `createChatChannelPlugin`, `createChannelPluginBase` | | `plugin-sdk/config-schema` | 根 `openclaw.json` Zod schema 导出(`OpenClawSchema`) | | `plugin-sdk/channel-setup` | `createOptionalChannelSetupSurface`, `createOptionalChannelSetupAdapter`, `createOptionalChannelSetupWizard`,以及 `DEFAULT_ACCOUNT_ID`, `createTopLevelChannelDmPolicy`, `setSetupChannelEnabled`, `splitSetupEntries` | - | `plugin-sdk/setup` | 共享设置向导辅助函数、allowlist 提示、设置状态构建器 | + | `plugin-sdk/setup` | 共享的设置向导辅助函数、允许列表提示、设置状态构建器 | | `plugin-sdk/setup-runtime` | `createPatchedAccountSetupAdapter`, `createEnvPatchedAccountSetupAdapter`, `createSetupInputPresenceValidator`, `noteChannelLookupFailure`, `noteChannelLookupSummary`, `promptResolvedAllowFrom`, `splitSetupEntries`, `createAllowlistSetupWizardProxy`, `createDelegatedSetupWizardProxy` | | `plugin-sdk/setup-adapter-runtime` | `createEnvPatchedAccountSetupAdapter` | | `plugin-sdk/setup-tools` | `formatCliCommand`, `detectBinary`, `extractArchive`, `resolveBrewExecutable`, `formatDocsLink`, `CONFIG_DIR` | - | `plugin-sdk/account-core` | 多账户配置 / action-gate 辅助函数,以及默认账户回退辅助函数 | - | `plugin-sdk/account-id` | `DEFAULT_ACCOUNT_ID`,以及 account-id 规范化辅助函数 | + | `plugin-sdk/account-core` | 多账户配置/操作门控辅助函数、默认账户回退辅助函数 | + | `plugin-sdk/account-id` | `DEFAULT_ACCOUNT_ID`、账户 ID 规范化辅助函数 | | `plugin-sdk/account-resolution` | 账户查找 + 默认回退辅助函数 | - | `plugin-sdk/account-helpers` | 精简的账户列表 / 账户操作辅助函数 | + | `plugin-sdk/account-helpers` | 精简的账户列表/账户操作辅助函数 | | `plugin-sdk/channel-pairing` | `createChannelPairingController` | | `plugin-sdk/channel-reply-pipeline` | `createChannelReplyPipeline` | | `plugin-sdk/channel-config-helpers` | `createHybridChannelConfigAdapter` | | `plugin-sdk/channel-config-schema` | 渠道配置 schema 类型 | - | `plugin-sdk/telegram-command-config` | Telegram 自定义命令规范化 / 校验辅助函数,并带有 bundled-contract 回退 | - | `plugin-sdk/command-gating` | 精简的命令授权 gate 辅助函数 | + | `plugin-sdk/telegram-command-config` | Telegram 自定义命令规范化/校验辅助函数,并带有内置合约回退 | + | `plugin-sdk/command-gating` | 精简的命令授权门控辅助函数 | | `plugin-sdk/channel-policy` | `resolveChannelGroupRequireMention` | - | `plugin-sdk/channel-lifecycle` | `createAccountStatusSink`,草稿流生命周期 / 收尾辅助函数 | - | `plugin-sdk/inbound-envelope` | 共享的入站路由 + envelope 构建辅助函数 | + | `plugin-sdk/channel-lifecycle` | `createAccountStatusSink`、草稿流生命周期/完成辅助函数 | + | `plugin-sdk/inbound-envelope` | 共享的入站路由 + envelope 构建器辅助函数 | | `plugin-sdk/inbound-reply-dispatch` | 共享的入站记录与分发辅助函数 | - | `plugin-sdk/messaging-targets` | 目标解析 / 匹配辅助函数 | + | `plugin-sdk/messaging-targets` | 目标解析/匹配辅助函数 | | `plugin-sdk/outbound-media` | 共享的出站媒体加载辅助函数 | | `plugin-sdk/outbound-send-deps` | 面向渠道适配器的轻量级出站发送依赖查找 | - | `plugin-sdk/outbound-runtime` | 出站投递、身份、发送委托、会话、格式化以及 payload 规划辅助函数 | + | `plugin-sdk/outbound-runtime` | 出站投递、身份、发送委托、会话、格式化与载荷规划辅助函数 | | `plugin-sdk/poll-runtime` | 精简的投票规范化辅助函数 | - | `plugin-sdk/thread-bindings-runtime` | 线程绑定生命周期和适配器辅助函数 | - | `plugin-sdk/agent-media-payload` | 旧版智能体媒体 payload 构建器 | - | `plugin-sdk/conversation-runtime` | 会话 / 线程绑定、配对以及已配置绑定辅助函数 | + | `plugin-sdk/thread-bindings-runtime` | 线程绑定生命周期与适配器辅助函数 | + | `plugin-sdk/agent-media-payload` | 旧版智能体媒体载荷构建器 | + | `plugin-sdk/conversation-runtime` | 会话/线程绑定、配对与已配置绑定辅助函数 | | `plugin-sdk/runtime-config-snapshot` | 运行时配置快照辅助函数 | | `plugin-sdk/runtime-group-policy` | 运行时群组策略解析辅助函数 | - | `plugin-sdk/channel-status` | 共享的渠道 Status 快照 / 摘要辅助函数 | - | `plugin-sdk/channel-config-primitives` | 精简的渠道配置 schema 原语 | + | `plugin-sdk/channel-status` | 共享的渠道 Status 快照/摘要辅助函数 | + | `plugin-sdk/channel-config-primitives` | 精简的渠道配置 schema 基元 | | `plugin-sdk/channel-config-writes` | 渠道配置写入授权辅助函数 | - | `plugin-sdk/channel-plugin-common` | 共享的渠道插件 prelude 导出 | - | `plugin-sdk/allowlist-config-edit` | allowlist 配置编辑 / 读取辅助函数 | + | `plugin-sdk/channel-plugin-common` | 共享的渠道插件前导导出 | + | `plugin-sdk/allowlist-config-edit` | 允许列表配置编辑/读取辅助函数 | | `plugin-sdk/group-access` | 共享的群组访问决策辅助函数 | - | `plugin-sdk/direct-dm` | 共享的直接私信认证 / 守卫辅助函数 | - | `plugin-sdk/interactive-runtime` | 语义化消息展示、投递以及旧版交互式回复辅助函数。参见 [消息展示](/zh-CN/plugins/message-presentation) | - | `plugin-sdk/channel-inbound` | 面向入站防抖、提及匹配、提及策略辅助函数以及 envelope 辅助函数的兼容性 barrel | - | `plugin-sdk/channel-inbound-debounce` | 精简的入站防抖辅助函数 | + | `plugin-sdk/direct-dm` | 共享的直接私信认证/保护辅助函数 | + | `plugin-sdk/interactive-runtime` | 语义消息呈现、投递与旧版交互式回复辅助函数。参见 [消息呈现](/zh-CN/plugins/message-presentation) | + | `plugin-sdk/channel-inbound` | 用于入站去抖动、提及匹配、提及策略辅助函数以及 envelope 辅助函数的兼容性 barrel | + | `plugin-sdk/channel-inbound-debounce` | 精简的入站去抖动辅助函数 | | `plugin-sdk/channel-mention-gating` | 精简的提及策略与提及文本辅助函数,不包含更广泛的入站运行时接口 | | `plugin-sdk/channel-envelope` | 精简的入站 envelope 格式化辅助函数 | | `plugin-sdk/channel-location` | 渠道位置上下文与格式化辅助函数 | - | `plugin-sdk/channel-logging` | 用于入站丢弃以及 typing / ack 失败的渠道日志辅助函数 | + | `plugin-sdk/channel-logging` | 用于入站丢弃和 typing/ack 失败的渠道日志辅助函数 | | `plugin-sdk/channel-send-result` | 回复结果类型 | | `plugin-sdk/channel-actions` | 渠道消息操作辅助函数,以及为插件兼容性保留的已弃用原生 schema 辅助函数 | - | `plugin-sdk/channel-targets` | 目标解析 / 匹配辅助函数 | - | `plugin-sdk/channel-contract` | 渠道 contract 类型 | - | `plugin-sdk/channel-feedback` | 反馈 / reaction 接线 | - | `plugin-sdk/channel-secret-runtime` | 精简的 secret-contract 辅助函数,例如 `collectSimpleChannelFieldAssignments`, `getChannelSurface`, `pushAssignment`,以及 secret target 类型 | + | `plugin-sdk/channel-targets` | 目标解析/匹配辅助函数 | + | `plugin-sdk/channel-contract` | 渠道合约类型 | + | `plugin-sdk/channel-feedback` | 反馈/表情反应接线 | + | `plugin-sdk/channel-secret-runtime` | 精简的 secret 合约辅助函数,例如 `collectSimpleChannelFieldAssignments`, `getChannelSurface`, `pushAssignment`,以及 secret 目标类型 | | 子路径 | 关键导出 | | --- | --- | | `plugin-sdk/provider-entry` | `defineSingleProviderPluginEntry` | - | `plugin-sdk/provider-setup` | 经过整理的本地 / 自托管提供商设置辅助函数 | - | `plugin-sdk/self-hosted-provider-setup` | 面向 OpenAI 兼容自托管提供商的聚焦型设置辅助函数 | + | `plugin-sdk/provider-setup` | 精选的本地/自托管 provider 设置辅助函数 | + | `plugin-sdk/self-hosted-provider-setup` | 聚焦于兼容 OpenAI 的自托管 provider 设置辅助函数 | | `plugin-sdk/cli-backend` | CLI 后端默认值 + watchdog 常量 | - | `plugin-sdk/provider-auth-runtime` | 面向提供商插件的运行时 API key 解析辅助函数 | - | `plugin-sdk/provider-auth-api-key` | API key 新手引导 / profile 写入辅助函数,例如 `upsertApiKeyProfile` | - | `plugin-sdk/provider-auth-result` | 标准 OAuth auth-result 构建器 | - | `plugin-sdk/provider-auth-login` | 面向提供商插件的共享交互式登录辅助函数 | - | `plugin-sdk/provider-env-vars` | 提供商认证环境变量查找辅助函数 | + | `plugin-sdk/provider-auth-runtime` | 供 provider 插件使用的运行时 API 密钥解析辅助函数 | + | `plugin-sdk/provider-auth-api-key` | API 密钥新手引导/profile 写入辅助函数,例如 `upsertApiKeyProfile` | + | `plugin-sdk/provider-auth-result` | 标准 OAuth 认证结果构建器 | + | `plugin-sdk/provider-auth-login` | 供 provider 插件使用的共享交互式登录辅助函数 | + | `plugin-sdk/provider-env-vars` | provider 认证环境变量查找辅助函数 | | `plugin-sdk/provider-auth` | `createProviderApiKeyAuthMethod`, `ensureApiKeyFromOptionEnvOrPrompt`, `upsertAuthProfile`, `upsertApiKeyProfile`, `writeOAuthCredentials` | - | `plugin-sdk/provider-model-shared` | `ProviderReplayFamily`, `buildProviderReplayFamilyHooks`, `normalizeModelCompat`,共享 replay-policy 构建器、提供商 endpoint 辅助函数,以及模型 ID 规范化辅助函数,例如 `normalizeNativeXaiModelId` | + | `plugin-sdk/provider-model-shared` | `ProviderReplayFamily`, `buildProviderReplayFamilyHooks`, `normalizeModelCompat`、共享重放策略构建器、provider 端点辅助函数,以及模型 ID 规范化辅助函数,例如 `normalizeNativeXaiModelId` | | `plugin-sdk/provider-catalog-shared` | `findCatalogTemplate`, `buildSingleProviderApiKeyCatalog`, `supportsNativeStreamingUsageCompat`, `applyProviderNativeStreamingUsageCompat` | - | `plugin-sdk/provider-http` | 通用提供商 HTTP / endpoint 能力辅助函数、提供商 HTTP 错误,以及音频转录 multipart form 辅助函数 | - | `plugin-sdk/provider-web-fetch-contract` | 精简的 web-fetch 配置 / 选择 contract 辅助函数,例如 `enablePluginInConfig` 和 `WebFetchProviderPlugin` | - | `plugin-sdk/provider-web-fetch` | Web-fetch 提供商注册 / 缓存辅助函数 | - | `plugin-sdk/provider-web-search-config-contract` | 面向不需要插件启用接线的提供商的精简 web-search 配置 / 凭证辅助函数 | - | `plugin-sdk/provider-web-search-contract` | 精简的 web-search 配置 / 凭证 contract 辅助函数,例如 `createWebSearchProviderContractFields`, `enablePluginInConfig`, `resolveProviderWebSearchPluginConfig`,以及有作用域的凭证 setter / getter | - | `plugin-sdk/provider-web-search` | Web 搜索提供商注册 / 缓存 / 运行时辅助函数 | + | `plugin-sdk/provider-http` | 通用 provider HTTP/端点能力辅助函数、provider HTTP 错误,以及音频转录 multipart form 辅助函数 | + | `plugin-sdk/provider-web-fetch-contract` | 精简的 web-fetch 配置/选择合约辅助函数,例如 `enablePluginInConfig` 和 `WebFetchProviderPlugin` | + | `plugin-sdk/provider-web-fetch` | web-fetch provider 注册/缓存辅助函数 | + | `plugin-sdk/provider-web-search-config-contract` | 面向不需要插件启用接线的 provider 的精简 web-search 配置/凭证辅助函数 | + | `plugin-sdk/provider-web-search-contract` | 精简的 web-search 配置/凭证合约辅助函数,例如 `createWebSearchProviderContractFields`, `enablePluginInConfig`, `resolveProviderWebSearchPluginConfig`,以及作用域凭证 setter/getter | + | `plugin-sdk/provider-web-search` | web-search provider 注册/缓存/运行时辅助函数 | | `plugin-sdk/provider-tools` | `ProviderToolCompatFamily`, `buildProviderToolCompatFamilyHooks`, Gemini schema 清理 + 诊断,以及 xAI 兼容辅助函数,例如 `resolveXaiModelCompatPatch` / `applyXaiModelCompat` | | `plugin-sdk/provider-usage` | `fetchClaudeUsage` 及类似函数 | - | `plugin-sdk/provider-stream` | `ProviderStreamFamily`, `buildProviderStreamFamilyHooks`, `composeProviderStreamWrappers`、流包装器类型,以及共享的 Anthropic / Bedrock / DeepSeek V4 / Google / Kilocode / Moonshot / OpenAI / OpenRouter / Z.A.I / MiniMax / Copilot 包装器辅助函数 | - | `plugin-sdk/provider-transport-runtime` | 原生提供商传输辅助函数,例如 guarded fetch、传输消息转换以及可写传输事件流 | + | `plugin-sdk/provider-stream` | `ProviderStreamFamily`, `buildProviderStreamFamilyHooks`, `composeProviderStreamWrappers`、流包装器类型,以及共享的 Anthropic/Bedrock/DeepSeek V4/Google/Kilocode/Moonshot/OpenAI/OpenRouter/Z.A.I/MiniMax/Copilot 包装器辅助函数 | + | `plugin-sdk/provider-transport-runtime` | 原生 provider 传输辅助函数,例如受保护抓取、传输消息转换和可写传输事件流 | | `plugin-sdk/provider-onboard` | 新手引导配置补丁辅助函数 | - | `plugin-sdk/global-singleton` | 进程本地 singleton / map / cache 辅助函数 | + | `plugin-sdk/global-singleton` | 进程本地 singleton/map/cache 辅助函数 | | `plugin-sdk/group-activation` | 精简的群组激活模式与命令解析辅助函数 | @@ -118,164 +121,164 @@ x-i18n: | 子路径 | 关键导出 | | --- | --- | | `plugin-sdk/command-auth` | `resolveControlCommandGate`、命令注册表辅助函数(包括动态参数菜单格式化)、发送者授权辅助函数 | - | `plugin-sdk/command-status` | 命令 / 帮助消息构建器,例如 `buildCommandsMessagePaginated` 和 `buildHelpMessage` | - | `plugin-sdk/approval-auth-runtime` | 审批人解析以及同聊天 action-auth 辅助函数 | - | `plugin-sdk/approval-client-runtime` | 原生 exec 审批 profile / filter 辅助函数 | - | `plugin-sdk/approval-delivery-runtime` | 原生审批能力 / 投递适配器 | - | `plugin-sdk/approval-gateway-runtime` | 共享审批 Gateway 网关解析辅助函数 | - | `plugin-sdk/approval-handler-adapter-runtime` | 面向热路径渠道入口点的轻量级原生审批适配器加载辅助函数 | - | `plugin-sdk/approval-handler-runtime` | 更广泛的审批处理器运行时辅助函数;若更精简的 adapter / gateway 接口已足够,优先使用它们 | + | `plugin-sdk/command-status` | 命令/帮助消息构建器,例如 `buildCommandsMessagePaginated` 和 `buildHelpMessage` | + | `plugin-sdk/approval-auth-runtime` | 审批人解析和同聊天操作认证辅助函数 | + | `plugin-sdk/approval-client-runtime` | 原生执行审批 profile/filter 辅助函数 | + | `plugin-sdk/approval-delivery-runtime` | 原生审批能力/投递适配器 | + | `plugin-sdk/approval-gateway-runtime` | 共享的审批 Gateway 网关解析辅助函数 | + | `plugin-sdk/approval-handler-adapter-runtime` | 面向热渠道入口点的轻量级原生审批适配器加载辅助函数 | + | `plugin-sdk/approval-handler-runtime` | 更广泛的审批处理器运行时辅助函数;当更精简的 adapter/gateway 接口已足够时,应优先使用它们 | | `plugin-sdk/approval-native-runtime` | 原生审批目标 + 账户绑定辅助函数 | - | `plugin-sdk/approval-reply-runtime` | exec / 插件审批回复 payload 辅助函数 | - | `plugin-sdk/approval-runtime` | exec / 插件审批 payload 辅助函数、原生审批路由 / 运行时辅助函数,以及结构化审批显示辅助函数,例如 `formatApprovalDisplayPath` | + | `plugin-sdk/approval-reply-runtime` | exec/插件审批回复载荷辅助函数 | + | `plugin-sdk/approval-runtime` | exec/插件审批载荷辅助函数、原生审批路由/运行时辅助函数,以及结构化审批显示辅助函数,例如 `formatApprovalDisplayPath` | | `plugin-sdk/reply-dedupe` | 精简的入站回复去重重置辅助函数 | - | `plugin-sdk/channel-contract-testing` | 精简的渠道 contract 测试辅助函数,不包含宽泛的 testing barrel | + | `plugin-sdk/channel-contract-testing` | 精简的渠道合约测试辅助函数,不包含宽泛的测试 barrel | | `plugin-sdk/command-auth-native` | 原生命令认证、动态参数菜单格式化,以及原生会话目标辅助函数 | - | `plugin-sdk/command-detection` | 共享命令检测辅助函数 | - | `plugin-sdk/command-primitives-runtime` | 面向热路径渠道路径的轻量级命令文本谓词 | - | `plugin-sdk/command-surface` | 命令正文规范化和命令接口辅助函数 | + | `plugin-sdk/command-detection` | 共享的命令检测辅助函数 | + | `plugin-sdk/command-primitives-runtime` | 面向热渠道路径的轻量级命令文本谓词 | + | `plugin-sdk/command-surface` | 命令体规范化和命令表面辅助函数 | | `plugin-sdk/allow-from` | `formatAllowFromLowercase` | - | `plugin-sdk/channel-secret-runtime` | 面向渠道 / 插件 secret 接口的精简 secret-contract 收集辅助函数 | - | `plugin-sdk/secret-ref-runtime` | 面向 secret-contract / 配置解析的精简 `coerceSecretRef` 和 SecretRef 类型辅助函数 | - | `plugin-sdk/security-runtime` | 共享的信任、私信 gate、外部内容以及 secret 收集辅助函数 | - | `plugin-sdk/ssrf-policy` | 主机 allowlist 和私有网络 SSRF 策略辅助函数 | - | `plugin-sdk/ssrf-dispatcher` | 精简的 pinned-dispatcher 辅助函数,不包含宽泛的基础设施运行时接口 | - | `plugin-sdk/ssrf-runtime` | pinned-dispatcher、受 SSRF 保护的 fetch,以及 SSRF 策略辅助函数 | + | `plugin-sdk/channel-secret-runtime` | 面向渠道/插件 secret 接口的精简 secret 合约收集辅助函数 | + | `plugin-sdk/secret-ref-runtime` | 用于 secret 合约/配置解析的精简 `coerceSecretRef` 和 `SecretRef` 类型辅助函数 | + | `plugin-sdk/security-runtime` | 共享的信任、私信门控、外部内容和 secret 收集辅助函数 | + | `plugin-sdk/ssrf-policy` | 主机允许列表和私有网络 SSRF 策略辅助函数 | + | `plugin-sdk/ssrf-dispatcher` | 精简的固定 dispatcher 辅助函数,不包含宽泛的基础设施运行时接口 | + | `plugin-sdk/ssrf-runtime` | 固定 dispatcher、受 SSRF 保护的 fetch,以及 SSRF 策略辅助函数 | | `plugin-sdk/secret-input` | secret 输入解析辅助函数 | - | `plugin-sdk/webhook-ingress` | webhook 请求 / 目标辅助函数 | - | `plugin-sdk/webhook-request-guards` | 请求体大小 / 超时辅助函数 | + | `plugin-sdk/webhook-ingress` | Webhook 请求/目标辅助函数 | + | `plugin-sdk/webhook-request-guards` | 请求体大小/超时辅助函数 | | 子路径 | 关键导出 | | --- | --- | - | `plugin-sdk/runtime` | 宽泛的运行时 / 日志 / 备份 / 插件安装辅助函数 | + | `plugin-sdk/runtime` | 宽泛的运行时/日志/备份/插件安装辅助函数 | | `plugin-sdk/runtime-env` | 精简的运行时环境、logger、超时、重试和退避辅助函数 | | `plugin-sdk/channel-runtime-context` | 通用渠道运行时上下文注册与查找辅助函数 | | `plugin-sdk/runtime-store` | `createPluginRuntimeStore` | - | `plugin-sdk/plugin-runtime` | 共享的插件命令 / hook / HTTP / 交互辅助函数 | - | `plugin-sdk/hook-runtime` | 共享 webhook / 内部 hook 流水线辅助函数 | - | `plugin-sdk/lazy-runtime` | 惰性运行时导入 / 绑定辅助函数,例如 `createLazyRuntimeModule`、`createLazyRuntimeMethod` 和 `createLazyRuntimeSurface` | - | `plugin-sdk/process-runtime` | 进程 exec 辅助函数 | - | `plugin-sdk/cli-runtime` | CLI 格式化、等待、版本、参数调用以及惰性命令组辅助函数 | - | `plugin-sdk/gateway-runtime` | Gateway 网关客户端和渠道 Status 补丁辅助函数 | - | `plugin-sdk/config-runtime` | 配置加载 / 写入辅助函数,以及插件配置查找辅助函数 | - | `plugin-sdk/telegram-command-config` | Telegram 命令名 / 描述规范化,以及重复 / 冲突检查,即使 bundled Telegram contract 接口不可用时也可使用 | + | `plugin-sdk/plugin-runtime` | 共享的插件命令/钩子/http/交互式辅助函数 | + | `plugin-sdk/hook-runtime` | 共享的 webhook/内部钩子流水线辅助函数 | + | `plugin-sdk/lazy-runtime` | 惰性运行时导入/绑定辅助函数,例如 `createLazyRuntimeModule`、`createLazyRuntimeMethod` 和 `createLazyRuntimeSurface` | + | `plugin-sdk/process-runtime` | 进程执行辅助函数 | + | `plugin-sdk/cli-runtime` | CLI 格式化、等待、版本、参数调用和惰性命令组辅助函数 | + | `plugin-sdk/gateway-runtime` | Gateway 网关客户端与渠道 Status 补丁辅助函数 | + | `plugin-sdk/config-runtime` | 配置加载/写入辅助函数和插件配置查找辅助函数 | + | `plugin-sdk/telegram-command-config` | Telegram 命令名称/描述规范化以及重复/冲突检查,即使内置 Telegram 合约接口不可用时也可使用 | | `plugin-sdk/text-autolink-runtime` | 文件引用自动链接检测,不包含宽泛的 text-runtime barrel | - | `plugin-sdk/approval-runtime` | exec / 插件审批辅助函数、审批能力构建器、认证 / profile 辅助函数、原生路由 / 运行时辅助函数,以及结构化审批显示路径格式化 | - | `plugin-sdk/reply-runtime` | 共享的入站 / 回复运行时辅助函数、分块、分发、心跳、回复规划器 | - | `plugin-sdk/reply-dispatch-runtime` | 精简的回复分发 / 完成处理以及会话标签辅助函数 | + | `plugin-sdk/approval-runtime` | exec/插件审批辅助函数、审批能力构建器、认证/profile 辅助函数、原生路由/运行时辅助函数,以及结构化审批显示路径格式化 | + | `plugin-sdk/reply-runtime` | 共享的入站/回复运行时辅助函数、分块、分发、心跳、回复规划器 | + | `plugin-sdk/reply-dispatch-runtime` | 精简的回复分发/完成以及会话标签辅助函数 | | `plugin-sdk/reply-history` | 共享的短窗口回复历史辅助函数,例如 `buildHistoryContext`、`recordPendingHistoryEntry` 和 `clearHistoryEntriesIfEnabled` | | `plugin-sdk/reply-reference` | `createReplyReferencePlanner` | - | `plugin-sdk/reply-chunking` | 精简的文本 / Markdown 分块辅助函数 | - | `plugin-sdk/session-store-runtime` | 会话存储路径 + `updated-at` 辅助函数 | - | `plugin-sdk/state-paths` | 状态 / OAuth 目录路径辅助函数 | - | `plugin-sdk/routing` | 路由 / 会话键 / 账户绑定辅助函数,例如 `resolveAgentRoute`、`buildAgentSessionKey` 和 `resolveDefaultAgentBoundAccountId` | - | `plugin-sdk/status-helpers` | 共享的渠道 / 账户 Status 摘要辅助函数、运行时状态默认值以及问题元数据辅助函数 | - | `plugin-sdk/target-resolver-runtime` | 共享目标解析器辅助函数 | - | `plugin-sdk/string-normalization-runtime` | slug / 字符串规范化辅助函数 | - | `plugin-sdk/request-url` | 从类似 fetch / request 的输入中提取字符串 URL | - | `plugin-sdk/run-command` | 带超时的命令运行器,并返回规范化的 stdout / stderr 结果 | - | `plugin-sdk/param-readers` | 通用工具 / CLI 参数读取器 | - | `plugin-sdk/tool-payload` | 从工具结果对象中提取规范化 payload | - | `plugin-sdk/tool-send` | 从工具参数中提取规范的发送目标字段 | + | `plugin-sdk/reply-chunking` | 精简的文本/Markdown 分块辅助函数 | + | `plugin-sdk/session-store-runtime` | 会话存储路径 + updated-at 辅助函数 | + | `plugin-sdk/state-paths` | 状态/OAuth 目录路径辅助函数 | + | `plugin-sdk/routing` | 路由/会话键/账户绑定辅助函数,例如 `resolveAgentRoute`、`buildAgentSessionKey` 和 `resolveDefaultAgentBoundAccountId` | + | `plugin-sdk/status-helpers` | 共享的渠道/账户 Status 摘要辅助函数、运行时状态默认值和问题元数据辅助函数 | + | `plugin-sdk/target-resolver-runtime` | 共享的目标解析器辅助函数 | + | `plugin-sdk/string-normalization-runtime` | slug/字符串规范化辅助函数 | + | `plugin-sdk/request-url` | 从 fetch/request 类输入中提取字符串 URL | + | `plugin-sdk/run-command` | 带计时的命令运行器,输出规范化的 stdout/stderr 结果 | + | `plugin-sdk/param-readers` | 通用工具/CLI 参数读取器 | + | `plugin-sdk/tool-payload` | 从工具结果对象中提取规范化载荷 | + | `plugin-sdk/tool-send` | 从工具参数中提取规范发送目标字段 | | `plugin-sdk/temp-path` | 共享的临时下载路径辅助函数 | | `plugin-sdk/logging-core` | 子系统 logger 和脱敏辅助函数 | | `plugin-sdk/markdown-table-runtime` | Markdown 表格模式和转换辅助函数 | - | `plugin-sdk/json-store` | 小型 JSON 状态读写辅助函数 | + | `plugin-sdk/json-store` | 小型 JSON 状态读取/写入辅助函数 | | `plugin-sdk/file-lock` | 可重入文件锁辅助函数 | | `plugin-sdk/persistent-dedupe` | 磁盘支持的去重缓存辅助函数 | - | `plugin-sdk/acp-runtime` | ACP 运行时 / 会话和回复分发辅助函数 | - | `plugin-sdk/acp-binding-resolve-runtime` | 只读 ACP 绑定解析,不引入生命周期启动导入 | - | `plugin-sdk/agent-config-primitives` | 精简的智能体运行时配置 schema 原语 | + | `plugin-sdk/acp-runtime` | ACP 运行时/会话和回复分发辅助函数 | + | `plugin-sdk/acp-binding-resolve-runtime` | 不包含生命周期启动导入的只读 ACP 绑定解析 | + | `plugin-sdk/agent-config-primitives` | 精简的智能体运行时配置 schema 基元 | | `plugin-sdk/boolean-param` | 宽松布尔参数读取器 | | `plugin-sdk/dangerous-name-runtime` | 危险名称匹配解析辅助函数 | | `plugin-sdk/device-bootstrap` | 设备引导和配对令牌辅助函数 | - | `plugin-sdk/extension-shared` | 共享的被动渠道、Status 和环境代理辅助原语 | - | `plugin-sdk/models-provider-runtime` | `/models` 命令 / 提供商回复辅助函数 | + | `plugin-sdk/extension-shared` | 共享的被动渠道、Status 和环境代理辅助基元 | + | `plugin-sdk/models-provider-runtime` | `/models` 命令/provider 回复辅助函数 | | `plugin-sdk/skill-commands-runtime` | Skills 命令列表辅助函数 | - | `plugin-sdk/native-command-registry` | 原生命令注册表构建 / 序列化辅助函数 | - | `plugin-sdk/agent-harness` | 面向低层 Agent harness 的实验性受信任插件接口:harness 类型、活动运行 steer / abort 辅助函数、OpenClaw 工具桥接辅助函数、运行时计划工具策略辅助函数、终端结果分类、工具进度格式化 / 详情辅助函数,以及尝试结果工具函数 | - | `plugin-sdk/provider-zai-endpoint` | Z.A.I endpoint 检测辅助函数 | - | `plugin-sdk/infra-runtime` | 系统事件 / 心跳辅助函数 | + | `plugin-sdk/native-command-registry` | 原生命令注册表构建/序列化辅助函数 | + | `plugin-sdk/agent-harness` | 面向受信任插件的实验性低层 Agent harness 接口:harness 类型、活动运行转向/中止辅助函数、OpenClaw 工具桥接辅助函数、运行时计划工具策略辅助函数、终端结果分类、工具进度格式化/详情辅助函数,以及尝试结果工具函数 | + | `plugin-sdk/provider-zai-endpoint` | Z.A.I 端点检测辅助函数 | + | `plugin-sdk/infra-runtime` | 系统事件/心跳辅助函数 | | `plugin-sdk/collection-runtime` | 小型有界缓存辅助函数 | | `plugin-sdk/diagnostic-runtime` | 诊断标志和事件辅助函数 | | `plugin-sdk/error-runtime` | 错误图、格式化、共享错误分类辅助函数、`isApprovalNotFoundError` | - | `plugin-sdk/fetch-runtime` | 包装后的 fetch、代理和 pinned 查找辅助函数 | - | `plugin-sdk/runtime-fetch` | 感知 dispatcher 的运行时 fetch,不引入代理 / 受保护 fetch 导入 | + | `plugin-sdk/fetch-runtime` | 封装的 fetch、代理和固定查找辅助函数 | + | `plugin-sdk/runtime-fetch` | 具备 dispatcher 感知能力的运行时 fetch,不包含代理/受保护 fetch 导入 | | `plugin-sdk/response-limit-runtime` | 有界响应体读取器,不包含宽泛的媒体运行时接口 | | `plugin-sdk/session-binding-runtime` | 当前会话绑定状态,不包含已配置绑定路由或配对存储 | - | `plugin-sdk/session-store-runtime` | 会话存储读取辅助函数,不引入宽泛的配置写入 / 维护导入 | - | `plugin-sdk/context-visibility-runtime` | 上下文可见性解析和补充上下文过滤,不引入宽泛的配置 / 安全导入 | - | `plugin-sdk/string-coerce-runtime` | 精简的原始记录 / 字符串强制转换与规范化辅助函数,不引入 Markdown / 日志导入 | + | `plugin-sdk/session-store-runtime` | 会话存储读取辅助函数,不包含宽泛的配置写入/维护导入 | + | `plugin-sdk/context-visibility-runtime` | 上下文可见性解析和补充上下文过滤,不包含宽泛的配置/安全导入 | + | `plugin-sdk/string-coerce-runtime` | 精简的原始记录/字符串强制转换和规范化辅助函数,不包含 Markdown/日志导入 | | `plugin-sdk/host-runtime` | 主机名和 SCP 主机规范化辅助函数 | | `plugin-sdk/retry-runtime` | 重试配置和重试运行器辅助函数 | - | `plugin-sdk/agent-runtime` | 智能体目录 / 身份 / 工作区辅助函数 | - | `plugin-sdk/directory-runtime` | 基于配置的目录查询 / 去重 | + | `plugin-sdk/agent-runtime` | 智能体目录/身份/工作区辅助函数 | + | `plugin-sdk/directory-runtime` | 基于配置的目录查询/去重 | | `plugin-sdk/keyed-async-queue` | `KeyedAsyncQueue` | | 子路径 | 关键导出 | | --- | --- | - | `plugin-sdk/media-runtime` | 共享媒体获取 / 转换 / 存储辅助函数,以及媒体 payload 构建器 | + | `plugin-sdk/media-runtime` | 共享的媒体获取/转换/存储辅助函数,以及媒体载荷构建器 | | `plugin-sdk/media-store` | 精简的媒体存储辅助函数,例如 `saveMediaBuffer` | - | `plugin-sdk/media-generation-runtime` | 共享媒体生成故障转移辅助函数、候选项选择以及缺失模型提示 | - | `plugin-sdk/media-understanding` | 媒体理解提供商类型,以及面向提供商的图像 / 音频辅助导出 | - | `plugin-sdk/text-runtime` | 共享文本 / Markdown / 日志辅助函数,例如面向助手可见文本剥离、Markdown 渲染 / 分块 / 表格辅助函数、脱敏辅助函数、directive-tag 辅助函数以及安全文本工具函数 | + | `plugin-sdk/media-generation-runtime` | 共享的媒体生成故障切换辅助函数、候选项选择和缺失模型消息 | + | `plugin-sdk/media-understanding` | 媒体理解 provider 类型,以及面向 provider 的图像/音频辅助导出 | + | `plugin-sdk/text-runtime` | 共享的文本/Markdown/日志辅助函数,例如面向助手可见文本剥离、Markdown 渲染/分块/表格辅助函数、脱敏辅助函数、指令标签辅助函数,以及安全文本工具 | | `plugin-sdk/text-chunking` | 出站文本分块辅助函数 | - | `plugin-sdk/speech` | 语音提供商类型,以及面向提供商的 directive、注册表、校验和语音辅助导出 | - | `plugin-sdk/speech-core` | 共享语音提供商类型、注册表、directive、规范化和语音辅助导出 | - | `plugin-sdk/realtime-transcription` | 实时转录提供商类型、注册表辅助函数,以及共享 WebSocket 会话辅助函数 | - | `plugin-sdk/realtime-voice` | 实时语音提供商类型和注册表辅助函数 | - | `plugin-sdk/image-generation` | 图像生成提供商类型 | - | `plugin-sdk/image-generation-core` | 共享图像生成类型、故障转移、认证和注册表辅助函数 | - | `plugin-sdk/music-generation` | 音乐生成提供商 / 请求 / 结果类型 | - | `plugin-sdk/music-generation-core` | 共享音乐生成类型、故障转移辅助函数、提供商查找以及 model-ref 解析 | - | `plugin-sdk/video-generation` | 视频生成提供商 / 请求 / 结果类型 | - | `plugin-sdk/video-generation-core` | 共享视频生成类型、故障转移辅助函数、提供商查找以及 model-ref 解析 | - | `plugin-sdk/webhook-targets` | webhook 目标注册表和路由安装辅助函数 | - | `plugin-sdk/webhook-path` | webhook 路径规范化辅助函数 | - | `plugin-sdk/web-media` | 共享远程 / 本地媒体加载辅助函数 | + | `plugin-sdk/speech` | 语音 provider 类型,以及面向 provider 的指令、注册表、校验和语音辅助导出 | + | `plugin-sdk/speech-core` | 共享的语音 provider 类型、注册表、指令、规范化和语音辅助导出 | + | `plugin-sdk/realtime-transcription` | 实时转录 provider 类型、注册表辅助函数和共享 WebSocket 会话辅助函数 | + | `plugin-sdk/realtime-voice` | 实时语音 provider 类型和注册表辅助函数 | + | `plugin-sdk/image-generation` | 图像生成 provider 类型 | + | `plugin-sdk/image-generation-core` | 共享的图像生成类型、故障切换、认证和注册表辅助函数 | + | `plugin-sdk/music-generation` | 音乐生成 provider/请求/结果类型 | + | `plugin-sdk/music-generation-core` | 共享的音乐生成类型、故障切换辅助函数、provider 查找和 model-ref 解析 | + | `plugin-sdk/video-generation` | 视频生成 provider/请求/结果类型 | + | `plugin-sdk/video-generation-core` | 共享的视频生成类型、故障切换辅助函数、provider 查找和 model-ref 解析 | + | `plugin-sdk/webhook-targets` | Webhook 目标注册表和路由安装辅助函数 | + | `plugin-sdk/webhook-path` | Webhook 路径规范化辅助函数 | + | `plugin-sdk/web-media` | 共享的远程/本地媒体加载辅助函数 | | `plugin-sdk/zod` | 为插件 SDK 使用者重新导出的 `zod` | - | `plugin-sdk/testing` | `installCommonResolveTargetErrorCases`、`shouldAckReaction` | + | `plugin-sdk/testing` | `installCommonResolveTargetErrorCases`, `shouldAckReaction` | | 子路径 | 关键导出 | | --- | --- | - | `plugin-sdk/memory-core` | 内置 `memory-core` 辅助接口,包含 manager / config / file / CLI 辅助函数 | - | `plugin-sdk/memory-core-engine-runtime` | Memory 索引 / 搜索运行时 facade | - | `plugin-sdk/memory-core-host-engine-foundation` | Memory host foundation engine 导出 | - | `plugin-sdk/memory-core-host-engine-embeddings` | Memory host embedding contract、注册表访问、本地提供商以及通用批处理 / 远程辅助函数 | - | `plugin-sdk/memory-core-host-engine-qmd` | Memory host QMD engine 导出 | - | `plugin-sdk/memory-core-host-engine-storage` | Memory host storage engine 导出 | - | `plugin-sdk/memory-core-host-multimodal` | Memory host 多模态辅助函数 | - | `plugin-sdk/memory-core-host-query` | Memory host 查询辅助函数 | - | `plugin-sdk/memory-core-host-secret` | Memory host secret 辅助函数 | - | `plugin-sdk/memory-core-host-events` | Memory host 事件日志辅助函数 | - | `plugin-sdk/memory-core-host-status` | Memory host Status 辅助函数 | - | `plugin-sdk/memory-core-host-runtime-cli` | Memory host CLI 运行时辅助函数 | - | `plugin-sdk/memory-core-host-runtime-core` | Memory host 核心运行时辅助函数 | - | `plugin-sdk/memory-core-host-runtime-files` | Memory host 文件 / 运行时辅助函数 | - | `plugin-sdk/memory-host-core` | 面向供应商中立的 Memory host 核心运行时辅助函数别名 | - | `plugin-sdk/memory-host-events` | 面向供应商中立的 Memory host 事件日志辅助函数别名 | - | `plugin-sdk/memory-host-files` | 面向供应商中立的 Memory host 文件 / 运行时辅助函数别名 | + | `plugin-sdk/memory-core` | 内置的 memory-core 辅助接口,用于 manager/config/file/CLI 辅助函数 | + | `plugin-sdk/memory-core-engine-runtime` | Memory 索引/搜索运行时外观层 | + | `plugin-sdk/memory-core-host-engine-foundation` | Memory 主机基础引擎导出 | + | `plugin-sdk/memory-core-host-engine-embeddings` | Memory 主机嵌入合约、注册表访问、本地 provider,以及通用批处理/远程辅助函数 | + | `plugin-sdk/memory-core-host-engine-qmd` | Memory 主机 QMD 引擎导出 | + | `plugin-sdk/memory-core-host-engine-storage` | Memory 主机存储引擎导出 | + | `plugin-sdk/memory-core-host-multimodal` | Memory 主机多模态辅助函数 | + | `plugin-sdk/memory-core-host-query` | Memory 主机查询辅助函数 | + | `plugin-sdk/memory-core-host-secret` | Memory 主机 secret 辅助函数 | + | `plugin-sdk/memory-core-host-events` | Memory 主机事件日志辅助函数 | + | `plugin-sdk/memory-core-host-status` | Memory 主机 Status 辅助函数 | + | `plugin-sdk/memory-core-host-runtime-cli` | Memory 主机 CLI 运行时辅助函数 | + | `plugin-sdk/memory-core-host-runtime-core` | Memory 主机核心运行时辅助函数 | + | `plugin-sdk/memory-core-host-runtime-files` | Memory 主机文件/运行时辅助函数 | + | `plugin-sdk/memory-host-core` | 面向供应商中立的别名,用于 Memory 主机核心运行时辅助函数 | + | `plugin-sdk/memory-host-events` | 面向供应商中立的别名,用于 Memory 主机事件日志辅助函数 | + | `plugin-sdk/memory-host-files` | 面向供应商中立的别名,用于 Memory 主机文件/运行时辅助函数 | | `plugin-sdk/memory-host-markdown` | 面向 Memory 邻接插件的共享托管 Markdown 辅助函数 | - | `plugin-sdk/memory-host-search` | 用于访问搜索管理器的活动 Memory 运行时 facade | - | `plugin-sdk/memory-host-status` | 面向供应商中立的 Memory host Status 辅助函数别名 | - | `plugin-sdk/memory-lancedb` | 内置 `memory-lancedb` 辅助接口 | + | `plugin-sdk/memory-host-search` | 用于访问搜索管理器的活动 Memory 运行时外观层 | + | `plugin-sdk/memory-host-status` | 面向供应商中立的别名,用于 Memory 主机 Status 辅助函数 | + | `plugin-sdk/memory-lancedb` | 内置的 memory-lancedb 辅助接口 | - | 类别 | 当前子路径 | 预期用途 | + | 家族 | 当前子路径 | 预期用途 | | --- | --- | --- | - | Browser | `plugin-sdk/browser-cdp`, `plugin-sdk/browser-config-runtime`, `plugin-sdk/browser-config-support`, `plugin-sdk/browser-control-auth`, `plugin-sdk/browser-node-runtime`, `plugin-sdk/browser-profiles`, `plugin-sdk/browser-security-runtime`, `plugin-sdk/browser-setup-tools`, `plugin-sdk/browser-support` | 内置浏览器插件支持辅助函数。`browser-profiles` 导出 `resolveBrowserConfig`、`resolveProfile`、`ResolvedBrowserConfig`、`ResolvedBrowserProfile` 和 `ResolvedBrowserTabCleanupConfig`,用于规范化后的 `browser.tabCleanup` 结构。`browser-support` 仍然是兼容性 barrel。 | - | Matrix | `plugin-sdk/matrix`, `plugin-sdk/matrix-helper`, `plugin-sdk/matrix-runtime-heavy`, `plugin-sdk/matrix-runtime-shared`, `plugin-sdk/matrix-runtime-surface`, `plugin-sdk/matrix-surface`, `plugin-sdk/matrix-thread-bindings` | 内置 Matrix 辅助 / 运行时接口 | - | Line | `plugin-sdk/line`, `plugin-sdk/line-core`, `plugin-sdk/line-runtime`, `plugin-sdk/line-surface` | 内置 LINE 辅助 / 运行时接口 | - | IRC | `plugin-sdk/irc`, `plugin-sdk/irc-surface` | 内置 IRC 辅助接口 | - | 渠道专用辅助函数 | `plugin-sdk/googlechat`, `plugin-sdk/zalouser`, `plugin-sdk/bluebubbles`, `plugin-sdk/bluebubbles-policy`, `plugin-sdk/mattermost`, `plugin-sdk/mattermost-policy`, `plugin-sdk/feishu-conversation`, `plugin-sdk/msteams`, `plugin-sdk/nextcloud-talk`, `plugin-sdk/nostr`, `plugin-sdk/tlon`, `plugin-sdk/twitch` | 内置渠道兼容性 / 辅助接口 | - | 认证 / 插件专用辅助函数 | `plugin-sdk/github-copilot-login`, `plugin-sdk/github-copilot-token`, `plugin-sdk/diagnostics-otel`, `plugin-sdk/diagnostics-prometheus`, `plugin-sdk/diffs`, `plugin-sdk/llm-task`, `plugin-sdk/thread-ownership`, `plugin-sdk/voice-call` | 内置功能 / 插件辅助接口;`plugin-sdk/github-copilot-token` 当前导出 `DEFAULT_COPILOT_API_BASE_URL`、`deriveCopilotApiBaseUrlFromToken` 和 `resolveCopilotApiToken` | + | Browser | `plugin-sdk/browser-cdp`, `plugin-sdk/browser-config-runtime`, `plugin-sdk/browser-config-support`, `plugin-sdk/browser-control-auth`, `plugin-sdk/browser-node-runtime`, `plugin-sdk/browser-profiles`, `plugin-sdk/browser-security-runtime`, `plugin-sdk/browser-setup-tools`, `plugin-sdk/browser-support` | 内置 Browser 插件支持辅助函数。`browser-profiles` 导出 `resolveBrowserConfig`、`resolveProfile`、`ResolvedBrowserConfig`、`ResolvedBrowserProfile` 和 `ResolvedBrowserTabCleanupConfig`,用于规范化后的 `browser.tabCleanup` 结构。`browser-support` 仍然是兼容性 barrel。 | + | Matrix | `plugin-sdk/matrix`, `plugin-sdk/matrix-helper`, `plugin-sdk/matrix-runtime-heavy`, `plugin-sdk/matrix-runtime-shared`, `plugin-sdk/matrix-runtime-surface`, `plugin-sdk/matrix-surface`, `plugin-sdk/matrix-thread-bindings` | 内置的 Matrix 辅助/运行时接口 | + | Line | `plugin-sdk/line`, `plugin-sdk/line-core`, `plugin-sdk/line-runtime`, `plugin-sdk/line-surface` | 内置的 LINE 辅助/运行时接口 | + | IRC | `plugin-sdk/irc`, `plugin-sdk/irc-surface` | 内置的 IRC 辅助接口 | + | 渠道专用辅助函数 | `plugin-sdk/googlechat`, `plugin-sdk/zalouser`, `plugin-sdk/bluebubbles`, `plugin-sdk/bluebubbles-policy`, `plugin-sdk/mattermost`, `plugin-sdk/mattermost-policy`, `plugin-sdk/feishu-conversation`, `plugin-sdk/msteams`, `plugin-sdk/nextcloud-talk`, `plugin-sdk/nostr`, `plugin-sdk/tlon`, `plugin-sdk/twitch` | 内置的渠道兼容性/辅助接口 | + | 认证/插件专用辅助函数 | `plugin-sdk/github-copilot-login`, `plugin-sdk/github-copilot-token`, `plugin-sdk/diagnostics-otel`, `plugin-sdk/diagnostics-prometheus`, `plugin-sdk/diffs`, `plugin-sdk/llm-task`, `plugin-sdk/thread-ownership`, `plugin-sdk/voice-call` | 内置的功能/插件辅助接口;`plugin-sdk/github-copilot-token` 当前导出 `DEFAULT_COPILOT_API_BASE_URL`、`deriveCopilotApiBaseUrlFromToken` 和 `resolveCopilotApiToken` | diff --git a/docs/zh-CN/providers/lmstudio.md b/docs/zh-CN/providers/lmstudio.md index 9c49c6caf..1be2defab 100644 --- a/docs/zh-CN/providers/lmstudio.md +++ b/docs/zh-CN/providers/lmstudio.md @@ -1,19 +1,19 @@ --- read_when: - - 你想通过 LM Studio 使用开源模型运行 OpenClaw。 - - 你想设置并配置 LM Studio。 + - 你想通过 LM Studio 使用开源模型运行 OpenClaw + - 你想要设置并配置 LM Studio summary: 使用 LM Studio 运行 OpenClaw title: LM Studio x-i18n: - generated_at: "2026-04-27T07:21:11Z" + generated_at: "2026-04-27T08:01:18Z" model: gpt-5.4 provider: openai - source_hash: 0077108b7ab3171084f89234e25f5f5e8b68239a6fa6c11fa70c65f52d56670f + source_hash: 98edefa8b57ab2a89d1c4405827335a421c3157f51c5d23ac5f83c1cbeab20a9 source_path: providers/lmstudio.md workflow: 15 --- -LM Studio 是一款对用户友好且功能强大的应用,可让你在自己的硬件上运行开放权重模型。它支持运行 llama.cpp(GGUF)或 MLX 模型(Apple Silicon)。提供 GUI 安装包,也提供无头守护进程(`llmster`)。产品和设置文档请参阅 [lmstudio.ai](https://lmstudio.ai/)。 +LM Studio 是一款友好且功能强大的应用,可让你在自己的硬件上运行开放权重模型。它支持运行 llama.cpp(GGUF)或 MLX 模型(Apple Silicon)。既提供 GUI 应用,也提供无头守护进程(`llmster`)。产品和设置文档请参见 [lmstudio.ai](https://lmstudio.ai/)。 ## 快速开始 @@ -25,7 +25,7 @@ curl -fsSL https://lmstudio.ai/install.sh | bash 2. 启动服务器 -确保你已经启动桌面应用,或使用以下命令运行守护进程: +请确保你已启动桌面应用,或者使用以下命令运行守护进程: ```bash lms daemon up @@ -35,17 +35,17 @@ lms daemon up lms server start --port 1234 ``` -如果你使用的是应用,请确保已启用 JIT,以获得流畅的体验。详情请参阅 [LM Studio JIT and TTL guide](https://lmstudio.ai/docs/developer/core/ttl-and-auto-evict)。 +如果你使用的是应用,请确保已启用 JIT,以获得更流畅的体验。更多信息请参见 [LM Studio JIT and TTL guide](https://lmstudio.ai/docs/developer/core/ttl-and-auto-evict)。 -3. 如果已启用 LM Studio 身份验证,请设置 `LM_API_TOKEN`: +3. 如果已启用 LM Studio 认证,请设置 `LM_API_TOKEN`: ```bash export LM_API_TOKEN="your-lm-studio-api-token" ``` -如果 LM Studio 身份验证已禁用,你可以在交互式 OpenClaw 设置期间将 API 密钥留空。 +如果 LM Studio 认证已禁用,则在交互式 OpenClaw 设置期间,你可以将 API 密钥留空。 -有关 LM Studio 身份验证设置的详细信息,请参阅 [LM Studio Authentication](https://lmstudio.ai/docs/developer/core/authentication)。 +有关 LM Studio 认证设置的详细信息,请参见 [LM Studio Authentication](https://lmstudio.ai/docs/developer/core/authentication)。 4. 运行新手引导并选择 `LM Studio`: @@ -61,11 +61,12 @@ openclaw onboard openclaw models set lmstudio/qwen/qwen3.5-9b ``` -LM Studio 模型键遵循 `author/model-name` 格式(例如 `qwen/qwen3.5-9b`)。OpenClaw 模型引用会在前面加上提供商名称:`lmstudio/qwen/qwen3.5-9b`。你可以运行 `curl http://localhost:1234/api/v1/models` 并查看 `key` 字段,以找到某个模型的准确键名。 +LM Studio 模型键采用 `author/model-name` 格式(例如 `qwen/qwen3.5-9b`)。OpenClaw +模型引用会加上提供商名前缀:`lmstudio/qwen/qwen3.5-9b`。你可以通过运行 `curl http://localhost:1234/api/v1/models` 并查看 `key` 字段,找到某个模型的精确键名。 ## 非交互式新手引导 -当你想通过脚本完成设置时(CI、预配、远程引导),请使用非交互式新手引导: +如果你想通过脚本完成设置(CI、预配、远程引导初始化),请使用非交互式新手引导: ```bash openclaw onboard \ @@ -74,7 +75,7 @@ openclaw onboard \ --auth-choice lmstudio ``` -或者指定基础 URL、模型和可选的 API 密钥: +或者指定 base URL、模型和可选 API 密钥: ```bash openclaw onboard \ @@ -86,28 +87,30 @@ openclaw onboard \ --custom-model-id qwen/qwen3.5-9b ``` -`--custom-model-id` 接受 LM Studio 返回的模型键(例如 `qwen/qwen3.5-9b`),不包含 `lmstudio/` 提供商前缀。 +`--custom-model-id` 接收 LM Studio 返回的模型键(例如 `qwen/qwen3.5-9b`),不包含 +`lmstudio/` 提供商前缀。 -对于启用了身份验证的 LM Studio 服务器,请传入 `--lmstudio-api-key` 或设置 `LM_API_TOKEN`。 -对于未启用身份验证的 LM Studio 服务器,请省略该密钥;OpenClaw 会存储一个本地的非机密标记。 +对于启用了认证的 LM Studio 服务器,请传入 `--lmstudio-api-key` 或设置 `LM_API_TOKEN`。 +对于未启用认证的 LM Studio 服务器,请省略该密钥;OpenClaw 会存储一个本地非机密标记。 -出于兼容性考虑,`--custom-api-key` 仍然受支持,但对于 LM Studio,优先使用 `--lmstudio-api-key`。 +`--custom-api-key` 仍然支持以保持兼容性,但对于 LM Studio,更推荐使用 `--lmstudio-api-key`。 这会写入 `models.providers.lmstudio`,并将默认模型设置为 `lmstudio/`。当你提供 API 密钥时,设置还会写入 -`lmstudio:default` 身份验证配置文件。 +`lmstudio:default` 认证配置文件。 -交互式设置可以提示输入一个可选的首选加载上下文长度,并将其应用到发现到的、保存进配置中的所有 LM Studio 模型。 +交互式设置可以提示输入一个可选的首选加载上下文长度,并将其应用到保存进配置中的已发现 LM Studio 模型。 +LM Studio 插件配置会信任为模型请求所配置的 LM Studio 端点,包括 loopback、LAN 和 tailnet 主机。你可以通过设置 `models.providers.lmstudio.request.allowPrivateNetwork: false` 选择退出。 ## 配置 -### 流式传输用量兼容性 +### 流式传输 usage 兼容性 -LM Studio 兼容流式传输用量统计。当它没有输出符合 OpenAI 形状的 +LM Studio 与流式 usage 兼容。当它未发出 OpenAI 形状的 `usage` 对象时,OpenClaw 会改为从 llama.cpp 风格的 `timings.prompt_n` / `timings.predicted_n` 元数据中恢复 token 计数。 -相同行为也适用于这些兼容 OpenAI 的本地后端: +同样的行为也适用于这些兼容 OpenAI 的本地后端: - vLLM - SGLang @@ -148,30 +151,51 @@ LM Studio 兼容流式传输用量统计。当它没有输出符合 OpenAI 形 ### 未检测到 LM Studio -请确认 LM Studio 正在运行。如果已启用身份验证,还要设置 `LM_API_TOKEN`: +请确保 LM Studio 正在运行。如果启用了认证,还要设置 `LM_API_TOKEN`: ```bash # 通过桌面应用启动,或以无头方式启动: lms server start --port 1234 ``` -确认 API 可访问: +验证 API 是否可访问: ```bash curl http://localhost:1234/api/v1/models ``` -### 身份验证错误(HTTP 401) +### 认证错误(HTTP 401) 如果设置报告 HTTP 401,请验证你的 API 密钥: -- 检查 `LM_API_TOKEN` 是否与 LM Studio 中配置的密钥匹配。 -- 有关 LM Studio 身份验证设置的详细信息,请参阅 [LM Studio Authentication](https://lmstudio.ai/docs/developer/core/authentication)。 -- 如果你的服务器不需要身份验证,请在设置期间将密钥留空。 +- 检查 `LM_API_TOKEN` 是否与你在 LM Studio 中配置的密钥一致。 +- 有关 LM Studio 认证设置的详细信息,请参见 [LM Studio Authentication](https://lmstudio.ai/docs/developer/core/authentication)。 +- 如果你的服务器不要求认证,请在设置期间将密钥留空。 ### 即时模型加载 -LM Studio 支持即时(JIT)模型加载,即模型会在第一次请求时加载。请确保已启用此功能,以避免出现“Model not loaded”错误。 +LM Studio 支持即时(JIT)模型加载,即模型会在首次请求时加载。请确保已启用此功能,以避免出现“Model not loaded”错误。 + +### LAN 或 tailnet LM Studio 主机 + +请使用 LM Studio 主机的可访问地址,保留 `/v1`,并确保该机器上的 LM Studio 绑定到了 loopback 之外的地址: + +```json5 +{ + models: { + providers: { + lmstudio: { + baseUrl: "http://gpu-box.local:1234/v1", + apiKey: "lmstudio", + api: "openai-completions", + models: [{ id: "qwen/qwen3.5-9b" }], + }, + }, + }, +} +``` + +与通用的兼容 OpenAI 提供商不同,`lmstudio` 会自动信任其为受保护模型请求所配置的本地/私有端点。如果你使用的是自定义提供商 id 而不是 `lmstudio`,请显式设置 `models.providers..request.allowPrivateNetwork: true`。 ## 相关内容