diff --git a/docs/zh-CN/cli/node.md b/docs/zh-CN/cli/node.md index c6c02bc6b..2a2e727ed 100644 --- a/docs/zh-CN/cli/node.md +++ b/docs/zh-CN/cli/node.md @@ -5,39 +5,40 @@ read_when: summary: '`openclaw node` 的 CLI 参考(无头节点主机)' title: 节点 x-i18n: - generated_at: "2026-04-24T05:21:41Z" + generated_at: "2026-04-24T06:43:56Z" model: gpt-5.4 provider: openai - source_hash: 61b16bdd0c52115bc9938a0fc975369159a4e45d743173ab4e65fce8292af51e + source_hash: 9f2bd6d61ee87d36f7691207d03a91c914e6460549256e0cc6ea7bebfa713923 source_path: cli/node.md workflow: 15 --- # `openclaw node` -运行一个**无头节点主机**,连接到 Gateway 网关 WebSocket,并在此机器上公开 +运行一个**无头节点主机**,连接到 Gateway 网关 WebSocket,并在这台机器上暴露 `system.run` / `system.which`。 ## 为什么要使用节点主机? -当你希望智能体能够**在网络中的其他机器上运行命令**,而又不想在那些机器上安装完整的 macOS 配套应用时,可以使用节点主机。 +当你希望智能体能够**在网络中的其他机器上运行命令**,而又不想在那里安装完整的 macOS 配套应用时,可以使用节点主机。 常见用例: - 在远程 Linux/Windows 机器上运行命令(构建服务器、实验室机器、NAS)。 -- 将 exec 保持在 Gateway 网关上的**沙箱隔离**状态,同时把已批准的执行委托给其他主机。 -- 为自动化或 CI 节点提供一个轻量级、无头的执行目标。 +- 将 exec 保持在 Gateway 网关上**沙箱隔离**,但把已批准的运行委派给其他主机。 +- 为自动化或 CI 节点提供轻量级、无头的执行目标。 -执行仍然受**exec 批准**和节点主机上按智能体划分的允许列表保护,因此你可以将命令访问范围保持为受限且明确。 +执行仍然受到**exec 批准**和节点主机上按智能体划分的允许列表保护,因此你可以让命令访问保持在明确且受限的范围内。 ## 浏览器代理(零配置) -如果节点上的 `browser.enabled` 未被禁用,节点主机会自动公布一个浏览器代理。这样,智能体无需额外配置即可在该节点上使用浏览器自动化。 +如果节点上的 `browser.enabled` 未被禁用,节点主机会自动公布一个浏览器代理。这样一来,智能体无需额外配置即可在该节点上使用浏览器自动化。 -默认情况下,该代理会公开节点的常规浏览器配置文件界面。如果你设置了 `nodeHost.browserProxy.allowProfiles`,该代理将变为受限模式: -不在允许列表中的配置文件目标会被拒绝,并且通过代理会阻止持久化配置文件的创建/删除路由。 +默认情况下,该代理会暴露节点的常规浏览器配置文件表面。如果你设置了 +`nodeHost.browserProxy.allowProfiles`,代理将变为受限模式: +不在允许列表中的配置文件目标会被拒绝,并且通过该代理会阻止持久化配置文件的创建/删除路由。 -如有需要,可在节点上禁用它: +如有需要,可在节点上将其禁用: ```json5 { @@ -66,17 +67,18 @@ openclaw node run --host --port 18789 ## 节点主机的 Gateway 网关认证 -`openclaw node run` 和 `openclaw node install` 会从配置/环境变量中解析 Gateway 网关认证信息(节点命令上没有 `--token`/`--password` 标志): +`openclaw node run` 和 `openclaw node install` 会从配置/环境变量中解析 Gateway 网关认证信息(节点命令不支持 `--token`/`--password` 标志): - 首先检查 `OPENCLAW_GATEWAY_TOKEN` / `OPENCLAW_GATEWAY_PASSWORD`。 - 然后回退到本地配置:`gateway.auth.token` / `gateway.auth.password`。 -- 在本地模式下,节点主机不会刻意继承 `gateway.remote.token` / `gateway.remote.password`。 -- 如果通过 SecretRef 显式配置了 `gateway.auth.token` / `gateway.auth.password` 但未能解析,节点认证解析会以失败关闭的方式处理(不会用远程回退来掩盖问题)。 -- 在 `gateway.mode=remote` 中,远程客户端字段(`gateway.remote.token` / `gateway.remote.password`)也会根据远程优先级规则纳入候选。 -- 节点主机认证解析只接受 `OPENCLAW_GATEWAY_*` 环境变量。 +- 在本地模式下,节点主机有意不继承 `gateway.remote.token` / `gateway.remote.password`。 +- 如果通过 SecretRef 显式配置了 `gateway.auth.token` / `gateway.auth.password` 但未能解析,节点认证解析会以关闭方式失败(不会使用远程回退来掩盖问题)。 +- 在 `gateway.mode=remote` 下,远程客户端字段(`gateway.remote.token` / `gateway.remote.password`)也会按照远程优先级规则参与解析。 +- 节点主机认证解析仅识别 `OPENCLAW_GATEWAY_*` 环境变量。 -对于连接到受信任私有网络中非 loopback `ws://` Gateway 网关的节点,请设置 `OPENCLAW_ALLOW_INSECURE_PRIVATE_WS=1`。如果不设置,节点启动将以失败关闭的方式终止,并提示你使用 `wss://`、SSH 隧道或 Tailscale。 -`openclaw node install` 会将此显式启用项持久化到受监管的节点服务中。 +对于要连接到受信任私有网络中非 loopback `ws://` Gateway 网关的节点,请设置 `OPENCLAW_ALLOW_INSECURE_PRIVATE_WS=1`。如果不设置,节点启动将以关闭方式失败,并提示你使用 `wss://`、SSH 隧道或 Tailscale。 +这是进程环境级别的显式启用项,不是 `openclaw.json` 配置键。 +当它存在于安装命令环境中时,`openclaw node install` 会将其持久化到受监管的节点服务中。 ## 服务(后台) @@ -95,9 +97,9 @@ openclaw node install --host --port 18789 - `--node-id `:覆盖节点 id(会清除配对令牌) - `--display-name `:覆盖节点显示名称 - `--runtime `:服务运行时(`node` 或 `bun`) -- `--force`:如果已安装,则重新安装/覆盖 +- `--force`:如果已安装则重新安装/覆盖 -管理该服务: +管理服务: ```bash openclaw node status @@ -106,24 +108,24 @@ openclaw node restart openclaw node uninstall ``` -如需前台节点主机(非服务),请使用 `openclaw node run`。 +如需前台运行的节点主机(非服务),请使用 `openclaw node run`。 -服务命令接受 `--json`,用于机器可读输出。 +服务命令支持 `--json`,用于机器可读输出。 ## 配对 -首次连接会在 Gateway 网关上创建一个待处理的设备配对请求(`role: node`)。 -可通过以下方式批准: +第一次连接会在 Gateway 网关上创建一个待处理的设备配对请求(`role: node`)。 +通过以下命令批准: ```bash openclaw devices list openclaw devices approve ``` -如果节点在认证细节(角色/作用域/公钥)发生变化后重试配对,之前待处理的请求会被新请求取代,并创建新的 `requestId`。 -批准前请再次运行 `openclaw devices list`。 +如果节点在认证详情发生变化(角色/作用域/公钥)后重试配对,之前的待处理请求会被替代,并创建新的 `requestId`。 +请在批准前再次运行 `openclaw devices list`。 -节点主机会将其节点 id、令牌、显示名称和 Gateway 网关连接信息存储在 +节点主机会将其节点 id、令牌、显示名称以及 Gateway 网关连接信息存储在 `~/.openclaw/node.json` 中。 ## Exec 批准 @@ -135,9 +137,9 @@ openclaw devices approve - `openclaw approvals --node `(从 Gateway 网关编辑) 对于已批准的异步节点 exec,OpenClaw 会在提示前准备规范化的 `systemRunPlan`。 -之后转发的已批准 `system.run` 会复用该已存储的计划,因此在批准请求创建后,对命令/cwd/session 字段的编辑会被拒绝,而不是改变节点实际执行的内容。 +之后被批准的 `system.run` 转发会复用该已存储的计划,因此在批准请求创建之后对命令/cwd/session 字段的编辑将被拒绝,而不是改变节点实际执行的内容。 -## 相关内容 +## 相关 - [CLI 参考](/zh-CN/cli) - [节点](/zh-CN/nodes) diff --git a/docs/zh-CN/cli/onboard.md b/docs/zh-CN/cli/onboard.md index 8d0209981..bf6fc9372 100644 --- a/docs/zh-CN/cli/onboard.md +++ b/docs/zh-CN/cli/onboard.md @@ -1,13 +1,13 @@ --- read_when: - - 你希望通过引导式设置完成 gateway、工作区、认证、渠道和 Skills 的配置 + - 你希望通过引导式设置来配置 Gateway 网关、工作区、凭证、渠道和 Skills summary: '`openclaw onboard` 的 CLI 参考(交互式新手引导)' title: 新手引导 x-i18n: - generated_at: "2026-04-23T20:44:32Z" + generated_at: "2026-04-24T06:43:47Z" model: gpt-5.4 provider: openai - source_hash: ab92ff5651b7db18850558cbb47527bf0486f278c8aed0929eaeff0017b6c280 + source_hash: c1959ad7014b891230e497a2e0ab494ba316090c81629f25b8147614b694ead5 source_path: cli/onboard.md workflow: 15 --- @@ -18,11 +18,11 @@ x-i18n: ## 相关指南 -- CLI 新手引导总览:[新手引导(CLI)](/zh-CN/start/wizard) +- CLI 新手引导中心:[设置向导(CLI)](/zh-CN/start/wizard) - 新手引导概览:[新手引导概览](/zh-CN/start/onboarding-overview) - CLI 新手引导参考:[CLI 设置参考](/zh-CN/start/wizard-cli-reference) - CLI 自动化:[CLI 自动化](/zh-CN/start/wizard-cli-automation) -- macOS 新手引导:[新手引导(macOS App)](/zh-CN/start/onboarding) +- macOS 新手引导:[新手引导(macOS 应用)](/zh-CN/start/onboarding) ## 示例 @@ -35,8 +35,10 @@ openclaw onboard --mode remote --remote-url wss://gateway-host:18789 对于明文私有网络 `ws://` 目标(仅限受信任网络),请在新手引导进程环境中设置 `OPENCLAW_ALLOW_INSECURE_PRIVATE_WS=1`。 +此客户端传输层紧急开关 +没有对应的 `openclaw.json` 等效项。 -非交互式自定义 provider: +非交互式自定义提供商: ```bash openclaw onboard --non-interactive \ @@ -48,9 +50,9 @@ openclaw onboard --non-interactive \ --custom-compatibility openai ``` -在非交互模式下,`--custom-api-key` 是可选的。如果省略,新手引导会检查 `CUSTOM_API_KEY`。 +在非交互式模式下,`--custom-api-key` 是可选的。如果省略,新手引导会检查 `CUSTOM_API_KEY`。 -LM Studio 在非交互模式下也支持 provider 专用密钥标志: +LM Studio 在非交互式模式下也支持提供商专用的密钥标志: ```bash openclaw onboard --non-interactive \ @@ -71,9 +73,9 @@ 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 在这里也可用。 -将 provider 密钥存储为引用而不是明文: +将提供商密钥存储为引用而不是明文: ```bash openclaw onboard --non-interactive \ @@ -83,25 +85,25 @@ openclaw onboard --non-interactive \ ``` 使用 `--secret-input-mode ref` 时,新手引导会写入由环境变量支持的引用,而不是明文密钥值。 -对于基于 auth-profile 的 providers,这会写入 `keyRef` 条目;对于自定义 providers,这会将 `models.providers..apiKey` 写为环境变量引用(例如 `{ source: "env", provider: "default", id: "CUSTOM_API_KEY" }`)。 +对于基于 auth-profile 的提供商,这会写入 `keyRef` 条目;对于自定义提供商,这会将 `models.providers..apiKey` 写为环境变量引用(例如 `{ source: "env", provider: "default", id: "CUSTOM_API_KEY" }`)。 -非交互式 `ref` 模式契约: +非交互式 `ref` 模式约定: -- 在新手引导进程环境中设置 provider 环境变量(例如 `OPENAI_API_KEY`)。 -- 不要传递内联密钥标志(例如 `--openai-api-key`),除非该环境变量也已设置。 -- 如果传递了内联密钥标志但缺少所需环境变量,新手引导会快速失败并给出指引。 +- 在新手引导进程环境中设置提供商环境变量(例如 `OPENAI_API_KEY`)。 +- 不要传递内联密钥标志(例如 `--openai-api-key`),除非同时设置了该环境变量。 +- 如果传递了内联密钥标志但未设置所需环境变量,新手引导会快速失败并给出指引。 -非交互模式下的 Gateway 网关 token 选项: +非交互式模式下的 Gateway 网关令牌选项: -- `--gateway-auth token --gateway-token ` 存储明文 token。 +- `--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` 使用时,当 token 认证要求 token 时,由 SecretRef 管理的 Gateway 网关 token 会被验证,但不会以已解析的明文形式持久化到 supervisor 服务环境元数据中。 -- 配合 `--install-daemon` 使用时,如果 token 模式要求 token,且配置的 token 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`。 示例: @@ -117,24 +119,24 @@ openclaw onboard --non-interactive \ 非交互式本地 Gateway 网关健康检查: -- 除非你传递 `--skip-health`,否则新手引导会在本地 Gateway 网关可连接之前一直等待,只有成功后才退出。 -- `--install-daemon` 会先启动受管理的 Gateway 网关安装路径。如果不使用它,你必须已经运行本地 Gateway 网关,例如 `openclaw gateway run`。 -- 如果你在自动化中只想写入配置/工作区/引导文件,请使用 `--skip-health`。 -- 在原生 Windows 上,`--install-daemon` 会先尝试 Scheduled Tasks;如果任务创建被拒绝,则回退到每用户 Startup 文件夹登录项。 +- 除非你传递 `--skip-health`,否则新手引导会等待本地 Gateway 网关可达后才成功退出。 +- `--install-daemon` 会先启动托管式 Gateway 网关安装路径。如果不使用它,你必须已经有一个正在运行的本地 Gateway 网关,例如 `openclaw gateway run`。 +- 如果你只想在自动化中写入配置 / 工作区 / 引导初始内容,请使用 `--skip-health`。 +- 在原生 Windows 上,`--install-daemon` 会先尝试使用计划任务;如果任务创建被拒绝,则回退到每用户 Startup 文件夹登录项。 -启用引用模式时的交互式新手引导行为: +使用引用模式时的交互式新手引导行为: -- 出现提示时选择**使用 secret reference**。 -- 然后选择以下之一: - - 环境变量 +- 出现提示时,选择 **Use secret reference**。 +- 然后选择以下其中一项: + - Environment variable - 已配置的 secret provider(`file` 或 `exec`) -- 新手引导会在保存引用前执行快速预检验证。 - - 如果验证失败,新手引导会显示错误并允许你重试。 +- 新手引导会在保存引用前执行快速预检校验。 + - 如果校验失败,新手引导会显示错误并允许你重试。 -非交互式 Z.AI 端点选项: +非交互式 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 # 无提示端点选择 @@ -158,17 +160,16 @@ openclaw onboard --non-interactive \ 流程说明: -- `quickstart`:最少提示,自动生成 gateway token。 -- `manual`:针对 port/bind/auth 提供完整提示(`advanced` 的别名)。 -- 当某个认证选项暗示首选 provider 时,新手引导会将默认模型和允许列表选择器预过滤到该 provider。对于 Volcengine 和 BytePlus(国际版),这也会匹配 coding-plan 变体 - (`volcengine-plan/*`、`byteplus-plan/*`)。 -- 如果首选 provider 过滤后尚未得到任何已加载模型,新手引导会回退到未过滤目录,而不是让选择器保持为空。 -- 在网页搜索步骤中,某些 providers 可能触发 provider 专用的后续提示: - - **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,无需设置渠道)。 -- 自定义 Provider:连接任意兼容 OpenAI 或 Anthropic 的端点,包括未列出的托管 provider。使用 Unknown 进行自动检测。 +- `quickstart`:最少提示,自动生成 Gateway 网关令牌。 +- `manual`:提供端口 / 绑定 / 认证的完整提示(`advanced` 的别名)。 +- 当某个认证选项隐含首选提供商时,新手引导会将默认模型和 allowlist 选择器预先筛选到该提供商。对于 Volcengine 和 BytePlus(国际版),这也会匹配 coding-plan 变体(`volcengine-plan/*`、`byteplus-plan/*`)。 +- 如果首选提供商筛选后尚未产生任何已加载模型,新手引导会回退到未筛选目录,而不是让选择器保持为空。 +- 在 web-search 步骤中,某些提供商可能会触发提供商专属的后续提示: + - **Grok** 可能会提供可选的 `x_search` 设置,使用同一个 `XAI_API_KEY` 和一个 `x_search` 模型选择。 + - **Kimi** 可能会询问 Moonshot AI API 区域(`api.moonshot.ai` 或 `api.moonshot.cn`)以及默认的 Kimi web-search 模型。 +- 本地新手引导的私信范围行为:[CLI 设置参考](/zh-CN/start/wizard-cli-reference#outputs-and-internals)。 +- 最快开始第一次聊天:`openclaw dashboard`(控制 UI,无需设置渠道)。 +- 自定义提供商:连接任何兼容 OpenAI 或 Anthropic 的端点,包括未列出的托管提供商。使用 Unknown 可自动检测。 ## 常见后续命令 @@ -178,5 +179,5 @@ openclaw agents add ``` -`--json` 不代表非交互模式。脚本中请使用 `--non-interactive`。 +`--json` 并不表示非交互式模式。脚本中请使用 `--non-interactive`。 diff --git a/docs/zh-CN/gateway/configuration-reference.md b/docs/zh-CN/gateway/configuration-reference.md index 9f033f060..a31637c53 100644 --- a/docs/zh-CN/gateway/configuration-reference.md +++ b/docs/zh-CN/gateway/configuration-reference.md @@ -2,32 +2,32 @@ read_when: - 你需要精确到字段级别的配置语义或默认值 - 你正在验证渠道、模型、Gateway 网关或工具配置块 -summary: OpenClaw 核心配置键、默认值及专用子系统参考链接的 Gateway 网关配置参考 +summary: Gateway 网关配置参考,涵盖核心 OpenClaw 键名、默认值,以及指向专用子系统参考文档的链接 title: 配置参考 x-i18n: - generated_at: "2026-04-24T04:02:19Z" + generated_at: "2026-04-24T06:43:47Z" model: gpt-5.4 provider: openai - source_hash: 6dc3b920ada38951086908713e9347141d8b11faa007df23a90a2532ac6f3bb2 + source_hash: dc0d9feea2f2707f267d50ec83aa664ef503db8f9132762345cc80305f8bef73 source_path: gateway/configuration-reference.md workflow: 15 --- -`~/.openclaw/openclaw.json` 的核心配置参考。若需面向任务的概览,请参阅[配置](/zh-CN/gateway/configuration)。 +`~/.openclaw/openclaw.json` 的核心配置参考。若需按任务查看的概览,请参见 [Configuration](/zh-CN/gateway/configuration)。 -本页涵盖 OpenClaw 的主要配置能力,并在某个子系统拥有更深入的独立参考时提供跳转链接。它**不会**尝试在单个页面中内联每个由渠道/插件拥有的命令目录,或每个深层记忆/QMD 调节项。 +本页涵盖 OpenClaw 的主要配置面,并在某个子系统有自己更深入的参考文档时提供跳转链接。它**不会**尝试在单页中内联每个渠道 / 插件自有的命令目录,也不会包含每个深层 memory/QMD 旋钮。 -代码真相: +代码真实来源: -- `openclaw config schema` 会打印用于验证和 Control UI 的实时 JSON Schema,并在可用时合并内置/插件/渠道元数据 -- `config.schema.lookup` 会返回一个按路径限定的 schema 节点,供下钻工具使用 -- `pnpm config:docs:check` / `pnpm config:docs:gen` 会根据当前 schema 能力验证配置文档基线哈希 +- `openclaw config schema` 会打印用于验证和 Control UI 的实时 JSON Schema,并在可用时合并内置 / 插件 / 渠道元数据 +- `config.schema.lookup` 返回一个按路径作用域划分的 schema 节点,供深入查看工具使用 +- `pnpm config:docs:check` / `pnpm config:docs:gen` 会根据当前 schema 表面校验配置文档基线哈希 -专门的深度参考: +专用深度参考: -- [记忆配置参考](/zh-CN/reference/memory-config),适用于 `agents.defaults.memorySearch.*`、`memory.qmd.*`、`memory.citations` 以及位于 `plugins.entries.memory-core.config.dreaming` 下的 dreaming 配置 -- [斜杠命令](/zh-CN/tools/slash-commands),查看当前内置 + 内置打包命令目录 -- 各自所属的渠道/插件页面,用于查看渠道专属命令能力 +- [Memory configuration reference](/zh-CN/reference/memory-config),适用于 `agents.defaults.memorySearch.*`、`memory.qmd.*`、`memory.citations`,以及位于 `plugins.entries.memory-core.config.dreaming` 下的 dreaming 配置 +- [Slash Commands](/zh-CN/tools/slash-commands),查看当前内置 + 内置插件命令目录 +- 各所属渠道 / 插件页面,查看渠道专属命令面 配置格式为 **JSON5**(允许注释和尾随逗号)。所有字段都是可选的——省略时,OpenClaw 会使用安全默认值。 @@ -35,28 +35,28 @@ x-i18n: ## 渠道 -各渠道配置键已移至独立页面——请参阅 -[配置——渠道](/zh-CN/gateway/config-channels),了解 `channels.*`, -包括 Slack、Discord、Telegram、WhatsApp、Matrix、iMessage 及其他 +每个渠道的配置键已迁移到专用页面——请参见 +[Configuration — channels](/zh-CN/gateway/config-channels) 了解 `channels.*`, +包括 Slack、Discord、Telegram、WhatsApp、Matrix、iMessage 以及其他 内置渠道(认证、访问控制、多账号、提及门控)。 -## 智能体默认值、多智能体、会话与消息 +## 智能体默认值、多智能体、会话和消息 -已移至独立页面——请参阅 -[配置——智能体](/zh-CN/gateway/config-agents),了解: +已迁移到专用页面——请参见 +[Configuration — agents](/zh-CN/gateway/config-agents) 了解: - `agents.defaults.*`(工作区、模型、思考、心跳、记忆、媒体、Skills、沙箱) - `multiAgent.*`(多智能体路由和绑定) -- `session.*`(会话生命周期、压缩、清理) +- `session.*`(会话生命周期、压缩、修剪) - `messages.*`(消息投递、TTS、Markdown 渲染) - `talk.*`(Talk 模式) - - `talk.silenceTimeoutMs`:未设置时,Talk 会在发送转录内容前保留平台默认的停顿窗口(`macOS 和 Android 为 700 ms,iOS 为 900 ms`) + - `talk.silenceTimeoutMs`:未设置时,Talk 会在发送转录内容前保持平台默认的停顿窗口(`macOS 和 Android 为 700 ms,iOS 为 900 ms`) ## 工具和自定义提供商 工具策略、实验性开关、提供商支持的工具配置,以及自定义 -提供商 / base-URL 设置已移至独立页面——请参阅 -[配置——工具和自定义提供商](/zh-CN/gateway/config-tools)。 +提供商 / 基础 URL 设置已迁移到专用页面——请参见 +[Configuration — tools and custom providers](/zh-CN/gateway/config-tools)。 ## Skills @@ -83,12 +83,12 @@ x-i18n: } ``` -- `allowBundled`:仅针对内置 Skills 的可选允许列表(不影响托管/工作区 Skills)。 -- `load.extraDirs`:额外的共享 Skills 根目录(最低优先级)。 -- `install.preferBrew`:为 true 时,如果 `brew` 可用,则优先使用 Homebrew 安装器,之后才回退到其他安装器类型。 -- `install.nodeManager`:用于 `metadata.openclaw.install` 规范的 Node 安装器偏好(`npm` | `pnpm` | `yarn` | `bun`)。 -- `entries..enabled: false`:即使某个 Skill 已内置/已安装,也会禁用它。 -- `entries..apiKey`:为声明了主环境变量的 Skills 提供的便捷字段(明文字符串或 SecretRef 对象)。 +- `allowBundled`:仅对内置 skills 生效的可选允许列表(托管 / 工作区 skills 不受影响)。 +- `load.extraDirs`:额外的共享 skill 根目录(最低优先级)。 +- `install.preferBrew`:为 `true` 时,若 `brew` 可用,则优先使用 Homebrew 安装器,再回退到其他安装器类型。 +- `install.nodeManager`:用于 `metadata.openclaw.install` 规范的 Node 安装器优先项(`npm` | `pnpm` | `yarn` | `bun`)。 +- `entries..enabled: false`:即使某个 skill 已内置 / 已安装,也会禁用它。 +- `entries..apiKey`:为声明了主环境变量的 skills 提供的便捷字段(明文字符串或 SecretRef 对象)。 --- @@ -117,42 +117,42 @@ x-i18n: ``` - 从 `~/.openclaw/extensions`、`/.openclaw/extensions` 以及 `plugins.load.paths` 加载。 -- 发现过程接受原生 OpenClaw 插件,以及兼容的 Codex bundle 和 Claude bundle,包括无 manifest 的 Claude 默认布局 bundle。 +- 设备发现接受原生 OpenClaw 插件,以及兼容的 Codex bundle 和 Claude bundle,包括无 manifest 的 Claude 默认布局 bundle。 - **配置变更需要重启 Gateway 网关。** -- `allow`:可选允许列表(仅加载列出的插件)。`deny` 优先。 -- `plugins.entries..apiKey`:插件级 API key 便捷字段(插件支持时可用)。 +- `allow`:可选允许列表(仅加载列出的插件)。`deny` 优先生效。 +- `plugins.entries..apiKey`:插件级 API 密钥便捷字段(插件支持时可用)。 - `plugins.entries..env`:插件作用域的环境变量映射。 -- `plugins.entries..hooks.allowPromptInjection`:当为 `false` 时,核心会阻止 `before_prompt_build`,并忽略旧版 `before_agent_start` 中会修改提示的字段,同时保留旧版 `modelOverride` 和 `providerOverride`。适用于原生插件 hook,以及受支持 bundle 提供的 hook 目录。 -- `plugins.entries..subagent.allowModelOverride`:显式信任该插件可为后台子智能体运行请求按次生效的 `provider` 和 `model` 覆盖。 -- `plugins.entries..subagent.allowedModels`:受信任子智能体覆盖可使用的规范 `provider/model` 目标可选允许列表。仅当你有意允许任意模型时才使用 `"*"`。 -- `plugins.entries..config`:插件定义的配置对象(在可用时由原生 OpenClaw 插件 schema 验证)。 -- `plugins.entries.firecrawl.config.webFetch`:Firecrawl web-fetch 提供商设置。 - - `apiKey`:Firecrawl API key(接受 SecretRef)。会回退到 `plugins.entries.firecrawl.config.webSearch.apiKey`、旧版 `tools.web.fetch.firecrawl.apiKey` 或 `FIRECRAWL_API_KEY` 环境变量。 - - `baseUrl`:Firecrawl API base URL(默认:`https://api.firecrawl.dev`)。 +- `plugins.entries..hooks.allowPromptInjection`:为 `false` 时,核心会阻止 `before_prompt_build`,并忽略旧版 `before_agent_start` 中会修改提示词的字段,同时保留旧版 `modelOverride` 和 `providerOverride`。适用于原生插件 hooks,以及受支持的 bundle 提供的 hook 目录。 +- `plugins.entries..subagent.allowModelOverride`:显式信任此插件,使其可为后台子智能体运行请求按次运行的 `provider` 和 `model` 覆盖。 +- `plugins.entries..subagent.allowedModels`:受信任子智能体覆盖的规范 `provider/model` 目标可选允许列表。仅当你明确想允许任意模型时才使用 `"*"`。 +- `plugins.entries..config`:插件定义的配置对象(若可用,则由原生 OpenClaw 插件 schema 验证)。 +- `plugins.entries.firecrawl.config.webFetch`:Firecrawl 网页抓取提供商设置。 + - `apiKey`:Firecrawl API 密钥(接受 SecretRef)。会回退到 `plugins.entries.firecrawl.config.webSearch.apiKey`、旧版 `tools.web.fetch.firecrawl.apiKey` 或 `FIRECRAWL_API_KEY` 环境变量。 + - `baseUrl`:Firecrawl API 基础 URL(默认:`https://api.firecrawl.dev`)。 - `onlyMainContent`:仅提取页面主体内容(默认:`true`)。 - - `maxAgeMs`:缓存的最大存活时间(毫秒)(默认:`172800000` / 2 天)。 - - `timeoutSeconds`:抓取请求超时时间(秒)(默认:`60`)。 + - `maxAgeMs`:缓存的最大保留时长,单位毫秒(默认:`172800000` / 2 天)。 + - `timeoutSeconds`:抓取请求超时,单位秒(默认:`60`)。 - `plugins.entries.xai.config.xSearch`:xAI X Search(Grok web search)设置。 - `enabled`:启用 X Search 提供商。 - `model`:用于搜索的 Grok 模型(例如 `"grok-4-1-fast"`)。 -- `plugins.entries.memory-core.config.dreaming`:记忆 Dreaming 设置。阶段和阈值请参阅 [Dreaming](/zh-CN/concepts/dreaming)。 - - `enabled`:Dreaming 总开关(默认 `false`)。 - - `frequency`:每次完整 Dreaming 扫描的 cron 频率(默认 `"0 3 * * *"`)。 +- `plugins.entries.memory-core.config.dreaming`:memory dreaming 设置。各阶段和阈值请参见 [Dreaming](/zh-CN/concepts/dreaming)。 + - `enabled`:dreaming 总开关(默认 `false`)。 + - `frequency`:每次完整 dreaming 扫描的 cron 频率(默认 `"0 3 * * *"`)。 - 阶段策略和阈值属于实现细节(不是面向用户的配置键)。 -- 完整记忆配置位于[记忆配置参考](/zh-CN/reference/memory-config): +- 完整 memory 配置位于 [Memory configuration reference](/zh-CN/reference/memory-config): - `agents.defaults.memorySearch.*` - `memory.backend` - `memory.citations` - `memory.qmd.*` - `plugins.entries.memory-core.config.dreaming` -- 已启用的 Claude bundle 插件也可以通过 `settings.json` 提供嵌入式 Pi 默认值;OpenClaw 会将其作为已净化的智能体设置应用,而不是作为原始 OpenClaw 配置补丁。 -- `plugins.slots.memory`:选择活动记忆插件 id,或设为 `"none"` 以禁用记忆插件。 -- `plugins.slots.contextEngine`:选择活动上下文引擎插件 id;默认是 `"legacy"`,除非你安装并选择了其他引擎。 +- 已启用的 Claude bundle 插件也可以通过 `settings.json` 提供内嵌的 Pi 默认值;OpenClaw 会将其作为清理后的智能体设置应用,而不是作为原始 OpenClaw 配置补丁。 +- `plugins.slots.memory`:选择当前启用的 memory 插件 id,或设为 `"none"` 以禁用 memory 插件。 +- `plugins.slots.contextEngine`:选择当前启用的 context engine 插件 id;默认值为 `"legacy"`,除非你安装并选择了其他引擎。 - `plugins.installs`:由 CLI 管理的安装元数据,供 `openclaw plugins update` 使用。 - 包含 `source`、`spec`、`sourcePath`、`installPath`、`version`、`resolvedName`、`resolvedVersion`、`resolvedSpec`、`integrity`、`shasum`、`resolvedAt`、`installedAt`。 - - 请将 `plugins.installs.*` 视为托管状态;优先使用 CLI 命令,而不是手动编辑。 + - 将 `plugins.installs.*` 视为托管状态;优先使用 CLI 命令,而不是手动编辑。 -参见 [插件](/zh-CN/tools/plugin)。 +参见 [Plugins](/zh-CN/tools/plugin)。 --- @@ -193,21 +193,28 @@ x-i18n: ``` - `evaluateEnabled: false` 会禁用 `act:evaluate` 和 `wait --fn`。 -- 未设置时,`ssrfPolicy.dangerouslyAllowPrivateNetwork` 为禁用,因此浏览器导航默认保持严格模式。 +- 未设置 `ssrfPolicy.dangerouslyAllowPrivateNetwork` 时,该项为禁用状态,因此浏览器导航默认保持严格。 - 仅当你明确可信任私有网络浏览器导航时,才设置 `ssrfPolicy.dangerouslyAllowPrivateNetwork: true`。 -- 在严格模式下,远程 CDP 配置文件端点(`profiles.*.cdpUrl`)在可达性/发现检查期间也受同样的私有网络阻止策略约束。 -- `ssrfPolicy.allowPrivateNetwork` 仍支持作为旧版别名使用。 -- 在严格模式下,使用 `ssrfPolicy.hostnameAllowlist` 和 `ssrfPolicy.allowedHostnames` 做显式例外配置。 -- 远程配置文件为仅附加模式(禁用启动/停止/重置)。 +- 在严格模式下,远程 CDP 配置项端点(`profiles.*.cdpUrl`)在可达性 / 设备发现检查期间也会受到相同的私有网络阻止策略约束。 +- `ssrfPolicy.allowPrivateNetwork` 仍作为旧版别名受支持。 +- 在严格模式下,使用 `ssrfPolicy.hostnameAllowlist` 和 `ssrfPolicy.allowedHostnames` 来添加显式例外。 +- 远程配置项为仅附加模式(禁用 start/stop/reset)。 - `profiles.*.cdpUrl` 接受 `http://`、`https://`、`ws://` 和 `wss://`。 - 当你希望 OpenClaw 发现 `/json/version` 时,使用 HTTP(S);当提供商直接给出 DevTools WebSocket URL 时,使用 WS(S)。 -- `existing-session` 配置文件使用 Chrome MCP 而不是 CDP,并且可以附加到选定主机上,或通过已连接的浏览器节点附加。 -- `existing-session` 配置文件可以设置 `userDataDir`,以定位特定的 Chromium 系浏览器配置文件,例如 Brave 或 Edge。 -- `existing-session` 配置文件保留当前 Chrome MCP 路由限制:使用 snapshot/ref 驱动操作而非 CSS 选择器定位、单文件上传 hook、不支持对话框超时覆盖、不支持 `wait --load networkidle`,以及不支持 `responsebody`、PDF 导出、下载拦截或批量操作。 -- 本地受管的 `openclaw` 配置文件会自动分配 `cdpPort` 和 `cdpUrl`;只有远程 CDP 才需要显式设置 `cdpUrl`。 -- 自动检测顺序:默认浏览器(如果是 Chromium 系)→ Chrome → Brave → Edge → Chromium → Chrome Canary。 + 当你希望 OpenClaw 发现 `/json/version` 时,请使用 HTTP(S); + 当你的提供商直接给出 DevTools WebSocket URL 时,请使用 WS(S)。 +- `existing-session` 配置项使用 Chrome MCP 而不是 CDP,并且可以附加到 + 所选主机上,或通过已连接的浏览器节点附加。 +- `existing-session` 配置项可设置 `userDataDir`,以指定特定的 + 基于 Chromium 的浏览器配置,例如 Brave 或 Edge。 +- `existing-session` 配置项保留当前的 Chrome MCP 路由限制: + 使用 snapshot/ref 驱动的操作,而不是 CSS 选择器定位;单文件上传 + hooks;不支持对话框超时覆盖;不支持 `wait --load networkidle`,也不支持 + `responsebody`、PDF 导出、下载拦截或批量操作。 +- 本地托管的 `openclaw` 配置项会自动分配 `cdpPort` 和 `cdpUrl`;仅在远程 CDP 场景下才显式设置 `cdpUrl`。 +- 自动检测顺序:默认浏览器若为基于 Chromium → Chrome → Brave → Edge → Chromium → Chrome Canary。 - 控制服务:仅 loopback(端口由 `gateway.port` 派生,默认 `18791`)。 -- `extraArgs` 会将额外启动标志附加到本地 Chromium 启动参数中(例如 `--disable-gpu`、窗口大小设置或调试标志)。 +- `extraArgs` 会将额外启动标志追加到本地 Chromium 启动参数中(例如 + `--disable-gpu`、窗口尺寸或调试标志)。 --- @@ -226,7 +233,7 @@ x-i18n: ``` - `seamColor`:原生应用 UI 外观的强调色(Talk 模式气泡色调等)。 -- `assistant`:Control UI 身份覆盖。会回退到当前活动智能体身份。 +- `assistant`:Control UI 身份覆盖。默认回退到当前激活的智能体身份。 --- @@ -273,12 +280,12 @@ x-i18n: // password: "your-password", }, trustedProxies: ["10.0.0.1"], - // Optional. Default false. + // 可选。默认 false。 allowRealIpFallback: false, tools: { - // Additional /tools/invoke HTTP denies + // 对 /tools/invoke HTTP 的额外拒绝项 deny: ["browser"], - // Remove tools from the default HTTP deny list + // 从默认 HTTP 拒绝列表中移除工具 allow: ["gateway"], }, push: { @@ -293,66 +300,70 @@ x-i18n: } ``` - + -- `mode`:`local`(运行 Gateway 网关)或 `remote`(连接到远程 Gateway 网关)。除非为 `local`,否则 Gateway 网关将拒绝启动。 +- `mode`:`local`(运行 Gateway 网关)或 `remote`(连接到远程 Gateway 网关)。除非为 `local`,否则 Gateway 网关会拒绝启动。 - `port`:用于 WS + HTTP 的单一复用端口。优先级:`--port` > `OPENCLAW_GATEWAY_PORT` > `gateway.port` > `18789`。 - `bind`:`auto`、`loopback`(默认)、`lan`(`0.0.0.0`)、`tailnet`(仅 Tailscale IP)或 `custom`。 - **旧版 bind 别名**:请在 `gateway.bind` 中使用 bind 模式值(`auto`、`loopback`、`lan`、`tailnet`、`custom`),不要使用主机别名(`0.0.0.0`、`127.0.0.1`、`localhost`、`::`、`::1`)。 -- **Docker 说明**:默认的 `loopback` bind 会在容器内部监听 `127.0.0.1`。使用 Docker bridge 网络(`-p 18789:18789`)时,流量会到达 `eth0`,因此 Gateway 网关不可访问。请使用 `--network host`,或设置 `bind: "lan"`(或设置 `bind: "custom"` 且 `customBindHost: "0.0.0.0"`)以监听所有接口。 -- **Auth**:默认必需。非 loopback bind 要求 Gateway 网关 auth。实际上,这意味着需要共享 token/password,或使用带有 `gateway.auth.mode: "trusted-proxy"` 的身份感知型反向代理。新手引导向导默认会生成 token。 -- 如果同时配置了 `gateway.auth.token` 和 `gateway.auth.password`(包括 SecretRefs),请显式设置 `gateway.auth.mode` 为 `token` 或 `password`。如果两者都已配置但未设置 mode,启动以及服务安装/修复流程都会失败。 -- `gateway.auth.mode: "none"`:显式无 auth 模式。仅用于受信任的本地 local loopback 设置;新手引导提示中不会提供此选项。 -- `gateway.auth.mode: "trusted-proxy"`:将 auth 委托给身份感知型反向代理,并信任来自 `gateway.trustedProxies` 的身份头(参见 [Trusted Proxy Auth](/zh-CN/gateway/trusted-proxy-auth))。此模式要求**非 loopback** 代理来源;同机 loopback 反向代理不满足 trusted-proxy auth 的要求。 -- `gateway.auth.allowTailscale`:为 `true` 时,Tailscale Serve 身份头可满足 Control UI/WebSocket auth(通过 `tailscale whois` 验证)。HTTP API 端点**不会**使用该 Tailscale 头 auth;它们仍遵循 Gateway 网关常规的 HTTP auth 模式。此无 token 流程假设 Gateway 网关主机是受信任的。当 `tailscale.mode = "serve"` 时默认值为 `true`。 -- `gateway.auth.rateLimit`:可选的 auth 失败限速器。按客户端 IP 和 auth 作用域生效(共享密钥与设备 token 分开跟踪)。被阻止的尝试会返回 `429` + `Retry-After`。 - - 在异步 Tailscale Serve Control UI 路径上,对于相同 `{scope, clientIp}` 的失败尝试,会在写入失败记录前进行串行化。因此,同一客户端并发的错误尝试,可能会在第二个请求时触发限速,而不是两个请求都作为普通不匹配同时通过。 - - `gateway.auth.rateLimit.exemptLoopback` 默认为 `true`;如果你有意也要对 localhost 流量进行限速(用于测试设置或严格代理部署),请设为 `false`。 -- 来自浏览器源的 WS auth 尝试始终会应用限速,且禁用 loopback 豁免(作为针对基于浏览器的 localhost 暴力破解的纵深防御)。 -- 在 loopback 上,这些来自浏览器源的锁定会按规范化后的 `Origin` - 值彼此隔离,因此一个 localhost origin 的重复失败不会自动 +- **Docker 注意事项**:默认的 `loopback` bind 会在容器内监听 `127.0.0.1`。使用 Docker bridge 网络(`-p 18789:18789`)时,流量会到达 `eth0`,因此 Gateway 网关无法访问。请使用 `--network host`,或设置 `bind: "lan"`(或 `bind: "custom"` 并搭配 `customBindHost: "0.0.0.0"`)以在所有网络接口上监听。 +- **认证**:默认必须启用。非 loopback bind 必须使用 Gateway 网关认证。实际这意味着共享 token/password,或使用带有 `gateway.auth.mode: "trusted-proxy"` 的身份感知型反向代理。新手引导向导默认会生成 token。 +- 如果同时配置了 `gateway.auth.token` 和 `gateway.auth.password`(包括 SecretRef),请显式将 `gateway.auth.mode` 设为 `token` 或 `password`。若两者都已配置但未设置 mode,启动以及服务安装 / 修复流程都会失败。 +- `gateway.auth.mode: "none"`:显式无认证模式。仅可用于受信任的本地 local loopback 设置;新手引导提示中不会提供此选项。 +- `gateway.auth.mode: "trusted-proxy"`:将认证委托给身份感知型反向代理,并信任来自 `gateway.trustedProxies` 的身份头(见 [Trusted Proxy Auth](/zh-CN/gateway/trusted-proxy-auth))。此模式要求**非 loopback** 的代理来源;同机 loopback 反向代理不满足 trusted-proxy 认证要求。 +- `gateway.auth.allowTailscale`:为 `true` 时,Tailscale Serve 身份头可用于满足 Control UI/WebSocket 认证(通过 `tailscale whois` 验证)。HTTP API 端点**不会**使用该 Tailscale 头认证;它们仍遵循 Gateway 网关正常的 HTTP 认证模式。这个无 token 流程假定 Gateway 网关主机是受信任的。当 `tailscale.mode = "serve"` 时,默认值为 `true`。 +- `gateway.auth.rateLimit`:可选的认证失败限流器。按客户端 IP 和认证范围生效(共享密钥与设备 token 分别独立跟踪)。被阻止的尝试会返回 `429` + `Retry-After`。 + - 在异步 Tailscale Serve Control UI 路径上,同一 `{scope, clientIp}` 的失败尝试会在写入失败记录前串行化处理。因此,同一客户端的并发错误尝试,可能会在第二个请求时触发限流,而不是两个请求都竞态通过并仅表现为普通不匹配。 + - `gateway.auth.rateLimit.exemptLoopback` 默认值为 `true`;如果你明确希望 localhost 流量也被限流(用于测试设置或严格代理部署),请设为 `false`。 +- 来自浏览器源的 WS 认证尝试始终会受到限流,且不会豁免 loopback(作为防御加固,以应对基于浏览器的 localhost 暴力破解)。 +- 在 loopback 上,这些来自浏览器源的锁定会按标准化后的 `Origin` + 值隔离,因此来自某个 localhost origin 的重复失败不会自动 锁定另一个 origin。 -- `tailscale.mode`:`serve`(仅 tailnet,loopback bind)或 `funnel`(公网,需要 auth)。 -- `controlUi.allowedOrigins`:用于 Gateway 网关 WebSocket 连接的显式浏览器源允许列表。当预期浏览器客户端来自非 loopback 源时为必需。 -- `controlUi.dangerouslyAllowHostHeaderOriginFallback`:危险模式,为有意依赖 Host 头 origin 策略的部署启用 Host 头 origin 回退。 -- `remote.transport`:`ssh`(默认)或 `direct`(ws/wss)。对于 `direct`,`remote.url` 必须是 `ws://` 或 `wss://`。 -- `OPENCLAW_ALLOW_INSECURE_PRIVATE_WS=1`:客户端侧的紧急破窗覆盖,允许向受信任私有网络 IP 使用明文 `ws://`;默认情况下,明文仍然仅限 loopback。 -- `gateway.remote.token` / `.password` 是远程客户端凭证字段。它们本身不会配置 Gateway 网关 auth。 -- `gateway.push.apns.relay.baseUrl`:官方/TestFlight iOS 构建在将基于 relay 的注册发布到 Gateway 网关后,供其使用的外部 APNs relay 的基础 HTTPS URL。该 URL 必须与编译进 iOS 构建中的 relay URL 匹配。 -- `gateway.push.apns.relay.timeoutMs`:Gateway 网关到 relay 的发送超时时间(毫秒)。默认值为 `10000`。 -- 基于 relay 的注册会委托给特定的 Gateway 网关身份。配对的 iOS 应用会获取 `gateway.identity.get`,在 relay 注册中包含该身份,并将注册作用域的发送授权转发给 Gateway 网关。另一个 Gateway 网关无法复用该已存储注册。 -- `OPENCLAW_APNS_RELAY_BASE_URL` / `OPENCLAW_APNS_RELAY_TIMEOUT_MS`:上述 relay 配置的临时环境变量覆盖。 -- `OPENCLAW_APNS_RELAY_ALLOW_HTTP=true`:仅供开发使用的例外开关,允许使用 loopback HTTP relay URL。生产环境的 relay URL 应保持为 HTTPS。 -- `gateway.channelHealthCheckMinutes`:渠道健康监视器间隔,单位为分钟。设为 `0` 可全局禁用健康监视器重启。默认值:`5`。 -- `gateway.channelStaleEventThresholdMinutes`:过期 socket 阈值,单位为分钟。请保持其大于或等于 `gateway.channelHealthCheckMinutes`。默认值:`30`。 -- `gateway.channelMaxRestartsPerHour`:滚动一小时内每个渠道/账号的健康监视器最大重启次数。默认值:`10`。 -- `channels..healthMonitor.enabled`:按渠道关闭健康监视器重启,同时保留全局监视器启用。 -- `channels..accounts..healthMonitor.enabled`:多账号渠道中的按账号覆盖。设置后,它的优先级高于渠道级覆盖。 -- 仅当 `gateway.auth.*` 未设置时,本地 Gateway 网关调用路径才能使用 `gateway.remote.*` 作为回退。 -- 如果 `gateway.auth.token` / `gateway.auth.password` 通过 SecretRef 显式配置但无法解析,则解析会以关闭方式失败(不会使用远程回退进行掩盖)。 -- `trustedProxies`:终止 TLS 或注入转发客户端头的反向代理 IP。只列出你控制的代理。loopback 条目对于同机代理/本地检测设置(例如 Tailscale Serve 或本地反向代理)仍然有效,但它们**不会**让 loopback 请求符合 `gateway.auth.mode: "trusted-proxy"` 的条件。 -- `allowRealIpFallback`:为 `true` 时,若缺少 `X-Forwarded-For`,Gateway 网关会接受 `X-Real-IP`。默认 `false`,以保持失败即关闭的行为。 -- `gateway.tools.deny`:为 HTTP `POST /tools/invoke` 额外阻止的工具名称(扩展默认阻止列表)。 -- `gateway.tools.allow`:从默认 HTTP 阻止列表中移除工具名称。 +- `tailscale.mode`:`serve`(仅 tailnet,loopback bind)或 `funnel`(公开访问,需要认证)。 +- `controlUi.allowedOrigins`:用于 Gateway 网关 WebSocket 连接的显式浏览器源允许列表。当预期浏览器客户端来自非 loopback origin 时必须设置。 +- `controlUi.dangerouslyAllowHostHeaderOriginFallback`:危险模式,为刻意依赖 Host 头 origin 策略的部署启用 Host 头 origin 回退。 +- `remote.transport`:`ssh`(默认)或 `direct`(ws/wss)。对于 `direct`,`remote.url` 必须为 `ws://` 或 `wss://`。 +- `OPENCLAW_ALLOW_INSECURE_PRIVATE_WS=1`:客户端进程环境变量级别的紧急覆盖, + 允许明文 `ws://` 连接到受信任的私有网络 IP;默认情况下,明文连接仍仅限于 loopback。 + 没有对应的 `openclaw.json` 配置项,而且诸如 + `browser.ssrfPolicy.dangerouslyAllowPrivateNetwork` 之类的浏览器私有网络配置 + 不会影响 Gateway 网关 WebSocket 客户端。 +- `gateway.remote.token` / `.password` 是远程客户端凭据字段。它们本身不会配置 Gateway 网关认证。 +- `gateway.push.apns.relay.baseUrl`:官方 / TestFlight iOS 构建在将基于 relay 的注册发布到 Gateway 网关之后,用于外部 APNs relay 的基础 HTTPS URL。此 URL 必须与编译进 iOS 构建的 relay URL 一致。 +- `gateway.push.apns.relay.timeoutMs`:Gateway 网关到 relay 的发送超时,单位毫秒。默认值为 `10000`。 +- 基于 relay 的注册会委托给特定的 Gateway 网关身份。配对的 iOS 应用会获取 `gateway.identity.get`,在 relay 注册中包含该身份,并将按注册范围的发送授权转发给 Gateway 网关。其他 Gateway 网关无法复用该已存储注册。 +- `OPENCLAW_APNS_RELAY_BASE_URL` / `OPENCLAW_APNS_RELAY_TIMEOUT_MS`:对上述 relay 配置的临时环境变量覆盖。 +- `OPENCLAW_APNS_RELAY_ALLOW_HTTP=true`:仅用于开发环境的放宽开关,允许使用 loopback HTTP relay URL。生产环境的 relay URL 应保持使用 HTTPS。 +- `gateway.channelHealthCheckMinutes`:渠道健康监控间隔,单位分钟。设为 `0` 可全局禁用健康监控重启。默认值:`5`。 +- `gateway.channelStaleEventThresholdMinutes`:陈旧 socket 阈值,单位分钟。应保持大于或等于 `gateway.channelHealthCheckMinutes`。默认值:`30`。 +- `gateway.channelMaxRestartsPerHour`:每个渠道 / 账号在滚动一小时内允许的最大健康监控重启次数。默认值:`10`。 +- `channels..healthMonitor.enabled`:按渠道选择退出健康监控重启,同时保留全局监控启用。 +- `channels..accounts..healthMonitor.enabled`:多账号渠道中的按账号覆盖。设置后,其优先级高于渠道级覆盖。 +- 仅当 `gateway.auth.*` 未设置时,本地 Gateway 网关调用路径才能将 `gateway.remote.*` 用作回退。 +- 如果通过 SecretRef 显式配置了 `gateway.auth.token` / `gateway.auth.password` 但无法解析,则解析会以关闭方式失败(不会通过远程回退掩盖问题)。 +- `trustedProxies`:终止 TLS 或注入转发客户端头的反向代理 IP。只列出你控制的代理。loopback 条目对同机代理 / 本地检测设置仍然有效(例如 Tailscale Serve 或本地反向代理),但它们**不会**让 loopback 请求符合 `gateway.auth.mode: "trusted-proxy"` 的资格。 +- `allowRealIpFallback`:为 `true` 时,如果缺少 `X-Forwarded-For`,Gateway 网关会接受 `X-Real-IP`。默认值为 `false`,以保持失败即关闭的行为。 +- `gateway.tools.deny`:对 HTTP `POST /tools/invoke` 额外阻止的工具名(扩展默认拒绝列表)。 +- `gateway.tools.allow`:从默认 HTTP 拒绝列表中移除工具名。 ### OpenAI 兼容端点 -- Chat Completions:默认禁用。通过 `gateway.http.endpoints.chatCompletions.enabled: true` 启用。 +- Chat Completions:默认禁用。使用 `gateway.http.endpoints.chatCompletions.enabled: true` 启用。 - Responses API:`gateway.http.endpoints.responses.enabled`。 - Responses URL 输入加固: - `gateway.http.endpoints.responses.maxUrlParts` - `gateway.http.endpoints.responses.files.urlAllowlist` - `gateway.http.endpoints.responses.images.urlAllowlist` 空允许列表会被视为未设置;使用 `gateway.http.endpoints.responses.files.allowUrl=false` - 和/或 `gateway.http.endpoints.responses.images.allowUrl=false` 可禁用 URL 抓取。 -- 可选的响应加固头: - - `gateway.http.securityHeaders.strictTransportSecurity`(仅对你控制的 HTTPS 源设置;参见 [Trusted Proxy Auth](/zh-CN/gateway/trusted-proxy-auth#tls-termination-and-hsts)) + 和 / 或 `gateway.http.endpoints.responses.images.allowUrl=false` 可禁用 URL 抓取。 +- 可选响应加固头: + - `gateway.http.securityHeaders.strictTransportSecurity`(仅对你控制的 HTTPS origin 设置;参见 [Trusted Proxy Auth](/zh-CN/gateway/trusted-proxy-auth#tls-termination-and-hsts)) ### 多实例隔离 -在同一主机上运行多个 Gateway 网关时,请使用唯一端口和状态目录: +在一台主机上运行多个 Gateway 网关时,请为每个实例使用唯一端口和状态目录: ```bash OPENCLAW_CONFIG_PATH=~/.openclaw/a.json \ @@ -360,9 +371,9 @@ OPENCLAW_STATE_DIR=~/.openclaw-a \ openclaw gateway --port 19001 ``` -便捷标志:`--dev`(使用 `~/.openclaw-dev` + 端口 `19001`)、`--profile `(使用 `~/.openclaw-`)。 +便捷标志:`--dev`(使用 `~/.openclaw-dev` + 端口 `19001`),`--profile `(使用 `~/.openclaw-`)。 -参见 [多个 Gateway 网关](/zh-CN/gateway/multiple-gateways)。 +参见 [Multiple Gateways](/zh-CN/gateway/multiple-gateways)。 ### `gateway.tls` @@ -380,10 +391,10 @@ openclaw gateway --port 19001 } ``` -- `enabled`:在 Gateway 网关监听器上启用 TLS 终止(HTTPS/WSS)(默认:`false`)。 -- `autoGenerate`:当未配置显式文件时,自动生成本地自签名证书/密钥对;仅适用于本地/开发环境。 +- `enabled`:在 Gateway 网关监听器处启用 TLS 终止(HTTPS/WSS)(默认:`false`)。 +- `autoGenerate`:当未配置显式文件时,自动生成本地自签名证书 / 密钥对;仅用于本地 / 开发环境。 - `certPath`:TLS 证书文件的文件系统路径。 -- `keyPath`:TLS 私钥文件的文件系统路径;请限制文件权限。 +- `keyPath`:TLS 私钥文件的文件系统路径;应限制访问权限。 - `caPath`:用于客户端验证或自定义信任链的可选 CA bundle 路径。 ### `gateway.reload` @@ -400,13 +411,13 @@ openclaw gateway --port 19001 } ``` -- `mode`:控制在运行时如何应用配置编辑。 +- `mode`:控制如何在运行时应用配置编辑。 - `"off"`:忽略实时编辑;更改需要显式重启。 - `"restart"`:配置变更时始终重启 Gateway 网关进程。 - `"hot"`:在进程内应用更改而不重启。 - - `"hybrid"`(默认):先尝试热重载;如有需要则回退为重启。 -- `debounceMs`:应用配置变更前的去抖窗口,单位为毫秒(非负整数)。 -- `deferralTimeoutMs`:在强制重启前等待进行中操作完成的最长时间,单位为毫秒(默认:`300000` = 5 分钟)。 + - `"hybrid"`(默认):先尝试热重载;如果必须,再回退为重启。 +- `debounceMs`:应用配置更改前的防抖窗口,单位毫秒(非负整数)。 +- `deferralTimeoutMs`:在强制重启前等待进行中操作完成的最长时间,单位毫秒(默认:`300000` = 5 分钟)。 --- @@ -443,47 +454,47 @@ openclaw gateway --port 19001 } ``` -Auth:`Authorization: Bearer ` 或 `x-openclaw-token: `。 -拒绝使用查询字符串中的 hook token。 +认证方式:`Authorization: Bearer ` 或 `x-openclaw-token: `。 +不接受查询字符串中的 hook token。 验证与安全说明: -- `hooks.enabled=true` 需要一个非空的 `hooks.token`。 -- `hooks.token` 必须与 `gateway.auth.token` **不同**;重复使用 Gateway 网关 token 会被拒绝。 -- `hooks.path` 不能是 `/`;请使用专用子路径,例如 `/hooks`。 +- `hooks.enabled=true` 要求 `hooks.token` 为非空。 +- `hooks.token` 必须与 `gateway.auth.token` **不同**;复用 Gateway 网关 token 会被拒绝。 +- `hooks.path` 不能为 `/`;请使用专用子路径,例如 `/hooks`。 - 如果 `hooks.allowRequestSessionKey=true`,请限制 `hooks.allowedSessionKeyPrefixes`(例如 `["hook:"]`)。 -- 如果某个映射或 preset 使用模板化的 `sessionKey`,请设置 `hooks.allowedSessionKeyPrefixes` 和 `hooks.allowRequestSessionKey=true`。静态映射键不需要该选择加入开关。 +- 如果某个 mapping 或 preset 使用了模板化的 `sessionKey`,请设置 `hooks.allowedSessionKeyPrefixes` 和 `hooks.allowRequestSessionKey=true`。静态 mapping 键不需要此显式启用。 **端点:** - `POST /hooks/wake` → `{ text, mode?: "now"|"next-heartbeat" }` - `POST /hooks/agent` → `{ message, name?, agentId?, sessionKey?, wakeMode?, deliver?, channel?, to?, model?, thinking?, timeoutSeconds? }` - - 仅当 `hooks.allowRequestSessionKey=true`(默认:`false`)时,才接受请求载荷中的 `sessionKey`。 + - 仅当 `hooks.allowRequestSessionKey=true`(默认:`false`)时,才接受请求负载中的 `sessionKey`。 - `POST /hooks/` → 通过 `hooks.mappings` 解析 - - 模板渲染后的映射 `sessionKey` 值会被视为外部提供,因此同样要求 `hooks.allowRequestSessionKey=true`。 + - 模板渲染后的 mapping `sessionKey` 值会被视为外部提供,因此同样要求 `hooks.allowRequestSessionKey=true`。 - `match.path` 匹配 `/hooks` 之后的子路径(例如 `/hooks/gmail` → `gmail`)。 -- `match.source` 匹配通用路径的某个载荷字段。 -- `{{messages[0].subject}}` 这类模板会从载荷中读取。 +- `match.source` 匹配通用路径中的某个负载字段。 +- 类似 `{{messages[0].subject}}` 的模板会从负载中读取。 - `transform` 可以指向一个返回 hook 动作的 JS/TS 模块。 - - `transform.module` 必须是相对路径,并保持在 `hooks.transformsDir` 内(绝对路径和路径穿越都会被拒绝)。 -- `agentId` 会路由到特定智能体;未知 id 会回退到默认值。 + - `transform.module` 必须是相对路径,并且必须位于 `hooks.transformsDir` 内部(绝对路径和路径穿越都会被拒绝)。 +- `agentId` 会路由到特定智能体;未知 ID 会回退到默认值。 - `allowedAgentIds`:限制显式路由(`*` 或省略 = 允许全部,`[]` = 全部拒绝)。 -- `defaultSessionKey`:对于没有显式 `sessionKey` 的 hook 智能体运行,可选的固定会话键。 -- `allowRequestSessionKey`:允许 `/hooks/agent` 调用方以及模板驱动的映射会话键设置 `sessionKey`(默认:`false`)。 -- `allowedSessionKeyPrefixes`:显式 `sessionKey` 值(请求 + 映射)的可选前缀允许列表,例如 `["hook:"]`。当任何映射或 preset 使用模板化 `sessionKey` 时,它就变为必需项。 -- `deliver: true` 会将最终回复发送到渠道;`channel` 默认为 `last`。 -- `model` 会为此 hook 运行覆盖 LLM(如果设置了模型目录,则该模型必须被允许)。 +- `defaultSessionKey`:可选的固定会话键,用于没有显式 `sessionKey` 的 hook 智能体运行。 +- `allowRequestSessionKey`:允许 `/hooks/agent` 调用方和模板驱动的 mapping session key 设置 `sessionKey`(默认:`false`)。 +- `allowedSessionKeyPrefixes`:显式 `sessionKey` 值(请求 + mapping)的可选前缀允许列表,例如 `["hook:"]`。当任何 mapping 或 preset 使用模板化 `sessionKey` 时,此项变为必需。 +- `deliver: true` 会将最终回复发送到某个渠道;`channel` 默认值为 `last`。 +- `model` 为此次 hook 运行覆盖 LLM(如果设置了模型目录,则该模型必须被允许)。 ### Gmail 集成 - 内置 Gmail preset 使用 `sessionKey: "hook:gmail:{{messages[0].id}}"`。 -- 如果你保留这种按消息路由的方式,请设置 `hooks.allowRequestSessionKey: true`,并限制 `hooks.allowedSessionKeyPrefixes` 以匹配 Gmail 命名空间,例如 `["hook:", "hook:gmail:"]`。 -- 如果你需要 `hooks.allowRequestSessionKey: false`,请使用静态 `sessionKey` 覆盖该 preset,而不是使用默认的模板化值。 +- 如果你保留这种按消息路由的方式,请设置 `hooks.allowRequestSessionKey: true`,并将 `hooks.allowedSessionKeyPrefixes` 限制为匹配 Gmail 命名空间,例如 `["hook:", "hook:gmail:"]`。 +- 如果你需要 `hooks.allowRequestSessionKey: false`,请用静态 `sessionKey` 覆盖该 preset,而不是使用默认的模板化值。 ```json5 { @@ -527,14 +538,14 @@ Auth:`Authorization: Bearer ` 或 `x-openclaw-token: `。 - `http://:/__openclaw__/canvas/` - `http://:/__openclaw__/a2ui/` - 仅限本地:保持 `gateway.bind: "loopback"`(默认)。 -- 非 loopback bind:canvas 路由和其他 Gateway 网关 HTTP 能力一样,需要 Gateway 网关 auth(token/password/trusted-proxy)。 -- Node WebView 通常不会发送 auth 头;节点配对并连接后,Gateway 网关会为 canvas/A2UI 访问公布节点作用域的能力 URL。 -- 能力 URL 绑定到当前活动的节点 WS 会话,并且很快过期。不使用基于 IP 的回退。 +- 非 loopback bind:canvas 路由与其他 Gateway 网关 HTTP 面一样,需要 Gateway 网关认证(token/password/trusted-proxy)。 +- 节点 WebView 通常不会发送认证头;节点完成配对并连接后,Gateway 网关会发布节点作用域的能力 URL,用于访问 canvas/A2UI。 +- 能力 URL 绑定到当前活跃的节点 WS 会话,并且会很快过期。不使用基于 IP 的回退。 - 会向所提供的 HTML 中注入 live-reload 客户端。 -- 为空时会自动创建初始 `index.html`。 -- 同时也会在 `/__openclaw__/a2ui/` 下提供 A2UI。 -- 更改需要重启 Gateway 网关。 -- 对于大型目录或 `EMFILE` 错误,请禁用 live reload。 +- 为空时会自动创建起始 `index.html`。 +- 也会在 `/__openclaw__/a2ui/` 提供 A2UI。 +- 变更需要重启 Gateway 网关。 +- 对于大型目录或出现 `EMFILE` 错误时,请禁用 live reload。 --- @@ -552,9 +563,9 @@ Auth:`Authorization: Bearer ` 或 `x-openclaw-token: `。 } ``` -- `minimal`(默认):在 TXT 记录中省略 `cliPath` 和 `sshPort`。 -- `full`:包含 `cliPath` 和 `sshPort`。 -- 主机名默认为 `openclaw`。可使用 `OPENCLAW_MDNS_HOSTNAME` 覆盖。 +- `minimal`(默认):从 TXT 记录中省略 `cliPath` + `sshPort`。 +- `full`:包含 `cliPath` + `sshPort`。 +- 主机名默认为 `openclaw`。可通过 `OPENCLAW_MDNS_HOSTNAME` 覆盖。 ### 广域(DNS-SD) @@ -566,7 +577,7 @@ Auth:`Authorization: Bearer ` 或 `x-openclaw-token: `。 } ``` -会在 `~/.openclaw/dns/` 下写入一个单播 DNS-SD 区域。要实现跨网络发现,请配合 DNS 服务器(推荐 CoreDNS)+ Tailscale split DNS 使用。 +会在 `~/.openclaw/dns/` 下写入一个单播 DNS-SD 区域。若要实现跨网络设备发现,请结合 DNS 服务器(推荐 CoreDNS)+ Tailscale split DNS 一起使用。 设置:`openclaw dns setup --apply`。 @@ -591,10 +602,10 @@ Auth:`Authorization: Bearer ` 或 `x-openclaw-token: `。 } ``` -- 仅当进程环境中缺少该键时,才会应用内联环境变量。 +- 只有当进程环境中缺少对应键时,才会应用内联环境变量。 - `.env` 文件:当前工作目录下的 `.env` + `~/.openclaw/.env`(两者都不会覆盖现有变量)。 -- `shellEnv`:从你的登录 shell 配置文件中导入缺失的预期键名。 -- 完整优先级请参阅[环境](/zh-CN/help/environment)。 +- `shellEnv`:从你的登录 shell profile 中导入缺失的预期键名。 +- 完整优先级请参见 [Environment](/zh-CN/help/environment)。 ### 环境变量替换 @@ -609,15 +620,15 @@ Auth:`Authorization: Bearer ` 或 `x-openclaw-token: `。 ``` - 仅匹配大写名称:`[A-Z_][A-Z0-9_]*`。 -- 缺失/为空的变量会在配置加载时报错。 +- 缺失 / 为空的变量会在配置加载时抛出错误。 - 使用 `$${VAR}` 可转义为字面量 `${VAR}`。 - 适用于 `$include`。 --- -## 密钥 +## Secrets -Secret ref 是增量能力:明文值仍然可用。 +SecretRef 是增量式的:明文值仍然可用。 ### `SecretRef` @@ -633,15 +644,15 @@ Secret ref 是增量能力:明文值仍然可用。 - `source: "env"` 的 id 模式:`^[A-Z][A-Z0-9_]{0,127}$` - `source: "file"` 的 id:绝对 JSON pointer(例如 `"/providers/openai/apiKey"`) - `source: "exec"` 的 id 模式:`^[A-Za-z0-9][A-Za-z0-9._:/-]{0,255}$` -- `source: "exec"` 的 id 不能包含 `.` 或 `..` 这样的斜杠分隔路径段(例如 `a/../b` 会被拒绝) +- `source: "exec"` 的 id 不能包含 `.` 或 `..` 这样的按斜杠分隔路径段(例如 `a/../b` 会被拒绝) -### 支持的凭证能力 +### 支持的凭据面 -- 规范矩阵:[SecretRef 凭证能力](/zh-CN/reference/secretref-credential-surface) -- `secrets apply` 会定位受支持的 `openclaw.json` 凭证路径。 -- `auth-profiles.json` 中的 ref 也包含在运行时解析和审计覆盖范围内。 +- 规范矩阵:[SecretRef Credential Surface](/zh-CN/reference/secretref-credential-surface) +- `secrets apply` 会定位受支持的 `openclaw.json` 凭据路径。 +- `auth-profiles.json` 引用也包含在运行时解析和审计覆盖范围内。 -### Secret providers 配置 +### Secret 提供商配置 ```json5 { @@ -671,18 +682,18 @@ Secret ref 是增量能力:明文值仍然可用。 说明: -- `file` provider 支持 `mode: "json"` 和 `mode: "singleValue"`(在 singleValue 模式下,`id` 必须是 `"value"`)。 -- 当无法验证 Windows ACL 时,file 和 exec provider 路径会以失败即关闭的方式处理。只有在路径受信任但无法验证时,才设置 `allowInsecurePath: true`。 -- `exec` provider 要求使用绝对 `command` 路径,并通过 stdin/stdout 传递协议载荷。 -- 默认情况下,符号链接命令路径会被拒绝。设置 `allowSymlinkCommand: true` 可允许符号链接路径,同时仍验证解析后的目标路径。 -- 如果配置了 `trustedDirs`,受信任目录检查将作用于解析后的目标路径。 +- `file` 提供商支持 `mode: "json"` 和 `mode: "singleValue"`(在 singleValue 模式下,`id` 必须为 `"value"`)。 +- 当 Windows ACL 验证不可用时,文件和 exec 提供商路径会以关闭方式失败。仅当路径可信但无法验证时,才设置 `allowInsecurePath: true`。 +- `exec` 提供商要求 `command` 为绝对路径,并通过 stdin/stdout 使用协议负载。 +- 默认情况下,符号链接命令路径会被拒绝。设置 `allowSymlinkCommand: true` 可允许符号链接路径,同时仍验证其解析后的目标路径。 +- 如果配置了 `trustedDirs`,则受信任目录检查会应用于解析后的目标路径。 - 默认情况下,`exec` 子进程环境是最小化的;请通过 `passEnv` 显式传递所需变量。 -- Secret ref 会在激活时解析到内存快照中,然后请求路径只读取该快照。 -- 激活期间会应用活动能力过滤:启用能力上的未解析 ref 会导致启动/重载失败,而未激活能力会被跳过并附带诊断信息。 +- Secret 引用会在激活时解析为内存快照,之后请求路径只读取该快照。 +- 激活期间会应用活跃面过滤:启用面上的未解析引用会导致启动 / 重载失败,而未激活的面会被跳过并附带诊断信息。 --- -## Auth 存储 +## 凭据存储 ```json5 { @@ -700,13 +711,13 @@ Secret ref 是增量能力:明文值仍然可用。 } ``` -- 按智能体划分的配置文件存储在 `/auth-profiles.json`。 -- `auth-profiles.json` 支持静态凭证模式的值级 ref(`api_key` 使用 `keyRef`,`token` 使用 `tokenRef`)。 -- OAuth 模式配置文件(`auth.profiles..mode = "oauth"`)不支持基于 SecretRef 的 auth 配置文件凭证。 -- 静态运行时凭证来自内存中的已解析快照;发现旧版静态 `auth.json` 条目时会进行清理。 -- 旧版 OAuth 从 `~/.openclaw/credentials/oauth.json` 导入。 -- 参阅 [OAuth](/zh-CN/concepts/oauth)。 -- 密钥运行时行为以及 `audit/configure/apply` 工具:参阅[密钥管理](/zh-CN/gateway/secrets)。 +- 按智能体划分的 profiles 存储在 `/auth-profiles.json`。 +- `auth-profiles.json` 支持值级引用(静态凭据模式下,`api_key` 使用 `keyRef`,`token` 使用 `tokenRef`)。 +- OAuth 模式 profile(`auth.profiles..mode = "oauth"`)不支持由 SecretRef 提供支持的 auth-profile 凭据。 +- 静态运行时凭据来自内存中的已解析快照;发现旧版静态 `auth.json` 条目时会进行清理。 +- 旧版 OAuth 会从 `~/.openclaw/credentials/oauth.json` 导入。 +- 参见 [OAuth](/zh-CN/concepts/oauth)。 +- Secrets 运行时行为以及 `audit/configure/apply` 工具:参见 [Secrets Management](/zh-CN/gateway/secrets)。 ### `auth.cooldowns` @@ -728,15 +739,20 @@ Secret ref 是增量能力:明文值仍然可用。 } ``` -- `billingBackoffHours`:当配置文件因真实的计费/余额不足错误而失败时,使用的基础退避时长(小时)(默认:`5`)。即使在 `401`/`403` 响应上,明确的计费文本仍可能归入这里,但提供商专属文本匹配器仍仅限于其所属提供商(例如 OpenRouter 的 `Key limit exceeded`)。可重试的 HTTP `402` 使用窗口或 organization/workspace 支出限制消息,则仍归入 `rate_limit` 路径。 -- `billingBackoffHoursByProvider`:计费退避时长的可选按提供商覆盖。 -- `billingMaxHours`:计费退避指数增长的小时上限(默认:`24`)。 -- `authPermanentBackoffMinutes`:高置信度 `auth_permanent` 失败的基础退避时长(分钟)(默认:`10`)。 -- `authPermanentMaxMinutes`:`auth_permanent` 退避增长的分钟上限(默认:`60`)。 -- `failureWindowHours`:用于退避计数器的滚动时间窗口(小时)(默认:`24`)。 -- `overloadedProfileRotations`:对于 overloaded 错误,在切换到模型回退之前,允许同一提供商 auth 配置文件轮换的最大次数(默认:`1`)。像 `ModelNotReadyException` 这样的提供商繁忙形态会归入这里。 -- `overloadedBackoffMs`:在重试 overloaded 提供商/配置文件轮换之前的固定延迟(毫秒)(默认:`0`)。 -- `rateLimitedProfileRotations`:对于 rate-limit 错误,在切换到模型回退之前,允许同一提供商 auth 配置文件轮换的最大次数(默认:`1`)。该 rate-limit 桶包括提供商形态文本,例如 `Too many concurrent requests`、`ThrottlingException`、`concurrency limit reached`、`workers_ai ... quota limit exceeded` 和 `resource exhausted`。 +- `billingBackoffHours`:当某个 profile 因真实的 + 计费 / 额度不足错误而失败时,使用的基础退避时间(单位:小时)(默认:`5`)。即使在 `401`/`403` 响应中, + 明确的计费文本仍可能归入这里,但提供商专属的文本 + 匹配器仍然仅作用于拥有它们的提供商(例如 OpenRouter 的 + `Key limit exceeded`)。可重试的 HTTP `402` 用量窗口或 + organization/workspace 支出上限消息则仍归入 `rate_limit` 路径。 +- `billingBackoffHoursByProvider`:可选的按提供商划分的计费退避小时数覆盖。 +- `billingMaxHours`:计费退避指数增长的上限小时数(默认:`24`)。 +- `authPermanentBackoffMinutes`:高置信度 `auth_permanent` 失败的基础退避时间,单位分钟(默认:`10`)。 +- `authPermanentMaxMinutes`:`auth_permanent` 退避增长的上限分钟数(默认:`60`)。 +- `failureWindowHours`:用于退避计数器的滚动时间窗口,单位小时(默认:`24`)。 +- `overloadedProfileRotations`:对于过载错误,在切换到模型回退之前,同一提供商 auth-profile 可轮换的最大次数(默认:`1`)。诸如 `ModelNotReadyException` 这类提供商忙碌形态会归入此项。 +- `overloadedBackoffMs`:在重试过载的提供商 / profile 轮换前的固定延迟,单位毫秒(默认:`0`)。 +- `rateLimitedProfileRotations`:对于速率限制错误,在切换到模型回退之前,同一提供商 auth-profile 可轮换的最大次数(默认:`1`)。该速率限制桶包括提供商形态的文本,例如 `Too many concurrent requests`、`ThrottlingException`、`concurrency limit reached`、`workers_ai ... quota limit exceeded` 和 `resource exhausted`。 --- @@ -756,9 +772,9 @@ Secret ref 是增量能力:明文值仍然可用。 ``` - 默认日志文件:`/tmp/openclaw/openclaw-YYYY-MM-DD.log`。 -- 设置 `logging.file` 可使用固定路径。 +- 设置 `logging.file` 以使用固定路径。 - 使用 `--verbose` 时,`consoleLevel` 会提升为 `debug`。 -- `maxFileBytes`:在抑制写入之前,日志文件允许的最大大小(字节)(正整数;默认:`524288000` = 500 MB)。生产部署请使用外部日志轮转。 +- `maxFileBytes`:在抑制写入前,日志文件允许的最大字节数(正整数;默认:`524288000` = 500 MB)。生产部署请使用外部日志轮转。 --- @@ -796,19 +812,19 @@ Secret ref 是增量能力:明文值仍然可用。 ``` - `enabled`:仪表输出的总开关(默认:`true`)。 -- `flags`:启用定向日志输出的标志字符串数组(支持通配符,例如 `"telegram.*"` 或 `"*"`)。 -- `stuckSessionWarnMs`:当会话仍处于处理中状态时,发出会话卡住警告的时长阈值(毫秒)。 -- `otel.enabled`:启用 OpenTelemetry 导出管道(默认:`false`)。 -- `otel.endpoint`:用于 OTel 导出的采集器 URL。 +- `flags`:用于启用定向日志输出的标志字符串数组(支持通配符,如 `"telegram.*"` 或 `"*"`)。 +- `stuckSessionWarnMs`:当某个会话仍处于处理中状态时,发出卡住会话警告的时长阈值,单位毫秒。 +- `otel.enabled`:启用 OpenTelemetry 导出管线(默认:`false`)。 +- `otel.endpoint`:用于 OTel 导出的收集器 URL。 - `otel.protocol`:`"http/protobuf"`(默认)或 `"grpc"`。 - `otel.headers`:随 OTel 导出请求发送的额外 HTTP/gRPC 元数据头。 -- `otel.serviceName`:资源属性使用的服务名称。 +- `otel.serviceName`:资源属性中的服务名。 - `otel.traces` / `otel.metrics` / `otel.logs`:启用 trace、metrics 或 log 导出。 - `otel.sampleRate`:trace 采样率,范围 `0`–`1`。 -- `otel.flushIntervalMs`:定期刷新遥测数据的时间间隔(毫秒)。 +- `otel.flushIntervalMs`:定期刷新遥测数据的时间间隔,单位毫秒。 - `cacheTrace.enabled`:为嵌入式运行记录缓存跟踪快照(默认:`false`)。 - `cacheTrace.filePath`:缓存跟踪 JSONL 的输出路径(默认:`$OPENCLAW_STATE_DIR/logs/cache-trace.jsonl`)。 -- `cacheTrace.includeMessages` / `includePrompt` / `includeSystem`:控制缓存跟踪输出中包含的内容(默认全部为 `true`)。 +- `cacheTrace.includeMessages` / `includePrompt` / `includeSystem`:控制缓存跟踪输出中包含哪些内容(默认全部为 `true`)。 --- @@ -830,12 +846,12 @@ Secret ref 是增量能力:明文值仍然可用。 } ``` -- `channel`:npm/git 安装所使用的发布渠道——`"stable"`、`"beta"` 或 `"dev"`。 +- `channel`:用于 npm/git 安装的发布渠道——`"stable"`、`"beta"` 或 `"dev"`。 - `checkOnStart`:Gateway 网关启动时检查 npm 更新(默认:`true`)。 - `auto.enabled`:为包安装启用后台自动更新(默认:`false`)。 -- `auto.stableDelayHours`:stable 渠道自动应用前的最小时延(小时)(默认:`6`;最大:`168`)。 -- `auto.stableJitterHours`:stable 渠道额外的发布时间分散窗口(小时)(默认:`12`;最大:`168`)。 -- `auto.betaCheckIntervalHours`:beta 渠道检查运行的频率(小时)(默认:`1`;最大:`24`)。 +- `auto.stableDelayHours`:stable 渠道自动应用前的最小延迟,单位小时(默认:`6`;最大:`168`)。 +- `auto.stableJitterHours`:stable 渠道发布额外分散窗口,单位小时(默认:`12`;最大:`168`)。 +- `auto.betaCheckIntervalHours`:beta 渠道检查运行频率,单位小时(默认:`1`;最大:`24`)。 --- @@ -868,22 +884,22 @@ Secret ref 是增量能力:明文值仍然可用。 } ``` -- `enabled`:ACP 功能总开关(默认:`false`)。 -- `dispatch.enabled`:ACP 会话轮次分发的独立开关(默认:`true`)。设为 `false` 可在保留 ACP 命令可用的同时阻止执行。 -- `backend`:默认 ACP 运行时后端 id(必须与已注册的 ACP 运行时插件匹配)。 -- `defaultAgent`:当生成操作未指定显式目标时,ACP 目标智能体 id 的回退值。 -- `allowedAgents`:允许用于 ACP 运行时会话的智能体 id 列表;空值表示不施加额外限制。 -- `maxConcurrentSessions`:同时处于活动状态的 ACP 会话最大数量。 -- `stream.coalesceIdleMs`:流式文本的空闲合并刷新窗口(毫秒)。 -- `stream.maxChunkChars`:在拆分流式分块投影之前允许的最大分块大小。 -- `stream.repeatSuppression`:每轮抑制重复的状态/工具行(默认:`true`)。 -- `stream.deliveryMode`:`"live"` 表示增量流式传输;`"final_only"` 表示缓冲到轮次终止事件后再输出。 -- `stream.hiddenBoundarySeparator`:隐藏工具事件之后、可见文本之前使用的分隔符(默认:`"paragraph"`)。 -- `stream.maxOutputChars`:每个 ACP 轮次可投影的助手输出最大字符数。 -- `stream.maxSessionUpdateChars`:投影 ACP 状态/更新行的最大字符数。 -- `stream.tagVisibility`:标签名到布尔可见性覆盖的记录,用于流式事件。 -- `runtime.ttlMinutes`:ACP 会话工作进程在符合清理条件前的空闲 TTL(分钟)。 -- `runtime.installCommand`:在引导 ACP 运行时环境时执行的可选安装命令。 +- `enabled`:全局 ACP 功能门控(默认:`false`)。 +- `dispatch.enabled`:ACP 会话轮次分发的独立门控(默认:`true`)。设为 `false` 可在保留 ACP 命令可用的同时阻止执行。 +- `backend`:默认 ACP 运行时 backend id(必须匹配已注册的 ACP 运行时插件)。 +- `defaultAgent`:当生成运行未指定显式目标时,ACP 目标智能体 id 的回退值。 +- `allowedAgents`:允许用于 ACP 运行时会话的智能体 id 允许列表;为空表示没有额外限制。 +- `maxConcurrentSessions`:最大并发活跃 ACP 会话数。 +- `stream.coalesceIdleMs`:流式文本的空闲合并刷新窗口,单位毫秒。 +- `stream.maxChunkChars`:流式分块投影在拆分前允许的最大块大小。 +- `stream.repeatSuppression`:按轮次抑制重复的状态 / 工具行(默认:`true`)。 +- `stream.deliveryMode`:`"live"` 表示增量流式输出;`"final_only"` 表示缓冲至轮次终结事件后再输出。 +- `stream.hiddenBoundarySeparator`:隐藏工具事件之后、可见文本之前所使用的分隔符(默认:`"paragraph"`)。 +- `stream.maxOutputChars`:每个 ACP 轮次投影的最大助手输出字符数。 +- `stream.maxSessionUpdateChars`:投影的 ACP 状态 / 更新行允许的最大字符数。 +- `stream.tagVisibility`:tag 名称到布尔可见性覆盖的记录,用于流式事件。 +- `runtime.ttlMinutes`:ACP 会话 worker 在空闲后可被清理前的 TTL,单位分钟。 +- `runtime.installCommand`:在引导 ACP 运行时环境时可运行的可选安装命令。 --- @@ -899,11 +915,11 @@ Secret ref 是增量能力:明文值仍然可用。 } ``` -- `cli.banner.taglineMode` 控制 banner 标语样式: - - `"random"`(默认):轮换的有趣/节日标语。 - - `"default"`:固定的中性标语(`All your chats, one OpenClaw.`)。 - - `"off"`:不显示标语文本(仍显示 banner 标题/版本)。 -- 若要隐藏整个 banner(而不仅仅是标语),请设置环境变量 `OPENCLAW_HIDE_BANNER=1`。 +- `cli.banner.taglineMode` 控制横幅标语样式: + - `"random"`(默认):轮换显示有趣 / 季节性标语。 + - `"default"`:固定中性标语(`All your chats, one OpenClaw.`)。 + - `"off"`:不显示标语文本(仍显示横幅标题 / 版本)。 +- 若要隐藏整个横幅(而不仅仅是标语),请设置环境变量 `OPENCLAW_HIDE_BANNER=1`。 --- @@ -927,13 +943,13 @@ Secret ref 是增量能力:明文值仍然可用。 ## 身份 -请参阅[智能体默认值](/zh-CN/gateway/config-agents#agent-defaults)中的 `agents.list` 身份字段。 +请参见 [智能体默认值](/zh-CN/gateway/config-agents#agent-defaults) 下 `agents.list` 的身份字段。 --- -## Bridge protocol(旧版节点,历史参考) +## Bridge protocol(旧版节点,历史参考)(旧版,已移除) -当前构建已不再包含 TCP bridge。节点通过 Gateway 网关 WebSocket 连接。`bridge.*` 键已不再属于配置 schema 的一部分(在移除前,验证会失败;`openclaw doctor --fix` 可移除未知键)。 +当前构建已不再包含 TCP bridge。节点通过 Gateway 网关 WebSocket 连接。`bridge.*` 键已不再属于配置 schema 的一部分(在移除前,验证会失败;可使用 `openclaw doctor --fix` 清理未知键)。 @@ -973,11 +989,11 @@ Secret ref 是增量能力:明文值仍然可用。 } ``` -- `sessionRetention`:从 `sessions.json` 中清理前,已完成的隔离 cron 运行会话应保留多长时间。也控制已归档、已删除的 cron 转录内容的清理。默认:`24h`;设为 `false` 可禁用。 -- `runLog.maxBytes`:每个运行日志文件(`cron/runs/.jsonl`)在触发清理前允许的最大大小。默认:`2_000_000` 字节。 -- `runLog.keepLines`:触发运行日志清理时保留的最新行数。默认:`2000`。 -- `webhookToken`:用于 cron webhook POST 投递(`delivery.mode = "webhook"`)的 bearer token;如果省略,则不会发送 auth 头。 -- `webhook`:已弃用的旧版回退 webhook URL(http/https),仅用于仍带有 `notify: true` 的已存储任务。 +- `sessionRetention`:完成的隔离 cron 运行会话在从 `sessions.json` 修剪前保留多久。也控制已归档、已删除的 cron 转录内容的清理。默认值:`24h`;设为 `false` 可禁用。 +- `runLog.maxBytes`:每个运行日志文件(`cron/runs/.jsonl`)在触发修剪前允许的最大大小。默认值:`2_000_000` 字节。 +- `runLog.keepLines`:触发运行日志修剪时保留的最新行数。默认值:`2000`。 +- `webhookToken`:用于 cron webhook `POST` 投递(`delivery.mode = "webhook"`)的 bearer token;若省略,则不会发送认证头。 +- `webhook`:已弃用的旧版回退 webhook URL(http/https),仅用于仍然带有 `notify: true` 的已存储任务。 ### `cron.retry` @@ -993,11 +1009,11 @@ Secret ref 是增量能力:明文值仍然可用。 } ``` -- `maxAttempts`:一次性任务在瞬时错误上的最大重试次数(默认:`3`;范围:`0`–`10`)。 -- `backoffMs`:每次重试对应的退避延迟数组,单位为毫秒(默认:`[30000, 60000, 300000]`;1–10 项)。 -- `retryOn`:触发重试的错误类型——`"rate_limit"`、`"overloaded"`、`"network"`、`"timeout"`、`"server_error"`。省略时将重试所有瞬时类型。 +- `maxAttempts`:单次任务在瞬时错误下的最大重试次数(默认:`3`;范围:`0`–`10`)。 +- `backoffMs`:每次重试尝试使用的退避延迟数组,单位毫秒(默认:`[30000, 60000, 300000]`;1–10 个条目)。 +- `retryOn`:触发重试的错误类型——`"rate_limit"`、`"overloaded"`、`"network"`、`"timeout"`、`"server_error"`。省略则表示对所有瞬时类型都进行重试。 -仅适用于一次性 cron 任务。周期性任务使用单独的失败处理机制。 +仅适用于单次 cron 任务。周期性任务使用独立的失败处理机制。 ### `cron.failureAlert` @@ -1015,11 +1031,11 @@ Secret ref 是增量能力:明文值仍然可用。 } ``` -- `enabled`:为 cron 任务启用失败告警(默认:`false`)。 +- `enabled`:启用 cron 任务失败告警(默认:`false`)。 - `after`:连续失败多少次后触发告警(正整数,最小值:`1`)。 -- `cooldownMs`:同一任务重复告警之间的最小间隔,单位为毫秒(非负整数)。 -- `mode`:投递模式——`"announce"` 通过渠道消息发送;`"webhook"` 向已配置 webhook 发起 POST。 -- `accountId`:可选的账号或渠道 id,用于限定告警投递范围。 +- `cooldownMs`:同一任务重复告警之间的最小毫秒间隔(非负整数)。 +- `mode`:投递模式——`"announce"` 通过渠道消息发送;`"webhook"` 向已配置的 webhook 发起 `POST`。 +- `accountId`:用于限定告警投递范围的可选账号或渠道 id。 ### `cron.failureDestination` @@ -1037,15 +1053,15 @@ Secret ref 是增量能力:明文值仍然可用。 ``` - 所有任务共用的 cron 失败通知默认目标。 -- `mode`:`"announce"` 或 `"webhook"`;当存在足够的目标数据时,默认为 `"announce"`。 -- `channel`:announce 投递的渠道覆盖。`"last"` 会复用最近一次已知的投递渠道。 -- `to`:显式的 announce 目标或 webhook URL。webhook 模式下为必需。 +- `mode`:`"announce"` 或 `"webhook"`;当存在足够的目标数据时,默认值为 `"announce"`。 +- `channel`:announce 投递的渠道覆盖。`"last"` 会复用最后一次已知的投递渠道。 +- `to`:显式 announce 目标或 webhook URL。webhook 模式下必填。 - `accountId`:可选的投递账号覆盖。 -- 每个任务的 `delivery.failureDestination` 会覆盖该全局默认值。 -- 当全局和任务级失败目标都未设置时,已通过 `announce` 投递的任务在失败时会回退到其主 announce 目标。 -- `delivery.failureDestination` 仅支持 `sessionTarget="isolated"` 的任务,除非该任务的主 `delivery.mode` 为 `"webhook"`。 +- 每个任务的 `delivery.failureDestination` 会覆盖这个全局默认值。 +- 当全局和按任务失败目标都未设置时,那些已通过 `announce` 投递的任务在失败时会回退到其主要 announce 目标。 +- 除非任务的主 `delivery.mode` 为 `"webhook"`,否则 `delivery.failureDestination` 仅支持 `sessionTarget="isolated"` 的任务。 -请参阅 [Cron Jobs](/zh-CN/automation/cron-jobs)。隔离的 cron 执行会作为[后台任务](/zh-CN/automation/tasks)进行跟踪。 +参见 [Cron Jobs](/zh-CN/automation/cron-jobs)。隔离的 cron 执行会作为[后台任务](/zh-CN/automation/tasks)进行跟踪。 --- @@ -1053,32 +1069,32 @@ Secret ref 是增量能力:明文值仍然可用。 在 `tools.media.models[].args` 中展开的模板占位符: -| Variable | Description | -| ------------------ | ------------------------------------------------- | -| `{{Body}}` | 完整的入站消息正文 | -| `{{RawBody}}` | 原始正文(无历史记录/发送者包装) | -| `{{BodyStripped}}` | 去除群组提及后的正文 | -| `{{From}}` | 发送者标识符 | -| `{{To}}` | 目标标识符 | -| `{{MessageSid}}` | 渠道消息 id | -| `{{SessionId}}` | 当前会话 UUID | -| `{{IsNewSession}}` | 新建会话时为 `"true"` | -| `{{MediaUrl}}` | 入站媒体伪 URL | -| `{{MediaPath}}` | 本地媒体路径 | -| `{{MediaType}}` | 媒体类型(image/audio/document/…) | -| `{{Transcript}}` | 音频转录文本 | -| `{{Prompt}}` | CLI 条目的已解析媒体提示 | -| `{{MaxChars}}` | CLI 条目的已解析最大输出字符数 | -| `{{ChatType}}` | `"direct"` 或 `"group"` | -| `{{GroupSubject}}` | 群组主题(尽力而为) | -| `{{GroupMembers}}` | 群组成员预览(尽力而为) | -| `{{SenderName}}` | 发送者显示名称(尽力而为) | -| `{{SenderE164}}` | 发送者电话号码(尽力而为) | -| `{{Provider}}` | 提供商提示(whatsapp、telegram、discord 等) | +| Variable | Description | +| ------------------ | ---------------------------------- | +| `{{Body}}` | 完整的入站消息正文 | +| `{{RawBody}}` | 原始正文(无历史记录 / 发送者包装) | +| `{{BodyStripped}}` | 去除群组提及后的正文 | +| `{{From}}` | 发送者标识符 | +| `{{To}}` | 目标标识符 | +| `{{MessageSid}}` | 渠道消息 id | +| `{{SessionId}}` | 当前会话 UUID | +| `{{IsNewSession}}` | 新建会话时为 `"true"` | +| `{{MediaUrl}}` | 入站媒体伪 URL | +| `{{MediaPath}}` | 本地媒体路径 | +| `{{MediaType}}` | 媒体类型(image/audio/document/…) | +| `{{Transcript}}` | 音频转录文本 | +| `{{Prompt}}` | CLI 条目的已解析媒体提示词 | +| `{{MaxChars}}` | CLI 条目的已解析最大输出字符数 | +| `{{ChatType}}` | `"direct"` 或 `"group"` | +| `{{GroupSubject}}` | 群组主题(尽力而为) | +| `{{GroupMembers}}` | 群组成员预览(尽力而为) | +| `{{SenderName}}` | 发送者显示名称(尽力而为) | +| `{{SenderE164}}` | 发送者电话号码(尽力而为) | +| `{{Provider}}` | 提供商提示(whatsapp、telegram、discord 等) | --- -## 配置包含(`$include`) +## 配置 include(`$include`) 将配置拆分为多个文件: @@ -1095,20 +1111,20 @@ Secret ref 是增量能力:明文值仍然可用。 **合并行为:** -- 单个文件:替换所在的整个对象。 +- 单文件:替换其所在的容器对象。 - 文件数组:按顺序深度合并(后者覆盖前者)。 -- 同级键:在包含之后合并(覆盖被包含的值)。 -- 嵌套包含:最多 10 层。 -- 路径:相对于包含它的文件解析,但必须保持在顶层配置目录(`openclaw.json` 的 `dirname`)内。只有在最终仍解析到该边界内时,才允许绝对路径/`../` 形式。 -- 当 OpenClaw 拥有的写入仅更改某个由单文件 include 支持的顶层分区时,写入会直通到该被包含文件。例如,`plugins install` 会将 `plugins: { $include: "./plugins.json5" }` 的更新写入 `plugins.json5`,并保持 `openclaw.json` 不变。 -- 根级 include、include 数组以及带有同级覆盖的 include,对于 OpenClaw 拥有的写入都是只读的;此类写入会以失败即关闭的方式失败,而不会将配置拍平。 -- 错误:对于缺失文件、解析错误和循环包含,会提供清晰的错误消息。 +- 同级键:在 include 之后合并(覆盖 include 的值)。 +- 嵌套 include:最多支持 10 层深度。 +- 路径:相对于包含它的文件解析,但必须保持在顶层配置目录(`openclaw.json` 的 `dirname`)之内。只有在最终解析结果仍位于该边界内时,才允许使用绝对路径 / `../` 形式。 +- 当 OpenClaw 自有写入仅更改由单文件 include 支持的某个顶层 section 时,写入会透传到该 include 文件。例如,`plugins install` 会将 `plugins: { $include: "./plugins.json5" }` 更新到 `plugins.json5` 中,而保持 `openclaw.json` 不变。 +- 根 include、include 数组,以及带有同级覆盖的 include,对于 OpenClaw 自有写入来说是只读的;这类写入会以关闭方式失败,而不会扁平化配置。 +- 错误:对于缺失文件、解析错误和循环 include,会给出清晰的消息。 --- -_相关内容:[配置](/zh-CN/gateway/configuration) · [配置示例](/zh-CN/gateway/configuration-examples) · [Doctor](/zh-CN/gateway/doctor)_ +_相关:[Configuration](/zh-CN/gateway/configuration) · [Configuration Examples](/zh-CN/gateway/configuration-examples) · [Doctor](/zh-CN/gateway/doctor)_ -## 相关内容 +## 相关 -- [配置](/zh-CN/gateway/configuration) -- [配置示例](/zh-CN/gateway/configuration-examples) +- [Configuration](/zh-CN/gateway/configuration) +- [Configuration examples](/zh-CN/gateway/configuration-examples) diff --git a/docs/zh-CN/gateway/remote.md b/docs/zh-CN/gateway/remote.md index 92d47c11f..c54a6e0f4 100644 --- a/docs/zh-CN/gateway/remote.md +++ b/docs/zh-CN/gateway/remote.md @@ -1,81 +1,81 @@ --- read_when: - - 运行或排查远程 Gateway 网关设置 -summary: 使用 SSH 隧道(Gateway 网关 WS)和 tailnet 的远程访问 + - 运行或排查远程 Gateway 网关设置问题 +summary: 使用 SSH 隧道(Gateway 网关 WS)和 tailnet 进行远程访问 title: 远程访问 x-i18n: - generated_at: "2026-04-24T03:16:26Z" + generated_at: "2026-04-24T06:43:47Z" model: gpt-5.4 provider: openai - source_hash: 3753f29d6b3cc3f1a2f749cc0fdfdd60dfde8822f0ec6db0e18e5412de0980da + source_hash: 66eebbe3762134f29f982201d7e79a789624b96042bd931e07d9855710d64bfe source_path: gateway/remote.md workflow: 15 --- # 远程访问(SSH、隧道和 tailnet) -本仓库通过在专用主机(桌面机 / 服务器)上保持单个 Gateway 网关(主实例)运行,并让客户端连接到它,来支持“通过 SSH 远程访问”。 +此仓库通过在专用主机(桌面机/服务器)上保持一个正在运行的 Gateway 网关(主节点),并让客户端连接到它,从而支持“通过 SSH 进行远程访问”。 -- 对于**操作员(你 / macOS 应用)**:SSH 隧道是通用回退方案。 -- 对于**节点(iOS/Android 和未来设备)**:连接到 Gateway 网关 **WebSocket**(按需使用 LAN/tailnet 或 SSH 隧道)。 +- 对于**操作端(你 / macOS 应用)**:SSH 隧道是通用的兜底方案。 +- 对于**节点(iOS/Android 和未来的设备)**:连接到 Gateway 网关 **WebSocket**(根据需要使用局域网 / tailnet 或 SSH 隧道)。 ## 核心思路 -- Gateway 网关 WebSocket 会绑定到你配置端口上的**回环地址**(默认是 18789)。 -- 对于远程使用,你可以通过 SSH 转发这个回环端口(或者使用 tailnet/VPN,以减少隧道依赖)。 +- Gateway 网关 WebSocket 绑定到你所配置端口的**loopback**(默认是 18789)。 +- 在远程使用时,你可以通过 SSH 转发这个 loopback 端口(或者使用 tailnet / VPN,以减少对隧道的依赖)。 -## 常见 VPN/tailnet 设置(智能体所在位置) +## 常见 VPN / tailnet 设置(智能体所在位置) -把**Gateway 网关主机**理解为“智能体所在的位置”。它持有会话、认证配置文件、渠道和状态。 -你的笔记本 / 桌面机(以及节点)会连接到这台主机。 +把 **Gateway 主机**看作“智能体所在的位置”。它持有会话、认证配置文件、渠道和状态。 +你的笔记本 / 台式机(以及节点)会连接到这台主机。 -### 1)始终在线的 Gateway 网关 位于你的 tailnet 中(VPS 或家用服务器) +### 1)tailnet 中始终在线的 Gateway 网关(VPS 或家用服务器) -在持久化主机上运行 Gateway 网关,并通过 **Tailscale** 或 SSH 访问它。 +在持久运行的主机上运行 Gateway 网关,并通过 **Tailscale** 或 SSH 访问它。 -- **最佳体验:** 保持 `gateway.bind: "loopback"`,并对 Control UI 使用 **Tailscale Serve**。 -- **回退方案:** 保持回环绑定 + 从任何需要访问的机器建立 SSH 隧道。 -- **示例:** [exe.dev](/zh-CN/install/exe-dev)(简单 VM)或 [Hetzner](/zh-CN/install/hetzner)(生产级 VPS)。 +- **最佳体验:**保持 `gateway.bind: "loopback"`,并为控制 UI 使用 **Tailscale Serve**。 +- **兜底方案:**保持 loopback,然后从任何需要访问的机器建立 SSH 隧道。 +- **示例:**[exe.dev](/zh-CN/install/exe-dev)(简单虚拟机)或 [Hetzner](/zh-CN/install/hetzner)(生产环境 VPS)。 -当你的笔记本经常休眠,但你希望智能体始终在线时,这种方式非常理想。 +当你的笔记本经常休眠,但你希望智能体始终在线时,这种方式最理想。 -### 2)家里的桌面机运行 Gateway 网关,笔记本作为远程控制端 +### 2)家用台式机运行 Gateway 网关,笔记本作为远程控制端 笔记本**不**运行智能体。它通过远程方式连接: -- 使用 macOS 应用的**通过 SSH 远程访问**模式(设置 → 通用 → “OpenClaw runs”)。 -- 应用会打开并管理隧道,因此 WebChat + 健康检查“开箱即用”。 +- 使用 macOS 应用的**通过 SSH 远程连接**模式(设置 → 通用 → “OpenClaw 运行于”)。 +- 应用会打开并管理隧道,因此 WebChat 和健康检查都能“正常工作”。 -操作手册: [macOS 远程访问](/zh-CN/platforms/mac/remote)。 +操作手册:[macOS 远程访问](/zh-CN/platforms/mac/remote)。 -### 3)笔记本运行 Gateway 网关,其他机器远程访问 +### 3)笔记本运行 Gateway 网关,从其他机器远程访问 -保持 Gateway 网关 在本地运行,但以安全方式暴露它: +让 Gateway 网关保持本地运行,但以安全方式暴露出来: -- 从其他机器通过 SSH 隧道连接到笔记本,或 -- 使用 Tailscale Serve 暴露 Control UI,并让 Gateway 网关 保持仅回环访问。 +- 从其他机器通过 SSH 隧道连接到笔记本,或者 +- 使用 Tailscale Serve 暴露控制 UI,同时让 Gateway 网关仅绑定 loopback。 -指南: [Tailscale](/zh-CN/gateway/tailscale) 和 [Web 概览](/zh-CN/web)。 +指南:[Tailscale](/zh-CN/gateway/tailscale) 和 [Web 概览](/zh-CN/web)。 -## 命令流(哪些内容运行在哪里) +## 命令流(哪些组件运行在哪里) -一个 Gateway 网关服务负责状态 + 渠道。节点是外围设备。 +一个 Gateway 网关服务持有状态 + 渠道。节点是外围设备。 流程示例(Telegram → 节点): - Telegram 消息到达 **Gateway 网关**。 -- Gateway 网关 运行**智能体**并决定是否调用节点工具。 -- Gateway 网关 通过 Gateway 网关 WebSocket(`node.*` RPC)调用**节点**。 -- 节点返回结果;Gateway 网关 再将回复发回 Telegram。 +- Gateway 网关运行**智能体**,并决定是否调用某个节点工具。 +- Gateway 网关通过 Gateway 网关 WebSocket(`node.*` RPC)调用**节点**。 +- 节点返回结果;Gateway 网关再将回复发回 Telegram。 说明: -- **节点不会运行 Gateway 网关服务。** 除非你有意运行隔离配置文件,否则每台主机只应运行一个 Gateway 网关(参见 [多个 Gateway 网关](/zh-CN/gateway/multiple-gateways))。 -- macOS 应用的“节点模式”本质上只是一个通过 Gateway 网关 WebSocket 连接的节点客户端。 +- **节点不会运行 gateway 服务。**每台主机通常只应运行一个 gateway,除非你有意运行隔离的配置文件(参见 [多个 gateway](/zh-CN/gateway/multiple-gateways))。 +- macOS 应用的“节点模式”本质上只是通过 Gateway 网关 WebSocket 连接的节点客户端。 ## SSH 隧道(CLI + 工具) -为远程 Gateway 网关 WS 创建本地隧道: +创建一个指向远程 Gateway 网关 WS 的本地隧道: ```bash ssh -N -L 18789:127.0.0.1:18789 user@host @@ -83,16 +83,16 @@ ssh -N -L 18789:127.0.0.1:18789 user@host 隧道建立后: -- `openclaw health` 和 `openclaw status --deep` 现在会通过 `ws://127.0.0.1:18789` 访问远程 Gateway 网关。 +- `openclaw health` 和 `openclaw status --deep` 现在会通过 `ws://127.0.0.1:18789` 访问远程 gateway。 - `openclaw gateway status`、`openclaw gateway health`、`openclaw gateway probe` 和 `openclaw gateway call` 也可以在需要时通过 `--url` 指向转发后的 URL。 -注意:请将 `18789` 替换为你配置的 `gateway.port`(或 `--port`/`OPENCLAW_GATEWAY_PORT`)。 -注意:当你传入 `--url` 时,CLI 不会回退到配置或环境凭证。 -请显式传入 `--token` 或 `--password`。缺少显式凭证会报错。 +注意:请将 `18789` 替换为你配置的 `gateway.port`(或 `--port` / `OPENCLAW_GATEWAY_PORT`)。 +注意:当你传入 `--url` 时,CLI 不会回退到配置或环境中的凭证。 +请显式提供 `--token` 或 `--password`。如果未显式提供凭证,将报错。 ## CLI 远程默认值 -你可以持久化一个远程目标,以便 CLI 命令默认使用它: +你可以持久化一个远程目标,让 CLI 命令默认使用它: ```json5 { @@ -106,65 +106,66 @@ ssh -N -L 18789:127.0.0.1:18789 user@host } ``` -当 Gateway 网关 仅绑定回环地址时,请将 URL 保持为 `ws://127.0.0.1:18789`,并先建立 SSH 隧道。 +当 gateway 仅绑定 loopback 时,请将 URL 保持为 `ws://127.0.0.1:18789`,并先建立 SSH 隧道。 ## 凭证优先级 -Gateway 网关凭证解析在 call/probe/status 路径以及 Discord exec-approval 监控中遵循同一套共享契约。节点主机使用相同的基础契约,但有一个本地模式例外(它会有意忽略 `gateway.remote.*`): +Gateway 网关凭证解析在 call / probe / status 路径以及 Discord exec-approval 监控中遵循同一套共享约定。节点主机使用相同的基础约定,但有一个本地模式例外(它会有意忽略 `gateway.remote.*`): -- 显式凭证(`--token`、`--password` 或工具 `gatewayToken`)在接受显式认证的调用路径中始终优先。 +- 显式凭证(`--token`、`--password` 或工具的 `gatewayToken`)在支持显式认证的调用路径中始终优先。 - URL 覆盖安全规则: - CLI URL 覆盖(`--url`)绝不会复用隐式配置 / 环境凭证。 - 环境 URL 覆盖(`OPENCLAW_GATEWAY_URL`)只能使用环境凭证(`OPENCLAW_GATEWAY_TOKEN` / `OPENCLAW_GATEWAY_PASSWORD`)。 - 本地模式默认值: - - token:`OPENCLAW_GATEWAY_TOKEN` -> `gateway.auth.token` -> `gateway.remote.token`(仅当本地认证 token 输入未设置时,才会应用远程回退) - - password:`OPENCLAW_GATEWAY_PASSWORD` -> `gateway.auth.password` -> `gateway.remote.password`(仅当本地认证 password 输入未设置时,才会应用远程回退) + - token:`OPENCLAW_GATEWAY_TOKEN` -> `gateway.auth.token` -> `gateway.remote.token`(仅当本地认证 token 输入未设置时,才应用远程回退) + - password:`OPENCLAW_GATEWAY_PASSWORD` -> `gateway.auth.password` -> `gateway.remote.password`(仅当本地认证 password 输入未设置时,才应用远程回退) - 远程模式默认值: - token:`gateway.remote.token` -> `OPENCLAW_GATEWAY_TOKEN` -> `gateway.auth.token` - password:`OPENCLAW_GATEWAY_PASSWORD` -> `gateway.remote.password` -> `gateway.auth.password` -- 节点主机本地模式例外:`gateway.remote.token` / `gateway.remote.password` 会被忽略。 -- 远程 probe/status token 检查默认是严格的:在面向远程模式时,它们仅使用 `gateway.remote.token`(不会回退到本地 token)。 +- 节点主机本地模式例外:会忽略 `gateway.remote.token` / `gateway.remote.password`。 +- 远程 probe / status token 检查默认是严格的:在目标为远程模式时,它们只使用 `gateway.remote.token`(不会回退到本地 token)。 - Gateway 网关环境覆盖仅使用 `OPENCLAW_GATEWAY_*`。 ## 通过 SSH 使用聊天 UI -WebChat 不再使用单独的 HTTP 端口。SwiftUI 聊天 UI 会直接连接到 Gateway 网关 WebSocket。 +WebChat 不再使用单独的 HTTP 端口。SwiftUI 聊天 UI 直接连接到 Gateway 网关 WebSocket。 - 通过 SSH 转发 `18789`(见上文),然后让客户端连接到 `ws://127.0.0.1:18789`。 -- 在 macOS 上,优先使用应用的“通过 SSH 远程访问”模式,它会自动管理隧道。 +- 在 macOS 上,优先使用应用的“通过 SSH 远程连接”模式,它会自动管理隧道。 -## macOS 应用“通过 SSH 远程访问” +## macOS 应用“通过 SSH 远程连接” macOS 菜单栏应用可以端到端驱动同一套设置(远程状态检查、WebChat 和 Voice Wake 转发)。 -操作手册: [macOS 远程访问](/zh-CN/platforms/mac/remote)。 +操作手册:[macOS 远程访问](/zh-CN/platforms/mac/remote)。 ## 安全规则(远程 / VPN) -简短版本:**除非你确定需要绑定,否则请让 Gateway 网关 保持仅回环访问。** +简短版本:**除非你确定需要 bind,否则请让 Gateway 网关仅绑定 loopback。** -- **回环 + SSH/Tailscale Serve** 是最安全的默认方式(不会公开暴露)。 -- 明文 `ws://` 默认仅限回环。对于受信任的私有网络, - 可在客户端进程上设置 `OPENCLAW_ALLOW_INSECURE_PRIVATE_WS=1` 作为紧急放行手段。 -- **非回环绑定**(`lan`/`tailnet`/`custom`,或当回环不可用时的 `auto`)必须使用 Gateway 网关认证:token、password,或带有 `gateway.auth.mode: "trusted-proxy"` 的身份感知反向代理。 +- **loopback + SSH / Tailscale Serve** 是最安全的默认方案(不会公开暴露)。 +- 默认情况下,明文 `ws://` 仅限 loopback。对于受信任的私有网络, + 在客户端进程上设置 `OPENCLAW_ALLOW_INSECURE_PRIVATE_WS=1` 作为紧急兜底。 + 没有对应的 `openclaw.json` 配置项;这必须设置在建立 WebSocket 连接的客户端进程 + 环境中。 +- **非 loopback 绑定**(`lan` / `tailnet` / `custom`,或在 loopback 不可用时使用 `auto`)必须启用 gateway 认证:token、password,或使用带有 `gateway.auth.mode: "trusted-proxy"` 的身份感知型反向代理。 - `gateway.remote.token` / `.password` 是客户端凭证来源。它们**不会**自行配置服务器认证。 -- 仅当 `gateway.auth.*` 未设置时,本地调用路径才可将 `gateway.remote.*` 作为回退。 -- 如果 `gateway.auth.token` / `gateway.auth.password` 通过 SecretRef 显式配置但无法解析,则解析会失败关闭(不会用远程回退进行掩盖)。 -- `gateway.remote.tlsFingerprint` 会在使用 `wss://` 时固定远程 TLS 证书。 -- **Tailscale Serve** 可以在 `gateway.auth.allowTailscale: true` 时,通过身份 - 标头为 Control UI/WebSocket 流量提供认证;HTTP API 端点不会 - 使用该 Tailscale 标头认证,而是遵循 Gateway 网关的常规 HTTP - 认证模式。这种无 token 流程假设 Gateway 网关主机是受信任的。如果你希望所有地方都使用共享密钥认证,请将其设为 - `false`。 -- **trusted-proxy** 认证仅适用于非回环、身份感知代理的部署场景。 - 同主机回环反向代理不满足 `gateway.auth.mode: "trusted-proxy"`。 -- 请将浏览器控制视为操作员访问:仅限 tailnet + 明确的节点配对。 +- 本地调用路径仅会在 `gateway.auth.*` 未设置时,将 `gateway.remote.*` 作为回退使用。 +- 如果通过 SecretRef 显式配置了 `gateway.auth.token` / `gateway.auth.password` 但未能解析,解析会以关闭方式失败(不会用远程回退来掩盖问题)。 +- 使用 `wss://` 时,`gateway.remote.tlsFingerprint` 会固定远程 TLS 证书。 +- 当 `gateway.auth.allowTailscale: true` 时,**Tailscale Serve** 可以通过身份 + 标头为控制 UI / WebSocket 流量进行认证;HTTP API 端点不会使用这种 Tailscale 标头认证, + 而是遵循 gateway 的常规 HTTP 认证模式。这个无 token 流程假设 gateway 主机是受信任的。 + 如果你希望所有位置都使用共享密钥认证,请将其设为 `false`。 +- **trusted-proxy** 认证仅适用于非 loopback 的身份感知型代理设置。 + 同主机的 loopback 反向代理不满足 `gateway.auth.mode: "trusted-proxy"` 的要求。 +- 请将浏览器控制视为操作端访问:仅限 tailnet + 经过有意的节点配对。 -深入说明: [安全性](/zh-CN/gateway/security)。 +深入说明:[安全性](/zh-CN/gateway/security)。 ### macOS:通过 LaunchAgent 持久化 SSH 隧道 -对于连接到远程 Gateway 网关的 macOS 客户端,最简单的持久化设置是使用 SSH `LocalForward` 配置项,再配合 LaunchAgent 让隧道在重启和崩溃后保持存活。 +对于连接到远程 gateway 的 macOS 客户端,最简单的持久化方案是使用 SSH `LocalForward` 配置项,再配合 LaunchAgent 在重启和崩溃后保持隧道存活。 #### 第 1 步:添加 SSH 配置 @@ -178,7 +179,7 @@ Host remote-gateway IdentityFile ~/.ssh/id_rsa ``` -将 `` 和 `` 替换为你的实际值。 +请将 `` 和 `` 替换为你的实际值。 #### 第 2 步:复制 SSH 密钥(一次性) @@ -186,9 +187,9 @@ Host remote-gateway ssh-copy-id -i ~/.ssh/id_rsa @ ``` -#### 第 3 步:配置 Gateway 网关 token +#### 第 3 步:配置 gateway token -将 token 存入配置,以便在重启后依然保留: +将 token 存储到配置中,以便它在重启后依然保留: ```bash openclaw config set gateway.remote.token "" @@ -225,9 +226,9 @@ openclaw config set gateway.remote.token "" launchctl bootstrap gui/$UID ~/Library/LaunchAgents/ai.openclaw.ssh-tunnel.plist ``` -该隧道会在登录时自动启动,在崩溃后自动重启,并保持转发端口持续可用。 +隧道会在登录时自动启动,在崩溃后自动重启,并保持转发端口处于可用状态。 -注意:如果你还有旧设置遗留的 `com.openclaw.ssh-tunnel` LaunchAgent,请先卸载并删除它。 +注意:如果你仍然保留旧设置遗留的 `com.openclaw.ssh-tunnel` LaunchAgent,请先卸载并删除它。 #### 故障排除 @@ -250,15 +251,15 @@ launchctl kickstart -k gui/$UID/ai.openclaw.ssh-tunnel launchctl bootout gui/$UID/ai.openclaw.ssh-tunnel ``` -| 配置项 | 作用 | +| 配置项 | 作用 | | ------------------------------------ | ------------------------------------------------------------ | -| `LocalForward 18789 127.0.0.1:18789` | 将本地端口 18789 转发到远程端口 18789 | -| `ssh -N` | SSH 连接但不执行远程命令(仅用于端口转发) | -| `KeepAlive` | 如果隧道崩溃则自动重启 | -| `RunAtLoad` | 在登录时 LaunchAgent 加载时启动隧道 | +| `LocalForward 18789 127.0.0.1:18789` | 将本地端口 18789 转发到远程端口 18789 | +| `ssh -N` | SSH 连接但不执行远程命令(仅用于端口转发) | +| `KeepAlive` | 如果隧道崩溃则自动重启 | +| `RunAtLoad` | 在登录时 LaunchAgent 加载后启动隧道 | ## 相关内容 - [Tailscale](/zh-CN/gateway/tailscale) -- [认证](/zh-CN/gateway/authentication) -- [远程 Gateway 网关设置](/zh-CN/gateway/remote-gateway-readme) +- [Authentication](/zh-CN/gateway/authentication) +- [Remote gateway setup](/zh-CN/gateway/remote-gateway-readme) diff --git a/docs/zh-CN/gateway/security/index.md b/docs/zh-CN/gateway/security/index.md index a20bec2ab..ba5384499 100644 --- a/docs/zh-CN/gateway/security/index.md +++ b/docs/zh-CN/gateway/security/index.md @@ -1,37 +1,35 @@ --- read_when: - - 添加会扩大访问范围或增强自动化的功能 + - 添加会扩大访问范围或自动化能力的功能 summary: 运行具有 shell 访问权限的 AI Gateway 网关时的安全注意事项和威胁模型 title: 安全性 x-i18n: - generated_at: "2026-04-23T18:24:11Z" + generated_at: "2026-04-24T06:43:46Z" model: gpt-5.4 provider: openai - source_hash: 9d0e79f3fd76d75e545f8e58883bd06ffbf48f909b4987e90d6bae72ad9808b3 + source_hash: 9e8cfc2bd0b4519f60d10b10b3496869a1668d57905926607f597aa34e4ce6de source_path: gateway/security/index.md workflow: 15 --- - **个人助理信任模型。** 本指南假定每个 Gateway 网关只有一个受信任的操作员边界(单用户、个人助理模型)。 - OpenClaw **并不是** 为多个对抗性用户共享同一个智能体或 Gateway 网关而设计的敌对多租户安全边界。 - 如果你需要混合信任或对抗性用户场景,请拆分信任边界(单独的 Gateway 网关 + 凭证,最好再配合单独的 OS 用户或主机)。 + **个人助理信任模型。** 本指南假设每个 Gateway 网关对应一个受信任的操作员边界(单用户、个人助理模型)。OpenClaw **并不是** 一个适用于多个对抗性用户共享同一个智能体或 Gateway 网关的敌对多租户安全边界。如果你需要混合信任或对抗性用户运行,请拆分信任边界(独立的 Gateway 网关 + 凭证,最好再配合独立的操作系统用户或主机)。 -## 先明确范围:个人助理安全模型 +## 先界定范围:个人助理安全模型 -OpenClaw 的安全指南基于**个人助理**部署模型:一个受信任的操作员边界,可包含多个智能体。 +OpenClaw 的安全指南假设采用**个人助理**部署方式:一个受信任的操作员边界,可以包含多个智能体。 -- 支持的安全姿态:每个 Gateway 网关对应一个用户/信任边界(最好每个边界使用单独的 OS 用户/主机/VPS)。 -- 不支持作为安全边界的场景:多个彼此不受信任或具有对抗关系的用户共享同一个 Gateway 网关/智能体。 -- 如果需要对抗性用户隔离,请按信任边界拆分(单独的 Gateway 网关 + 凭证,并且最好使用单独的 OS 用户/主机)。 -- 如果多个不受信任的用户都可以向同一个启用了工具的智能体发消息,应视为他们共享该智能体所委托的同一套工具权限。 +- 支持的安全姿态:每个 Gateway 网关对应一个用户/信任边界(最好每个边界使用独立的操作系统用户/主机/VPS)。 +- 不受支持的安全边界:多个互不信任或具有对抗关系的用户共享同一个 Gateway 网关/智能体。 +- 如果需要对抗性用户隔离,请按信任边界拆分(独立的 Gateway 网关 + 凭证,最好再配合独立的操作系统用户/主机)。 +- 如果多个不受信任的用户都可以向同一个启用了工具的智能体发送消息,应视为他们共享该智能体所委托的同一组工具权限。 -本页解释的是**在该模型内部**如何加固。它并不声称在一个共享 Gateway 网关上提供敌对多租户隔离。 +本页说明的是**在这一模型内**如何加固安全性。它并不声称单个共享 Gateway 网关具备敌对多租户隔离能力。 ## 快速检查:`openclaw security audit` -另请参阅:[Formal Verification(安全模型)](/zh-CN/security/formal-verification) +另请参阅:[Formal Verification(Security Models)](/zh-CN/security/formal-verification) 请定期运行此命令(尤其是在修改配置或暴露网络接口之后): @@ -42,96 +40,94 @@ openclaw security audit --fix openclaw security audit --json ``` -`security audit --fix` 有意保持较窄范围:它会将常见的开放群组策略切换为 allowlist,恢复 `logging.redactSensitive: "tools"`,收紧状态/配置/包含文件的权限,并且在 Windows 上运行时使用 Windows ACL 重置,而不是 POSIX `chmod`。 +`security audit --fix` 的修复范围刻意保持较窄:它会将常见的开放群组策略切换为 allowlist,恢复 `logging.redactSensitive: "tools"`,收紧状态/配置/包含文件的权限,并且在 Windows 上运行时会使用 Windows ACL 重置,而不是 POSIX `chmod`。 -它会标记常见陷阱(Gateway 网关认证暴露、浏览器控制暴露、提升权限的 allowlist、文件系统权限、宽松的 exec 审批,以及开放渠道的工具暴露)。 +它会标记常见的危险配置(Gateway 网关身份验证暴露、浏览器控制暴露、提升权限的 allowlist、文件系统权限、宽松的 exec 审批,以及开放渠道的工具暴露)。 -OpenClaw 既是一个产品,也是一个实验:你正在把前沿模型行为接入真实的消息界面和真实工具。**不存在“绝对安全”的配置。** 目标是有意识地明确以下几点: +OpenClaw 既是一个产品,也是一个实验:你正在将前沿模型行为接入真实的消息渠道和真实工具。**不存在“绝对安全”的配置。** 目标是有意识地明确: - 谁可以和你的机器人对话 -- 机器人可以在哪里执行操作 +- 机器人被允许在哪些地方执行操作 - 机器人可以接触哪些内容 -先从仍能满足需求的最小权限开始,随着信心提升再逐步放宽。 +从仍能满足需求的最小访问范围开始,随着你建立信心,再逐步扩大。 -### 部署与主机信任 +### 部署和主机信任 -OpenClaw 假定主机和配置边界是受信任的: +OpenClaw 假设主机和配置边界是受信任的: -- 如果有人可以修改 Gateway 网关主机状态/配置(`~/.openclaw`,包括 `openclaw.json`),就应将其视为受信任的操作员。 -- 为多个彼此不受信任/具有对抗关系的操作员运行同一个 Gateway 网关,**不是推荐的配置**。 -- 对于混合信任团队,请通过单独的 Gateway 网关(或至少单独的 OS 用户/主机)拆分信任边界。 -- 推荐默认方式:每台机器/主机(或 VPS)一个用户,该用户一个 Gateway 网关,该 Gateway 网关中运行一个或多个智能体。 -- 在同一个 Gateway 网关实例内部,经过认证的操作员访问属于受信任的控制平面角色,而不是按用户隔离的租户角色。 -- 会话标识符(`sessionKey`、会话 ID、标签)是路由选择器,不是授权令牌。 -- 如果多个人都可以向同一个启用了工具的智能体发消息,那么他们都可以驱动这同一套权限。按用户隔离会话/记忆有助于保护隐私,但并不能把共享智能体变成按用户划分的主机授权边界。 +- 如果某人可以修改 Gateway 网关主机状态/配置(`~/.openclaw`,包括 `openclaw.json`),就应将其视为受信任的操作员。 +- 让多个互不信任/具有对抗关系的操作员共享同一个 Gateway 网关**不是推荐的配置**。 +- 对于混合信任团队,请使用独立的 Gateway 网关 来拆分信任边界(或至少使用独立的操作系统用户/主机)。 +- 推荐的默认方式:每台机器/主机(或 VPS)一个用户,该用户一个 Gateway 网关,并在该 Gateway 网关中运行一个或多个智能体。 +- 在单个 Gateway 网关实例内部,经过身份验证的操作员访问属于受信任的控制平面角色,而不是按用户划分的租户角色。 +- 会话标识符(`sessionKey`、session ID、labels)是路由选择器,不是授权令牌。 +- 如果多个人都可以向同一个启用了工具的智能体发送消息,那么他们每个人都可以驱动这一组相同的权限。按用户隔离会话/内存有助于隐私,但并不会把共享智能体变成按用户划分的主机授权边界。 ### 共享 Slack 工作区:真实风险 -如果“Slack 里的所有人都可以给机器人发消息”,核心风险在于委托的工具权限: +如果“Slack 中所有人都可以给机器人发消息”,核心风险在于委托出去的工具权限: -- 任何被允许的发送者都可以在该智能体的策略范围内诱导工具调用(`exec`、浏览器、网络/文件工具); -- 来自某个发送者的提示词/内容注入,可能导致影响共享状态、设备或输出的操作; -- 如果某个共享智能体拥有敏感凭证/文件,任何被允许的发送者都可能通过工具使用驱动数据外泄。 +- 任何被允许的发送者都可以在智能体策略允许范围内触发工具调用(`exec`、浏览器、网络/文件工具); +- 来自某个发送者的提示词/内容注入可能导致影响共享状态、设备或输出的操作; +- 如果某个共享智能体拥有敏感凭证/文件,那么任何被允许的发送者都可能通过工具使用来驱动数据外流。 -对于团队工作流,请使用工具最少的独立智能体/Gateway 网关;涉及个人数据的智能体应保持私有。 +对于团队工作流,请使用工具最少化的独立智能体/Gateway 网关;处理个人数据的智能体应保持私有。 -### 公司共享智能体:可接受的模式 +### 公司共享智能体:可接受模式 -当使用该智能体的所有人都处于同一个信任边界内(例如同一家公司团队),并且该智能体严格限定在业务范围内时,这是可接受的。 +当使用该智能体的所有人都处于同一信任边界内(例如同一个公司团队),并且该智能体严格限定在业务范围内时,这是可接受的。 - 在专用机器/VM/容器上运行它; -- 为该运行环境使用专用 OS 用户 + 专用浏览器/配置文件/账号; -- 不要让该运行环境登录个人 Apple/Google 账号,或个人密码管理器/浏览器配置文件。 +- 为该运行时使用专用的操作系统用户 + 专用浏览器/配置文件/账号; +- 不要让该运行时登录个人 Apple/Google 账号,也不要使用个人密码管理器/浏览器配置文件。 -如果你在同一个运行环境中混用个人身份和公司身份,就会破坏隔离,并增加个人数据暴露风险。 +如果你在同一个运行时中混用个人身份和公司身份,就会打破隔离并提高个人数据暴露风险。 -## Gateway 网关与节点信任概念 +## Gateway 网关与 node 节点的信任概念 -请将 Gateway 网关和节点视为同一个操作员信任域中的不同角色: +应将 Gateway 网关和 node 节点视为同一个操作员信任域中的不同角色: - **Gateway 网关**是控制平面和策略界面(`gateway.auth`、工具策略、路由)。 -- **节点**是与该 Gateway 网关配对的远程执行界面(命令、设备操作、主机本地能力)。 -- 通过 Gateway 网关认证的调用方,在 Gateway 网关范围内是受信任的。完成配对后,节点操作就是该节点上的受信任操作员操作。 -- `sessionKey` 是路由/上下文选择机制,不是按用户划分的认证。 -- Exec 审批(allowlist + 询问)是用于表达操作员意图的护栏,而不是敌对多租户隔离。 -- OpenClaw 针对受信任单操作员场景的产品默认设置,是允许在 `gateway`/`node` 上无审批提示地执行主机 exec(`security="full"`、`ask="off"`,除非你主动收紧)。这是一种有意的 UX 默认值,本身并不是漏洞。 -- Exec 审批会绑定精确的请求上下文以及尽力识别的直接本地文件操作数;它不会对所有运行时/解释器加载路径做语义建模。若需要强边界,请使用沙箱隔离和主机隔离。 +- **Node 节点**是与该 Gateway 网关配对的远程执行界面(命令、设备操作、主机本地能力)。 +- 向 Gateway 网关通过身份验证的调用方,在 Gateway 网关作用域内是受信任的。完成配对后,node 节点上的操作就是该节点上的受信任操作员操作。 +- `sessionKey` 是路由/上下文选择器,不是按用户划分的身份验证。 +- Exec 审批(allowlist + 询问)是针对操作员意图的护栏,而不是敌对多租户隔离。 +- OpenClaw 针对受信任的单操作员配置的产品默认行为是:允许在 `gateway`/`node` 上执行主机 exec,且无需审批提示(`security="full"`,`ask="off"`,除非你手动收紧)。这一默认值是有意的 UX 设计,本身并不是漏洞。 +- Exec 审批会绑定精确的请求上下文以及尽力识别的直接本地文件操作数;它不会对每一种运行时/解释器加载路径进行语义建模。若要获得强边界,请使用沙箱隔离和主机隔离。 -如果你需要敌对用户隔离,请按 OS 用户/主机拆分信任边界,并运行单独的 Gateway 网关。 +如果你需要敌对用户隔离,请按操作系统用户/主机拆分信任边界,并运行独立的 Gateway 网关。 ## 信任边界矩阵 -在进行风险分级时,可将下表作为快速模型: +在进行风险研判时,可以把下表当作快速模型: -| 边界或控制项 | 含义 | 常见误解 | -| --- | --- | --- | -| `gateway.auth`(token/password/trusted-proxy/device auth) | 对 Gateway 网关 API 的调用方进行认证 | “要安全,就必须对每一帧消息都做逐条签名” | -| `sessionKey` | 用于上下文/会话选择的路由键 | “会话 key 是用户认证边界” | -| 提示词/内容护栏 | 降低模型被滥用的风险 | “仅凭提示词注入就足以证明认证绕过” | -| `canvas.eval` / 浏览器 evaluate | 启用时属于有意提供给操作员的能力 | “任何 JS eval 原语在这个信任模型中都自动属于漏洞” | +| 边界或控制 | 含义 | 常见误解 | +| --------------------------------------------------------- | ------------------------------------------------- | ----------------------------------------------------------------------------- | +| `gateway.auth`(token/password/trusted-proxy/device auth) | 对 Gateway 网关 API 的调用方进行身份验证 | “要想安全,就必须对每一帧消息都做逐条签名” | +| `sessionKey` | 用于上下文/会话选择的路由键 | “Session key 是用户身份验证边界” | +| 提示词/内容护栏 | 降低模型被滥用的风险 | “仅凭提示词注入就能证明存在身份验证绕过” | +| `canvas.eval` / 浏览器 evaluate | 启用时属于有意开放给操作员的能力 | “在这个信任模型下,任何 JS eval 原语自动都算漏洞” | | 本地 TUI `!` shell | 由操作员显式触发的本地执行 | “本地 shell 便捷命令就是远程注入” | -| 节点配对和节点命令 | 对已配对设备的操作员级远程执行 | “默认应将远程设备控制视为不受信任用户访问” | +| Node 配对和 node 命令 | 在已配对设备上的操作员级远程执行 | “远程设备控制默认应视为不受信任用户访问” | ## 按设计不视为漏洞的情况 - - 这些模式经常被报告;除非能证明真实的边界绕过,否则通常会被关闭且不采取行动: + + 这些模式经常被报告,但通常都会作为无须处理关闭,除非能证明存在真实的边界绕过: -- 只有提示词注入链条,但没有策略、认证或沙箱绕过。 -- 基于同一共享主机或配置上存在敌对多租户运行这一前提提出的说法。 -- 将正常的操作员读取路径访问(例如 - `sessions.list` / `sessions.preview` / `chat.history`)在共享 Gateway 网关配置中归类为 IDOR 的说法。 -- 仅限 localhost 的部署发现(例如仅 loopback Gateway 网关上的 HSTS)。 +- 仅包含提示词注入链,但没有策略、身份验证或沙箱绕过。 +- 假设在同一个共享主机或共享配置上进行敌对多租户运行的指控。 +- 将共享 Gateway 网关 配置中的正常操作员读取路径访问(例如 `sessions.list` / `sessions.preview` / `chat.history`)归类为 IDOR 的指控。 +- 仅限 localhost 部署的发现(例如仅 loopback Gateway 网关缺少 HSTS)。 - 针对本仓库中并不存在的入站路径而提出的 Discord 入站 webhook 签名问题。 -- 将节点配对元数据误当成 `system.run` 的隐藏二级逐命令审批层的报告,而真实执行边界仍然是 Gateway 网关的全局节点命令策略,加上节点自身的 exec - 审批。 -- 将 `sessionKey` 视为认证令牌的“缺少逐用户授权”发现。 +- 将 node 配对元数据视为 `system.run` 的隐藏第二层逐命令审批,而实际上真正的执行边界仍是 Gateway 网关的全局 node 命令策略加上 node 节点自身的 exec 审批。 +- 将 `sessionKey` 当作身份验证令牌,从而得出“缺少按用户授权”的结论。 -## 60 秒内完成的加固基线 +## 60 秒内建立加固基线 -请先使用这套基线,然后再按受信任智能体有选择地重新启用工具: +先使用这个基线,然后再按受信任智能体逐项重新启用工具: ```json5 { @@ -156,65 +152,65 @@ OpenClaw 假定主机和配置边界是受信任的: } ``` -这会将 Gateway 网关保持为仅本地访问、隔离私信,并默认禁用控制平面/运行时工具。 +这样会让 Gateway 网关仅在本地可访问,隔离私信,并默认禁用控制平面/运行时工具。 ## 共享收件箱快速规则 -如果不止一个人可以私信你的机器人: +如果不止一个人可以向你的机器人发送私信: - 设置 `session.dmScope: "per-channel-peer"`(多账号渠道则使用 `"per-account-channel-peer"`)。 - 保持 `dmPolicy: "pairing"` 或使用严格的 allowlist。 -- 绝不要将共享私信与广泛的工具访问权限结合使用。 -- 这能加固协作式/共享收件箱,但在用户共享主机/配置写入权限时,并不是为敌对共租户隔离而设计的。 +- 绝不要把共享私信和广泛的工具访问权限组合在一起。 +- 这有助于加固协作式/共享收件箱,但并不是为在用户共享主机/配置写权限时提供敌对共租户隔离而设计的。 ## 上下文可见性模型 -OpenClaw 区分两个概念: +OpenClaw 将两个概念区分开来: -- **触发授权**:谁可以触发智能体(`dmPolicy`、`groupPolicy`、allowlist、提及门控)。 +- **触发授权**:谁可以触发智能体(`dmPolicy`、`groupPolicy`、allowlist、提及门槛)。 - **上下文可见性**:哪些补充上下文会被注入到模型输入中(回复正文、引用文本、线程历史、转发元数据)。 -Allowlists 用于控制触发和命令授权。`contextVisibility` 设置则控制补充上下文(引用回复、线程根消息、获取到的历史记录)的过滤方式: +Allowlist 控制触发和命令授权。`contextVisibility` 设置控制补充上下文(引用回复、线程根消息、拉取的历史记录)如何被过滤: -- `contextVisibility: "all"`(默认)会保留收到的全部补充上下文。 +- `contextVisibility: "all"`(默认)会按接收到的原样保留补充上下文。 - `contextVisibility: "allowlist"` 会将补充上下文过滤为仅包含通过当前 allowlist 检查的发送者内容。 -- `contextVisibility: "allowlist_quote"` 的行为与 `allowlist` 相同,但仍会保留一条显式引用的回复。 +- `contextVisibility: "allowlist_quote"` 的行为类似 `allowlist`,但仍会保留一条显式引用回复。 -你可以按渠道或按房间/会话设置 `contextVisibility`。有关配置细节,请参阅 [Group Chats](/zh-CN/channels/groups#context-visibility-and-allowlists)。 +你可以按渠道或按房间/会话设置 `contextVisibility`。配置细节见 [Group Chats](/zh-CN/channels/groups#context-visibility-and-allowlists)。 -安全分诊指导: +安全通告分级处理指南: -- 如果某个报告仅表明“模型可以看到来自未在 allowlist 中发送者的引用或历史文本”,那么这属于可通过 `contextVisibility` 解决的加固问题,而不是认证或沙箱边界绕过本身。 -- 若要构成安全影响,报告仍需要证明存在实际的信任边界绕过(认证、策略、沙箱、审批,或其他已记录的边界)。 +- 如果报告仅表明“模型可以看到来自未列入 allowlist 的发送者的引用文本或历史文本”,这属于可以通过 `contextVisibility` 解决的加固发现,而不是身份验证或沙箱边界本身被绕过。 +- 若要构成真正具有安全影响的问题,报告仍需证明存在信任边界绕过(身份验证、策略、沙箱、审批,或其他文档化边界)。 -## 审计会检查什么(高级概览) +## 审计会检查什么(高层概览) -- **入站访问**(私信策略、群组策略、allowlist):陌生人能否触发机器人? -- **工具影响半径**(提升权限工具 + 开放房间):提示词注入是否可能演变成 shell/文件/网络操作? -- **Exec 审批漂移**(`security=full`、`autoAllowSkills`、未启用 `strictInlineEval` 的解释器 allowlist):主机 exec 护栏是否仍按你的预期工作? - - `security="full"` 是广义姿态警告,不代表一定存在 bug。它是受信任个人助理部署的默认选择;只有当你的威胁模型确实需要审批或 allowlist 护栏时,才应收紧。 -- **网络暴露面**(Gateway 网关 bind/auth、Tailscale Serve/Funnel、弱或过短的认证 token)。 -- **浏览器控制暴露面**(远程节点、中继端口、远程 CDP 端点)。 +- **入站访问**(私信策略、群组策略、allowlist):陌生人能否触发这个机器人? +- **工具爆炸半径**(高权限工具 + 开放房间):提示词注入是否可能演变为 shell / 文件 / 网络操作? +- **Exec 审批漂移**(`security=full`、`autoAllowSkills`、未启用 `strictInlineEval` 的解释器 allowlist):主机 exec 护栏是否仍然按你的预期生效? + - `security="full"` 是一种宽泛的姿态警告,不代表一定存在 bug。它是受信任个人助理配置的默认选择;只有当你的威胁模型需要审批或 allowlist 护栏时,才需要收紧它。 +- **网络暴露**(Gateway 网关 bind/auth、Tailscale Serve/Funnel、弱或过短的身份验证 token)。 +- **浏览器控制暴露**(远程 node 节点、中继端口、远程 CDP 端点)。 - **本地磁盘卫生**(权限、符号链接、配置 include、 “synced folder” 路径)。 - **插件**(插件在没有显式 allowlist 的情况下加载)。 -- **策略漂移/配置错误**(已配置沙箱 Docker 设置但沙箱模式关闭;无效的 `gateway.nodes.denyCommands` 模式,因为匹配仅限精确命令名,例如 `system.run`,不会检查 shell 文本;危险的 `gateway.nodes.allowCommands` 条目;全局 `tools.profile="minimal"` 被按智能体配置的 profile 覆盖;在宽松工具策略下可访问插件自有工具)。 -- **运行时期望漂移**(例如假设隐式 exec 仍表示 `sandbox`,但 `tools.exec.host` 现在默认是 `auto`;或显式设置 `tools.exec.host="sandbox"`,但沙箱模式其实已关闭)。 -- **模型卫生**(当已配置模型看起来较旧时发出警告;不是硬阻断)。 +- **策略漂移/配置错误**(已配置沙箱 Docker 设置但沙箱模式关闭;无效的 `gateway.nodes.denyCommands` 模式,因为匹配仅针对精确命令名生效——例如 `system.run`——而不会检查 shell 文本;危险的 `gateway.nodes.allowCommands` 条目;全局 `tools.profile="minimal"` 被按智能体配置覆盖;插件拥有的工具在宽松工具策略下可被访问)。 +- **运行时期望漂移**(例如假设隐式 exec 仍然表示 `sandbox`,而 `tools.exec.host` 现在默认是 `auto`;或者显式设置 `tools.exec.host="sandbox"`,但沙箱模式处于关闭状态)。 +- **模型卫生**(当配置的模型看起来过旧时发出警告;不是硬性阻止)。 -如果你运行 `--deep`,OpenClaw 还会尽力对在线 Gateway 网关进行探测。 +如果你运行 `--deep`,OpenClaw 还会尽力尝试进行实时 Gateway 网关探测。 ## 凭证存储映射 -在审计访问权限或决定哪些内容需要备份时,可使用此清单: +在审计访问权限或决定备份内容时,可参考此清单: - **WhatsApp**:`~/.openclaw/credentials/whatsapp//creds.json` -- **Telegram 机器人 token**:配置/环境变量,或 `channels.telegram.tokenFile`(仅允许常规文件;拒绝符号链接) -- **Discord 机器人 token**:配置/环境变量,或 SecretRef(env/file/exec 提供商) +- **Telegram bot token**:配置/环境变量,或 `channels.telegram.tokenFile`(仅允许常规文件;拒绝符号链接) +- **Discord bot token**:配置/环境变量,或 SecretRef(env/file/exec 提供商) - **Slack tokens**:配置/环境变量(`channels.slack.*`) -- **Pairing allowlists**: +- **配对 allowlist**: - `~/.openclaw/credentials/-allowFrom.json`(默认账号) - `~/.openclaw/credentials/--allowFrom.json`(非默认账号) -- **模型认证配置文件**:`~/.openclaw/agents//agent/auth-profiles.json` +- **模型 auth 配置文件**:`~/.openclaw/agents//agent/auth-profiles.json` - **基于文件的 secrets 负载(可选)**:`~/.openclaw/secrets.json` - **旧版 OAuth 导入**:`~/.openclaw/credentials/oauth.json` @@ -222,54 +218,54 @@ Allowlists 用于控制触发和命令授权。`contextVisibility` 设置则控 当审计输出发现项时,请按以下优先级处理: -1. **任何“开放” + 已启用工具**:先锁定私信/群组(pairing/allowlists),然后收紧工具策略/沙箱隔离。 -2. **公共网络暴露**(LAN bind、Funnel、缺少认证):立即修复。 -3. **浏览器控制的远程暴露**:将其视为操作员访问权限(仅 tailnet、谨慎配对节点、避免公开暴露)。 -4. **权限**:确保状态/配置/凭证/认证信息对 group/world 不可读。 -5. **插件**:只加载你明确信任的插件。 -6. **模型选择**:任何启用了工具的机器人都应优先使用现代、具备更强指令抗性的模型。 +1. **任何“开放”状态 + 已启用工具**:先锁定私信/群组(配对/allowlist),再收紧工具策略/沙箱隔离。 +2. **公共网络暴露**(LAN 绑定、Funnel、缺少身份验证):立即修复。 +3. **浏览器控制的远程暴露**:应将其视为操作员访问(仅 tailnet、谨慎配对 node 节点、避免公开暴露)。 +4. **权限**:确保状态/配置/凭证/auth 不可被组用户或所有人读取。 +5. **插件**:只加载你明确信任的内容。 +6. **模型选择**:对于任何启用了工具的机器人,优先使用现代、具备更强指令加固能力的模型。 ## 安全审计术语表 -每个审计发现项都带有结构化的 `checkId`(例如 -`gateway.bind_no_auth` 或 `tools.exec.security_full_configured`)。常见的高严重性类别包括: +每条审计发现都会使用结构化的 `checkId` 作为键(例如 +`gateway.bind_no_auth` 或 `tools.exec.security_full_configured`)。常见的严重等级类别包括: -- `fs.*` — 状态、配置、凭证、认证配置文件的文件系统权限。 -- `gateway.*` — bind 模式、认证、Tailscale、Control UI、trusted-proxy 设置。 -- `hooks.*`、`browser.*`、`sandbox.*`、`tools.exec.*` — 各个暴露面的加固检查。 -- `plugins.*`、`skills.*` — 插件/skill 供应链和扫描发现。 -- `security.exposure.*` — 访问策略与工具影响半径交叉产生的综合检查。 +- `fs.*` —— 状态、配置、凭证、auth 配置文件的文件系统权限。 +- `gateway.*` —— bind 模式、auth、Tailscale、Control UI、trusted-proxy 设置。 +- `hooks.*`、`browser.*`、`sandbox.*`、`tools.exec.*` —— 各个界面的加固检查。 +- `plugins.*`、`skills.*` —— 插件/Skills 供应链和扫描发现。 +- `security.exposure.*` —— 访问策略与工具爆炸半径相交的跨领域检查。 -完整目录、严重级别、修复键名以及自动修复支持,请参阅 +完整目录(包括严重等级、修复键和自动修复支持)见 [Security audit checks](/zh-CN/gateway/security/audit-checks)。 ## 通过 HTTP 使用 Control UI -Control UI 需要**安全上下文**(HTTPS 或 localhost)来生成设备身份。 +Control UI 需要一个**安全上下文**(HTTPS 或 localhost)才能生成设备身份。 `gateway.controlUi.allowInsecureAuth` 是一个本地兼容性开关: -- 在 localhost 上,当页面通过非安全 HTTP 加载时,它允许 Control UI 在没有设备身份的情况下完成认证。 -- 它不会绕过 pairing 检查。 +- 在 localhost 上,当页面通过非安全 HTTP 加载时,它允许 Control UI 在没有设备身份的情况下进行 auth。 +- 它不会绕过配对检查。 - 它不会放宽远程(非 localhost)设备身份要求。 -优先使用 HTTPS(Tailscale Serve),或在 `127.0.0.1` 上打开 UI。 +优先使用 HTTPS(Tailscale Serve),或者在 `127.0.0.1` 上打开 UI。 -仅用于紧急破玻璃场景时,`gateway.controlUi.dangerouslyDisableDeviceAuth` -会完全禁用设备身份检查。这会严重降低安全性;除非你正在主动调试且能够迅速恢复,否则请保持关闭。 +仅在紧急破窗场景下,`gateway.controlUi.dangerouslyDisableDeviceAuth` +会完全禁用设备身份检查。这会严重降低安全性;除非你正在主动调试并且能很快回滚,否则请保持关闭。 -与这些危险标志分开的是,成功配置 `gateway.auth.mode: "trusted-proxy"` -可以让**操作员** Control UI 会话在没有设备身份的情况下通过。这是有意设计的认证模式行为,不是 `allowInsecureAuth` 的捷径,而且它仍然 +与这些危险标志分开的是,成功的 `gateway.auth.mode: "trusted-proxy"` +可以在没有设备身份的情况下允许**操作员** Control UI 会话。这是有意设计的 auth 模式行为,不是 `allowInsecureAuth` 的捷径,并且仍然 不适用于 node 角色的 Control UI 会话。 当此设置启用时,`openclaw security audit` 会发出警告。 ## 不安全或危险标志摘要 -当已知的不安全/危险调试开关被启用时,`openclaw security audit` 会报告 `config.insecure_or_dangerous_flags`。 -在生产环境中请保持这些设置未启用。 +当已知的不安全/危险调试开关被启用时, +`openclaw security audit` 会报告 `config.insecure_or_dangerous_flags`。在生产环境中请保持这些设置未启用。 - + - `gateway.controlUi.allowInsecureAuth=true` - `gateway.controlUi.dangerouslyAllowHostHeaderOriginFallback=true` - `gateway.controlUi.dangerouslyDisableDeviceAuth=true` @@ -286,8 +282,8 @@ Control UI 需要**安全上下文**(HTTPS 或 localhost)来生成设备身 - `gateway.controlUi.dangerouslyDisableDeviceAuth` - `browser.ssrfPolicy.dangerouslyAllowPrivateNetwork` - 渠道名称匹配(内置渠道和插件渠道;如适用,也可在每个 - `accounts.` 下设置): + 渠道名称匹配(内置渠道和插件渠道;在适用情况下,也可按 + `accounts.` 单独设置): - `channels.discord.dangerouslyAllowNameMatching` - `channels.slack.dangerouslyAllowNameMatching` @@ -299,9 +295,9 @@ Control UI 需要**安全上下文**(HTTPS 或 localhost)来生成设备身 - `channels.irc.dangerouslyAllowNameMatching`(插件渠道) - `channels.mattermost.dangerouslyAllowNameMatching`(插件渠道) - 网络暴露面: + 网络暴露: - - `channels.telegram.network.dangerouslyAllowPrivateNetwork`(也可按账号设置) + - `channels.telegram.network.dangerouslyAllowPrivateNetwork`(也支持按账号设置) 沙箱 Docker(默认值 + 按智能体设置): @@ -314,30 +310,30 @@ Control UI 需要**安全上下文**(HTTPS 或 localhost)来生成设备身 ## 反向代理配置 -如果你在反向代理(nginx、Caddy、Traefik 等)后运行 Gateway 网关,请配置 -`gateway.trustedProxies`,以正确处理转发后的客户端 IP。 +如果你在反向代理(nginx、Caddy、Traefik 等)后面运行 Gateway 网关,请配置 +`gateway.trustedProxies`,以正确处理转发的客户端 IP。 -当 Gateway 网关检测到来自**不在** `trustedProxies` 中地址的代理头时,它将**不会**把连接视为本地客户端。如果 Gateway 网关认证被禁用,这些连接会被拒绝。这样可以防止认证绕过,因为否则经代理转发的连接可能看起来像来自 localhost,从而自动获得信任。 +当 Gateway 网关检测到来自**不在** `trustedProxies` 中的地址的代理头时,它将**不会**把连接视为本地客户端。如果 Gateway 网关 auth 被禁用,这些连接会被拒绝。这可以防止身份验证绕过:否则,被代理的连接可能会看起来来自 localhost,从而自动获得信任。 -`gateway.trustedProxies` 也会用于 `gateway.auth.mode: "trusted-proxy"`,但该认证模式更加严格: +`gateway.trustedProxies` 也会供 `gateway.auth.mode: "trusted-proxy"` 使用,但这种 auth 模式更严格: -- trusted-proxy auth **对 loopback 来源代理采取失败即拒绝** -- 同主机上的 loopback 反向代理仍可使用 `gateway.trustedProxies` 进行本地客户端识别和转发 IP 处理 -- 对于同主机上的 loopback 反向代理,请使用 token/password 认证,而不是 `gateway.auth.mode: "trusted-proxy"` +- trusted-proxy auth **对来自 loopback 源的代理采用失败即关闭** +- 同主机上的 loopback 反向代理仍然可以使用 `gateway.trustedProxies` 进行本地客户端检测和转发 IP 处理 +- 对于同主机上的 loopback 反向代理,请使用 token/password auth,而不是 `gateway.auth.mode: "trusted-proxy"` ```yaml gateway: trustedProxies: - - "10.0.0.1" # 反向代理 IP - # 可选。默认 false。 - # 仅在你的代理无法提供 X-Forwarded-For 时启用。 + - "10.0.0.1" # reverse proxy IP + # 可选。默认为 false。 + # 仅当你的代理无法提供 X-Forwarded-For 时才启用。 allowRealIpFallback: false auth: mode: password password: ${OPENCLAW_GATEWAY_PASSWORD} ``` -配置了 `trustedProxies` 后,Gateway 网关会使用 `X-Forwarded-For` 来确定客户端 IP。默认会忽略 `X-Real-IP`,除非明确设置 `gateway.allowRealIpFallback: true`。 +当配置了 `trustedProxies` 时,Gateway 网关会使用 `X-Forwarded-For` 来确定客户端 IP。默认会忽略 `X-Real-IP`,除非明确设置 `gateway.allowRealIpFallback: true`。 良好的反向代理行为(覆盖传入的转发头): @@ -352,54 +348,52 @@ proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; ``` -## HSTS 与来源说明 +## HSTS 和 origin 说明 -- OpenClaw Gateway 网关优先用于本地/loopback。如果你在反向代理处终止 TLS,请在代理对外的 HTTPS 域名上设置 HSTS。 +- OpenClaw Gateway 网关优先面向本地/loopback。如果你在反向代理处终止 TLS,请在那里为面向代理的 HTTPS 域设置 HSTS。 - 如果由 Gateway 网关自身终止 HTTPS,你可以设置 `gateway.http.securityHeaders.strictTransportSecurity`,让 OpenClaw 在响应中发出 HSTS 头。 - 详细部署指南见 [Trusted Proxy Auth](/zh-CN/gateway/trusted-proxy-auth#tls-termination-and-hsts)。 -- 对于非 loopback 的 Control UI 部署,默认要求配置 `gateway.controlUi.allowedOrigins`。 -- `gateway.controlUi.allowedOrigins: ["*"]` 是显式允许所有浏览器来源的策略,不是加固默认值。除非是在严格受控的本地测试中,否则应避免使用。 -- 即使启用了通用的 loopback 豁免,loopback 上的浏览器来源认证失败仍会被限速,但锁定键是按规范化后的 `Origin` 值划分,而不是共享一个 localhost 桶。 -- `gateway.controlUi.dangerouslyAllowHostHeaderOriginFallback=true` 会启用 Host 头来源回退模式;应将其视为由操作员主动选择的危险策略。 -- 请将 DNS rebinding 和代理 Host 头行为视为部署加固问题;保持 `trustedProxies` 尽量精确,并避免将 Gateway 网关直接暴露到公共互联网。 +- 对于非 loopback 的 Control UI 部署,默认要求设置 `gateway.controlUi.allowedOrigins`。 +- `gateway.controlUi.allowedOrigins: ["*"]` 是显式允许所有浏览器来源的策略,不是加固后的默认值。除非是在严格受控的本地测试中,否则应避免使用。 +- 即使启用了通用的 loopback 豁免,loopback 上的浏览器来源 auth 失败仍会受到速率限制,但锁定键会按规范化后的 `Origin` 值进行范围划分,而不是共享一个 localhost 桶。 +- `gateway.controlUi.dangerouslyAllowHostHeaderOriginFallback=true` 会启用 Host 头 origin 回退模式;应将其视为由操作员主动选择的危险策略。 +- 应将 DNS 重绑定和代理 Host 头行为视为部署加固问题;保持 `trustedProxies` 严格,并避免将 Gateway 网关直接暴露到公共互联网。 ## 本地会话日志存储在磁盘上 -OpenClaw 会将会话转录记录存储在磁盘上的 `~/.openclaw/agents//sessions/*.jsonl`。 -这是会话连续性以及(可选)会话记忆索引所必需的,但这也意味着 -**任何拥有文件系统访问权限的进程/用户都可以读取这些日志**。请将磁盘访问视为信任 -边界,并收紧 `~/.openclaw` 的权限(见下方审计部分)。如果你需要在智能体之间实现 -更强的隔离,请让它们运行在不同的 OS 用户或不同主机下。 +OpenClaw 会将会话转录存储到磁盘上的 `~/.openclaw/agents//sessions/*.jsonl`。 +这对于会话连续性以及(可选的)会话记忆索引是必需的,但这也意味着 +**任何拥有文件系统访问权限的进程/用户都可以读取这些日志**。应将磁盘访问视为信任 +边界,并锁定 `~/.openclaw` 的权限(参见下方审计部分)。如果你需要在智能体之间实现 +更强隔离,请让它们运行在独立的操作系统用户下,或使用独立主机。 -## 节点执行(`system.run`) +## Node 执行(system.run) -如果已配对 macOS 节点,Gateway 网关可以在该节点上调用 `system.run`。这属于**在该 Mac 上的远程代码执行**: +如果已配对 macOS node 节点,Gateway 网关就可以在该节点上调用 `system.run`。这属于 **Mac 上的远程代码执行**: -- 需要节点配对(审批 + token)。 -- Gateway 网关节点配对不是逐命令审批界面。它用于建立节点身份/信任并签发 token。 -- Gateway 网关通过 `gateway.nodes.allowCommands` / `denyCommands` 应用粗粒度的全局节点命令策略。 -- 在 Mac 上通过**设置 → Exec 审批**控制(security + ask + allowlist)。 -- 每个节点的 `system.run` 策略由节点自己的 exec 审批文件(`exec.approvals.node.*`)决定,它可以比 Gateway 网关的全局命令 ID 策略更严格,也可以更宽松。 -- 以 `security="full"` 和 `ask="off"` 运行的节点,遵循的是默认的受信任操作员模型。除非你的部署明确要求更严格的审批或 allowlist 策略,否则应将其视为预期行为。 -- 审批模式会绑定精确的请求上下文,并在可能时绑定一个具体的本地脚本/文件操作数。如果 OpenClaw 无法为解释器/运行时命令准确识别出唯一一个直接本地文件,那么基于审批的执行会被拒绝,而不是承诺提供完整的语义覆盖。 -- 对于 `host=node`,基于审批的运行还会存储一个规范化的预处理 - `systemRunPlan`;后续已批准的转发会复用这个已存储计划,而 Gateway 网关 - 验证会拒绝调用方在审批请求创建之后对 command/cwd/session 上下文的修改。 -- 如果你不希望进行远程执行,请将 security 设置为 **deny**,并移除该 Mac 的节点配对。 +- 需要 node 配对(审批 + token)。 +- Gateway 网关的 node 配对不是逐命令审批界面。它建立的是 node 身份/信任以及 token 签发。 +- Gateway 网关通过 `gateway.nodes.allowCommands` / `denyCommands` 应用粗粒度的全局 node 命令策略。 +- 在 Mac 上通过**设置 → Exec 审批**进行控制(security + ask + allowlist)。 +- 每个 node 的 `system.run` 策略由该 node 自身的 exec 审批文件(`exec.approvals.node.*`)控制,它可以比 Gateway 网关的全局命令 ID 策略更严格,也可以更宽松。 +- 以 `security="full"` 和 `ask="off"` 运行的 node 节点是在遵循默认的受信任操作员模型。除非你的部署明确需要更严格的审批或 allowlist 策略,否则应将其视为预期行为。 +- 审批模式会绑定精确的请求上下文,并在可能时绑定一个具体的本地脚本/文件操作数。如果 OpenClaw 无法为某个解释器/运行时命令精确识别唯一的直接本地文件,则会拒绝基于审批的执行,而不会声称提供完整的语义覆盖。 +- 对于 `host=node`,基于审批的运行还会存储一个规范化的预处理 `systemRunPlan`;之后获得批准的转发会复用该已存储计划,并且 Gateway 网关验证会拒绝在审批请求创建后由调用方修改命令/cwd/session 上下文。 +- 如果你不希望远程执行,请将 security 设为 **deny**,并移除该 Mac 的 node 配对。 -这一差别对安全分诊非常重要: +这个区别在分级研判时很重要: -- 已配对节点重新连接后宣告了不同的命令列表,这本身并不构成漏洞,前提是 Gateway 网关的全局策略和节点本地 exec 审批仍然在真正的执行边界上生效。 -- 把节点配对元数据当成第二层隐藏的逐命令审批层的报告,通常属于策略/UX 理解混淆,而不是安全边界绕过。 +- 一个重新连接的已配对 node 节点通告了不同的命令列表,这本身并不构成漏洞,只要 Gateway 网关全局策略和 node 节点本地 exec 审批仍然强制执行真实的执行边界。 +- 将 node 配对元数据视为隐藏的第二层逐命令审批界面的报告,通常属于策略/UX 理解混淆,而不是安全边界绕过。 -## 动态 Skills(watcher / 远程节点) +## 动态 Skills(watcher / 远程 node 节点) OpenClaw 可以在会话中途刷新 Skills 列表: - **Skills watcher**:对 `SKILL.md` 的更改可以在智能体下一轮处理时更新 Skills 快照。 -- **远程节点**:连接 macOS 节点后,macOS 专属 Skills 可能变为可用(基于二进制探测结果)。 +- **远程 node 节点**:连接 macOS node 节点后,可能会使仅限 macOS 的 Skills 变为可用(基于 bin 探测)。 -请将 skill 文件夹视为**受信任代码**,并限制谁可以修改它们。 +应将 skill 文件夹视为**受信任代码**,并限制谁可以修改它们。 ## 威胁模型 @@ -408,46 +402,46 @@ OpenClaw 可以在会话中途刷新 Skills 列表: - 执行任意 shell 命令 - 读写文件 - 访问网络服务 -- 给任何人发送消息(如果你赋予它 WhatsApp 访问权限) +- 向任何人发送消息(如果你赋予了它 WhatsApp 访问权限) -向你发消息的人可以: +给你发消息的人可以: -- 试图诱骗你的 AI 做坏事 -- 通过社工手段获取你的数据访问权限 -- 探测你的基础设施细节 +- 试图诱骗你的 AI 执行有害操作 +- 通过社会工程获取你的数据访问权限 +- 探查基础设施细节 ## 核心概念:先做访问控制,再谈智能 -这里的大多数失败并不是什么高级利用,而是“有人给机器人发了消息,然后机器人照做了”。 +这里的大多数失败并不是什么花哨的漏洞利用——而是“有人给机器人发了消息,然后机器人照做了”。 OpenClaw 的立场是: -- **身份优先:**先决定谁可以和机器人对话(私信 pairing / allowlists / 显式 “open”)。 -- **范围其次:**再决定机器人被允许在哪里行动(群组 allowlists + 提及门控、工具、沙箱隔离、设备权限)。 -- **模型最后:**假设模型可以被操纵;设计时要让操纵的影响半径保持有限。 +- **先身份**:决定谁可以和机器人对话(DM 配对 / allowlist / 显式 `open`)。 +- **再范围**:决定机器人被允许在哪里执行操作(群组 allowlist + 提及门槛、工具、沙箱隔离、设备权限)。 +- **最后才是模型**:假设模型可能被操控;要把系统设计成即使被操控,爆炸半径也有限。 ## 命令授权模型 -斜杠命令和指令只会对**已授权发送者**生效。授权来源于 -渠道 allowlists/pairing 加上 `commands.useAccessGroups`(参见 [Configuration](/zh-CN/gateway/configuration) +斜杠命令和指令仅对**已授权发送者**生效。授权来源于 +渠道 allowlist/配对以及 `commands.useAccessGroups`(参见 [Configuration](/zh-CN/gateway/configuration) 和 [Slash commands](/zh-CN/tools/slash-commands))。如果某个渠道的 allowlist 为空或包含 `"*"`, -那么该渠道中的命令实际上就是开放的。 +那么该渠道的命令实际上就是开放的。 -`/exec` 是仅限会话使用的授权操作员便捷命令。它**不会**写入配置,也 +`/exec` 是面向已授权操作员的仅会话便捷功能。它**不会**写入配置,也 不会更改其他会话。 ## 控制平面工具风险 -有两个内置工具可以进行持久性的控制平面变更: +有两个内置工具可以进行持久化的控制平面更改: -- `gateway` 可以通过 `config.schema.lookup` / `config.get` 检查配置,并可通过 `config.apply`、`config.patch` 和 `update.run` 进行持久化修改。 -- `cron` 可以创建定时任务,这些任务会在原始聊天/任务结束后继续运行。 +- `gateway` 可以通过 `config.schema.lookup` / `config.get` 检查配置,并可以通过 `config.apply`、`config.patch` 和 `update.run` 进行持久化更改。 +- `cron` 可以创建定时任务,使其在原始聊天/任务结束后继续运行。 -仅限所有者的 `gateway` 运行时工具仍然拒绝改写 -`tools.exec.ask` 或 `tools.exec.security`;旧版 `tools.bash.*` 别名会 -先被规范化到同样受保护的 exec 路径,再进行写入。 +仅 owner 可用的 `gateway` 运行时工具仍然拒绝重写 +`tools.exec.ask` 或 `tools.exec.security`;旧版 `tools.bash.*` 别名会在写入前 +被规范化到同样受保护的 exec 路径。 -对于任何会处理不受信任内容的智能体/界面,默认都应禁用这些工具: +对于任何处理不受信任内容的智能体/界面,默认应禁用这些工具: ```json5 { @@ -457,36 +451,36 @@ OpenClaw 的立场是: } ``` -`commands.restart=false` 只会阻止重启动作。它不会禁用 `gateway` 的配置/更新操作。 +`commands.restart=false` 只会阻止重启操作。它不会禁用 `gateway` 的配置/更新操作。 ## 插件 -插件会与 Gateway 网关**在同一进程内**运行。请将其视为受信任代码: +插件会**在进程内**与 Gateway 网关一起运行。应将其视为受信任代码: - 只安装来自你信任来源的插件。 -- 优先使用显式的 `plugins.allow` allowlist。 -- 启用前检查插件配置。 -- 插件变更后重启 Gateway 网关。 +- 优先使用显式 `plugins.allow` allowlist。 +- 启用前先审查插件配置。 +- 修改插件后重启 Gateway 网关。 - 如果你安装或更新插件(`openclaw plugins install `、`openclaw plugins update `),应将其视为运行不受信任代码: - - 安装路径是当前插件安装根目录下的对应插件目录。 - - OpenClaw 会在安装/更新前运行内置的危险代码扫描。`critical` 级发现默认会阻止继续。 - - OpenClaw 会使用 `npm pack`,然后在该目录中运行 `npm install --omit=dev`(npm 生命周期脚本可能在安装期间执行代码)。 - - 优先使用固定的精确版本(`@scope/pkg@1.2.3`),并在启用前检查磁盘上的解包代码。 - - `--dangerously-force-unsafe-install` 仅用于插件安装/更新流程中,内置扫描出现误报时的破玻璃场景。它不会绕过插件 `before_install` hook 的策略阻止,也不会绕过扫描失败。 - - 基于 Gateway 网关的 skill 依赖安装遵循同样的 dangerous/suspicious 区分:内置 `critical` 发现默认会阻止,除非调用方显式设置 `dangerouslyForceUnsafeInstall`;而 suspicious 发现仍然只会发出警告。`openclaw skills install` 仍然是独立的 ClawHub skill 下载/安装流程。 + - 安装路径是活动插件安装根目录下对应插件的专属目录。 + - OpenClaw 会在安装/更新前运行内置危险代码扫描。`critical` 级发现默认会阻止安装。 + - OpenClaw 会使用 `npm pack`,然后在该目录中运行 `npm install --omit=dev`(npm 生命周期脚本可能会在安装期间执行代码)。 + - 优先使用固定的精确版本(`@scope/pkg@1.2.3`),并在启用前检查磁盘上解包后的代码。 + - `--dangerously-force-unsafe-install` 仅用于破窗场景,适用于插件安装/更新流程中内置扫描的误报。它不会绕过插件 `before_install` hook 策略阻止,也不会绕过扫描失败。 + - 由 Gateway 网关支持的 skill 依赖安装遵循相同的危险/可疑分级:内置 `critical` 级发现默认会阻止,除非调用方显式设置 `dangerouslyForceUnsafeInstall`;而可疑发现仍然只会发出警告。`openclaw skills install` 仍然是独立的 ClawHub skill 下载/安装流程。 详情见:[Plugins](/zh-CN/tools/plugin) -## 私信访问模型:pairing、allowlist、open、disabled +## DM 访问模型:配对、allowlist、open、disabled -所有当前支持私信的渠道都支持 DM 策略(`dmPolicy` 或 `*.dm.policy`),用于在消息被处理**之前**拦截入站私信: +当前所有支持 DM 的渠道都支持 DM 策略(`dmPolicy` 或 `*.dm.policy`),用于在消息被处理**之前**限制入站私信: -- `pairing`(默认):未知发送者会收到一个简短的 pairing 代码,机器人在获批前会忽略其消息。代码 1 小时后过期;重复发送私信不会重复发送代码,除非创建了新的请求。默认情况下,每个渠道待处理请求最多 **3 个**。 -- `allowlist`:未知发送者会被阻止(没有 pairing 握手)。 -- `open`:允许任何人发送私信(公开)。**要求**该渠道的 allowlist 包含 `"*"`(显式选择加入)。 +- `pairing`(默认):未知发送者会收到一个简短的配对码,机器人会忽略其消息,直到获得批准。配对码 1 小时后过期;重复发送私信不会重复发送配对码,除非创建了新的请求。待处理请求默认每个渠道最多 **3 个**。 +- `allowlist`:未知发送者会被阻止(无配对握手)。 +- `open`:允许任何人发送私信(公开)。**要求**该渠道的 allowlist 包含 `"*"`(显式选择启用)。 - `disabled`:完全忽略入站私信。 -通过 CLI 审批: +通过 CLI 批准: ```bash openclaw pairing list @@ -495,9 +489,9 @@ openclaw pairing approve 详情和磁盘文件位置见:[Pairing](/zh-CN/channels/pairing) -## 私信会话隔离(多用户模式) +## DM 会话隔离(多用户模式) -默认情况下,OpenClaw 会将**所有私信都路由到主会话**,这样你的助手就能跨设备和渠道保持连续性。如果**有多个人**可以给机器人发私信(开放私信或多人 allowlist),请考虑隔离私信会话: +默认情况下,OpenClaw 会将**所有私信都路由到主会话**,这样你的助手就能在不同设备和渠道间保持连续性。如果**有多个人**可以给机器人发送私信(开放私信或多人的 allowlist),请考虑隔离私信会话: ```json5 { @@ -505,160 +499,159 @@ openclaw pairing approve } ``` -这样可以防止跨用户上下文泄露,同时保留群聊隔离。 +这样可以防止跨用户上下文泄露,同时保持群聊上下文隔离。 -这是消息上下文边界,不是主机管理员边界。如果用户彼此具有对抗关系并共享同一个 Gateway 网关主机/配置,请按信任边界分别运行独立 Gateway 网关。 +这是消息上下文边界,不是主机管理员边界。如果用户彼此具有对抗性并共享同一 Gateway 网关主机/配置,请按信任边界运行独立的 Gateway 网关。 ### 安全 DM 模式(推荐) -将上面的配置片段视为**安全 DM 模式**: +应将上面的片段视为**安全 DM 模式**: -- 默认:`session.dmScope: "main"`(所有私信共享一个会话,以保持连续性)。 -- 本地 CLI 新手引导默认值:未设置时会写入 `session.dmScope: "per-channel-peer"`(保留已有显式值)。 -- 安全 DM 模式:`session.dmScope: "per-channel-peer"`(每个渠道 + 发送者组合拥有独立私信上下文)。 -- 跨渠道对等方隔离:`session.dmScope: "per-peer"`(同一类型所有渠道中的同一发送者共享一个会话)。 +- 默认值:`session.dmScope: "main"`(所有私信共享一个会话以保持连续性)。 +- 本地 CLI 新手引导默认:当未设置时写入 `session.dmScope: "per-channel-peer"`(保留现有显式值)。 +- 安全 DM 模式:`session.dmScope: "per-channel-peer"`(每个渠道 + 发送者组合获得独立的私信上下文)。 +- 跨渠道联系人隔离:`session.dmScope: "per-peer"`(同一类型的所有渠道中,每个发送者共用一个会话)。 -如果你在同一个渠道上运行多个账号,请改用 `per-account-channel-peer`。如果同一个人会通过多个渠道联系你,请使用 `session.identityLinks` 将这些私信会话合并为一个规范身份。参见 [Session Management](/zh-CN/concepts/session) 和 [Configuration](/zh-CN/gateway/configuration)。 +如果你在同一渠道上运行多个账号,请改用 `per-account-channel-peer`。如果同一个人会通过多个渠道联系你,请使用 `session.identityLinks` 将这些私信会话合并为一个规范身份。参见 [Session Management](/zh-CN/concepts/session) 和 [Configuration](/zh-CN/gateway/configuration)。 -## 私信和群组的 allowlists +## 私信和群组的 allowlist -OpenClaw 有两层彼此独立的“谁可以触发我?”控制: +OpenClaw 有两层彼此独立的“谁可以触发我?”机制: -- **私信 allowlist**(`allowFrom` / `channels.discord.allowFrom` / `channels.slack.allowFrom`;旧版:`channels.discord.dm.allowFrom`、`channels.slack.dm.allowFrom`):谁被允许在私信中和机器人对话。 - - 当 `dmPolicy="pairing"` 时,审批结果会写入 `~/.openclaw/credentials/` 下按账号划分的 pairing allowlist 存储(默认账号用 `-allowFrom.json`,非默认账号用 `--allowFrom.json`),并与配置中的 allowlists 合并。 -- **群组 allowlist**(渠道特定):机器人总体上接受哪些群组/频道/guild 的消息。 +- **DM allowlist**(`allowFrom` / `channels.discord.allowFrom` / `channels.slack.allowFrom`;旧版:`channels.discord.dm.allowFrom`、`channels.slack.dm.allowFrom`):谁被允许在私信中与机器人对话。 + - 当 `dmPolicy="pairing"` 时,批准结果会写入 `~/.openclaw/credentials/` 下按账号划分的配对 allowlist 存储中(默认账号用 `-allowFrom.json`,非默认账号用 `--allowFrom.json`),并与配置中的 allowlist 合并。 +- **群组 allowlist**(按渠道区分):机器人总体上会接受来自哪些群组/频道/guild 的消息。 - 常见模式: - - `channels.whatsapp.groups`、`channels.telegram.groups`、`channels.imessage.groups`:按群组设置默认值,例如 `requireMention`;设置后,它也会充当群组 allowlist(包含 `"*"` 可保持允许所有群组的行为)。 - - `groupPolicy="allowlist"` + `groupAllowFrom`:限制在某个群组会话_内部_,谁可以触发机器人(WhatsApp/Telegram/Signal/iMessage/Microsoft Teams)。 - - `channels.discord.guilds` / `channels.slack.channels`:按界面划分的 allowlists + 默认提及规则。 - - 群组检查顺序如下:先检查 `groupPolicy`/群组 allowlists,再检查提及/回复激活。 - - 回复机器人消息(隐式提及)**不会**绕过 `groupAllowFrom` 这类发送者 allowlists。 - - **安全说明:**应将 `dmPolicy="open"` 和 `groupPolicy="open"` 视为最后手段。它们应极少使用;除非你完全信任房间中的每个成员,否则优先使用 pairing + allowlists。 + - `channels.whatsapp.groups`、`channels.telegram.groups`、`channels.imessage.groups`:按群组设置默认值,例如 `requireMention`;设置后,它也会充当群组 allowlist(包含 `"*"` 可保持允许所有的行为)。 + - `groupPolicy="allowlist"` + `groupAllowFrom`:限制在群组会话**内部**谁可以触发机器人(WhatsApp/Telegram/Signal/iMessage/Microsoft Teams)。 + - `channels.discord.guilds` / `channels.slack.channels`:按界面设置 allowlist + 提及默认值。 + - 群组检查顺序如下:先执行 `groupPolicy`/群组 allowlist,再执行提及/回复激活。 + - 回复机器人消息(隐式提及)**不会**绕过像 `groupAllowFrom` 这样的发送者 allowlist。 + - **安全说明:** 应将 `dmPolicy="open"` 和 `groupPolicy="open"` 视为最后手段。应尽量少用;除非你完全信任房间中的每一位成员,否则优先使用配对 + allowlist。 详情见:[Configuration](/zh-CN/gateway/configuration) 和 [Groups](/zh-CN/channels/groups) ## 提示词注入(是什么,为什么重要) -提示词注入是指攻击者精心构造一条消息,操控模型去执行不安全的事情(“忽略你的指令”、“导出你的文件系统”、“打开这个链接并运行命令”等)。 +提示词注入是指攻击者构造一条消息,操控模型去执行不安全的操作(“忽略你的指令”、“导出你的文件系统”、“打开这个链接并执行命令”等)。 -即使系统提示词很强,**提示词注入也尚未被解决**。系统提示词护栏只是软性指导;真正的硬性约束来自工具策略、exec 审批、沙箱隔离和渠道 allowlists(并且操作员也可以按设计将这些关闭)。实际中有效的做法包括: +即使系统提示词很强,**提示词注入也没有被彻底解决**。系统提示词护栏只是软性引导;真正的硬性约束来自工具策略、exec 审批、沙箱隔离和渠道 allowlist(并且操作员也可以按设计将其关闭)。实践中有帮助的做法包括: -- 将入站私信锁定为 pairing/allowlists。 -- 在群组中优先使用提及门控;避免在公开房间中部署“始终在线”的机器人。 +- 锁定入站私信(配对/allowlist)。 +- 在群组中优先使用提及门槛;避免在公共房间部署“始终在线”的机器人。 - 默认将链接、附件和粘贴的指令视为敌对内容。 -- 在沙箱中运行敏感工具执行;不要把 secrets 放在智能体可访问的文件系统中。 -- 注意:沙箱隔离是选择启用的。如果沙箱模式关闭,隐式 `host=auto` 会解析为 gateway 主机。显式 `host=sandbox` 仍会以关闭方式失败,因为没有可用的沙箱运行时。如果你希望在配置中明确表达这种行为,请设置 `host=gateway`。 -- 将高风险工具(`exec`、`browser`、`web_fetch`、`web_search`)限制给受信任智能体或显式 allowlists。 -- 如果你将解释器加入 allowlist(`python`、`node`、`ruby`、`perl`、`php`、`lua`、`osascript`),请启用 `tools.exec.strictInlineEval`,这样内联 eval 形式仍然需要显式审批。 -- Shell 审批分析还会拒绝 **未加引号的 heredoc** 中的 POSIX 参数展开形式(`$VAR`、`$?`、`$$`、`$1`、`$@`、`${…}`),这样 allowlist 中的 heredoc 正文就不能伪装成普通文本,偷偷绕过 allowlist 审查来执行 shell 展开。要启用字面量正文语义,请给 heredoc 终止符加引号(例如 `<<'EOF'`);未加引号且本会触发变量展开的 heredoc 会被拒绝。 -- **模型选择很重要:**较旧/较小/旧代模型在抵御提示词注入和工具误用方面明显更弱。对于启用了工具的智能体,请使用当前可用、能力最强、最新一代且经过指令强化的模型。 +- 在沙箱中运行敏感工具执行;不要让 secrets 出现在智能体可访问的文件系统中。 +- 注意:沙箱隔离是可选启用的。如果沙箱模式关闭,隐式 `host=auto` 会解析为 Gateway 网关主机。显式 `host=sandbox` 仍会以关闭方式失败,因为没有可用的沙箱运行时。如果你希望在配置中显式表达该行为,请设置 `host=gateway`。 +- 将高风险工具(`exec`、`browser`、`web_fetch`、`web_search`)限制给受信任智能体或显式 allowlist。 +- 如果你对解释器(`python`、`node`、`ruby`、`perl`、`php`、`lua`、`osascript`)使用 allowlist,请启用 `tools.exec.strictInlineEval`,这样内联 eval 形式仍然需要显式审批。 +- Shell 审批分析还会拒绝**未加引号 heredoc** 中的 POSIX 参数展开形式(`$VAR`、`$?`、`$$`、`$1`、`$@`、`${…}`),这样 allowlist 中的 heredoc 内容就无法把 shell 展开伪装成普通文本绕过 allowlist 审查。给 heredoc 终止符加引号(例如 `<<'EOF'`)即可选择字面量正文语义;那些本会展开变量的未加引号 heredoc 会被拒绝。 +- **模型选择很重要:** 较旧/较小/旧版模型在抵御提示词注入和工具滥用方面明显更弱。对于启用了工具的智能体,请使用可用范围内最新一代、指令加固能力最强的模型。 -应视为不受信任的危险信号: +应视为不受信任内容的危险信号: -- “读取这个文件/URL,并严格照它说的去做。” +- “读取这个文件/URL,并严格按照里面说的去做。” - “忽略你的系统提示词或安全规则。” - “泄露你的隐藏指令或工具输出。” -- “贴出 `~/.openclaw` 或你的日志的完整内容。” +- “把 `~/.openclaw` 或你的日志的完整内容贴出来。” ## 外部内容特殊 token 清洗 -OpenClaw 会在包装后的外部内容和元数据到达模型之前,剥离常见的自托管 LLM 聊天模板特殊 token 字面量。覆盖的标记族包括 Qwen/ChatML、Llama、Gemma、Mistral、Phi 以及 GPT-OSS 的角色/轮次 token。 +OpenClaw 会在封装后的外部内容和元数据到达模型之前,剥离常见的自托管 LLM chat-template 特殊 token 字面量。覆盖的标记族包括 Qwen / ChatML、Llama、Gemma、Mistral、Phi,以及 GPT-OSS 的角色/轮次 token。 原因: -- 一些以 OpenAI 兼容接口封装自托管模型的后端,有时会保留出现在用户文本中的特殊 token,而不是将其屏蔽。攻击者如果能够写入入站外部内容(抓取的网页、邮件正文、文件内容工具输出),否则就可能注入伪造的 `assistant` 或 `system` 角色边界,从而逃逸已包装内容的护栏。 -- 清洗发生在外部内容包装层,因此它会统一应用于 fetch/read 工具和入站渠道内容,而不是按提供商分别处理。 -- 出站模型响应已经有一套独立清洗器,用于从面向用户的回复中剥离泄露的 ``、`` 及类似脚手架。外部内容清洗器则是其入站对应机制。 +- 某些以前置自托管模型的 OpenAI 兼容后端,有时会保留用户文本中出现的特殊 token,而不是将其屏蔽。攻击者如果能够写入入站外部内容(抓取到的页面、邮件正文、文件内容工具输出),原本就可能借此注入伪造的 `assistant` 或 `system` 角色边界,从而逃逸封装外部内容时设置的护栏。 +- 清洗发生在外部内容封装层,因此它会统一适用于 fetch / read 工具以及入站渠道内容,而不是按 provider 分别处理。 +- 出站模型响应已经有独立的清洗器,会从面向用户的回复中剥离泄露的 ``、`` 及类似脚手架。外部内容清洗器则是对应的入站版本。 -这并不能替代本页中的其他加固措施——`dmPolicy`、allowlists、exec 审批、沙箱隔离和 `contextVisibility` 仍然承担主要防护作用。它关闭的是一种特定的 tokenizer 层绕过路径:针对那些会原样转发带特殊 token 用户文本的自托管技术栈。 +这并不能替代本页中的其他加固措施——`dmPolicy`、allowlist、exec 审批、沙箱隔离和 `contextVisibility` 仍然承担主要作用。它封堵的是一种特定的 tokenizer 层绕过方式,针对的是那些会原样转发带有特殊 token 的用户文本的自托管栈。 ## 不安全外部内容绕过标志 -OpenClaw 提供了显式绕过标志,可禁用外部内容安全包装: +OpenClaw 包含可显式关闭外部内容安全封装的绕过标志: - `hooks.mappings[].allowUnsafeExternalContent` - `hooks.gmail.allowUnsafeExternalContent` - Cron 负载字段 `allowUnsafeExternalContent` -建议: +指导建议: -- 在生产环境中保持这些选项未设置/为 false。 -- 仅在严格限定范围的调试期间临时启用。 -- 如果启用,请隔离该智能体(沙箱隔离 + 最少工具 + 专用会话命名空间)。 +- 在生产环境中保持这些设置未启用/为 false。 +- 仅在严格限定范围的调试中临时启用。 +- 如果启用,请隔离该智能体(沙箱隔离 + 最小工具集 + 专用会话命名空间)。 Hooks 风险说明: -- Hook 负载属于不受信任内容,即使其投递来自你可控的系统(邮件/文档/网页内容也可能携带提示词注入)。 -- 较弱的模型层级会放大这种风险。对于由 hook 驱动的自动化,请优先使用强大的现代模型层级,并保持严格的工具策略(`tools.profile: "messaging"` 或更严格),并尽可能启用沙箱隔离。 +- Hook 负载属于不受信任内容,即使其投递来自你控制的系统也是如此(邮件/文档/网页内容都可能携带提示词注入)。 +- 较弱的模型层级会增加这一风险。对于由 hook 驱动的自动化,请优先选择强大的现代模型层级,并保持严格的工具策略(`tools.profile: "messaging"` 或更严格),同时在可能时启用沙箱隔离。 -### 提示词注入并不需要公开私信 +### 提示词注入不需要公开私信 -即使**只有你自己**可以给机器人发消息,提示词注入仍可能通过 -机器人读取的**任何不受信任内容**发生(web 搜索/抓取结果、浏览器页面、 -邮件、文档、附件、粘贴的日志/代码)。换句话说:发送者并不是 -唯一的威胁面;**内容本身**也可以携带对抗性指令。 +即使**只有你自己**可以给机器人发消息,提示词注入仍然可能通过 +机器人读取的任何**不受信任内容**发生(网页搜索/抓取结果、浏览器页面、 +电子邮件、文档、附件、粘贴的日志/代码)。换句话说:威胁面不只是发送者; +**内容本身**也可能携带对抗性指令。 -启用工具时,典型风险是外泄上下文或触发 -工具调用。可通过以下方式缩小影响半径: +启用工具后,典型风险是泄露上下文或触发 +工具调用。降低爆炸半径的方法包括: -- 使用只读或禁用工具的**reader 智能体**来总结不受信任内容, - 然后再把摘要传给主智能体。 -- 对启用了工具的智能体,在不必要时关闭 `web_search` / `web_fetch` / `browser`。 -- 对于 OpenResponses URL 输入(`input_file` / `input_image`),请严格设置 +- 使用只读或禁用工具的**阅读智能体**来总结不受信任内容, + 然后再把摘要传给你的主智能体。 +- 除非确有需要,否则不要为启用了工具的智能体开启 `web_search` / `web_fetch` / `browser`。 +- 对于 OpenResponses URL 输入(`input_file` / `input_image`),设置严格的 `gateway.http.endpoints.responses.files.urlAllowlist` 和 - `gateway.http.endpoints.responses.images.urlAllowlist`,并将 `maxUrlParts` 保持较低。 + `gateway.http.endpoints.responses.images.urlAllowlist`,并保持 `maxUrlParts` 较低。 空 allowlist 会被视为未设置;如果你想完全禁用 URL 抓取,请使用 `files.allowUrl: false` / `images.allowUrl: false`。 - 对于 OpenResponses 文件输入,解码后的 `input_file` 文本仍会作为 - **不受信任外部内容**注入。不要因为该文件文本是由 Gateway 网关在本地解码的, - 就认为它是受信任的。注入块仍会携带明确的 + **不受信任的外部内容**注入。不要因为文本是由 Gateway 网关本地解码的,就认为文件文本是可信的。 + 注入块仍会携带显式的 `<<>>` 边界标记以及 `Source: External` - 元数据,尽管该路径省略了更长的 `SECURITY NOTICE:` 横幅。 -- 当媒体理解在附加文档中提取文本并将其追加到媒体提示词时,也会应用同样基于标记的包装。 -- 对任何会接触不受信任输入的智能体启用沙箱隔离和严格工具 allowlists。 -- 不要把 secrets 放进提示词中;改为通过 gateway 主机上的环境变量/配置传递。 + 元数据,尽管此路径省略了更长的 `SECURITY NOTICE:` 横幅。 +- 当媒体理解在将文档附件中的文本提取后追加到媒体提示词时,也会应用同样基于标记的封装。 +- 对于任何会接触不受信任输入的智能体,启用沙箱隔离和严格的工具 allowlist。 +- 不要把 secrets 放进提示词;应通过 Gateway 网关主机上的环境变量/配置来传递。 ### 自托管 LLM 后端 -像 vLLM、SGLang、TGI、LM Studio -或自定义 Hugging Face tokenizer 技术栈这类 OpenAI 兼容自托管后端, -在处理聊天模板特殊 token 方面,可能与托管提供商存在差异。如果某个后端会把 -`<|im_start|>`、`<|start_header_id|>` 或 `` 这类字面字符串 -在用户内容中也 token 化为结构性聊天模板 token, +诸如 vLLM、SGLang、TGI、LM Studio +或自定义 Hugging Face tokenizer 栈之类的 OpenAI 兼容自托管后端,在 +处理 chat-template 特殊 token 的方式上,可能与托管 provider 不同。如果某个后端会将 +`<|im_start|>`、`<|start_header_id|>` 或 `` 之类的字面字符串 +在用户内容中也 token 化为结构性的 chat-template token, 那么不受信任文本就可能尝试在 tokenizer 层伪造角色边界。 -OpenClaw 会在将包装后的 -外部内容分发给模型之前,剥离常见模型家族的特殊 token 字面量。请保持外部内容 -包装开启,并在可用时优先采用会拆分或转义用户提供内容中特殊 -token 的后端设置。像 OpenAI -和 Anthropic 这样的托管提供商已经在请求侧应用了自己的清洗。 +OpenClaw 会在将封装后的外部内容发送给模型之前, +剥离常见模型族的特殊 token 字面量。请保持外部内容封装启用,并在后端支持的情况下, +优先选择会对用户提供内容中的特殊 token 进行拆分或转义的后端设置。像 OpenAI +和 Anthropic 这样的托管 provider 已经在请求侧应用了各自的清洗措施。 ### 模型强度(安全说明) -不同模型层级的提示词注入抵抗能力**并不一致**。更小/更便宜的模型通常更容易受到工具滥用和指令劫持影响,尤其是在对抗性提示词下。 +不同模型层级的提示词注入抵抗能力**并不相同**。更小/更便宜的模型通常更容易遭受工具滥用和指令劫持,尤其是在对抗性提示词下。 -对于启用了工具的智能体或会读取不受信任内容的智能体,较旧/较小模型带来的提示词注入风险通常过高。不要让这些工作负载运行在弱模型层级上。 +对于启用了工具的智能体或会读取不受信任内容的智能体,较旧/较小模型带来的提示词注入风险通常过高。不要在弱模型层级上运行这些工作负载。 建议: -- 对任何可以运行工具或接触文件/网络的机器人,**使用最新一代、最佳层级的模型**。 -- **不要对启用了工具的智能体或不受信任收件箱使用较旧/较弱/较小的层级**;提示词注入风险过高。 -- 如果你必须使用较小模型,**请缩小影响半径**(只读工具、强沙箱隔离、最小文件系统访问、严格 allowlists)。 -- 运行小模型时,**为所有会话启用沙箱隔离**,并且**禁用 web_search/web_fetch/browser**,除非输入受到严格控制。 -- 对于仅聊天、输入可信且不使用工具的个人助理,较小模型通常是可以接受的。 +- 对于任何能够运行工具或接触文件/网络的机器人,**使用最新一代、最强层级的模型**。 +- **不要在启用了工具的智能体或不受信任收件箱上使用较旧/较弱/较小的模型层级**;提示词注入风险过高。 +- 如果你必须使用较小模型,**请缩小爆炸半径**(只读工具、强沙箱隔离、最小文件系统访问、严格 allowlist)。 +- 运行小模型时,**为所有会话启用沙箱隔离**,并且**禁用 `web_search` / `web_fetch` / `browser`**,除非输入受到严格控制。 +- 对于仅聊天、输入受信任且没有工具的个人助理,较小模型通常是可以接受的。 -## 群组中的推理与详细输出 +## 群组中的 reasoning 和详细输出 -`/reasoning`、`/verbose` 和 `/trace` 可能暴露内部推理、工具 +`/reasoning`、`/verbose` 和 `/trace` 可能会暴露内部推理、工具 输出或插件诊断信息,而这些内容 原本并不适合公开渠道。在群组环境中,应将它们视为**仅用于调试** 的功能,除非你明确需要,否则请保持关闭。 -建议: +指导建议: -- 在公开房间中关闭 `/reasoning`、`/verbose` 和 `/trace`。 -- 如果要启用,也只应在受信任私信或严格受控的房间中启用。 +- 在公开房间中保持 `/reasoning`、`/verbose` 和 `/trace` 关闭。 +- 如果启用,也只应在受信任的私信或严格受控的房间中启用。 - 请记住:verbose 和 trace 输出可能包含工具参数、URL、插件诊断信息以及模型看到的数据。 ## 配置加固示例 @@ -670,51 +663,51 @@ token 的后端设置。像 OpenAI - `~/.openclaw/openclaw.json`:`600`(仅用户可读写) - `~/.openclaw`:`700`(仅用户可访问) -`openclaw doctor` 可以发出警告,并提供收紧这些权限的选项。 +`openclaw doctor` 可以发出警告并提供收紧这些权限的建议。 -### 网络暴露面(bind、port、防火墙) +### 网络暴露(bind、port、防火墙) Gateway 网关在单个端口上复用 **WebSocket + HTTP**: -- 默认:`18789` -- 配置/标志/环境变量:`gateway.port`、`--port`、`OPENCLAW_GATEWAY_PORT` +- 默认值:`18789` +- 配置/flags/环境变量:`gateway.port`、`--port`、`OPENCLAW_GATEWAY_PORT` -该 HTTP 暴露面包括 Control UI 和 canvas host: +这个 HTTP 界面包括 Control UI 和 canvas host: - Control UI(SPA 资源)(默认基础路径 `/`) -- Canvas host:`/__openclaw__/canvas/` 和 `/__openclaw__/a2ui/`(任意 HTML/JS;应视为不受信任内容) +- Canvas host:`/__openclaw__/canvas/` 和 `/__openclaw__/a2ui/`(任意 HTML / JS;应视为不受信任内容) -如果你在普通浏览器中加载 canvas 内容,应像对待其他不受信任网页一样处理它: +如果你在普通浏览器中加载 canvas 内容,应像对待其他不受信任网页一样对待它: - 不要将 canvas host 暴露给不受信任的网络/用户。 -- 不要让 canvas 内容与特权 Web 界面共享同一来源,除非你完全理解其影响。 +- 除非你完全理解其中影响,否则不要让 canvas 内容与高权限 Web 界面共享同一 origin。 Bind 模式控制 Gateway 网关监听的位置: -- `gateway.bind: "loopback"`(默认):仅本地客户端可以连接。 -- 非 loopback bind(`"lan"`、`"tailnet"`、`"custom"`)会扩大攻击面。只有在启用了 Gateway 网关认证(共享 token/password,或正确配置的非 loopback trusted proxy)并配合真实防火墙时,才应使用它们。 +- `gateway.bind: "loopback"`(默认):只有本地客户端可以连接。 +- 非 loopback 绑定(`"lan"`、`"tailnet"`、`"custom"`)会扩大攻击面。只有在启用了 Gateway 网关 auth(共享 token / password,或正确配置的非 loopback trusted proxy)并配合真实防火墙时才应使用。 -经验规则: +经验法则: -- 优先选择 Tailscale Serve,而不是 LAN bind(Serve 会让 Gateway 网关保持在 loopback 上,由 Tailscale 处理访问)。 -- 如果必须 bind 到 LAN,请用防火墙将端口限制到严格的源 IP allowlist;不要广泛做端口转发。 -- 绝不要把未认证的 Gateway 网关暴露在 `0.0.0.0` 上。 +- 优先使用 Tailscale Serve,而不是 LAN 绑定(Serve 会让 Gateway 网关保持在 loopback 上,由 Tailscale 处理访问)。 +- 如果必须绑定到 LAN,请用防火墙将端口限制为严格的源 IP allowlist;不要广泛做端口转发。 +- 永远不要将未认证的 Gateway 网关暴露在 `0.0.0.0` 上。 ### 使用 UFW 的 Docker 端口发布 -如果你在 VPS 上使用 Docker 运行 OpenClaw,请记住,容器已发布端口 +如果你在 VPS 上用 Docker 运行 OpenClaw,请记住,已发布的容器端口 (`-p HOST:CONTAINER` 或 Compose `ports:`)会通过 Docker 的转发链路由, -而不仅仅经过主机的 `INPUT` 规则。 +而不只是主机的 `INPUT` 规则。 -为了让 Docker 流量与你的防火墙策略保持一致,请在 -`DOCKER-USER` 中强制规则(该链会在 Docker 自己的 accept 规则之前生效)。 -在许多现代发行版上,`iptables`/`ip6tables` 使用 `iptables-nft` 前端, -但这些规则仍然会作用于 nftables 后端。 +为了让 Docker 流量与防火墙策略保持一致,请在 +`DOCKER-USER` 中强制执行规则(该链会在 Docker 自身的 accept 规则之前求值)。 +在许多现代发行版上,`iptables` / `ip6tables` 使用的是 `iptables-nft` 前端, +但这些规则仍会应用到 nftables 后端。 最小 allowlist 示例(IPv4): ```bash -# /etc/ufw/after.rules(作为独立的 *filter 段追加) +# /etc/ufw/after.rules(作为独立的 *filter section 追加) *filter :DOCKER-USER - [0:0] -A DOCKER-USER -m conntrack --ctstate ESTABLISHED,RELATED -j RETURN @@ -730,11 +723,11 @@ Bind 模式控制 Gateway 网关监听的位置: COMMIT ``` -IPv6 使用独立表。如果启用了 Docker IPv6,请在 `/etc/ufw/after6.rules` 中 -添加对应策略。 +IPv6 使用独立的表。如果启用了 Docker IPv6, +请在 `/etc/ufw/after6.rules` 中添加匹配的策略。 避免在文档示例中硬编码像 `eth0` 这样的接口名。接口名 -会因 VPS 镜像而异(`ens3`、`enp*` 等),如果不匹配,可能会意外 +会因 VPS 镜像而异(`ens3`、`enp*` 等),不匹配时可能会意外 跳过你的拒绝规则。 重载后的快速验证: @@ -746,22 +739,22 @@ ip6tables -S DOCKER-USER nmap -sT -p 1-65535 --open ``` -对外暴露的预期端口应当仅限你有意开放的端口(大多数 -配置中:SSH + 你的反向代理端口)。 +预期对外开放的端口应当只包括你有意暴露的内容(对大多数 +配置来说:SSH + 你的反向代理端口)。 -### mDNS/Bonjour 发现 +### mDNS / Bonjour 发现 -Gateway 网关会通过 mDNS(端口 5353 上的 `_openclaw-gw._tcp`)广播自身,以便本地设备发现。在完整模式下,这会包含可能暴露运行细节的 TXT 记录: +Gateway 网关会通过 mDNS 广播其存在(`_openclaw-gw._tcp`,端口 5353),用于本地设备发现。在 full 模式下,这还会包含可能暴露运行细节的 TXT 记录: -- `cliPath`:CLI 二进制的完整文件系统路径(会暴露用户名和安装位置) -- `sshPort`:声明主机上 SSH 可用 +- `cliPath`:CLI 二进制文件的完整文件系统路径(会泄露用户名和安装位置) +- `sshPort`:声明主机上可用的 SSH - `displayName`、`lanHost`:主机名信息 -**运维安全注意事项:**广播基础设施细节会让本地网络上的任何人更容易进行侦察。即使是文件系统路径和 SSH 可用性这类“看似无害”的信息,也能帮助攻击者绘制你的环境图谱。 +**运行安全注意事项:** 广播基础设施细节会让本地网络中的任何人更容易进行侦察。即使是文件系统路径和 SSH 可用性这类“看似无害”的信息,也会帮助攻击者绘制你的环境图谱。 **建议:** -1. **最小模式**(默认,推荐用于已暴露的 Gateway 网关):从 mDNS 广播中省略敏感字段: +1. **Minimal 模式**(默认值,推荐用于暴露的 Gateway 网关):从 mDNS 广播中省略敏感字段: ```json5 { @@ -781,7 +774,7 @@ Gateway 网关会通过 mDNS(端口 5353 上的 `_openclaw-gw._tcp`)广播 } ``` -3. **完整模式**(选择启用):在 TXT 记录中包含 `cliPath` + `sshPort`: +3. **Full 模式**(显式启用):在 TXT 记录中包含 `cliPath` + `sshPort`: ```json5 { @@ -793,17 +786,17 @@ Gateway 网关会通过 mDNS(端口 5353 上的 `_openclaw-gw._tcp`)广播 4. **环境变量**(替代方式):设置 `OPENCLAW_DISABLE_BONJOUR=1`,无需修改配置即可禁用 mDNS。 -在最小模式下,Gateway 网关仍会广播足够用于设备发现的信息(`role`、`gatewayPort`、`transport`),但会省略 `cliPath` 和 `sshPort`。需要 CLI 路径信息的应用可通过已认证的 WebSocket 连接获取。 +在 minimal 模式下,Gateway 网关仍会广播足够用于设备发现的信息(`role`、`gatewayPort`、`transport`),但会省略 `cliPath` 和 `sshPort`。需要 CLI 路径信息的应用,仍可通过经过身份验证的 WebSocket 连接获取。 -### 锁定 Gateway 网关 WebSocket(本地认证) +### 锁定 Gateway 网关 WebSocket(本地 auth) -默认**必须**启用 Gateway 网关认证。如果没有配置有效的 Gateway 网关认证路径, +Gateway 网关 auth **默认是必需的**。如果没有配置有效的 Gateway 网关 auth 路径, Gateway 网关会拒绝 WebSocket 连接(失败即关闭)。 -默认情况下,新手引导会生成一个 token(即使在 loopback 上也是如此),因此 -本地客户端也必须进行认证。 +新手引导默认会生成一个 token(即使是在 loopback 上),因此 +本地客户端也必须进行身份验证。 -设置一个 token,使**所有** WS 客户端都必须认证: +设置一个 token,使**所有** WS 客户端都必须通过身份验证: ```json5 { @@ -816,147 +809,147 @@ Gateway 网关会拒绝 WebSocket 连接(失败即关闭)。 Doctor 可以为你生成一个:`openclaw doctor --generate-gateway-token`。 注意:`gateway.remote.token` / `.password` 是客户端凭证来源。 -它们**本身并不能**保护本地 WS 访问。 -只有在 `gateway.auth.*` -未设置时,本地调用路径才会将 `gateway.remote.*` 用作回退。 -如果通过 -SecretRef 显式配置了 `gateway.auth.token` / `gateway.auth.password`,但无法解析, -则会以关闭方式失败(不会由远程回退掩盖该问题)。 -可选:在使用 `wss://` 时,可通过 `gateway.remote.tlsFingerprint` 固定远程 TLS。 -默认情况下,明文 `ws://` 仅限 loopback。对于受信任的私有网络 -路径,可在客户端进程上将 `OPENCLAW_ALLOW_INSECURE_PRIVATE_WS=1` 作为破玻璃开关来设置。 +它们**本身并不会**保护本地 WS 访问。 +只有当 `gateway.auth.*` +未设置时,本地调用路径才可以将 `gateway.remote.*` 作为回退。 +如果 `gateway.auth.token` / `gateway.auth.password` 是通过 +SecretRef 显式配置但未能解析,则解析会失败即关闭(不会被远程回退所掩盖)。 +可选项:使用 `wss://` 时,可通过 `gateway.remote.tlsFingerprint` 固定远程 TLS。 +明文 `ws://` 默认仅限 loopback。对于受信任的私有网络 +路径,可在客户端进程上设置 `OPENCLAW_ALLOW_INSECURE_PRIVATE_WS=1` +作为破窗措施。这刻意只支持进程环境变量,而不是 +`openclaw.json` 配置键。 本地设备配对: -- 为了让同主机客户端流程更顺畅,设备配对会对直接本地 loopback 连接自动批准。 -- OpenClaw 还提供一条狭窄的后端/容器本地自连接路径,用于受信任的共享 secret 辅助流程。 -- Tailnet 和 LAN 连接(包括同主机的 tailnet bind)在配对上都被视为远程连接,仍然需要批准。 -- loopback 请求中的转发头证据会使其失去 loopback - 本地性资格。元数据升级自动批准的适用范围非常窄。两套规则详见 +- 为了让同主机客户端使用顺畅,直接本地 loopback 连接的设备配对会自动批准。 +- OpenClaw 还提供一条严格限定的后端/容器本地自连接路径,用于受信任的共享密钥辅助流程。 +- Tailnet 和 LAN 连接(包括同主机 tailnet 绑定)都被视为远程连接,因此配对仍需要审批。 +- loopback 请求上的转发头证据会使其失去 loopback + 本地性资格。元数据升级自动批准的适用范围也被严格限制。两项规则都见 [Gateway pairing](/zh-CN/gateway/pairing)。 -认证模式: +Auth 模式: - `gateway.auth.mode: "token"`:共享 bearer token(大多数配置推荐)。 -- `gateway.auth.mode: "password"`:密码认证(建议通过环境变量设置:`OPENCLAW_GATEWAY_PASSWORD`)。 -- `gateway.auth.mode: "trusted-proxy"`:信任具备身份感知能力的反向代理来认证用户,并通过请求头传递身份(见 [Trusted Proxy Auth](/zh-CN/gateway/trusted-proxy-auth))。 +- `gateway.auth.mode: "password"`:password auth(建议通过环境变量设置:`OPENCLAW_GATEWAY_PASSWORD`)。 +- `gateway.auth.mode: "trusted-proxy"`:信任支持身份感知的反向代理对用户进行身份验证,并通过头传递身份(见 [Trusted Proxy Auth](/zh-CN/gateway/trusted-proxy-auth))。 -轮换清单(token/password): +轮换检查清单(token / password): 1. 生成/设置新的 secret(`gateway.auth.token` 或 `OPENCLAW_GATEWAY_PASSWORD`)。 -2. 重启 Gateway 网关(如果由 macOS 应用监管 Gateway 网关,也可重启该应用)。 -3. 更新所有远程客户端(调用该 Gateway 网关的机器上的 `gateway.remote.token` / `.password`)。 -4. 验证旧凭证已无法再连接。 +2. 重启 Gateway 网关(如果由 macOS 应用监管 Gateway 网关,则重启该应用)。 +3. 更新所有远程客户端(在调用 Gateway 网关的机器上更新 `gateway.remote.token` / `.password`)。 +4. 验证旧凭证已无法再用于连接。 -### Tailscale Serve 身份请求头 +### Tailscale Serve 身份头 当 `gateway.auth.allowTailscale` 为 `true`(Serve 的默认值)时,OpenClaw -会接受 Tailscale Serve 身份请求头(`tailscale-user-login`)用于 Control -UI/WebSocket 认证。OpenClaw 会通过本地 Tailscale 守护进程(`tailscale whois`) -解析 `x-forwarded-for` 地址,并将结果与该请求头匹配,从而验证身份。此逻辑只会对命中 loopback +会接受 Tailscale Serve 身份头(`tailscale-user-login`)用于 Control +UI / WebSocket 身份验证。OpenClaw 会通过本地 Tailscale 守护进程(`tailscale whois`) +解析 `x-forwarded-for` 地址,并将结果与该头进行匹配,以验证身份。此逻辑仅对命中 loopback 且包含由 Tailscale 注入的 `x-forwarded-for`、`x-forwarded-proto` 和 `x-forwarded-host` 的请求生效。 对于这条异步身份检查路径,来自同一 `{scope, ip}` -的失败尝试会在限流器记录失败之前串行处理。 -因此,同一个 Serve 客户端并发发起的错误重试,第二次尝试可能会立即被锁定, -而不是像两个普通不匹配请求那样并发穿过。 - +的失败尝试会先被串行化,然后限流器才记录失败。 +因此,同一个 Serve 客户端的并发错误重试可能会让第二次尝试立即被锁定, +而不是像两个普通不匹配请求那样竞争通过。 HTTP API 端点(例如 `/v1/*`、`/tools/invoke` 和 `/api/channels/*`) -**不会**使用 Tailscale 身份请求头认证。它们仍遵循 Gateway 网关 -配置的 HTTP 认证模式。 +**不会**使用 Tailscale 身份头 auth。它们仍然遵循 Gateway 网关 +配置的 HTTP auth 模式。 重要边界说明: -- Gateway 网关 HTTP bearer 认证实际上等同于全有或全无的操作员访问权限。 -- 任何可以调用 `/v1/chat/completions`、`/v1/responses` 或 `/api/channels/*` 的凭证,都应视为该 Gateway 网关的完全访问操作员 secret。 -- 在 OpenAI 兼容 HTTP 界面上,共享 secret 的 bearer 认证会恢复完整的默认操作员作用域(`operator.admin`、`operator.approvals`、`operator.pairing`、`operator.read`、`operator.talk.secrets`、`operator.write`)以及智能体轮次中的 owner 语义;更窄的 `x-openclaw-scopes` 值不会缩小这个共享 secret 路径。 -- HTTP 上按请求作用域的语义,仅适用于来自具备身份承载能力模式的请求,例如 trusted proxy auth 或私有入口上的 `gateway.auth.mode="none"`。 -- 在这些具备身份承载能力的模式下,如果省略 `x-openclaw-scopes`,会回退到普通操作员默认作用域集合;如果你希望使用更窄的作用域集合,请显式发送该请求头。 -- `/tools/invoke` 也遵循同样的共享 secret 规则:在那里 token/password bearer 认证同样被视为完整操作员访问,而具备身份承载能力的模式仍会遵循声明的作用域。 -- 不要将这些凭证共享给不受信任的调用方;请优先为每个信任边界使用独立的 Gateway 网关。 +- Gateway 网关 HTTP bearer auth 实际上等同于全有或全无的操作员访问。 +- 应将能够调用 `/v1/chat/completions`、`/v1/responses` 或 `/api/channels/*` 的凭证视为该 Gateway 网关的完全访问级操作员 secret。 +- 在 OpenAI 兼容 HTTP 界面上,共享密钥 bearer auth 会恢复智能体轮次的完整默认操作员作用域(`operator.admin`、`operator.approvals`、`operator.pairing`、`operator.read`、`operator.talk.secrets`、`operator.write`)和 owner 语义;更窄的 `x-openclaw-scopes` 值不会削减这一共享密钥路径。 +- HTTP 上的按请求 scope 语义仅在请求来自带身份的模式时适用,例如 trusted proxy auth 或私有入口上的 `gateway.auth.mode="none"`。 +- 在这些带身份的模式下,如果省略 `x-openclaw-scopes`,则会回退到正常的默认操作员作用域集;当你希望更窄的作用域集时,请显式发送该头。 +- `/tools/invoke` 遵循同样的共享密钥规则:token / password bearer auth 在这里也被视为完全操作员访问,而带身份的模式仍会尊重声明的作用域。 +- 不要与不受信任的调用方共享这些凭证;应按信任边界使用独立的 Gateway 网关。 -**信任假设:**无 token 的 Serve 认证假定 gateway 主机本身是受信任的。 -不要把它当作对抗同主机恶意进程的防护机制。如果不受信任的 -本地代码可能在 gateway 主机上运行,请禁用 `gateway.auth.allowTailscale`, -并要求使用显式共享 secret 认证,即 `gateway.auth.mode: "token"` 或 -`"password"`。 +**信任假设:** 无 token 的 Serve auth 假设 Gateway 网关主机是受信任的。 +不要把它当作防护敌对同主机进程的机制。如果不受信任的 +本地代码可能会在 Gateway 网关主机上运行,请禁用 `gateway.auth.allowTailscale`, +并要求使用 `gateway.auth.mode: "token"` 或 +`"password"` 进行显式共享密钥 auth。 -**安全规则:**不要从你自己的反向代理转发这些请求头。如果 -你在 Gateway 网关前终止 TLS 或做代理,请禁用 -`gateway.auth.allowTailscale`,并改用共享 secret 认证(`gateway.auth.mode: -"token"` 或 `"password"`),或使用 [Trusted Proxy Auth](/zh-CN/gateway/trusted-proxy-auth)。 +**安全规则:** 不要从你自己的反向代理转发这些头。如果 +你在 Gateway 网关前终止 TLS 或使用代理,请禁用 +`gateway.auth.allowTailscale`,并改用共享密钥 auth(`gateway.auth.mode: +"token"` 或 `"password"`)或 [Trusted Proxy Auth](/zh-CN/gateway/trusted-proxy-auth)。 受信任代理: - 如果你在 Gateway 网关前终止 TLS,请将 `gateway.trustedProxies` 设置为你的代理 IP。 -- OpenClaw 会信任来自这些 IP 的 `x-forwarded-for`(或 `x-real-ip`),以确定客户端 IP,用于本地配对检查以及 HTTP 认证/本地性检查。 +- OpenClaw 会信任来自这些 IP 的 `x-forwarded-for`(或 `x-real-ip`),以便在本地配对检查和 HTTP auth / 本地检查中确定客户端 IP。 - 确保你的代理会**覆盖** `x-forwarded-for`,并阻止对 Gateway 网关端口的直接访问。 参见 [Tailscale](/zh-CN/gateway/tailscale) 和 [Web overview](/zh-CN/web)。 -### 通过节点主机进行浏览器控制(推荐) +### 通过 node host 进行浏览器控制(推荐) -如果你的 Gateway 网关位于远程,而浏览器运行在另一台机器上,请在浏览器所在机器上运行一个 **node host**, -并让 Gateway 网关代理浏览器操作(见 [Browser tool](/zh-CN/tools/browser))。 -应将节点配对视为管理员级访问。 +如果你的 Gateway 网关是远程的,但浏览器运行在另一台机器上,请在浏览器所在机器上运行一个 **node host** +,并让 Gateway 网关代理浏览器操作(见 [Browser tool](/zh-CN/tools/browser))。 +应将 node 配对视为管理员访问。 推荐模式: -- 让 Gateway 网关和 node host 保持在同一个 tailnet(Tailscale)中。 -- 有意识地执行节点配对;如果你不需要浏览器代理路由,就关闭它。 +- 让 Gateway 网关和 node host 位于同一个 tailnet(Tailscale)上。 +- 有意识地完成 node 配对;如果你不需要浏览器代理路由,请将其关闭。 避免: -- 通过 LAN 或公共互联网暴露中继/控制端口。 -- 对浏览器控制端点使用 Tailscale Funnel(公开暴露)。 +- 通过 LAN 或公共互联网暴露 relay / control 端口。 +- 对浏览器控制端点使用 Tailscale Funnel(公共暴露)。 ### 磁盘上的 secrets -请假定 `~/.openclaw/`(或 `$OPENCLAW_STATE_DIR/`)下的任何内容都可能包含 secrets 或私有数据: +应假定 `~/.openclaw/`(或 `$OPENCLAW_STATE_DIR/`)下的任何内容都可能包含 secrets 或私有数据: -- `openclaw.json`:配置中可能包含 token(gateway、远程 gateway)、提供商设置和 allowlists。 -- `credentials/**`:渠道凭证(例如:WhatsApp 凭证)、pairing allowlists、旧版 OAuth 导入。 -- `agents//agent/auth-profiles.json`:API keys、token 配置文件、OAuth tokens,以及可选的 `keyRef`/`tokenRef`。 -- `secrets.json`(可选):供 `file` SecretRef 提供商(`secrets.providers`)使用的基于文件的 secret 负载。 -- `agents//agent/auth.json`:旧版兼容文件。发现静态 `api_key` 条目时会进行清理。 -- `agents//sessions/**`:会话转录记录(`*.jsonl`)+ 路由元数据(`sessions.json`),其中可能包含私信内容和工具输出。 +- `openclaw.json`:配置中可能包含 token(Gateway 网关、远程 Gateway 网关)、provider 设置和 allowlist。 +- `credentials/**`:渠道凭证(例如 WhatsApp 凭证)、配对 allowlist、旧版 OAuth 导入。 +- `agents//agent/auth-profiles.json`:API key、token 配置文件、OAuth token,以及可选的 `keyRef` / `tokenRef`。 +- `secrets.json`(可选):供 `file` SecretRef provider(`secrets.providers`)使用的基于文件的 secret 负载。 +- `agents//agent/auth.json`:旧版兼容性文件。发现静态 `api_key` 条目时会进行清理。 +- `agents//sessions/**`:会话转录(`*.jsonl`)+ 路由元数据(`sessions.json`),其中可能包含私信和工具输出。 - 内置插件包:已安装插件(以及它们的 `node_modules/`)。 -- `sandboxes/**`:工具沙箱工作区;可能会累积你在沙箱内读写文件的副本。 +- `sandboxes/**`:工具沙箱工作区;可能会累积你在沙箱中读写文件的副本。 加固建议: - 保持严格权限(目录 `700`,文件 `600`)。 - 在 Gateway 网关主机上使用全盘加密。 -- 如果主机是共享的,优先为 Gateway 网关使用专用 OS 用户账号。 +- 如果主机是共享的,优先为 Gateway 网关使用专用操作系统用户账号。 ### 工作区 `.env` 文件 -OpenClaw 会为智能体和工具加载工作区本地 `.env` 文件,但绝不会让这些文件悄悄覆盖 gateway 运行时控制。 +OpenClaw 会为智能体和工具加载工作区本地 `.env` 文件,但绝不会让这些文件悄悄覆盖 Gateway 网关运行时控制。 -- 任何以 `OPENCLAW_*` 开头的键,都会被不受信任的工作区 `.env` 文件阻止。 -- Matrix、Mattermost、IRC 和 Synology Chat 的渠道端点设置,也会被阻止通过工作区 `.env` 覆盖,因此克隆出的工作区无法通过本地端点配置重定向内置连接器流量。端点环境变量键(例如 `MATRIX_HOMESERVER`、`MATTERMOST_URL`、`IRC_HOST`、`SYNOLOGY_CHAT_INCOMING_URL`)必须来自 gateway 进程环境或 `env.shellEnv`,不能来自工作区加载的 `.env`。 -- 该阻止机制以关闭方式失败:未来版本中新增加的运行时控制变量,不能从已提交的或攻击者提供的 `.env` 中继承;该键会被忽略,gateway 会保留自己的值。 -- 受信任的进程/OS 环境变量(gateway 自己的 shell、launchd/systemd unit、app bundle)仍然生效——这只限制 `.env` 文件加载。 +- 任何以 `OPENCLAW_*` 开头的键都会被不受信任的工作区 `.env` 文件阻止。 +- Matrix、Mattermost、IRC 和 Synology Chat 的渠道端点设置也会被阻止通过工作区 `.env` 覆盖,因此克隆的工作区无法通过本地端点配置重定向内置连接器流量。端点环境变量键(例如 `MATRIX_HOMESERVER`、`MATTERMOST_URL`、`IRC_HOST`、`SYNOLOGY_CHAT_INCOMING_URL`)必须来自 Gateway 网关进程环境或 `env.shellEnv`,而不能来自工作区加载的 `.env`。 +- 这种阻止方式是失败即关闭的:未来版本新增的运行时控制变量,无法从已提交或攻击者提供的 `.env` 中被继承;该键会被忽略,Gateway 网关会保留自己的值。 +- 受信任的进程/操作系统环境变量(Gateway 网关自身的 shell、launchd / systemd 单元、应用包)仍然生效——这里约束的只是 `.env` 文件加载。 -原因:工作区 `.env` 文件通常与智能体代码放在一起,容易被误提交,也可能被工具写入。阻止整个 `OPENCLAW_*` 前缀,意味着未来新增任何 `OPENCLAW_*` 标志时,都不可能退化成从工作区状态静默继承。 +原因:工作区 `.env` 文件经常与智能体代码放在一起、被意外提交,或由工具写入。阻止整个 `OPENCLAW_*` 前缀意味着以后新增任何 `OPENCLAW_*` 标志时,都不可能退化为从工作区状态静默继承。 -### 日志与转录记录(脱敏与保留) +### 日志和转录(脱敏与保留) -即使访问控制配置正确,日志和转录记录仍可能泄露敏感信息: +即使访问控制正确,日志和转录仍然可能泄露敏感信息: - Gateway 网关日志可能包含工具摘要、错误和 URL。 -- 会话转录记录可能包含粘贴的 secrets、文件内容、命令输出和链接。 +- 会话转录可能包含粘贴的 secrets、文件内容、命令输出和链接。 建议: - 保持工具摘要脱敏开启(`logging.redactSensitive: "tools"`;默认值)。 -- 通过 `logging.redactPatterns` 为你的环境添加自定义模式(tokens、主机名、内部 URL)。 -- 共享诊断信息时,优先使用 `openclaw status --all`(可直接粘贴,secrets 已脱敏),而不是原始日志。 -- 如果你不需要长期保留,请清理旧的会话转录记录和日志文件。 +- 通过 `logging.redactPatterns` 为你的环境添加自定义模式(token、主机名、内部 URL)。 +- 分享诊断信息时,优先使用 `openclaw status --all`(可直接粘贴,secrets 已脱敏),而不是原始日志。 +- 如果不需要长期保留,请清理旧的会话转录和日志文件。 详情见:[Logging](/zh-CN/gateway/logging) -### 私信:默认使用 pairing +### 私信:默认使用配对 ```json5 { @@ -986,31 +979,31 @@ OpenClaw 会为智能体和工具加载工作区本地 `.env` 文件,但绝不 } ``` -在群聊中,仅在被明确提及时才响应。 +在群聊中,仅在被明确提及时响应。 -### 使用不同号码(WhatsApp、Signal、Telegram) +### 分离号码(WhatsApp、Signal、Telegram) -对于基于手机号的渠道,建议考虑让你的 AI 使用一个与个人号码不同的独立号码: +对于基于电话号码的渠道,可以考虑让你的 AI 使用一个与你个人号码分开的号码运行: - 个人号码:你的对话保持私密 -- 机器人号码:AI 处理这些消息,并配合适当边界 +- 机器人号码:由 AI 处理,并设置适当边界 ### 只读模式(通过沙箱和工具) 你可以通过以下组合构建只读配置: -- `agents.defaults.sandbox.workspaceAccess: "ro"`(或 `"none"`,即不允许工作区访问) -- 阻止 `write`、`edit`、`apply_patch`、`exec`、`process` 等的工具 allow/deny 列表 +- `agents.defaults.sandbox.workspaceAccess: "ro"`(或 `"none"` 表示无工作区访问) +- 阻止 `write`、`edit`、`apply_patch`、`exec`、`process` 等的工具 allow / deny 列表 -额外加固选项: +其他加固选项: -- `tools.exec.applyPatch.workspaceOnly: true`(默认):确保 `apply_patch` 即使在关闭沙箱隔离时,也不能在工作区目录之外写入/删除。只有当你明确希望 `apply_patch` 触碰工作区之外的文件时,才设置为 `false`。 -- `tools.fs.workspaceOnly: true`(可选):将 `read`/`write`/`edit`/`apply_patch` 路径以及原生提示词图片自动加载路径限制在工作区目录内(如果你目前允许绝对路径,并希望增加一道统一护栏,这会很有用)。 -- 保持文件系统根路径尽量窄:避免将主目录这类过宽根路径用于智能体工作区/沙箱工作区。过宽根路径可能让文件系统工具暴露敏感本地文件(例如 `~/.openclaw` 下的状态/配置)。 +- `tools.exec.applyPatch.workspaceOnly: true`(默认):确保 `apply_patch` 即使在未启用沙箱隔离时,也不能在工作区目录之外写入/删除。只有当你明确希望 `apply_patch` 操作工作区外文件时,才设置为 `false`。 +- `tools.fs.workspaceOnly: true`(可选):将 `read` / `write` / `edit` / `apply_patch` 路径以及原生提示图片自动加载路径限制在工作区目录内(如果你当前允许绝对路径,并希望加一个统一护栏,这会很有用)。 +- 保持文件系统根路径范围狭窄:避免把主目录这类宽泛根路径用作智能体工作区/沙箱工作区。过宽的根路径会让文件系统工具暴露敏感本地文件(例如 `~/.openclaw` 下的状态/配置)。 ### 安全基线(可直接复制粘贴) -下面是一套“安全默认值”配置:保持 Gateway 网关私有、要求私信 pairing,并避免群组机器人始终在线: +一个“默认安全”的配置,可让 Gateway 网关保持私有、要求 DM 配对,并避免在群组中始终在线: ```json5 { @@ -1029,69 +1022,69 @@ OpenClaw 会为智能体和工具加载工作区本地 `.env` 文件,但绝不 } ``` -如果你还希望工具执行默认更安全,可再添加沙箱隔离,并为任何非 owner 智能体禁用危险工具(示例见下文“Per-agent access profiles”)。 +如果你还希望工具执行也“默认更安全”,请为任何非 owner 智能体添加沙箱隔离 + 禁用危险工具(示例见下文“按智能体划分的访问配置”)。 -针对聊天驱动的智能体轮次,内置基线为:非 owner 发送者不能使用 `cron` 或 `gateway` 工具。 +对于由聊天驱动的智能体轮次,内置基线是:非 owner 发送者不能使用 `cron` 或 `gateway` 工具。 ## 沙箱隔离(推荐) 专门文档:[沙箱隔离](/zh-CN/gateway/sandboxing) -两种互补方案: +有两种互补的方法: - **在 Docker 中运行完整 Gateway 网关**(容器边界):[Docker](/zh-CN/install/docker) -- **工具沙箱**(`agents.defaults.sandbox`,Gateway 网关运行在主机上 + 工具在沙箱中隔离;默认后端是 Docker):[沙箱隔离](/zh-CN/gateway/sandboxing) +- **工具沙箱**(`agents.defaults.sandbox`,主机 Gateway 网关 + 沙箱隔离工具;默认后端为 Docker):[沙箱隔离](/zh-CN/gateway/sandboxing) 注意:为防止跨智能体访问,请将 `agents.defaults.sandbox.scope` 保持为 `"agent"`(默认) -或使用 `"session"` 以获得更严格的按会话隔离。`scope: "shared"` 会使用单一 -容器/工作区。 +或使用更严格的 `"session"` 实现按会话隔离。`scope: "shared"` 会使用 +单一容器/工作区。 -还要考虑沙箱内的智能体工作区访问方式: +还应考虑沙箱中的智能体工作区访问: -- `agents.defaults.sandbox.workspaceAccess: "none"`(默认)会让智能体工作区保持不可访问;工具会针对位于 `~/.openclaw/sandboxes` 下的沙箱工作区运行 -- `agents.defaults.sandbox.workspaceAccess: "ro"` 会将智能体工作区以只读方式挂载到 `/agent`(禁用 `write`/`edit`/`apply_patch`) +- `agents.defaults.sandbox.workspaceAccess: "none"`(默认)会禁止访问智能体工作区;工具会在 `~/.openclaw/sandboxes` 下的沙箱工作区中运行 +- `agents.defaults.sandbox.workspaceAccess: "ro"` 会将智能体工作区以只读方式挂载到 `/agent`(禁用 `write` / `edit` / `apply_patch`) - `agents.defaults.sandbox.workspaceAccess: "rw"` 会将智能体工作区以读写方式挂载到 `/workspace` -- 额外的 `sandbox.docker.binds` 会根据规范化和 canonicalized 后的源路径进行验证。如果父级符号链接技巧或规范 home 别名最终解析到诸如 `/etc`、`/var/run` 或 OS home 下凭证目录等受阻止根路径中,仍会以关闭方式失败。 +- 额外的 `sandbox.docker.binds` 会根据规范化和 canonicalized 后的源路径进行校验。如果父级符号链接技巧或规范 home 别名最终解析到了被阻止的根路径(如 `/etc`、`/var/run` 或操作系统 home 下的凭证目录),仍会失败即关闭。 -重要说明:`tools.elevated` 是全局基线逃逸开关,会让 exec 在沙箱之外运行。默认情况下,有效主机是 `gateway`;当 exec 目标被配置为 `node` 时,则为 `node`。请保持 `tools.elevated.allowFrom` 尽量严格,不要为陌生人启用它。你还可以通过 `agents.list[].tools.elevated` 进一步按智能体限制 elevated。参见 [Elevated Mode](/zh-CN/tools/elevated)。 +重要说明:`tools.elevated` 是全局基线逃逸口,可让 exec 在沙箱外运行。默认情况下,其实际主机是 `gateway`;当 exec 目标配置为 `node` 时,则为 `node`。请保持 `tools.elevated.allowFrom` 严格收紧,不要为陌生人启用它。你还可以通过 `agents.list[].tools.elevated` 对单个智能体进一步限制 elevated。参见 [Elevated Mode](/zh-CN/tools/elevated)。 ### 子智能体委派护栏 -如果你允许会话工具,请将委派给子智能体的运行视为另一项边界决策: +如果你允许会话工具,请将委派给子智能体运行视为另一项边界决策: -- 除非智能体确实需要委派,否则请禁用 `sessions_spawn`。 -- 将 `agents.defaults.subagents.allowAgents` 以及任何按智能体覆盖的 `agents.list[].subagents.allowAgents` 限制为已知安全的目标智能体。 +- 除非智能体确实需要委派,否则禁用 `sessions_spawn`。 +- 保持 `agents.defaults.subagents.allowAgents` 以及任何按智能体覆盖的 `agents.list[].subagents.allowAgents` 仅限于已知安全的目标智能体。 - 对于任何必须保持沙箱隔离的工作流,请在调用 `sessions_spawn` 时使用 `sandbox: "require"`(默认值是 `inherit`)。 -- `sandbox: "require"` 会在目标子运行时未启用沙箱隔离时快速失败。 +- 当目标子运行时未启用沙箱隔离时,`sandbox: "require"` 会快速失败。 ## 浏览器控制风险 -启用浏览器控制会赋予模型驱动真实浏览器的能力。 -如果该浏览器配置文件中已经包含已登录会话,模型就可以 -访问这些账号和数据。请将浏览器配置文件视为**敏感状态**: +启用浏览器控制会让模型具备驱动真实浏览器的能力。 +如果该浏览器配置文件中已经包含登录会话,模型就可以 +访问这些账号和数据。应将浏览器配置文件视为**敏感状态**: -- 优先为智能体使用专用配置文件(默认的 `openclaw` 配置文件)。 +- 优先为智能体使用专用配置文件(默认 `openclaw` 配置文件)。 - 避免让智能体使用你的个人日常浏览器配置文件。 -- 对于沙箱隔离智能体,除非你信任它们,否则请保持主机浏览器控制关闭。 -- 独立的 loopback 浏览器控制 API 仅接受共享 secret 认证 - (gateway token bearer auth 或 gateway password)。它不会使用 - trusted-proxy 或 Tailscale Serve 身份请求头。 -- 请将浏览器下载视为不受信任输入;优先使用隔离的下载目录。 -- 如果可能,请在智能体浏览器配置文件中禁用浏览器同步/密码管理器(缩小影响半径)。 -- 对于远程 Gateway 网关,应假定“浏览器控制”等同于该配置文件可访问内容的“操作员访问”。 -- 让 Gateway 网关和 node hosts 仅暴露在 tailnet 中;避免将浏览器控制端口暴露给 LAN 或公共互联网。 -- 在不需要时禁用浏览器代理路由(`gateway.nodes.browser.mode="off"`)。 -- Chrome MCP 现有会话模式**并不**“更安全”;它可以像你本人一样操作该主机 Chrome 配置文件能够访问的任何内容。 +- 除非你信任这些智能体,否则应对启用沙箱隔离的智能体保持主机浏览器控制关闭。 +- 独立的 loopback 浏览器控制 API 仅接受共享密钥 auth + (Gateway 网关 token bearer auth 或 Gateway 网关 password)。它不使用 + trusted-proxy 或 Tailscale Serve 身份头。 +- 应将浏览器下载内容视为不受信任输入;优先使用隔离的下载目录。 +- 如果可能,请在智能体配置文件中禁用浏览器同步/密码管理器(降低爆炸半径)。 +- 对于远程 Gateway 网关,应假设“浏览器控制”等同于对该配置文件可访问内容的“操作员访问”。 +- 让 Gateway 网关和 node host 保持仅 tailnet 可访问;避免将浏览器控制端口暴露到 LAN 或公共互联网。 +- 在不需要时关闭浏览器代理路由(`gateway.nodes.browser.mode="off"`)。 +- Chrome MCP 现有会话模式**并不**“更安全”;它可以像你一样操作该主机上 Chrome 配置文件可访问的任何内容。 ### 浏览器 SSRF 策略(默认严格) -OpenClaw 的浏览器导航策略默认是严格的:私有/内部目标会保持阻止状态,除非你显式选择允许。 +OpenClaw 的浏览器导航策略默认是严格的:私有/内部目标会保持阻止状态,除非你显式选择启用。 -- 默认:`browser.ssrfPolicy.dangerouslyAllowPrivateNetwork` 未设置,因此浏览器导航会阻止私有/内部/特殊用途目标。 -- 旧版别名:出于兼容性,仍接受 `browser.ssrfPolicy.allowPrivateNetwork`。 -- 选择启用模式:设置 `browser.ssrfPolicy.dangerouslyAllowPrivateNetwork: true`,以允许私有/内部/特殊用途目标。 -- 在严格模式下,使用 `hostnameAllowlist`(如 `*.example.com` 这类模式)和 `allowedHostnames`(精确主机例外,包括像 `localhost` 这样原本被阻止的名称)来设置显式例外。 -- 为减少基于重定向的跳转利用,会在请求前检查导航目标,并在导航完成后的最终 `http(s)` URL 上尽力再次检查。 +- 默认值:`browser.ssrfPolicy.dangerouslyAllowPrivateNetwork` 未设置,因此浏览器导航会继续阻止私有/内部/特殊用途目标。 +- 旧版别名:为兼容起见,仍接受 `browser.ssrfPolicy.allowPrivateNetwork`。 +- 显式启用模式:将 `browser.ssrfPolicy.dangerouslyAllowPrivateNetwork: true` 设为允许私有/内部/特殊用途目标。 +- 在严格模式下,可使用 `hostnameAllowlist`(如 `*.example.com` 之类的模式)和 `allowedHostnames`(精确主机例外,包括 `localhost` 这类被阻止名称)进行显式例外配置。 +- 导航会在请求前检查,并在导航结束后的最终 `http(s)` URL 上尽力重新检查,以减少基于重定向的跳转利用。 严格策略示例: @@ -1107,19 +1100,19 @@ OpenClaw 的浏览器导航策略默认是严格的:私有/内部目标会保 } ``` -## 按智能体划分的访问配置文件(多智能体) +## 按智能体划分的访问配置(多智能体) 在多智能体路由中,每个智能体都可以拥有自己的沙箱隔离 + 工具策略: -利用这一点,可按智能体分别授予**完全访问**、**只读**或**无访问权限**。 +请利用这一点为不同智能体分别配置**完全访问**、**只读**或**无访问权限**。 完整细节和优先级规则见 [Multi-Agent Sandbox & Tools](/zh-CN/tools/multi-agent-sandbox-tools)。 常见用例: -- 个人智能体:完全访问,不启用沙箱 +- 个人智能体:完全访问,无沙箱隔离 - 家庭/工作智能体:沙箱隔离 + 只读工具 - 公开智能体:沙箱隔离 + 无文件系统/shell 工具 -### 示例:完全访问(不启用沙箱) +### 示例:完全访问(无沙箱隔离) ```json5 { @@ -1159,7 +1152,7 @@ OpenClaw 的浏览器导航策略默认是严格的:私有/内部目标会保 } ``` -### 示例:无文件系统/shell 访问(允许提供商消息能力) +### 示例:无文件系统/shell 访问(允许 provider 消息) ```json5 { @@ -1173,8 +1166,8 @@ OpenClaw 的浏览器导航策略默认是严格的:私有/内部目标会保 scope: "agent", workspaceAccess: "none", }, - // 会话工具可能暴露转录记录中的敏感数据。默认情况下,OpenClaw 将这些工具限制为 - // 当前会话 + 派生出的子智能体会话,但如果需要,你可以进一步收紧。 + // 会话工具可能会从转录中泄露敏感数据。默认情况下 OpenClaw 会将这些工具限制为 + // 当前会话 + 已启动的子智能体会话,但如果需要,你还可以进一步收紧。 // 参见配置参考中的 `tools.sessions.visibility`。 tools: { sessions: { visibility: "tree" }, // self | tree | agent | all @@ -1216,36 +1209,35 @@ OpenClaw 的浏览器导航策略默认是严格的:私有/内部目标会保 ### 遏制 -1. **先停下来:**停止 macOS 应用(如果它负责监管 Gateway 网关),或终止你的 `openclaw gateway` 进程。 -2. **关闭暴露面:**将 `gateway.bind` 设为 `"loopback"`(或禁用 Tailscale Funnel/Serve),直到你弄清楚发生了什么。 -3. **冻结访问:**将高风险私信/群组切换为 `dmPolicy: "disabled"` / 要求提及,并删除你之前可能设置的 `"*"` 全部允许项。 +1. **停止它:** 停止 macOS 应用(如果它负责监管 Gateway 网关),或者终止你的 `openclaw gateway` 进程。 +2. **关闭暴露面:** 将 `gateway.bind` 设为 `"loopback"`(或禁用 Tailscale Funnel / Serve),直到你弄清楚发生了什么。 +3. **冻结访问:** 将高风险私信/群组切换为 `dmPolicy: "disabled"` / 要求提及,并移除你曾设置的 `"*"` 全开放条目。 -### 轮换(如果 secrets 泄露,则视为已被攻陷) +### 轮换(如果 secrets 泄露,则视为已被攻破) -1. 轮换 Gateway 网关认证(`gateway.auth.token` / `OPENCLAW_GATEWAY_PASSWORD`)并重启。 -2. 轮换所有可调用 Gateway 网关机器上的远程客户端 secrets(`gateway.remote.token` / `.password`)。 -3. 轮换提供商/API 凭证(WhatsApp 凭证、Slack/Discord tokens、`auth-profiles.json` 中的模型/API keys,以及启用时的加密 secrets 负载值)。 +1. 轮换 Gateway 网关 auth(`gateway.auth.token` / `OPENCLAW_GATEWAY_PASSWORD`)并重启。 +2. 轮换任意可调用 Gateway 网关的机器上的远程客户端 secrets(`gateway.remote.token` / `.password`)。 +3. 轮换 provider / API 凭证(WhatsApp 凭证、Slack / Discord token、`auth-profiles.json` 中的模型 / API key,以及使用时的加密 secrets 负载值)。 ### 审计 1. 检查 Gateway 网关日志:`/tmp/openclaw/openclaw-YYYY-MM-DD.log`(或 `logging.file`)。 -2. 检查相关转录记录:`~/.openclaw/agents//sessions/*.jsonl`。 -3. 检查最近的配置更改(任何可能扩大访问范围的内容:`gateway.bind`、`gateway.auth`、私信/群组策略、`tools.elevated`、插件变更)。 -4. 重新运行 `openclaw security audit --deep`,并确认关键发现项已解决。 +2. 查看相关转录:`~/.openclaw/agents//sessions/*.jsonl`。 +3. 查看最近的配置更改(任何可能扩大访问范围的内容:`gateway.bind`、`gateway.auth`、私信/群组策略、`tools.elevated`、插件更改)。 +4. 重新运行 `openclaw security audit --deep` 并确认关键发现已解决。 -### 为报告收集信息 +### 收集报告所需信息 -- 时间戳、gateway 主机 OS + OpenClaw 版本 -- 会话转录记录 + 一小段日志尾部(脱敏后) +- 时间戳、Gateway 网关主机操作系统 + OpenClaw 版本 +- 会话转录 + 简短日志尾部(脱敏后) - 攻击者发送了什么 + 智能体做了什么 -- Gateway 网关是否被暴露到 loopback 之外(LAN/Tailscale Funnel/Serve) +- Gateway 网关是否暴露到了 loopback 之外(LAN / Tailscale Funnel / Serve) ## 使用 detect-secrets 进行 secret 扫描 CI 会在 `secrets` job 中运行 `detect-secrets` pre-commit hook。 -推送到 `main` 时始终会扫描所有文件。Pull request 会在有基线提交可用时 -走变更文件快速路径,否则回退为全文件扫描。 -如果失败,说明出现了尚未写入 baseline 的新候选项。 +推送到 `main` 时始终执行全文件扫描。Pull request 会在存在基准提交时使用变更文件 +快速路径,否则回退为全文件扫描。如果失败,说明存在尚未加入 baseline 的新候选项。 ### 如果 CI 失败 @@ -1257,25 +1249,25 @@ CI 会在 `secrets` job 中运行 `detect-secrets` pre-commit hook。 2. 了解这些工具: - pre-commit 中的 `detect-secrets` 会使用仓库的 - baseline 和排除规则运行 `detect-secrets-hook`。 - - `detect-secrets audit` 会打开交互式审查界面,用于将 baseline - 中每一项标记为真实 secret 或误报。 -3. 对于真实 secrets:轮换/移除它们,然后重新运行扫描以更新 baseline。 -4. 对于误报:运行交互式审查,并将其标记为误报: + baseline 和排除规则来运行 `detect-secrets-hook`。 + - `detect-secrets audit` 会打开交互式审查,用于将 baseline + 中的每一项标记为真实或误报。 +3. 对于真实 secrets:轮换/删除它们,然后重新运行扫描以更新 baseline。 +4. 对于误报:运行交互式审查,并将它们标记为误报: ```bash detect-secrets audit .secrets.baseline ``` -5. 如果你需要新的排除规则,请将其添加到 `.detect-secrets.cfg`,并使用匹配的 `--exclude-files` / `--exclude-lines` 标志重新生成 - baseline(该配置文件仅供参考;detect-secrets 不会自动读取它)。 +5. 如果需要新增排除项,请将其加入 `.detect-secrets.cfg`,并使用匹配的 `--exclude-files` / `--exclude-lines` 参数重新生成 + baseline(该配置文件仅作参考;detect-secrets 不会自动读取它)。 -当 `.secrets.baseline` 反映出预期状态后,提交更新后的文件。 +当更新后的 `.secrets.baseline` 反映出预期状态后,请将其提交。 ## 报告安全问题 -在 OpenClaw 中发现漏洞了吗?请负责任地报告: +如果你在 OpenClaw 中发现漏洞,请负责任地报告: -1. 发送邮件至:[security@openclaw.ai](mailto:security@openclaw.ai) -2. 在修复之前不要公开发布 -3. 我们会署名致谢你(除非你希望匿名) +1. 邮箱:[security@openclaw.ai](mailto:security@openclaw.ai) +2. 在修复前不要公开发布 +3. 我们会为你署名致谢(如果你更希望匿名,也可以) diff --git a/docs/zh-CN/help/testing.md b/docs/zh-CN/help/testing.md index 4aa2857ef..d8ffec6ec 100644 --- a/docs/zh-CN/help/testing.md +++ b/docs/zh-CN/help/testing.md @@ -3,132 +3,134 @@ read_when: - 在本地或 CI 中运行测试 - 为模型 / 提供商缺陷添加回归测试 - 调试 Gateway 网关 + 智能体行为 -summary: 测试工具包:单元 / e2e / 实时测试套件、Docker 运行器,以及每项测试覆盖的内容 +summary: 测试工具包:unit/e2e/live 测试套件、Docker 运行器,以及每类测试涵盖的内容 title: 测试 x-i18n: - generated_at: "2026-04-24T06:14:26Z" + generated_at: "2026-04-24T06:43:49Z" model: gpt-5.4 provider: openai - source_hash: b825d25da0eb504dfc19e5dcf18b50e8c3bf07e616d0be82d096f3973dbbd785 + source_hash: 6c88325e0edb49437e7faa2eaf730eb3be59054d8c4bb86e56a42bc39a29a2b1 source_path: help/testing.md workflow: 15 --- -OpenClaw 有三个 Vitest 测试套件(单元 / 集成、e2e、实时),以及一小组 Docker 运行器。本文档是一份“我们如何测试”的指南: +OpenClaw 有三个 Vitest 测试套件(unit/integration、e2e、live)以及一小组 Docker 运行器。本文档是一份“我们如何测试”的指南: -- 每个测试套件覆盖什么内容(以及它刻意 _不_ 覆盖什么)。 -- 常见工作流该运行哪些命令(本地、推送前、调试)。 -- 实时测试如何发现凭证并选择模型 / 提供商。 +- 每个测试套件涵盖什么内容(以及它刻意 _不_ 涵盖什么)。 +- 常见工作流(本地、推送前、调试)应运行哪些命令。 +- live 测试如何发现凭证并选择模型 / 提供商。 - 如何为真实世界中的模型 / 提供商问题添加回归测试。 ## 快速开始 大多数时候: -- 完整门禁(预期在推送前执行):`pnpm build && pnpm check && pnpm check:test-types && pnpm test` -- 在配置充足的机器上更快地运行本地完整测试套件:`pnpm test:max` -- 直接使用 Vitest 监听循环:`pnpm test:watch` -- 直接按文件定位现在也支持扩展 / 渠道路径:`pnpm test extensions/discord/src/monitor/message-handler.preflight.test.ts` -- 当你在迭代单个失败用例时,优先使用定向运行。 +- 完整门禁(预期在 push 前运行):`pnpm build && pnpm check && pnpm check:test-types && pnpm test` +- 在配置较高的机器上进行更快的本地全套件运行:`pnpm test:max` +- 直接使用 Vitest watch 循环:`pnpm test:watch` +- 现在直接按文件定位也会路由到 extension / channel 路径:`pnpm test extensions/discord/src/monitor/message-handler.preflight.test.ts` +- 当你正在迭代单个失败用例时,优先使用有针对性的运行。 - 基于 Docker 的 QA 站点:`pnpm qa:lab:up` - 基于 Linux VM 的 QA 通道:`pnpm openclaw qa suite --runner multipass --scenario channel-chat-baseline` -当你修改了测试,或想要更多信心时: +当你修改测试或想要更多信心时: - 覆盖率门禁:`pnpm test:coverage` - E2E 测试套件:`pnpm test:e2e` -当你在调试真实提供商 / 模型时(需要真实凭证): +当你调试真实提供商 / 模型时(需要真实凭证): -- 实时测试套件(模型 + Gateway 网关工具 / 图像探测):`pnpm test:live` -- 安静地只跑一个实时测试文件:`pnpm test:live -- src/agents/models.profiles.live.test.ts` -- Docker 实时模型扫描:`pnpm test:docker:live-models` - - 现在每个选中的模型都会运行一次文本轮次外加一个小型“文件读取风格”探测。元数据声明支持 `image` 输入的模型还会运行一个很小的图像轮次。隔离提供商故障时,可用 `OPENCLAW_LIVE_MODEL_FILE_PROBE=0` 或 `OPENCLAW_LIVE_MODEL_IMAGE_PROBE=0` 禁用额外探测。 - - CI 覆盖:每日的 `OpenClaw Scheduled Live And E2E Checks` 和手动触发的 `OpenClaw Release Checks` 都会调用可复用的实时 / E2E 工作流,并设置 `include_live_suites: true`,其中包含按提供商分片的独立 Docker 实时模型矩阵作业。 - - 若要有针对性地重跑 CI,可触发 `OpenClaw Live And E2E Checks (Reusable)`,并设置 `include_live_suites: true` 与 `live_models_only: true`。 - - 添加新的高信号提供商密钥时,同时更新 `scripts/ci-hydrate-live-auth.sh`、`.github/workflows/openclaw-live-and-e2e-checks-reusable.yml` 以及其计划 / 发布调用方。 +- 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`,其中包括按 provider 分片的独立 Docker live 模型矩阵作业。 + - 若要聚焦 CI 重跑,可触发 `OpenClaw Live And E2E Checks (Reusable)`,并设置 `include_live_suites: true` 和 `live_models_only: true`。 + - 将新的高信号 provider 密钥添加到 `scripts/ci-hydrate-live-auth.sh`、`.github/workflows/openclaw-live-and-e2e-checks-reusable.yml` 以及其 scheduled / release 调用方中。 - 原生 Codex 绑定聊天冒烟测试:`pnpm test:docker:live-codex-bind` - - 在 Docker 中针对 Codex app-server 路径运行一个实时测试通道,使用 `/codex bind` 绑定一个合成 Slack 私信,会执行 `/codex fast` 和 `/codex permissions`,然后验证普通回复和图像附件都通过原生插件绑定而不是 ACP 路由。 -- Moonshot / Kimi 成本冒烟测试:设置 `MOONSHOT_API_KEY` 后,运行 `openclaw models list --provider moonshot --json`,然后针对 `moonshot/kimi-k2.6` 运行一个隔离的 `openclaw agent --local --session-id live-kimi-cost --message 'Reply exactly: KIMI_LIVE_OK' --thinking off --json`。验证 JSON 报告的是 Moonshot / K2.6,并且助手转录中存储了规范化的 `usage.cost`。 + - 针对 Codex app-server 路径运行一个 Docker live 通道,使用 `/codex bind` 绑定一个合成 Slack 私信,执行 `/codex fast` 和 `/codex permissions`,然后验证普通回复和图像附件都通过原生插件绑定而不是 ACP 路由。 +- Moonshot / Kimi 成本冒烟测试:设置 `MOONSHOT_API_KEY` 后,运行 `openclaw models list --provider moonshot --json`,然后针对 `moonshot/kimi-k2.6` 运行一个隔离的 `openclaw agent --local --session-id live-kimi-cost --message 'Reply exactly: KIMI_LIVE_OK' --thinking off --json`。验证 JSON 报告的是 Moonshot / K2.6,且 assistant transcript 存储了规范化的 `usage.cost`。 -提示:如果你只需要一个失败用例,优先通过下文介绍的 allowlist 环境变量来缩小实时测试范围。 +提示:如果你只需要一个失败用例,优先使用下文描述的 allowlist 环境变量来收窄 live 测试范围。 ## QA 专用运行器 -当你需要 QA-lab 级真实环境时,这些命令与主测试套件并列存在: +当你需要 QA-lab 级别的真实感时,这些命令与主测试套件配套使用: -CI 会在专用工作流中运行 QA Lab。`Parity gate` 会在匹配的 PR 上运行,也可通过手动触发结合模拟提供商运行。`QA-Lab - All Lanes` 会在 `main` 上每夜运行,也可通过手动触发,以模拟 parity gate、实时 Matrix 通道以及由 Convex 管理的实时 Telegram 通道作为并行作业运行。`OpenClaw Release Checks` 会在发布批准前运行相同通道。 +CI 会在专用工作流中运行 QA Lab。`Parity gate` 会在匹配的 PR 上运行,也可通过手动触发配合 mock 提供商运行。`QA-Lab - All Lanes` 会在 `main` 上每晚运行,也可手动触发;它会将 mock parity gate、live Matrix 通道以及由 Convex 管理的 live Telegram 通道作为并行作业运行。`OpenClaw Release Checks` 会在发布审批前运行相同的通道。 - `pnpm openclaw qa suite` - 直接在主机上运行基于仓库的 QA 场景。 - - 默认使用隔离的 Gateway 网关工作进程并行运行多个选定场景。`qa-channel` 默认并发数为 4(受所选场景数量限制)。使用 `--concurrency ` 调整工作进程数,或使用 `--concurrency 1` 回退到旧的串行通道。 - - 任一场景失败时以非零状态退出。若你想获取制品而不让退出码失败,可使用 `--allow-failures`。 - - 支持提供商模式 `live-frontier`、`mock-openai` 和 `aimock`。`aimock` 会启动一个本地的 AIMock 支持提供商服务器,用于实验性的夹具和协议模拟覆盖,但不会替代具备场景感知能力的 `mock-openai` 通道。 + - 默认会使用隔离的 Gateway 网关 worker 并行运行多个选定场景。`qa-channel` 默认并发数为 4(受所选场景数量限制)。使用 `--concurrency ` 调整 worker 数量,或使用 `--concurrency 1` 回到旧的串行通道。 + - 任一场景失败时以非零状态退出。若你想保留工件但不希望退出码失败,可使用 `--allow-failures`。 + - 支持 provider 模式 `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`。 - - 输出目录必须位于仓库根目录下,以便访客环境可以通过挂载的工作区回写。 + - 在一次性 Multipass Linux VM 中运行同样的 QA 套件。 + - 保持与主机上 `qa suite` 相同的场景选择行为。 + - 复用与 `qa suite` 相同的 provider / model 选择标志。 + - live 运行会转发对 guest 来说实际可用的 QA 认证输入:基于环境变量的 provider 密钥、QA live provider 配置路径,以及存在时的 `CODEX_HOME`。 + - 输出目录必须保留在仓库根目录下,以便 guest 能通过挂载的工作区回写。 - 在 `.artifacts/qa-e2e/...` 下写入常规 QA 报告 + 摘要,以及 Multipass 日志。 - `pnpm qa:lab:up` - - 启动基于 Docker 的 QA 站点,用于偏操作员风格的 QA 工作。 + - 启动基于 Docker 的 QA 站点,供操作员风格的 QA 工作使用。 - `pnpm test:docker:npm-onboard-channel-agent` - - 从当前检出构建 npm tarball,在 Docker 中全局安装,运行非交互式 OpenAI API 密钥新手引导,默认配置 Telegram,验证启用插件时会按需安装运行时依赖,运行 doctor,并针对一个模拟 OpenAI 端点运行一次本地智能体轮次。 - - 使用 `OPENCLAW_NPM_ONBOARD_CHANNEL=discord` 可让同一个打包安装通道改用 Discord。 + - 从当前 checkout 构建一个 npm tarball,在 Docker 中全局安装,以非交互方式运行 OpenAI API key onboarding,默认配置 Telegram,验证启用插件时会按需安装运行时依赖,运行 doctor,并针对一个模拟的 OpenAI 端点执行一次本地 agent 轮次。 + - 使用 `OPENCLAW_NPM_ONBOARD_CHANNEL=discord` 可用 Discord 运行同样的打包安装通道。 - `pnpm test:docker:npm-telegram-live` - - 在 Docker 中安装一个已发布的 OpenClaw 包,运行已安装包的新手引导,通过已安装的 CLI 配置 Telegram,然后复用实时 Telegram QA 通道,并将该已安装包作为被测 Gateway 网关。 - - 默认为 `OPENCLAW_NPM_TELEGRAM_PACKAGE_SPEC=openclaw@beta`。 - - 使用与 `pnpm openclaw qa telegram` 相同的 Telegram 环境变量凭证或 Convex 凭证来源。 + - 在 Docker 中安装已发布的 OpenClaw 包,运行已安装包的新手引导,通过已安装的 CLI 配置 Telegram,然后复用 live Telegram QA 通道,并将该已安装包作为 SUT Gateway 网关。 + - 默认使用 `OPENCLAW_NPM_TELEGRAM_PACKAGE_SPEC=openclaw@beta`。 + - 使用与 `pnpm openclaw qa telegram` 相同的 Telegram 环境变量凭证或 Convex 凭证来源。对于 CI / 发布自动化,请设置 `OPENCLAW_NPM_TELEGRAM_CREDENTIAL_SOURCE=convex`,以及 `OPENCLAW_QA_CONVEX_SITE_URL` 和角色密钥。如果在 CI 中存在 `OPENCLAW_QA_CONVEX_SITE_URL` 和 Convex 角色密钥,Docker 包装器会自动选择 Convex。 + - `OPENCLAW_NPM_TELEGRAM_CREDENTIAL_ROLE=ci|maintainer` 会仅对该通道覆盖共享的 `OPENCLAW_QA_CREDENTIAL_ROLE`。 + - GitHub Actions 将此通道公开为手动维护者工作流 `NPM Telegram Beta E2E`。它不会在合并时运行。该工作流使用 `qa-live-shared` environment 和 Convex CI 凭证租约。 - `pnpm test:docker:bundled-channel-deps` - - 在 Docker 中打包并安装当前 OpenClaw 构建,启动一个已配置 OpenAI 的 Gateway 网关,然后通过修改配置启用内置渠道 / 插件。 - - 验证设置发现阶段不会提前安装未配置插件的运行时依赖,第一次配置好的 Gateway 网关或 doctor 运行时会按需安装每个内置插件的运行时依赖,而第二次重启不会重新安装已激活的依赖。 - - 还会安装一个已知较旧的 npm 基线版本,在运行 `openclaw update --tag ` 之前启用 Telegram,并验证候选版本更新后的 doctor 会修复内置渠道运行时依赖,而无需测试框架侧的 postinstall 修复。 + - 在 Docker 中打包并安装当前 OpenClaw 构建,使用已配置的 OpenAI 启动 Gateway 网关,然后通过编辑配置启用内置 channel / plugins。 + - 验证设置发现过程会让未配置插件的运行时依赖保持未安装状态,第一次配置后的 Gateway 网关或 doctor 运行会按需安装每个内置插件的运行时依赖,而第二次重启不会重新安装已激活的依赖。 + - 还会安装一个已知的旧版 npm 基线,在运行 `openclaw update --tag ` 之前启用 Telegram,并验证候选版本在更新后的 doctor 中会修复内置 channel 运行时依赖,而不需要 harness 侧的 postinstall 修复。 - `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`)和一个私有房间,然后启动一个使用真实 Matrix 插件作为 SUT 传输层的 QA Gateway 网关子进程。 - - 默认使用固定稳定版 Tuwunel 镜像 `ghcr.io/matrix-construct/tuwunel:v1.5.1`。如需测试其他镜像,可通过 `OPENCLAW_QA_MATRIX_TUWUNEL_IMAGE` 覆盖。 - - Matrix 不暴露共享凭证来源标志,因为该通道会在本地配置一次性用户。 - - 在 `.artifacts/qa-e2e/...` 下写入 Matrix QA 报告、摘要、observed-events 制品,以及合并的 stdout / stderr 输出日志。 + - 针对一个一次性的基于 Docker 的 Tuwunel homeserver 运行 Matrix live QA 通道。 + - 这个 QA 主机目前仅供仓库 / 开发环境使用。打包后的 OpenClaw 安装不会附带 `qa-lab`,因此不会暴露 `openclaw qa`。 + - 仓库 checkout 会直接加载内置运行器;无需单独安装插件。 + - 会预配三个临时 Matrix 用户(`driver`、`sut`、`observer`)以及一个私有房间,然后启动一个 QA gateway 子进程,并使用真实的 Matrix 插件作为 SUT 传输层。 + - 默认使用固定的稳定版 Tuwunel 镜像 `ghcr.io/matrix-construct/tuwunel:v1.5.1`。如果你需要测试不同镜像,可通过 `OPENCLAW_QA_MATRIX_TUWUNEL_IMAGE` 覆盖。 + - Matrix 不暴露共享的 credential-source 标志,因为该通道会在本地预配一次性用户。 + - 会在 `.artifacts/qa-e2e/...` 下写入 Matrix QA 报告、摘要、observed-events 工件,以及合并的 stdout / stderr 输出日志。 - `pnpm openclaw qa telegram` - - 使用环境变量中的 driver 和 SUT bot token,针对一个真实私有群组运行 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`。 - - 需要同一个私有群组中的两个不同 bot,并且 SUT bot 必须公开 Telegram 用户名。 - - 为了稳定地观察 bot 之间的通信,请在 `@BotFather` 中为两个 bot 都启用 Bot-to-Bot Communication Mode,并确保 driver bot 可以观察群组中的 bot 流量。 - - 在 `.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`。group id 必须是 Telegram chat 的数字 id。 + - 支持 `--credential-source convex` 以使用共享池化凭证。默认使用 env 模式,或设置 `OPENCLAW_QA_CREDENTIAL_SOURCE=convex` 以启用池化租约。 + - 任一场景失败时以非零状态退出。若你想保留工件但不希望退出码失败,可使用 `--allow-failures`。 + - 需要同一私有群组中的两个不同 bot,并且 SUT bot 需要公开 Telegram 用户名。 + - 为了实现稳定的 bot 对 bot 观测,请在 `@BotFather` 中为两个 bot 启用 Bot-to-Bot Communication Mode,并确保 driver bot 能观测群组中的 bot 流量。 + - 会在 `.artifacts/qa-e2e/...` 下写入 Telegram QA 报告、摘要和 observed-messages 工件。replying 场景会包含从 driver 发送请求到观测到 SUT 回复的 RTT。 -实时传输通道共享一套标准契约,以避免新传输层发生漂移: +live 传输通道共享一个标准契约,以避免新传输出现漂移: -`qa-channel` 仍然是覆盖面广的合成 QA 套件,不属于实时传输覆盖矩阵的一部分。 +`qa-channel` 仍然是广义的合成 QA 套件,不属于 live 传输覆盖矩阵的一部分。 -| 通道 | Canary | 提及门控 | allowlist 阻止 | 顶层回复 | 重启恢复 | 线程跟进 | 线程隔离 | 反应观测 | 帮助命令 | -| -------- | ------ | -------------- | --------------- | --------------- | -------------- | ---------------- | ---------------- | -------------------- | ------------ | -| Matrix | x | x | x | x | x | x | x | x | | -| Telegram | x | | | | | | | | x | +| 通道 | Canary | Mention gating | Allowlist block | 顶层回复 | 重启恢复 | 线程跟进 | 线程隔离 | 反应观测 | 帮助命令 | +| ---- | ------ | -------------- | --------------- | -------- | -------- | -------- | -------- | -------- | -------- | +| Matrix | x | x | x | x | x | x | x | x | | +| Telegram | x | | | | | | | | x | ### 通过 Convex 共享 Telegram 凭证(v1) -当为 `openclaw qa telegram` 启用 `--credential-source convex`(或 `OPENCLAW_QA_CREDENTIAL_SOURCE=convex`)时,QA lab 会从一个由 Convex 支持的池中获取独占租约,在通道运行期间为该租约发送心跳,并在关闭时释放租约。 +当为 `openclaw qa telegram` 启用 `--credential-source convex`(或 `OPENCLAW_QA_CREDENTIAL_SOURCE=convex`)时,QA lab 会从一个由 Convex 支持的池中获取独占租约,在通道运行期间对该租约发送 heartbeat,并在关闭时释放该租约。 -参考 Convex 项目脚手架: +参考的 Convex 项目脚手架: - `qa/convex-credential-broker/` 必需环境变量: - `OPENCLAW_QA_CONVEX_SITE_URL`(例如 `https://your-deployment.convex.site`) -- 针对所选角色的一个密钥: +- 为所选角色提供一个密钥: - `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`) 可选环境变量: @@ -137,12 +139,12 @@ CI 会在专用工作流中运行 QA Lab。`Parity gate` 会在匹配的 PR 上 - `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_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 辅助命令: @@ -152,14 +154,14 @@ pnpm openclaw qa credentials list --kind telegram pnpm openclaw qa credentials remove --credential-id ``` -在脚本和 CI 工具中使用 `--json` 可获得机器可读输出。 +在脚本和 CI 工具中使用 `--json` 以获得机器可读的输出。 默认端点契约(`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`) @@ -180,58 +182,59 @@ pnpm openclaw qa credentials remove --credential-id Telegram 类型的 payload 结构: - `{ groupId: string, driverToken: string, sutToken: string }` -- `groupId` 必须是 Telegram 聊天的数字 id 字符串。 -- `admin/add` 会对 `kind: "telegram"` 的此结构进行校验,并拒绝格式错误的 payload。 +- `groupId` 必须是 Telegram chat id 的数字字符串。 +- `admin/add` 会对 `kind: "telegram"` 验证此结构,并拒绝格式错误的 payload。 ### 向 QA 添加一个渠道 -将一个渠道添加到 Markdown QA 系统中,严格只需要两样东西: +向 Markdown QA 系统添加一个渠道,严格来说只需要两样东西: 1. 该渠道的传输适配器。 -2. 一个用于验证渠道契约的场景包。 +2. 一个用于验证该渠道契约的场景包。 -如果共享的 `qa-lab` 主机可以承载该流程,就不要新增顶层 QA 命令根。 +如果共享的 `qa-lab` 主机能够承载整个流程,就不要新增一个顶层 QA 命令根。 `qa-lab` 负责共享主机机制: - `openclaw qa` 命令根 -- 套件启动与拆卸 +- 套件启动与拆除 - worker 并发 -- 制品写入 +- 工件写入 - 报告生成 - 场景执行 -- 对旧 `qa-channel` 场景的兼容别名 +- 对旧版 `qa-channel` 场景的兼容别名 运行器插件负责传输契约: -- `openclaw qa ` 如何挂载到共享 `qa` 根下 +- `openclaw qa ` 如何挂载到共享 `qa` 根命令之下 - 如何为该传输配置 Gateway 网关 - 如何检查就绪状态 - 如何注入入站事件 - 如何观测出站消息 -- 如何暴露转录和规范化的传输状态 -- 如何执行基于传输的操作 -- 如何处理传输专属的重置或清理 +- 如何暴露 transcript 和规范化后的传输状态 +- 如何执行由传输支持的动作 +- 如何处理传输特定的重置或清理 -新渠道的最低采纳门槛是: +新渠道的最低接入门槛是: 1. 保持 `qa-lab` 作为共享 `qa` 根的拥有者。 2. 在共享的 `qa-lab` 主机接缝上实现传输运行器。 -3. 将传输专属机制保留在运行器插件或渠道测试支架内部。 -4. 将运行器挂载为 `openclaw qa `,而不是注册一个竞争性的根命令。运行器插件应在 `openclaw.plugin.json` 中声明 `qaRunners`,并从 `runtime-api.ts` 导出匹配的 `qaRunnerCliRegistrations` 数组。 - 保持 `runtime-api.ts` 足够轻量;惰性 CLI 和运行器执行应放在单独的入口点之后。 -5. 在按主题组织的 `qa/scenarios/` 目录下编写或调整 Markdown 场景。 +3. 将传输特定机制保留在运行器插件或渠道 harness 内部。 +4. 将运行器挂载为 `openclaw qa `,而不是注册一个相互竞争的根命令。 + 运行器插件应在 `openclaw.plugin.json` 中声明 `qaRunners`,并从 `runtime-api.ts` 导出匹配的 `qaRunnerCliRegistrations` 数组。 + 保持 `runtime-api.ts` 轻量;惰性 CLI 和运行器执行应保留在独立入口点之后。 +5. 在按主题组织的 `qa/scenarios/` 目录下编写或改造 Markdown 场景。 6. 为新场景使用通用场景辅助函数。 7. 除非仓库正在进行有意的迁移,否则保持现有兼容别名继续可用。 -决策规则是严格的: +决策规则很严格: - 如果某个行为可以在 `qa-lab` 中统一表达一次,就把它放进 `qa-lab`。 -- 如果某个行为依赖某一个渠道传输,就把它保留在该运行器插件或插件测试支架中。 -- 如果某个场景需要一个多个渠道都能使用的新能力,应添加通用辅助函数,而不是在 `suite.ts` 中添加渠道专属分支。 -- 如果某个行为只对一种传输有意义,就保持该场景为传输专属,并在场景契约中明确说明。 +- 如果某个行为依赖单一渠道传输,就将其保留在该运行器插件或插件 harness 中。 +- 如果某个场景需要一个可被多个渠道使用的新能力,请添加通用辅助函数,而不是在 `suite.ts` 中添加渠道特定分支。 +- 如果某个行为只对一种传输有意义,就让该场景保持传输特定,并在场景契约中明确说明。 -新场景推荐使用的通用辅助函数名称是: +新场景推荐使用的通用辅助函数名称: - `waitForTransportReady` - `waitForChannelReady` @@ -254,18 +257,18 @@ Telegram 类型的 payload 结构: - `formatConversationTranscript` - `resetBus` -新的渠道工作应使用通用辅助函数名称。 -兼容别名的存在是为了避免一次性迁移,不应作为新场景编写的范式。 +新的渠道工作应使用通用辅助函数名称。 +兼容别名的存在是为了避免一次性迁移日,而不是作为新场景编写的范式。 -## 测试套件(各自运行位置) +## 测试套件(哪些内容在哪里运行) -可以把这些套件理解为“真实度逐步增加”(同时不稳定性 / 成本也逐步增加): +可以将这些套件理解为“真实性逐步提升”(同时不稳定性 / 成本也逐步上升): -### 单元 / 集成(默认) +### Unit / integration(默认) - 命令:`pnpm test` - 配置:未定向运行使用 `vitest.full-*.config.ts` 分片集合,并且可能会将多项目分片展开为按项目划分的配置,以便并行调度 -- 文件:核心 / 单元清单位于 `src/**/*.test.ts`、`packages/**/*.test.ts`、`test/**/*.test.ts`,以及由 `vitest.unit.config.ts` 覆盖的白名单 `ui` node 测试 +- 文件:`src/**/*.test.ts`、`packages/**/*.test.ts`、`test/**/*.test.ts` 下的 core / unit 清单,以及 `vitest.unit.config.ts` 覆盖的白名单 `ui` node 测试 - 范围: - 纯单元测试 - 进程内集成测试(Gateway 网关认证、路由、工具、解析、配置) @@ -275,285 +278,289 @@ Telegram 类型的 payload 结构: - 不需要真实密钥 - 应该快速且稳定 - - 未定向的 `pnpm test` 运行的是十二个较小的分片配置(`core-unit-fast`、`core-unit-src`、`core-unit-security`、`core-unit-ui`、`core-unit-support`、`core-support-boundary`、`core-contracts`、`core-bundled`、`core-runtime`、`agentic`、`auto-reply`、`extensions`),而不是一个巨大的原生根项目进程。这样可以降低高负载机器上的 RSS 峰值,并避免 auto-reply / 扩展工作拖累无关套件。 - `pnpm test --watch` 仍然使用原生根 `vitest.config.ts` 项目图,因为多分片 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 变更路径展开到相同的定向通道;配置 / 设置修改仍会回退到更广泛的根项目重跑。 - `pnpm check:changed` 是窄范围工作常规使用的智能本地门禁。它会将 diff 分类为核心、核心测试、扩展、扩展测试、应用、文档、发布元数据和工具,然后运行匹配的 typecheck / lint / 测试通道。公共插件 SDK 和插件契约变更会额外包含一次扩展验证,因为扩展依赖这些核心契约。仅发布元数据版本号变更会运行定向的版本 / 配置 / 根依赖检查,而不是完整套件,同时有一个保护措施会拒绝顶层版本字段之外的 `package` 变更。 - 来自智能体、命令、插件、auto-reply 辅助函数、`plugin-sdk` 以及类似纯工具区域的轻导入单元测试会路由到 `unit-fast` 通道,该通道会跳过 `test/setup-openclaw-runtime.ts`;有状态 / 运行时较重的文件仍保留在现有通道中。 - 某些选定的 `plugin-sdk` 和 `commands` 辅助源文件在 changed 模式下也会映射到这些轻量通道中的显式同级测试,因此辅助函数改动无需让该目录重跑完整的重型套件。 - `auto-reply` 有三个专用分桶:顶层核心辅助函数、顶层 `reply.*` 集成测试,以及 `src/auto-reply/reply/**` 子树。这让最重的 reply 测试支架工作不会压到廉价的状态 / 分块 / token 测试上。 + - 未定向的 `pnpm test` 会运行十二个更小的分片配置(`core-unit-fast`、`core-unit-src`、`core-unit-security`、`core-unit-ui`、`core-unit-support`、`core-support-boundary`、`core-contracts`、`core-bundled`、`core-runtime`、`agentic`、`auto-reply`、`extensions`),而不是运行一个庞大的原生根项目进程。这样可以降低高负载机器上的峰值 RSS,并避免 auto-reply / extension 工作拖慢无关套件。 - `pnpm test --watch` 仍然使用原生根 `vitest.config.ts` 项目图,因为多分片 watch 循环并不实际。 - `pnpm test`、`pnpm test:watch` 和 `pnpm test:perf:imports` 会优先通过作用域通道路由显式文件 / 目录目标,因此 `pnpm test extensions/discord/src/monitor/message-handler.preflight.test.ts` 可以避免承担完整根项目启动开销。 - 当变更只涉及可路由的源文件 / 测试文件时,`pnpm test:changed` 会将变更的 git 路径展开到同样的作用域通道;而配置 / setup 编辑仍会回退到广泛的根项目重跑。 - `pnpm check:changed` 是窄范围工作时常规的智能本地门禁。它会将 diff 分类为 core、core tests、extensions、extension tests、apps、docs、发布元数据和工具,然后运行匹配的 typecheck / lint / test 通道。公共插件 SDK 和插件契约变更会额外包含一次 extension 验证,因为 extensions 依赖这些 core 契约。仅包含发布元数据的版本升级会运行定向的版本 / 配置 / 根依赖检查,而不是完整套件,并带有一个保护机制:若包变更超出顶层版本字段,则会被拒绝。 - 来自 agents、commands、plugins、auto-reply helpers、`plugin-sdk` 以及类似纯工具区域的轻导入 unit 测试,会通过 `unit-fast` 通道路由,该通道会跳过 `test/setup-openclaw-runtime.ts`;而有状态 / 运行时较重的文件仍保留在现有通道上。 - 某些 `plugin-sdk` 和 `commands` helper 源文件在 changed-mode 运行中也会映射到轻量通道中的显式同级测试,因此 helper 编辑无需为该目录重跑完整的重型套件。 - `auto-reply` 有三个专用桶:顶层 core helpers、顶层 `reply.*` 集成测试,以及 `src/auto-reply/reply/**` 子树。这样可以让最重的 reply harness 工作脱离廉价的状态 / 分块 / token 测试。 - - 当你修改消息工具发现输入或压缩运行时上下文时,请同时保持两个层级的覆盖。 - - 为纯路由和规范化边界添加聚焦的辅助函数回归测试。 - - 保持嵌入式运行器集成测试套件健康: - `src/agents/pi-embedded-runner/compact.hooks.test.ts`、 - `src/agents/pi-embedded-runner/run.overflow-compaction.test.ts` 和 + - 当你修改消息工具发现输入或压缩运行时上下文时,请同时保持两层覆盖。 + - 为纯路由和规范化边界添加聚焦的 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 和压缩行为仍通过真实的 `run.ts` / `compact.ts` 路径流转;仅有 helper 测试不足以替代这些集成路径。 - + - 基础 Vitest 配置默认使用 `threads`。 - - 共享 Vitest 配置固定 `isolate: false`,并在根项目、e2e 和实时配置中使用非隔离运行器。 - - 根 UI 通道保留其 `jsdom` 设置和优化器,但同样运行在共享的非隔离运行器上。 + - 共享的 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 行为进行对比。 + - `scripts/run-vitest.mjs` 默认会为 Vitest 子 Node 进程添加 `--no-maglev`,以减少大型本地运行期间的 V8 编译抖动。设置 `OPENCLAW_VITEST_ENABLE_MAGLEV=1` 可与原生 V8 行为进行对比。 - - `pnpm changed:lanes` 会显示一个 diff 会触发哪些架构通道。 - - pre-commit hook 仅做格式化。它会重新暂存格式化后的文件,但不会运行 lint、typecheck 或测试。 - - 当你需要智能本地门禁时,请在交接或推送前显式运行 `pnpm check:changed`。公共插件 SDK 和插件契约变更会额外包含一次扩展验证。 - - `pnpm test:changed` 会在变更路径可以清晰映射到较小套件时通过定向通道执行。 + - `pnpm changed:lanes` 会显示某个 diff 会触发哪些架构通道。 + - pre-commit hook 仅负责格式化。它会重新暂存格式化后的文件,不会运行 lint、typecheck 或测试。 + - 当你需要智能本地门禁时,请在交接或 push 前显式运行 `pnpm check:changed`。公共插件 SDK 和插件契约变更会包含一次 extension 验证。 + - 当变更路径能清晰映射到更小套件时,`pnpm test:changed` 会通过作用域通道路由。 - `pnpm test:max` 和 `pnpm test:changed:max` 保持相同的路由行为,只是使用更高的 worker 上限。 - - 本地 worker 自动扩缩容刻意较为保守,当主机负载平均值已经较高时会主动回退,因此默认情况下多个并发 Vitest 运行造成的影响更小。 - - 基础 Vitest 配置会将项目 / 配置文件标记为 `forceRerunTriggers`,从而在测试接线变更时仍能保证 changed 模式重跑的正确性。 - - 配置会在受支持主机上保持启用 `OPENCLAW_VITEST_FS_MODULE_CACHE`;如果你想为直接分析指定一个明确的缓存位置,可设置 `OPENCLAW_VITEST_FS_MODULE_CACHE_PATH=/abs/path`。 + - 本地 worker 自动扩缩容有意保持保守;当主机负载平均值已经很高时,会自动降速,因此默认情况下多个并发 Vitest 运行造成的影响更小。 + - 基础 Vitest 配置会将项目 / 配置文件标记为 `forceRerunTriggers`,以便测试接线变化时 changed-mode 重跑仍然正确。 + - 在受支持主机上,配置会保持启用 `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` 以来变更的文件。 - - 如果某个热点测试仍然把大部分时间花在启动导入上,请把重依赖放在一个窄范围的本地 `*.runtime.ts` 接缝之后,并直接 mock 该接缝,而不要仅仅为了通过 `vi.mock(...)` 传递它们就深度导入运行时辅助函数。 - - `pnpm test:perf:changed:bench -- --ref ` 会将定向 `test:changed` 与该提交 diff 的原生根项目路径进行对比,并输出墙钟时间以及 macOS 最大 RSS。 - - `pnpm test:perf:changed:bench -- --worktree` 会通过 `scripts/test-projects.mjs` 和根 Vitest 配置将当前脏工作树的变更文件列表进行路由,并做基准测试。 + - `pnpm test:perf:imports` 会启用 Vitest 导入时长报告以及导入拆解输出。 + - `pnpm test:perf:imports:changed` 会将相同的分析视图限定到自 `origin/main` 以来变更的文件。 + - 当某个热点测试仍将大部分时间花在启动导入上时,应将重依赖放在狭窄的本地 `*.runtime.ts` 接缝之后,并直接 mock 该接缝,而不是为了通过 `vi.mock(...)` 传递它们就深度导入运行时辅助函数。 + - `pnpm test:perf:changed:bench -- --ref ` 会将已路由的 `test:changed` 与该已提交 diff 的原生根项目路径进行比较,并输出 wall time 以及 macOS 最大 RSS。 + - `pnpm test:perf:changed:bench -- --worktree` 会通过将变更文件列表路由到 `scripts/test-projects.mjs` 和根 Vitest 配置,对当前未提交工作树进行基准测试。 - `pnpm test:perf:profile:main` 会为 Vitest / Vite 启动与 transform 开销写入主线程 CPU profile。 - - `pnpm test:perf:profile:runner` 会在禁用文件并行的情况下,为单元测试套件写入运行器 CPU + heap profile。 + - `pnpm test:perf:profile:runner` 会在禁用文件级并行的情况下,为 unit 套件写入 runner CPU + heap profile。 ### 稳定性(Gateway 网关) - 命令:`pnpm test:stability:gateway` -- 配置:`vitest.gateway.config.ts`,强制单 worker +- 配置:`vitest.gateway.config.ts`,强制使用单个 worker - 范围: - - 启动一个默认启用诊断功能的真实 loopback Gateway 网关 - - 通过诊断事件路径驱动合成的 Gateway 网关消息、内存和大载荷抖动 + - 启动一个真实的 loopback Gateway 网关,并默认启用诊断 + - 通过诊断事件路径驱动合成的 gateway 消息、memory 和大负载 churn - 通过 Gateway 网关 WS RPC 查询 `diagnostics.stability` - 覆盖诊断稳定性 bundle 持久化辅助函数 - - 断言记录器保持有界、合成 RSS 采样保持在压力预算之下,并且每个会话的队列深度最终回落到零 + - 断言 recorder 保持有界、合成 RSS 样本保持在压力预算之下,以及每个 session 的队列深度会回落到零 - 预期: - - 对 CI 安全且不需要密钥 - - 这是用于稳定性回归跟进的窄通道,不可替代完整的 Gateway 网关测试套件 + - 可安全用于 CI,且不需要密钥 + - 这是一个用于稳定性回归跟进的窄通道,不可替代完整的 Gateway 网关套件 ### E2E(Gateway 网关冒烟) - 命令:`pnpm test:e2e` - 配置:`vitest.e2e.config.ts` -- 文件:`src/**/*.e2e.test.ts`、`test/**/*.e2e.test.ts`,以及 `extensions/` 下的内置插件 E2E 测试 +- 文件:`src/**/*.e2e.test.ts`、`test/**/*.e2e.test.ts`,以及 `extensions/` 下内置插件的 E2E 测试 - 运行时默认值: - - 使用 Vitest `threads`,并设置 `isolate: false`,与仓库其余部分保持一致。 + - 使用 Vitest `threads` 并设置 `isolate: false`,与仓库其余部分保持一致。 - 使用自适应 worker(CI:最多 2 个,本地:默认 1 个)。 - 默认以静默模式运行,以减少控制台 I/O 开销。 - 常用覆盖项: - - `OPENCLAW_E2E_WORKERS=` 用于强制指定 worker 数量(上限为 16)。 - - `OPENCLAW_E2E_VERBOSE=1` 用于重新启用详细控制台输出。 + - `OPENCLAW_E2E_WORKERS=` 强制指定 worker 数量(上限为 16)。 + - `OPENCLAW_E2E_VERBOSE=1` 重新启用详细控制台输出。 - 范围: - - 多实例 Gateway 网关端到端行为 + - 多实例 gateway 端到端行为 - WebSocket / HTTP 接口、节点配对以及更重的网络行为 - 预期: - - 会在 CI 中运行(当流水线启用时) + - 在 CI 中运行(当流水线启用时) - 不需要真实密钥 - - 比单元测试涉及更多活动部件(可能更慢) + - 比 unit 测试涉及更多活动部件(可能更慢) ### E2E:OpenShell 后端冒烟 - 命令:`pnpm test:e2e:openshell` - 文件:`extensions/openshell/src/backend.e2e.test.ts` - 范围: - - 通过 Docker 在主机上启动一个隔离的 OpenShell Gateway 网关 + - 通过 Docker 在主机上启动一个隔离的 OpenShell gateway - 从临时本地 Dockerfile 创建一个沙箱 - - 通过真实的 `sandbox ssh-config` + SSH exec 运行 OpenClaw 的 OpenShell 后端 + - 通过真实的 `sandbox ssh-config` + SSH exec 测试 OpenClaw 的 OpenShell 后端 - 通过沙箱 fs bridge 验证远端规范文件系统行为 - 预期: - 仅按需启用;不属于默认 `pnpm test:e2e` 运行的一部分 - - 需要本地 `openshell` CLI 和可用的 Docker daemon - - 使用隔离的 `HOME` / `XDG_CONFIG_HOME`,然后销毁测试 Gateway 网关和沙箱 + - 需要本地 `openshell` CLI 以及可用的 Docker daemon + - 使用隔离的 `HOME` / `XDG_CONFIG_HOME`,然后销毁测试 gateway 和沙箱 - 常用覆盖项: - - `OPENCLAW_E2E_OPENSHELL=1`,在手动运行更广泛的 e2e 测试套件时启用该测试 - - `OPENCLAW_E2E_OPENSHELL_COMMAND=/path/to/openshell`,用于指定非默认 CLI 二进制或包装脚本 + - `OPENCLAW_E2E_OPENSHELL=1`,在手动运行更广泛的 e2e 套件时启用该测试 + - `OPENCLAW_E2E_OPENSHELL_COMMAND=/path/to/openshell`,指向非默认 CLI 二进制或包装脚本 -### 实时测试(真实提供商 + 真实模型) +### Live(真实 provider + 真实模型) - 命令:`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`) - 范围: - - “这个提供商 / 模型在 _今天_ 搭配真实凭证时真的能工作吗?” - - 捕获提供商格式变化、工具调用怪癖、认证问题以及速率限制行为 + - “这个 provider / 模型 _今天_ 是否真的能在真实凭证下工作?” + - 捕获 provider 格式变化、工具调用怪癖、认证问题和限流行为 - 预期: - - 按设计并不具备 CI 稳定性(真实网络、真实提供商策略、配额、故障) - - 会花钱 / 消耗速率限制 - - 优先运行缩小范围的子集,而不是“全部” -- 实时运行会读取 `~/.profile`,以获取缺失的 API 密钥。 -- 默认情况下,实时运行仍会隔离 `HOME`,并将配置 / 认证材料复制到临时测试 home 中,以便单元测试夹具不会修改你的真实 `~/.openclaw`。 -- 仅当你有意需要让实时测试使用真实 home 目录时,才设置 `OPENCLAW_LIVE_USE_REAL_HOME=1`。 -- `pnpm test:live` 现在默认采用更安静的模式:会保留 `[live] ...` 进度输出,但抑制额外的 `~/.profile` 提示,并静默 Gateway 网关启动日志 / Bonjour 噪声。如果你想恢复完整启动日志,可设置 `OPENCLAW_LIVE_TEST_QUIET=0`。 -- API 密钥轮换(提供商专属):设置逗号 / 分号格式的 `*_API_KEYS` 或 `*_API_KEY_1`、`*_API_KEY_2`(例如 `OPENAI_API_KEYS`、`ANTHROPIC_API_KEYS`、`GEMINI_API_KEYS`),或者通过 `OPENCLAW_LIVE_*_KEY` 进行每次实时运行覆盖;测试在遇到速率限制响应时会重试。 -- 进度 / 心跳输出: - - 实时测试套件现在会将进度行输出到 stderr,因此即使 Vitest 控制台捕获较安静,长时间的提供商调用也能明显显示为仍在活动中。 - - `vitest.live.config.ts` 禁用了 Vitest 控制台拦截,因此提供商 / Gateway 网关进度行会在实时运行期间立即流式输出。 - - 使用 `OPENCLAW_LIVE_HEARTBEAT_MS` 调整直接模型心跳。 - - 使用 `OPENCLAW_LIVE_GATEWAY_HEARTBEAT_MS` 调整 Gateway 网关 / 探测心跳。 + - 按设计不具有 CI 稳定性(真实网络、真实 provider 策略、配额、故障) + - 会花钱 / 使用限流额度 + - 应优先运行收窄后的子集,而不是“全部” +- live 运行会 source `~/.profile`,以获取缺失的 API key。 +- 默认情况下,live 运行仍会隔离 `HOME`,并将配置 / 认证材料复制到临时测试 home 中,这样 unit fixture 就不会修改你真实的 `~/.openclaw`。 +- 仅当你有意让 live 测试使用真实 home 目录时,才设置 `OPENCLAW_LIVE_USE_REAL_HOME=1`。 +- `pnpm test:live` 现在默认使用更安静的模式:它保留 `[live] ...` 进度输出,但会抑制额外的 `~/.profile` 提示,并静默 gateway 启动日志 / Bonjour 杂讯。如果你想恢复完整启动日志,请设置 `OPENCLAW_LIVE_TEST_QUIET=0`。 +- API key 轮换(provider 特定):设置 `*_API_KEYS`,使用逗号 / 分号格式,或设置 `*_API_KEY_1`、`*_API_KEY_2`(例如 `OPENAI_API_KEYS`、`ANTHROPIC_API_KEYS`、`GEMINI_API_KEYS`),也可以通过 `OPENCLAW_LIVE_*_KEY` 进行每次 live 运行覆盖;测试会在遇到 rate limit 响应时重试。 +- 进度 / heartbeat 输出: + - live 套件现在会将进度行输出到 stderr,因此即使 Vitest 控制台捕获很安静,长时间的 provider 调用也能显示仍在活动中。 + - `vitest.live.config.ts` 会禁用 Vitest 控制台拦截,以便 provider / gateway 进度行在 live 运行期间立即流式输出。 + - 使用 `OPENCLAW_LIVE_HEARTBEAT_MS` 调整直接模型 heartbeat。 + - 使用 `OPENCLAW_LIVE_GATEWAY_HEARTBEAT_MS` 调整 gateway / probe heartbeat。 -## 我应该运行哪个测试套件? +## 我应该运行哪个套件? -使用这个决策表: +使用下面这个决策表: -- 修改逻辑 / 测试:运行 `pnpm test`(如果你改动很多,再运行 `pnpm test:coverage`) -- 触及 Gateway 网关网络 / WS 协议 / 配对:额外运行 `pnpm test:e2e` -- 调试“我的 bot 挂了” / 提供商专属故障 / 工具调用问题:运行缩小范围的 `pnpm test:live` +- 编辑逻辑 / 测试:运行 `pnpm test`(如果你改动很多,再加上 `pnpm test:coverage`) +- 涉及 gateway 网络 / WS 协议 / 配对:加跑 `pnpm test:e2e` +- 调试“我的 bot 挂了” / provider 特定故障 / 工具调用:运行收窄后的 `pnpm test:live` -## 实时测试(触网测试) +## Live(触网)测试 -关于实时模型矩阵、CLI 后端冒烟、ACP 冒烟、Codex app-server -测试支架,以及所有媒体提供商实时测试(Deepgram、BytePlus(国际版)、ComfyUI、图像、音乐、视频、媒体测试支架)——以及实时运行的凭证处理——请参见 -[测试——实时测试套件](/zh-CN/help/testing-live)。 +关于 live 模型矩阵、CLI 后端冒烟、ACP 冒烟、Codex app-server +harness,以及所有媒体 provider live 测试(Deepgram、BytePlus(国际版)、ComfyUI、图像、 +音乐、视频、媒体 harness)——外加 live 运行的凭证处理——请参见 +[测试 — live 套件](/zh-CN/help/testing-live)。 ## Docker 运行器(可选的“在 Linux 中可工作”检查) -这些 Docker 运行器分成两类: +这些 Docker 运行器分为两类: -- 实时模型运行器:`test:docker:live-models` 和 `test:docker:live-gateway` 只会在仓库 Docker 镜像中运行与之匹配的 profile-key 实时测试文件(`src/agents/models.profiles.live.test.ts` 和 `src/gateway/gateway-models.profiles.live.test.ts`),挂载你的本地配置目录和工作区(如果已挂载,也会读取 `~/.profile`)。对应的本地入口点是 `test:live:models-profiles` 和 `test:live:gateway-profiles`。 -- Docker 实时运行器默认使用较小的冒烟上限,以便完整 Docker 扫描保持可行: - `test:docker:live-models` 默认设置 `OPENCLAW_LIVE_MAX_MODELS=12`,而 - `test:docker:live-gateway` 默认设置 `OPENCLAW_LIVE_GATEWAY_SMOKE=1`、 +- live 模型运行器:`test:docker:live-models` 和 `test:docker:live-gateway` 只会在仓库 Docker 镜像内运行其对应的 profile-key live 文件(`src/agents/models.profiles.live.test.ts` 和 `src/gateway/gateway-models.profiles.live.test.ts`),并挂载你的本地配置目录和工作区(如果已挂载,则也会 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 镜像,然后在两个实时 Docker 通道中复用它。它还会通过 `test:docker:e2e-build` 构建一个共享的 `scripts/e2e/Dockerfile` 镜像,并在执行已构建应用的 E2E 容器冒烟运行器中复用该镜像。 + `OPENCLAW_LIVE_GATEWAY_MODEL_TIMEOUT_MS=90000`。当你 + 明确想要更大规模的穷尽扫描时,可覆盖这些环境变量。 +- `test:docker:all` 会先通过 `test:docker:live-build` 构建一次 live Docker 镜像,然后在两个 live Docker 通道中复用它。它还会通过 `test:docker:e2e-build` 构建一个共享的 `scripts/e2e/Dockerfile` 镜像,并将其复用于测试构建后应用的 E2E 容器冒烟运行器。 - 容器冒烟运行器:`test:docker:openwebui`、`test:docker:onboard`、`test:docker:npm-onboard-channel-agent`、`test:docker:gateway-network`、`test:docker:mcp-channels`、`test:docker:pi-bundle-mcp-tools`、`test:docker:cron-mcp-cleanup`、`test:docker:plugins`、`test:docker:plugin-update` 和 `test:docker:config-reload` 会启动一个或多个真实容器,并验证更高层级的集成路径。 -实时模型 Docker 运行器还只会 bind-mount 所需的 CLI 认证 home(如果运行未缩小范围,则挂载所有受支持的 home),然后在运行前将它们复制到容器 home 中,以便外部 CLI OAuth 可以刷新 token,同时不会修改主机认证存储: +live 模型 Docker 运行器还只会 bind-mount 所需的 CLI 认证 home(如果运行未收窄,则挂载所有受支持的认证 home),然后在运行前将它们复制到容器 home 中,这样外部 CLI OAuth 就可以刷新 token,而不会修改主机认证存储: - 直接模型:`pnpm test:docker:live-models`(脚本:`scripts/test-live-models-docker.sh`) - ACP 绑定冒烟:`pnpm test:docker:live-acp-bind`(脚本:`scripts/test-live-acp-bind-docker.sh`) - CLI 后端冒烟:`pnpm test:docker:live-cli-backend`(脚本:`scripts/test-live-cli-backend-docker.sh`) -- Codex app-server 测试支架冒烟:`pnpm test:docker:live-codex-harness`(脚本:`scripts/test-live-codex-harness-docker.sh`) -- Gateway 网关 + 开发智能体:`pnpm test:docker:live-gateway`(脚本:`scripts/test-live-gateway-models-docker.sh`) -- Open WebUI 实时冒烟:`pnpm test:docker:openwebui`(脚本:`scripts/e2e/openwebui-docker.sh`) +- Codex app-server harness 冒烟:`pnpm test:docker:live-codex-harness`(脚本:`scripts/test-live-codex-harness-docker.sh`) +- Gateway 网关 + dev 智能体:`pnpm test:docker:live-gateway`(脚本:`scripts/test-live-gateway-models-docker.sh`) +- Open WebUI live 冒烟:`pnpm test:docker:openwebui`(脚本:`scripts/e2e/openwebui-docker.sh`) - 新手引导向导(TTY,完整脚手架):`pnpm test:docker:onboard`(脚本:`scripts/e2e/onboard-docker.sh`) -- npm tarball 新手引导 / 渠道 / 智能体冒烟:`pnpm test:docker:npm-onboard-channel-agent` 会在 Docker 中全局安装打包后的 OpenClaw tarball,通过环境变量引用式新手引导配置 OpenAI,并默认配置 Telegram,验证 doctor 会修复已激活插件的运行时依赖,然后运行一次模拟的 OpenAI 智能体轮次。可通过 `OPENCLAW_NPM_ONBOARD_PACKAGE_TGZ=/path/to/openclaw-*.tgz` 复用预构建 tarball,通过 `OPENCLAW_NPM_ONBOARD_HOST_BUILD=0` 跳过主机构建,或通过 `OPENCLAW_NPM_ONBOARD_CHANNEL=discord` 切换渠道。 -- Bun 全局安装冒烟:`bash scripts/e2e/bun-global-install-smoke.sh` 会打包当前工作树,在隔离的 home 中使用 `bun install -g` 安装,并验证 `openclaw infer image providers --json` 会返回内置图像提供商而不是卡住。可通过 `OPENCLAW_BUN_GLOBAL_SMOKE_PACKAGE_TGZ=/path/to/openclaw-*.tgz` 复用预构建 tarball,通过 `OPENCLAW_BUN_GLOBAL_SMOKE_HOST_BUILD=0` 跳过主机构建,或通过 `OPENCLAW_BUN_GLOBAL_SMOKE_DIST_IMAGE=openclaw-dockerfile-smoke:local` 从已构建的 Docker 镜像复制 `dist/`。 -- 安装冒烟 Docker 测试:`bash scripts/test-install-sh-docker.sh` 会在 root、更新和 direct-npm 容器之间共享一个 npm 缓存。更新冒烟默认以 npm `latest` 作为稳定基线,再升级到候选 tarball。非 root 安装器检查会保持隔离的 npm 缓存,以免 root 拥有的缓存条目掩盖用户本地安装行为。设置 `OPENCLAW_INSTALL_SMOKE_NPM_CACHE_DIR=/path/to/cache` 可在本地重跑之间复用 root / 更新 / direct-npm 缓存。 -- Install Smoke CI 会通过 `OPENCLAW_INSTALL_SMOKE_SKIP_NPM_GLOBAL=1` 跳过重复的 direct-npm 全局更新;如果你需要直接 `npm install -g` 覆盖,请在本地运行脚本时不要设置该环境变量。 +- Npm tarball 新手引导 / 渠道 / 智能体冒烟:`pnpm test:docker:npm-onboard-channel-agent` 会在 Docker 中全局安装打包后的 OpenClaw tarball,通过 env-ref onboarding 配置 OpenAI,并默认配置 Telegram,验证 doctor 会修复已激活插件的运行时依赖,并运行一次模拟的 OpenAI 智能体轮次。可使用 `OPENCLAW_NPM_ONBOARD_PACKAGE_TGZ=/path/to/openclaw-*.tgz` 复用预构建 tarball,使用 `OPENCLAW_NPM_ONBOARD_HOST_BUILD=0` 跳过主机构建,或使用 `OPENCLAW_NPM_ONBOARD_CHANNEL=discord` 切换渠道。 +- Bun 全局安装冒烟:`bash scripts/e2e/bun-global-install-smoke.sh` 会打包当前工作树,在隔离的 home 中使用 `bun install -g` 安装,并验证 `openclaw infer image providers --json` 会返回内置图像 provider,而不是卡住。可使用 `OPENCLAW_BUN_GLOBAL_SMOKE_PACKAGE_TGZ=/path/to/openclaw-*.tgz` 复用预构建 tarball,使用 `OPENCLAW_BUN_GLOBAL_SMOKE_HOST_BUILD=0` 跳过主机构建,或使用 `OPENCLAW_BUN_GLOBAL_SMOKE_DIST_IMAGE=openclaw-dockerfile-smoke:local` 从已构建的 Docker 镜像复制 `dist/`。 +- 安装器 Docker 冒烟:`bash scripts/test-install-sh-docker.sh` 会在其 root、update 和 direct-npm 容器之间共享一个 npm 缓存。更新冒烟默认使用 npm `latest` 作为稳定基线,然后再升级到候选 tarball。非 root 安装器检查会保留独立的 npm 缓存,这样 root 拥有的缓存条目就不会掩盖用户本地安装行为。设置 `OPENCLAW_INSTALL_SMOKE_NPM_CACHE_DIR=/path/to/cache` 可在本地重跑之间复用 root / update / direct-npm 缓存。 +- Install Smoke CI 会通过 `OPENCLAW_INSTALL_SMOKE_SKIP_NPM_GLOBAL=1` 跳过重复的 direct-npm 全局更新;当你需要覆盖直接 `npm install -g` 时,请在本地运行脚本且不要设置该环境变量。 - Gateway 网关网络(两个容器,WS 认证 + 健康检查):`pnpm test:docker:gateway-network`(脚本:`scripts/e2e/gateway-network-docker.sh`) -- OpenAI Responses `web_search` 最小推理回归测试:`pnpm test:docker:openai-web-search-minimal`(脚本:`scripts/e2e/openai-web-search-minimal-docker.sh`)会通过 Gateway 网关运行一个模拟 OpenAI 服务器,验证 `web_search` 会将 `reasoning.effort` 从 `minimal` 提升到 `low`,然后强制提供商 schema 拒绝,并检查原始细节是否出现在 Gateway 网关日志中。 -- MCP 渠道桥接(带种子 Gateway 网关 + stdio bridge + 原始 Claude notification-frame 冒烟):`pnpm test:docker:mcp-channels`(脚本:`scripts/e2e/mcp-channels-docker.sh`) +- OpenAI Responses `web_search` 最小推理回归:`pnpm test:docker:openai-web-search-minimal`(脚本:`scripts/e2e/openai-web-search-minimal-docker.sh`)会通过 Gateway 网关运行一个模拟的 OpenAI 服务器,验证 `web_search` 会将 `reasoning.effort` 从 `minimal` 提升到 `low`,然后强制 provider schema 拒绝,并检查原始细节是否出现在 Gateway 网关日志中。 +- MCP 渠道桥接(带 seed 的 Gateway 网关 + stdio bridge + 原始 Claude 通知帧冒烟):`pnpm test:docker:mcp-channels`(脚本:`scripts/e2e/mcp-channels-docker.sh`) - Pi bundle MCP 工具(真实 stdio MCP 服务器 + 嵌入式 Pi profile allow / deny 冒烟):`pnpm test:docker:pi-bundle-mcp-tools`(脚本:`scripts/e2e/pi-bundle-mcp-tools-docker.sh`) -- Cron / 子智能体 MCP 清理(真实 Gateway 网关 + stdio MCP 子进程在隔离 cron 和一次性子智能体运行后的销毁):`pnpm test:docker:cron-mcp-cleanup`(脚本:`scripts/e2e/cron-mcp-cleanup-docker.sh`) +- Cron / subagent MCP 清理(真实 Gateway 网关 + 隔离 cron 和一次性 subagent 运行后的 stdio MCP 子进程拆除):`pnpm test:docker:cron-mcp-cleanup`(脚本:`scripts/e2e/cron-mcp-cleanup-docker.sh`) - 插件(安装冒烟 + `/plugin` 别名 + Claude bundle 重启语义):`pnpm test:docker:plugins`(脚本:`scripts/e2e/plugins-docker.sh`) - 插件更新未变更冒烟:`pnpm test:docker:plugin-update`(脚本:`scripts/e2e/plugin-update-unchanged-docker.sh`) - 配置热重载元数据冒烟:`pnpm test:docker:config-reload`(脚本:`scripts/e2e/config-reload-source-docker.sh`) -- 内置插件运行时依赖:`pnpm test:docker:bundled-channel-deps` 默认会构建一个小型 Docker 运行器镜像,在主机上构建并打包一次 OpenClaw,然后将该 tarball 挂载到每个 Linux 安装场景中。可通过 `OPENCLAW_SKIP_DOCKER_BUILD=1` 复用该镜像,在刚完成本地构建后通过 `OPENCLAW_BUNDLED_CHANNEL_HOST_BUILD=0` 跳过主机重建,或通过 `OPENCLAW_BUNDLED_CHANNEL_PACKAGE_TGZ=/path/to/openclaw-*.tgz` 指向现有 tarball。 -- 在迭代时,你可以通过禁用无关场景来缩小内置插件运行时依赖测试范围,例如: +- 内置插件运行时依赖:`pnpm test:docker:bundled-channel-deps` 默认会构建一个小型 Docker 运行器镜像,在主机上构建并打包一次 OpenClaw,然后将该 tarball 挂载到每个 Linux 安装场景中。可使用 `OPENCLAW_SKIP_DOCKER_BUILD=1` 复用该镜像,在完成一次新的本地构建后使用 `OPENCLAW_BUNDLED_CHANNEL_HOST_BUILD=0` 跳过主机构建,或通过 `OPENCLAW_BUNDLED_CHANNEL_PACKAGE_TGZ=/path/to/openclaw-*.tgz` 指向现有 tarball。 +- 在迭代时,通过禁用无关场景来收窄内置插件运行时依赖测试,例如: `OPENCLAW_BUNDLED_CHANNEL_SCENARIOS=0 OPENCLAW_BUNDLED_CHANNEL_UPDATE_SCENARIO=0 OPENCLAW_BUNDLED_CHANNEL_ROOT_OWNED_SCENARIO=0 OPENCLAW_BUNDLED_CHANNEL_SETUP_ENTRY_SCENARIO=0 pnpm test:docker:bundled-channel-deps`。 -若要手动预构建并复用共享的已构建应用镜像: +要手动预构建并复用共享的 built-app 镜像: ```bash OPENCLAW_DOCKER_E2E_IMAGE=openclaw-docker-e2e:local pnpm test:docker:e2e-build OPENCLAW_DOCKER_E2E_IMAGE=openclaw-docker-e2e:local OPENCLAW_SKIP_DOCKER_BUILD=1 pnpm test:docker:mcp-channels ``` -当设置时,诸如 `OPENCLAW_GATEWAY_NETWORK_E2E_IMAGE` 这样的套件专属镜像覆盖仍然优先生效。当 `OPENCLAW_SKIP_DOCKER_BUILD=1` 指向远程共享镜像时,如果该镜像尚未存在于本地,脚本会先拉取它。QR 和安装器 Docker 测试保留各自独立的 Dockerfile,因为它们验证的是包 / 安装行为,而不是共享的已构建应用运行时。 +当设置了套件特定镜像覆盖(例如 `OPENCLAW_GATEWAY_NETWORK_E2E_IMAGE`)时,它们仍然优先生效。当 `OPENCLAW_SKIP_DOCKER_BUILD=1` 指向远程共享镜像时,如果本地尚不存在,该脚本会拉取它。QR 和安装器 Docker 测试会保留自己的 Dockerfile,因为它们验证的是打包 / 安装行为,而不是共享的 built-app 运行时。 -实时模型 Docker 运行器还会以只读方式 bind-mount 当前检出内容,并将其暂存到容器内的临时工作目录中。这样既能保持运行时镜像精简,又能让 Vitest 针对你本地的精确源代码 / 配置运行。暂存步骤会跳过大型仅本地缓存和应用构建输出,例如 `.pnpm-store`、`.worktrees`、`__openclaw_vitest__` 以及应用本地的 `.build` 或 Gradle 输出目录,因此 Docker 实时运行不会花几分钟去复制机器专属制品。 -它们还会设置 `OPENCLAW_SKIP_CHANNELS=1`,这样 Gateway 网关实时探测就不会在容器内启动真实的 Telegram / Discord / 等渠道 worker。 -`test:docker:live-models` 仍然运行 `pnpm test:live`,因此当你需要缩小或排除该 Docker 通道中的 Gateway 网关实时覆盖时,也要一并传入 `OPENCLAW_LIVE_GATEWAY_*`。 -`test:docker:openwebui` 是一个更高层级的兼容性冒烟测试:它会启动一个启用了 OpenAI 兼容 HTTP 端点的 OpenClaw Gateway 网关容器,再针对该 Gateway 网关启动一个固定版本的 Open WebUI 容器,通过 Open WebUI 登录,验证 `/api/models` 暴露了 `openclaw/default`,然后通过 Open WebUI 的 `/api/chat/completions` 代理发送一个真实聊天请求。 -首次运行可能会明显更慢,因为 Docker 可能需要拉取 Open WebUI 镜像,并且 Open WebUI 可能需要完成自身的冷启动设置。 -这个通道需要一个可用的实时模型密钥,而 `OPENCLAW_PROFILE_FILE`(默认是 `~/.profile`)是在 Docker 化运行中提供它的主要方式。 -成功运行会打印一小段 JSON 载荷,例如 `{ "ok": true, "model": "openclaw/default", ... }`。 -`test:docker:mcp-channels` 刻意设计为确定性测试,不需要真实的 Telegram、Discord 或 iMessage 账号。它会启动一个已播种的 Gateway 网关容器,再启动第二个容器来拉起 `openclaw mcp serve`,然后通过真实的 stdio MCP bridge 验证路由后的会话发现、转录读取、附件元数据、实时事件队列行为、出站发送路由,以及 Claude 风格的渠道 + 权限通知。通知检查会直接检查原始 stdio MCP 帧,因此该冒烟测试验证的是 bridge 实际发出了什么,而不仅仅是某个特定客户端 SDK 恰好暴露了什么。 -`test:docker:pi-bundle-mcp-tools` 是确定性的,不需要实时模型密钥。它会构建仓库 Docker 镜像,在容器内启动一个真实的 stdio MCP 探测服务器,通过嵌入式 Pi bundle MCP 运行时实例化该服务器,执行工具,然后验证 `coding` 和 `messaging` 会保留 `bundle-mcp` 工具,而 `minimal` 和 `tools.deny: ["bundle-mcp"]` 会将其过滤掉。 -`test:docker:cron-mcp-cleanup` 是确定性的,也不需要实时模型密钥。它会启动一个带真实 stdio MCP 探测服务器的已播种 Gateway 网关,运行一个隔离的 cron 轮次和一个 `/subagents spawn` 一次性子智能体轮次,然后验证 MCP 子进程会在每次运行后退出。 +live 模型 Docker 运行器还会以只读方式 bind-mount 当前 checkout,并在容器内将其暂存到一个临时 workdir。这样既能保持运行时镜像精简,又仍然能针对你本地的精确 source / 配置运行 Vitest。暂存步骤会跳过大型本地专用缓存和应用构建输出,例如 `.pnpm-store`、`.worktrees`、`__openclaw_vitest__`,以及应用本地的 `.build` 或 Gradle 输出目录,从而避免 Docker live 运行花费数分钟复制与机器相关的工件。 +它们还会设置 `OPENCLAW_SKIP_CHANNELS=1`,这样 gateway live 探测就不会在容器内启动真实的 Telegram / Discord / 等渠道 worker。 +`test:docker:live-models` 仍然会运行 `pnpm test:live`,因此当你需要从该 Docker 通道中收窄或排除 gateway live 覆盖时,也要一并传入 `OPENCLAW_LIVE_GATEWAY_*`。 +`test:docker:openwebui` 是一个更高层的兼容性冒烟测试:它会启动一个启用了 OpenAI 兼容 HTTP 端点的 OpenClaw gateway 容器,启动一个固定版本的 Open WebUI 容器并将其指向该 gateway,通过 Open WebUI 登录,验证 `/api/models` 暴露了 `openclaw/default`,然后通过 Open WebUI 的 `/api/chat/completions` 代理发送一个真实聊天请求。 +第一次运行可能会明显更慢,因为 Docker 可能需要拉取 Open WebUI 镜像,而且 Open WebUI 可能需要完成自己的冷启动设置。 +该通道需要一个可用的 live 模型 key,而 `OPENCLAW_PROFILE_FILE` +(默认 `~/.profile`)是在 Docker 化运行中提供该 key 的主要方式。 +成功运行会打印一个小型 JSON payload,例如 `{ "ok": true, "model": +"openclaw/default", ... }`。 +`test:docker:mcp-channels` 是刻意保持确定性的,不需要真实的 Telegram、Discord 或 iMessage 账户。它会启动一个带 seed 的 Gateway 容器,启动第二个容器来运行 `openclaw mcp serve`,然后验证通过真实 stdio MCP bridge 路由的会话发现、transcript 读取、附件元数据、live 事件队列行为、出站发送路由,以及 Claude 风格的渠道 + 权限通知。通知检查会直接检查原始 stdio MCP 帧,因此该冒烟测试验证的是 bridge 实际发出的内容,而不仅仅是某个特定 client SDK 恰好暴露出来的内容。 +`test:docker:pi-bundle-mcp-tools` 是确定性的,不需要 live 模型 key。它会构建仓库 Docker 镜像,在容器内启动一个真实 stdio MCP 探测服务器,通过嵌入式 Pi bundle MCP 运行时实例化该服务器,执行工具,然后验证 `coding` 和 `messaging` 会保留 `bundle-mcp` 工具,而 `minimal` 和 `tools.deny: ["bundle-mcp"]` 会将其过滤掉。 +`test:docker:cron-mcp-cleanup` 是确定性的,不需要 live 模型 key。它会启动一个带 seed 的 Gateway 网关和一个真实 stdio MCP 探测服务器,运行一次隔离的 cron 轮次和一次 `/subagents spawn` 单次子智能体轮次,然后验证 MCP 子进程会在每次运行后退出。 手动 ACP 自然语言线程冒烟测试(非 CI): - `bun scripts/dev/discord-acp-plain-language-smoke.ts --channel ...` -- 保留这个脚本用于回归 / 调试工作流。之后做 ACP 线程路由验证时可能还需要它,因此不要删除它。 +- 为回归 / 调试工作流保留此脚本。后续可能仍需要它来验证 ACP 线程路由,因此不要删除它。 常用环境变量: - `OPENCLAW_CONFIG_DIR=...`(默认:`~/.openclaw`)挂载到 `/home/node/.openclaw` - `OPENCLAW_WORKSPACE_DIR=...`(默认:`~/.openclaw/workspace`)挂载到 `/home/node/.openclaw/workspace` -- `OPENCLAW_PROFILE_FILE=...`(默认:`~/.profile`)挂载到 `/home/node/.profile`,并在运行测试前读取 -- `OPENCLAW_DOCKER_PROFILE_ENV_ONLY=1` 用于仅验证从 `OPENCLAW_PROFILE_FILE` 读取的环境变量,此时使用临时配置 / 工作区目录,并且不挂载外部 CLI 认证 +- `OPENCLAW_PROFILE_FILE=...`(默认:`~/.profile`)挂载到 `/home/node/.profile`,并在运行测试前 source +- `OPENCLAW_DOCKER_PROFILE_ENV_ONLY=1` 用于验证仅使用从 `OPENCLAW_PROFILE_FILE` source 的环境变量,采用临时 config / workspace 目录,并且不挂载外部 CLI 认证 - `OPENCLAW_DOCKER_CLI_TOOLS_DIR=...`(默认:`~/.cache/openclaw/docker-cli-tools`)挂载到 `/home/node/.npm-global`,用于 Docker 内缓存的 CLI 安装 - `$HOME` 下的外部 CLI 认证目录 / 文件会以只读方式挂载到 `/host-auth...` 下,然后在测试开始前复制到 `/home/node/...` - 默认目录:`.minimax` - 默认文件:`~/.codex/auth.json`、`~/.codex/config.toml`、`.claude.json`、`~/.claude/.credentials.json`、`~/.claude/settings.json`、`~/.claude/settings.local.json` - - 缩小范围的提供商运行只会挂载根据 `OPENCLAW_LIVE_PROVIDERS` / `OPENCLAW_LIVE_GATEWAY_PROVIDERS` 推断出的所需目录 / 文件 - - 可通过 `OPENCLAW_DOCKER_AUTH_DIRS=all`、`OPENCLAW_DOCKER_AUTH_DIRS=none`,或类似 `OPENCLAW_DOCKER_AUTH_DIRS=.claude,.codex` 的逗号列表手动覆盖 -- `OPENCLAW_LIVE_GATEWAY_MODELS=...` / `OPENCLAW_LIVE_MODELS=...` 用于缩小运行范围 -- `OPENCLAW_LIVE_GATEWAY_PROVIDERS=...` / `OPENCLAW_LIVE_PROVIDERS=...` 用于在容器内筛选提供商 -- `OPENCLAW_SKIP_DOCKER_BUILD=1` 用于复用现有的 `openclaw:local-live` 镜像,以便在无需重建的重跑中使用 -- `OPENCLAW_LIVE_REQUIRE_PROFILE_KEYS=1` 用于确保凭证来自 profile 存储(而不是环境变量) -- `OPENCLAW_OPENWEBUI_MODEL=...` 用于选择 Gateway 网关为 Open WebUI 冒烟测试暴露的模型 -- `OPENCLAW_OPENWEBUI_PROMPT=...` 用于覆盖 Open WebUI 冒烟测试使用的 nonce 检查提示词 + - 收窄后的 provider 运行只会挂载根据 `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=...` 用于在容器内筛选 provider +- `OPENCLAW_SKIP_DOCKER_BUILD=1` 用于在不需要重建的重跑中复用现有 `openclaw:local-live` 镜像 +- `OPENCLAW_LIVE_REQUIRE_PROFILE_KEYS=1` 用于确保凭证来自 profile 存储(而非 env) +- `OPENCLAW_OPENWEBUI_MODEL=...` 用于选择 gateway 为 Open WebUI 冒烟测试暴露的模型 +- `OPENCLAW_OPENWEBUI_PROMPT=...` 用于覆盖 Open WebUI 冒烟测试使用的 nonce-check 提示词 - `OPENWEBUI_IMAGE=...` 用于覆盖固定的 Open WebUI 镜像标签 ## 文档完整性检查 修改文档后运行文档检查:`pnpm check:docs`。 -当你还需要检查页内标题时,运行完整的 Mintlify anchor 验证:`pnpm docs:check-links:anchors`。 +当你还需要完整的 Mintlify 锚点校验(包括页内标题检查)时,运行:`pnpm docs:check-links:anchors`。 -## 离线回归测试(CI 安全) +## 离线回归(CI 安全) -这些是在没有真实提供商的情况下进行的“真实流水线”回归测试: +这些是在没有真实 provider 的情况下进行的“真实流水线”回归: -- Gateway 网关工具调用(模拟 OpenAI,真实 Gateway 网关 + 智能体循环):`src/gateway/gateway.test.ts`(用例:“runs a mock OpenAI tool call end-to-end via gateway agent loop”) -- Gateway 网关向导(WS `wizard.start` / `wizard.next`,强制写入配置 + 认证):`src/gateway/gateway.test.ts`(用例:“runs wizard over ws and writes auth token config”) +- Gateway 网关工具调用(模拟 OpenAI、真实 gateway + 智能体循环):`src/gateway/gateway.test.ts`(用例:“runs a mock OpenAI tool call end-to-end via gateway agent loop”) +- Gateway 网关向导(WS `wizard.start` / `wizard.next`,会写入配置 + 强制写入认证):`src/gateway/gateway.test.ts`(用例:“runs wizard over ws and writes auth token config”) ## 智能体可靠性评估(Skills) -我们已经有一些 CI 安全的测试,它们的行为就像“智能体可靠性评估”: +我们已经有一些 CI 安全的测试,它们的行为类似“智能体可靠性评估”: -- 通过真实 Gateway 网关 + 智能体循环的模拟工具调用(`src/gateway/gateway.test.ts`)。 -- 验证会话接线和配置效果的端到端向导流程(`src/gateway/gateway.test.ts`)。 +- 通过真实 gateway + 智能体循环进行的模拟工具调用(`src/gateway/gateway.test.ts`)。 +- 验证 session 接线和配置效果的端到端向导流程(`src/gateway/gateway.test.ts`)。 对于 Skills(见 [Skills](/zh-CN/tools/skills)),目前仍缺少的是: -- **决策能力:** 当提示中列出 Skills 时,智能体是否会选择正确的 Skills(或避开无关的 Skills)? -- **合规性:** 智能体是否会在使用前读取 `SKILL.md`,并遵循所需步骤 / 参数? -- **工作流契约:** 断言工具顺序、会话历史延续和沙箱边界的多轮场景。 +- **决策能力:** 当提示词中列出 Skills 时,智能体是否会选择正确的 skill(或避免选择无关的 skill)? +- **合规性:** 智能体是否会在使用前读取 `SKILL.md`,并遵循要求的步骤 / 参数? +- **工作流契约:** 断言工具顺序、session 历史延续以及沙箱边界的多轮场景。 -未来的评估应首先保持确定性: +未来的评估应优先保持确定性: -- 一个使用模拟提供商的场景运行器,用于断言工具调用 + 顺序、skill 文件读取和会话接线。 -- 一小组聚焦 skill 的场景(使用 vs 避免、门控、提示注入)。 -- 只有在 CI 安全套件落地之后,才考虑可选的实时评估(按需启用,受环境变量门控)。 +- 一个使用 mock provider 的场景运行器,用于断言工具调用 + 顺序、skill 文件读取以及 session 接线。 +- 一小组聚焦于 skill 的场景(使用 vs 避免、门控、提示词注入)。 +- 可选的 live evals(仅限 opt-in,受环境变量控制),但必须在 CI 安全套件就位之后再添加。 ## 契约测试(插件和渠道形状) -契约测试会验证每个已注册插件和渠道都符合其接口契约。它们会遍历所有已发现的插件,并运行一组关于形状和行为的断言。默认的 `pnpm test` 单元通道刻意跳过这些共享接缝和冒烟文件;当你修改共享渠道或提供商表面时,请显式运行契约命令。 +契约测试用于验证每个已注册插件和渠道都符合其接口契约。它们会遍历所有已发现的插件,并运行一组关于形状和行为的断言。默认的 `pnpm test` unit 通道会刻意跳过这些共享接缝和冒烟文件;当你修改共享的 channel 或 provider 接口时,请显式运行这些契约命令。 ### 命令 -- 所有契约测试:`pnpm test:contracts` -- 仅渠道契约测试:`pnpm test:contracts:channels` -- 仅提供商契约测试:`pnpm test:contracts:plugins` +- 所有契约:`pnpm test:contracts` +- 仅渠道契约:`pnpm test:contracts:channels` +- 仅 provider 契约:`pnpm test:contracts:plugins` -### 渠道契约测试 +### 渠道契约 位于 `src/channels/plugins/contracts/*.contract.test.ts`: - **plugin** - 基本插件形状(id、name、capabilities) - **setup** - 设置向导契约 - **session-binding** - 会话绑定行为 -- **outbound-payload** - 消息载荷结构 +- **outbound-payload** - 消息 payload 结构 - **inbound** - 入站消息处理 - **actions** - 渠道动作处理器 - **threading** - 线程 ID 处理 - **directory** - 目录 / roster API - **group-policy** - 群组策略执行 -### 提供商状态契约测试 +### Provider 状态契约 位于 `src/plugins/contracts/*.contract.test.ts`。 - **status** - 渠道状态探测 - **registry** - 插件注册表形状 -### 提供商契约测试 +### Provider 契约 位于 `src/plugins/contracts/*.contract.test.ts`: @@ -562,32 +569,32 @@ OPENCLAW_DOCKER_E2E_IMAGE=openclaw-docker-e2e:local OPENCLAW_SKIP_DOCKER_BUILD=1 - **catalog** - 模型目录 API - **discovery** - 插件发现 - **loader** - 插件加载 -- **runtime** - 提供商运行时 +- **runtime** - provider 运行时 - **shape** - 插件形状 / 接口 - **wizard** - 设置向导 ### 何时运行 -- 修改插件 SDK 导出或子路径之后 -- 添加或修改渠道或提供商插件之后 +- 修改 plugin-sdk 导出或子路径之后 +- 添加或修改 channel 或 provider 插件之后 - 重构插件注册或发现逻辑之后 -契约测试会在 CI 中运行,并且不需要真实 API 密钥。 +契约测试会在 CI 中运行,并且不需要真实 API key。 -## 添加回归测试(指导) +## 添加回归测试(指南) -当你修复一个在实时测试中发现的提供商 / 模型问题时: +当你修复在 live 中发现的 provider / 模型问题时: -- 如果可能,添加一个 CI 安全的回归测试(模拟 / stub 提供商,或捕获精确的请求形状转换) -- 如果它天然只能在实时测试中复现(速率限制、认证策略),就保持实时测试足够窄,并通过环境变量按需启用 -- 优先定位能捕获该缺陷的最小层级: - - 提供商请求转换 / 重放缺陷 → 直接模型测试 - - Gateway 网关会话 / 历史 / 工具流水线缺陷 → Gateway 网关实时冒烟测试或 CI 安全的 Gateway 网关模拟测试 -- SecretRef 遍历护栏: - - `src/secrets/exec-secret-ref-id-parity.test.ts` 会从注册表元数据(`listSecretTargetRegistryEntries()`)中为每个 SecretRef 类派生一个采样目标,然后断言遍历片段 exec id 会被拒绝。 - - 如果你在 `src/secrets/target-registry-data.ts` 中添加了新的 `includeInPlan` SecretRef 目标族,请更新该测试中的 `classifyTargetClass`。该测试会在遇到未分类目标 id 时故意失败,以确保新类别不会被静默跳过。 +- 如果可能,添加一个 CI 安全的回归测试(mock / stub provider,或捕获精确的请求形状转换) +- 如果它本质上只能在 live 中测试(限流、认证策略),请让 live 测试保持收窄,并通过环境变量启用 opt-in +- 优先瞄准能捕获该缺陷的最小层级: + - 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/plugins/google-meet.md b/docs/zh-CN/plugins/google-meet.md index e8d85b4cb..9c1604136 100644 --- a/docs/zh-CN/plugins/google-meet.md +++ b/docs/zh-CN/plugins/google-meet.md @@ -1,33 +1,33 @@ --- read_when: - - 你希望一个 OpenClaw 智能体加入 Google Meet 通话 + - 你希望一个 OpenClaw 智能体加入一个 Google Meet 通话 - 你正在将 Chrome、Chrome 节点或 Twilio 配置为 Google Meet 传输方式 -summary: Google Meet 插件:通过 Chrome 或 Twilio 使用实时语音默认设置加入明确指定的 Meet URL +summary: Google Meet 插件:通过 Chrome 或 Twilio 加入明确的 Meet URL,并使用实时语音默认设置 title: Google Meet 插件 x-i18n: - generated_at: "2026-04-24T05:28:12Z" + generated_at: "2026-04-24T06:43:49Z" model: gpt-5.4 provider: openai - source_hash: ab439b777e3043cc647a29e8e17b2794d14f48deceaadf8f81a014dd44583e23 + source_hash: f0bf06b7ab585bf2dc9dbf6d890e1954e89e4deea148380e350d2d7f4d954f5e source_path: plugins/google-meet.md workflow: 15 --- # Google Meet(插件) -OpenClaw 的 Google Meet 参与者支持。 +OpenClaw 的 Google Meet 参会支持。 该插件在设计上是显式的: -- 它只加入明确指定的 `https://meet.google.com/...` URL。 +- 它只会加入明确的 `https://meet.google.com/...` URL。 - `realtime` 语音是默认模式。 - 当需要更深入的推理或工具时,实时语音可以回调到完整的 OpenClaw 智能体。 -- 认证从个人 Google OAuth 或已登录的 Chrome 配置文件开始。 -- 不会自动进行同意声明。 +- 认证起点是个人 Google OAuth 或已登录的 Chrome 配置文件。 +- 不会自动播报同意声明。 - 默认的 Chrome 音频后端是 `BlackHole 2ch`。 - Chrome 可以在本地运行,也可以在已配对的节点主机上运行。 -- Twilio 接受一个拨入号码以及可选的 PIN 或 DTMF 序列。 -- CLI 命令是 `googlemeet`;`meet` 保留给更广泛的智能体电话会议工作流使用。 +- Twilio 接受拨入号码以及可选的 PIN 或 DTMF 序列。 +- CLI 命令是 `googlemeet`;`meet` 保留给更广泛的智能体电话会议工作流。 ## 快速开始 @@ -44,7 +44,7 @@ export OPENAI_API_KEY=sk-... sudo reboot ``` -重启后,验证这两项是否都已就绪: +重启后,验证这两部分都已就绪: ```bash system_profiler SPAudioDataType | grep -i BlackHole @@ -87,17 +87,17 @@ openclaw googlemeet join https://meet.google.com/abc-defg-hij } ``` -Chrome 将以已登录的 Chrome 配置文件身份加入。在 Meet 中,选择 `BlackHole 2ch` 作为 OpenClaw 使用的麦克风/扬声器路径。为了获得干净的双工音频,请使用独立的虚拟设备或类似 Loopback 的音频图;单个 BlackHole 设备足以完成首次冒烟测试,但可能会产生回声。 +Chrome 会以已登录的 Chrome 配置文件身份加入。在 Meet 中,为 OpenClaw 使用的麦克风/扬声器路径选择 `BlackHole 2ch`。为了获得干净的双工音频,请使用独立的虚拟设备或类似 Loopback 的音频图;单个 BlackHole 设备足以用于第一次冒烟测试,但可能会产生回声。 ### 本地 Gateway 网关 + Parallels Chrome -你**不**需要在 macOS VM 中运行完整的 OpenClaw Gateway 网关或配置模型 API 密钥,只是为了让 VM 承载 Chrome。你可以在本地运行 Gateway 网关和智能体,然后在 VM 中运行一个节点主机。在 VM 中启用一次内置插件,这样节点就会通告 Chrome 命令: +你**不**需要在 macOS VM 中运行完整的 OpenClaw Gateway 网关,也不需要模型 API 密钥,只为了让 VM 承担 Chrome。你可以在本地运行 Gateway 网关和智能体,然后在 VM 中运行一个节点主机。只需在 VM 上启用一次内置插件,这样节点就会通告 Chrome 命令: -各组件运行位置如下: +各组件分别运行在何处: - Gateway 网关主机:OpenClaw Gateway 网关、智能体工作区、模型/API 密钥、实时提供商,以及 Google Meet 插件配置。 - Parallels macOS VM:OpenClaw CLI/节点主机、Google Chrome、SoX、BlackHole 2ch,以及一个已登录 Google 的 Chrome 配置文件。 -- VM 中不需要:Gateway 网关服务、智能体配置、OpenAI/GPT 密钥,或模型提供商设置。 +- VM 中不需要:Gateway 网关服务、智能体配置、OpenAI/GPT 密钥或模型提供商设置。 安装 VM 依赖: @@ -111,7 +111,7 @@ brew install blackhole-2ch sox sudo reboot ``` -重启后,验证 VM 可以看到该音频设备以及 SoX 命令: +重启后,验证 VM 能看到音频设备和 SoX 命令: ```bash system_profiler SPAudioDataType | grep -i BlackHole @@ -130,7 +130,7 @@ openclaw plugins enable google-meet openclaw node run --host --port 18789 --display-name parallels-macos ``` -如果 `` 是局域网 IP,且你没有使用 TLS,除非你显式允许该受信私有网络,否则节点会拒绝明文 WebSocket: +如果 `` 是局域网 IP,且你未使用 TLS,那么除非你为该受信任的私有网络显式启用明文 WebSocket,否则节点会拒绝连接: ```bash OPENCLAW_ALLOW_INSECURE_PRIVATE_WS=1 \ @@ -145,20 +145,22 @@ OPENCLAW_ALLOW_INSECURE_PRIVATE_WS=1 \ openclaw node restart ``` -从 Gateway 网关主机批准该节点: +`OPENCLAW_ALLOW_INSECURE_PRIVATE_WS=1` 是进程环境变量,不是 `openclaw.json` 设置。若在安装命令中存在该变量,`openclaw node install` 会将其存储到 LaunchAgent 环境中。 + +在 Gateway 网关主机上批准该节点: ```bash openclaw devices list openclaw devices approve ``` -确认 Gateway 网关可以看到该节点,并且它通告了 `googlemeet.chrome`: +确认 Gateway 网关能看到该节点,并且它通告了 `googlemeet.chrome`: ```bash openclaw nodes status ``` -在 Gateway 网关主机上通过该节点路由 Meet: +在 Gateway 网关主机上将 Meet 路由到该节点: ```json5 { @@ -183,48 +185,48 @@ 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"`。 -如果省略 `chromeNode.node`,只有在恰好有一个已连接节点通告 `googlemeet.chrome` 时,OpenClaw 才会自动选择。如果连接了多个具备能力的节点,请将 `chromeNode.node` 设置为节点 ID、显示名称或远程 IP。 +如果省略 `chromeNode.node`,则仅当恰好有一个已连接节点通告 `googlemeet.chrome` 时,OpenClaw 才会自动选择。如果连接了多个具备该能力的节点,请将 `chromeNode.node` 设置为节点 id、显示名称或远程 IP。 常见故障检查: -- `No connected Google Meet-capable node`:在 VM 中启动 `openclaw node run`,批准配对,并确保已在 VM 中运行 `openclaw plugins enable google-meet`。同时确认 Gateway 网关主机通过 `gateway.nodes.allowCommands: ["googlemeet.chrome"]` 允许该节点命令。 +- `No connected Google Meet-capable node`:在 VM 中启动 `openclaw node run`,批准配对,并确保已在 VM 中运行 `openclaw plugins enable google-meet`。同时确认 Gateway 网关主机允许该节点命令,即设置 `gateway.nodes.allowCommands: ["googlemeet.chrome"]`。 - `BlackHole 2ch audio device not found on the node`:在 VM 中安装 `blackhole-2ch` 并重启 VM。 -- Chrome 已打开但无法加入:在 VM 中登录 Chrome,并确认该配置文件可以手动加入该 Meet URL。 -- 没有音频:在 Meet 中,将麦克风/扬声器路由到 OpenClaw 使用的虚拟音频设备路径;使用独立虚拟设备或类似 Loopback 的路由以获得干净的双工音频。 +- Chrome 已打开但无法加入:在 VM 中登录 Chrome,并确认该配置文件可以手动加入 Meet URL。 +- 没有音频:在 Meet 中,将麦克风/扬声器路由到 OpenClaw 使用的虚拟音频设备路径;为获得干净的双工音频,请使用独立的虚拟设备或类似 Loopback 的路由方式。 ## 安装说明 -Chrome 实时默认路径使用两个外部工具: +Chrome realtime 默认路径使用两个外部工具: -- `sox`:命令行音频工具。该插件使用其 `rec` 和 `play` 命令来实现默认的 8 kHz G.711 mu-law 音频桥接。 +- `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 VM)上时,请使用 `chrome-node`。 +Chrome 传输方式会在 Google Chrome 中打开 Meet URL,并以已登录的 Chrome 配置文件身份加入。在 macOS 上,插件会在启动前检查是否存在 `BlackHole 2ch`。如果已配置,它还会在打开 Chrome 前运行音频桥接健康检查命令和启动命令。当 Chrome/音频位于 Gateway 网关主机上时,使用 `chrome`;当 Chrome/音频位于已配对节点(如 Parallels macOS VM)上时,使用 `chrome-node`。 ```bash openclaw googlemeet join https://meet.google.com/abc-defg-hij --transport chrome openclaw googlemeet join https://meet.google.com/abc-defg-hij --transport chrome-node ``` -将 Chrome 的麦克风和扬声器音频通过本地 OpenClaw 音频桥进行路由。如果未安装 `BlackHole 2ch`,加入操作会以设置错误失败,而不是在没有音频路径的情况下静默加入。 +通过本地 OpenClaw 音频桥接来路由 Chrome 的麦克风和扬声器音频。如果未安装 `BlackHole 2ch`,加入操作会以设置错误失败,而不是在没有音频路径的情况下静默加入。 ### Twilio -Twilio 传输方式是委托给 Voice Call 插件的严格拨号方案。它不会解析 Meet 页面中的电话号码。 +Twilio 传输方式是一个严格的拨号计划,并委托给 Voice Call 插件。它不会从 Meet 页面中解析电话号码。 ```bash openclaw googlemeet join https://meet.google.com/abc-defg-hij \ @@ -233,7 +235,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 \ @@ -252,14 +254,13 @@ openclaw googlemeet auth login --json 该命令会打印一个包含刷新令牌的 `oauth` 配置块。它使用 PKCE、位于 `http://localhost:8085/oauth2callback` 的 localhost 回调,以及通过 `--manual` 进行的手动复制/粘贴流程。 -以下环境变量可作为回退值使用: +以下环境变量可作为后备: - `OPENCLAW_GOOGLE_MEET_CLIENT_ID` 或 `GOOGLE_MEET_CLIENT_ID` - `OPENCLAW_GOOGLE_MEET_CLIENT_SECRET` 或 `GOOGLE_MEET_CLIENT_SECRET` - `OPENCLAW_GOOGLE_MEET_REFRESH_TOKEN` 或 `GOOGLE_MEET_REFRESH_TOKEN` - `OPENCLAW_GOOGLE_MEET_ACCESS_TOKEN` 或 `GOOGLE_MEET_ACCESS_TOKEN` -- `OPENCLAW_GOOGLE_MEET_ACCESS_TOKEN_EXPIRES_AT` 或 - `GOOGLE_MEET_ACCESS_TOKEN_EXPIRES_AT` +- `OPENCLAW_GOOGLE_MEET_ACCESS_TOKEN_EXPIRES_AT` 或 `GOOGLE_MEET_ACCESS_TOKEN_EXPIRES_AT` - `OPENCLAW_GOOGLE_MEET_DEFAULT_MEETING` 或 `GOOGLE_MEET_DEFAULT_MEETING` - `OPENCLAW_GOOGLE_MEET_PREVIEW_ACK` 或 `GOOGLE_MEET_PREVIEW_ACK` @@ -269,17 +270,17 @@ openclaw googlemeet auth login --json openclaw googlemeet resolve-space --meeting https://meet.google.com/abc-defg-hij ``` -在进行媒体工作前运行预检: +在进行媒体工作之前运行预检: ```bash openclaw googlemeet preflight --meeting https://meet.google.com/abc-defg-hij ``` -只有在确认你的 Cloud 项目、OAuth 主体以及会议参与者都已加入 Google Workspace Developer Preview Program 的 Meet media APIs 预览后,才设置 `preview.enrollmentAcknowledged: true`。 +只有在确认你的 Cloud 项目、OAuth 主体以及会议参与者都已加入 Meet media API 的 Google Workspace Developer Preview Program 后,才设置 `preview.enrollmentAcknowledged: true`。 ## 配置 -常见的 Chrome 实时路径只需要启用插件、安装 BlackHole、SoX,以及一个 OpenAI 密钥: +常见的 Chrome realtime 路径只需要启用插件、BlackHole、SoX 和一个 OpenAI 密钥: ```bash brew install blackhole-2ch sox @@ -305,7 +306,7 @@ export OPENAI_API_KEY=sk-... - `defaultTransport: "chrome"` - `defaultMode: "realtime"` -- `chromeNode.node`:`chrome-node` 的可选节点 ID/名称/IP +- `chromeNode.node`:`chrome-node` 的可选节点 id/名称/IP - `chrome.audioBackend: "blackhole-2ch"` - `chrome.audioInputCommand`:将 8 kHz G.711 mu-law 音频写入 stdout 的 SoX `rec` 命令 - `chrome.audioOutputCommand`:从 stdin 读取 8 kHz G.711 mu-law 音频的 SoX `play` 命令 @@ -332,7 +333,7 @@ export OPENAI_API_KEY=sk-... } ``` -仅 Twilio 配置: +仅用于 Twilio 的配置: ```json5 { @@ -360,36 +361,36 @@ export OPENAI_API_KEY=sk-... } ``` -当 Chrome 运行在 Gateway 网关主机上时,使用 `transport: "chrome"`。当 Chrome 运行在已配对节点(例如 Parallels VM)上时,使用 `transport: "chrome-node"`。在这两种情况下,实时模型和 `openclaw_agent_consult` 都运行在 Gateway 网关主机上,因此模型凭证会保留在那里。 +当 Chrome 运行在 Gateway 网关主机上时,使用 `transport: "chrome"`。当 Chrome 运行在已配对节点(如 Parallels VM)上时,使用 `transport: "chrome-node"`。在这两种情况下,realtime 模型和 `openclaw_agent_consult` 都运行在 Gateway 网关主机上,因此模型凭证会保留在那里。 -使用 `action: "status"` 列出活动会话或检查某个会话 ID。使用 `action: "leave"` 将某个会话标记为已结束。 +使用 `action: "status"` 列出活动会话或检查某个会话 ID。使用 `action: "leave"` 将会话标记为已结束。 ## 实时智能体咨询 -Chrome 实时模式针对实时语音循环进行了优化。实时语音提供商会听取会议音频,并通过已配置的音频桥发声。当实时模型需要更深入的推理、当前信息或常规 OpenClaw 工具时,它可以调用 `openclaw_agent_consult`。 +Chrome realtime 模式针对实时语音循环进行了优化。实时语音提供商会听取会议音频,并通过已配置的音频桥接进行发声。当实时模型需要更深入的推理、最新信息或常规 OpenClaw 工具时,它可以调用 `openclaw_agent_consult`。 -咨询工具会在后台运行常规 OpenClaw 智能体,并带上最近会议转录的上下文,随后向实时语音会话返回简明的口语回答。然后语音模型可以将该回答再说回会议中。 +该咨询工具会在后台运行常规 OpenClaw 智能体,携带最近的会议转录上下文,并向实时语音会话返回简洁的口语答复。然后语音模型就可以将该答复说回会议中。 -`realtime.toolPolicy` 控制咨询运行方式: +`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`:不要向 realtime 语音模型暴露咨询工具。 -咨询会话键按每个 Meet 会话进行作用域划分,因此在同一场会议期间,后续的咨询调用可以复用先前的咨询上下文。 +咨询会话键按每个 Meet 会话进行作用域隔离,因此在同一场会议期间,后续咨询调用可以复用先前的咨询上下文。 ## 说明 -Google Meet 的官方媒体 API 偏向接收,因此要在 Meet 通话中发言,仍然需要一个参与者路径。该插件将这一边界保持为可见状态:Chrome 负责浏览器参与和本地音频路由;Twilio 负责电话拨入参与。 +Google Meet 的官方媒体 API 是面向接收的,因此要在 Meet 通话中发声,仍然需要一个参与者路径。该插件会保持这条边界清晰可见:Chrome 负责浏览器参与和本地音频路由;Twilio 负责电话拨入参与。 -Chrome 实时模式需要以下两者之一: +Chrome realtime 模式需要以下两者之一: -- `chrome.audioInputCommand` 加 `chrome.audioOutputCommand`:OpenClaw 拥有实时模型桥,并在这些命令与所选实时语音提供商之间传输 8 kHz G.711 mu-law 音频。 -- `chrome.audioBridgeCommand`:一个外部桥接命令拥有整个本地音频路径,并且必须在启动或验证其守护进程后退出。 +- `chrome.audioInputCommand` 加 `chrome.audioOutputCommand`:OpenClaw 拥有 realtime 模型桥接,并在这些命令与所选 realtime 语音提供商之间传输 8 kHz G.711 mu-law 音频。 +- `chrome.audioBridgeCommand`:一个外部桥接命令拥有完整的本地音频路径,并且必须在启动或验证其守护进程后退出。 -为了获得干净的双工音频,请将 Meet 输出和 Meet 麦克风通过独立的虚拟设备或类似 Loopback 的虚拟设备图进行路由。单个共享的 BlackHole 设备可能会将其他参与者的声音回声回通话中。 +为了获得干净的双工音频,请将 Meet 输出和 Meet 麦克风分别路由到独立的虚拟设备,或使用类似 Loopback 的虚拟设备图。单个共享的 BlackHole 设备可能会将其他参与者的声音回送到通话中。 -`googlemeet leave` 会停止用于 Chrome 会话的命令对实时音频桥。对于通过 Voice Call 插件委托的 Twilio 会话,它还会挂断底层语音通话。 +`googlemeet leave` 会停止用于 Chrome 会话的命令对 realtime 音频桥接。对于通过 Voice Call 插件委派的 Twilio 会话,它也会挂断底层语音通话。 ## 相关内容 diff --git a/docs/zh-CN/reference/RELEASING.md b/docs/zh-CN/reference/RELEASING.md index 8ef67bfdb..7d59ee538 100644 --- a/docs/zh-CN/reference/RELEASING.md +++ b/docs/zh-CN/reference/RELEASING.md @@ -1,61 +1,62 @@ --- read_when: - - 查找公开发布渠道定义 - - 查找版本命名和发布节奏 + - 正在查找公开发布渠道定义 + - 正在查找版本命名和发布节奏 summary: 公开发布渠道、版本命名和发布节奏 title: 发布策略 x-i18n: - generated_at: "2026-04-24T05:03:01Z" + generated_at: "2026-04-24T06:43:47Z" model: gpt-5.4 provider: openai - source_hash: 32c6d904e21f6d4150cf061ae27594bc2364f0927c48388362b16d8bf97491dc + source_hash: 2cba6cd02c6fb2380abd8d46e10567af2f96c7c6e45236689d69289348b829ce source_path: reference/RELEASING.md workflow: 15 --- OpenClaw 有三个公开发布渠道: -- stable:带标签的发布版本,默认发布到 npm `beta`,或在明确要求时发布到 npm `latest` +- stable:带标签的发布版本,默认发布到 npm `beta`,或在明确指定时发布到 npm `latest` - beta:预发布标签,发布到 npm `beta` -- dev:`main` 的持续最新版本 +- dev:`main` 的最新移动头部版本 ## 版本命名 -- Stable 发布版本:`YYYY.M.D` +- 稳定版发布版本:`YYYY.M.D` - Git 标签:`vYYYY.M.D` -- Stable 修正版发布版本:`YYYY.M.D-N` +- 稳定版修正发布版本:`YYYY.M.D-N` - Git 标签:`vYYYY.M.D-N` - Beta 预发布版本:`YYYY.M.D-beta.N` - Git 标签:`vYYYY.M.D-beta.N` - 月和日不要补零 -- `latest` 表示当前已提升为正式版的 stable npm 发布版本 +- `latest` 表示当前已提升为正式的稳定 npm 发布版本 - `beta` 表示当前 beta 安装目标 -- Stable 和 stable 修正版发布默认发布到 npm `beta`;发布操作人员可以显式指定目标为 `latest`,或者稍后再将经过验证的 beta 构建提升过去 -- 每个 stable OpenClaw 发布都会同时交付 npm 包和 macOS 应用; - beta 发布通常会先验证并发布 npm/package 路径,而 mac 应用的构建/签名/公证默认保留给 stable,除非另有明确要求 +- 稳定版和稳定版修正发布默认发布到 npm `beta`;发布操作人员可以明确指定目标为 `latest`,或者稍后再提升经过验证的 beta 构建 +- 每个稳定版 OpenClaw 发布都会同时交付 npm 包和 macOS 应用; + beta 发布通常会先验证并发布 npm/package 路径,而 mac 应用的构建/签名/公证除非明确要求,否则保留给稳定版 ## 发布节奏 -- 发布采用 beta 优先 -- 只有在最新 beta 验证通过后,才会跟进 stable +- 发布先走 beta +- 只有在最新 beta 验证通过后,才会跟进稳定版 - 维护者通常会从当前 `main` 创建 `release/YYYY.M.D` 分支来切发布, 这样发布验证和修复就不会阻塞 `main` 上的新开发 -- 如果某个 beta 标签已经推送或发布后还需要修复,维护者会切下一个 +- 如果某个 beta 标签已经推送或发布后需要修复,维护者会切下一个 `-beta.N` 标签,而不是删除或重建旧的 beta 标签 - 详细的发布流程、审批、凭证和恢复说明仅对维护者开放 -## 发布预检 +## 发布前检查 -- 在发布预检前运行 `pnpm check:test-types`,这样测试 TypeScript 也能继续 - 被覆盖,而不只是依赖更快的本地 `pnpm check` 检查 -- 在发布预检前运行 `pnpm check:architecture`,这样更广泛的导入环和架构 - 边界检查也会通过,而不是只依赖更快的本地检查 -- 在 `pnpm release:check` 之前运行 `pnpm build && pnpm ui:build`,这样打包 - 验证步骤所需的 `dist/*` 发布产物和 Control UI bundle 才会存在 -- 每次带标签发布前都要运行 `pnpm release:check` +- 在发布前检查前运行 `pnpm check:test-types`,这样测试 TypeScript 仍会被覆盖, + 不会遗漏在更快的本地 `pnpm check` 检查之外 +- 在发布前检查前运行 `pnpm check:architecture`,这样更广泛的导入循环和架构边界检查会保持绿色, + 不会遗漏在更快的本地检查之外 +- 在 `pnpm release:check` 之前运行 `pnpm build && pnpm ui:build`,这样预期的 + `dist/*` 发布产物和 Control UI 打包结果会存在,供 pack + 验证步骤使用 +- 每次带标签发布前都运行 `pnpm release:check` - 发布检查现在在单独的手动工作流中运行: `OpenClaw Release Checks` -- `OpenClaw Release Checks` 还会在发布审批前运行 QA Lab mock 对齐检查,以及实时 +- `OpenClaw Release Checks` 还会在发布审批前运行 QA Lab 模拟一致性检查,以及实时的 Matrix 和 Telegram QA 通道。实时通道使用 `qa-live-shared` 环境;Telegram 还会使用 Convex CI 凭证租约。 - 跨操作系统的安装和升级运行时验证由私有调用方工作流 @@ -63,129 +64,135 @@ OpenClaw 有三个公开发布渠道: 发起,它会调用可复用的公开工作流 `.github/workflows/openclaw-cross-os-release-checks-reusable.yml` - 这种拆分是有意为之:让真正的 npm 发布路径保持简短、 - 可预测且聚焦于产物,而把较慢的实时检查放在单独通道中, - 以免拖慢或阻塞发布 + 可预测,并且聚焦产物;同时把较慢的实时检查放在它们自己的通道中, + 这样它们就不会拖慢或阻塞发布 - 发布检查必须从 `main` 工作流引用或 `release/YYYY.M.D` 工作流引用发起,这样工作流逻辑和密钥才能保持受控 -- 该工作流接受现有发布标签,或当前完整的 - 40 字符工作流分支提交 SHA -- 在提交 SHA 模式下,它只接受当前工作流分支 HEAD;如果要验证更早的发布提交, - 请使用发布标签 -- `OpenClaw NPM Release` 的仅验证预检也接受当前完整的 - 40 字符工作流分支提交 SHA,而不要求已有推送的标签 +- 该工作流接受已有的发布标签,或当前工作流分支完整的 + 40 字符提交 SHA +- 在提交 SHA 模式下,它只接受当前工作流分支的 HEAD;较旧的发布提交请使用 + 发布标签 +- `OpenClaw NPM Release` 的仅验证前检查也接受当前工作流分支完整的 + 40 字符提交 SHA,而不要求已推送标签 - 该 SHA 路径仅用于验证,不能提升为真实发布 -- 在 SHA 模式下,工作流仅为包元数据检查临时构造 `v`; - 真正发布仍然需要真实的发布标签 -- 这两个工作流都将真实发布和提升路径保留在 GitHub 托管运行器上, - 而非变更性的验证路径则可以使用更大的 - Blacksmith Linux 运行器 +- 在 SHA 模式下,该工作流只为包元数据检查合成 + `v`;真实发布仍然需要真实的发布标签 +- 这两个工作流都将真实发布和提升路径保留在 GitHub 托管的 + runner 上,而非变更型验证路径则可以使用更大的 + Blacksmith Linux runner - 该工作流会运行 `OPENCLAW_LIVE_TEST=1 OPENCLAW_LIVE_CACHE_TEST=1 pnpm test:live:cache` - ,并使用 `OPENAI_API_KEY` 和 `ANTHROPIC_API_KEY` 两个工作流密钥 -- npm 发布预检不再等待单独的发布检查通道 -- 审批前运行 + 并使用 `OPENAI_API_KEY` 和 `ANTHROPIC_API_KEY` 两个工作流密钥 +- npm 发布前检查不再等待单独的发布检查通道 +- 在审批前运行 `RELEASE_TAG=vYYYY.M.D node --import tsx scripts/openclaw-npm-release-check.ts` (或对应的 beta/修正标签) - npm 发布后,运行 `node --import tsx scripts/openclaw-npm-postpublish-verify.ts YYYY.M.D` - (或对应的 beta/修正版本),在全新的临时前缀中验证已发布注册表的安装路径 -- beta 发布后,运行 `OPENCLAW_NPM_TELEGRAM_PACKAGE_SPEC=openclaw@YYYY.M.D-beta.N pnpm test:docker:npm-telegram-live` - ,以针对已发布的 npm 包验证已安装包的新手引导、Telegram 设置,以及真实 Telegram E2E。 -- 维护者发布自动化现在采用“先预检、后提升”: - - 真实 npm 发布必须通过成功的 npm `preflight_run_id` - - 真实 npm 发布必须从与成功预检运行相同的 `main` 或 + (或对应的 beta/修正版本),在全新的临时前缀中验证已发布的注册表 + 安装路径 +- beta 发布后,运行 `OPENCLAW_NPM_TELEGRAM_PACKAGE_SPEC=openclaw@YYYY.M.D-beta.N OPENCLAW_NPM_TELEGRAM_CREDENTIAL_SOURCE=convex OPENCLAW_NPM_TELEGRAM_CREDENTIAL_ROLE=ci pnpm test:docker:npm-telegram-live` + 以验证已安装包的新手引导、Telegram 设置,以及针对已发布 npm 包的真实 Telegram 端到端流程, + 并使用共享租赁的 Telegram 凭证池。本地维护者的一次性检查可以省略 Convex 变量, + 直接传入三个 `OPENCLAW_QA_TELEGRAM_*` 环境变量凭证。 +- 维护者也可以通过 GitHub Actions 中手动触发的 + `NPM Telegram Beta E2E` 工作流运行同样的发布后检查。它有意只支持手动触发, + 不会在每次合并时运行。 +- 维护者发布自动化现在采用“先前检查后提升”: + - 真正的 npm 发布必须通过成功的 npm `preflight_run_id` + - 真正的 npm 发布必须从与成功前检查运行相同的 `main` 或 `release/YYYY.M.D` 分支发起 - - stable npm 发布默认指向 `beta` - - stable npm 发布可以通过工作流输入显式指定目标为 `latest` + - 稳定版 npm 发布默认目标为 `beta` + - 稳定版 npm 发布可以通过工作流输入明确指定目标为 `latest` - 基于令牌的 npm dist-tag 变更现在位于 `openclaw/releases-private/.github/workflows/openclaw-npm-dist-tags.yml` - 中,以提高安全性,因为 `npm dist-tag add` 仍需要 `NPM_TOKEN`,而公开仓库 - 仅保留基于 OIDC 的发布 + 中,以提高安全性,因为 `npm dist-tag add` 仍然需要 `NPM_TOKEN`,而公开仓库 + 保持仅使用 OIDC 发布 - 公开的 `macOS Release` 仅用于验证 - - 真实的私有 mac 发布必须通过成功的私有 mac + - 真正的私有 mac 发布必须通过成功的私有 mac `preflight_run_id` 和 `validate_run_id` - - 真正发布路径会提升已准备好的产物,而不是再次重新构建 -- 对于像 `YYYY.M.D-N` 这样的 stable 修正版发布,发布后验证器 - 还会检查从 `YYYY.M.D` 升级到 `YYYY.M.D-N` 的同一临时前缀升级路径, - 这样发布修正就不会悄悄让旧的全局安装继续停留在基础 stable 载荷上 -- npm 发布预检默认采用失败即阻止的策略,除非 tarball 同时包含 - `dist/control-ui/index.html` 和非空的 `dist/control-ui/assets/` 内容, - 这样我们就不会再次发布一个空的浏览器仪表盘 -- 发布后验证还会检查已发布的注册表安装是否在根 `dist/*` - 布局下包含非空的内置插件运行时依赖。若某个发布带着缺失或空的内置插件 - 依赖内容发出,发布后验证器会判定失败,并且不能被提升到 `latest`。 + - 真正的发布路径会提升已准备好的产物,而不是再次重新构建 +- 对于像 `YYYY.M.D-N` 这样的稳定版修正发布,发布后验证器 + 还会检查从 `YYYY.M.D` 到 `YYYY.M.D-N` 的相同临时前缀升级路径, + 这样发布修正就不会悄悄让旧的全局安装仍停留在基础稳定版载荷上 +- npm 发布前检查会以默认拒绝方式失败,除非 tarball 同时包含 + `dist/control-ui/index.html` 和非空的 `dist/control-ui/assets/` 载荷, + 这样我们就不会再次发布一个空的浏览器仪表板 +- 发布后验证还会检查已发布的注册表安装中,根级 `dist/*` + 布局下是否包含非空的内置插件运行时依赖。若某个发布带有缺失或为空的内置插件 + 依赖载荷,则发布后验证器会失败,且该版本不能被提升 + 到 `latest`。 - `pnpm test:install:smoke` 还会对候选更新 tarball 的 npm pack `unpackedSize` 预算进行强制检查, - 这样安装器 e2e 就能在发布路径之前捕获意外的打包膨胀 -- 如果发布工作涉及 CI 规划、扩展计时清单或扩展测试矩阵, - 请在审批前重新生成并审查由规划器负责的 - `checks-node-extensions` 工作流矩阵输出,来源于 `.github/workflows/ci.yml`, + 这样安装器端到端流程就能在发布路径之前捕获意外的打包膨胀 +- 如果发布工作涉及 CI 规划、扩展计时清单或 + 扩展测试矩阵,请在审批前重新生成并审查由规划器负责的 + `.github/workflows/ci.yml` 中 `checks-node-extensions` 工作流矩阵输出, 这样发布说明就不会描述过时的 CI 布局 -- Stable macOS 发布就绪还包括更新器相关界面: +- 稳定版 macOS 发布就绪还包括更新器相关界面: - GitHub 发布最终必须包含打包好的 `.zip`、`.dmg` 和 `.dSYM.zip` - - 发布后,`main` 上的 `appcast.xml` 必须指向新的 stable zip - - 打包应用必须继续使用非调试 bundle id、非空的 Sparkle feed - URL,以及不低于该发布版本规范 Sparkle 构建下限的 `CFBundleVersion` + - 发布后,`main` 上的 `appcast.xml` 必须指向新的稳定版 zip + - 打包后的应用必须保持非调试 bundle id、非空的 Sparkle feed + URL,并且 `CFBundleVersion` 至少达到该发布版本对应的规范 Sparkle 构建下限 ## NPM 工作流输入 -`OpenClaw NPM Release` 接受这些由操作人员控制的输入: +`OpenClaw NPM Release` 接受以下由操作人员控制的输入: -- `tag`:必填的发布标签,例如 `v2026.4.2`、`v2026.4.2-1` 或 +- `tag`:必填发布标签,例如 `v2026.4.2`、`v2026.4.2-1` 或 `v2026.4.2-beta.1`;当 `preflight_only=true` 时,也可以是当前 - 完整的 40 字符工作流分支提交 SHA,用于仅验证的预检 -- `preflight_only`:`true` 表示仅验证/构建/打包,`false` 表示 + 工作流分支完整的 40 字符提交 SHA,用于仅验证的前检查 +- `preflight_only`:`true` 表示只做验证/构建/打包,`false` 表示走 真实发布路径 -- `preflight_run_id`:真实发布路径下必填,这样工作流就能复用成功预检运行中 +- `preflight_run_id`:真实发布路径必填,这样工作流才能复用成功前检查运行中 准备好的 tarball -- `npm_dist_tag`:发布路径的 npm 目标标签;默认值为 `beta` +- `npm_dist_tag`:发布路径的 npm 目标标签;默认是 `beta` -`OpenClaw Release Checks` 接受这些由操作人员控制的输入: +`OpenClaw Release Checks` 接受以下由操作人员控制的输入: -- `ref`:现有发布标签,或从 `main` 发起时要验证的当前完整 - 40 字符 `main` 提交 SHA;如果从发布分支发起,则使用现有发布标签或 - 当前完整的 40 字符发布分支提交 SHA +- `ref`:已有发布标签,或从 `main` 发起时当前完整的 40 字符 `main` 提交 + SHA;若从发布分支发起,请使用已有发布标签或当前完整的 40 字符 + 发布分支提交 SHA 规则: -- Stable 和修正标签可以发布到 `beta` 或 `latest` +- 稳定版和修正标签可以发布到 `beta` 或 `latest` - Beta 预发布标签只能发布到 `beta` -- 对于 `OpenClaw NPM Release`,仅当 +- 对于 `OpenClaw NPM Release`,只有在 `preflight_only=true` 时才允许输入完整提交 SHA -- `OpenClaw Release Checks` 始终仅用于验证,并且也接受 +- `OpenClaw Release Checks` 始终只用于验证,并且也接受 当前工作流分支提交 SHA -- 发布检查的提交 SHA 模式还要求必须是当前工作流分支 HEAD -- 真实发布路径必须使用预检时使用的同一个 `npm_dist_tag`; +- 发布检查的提交 SHA 模式还要求必须是当前工作流分支的 HEAD +- 真正的发布路径必须使用与前检查相同的 `npm_dist_tag`; 工作流会在继续发布前验证该元数据 -## Stable npm 发布顺序 +## 稳定版 npm 发布顺序 -在切 stable npm 发布时: +切稳定版 npm 发布时: 1. 运行 `OpenClaw NPM Release`,并设置 `preflight_only=true` - - 在标签尚不存在时,你可以使用当前完整工作流分支提交 - SHA,对预检工作流做一次仅验证的干运行 -2. 对于正常的 beta 优先流程,选择 `npm_dist_tag=beta`;只有在你 - 明确希望直接发布 stable 时才使用 `latest` -3. 单独运行 `OpenClaw Release Checks`,使用相同标签,或者 - 当前完整工作流分支提交 SHA,以便获得实时 prompt cache、 - QA Lab 对齐、Matrix 和 Telegram 覆盖 - - 这样刻意分开,是为了让实时覆盖保持可用,而不会再次把长时间运行或不稳定的检查 - 耦合回发布工作流 + - 在标签尚不存在时,你可以使用当前完整的工作流分支提交 + SHA,对前检查工作流进行一次仅验证的演练 +2. 正常的先 beta 后正式流程请选择 `npm_dist_tag=beta`,只有在你明确想直接发布稳定版时 + 才选择 `latest` +3. 使用相同标签单独运行 `OpenClaw Release Checks`,或者在你希望获得实时 prompt cache、 + QA Lab 一致性、Matrix 和 Telegram 覆盖时,使用当前完整的工作流分支提交 SHA + - 这一步故意单独分离,这样实时覆盖仍然可用,而不会把长时间运行或不稳定的检查 + 重新耦合进发布工作流 4. 保存成功的 `preflight_run_id` -5. 再次运行 `OpenClaw NPM Release`,并设置 `preflight_only=false`,使用相同的 - `tag`、相同的 `npm_dist_tag`,以及保存下来的 `preflight_run_id` -6. 如果该发布先落在 `beta`,使用私有工作流 +5. 再次运行 `OpenClaw NPM Release`,设置 `preflight_only=false`,并使用相同的 + `tag`、相同的 `npm_dist_tag` 以及保存下来的 `preflight_run_id` +6. 如果该发布先落在 `beta`,请使用私有工作流 `openclaw/releases-private/.github/workflows/openclaw-npm-dist-tags.yml` - 将该 stable 版本从 `beta` 提升到 `latest` -7. 如果该发布是有意直接发布到 `latest`,并且希望 `beta` - 立即跟随同一个 stable 构建,使用同一个私有工作流将这两个 dist-tag - 都指向该 stable 版本,或者让其计划任务式的自愈同步稍后再移动 `beta` + 将该稳定版从 `beta` 提升到 `latest` +7. 如果该发布有意直接发布到 `latest`,并且希望 `beta` + 立即跟随同一个稳定构建,请使用同一个私有工作流将两个 dist-tag + 都指向该稳定版本,或者让它的定时自愈同步稍后再移动 `beta` -dist-tag 变更位于私有仓库中以提高安全性,因为它仍然 -需要 `NPM_TOKEN`,而公开仓库仅保留基于 OIDC 的发布。 +出于安全原因,dist-tag 变更位于私有仓库中,因为它仍然 +需要 `NPM_TOKEN`,而公开仓库保持仅使用 OIDC 发布。 -这样可以让直接发布路径和 beta 优先提升路径都保持文档化, -并且对操作人员可见。 +这样既保留了直接发布路径,也保留了先 beta 后提升路径,并且两者都已文档化、 +对操作人员可见。 ## 公开参考 @@ -198,7 +205,7 @@ dist-tag 变更位于私有仓库中以提高安全性,因为它仍然 维护者会使用私有发布文档 [`openclaw/maintainers/release/README.md`](https://github.com/openclaw/maintainers/blob/main/release/README.md) -作为实际运行手册。 +作为实际操作手册。 ## 相关内容