chore(i18n): refresh zh-CN translations
This commit is contained in:
parent
cbe5516380
commit
a0337d1198
@ -1,25 +1,25 @@
|
||||
---
|
||||
read_when:
|
||||
- 安排后台任务或唤醒操作
|
||||
- 将外部触发器(webhook、Gmail)接入 OpenClaw
|
||||
- 为定时任务决定使用 heartbeat 还是 cron
|
||||
summary: Gateway 网关调度器的定时任务、webhook 和 Gmail PubSub 触发器
|
||||
title: 定时任务
|
||||
- 调度后台作业或唤醒任务
|
||||
- 将外部触发器(webhooks、Gmail)接入 OpenClaw
|
||||
- 为计划任务决定使用 heartbeat 还是 cron
|
||||
summary: 用于 Gateway 网关调度器的计划任务、webhooks 和 Gmail PubSub 触发器
|
||||
title: 计划任务
|
||||
x-i18n:
|
||||
generated_at: "2026-04-24T18:07:27Z"
|
||||
generated_at: "2026-04-25T05:53:14Z"
|
||||
model: gpt-5.4
|
||||
provider: openai
|
||||
source_hash: 8d59ab85d788afce2a9a320b5e1d7d301c7c0d0d5f78c43dbbce3fe6b125e414
|
||||
source_hash: 9ed4dc7222b601b37d98cf1575ced7fd865987882a8c5b28245c5d2423b4cc56
|
||||
source_path: automation/cron-jobs.md
|
||||
workflow: 15
|
||||
---
|
||||
|
||||
Cron 是 Gateway 网关内置的调度器。它会持久化作业,在正确的时间唤醒智能体,并且可以将输出回传到聊天渠道或 webhook 端点。
|
||||
Cron 是 Gateway 网关内置的调度器。它会持久化作业,在正确的时间唤醒智能体,并可将输出回传到聊天渠道或 webhook 端点。
|
||||
|
||||
## 快速开始
|
||||
|
||||
```bash
|
||||
# 添加一个一次性提醒
|
||||
# 添加一次性提醒
|
||||
openclaw cron add \
|
||||
--name "Reminder" \
|
||||
--at "2026-02-01T16:00:00Z" \
|
||||
@ -36,21 +36,20 @@ openclaw cron show <job-id>
|
||||
openclaw cron runs --id <job-id>
|
||||
```
|
||||
|
||||
## cron 的工作原理
|
||||
## cron 的工作方式
|
||||
|
||||
- Cron **运行在 Gateway 网关** 进程内部(而不是在模型内部)。
|
||||
- 作业定义会持久化到 `~/.openclaw/cron/jobs.json`,因此重启不会丢失调度。
|
||||
- 运行时执行状态会持久化到旁边的 `~/.openclaw/cron/jobs-state.json`。如果你在 git 中跟踪 cron 定义,请跟踪 `jobs.json`,并将 `jobs-state.json` 加入 gitignore。
|
||||
- 拆分之后,旧版本的 OpenClaw 可以读取 `jobs.json`,但可能会将作业视为全新作业,因为运行时字段现在存储在 `jobs-state.json` 中。
|
||||
- 所有 cron 执行都会创建 [后台任务](/zh-CN/automation/tasks) 记录。
|
||||
- 一次性作业(`--at`)默认会在成功后自动删除。
|
||||
- 独立 cron 运行会尽力在运行完成时关闭其 `cron:<jobId>` 会话所跟踪的浏览器标签页/进程,因此分离的浏览器自动化不会留下孤儿进程。
|
||||
- 独立 cron 运行还会防止过时的确认回复。如果第一个结果只是中间状态更新(例如 `on it`、`pulling everything together` 以及类似提示),并且没有任何后代子智能体运行仍负责最终答案,OpenClaw 会在交付前再次提示一次以获取实际结果。
|
||||
- Cron 在 **Gateway 网关** 进程**内部**运行(不是在模型内部)。
|
||||
- 作业定义持久化保存在 `~/.openclaw/cron/jobs.json`,因此重启不会丢失调度计划。
|
||||
- 运行时执行状态保存在旁边的 `~/.openclaw/cron/jobs-state.json`。如果你用 git 跟踪 cron 定义,请跟踪 `jobs.json`,并将 `jobs-state.json` 加入 gitignore。
|
||||
- 拆分之后,较旧版本的 OpenClaw 可以读取 `jobs.json`,但可能会将作业视为全新作业,因为运行时字段现在保存在 `jobs-state.json` 中。
|
||||
- 所有 cron 执行都会创建[后台任务](/zh-CN/automation/tasks)记录。
|
||||
- 一次性作业(`--at`)默认在成功后自动删除。
|
||||
- 隔离的 cron 运行会尽力关闭其 `cron:<jobId>` 会话所跟踪的浏览器标签页 / 进程,因此分离的浏览器自动化不会在运行完成后留下孤儿进程。
|
||||
- 隔离的 cron 运行还会防止陈旧的确认回复。如果第一个结果只是临时状态更新(例如 `on it`、`pulling everything together` 以及类似提示),并且没有后代子智能体运行仍负责最终答案,OpenClaw 会在交付前再次提示一次以获取实际结果。
|
||||
|
||||
<a id="maintenance"></a>
|
||||
|
||||
cron 的任务协调由运行时负责:只要 cron 运行时仍将该作业标记为正在运行,活动中的 cron 任务就会保持存活,即使旧的子会话记录仍然存在。
|
||||
一旦运行时不再拥有该作业,且 5 分钟宽限期已过,维护流程就可以将该任务标记为 `lost`。
|
||||
cron 的任务协调由运行时负责:只要 cron 运行时仍将该作业标记为正在运行,活动的 cron 任务就会保持存活,即使旧的子会话行仍然存在也是如此。一旦运行时不再拥有该作业且 5 分钟宽限期到期,维护过程就可以将任务标记为 `lost`。
|
||||
|
||||
## 调度类型
|
||||
|
||||
@ -58,79 +57,83 @@ cron 的任务协调由运行时负责:只要 cron 运行时仍将该作业标
|
||||
| ------- | --------- | ---- |
|
||||
| `at` | `--at` | 一次性时间戳(ISO 8601 或类似 `20m` 的相对时间) |
|
||||
| `every` | `--every` | 固定间隔 |
|
||||
| `cron` | `--cron` | 5 字段或 6 字段 cron 表达式,可选配 `--tz` |
|
||||
| `cron` | `--cron` | 5 字段或 6 字段的 cron 表达式,可选 `--tz` |
|
||||
|
||||
不带时区的时间戳会被视为 UTC。添加 `--tz America/New_York` 可按本地墙上时钟时间进行调度。
|
||||
不带时区的时间戳会按 UTC 处理。添加 `--tz America/New_York` 可按本地挂钟时间调度。
|
||||
|
||||
每小时整点的重复表达式会自动错开最多 5 分钟,以减少负载尖峰。使用 `--exact` 强制精确触发,或使用 `--stagger 30s` 指定明确的错开窗口。
|
||||
每小时整点循环表达式会自动错峰,最多延后 5 分钟,以降低负载尖峰。使用 `--exact` 可强制精确时间,或使用 `--stagger 30s` 指定明确的错峰窗口。
|
||||
|
||||
### 日与周字段使用 OR 逻辑
|
||||
### 月中的某一天和星期几使用 OR 逻辑
|
||||
|
||||
Cron 表达式由 [croner](https://github.com/Hexagon/croner) 解析。当“月中的第几天”和“周中的第几天”两个字段都不是通配符时,croner 会在**任一**字段匹配时触发——而不是两个都匹配。这是标准的 Vixie cron 行为。
|
||||
Cron 表达式由 [croner](https://github.com/Hexagon/croner) 解析。当“月中的某一天”和“星期几”两个字段都不是通配符时,croner 会在**任一**字段匹配时触发——而不是两个都匹配。这是标准的 Vixie cron 行为。
|
||||
|
||||
```
|
||||
# 预期:"15 号上午 9 点,仅当这一天是周一"
|
||||
# 实际: "每月 15 号上午 9 点,以及每周一上午 9 点"
|
||||
# 预期:"每月 15 日上午 9 点,但仅当这天是周一"
|
||||
# 实际:"每月 15 日上午 9 点,以及每个周一上午 9 点"
|
||||
0 9 15 * 1
|
||||
```
|
||||
|
||||
这样每月会触发约 5–6 次,而不是每月 0–1 次。OpenClaw 在这里使用 Croner 默认的 OR 行为。若要同时要求两个条件成立,请使用 Croner 的 `+` 星期修饰符(`0 9 15 * +1`),或者只在一个字段上调度,并在作业的提示词或命令中对另一个条件进行判断。
|
||||
这会每月触发约 5–6 次,而不是每月 0–1 次。OpenClaw 在这里使用 Croner 默认的 OR 行为。若要同时要求两个条件,请使用 Croner 的 `+` 星期几修饰符(`0 9 15 * +1`),或者仅基于其中一个字段调度,并在你的作业提示词或命令中校验另一个条件。
|
||||
|
||||
## 执行方式
|
||||
|
||||
| 方式 | `--session` 值 | 运行位置 | 最适合 |
|
||||
| --------------- | ------------------- | ------------------------ | ------ |
|
||||
| 主会话 | `main` | 下一次 heartbeat 轮次 | 提醒、系统事件 |
|
||||
| 独立 | `isolated` | 专用 `cron:<jobId>` | 报告、后台杂务 |
|
||||
| 当前会话 | `current` | 在创建时绑定 | 感知上下文的周期性工作 |
|
||||
| 自定义会话 | `session:custom-id` | 持久命名会话 | 基于历史持续推进的工作流 |
|
||||
| 隔离 | `isolated` | 专用 `cron:<jobId>` | 报告、后台事务 |
|
||||
| 当前会话 | `current` | 在创建时绑定 | 依赖上下文的循环工作 |
|
||||
| 自定义会话 | `session:custom-id` | 持久命名会话 | 基于历史构建的工作流 |
|
||||
|
||||
**主会话** 作业会排入一个系统事件队列,并可选择唤醒 heartbeat(`--wake now` 或 `--wake next-heartbeat`)。**独立** 作业会使用一个全新会话运行专用的智能体轮次。**自定义会话**(`session:xxx`)会在各次运行之间保留上下文,从而支持如每日站会这类基于先前摘要不断累积的工作流。
|
||||
**主会话**作业会排入一个系统事件,并可选唤醒 heartbeat(`--wake now` 或 `--wake next-heartbeat`)。**隔离**作业会以全新会话运行一个专用智能体轮次。**自定义会话**(`session:xxx`)会在多次运行之间保留上下文,从而支持例如基于先前摘要构建的每日站会等工作流。
|
||||
|
||||
对于独立作业,运行时拆除现在还包括尽力清理该 cron 会话的浏览器资源。清理失败会被忽略,因此实际 cron 结果仍然优先。
|
||||
对于隔离作业,“全新会话”表示每次运行都有新的 transcript / session id。OpenClaw 可能会保留安全的偏好设置,例如 thinking / fast / verbose 设置、标签以及用户显式选择的模型 / 凭证覆盖,但不会继承旧 cron 记录中的环境会话上下文:渠道 / 群组路由、发送或排队策略、提权、来源或 ACP 运行时绑定。如果循环作业应有意建立在同一会话上下文之上,请使用 `current` 或 `session:<id>`。
|
||||
|
||||
独立 cron 运行还会通过共享的运行时清理路径,释放该作业创建的任何内置 MCP 运行时实例。这与主会话和自定义会话的 MCP 客户端销毁方式保持一致,因此独立 cron 作业不会在多次运行之间泄漏 stdio 子进程或长生命周期的 MCP 连接。
|
||||
对于隔离作业,运行时拆除现在包括尽力清理该 cron 会话的浏览器。清理失败会被忽略,因此实际的 cron 结果仍然优先。
|
||||
|
||||
当独立 cron 运行编排子智能体时,交付逻辑也会优先使用最终后代输出,而不是过时的父级中间文本。如果后代仍在运行,OpenClaw 会抑制该父级的部分更新,而不是直接宣布它。
|
||||
隔离的 cron 运行还会通过共享的运行时清理路径,释放为该作业创建的所有内置 MCP 运行时实例。这与主会话和自定义会话的 MCP 客户端销毁方式一致,因此隔离的 cron 作业不会在多次运行间泄漏 stdio 子进程或长期存在的 MCP 连接。
|
||||
|
||||
### 独立作业的负载选项
|
||||
当隔离的 cron 运行协调子智能体时,交付也会优先使用最终的后代输出,而不是陈旧的父级临时文本。如果后代仍在运行,OpenClaw 会抑制该部分父级更新,而不是把它公布出去。
|
||||
|
||||
- `--message`:提示文本(独立模式必填)
|
||||
- `--model` / `--thinking`:模型和思考级别覆盖
|
||||
对于纯文本的 Discord 通知目标,OpenClaw 只会发送一次规范的最终助手文本,而不会同时重放流式 / 中间文本负载和最终答案。媒体和结构化的 Discord 负载仍会作为独立负载交付,以避免附件和组件被丢弃。
|
||||
|
||||
### 隔离作业的负载选项
|
||||
|
||||
- `--message`:提示词文本(隔离模式必需)
|
||||
- `--model` / `--thinking`:模型和 thinking 级别覆盖
|
||||
- `--light-context`:跳过工作区引导文件注入
|
||||
- `--tools exec,read`:限制该作业可使用的工具
|
||||
- `--tools exec,read`:限制作业可使用的工具
|
||||
|
||||
`--model` 会为该作业使用所选的允许模型。如果请求的模型不被允许,cron 会记录一条警告,并回退到该作业的智能体/默认模型选择。已配置的回退链仍然生效,但如果只是普通的模型覆盖且没有显式的按作业回退列表,则不再将智能体主模型作为隐藏的额外重试目标附加进去。
|
||||
`--model` 会为该作业使用所选且被允许的模型。如果请求的模型不被允许,cron 会记录警告,并改为回退到该作业的智能体 / 默认模型选择。已配置的回退链仍然适用,但单纯的模型覆盖在没有显式的按作业回退列表时,不再把智能体主模型追加为隐藏的额外重试目标。
|
||||
|
||||
独立作业的模型选择优先级如下:
|
||||
隔离作业的模型选择优先级如下:
|
||||
|
||||
1. Gmail hook 模型覆盖(当该运行来自 Gmail 且该覆盖模型被允许时)
|
||||
1. Gmail hook 模型覆盖(当运行来自 Gmail 且该覆盖被允许时)
|
||||
2. 按作业负载中的 `model`
|
||||
3. 已存储的 cron 会话模型覆盖
|
||||
4. 智能体/默认模型选择
|
||||
3. 用户选择的已存储 cron 会话模型覆盖
|
||||
4. 智能体 / 默认模型选择
|
||||
|
||||
快速模式也会遵循解析后的实时选择。如果所选模型配置带有 `params.fastMode`,独立 cron 默认会启用它。已存储的会话 `fastMode` 覆盖仍然在两个方向上都优先于配置。
|
||||
Fast mode 也会遵循解析后的实时选择。如果所选模型配置带有 `params.fastMode`,隔离的 cron 默认会使用它。已存储的会话 `fastMode` 覆盖在任一方向上都仍然优先于配置。
|
||||
|
||||
如果独立运行遇到实时模型切换移交,cron 会使用切换后的 provider/模型重试,并在重试前持久化该实时选择。如果切换还携带了新的认证配置文件,cron 也会持久化该认证配置文件覆盖。重试次数是有上限的:在初始尝试加上 2 次切换重试之后,cron 会中止,而不是无限循环。
|
||||
如果某个隔离运行遇到实时模型切换交接,cron 会使用切换后的 provider / 模型重试,并在重试前为当前运行持久化该实时选择。当切换同时携带新的 auth profile 时,cron 也会为当前运行持久化该 auth profile 覆盖。重试次数有上限:在初始尝试加上 2 次切换重试之后,cron 会中止,而不是无限循环。
|
||||
|
||||
## 交付与输出
|
||||
|
||||
| 模式 | 行为 |
|
||||
| ---------- | ---- |
|
||||
| `announce` | 如果智能体未发送,则回退将最终文本交付到目标 |
|
||||
| `webhook` | 向一个 URL `POST` 已完成事件负载 |
|
||||
| `none` | 不进行运行器回退交付 |
|
||||
| 模式 | 发生的情况 |
|
||||
| ---------- | ---------- |
|
||||
| `announce` | 如果智能体未发送,则回退交付最终文本到目标 |
|
||||
| `webhook` | 向某个 URL `POST` 完成事件负载 |
|
||||
| `none` | 运行器不做回退交付 |
|
||||
|
||||
使用 `--announce --channel telegram --to "-1001234567890"` 可进行渠道交付。对于 Telegram 论坛话题,请使用 `-1001234567890:topic:123`。Slack/Discord/Mattermost 目标应使用显式前缀(`channel:<id>`、`user:<id>`)。
|
||||
使用 `--announce --channel telegram --to "-1001234567890"` 可交付到渠道。对于 Telegram forum topics,使用 `-1001234567890:topic:123`。Slack / Discord / Mattermost 目标应使用显式前缀(`channel:<id>`、`user:<id>`)。
|
||||
|
||||
对于独立作业,聊天交付是共享的。如果存在聊天路由,即使作业使用了 `--no-deliver`,智能体也可以使用 `message` 工具。如果智能体发送到了配置的/当前目标,OpenClaw 会跳过回退 announce。否则,`announce`、`webhook` 和 `none` 仅控制运行器在智能体轮次结束后如何处理最终回复。
|
||||
对于隔离作业,聊天交付是共享的。如果存在聊天路由,即使作业使用 `--no-deliver`,智能体仍可使用 `message` 工具。如果智能体发送到了已配置 / 当前目标,OpenClaw 会跳过回退通知。否则,`announce`、`webhook` 和 `none` 只控制运行器如何在智能体轮次结束后处理最终回复。
|
||||
|
||||
失败通知会遵循单独的目标路径:
|
||||
失败通知遵循单独的目标路径:
|
||||
|
||||
- `cron.failureDestination` 为失败通知设置全局默认值。
|
||||
- `job.delivery.failureDestination` 为每个作业单独覆盖该值。
|
||||
- 如果两者都未设置,而该作业已经通过 `announce` 进行交付,则失败通知现在会回退到该主 announce 目标。
|
||||
- `delivery.failureDestination` 仅在 `sessionTarget="isolated"` 的作业上受支持,除非主交付模式为 `webhook`。
|
||||
- `cron.failureDestination` 设置失败通知的全局默认值。
|
||||
- `job.delivery.failureDestination` 可按作业覆盖它。
|
||||
- 如果两者都未设置,且作业已通过 `announce` 交付,失败通知现在会回退到该主要通知目标。
|
||||
- `delivery.failureDestination` 仅在 `sessionTarget="isolated"` 的作业中受支持,除非主要交付模式是 `webhook`。
|
||||
|
||||
## CLI 示例
|
||||
|
||||
@ -145,7 +148,7 @@ openclaw cron add \
|
||||
--wake now
|
||||
```
|
||||
|
||||
带交付的周期性独立作业:
|
||||
带交付的循环隔离作业:
|
||||
|
||||
```bash
|
||||
openclaw cron add \
|
||||
@ -159,7 +162,7 @@ openclaw cron add \
|
||||
--to "channel:C1234567890"
|
||||
```
|
||||
|
||||
带模型和思考覆盖的独立作业:
|
||||
带模型和 thinking 覆盖的隔离作业:
|
||||
|
||||
```bash
|
||||
openclaw cron add \
|
||||
@ -175,7 +178,7 @@ openclaw cron add \
|
||||
|
||||
## Webhooks
|
||||
|
||||
Gateway 网关可以公开 HTTP webhook 端点以接收外部触发器。在配置中启用:
|
||||
Gateway 网关可以暴露 HTTP webhook 端点以接收外部触发器。在配置中启用:
|
||||
|
||||
```json5
|
||||
{
|
||||
@ -187,14 +190,14 @@ Gateway 网关可以公开 HTTP webhook 端点以接收外部触发器。在配
|
||||
}
|
||||
```
|
||||
|
||||
### 认证
|
||||
### 身份验证
|
||||
|
||||
每个请求都必须通过请求头包含 hook token:
|
||||
每个请求都必须通过请求头携带 hook token:
|
||||
|
||||
- `Authorization: Bearer <token>`(推荐)
|
||||
- `x-openclaw-token: <token>`
|
||||
|
||||
查询字符串中的 token 会被拒绝。
|
||||
不接受查询字符串中的 token。
|
||||
|
||||
### POST /hooks/wake
|
||||
|
||||
@ -207,12 +210,12 @@ curl -X POST http://127.0.0.1:18789/hooks/wake \
|
||||
-d '{"text":"New email received","mode":"now"}'
|
||||
```
|
||||
|
||||
- `text`(必填):事件描述
|
||||
- `text`(必需):事件描述
|
||||
- `mode`(可选):`now`(默认)或 `next-heartbeat`
|
||||
|
||||
### POST /hooks/agent
|
||||
|
||||
运行一个独立的智能体轮次:
|
||||
运行一个隔离的智能体轮次:
|
||||
|
||||
```bash
|
||||
curl -X POST http://127.0.0.1:18789/hooks/agent \
|
||||
@ -221,27 +224,27 @@ curl -X POST http://127.0.0.1:18789/hooks/agent \
|
||||
-d '{"message":"Summarize inbox","name":"Email","model":"openai/gpt-5.4"}'
|
||||
```
|
||||
|
||||
字段:`message`(必填)、`name`、`agentId`、`wakeMode`、`deliver`、`channel`、`to`、`model`、`thinking`、`timeoutSeconds`。
|
||||
字段:`message`(必需)、`name`、`agentId`、`wakeMode`、`deliver`、`channel`、`to`、`model`、`thinking`、`timeoutSeconds`。
|
||||
|
||||
### 映射 hooks(POST /hooks/\<name\>)
|
||||
|
||||
自定义 hook 名称会通过配置中的 `hooks.mappings` 进行解析。映射可以使用模板或代码转换,将任意负载转换为 `wake` 或 `agent` 动作。
|
||||
自定义 hook 名称通过配置中的 `hooks.mappings` 解析。映射可以使用模板或代码转换,将任意负载转换为 `wake` 或 `agent` 动作。
|
||||
|
||||
### 安全性
|
||||
|
||||
- 将 hook 端点放在 loopback、tailnet 或受信任的反向代理之后。
|
||||
- 将 hook 端点置于 loopback、tailnet 或受信任的反向代理之后。
|
||||
- 使用专用的 hook token;不要复用 gateway 认证 token。
|
||||
- 将 `hooks.path` 放在专用子路径下;`/` 会被拒绝。
|
||||
- 设置 `hooks.allowedAgentIds` 以限制显式 `agentId` 路由。
|
||||
- 除非你确实需要由调用方选择会话,否则请保持 `hooks.allowRequestSessionKey=false`。
|
||||
- 如果你启用了 `hooks.allowRequestSessionKey`,也请设置 `hooks.allowedSessionKeyPrefixes` 以限制允许的会话键格式。
|
||||
- 默认情况下,hook 负载会被安全边界包裹。
|
||||
- 将 `hooks.path` 保持在专用子路径下;`/` 会被拒绝。
|
||||
- 设置 `hooks.allowedAgentIds` 以限制显式的 `agentId` 路由。
|
||||
- 保持 `hooks.allowRequestSessionKey=false`,除非你确实需要由调用方选择会话。
|
||||
- 如果你启用了 `hooks.allowRequestSessionKey`,也请设置 `hooks.allowedSessionKeyPrefixes` 以限制允许的会话键形态。
|
||||
- 默认情况下,hook 负载会包裹安全边界。
|
||||
|
||||
## Gmail PubSub 集成
|
||||
|
||||
通过 Google PubSub 将 Gmail 收件箱触发器接入 OpenClaw。
|
||||
|
||||
**前提条件**:`gcloud` CLI、`gog`(gogcli)、已启用 OpenClaw hooks、用于公开 HTTPS 端点的 Tailscale。
|
||||
**前置条件**:`gcloud` CLI、`gog`(gogcli)、已启用 OpenClaw hooks,以及用于公共 HTTPS 端点的 Tailscale。
|
||||
|
||||
### 向导设置(推荐)
|
||||
|
||||
@ -249,15 +252,15 @@ curl -X POST http://127.0.0.1:18789/hooks/agent \
|
||||
openclaw webhooks gmail setup --account openclaw@gmail.com
|
||||
```
|
||||
|
||||
这会写入 `hooks.gmail` 配置,启用 Gmail 预设,并使用 Tailscale Funnel 作为推送端点。
|
||||
这会写入 `hooks.gmail` 配置、启用 Gmail 预设,并为推送端点使用 Tailscale Funnel。
|
||||
|
||||
### Gateway 网关自动启动
|
||||
|
||||
当 `hooks.enabled=true` 且设置了 `hooks.gmail.account` 时,Gateway 网关会在启动时运行 `gog gmail watch serve` 并自动续订 watch。设置 `OPENCLAW_SKIP_GMAIL_WATCHER=1` 可选择退出。
|
||||
当 `hooks.enabled=true` 且设置了 `hooks.gmail.account` 时,Gateway 网关会在启动时启动 `gog gmail watch serve`,并自动续订 watch。设置 `OPENCLAW_SKIP_GMAIL_WATCHER=1` 可选择退出。
|
||||
|
||||
### 手动一次性设置
|
||||
|
||||
1. 选择拥有 `gog` 所用 OAuth 客户端的 GCP 项目:
|
||||
1. 选择拥有 `gog` 所使用 OAuth 客户端的 GCP 项目:
|
||||
|
||||
```bash
|
||||
gcloud auth login
|
||||
@ -265,7 +268,7 @@ gcloud config set project <project-id>
|
||||
gcloud services enable gmail.googleapis.com pubsub.googleapis.com
|
||||
```
|
||||
|
||||
2. 创建 topic,并授予 Gmail 推送权限:
|
||||
2. 创建 topic 并授予 Gmail 推送访问权限:
|
||||
|
||||
```bash
|
||||
gcloud pubsub topics create gog-gmail-watch
|
||||
@ -328,9 +331,9 @@ openclaw cron edit <jobId> --clear-agent
|
||||
模型覆盖说明:
|
||||
|
||||
- `openclaw cron add|edit --model ...` 会更改作业所选的模型。
|
||||
- 如果该模型被允许,那个确切的 provider/模型 会传递到独立智能体运行中。
|
||||
- 如果它不被允许,cron 会发出警告,并回退到该作业的智能体/默认模型选择。
|
||||
- 已配置的回退链仍然生效,但普通的 `--model` 覆盖如果没有显式的按作业回退列表,将不再静默回落到智能体主模型作为额外的重试目标。
|
||||
- 如果该模型被允许,那个精确的 provider / 模型 就会传递到隔离的智能体运行。
|
||||
- 如果不被允许,cron 会发出警告,并回退到该作业的智能体 / 默认模型选择。
|
||||
- 已配置的回退链仍然适用,但普通的 `--model` 覆盖在没有显式按作业回退列表时,不再静默回退到智能体主模型作为额外重试目标。
|
||||
|
||||
## 配置
|
||||
|
||||
@ -352,16 +355,15 @@ openclaw cron edit <jobId> --clear-agent
|
||||
}
|
||||
```
|
||||
|
||||
运行时状态 sidecar 由 `cron.store` 推导得出:像
|
||||
`~/clawd/cron/jobs.json` 这样的 `.json` 存储会使用 `~/clawd/cron/jobs-state.json`,而不带 `.json` 后缀的存储路径则会附加 `-state.json`。
|
||||
运行时状态 sidecar 由 `cron.store` 派生:像 `~/clawd/cron/jobs.json` 这样的 `.json` 存储会使用 `~/clawd/cron/jobs-state.json`,而没有 `.json` 后缀的存储路径则会追加 `-state.json`。
|
||||
|
||||
禁用 cron:`cron.enabled: false` 或 `OPENCLAW_SKIP_CRON=1`。
|
||||
|
||||
**一次性作业重试**:瞬时错误(限流、过载、网络、服务器错误)最多重试 3 次,并采用指数退避。永久性错误会立即禁用。
|
||||
**一次性重试**:瞬时错误(速率限制、过载、网络、服务器错误)最多重试 3 次,并使用指数退避。永久错误会立即禁用。
|
||||
|
||||
**周期性作业重试**:重试之间使用指数退避(30 秒到 60 分钟)。在下一次成功运行后,退避会重置。
|
||||
**循环重试**:重试之间使用指数退避(30 秒到 60 分钟)。在下一次成功运行后,退避会重置。
|
||||
|
||||
**维护**:`cron.sessionRetention`(默认 `24h`)会清理独立运行会话条目。`cron.runLog.maxBytes` / `cron.runLog.keepLines` 会自动清理运行日志文件。
|
||||
**维护**:`cron.sessionRetention`(默认 `24h`)会清理隔离运行的会话条目。`cron.runLog.maxBytes` / `cron.runLog.keepLines` 会自动清理运行日志文件。
|
||||
|
||||
## 故障排除
|
||||
|
||||
@ -381,27 +383,27 @@ openclaw doctor
|
||||
### Cron 未触发
|
||||
|
||||
- 检查 `cron.enabled` 和 `OPENCLAW_SKIP_CRON` 环境变量。
|
||||
- 确认 Gateway 网关持续运行中。
|
||||
- 对于 `cron` 调度,检查时区(`--tz`)与主机时区是否一致。
|
||||
- 运行输出中的 `reason: not-due` 表示你使用 `openclaw cron run <jobId> --due` 检查了手动运行,但该作业尚未到期。
|
||||
- 确认 Gateway 网关在持续运行。
|
||||
- 对于 `cron` 调度,验证时区(`--tz`)与主机时区是否一致。
|
||||
- 运行输出中的 `reason: not-due` 表示通过 `openclaw cron run <jobId> --due` 检查手动运行时,该作业尚未到期。
|
||||
|
||||
### Cron 已触发但没有交付
|
||||
|
||||
- 交付模式 `none` 表示不会进行运行器回退发送。只要有聊天路由可用,智能体仍可使用 `message` 工具直接发送。
|
||||
- 缺少/无效的交付目标(`channel`/`to`)表示已跳过出站发送。
|
||||
- 交付模式为 `none` 表示预期不会有运行器回退发送。当存在聊天路由时,智能体仍可通过 `message` 工具直接发送。
|
||||
- 交付目标缺失 / 无效(`channel` / `to`)表示已跳过出站发送。
|
||||
- 渠道认证错误(`unauthorized`、`Forbidden`)表示交付被凭证阻止。
|
||||
- 如果独立运行只返回静默 token(`NO_REPLY` / `no_reply`),OpenClaw 会抑制直接出站交付,也会抑制回退排队摘要路径,因此不会向聊天回发任何内容。
|
||||
- 如果智能体应该自行向用户发送消息,请检查该作业是否具有可用路由(带有之前聊天记录的 `channel: "last"`,或显式的渠道/目标)。
|
||||
- 如果隔离运行只返回静默 token(`NO_REPLY` / `no_reply`),OpenClaw 会抑制直接出站交付,也会抑制回退排队摘要路径,因此不会向聊天回发任何内容。
|
||||
- 如果应由智能体自行向用户发送消息,请检查该作业是否有可用路由(带有先前聊天记录的 `channel: "last"`,或显式的 channel / target)。
|
||||
|
||||
### 时区注意事项
|
||||
|
||||
- 不带 `--tz` 的 cron 会使用 Gateway 网关主机时区。
|
||||
- 不带时区的 `at` 调度会被视为 UTC。
|
||||
- Heartbeat 的 `activeHours` 使用已配置的时区解析。
|
||||
- 未指定 `--tz` 的 cron 会使用 gateway 主机时区。
|
||||
- 未指定时区的 `at` 调度会按 UTC 处理。
|
||||
- Heartbeat `activeHours` 使用已配置的时区解析。
|
||||
|
||||
## 相关内容
|
||||
|
||||
- [自动化与任务](/zh-CN/automation) — 一览所有自动化机制
|
||||
- [后台任务](/zh-CN/automation/tasks) — cron 执行的任务台账
|
||||
- [Automation & Tasks](/zh-CN/automation) — 所有自动化机制概览
|
||||
- [Background Tasks](/zh-CN/automation/tasks) — cron 执行的任务账本
|
||||
- [Heartbeat](/zh-CN/gateway/heartbeat) — 周期性的主会话轮次
|
||||
- [时区](/zh-CN/concepts/timezone) — 时区配置
|
||||
- [Timezone](/zh-CN/concepts/timezone) — 时区配置
|
||||
|
||||
@ -4,15 +4,15 @@ read_when:
|
||||
summary: Discord 机器人支持状态、功能和配置
|
||||
title: Discord
|
||||
x-i18n:
|
||||
generated_at: "2026-04-25T00:40:14Z"
|
||||
generated_at: "2026-04-25T05:53:10Z"
|
||||
model: gpt-5.4
|
||||
provider: openai
|
||||
source_hash: 349f82e96e17aad30e4dc28c25d06841121f37b35c367f13f52cd0700105bd11
|
||||
source_hash: 4f40c8a768c850e0e90e698fa82eaca81a0a7cd682f5dee8609793f60cc83355
|
||||
source_path: channels/discord.md
|
||||
workflow: 15
|
||||
---
|
||||
|
||||
已准备好通过官方 Discord Gateway 网关支持私信和服务器频道。
|
||||
已准备好通过官方 Discord Gateway 网关支持私信和服务器渠道。
|
||||
|
||||
<CardGroup cols={3}>
|
||||
<Card title="配对" icon="link" href="/zh-CN/channels/pairing">
|
||||
@ -26,42 +26,42 @@ x-i18n:
|
||||
</Card>
|
||||
</CardGroup>
|
||||
|
||||
## 快速设置
|
||||
## 快速开始
|
||||
|
||||
你需要创建一个带有机器人的新应用,将机器人添加到你的服务器,并将其与 OpenClaw 配对。我们建议将你的机器人添加到你自己的私人服务器。如果你还没有,请先[创建一个](https://support.discord.com/hc/en-us/articles/204849977-How-do-I-create-a-server)(选择 **Create My Own > For me and my friends**)。
|
||||
你需要创建一个带有机器人的新应用,将机器人添加到你的服务器,并将其与 OpenClaw 配对。我们建议你把机器人添加到你自己的私有服务器。如果你还没有服务器,请先[创建一个](https://support.discord.com/hc/en-us/articles/204849977-How-do-I-create-a-server)(选择 **Create My Own > For me and my friends**)。
|
||||
|
||||
<Steps>
|
||||
<Step title="创建 Discord 应用和机器人">
|
||||
前往 [Discord Developer Portal](https://discord.com/developers/applications),然后点击 **New Application**。给它起一个类似 “OpenClaw” 的名字。
|
||||
前往 [Discord Developer Portal](https://discord.com/developers/applications),点击 **New Application**。给它起一个类似 “OpenClaw” 的名字。
|
||||
|
||||
点击侧边栏中的 **Bot**。将 **Username** 设置为你对 OpenClaw 智能体的称呼。
|
||||
|
||||
</Step>
|
||||
|
||||
<Step title="启用特权 intents">
|
||||
仍在 **Bot** 页面中,向下滚动到 **Privileged Gateway Intents** 并启用:
|
||||
仍然停留在 **Bot** 页面,向下滚动到 **Privileged Gateway Intents**,然后启用:
|
||||
|
||||
- **Message Content Intent**(必需)
|
||||
- **Server Members Intent**(推荐;角色允许列表和名称到 ID 匹配时必需)
|
||||
- **Presence Intent**(可选;仅在需要在线状态更新时使用)
|
||||
- **Server Members Intent**(推荐;角色 allowlist 和名称到 ID 匹配需要它)
|
||||
- **Presence Intent**(可选;仅在需要状态更新时使用)
|
||||
|
||||
</Step>
|
||||
|
||||
<Step title="复制你的机器人令牌">
|
||||
向上滚动回 **Bot** 页面顶部并点击 **Reset Token**。
|
||||
回到 **Bot** 页面的顶部,点击 **Reset Token**。
|
||||
|
||||
<Note>
|
||||
尽管名字如此,这会生成你的第一个令牌——并没有任何内容被“重置”。
|
||||
尽管名字叫这个,但它会生成你的第一个令牌——并没有任何内容被“重置”。
|
||||
</Note>
|
||||
|
||||
复制该令牌并将其保存到某个地方。这就是你的 **Bot Token**,你很快就会用到它。
|
||||
复制该令牌并将其保存到某处。这就是你的 **Bot Token**,你很快就会用到它。
|
||||
|
||||
</Step>
|
||||
|
||||
<Step title="生成邀请 URL 并将机器人添加到你的服务器">
|
||||
点击侧边栏中的 **OAuth2**。你将生成一个具有正确权限的邀请 URL,用于将机器人添加到你的服务器。
|
||||
点击侧边栏中的 **OAuth2**。你将生成一个带有正确权限的邀请 URL,用来将机器人添加到你的服务器。
|
||||
|
||||
向下滚动到 **OAuth2 URL Generator** 并启用:
|
||||
向下滚动到 **OAuth2 URL Generator**,并启用:
|
||||
|
||||
- `bot`
|
||||
- `applications.commands`
|
||||
@ -77,8 +77,8 @@ x-i18n:
|
||||
- Attach Files
|
||||
- Add Reactions(可选)
|
||||
|
||||
这是普通文本频道的基础权限集。如果你计划在 Discord 线程中发帖,包括会创建或继续线程的论坛或媒体频道工作流,还需要启用 **Send Messages in Threads**。
|
||||
复制底部生成的 URL,将其粘贴到浏览器中,选择你的服务器,然后点击 **Continue** 进行连接。现在你应该能在 Discord 服务器中看到你的机器人。
|
||||
这是普通文本渠道的基础权限集合。如果你计划在 Discord 线程中发帖,包括会创建或继续线程的论坛或媒体渠道工作流,还要启用 **Send Messages in Threads**。
|
||||
复制底部生成的 URL,将其粘贴到浏览器中,选择你的服务器,然后点击 **Continue** 完成连接。现在你应该能在 Discord 服务器中看到你的机器人。
|
||||
|
||||
</Step>
|
||||
|
||||
@ -89,19 +89,19 @@ x-i18n:
|
||||
2. 在侧边栏中右键点击你的**服务器图标** → **Copy Server ID**
|
||||
3. 右键点击你自己的**头像** → **Copy User ID**
|
||||
|
||||
将你的 **Server ID** 和 **User ID** 与你的 Bot Token 一起保存——你会在下一步将这三项都发给 OpenClaw。
|
||||
将你的 **Server ID** 和 **User ID** 与 Bot Token 一起保存——你会在下一步把这三项都发送给 OpenClaw。
|
||||
|
||||
</Step>
|
||||
|
||||
<Step title="允许来自服务器成员的私信">
|
||||
为了让配对正常工作,Discord 需要允许你的机器人向你发送私信。右键点击你的**服务器图标** → **Privacy Settings** → 打开 **Direct Messages**。
|
||||
为了让配对正常工作,Discord 需要允许你的机器人给你发送私信。右键点击你的**服务器图标** → **Privacy Settings** → 打开 **Direct Messages**。
|
||||
|
||||
这会允许服务器成员(包括机器人)向你发送私信。如果你想通过 Discord 私信使用 OpenClaw,请保持此选项开启。如果你只打算使用服务器频道,则可以在配对后禁用私信。
|
||||
这会允许服务器成员(包括机器人)向你发送私信。如果你想在 OpenClaw 中使用 Discord 私信,请保持该选项开启。如果你只打算使用服务器渠道,则可以在配对后关闭私信。
|
||||
|
||||
</Step>
|
||||
|
||||
<Step title="安全设置你的机器人令牌(不要在聊天中发送它)">
|
||||
你的 Discord 机器人令牌是一个密钥(类似密码)。在给你的智能体发消息之前,先在运行 OpenClaw 的机器上设置它。
|
||||
<Step title="安全设置你的机器人令牌(不要在聊天中发送)">
|
||||
你的 Discord 机器人令牌是一个密钥(类似密码)。在向你的智能体发消息之前,先在运行 OpenClaw 的机器上设置它。
|
||||
|
||||
```bash
|
||||
export DISCORD_BOT_TOKEN="YOUR_BOT_TOKEN"
|
||||
@ -111,17 +111,17 @@ openclaw config set channels.discord.enabled true --strict-json
|
||||
openclaw gateway
|
||||
```
|
||||
|
||||
如果 OpenClaw 已经作为后台服务运行,请通过 OpenClaw Mac 应用重启它,或者停止并重新启动 `openclaw gateway run` 进程。
|
||||
如果 OpenClaw 已经作为后台服务运行,请通过 OpenClaw Mac 应用重启它,或停止并重新启动 `openclaw gateway run` 进程。
|
||||
|
||||
</Step>
|
||||
|
||||
<Step title="配置 OpenClaw 并配对">
|
||||
<Step title="配置 OpenClaw 并完成配对">
|
||||
|
||||
<Tabs>
|
||||
<Tab title="让你的智能体来做">
|
||||
在任何现有渠道(例如 Telegram)上与你的 OpenClaw 智能体聊天并告诉它。如果 Discord 是你的第一个渠道,请改用 CLI / 配置选项卡。
|
||||
<Tab title="询问你的智能体">
|
||||
在任意现有渠道(例如 Telegram)中与你的 OpenClaw 智能体聊天并告诉它。如果 Discord 是你的第一个渠道,请改用 CLI / 配置标签页。
|
||||
|
||||
> “我已经在配置中设置了 Discord 机器人令牌。请使用 User ID `<user_id>` 和 Server ID `<server_id>` 完成 Discord 设置。”
|
||||
> “我已经在配置中设置好了 Discord 机器人令牌。请使用 User ID `<user_id>` 和 Server ID `<server_id>` 完成 Discord 设置。”
|
||||
</Tab>
|
||||
<Tab title="CLI / 配置">
|
||||
如果你更喜欢基于文件的配置,请设置:
|
||||
@ -147,7 +147,7 @@ openclaw gateway
|
||||
DISCORD_BOT_TOKEN=...
|
||||
```
|
||||
|
||||
也支持明文 `token` 值。`channels.discord.token` 也支持跨 env/file/exec 提供商的 SecretRef 值。参见 [Secrets Management](/zh-CN/gateway/secrets)。
|
||||
支持明文 `token` 值。`channels.discord.token` 也支持跨 env/file/exec providers 的 SecretRef 值。参见 [Secrets Management](/zh-CN/gateway/secrets)。
|
||||
|
||||
</Tab>
|
||||
</Tabs>
|
||||
@ -155,11 +155,11 @@ DISCORD_BOT_TOKEN=...
|
||||
</Step>
|
||||
|
||||
<Step title="批准首次私信配对">
|
||||
等待 Gateway 网关运行后,在 Discord 中向你的机器人发送私信。它会回复一个配对码。
|
||||
等待 Gateway 网关运行后,在 Discord 中给你的机器人发送私信。它会回复一个配对码。
|
||||
|
||||
<Tabs>
|
||||
<Tab title="让你的智能体来做">
|
||||
将该配对码发送给你现有渠道中的智能体:
|
||||
<Tab title="询问你的智能体">
|
||||
将配对码发送给你现有渠道中的智能体:
|
||||
|
||||
> “批准这个 Discord 配对码:`<CODE>`”
|
||||
</Tab>
|
||||
@ -175,27 +175,27 @@ openclaw pairing approve discord <CODE>
|
||||
|
||||
配对码会在 1 小时后过期。
|
||||
|
||||
现在你应该可以通过私信在 Discord 中与你的智能体聊天了。
|
||||
现在你应该已经可以通过 Discord 私信与你的智能体聊天了。
|
||||
|
||||
</Step>
|
||||
</Steps>
|
||||
|
||||
<Note>
|
||||
令牌解析具有账户感知能力。配置中的 token 值优先于环境变量回退。`DISCORD_BOT_TOKEN` 仅用于默认账户。
|
||||
对于高级出站调用(消息工具/渠道操作),显式提供的逐次调用 `token` 会用于该次调用。这适用于发送以及读取/探测类操作(例如 read/search/fetch/thread/pins/permissions)。账户策略/重试设置仍然来自活动运行时快照中所选的账户。
|
||||
令牌解析具有账户感知能力。配置中的令牌值优先于环境变量回退。`DISCORD_BOT_TOKEN` 仅用于默认账户。
|
||||
对于高级出站调用(消息工具/渠道操作),每次调用显式指定的 `token` 会用于该次调用。这适用于发送以及读取/探测类操作(例如 read/search/fetch/thread/pins/permissions)。账户策略和重试设置仍然来自活动运行时快照中所选的账户。
|
||||
</Note>
|
||||
|
||||
## 推荐:设置服务器工作区
|
||||
|
||||
一旦私信正常工作,你就可以将 Discord 服务器设置为一个完整工作区,其中每个频道都会获得自己的智能体会话和各自的上下文。对于只有你和你的机器人的私人服务器,我们推荐这样做。
|
||||
当私信可用后,你可以将 Discord 服务器设置为完整工作区,其中每个渠道都会获得自己的智能体会话及其独立上下文。这对于只有你和你的机器人的私有服务器特别推荐。
|
||||
|
||||
<Steps>
|
||||
<Step title="将你的服务器添加到服务器允许列表">
|
||||
这样你的智能体就可以在你服务器上的任意频道中回复,而不仅仅是私信。
|
||||
<Step title="将你的服务器添加到 guild allowlist">
|
||||
这会使你的智能体能够在服务器中的任意渠道响应,而不仅仅是私信。
|
||||
|
||||
<Tabs>
|
||||
<Tab title="让你的智能体来做">
|
||||
> “将我的 Discord Server ID `<server_id>` 添加到服务器允许列表”
|
||||
<Tab title="询问你的智能体">
|
||||
> “将我的 Discord Server ID `<server_id>` 添加到 guild allowlist”
|
||||
</Tab>
|
||||
<Tab title="配置">
|
||||
|
||||
@ -220,15 +220,15 @@ openclaw pairing approve discord <CODE>
|
||||
|
||||
</Step>
|
||||
|
||||
<Step title="允许在没有 @mention 的情况下回复">
|
||||
默认情况下,你的智能体只会在被 @mention 时才在服务器频道中回复。对于私人服务器,你可能更希望它对每条消息都进行回复。
|
||||
<Step title="允许在没有 @mention 的情况下响应">
|
||||
默认情况下,你的智能体只有在被 @ 提及时,才会在服务器渠道中响应。对于私有服务器,你很可能希望它对每条消息都作出响应。
|
||||
|
||||
<Tabs>
|
||||
<Tab title="让你的智能体来做">
|
||||
> “允许我的智能体在这个服务器中无需 @mention 也能回复”
|
||||
<Tab title="询问你的智能体">
|
||||
> “允许我的智能体在这个服务器中无需被 @ 提及也能响应”
|
||||
</Tab>
|
||||
<Tab title="配置">
|
||||
在你的服务器配置中设置 `requireMention: false`:
|
||||
在你的 guild 配置中设置 `requireMention: false`:
|
||||
|
||||
```json5
|
||||
{
|
||||
@ -249,40 +249,42 @@ openclaw pairing approve discord <CODE>
|
||||
|
||||
</Step>
|
||||
|
||||
<Step title="为服务器频道中的记忆做好规划">
|
||||
默认情况下,长期记忆(MEMORY.md)只会在私信会话中加载。服务器频道不会自动加载 MEMORY.md。
|
||||
<Step title="为服务器渠道中的内存做好规划">
|
||||
默认情况下,长期记忆(MEMORY.md)只会在私信会话中加载。服务器渠道不会自动加载 MEMORY.md。
|
||||
|
||||
<Tabs>
|
||||
<Tab title="让你的智能体来做">
|
||||
> “当我在 Discord 频道中提问时,如果你需要来自 MEMORY.md 的长期上下文,请使用 memory_search 或 memory_get。”
|
||||
<Tab title="询问你的智能体">
|
||||
> “当我在 Discord 渠道中提问时,如果你需要来自 MEMORY.md 的长期上下文,请使用 memory_search 或 memory_get。”
|
||||
</Tab>
|
||||
<Tab title="手动">
|
||||
如果你需要每个频道都共享上下文,请将稳定的说明放入 `AGENTS.md` 或 `USER.md`(它们会注入到每个会话中)。将长期笔记保存在 `MEMORY.md` 中,并在需要时通过记忆工具访问它们。
|
||||
如果你需要在每个渠道中共享上下文,请将稳定的指令放入 `AGENTS.md` 或 `USER.md`(它们会注入到每个会话中)。将长期笔记保存在 `MEMORY.md` 中,并在需要时通过内存工具访问它们。
|
||||
</Tab>
|
||||
</Tabs>
|
||||
|
||||
</Step>
|
||||
</Steps>
|
||||
|
||||
现在,在你的 Discord 服务器上创建一些频道并开始聊天吧。你的智能体可以看到频道名称,并且每个频道都会获得各自独立隔离的会话——因此你可以设置 `#coding`、`#home`、`#research`,或任何适合你工作流的频道。
|
||||
现在,在你的 Discord 服务器中创建一些渠道并开始聊天吧。你的智能体可以看到渠道名称,并且每个渠道都会获得自己隔离的会话——因此你可以设置 `#coding`、`#home`、`#research`,或任何适合你工作流的渠道。
|
||||
|
||||
## 运行时模型
|
||||
|
||||
- Gateway 网关拥有 Discord 连接。
|
||||
- 回复路由是确定性的:从 Discord 进入的回复会返回到 Discord。
|
||||
- 回复路由是确定性的:来自 Discord 的入站回复会返回到 Discord。
|
||||
- 默认情况下(`session.dmScope=main`),私聊共享智能体主会话(`agent:main:main`)。
|
||||
- 服务器频道使用隔离的会话键(`agent:<agentId>:discord:channel:<channelId>`)。
|
||||
- 服务器渠道使用隔离的会话键(`agent:<agentId>:discord:channel:<channelId>`)。
|
||||
- 群组私信默认会被忽略(`channels.discord.dm.groupEnabled=false`)。
|
||||
- 原生斜杠命令在隔离的命令会话中运行(`agent:<agentId>:discord:slash:<userId>`),同时仍会将 `CommandTargetSessionKey` 传递到已路由的对话会话。
|
||||
- 原生斜杠命令在隔离的命令会话中运行(`agent:<agentId>:discord:slash:<userId>`),同时仍携带 `CommandTargetSessionKey` 指向被路由的对话会话。
|
||||
- 发送到 Discord 的纯文本 cron/heartbeat 公告默认只使用一次对智能体可见的最终回答。
|
||||
当智能体发出多个可投递载荷时,媒体和结构化组件载荷仍会保持多消息形式。
|
||||
|
||||
## 论坛频道
|
||||
## 论坛渠道
|
||||
|
||||
Discord 论坛和媒体频道只接受线程帖子。OpenClaw 支持两种创建方式:
|
||||
Discord 论坛和媒体渠道仅接受线程帖子。OpenClaw 支持两种创建方式:
|
||||
|
||||
- 向论坛父频道(`channel:<forumId>`)发送消息以自动创建线程。线程标题使用你消息中的第一行非空内容。
|
||||
- 使用 `openclaw message thread create` 直接创建线程。对于论坛频道,不要传递 `--message-id`。
|
||||
- 向论坛父级发送消息(`channel:<forumId>`)以自动创建线程。线程标题使用消息中第一行非空内容。
|
||||
- 使用 `openclaw message thread create` 直接创建线程。对于论坛渠道,不要传入 `--message-id`。
|
||||
|
||||
示例:发送到论坛父频道以创建线程
|
||||
示例:发送到论坛父级以创建线程
|
||||
|
||||
```bash
|
||||
openclaw message send --channel discord --target channel:<forumId> \
|
||||
@ -296,35 +298,35 @@ openclaw message thread create --channel discord --target channel:<forumId> \
|
||||
--thread-name "Topic title" --message "Body of the post"
|
||||
```
|
||||
|
||||
论坛父频道不接受 Discord components。如果你需要 components,请发送到线程本身(`channel:<threadId>`)。
|
||||
论坛父级不接受 Discord 组件。如果你需要组件,请发送到线程本身(`channel:<threadId>`)。
|
||||
|
||||
## 交互式组件
|
||||
|
||||
OpenClaw 支持为智能体消息使用 Discord components v2 容器。使用消息工具并提供 `components` 负载。交互结果会作为普通入站消息路由回智能体,并遵循现有的 Discord `replyToMode` 设置。
|
||||
OpenClaw 支持在智能体消息中使用 Discord components v2 容器。使用消息工具并传入 `components` 载荷即可。交互结果会像普通入站消息一样路由回智能体,并遵循现有的 Discord `replyToMode` 设置。
|
||||
|
||||
支持的块:
|
||||
|
||||
- `text`、`section`、`separator`、`actions`、`media-gallery`、`file`
|
||||
- 操作行最多允许 5 个按钮或 1 个单选菜单
|
||||
- `text`, `section`, `separator`, `actions`, `media-gallery`, `file`
|
||||
- 操作行最多允许 5 个按钮,或一个单独的选择菜单
|
||||
- 选择类型:`string`、`user`、`role`、`mentionable`、`channel`
|
||||
|
||||
默认情况下,components 为一次性使用。设置 `components.reusable=true` 可允许按钮、选择器和表单在过期前被多次使用。
|
||||
默认情况下,组件为一次性使用。设置 `components.reusable=true` 可允许按钮、选择器和表单在过期前被多次使用。
|
||||
|
||||
若要限制谁可以点击某个按钮,请在该按钮上设置 `allowedUsers`(Discord 用户 ID、标签,或 `*`)。配置后,不匹配的用户会收到一个临时拒绝提示。
|
||||
要限制谁可以点击某个按钮,请在该按钮上设置 `allowedUsers`(Discord 用户 ID、标签或 `*`)。配置后,不匹配的用户会收到一个临时拒绝提示。
|
||||
|
||||
`/model` 和 `/models` 斜杠命令会打开一个交互式模型选择器,其中包含提供商、模型和兼容运行时下拉菜单,以及一个提交步骤。`/models add` 已弃用,现在会返回弃用消息,而不会再通过聊天注册模型。选择器回复是临时的,并且只有调用它的用户可以使用。
|
||||
`/model` 和 `/models` 斜杠命令会打开一个交互式模型选择器,其中包含提供商、模型以及兼容运行时下拉菜单,并带有提交步骤。`/models add` 已弃用,现在会返回弃用提示消息,而不是通过聊天注册模型。选择器回复是临时的,并且只有调用它的用户可以使用。
|
||||
|
||||
文件附件:
|
||||
|
||||
- `file` 块必须指向一个附件引用(`attachment://<filename>`)
|
||||
- 通过 `media`/`path`/`filePath` 提供附件(单个文件);多个文件请使用 `media-gallery`
|
||||
- 当上传名称应与附件引用匹配时,使用 `filename` 覆盖上传名称
|
||||
- `file` 块必须指向附件引用(`attachment://<filename>`)
|
||||
- 通过 `media` / `path` / `filePath` 提供附件(单个文件);多个文件请使用 `media-gallery`
|
||||
- 当上传名称应与附件引用匹配时,使用 `filename` 覆盖上传文件名
|
||||
|
||||
模态表单:
|
||||
|
||||
- 添加 `components.modal`,最多可包含 5 个字段
|
||||
- 字段类型:`text`、`checkbox`、`radio`、`select`、`role-select`、`user-select`
|
||||
- OpenClaw 会自动添加一个触发按钮
|
||||
- OpenClaw 会自动添加触发表单的按钮
|
||||
|
||||
示例:
|
||||
|
||||
@ -391,20 +393,20 @@ OpenClaw 支持为智能体消息使用 Discord components v2 容器。使用消
|
||||
- `open`(要求 `channels.discord.allowFrom` 包含 `"*"`;旧版:`channels.discord.dm.allowFrom`)
|
||||
- `disabled`
|
||||
|
||||
如果私信策略不是 open,未知用户会被阻止(或在 `pairing` 模式下提示进行配对)。
|
||||
如果私信策略不是 open,未知用户将被阻止(或在 `pairing` 模式下提示进行配对)。
|
||||
|
||||
多账户优先级:
|
||||
|
||||
- `channels.discord.accounts.default.allowFrom` 仅适用于 `default` 账户。
|
||||
- 已命名账户在自身 `allowFrom` 未设置时,会继承 `channels.discord.allowFrom`。
|
||||
- 已命名账户不会继承 `channels.discord.accounts.default.allowFrom`。
|
||||
- 命名账户在其自身 `allowFrom` 未设置时,会继承 `channels.discord.allowFrom`。
|
||||
- 命名账户不会继承 `channels.discord.accounts.default.allowFrom`。
|
||||
|
||||
用于投递的私信目标格式:
|
||||
|
||||
- `user:<id>`
|
||||
- `<@id>` 提及
|
||||
|
||||
裸数字 ID 存在歧义,除非明确提供 user/channel 目标种类,否则会被拒绝。
|
||||
裸数字 ID 存在歧义,除非显式提供 user/channel 目标类型,否则会被拒绝。
|
||||
|
||||
</Tab>
|
||||
|
||||
@ -415,16 +417,16 @@ OpenClaw 支持为智能体消息使用 Discord components v2 容器。使用消
|
||||
- `allowlist`
|
||||
- `disabled`
|
||||
|
||||
当存在 `channels.discord` 时,安全基线是 `allowlist`。
|
||||
当存在 `channels.discord` 时,安全基线为 `allowlist`。
|
||||
|
||||
`allowlist` 行为:
|
||||
|
||||
- 服务器必须匹配 `channels.discord.guilds`(优先使用 `id`,也接受 slug)
|
||||
- 可选的发送者允许列表:`users`(推荐使用稳定 ID)和 `roles`(仅角色 ID);如果配置了任一项,当发送者匹配 `users` 或 `roles` 时即被允许
|
||||
- 可选的发送者 allowlist:`users`(推荐使用稳定 ID)和 `roles`(仅角色 ID);如果配置了任一项,则当发送者匹配 `users` 或 `roles` 时被允许
|
||||
- 直接名称/标签匹配默认禁用;仅在紧急兼容模式下启用 `channels.discord.dangerouslyAllowNameMatching: true`
|
||||
- `users` 支持名称/标签,但 ID 更安全;当使用名称/标签条目时,`openclaw security audit` 会发出警告
|
||||
- 如果某个服务器配置了 `channels`,则未列出的频道会被拒绝
|
||||
- 如果某个服务器没有 `channels` 块,则该允许列表服务器中的所有频道都被允许
|
||||
- 如果某个服务器配置了 `channels`,则未列出的渠道会被拒绝
|
||||
- 如果某个服务器没有 `channels` 块,则该已 allowlist 的服务器中的所有渠道都被允许
|
||||
|
||||
示例:
|
||||
|
||||
@ -450,26 +452,26 @@ OpenClaw 支持为智能体消息使用 Discord components v2 容器。使用消
|
||||
}
|
||||
```
|
||||
|
||||
如果你只设置了 `DISCORD_BOT_TOKEN` 而没有创建 `channels.discord` 块,即使 `channels.defaults.groupPolicy` 是 `open`,运行时回退仍会使用 `groupPolicy="allowlist"`(并在日志中发出警告)。
|
||||
如果你只设置了 `DISCORD_BOT_TOKEN` 而没有创建 `channels.discord` 块,则运行时回退为 `groupPolicy="allowlist"`(日志中会有警告),即使 `channels.defaults.groupPolicy` 是 `open` 也是如此。
|
||||
|
||||
</Tab>
|
||||
|
||||
<Tab title="提及和群组私信">
|
||||
默认情况下,服务器消息需要提及才能触发。
|
||||
默认情况下,服务器消息受提及限制。
|
||||
|
||||
提及检测包括:
|
||||
|
||||
- 显式提及机器人
|
||||
- 已配置的提及模式(`agents.list[].groupChat.mentionPatterns`,回退为 `messages.groupChat.mentionPatterns`)
|
||||
- 在支持场景中的隐式回复机器人行为
|
||||
- 已配置的提及模式(`agents.list[].groupChat.mentionPatterns`,回退到 `messages.groupChat.mentionPatterns`)
|
||||
- 在支持情况下的隐式回复机器人行为
|
||||
|
||||
`requireMention` 按服务器/频道配置(`channels.discord.guilds...`)。
|
||||
`ignoreOtherMentions` 可选择丢弃提及了其他用户/角色但未提及机器人的消息(不包括 @everyone/@here)。
|
||||
`requireMention` 按服务器/渠道配置(`channels.discord.guilds...`)。
|
||||
`ignoreOtherMentions` 可选择性地丢弃提及了其他用户/角色但未提及机器人的消息(不包括 @everyone / @here)。
|
||||
|
||||
群组私信:
|
||||
|
||||
- 默认:忽略(`dm.groupEnabled=false`)
|
||||
- 可选:通过 `dm.groupChannels` 允许列表启用(频道 ID 或 slug)
|
||||
- 可选 allowlist:通过 `dm.groupChannels`(渠道 ID 或 slug)
|
||||
|
||||
</Tab>
|
||||
</Tabs>
|
||||
@ -502,13 +504,13 @@ OpenClaw 支持为智能体消息使用 Discord components v2 容器。使用消
|
||||
|
||||
## 原生命令和命令鉴权
|
||||
|
||||
- `commands.native` 默认值为 `"auto"`,并且对 Discord 已启用。
|
||||
- `commands.native` 默认为 `"auto"`,并且对 Discord 已启用。
|
||||
- 按渠道覆盖:`channels.discord.commands.native`。
|
||||
- `commands.native=false` 会显式清除先前已注册的 Discord 原生命令。
|
||||
- 原生命令鉴权与普通消息处理使用相同的 Discord 允许列表/策略。
|
||||
- 对于未获授权的用户,这些命令仍可能在 Discord UI 中可见;但执行时仍会强制执行 OpenClaw 鉴权,并返回“未授权”。
|
||||
- 原生命令鉴权使用与普通消息处理相同的 Discord allowlist / 策略。
|
||||
- 即使未授权用户仍能在 Discord UI 中看到命令,执行时仍会强制执行 OpenClaw 鉴权,并返回 “not authorized”。
|
||||
|
||||
有关命令目录和行为,请参见 [Slash commands](/zh-CN/tools/slash-commands)。
|
||||
参见 [Slash commands](/zh-CN/tools/slash-commands) 了解命令目录和行为。
|
||||
|
||||
默认斜杠命令设置:
|
||||
|
||||
@ -530,18 +532,18 @@ OpenClaw 支持为智能体消息使用 Discord components v2 容器。使用消
|
||||
- `all`
|
||||
- `batched`
|
||||
|
||||
注意:`off` 会禁用隐式回复线程。显式的 `[[reply_to_*]]` 标签仍会被遵循。
|
||||
`first` 会始终将隐式原生回复引用附加到该轮中的第一条出站 Discord 消息。
|
||||
`batched` 仅在入站轮次是多条消息的去抖批处理时,才附加 Discord 的隐式原生回复引用。这在你只想在突发、容易产生歧义的聊天中主要使用原生回复,而不是在每个单消息轮次中都使用时很有帮助。
|
||||
注意:`off` 会禁用隐式回复线程。显式 `[[reply_to_*]]` 标签仍会被遵循。
|
||||
`first` 会始终将隐式原生回复引用附加到该轮次的第一条 Discord 出站消息。
|
||||
`batched` 仅在入站轮次是多个消息的去抖批处理时,才附加 Discord 的隐式原生回复引用。这在你希望原生回复主要用于有歧义的突发聊天,而不是每一条单消息轮次时很有用。
|
||||
|
||||
消息 ID 会在上下文/历史记录中公开,因此智能体可以定位特定消息。
|
||||
消息 ID 会在上下文/历史中显示,因此智能体可以定位特定消息。
|
||||
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="实时流式预览">
|
||||
OpenClaw 可以通过发送临时消息并在文本到达时持续编辑来流式传输草稿回复。`channels.discord.streaming` 可取 `off`(默认)| `partial` | `block` | `progress`。`progress` 在 Discord 上会映射为 `partial`;`streamMode` 是旧版别名,会自动迁移。
|
||||
OpenClaw 可以通过发送临时消息并在文本到达时编辑它来流式显示草稿回复。`channels.discord.streaming` 支持 `off`(默认)| `partial` | `block` | `progress`。`progress` 在 Discord 上会映射为 `partial`;`streamMode` 是旧别名,并会自动迁移。
|
||||
|
||||
默认值保持为 `off`,因为当多个机器人或 Gateway 网关共享同一账户时,Discord 预览编辑会很快触及速率限制。
|
||||
默认仍为 `off`,因为当多个机器人或 Gateway 网关共享同一账户时,Discord 预览编辑很快会触及速率限制。
|
||||
|
||||
```json5
|
||||
{
|
||||
@ -559,19 +561,19 @@ OpenClaw 支持为智能体消息使用 Discord components v2 容器。使用消
|
||||
```
|
||||
|
||||
- `partial` 会在 token 到达时编辑单条预览消息。
|
||||
- `block` 会输出草稿大小的分块(使用 `draftChunk` 调整大小和断点,受限于 `textChunkLimit`)。
|
||||
- 媒体、错误和显式回复的最终消息会取消待处理的预览编辑。
|
||||
- `block` 会输出草稿大小的分块(使用 `draftChunk` 调整大小和断点,受 `textChunkLimit` 限制)。
|
||||
- 媒体、错误和显式回复的最终消息会取消挂起的预览编辑。
|
||||
- `streaming.preview.toolProgress`(默认 `true`)控制工具/进度更新是否复用预览消息。
|
||||
|
||||
预览流式传输仅支持文本;媒体回复会回退为正常投递。当显式启用分块流式传输时,OpenClaw 会跳过预览流,以避免双重流式传输。
|
||||
预览流式传输仅支持文本;媒体回复会回退为普通投递。当显式启用分块流式传输时,OpenClaw 会跳过预览流,以避免双重流式传输。
|
||||
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="历史记录、上下文和线程行为">
|
||||
<Accordion title="历史、上下文和线程行为">
|
||||
服务器历史上下文:
|
||||
|
||||
- `channels.discord.historyLimit` 默认值为 `20`
|
||||
- 回退值:`messages.groupChat.historyLimit`
|
||||
- 回退:`messages.groupChat.historyLimit`
|
||||
- `0` 表示禁用
|
||||
|
||||
私信历史控制:
|
||||
@ -581,25 +583,25 @@ OpenClaw 支持为智能体消息使用 Discord components v2 容器。使用消
|
||||
|
||||
线程行为:
|
||||
|
||||
- Discord 线程按频道会话进行路由,并继承父频道配置,除非被覆盖。
|
||||
- `channels.discord.thread.inheritParent`(默认 `false`)允许新的自动线程从父级对话记录中播种。按账户的覆盖位于 `channels.discord.accounts.<id>.thread.inheritParent`。
|
||||
- 消息工具反应可以解析 `user:<id>` 私信目标。
|
||||
- Discord 线程按渠道会话路由,并继承父渠道配置,除非被覆盖。
|
||||
- `channels.discord.thread.inheritParent`(默认 `false`)可让新的自动线程选择从父级对话记录播种。按账户的覆盖位于 `channels.discord.accounts.<id>.thread.inheritParent`。
|
||||
- 消息工具的 reaction 可以解析 `user:<id>` 私信目标。
|
||||
- `guilds.<guild>.channels.<channel>.requireMention: false` 会在回复阶段激活回退期间保留。
|
||||
|
||||
频道主题会作为**不受信任**的上下文注入。允许列表控制谁可以触发智能体,而不是完整的补充上下文脱敏边界。
|
||||
渠道主题会作为**不受信任**的上下文注入。allowlist 用于限制谁可以触发智能体,而不是完整的补充上下文脱敏边界。
|
||||
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="子智能体的线程绑定会话">
|
||||
Discord 可以将线程绑定到某个会话目标,这样该线程中的后续消息会持续路由到同一会话(包括子智能体会话)。
|
||||
<Accordion title="用于子智能体的线程绑定会话">
|
||||
Discord 可以将线程绑定到某个会话目标,因此该线程中的后续消息会持续路由到同一个会话(包括子智能体会话)。
|
||||
|
||||
命令:
|
||||
|
||||
- `/focus <target>` 将当前/新线程绑定到子智能体/会话目标
|
||||
- `/unfocus` 移除当前线程绑定
|
||||
- `/agents` 显示活动运行和绑定状态
|
||||
- `/session idle <duration|off>` 检查/更新聚焦绑定的无活动自动取消聚焦设置
|
||||
- `/session max-age <duration|off>` 检查/更新聚焦绑定的硬性最大时长
|
||||
- `/session idle <duration|off>` 查看/更新聚焦绑定的空闲自动取消聚焦设置
|
||||
- `/session max-age <duration|off>` 查看/更新聚焦绑定的硬性最大时长
|
||||
|
||||
配置:
|
||||
|
||||
@ -618,7 +620,7 @@ OpenClaw 支持为智能体消息使用 Discord components v2 容器。使用消
|
||||
enabled: true,
|
||||
idleHours: 24,
|
||||
maxAgeHours: 0,
|
||||
spawnSubagentSessions: false, // 选择启用
|
||||
spawnSubagentSessions: false, // opt-in
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -637,8 +639,8 @@ OpenClaw 支持为智能体消息使用 Discord components v2 容器。使用消
|
||||
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="持久 ACP 频道绑定">
|
||||
对于稳定的“始终在线” ACP 工作区,请配置以 Discord 对话为目标的顶层类型化 ACP 绑定。
|
||||
<Accordion title="持久化 ACP 渠道绑定">
|
||||
对于稳定的“始终在线” ACP 工作区,可配置顶层类型化 ACP 绑定以定位 Discord 对话。
|
||||
|
||||
配置路径:
|
||||
|
||||
@ -694,27 +696,27 @@ OpenClaw 支持为智能体消息使用 Discord components v2 容器。使用消
|
||||
|
||||
说明:
|
||||
|
||||
- `/acp spawn codex --bind here` 会就地绑定当前频道或线程,并让后续消息持续使用同一个 ACP 会话。线程消息会继承父频道绑定。
|
||||
- 在已绑定的频道或线程中,`/new` 和 `/reset` 会就地重置同一个 ACP 会话。临时线程绑定在生效期间可以覆盖目标解析。
|
||||
- 仅当 OpenClaw 需要通过 `--thread auto|here` 创建/绑定子线程时,才需要 `spawnAcpSessions`。
|
||||
- `/acp spawn codex --bind here` 会就地绑定当前渠道或线程,并让后续消息保持在同一个 ACP 会话上。线程消息会继承父渠道绑定。
|
||||
- 在已绑定的渠道或线程中,`/new` 和 `/reset` 会就地重置同一个 ACP 会话。临时线程绑定在激活期间可以覆盖目标解析。
|
||||
- 只有当 OpenClaw 需要通过 `--thread auto|here` 创建/绑定子线程时,才需要 `spawnAcpSessions`。
|
||||
|
||||
有关绑定行为的详细信息,请参见 [ACP Agents](/zh-CN/tools/acp-agents)。
|
||||
参见 [ACP Agents](/zh-CN/tools/acp-agents) 了解绑定行为细节。
|
||||
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="反应通知">
|
||||
按服务器设置的反应通知模式:
|
||||
<Accordion title="Reaction 通知">
|
||||
按服务器设置的 Reaction 通知模式:
|
||||
|
||||
- `off`
|
||||
- `own`(默认)
|
||||
- `all`
|
||||
- `allowlist`(使用 `guilds.<id>.users`)
|
||||
|
||||
反应事件会转换为系统事件,并附加到已路由的 Discord 会话中。
|
||||
Reaction 事件会转换为系统事件,并附加到已路由的 Discord 会话中。
|
||||
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="确认反应">
|
||||
<Accordion title="确认 Reaction">
|
||||
`ackReaction` 会在 OpenClaw 处理入站消息时发送一个确认表情符号。
|
||||
|
||||
解析顺序:
|
||||
@ -722,19 +724,19 @@ OpenClaw 支持为智能体消息使用 Discord components v2 容器。使用消
|
||||
- `channels.discord.accounts.<accountId>.ackReaction`
|
||||
- `channels.discord.ackReaction`
|
||||
- `messages.ackReaction`
|
||||
- 智能体身份 emoji 回退值(`agents.list[].identity.emoji`,否则为 “👀”)
|
||||
- 智能体身份 emoji 回退(`agents.list[].identity.emoji`,否则为 "👀")
|
||||
|
||||
说明:
|
||||
|
||||
- Discord 接受 unicode emoji 或自定义 emoji 名称。
|
||||
- 使用 `""` 可为某个渠道或账户禁用该反应。
|
||||
- 使用 `""` 可为某个渠道或账户禁用该 Reaction。
|
||||
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="配置写入">
|
||||
默认启用由渠道发起的配置写入。
|
||||
|
||||
这会影响 `/config set|unset` 流程(当命令功能启用时)。
|
||||
这会影响 `/config set|unset` 流程(启用命令功能时)。
|
||||
|
||||
禁用:
|
||||
|
||||
@ -751,7 +753,7 @@ OpenClaw 支持为智能体消息使用 Discord components v2 容器。使用消
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="Gateway 网关代理">
|
||||
使用 `channels.discord.proxy` 通过 HTTP(S) 代理路由 Discord Gateway 网关 WebSocket 流量和启动时的 REST 查找(应用 ID + allowlist 解析)。
|
||||
使用 `channels.discord.proxy` 通过 HTTP(S) 代理路由 Discord Gateway 网关 WebSocket 流量以及启动时的 REST 查询(应用 ID + allowlist 解析)。
|
||||
|
||||
```json5
|
||||
{
|
||||
@ -782,7 +784,7 @@ OpenClaw 支持为智能体消息使用 Discord components v2 容器。使用消
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="PluralKit 支持">
|
||||
启用 PluralKit 解析,以将代理消息映射到系统成员身份:
|
||||
启用 PluralKit 解析,将代理消息映射到系统成员身份:
|
||||
|
||||
```json5
|
||||
{
|
||||
@ -790,7 +792,7 @@ OpenClaw 支持为智能体消息使用 Discord components v2 容器。使用消
|
||||
discord: {
|
||||
pluralkit: {
|
||||
enabled: true,
|
||||
token: "pk_live_...", // 可选;私有系统需要
|
||||
token: "pk_live_...", // optional; needed for private systems
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -800,14 +802,14 @@ OpenClaw 支持为智能体消息使用 Discord components v2 容器。使用消
|
||||
说明:
|
||||
|
||||
- allowlist 可以使用 `pk:<memberId>`
|
||||
- 只有当 `channels.discord.dangerouslyAllowNameMatching: true` 时,才会按名称/slug 匹配成员显示名
|
||||
- 查找使用原始消息 ID,并受时间窗口限制
|
||||
- 如果查找失败,代理消息会被视为机器人消息并丢弃,除非 `allowBots=true`
|
||||
- 仅当 `channels.discord.dangerouslyAllowNameMatching: true` 时,才会按名称/slug 匹配成员显示名
|
||||
- 查询使用原始消息 ID,并受时间窗口限制
|
||||
- 如果查询失败,代理消息会被视为机器人消息并丢弃,除非 `allowBots=true`
|
||||
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="在线状态配置">
|
||||
当你设置状态或活动字段,或启用自动在线状态时,会应用在线状态更新。
|
||||
<Accordion title="状态配置">
|
||||
当你设置状态或活动字段,或启用自动状态时,会应用状态更新。
|
||||
|
||||
仅状态示例:
|
||||
|
||||
@ -834,7 +836,7 @@ OpenClaw 支持为智能体消息使用 Discord components v2 容器。使用消
|
||||
}
|
||||
```
|
||||
|
||||
直播示例:
|
||||
Streaming 示例:
|
||||
|
||||
```json5
|
||||
{
|
||||
@ -850,14 +852,14 @@ OpenClaw 支持为智能体消息使用 Discord components v2 容器。使用消
|
||||
|
||||
活动类型映射:
|
||||
|
||||
- 0:Playing
|
||||
- 1:Streaming(需要 `activityUrl`)
|
||||
- 2:Listening
|
||||
- 3:Watching
|
||||
- 4:Custom(使用活动文本作为状态内容;emoji 可选)
|
||||
- 5:Competing
|
||||
- 0: Playing
|
||||
- 1: Streaming(需要 `activityUrl`)
|
||||
- 2: Listening
|
||||
- 3: Watching
|
||||
- 4: Custom(使用活动文本作为状态文本;emoji 可选)
|
||||
- 5: Competing
|
||||
|
||||
自动在线状态示例(运行时健康信号):
|
||||
自动状态示例(运行时健康信号):
|
||||
|
||||
```json5
|
||||
{
|
||||
@ -874,7 +876,7 @@ OpenClaw 支持为智能体消息使用 Discord components v2 容器。使用消
|
||||
}
|
||||
```
|
||||
|
||||
自动在线状态会将运行时可用性映射到 Discord 状态:healthy => online,degraded 或 unknown => idle,exhausted 或 unavailable => dnd。可选文本覆盖:
|
||||
自动状态会将运行时可用性映射为 Discord 状态:healthy => online,degraded 或 unknown => idle,exhausted 或 unavailable => dnd。可选文本覆盖:
|
||||
|
||||
- `autoPresence.healthyText`
|
||||
- `autoPresence.degradedText`
|
||||
@ -883,7 +885,7 @@ OpenClaw 支持为智能体消息使用 Discord components v2 容器。使用消
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="Discord 中的审批">
|
||||
Discord 支持在私信中使用基于按钮的审批处理,并且可以选择在原始频道中发布审批提示。
|
||||
Discord 支持在私信中基于按钮处理审批,并且可以选择在发起渠道中发布审批提示。
|
||||
|
||||
配置路径:
|
||||
|
||||
@ -892,14 +894,14 @@ OpenClaw 支持为智能体消息使用 Discord components v2 容器。使用消
|
||||
- `channels.discord.execApprovals.target`(`dm` | `channel` | `both`,默认:`dm`)
|
||||
- `agentFilter`、`sessionFilter`、`cleanupAfterResolve`
|
||||
|
||||
当 `enabled` 未设置或为 `"auto"`,且至少可以从 `execApprovals.approvers` 或 `commands.ownerAllowFrom` 解析出一个审批人时,Discord 会自动启用原生 exec 审批。Discord 不会从渠道 `allowFrom`、旧版 `dm.allowFrom` 或私信 `defaultTo` 推断 exec 审批人。设置 `enabled: false` 可显式禁用 Discord 作为原生审批客户端。
|
||||
当 `enabled` 未设置或为 `"auto"`,并且至少有一个 approver 可被解析时,Discord 会自动启用原生 exec 审批;这些 approver 可来自 `execApprovals.approvers` 或 `commands.ownerAllowFrom`。Discord 不会从渠道 `allowFrom`、旧版 `dm.allowFrom` 或私信 `defaultTo` 推断 exec approver。设置 `enabled: false` 可显式禁用 Discord 作为原生审批客户端。
|
||||
|
||||
当 `target` 为 `channel` 或 `both` 时,审批提示会显示在频道中。只有已解析出的审批人可以使用这些按钮;其他用户会收到临时拒绝提示。审批提示包含命令文本,因此仅应在受信任频道中启用频道投递。如果无法从会话键派生出频道 ID,OpenClaw 会回退为私信投递。
|
||||
当 `target` 为 `channel` 或 `both` 时,审批提示会显示在渠道中。只有已解析的 approver 可以使用这些按钮;其他用户会收到临时拒绝提示。审批提示包含命令文本,因此仅应在可信渠道中启用渠道投递。如果无法从会话键推导出渠道 ID,OpenClaw 会回退为私信投递。
|
||||
|
||||
Discord 还会渲染其他聊天渠道使用的共享审批按钮。原生 Discord 适配器主要增加了审批人私信路由和频道扇出。
|
||||
当这些按钮存在时,它们就是主要的审批 UX;只有当工具结果表明聊天审批不可用,或手动审批是唯一途径时,OpenClaw 才应包含手动 `/approve` 命令。
|
||||
Discord 也会渲染其他聊天渠道使用的共享审批按钮。原生 Discord 适配器主要增加 approver 私信路由和渠道扇出。
|
||||
当这些按钮存在时,它们就是主要的审批 UX;只有当工具结果表明聊天审批不可用或手动审批是唯一途径时,OpenClaw 才应包含手动 `/approve` 命令。
|
||||
|
||||
Gateway 网关鉴权和审批解析遵循共享的 Gateway 网关客户端契约(`plugin:` ID 通过 `plugin.approval.resolve` 解析;其他 ID 通过 `exec.approval.resolve` 解析)。审批默认会在 30 分钟后过期。
|
||||
Gateway 网关鉴权和审批解析遵循共享的 Gateway 网关客户端契约(`plugin:` ID 通过 `plugin.approval.resolve` 解析;其他 ID 通过 `exec.approval.resolve` 解析)。审批默认在 30 分钟后过期。
|
||||
|
||||
参见 [Exec approvals](/zh-CN/tools/exec-approvals)。
|
||||
|
||||
@ -908,34 +910,34 @@ OpenClaw 支持为智能体消息使用 Discord components v2 容器。使用消
|
||||
|
||||
## 工具和操作门控
|
||||
|
||||
Discord 消息操作包括消息处理、频道管理、审核、在线状态和元数据操作。
|
||||
Discord 消息操作包括消息传递、渠道管理、审核、状态和元数据操作。
|
||||
|
||||
核心示例:
|
||||
|
||||
- 消息处理:`sendMessage`、`readMessages`、`editMessage`、`deleteMessage`、`threadReply`
|
||||
- 反应:`react`、`reactions`、`emojiList`
|
||||
- 消息传递:`sendMessage`、`readMessages`、`editMessage`、`deleteMessage`、`threadReply`
|
||||
- Reaction:`react`、`reactions`、`emojiList`
|
||||
- 审核:`timeout`、`kick`、`ban`
|
||||
- 在线状态:`setPresence`
|
||||
- 状态:`setPresence`
|
||||
|
||||
`event-create` 操作接受一个可选的 `image` 参数(URL 或本地文件路径),用于设置计划事件封面图。
|
||||
`event-create` 操作接受可选的 `image` 参数(URL 或本地文件路径),用于设置计划事件封面图像。
|
||||
|
||||
操作门控位于 `channels.discord.actions.*` 下。
|
||||
|
||||
默认门控行为:
|
||||
|
||||
| 操作组 | 默认值 |
|
||||
| ------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -------- |
|
||||
| reactions, messages, threads, pins, polls, search, memberInfo, roleInfo, channelInfo, channels, voiceStatus, events, stickers, emojiUploads, stickerUploads, permissions | enabled |
|
||||
| roles | disabled |
|
||||
| moderation | disabled |
|
||||
| presence | disabled |
|
||||
| 操作组 | 默认值 |
|
||||
| --- | --- |
|
||||
| reactions, messages, threads, pins, polls, search, memberInfo, roleInfo, channelInfo, channels, voiceStatus, events, stickers, emojiUploads, stickerUploads, permissions | enabled |
|
||||
| roles | disabled |
|
||||
| moderation | disabled |
|
||||
| presence | disabled |
|
||||
|
||||
## Components v2 UI
|
||||
|
||||
OpenClaw 为 exec 审批和跨上下文标记使用 Discord components v2。Discord 消息操作也可以接受 `components` 来构建自定义 UI(高级用法;需要通过 discord 工具构造组件负载),而旧版 `embeds` 仍可用,但不推荐。
|
||||
OpenClaw 对 exec 审批和跨上下文标记使用 Discord components v2。Discord 消息操作也可以接受 `components` 以构建自定义 UI(高级用法;需要通过 discord 工具构造组件载荷),而旧版 `embeds` 仍可用,但不推荐。
|
||||
|
||||
- `channels.discord.ui.components.accentColor` 设置 Discord 组件容器使用的强调色(hex)。
|
||||
- 可通过 `channels.discord.accounts.<id>.ui.components.accentColor` 按账户设置。
|
||||
- 可通过 `channels.discord.accounts.<id>.ui.components.accentColor` 为每个账户单独设置。
|
||||
- 当存在 components v2 时,`embeds` 会被忽略。
|
||||
|
||||
示例:
|
||||
@ -956,17 +958,17 @@ OpenClaw 为 exec 审批和跨上下文标记使用 Discord components v2。Disc
|
||||
|
||||
## 语音
|
||||
|
||||
Discord 有两种不同的语音界面:实时**语音频道**(持续对话)和**语音消息附件**(波形预览格式)。Gateway 网关同时支持这两者。
|
||||
Discord 有两种不同的语音界面:实时**语音渠道**(连续对话)和**语音消息附件**(波形预览格式)。Gateway 网关同时支持这两种。
|
||||
|
||||
### 语音频道
|
||||
### 语音渠道
|
||||
|
||||
要求:
|
||||
|
||||
- 启用原生命令(`commands.native` 或 `channels.discord.commands.native`)。
|
||||
- 配置 `channels.discord.voice`。
|
||||
- 机器人需要在目标语音频道中拥有 Connect 和 Speak 权限。
|
||||
- 机器人在目标语音渠道中需要 Connect 和 Speak 权限。
|
||||
|
||||
使用 `/vc join|leave|status` 控制会话。该命令使用账户默认智能体,并遵循与其他 Discord 命令相同的 allowlist 和 group policy 规则。
|
||||
使用 `/vc join|leave|status` 控制会话。该命令使用账户默认智能体,并遵循与其他 Discord 命令相同的 allowlist 和服务器策略规则。
|
||||
|
||||
自动加入示例:
|
||||
|
||||
@ -996,20 +998,20 @@ Discord 有两种不同的语音界面:实时**语音频道**(持续对话
|
||||
|
||||
说明:
|
||||
|
||||
- `voice.tts` 仅覆盖语音播放的 `messages.tts`。
|
||||
- 语音转录轮次会从 Discord `allowFrom`(或 `dm.allowFrom`)派生所有者状态;非所有者发言者不能访问仅限所有者的工具(例如 `gateway` 和 `cron`)。
|
||||
- `voice.tts` 仅对语音播放覆盖 `messages.tts`。
|
||||
- 语音转录轮次从 Discord `allowFrom`(或 `dm.allowFrom`)派生 owner 状态;非 owner 说话者无法访问仅限 owner 的工具(例如 `gateway` 和 `cron`)。
|
||||
- 语音默认启用;设置 `channels.discord.voice.enabled=false` 可禁用。
|
||||
- `voice.daveEncryption` 和 `voice.decryptionFailureTolerance` 会透传给 `@discordjs/voice` 的加入选项。
|
||||
- `voice.daveEncryption` 和 `voice.decryptionFailureTolerance` 会直通传递给 `@discordjs/voice` 的 join 选项。
|
||||
- 如果未设置,`@discordjs/voice` 的默认值为 `daveEncryption=true` 和 `decryptionFailureTolerance=24`。
|
||||
- OpenClaw 还会监控接收端解密失败,并在短时间内多次失败后,通过离开/重新加入语音频道来自动恢复。
|
||||
- 如果接收日志中反复出现 `DecryptionFailed(UnencryptedWhenPassthroughDisabled)`,这可能是上游 `@discordjs/voice` 接收端 bug,详见 [discord.js #11419](https://github.com/discordjs/discord.js/issues/11419)。
|
||||
- OpenClaw 还会监视接收解密失败,并在短时间内反复失败后通过离开/重新加入语音渠道来自动恢复。
|
||||
- 如果接收日志反复显示 `DecryptionFailed(UnencryptedWhenPassthroughDisabled)`,这可能是上游 `@discordjs/voice` 的接收 bug,见 [discord.js #11419](https://github.com/discordjs/discord.js/issues/11419)。
|
||||
|
||||
### 语音消息
|
||||
|
||||
Discord 语音消息会显示波形预览,并要求使用 OGG/Opus 音频。OpenClaw 会自动生成波形,但需要在 Gateway 网关主机上安装 `ffmpeg` 和 `ffprobe` 以进行检查和转换。
|
||||
Discord 语音消息会显示波形预览,并要求使用 OGG/Opus 音频。OpenClaw 会自动生成波形,但需要在 Gateway 网关主机上提供 `ffmpeg` 和 `ffprobe` 以进行检查和转换。
|
||||
|
||||
- 提供**本地文件路径**(不接受 URL)。
|
||||
- 省略文本内容(Discord 会拒绝同时包含文本和语音消息的负载)。
|
||||
- 省略文本内容(Discord 会拒绝同一载荷中的文本 + 语音消息)。
|
||||
- 接受任意音频格式;OpenClaw 会在需要时将其转换为 OGG/Opus。
|
||||
|
||||
```bash
|
||||
@ -1023,7 +1025,7 @@ message(action="send", channel="discord", target="channel:123", path="/path/to/a
|
||||
|
||||
- 启用 Message Content Intent
|
||||
- 当你依赖用户/成员解析时,启用 Server Members Intent
|
||||
- 修改 intents 后重启 Gateway 网关
|
||||
- 更改 intents 后重启 Gateway 网关
|
||||
|
||||
</Accordion>
|
||||
|
||||
@ -1031,7 +1033,7 @@ message(action="send", channel="discord", target="channel:123", path="/path/to/a
|
||||
|
||||
- 验证 `groupPolicy`
|
||||
- 验证 `channels.discord.guilds` 下的服务器 allowlist
|
||||
- 如果存在服务器 `channels` 映射,则只允许列出的频道
|
||||
- 如果存在服务器 `channels` 映射,则只允许列出的渠道
|
||||
- 验证 `requireMention` 行为和提及模式
|
||||
|
||||
有用的检查:
|
||||
@ -1044,12 +1046,12 @@ openclaw logs --follow
|
||||
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="已设置 requireMention false 但仍被阻止">
|
||||
<Accordion title="已设置 requireMention false 但仍然被阻止">
|
||||
常见原因:
|
||||
|
||||
- `groupPolicy="allowlist"` 但没有匹配的服务器/频道 allowlist
|
||||
- `requireMention` 配置在了错误的位置(必须位于 `channels.discord.guilds` 下或频道条目下)
|
||||
- 发送者被服务器/频道 `users` allowlist 阻止
|
||||
- `groupPolicy="allowlist"`,但没有匹配的服务器/渠道 allowlist
|
||||
- `requireMention` 配置在错误位置(必须位于 `channels.discord.guilds` 或渠道条目下)
|
||||
- 发送者被服务器/渠道 `users` allowlist 阻止
|
||||
|
||||
</Accordion>
|
||||
|
||||
@ -1061,12 +1063,12 @@ openclaw logs --follow
|
||||
- `Slow listener detected ...`
|
||||
- `discord inbound worker timed out after ...`
|
||||
|
||||
监听器预算旋钮:
|
||||
监听器预算控制项:
|
||||
|
||||
- 单账户:`channels.discord.eventQueue.listenerTimeout`
|
||||
- 多账户:`channels.discord.accounts.<accountId>.eventQueue.listenerTimeout`
|
||||
|
||||
Worker 运行超时旋钮:
|
||||
Worker 运行超时控制项:
|
||||
|
||||
- 单账户:`channels.discord.inboundWorker.runTimeoutMs`
|
||||
- 多账户:`channels.discord.accounts.<accountId>.inboundWorker.runTimeoutMs`
|
||||
@ -1093,14 +1095,14 @@ openclaw logs --follow
|
||||
}
|
||||
```
|
||||
|
||||
对于较慢的监听器初始化,使用 `eventQueue.listenerTimeout`;仅当你希望为排队的智能体轮次设置单独的安全阀时,才使用 `inboundWorker.runTimeoutMs`。
|
||||
对于缓慢的监听器设置,请使用 `eventQueue.listenerTimeout`;只有当你希望为排队中的智能体轮次设置单独的安全阀时,才使用 `inboundWorker.runTimeoutMs`。
|
||||
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="权限审计不匹配">
|
||||
`channels status --probe` 权限检查仅对数字频道 ID 有效。
|
||||
`channels status --probe` 的权限检查仅适用于数字渠道 ID。
|
||||
|
||||
如果你使用 slug 键,运行时匹配仍然可以工作,但 probe 无法完整验证权限。
|
||||
如果你使用 slug 键,运行时匹配仍然可以正常工作,但探测无法完整验证权限。
|
||||
|
||||
</Accordion>
|
||||
|
||||
@ -1113,10 +1115,10 @@ openclaw logs --follow
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="机器人对机器人循环">
|
||||
默认情况下,由机器人发布的消息会被忽略。
|
||||
默认情况下,会忽略由机器人发送的消息。
|
||||
|
||||
如果你设置了 `channels.discord.allowBots=true`,请使用严格的提及和 allowlist 规则来避免循环行为。
|
||||
更推荐 `channels.discord.allowBots="mentions"`,这样只接受提及该机器人的机器人消息。
|
||||
如果你设置了 `channels.discord.allowBots=true`,请使用严格的提及和 allowlist 规则以避免循环行为。
|
||||
更推荐使用 `channels.discord.allowBots="mentions"`,仅接受提及该机器人的机器人消息。
|
||||
|
||||
</Accordion>
|
||||
|
||||
@ -1124,18 +1126,18 @@ openclaw logs --follow
|
||||
|
||||
- 保持 OpenClaw 为最新版本(`openclaw update`),以确保包含 Discord 语音接收恢复逻辑
|
||||
- 确认 `channels.discord.voice.daveEncryption=true`(默认值)
|
||||
- 从 `channels.discord.voice.decryptionFailureTolerance=24`(上游默认值)开始,仅在需要时调整
|
||||
- 关注日志中的以下内容:
|
||||
- 从 `channels.discord.voice.decryptionFailureTolerance=24`(上游默认值)开始,仅在需要时再调整
|
||||
- 观察日志中是否出现:
|
||||
- `discord voice: DAVE decrypt failures detected`
|
||||
- `discord voice: repeated decrypt failures; attempting rejoin`
|
||||
- 如果自动重新加入后故障仍然持续,请收集日志并与 [discord.js #11419](https://github.com/discordjs/discord.js/issues/11419) 进行对比
|
||||
- 如果自动重新加入后仍持续失败,请收集日志并与 [discord.js #11419](https://github.com/discordjs/discord.js/issues/11419) 对比
|
||||
|
||||
</Accordion>
|
||||
</AccordionGroup>
|
||||
|
||||
## 配置参考
|
||||
|
||||
主要参考文档:[Configuration reference - Discord](/zh-CN/gateway/config-channels#discord)。
|
||||
主要参考: [Configuration reference - Discord](/zh-CN/gateway/config-channels#discord)。
|
||||
|
||||
<Accordion title="高信号 Discord 字段">
|
||||
|
||||
@ -1146,10 +1148,10 @@ openclaw logs --follow
|
||||
- 入站 worker:`inboundWorker.runTimeoutMs`
|
||||
- 回复/历史:`replyToMode`、`historyLimit`、`dmHistoryLimit`、`dms.*.historyLimit`
|
||||
- 投递:`textChunkLimit`、`chunkMode`、`maxLinesPerMessage`
|
||||
- 流式传输:`streaming`(旧版别名:`streamMode`)、`streaming.preview.toolProgress`、`draftChunk`、`blockStreaming`、`blockStreamingCoalesce`
|
||||
- 媒体/重试:`mediaMaxMb`(限制发往 Discord 的上传大小,默认 `100MB`)、`retry`
|
||||
- 流式传输:`streaming`(旧别名:`streamMode`)、`streaming.preview.toolProgress`、`draftChunk`、`block streaming`、`blockStreamingCoalesce`
|
||||
- 媒体/重试:`mediaMaxMb`(限制 Discord 出站上传,默认 `100MB`)、`retry`
|
||||
- 操作:`actions.*`
|
||||
- 在线状态:`activity`、`status`、`activityType`、`activityUrl`
|
||||
- 状态:`activity`、`status`、`activityType`、`activityUrl`
|
||||
- UI:`ui.components.accentColor`
|
||||
- 功能:`threadBindings`、顶层 `bindings[]`(`type: "acp"`)、`pluralkit`、`execApprovals`、`intents`、`agentComponents`、`heartbeat`、`responsePrefix`
|
||||
|
||||
@ -1158,8 +1160,8 @@ openclaw logs --follow
|
||||
## 安全和运维
|
||||
|
||||
- 将机器人令牌视为密钥(在受监管环境中优先使用 `DISCORD_BOT_TOKEN`)。
|
||||
- 按最小权限原则授予 Discord 权限。
|
||||
- 如果命令部署/状态已过期,请重启 Gateway 网关,并使用 `openclaw channels status --probe` 重新检查。
|
||||
- 授予最小必要的 Discord 权限。
|
||||
- 如果命令部署/状态已过时,请重启 Gateway 网关,并使用 `openclaw channels status --probe` 重新检查。
|
||||
|
||||
## 相关内容
|
||||
|
||||
@ -1174,10 +1176,10 @@ openclaw logs --follow
|
||||
将入站消息路由到智能体。
|
||||
</Card>
|
||||
<Card title="安全" icon="shield" href="/zh-CN/gateway/security">
|
||||
威胁模型与加固。
|
||||
威胁模型和加固。
|
||||
</Card>
|
||||
<Card title="多智能体路由" icon="sitemap" href="/zh-CN/concepts/multi-agent">
|
||||
将服务器和频道映射到智能体。
|
||||
将服务器和渠道映射到智能体。
|
||||
</Card>
|
||||
<Card title="斜杠命令" icon="terminal" href="/zh-CN/tools/slash-commands">
|
||||
原生命令行为。
|
||||
|
||||
@ -1,20 +1,20 @@
|
||||
---
|
||||
read_when:
|
||||
- 设置私信访问控制
|
||||
- 配对新的 iOS/Android 节点
|
||||
- 审查 OpenClaw 的安全态势
|
||||
summary: 配对概览:批准谁可以向你发送私信,以及哪些节点可以加入
|
||||
- 为新的 iOS/Android 节点配对
|
||||
- 审查 OpenClaw 安全态势
|
||||
summary: 配对概览:批准谁可以向你发送私信 + 哪些节点可以加入
|
||||
title: 配对
|
||||
x-i18n:
|
||||
generated_at: "2026-04-23T20:41:52Z"
|
||||
generated_at: "2026-04-25T05:53:12Z"
|
||||
model: gpt-5.4
|
||||
provider: openai
|
||||
source_hash: 373eaa02865995ada0c906df9bad4e8328f085a8bb3679b0a5820dc397130137
|
||||
source_hash: 8f11c992f7cbde12f8c6963279dbaea420941e2fc088179d3fd259e4aa007e34
|
||||
source_path: channels/pairing.md
|
||||
workflow: 15
|
||||
---
|
||||
|
||||
“配对”是 OpenClaw 中明确的**所有者批准**步骤。
|
||||
“配对” 是 OpenClaw 的显式**所有者批准**步骤。
|
||||
它用于两个场景:
|
||||
|
||||
1. **私信配对**(谁被允许与机器人对话)
|
||||
@ -22,19 +22,19 @@ x-i18n:
|
||||
|
||||
安全背景: [Security](/zh-CN/gateway/security)
|
||||
|
||||
## 1)私信配对(入站聊天访问)
|
||||
## 1) 私信配对(入站聊天访问)
|
||||
|
||||
当某个渠道配置了 `pairing` 私信策略时,未知发送者会收到一个短代码,在你批准之前,他们的消息**不会被处理**。
|
||||
当某个渠道配置了私信策略 `pairing` 时,未知发送者会收到一个短代码,并且在你批准之前,他们的消息**不会被处理**。
|
||||
|
||||
默认私信策略文档见: [Security](/zh-CN/gateway/security)
|
||||
默认私信策略记录在: [Security](/zh-CN/gateway/security)
|
||||
|
||||
配对代码:
|
||||
|
||||
- 8 个字符,大写,不含易混淆字符(`0O1I`)。
|
||||
- **1 小时后过期**。机器人只会在创建新请求时发送配对消息(大致为每个发送者每小时一次)。
|
||||
- 默认情况下,待处理的私信配对请求每个渠道最多 **3 个**;在某个请求过期或获批之前,额外请求会被忽略。
|
||||
- 待处理的私信配对请求默认每个渠道最多 **3 个**;在其中一个过期或被批准前,额外请求会被忽略。
|
||||
|
||||
### 批准发送者
|
||||
### 批准一个发送者
|
||||
|
||||
```bash
|
||||
openclaw pairing list telegram
|
||||
@ -45,54 +45,54 @@ openclaw pairing approve telegram <CODE>
|
||||
|
||||
### 状态存储位置
|
||||
|
||||
存储于 `~/.openclaw/credentials/` 下:
|
||||
存储在 `~/.openclaw/credentials/` 下:
|
||||
|
||||
- 待处理请求:`<channel>-pairing.json`
|
||||
- 已批准允许列表存储:
|
||||
- 已批准的允许列表存储:
|
||||
- 默认账户:`<channel>-allowFrom.json`
|
||||
- 非默认账户:`<channel>-<accountId>-allowFrom.json`
|
||||
|
||||
账户作用域行为:
|
||||
|
||||
- 非默认账户只会读取/写入其各自作用域的允许列表文件。
|
||||
- 默认账户使用按渠道划分、无账户作用域的允许列表文件。
|
||||
- 非默认账户只读取/写入其带作用域的允许列表文件。
|
||||
- 默认账户使用按渠道划分但不带账户作用域的允许列表文件。
|
||||
|
||||
请将这些文件视为敏感信息(它们控制对你的助手的访问)。
|
||||
请将这些文件视为敏感信息(它们控制着对你的智能体的访问)。
|
||||
|
||||
重要:此存储仅用于私信访问。群组授权是单独处理的。
|
||||
批准私信配对代码并不会自动允许该发送者在群组中执行命令或控制机器人。对于群组访问,请配置该渠道的显式群组允许列表(例如 `groupAllowFrom`、`groups`,或按渠道而定的每群组/每主题覆盖项)。
|
||||
重要:这个存储仅用于私信访问。群组授权是分开的。
|
||||
批准某个私信配对代码,并不会自动允许该发送者运行群组命令,或在群组中控制机器人。对于群组访问,请配置该渠道的显式群组允许列表(例如 `groupAllowFrom`、`groups`,或按渠道支持的按群组/按话题覆盖配置)。
|
||||
|
||||
## 2)节点设备配对(iOS/Android/macOS/无头节点)
|
||||
## 2) 节点设备配对(iOS/Android/macOS/无头节点)
|
||||
|
||||
节点以 **device** 身份并使用 `role: node` 连接到 Gateway 网关。Gateway 网关会创建设备配对请求,必须经过批准。
|
||||
节点作为**设备**连接到 Gateway 网关,使用 `role: node`。Gateway 网关会创建设备配对请求,必须经过批准。
|
||||
|
||||
### 通过 Telegram 配对(iOS 推荐)
|
||||
### 通过 Telegram 配对(推荐用于 iOS)
|
||||
|
||||
如果你使用 `device-pair` 插件,你可以完全通过 Telegram 完成首次设备配对:
|
||||
|
||||
1. 在 Telegram 中向你的机器人发送:`/pair`
|
||||
2. 机器人会回复两条消息:一条说明消息,以及另一条单独的**设置代码**消息(便于在 Telegram 中复制/粘贴)。
|
||||
3. 在手机上打开 OpenClaw iOS 应用 → Settings → Gateway。
|
||||
1. 在 Telegram 中,向你的机器人发送:`/pair`
|
||||
2. 机器人会回复两条消息:一条说明消息和一条单独的**设置代码**消息(便于在 Telegram 中复制/粘贴)。
|
||||
3. 在你的手机上,打开 OpenClaw iOS 应用 → Settings → Gateway。
|
||||
4. 粘贴设置代码并连接。
|
||||
5. 回到 Telegram:`/pair pending`(查看请求 ID、角色和作用域),然后批准。
|
||||
|
||||
该设置代码是一个 base64 编码的 JSON 载荷,包含:
|
||||
设置代码是一个经过 base64 编码的 JSON 负载,其中包含:
|
||||
|
||||
- `url`:Gateway 网关 WebSocket URL(`ws://...` 或 `wss://...`)
|
||||
- `bootstrapToken`:用于初始配对握手的短期单设备 bootstrap 令牌
|
||||
- `bootstrapToken`:用于初始配对握手的短期单设备引导令牌
|
||||
|
||||
该 bootstrap 令牌带有内置的配对 bootstrap 配置:
|
||||
该引导令牌携带内置的配对引导配置:
|
||||
|
||||
- 主交接的 `node` 令牌保持为 `scopes: []`
|
||||
- 任何交接的 `operator` 令牌都会限制在 bootstrap 允许列表内:
|
||||
- 任何交接的 `operator` 令牌仍限制在引导允许列表内:
|
||||
`operator.approvals`、`operator.read`、`operator.talk.secrets`、`operator.write`
|
||||
- bootstrap 作用域检查采用角色前缀,而不是单一平坦作用域池:
|
||||
operator 作用域条目只满足 operator 请求,而非 operator 角色
|
||||
仍必须在其自身角色前缀下请求作用域
|
||||
- 引导作用域检查按角色前缀进行,而不是使用单一扁平作用域池:
|
||||
operator 作用域条目只满足 operator 请求,非 operator 角色
|
||||
仍必须在它们自己的角色前缀下请求作用域
|
||||
|
||||
在设置代码有效期间,请像对待密码一样保护它。
|
||||
在设置代码有效期间,请像对待密码一样保管它。
|
||||
|
||||
### 批准节点设备
|
||||
### 批准一个节点设备
|
||||
|
||||
```bash
|
||||
openclaw devices list
|
||||
@ -100,31 +100,49 @@ openclaw devices approve <requestId>
|
||||
openclaw devices reject <requestId>
|
||||
```
|
||||
|
||||
如果同一设备使用不同的认证详情重试(例如不同的角色/作用域/公钥),之前的待处理请求会被替代,并创建新的 `requestId`。
|
||||
如果同一设备使用不同的认证详情重试(例如不同的角色/作用域/公钥),之前的待处理请求会被替换,并创建一个新的 `requestId`。
|
||||
|
||||
重要:已配对设备不会悄悄获得更广泛的访问权限。如果它重新连接并请求更多作用域或更高权限的角色,OpenClaw 会保留现有批准状态不变,并创建新的待处理升级请求。在你批准之前,请使用 `openclaw devices list` 比较当前已批准的访问权限与新请求的访问权限。
|
||||
重要:已配对设备不会悄悄获得更广泛的访问权限。如果它重新连接并请求更多作用域或更宽的角色,OpenClaw 会保持现有批准不变,并创建一个新的待处理升级请求。请使用 `openclaw devices list` 比较当前已批准的访问权限与新请求的访问权限,然后再批准。
|
||||
|
||||
### 可选的受信任 CIDR 节点自动批准
|
||||
|
||||
默认情况下,设备配对仍然需要手动操作。对于严格受控的节点网络,你可以选择通过显式 CIDR 或精确 IP,为首次节点连接启用自动批准:
|
||||
|
||||
```json5
|
||||
{
|
||||
gateway: {
|
||||
nodes: {
|
||||
pairing: {
|
||||
autoApproveCidrs: ["192.168.1.0/24"],
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
这仅适用于没有请求任何作用域的全新 `role: node` 配对请求。Operator、浏览器、Control UI 和 WebChat 客户端仍然需要手动批准。角色、作用域、元数据和公钥的变更仍然需要手动批准。
|
||||
|
||||
### 节点配对状态存储
|
||||
|
||||
存储于 `~/.openclaw/devices/` 下:
|
||||
存储在 `~/.openclaw/devices/` 下:
|
||||
|
||||
- `pending.json`(短期;待处理请求会过期)
|
||||
- `paired.json`(已配对设备 + 令牌)
|
||||
|
||||
### 说明
|
||||
|
||||
- 旧版 `node.pair.*` API(CLI:`openclaw nodes pending|approve|reject|rename`)是一个单独的、由 Gateway 网关持有的配对存储。WS 节点仍然需要设备配对。
|
||||
- 配对记录是已批准角色的持久化真实来源。活动设备令牌会继续受限于该已批准角色集合;即使存在超出已批准角色范围的异常令牌条目,也不会产生新的访问权限。
|
||||
- 旧版 `node.pair.*` API(CLI:`openclaw nodes pending|approve|reject|rename`)使用的是一个单独的、由 Gateway 网关拥有的配对存储。WS 节点仍然需要设备配对。
|
||||
- 配对记录是已批准角色的持久化事实来源。活动设备令牌仍受限于该已批准角色集;已批准角色之外的零散令牌条目不会创建新的访问权限。
|
||||
|
||||
## 相关文档
|
||||
|
||||
- 安全模型 + prompt injection: [Security](/zh-CN/gateway/security)
|
||||
- 安全模型 + 提示注入: [Security](/zh-CN/gateway/security)
|
||||
- 安全更新(运行 doctor): [Updating](/zh-CN/install/updating)
|
||||
- 渠道配置:
|
||||
- Telegram: [Telegram](/zh-CN/channels/telegram)
|
||||
- WhatsApp: [WhatsApp](/zh-CN/channels/whatsapp)
|
||||
- Signal: [Signal](/zh-CN/channels/signal)
|
||||
- BlueBubbles(iMessage): [BlueBubbles](/zh-CN/channels/bluebubbles)
|
||||
- iMessage(传统版): [iMessage](/zh-CN/channels/imessage)
|
||||
- iMessage(旧版): [iMessage](/zh-CN/channels/imessage)
|
||||
- Discord: [Discord](/zh-CN/channels/discord)
|
||||
- Slack: [Slack](/zh-CN/channels/slack)
|
||||
|
||||
@ -1,14 +1,14 @@
|
||||
---
|
||||
read_when:
|
||||
- 设置 Signal 支持
|
||||
- 调试 Signal 发送/接收
|
||||
summary: 通过 `signal-cli` 提供 Signal 支持(JSON-RPC + SSE)、设置路径和号码模型
|
||||
- 调试 Signal 的发送/接收
|
||||
summary: 通过 `signal-cli`(JSON-RPC + SSE)提供的 Signal 支持、设置路径,以及号码模型
|
||||
title: Signal
|
||||
x-i18n:
|
||||
generated_at: "2026-04-24T18:07:28Z"
|
||||
generated_at: "2026-04-25T05:53:13Z"
|
||||
model: gpt-5.4
|
||||
provider: openai
|
||||
source_hash: bc755f905af6c79903742e2ccdcc088666038dc78e36150f3f214e9c3245ad50
|
||||
source_hash: cb1ff4328aae73576a78b00be3dd79e9768badfc6193843ed3c05439765ae295
|
||||
source_path: channels/signal.md
|
||||
workflow: 15
|
||||
---
|
||||
@ -18,16 +18,16 @@ x-i18n:
|
||||
## 前提条件
|
||||
|
||||
- 你的服务器上已安装 OpenClaw(下方 Linux 流程已在 Ubuntu 24 上测试)。
|
||||
- Gateway 网关运行所在主机上可用 `signal-cli`。
|
||||
- 一个可以接收一次验证短信的手机号(用于短信注册路径)。
|
||||
- 注册期间可通过浏览器访问 Signal 验证码页面(`signalcaptchas.org`)。
|
||||
- 运行 Gateway 网关的主机上可用 `signal-cli`。
|
||||
- 一个可以接收一次验证码短信的电话号码(用于短信注册路径)。
|
||||
- 注册期间可访问 Signal 验证码页面(`signalcaptchas.org`)的浏览器。
|
||||
|
||||
## 快速设置(新手)
|
||||
## 快速设置(初学者)
|
||||
|
||||
1. 为机器人使用一个**单独的 Signal 号码**(推荐)。
|
||||
2. 安装 `signal-cli`(如果你使用 JVM 构建版本,则需要 Java)。
|
||||
3. 选择一种设置路径:
|
||||
- **路径 A(QR 链接):** `signal-cli link -n "OpenClaw"`,然后用 Signal 扫码。
|
||||
- **路径 A(QR 链接):** `signal-cli link -n "OpenClaw"`,然后用 Signal 扫描。
|
||||
- **路径 B(短信注册):** 使用验证码 + 短信验证注册一个专用号码。
|
||||
4. 配置 OpenClaw 并重启 Gateway 网关。
|
||||
5. 发送第一条私信并批准配对(`openclaw pairing approve signal <CODE>`)。
|
||||
@ -50,10 +50,10 @@ x-i18n:
|
||||
|
||||
字段说明:
|
||||
|
||||
| 字段 | 描述 |
|
||||
| 字段 | 说明 |
|
||||
| ----------- | ------------------------------------------------- |
|
||||
| `account` | 机器人电话号码,使用 E.164 格式(`+15551234567`) |
|
||||
| `cliPath` | `signal-cli` 的路径(如果在 `PATH` 中则为 `signal-cli`) |
|
||||
| `account` | 机器人电话号码,采用 E.164 格式(`+15551234567`) |
|
||||
| `cliPath` | `signal-cli` 的路径(如果在 `PATH` 中则写 `signal-cli`) |
|
||||
| `dmPolicy` | 私信访问策略(推荐使用 `pairing`) |
|
||||
| `allowFrom` | 允许发送私信的电话号码或 `uuid:<id>` 值 |
|
||||
|
||||
@ -79,13 +79,13 @@ x-i18n:
|
||||
|
||||
- Gateway 网关连接到一个 **Signal 设备**(即 `signal-cli` 账户)。
|
||||
- 如果你在**自己的个人 Signal 账户**上运行机器人,它会忽略你自己发送的消息(循环保护)。
|
||||
- 如果你想实现“我给机器人发消息,它会回复我”,请使用**单独的机器人号码**。
|
||||
- 如果你想要“我给机器人发消息,它再回复我”,请使用一个**单独的机器人号码**。
|
||||
|
||||
## 设置路径 A:链接现有 Signal 账户(QR)
|
||||
|
||||
1. 安装 `signal-cli`(JVM 或原生构建版本)。
|
||||
2. 链接一个机器人账户:
|
||||
- 运行 `signal-cli link -n "OpenClaw"`,然后在 Signal 中扫描二维码。
|
||||
- `signal-cli link -n "OpenClaw"`,然后在 Signal 中扫描 QR 码。
|
||||
3. 配置 Signal 并启动 Gateway 网关。
|
||||
|
||||
示例:
|
||||
@ -104,13 +104,13 @@ x-i18n:
|
||||
}
|
||||
```
|
||||
|
||||
多账户支持:使用 `channels.signal.accounts` 配合每个账户的配置和可选的 `name`。共享模式见 [`gateway/configuration`](/zh-CN/gateway/config-channels#multi-account-all-channels)。
|
||||
多账户支持:使用 `channels.signal.accounts` 配合每个账户的独立配置,以及可选的 `name`。共享模式请参见 [`gateway/configuration`](/zh-CN/gateway/config-channels#multi-account-all-channels)。
|
||||
|
||||
## 设置路径 B:注册专用机器人号码(短信,Linux)
|
||||
|
||||
当你想使用专用机器人号码,而不是链接现有 Signal 应用账户时,请使用此方式。
|
||||
|
||||
1. 获取一个可以接收短信的号码(座机可使用语音验证)。
|
||||
1. 获取一个可以接收短信的号码(或座机语音验证号码)。
|
||||
- 使用专用机器人号码以避免账户/会话冲突。
|
||||
2. 在 Gateway 网关主机上安装 `signal-cli`:
|
||||
|
||||
@ -134,19 +134,19 @@ signal-cli -a +<BOT_PHONE_NUMBER> register
|
||||
如果需要验证码:
|
||||
|
||||
1. 打开 `https://signalcaptchas.org/registration/generate.html`。
|
||||
2. 完成验证码后,从 “Open Signal” 中复制 `signalcaptcha://...` 链接目标。
|
||||
3. 尽量从与浏览器会话相同的外部 IP 运行以下命令。
|
||||
4. 立即再次运行注册(验证码令牌很快会过期):
|
||||
2. 完成验证码,并从“Open Signal”复制 `signalcaptcha://...` 链接目标。
|
||||
3. 尽量使用与浏览器会话相同的外部 IP 重新执行命令。
|
||||
4. 立即再次运行注册(验证码令牌过期很快):
|
||||
|
||||
```bash
|
||||
signal-cli -a +<BOT_PHONE_NUMBER> register --captcha '<SIGNALCAPTCHA_URL>'
|
||||
signal-cli -a +<BOT_PHONE_NUMBER> verify <VERIFICATION_CODE>
|
||||
```
|
||||
|
||||
4. 配置 OpenClaw、重启 Gateway 网关并验证渠道:
|
||||
4. 配置 OpenClaw,重启 Gateway 网关,并验证渠道:
|
||||
|
||||
```bash
|
||||
# 如果你将 Gateway 网关作为用户级 systemd 服务运行:
|
||||
# 如果你以用户级 systemd 服务运行 Gateway 网关:
|
||||
systemctl --user restart openclaw-gateway.service
|
||||
|
||||
# 然后验证:
|
||||
@ -157,9 +157,9 @@ openclaw channels status --probe
|
||||
5. 配对你的私信发送者:
|
||||
- 向机器人号码发送任意消息。
|
||||
- 在服务器上批准代码:`openclaw pairing approve signal <PAIRING_CODE>`。
|
||||
- 在你的手机上将机器人号码保存为联系人,以避免显示为 “未知联系人”。
|
||||
- 将机器人号码保存为你手机中的联系人,以避免显示“Unknown contact”。
|
||||
|
||||
重要:使用 `signal-cli` 注册一个电话号码账户,可能会使该号码对应的主 Signal 应用会话失去授权。建议优先使用专用机器人号码;如果你需要保留现有手机应用设置,请使用 QR 链接模式。
|
||||
重要:使用 `signal-cli` 注册一个电话号码账户,可能会使该号码在主 Signal 应用中的会话失去认证。优先使用专用机器人号码,或者如果你需要保留现有手机应用设置,请使用 QR 链接模式。
|
||||
|
||||
上游参考:
|
||||
|
||||
@ -169,7 +169,7 @@ openclaw channels status --probe
|
||||
|
||||
## 外部守护进程模式(httpUrl)
|
||||
|
||||
如果你希望自行管理 `signal-cli`(例如 JVM 冷启动慢、容器初始化或共享 CPU),可以单独运行守护进程,并让 OpenClaw 指向它:
|
||||
如果你想自己管理 `signal-cli`(例如 JVM 冷启动较慢、容器初始化,或共享 CPU 的情况),可以单独运行守护进程,并让 OpenClaw 指向它:
|
||||
|
||||
```json5
|
||||
{
|
||||
@ -182,27 +182,27 @@ openclaw channels status --probe
|
||||
}
|
||||
```
|
||||
|
||||
这会跳过 OpenClaw 内部的自动拉起和启动等待。对于自动拉起时启动较慢的情况,可设置 `channels.signal.startupTimeoutMs`。
|
||||
这会跳过 OpenClaw 内部的自动启动和启动等待。对于自动启动但启动较慢的情况,可设置 `channels.signal.startupTimeoutMs`。
|
||||
|
||||
## 访问控制(私信 + 群组)
|
||||
|
||||
私信:
|
||||
|
||||
- 默认值:`channels.signal.dmPolicy = "pairing"`。
|
||||
- 未知发送者会收到一个配对代码;在批准前,其消息会被忽略(代码 1 小时后过期)。
|
||||
- 未知发送者会收到一个配对码;在批准之前,消息会被忽略(代码 1 小时后过期)。
|
||||
- 批准方式:
|
||||
- `openclaw pairing list signal`
|
||||
- `openclaw pairing approve signal <CODE>`
|
||||
- 配对是 Signal 私信的默认令牌交换方式。详情见:[Pairing](/zh-CN/channels/pairing)
|
||||
- 仅 UUID 发送者(来自 `sourceUuid`)会以 `uuid:<id>` 形式存储在 `channels.signal.allowFrom` 中。
|
||||
- 配对是 Signal 私信的默认令牌交换方式。详情见:[配对](/zh-CN/channels/pairing)
|
||||
- 仅 UUID 的发送者(来自 `sourceUuid`)会以 `uuid:<id>` 的形式存储在 `channels.signal.allowFrom` 中。
|
||||
|
||||
群组:
|
||||
|
||||
- `channels.signal.groupPolicy = open | allowlist | disabled`。
|
||||
- 当设置为 `allowlist` 时,`channels.signal.groupAllowFrom` 控制哪些人可以在群组中触发。
|
||||
- `channels.signal.groups["<group-id>" | "*"]` 可通过 `requireMention`、`tools` 和 `toolsBySender` 覆盖群组行为。
|
||||
- 在多账户设置中,使用 `channels.signal.accounts.<id>.groups` 进行按账户覆盖。
|
||||
- 运行时说明:如果完全缺少 `channels.signal`,运行时在进行群组检查时会回退到 `groupPolicy="allowlist"`(即使设置了 `channels.defaults.groupPolicy` 也是如此)。
|
||||
- `channels.signal.groups["<group-id>" | "*"]` 可以使用 `requireMention`、`tools` 和 `toolsBySender` 覆盖群组行为。
|
||||
- 在多账户设置中,使用 `channels.signal.accounts.<id>.groups` 进行每个账户的独立覆盖。
|
||||
- 运行时说明:如果完全缺少 `channels.signal`,运行时在执行群组检查时会回退为 `groupPolicy="allowlist"`(即使设置了 `channels.defaults.groupPolicy` 也是如此)。
|
||||
|
||||
## 工作原理(行为)
|
||||
|
||||
@ -213,24 +213,25 @@ openclaw channels status --probe
|
||||
## 媒体 + 限制
|
||||
|
||||
- 出站文本会按 `channels.signal.textChunkLimit` 分块(默认 4000)。
|
||||
- 可选换行分块:设置 `channels.signal.chunkMode="newline"`,以便在按长度分块前先按空行(段落边界)拆分。
|
||||
- 可选换行分块:设置 `channels.signal.chunkMode="newline"`,先按空行(段落边界)拆分,再按长度分块。
|
||||
- 支持附件(从 `signal-cli` 获取 base64)。
|
||||
- 默认媒体大小上限:`channels.signal.mediaMaxMb`(默认 8)。
|
||||
- 语音便笺附件在缺少 `contentType` 时,会使用 `signal-cli` 的文件名作为 MIME 回退,因此音频转写仍可识别 AAC 语音备忘录。
|
||||
- 默认媒体上限:`channels.signal.mediaMaxMb`(默认 8)。
|
||||
- 使用 `channels.signal.ignoreAttachments` 可跳过媒体下载。
|
||||
- 群组历史上下文使用 `channels.signal.historyLimit`(或 `channels.signal.accounts.*.historyLimit`),并回退到 `messages.groupChat.historyLimit`。设置为 `0` 可禁用(默认 50)。
|
||||
- 群组历史上下文使用 `channels.signal.historyLimit`(或 `channels.signal.accounts.*.historyLimit`),并回退到 `messages.groupChat.historyLimit`。设为 `0` 可禁用(默认 50)。
|
||||
|
||||
## 正在输入 + 已读回执
|
||||
|
||||
- **输入指示器**:OpenClaw 通过 `signal-cli sendTyping` 发送输入状态,并在回复运行期间持续刷新。
|
||||
- **已读回执**:当 `channels.signal.sendReadReceipts` 为 true 时,OpenClaw 会为已允许的私信转发已读回执。
|
||||
- **正在输入指示器**:OpenClaw 通过 `signal-cli sendTyping` 发送正在输入信号,并在回复执行期间持续刷新。
|
||||
- **已读回执**:当 `channels.signal.sendReadReceipts` 为 true 时,OpenClaw 会为允许的私信转发已读回执。
|
||||
- Signal-cli 不提供群组的已读回执。
|
||||
|
||||
## 反应(message 工具)
|
||||
## 表情回应(消息工具)
|
||||
|
||||
- 使用 `message action=react` 并设置 `channel=signal`。
|
||||
- 使用 `message action=react`,并设置 `channel=signal`。
|
||||
- 目标:发送者 E.164 或 UUID(使用配对输出中的 `uuid:<id>`;裸 UUID 也可以)。
|
||||
- `messageId` 是你要反应的那条消息的 Signal 时间戳。
|
||||
- 群组反应需要 `targetAuthor` 或 `targetAuthorUuid`。
|
||||
- `messageId` 是你要回应的那条消息的 Signal 时间戳。
|
||||
- 群组回应需要 `targetAuthor` 或 `targetAuthorUuid`。
|
||||
|
||||
示例:
|
||||
|
||||
@ -242,11 +243,11 @@ message action=react channel=signal target=signal:group:<groupId> targetAuthor=u
|
||||
|
||||
配置:
|
||||
|
||||
- `channels.signal.actions.reactions`:启用/禁用反应操作(默认 true)。
|
||||
- `channels.signal.actions.reactions`:启用/禁用回应操作(默认 true)。
|
||||
- `channels.signal.reactionLevel`:`off | ack | minimal | extensive`。
|
||||
- `off`/`ack` 会禁用智能体反应(message 工具中的 `react` 将报错)。
|
||||
- `minimal`/`extensive` 会启用智能体反应,并设置指导级别。
|
||||
- 按账户覆盖:`channels.signal.accounts.<id>.actions.reactions`、`channels.signal.accounts.<id>.reactionLevel`。
|
||||
- `off`/`ack` 会禁用智能体回应(消息工具 `react` 会报错)。
|
||||
- `minimal`/`extensive` 会启用智能体回应,并设置指导级别。
|
||||
- 每账户覆盖:`channels.signal.accounts.<id>.actions.reactions`、`channels.signal.accounts.<id>.reactionLevel`。
|
||||
|
||||
## 投递目标(CLI/cron)
|
||||
|
||||
@ -257,7 +258,7 @@ message action=react channel=signal target=signal:group:<groupId> targetAuthor=u
|
||||
|
||||
## 故障排除
|
||||
|
||||
先运行以下阶梯检查:
|
||||
先运行这一组检查步骤:
|
||||
|
||||
```bash
|
||||
openclaw status
|
||||
@ -267,7 +268,7 @@ openclaw doctor
|
||||
openclaw channels status --probe
|
||||
```
|
||||
|
||||
然后根据需要确认私信配对状态:
|
||||
然后在需要时确认私信配对状态:
|
||||
|
||||
```bash
|
||||
openclaw pairing list signal
|
||||
@ -275,10 +276,10 @@ openclaw pairing list signal
|
||||
|
||||
常见故障:
|
||||
|
||||
- 守护进程可访问但没有回复:检查账户/守护进程设置(`httpUrl`、`account`)和接收模式。
|
||||
- 私信被忽略:发送者仍在等待配对批准。
|
||||
- 守护进程可访问但没有回复:验证账户/守护进程设置(`httpUrl`、`account`)以及接收模式。
|
||||
- 私信被忽略:发送者正在等待配对批准。
|
||||
- 群组消息被忽略:群组发送者/提及门控阻止了投递。
|
||||
- 编辑后出现配置验证错误:运行 `openclaw doctor --fix`。
|
||||
- 编辑后出现配置校验错误:运行 `openclaw doctor --fix`。
|
||||
- 诊断中缺少 Signal:确认 `channels.signal.enabled: true`。
|
||||
|
||||
额外检查:
|
||||
@ -289,18 +290,18 @@ pgrep -af signal-cli
|
||||
grep -i "signal" "/tmp/openclaw/openclaw-$(date +%Y-%m-%d).log" | tail -20
|
||||
```
|
||||
|
||||
排查流程见:[/channels/troubleshooting](/zh-CN/channels/troubleshooting)。
|
||||
排查流程请见:[/channels/troubleshooting](/zh-CN/channels/troubleshooting)。
|
||||
|
||||
## 安全说明
|
||||
|
||||
- `signal-cli` 会在本地存储账户密钥(通常位于 `~/.local/share/signal-cli/data/`)。
|
||||
- 在服务器迁移或重建前,请备份 Signal 账户状态。
|
||||
- 除非你明确希望开放更广泛的私信访问,否则请保持 `channels.signal.dmPolicy: "pairing"`。
|
||||
- 短信验证只在注册或恢复流程中需要,但如果失去对该号码/账户的控制,重新注册会变得更复杂。
|
||||
- 除非你明确希望更广泛的私信访问,否则请保持 `channels.signal.dmPolicy: "pairing"`。
|
||||
- 短信验证仅在注册或恢复流程中需要,但如果失去对号码/账户的控制,重新注册会变得复杂。
|
||||
|
||||
## 配置参考(Signal)
|
||||
|
||||
完整配置:[Configuration](/zh-CN/gateway/configuration)
|
||||
完整配置:[配置](/zh-CN/gateway/configuration)
|
||||
|
||||
提供商选项:
|
||||
|
||||
@ -309,23 +310,23 @@ grep -i "signal" "/tmp/openclaw/openclaw-$(date +%Y-%m-%d).log" | tail -20
|
||||
- `channels.signal.cliPath`:`signal-cli` 的路径。
|
||||
- `channels.signal.httpUrl`:完整的守护进程 URL(覆盖 host/port)。
|
||||
- `channels.signal.httpHost`、`channels.signal.httpPort`:守护进程绑定地址(默认 `127.0.0.1:8080`)。
|
||||
- `channels.signal.autoStart`:自动拉起守护进程(当未设置 `httpUrl` 时,默认值为 true)。
|
||||
- `channels.signal.startupTimeoutMs`:启动等待超时(毫秒,最大 120000)。
|
||||
- `channels.signal.autoStart`:自动启动守护进程(如果未设置 `httpUrl`,默认 true)。
|
||||
- `channels.signal.startupTimeoutMs`:启动等待超时时间,单位为毫秒(上限 120000)。
|
||||
- `channels.signal.receiveMode`:`on-start | manual`。
|
||||
- `channels.signal.ignoreAttachments`:跳过附件下载。
|
||||
- `channels.signal.ignoreStories`:忽略来自守护进程的动态消息。
|
||||
- `channels.signal.ignoreStories`:忽略来自守护进程的动态。
|
||||
- `channels.signal.sendReadReceipts`:转发已读回执。
|
||||
- `channels.signal.dmPolicy`:`pairing | allowlist | open | disabled`(默认:pairing)。
|
||||
- `channels.signal.allowFrom`:私信允许名单(E.164 或 `uuid:<id>`)。`open` 需要 `"*"`。Signal 不支持用户名;请使用电话号码/UUID 标识。
|
||||
- `channels.signal.allowFrom`:私信允许列表(E.164 或 `uuid:<id>`)。`open` 需要 `"*"`。Signal 不支持用户名;请使用电话号码/UUID 标识。
|
||||
- `channels.signal.groupPolicy`:`open | allowlist | disabled`(默认:allowlist)。
|
||||
- `channels.signal.groupAllowFrom`:群组发送者允许名单。
|
||||
- `channels.signal.groups`:按群组覆盖,键为 Signal 群组 id(或 `"*"`)。支持的字段:`requireMention`、`tools`、`toolsBySender`。
|
||||
- `channels.signal.accounts.<id>.groups`:多账户设置中 `channels.signal.groups` 的按账户版本。
|
||||
- `channels.signal.historyLimit`:作为上下文包含的最大群组消息数(`0` 表示禁用)。
|
||||
- `channels.signal.dmHistoryLimit`:以用户轮次计的私信历史上限。按用户覆盖:`channels.signal.dms["<phone_or_uuid>"].historyLimit`。
|
||||
- `channels.signal.groupAllowFrom`:群组发送者允许列表。
|
||||
- `channels.signal.groups`:按 Signal 群组 id(或 `"*"`)键控的每群组覆盖。支持的字段:`requireMention`、`tools`、`toolsBySender`。
|
||||
- `channels.signal.accounts.<id>.groups`:用于多账户设置的 `channels.signal.groups` 每账户版本。
|
||||
- `channels.signal.historyLimit`:作为上下文包含的最大群组消息数(0 表示禁用)。
|
||||
- `channels.signal.dmHistoryLimit`:以用户轮次计的私信历史记录上限。每用户覆盖:`channels.signal.dms["<phone_or_uuid>"].historyLimit`。
|
||||
- `channels.signal.textChunkLimit`:出站分块大小(字符数)。
|
||||
- `channels.signal.chunkMode`:`length`(默认)或 `newline`,表示在按长度分块前先按空行(段落边界)拆分。
|
||||
- `channels.signal.mediaMaxMb`:入站/出站媒体大小上限(MB)。
|
||||
- `channels.signal.chunkMode`:`length`(默认)或 `newline`,先按空行(段落边界)拆分,再按长度分块。
|
||||
- `channels.signal.mediaMaxMb`:入站/出站媒体上限(MB)。
|
||||
|
||||
相关全局选项:
|
||||
|
||||
@ -335,8 +336,8 @@ grep -i "signal" "/tmp/openclaw/openclaw-$(date +%Y-%m-%d).log" | tail -20
|
||||
|
||||
## 相关内容
|
||||
|
||||
- [渠道概览](/zh-CN/channels) —— 所有受支持的渠道
|
||||
- [Pairing](/zh-CN/channels/pairing) —— 私信认证与配对流程
|
||||
- [群组](/zh-CN/channels/groups) —— 群聊行为与提及门控
|
||||
- [渠道路由](/zh-CN/channels/channel-routing) —— 消息的会话路由
|
||||
- [安全](/zh-CN/gateway/security) —— 访问模型与加固措施
|
||||
- [渠道概览](/zh-CN/channels) — 所有支持的渠道
|
||||
- [配对](/zh-CN/channels/pairing) — 私信身份验证与配对流程
|
||||
- [群组](/zh-CN/channels/groups) — 群聊行为与提及门控
|
||||
- [渠道路由](/zh-CN/channels/channel-routing) — 消息的会话路由
|
||||
- [安全](/zh-CN/gateway/security) — 访问模型与加固措施
|
||||
|
||||
@ -1,27 +1,26 @@
|
||||
---
|
||||
read_when:
|
||||
- 处理 WhatsApp/web 渠道行为或收件箱路由
|
||||
summary: WhatsApp 渠道支持、访问控制、传递行为和运维
|
||||
summary: WhatsApp 渠道支持、访问控制、投递行为和运维
|
||||
title: WhatsApp
|
||||
x-i18n:
|
||||
generated_at: "2026-04-25T00:40:15Z"
|
||||
generated_at: "2026-04-25T05:53:10Z"
|
||||
model: gpt-5.4
|
||||
provider: openai
|
||||
source_hash: d35888ce536d82d52a94c369e85af77447435a09092226fc3317e11edb1f5c71
|
||||
source_hash: 9510b013f19c0ff4cd8376b7a3d0eca7466cf6ef17255349ccc729fe919911a0
|
||||
source_path: channels/whatsapp.md
|
||||
workflow: 15
|
||||
---
|
||||
|
||||
状态:通过 WhatsApp Web(Baileys)达到生产就绪。Gateway 网关负责已关联的会话。
|
||||
Status:通过 WhatsApp Web(Baileys)已达到生产可用。Gateway 网关负责已链接的会话。
|
||||
|
||||
## 安装(按需)
|
||||
|
||||
- 新手引导(`openclaw onboard`)和 `openclaw channels add --channel whatsapp`
|
||||
会在你首次选择它时提示安装 WhatsApp 插件。
|
||||
- `openclaw channels login --channel whatsapp` 也会在
|
||||
插件尚未安装时提供安装流程。
|
||||
会在你第一次选择时提示安装 WhatsApp 插件。
|
||||
- 当插件尚未安装时,`openclaw channels login --channel whatsapp` 也会提供安装流程。
|
||||
- 开发渠道 + git 检出:默认使用本地插件路径。
|
||||
- 稳定版 / Beta:默认使用 npm 包 `@openclaw/whatsapp`。
|
||||
- Stable/Beta:默认使用 npm 包 `@openclaw/whatsapp`。
|
||||
|
||||
仍然支持手动安装:
|
||||
|
||||
@ -31,7 +30,7 @@ openclaw plugins install @openclaw/whatsapp
|
||||
|
||||
<CardGroup cols={3}>
|
||||
<Card title="配对" icon="link" href="/zh-CN/channels/pairing">
|
||||
对未知发送者的默认私信策略是配对。
|
||||
未知发送者的默认私信策略是配对。
|
||||
</Card>
|
||||
<Card title="渠道故障排除" icon="wrench" href="/zh-CN/channels/troubleshooting">
|
||||
跨渠道诊断和修复操作手册。
|
||||
@ -61,7 +60,7 @@ openclaw plugins install @openclaw/whatsapp
|
||||
|
||||
</Step>
|
||||
|
||||
<Step title="关联 WhatsApp(QR 码)">
|
||||
<Step title="链接 WhatsApp(QR 码)">
|
||||
|
||||
```bash
|
||||
openclaw channels login --channel whatsapp
|
||||
@ -73,7 +72,7 @@ openclaw channels login --channel whatsapp
|
||||
openclaw channels login --channel whatsapp --account work
|
||||
```
|
||||
|
||||
若要在登录前附加一个现有 / 自定义的 WhatsApp Web 认证目录:
|
||||
要在登录前附加现有/自定义的 WhatsApp Web 认证目录:
|
||||
|
||||
```bash
|
||||
openclaw channels add --channel whatsapp --account work --auth-dir /path/to/wa-auth
|
||||
@ -82,7 +81,7 @@ openclaw channels login --channel whatsapp --account work
|
||||
|
||||
</Step>
|
||||
|
||||
<Step title="启动 Gateway 网关">
|
||||
<Step title="启动网关">
|
||||
|
||||
```bash
|
||||
openclaw gateway
|
||||
@ -97,13 +96,13 @@ openclaw pairing list whatsapp
|
||||
openclaw pairing approve whatsapp <CODE>
|
||||
```
|
||||
|
||||
配对请求会在 1 小时后过期。每个渠道的待处理请求上限为 3 个。
|
||||
配对请求会在 1 小时后过期。每个渠道最多保留 3 个待处理请求。
|
||||
|
||||
</Step>
|
||||
</Steps>
|
||||
|
||||
<Note>
|
||||
OpenClaw 建议尽可能为 WhatsApp 使用一个单独的号码。(渠道元数据和设置流程已针对这种设置进行优化,但也支持个人号码设置。)
|
||||
OpenClaw 建议尽可能为 WhatsApp 使用单独的号码。(渠道元数据和设置流程针对这种方式做了优化,但也支持个人号码配置。)
|
||||
</Note>
|
||||
|
||||
## 部署模式
|
||||
@ -113,7 +112,7 @@ OpenClaw 建议尽可能为 WhatsApp 使用一个单独的号码。(渠道元
|
||||
这是最简洁的运维模式:
|
||||
|
||||
- 为 OpenClaw 使用单独的 WhatsApp 身份
|
||||
- 更清晰的私信允许列表和路由边界
|
||||
- 更清晰的私信允许名单和路由边界
|
||||
- 更低的自聊混淆概率
|
||||
|
||||
最小策略模式:
|
||||
@ -132,17 +131,17 @@ OpenClaw 建议尽可能为 WhatsApp 使用一个单独的号码。(渠道元
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="个人号码回退方案">
|
||||
新手引导支持个人号码模式,并会写入一个对自聊友好的基础配置:
|
||||
新手引导支持个人号码模式,并会写入适合自聊的基础配置:
|
||||
|
||||
- `dmPolicy: "allowlist"`
|
||||
- `allowFrom` 包含你的个人号码
|
||||
- `selfChatMode: true`
|
||||
|
||||
在运行时,自聊保护会基于已关联的自身号码和 `allowFrom` 生效。
|
||||
在运行时,自聊保护依赖已链接的自身号码和 `allowFrom`。
|
||||
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="仅 WhatsApp Web 的渠道范围">
|
||||
<Accordion title="仅限 WhatsApp Web 的渠道范围">
|
||||
在当前 OpenClaw 渠道架构中,消息平台渠道基于 WhatsApp Web(`Baileys`)。
|
||||
|
||||
内置聊天渠道注册表中没有单独的 Twilio WhatsApp 消息渠道。
|
||||
@ -153,18 +152,17 @@ OpenClaw 建议尽可能为 WhatsApp 使用一个单独的号码。(渠道元
|
||||
## 运行时模型
|
||||
|
||||
- Gateway 网关负责 WhatsApp socket 和重连循环。
|
||||
- 出站发送要求目标账户存在一个活动的 WhatsApp 监听器。
|
||||
- 状态和广播聊天会被忽略(`@status`、`@broadcast`)。
|
||||
- 出站发送要求目标账户存在活动中的 WhatsApp 监听器。
|
||||
- Status 和广播聊天会被忽略(`@status`、`@broadcast`)。
|
||||
- 直接聊天使用私信会话规则(`session.dmScope`;默认 `main` 会将私信折叠到智能体主会话)。
|
||||
- 群组会话是隔离的(`agent:<agentId>:whatsapp:group:<jid>`)。
|
||||
- WhatsApp Web 传输遵循 Gateway 网关主机上的标准代理环境变量(`HTTPS_PROXY`、`HTTP_PROXY`、`NO_PROXY` 及其小写变体)。优先使用主机级代理配置,而不是渠道级的 WhatsApp 代理设置。
|
||||
- 群组会话相互隔离(`agent:<agentId>:whatsapp:group:<jid>`)。
|
||||
- WhatsApp Web 传输遵循 Gateway 网关主机上的标准代理环境变量(`HTTPS_PROXY`、`HTTP_PROXY`、`NO_PROXY` 及其小写变体)。优先使用主机级代理配置,而不是渠道专用的 WhatsApp 代理设置。
|
||||
|
||||
## 插件钩子和隐私
|
||||
|
||||
WhatsApp 入站消息可能包含个人消息内容、电话号码、
|
||||
群组标识符、发送者姓名以及会话关联字段。因此,
|
||||
除非你明确选择启用,否则 WhatsApp 不会向插件广播入站的
|
||||
`message_received` 钩子负载:
|
||||
群组标识符、发送者姓名和会话关联字段。因此,
|
||||
除非你显式选择启用,否则 WhatsApp 不会将入站 `message_received` 钩子负载广播给插件:
|
||||
|
||||
```json5
|
||||
{
|
||||
@ -178,7 +176,7 @@ WhatsApp 入站消息可能包含个人消息内容、电话号码、
|
||||
}
|
||||
```
|
||||
|
||||
你可以将这一选择启用范围限定到单个账户:
|
||||
你可以将此启用范围限定到某个账户:
|
||||
|
||||
```json5
|
||||
{
|
||||
@ -196,8 +194,7 @@ WhatsApp 入站消息可能包含个人消息内容、电话号码、
|
||||
}
|
||||
```
|
||||
|
||||
仅在你信任相关插件可以接收入站 WhatsApp 消息
|
||||
内容和标识符时启用此项。
|
||||
仅当你信任插件可以接收入站 WhatsApp 消息内容和标识符时,才启用此项。
|
||||
|
||||
## 访问控制和激活
|
||||
|
||||
@ -210,78 +207,78 @@ WhatsApp 入站消息可能包含个人消息内容、电话号码、
|
||||
- `open`(要求 `allowFrom` 包含 `"*"`)
|
||||
- `disabled`
|
||||
|
||||
`allowFrom` 接受 E.164 风格的号码(内部会进行规范化)。
|
||||
`allowFrom` 接受 E.164 风格号码(内部会进行标准化)。
|
||||
|
||||
多账户覆盖:对于该账户,`channels.whatsapp.accounts.<id>.dmPolicy`(以及 `allowFrom`)优先于渠道级默认值。
|
||||
|
||||
运行时行为细节:
|
||||
|
||||
- 配对会持久化到渠道允许存储中,并与已配置的 `allowFrom` 合并
|
||||
- 如果未配置允许列表,则默认允许已关联的自身号码
|
||||
- OpenClaw 绝不会自动配对出站 `fromMe` 私信(即你从已关联设备发送给自己的消息)
|
||||
- 配对会持久化到渠道 allow-store,并与已配置的 `allowFrom` 合并
|
||||
- 如果未配置允许名单,则默认允许已链接的自身号码
|
||||
- OpenClaw 永远不会自动配对出站 `fromMe` 私信(即你从已链接设备发给自己的消息)
|
||||
|
||||
</Tab>
|
||||
|
||||
<Tab title="群组策略 + 允许列表">
|
||||
<Tab title="群组策略 + 允许名单">
|
||||
群组访问有两层:
|
||||
|
||||
1. **群组成员允许列表**(`channels.whatsapp.groups`)
|
||||
1. **群组成员资格允许名单**(`channels.whatsapp.groups`)
|
||||
- 如果省略 `groups`,则所有群组都有资格
|
||||
- 如果存在 `groups`,它将作为群组允许列表(允许 `"*"`)
|
||||
- 如果存在 `groups`,它会充当群组允许名单(允许 `"*"`)
|
||||
|
||||
2. **群组发送者策略**(`channels.whatsapp.groupPolicy` + `groupAllowFrom`)
|
||||
- `open`:绕过发送者允许列表
|
||||
- `open`:绕过发送者允许名单
|
||||
- `allowlist`:发送者必须匹配 `groupAllowFrom`(或 `*`)
|
||||
- `disabled`:阻止所有群组入站消息
|
||||
- `disabled`:阻止所有群组入站
|
||||
|
||||
发送者允许列表回退:
|
||||
发送者允许名单回退:
|
||||
|
||||
- 如果未设置 `groupAllowFrom`,运行时会在可用时回退到 `allowFrom`
|
||||
- 发送者允许列表会在提及 / 回复激活之前进行评估
|
||||
- 发送者允许名单会在提及/回复激活之前进行评估
|
||||
|
||||
注意:如果根本不存在 `channels.whatsapp` 配置块,运行时群组策略回退为 `allowlist`(并记录一条警告日志),即使已设置 `channels.defaults.groupPolicy` 也是如此。
|
||||
注意:如果根本不存在 `channels.whatsapp` 配置块,即使设置了 `channels.defaults.groupPolicy`,运行时群组策略回退仍是 `allowlist`(并记录警告日志)。
|
||||
|
||||
</Tab>
|
||||
|
||||
<Tab title="提及 + /activation">
|
||||
群组回复默认要求被提及。
|
||||
默认情况下,群组回复需要被提及。
|
||||
|
||||
提及检测包括:
|
||||
|
||||
- 明确提及机器人身份的 WhatsApp 提及
|
||||
- 已配置的提及正则模式(`agents.list[].groupChat.mentionPatterns`,回退到 `messages.groupChat.mentionPatterns`)
|
||||
- 隐式回复机器人检测(回复发送者匹配机器人身份)
|
||||
- 对机器人身份的显式 WhatsApp 提及
|
||||
- 已配置的提及正则模式(`agents.list[].groupChat.mentionPatterns`,回退为 `messages.groupChat.mentionPatterns`)
|
||||
- 隐式回复给机器人的检测(回复发送者与机器人身份匹配)
|
||||
|
||||
安全说明:
|
||||
|
||||
- 引用 / 回复只能满足提及门控;它**不会**授予发送者授权
|
||||
- 当 `groupPolicy: "allowlist"` 时,即使非允许列表中的发送者回复了允许列表用户的消息,仍然会被阻止
|
||||
- 引用/回复只满足提及门控;它**不会**授予发送者授权
|
||||
- 在 `groupPolicy: "allowlist"` 下,即使未在允许名单中的发送者回复了允许名单用户的消息,仍然会被阻止
|
||||
|
||||
会话级激活命令:
|
||||
|
||||
- `/activation mention`
|
||||
- `/activation always`
|
||||
|
||||
`activation` 会更新会话状态(而非全局配置)。它受所有者门控保护。
|
||||
`activation` 会更新会话状态(而不是全局配置)。它受所有者权限控制。
|
||||
|
||||
</Tab>
|
||||
</Tabs>
|
||||
|
||||
## 个人号码和自聊行为
|
||||
|
||||
当已关联的自身号码也存在于 `allowFrom` 中时,WhatsApp 自聊保护会激活:
|
||||
当已链接的自身号码也存在于 `allowFrom` 中时,WhatsApp 自聊保护会启用:
|
||||
|
||||
- 跳过自聊回合的已读回执
|
||||
- 忽略原本会触发提醒你自己的 mention-JID 自动触发行为
|
||||
- 跳过自聊轮次的已读回执
|
||||
- 忽略本会触发自我提醒的 mention-JID 自动触发行为
|
||||
- 如果未设置 `messages.responsePrefix`,自聊回复默认使用 `[{identity.name}]` 或 `[openclaw]`
|
||||
|
||||
## 消息规范化和上下文
|
||||
## 消息标准化和上下文
|
||||
|
||||
<AccordionGroup>
|
||||
<Accordion title="入站封装 + 回复上下文">
|
||||
传入的 WhatsApp 消息会被包装进共享的入站封装中。
|
||||
<Accordion title="入站信封 + 回复上下文">
|
||||
传入的 WhatsApp 消息会包装进共享的入站信封中。
|
||||
|
||||
如果存在引用回复,上下文会按以下形式追加:
|
||||
如果存在引用回复,上下文会以如下形式追加:
|
||||
|
||||
```text
|
||||
[Replying to <sender> id:<stanzaId>]
|
||||
@ -289,12 +286,12 @@ WhatsApp 入站消息可能包含个人消息内容、电话号码、
|
||||
[/Replying]
|
||||
```
|
||||
|
||||
回复元数据字段也会在可用时填充(`ReplyToId`、`ReplyToBody`、`ReplyToSender`、发送者 JID/E.164)。
|
||||
回复元数据字段也会在可用时填充(`ReplyToId`、`ReplyToBody`、`ReplyToSender`、sender JID/E.164)。
|
||||
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="媒体占位符以及位置 / 联系人提取">
|
||||
仅包含媒体的入站消息会使用如下占位符进行规范化:
|
||||
<Accordion title="媒体占位符以及位置/联系人提取">
|
||||
仅包含媒体的入站消息会使用如下占位符进行标准化:
|
||||
|
||||
- `<media:image>`
|
||||
- `<media:video>`
|
||||
@ -302,14 +299,14 @@ WhatsApp 入站消息可能包含个人消息内容、电话号码、
|
||||
- `<media:document>`
|
||||
- `<media:sticker>`
|
||||
|
||||
位置消息正文使用简洁的坐标文本。位置标签 / 注释以及联系人 / vCard 详细信息会被渲染为带围栏的不受信任元数据,而不是内联提示文本。
|
||||
位置内容使用简洁的坐标文本。位置标签/备注以及联系人/vCard 详情会渲染为带围栏的不受信任元数据,而不是内联提示文本。
|
||||
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="待处理群组历史注入">
|
||||
对于群组,当机器人最终被触发时,未处理的消息可以被缓冲并作为上下文注入。
|
||||
对于群组,未处理的消息可以被缓冲,并在机器人最终被触发时作为上下文注入。
|
||||
|
||||
- 默认限制:`50`
|
||||
- 默认上限:`50`
|
||||
- 配置:`channels.whatsapp.historyLimit`
|
||||
- 回退:`messages.groupChat.historyLimit`
|
||||
- `0` 表示禁用
|
||||
@ -322,7 +319,7 @@ WhatsApp 入站消息可能包含个人消息内容、电话号码、
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="已读回执">
|
||||
默认会为已接受的入站 WhatsApp 消息启用已读回执。
|
||||
默认情况下,会为已接受的入站 WhatsApp 消息发送已读回执。
|
||||
|
||||
全局禁用:
|
||||
|
||||
@ -352,25 +349,26 @@ WhatsApp 入站消息可能包含个人消息内容、电话号码、
|
||||
}
|
||||
```
|
||||
|
||||
即使全局启用,自聊回合也会跳过已读回执。
|
||||
即使全局启用,自聊轮次也会跳过已读回执。
|
||||
|
||||
</Accordion>
|
||||
</AccordionGroup>
|
||||
|
||||
## 传递、分块和媒体
|
||||
## 投递、分块和媒体
|
||||
|
||||
<AccordionGroup>
|
||||
<Accordion title="文本分块">
|
||||
- 默认分块限制:`channels.whatsapp.textChunkLimit = 4000`
|
||||
- 默认分块上限:`channels.whatsapp.textChunkLimit = 4000`
|
||||
- `channels.whatsapp.chunkMode = "length" | "newline"`
|
||||
- `newline` 模式优先按段落边界(空行)分割,然后回退到按长度安全分块
|
||||
- `newline` 模式优先按段落边界(空行)拆分,然后回退到按长度安全分块
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="出站媒体行为">
|
||||
- 支持图片、视频、音频(PTT 语音消息)和文档负载
|
||||
- `audio/ogg` 会被改写为 `audio/ogg; codecs=opus` 以兼容语音消息
|
||||
- 视频发送时通过 `gifPlayback: true` 支持动画 GIF 播放
|
||||
- 发送多媒体回复负载时,说明文字会应用到第一项媒体
|
||||
- 支持图片、视频、音频(PTT 语音便签)和文档负载
|
||||
- 回复负载会保留 `audioAsVoice`;WhatsApp 会将音频媒体作为 Baileys PTT 语音便签发送
|
||||
- `audio/ogg` 会被改写为 `audio/ogg; codecs=opus`,以兼容语音便签
|
||||
- 发送视频时通过 `gifPlayback: true` 支持动画 GIF 播放
|
||||
- 发送多媒体回复负载时,说明文字会应用到第一个媒体项
|
||||
- 媒体来源可以是 HTTP(S)、`file://` 或本地路径
|
||||
</Accordion>
|
||||
|
||||
@ -378,21 +376,21 @@ WhatsApp 入站消息可能包含个人消息内容、电话号码、
|
||||
- 入站媒体保存上限:`channels.whatsapp.mediaMaxMb`(默认 `50`)
|
||||
- 出站媒体发送上限:`channels.whatsapp.mediaMaxMb`(默认 `50`)
|
||||
- 按账户覆盖使用 `channels.whatsapp.accounts.<accountId>.mediaMaxMb`
|
||||
- 图片会自动优化(调整尺寸 / 质量扫描)以适配限制
|
||||
- 当媒体发送失败时,首项回退会发送文本警告,而不是静默丢弃响应
|
||||
- 图片会自动优化(调整尺寸/质量扫描)以适配限制
|
||||
- 媒体发送失败时,首项回退会发送文本警告,而不是静默丢弃响应
|
||||
</Accordion>
|
||||
</AccordionGroup>
|
||||
|
||||
## 回复引用
|
||||
|
||||
WhatsApp 支持原生回复引用,即出站回复会可见地引用入站消息。可通过 `channels.whatsapp.replyToMode` 控制。
|
||||
WhatsApp 支持原生回复引用,出站回复会可见地引用入站消息。使用 `channels.whatsapp.replyToMode` 控制此行为。
|
||||
|
||||
| 值 | 行为 |
|
||||
| 值 | 行为 |
|
||||
| ----------- | --------------------------------------------------------------------- |
|
||||
| `"off"` | 从不引用;作为普通消息发送 |
|
||||
| `"first"` | 仅引用第一段出站回复分块 |
|
||||
| `"all"` | 引用每一段出站回复分块 |
|
||||
| `"batched"` | 引用排队的批量回复,同时让即时回复保持不引用 |
|
||||
| `"off"` | 从不引用;作为普通消息发送 |
|
||||
| `"first"` | 仅引用第一段出站回复分块 |
|
||||
| `"all"` | 引用每一段出站回复分块 |
|
||||
| `"batched"` | 引用排队的批量回复,同时让即时回复不带引用 |
|
||||
|
||||
默认值为 `"off"`。按账户覆盖使用 `channels.whatsapp.accounts.<id>.replyToMode`。
|
||||
|
||||
@ -408,14 +406,14 @@ WhatsApp 支持原生回复引用,即出站回复会可见地引用入站消
|
||||
|
||||
## Reaction 级别
|
||||
|
||||
`channels.whatsapp.reactionLevel` 控制智能体在 WhatsApp 上使用表情反应的范围有多广:
|
||||
`channels.whatsapp.reactionLevel` 控制智能体在 WhatsApp 上使用 emoji 反应的广度:
|
||||
|
||||
| 级别 | 确认反应 | 智能体主动反应 | 描述 |
|
||||
| ------------- | ------------- | ------------------------- | ------------------------------------------------ |
|
||||
| `"off"` | 否 | 否 | 完全不使用反应 |
|
||||
| `"ack"` | 是 | 否 | 仅确认反应(回复前回执) |
|
||||
| `"minimal"` | 是 | 是(保守) | 确认反应 + 采用保守指引的智能体反应 |
|
||||
| `"extensive"` | 是 | 是(鼓励) | 确认反应 + 采用鼓励性指引的智能体反应 |
|
||||
| 级别 | 确认反应 | 智能体主动发起的反应 | 描述 |
|
||||
| ------------- | -------- | -------------------- | ------------------------------------------------ |
|
||||
| `"off"` | 否 | 否 | 完全不使用反应 |
|
||||
| `"ack"` | 是 | 否 | 仅确认反应(回复前回执) |
|
||||
| `"minimal"` | 是 | 是(保守) | 确认反应 + 带保守指导的智能体反应 |
|
||||
| `"extensive"` | 是 | 是(鼓励) | 确认反应 + 带鼓励性指导的智能体反应 |
|
||||
|
||||
默认值:`"minimal"`。
|
||||
|
||||
@ -434,7 +432,7 @@ WhatsApp 支持原生回复引用,即出站回复会可见地引用入站消
|
||||
## 确认反应
|
||||
|
||||
WhatsApp 支持通过 `channels.whatsapp.ackReaction` 在接收入站消息时立即发送确认反应。
|
||||
确认反应受 `reactionLevel` 门控控制 —— 当 `reactionLevel` 为 `"off"` 时会被抑制。
|
||||
确认反应受 `reactionLevel` 控制——当 `reactionLevel` 为 `"off"` 时会被抑制。
|
||||
|
||||
```json5
|
||||
{
|
||||
@ -453,48 +451,48 @@ WhatsApp 支持通过 `channels.whatsapp.ackReaction` 在接收入站消息时
|
||||
行为说明:
|
||||
|
||||
- 在接受入站消息后立即发送(回复前)
|
||||
- 失败会被记录到日志中,但不会阻止正常回复传递
|
||||
- 群组模式 `mentions` 会在由提及触发的回合中发送反应;群组激活 `always` 会绕过此检查
|
||||
- WhatsApp 使用 `channels.whatsapp.ackReaction`(这里不会使用旧版的 `messages.ackReaction`)
|
||||
- 失败会记录日志,但不会阻止正常回复投递
|
||||
- 群组模式 `mentions` 会在通过提及触发的轮次中发送反应;群组激活 `always` 会绕过此检查
|
||||
- WhatsApp 使用 `channels.whatsapp.ackReaction`(这里不使用旧版 `messages.ackReaction`)
|
||||
|
||||
## 多账户和凭证
|
||||
|
||||
<AccordionGroup>
|
||||
<Accordion title="账户选择和默认值">
|
||||
- 账户 id 来自 `channels.whatsapp.accounts`
|
||||
- 默认账户选择:如果存在则为 `default`,否则为第一个已配置的账户 id(按排序)
|
||||
- 账户 id 会在内部规范化以供查找
|
||||
- 默认账户选择:如果存在 `default` 则使用它,否则使用第一个已配置的账户 id(已排序)
|
||||
- 账户 id 会在内部标准化以便查找
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="凭证路径和旧版兼容性">
|
||||
- 当前认证路径:`~/.openclaw/credentials/whatsapp/<accountId>/creds.json`
|
||||
- 备份文件:`creds.json.bak`
|
||||
- 位于 `~/.openclaw/credentials/` 的旧版默认认证仍会在默认账户流程中被识别 / 迁移
|
||||
- `~/.openclaw/credentials/` 中的旧版默认认证仍会被识别/迁移,用于默认账户流程
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="登出行为">
|
||||
`openclaw channels logout --channel whatsapp [--account <id>]` 会清除该账户的 WhatsApp 认证状态。
|
||||
`openclaw channels logout --channel whatsapp [--account <id>]` 会清除此账户的 WhatsApp 认证状态。
|
||||
|
||||
在旧版认证目录中,会保留 `oauth.json`,同时移除 Baileys 认证文件。
|
||||
|
||||
</Accordion>
|
||||
</AccordionGroup>
|
||||
|
||||
## 工具、操作和配置写入
|
||||
## 工具、动作和配置写入
|
||||
|
||||
- 智能体工具支持包括 WhatsApp reaction 操作(`react`)。
|
||||
- 操作门控:
|
||||
- 智能体工具支持包括 WhatsApp 反应动作(`react`)。
|
||||
- 动作门控:
|
||||
- `channels.whatsapp.actions.reactions`
|
||||
- `channels.whatsapp.actions.polls`
|
||||
- 渠道发起的配置写入默认启用(可通过 `channels.whatsapp.configWrites=false` 禁用)。
|
||||
- 默认启用由渠道发起的配置写入(可通过 `channels.whatsapp.configWrites=false` 禁用)。
|
||||
|
||||
## 故障排除
|
||||
|
||||
<AccordionGroup>
|
||||
<Accordion title="未关联(需要 QR 码)">
|
||||
症状:渠道状态报告为未关联。
|
||||
<Accordion title="未链接(需要 QR 码)">
|
||||
症状:渠道 Status 报告未链接。
|
||||
|
||||
修复:
|
||||
修复方法:
|
||||
|
||||
```bash
|
||||
openclaw channels login --channel whatsapp
|
||||
@ -503,40 +501,40 @@ WhatsApp 支持通过 `channels.whatsapp.ackReaction` 在接收入站消息时
|
||||
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="已关联但已断开 / 重连循环">
|
||||
症状:已关联的账户反复断开连接或尝试重连。
|
||||
<Accordion title="已链接但断开 / 重连循环">
|
||||
症状:已链接账户反复断开或重复尝试重连。
|
||||
|
||||
修复:
|
||||
修复方法:
|
||||
|
||||
```bash
|
||||
openclaw doctor
|
||||
openclaw logs --follow
|
||||
```
|
||||
|
||||
如有需要,使用 `channels login` 重新关联。
|
||||
如有需要,使用 `channels login` 重新链接。
|
||||
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="发送时没有活动监听器">
|
||||
当目标账户没有活动的 Gateway 网关监听器时,出站发送会快速失败。
|
||||
当目标账户没有活动中的 Gateway 网关监听器时,出站发送会快速失败。
|
||||
|
||||
请确保 Gateway 网关正在运行,且该账户已关联。
|
||||
请确保 Gateway 网关正在运行,并且该账户已完成链接。
|
||||
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="群组消息意外被忽略">
|
||||
请按以下顺序检查:
|
||||
<Accordion title="群组消息被意外忽略">
|
||||
按以下顺序检查:
|
||||
|
||||
- `groupPolicy`
|
||||
- `groupAllowFrom` / `allowFrom`
|
||||
- `groups` 允许列表条目
|
||||
- `groups` 允许名单条目
|
||||
- 提及门控(`requireMention` + 提及模式)
|
||||
- `openclaw.json`(JSON5)中的重复键:后面的条目会覆盖前面的条目,因此每个作用域只保留一个 `groupPolicy`
|
||||
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="Bun 运行时警告">
|
||||
WhatsApp Gateway 网关运行时应使用 Node。对于稳定的 WhatsApp/Telegram Gateway 网关运行,Bun 被标记为不兼容。
|
||||
WhatsApp Gateway 网关运行时应使用 Node。Bun 被标记为与稳定的 WhatsApp/Telegram Gateway 网关运行不兼容。
|
||||
</Accordion>
|
||||
</AccordionGroup>
|
||||
|
||||
@ -546,28 +544,28 @@ WhatsApp 通过 `groups` 和 `direct` 映射支持类似 Telegram 风格的群
|
||||
|
||||
群组消息的解析层级:
|
||||
|
||||
首先确定生效的 `groups` 映射:如果账户定义了自己的 `groups`,它将完全替换根级 `groups` 映射(不进行深度合并)。随后,提示词查找会在得到的这个单一映射上运行:
|
||||
首先确定生效的 `groups` 映射:如果账户定义了自己的 `groups`,它会完全替换根级 `groups` 映射(不进行深度合并)。随后提示词查找会在得到的单一映射上运行:
|
||||
|
||||
1. **群组特定系统提示词**(`groups["<groupId>"].systemPrompt`):当映射中存在特定群组条目**且**其定义了 `systemPrompt` 键时使用。如果 `systemPrompt` 是空字符串(`""`),则会抑制通配符,并且不会应用任何系统提示词。
|
||||
2. **群组通配符系统提示词**(`groups["*"].systemPrompt`):当映射中完全不存在特定群组条目,或者该条目存在但未定义 `systemPrompt` 键时使用。
|
||||
1. **群组专用系统提示词**(`groups["<groupId>"].systemPrompt`):当映射中存在该特定群组条目,**且** 其 `systemPrompt` 键已定义时使用。如果 `systemPrompt` 是空字符串(`""`),则会抑制通配符,并且不会应用任何系统提示词。
|
||||
2. **群组通配符系统提示词**(`groups["*"].systemPrompt`):当映射中完全不存在该特定群组条目,或该条目存在但未定义 `systemPrompt` 键时使用。
|
||||
|
||||
直接消息的解析层级:
|
||||
|
||||
首先确定生效的 `direct` 映射:如果账户定义了自己的 `direct`,它将完全替换根级 `direct` 映射(不进行深度合并)。随后,提示词查找会在得到的这个单一映射上运行:
|
||||
首先确定生效的 `direct` 映射:如果账户定义了自己的 `direct`,它会完全替换根级 `direct` 映射(不进行深度合并)。随后提示词查找会在得到的单一映射上运行:
|
||||
|
||||
1. **直接消息特定系统提示词**(`direct["<peerId>"].systemPrompt`):当映射中存在特定对端条目**且**其定义了 `systemPrompt` 键时使用。如果 `systemPrompt` 是空字符串(`""`),则会抑制通配符,并且不会应用任何系统提示词。
|
||||
2. **直接消息通配符系统提示词**(`direct["*"].systemPrompt`):当映射中完全不存在特定对端条目,或者该条目存在但未定义 `systemPrompt` 键时使用。
|
||||
1. **直接消息专用系统提示词**(`direct["<peerId>"].systemPrompt`):当映射中存在该特定对端条目,**且** 其 `systemPrompt` 键已定义时使用。如果 `systemPrompt` 是空字符串(`""`),则会抑制通配符,并且不会应用任何系统提示词。
|
||||
2. **直接消息通配符系统提示词**(`direct["*"].systemPrompt`):当映射中完全不存在该特定对端条目,或该条目存在但未定义 `systemPrompt` 键时使用。
|
||||
|
||||
注意:`dms` 仍然是轻量级的按私信历史覆盖桶(`dms.<id>.historyLimit`);提示词覆盖位于 `direct` 下。
|
||||
注意:`dms` 仍然是轻量级的按私信历史覆盖存储区(`dms.<id>.historyLimit`);提示词覆盖位于 `direct` 下。
|
||||
|
||||
**与 Telegram 多账户行为的区别:** 在 Telegram 中,在多账户设置下,根级 `groups` 会对所有账户有意抑制 —— 即使某些账户没有定义自己的 `groups` 也是如此 —— 以防机器人接收到它并不属于的群组消息。WhatsApp 不应用此保护:对于未定义账户级覆盖的账户,无论配置了多少账户,都会始终继承根级 `groups` 和根级 `direct`。在多账户 WhatsApp 设置中,如果你想为每个账户设置群组或直接消息提示词,请在每个账户下显式定义完整映射,而不要依赖根级默认值。
|
||||
**与 Telegram 多账户行为的区别:** 在 Telegram 中,在多账户设置下,根级 `groups` 会被有意抑制——即使某些账户没有定义自己的 `groups` 也是如此——以防止机器人接收其并不属于的群组消息。WhatsApp 不会应用这一保护机制:无论配置了多少个账户,没有定义账户级覆盖的账户始终会继承根级 `groups` 和根级 `direct`。在多账户 WhatsApp 设置中,如果你希望按账户分别设置群组或直接消息提示词,请在每个账户下显式定义完整映射,而不要依赖根级默认值。
|
||||
|
||||
重要行为:
|
||||
|
||||
- `channels.whatsapp.groups` 既是按群组的配置映射,也是聊天级的群组允许列表。在根级或账户作用域中,`groups["*"]` 都表示该作用域“允许所有群组”。
|
||||
- 仅当你本来就希望该作用域允许所有群组时,才添加通配符群组 `systemPrompt`。如果你仍然只希望一组固定的群组 id 具备资格,请不要将 `groups["*"]` 用作提示词默认值。相反,应在每个显式加入允许列表的群组条目上重复该提示词。
|
||||
- 群组准入和发送者授权是独立检查。`groups["*"]` 会扩大可进入群组处理流程的群组集合,但它本身不会授权这些群组中的每个发送者。发送者访问仍由 `channels.whatsapp.groupPolicy` 和 `channels.whatsapp.groupAllowFrom` 单独控制。
|
||||
- `channels.whatsapp.direct` 对私信没有同样的副作用。`direct["*"]` 只会在某条私信已经通过 `dmPolicy` 加上 `allowFrom` 或配对存储规则而被准入后,提供默认的直接聊天配置。
|
||||
- `channels.whatsapp.groups` 同时是每个群组的配置映射以及聊天级群组允许名单。在根级或账户作用域中,`groups["*"]` 表示该作用域“允许所有群组”。
|
||||
- 只有在你已经希望该作用域允许所有群组时,才添加通配符群组 `systemPrompt`。如果你仍然只希望固定的一组群组 id 符合条件,请不要将 `groups["*"]` 用作默认提示词。相反,请在每个显式加入允许名单的群组条目上重复设置该提示词。
|
||||
- 群组准入和发送者授权是分开的检查。`groups["*"]` 会扩大可以进入群组处理流程的群组集合,但它本身不会授权这些群组中的每一个发送者。发送者访问仍然分别由 `channels.whatsapp.groupPolicy` 和 `channels.whatsapp.groupAllowFrom` 控制。
|
||||
- `channels.whatsapp.direct` 对私信没有相同的副作用。`direct["*"]` 只会在私信已经通过 `dmPolicy` 以及 `allowFrom` 或配对存储规则获准后,提供默认的直接聊天配置。
|
||||
|
||||
示例:
|
||||
|
||||
@ -576,7 +574,7 @@ WhatsApp 通过 `groups` 和 `direct` 映射支持类似 Telegram 风格的群
|
||||
channels: {
|
||||
whatsapp: {
|
||||
groups: {
|
||||
// 仅当根级作用域应允许所有群组时使用。
|
||||
// 仅当根级作用域应允许所有群组时才使用。
|
||||
// 适用于所有未定义自己 groups 映射的账户。
|
||||
"*": { systemPrompt: "所有群组的默认提示词。" },
|
||||
},
|
||||
@ -587,19 +585,19 @@ WhatsApp 通过 `groups` 和 `direct` 映射支持类似 Telegram 风格的群
|
||||
accounts: {
|
||||
work: {
|
||||
groups: {
|
||||
// 该账户定义了自己的 groups,因此根级 groups 会被完全
|
||||
// 此账户定义了自己的 groups,因此根级 groups 会被完全
|
||||
// 替换。若要保留通配符,也需要在这里显式定义 "*"。
|
||||
"120363406415684625@g.us": {
|
||||
requireMention: false,
|
||||
systemPrompt: "专注于项目管理。",
|
||||
systemPrompt: "聚焦项目管理。",
|
||||
},
|
||||
// 仅当该账户中应允许所有群组时使用。
|
||||
// 仅当此账户中应允许所有群组时才使用。
|
||||
"*": { systemPrompt: "工作群组的默认提示词。" },
|
||||
},
|
||||
direct: {
|
||||
// 该账户定义了自己的 direct 映射,因此根级 direct 条目会被
|
||||
// 此账户定义了自己的 direct 映射,因此根级 direct 条目会被
|
||||
// 完全替换。若要保留通配符,也需要在这里显式定义 "*"。
|
||||
"+15551234567": { systemPrompt: "特定工作直接聊天的提示词。" },
|
||||
"+15551234567": { systemPrompt: "某个特定工作直接聊天的提示词。" },
|
||||
"*": { systemPrompt: "工作直接聊天的默认提示词。" },
|
||||
},
|
||||
},
|
||||
@ -615,20 +613,20 @@ WhatsApp 通过 `groups` 和 `direct` 映射支持类似 Telegram 风格的群
|
||||
|
||||
- [配置参考 - WhatsApp](/zh-CN/gateway/config-channels#whatsapp)
|
||||
|
||||
高信号的 WhatsApp 字段:
|
||||
高信号 WhatsApp 字段:
|
||||
|
||||
- 访问控制:`dmPolicy`, `allowFrom`, `groupPolicy`, `groupAllowFrom`, `groups`
|
||||
- 传递:`textChunkLimit`, `chunkMode`, `mediaMaxMb`, `sendReadReceipts`, `ackReaction`, `reactionLevel`
|
||||
- 多账户:`accounts.<id>.enabled`, `accounts.<id>.authDir`, 账户级覆盖
|
||||
- 运维:`configWrites`, `debounceMs`, `web.enabled`, `web.heartbeatSeconds`, `web.reconnect.*`
|
||||
- 会话行为:`session.dmScope`, `historyLimit`, `dmHistoryLimit`, `dms.<id>.historyLimit`
|
||||
- 提示词:`groups.<id>.systemPrompt`, `groups["*"].systemPrompt`, `direct.<id>.systemPrompt`, `direct["*"].systemPrompt`
|
||||
- 访问控制:`dmPolicy`、`allowFrom`、`groupPolicy`、`groupAllowFrom`、`groups`
|
||||
- 投递:`textChunkLimit`、`chunkMode`、`mediaMaxMb`、`sendReadReceipts`、`ackReaction`、`reactionLevel`
|
||||
- 多账户:`accounts.<id>.enabled`、`accounts.<id>.authDir`、账户级覆盖
|
||||
- 运维:`configWrites`、`debounceMs`、`web.enabled`、`web.heartbeatSeconds`、`web.reconnect.*`
|
||||
- 会话行为:`session.dmScope`、`historyLimit`、`dmHistoryLimit`、`dms.<id>.historyLimit`
|
||||
- 提示词:`groups.<id>.systemPrompt`、`groups["*"].systemPrompt`、`direct.<id>.systemPrompt`、`direct["*"].systemPrompt`
|
||||
|
||||
## 相关内容
|
||||
|
||||
- [配对](/zh-CN/channels/pairing)
|
||||
- [群组](/zh-CN/channels/groups)
|
||||
- [安全](/zh-CN/gateway/security)
|
||||
- [安全性](/zh-CN/gateway/security)
|
||||
- [渠道路由](/zh-CN/channels/channel-routing)
|
||||
- [多智能体路由](/zh-CN/concepts/multi-agent)
|
||||
- [故障排除](/zh-CN/channels/troubleshooting)
|
||||
|
||||
@ -1,27 +1,27 @@
|
||||
---
|
||||
read_when:
|
||||
- 你需要了解某个 CI 作业为什么运行了,或者为什么没有运行
|
||||
- 你正在调试失败的 GitHub Actions 检查
|
||||
- 你需要了解某个 CI 作业为什么会运行,或者为什么没有运行。
|
||||
- 你正在调试失败的 GitHub Actions 检查。
|
||||
summary: CI 作业图、范围门控,以及本地等效命令
|
||||
title: CI 流水线
|
||||
x-i18n:
|
||||
generated_at: "2026-04-25T01:51:43Z"
|
||||
generated_at: "2026-04-25T05:53:11Z"
|
||||
model: gpt-5.4
|
||||
provider: openai
|
||||
source_hash: da983f025479feb82baf407e723bb663b1239f1abd931827a4c9f419ea88df67
|
||||
source_hash: fc363efb98c9f82b585161a017ba1c599344a4e38c3fe683d81b0997d1d2fd4d
|
||||
source_path: ci.md
|
||||
workflow: 15
|
||||
---
|
||||
|
||||
CI 会在每次推送到 `main` 以及每个拉取请求时运行。它使用智能范围控制,在仅更改了不相关区域时跳过高开销作业。
|
||||
CI 会在每次推送到 `main` 以及每个拉取请求时运行。它使用智能范围界定,在仅更改了不相关区域时跳过高成本作业。
|
||||
|
||||
QA Lab 在主智能范围工作流之外有专用的 CI 通道。`Parity gate` 工作流会在匹配的 PR 变更以及手动触发时运行;它会构建私有 QA 运行时,并比较模拟的 GPT-5.4 和 Opus 4.6 agentic 包。`QA-Lab - All Lanes` 工作流会在 `main` 上每晚运行,并支持手动触发;它会将模拟 parity gate、实时 Matrix 通道和实时 Telegram 通道作为并行作业扇出执行。实时作业使用 `qa-live-shared` 环境,而 Telegram 通道使用 Convex 租约。`OpenClaw Release Checks` 也会在发布审批前运行相同的 QA Lab 通道。
|
||||
QA Lab 在主智能范围工作流之外有专门的 CI 通道。`Parity gate` 工作流会在匹配的 PR 变更和手动触发时运行;它会构建私有 QA 运行时,并比较模拟的 GPT-5.4 和 Opus 4.6 agentic 包。`QA-Lab - All Lanes` 工作流会在 `main` 上每晚运行,并且也支持手动触发;它会将模拟 parity gate、实时 Matrix 通道和实时 Telegram 通道作为并行作业扇出执行。实时作业使用 `qa-live-shared` environment,Telegram 通道使用 Convex 租约。`OpenClaw Release Checks` 也会在发布批准前运行相同的 QA Lab 通道。
|
||||
|
||||
`Duplicate PRs After Merge` 工作流是一个供维护者使用的手动工作流,用于合并落地后的重复 PR 清理。它默认使用 dry-run,并且仅在 `apply=true` 时关闭被明确列出的 PR。在修改 GitHub 之前,它会验证已落地的 PR 确实已合并,并且验证每个重复 PR 都具备共享的被引用 issue,或存在重叠的变更代码块。
|
||||
`Duplicate PRs After Merge` 工作流是一个供维护者在合并后清理重复 PR 的手动工作流。它默认采用 dry-run,只有在 `apply=true` 时才会关闭明确列出的 PR。在修改 GitHub 之前,它会验证已落地的 PR 确实已合并,并检查每个重复 PR 是否具有共享的被引用 issue,或存在重叠的变更 hunk。
|
||||
|
||||
`Docs Agent` 工作流是一个事件驱动的 Codex 维护通道,用于让现有文档与最近落地的更改保持一致。它没有纯定时计划:`main` 上一次成功的、非机器人触发的 push CI 运行可以触发它,手动触发也可以直接运行它。workflow-run 调用会在 `main` 已继续前进,或在最近一小时内已经创建了另一个未被跳过的 Docs Agent 运行时跳过。运行时,它会审查从上一个未被跳过的 Docs Agent 源 SHA 到当前 `main` 的提交范围,因此每小时的一次运行可以覆盖自上次文档处理以来累积在 `main` 上的所有更改。
|
||||
`Docs Agent` 工作流是一个事件驱动的 Codex 维护通道,用于让现有文档与最近已落地的变更保持一致。它没有纯定时计划:`main` 上一次成功的、非机器人触发的 push CI 运行可以触发它,手动触发也可以直接运行它。基于 workflow-run 的调用会在 `main` 已继续前进,或最近一小时内已创建了另一个未被跳过的 Docs Agent 运行时跳过。运行时,它会审查从上一次未被跳过的 Docs Agent 源 SHA 到当前 `main` 的提交范围,因此每小时一次的运行可以覆盖自上次文档处理以来累积的所有 `main` 变更。
|
||||
|
||||
`Test Performance Agent` 工作流是一个事件驱动的 Codex 维护通道,用于处理慢速测试。它没有纯定时计划:`main` 上一次成功的、非机器人触发的 push CI 运行可以触发它,但如果当天 UTC 已经有另一个 workflow-run 调用运行过或正在运行,它就会跳过。手动触发会绕过这个按天统计的活动门控。该通道会构建一份完整测试套件的分组 Vitest 性能报告,让 Codex 只做小规模且不降低覆盖率的测试性能修复,而不是进行大范围重构,然后重新运行完整测试套件报告,并拒绝任何会降低通过基线测试数量的更改。如果基线中已有失败测试,Codex 只能修复明显的问题,并且智能体处理后的完整测试套件报告必须通过,之后才会提交任何内容。当 `main` 在机器人推送落地前继续前进时,该通道会 rebase 已验证的补丁,重新运行 `pnpm check:changed`,并重试推送;有冲突的陈旧补丁会被跳过。它使用 GitHub 托管的 Ubuntu,这样 Codex action 就可以与 docs agent 保持相同的 drop-sudo 安全策略。
|
||||
`Test Performance Agent` 工作流是一个事件驱动的 Codex 维护通道,用于处理慢测试。它没有纯定时计划:`main` 上一次成功的、非机器人触发的 push CI 运行可以触发它,但如果当天 UTC 时间内另一个基于 workflow-run 的调用已经运行或正在运行,它就会跳过。手动触发会绕过这一每日活动门控。该通道会构建一份全套件分组的 Vitest 性能报告,让 Codex 只进行小范围且保持覆盖率的测试性能修复,而不是进行大规模重构;然后重新运行全套件报告,并拒绝任何导致通过基线测试数量减少的更改。如果基线中存在失败测试,Codex 只能修复明显的失败,并且在提交任何内容之前,agent 运行后的全套件报告必须通过。当 `main` 在机器人推送落地前继续前进时,该通道会对已验证的补丁执行 rebase,重新运行 `pnpm check:changed`,并重试推送;存在冲突的过时补丁会被跳过。它使用 GitHub 托管的 Ubuntu,因此 Codex action 可以与 docs agent 保持相同的 drop-sudo 安全姿态。
|
||||
|
||||
```bash
|
||||
gh workflow run duplicate-after-merge.yml \
|
||||
@ -32,62 +32,63 @@ gh workflow run duplicate-after-merge.yml \
|
||||
|
||||
## 作业概览
|
||||
|
||||
| 作业 | 用途 | 运行时机 |
|
||||
| 作业 | 目的 | 运行时机 |
|
||||
| -------------------------------- | -------------------------------------------------------------------------------------------- | ------------------------------------ |
|
||||
| `preflight` | 检测是否仅有文档变更、变更的范围、变更的扩展,并构建 CI 清单 | 在所有非草稿 push 和 PR 上始终运行 |
|
||||
| `preflight` | 检测是否仅有文档变更、已变更的范围、已变更的扩展,并构建 CI 清单 | 在所有非草稿 push 和 PR 上始终运行 |
|
||||
| `security-scm-fast` | 通过 `zizmor` 进行私钥检测和工作流审计 | 在所有非草稿 push 和 PR 上始终运行 |
|
||||
| `security-dependency-audit` | 针对 npm advisories 执行无依赖的生产 lockfile 审计 | 在所有非草稿 push 和 PR 上始终运行 |
|
||||
| `security-fast` | 快速安全作业的必需聚合作业 | 在所有非草稿 push 和 PR 上始终运行 |
|
||||
| `build-artifacts` | 构建 `dist/`、Control UI、构建产物检查以及可复用的下游产物 | 与 Node 相关的变更 |
|
||||
| `build-artifacts` | 构建 `dist/`、Control UI、已构建产物检查,以及可复用的下游产物 | 与 Node 相关的变更 |
|
||||
| `checks-fast-core` | 快速 Linux 正确性通道,例如 bundled/plugin-contract/protocol 检查 | 与 Node 相关的变更 |
|
||||
| `checks-fast-contracts-channels` | 分片的渠道契约检查,并提供稳定的聚合检查结果 | 与 Node 相关的变更 |
|
||||
| `checks-node-extensions` | 针对整个扩展套件的完整内置插件测试分片 | 与 Node 相关的变更 |
|
||||
| `checks-node-core-test` | Node 核心测试分片,不包括渠道、内置、契约和扩展通道 | 与 Node 相关的变更 |
|
||||
| `extension-fast` | 仅针对已更改内置插件的聚焦测试 | 带有扩展变更的拉取请求 |
|
||||
| `check` | 分片的主要本地门控等效项:生产类型、lint、防护、测试类型和严格 smoke | 与 Node 相关的变更 |
|
||||
| `check-additional` | 架构、边界、扩展表面防护、包边界以及 gateway-watch 分片 | 与 Node 相关的变更 |
|
||||
| `checks-node-extensions` | 覆盖整个扩展套件的完整内置插件测试分片 | 与 Node 相关的变更 |
|
||||
| `checks-node-core-test` | 核心 Node 测试分片,不包括渠道、内置插件、契约和扩展通道 | 与 Node 相关的变更 |
|
||||
| `extension-fast` | 仅针对已更改的内置插件运行聚焦测试 | 带有扩展变更的拉取请求 |
|
||||
| `check` | 分片的主要本地门控等效项:生产类型、lint、守卫、测试类型和严格 smoke | 与 Node 相关的变更 |
|
||||
| `check-additional` | 架构、边界、扩展表面守卫、包边界和 gateway-watch 分片 | 与 Node 相关的变更 |
|
||||
| `build-smoke` | 已构建 CLI 的 smoke 测试和启动内存 smoke 测试 | 与 Node 相关的变更 |
|
||||
| `checks` | 已构建产物渠道测试的验证器,以及仅在 push 上运行的 Node 22 兼容性检查 | 与 Node 相关的变更 |
|
||||
| `check-docs` | 文档格式化、lint 和失效链接检查 | 文档发生变更 |
|
||||
| `checks` | 用于已构建产物渠道测试的验证器,以及仅在 push 上运行的 Node 22 兼容性检查 | 与 Node 相关的变更 |
|
||||
| `check-docs` | 文档格式、lint 和断链检查 | 文档有变更时 |
|
||||
| `skills-python` | 面向 Python 支持的 Skills 的 Ruff + pytest | 与 Python Skills 相关的变更 |
|
||||
| `checks-windows` | Windows 专用测试通道 | 与 Windows 相关的变更 |
|
||||
| `checks-windows` | Windows 特定测试通道 | 与 Windows 相关的变更 |
|
||||
| `macos-node` | 使用共享构建产物的 macOS TypeScript 测试通道 | 与 macOS 相关的变更 |
|
||||
| `macos-swift` | macOS 应用的 Swift lint、构建和测试 | 与 macOS 相关的变更 |
|
||||
| `android` | 两个 flavor 的 Android 单元测试,以及一次 debug APK 构建 | 与 Android 相关的变更 |
|
||||
| `test-performance-agent` | 在可信活动之后进行的每日 Codex 慢测试优化 | `main` CI 成功后或手动触发 |
|
||||
| `android` | 两个 flavor 的 Android 单元测试,以及一个 debug APK 构建 | 与 Android 相关的变更 |
|
||||
| `test-performance-agent` | 在受信任活动之后,每日执行一次由 Codex 驱动的慢测试优化 | `main` CI 成功后或手动触发 |
|
||||
|
||||
## 快速失败顺序
|
||||
|
||||
作业的排列顺序经过设计,使低成本检查先失败,再决定是否运行高成本作业:
|
||||
作业的排列顺序经过设计,以便让低成本检查先失败,从而避免高成本作业运行:
|
||||
|
||||
1. `preflight` 决定哪些通道实际存在。`docs-scope` 和 `changed-scope` 逻辑是这个作业中的步骤,而不是独立作业。
|
||||
2. `security-scm-fast`、`security-dependency-audit`、`security-fast`、`check`、`check-additional`、`check-docs` 和 `skills-python` 会快速失败,而不必等待更重的构建产物和平台矩阵作业。
|
||||
3. `build-artifacts` 会与快速 Linux 通道并行执行,这样下游消费者就可以在共享构建准备好后立即开始。
|
||||
4. 之后再扇出更重的平台和运行时通道:`checks-fast-core`、`checks-fast-contracts-channels`、`checks-node-extensions`、`checks-node-core-test`、仅限 PR 的 `extension-fast`、`checks`、`checks-windows`、`macos-node`、`macos-swift` 和 `android`。
|
||||
1. `preflight` 决定到底有哪些通道会存在。`docs-scope` 和 `changed-scope` 逻辑是此作业内部的步骤,不是独立作业。
|
||||
2. `security-scm-fast`、`security-dependency-audit`、`security-fast`、`check`、`check-additional`、`check-docs` 和 `skills-python` 会快速失败,而不会等待更重的产物和平台矩阵作业。
|
||||
3. `build-artifacts` 会与快速 Linux 通道并行进行,这样下游消费者可以在共享构建准备好后立即启动。
|
||||
4. 更重的平台和运行时通道会在之后扇出:`checks-fast-core`、`checks-fast-contracts-channels`、`checks-node-extensions`、`checks-node-core-test`、仅 PR 运行的 `extension-fast`、`checks`、`checks-windows`、`macos-node`、`macos-swift` 和 `android`。
|
||||
|
||||
范围逻辑位于 `scripts/ci-changed-scope.mjs`,并由 `src/scripts/ci-changed-scope.test.ts` 中的单元测试覆盖。
|
||||
CI 工作流编辑会验证 Node CI 图以及工作流 lint,但不会仅因自身修改就强制触发 Windows、Android 或 macOS 原生构建;这些平台通道仍然只针对对应平台源码变更进行范围控制。
|
||||
Windows Node 检查的范围仅限于 Windows 专用的进程/路径包装器、npm/pnpm/UI 运行器辅助工具、包管理器配置,以及执行该通道的 CI 工作流表面;不相关的源码、插件、install-smoke 和纯测试更改仍然只会进入 Linux Node 通道,这样就不会为了已由常规测试分片覆盖的内容而占用一台 16 vCPU 的 Windows worker。
|
||||
单独的 `install-smoke` 工作流会通过它自己的 `preflight` 作业复用同一个范围脚本。它将 smoke 覆盖拆分为 `run_fast_install_smoke` 和 `run_full_install_smoke`。拉取请求会针对 Docker/包表面、内置插件包/清单变更,以及 Docker smoke 作业会覆盖到的核心插件/渠道/Gateway 网关/插件 SDK 表面运行快速路径。仅源码层面的内置插件变更、纯测试编辑和仅文档编辑不会占用 Docker worker。快速路径会构建一次根 Dockerfile 镜像,检查 CLI,运行 agents delete shared-workspace CLI smoke,运行容器 gateway-network e2e,验证一个内置扩展构建参数,并在 120 秒命令超时限制下运行受限的内置插件 Docker profile。完整路径则保留 QR 包安装以及 installer Docker/update 覆盖,用于每晚定时运行、手动触发、workflow-call 发布检查,以及真正触及 installer/package/Docker 表面的拉取请求。推送到 `main`,包括 merge commit,不会强制走完整路径;当 changed-scope 逻辑在 push 上本会请求完整覆盖时,工作流仍会保留快速 Docker smoke,而将完整 install smoke 留给每晚运行或发布验证。较慢的 Bun 全局安装 image-provider smoke 由 `run_bun_global_install_smoke` 单独控制;它会在每晚定时任务以及发布检查工作流中运行,手动触发 `install-smoke` 时也可以选择启用,但拉取请求和 `main` push 不会运行它。QR 和 installer Docker 测试继续保留它们各自面向安装的 Dockerfile。本地 `test:docker:all` 会预构建一个共享的 live-test 镜像和一个共享的 `scripts/e2e/Dockerfile` built-app 镜像,然后使用加权调度器和 `OPENCLAW_SKIP_DOCKER_BUILD=1` 运行 live/E2E smoke 通道;默认主池槽位数为 10,可通过 `OPENCLAW_DOCKER_ALL_PARALLELISM` 调整,面向 provider 敏感的尾池槽位数默认也为 10,可通过 `OPENCLAW_DOCKER_ALL_TAIL_PARALLELISM` 调整。重型通道上限默认分别为 `OPENCLAW_DOCKER_ALL_LIVE_LIMIT=6`、`OPENCLAW_DOCKER_ALL_NPM_LIMIT=8` 和 `OPENCLAW_DOCKER_ALL_SERVICE_LIMIT=7`,这样 npm install 和多服务通道就不会过度占用 Docker,同时较轻的通道仍能填满可用槽位。默认会将各通道启动时间错开 2 秒,以避免本地 Docker 守护进程在创建阶段发生风暴;可通过 `OPENCLAW_DOCKER_ALL_START_STAGGER_MS=0` 或其他毫秒值覆盖。这个本地聚合器会在开始前预检查 Docker,移除陈旧的 OpenClaw E2E 容器,输出活跃通道状态,保存通道耗时以便按最长优先排序,并支持 `OPENCLAW_DOCKER_ALL_DRY_RUN=1` 用于调度器检查。默认情况下,它会在首次失败后停止调度新的池化通道,并且每个通道都有一个 120 分钟的后备超时,可通过 `OPENCLAW_DOCKER_ALL_LANE_TIMEOUT_MS` 覆盖;部分 live/tail 通道会使用更严格的单通道上限。可复用的 live/E2E 工作流通过在 Docker 矩阵之前先构建并推送一个带 SHA 标签的 GHCR Docker E2E 镜像来复用这种共享镜像模式,然后使用 `OPENCLAW_SKIP_DOCKER_BUILD=1` 运行矩阵。定时的 live/E2E 工作流会每日运行完整的发布路径 Docker 套件。内置更新矩阵会按更新目标拆分,这样重复的 npm update 和 doctor repair 过程就可以与其他内置检查一起分片运行。
|
||||
CI 工作流编辑会验证 Node CI 图以及工作流 lint,但它们本身不会强制触发 Windows、Android 或 macOS 原生构建;这些平台通道仍然只由对应平台源码变更来决定是否运行。
|
||||
仅涉及 CI 路由的编辑、部分低成本的核心测试夹具编辑,以及窄范围的插件契约辅助函数/测试路由编辑,会使用一个快速的仅 Node 清单路径:preflight、安全检查,以及一个单独的 `checks-fast-core` 任务。当前变更文件仅限于该快速任务直接覆盖的路由或辅助表面时,此路径会避免构建产物、Node 22 兼容性检查、渠道契约、完整核心分片、内置插件分片,以及额外的守卫矩阵。
|
||||
Windows Node 检查仅限于 Windows 特定的进程/路径包装器、npm/pnpm/UI 运行器辅助函数、包管理器配置,以及执行该通道的 CI 工作流表面;无关的源码、插件、install-smoke 和仅测试变更会保留在 Linux Node 通道上,这样它们就不会为了正常测试分片已经覆盖的内容而占用一个 16-vCPU 的 Windows worker。
|
||||
单独的 `install-smoke` 工作流会通过它自己的 `preflight` 作业复用同一个范围脚本。它将 smoke 覆盖拆分为 `run_fast_install_smoke` 和 `run_full_install_smoke`。对于拉取请求,Docker/包相关表面、内置插件包/清单变更,以及 Docker smoke 作业所覆盖的核心插件/渠道/Gateway 网关/插件 SDK 表面会运行快速路径。仅源码级的内置插件变更、仅测试编辑和仅文档编辑不会占用 Docker worker。快速路径会构建一次根 Dockerfile 镜像,检查 CLI,运行 agents 删除共享工作区 CLI smoke,运行容器 gateway-network e2e,验证一个内置扩展 build arg,并在总命令超时 240 秒的限制下运行有界的内置插件 Docker 配置文件,同时每个场景的 Docker run 也各自有单独上限。完整路径会保留 QR 包安装以及安装器 Docker/更新覆盖,用于每晚的定时运行、手动触发、workflow-call 发布检查,以及确实触及安装器/包/Docker 表面的拉取请求。推送到 `main`,包括合并提交,不会强制走完整路径;当 changed-scope 逻辑在 push 上会请求完整覆盖时,工作流会保留快速 Docker smoke,并将完整 install smoke 留给每夜运行或发布验证。较慢的 Bun 全局安装 image-provider smoke 由 `run_bun_global_install_smoke` 单独门控;它会在每夜计划和发布检查工作流中运行,手动触发 `install-smoke` 时也可以选择启用,但拉取请求和 `main` 推送不会运行它。QR 和安装器 Docker 测试保留各自专用、以安装为重点的 Dockerfile。本地 `test:docker:all` 会预构建一个共享的 live-test 镜像和一个共享的 `scripts/e2e/Dockerfile` built-app 镜像,然后使用加权调度器和 `OPENCLAW_SKIP_DOCKER_BUILD=1` 运行 live/E2E smoke 通道;默认主池槽位数为 10,可通过 `OPENCLAW_DOCKER_ALL_PARALLELISM` 调整;对 provider 敏感的尾池槽位数默认为 10,可通过 `OPENCLAW_DOCKER_ALL_TAIL_PARALLELISM` 调整。重型通道上限默认分别为 `OPENCLAW_DOCKER_ALL_LIVE_LIMIT=6`、`OPENCLAW_DOCKER_ALL_NPM_LIMIT=8` 和 `OPENCLAW_DOCKER_ALL_SERVICE_LIMIT=7`,这样 npm 安装和多服务通道就不会过度占用 Docker,而较轻的通道仍能填满可用槽位。默认情况下,各通道启动会错开 2 秒,以避免本地 Docker 守护进程出现 create storm;可通过 `OPENCLAW_DOCKER_ALL_START_STAGGER_MS=0` 或其他毫秒值覆盖。这个本地聚合器会先对 Docker 做 preflight,移除过期的 OpenClaw E2E 容器,输出活动通道状态,持久化通道耗时以便按最长优先排序,并支持 `OPENCLAW_DOCKER_ALL_DRY_RUN=1` 用于检查调度器。默认情况下,它会在首次失败后停止调度新的池化通道;每个通道都有一个 120 分钟的后备超时,可通过 `OPENCLAW_DOCKER_ALL_LANE_TIMEOUT_MS` 覆盖;部分 live/tail 通道使用更严格的单通道上限。可复用的 live/E2E 工作流也遵循共享镜像模式:在 Docker 矩阵之前先构建并推送一个带 SHA 标签的 GHCR Docker E2E 镜像,然后使用 `OPENCLAW_SKIP_DOCKER_BUILD=1` 运行矩阵。定时的 live/E2E 工作流每天运行一次完整的发布路径 Docker 套件。内置更新矩阵按更新目标拆分,以便重复的 npm update 和 doctor repair 过程可以与其他内置检查一起分片运行。
|
||||
|
||||
本地 changed-lane 逻辑位于 `scripts/changed-lanes.mjs`,并由 `scripts/check-changed.mjs` 执行。这个本地门控在架构边界方面比宽泛的 CI 平台范围更严格:核心生产代码变更会运行核心生产 typecheck 加核心测试,核心仅测试变更只运行核心测试 typecheck/测试,扩展生产代码变更会运行扩展生产 typecheck 加扩展测试,而扩展仅测试变更只运行扩展测试 typecheck/测试。公共插件 SDK 或 plugin-contract 变更会扩展到扩展验证,因为扩展依赖这些核心契约。仅发布元数据的版本号提升会运行定向的版本/配置/根依赖检查。未知的根目录/配置变更会以安全优先的方式回退到所有通道。
|
||||
本地 changed-lane 逻辑位于 `scripts/changed-lanes.mjs`,并由 `scripts/check-changed.mjs` 执行。这个本地门控在架构边界方面比宽泛的 CI 平台范围更严格:核心生产变更会运行核心生产 typecheck 加核心测试,核心仅测试变更只运行核心测试 typecheck/测试,扩展生产变更会运行扩展生产 typecheck 加扩展测试,而扩展仅测试变更只运行扩展测试 typecheck/测试。公开的插件 SDK 或插件契约变更会扩展到扩展验证,因为扩展依赖这些核心契约。仅发布元数据的版本号提升会运行有针对性的版本/配置/根依赖检查。未知的根目录/配置变更会以安全优先方式退回到所有通道。
|
||||
|
||||
在 push 上,`checks` 矩阵会添加仅限 push 的 `compat-node22` 通道。在拉取请求上,这个通道会被跳过,矩阵仍聚焦于常规测试/渠道通道。
|
||||
在 push 上,`checks` 矩阵会增加一个仅在 push 时运行的 `compat-node22` 通道。在拉取请求上,该通道会被跳过,矩阵会继续聚焦于常规测试/渠道通道。
|
||||
|
||||
最慢的 Node 测试家族会被拆分或平衡,以便每个作业都足够小,同时不过度预留 runner:渠道契约会作为三个加权分片运行,内置插件测试会在六个扩展 worker 间平衡分配,小型核心单元通道会成对组合,auto-reply 作为三个平衡 worker 运行而不是六个很小的 worker,而 agentic Gateway 网关/插件配置会分布到现有仅源码的 agentic Node 作业中,而不是等待构建产物。宽泛的浏览器、QA、媒体和杂项插件测试使用各自专用的 Vitest 配置,而不是共享的插件兜底配置。扩展分片作业一次最多运行两个插件配置组,每组只用一个 Vitest worker,并使用更大的 Node heap,这样导入密集型的插件批次就不会产生额外的 CI 作业。宽泛的 agents 通道使用共享的 Vitest 文件级并行调度器,因为它主要受导入/调度开销支配,而不是由某个单独的慢测试文件主导。`runtime-config` 会与 infra core-runtime 分片一起运行,以避免共享运行时分片承担拖尾。`check-additional` 将 package-boundary 的 compile/canary 工作保留在一起,并将运行时拓扑架构与 gateway watch 覆盖拆开;boundary guard 分片会在一个作业内部并发运行其小型且相互独立的 guard。Gateway watch、渠道测试以及核心 support-boundary 分片会在 `dist/` 和 `dist-runtime/` 已构建完成后,在 `build-artifacts` 内部并发运行,保留它们原有的检查名称作为轻量验证作业,同时避免额外占用两个 Blacksmith worker 和第二条产物消费者队列。
|
||||
Android CI 会运行 `testPlayDebugUnitTest` 和 `testThirdPartyDebugUnitTest`,然后构建 Play debug APK。第三方 flavor 没有单独的 source set 或 manifest;它的单元测试通道仍会使用 SMS/通话日志 BuildConfig 标志编译该 flavor,同时避免在每次与 Android 相关的 push 上重复执行 debug APK 打包作业。
|
||||
`extension-fast` 仅限 PR,因为 push 运行已经会执行完整的内置插件分片。这样可以为评审保留已更改插件的反馈,同时不会在 `main` 上额外占用一个 Blacksmith worker 去做 `checks-node-extensions` 已经覆盖的内容。
|
||||
最慢的 Node 测试家族会被拆分或重新平衡,以便每个作业都保持较小规模,同时不过度预留 runner:渠道契约作为 3 个加权分片运行,内置插件测试会在 6 个扩展 worker 间平衡,小型核心单元通道会成对组合,auto-reply 改为 3 个平衡 worker 而不是 6 个过小 worker,而 agentic Gateway 网关/插件配置会分散到现有的仅源码 agentic Node 作业中,而不是等待构建产物。广泛的浏览器、QA、媒体和杂项插件测试使用它们专用的 Vitest 配置,而不是共享的插件兜底配置。扩展分片作业一次最多运行两个插件配置组,每组只用一个 Vitest worker,并使用更大的 Node 堆,这样以导入为重的插件批次就不会产生额外的 CI 作业。广泛的 agents 通道使用共享的 Vitest 文件级并行调度器,因为它更受导入/调度主导,而不是由某个单独的慢测试文件主导。`runtime-config` 与 infra core-runtime 分片一起运行,以防共享运行时分片承担拖尾负担。`check-additional` 会将包边界 compile/canary 工作保留在一起,并把运行时拓扑架构与 gateway watch 覆盖分开;边界守卫分片会在一个作业内部并发运行它的小型独立守卫。Gateway 网关 watch、渠道测试和核心 support-boundary 分片会在 `build-artifacts` 内部并发运行,此时 `dist/` 和 `dist-runtime/` 已构建完成;这样既能将它们原有的检查名称保留为轻量验证作业,又能避免额外的两个 Blacksmith worker 和第二条产物消费者队列。
|
||||
Android CI 会同时运行 `testPlayDebugUnitTest` 和 `testThirdPartyDebugUnitTest`,然后构建 Play debug APK。第三方 flavor 没有单独的 source set 或 manifest;其单元测试通道仍会在启用 SMS/call-log BuildConfig 标志的情况下编译该 flavor,同时避免在每次与 Android 相关的 push 上重复进行一次 debug APK 打包作业。
|
||||
`extension-fast` 仅在 PR 上运行,因为 push 运行已经执行了完整的内置插件分片。这样既能为代码评审提供已变更插件的快速反馈,又不会在 `main` 上为 `checks-node-extensions` 中已经存在的覆盖而额外占用一个 Blacksmith worker。
|
||||
|
||||
当同一个 PR 或 `main` 引用上有更新的 push 落地时,GitHub 可能会将被替代的作业标记为 `cancelled`。除非同一引用的最新运行也失败,否则应将其视为 CI 噪音。聚合分片检查使用 `!cancelled() && always()`,因此它们仍会正常报告分片失败,但不会在整个工作流已经被替代后继续排队。
|
||||
CI 并发键是带版本号的(`CI-v7-*`),这样 GitHub 侧旧队列组中的僵尸任务就不会无限期阻塞较新的 `main` 运行。
|
||||
当同一个 PR 或 `main` 引用上有新的 push 到来时,GitHub 可能会将被替代的作业标记为 `cancelled`。除非同一引用上的最新运行也失败,否则应将其视为 CI 噪声。聚合分片检查使用 `!cancelled() && always()`,因此它们仍会报告正常的分片失败,但不会在整个工作流已经被替代后继续排队。
|
||||
CI 并发键是带版本的(`CI-v7-*`),这样 GitHub 端旧队列组中的僵尸任务就不会无限期阻塞较新的 main 运行。
|
||||
|
||||
## Runner
|
||||
## 运行器
|
||||
|
||||
| Runner | 作业 |
|
||||
| 运行器 | 作业 |
|
||||
| -------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `ubuntu-24.04` | `preflight`、快速安全作业及其聚合(`security-scm-fast`、`security-dependency-audit`、`security-fast`)、快速 protocol/contract/bundled 检查、分片的渠道契约检查、除 lint 外的 `check` 分片、`check-additional` 分片及其聚合、Node 测试聚合验证器、文档检查、Python Skills、workflow-sanity、labeler、auto-response;install-smoke 的 preflight 也使用 GitHub 托管的 Ubuntu,这样 Blacksmith 矩阵可以更早排队 |
|
||||
| `ubuntu-24.04` | `preflight`、快速安全作业及其聚合(`security-scm-fast`、`security-dependency-audit`、`security-fast`)、快速 protocol/contract/bundled 检查、分片的渠道契约检查、除 lint 外的 `check` 分片、`check-additional` 分片及其聚合、Node 测试聚合验证器、文档检查、Python Skills、workflow-sanity、labeler、auto-response;install-smoke preflight 也使用 GitHub 托管的 Ubuntu,这样 Blacksmith 矩阵可以更早排队 |
|
||||
| `blacksmith-8vcpu-ubuntu-2404` | `build-artifacts`、build-smoke、Linux Node 测试分片、内置插件测试分片、`android` |
|
||||
| `blacksmith-16vcpu-ubuntu-2404` | `check-lint`,它对 CPU 仍足够敏感,以至于 8 vCPU 的成本高于节省;install-smoke Docker 构建,在这里 32 vCPU 的排队时间成本高于其带来的收益 |
|
||||
| `blacksmith-16vcpu-ubuntu-2404` | `check-lint`,它仍然对 CPU 足够敏感,以至于 8 vCPU 的成本高于其节省;install-smoke Docker 构建,其中 32-vCPU 的排队时间成本高于其节省 |
|
||||
| `blacksmith-16vcpu-windows-2025` | `checks-windows` |
|
||||
| `blacksmith-6vcpu-macos-latest` | `openclaw/openclaw` 上的 `macos-node`;fork 会回退到 `macos-latest` |
|
||||
| `blacksmith-12vcpu-macos-latest` | `openclaw/openclaw` 上的 `macos-swift`;fork 会回退到 `macos-latest` |
|
||||
@ -96,20 +97,20 @@ CI 并发键是带版本号的(`CI-v7-*`),这样 GitHub 侧旧队列组中
|
||||
|
||||
```bash
|
||||
pnpm changed:lanes # 检查 origin/main...HEAD 的本地 changed-lane 分类器
|
||||
pnpm check:changed # 智能本地门控:按边界通道运行变更相关的 typecheck/lint/测试
|
||||
pnpm check # 快速本地门控:生产 tsgo + 分片 lint + 并行快速 guard
|
||||
pnpm check:changed # 智能本地门控:按边界通道执行变更相关的 typecheck/lint/测试
|
||||
pnpm check # 快速本地门控:生产 tsgo + 分片 lint + 并行快速守卫
|
||||
pnpm check:test-types
|
||||
pnpm check:timed # 同样的门控,但带有各阶段耗时
|
||||
pnpm check:timed # 相同门控,但带每个阶段的耗时统计
|
||||
pnpm build:strict-smoke
|
||||
pnpm check:architecture
|
||||
pnpm test:gateway:watch-regression
|
||||
pnpm test # vitest 测试
|
||||
pnpm test:channels
|
||||
pnpm test:contracts:channels
|
||||
pnpm check:docs # 文档格式 + lint + 失效链接
|
||||
pnpm build # 当 CI 产物/build-smoke 通道相关时构建 dist
|
||||
node scripts/ci-run-timings.mjs <run-id> # 汇总总耗时、排队时间和最慢作业
|
||||
node scripts/ci-run-timings.mjs --recent 10 # 比较最近成功的 main CI 运行
|
||||
pnpm check:docs # 文档格式 + lint + 断链检查
|
||||
pnpm build # 当 CI 产物/build-smoke 通道相关时,构建 dist
|
||||
node scripts/ci-run-timings.mjs <run-id> # 汇总总耗时、排队时间和最慢的作业
|
||||
node scripts/ci-run-timings.mjs --recent 10 # 对比最近成功的 10 次 main CI 运行
|
||||
pnpm test:perf:groups --full-suite --allow-failures --output .artifacts/test-perf/baseline-before.json
|
||||
pnpm test:perf:groups:compare .artifacts/test-perf/baseline-before.json .artifacts/test-perf/after-agent.json
|
||||
```
|
||||
|
||||
@ -4,23 +4,23 @@ read_when:
|
||||
summary: '`openclaw config` 的 CLI 参考(get/set/unset/file/schema/validate)'
|
||||
title: 配置
|
||||
x-i18n:
|
||||
generated_at: "2026-04-25T04:54:56Z"
|
||||
generated_at: "2026-04-25T05:53:10Z"
|
||||
model: gpt-5.4
|
||||
provider: openai
|
||||
source_hash: 60935e011a72e08c47dc21a634a78ce11edf261ff9896009519dc4e04561f465
|
||||
source_hash: 60567d39174d7214461f995d32f3064777d7437ff82226961eab404cd7fec5c4
|
||||
source_path: cli/config.md
|
||||
workflow: 15
|
||||
---
|
||||
|
||||
# `openclaw config`
|
||||
|
||||
用于在 `openclaw.json` 中进行非交互式编辑的配置辅助命令:按路径 get/set/unset/file/schema/validate 值,并打印当前激活的配置文件。不带子命令运行时,会打开配置向导(与 `openclaw configure` 相同)。
|
||||
用于在 `openclaw.json` 中进行非交互式编辑的配置辅助命令:按路径获取/设置/取消设置/file/schema/validate 值,并打印当前生效的配置文件。不带子命令运行时,将打开配置向导(与 `openclaw configure` 相同)。
|
||||
|
||||
根选项:
|
||||
|
||||
- `--section <section>`:当你在不带子命令的情况下运行 `openclaw config` 时,可重复使用的引导式设置分区过滤器
|
||||
|
||||
支持的引导分区:
|
||||
支持的引导式分区:
|
||||
|
||||
- `workspace`
|
||||
- `model`
|
||||
@ -55,7 +55,7 @@ openclaw config validate --json
|
||||
|
||||
### `config schema`
|
||||
|
||||
将 `openclaw.json` 的生成 JSON schema 以 JSON 形式打印到 stdout。
|
||||
将 `openclaw.json` 的生成式 JSON schema 以 JSON 形式输出到 stdout。
|
||||
|
||||
它包含的内容:
|
||||
|
||||
@ -63,18 +63,18 @@ openclaw config validate --json
|
||||
- Control UI 使用的字段 `title` 和 `description` 文档元数据
|
||||
- 当存在匹配的字段文档时,嵌套对象、通配符(`*`)和数组项(`[]`)节点会继承相同的 `title` / `description` 元数据
|
||||
- 当存在匹配的字段文档时,`anyOf` / `oneOf` / `allOf` 分支也会继承相同的文档元数据
|
||||
- 当可以加载运行时清单时,尽力提供实时插件和渠道 schema 元数据
|
||||
- 即使当前配置无效,也会提供一个干净的后备 schema
|
||||
- 当能够加载运行时清单时,尽力提供实时的插件 + 渠道 schema 元数据
|
||||
- 即使当前配置无效,也会提供一个干净的回退 schema
|
||||
|
||||
相关运行时 RPC:
|
||||
相关的运行时 RPC:
|
||||
|
||||
- `config.schema.lookup` 会返回一个标准化的配置路径,以及一个浅层 schema 节点(`title`、`description`、`type`、`enum`、`const`、常见边界)、匹配的 UI 提示元数据和直接子项摘要。可将其用于 Control UI 或自定义客户端中的按路径范围逐层钻取。
|
||||
- `config.schema.lookup` 返回一个标准化的配置路径,以及一个浅层 schema 节点(`title`、`description`、`type`、`enum`、`const`、常见边界)、匹配的 UI 提示元数据和直接子节点摘要。可将其用于 Control UI 或自定义客户端中的按路径逐层深入查看。
|
||||
|
||||
```bash
|
||||
openclaw config schema
|
||||
```
|
||||
|
||||
当你想用其他工具检查或验证它时,可以将其输出到文件:
|
||||
如果你想用其他工具检查或验证它,可以将其输出到文件:
|
||||
|
||||
```bash
|
||||
openclaw config schema > openclaw.schema.json
|
||||
@ -82,7 +82,7 @@ openclaw config schema > openclaw.schema.json
|
||||
|
||||
### 路径
|
||||
|
||||
路径使用点号或方括号表示法:
|
||||
路径支持点表示法或方括号表示法:
|
||||
|
||||
```bash
|
||||
openclaw config get agents.defaults.workspace
|
||||
@ -98,7 +98,7 @@ openclaw config set agents.list[1].tools.exec.node "node-id-or-name"
|
||||
|
||||
## 值
|
||||
|
||||
值会尽可能按 JSON5 解析;否则会被视为字符串。使用 `--strict-json` 可强制要求进行 JSON5 解析。`--json` 仍然作为旧别名受支持。
|
||||
值会尽可能按 JSON5 解析;否则会被视为字符串。使用 `--strict-json` 可强制要求 JSON5 解析。`--json` 仍作为旧版别名受支持。
|
||||
|
||||
```bash
|
||||
openclaw config set agents.defaults.heartbeat.every "0m"
|
||||
@ -106,9 +106,9 @@ openclaw config set gateway.port 19001 --strict-json
|
||||
openclaw config set channels.whatsapp.groups '["*"]' --strict-json
|
||||
```
|
||||
|
||||
`config get <path> --json` 会将原始值以 JSON 形式打印,而不是终端格式化文本。
|
||||
`config get <path> --json` 会将原始值作为 JSON 输出,而不是终端格式化文本。
|
||||
|
||||
对象赋值默认会替换目标路径。对那些通常保存用户添加条目的受保护映射/列表路径,例如 `agents.defaults.models`、`models.providers`、`models.providers.<id>.models`、`plugins.entries` 和 `auth.profiles`,如果替换会移除现有条目,则会拒绝,除非你传入 `--replace`。
|
||||
对象赋值默认会替换目标路径。对于通常保存用户新增条目的受保护映射/列表路径,例如 `agents.defaults.models`、`models.providers`、`models.providers.<id>.models`、`plugins.entries` 和 `auth.profiles`,如果替换会移除现有条目,则会拒绝,除非你传入 `--replace`。
|
||||
|
||||
向这些映射中添加条目时,请使用 `--merge`:
|
||||
|
||||
@ -117,7 +117,7 @@ openclaw config set agents.defaults.models '{"openai/gpt-5.4":{}}' --strict-json
|
||||
openclaw config set models.providers.ollama.models '[{"id":"llama3.2","name":"Llama 3.2"}]' --strict-json --merge
|
||||
```
|
||||
|
||||
仅当你明确希望所提供的值成为完整目标值时,才使用 `--replace`。
|
||||
仅当你明确希望提供的值成为完整目标值时,才使用 `--replace`。
|
||||
|
||||
## `config set` 模式
|
||||
|
||||
@ -133,7 +133,7 @@ openclaw config set channels.discord.token \
|
||||
--ref-id DISCORD_BOT_TOKEN
|
||||
```
|
||||
|
||||
3. provider 构建器模式(仅限 `secrets.providers.<alias>` 路径):
|
||||
3. 提供商构建器模式(仅限 `secrets.providers.<alias>` 路径):
|
||||
|
||||
```bash
|
||||
openclaw config set secrets.providers.vault \
|
||||
@ -144,7 +144,7 @@ openclaw config set secrets.providers.vault \
|
||||
--provider-timeout-ms 5000
|
||||
```
|
||||
|
||||
4. 批量模式(`--batch-json` 或 `--batch-file`):
|
||||
4. 批处理模式(`--batch-json` 或 `--batch-file`):
|
||||
|
||||
```bash
|
||||
openclaw config set --batch-json '[
|
||||
@ -165,12 +165,12 @@ openclaw config set --batch-file ./config-set.batch.json --dry-run
|
||||
|
||||
策略说明:
|
||||
|
||||
- 在不支持运行时可变更的表面上,SecretRef 赋值会被拒绝(例如 `hooks.token`、`commands.ownerDisplaySecret`、Discord 线程绑定 webhook token,以及 WhatsApp 凭据 JSON)。参见 [SecretRef 凭据表面](/zh-CN/reference/secretref-credential-surface)。
|
||||
- 对不支持运行时可变更的目标面进行 SecretRef 赋值会被拒绝(例如 `hooks.token`、`commands.ownerDisplaySecret`、Discord 线程绑定 webhook token,以及 WhatsApp 凭证 JSON)。参见 [SecretRef Credential Surface](/zh-CN/reference/secretref-credential-surface)。
|
||||
|
||||
批量解析始终将批量负载(`--batch-json`/`--batch-file`)作为事实来源。
|
||||
`--strict-json` / `--json` 不会改变批量解析行为。
|
||||
批处理解析始终将批处理载荷(`--batch-json`/`--batch-file`)作为唯一真实来源。
|
||||
`--strict-json` / `--json` 不会改变批处理解析行为。
|
||||
|
||||
JSON 路径/值模式对 SecretRefs 和 providers 仍然受支持:
|
||||
JSON 路径/值模式对 SecretRef 和提供商同样受支持:
|
||||
|
||||
```bash
|
||||
openclaw config set channels.discord.token \
|
||||
@ -182,27 +182,27 @@ openclaw config set secrets.providers.vaultfile \
|
||||
--strict-json
|
||||
```
|
||||
|
||||
## Provider 构建器标志
|
||||
## 提供商构建器标志
|
||||
|
||||
provider 构建器目标必须使用 `secrets.providers.<alias>` 作为路径。
|
||||
提供商构建器目标路径必须使用 `secrets.providers.<alias>`。
|
||||
|
||||
通用标志:
|
||||
|
||||
- `--provider-source <env|file|exec>`
|
||||
- `--provider-timeout-ms <ms>`(`file`、`exec`)
|
||||
|
||||
Env provider(`--provider-source env`):
|
||||
Env 提供商(`--provider-source env`):
|
||||
|
||||
- `--provider-allowlist <ENV_VAR>`(可重复)
|
||||
|
||||
File provider(`--provider-source file`):
|
||||
文件提供商(`--provider-source file`):
|
||||
|
||||
- `--provider-path <path>`(必需)
|
||||
- `--provider-mode <singleValue|json>`
|
||||
- `--provider-max-bytes <bytes>`
|
||||
- `--provider-allow-insecure-path`
|
||||
|
||||
Exec provider(`--provider-source exec`):
|
||||
Exec 提供商(`--provider-source exec`):
|
||||
|
||||
- `--provider-command <path>`(必需)
|
||||
- `--provider-arg <arg>`(可重复)
|
||||
@ -215,7 +215,7 @@ Exec provider(`--provider-source exec`):
|
||||
- `--provider-allow-insecure-path`
|
||||
- `--provider-allow-symlink-command`
|
||||
|
||||
强化型 exec provider 示例:
|
||||
加固的 exec 提供商示例:
|
||||
|
||||
```bash
|
||||
openclaw config set secrets.providers.vault \
|
||||
@ -231,7 +231,7 @@ openclaw config set secrets.providers.vault \
|
||||
|
||||
## Dry run
|
||||
|
||||
使用 `--dry-run` 可以在不写入 `openclaw.json` 的情况下验证变更。
|
||||
使用 `--dry-run` 可在不写入 `openclaw.json` 的情况下验证更改。
|
||||
|
||||
```bash
|
||||
openclaw config set channels.discord.token \
|
||||
@ -255,25 +255,25 @@ openclaw config set channels.discord.token \
|
||||
--allow-exec
|
||||
```
|
||||
|
||||
Dry-run 行为:
|
||||
dry-run 行为:
|
||||
|
||||
- 构建器模式:对已更改的 refs/providers 运行 SecretRef 可解析性检查。
|
||||
- JSON 模式(`--strict-json`、`--json` 或批量模式):运行 schema 验证以及 SecretRef 可解析性检查。
|
||||
- 已知不支持的 SecretRef 目标表面也会运行策略验证。
|
||||
- 策略检查会评估变更后的完整配置,因此对父对象的写入(例如将 `hooks` 设为对象)无法绕过不支持表面的验证。
|
||||
- 为避免命令副作用,dry-run 期间默认跳过 exec SecretRef 检查。
|
||||
- 将 `--allow-exec` 与 `--dry-run` 一起使用,可选择启用 exec SecretRef 检查(这可能会执行 provider 命令)。
|
||||
- `--allow-exec` 仅用于 dry-run;如果未与 `--dry-run` 一起使用会报错。
|
||||
- 构建器模式:对已更改的 ref/提供商运行 SecretRef 可解析性检查。
|
||||
- JSON 模式(`--strict-json`、`--json` 或批处理模式):运行 schema 验证以及 SecretRef 可解析性检查。
|
||||
- 也会对已知不受支持的 SecretRef 目标面运行策略验证。
|
||||
- 策略检查会基于变更后的完整配置进行评估,因此写入父对象(例如将 `hooks` 设置为对象)无法绕过对不受支持目标面的验证。
|
||||
- 默认情况下,dry-run 会跳过 exec SecretRef 检查,以避免命令副作用。
|
||||
- 如需启用 exec SecretRef 检查,请在 `--dry-run` 时配合使用 `--allow-exec`(这可能会执行提供商命令)。
|
||||
- `--allow-exec` 仅用于 dry-run;如果在未使用 `--dry-run` 时传入,则会报错。
|
||||
|
||||
`--dry-run --json` 会打印机器可读报告:
|
||||
`--dry-run --json` 会输出机器可读报告:
|
||||
|
||||
- `ok`:dry-run 是否通过
|
||||
- `operations`:已评估的赋值数量
|
||||
- `operations`:已评估的赋值操作数量
|
||||
- `checks`:是否运行了 schema/可解析性检查
|
||||
- `checks.resolvabilityComplete`:可解析性检查是否完整运行结束(当 exec refs 被跳过时为 false)
|
||||
- `checks.resolvabilityComplete`:可解析性检查是否完整执行(当跳过 exec ref 时为 false)
|
||||
- `refsChecked`:dry-run 期间实际解析的 ref 数量
|
||||
- `skippedExecRefs`:由于未设置 `--allow-exec` 而被跳过的 exec ref 数量
|
||||
- `errors`:当 `ok=false` 时的结构化 schema/可解析性失败信息
|
||||
- `skippedExecRefs`:由于未设置 `--allow-exec` 而跳过的 exec ref 数量
|
||||
- `errors`:当 `ok=false` 时,结构化的 schema/可解析性失败信息
|
||||
|
||||
### JSON 输出结构
|
||||
|
||||
@ -294,7 +294,7 @@ Dry-run 行为:
|
||||
{
|
||||
kind: "schema" | "resolvability",
|
||||
message: string,
|
||||
ref?: string, // 对于可解析性错误会出现
|
||||
ref?: string, // 对于可解析性错误时会出现
|
||||
},
|
||||
],
|
||||
}
|
||||
@ -345,18 +345,19 @@ Dry-run 行为:
|
||||
|
||||
如果 dry-run 失败:
|
||||
|
||||
- `config schema validation failed`:你变更后的配置结构无效;请修正路径/值或 provider/ref 对象结构。
|
||||
- `Config policy validation failed: unsupported SecretRef usage`:请将该凭据移回明文/字符串输入,并仅在受支持的表面上使用 SecretRefs。
|
||||
- `SecretRef assignment(s) could not be resolved`:当前无法解析所引用的 provider/ref(缺少环境变量、文件指针无效、exec provider 失败,或 provider/source 不匹配)。
|
||||
- `Dry run note: skipped <n> exec SecretRef resolvability check(s)`:dry-run 跳过了 exec refs;如果你需要验证 exec 可解析性,请使用 `--allow-exec` 重新运行。
|
||||
- 对于批量模式,请修复失败的条目,并在写入前重新运行 `--dry-run`。
|
||||
- `config schema validation failed`:你的变更后配置结构无效;请修正路径/值或提供商/ref 对象结构。
|
||||
- `Config policy validation failed: unsupported SecretRef usage`:请将该凭证移回明文/字符串输入,并仅在受支持的目标面上使用 SecretRef。
|
||||
- `SecretRef assignment(s) could not be resolved`:当前无法解析所引用的提供商/ref(缺少环境变量、文件指针无效、exec 提供商失败,或提供商/source 不匹配)。
|
||||
- `Dry run note: skipped <n> exec SecretRef resolvability check(s)`:dry-run 跳过了 exec ref;如果你需要验证 exec 可解析性,请使用 `--allow-exec` 重新运行。
|
||||
- 对于批处理模式,请修复失败的条目,然后在写入前重新运行 `--dry-run`。
|
||||
|
||||
## 写入安全
|
||||
|
||||
`openclaw config set` 以及其他由 OpenClaw 拥有的配置写入器,会在提交到磁盘前验证完整的变更后配置。如果新的负载未通过 schema 验证,或者看起来像是破坏性覆盖,则当前活动配置会保持不变,并且被拒绝的负载会保存在其旁边,命名为 `openclaw.json.rejected.*`。
|
||||
活动配置路径必须是常规文件。对于写入操作,不支持符号链接形式的 `openclaw.json` 布局;请改用 `OPENCLAW_CONFIG_PATH` 直接指向真实文件。
|
||||
`openclaw config set` 和其他由 OpenClaw 管理的配置写入器,会在提交到磁盘前验证变更后的完整配置。如果新载荷未通过 schema 验证,或看起来像是破坏性的覆盖,当前生效配置将保持不变,且被拒绝的载荷会保存在其旁边,命名为 `openclaw.json.rejected.*`。
|
||||
当前生效的配置路径必须是常规文件。对于符号链接的 `openclaw.json`
|
||||
布局,不支持写入;请改用 `OPENCLAW_CONFIG_PATH` 直接指向真实文件。
|
||||
|
||||
对于小型编辑,优先使用 CLI 写入:
|
||||
对于小范围编辑,优先使用 CLI 写入:
|
||||
|
||||
```bash
|
||||
openclaw config set gateway.reload.mode hybrid --dry-run
|
||||
@ -364,7 +365,7 @@ openclaw config set gateway.reload.mode hybrid
|
||||
openclaw config validate
|
||||
```
|
||||
|
||||
如果写入被拒绝,请检查保存的负载并修复完整配置结构:
|
||||
如果写入被拒绝,请检查保存的载荷,并修正完整配置结构:
|
||||
|
||||
```bash
|
||||
CONFIG="$(openclaw config file)"
|
||||
@ -372,34 +373,34 @@ ls -lt "$CONFIG".rejected.* 2>/dev/null | head
|
||||
openclaw config validate
|
||||
```
|
||||
|
||||
直接通过编辑器写入仍然是允许的,但正在运行的 Gateway 网关会在它们通过验证前将其视为不可信。在启动或热重载期间,无效的直接编辑可以从最后一个已知正常备份中恢复。参见 [Gateway 网关故障排除](/zh-CN/gateway/troubleshooting#gateway-restored-last-known-good-config)。
|
||||
仍然允许直接通过编辑器写入,但正在运行的 Gateway 网关 会在这些更改通过验证前将其视为不受信任。在启动或热重载期间,无效的直接编辑可能会从最后一次已知有效备份中恢复。参见 [Gateway 网关故障排除](/zh-CN/gateway/troubleshooting#gateway-restored-last-known-good-config)。
|
||||
|
||||
整文件恢复仅保留给全局性损坏的配置,例如解析错误、根级 schema 失败、旧版迁移失败,或插件与根配置的混合失败。如果验证仅在 `plugins.entries.<id>...` 下失败,OpenClaw 会保持当前 `openclaw.json` 不变,并报告插件本地问题,而不是恢复 `.last-good`。这可以防止插件 schema 变更或 `minHostVersion` 偏差回滚与你无关的用户设置,例如模型、提供商、auth 配置文件、渠道、Gateway 网关暴露、工具、内存、浏览器或 cron 配置。
|
||||
整文件恢复仅保留给全局损坏的配置,例如解析错误、根级 schema 失败、旧版迁移失败,或插件与根级配置混合失败。如果验证仅在 `plugins.entries.<id>...` 下失败,OpenClaw 会保持当前生效的 `openclaw.json` 不变,并报告插件本地问题,而不是恢复 `.last-good`。这可防止插件 schema 变更或 `minHostVersion` 不匹配导致回滚与你无关的用户设置,例如模型、提供商、auth 配置文件、渠道、Gateway 网关暴露设置、工具、内存、浏览器或 cron 配置。
|
||||
|
||||
## 子命令
|
||||
|
||||
- `config file`:打印当前激活的配置文件路径(从 `OPENCLAW_CONFIG_PATH` 或默认位置解析)。该路径应指向常规文件,而不是符号链接。
|
||||
- `config file`:打印当前生效的配置文件路径(从 `OPENCLAW_CONFIG_PATH` 或默认位置解析)。该路径应指向常规文件,而不是符号链接。
|
||||
|
||||
编辑后请重启网关。
|
||||
|
||||
## 验证
|
||||
|
||||
在不启动 Gateway 网关的情况下,根据当前激活的 schema 验证当前配置。
|
||||
在不启动 Gateway 网关 的情况下,使用当前生效的 schema 验证当前配置。
|
||||
|
||||
```bash
|
||||
openclaw config validate
|
||||
openclaw config validate --json
|
||||
```
|
||||
|
||||
在 `openclaw config validate` 通过后,你可以使用本地 TUI,让内嵌智能体在同一个终端中比较当前配置与文档,同时验证每一项更改:
|
||||
在 `openclaw config validate` 通过后,你可以使用本地 TUI,让内嵌智能体在你从同一个终端验证每项更改时,对照文档比较当前生效配置。
|
||||
|
||||
如果验证当前已经失败,请先使用 `openclaw configure` 或 `openclaw doctor --fix`。`openclaw chat` 不会绕过无效配置保护。
|
||||
如果验证已经失败,请先使用 `openclaw configure` 或 `openclaw doctor --fix`。`openclaw chat` 不会绕过无效配置保护。
|
||||
|
||||
```bash
|
||||
openclaw chat
|
||||
```
|
||||
|
||||
然后在 TUI 内:
|
||||
然后在 TUI 中:
|
||||
|
||||
```text
|
||||
!openclaw config file
|
||||
@ -410,10 +411,10 @@ openclaw chat
|
||||
|
||||
典型修复循环:
|
||||
|
||||
- 让智能体将你当前的配置与相关文档页面进行比较,并建议最小修复方案。
|
||||
- 请智能体将你当前的配置与相关文档页面进行比较,并建议最小修复方案。
|
||||
- 使用 `openclaw config set` 或 `openclaw configure` 应用有针对性的编辑。
|
||||
- 每次更改后重新运行 `openclaw config validate`。
|
||||
- 如果验证通过,但运行时仍然不健康,请运行 `openclaw doctor` 或 `openclaw doctor --fix` 以获取迁移和修复帮助。
|
||||
- 如果验证通过但运行时仍不健康,请运行 `openclaw doctor` 或 `openclaw doctor --fix` 以获取迁移和修复帮助。
|
||||
|
||||
## 相关内容
|
||||
|
||||
|
||||
@ -1,81 +1,68 @@
|
||||
---
|
||||
read_when:
|
||||
- 你想要定时任务和唤醒功能
|
||||
- 你想要计划任务和唤醒功能
|
||||
- 你正在调试 cron 执行和日志
|
||||
summary: '`openclaw cron` 的 CLI 参考(调度并运行后台任务)'
|
||||
summary: '`openclaw cron` 的 CLI 参考(调度并运行后台作业)'
|
||||
title: Cron
|
||||
x-i18n:
|
||||
generated_at: "2026-04-24T04:00:36Z"
|
||||
generated_at: "2026-04-25T05:53:11Z"
|
||||
model: gpt-5.4
|
||||
provider: openai
|
||||
source_hash: d3f5c262092b9b5b821ec824bc02dbbd806936d91f1d03ac6eb789f7e71ffc07
|
||||
source_hash: 281c0e0e5a3139d2b9cb7cc02afe3b9a9d4a20228a7891eb45c55b7e22c5e1c4
|
||||
source_path: cli/cron.md
|
||||
workflow: 15
|
||||
---
|
||||
|
||||
# `openclaw cron`
|
||||
|
||||
管理 Gateway 网关调度器的 cron 任务。
|
||||
管理 Gateway 网关调度器的 cron 作业。
|
||||
|
||||
相关内容:
|
||||
|
||||
- Cron 任务:[Cron 任务](/zh-CN/automation/cron-jobs)
|
||||
- Cron 作业:[Cron 作业](/zh-CN/automation/cron-jobs)
|
||||
|
||||
提示:运行 `openclaw cron --help` 查看完整命令功能。
|
||||
提示:运行 `openclaw cron --help` 可查看完整命令范围。
|
||||
|
||||
注意:`openclaw cron list` 和 `openclaw cron show <job-id>` 会预览已解析的投递路由。对于 `channel: "last"`,预览会显示该路由是从主会话/当前会话解析得到,还是会以安全关闭方式失败。
|
||||
注意:`openclaw cron list` 和 `openclaw cron show <job-id>` 会预览解析后的投递路由。对于 `channel: "last"`,预览会显示该路由是从主/当前会话解析得出,还是会以失败关闭。
|
||||
|
||||
注意:独立的 `cron add` 任务默认使用 `--announce` 投递。使用 `--no-deliver` 可将输出保留为内部可见。`--deliver` 仍作为 `--announce` 的已弃用别名保留。
|
||||
注意:独立的 `cron add` 作业默认使用 `--announce` 投递。使用 `--no-deliver` 可将输出保持为内部可见。`--deliver` 仍然保留为 `--announce` 的已弃用别名。
|
||||
|
||||
注意:独立 cron 聊天投递是共享的。`--announce` 是运行器对最终回复的后备投递;`--no-deliver` 会禁用该后备机制,但当聊天路由可用时,并不会移除智能体的 `message` 工具。
|
||||
注意:独立 cron 聊天投递是共享的。`--announce` 是用于最终回复的运行器后备投递;`--no-deliver` 会禁用该后备方式,但当聊天路由可用时,不会移除智能体的 `message` 工具。
|
||||
|
||||
注意:一次性(`--at`)任务在成功后默认删除。使用 `--keep-after-run` 可在运行后保留它们。
|
||||
注意:一次性(`--at`)作业默认在成功后删除。使用 `--keep-after-run` 可在运行后保留它们。
|
||||
|
||||
注意:`--session` 支持 `main`、`isolated`、`current` 和 `session:<id>`。
|
||||
使用 `current` 可在创建时绑定到当前活动会话,或使用 `session:<id>` 指定显式的持久会话键。
|
||||
注意:`--session` 支持 `main`、`isolated`、`current` 和 `session:<id>`。使用 `current` 可在创建时绑定到当前活动会话,或使用 `session:<id>` 指定一个显式的持久会话键。
|
||||
|
||||
注意:对于一次性 CLI 任务,不带偏移量的 `--at` 日期时间默认按 UTC 处理,除非你同时传入
|
||||
`--tz <iana>`,此时会将该本地墙上时钟时间解释为给定时区中的时间。
|
||||
注意:`--session isolated` 会为每次运行创建一个新的转录/会话 id。安全偏好设置和用户显式选择的模型/认证覆盖项可以继承,但环境中的对话上下文不会继承:渠道/群组路由、发送/排队策略、权限提升、来源和 ACP 运行时绑定都会为新的独立运行重置。
|
||||
|
||||
注意:循环任务现在会在连续出错后使用指数退避重试(30 秒 → 1 分钟 → 5 分钟 → 15 分钟 → 60 分钟),然后在下一次成功运行后恢复正常调度。
|
||||
注意:对于一次性的 CLI 作业,无偏移量的 `--at` 日期时间默认按 UTC 处理,除非你同时传入 `--tz <iana>`,此时会将该本地墙钟时间按给定时区解释。
|
||||
|
||||
注意:`openclaw cron run` 现在会在手动运行请求加入执行队列后立即返回。成功响应包含 `{ ok: true, enqueued: true, runId }`;使用 `openclaw cron runs --id <job-id>` 跟踪其最终结果。
|
||||
注意:循环作业现在会在连续错误后使用指数退避重试(30 秒 → 1 分钟 → 5 分钟 → 15 分钟 → 60 分钟),并在下一次成功运行后恢复正常调度。
|
||||
|
||||
注意:`openclaw cron run <job-id>` 默认会强制运行。使用 `--due` 可保留旧版的“仅在到期时运行”行为。
|
||||
注意:`openclaw cron run` 现在会在手动运行被加入执行队列后立即返回。成功响应包含 `{ ok: true, enqueued: true, runId }`;使用 `openclaw cron runs --id <job-id>` 可跟踪最终结果。
|
||||
|
||||
注意:独立 cron 轮次会抑制过时的仅确认类回复。如果第一个结果只是中间状态更新,且没有后代子智能体运行负责给出最终答案,cron 会在投递前再次提示一次以获取真实结果。
|
||||
注意:`openclaw cron run <job-id>` 默认会强制运行。使用 `--due` 可保留较早的“仅在到期时运行”行为。
|
||||
|
||||
注意:如果独立 cron 运行只返回静默令牌(`NO_REPLY` /
|
||||
`no_reply`),cron 会同时抑制直接对外投递和后备的队列摘要路径,因此不会向聊天回发任何内容。
|
||||
注意:独立 cron 轮次会抑制过时的、仅确认性质的回复。如果第一个结果只是中间状态更新,并且没有后代子智能体运行负责给出最终答案,cron 会再提示一次以获取真实结果后再投递。
|
||||
|
||||
注意:`cron add|edit --model ...` 会为该任务使用所选的允许模型。
|
||||
如果该模型不被允许,cron 会发出警告,并回退到该任务的智能体/默认
|
||||
模型选择。已配置的回退链仍然适用,但如果只是简单模型覆盖且没有显式的逐任务回退列表,则不再把智能体主模型作为隐藏的额外重试目标附加进去。
|
||||
注意:如果独立 cron 运行只返回静默令牌(`NO_REPLY` / `no_reply`),cron 会同时抑制直接对外投递和后备排队摘要路径,因此不会向聊天回发任何内容。
|
||||
|
||||
注意:独立 cron 的模型优先级依次为 Gmail-hook 覆盖、逐任务
|
||||
`--model`、任何已存储的 cron 会话模型覆盖,最后才是正常的
|
||||
智能体/默认选择。
|
||||
注意:`cron add|edit --model ...` 会为该作业使用所选的允许模型。如果该模型不被允许,cron 会发出警告,并回退到该作业的智能体/默认模型选择。已配置的回退链仍然适用,但如果只是普通模型覆盖且没有显式的每作业回退列表,就不会再把智能体主模型作为隐藏的额外重试目标附加进去。
|
||||
|
||||
注意:独立 cron 快速模式会跟随已解析出的实时模型选择。
|
||||
模型配置中的 `params.fastMode` 默认生效,但已存储会话中的 `fastMode`
|
||||
覆盖仍然优先于配置。
|
||||
注意:独立 cron 的模型优先级依次为:先 Gmail-hook 覆盖,然后是每作业的 `--model`,再然后是任何用户选择并存储的 cron 会话模型覆盖,最后才是常规的智能体/默认选择。
|
||||
|
||||
注意:如果独立运行抛出 `LiveSessionModelSwitchError`,cron 会在重试前持久化
|
||||
已切换的 provider/model(以及存在时已切换的 auth profile 覆盖)。外层重试循环在初次尝试之后最多只允许 2 次切换重试,之后会中止,而不是无限循环。
|
||||
注意:独立 cron 快速模式遵循已解析的实时模型选择。模型配置 `params.fastMode` 默认生效,但已存储的会话 `fastMode` 覆盖仍然优先于配置。
|
||||
|
||||
注意:失败通知会优先使用 `delivery.failureDestination`,然后使用
|
||||
全局 `cron.failureDestination`,最后在未配置显式失败目标时回退到该任务的主
|
||||
announce 目标。
|
||||
注意:如果独立运行抛出 `LiveSessionModelSwitchError`,cron 会在重试前为当前运行持久化切换后的 provider/模型(以及存在时切换后的认证配置覆盖)。外层重试循环限制为初始尝试后的 2 次切换重试,之后会中止,而不是无限循环。
|
||||
|
||||
注意:失败通知会优先使用 `delivery.failureDestination`,其次使用全局 `cron.failureDestination`,最后在未配置显式失败目标时回退到作业的主 announce 目标。
|
||||
|
||||
注意:保留/清理由配置控制:
|
||||
|
||||
- `cron.sessionRetention`(默认 `24h`)会清理已完成的独立运行会话。
|
||||
- `cron.runLog.maxBytes` + `cron.runLog.keepLines` 会清理 `~/.openclaw/cron/runs/<jobId>.jsonl`。
|
||||
|
||||
升级说明:如果你有早于当前投递/存储格式的旧 cron 任务,请运行
|
||||
`openclaw doctor --fix`。Doctor 现在会规范化旧版 cron 字段(`jobId`、`schedule.cron`、
|
||||
顶层投递字段,包括旧版 `threadId`、负载中的 `provider` 投递别名),并在配置了 `cron.webhook` 时,将简单的
|
||||
`notify: true` webhook 后备任务迁移为显式的 webhook 投递。
|
||||
升级说明:如果你有早于当前投递/存储格式的旧 cron 作业,请运行 `openclaw doctor --fix`。Doctor 现在会规范化旧版 cron 字段(`jobId`、`schedule.cron`、顶层投递字段,包括旧版 `threadId`、负载中的 `provider` 投递别名),并在配置了 `cron.webhook` 时,将简单的 `notify: true` webhook 后备作业迁移为显式 webhook 投递。
|
||||
|
||||
## 常见编辑
|
||||
|
||||
@ -85,25 +72,25 @@ announce 目标。
|
||||
openclaw cron edit <job-id> --announce --channel telegram --to "123456789"
|
||||
```
|
||||
|
||||
为独立任务禁用投递:
|
||||
为独立作业禁用投递:
|
||||
|
||||
```bash
|
||||
openclaw cron edit <job-id> --no-deliver
|
||||
```
|
||||
|
||||
为独立任务启用轻量级引导上下文:
|
||||
为独立作业启用轻量级引导上下文:
|
||||
|
||||
```bash
|
||||
openclaw cron edit <job-id> --light-context
|
||||
```
|
||||
|
||||
公告到特定渠道:
|
||||
向特定渠道 announce:
|
||||
|
||||
```bash
|
||||
openclaw cron edit <job-id> --announce --channel slack --to "channel:C1234567890"
|
||||
```
|
||||
|
||||
创建带轻量级引导上下文的独立任务:
|
||||
创建一个带轻量级引导上下文的独立作业:
|
||||
|
||||
```bash
|
||||
openclaw cron add \
|
||||
@ -115,14 +102,12 @@ openclaw cron add \
|
||||
--no-deliver
|
||||
```
|
||||
|
||||
`--light-context` 仅适用于独立智能体轮次任务。对于 cron 运行,轻量模式会保持引导上下文为空,而不是注入完整的工作区引导上下文集合。
|
||||
`--light-context` 仅适用于独立智能体轮次作业。对于 cron 运行,轻量模式会保持引导上下文为空,而不是注入完整的工作区引导集。
|
||||
|
||||
投递归属说明:
|
||||
|
||||
- 独立 cron 聊天投递是共享的。当聊天路由可用时,智能体可以通过
|
||||
`message` 工具直接发送。
|
||||
- `announce` 仅在智能体未直接发送到已解析目标时,才会以后备方式投递最终回复。`webhook` 会将完成后的负载发送到 URL。
|
||||
`none` 会禁用运行器后备投递。
|
||||
- 独立 cron 聊天投递是共享的。当聊天路由可用时,智能体可以使用 `message` 工具直接发送。
|
||||
- `announce` 仅在智能体未直接发送到已解析目标时,后备投递最终回复。`webhook` 会将完成后的负载发布到某个 URL。`none` 会禁用运行器后备投递。
|
||||
|
||||
## 常见管理命令
|
||||
|
||||
@ -136,8 +121,7 @@ openclaw cron run <job-id> --due
|
||||
openclaw cron runs --id <job-id> --limit 50
|
||||
```
|
||||
|
||||
`cron runs` 条目包含投递诊断信息,包括预期 cron 目标、
|
||||
已解析目标、message 工具发送情况、后备使用情况以及已投递状态。
|
||||
`cron runs` 条目包含投递诊断信息,其中包括预期的 cron 目标、已解析的目标、message-tool 发送、后备使用情况以及已投递状态。
|
||||
|
||||
智能体/会话重定向:
|
||||
|
||||
@ -159,13 +143,11 @@ openclaw cron edit <job-id> --no-deliver
|
||||
|
||||
失败投递说明:
|
||||
|
||||
- `delivery.failureDestination` 支持用于独立任务。
|
||||
- 主会话任务仅当主
|
||||
投递模式为 `webhook` 时,才可使用 `delivery.failureDestination`。
|
||||
- 如果你没有设置任何失败目标,而该任务已经向某个
|
||||
渠道进行 announce,失败通知会复用同一个 announce 目标。
|
||||
- `delivery.failureDestination` 支持用于独立作业。
|
||||
- 主会话作业仅在主投递模式为 `webhook` 时,才能使用 `delivery.failureDestination`。
|
||||
- 如果你未设置任何失败目标,并且该作业已经向某个渠道 announce,失败通知会复用同一个 announce 目标。
|
||||
|
||||
## 相关内容
|
||||
|
||||
- [CLI 参考](/zh-CN/cli)
|
||||
- [定时任务](/zh-CN/automation/cron-jobs)
|
||||
- [计划任务](/zh-CN/automation/cron-jobs)
|
||||
|
||||
@ -2,33 +2,33 @@
|
||||
read_when:
|
||||
- 你正在批准设备配对请求
|
||||
- 你需要轮换或撤销设备令牌
|
||||
summary: '`openclaw devices` 的 CLI 参考(设备配对 + 令牌轮换 / 撤销)'
|
||||
summary: '`openclaw devices` 的 CLI 参考(设备配对 + 令牌轮换/撤销)'
|
||||
title: 设备
|
||||
x-i18n:
|
||||
generated_at: "2026-04-24T04:00:45Z"
|
||||
generated_at: "2026-04-25T05:53:35Z"
|
||||
model: gpt-5.4
|
||||
provider: openai
|
||||
source_hash: c4ae835807ba4b0aea1073b9a84410a10fa0394d7d34e49d645071108cea6a35
|
||||
source_hash: 168afa3c784565c09ebdac854acc33cb7c0cacf4eba6a1a038c88c96af3c1430
|
||||
source_path: cli/devices.md
|
||||
workflow: 15
|
||||
---
|
||||
|
||||
# `openclaw devices`
|
||||
|
||||
管理设备配对请求和设备范围令牌。
|
||||
管理设备配对请求和设备作用域令牌。
|
||||
|
||||
## 命令
|
||||
|
||||
### `openclaw devices list`
|
||||
|
||||
列出待处理的配对请求和已配对的设备。
|
||||
列出待处理的配对请求和已配对设备。
|
||||
|
||||
```
|
||||
openclaw devices list
|
||||
openclaw devices list --json
|
||||
```
|
||||
|
||||
待处理请求的输出会在设备已配对时,将请求的访问权限显示在该设备当前已批准访问权限旁边。这样可以明确显示 scope / 角色升级,而不会看起来像是配对丢失了。
|
||||
当设备已配对时,待处理请求输出会在设备当前已批准访问权限旁边显示其请求的访问权限。这样可以明确显示作用域/角色升级,而不会看起来像是配对丢失了。
|
||||
|
||||
### `openclaw devices remove <deviceId>`
|
||||
|
||||
@ -53,11 +53,13 @@ openclaw devices clear --yes --pending --json
|
||||
|
||||
### `openclaw devices approve [requestId] [--latest]`
|
||||
|
||||
通过精确的 `requestId` 批准待处理的设备配对请求。如果省略 `requestId` 或传入 `--latest`,OpenClaw 只会打印所选的待处理请求并退出;请在验证详细信息后,使用精确的请求 ID 重新运行批准命令。
|
||||
通过精确的 `requestId` 批准待处理的设备配对请求。如果省略 `requestId` 或传入 `--latest`,OpenClaw 只会打印所选的待处理请求并退出;在核实详情后,请使用精确请求 ID 重新运行批准命令。
|
||||
|
||||
注意:如果设备使用变更后的认证详细信息(角色 / scopes / 公钥)重试配对,OpenClaw 会替换之前的待处理记录,并发出新的 `requestId`。请在批准前立刻运行 `openclaw devices list`,以使用当前 ID。
|
||||
注意:如果设备在认证详情发生变化后重试配对(角色/作用域/公钥),OpenClaw 会替换之前的待处理记录并签发新的 `requestId`。请在批准前立即运行 `openclaw devices list`,以使用当前 ID。
|
||||
|
||||
如果设备已经配对,并请求更宽的 scopes 或更高的角色,OpenClaw 会保留现有批准状态,并创建新的待处理升级请求。请查看 `openclaw devices list` 中的 `Requested` 和 `Approved` 列,或使用 `openclaw devices approve --latest` 在批准前预览准确的升级内容。
|
||||
如果设备已经配对,并请求更宽的作用域或更高权限的角色,OpenClaw 会保留现有批准,并创建新的待处理升级请求。请查看 `openclaw devices list` 中的 `Requested` 与 `Approved` 列,或使用 `openclaw devices approve --latest` 预览要批准的准确升级内容。
|
||||
|
||||
如果 Gateway 网关已显式配置 `gateway.nodes.pairing.autoApproveCidrs`,则来自匹配客户端 IP 的首次 `role: node` 请求,可能会在出现在此列表之前就被批准。该策略默认禁用,且绝不会应用于 operator/浏览器客户端或升级请求。
|
||||
|
||||
```
|
||||
openclaw devices approve
|
||||
@ -75,11 +77,11 @@ openclaw devices reject <requestId>
|
||||
|
||||
### `openclaw devices rotate --device <id> --role <role> [--scope <scope...>]`
|
||||
|
||||
为特定角色轮换设备令牌(可选更新 scopes)。
|
||||
目标角色必须已经存在于该设备已批准的配对契约中;轮换不能生成新的、未经批准的角色。
|
||||
如果你省略 `--scope`,以后使用存储的已轮换令牌重新连接时,将复用该令牌缓存的已批准 scopes。如果你显式传入 `--scope` 值,这些值将成为未来缓存令牌重连时存储的 scope 集合。
|
||||
非管理员的已配对设备调用方只能轮换**自己的**设备令牌。
|
||||
此外,任何显式的 `--scope` 值都必须保持在调用方当前会话自己的 operator scopes 范围内;轮换不能生成比调用方现有权限更宽的 operator 令牌。
|
||||
为特定角色轮换设备令牌(可选地更新作用域)。
|
||||
目标角色必须已经存在于该设备已批准的配对契约中;轮换不能生成一个新的、未获批准的角色。
|
||||
如果你省略 `--scope`,后续使用存储的已轮换令牌重新连接时,会复用该令牌缓存的已批准作用域。如果你传入显式的 `--scope` 值,这些值将成为未来缓存令牌重连时使用的已存储作用域集合。
|
||||
非管理员的已配对设备调用方只能轮换**自己的**设备令牌。
|
||||
此外,任何显式的 `--scope` 值都必须保持在调用方当前会话自身的 operator 作用域范围内;轮换不能生成比调用方现有权限更广的 operator 令牌。
|
||||
|
||||
```
|
||||
openclaw devices rotate --device <deviceId> --role operator --scope operator.read --scope operator.write
|
||||
@ -91,7 +93,7 @@ openclaw devices rotate --device <deviceId> --role operator --scope operator.rea
|
||||
|
||||
撤销特定角色的设备令牌。
|
||||
|
||||
非管理员的已配对设备调用方只能撤销**自己的**设备令牌。
|
||||
非管理员的已配对设备调用方只能撤销**自己的**设备令牌。
|
||||
撤销其他设备的令牌需要 `operator.admin`。
|
||||
|
||||
```
|
||||
@ -102,26 +104,28 @@ openclaw devices revoke --device <deviceId> --role node
|
||||
|
||||
## 常用选项
|
||||
|
||||
- `--url <url>`:Gateway 网关 WebSocket URL(配置后默认使用 `gateway.remote.url`)。
|
||||
- `--url <url>`:Gateway 网关 WebSocket URL(配置时默认使用 `gateway.remote.url`)。
|
||||
- `--token <token>`:Gateway 网关令牌(如需要)。
|
||||
- `--password <password>`:Gateway 网关密码(密码认证)。
|
||||
- `--timeout <ms>`:RPC 超时。
|
||||
- `--json`:JSON 输出(建议用于脚本)。
|
||||
- `--json`:JSON 输出(推荐用于脚本)。
|
||||
|
||||
注意:当你设置 `--url` 时,CLI 不会回退到配置或环境变量中的凭证。
|
||||
请显式传入 `--token` 或 `--password`。如果缺少显式凭证,将报错。
|
||||
注意:当你设置 `--url` 时,CLI 不会回退到配置或环境变量中的凭证。
|
||||
请显式传入 `--token` 或 `--password`。缺少显式凭证会报错。
|
||||
|
||||
## 说明
|
||||
|
||||
- 令牌轮换会返回一个新令牌(敏感信息)。请像对待机密一样处理它。
|
||||
- 这些命令需要 `operator.pairing`(或 `operator.admin`)scope。
|
||||
- 令牌轮换会保持在该设备已批准的配对角色集合和已批准 scope 基线之内。意外存在的缓存令牌记录不会授予新的轮换目标。
|
||||
- 对于已配对设备令牌会话,跨设备管理仅限管理员:`remove`、`rotate` 和 `revoke` 仅限管理自己的设备,除非调用方具有 `operator.admin`。
|
||||
- `devices clear` 会被 `--yes` 有意保护。
|
||||
- 如果 local loopback 上不可用配对 scope(且未显式传入 `--url`),`list` / `approve` 可以使用本地配对回退机制。
|
||||
- `devices approve` 在生成令牌前需要显式请求 ID;省略 `requestId` 或传入 `--latest` 只会预览最新的待处理请求。
|
||||
- 令牌轮换会返回一个新令牌(敏感)。请像对待密钥一样保管它。
|
||||
- 这些命令需要 `operator.pairing`(或 `operator.admin`)作用域。
|
||||
- `gateway.nodes.pairing.autoApproveCidrs` 是一个仅用于首次节点设备配对的可选启用 Gateway 网关策略;它不会改变 CLI 的批准权限。
|
||||
- 令牌轮换始终限制在该设备已批准的配对角色集和已批准的作用域基线内。零散的缓存令牌记录不会授予新的轮换目标。
|
||||
- 对于已配对设备令牌会话,跨设备管理仅限管理员:
|
||||
`remove`、`rotate` 和 `revoke` 默认仅允许操作自己,除非调用方具有 `operator.admin`。
|
||||
- `devices clear` 被有意用 `--yes` 进行保护。
|
||||
- 如果 local loopback 上没有可用的 pairing 作用域(且未传入显式 `--url`),`list/approve` 可以使用本地配对回退。
|
||||
- `devices approve` 在生成令牌之前需要显式请求 ID;省略 `requestId` 或传入 `--latest` 只会预览最新的待处理请求。
|
||||
|
||||
## 令牌漂移恢复检查清单
|
||||
## 令牌漂移恢复清单
|
||||
|
||||
当 Control UI 或其他客户端持续因 `AUTH_TOKEN_MISMATCH` 或 `AUTH_DEVICE_TOKEN_MISMATCH` 失败时,请使用此清单。
|
||||
|
||||
@ -143,7 +147,7 @@ openclaw devices list
|
||||
openclaw devices rotate --device <deviceId> --role operator
|
||||
```
|
||||
|
||||
4. 如果轮换还不够,请移除陈旧配对并重新批准:
|
||||
4. 如果轮换仍不够,请移除过期配对并重新批准:
|
||||
|
||||
```bash
|
||||
openclaw devices remove <deviceId>
|
||||
@ -151,19 +155,19 @@ openclaw devices list
|
||||
openclaw devices approve <requestId>
|
||||
```
|
||||
|
||||
5. 使用当前共享令牌 / 密码重试客户端连接。
|
||||
5. 使用当前共享令牌/密码重试客户端连接。
|
||||
|
||||
说明:
|
||||
|
||||
- 正常重连认证优先级依次为:显式共享令牌 / 密码,然后是显式 `deviceToken`,然后是存储的设备令牌,最后是 bootstrap 令牌。
|
||||
- 受信任的 `AUTH_TOKEN_MISMATCH` 恢复可以在一次受限重试中,临时同时发送共享令牌和存储的设备令牌。
|
||||
- 正常重连的认证优先级依次为:显式共享令牌/密码,然后是显式 `deviceToken`,然后是已存储设备令牌,最后是引导令牌。
|
||||
- 对于受信任的 `AUTH_TOKEN_MISMATCH` 恢复,可以在一次受限重试中临时同时发送共享令牌和已存储设备令牌。
|
||||
|
||||
相关内容:
|
||||
|
||||
- [Dashboard 认证故障排除](/zh-CN/web/dashboard#if-you-see-unauthorized-1008)
|
||||
- [Gateway 网关故障排除](/zh-CN/gateway/troubleshooting#dashboard-control-ui-connectivity)
|
||||
- [Dashboard auth troubleshooting](/zh-CN/web/dashboard#if-you-see-unauthorized-1008)
|
||||
- [Gateway troubleshooting](/zh-CN/gateway/troubleshooting#dashboard-control-ui-connectivity)
|
||||
|
||||
## 相关内容
|
||||
## 相关
|
||||
|
||||
- [CLI 参考](/zh-CN/cli)
|
||||
- [CLI reference](/zh-CN/cli)
|
||||
- [Nodes](/zh-CN/nodes)
|
||||
|
||||
@ -3,42 +3,39 @@ read_when:
|
||||
- 运行无头节点主机
|
||||
- 为 `system.run` 配对非 macOS 节点
|
||||
summary: '`openclaw node` 的 CLI 参考(无头节点主机)'
|
||||
title: 节点
|
||||
title: Node
|
||||
x-i18n:
|
||||
generated_at: "2026-04-24T06:43:56Z"
|
||||
generated_at: "2026-04-25T05:53:40Z"
|
||||
model: gpt-5.4
|
||||
provider: openai
|
||||
source_hash: 9f2bd6d61ee87d36f7691207d03a91c914e6460549256e0cc6ea7bebfa713923
|
||||
source_hash: d8c4b4697da3c0a4594dedd0033a114728ec599a7d33089a33e290e3cfafa5cd
|
||||
source_path: cli/node.md
|
||||
workflow: 15
|
||||
---
|
||||
|
||||
# `openclaw node`
|
||||
|
||||
运行一个**无头节点主机**,连接到 Gateway 网关 WebSocket,并在这台机器上暴露
|
||||
`system.run` / `system.which`。
|
||||
运行一个**无头节点主机**,将其连接到 Gateway 网关 WebSocket,并在这台机器上暴露 `system.run` / `system.which`。
|
||||
|
||||
## 为什么要使用节点主机?
|
||||
|
||||
当你希望智能体能够**在网络中的其他机器上运行命令**,而又不想在那里安装完整的 macOS 配套应用时,可以使用节点主机。
|
||||
当你希望智能体能够**在网络中的其他机器上运行命令**,而又不想在那些机器上安装完整的 macOS 配套应用时,可以使用节点主机。
|
||||
|
||||
常见用例:
|
||||
|
||||
- 在远程 Linux/Windows 机器上运行命令(构建服务器、实验室机器、NAS)。
|
||||
- 将 exec 保持在 Gateway 网关上**沙箱隔离**,但把已批准的运行委派给其他主机。
|
||||
- 在远程 Linux/Windows 主机上运行命令(构建服务器、实验室机器、NAS)。
|
||||
- 让 exec 在网关上保持**沙箱隔离**,但将获批的运行委派给其他主机。
|
||||
- 为自动化或 CI 节点提供轻量级、无头的执行目标。
|
||||
|
||||
执行仍然受到**exec 批准**和节点主机上按智能体划分的允许列表保护,因此你可以让命令访问保持在明确且受限的范围内。
|
||||
执行仍然受到**exec 审批**和节点主机上每个智能体允许列表的保护,因此你可以让命令访问范围保持明确且可控。
|
||||
|
||||
## 浏览器代理(零配置)
|
||||
|
||||
如果节点上的 `browser.enabled` 未被禁用,节点主机会自动公布一个浏览器代理。这样一来,智能体无需额外配置即可在该节点上使用浏览器自动化。
|
||||
如果节点上未禁用 `browser.enabled`,节点主机会自动发布浏览器代理。这使得智能体无需额外配置,就能在该节点上使用浏览器自动化。
|
||||
|
||||
默认情况下,该代理会暴露节点的常规浏览器配置文件表面。如果你设置了
|
||||
`nodeHost.browserProxy.allowProfiles`,代理将变为受限模式:
|
||||
不在允许列表中的配置文件目标会被拒绝,并且通过该代理会阻止持久化配置文件的创建/删除路由。
|
||||
默认情况下,该代理会暴露节点的常规浏览器配置文件能力范围。如果你设置了 `nodeHost.browserProxy.allowProfiles`,该代理就会变为限制模式:不在允许列表中的配置文件目标会被拒绝,并且通过代理访问持久化配置文件的创建/删除路由也会被阻止。
|
||||
|
||||
如有需要,可在节点上将其禁用:
|
||||
如有需要,可在节点上禁用它:
|
||||
|
||||
```json5
|
||||
{
|
||||
@ -60,25 +57,25 @@ openclaw node run --host <gateway-host> --port 18789
|
||||
|
||||
- `--host <host>`:Gateway 网关 WebSocket 主机(默认:`127.0.0.1`)
|
||||
- `--port <port>`:Gateway 网关 WebSocket 端口(默认:`18789`)
|
||||
- `--tls`:对 Gateway 网关连接使用 TLS
|
||||
- `--tls`:为网关连接使用 TLS
|
||||
- `--tls-fingerprint <sha256>`:预期的 TLS 证书指纹(sha256)
|
||||
- `--node-id <id>`:覆盖节点 id(会清除配对令牌)
|
||||
- `--display-name <name>`:覆盖节点显示名称
|
||||
|
||||
## 节点主机的 Gateway 网关认证
|
||||
|
||||
`openclaw node run` 和 `openclaw node install` 会从配置/环境变量中解析 Gateway 网关认证信息(节点命令不支持 `--token`/`--password` 标志):
|
||||
`openclaw node run` 和 `openclaw node install` 会从配置/环境变量解析网关认证信息(节点命令上没有 `--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.json` 配置键。
|
||||
当它存在于安装命令环境中时,`openclaw node install` 会将其持久化到受监管的节点服务中。
|
||||
对于连接到受信任私有网络中非 loopback `ws://` Gateway 网关的节点,请设置 `OPENCLAW_ALLOW_INSECURE_PRIVATE_WS=1`。否则,节点启动会以失败关闭,并提示你改用 `wss://`、SSH 隧道或 Tailscale。
|
||||
这是一个进程环境变量显式启用项,不是 `openclaw.json` 配置键。
|
||||
当它出现在安装命令环境中时,`openclaw node install` 会将其持久化到受监管的节点服务中。
|
||||
|
||||
## 服务(后台)
|
||||
|
||||
@ -92,14 +89,14 @@ openclaw node install --host <gateway-host> --port 18789
|
||||
|
||||
- `--host <host>`:Gateway 网关 WebSocket 主机(默认:`127.0.0.1`)
|
||||
- `--port <port>`:Gateway 网关 WebSocket 端口(默认:`18789`)
|
||||
- `--tls`:对 Gateway 网关连接使用 TLS
|
||||
- `--tls`:为网关连接使用 TLS
|
||||
- `--tls-fingerprint <sha256>`:预期的 TLS 证书指纹(sha256)
|
||||
- `--node-id <id>`:覆盖节点 id(会清除配对令牌)
|
||||
- `--display-name <name>`:覆盖节点显示名称
|
||||
- `--runtime <runtime>`:服务运行时(`node` 或 `bun`)
|
||||
- `--force`:如果已安装则重新安装/覆盖
|
||||
- `--force`:如果已安装,则重新安装/覆盖
|
||||
|
||||
管理服务:
|
||||
管理该服务:
|
||||
|
||||
```bash
|
||||
openclaw node status
|
||||
@ -108,38 +105,53 @@ 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>
|
||||
```
|
||||
|
||||
如果节点在认证详情发生变化(角色/作用域/公钥)后重试配对,之前的待处理请求会被替代,并创建新的 `requestId`。
|
||||
在严格受控的节点网络中,Gateway 网关操作员可以显式启用:对于来自受信任 CIDR 的首次节点配对自动批准:
|
||||
|
||||
```json5
|
||||
{
|
||||
gateway: {
|
||||
nodes: {
|
||||
pairing: {
|
||||
autoApproveCidrs: ["192.168.1.0/24"],
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
该功能默认禁用。它仅适用于没有请求作用域的全新 `role: node` 配对。操作员/浏览器客户端、Control UI、WebChat,以及角色、作用域、元数据或公钥升级,仍然需要手动批准。
|
||||
|
||||
如果节点使用变更后的认证详情(角色/作用域/公钥)重试配对,之前待处理的请求会被替代,并创建新的 `requestId`。
|
||||
请在批准前再次运行 `openclaw devices list`。
|
||||
|
||||
节点主机会将其节点 id、令牌、显示名称以及 Gateway 网关连接信息存储在
|
||||
`~/.openclaw/node.json` 中。
|
||||
节点主机会将其节点 id、令牌、显示名称和 Gateway 网关连接信息存储在 `~/.openclaw/node.json` 中。
|
||||
|
||||
## Exec 批准
|
||||
## Exec 审批
|
||||
|
||||
`system.run` 受本地 exec 批准控制:
|
||||
`system.run` 受本地 exec 审批控制:
|
||||
|
||||
- `~/.openclaw/exec-approvals.json`
|
||||
- [Exec 批准](/zh-CN/tools/exec-approvals)
|
||||
- [Exec 审批](/zh-CN/tools/exec-approvals)
|
||||
- `openclaw approvals --node <id|name|ip>`(从 Gateway 网关编辑)
|
||||
|
||||
对于已批准的异步节点 exec,OpenClaw 会在提示前准备规范化的 `systemRunPlan`。
|
||||
之后被批准的 `system.run` 转发会复用该已存储的计划,因此在批准请求创建之后对命令/cwd/session 字段的编辑将被拒绝,而不是改变节点实际执行的内容。
|
||||
对于已批准的异步节点 exec,OpenClaw 会在提示前准备一个规范的 `systemRunPlan`。
|
||||
之后获批的 `system.run` 转发会复用这个已存储的计划,因此在审批请求创建后对命令/cwd/会话字段的编辑会被拒绝,而不是改变节点实际执行的内容。
|
||||
|
||||
## 相关
|
||||
## 相关内容
|
||||
|
||||
- [CLI 参考](/zh-CN/cli)
|
||||
- [节点](/zh-CN/nodes)
|
||||
|
||||
@ -1,14 +1,14 @@
|
||||
---
|
||||
read_when:
|
||||
- 你正在管理已配对的节点(摄像头、屏幕、画布)
|
||||
- 你需要批准请求或调用节点命令
|
||||
- 你正在管理已配对的节点(相机、屏幕、画布)。
|
||||
- 你需要批准请求或调用节点命令。
|
||||
summary: '`openclaw nodes` 的 CLI 参考(status、pairing、invoke、camera/canvas/screen)'
|
||||
title: 节点
|
||||
x-i18n:
|
||||
generated_at: "2026-04-24T03:15:08Z"
|
||||
generated_at: "2026-04-25T05:53:58Z"
|
||||
model: gpt-5.4
|
||||
provider: openai
|
||||
source_hash: a1f1b440b3113b71338ae9cab5e1ded607dba79b9429f5c0b1b5f9e758b9f73e
|
||||
source_hash: 68a5701ce0dcba399d93f6eed864b0b0ae34320501de0176aeaad1712d392834
|
||||
source_path: cli/nodes.md
|
||||
workflow: 15
|
||||
---
|
||||
@ -19,11 +19,11 @@ x-i18n:
|
||||
|
||||
相关内容:
|
||||
|
||||
- 节点概览:[Nodes](/zh-CN/nodes)
|
||||
- 摄像头:[Camera nodes](/zh-CN/nodes/camera)
|
||||
- 图像:[Image nodes](/zh-CN/nodes/images)
|
||||
- 节点概览:[节点](/zh-CN/nodes)
|
||||
- 相机:[相机节点](/zh-CN/nodes/camera)
|
||||
- 图像:[图像节点](/zh-CN/nodes/images)
|
||||
|
||||
通用选项:
|
||||
常用选项:
|
||||
|
||||
- `--url`、`--token`、`--timeout`、`--json`
|
||||
|
||||
@ -42,15 +42,16 @@ openclaw nodes status --connected
|
||||
openclaw nodes status --last-connected 24h
|
||||
```
|
||||
|
||||
`nodes list` 会打印待处理/已配对表格。已配对行会包含最近一次连接的时间间隔(Last Connect)。
|
||||
使用 `--connected` 只显示当前已连接的节点。使用 `--last-connected <duration>` 可筛选出在指定时长内连接过的节点(例如 `24h`、`7d`)。
|
||||
`nodes list` 会打印待处理/已配对表格。已配对行包含最近一次连接的时间间隔(Last Connect)。
|
||||
使用 `--connected` 仅显示当前已连接的节点。使用 `--last-connected <duration>` 可筛选在某个时长内连接过的节点(例如 `24h`、`7d`)。
|
||||
|
||||
批准说明:
|
||||
|
||||
- `openclaw nodes pending` 仅需要 pairing 作用域。
|
||||
- `openclaw nodes approve <requestId>` 会继承待处理请求的额外作用域要求:
|
||||
- `openclaw nodes pending` 仅需要 pairing 范围。
|
||||
- `gateway.nodes.pairing.autoApproveCidrs` 仅对显式信任、首次进行 `role: node` 设备配对时可跳过待处理步骤。它默认关闭,且不会批准升级。
|
||||
- `openclaw nodes approve <requestId>` 会继承待处理请求的额外范围要求:
|
||||
- 无命令请求:仅 pairing
|
||||
- 非 exec 的节点命令:pairing + write
|
||||
- 非 exec 节点命令:pairing + write
|
||||
- `system.run` / `system.run.prepare` / `system.which`:pairing + admin
|
||||
|
||||
## 调用
|
||||
@ -61,15 +62,15 @@ openclaw nodes invoke --node <id|name|ip> --command <command> --params <json>
|
||||
|
||||
调用标志:
|
||||
|
||||
- `--params <json>`:JSON 对象字符串(默认为 `{}`)。
|
||||
- `--invoke-timeout <ms>`:节点调用超时(默认为 `15000`)。
|
||||
- `--params <json>`:JSON 对象字符串(默认 `{}`)。
|
||||
- `--invoke-timeout <ms>`:节点调用超时(默认 `15000`)。
|
||||
- `--idempotency-key <key>`:可选的幂等键。
|
||||
- 这里会阻止 `system.run` 和 `system.run.prepare`;如需执行 shell,请使用 `host=node` 的 `exec` 工具。
|
||||
- `system.run` 和 `system.run.prepare` 在此处被阻止;如需执行 shell,请使用 `host=node` 的 `exec` 工具。
|
||||
|
||||
如需在节点上执行 shell,请使用 `host=node` 的 `exec` 工具,而不是 `openclaw nodes run`。
|
||||
`nodes` CLI 现在聚焦于能力:通过 `nodes invoke` 进行直接 RPC,以及 pairing、摄像头、屏幕、位置、画布和通知。
|
||||
现在的 `nodes` CLI 以能力为中心:通过 `nodes invoke` 进行直接 RPC,并支持 pairing、相机、屏幕、位置、画布和通知。
|
||||
|
||||
## 相关内容
|
||||
|
||||
- [CLI reference](/zh-CN/cli)
|
||||
- [Nodes](/zh-CN/nodes)
|
||||
- [CLI 参考](/zh-CN/cli)
|
||||
- [节点](/zh-CN/nodes)
|
||||
|
||||
@ -2,32 +2,32 @@
|
||||
read_when:
|
||||
- 你正在 PI、Codex、ACP 或其他原生智能体运行时之间进行选择
|
||||
- 你对 Status 或配置中的提供商/模型/运行时标签感到困惑
|
||||
- 你正在为原生 harness 的支持一致性编写文档
|
||||
- 你正在为原生 harness 记录支持对齐情况
|
||||
summary: OpenClaw 如何区分模型提供商、模型、渠道和 Agent Runtimes
|
||||
title: Agent Runtimes
|
||||
x-i18n:
|
||||
generated_at: "2026-04-25T03:42:10Z"
|
||||
generated_at: "2026-04-25T05:54:03Z"
|
||||
model: gpt-5.4
|
||||
provider: openai
|
||||
source_hash: 5ccfdd0ac9e53f7196ff1884016b4bd890978de0c41a661f9264d2dde4c899b3
|
||||
source_hash: 6f492209da2334361060f0827c243d5d845744be906db9ef116ea00384879b33
|
||||
source_path: concepts/agent-runtimes.md
|
||||
workflow: 15
|
||||
---
|
||||
|
||||
**智能体运行时**是负责管理一个已准备好的模型循环的组件:它接收提示词,驱动模型输出,处理原生工具调用,并将完成的轮次返回给 OpenClaw。
|
||||
**智能体运行时**是负责一个已准备好模型循环的组件:它接收提示词,驱动模型输出,处理原生工具调用,并将完成的轮次返回给 OpenClaw。
|
||||
|
||||
运行时很容易与提供商混淆,因为两者都会出现在模型配置附近。它们是不同的层级:
|
||||
运行时很容易与提供商混淆,因为两者都会出现在模型配置附近。它们是不同的层:
|
||||
|
||||
| 层级 | 示例 | 含义 |
|
||||
| ------------- | ------------------------------------- | ------------------------------------------------------------------- |
|
||||
| 提供商 | `openai`, `anthropic`, `openai-codex` | OpenClaw 如何进行身份验证、发现模型并命名模型引用。 |
|
||||
| 提供商 | `openai`, `anthropic`, `openai-codex` | OpenClaw 如何进行认证、发现模型并命名模型引用。 |
|
||||
| 模型 | `gpt-5.5`, `claude-opus-4-6` | 为智能体轮次选择的模型。 |
|
||||
| Agent Runtimes | `pi`, `codex`, 由 ACP 支持的运行时 | 执行已准备轮次的底层循环。 |
|
||||
| Agent Runtimes | `pi`, `codex`, ACP 支持的运行时 | 执行已准备轮次的底层循环。 |
|
||||
| 渠道 | Telegram、Discord、Slack、WhatsApp | 消息进入和离开 OpenClaw 的位置。 |
|
||||
|
||||
你还会在代码和配置中看到 **harness** 这个词。harness 是提供智能体运行时的实现。例如,内置的 Codex harness 实现了 `codex` 运行时。出于兼容性原因,配置键仍然命名为 `embeddedHarness`,但面向用户的文档和 Status 输出通常应使用“运行时”。
|
||||
你还会在代码和配置中看到 **harness** 这个词。harness 是提供智能体运行时的实现。例如,内置的 Codex harness 实现了 `codex` 运行时。为了兼容性,配置键仍命名为 `embeddedHarness`,但面向用户的文档和 Status 输出通常应使用“运行时”。
|
||||
|
||||
常见的 Codex 设置使用 `openai` 提供商和 `codex` 运行时:
|
||||
常见的 Codex 设置会使用 `openai` 提供商和 `codex` 运行时:
|
||||
|
||||
```json5
|
||||
{
|
||||
@ -42,70 +42,70 @@ x-i18n:
|
||||
}
|
||||
```
|
||||
|
||||
这意味着 OpenClaw 选择一个 OpenAI 模型引用,然后请求 Codex app-server 运行时来运行嵌入式智能体轮次。这并不意味着渠道、模型提供商目录或 OpenClaw 会话存储会变成 Codex。
|
||||
这意味着 OpenClaw 选择一个 OpenAI 模型引用,然后请求 Codex app-server 运行时来运行嵌入式智能体轮次。这并不意味着渠道、模型提供商目录或 OpenClaw 会话存储变成了 Codex。
|
||||
|
||||
关于 OpenAI 系列前缀拆分,请参见 [OpenAI](/zh-CN/providers/openai) 和[模型提供商](/zh-CN/concepts/model-providers)。关于 Codex 运行时支持契约,请参见 [Codex harness](/zh-CN/plugins/codex-harness#v1-support-contract)。
|
||||
关于 OpenAI 系列前缀拆分,请参见 [OpenAI](/zh-CN/providers/openai) 和 [Model providers](/zh-CN/concepts/model-providers)。关于 Codex 运行时支持契约,请参见 [Codex harness](/zh-CN/plugins/codex-harness#v1-support-contract)。
|
||||
|
||||
## 运行时归属
|
||||
|
||||
不同的运行时负责循环中的不同部分。
|
||||
不同运行时负责循环中的不同部分。
|
||||
|
||||
| 界面 | OpenClaw PI embedded | Codex app-server |
|
||||
| 界面 | OpenClaw PI 嵌入式 | Codex app-server |
|
||||
| --------------------------- | --------------------------------------- | --------------------------------------------------------------------------- |
|
||||
| 模型循环所有者 | OpenClaw,通过 PI embedded runner | Codex app-server |
|
||||
| 规范线程状态 | OpenClaw transcript | Codex 线程,以及 OpenClaw transcript 镜像 |
|
||||
| 模型循环所有者 | OpenClaw 通过 PI 嵌入式运行器 | Codex app-server |
|
||||
| 规范线程状态 | OpenClaw 转录 | Codex 线程,加上 OpenClaw 转录镜像 |
|
||||
| OpenClaw 动态工具 | 原生 OpenClaw 工具循环 | 通过 Codex 适配器桥接 |
|
||||
| 原生 shell 和文件工具 | PI/OpenClaw 路径 | Codex 原生工具,在支持时通过原生钩子桥接 |
|
||||
| 上下文引擎 | 原生 OpenClaw 上下文组装 | OpenClaw projects 将上下文组装进 Codex 轮次 |
|
||||
| 压缩 | OpenClaw 或所选上下文引擎 | Codex 原生压缩,带有 OpenClaw 通知和镜像维护 |
|
||||
| 压缩 | OpenClaw 或选定的上下文引擎 | Codex 原生压缩,并带有 OpenClaw 通知和镜像维护 |
|
||||
| 渠道投递 | OpenClaw | OpenClaw |
|
||||
|
||||
这种归属划分是主要的设计规则:
|
||||
这种归属划分是主要设计规则:
|
||||
|
||||
- 如果某个界面由 OpenClaw 负责,OpenClaw 就可以提供常规的插件钩子行为。
|
||||
- 如果某个界面由原生运行时负责,OpenClaw 就需要运行时事件或原生钩子。
|
||||
- 如果原生运行时负责规范线程状态,OpenClaw 应该镜像并投射上下文,而不是重写不受支持的内部机制。
|
||||
- 如果 OpenClaw 拥有该界面,OpenClaw 就可以提供常规插件钩子行为。
|
||||
- 如果原生运行时拥有该界面,OpenClaw 就需要运行时事件或原生钩子。
|
||||
- 如果原生运行时拥有规范线程状态,OpenClaw 应该镜像并投射上下文,而不是重写不受支持的内部机制。
|
||||
|
||||
## 运行时选择
|
||||
|
||||
OpenClaw 会在提供商和模型解析之后选择一个嵌入式运行时:
|
||||
OpenClaw 会在提供商和模型解析之后选择嵌入式运行时:
|
||||
|
||||
1. 会话中记录的运行时优先生效。配置更改不会将现有 transcript 热切换到不同的原生线程系统。
|
||||
2. `OPENCLAW_AGENT_RUNTIME=<id>` 会强制新会话或已重置会话使用该运行时。
|
||||
3. `agents.defaults.embeddedHarness.runtime` 或 `agents.list[].embeddedHarness.runtime` 可以设置为 `auto`、`pi` 或已注册的运行时 id,例如 `codex`。
|
||||
4. 在 `auto` 模式下,已注册的插件运行时可以声明支持的提供商/模型对。
|
||||
5. 如果在 `auto` 模式下没有运行时声明某个轮次,且设置了 `fallback: "pi"`(默认值),OpenClaw 会使用 PI 作为兼容性回退。将 `fallback: "none"` 设置为不匹配的 `auto` 模式选择直接失败。
|
||||
1. 会话中记录的运行时优先。配置更改不会热切换现有转录到不同的原生线程系统。
|
||||
2. `OPENCLAW_AGENT_RUNTIME=<id>` 会为新的或重置的会话强制指定该运行时。
|
||||
3. `agents.defaults.embeddedHarness.runtime` 或 `agents.list[].embeddedHarness.runtime` 可以设置为 `auto`、`pi` 或已注册的运行时 ID,例如 `codex`。
|
||||
4. 在 `auto` 模式下,已注册的插件运行时可以声明支持的提供商/模型组合。
|
||||
5. 如果在 `auto` 模式下没有运行时认领某个轮次,并且设置了 `fallback: "pi"`(默认值),OpenClaw 会使用 PI 作为兼容性回退。将 `fallback: "none"` 设为无匹配 `auto` 模式选择时直接失败。
|
||||
|
||||
显式插件运行时默认会以封闭失败方式处理。例如,`runtime: "codex"` 表示要么使用 Codex,要么返回明确的选择错误,除非你在同一覆盖作用域中设置 `fallback: "pi"`。运行时覆盖不会继承更广泛的回退设置,因此,智能体级别的 `runtime: "codex"` 不会仅仅因为默认值使用了 `fallback: "pi"` 就被静默路由回 PI。
|
||||
显式插件运行时默认是失败关闭(fail closed)的。例如,`runtime: "codex"` 表示要么使用 Codex,要么产生明确的选择错误,除非你在相同覆盖作用域中设置 `fallback: "pi"`。运行时覆盖不会继承更广泛的回退设置,因此即使默认值使用了 `fallback: "pi"`,智能体级别的 `runtime: "codex"` 也不会被悄悄路由回 PI。
|
||||
|
||||
## 兼容性契约
|
||||
|
||||
当运行时不是 PI 时,它应当说明自己支持哪些 OpenClaw 界面。运行时文档应使用以下结构:
|
||||
当运行时不是 PI 时,它应记录自己支持哪些 OpenClaw 界面。运行时文档应使用以下结构:
|
||||
|
||||
| 问题 | 重要原因 |
|
||||
| -------------------------------------- | ------------------------------------------------------------------------------------------------- |
|
||||
| 谁负责模型循环? | 这决定了重试、工具续接和最终答案判断发生在哪里。 |
|
||||
| 谁负责规范线程历史? | 这决定了 OpenClaw 是可以编辑历史,还是只能镜像历史。 |
|
||||
| OpenClaw 动态工具是否可用? | 消息、会话、cron 和 OpenClaw 自有工具依赖这一点。 |
|
||||
| 动态工具钩子是否可用? | 插件期望在 OpenClaw 自有工具周围使用 `before_tool_call`、`after_tool_call` 和中间件。 |
|
||||
| 原生工具钩子是否可用? | shell、patch 和运行时自有工具需要原生钩子来实现策略与观测。 |
|
||||
| 上下文引擎生命周期是否运行? | Memory 和上下文插件依赖 assemble、ingest、after-turn 和 compaction 生命周期。 |
|
||||
| 暴露了哪些压缩数据? | 有些插件只需要通知,而有些则需要保留/丢弃元数据。 |
|
||||
| 哪些内容是有意不支持的? | 当原生运行时拥有更多状态时,用户不应假设它与 PI 等价。 |
|
||||
| 谁拥有模型循环? | 这决定了重试、工具续接和最终答案决策发生在哪里。 |
|
||||
| 谁拥有规范线程历史? | 这决定了 OpenClaw 是可以编辑历史,还是只能镜像它。 |
|
||||
| OpenClaw 动态工具是否可用? | 消息传递、会话、cron 和 OpenClaw 自有工具都依赖于此。 |
|
||||
| 动态工具钩子是否可用? | 插件期望围绕 OpenClaw 自有工具提供 `before_tool_call`、`after_tool_call` 和中间件。 |
|
||||
| 原生工具钩子是否可用? | shell、patch 和运行时自有工具需要原生钩子支持来实现策略和观测。 |
|
||||
| 上下文引擎生命周期是否运行? | 内存和上下文插件依赖 assemble、ingest、after-turn 和 compaction 生命周期。 |
|
||||
| 暴露了哪些压缩数据? | 某些插件只需要通知,而另一些则需要保留/丢弃元数据。 |
|
||||
| 哪些内容被有意不支持? | 当原生运行时拥有更多状态时,用户不应假定它与 PI 等价。 |
|
||||
|
||||
Codex 运行时支持契约记录在 [Codex harness](/zh-CN/plugins/codex-harness#v1-support-contract) 中。
|
||||
|
||||
## Status 标签
|
||||
|
||||
Status 输出可能同时显示 `Execution` 和 `Runtime` 标签。应将它们理解为诊断信息,而不是提供商名称。
|
||||
Status 输出可能同时显示 `Execution` 和 `Runtime` 标签。请将它们视为诊断信息,而不是提供商名称。
|
||||
|
||||
- 类似 `openai/gpt-5.5` 这样的模型引用会告诉你所选的提供商/模型。
|
||||
- 类似 `codex` 这样的运行时 id 会告诉你哪个循环正在执行该轮次。
|
||||
- 类似 Telegram 或 Discord 这样的渠道标签会告诉你对话发生在哪里。
|
||||
- 像 `openai/gpt-5.5` 这样的模型引用会告诉你所选的提供商/模型。
|
||||
- 像 `codex` 这样的运行时 ID 会告诉你是哪个循环在执行该轮次。
|
||||
- 像 Telegram 或 Discord 这样的渠道标签会告诉你对话发生在哪里。
|
||||
|
||||
如果在更改运行时配置后,会话仍然显示 PI,请使用 `/new` 开始新会话,或使用 `/reset` 清除当前会话。现有会话会保留其记录的运行时,这样 transcript 就不会通过两个不兼容的原生会话系统被重新播放。
|
||||
如果在更改运行时配置后,会话仍显示为 PI,请使用 `/new` 启动一个新会话,或使用 `/reset` 清除当前会话。现有会话会保留其已记录的运行时,这样同一份转录就不会通过两个不兼容的原生会话系统重放。
|
||||
|
||||
## 相关内容
|
||||
## 相关
|
||||
|
||||
- [Codex harness](/zh-CN/plugins/codex-harness)
|
||||
- [OpenAI](/zh-CN/providers/openai)
|
||||
|
||||
@ -1,84 +1,78 @@
|
||||
---
|
||||
read_when:
|
||||
- 你需要一份按提供商分类的模型设置参考文档
|
||||
- 你需要一份按提供商分类的模型设置参考资料
|
||||
- 你想要模型提供商的示例配置或 CLI 新手引导命令
|
||||
summary: 模型提供商概览,包含示例配置和 CLI 流程
|
||||
title: 模型提供商
|
||||
x-i18n:
|
||||
generated_at: "2026-04-25T04:09:43Z"
|
||||
generated_at: "2026-04-25T05:54:03Z"
|
||||
model: gpt-5.4
|
||||
provider: openai
|
||||
source_hash: 298eb377306ba5f02eab440775ce9171fab682ab9ede7c4443a994e594cf2b94
|
||||
source_hash: bdab460823e3138377a7e2b183b31caa64bb2eef4c9e77ebd8db0aacc97493bb
|
||||
source_path: concepts/model-providers.md
|
||||
workflow: 15
|
||||
---
|
||||
|
||||
此页面介绍的是 **LLM/模型提供商**(不是像 WhatsApp/Telegram 这样的聊天渠道)。
|
||||
关于模型选择规则,请参见 [/concepts/models](/zh-CN/concepts/models)。
|
||||
**LLM/模型提供商**参考(不是像 WhatsApp/Telegram 这样的聊天渠道)。有关模型选择规则,请参见 [Models](/zh-CN/concepts/models)。
|
||||
|
||||
## 快速规则
|
||||
|
||||
- 模型引用使用 `provider/model`(示例:`opencode/claude-opus-4-6`)。
|
||||
- 模型引用使用 `provider/model`(例如:`opencode/claude-opus-4-6`)。
|
||||
- 设置后,`agents.defaults.models` 会作为允许列表。
|
||||
- CLI 辅助命令:`openclaw onboard`、`openclaw models list`、`openclaw models set <provider/model>`。
|
||||
- `models.providers.*.models[].contextWindow` 是原生模型元数据;`contextTokens` 是运行时生效的上限。
|
||||
- 回退规则、冷却探测和会话覆盖持久化:请参见 [模型故障切换](/zh-CN/concepts/model-failover)。
|
||||
- OpenAI 系列路由具有前缀区分:`openai/<model>` 在 PI 中使用直接 OpenAI API 密钥提供商,`openai-codex/<model>` 在 PI 中使用 Codex OAuth,而 `openai/<model>` 加上 `agents.defaults.embeddedHarness.runtime: "codex"` 则使用原生 Codex app-server harness。请参见 [OpenAI](/zh-CN/providers/openai) 和 [Codex harness](/zh-CN/plugins/codex-harness)。如果你对提供商/运行时拆分感到困惑,请先阅读 [Agent Runtimes](/zh-CN/concepts/agent-runtimes)。
|
||||
- 插件自动启用遵循同样的边界:`openai-codex/<model>` 属于 OpenAI 插件,而 Codex 插件则由 `embeddedHarness.runtime: "codex"` 或旧版 `codex/<model>` 引用启用。
|
||||
- CLI 运行时也采用相同拆分:选择规范模型引用,例如 `anthropic/claude-*`、`google/gemini-*` 或 `openai/gpt-*`,然后在你希望使用本地 CLI 后端时,将 `agents.defaults.embeddedHarness.runtime` 设置为 `claude-cli`、`google-gemini-cli` 或 `codex-cli`。旧版 `claude-cli/*`、`google-gemini-cli/*` 和 `codex-cli/*` 引用会迁移回规范提供商引用,并将运行时单独记录。
|
||||
- GPT-5.5 当前可通过订阅/OAuth 路由使用:在 PI 中使用 `openai-codex/gpt-5.5`,或将 `openai/gpt-5.5` 与 Codex app-server harness 搭配使用。`openai/gpt-5.5` 的直接 API 密钥路由会在 OpenAI 于公共 API 上启用 GPT-5.5 后支持;在此之前,`OPENAI_API_KEY` 配置请使用已启用 API 的模型,例如 `openai/gpt-5.4`。
|
||||
- 回退规则、冷却探测和会话覆盖持久化:参见 [模型故障转移](/zh-CN/concepts/model-failover)。
|
||||
- OpenAI 系列路由按前缀区分:`openai/<model>` 在 PI 中使用直接的 OpenAI API 密钥提供商,`openai-codex/<model>` 在 PI 中使用 Codex OAuth,而 `openai/<model>` 加上 `agents.defaults.embeddedHarness.runtime: "codex"` 则使用原生 Codex app-server harness。参见 [OpenAI](/zh-CN/providers/openai) 和 [Codex harness](/zh-CN/plugins/codex-harness)。如果你对 provider/运行时的拆分感到困惑,请先阅读 [Agent Runtimes](/zh-CN/concepts/agent-runtimes)。
|
||||
- 插件自动启用遵循相同边界:`openai-codex/<model>` 属于 OpenAI 插件,而 Codex 插件则通过 `embeddedHarness.runtime: "codex"` 或旧版 `codex/<model>` 引用启用。
|
||||
- CLI 运行时也使用相同拆分:选择规范模型引用,例如 `anthropic/claude-*`、`google/gemini-*` 或 `openai/gpt-*`,然后在你想使用本地 CLI 后端时,将 `agents.defaults.embeddedHarness.runtime` 设为 `claude-cli`、`google-gemini-cli` 或 `codex-cli`。旧版 `claude-cli/*`、`google-gemini-cli/*` 和 `codex-cli/*` 引用会迁移回规范提供商引用,并将运行时单独记录。
|
||||
- GPT-5.5 当前通过订阅/OAuth 路由提供:PI 中使用 `openai-codex/gpt-5.5`,或使用带 Codex app-server harness 的 `openai/gpt-5.5`。`openai/gpt-5.5` 的直接 API 密钥路由会在 OpenAI 在公共 API 上启用 GPT-5.5 后受支持;在此之前,请为 `OPENAI_API_KEY` 配置使用已启用 API 的模型,例如 `openai/gpt-5.4`。
|
||||
|
||||
## 插件拥有的提供商行为
|
||||
## 由插件拥有的 provider 行为
|
||||
|
||||
大多数提供商特定逻辑都位于提供商插件中(`registerProvider(...)`),而 OpenClaw 保持通用推理循环。插件负责新手引导、模型目录、认证环境变量映射、传输/配置规范化、工具 schema 清理、故障切换分类、OAuth 刷新、使用情况上报、思考/推理配置等。
|
||||
大多数提供商特定逻辑都位于 provider 插件中(`registerProvider(...)`),而 OpenClaw 保留通用推理循环。插件负责新手引导、模型目录、认证环境变量映射、传输/配置规范化、工具 schema 清理、故障转移分类、OAuth 刷新、用量报告、thinking/reasoning 配置文件等。
|
||||
|
||||
提供商 SDK 钩子和内置插件示例的完整列表位于 [提供商插件](/zh-CN/plugins/sdk-provider-plugins)。如果某个提供商需要完全自定义的请求执行器,那将属于另一个更深层的扩展接口。
|
||||
完整的 provider SDK 钩子列表和内置插件示例见 [提供商插件](/zh-CN/plugins/sdk-provider-plugins)。如果某个提供商需要完全自定义的请求执行器,那属于另一个更深层的扩展面。
|
||||
|
||||
<Note>
|
||||
提供商运行时 `capabilities` 是共享的运行器元数据(提供商家族、转录/工具差异、传输/缓存提示)。它不同于[公开能力模型](/zh-CN/plugins/architecture#public-capability-model),后者描述的是一个插件注册了什么能力(文本推理、语音等)。
|
||||
provider 运行时 `capabilities` 是共享运行器元数据(provider 家族、转录/工具特性、传输/缓存提示)。它不同于[公开能力模型](/zh-CN/plugins/architecture#public-capability-model),后者描述的是插件注册了什么能力(文本推理、语音等)。
|
||||
</Note>
|
||||
|
||||
## API 密钥轮换
|
||||
|
||||
- 支持为选定提供商进行通用提供商轮换。
|
||||
- 通过以下方式配置多个密钥:
|
||||
- `OPENCLAW_LIVE_<PROVIDER>_KEY`(单个实时覆盖,优先级最高)
|
||||
- 支持所选提供商的通用提供商轮换。
|
||||
- 可通过以下方式配置多个密钥:
|
||||
- `OPENCLAW_LIVE_<PROVIDER>_KEY`(单个实时覆盖,最高优先级)
|
||||
- `<PROVIDER>_API_KEYS`(逗号或分号分隔列表)
|
||||
- `<PROVIDER>_API_KEY`(主密钥)
|
||||
- `<PROVIDER>_API_KEY_*`(编号列表,例如 `<PROVIDER>_API_KEY_1`)
|
||||
- 对于 Google 提供商,`GOOGLE_API_KEY` 也会作为回退项包含在内。
|
||||
- 对于 Google 提供商,还会将 `GOOGLE_API_KEY` 作为回退选项。
|
||||
- 密钥选择顺序会保留优先级并去重。
|
||||
- 仅在遇到限流响应时,请求才会使用下一个密钥重试(例如 `429`、`rate_limit`、`quota`、`resource exhausted`、`Too many
|
||||
concurrent requests`、`ThrottlingException`、`concurrency limit reached`、`workers_ai ... quota limit exceeded`,或周期性使用限制消息)。
|
||||
- 非限流失败会立即失败;不会尝试密钥轮换。
|
||||
- 当所有候选密钥都失败时,将返回最后一次尝试的最终错误。
|
||||
- 只有在收到速率限制响应时,请求才会使用下一个密钥重试(例如 `429`、`rate_limit`、`quota`、`resource exhausted`、`Too many concurrent requests`、`ThrottlingException`、`concurrency limit reached`、`workers_ai ... quota limit exceeded`,或周期性用量限制消息)。
|
||||
- 非速率限制失败会立即失败;不会尝试密钥轮换。
|
||||
- 当所有候选密钥都失败时,返回最后一次尝试的最终错误。
|
||||
|
||||
## 内置提供商(pi-ai 目录)
|
||||
|
||||
OpenClaw 附带 pi‑ai 目录。这些提供商**不需要**
|
||||
`models.providers` 配置;只需设置认证并选择一个模型。
|
||||
OpenClaw 自带 pi‑ai 目录。这些提供商**不需要** `models.providers` 配置;只需设置认证信息并选择模型。
|
||||
|
||||
### OpenAI
|
||||
|
||||
- 提供商:`openai`
|
||||
- Provider:`openai`
|
||||
- 认证:`OPENAI_API_KEY`
|
||||
- 可选轮换:`OPENAI_API_KEYS`、`OPENAI_API_KEY_1`、`OPENAI_API_KEY_2`,以及 `OPENCLAW_LIVE_OPENAI_KEY`(单个覆盖)
|
||||
- 示例模型:`openai/gpt-5.4`、`openai/gpt-5.4-mini`
|
||||
- 一旦 OpenAI 在 API 上开放 GPT-5.5,这里就已为 GPT-5.5 直接 API 支持做好准备
|
||||
- 在不使用 Codex app-server 运行时的情况下使用 `openai/gpt-5.5` 之前,请先通过 `openclaw models list --provider openai`
|
||||
验证直接 API 是否可用
|
||||
- 一旦 OpenAI 在 API 上公开 GPT-5.5,这里就已为 GPT-5.5 直接 API 支持做好准备
|
||||
- 在不使用 Codex app-server 运行时的情况下使用 `openai/gpt-5.5` 前,请先用 `openclaw models list --provider openai` 验证直接 API 可用性
|
||||
- CLI:`openclaw onboard --auth-choice openai-api-key`
|
||||
- 默认传输为 `auto`(优先 WebSocket,回退到 SSE)
|
||||
- 默认传输为 `auto`(优先 WebSocket,回退 SSE)
|
||||
- 可通过 `agents.defaults.models["openai/<model>"].params.transport` 按模型覆盖(`"sse"`、`"websocket"` 或 `"auto"`)
|
||||
- OpenAI Responses WebSocket 预热默认启用,通过 `params.openaiWsWarmup` 控制(`true`/`false`)
|
||||
- 可通过 `agents.defaults.models["openai/<model>"].params.serviceTier` 启用 OpenAI 优先级处理
|
||||
- OpenAI Responses WebSocket 预热默认通过 `params.openaiWsWarmup` 启用(`true`/`false`)
|
||||
- OpenAI 优先级处理可通过 `agents.defaults.models["openai/<model>"].params.serviceTier` 启用
|
||||
- `/fast` 和 `params.fastMode` 会将直接 `openai/*` Responses 请求映射为 `api.openai.com` 上的 `service_tier=priority`
|
||||
- 如果你想使用显式层级而不是共享的 `/fast` 开关,请使用 `params.serviceTier`
|
||||
- 隐藏的 OpenClaw 归因标头(`originator`、`version`、
|
||||
`User-Agent`)仅适用于发往 `api.openai.com` 的原生 OpenAI 流量,不适用于通用的 OpenAI 兼容代理
|
||||
- 原生 OpenAI 路由还会保留 Responses `store`、提示缓存提示,以及
|
||||
OpenAI 推理兼容负载整形;代理路由则不会
|
||||
- `openai/gpt-5.3-codex-spark` 在 OpenClaw 中被有意屏蔽,因为实时 OpenAI API 请求会拒绝它,而当前 Codex 目录也未公开它
|
||||
- 如果你想使用显式分层而不是共享的 `/fast` 开关,请使用 `params.serviceTier`
|
||||
- 隐藏的 OpenClaw 归因头(`originator`、`version`、`User-Agent`)仅适用于发往 `api.openai.com` 的原生 OpenAI 流量,不适用于通用 OpenAI 兼容代理
|
||||
- 原生 OpenAI 路由还会保留 Responses `store`、prompt-cache 提示以及 OpenAI reasoning 兼容载荷整形;代理路由则不会
|
||||
- `openai/gpt-5.3-codex-spark` 在 OpenClaw 中被有意抑制,因为实时 OpenAI API 请求会拒绝它,而当前 Codex 目录也未公开它
|
||||
|
||||
```json5
|
||||
{
|
||||
@ -88,14 +82,14 @@ OpenClaw 附带 pi‑ai 目录。这些提供商**不需要**
|
||||
|
||||
### Anthropic
|
||||
|
||||
- 提供商:`anthropic`
|
||||
- Provider:`anthropic`
|
||||
- 认证:`ANTHROPIC_API_KEY`
|
||||
- 可选轮换:`ANTHROPIC_API_KEYS`、`ANTHROPIC_API_KEY_1`、`ANTHROPIC_API_KEY_2`,以及 `OPENCLAW_LIVE_ANTHROPIC_KEY`(单个覆盖)
|
||||
- 示例模型:`anthropic/claude-opus-4-6`
|
||||
- CLI:`openclaw onboard --auth-choice apiKey`
|
||||
- 直接公共 Anthropic 请求支持共享的 `/fast` 开关和 `params.fastMode`,包括发送到 `api.anthropic.com` 的 API 密钥和 OAuth 认证流量;OpenClaw 会将其映射为 Anthropic 的 `service_tier`(`auto` 与 `standard_only`)
|
||||
- Anthropic 说明:Anthropic 员工告知我们,OpenClaw 风格的 Claude CLI 使用已再次被允许,因此除非 Anthropic 发布新政策,否则 OpenClaw 会将 Claude CLI 复用和 `claude -p` 用法视为该集成的许可方式。
|
||||
- Anthropic setup-token 仍然是 OpenClaw 支持的令牌路径,但 OpenClaw 现在在可用时优先选择 Claude CLI 复用和 `claude -p`。
|
||||
- 直接公共 Anthropic 请求支持共享的 `/fast` 开关和 `params.fastMode`,包括发送到 `api.anthropic.com` 的 API 密钥和 OAuth 认证流量;OpenClaw 会将其映射为 Anthropic `service_tier`(`auto` 或 `standard_only`)
|
||||
- Anthropic 说明:Anthropic 工作人员告诉我们,OpenClaw 风格的 Claude CLI 用法再次被允许,因此除非 Anthropic 发布新政策,否则 OpenClaw 会将 Claude CLI 复用和 `claude -p` 用法视为此集成的已授权方式。
|
||||
- Anthropic setup-token 仍作为 OpenClaw 支持的令牌路径提供,但 OpenClaw 现在在可用时更倾向于 Claude CLI 复用和 `claude -p`。
|
||||
|
||||
```json5
|
||||
{
|
||||
@ -105,26 +99,22 @@ OpenClaw 附带 pi‑ai 目录。这些提供商**不需要**
|
||||
|
||||
### OpenAI Codex OAuth
|
||||
|
||||
- 提供商:`openai-codex`
|
||||
- Provider:`openai-codex`
|
||||
- 认证:OAuth(ChatGPT)
|
||||
- PI 模型引用:`openai-codex/gpt-5.5`
|
||||
- 原生 Codex app-server harness 引用:`openai/gpt-5.5`,并设置 `agents.defaults.embeddedHarness.runtime: "codex"`
|
||||
- 原生 Codex app-server harness 引用:带 `agents.defaults.embeddedHarness.runtime: "codex"` 的 `openai/gpt-5.5`
|
||||
- 原生 Codex app-server harness 文档:[Codex harness](/zh-CN/plugins/codex-harness)
|
||||
- 旧版模型引用:`codex/gpt-*`
|
||||
- 插件边界:`openai-codex/*` 会加载 OpenAI 插件;原生 Codex
|
||||
app-server 插件只会由 Codex harness 运行时或旧版
|
||||
`codex/*` 引用选中。
|
||||
- 插件边界:`openai-codex/*` 加载 OpenAI 插件;原生 Codex app-server 插件仅通过 Codex harness 运行时或旧版 `codex/*` 引用选择
|
||||
- CLI:`openclaw onboard --auth-choice openai-codex` 或 `openclaw models auth login --provider openai-codex`
|
||||
- 默认传输为 `auto`(优先 WebSocket,回退到 SSE)
|
||||
- 默认传输为 `auto`(优先 WebSocket,回退 SSE)
|
||||
- 可通过 `agents.defaults.models["openai-codex/<model>"].params.transport` 按 PI 模型覆盖(`"sse"`、`"websocket"` 或 `"auto"`)
|
||||
- `params.serviceTier` 也会在原生 Codex Responses 请求中转发(`chatgpt.com/backend-api`)
|
||||
- 隐藏的 OpenClaw 归因标头(`originator`、`version`、
|
||||
`User-Agent`)仅附加在发往
|
||||
`chatgpt.com/backend-api` 的原生 Codex 流量上,不适用于通用 OpenAI 兼容代理
|
||||
- 与直接 `openai/*` 共享同样的 `/fast` 开关和 `params.fastMode` 配置;OpenClaw 会将其映射为 `service_tier=priority`
|
||||
- `openai-codex/gpt-5.5` 保留原生 `contextWindow = 1000000`,默认运行时 `contextTokens = 272000`;可通过 `models.providers.openai-codex.models[].contextTokens` 覆盖运行时上限
|
||||
- 策略说明:OpenAI Codex OAuth 明确支持用于 OpenClaw 这类外部工具/工作流。
|
||||
- 当前 GPT-5.5 访问使用此 OAuth/订阅路径,直到 OpenAI 在公共 API 上启用 GPT-5.5。
|
||||
- `params.serviceTier` 也会在原生 Codex Responses 请求(`chatgpt.com/backend-api`)上传递
|
||||
- 隐藏的 OpenClaw 归因头(`originator`、`version`、`User-Agent`)仅附加到发往 `chatgpt.com/backend-api` 的原生 Codex 流量,不适用于通用 OpenAI 兼容代理
|
||||
- 与直接 `openai/*` 共享相同的 `/fast` 开关和 `params.fastMode` 配置;OpenClaw 会将其映射为 `service_tier=priority`
|
||||
- `openai-codex/gpt-5.5` 保留原生 `contextWindow = 1000000` 和默认运行时 `contextTokens = 272000`;可通过 `models.providers.openai-codex.models[].contextTokens` 覆盖运行时上限
|
||||
- 策略说明:OpenAI Codex OAuth 明确支持像 OpenClaw 这样的外部工具/工作流。
|
||||
- 在 OpenAI 于公共 API 上启用 GPT-5.5 之前,当前 GPT-5.5 访问都通过此 OAuth/订阅路由进行。
|
||||
|
||||
```json5
|
||||
{
|
||||
@ -146,15 +136,15 @@ OpenClaw 附带 pi‑ai 目录。这些提供商**不需要**
|
||||
|
||||
### 其他订阅式托管选项
|
||||
|
||||
- [Qwen Cloud](/zh-CN/providers/qwen):Qwen Cloud 提供商接口,以及 Alibaba DashScope 和 Coding Plan 端点映射
|
||||
- [Qwen Cloud](/zh-CN/providers/qwen):Qwen Cloud provider 能力面,以及阿里巴巴 DashScope 和 Coding Plan 端点映射
|
||||
- [MiniMax](/zh-CN/providers/minimax):MiniMax Coding Plan OAuth 或 API 密钥访问
|
||||
- [GLM Models](/zh-CN/providers/glm):Z.AI Coding Plan 或通用 API 端点
|
||||
- [GLM models](/zh-CN/providers/glm):Z.AI Coding Plan 或通用 API 端点
|
||||
|
||||
### OpenCode
|
||||
|
||||
- 认证:`OPENCODE_API_KEY`(或 `OPENCODE_ZEN_API_KEY`)
|
||||
- Zen 运行时提供商:`opencode`
|
||||
- Go 运行时提供商:`opencode-go`
|
||||
- Zen 运行时 provider:`opencode`
|
||||
- Go 运行时 provider:`opencode-go`
|
||||
- 示例模型:`opencode/claude-opus-4-6`、`opencode-go/kimi-k2.6`
|
||||
- CLI:`openclaw onboard --auth-choice opencode-zen` 或 `openclaw onboard --auth-choice opencode-go`
|
||||
|
||||
@ -166,23 +156,20 @@ OpenClaw 附带 pi‑ai 目录。这些提供商**不需要**
|
||||
|
||||
### Google Gemini(API 密钥)
|
||||
|
||||
- 提供商:`google`
|
||||
- Provider:`google`
|
||||
- 认证:`GEMINI_API_KEY`
|
||||
- 可选轮换:`GEMINI_API_KEYS`、`GEMINI_API_KEY_1`、`GEMINI_API_KEY_2`、`GOOGLE_API_KEY` 回退项,以及 `OPENCLAW_LIVE_GEMINI_KEY`(单个覆盖)
|
||||
- 可选轮换:`GEMINI_API_KEYS`、`GEMINI_API_KEY_1`、`GEMINI_API_KEY_2`、`GOOGLE_API_KEY` 回退,以及 `OPENCLAW_LIVE_GEMINI_KEY`(单个覆盖)
|
||||
- 示例模型:`google/gemini-3.1-pro-preview`、`google/gemini-3-flash-preview`
|
||||
- 兼容性:旧版 OpenClaw 配置中使用的 `google/gemini-3.1-flash-preview` 会被规范化为 `google/gemini-3-flash-preview`
|
||||
- 兼容性:使用 `google/gemini-3.1-flash-preview` 的旧版 OpenClaw 配置会被规范化为 `google/gemini-3-flash-preview`
|
||||
- CLI:`openclaw onboard --auth-choice gemini-api-key`
|
||||
- 思考:`/think adaptive` 使用 Google 动态思考。Gemini 3/3.1 不包含固定的
|
||||
`thinkingLevel`;Gemini 2.5 发送 `thinkingBudget: -1`。
|
||||
- 直接 Gemini 运行也接受 `agents.defaults.models["google/<model>"].params.cachedContent`
|
||||
(或旧版 `cached_content`),以转发提供商原生的
|
||||
`cachedContents/...` 句柄;Gemini 缓存命中会显示为 OpenClaw `cacheRead`
|
||||
- Thinking:`/think adaptive` 使用 Google 动态 thinking。Gemini 3/3.1 不包含固定 `thinkingLevel`;Gemini 2.5 会发送 `thinkingBudget: -1`。
|
||||
- 直接 Gemini 运行还接受 `agents.defaults.models["google/<model>"].params.cachedContent`(或旧版 `cached_content`),以转发 provider 原生 `cachedContents/...` 句柄;Gemini 缓存命中会显示为 OpenClaw `cacheRead`
|
||||
|
||||
### Google Vertex 和 Gemini CLI
|
||||
|
||||
- 提供商:`google-vertex`、`google-gemini-cli`
|
||||
- Providers:`google-vertex`、`google-gemini-cli`
|
||||
- 认证:Vertex 使用 gcloud ADC;Gemini CLI 使用其 OAuth 流程
|
||||
- 注意:OpenClaw 中的 Gemini CLI OAuth 属于非官方集成。一些用户报告在使用第三方客户端后,其 Google 账号受到限制。若你选择继续,请查看 Google 条款并使用非关键账号。
|
||||
- 注意:OpenClaw 中的 Gemini CLI OAuth 属于非官方集成。一些用户报告称,在使用第三方客户端后其 Google 账号受到限制。若你选择继续,请先查看 Google 条款,并使用非关键账号。
|
||||
- Gemini CLI OAuth 作为内置 `google` 插件的一部分提供。
|
||||
- 先安装 Gemini CLI:
|
||||
- `brew install gemini-cli`
|
||||
@ -190,41 +177,35 @@ OpenClaw 附带 pi‑ai 目录。这些提供商**不需要**
|
||||
- 启用:`openclaw plugins enable google`
|
||||
- 登录:`openclaw models auth login --provider google-gemini-cli --set-default`
|
||||
- 默认模型:`google-gemini-cli/gemini-3-flash-preview`
|
||||
- 注意:你**不需要**将 client id 或 secret 粘贴到 `openclaw.json` 中。CLI 登录流程会将
|
||||
令牌存储在 Gateway 网关主机上的认证配置文件中。
|
||||
- 注意:你**不需要**将 client id 或 secret 粘贴到 `openclaw.json` 中。CLI 登录流程会将令牌存储在 Gateway 网关主机上的认证配置文件中。
|
||||
- 如果登录后请求失败,请在 Gateway 网关主机上设置 `GOOGLE_CLOUD_PROJECT` 或 `GOOGLE_CLOUD_PROJECT_ID`。
|
||||
- Gemini CLI JSON 响应会从 `response` 解析;使用情况会回退到
|
||||
`stats`,其中 `stats.cached` 会被规范化为 OpenClaw `cacheRead`。
|
||||
- Gemini CLI JSON 回复从 `response` 中解析;用量会回退到 `stats`,其中 `stats.cached` 会被规范化为 OpenClaw `cacheRead`。
|
||||
|
||||
### Z.AI(GLM)
|
||||
|
||||
- 提供商:`zai`
|
||||
- Provider:`zai`
|
||||
- 认证:`ZAI_API_KEY`
|
||||
- 示例模型:`zai/glm-5.1`
|
||||
- CLI:`openclaw onboard --auth-choice zai-api-key`
|
||||
- 别名:`z.ai/*` 和 `z-ai/*` 会规范化为 `zai/*`
|
||||
- `zai-api-key` 会自动检测匹配的 Z.AI 端点;`zai-coding-global`、`zai-coding-cn`、`zai-global` 和 `zai-cn` 会强制使用特定接口
|
||||
- 别名:`z.ai/*` 和 `z-ai/*` 会被规范化为 `zai/*`
|
||||
- `zai-api-key` 会自动检测匹配的 Z.AI 端点;`zai-coding-global`、`zai-coding-cn`、`zai-global` 和 `zai-cn` 会强制使用特定能力面
|
||||
|
||||
### Vercel AI Gateway
|
||||
|
||||
- 提供商:`vercel-ai-gateway`
|
||||
- Provider:`vercel-ai-gateway`
|
||||
- 认证:`AI_GATEWAY_API_KEY`
|
||||
- 示例模型:`vercel-ai-gateway/anthropic/claude-opus-4.6`、
|
||||
`vercel-ai-gateway/moonshotai/kimi-k2.6`
|
||||
- 示例模型:`vercel-ai-gateway/anthropic/claude-opus-4.6`、`vercel-ai-gateway/moonshotai/kimi-k2.6`
|
||||
- CLI:`openclaw onboard --auth-choice ai-gateway-api-key`
|
||||
|
||||
### Kilo Gateway 网关
|
||||
|
||||
- 提供商:`kilocode`
|
||||
- Provider:`kilocode`
|
||||
- 认证:`KILOCODE_API_KEY`
|
||||
- 示例模型:`kilocode/kilo/auto`
|
||||
- CLI:`openclaw onboard --auth-choice kilocode-api-key`
|
||||
- 基础 URL:`https://api.kilo.ai/api/gateway/`
|
||||
- 静态回退目录附带 `kilocode/kilo/auto`;实时
|
||||
`https://api.kilo.ai/api/gateway/models` 发现可进一步扩展运行时
|
||||
目录。
|
||||
- `kilocode/kilo/auto` 背后的确切上游路由由 Kilo Gateway 网关负责,
|
||||
并非在 OpenClaw 中硬编码。
|
||||
- Base URL:`https://api.kilo.ai/api/gateway/`
|
||||
- 静态回退目录内置了 `kilocode/kilo/auto`;实时 `https://api.kilo.ai/api/gateway/models` 发现还可以进一步扩展运行时目录。
|
||||
- `kilocode/kilo/auto` 背后的确切上游路由由 Kilo Gateway 网关负责,不是 OpenClaw 中硬编码的。
|
||||
|
||||
设置详情请参见 [/providers/kilocode](/zh-CN/providers/kilocode)。
|
||||
|
||||
@ -238,12 +219,12 @@ OpenClaw 附带 pi‑ai 目录。这些提供商**不需要**
|
||||
| DeepSeek | `deepseek` | `DEEPSEEK_API_KEY` | `deepseek/deepseek-v4-flash` |
|
||||
| GitHub Copilot | `github-copilot` | `COPILOT_GITHUB_TOKEN` / `GH_TOKEN` / `GITHUB_TOKEN` | — |
|
||||
| Groq | `groq` | `GROQ_API_KEY` | — |
|
||||
| Hugging Face Inference | `huggingface` | `HUGGINGFACE_HUB_TOKEN` or `HF_TOKEN` | `huggingface/deepseek-ai/DeepSeek-R1` |
|
||||
| Hugging Face Inference | `huggingface` | `HUGGINGFACE_HUB_TOKEN` 或 `HF_TOKEN` | `huggingface/deepseek-ai/DeepSeek-R1` |
|
||||
| Kilo Gateway 网关 | `kilocode` | `KILOCODE_API_KEY` | `kilocode/kilo/auto` |
|
||||
| Kimi Coding | `kimi` | `KIMI_API_KEY` or `KIMICODE_API_KEY` | `kimi/kimi-code` |
|
||||
| Kimi Coding | `kimi` | `KIMI_API_KEY` 或 `KIMICODE_API_KEY` | `kimi/kimi-code` |
|
||||
| MiniMax | `minimax` / `minimax-portal` | `MINIMAX_API_KEY` / `MINIMAX_OAUTH_TOKEN` | `minimax/MiniMax-M2.7` |
|
||||
| Mistral | `mistral` | `MISTRAL_API_KEY` | `mistral/mistral-large-latest` |
|
||||
| Moonshot | `moonshot` | `MOONSHOT_API_KEY` | `moonshot/kimi-k2.6` |
|
||||
| Moonshot AI | `moonshot` | `MOONSHOT_API_KEY` | `moonshot/kimi-k2.6` |
|
||||
| NVIDIA | `nvidia` | `NVIDIA_API_KEY` | `nvidia/nvidia/llama-3.1-nemotron-70b-instruct` |
|
||||
| OpenRouter | `openrouter` | `OPENROUTER_API_KEY` | `openrouter/auto` |
|
||||
| Qianfan | `qianfan` | `QIANFAN_API_KEY` | `qianfan/deepseek-v3.2` |
|
||||
@ -258,33 +239,29 @@ OpenClaw 附带 pi‑ai 目录。这些提供商**不需要**
|
||||
|
||||
一些值得了解的特殊行为:
|
||||
|
||||
- **OpenRouter** 仅在已验证的 `openrouter.ai` 路由上应用其应用归因标头和 Anthropic `cache_control` 标记。作为代理式 OpenAI 兼容路径,它会跳过仅原生 OpenAI 支持的整形逻辑(`serviceTier`、Responses `store`、提示缓存提示、OpenAI 推理兼容)。基于 Gemini 的引用仅保留代理 Gemini 思维签名清理。
|
||||
- **Kilo Gateway 网关** 中基于 Gemini 的引用遵循同样的代理 Gemini 清理路径;`kilocode/kilo/auto` 和其他不支持代理推理的引用会跳过代理推理注入。
|
||||
- **MiniMax** API 密钥新手引导会写入显式的纯文本 M2.7 聊天模型定义;图像理解仍由插件拥有的 `MiniMax-VL-01` 媒体提供商负责。
|
||||
- **OpenRouter** 仅在已验证的 `openrouter.ai` 路由上应用其应用归因头和 Anthropic `cache_control` 标记。DeepSeek、Moonshot 和 ZAI 引用可用于由 OpenRouter 管理的 prompt 缓存 TTL,但不会收到 Anthropic 缓存标记。作为代理风格的 OpenAI 兼容路径,它会跳过仅限原生 OpenAI 的整形(`serviceTier`、Responses `store`、prompt-cache 提示、OpenAI reasoning 兼容性)。Gemini 后端引用仅保留代理 Gemini thought-signature 清理。
|
||||
- **Kilo Gateway 网关** 的 Gemini 后端引用遵循相同的代理 Gemini 清理路径;`kilocode/kilo/auto` 和其他不支持代理 reasoning 的引用会跳过代理 reasoning 注入。
|
||||
- **MiniMax** API 密钥新手引导会写入显式的纯文本 M2.7 聊天模型定义;图像理解仍保留在由插件拥有的 `MiniMax-VL-01` 媒体 provider 上。
|
||||
- **xAI** 使用 xAI Responses 路径。`/fast` 或 `params.fastMode: true` 会将 `grok-3`、`grok-3-mini`、`grok-4` 和 `grok-4-0709` 重写为其 `*-fast` 变体。`tool_stream` 默认开启;可通过 `agents.defaults.models["xai/<model>"].params.tool_stream=false` 禁用。
|
||||
- **Cerebras** GLM 模型使用 `zai-glm-4.7` / `zai-glm-4.6`;OpenAI 兼容基础 URL 为 `https://api.cerebras.ai/v1`。
|
||||
- **Cerebras** GLM 模型使用 `zai-glm-4.7` / `zai-glm-4.6`;OpenAI 兼容 Base URL 为 `https://api.cerebras.ai/v1`。
|
||||
|
||||
## 通过 `models.providers` 使用提供商(自定义/基础 URL)
|
||||
## 通过 `models.providers` 的提供商(自定义/Base URL)
|
||||
|
||||
使用 `models.providers`(或 `models.json`)来添加**自定义**提供商或
|
||||
OpenAI/Anthropic 兼容代理。
|
||||
使用 `models.providers`(或 `models.json`)来添加**自定义**提供商或 OpenAI/Anthropic 兼容代理。
|
||||
|
||||
下方许多内置提供商插件已经发布了默认目录。
|
||||
仅当你想覆盖默认基础 URL、标头或模型列表时,
|
||||
才需要使用显式的 `models.providers.<id>` 条目。
|
||||
下面许多内置提供商插件已经发布了默认目录。
|
||||
只有当你想覆盖默认 Base URL、headers 或模型列表时,才需要使用显式的 `models.providers.<id>` 条目。
|
||||
|
||||
### Moonshot AI(Kimi)
|
||||
|
||||
Moonshot 作为内置提供商插件提供。默认请使用内置提供商,
|
||||
仅当你需要覆盖基础 URL 或模型元数据时,
|
||||
才添加显式的 `models.providers.moonshot` 条目:
|
||||
Moonshot 作为内置提供商插件提供。默认使用内置 provider,仅当你需要覆盖 Base URL 或模型元数据时,才添加显式 `models.providers.moonshot` 条目:
|
||||
|
||||
- 提供商:`moonshot`
|
||||
- Provider:`moonshot`
|
||||
- 认证:`MOONSHOT_API_KEY`
|
||||
- 示例模型:`moonshot/kimi-k2.6`
|
||||
- CLI:`openclaw onboard --auth-choice moonshot-api-key` 或 `openclaw onboard --auth-choice moonshot-api-key-cn`
|
||||
|
||||
Kimi K2 模型 ID:
|
||||
Kimi K2 模型 id:
|
||||
|
||||
[//]: # "moonshot-kimi-k2-model-refs:start"
|
||||
|
||||
@ -319,7 +296,7 @@ Kimi K2 模型 ID:
|
||||
|
||||
Kimi Coding 使用 Moonshot AI 的 Anthropic 兼容端点:
|
||||
|
||||
- 提供商:`kimi`
|
||||
- Provider:`kimi`
|
||||
- 认证:`KIMI_API_KEY`
|
||||
- 示例模型:`kimi/kimi-code`
|
||||
|
||||
@ -332,13 +309,13 @@ Kimi Coding 使用 Moonshot AI 的 Anthropic 兼容端点:
|
||||
}
|
||||
```
|
||||
|
||||
旧版 `kimi/k2p5` 仍然作为兼容模型 ID 被接受。
|
||||
旧版 `kimi/k2p5` 仍然作为兼容模型 id 被接受。
|
||||
|
||||
### Volcano Engine(Doubao)
|
||||
|
||||
Volcano Engine(火山引擎)在中国提供对 Doubao 和其他模型的访问。
|
||||
|
||||
- 提供商:`volcengine`(编码方案:`volcengine-plan`)
|
||||
- Provider:`volcengine`(编码:`volcengine-plan`)
|
||||
- 认证:`VOLCANO_ENGINE_API_KEY`
|
||||
- 示例模型:`volcengine-plan/ark-code-latest`
|
||||
- CLI:`openclaw onboard --auth-choice volcengine-api-key`
|
||||
@ -351,13 +328,9 @@ Volcano Engine(火山引擎)在中国提供对 Doubao 和其他模型的访
|
||||
}
|
||||
```
|
||||
|
||||
新手引导默认使用编码接口,但通用 `volcengine/*`
|
||||
目录会同时注册。
|
||||
新手引导默认使用编码能力面,但同时也会注册通用 `volcengine/*` 目录。
|
||||
|
||||
在新手引导/配置模型选择器中,Volcengine 认证选项会优先显示
|
||||
`volcengine/*` 和 `volcengine-plan/*` 两类条目。如果这些模型尚未加载,
|
||||
OpenClaw 会回退到未筛选目录,而不是显示一个空的
|
||||
按提供商范围过滤的选择器。
|
||||
在新手引导/配置模型选择器中,Volcengine 认证选项会优先显示 `volcengine/*` 和 `volcengine-plan/*` 两类条目。如果这些模型尚未加载,OpenClaw 会回退到未筛选目录,而不是显示一个空的 provider 作用域选择器。
|
||||
|
||||
可用模型:
|
||||
|
||||
@ -377,9 +350,9 @@ OpenClaw 会回退到未筛选目录,而不是显示一个空的
|
||||
|
||||
### BytePlus(国际版)
|
||||
|
||||
BytePlus ARK 为国际用户提供对与 Volcano Engine 相同模型的访问。
|
||||
BytePlus ARK 为国际用户提供与 Volcano Engine 相同模型的访问能力。
|
||||
|
||||
- 提供商:`byteplus`(编码方案:`byteplus-plan`)
|
||||
- Provider:`byteplus`(编码:`byteplus-plan`)
|
||||
- 认证:`BYTEPLUS_API_KEY`
|
||||
- 示例模型:`byteplus-plan/ark-code-latest`
|
||||
- CLI:`openclaw onboard --auth-choice byteplus-api-key`
|
||||
@ -392,13 +365,9 @@ BytePlus ARK 为国际用户提供对与 Volcano Engine 相同模型的访问。
|
||||
}
|
||||
```
|
||||
|
||||
新手引导默认使用编码接口,但通用 `byteplus/*`
|
||||
目录会同时注册。
|
||||
新手引导默认使用编码能力面,但同时也会注册通用 `byteplus/*` 目录。
|
||||
|
||||
在新手引导/配置模型选择器中,BytePlus(国际版)认证选项会优先显示
|
||||
`byteplus/*` 和 `byteplus-plan/*` 两类条目。如果这些模型尚未加载,
|
||||
OpenClaw 会回退到未筛选目录,而不是显示一个空的
|
||||
按提供商范围过滤的选择器。
|
||||
在新手引导/配置模型选择器中,BytePlus(国际版)认证选项会优先显示 `byteplus/*` 和 `byteplus-plan/*` 两类条目。如果这些模型尚未加载,OpenClaw 会回退到未筛选目录,而不是显示一个空的 provider 作用域选择器。
|
||||
|
||||
可用模型:
|
||||
|
||||
@ -416,9 +385,9 @@ OpenClaw 会回退到未筛选目录,而不是显示一个空的
|
||||
|
||||
### Synthetic
|
||||
|
||||
Synthetic 通过 `synthetic` 提供商提供 Anthropic 兼容模型:
|
||||
Synthetic 通过 `synthetic` provider 提供 Anthropic 兼容模型:
|
||||
|
||||
- 提供商:`synthetic`
|
||||
- Provider:`synthetic`
|
||||
- 认证:`SYNTHETIC_API_KEY`
|
||||
- 示例模型:`synthetic/hf:MiniMaxAI/MiniMax-M2.5`
|
||||
- CLI:`openclaw onboard --auth-choice synthetic-api-key`
|
||||
@ -450,31 +419,28 @@ MiniMax 通过 `models.providers` 配置,因为它使用自定义端点:
|
||||
- MiniMax OAuth(中国):`--auth-choice minimax-cn-oauth`
|
||||
- MiniMax API 密钥(全球):`--auth-choice minimax-global-api`
|
||||
- MiniMax API 密钥(中国):`--auth-choice minimax-cn-api`
|
||||
- 认证:`minimax` 使用 `MINIMAX_API_KEY`;`minimax-portal` 使用 `MINIMAX_OAUTH_TOKEN` 或
|
||||
`MINIMAX_API_KEY`
|
||||
- 认证:`minimax` 使用 `MINIMAX_API_KEY`;`minimax-portal` 使用 `MINIMAX_OAUTH_TOKEN` 或 `MINIMAX_API_KEY`
|
||||
|
||||
设置详情、模型选项和配置片段请参见 [/providers/minimax](/zh-CN/providers/minimax)。
|
||||
|
||||
在 MiniMax 的 Anthropic 兼容流式传输路径上,OpenClaw 默认禁用思考,
|
||||
除非你显式设置它;并且 `/fast on` 会将
|
||||
`MiniMax-M2.7` 重写为 `MiniMax-M2.7-highspeed`。
|
||||
在 MiniMax 的 Anthropic 兼容流式传输路径上,除非你显式设置,否则 OpenClaw 默认禁用 thinking;并且 `/fast on` 会将 `MiniMax-M2.7` 重写为 `MiniMax-M2.7-highspeed`。
|
||||
|
||||
插件拥有的能力拆分:
|
||||
由插件拥有的能力拆分:
|
||||
|
||||
- 文本/聊天默认使用 `minimax/MiniMax-M2.7`
|
||||
- 文本/聊天默认保持为 `minimax/MiniMax-M2.7`
|
||||
- 图像生成使用 `minimax/image-01` 或 `minimax-portal/image-01`
|
||||
- 图像理解在两种 MiniMax 认证路径上都使用由插件负责的 `MiniMax-VL-01`
|
||||
- Web 搜索保持使用提供商 id `minimax`
|
||||
- 图像理解在两种 MiniMax 认证路径上都使用由插件拥有的 `MiniMax-VL-01`
|
||||
- Web 搜索保持使用 provider id `minimax`
|
||||
|
||||
### LM Studio
|
||||
|
||||
LM Studio 作为内置提供商插件提供,并使用原生 API:
|
||||
|
||||
- 提供商:`lmstudio`
|
||||
- Provider:`lmstudio`
|
||||
- 认证:`LM_API_TOKEN`
|
||||
- 默认推理基础 URL:`http://localhost:1234/v1`
|
||||
- 默认推理 Base URL:`http://localhost:1234/v1`
|
||||
|
||||
然后设置一个模型(替换为 `http://localhost:1234/api/v1/models` 返回的其中一个 ID):
|
||||
然后设置一个模型(替换为 `http://localhost:1234/api/v1/models` 返回的某个 id):
|
||||
|
||||
```json5
|
||||
{
|
||||
@ -484,15 +450,14 @@ LM Studio 作为内置提供商插件提供,并使用原生 API:
|
||||
}
|
||||
```
|
||||
|
||||
OpenClaw 使用 LM Studio 原生的 `/api/v1/models` 和 `/api/v1/models/load`
|
||||
进行发现和自动加载,默认使用 `/v1/chat/completions` 进行推理。
|
||||
OpenClaw 使用 LM Studio 原生的 `/api/v1/models` 和 `/api/v1/models/load` 进行发现 + 自动加载,并默认使用 `/v1/chat/completions` 进行推理。
|
||||
设置和故障排除请参见 [/providers/lmstudio](/zh-CN/providers/lmstudio)。
|
||||
|
||||
### Ollama
|
||||
|
||||
Ollama 作为内置提供商插件提供,并使用 Ollama 的原生 API:
|
||||
Ollama 作为内置提供商插件提供,并使用 Ollama 原生 API:
|
||||
|
||||
- 提供商:`ollama`
|
||||
- Provider:`ollama`
|
||||
- 认证:无需(本地服务器)
|
||||
- 示例模型:`ollama/llama3.3`
|
||||
- 安装:[https://ollama.com/download](https://ollama.com/download)
|
||||
@ -510,26 +475,23 @@ ollama pull llama3.3
|
||||
}
|
||||
```
|
||||
|
||||
当你通过
|
||||
`OLLAMA_API_KEY` 选择启用时,系统会在本地 `http://127.0.0.1:11434` 检测 Ollama,内置提供商插件也会将 Ollama 直接添加到
|
||||
`openclaw onboard` 和模型选择器中。关于新手引导、云端/本地模式及自定义配置,请参见 [/providers/ollama](/zh-CN/providers/ollama)。
|
||||
当你通过 `OLLAMA_API_KEY` 显式启用时,系统会在本地 `http://127.0.0.1:11434` 检测 Ollama,并且内置 provider 插件会将 Ollama 直接加入 `openclaw onboard` 和模型选择器。有关新手引导、云端/本地模式和自定义配置,请参见 [/providers/ollama](/zh-CN/providers/ollama)。
|
||||
|
||||
### vLLM
|
||||
|
||||
vLLM 作为内置提供商插件提供,用于本地/自托管的 OpenAI 兼容
|
||||
服务器:
|
||||
vLLM 作为内置提供商插件提供,用于本地/自托管的 OpenAI 兼容服务器:
|
||||
|
||||
- 提供商:`vllm`
|
||||
- Provider:`vllm`
|
||||
- 认证:可选(取决于你的服务器)
|
||||
- 默认基础 URL:`http://127.0.0.1:8000/v1`
|
||||
- 默认 Base URL:`http://127.0.0.1:8000/v1`
|
||||
|
||||
要在本地选择启用自动发现(如果你的服务器不强制认证,则任意值都可以):
|
||||
若要在本地启用自动发现(如果你的服务器不强制认证,任意值都可):
|
||||
|
||||
```bash
|
||||
export VLLM_API_KEY="vllm-local"
|
||||
```
|
||||
|
||||
然后设置一个模型(替换为 `/v1/models` 返回的其中一个 ID):
|
||||
然后设置一个模型(替换为 `/v1/models` 返回的某个 id):
|
||||
|
||||
```json5
|
||||
{
|
||||
@ -543,21 +505,19 @@ export VLLM_API_KEY="vllm-local"
|
||||
|
||||
### SGLang
|
||||
|
||||
SGLang 作为内置提供商插件提供,用于快速自托管的
|
||||
OpenAI 兼容服务器:
|
||||
SGLang 作为内置提供商插件提供,用于高速自托管的 OpenAI 兼容服务器:
|
||||
|
||||
- 提供商:`sglang`
|
||||
- Provider:`sglang`
|
||||
- 认证:可选(取决于你的服务器)
|
||||
- 默认基础 URL:`http://127.0.0.1:30000/v1`
|
||||
- 默认 Base URL:`http://127.0.0.1:30000/v1`
|
||||
|
||||
要在本地选择启用自动发现(如果你的服务器不
|
||||
强制认证,则任意值都可以):
|
||||
若要在本地启用自动发现(如果你的服务器不强制认证,任意值都可):
|
||||
|
||||
```bash
|
||||
export SGLANG_API_KEY="sglang-local"
|
||||
```
|
||||
|
||||
然后设置一个模型(替换为 `/v1/models` 返回的其中一个 ID):
|
||||
然后设置一个模型(替换为 `/v1/models` 返回的某个 id):
|
||||
|
||||
```json5
|
||||
{
|
||||
@ -606,24 +566,19 @@ export SGLANG_API_KEY="sglang-local"
|
||||
|
||||
说明:
|
||||
|
||||
- 对于自定义提供商,`reasoning`、`input`、`cost`、`contextWindow` 和 `maxTokens` 都是可选的。
|
||||
省略时,OpenClaw 默认值为:
|
||||
- 对于自定义 provider,`reasoning`、`input`、`cost`、`contextWindow` 和 `maxTokens` 都是可选的。
|
||||
若省略,OpenClaw 默认值为:
|
||||
- `reasoning: false`
|
||||
- `input: ["text"]`
|
||||
- `cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }`
|
||||
- `contextWindow: 200000`
|
||||
- `maxTokens: 8192`
|
||||
- 建议:设置与你的代理/模型限制相匹配的显式值。
|
||||
- 对于非原生端点上的 `api: "openai-completions"`(任何非空 `baseUrl` 且其 host 不是 `api.openai.com`),OpenClaw 会强制设置 `compat.supportsDeveloperRole: false`,以避免提供商因不支持 `developer` 角色而返回 400 错误。
|
||||
- 代理式 OpenAI 兼容路由也会跳过仅原生 OpenAI 支持的请求
|
||||
整形逻辑:没有 `service_tier`,没有 Responses `store`,没有 Completions `store`,没有
|
||||
提示缓存提示,没有 OpenAI 推理兼容负载整形,也没有隐藏的
|
||||
OpenClaw 归因标头。
|
||||
- 对于需要厂商特定字段的 OpenAI 兼容 Completions 代理,
|
||||
请设置 `agents.defaults.models["provider/model"].params.extra_body`(或
|
||||
`extraBody`),以便将额外 JSON 合并到发送的请求体中。
|
||||
- 如果 `baseUrl` 为空/省略,OpenClaw 会保留默认 OpenAI 行为(即解析到 `api.openai.com`)。
|
||||
- 出于安全考虑,即使显式设置了 `compat.supportsDeveloperRole: true`,在非原生 `openai-completions` 端点上仍会被覆盖。
|
||||
- 对于非原生端点上的 `api: "openai-completions"`(任何非空 `baseUrl` 且其主机不是 `api.openai.com`),OpenClaw 会强制 `compat.supportsDeveloperRole: false`,以避免 provider 因不支持 `developer` 角色而返回 400 错误。
|
||||
- 代理风格的 OpenAI 兼容路由也会跳过仅限原生 OpenAI 的请求整形:不使用 `service_tier`,不使用 Responses `store`,不使用 Completions `store`,不使用 prompt-cache 提示,不使用 OpenAI reasoning 兼容载荷整形,也不添加隐藏的 OpenClaw 归因头。
|
||||
- 对于需要供应商特定字段的 OpenAI 兼容 Completions 代理,可设置 `agents.defaults.models["provider/model"].params.extra_body`(或 `extraBody`),以将额外 JSON 合并到出站请求体中。
|
||||
- 如果 `baseUrl` 为空/省略,OpenClaw 会保留默认 OpenAI 行为(会解析为 `api.openai.com`)。
|
||||
- 为安全起见,即使显式设置了 `compat.supportsDeveloperRole: true`,在非原生 `openai-completions` 端点上仍会被覆盖。
|
||||
|
||||
## CLI 示例
|
||||
|
||||
@ -633,11 +588,11 @@ openclaw models set opencode/claude-opus-4-6
|
||||
openclaw models list
|
||||
```
|
||||
|
||||
另请参见:[/gateway/configuration](/zh-CN/gateway/configuration) 了解完整配置示例。
|
||||
另见:[配置](/zh-CN/gateway/configuration),了解完整配置示例。
|
||||
|
||||
## 相关内容
|
||||
|
||||
- [Models](/zh-CN/concepts/models) — 模型配置和别名
|
||||
- [模型故障切换](/zh-CN/concepts/model-failover) — 回退链和重试行为
|
||||
- [模型故障转移](/zh-CN/concepts/model-failover) — 回退链和重试行为
|
||||
- [配置参考](/zh-CN/gateway/config-agents#agent-defaults) — 模型配置键
|
||||
- [Providers](/zh-CN/providers) — 各提供商设置指南
|
||||
- [Providers](/zh-CN/providers) — 每个 provider 的设置指南
|
||||
|
||||
@ -1,89 +1,88 @@
|
||||
---
|
||||
read_when:
|
||||
- 你想端到端地理解 OpenClaw OAuth
|
||||
- 你想端到端了解 OpenClaw OAuth
|
||||
- 你遇到了令牌失效 / 登出问题
|
||||
- 你想使用 Claude CLI 或 OAuth 认证流程
|
||||
- 你想使用多账号或配置文件路由
|
||||
summary: OpenClaw 中的 OAuth:令牌交换、存储与多账号模式
|
||||
- 你想了解 Claude CLI 或 OAuth 认证流程
|
||||
- 你想要多个账户或配置文件路由
|
||||
summary: OpenClaw 中的 OAuth:令牌交换、存储和多账户模式
|
||||
title: OAuth
|
||||
x-i18n:
|
||||
generated_at: "2026-04-25T00:54:54Z"
|
||||
generated_at: "2026-04-25T05:54:16Z"
|
||||
model: gpt-5.4
|
||||
provider: openai
|
||||
source_hash: 5fdff0aefba1db86b9fd07abdfc8f2f6f68b22af573c6a3c14f19d1a04d9d555
|
||||
source_hash: c793c52f48a3f49c0677d8e55a84c2bf5cdf0d385e6a858f26c0701d45583211
|
||||
source_path: concepts/oauth.md
|
||||
workflow: 15
|
||||
---
|
||||
|
||||
OpenClaw 支持通过 OAuth 使用提供商提供的“订阅认证”
|
||||
(尤其是 **OpenAI Codex(ChatGPT OAuth)**)。对于 Anthropic,当前实际上的划分
|
||||
是:
|
||||
OpenClaw 支持通过 OAuth 提供“订阅认证”,适用于提供该能力的提供商
|
||||
(尤其是 **OpenAI Codex(ChatGPT OAuth)**)。对于 Anthropic,目前更实际的划分
|
||||
如下:
|
||||
|
||||
- **Anthropic API key**:正常的 Anthropic API 计费
|
||||
- **Anthropic API 密钥**:标准 Anthropic API 计费
|
||||
- **Anthropic Claude CLI / OpenClaw 内的订阅认证**:Anthropic 员工
|
||||
告诉我们这种用法现已再次被允许
|
||||
告诉我们,这种用法现在再次被允许
|
||||
|
||||
OpenAI Codex OAuth 已明确支持在 OpenClaw 等外部工具中使用。本文说明:
|
||||
OpenAI Codex OAuth 已明确支持在 OpenClaw 这样的外部工具中使用。本页说明:
|
||||
|
||||
对于生产环境中的 Anthropic,API key 认证是更安全且推荐的路径。
|
||||
对于生产环境中的 Anthropic,API 密钥认证仍是更安全、推荐的路径。
|
||||
|
||||
- OAuth **令牌交换**如何工作(PKCE)
|
||||
- OAuth **令牌交换** 的工作方式(PKCE)
|
||||
- 令牌**存储**在哪里(以及原因)
|
||||
- 如何处理**多个账号**(配置文件 + 按会话覆盖)
|
||||
- 如何处理**多个账户**(配置文件 + 每会话覆盖)
|
||||
|
||||
OpenClaw 还支持自带 OAuth 或 API‑key
|
||||
流程的**提供商插件**。通过以下命令运行:
|
||||
OpenClaw 也支持自带 OAuth 或 API 密钥
|
||||
流程的**提供商插件**。可通过以下命令运行:
|
||||
|
||||
```bash
|
||||
openclaw models auth login --provider <id>
|
||||
```
|
||||
|
||||
## 令牌汇集点(为什么它存在)
|
||||
## 令牌汇聚点(为什么存在)
|
||||
|
||||
OAuth 提供商通常会在登录 / 刷新流程中签发**新的刷新令牌**。某些提供商(或 OAuth 客户端)可能会在为同一用户 / 应用签发新令牌时,使较旧的刷新令牌失效。
|
||||
OAuth 提供商通常会在登录/刷新流程中签发一个**新的刷新令牌**。某些提供商(或 OAuth 客户端)在为同一用户/应用签发新刷新令牌时,可能会使旧的刷新令牌失效。
|
||||
|
||||
实际症状:
|
||||
实际表现:
|
||||
|
||||
- 你通过 OpenClaw _以及_ Claude Code / Codex CLI 登录 → 之后其中一个会随机“被登出”
|
||||
- 你同时通过 OpenClaw _以及_ Claude Code / Codex CLI 登录 → 之后其中一个会随机出现“已登出”
|
||||
|
||||
为减少这种情况,OpenClaw 将 `auth-profiles.json` 视为**令牌汇集点**:
|
||||
为减少这种情况,OpenClaw 将 `auth-profiles.json` 视为一个**令牌汇聚点**:
|
||||
|
||||
- 运行时从**一个地方**读取凭证
|
||||
- 我们可以保留多个配置文件并进行确定性路由
|
||||
- 外部 CLI 复用取决于具体提供商:Codex CLI 可以初始化一个空的
|
||||
`openai-codex:default` 配置文件,但一旦 OpenClaw 拥有本地 OAuth 配置文件,
|
||||
本地刷新令牌就是规范来源;其他集成仍可保持外部管理,
|
||||
- 运行时从**一个位置**读取凭证
|
||||
- 我们可以保留多个配置文件,并以确定性的方式进行路由
|
||||
- 外部 CLI 复用是提供商特定的:Codex CLI 可以引导创建一个空的
|
||||
`openai-codex:default` 配置文件,但一旦 OpenClaw 已有本地 OAuth 配置文件,
|
||||
本地刷新令牌就是规范来源;其他集成可以继续由外部管理,
|
||||
并重新读取其 CLI 认证存储
|
||||
|
||||
## 存储(令牌存放在哪里)
|
||||
## 存储(令牌存放位置)
|
||||
|
||||
密钥按**每个智能体**存储:
|
||||
|
||||
- 认证配置文件(OAuth + API keys + 可选的值级引用):`~/.openclaw/agents/<agentId>/agent/auth-profiles.json`
|
||||
- 认证配置文件(OAuth + API 密钥 + 可选的值级引用):`~/.openclaw/agents/<agentId>/agent/auth-profiles.json`
|
||||
- 旧版兼容文件:`~/.openclaw/agents/<agentId>/agent/auth.json`
|
||||
(发现静态 `api_key` 条目时会被清理)
|
||||
(发现静态 `api_key` 条目时会被清除)
|
||||
|
||||
仅用于旧版导入的文件(仍受支持,但不是主存储):
|
||||
仅用于导入的旧版文件(仍受支持,但不是主存储):
|
||||
|
||||
- `~/.openclaw/credentials/oauth.json`(首次使用时会导入到 `auth-profiles.json`)
|
||||
|
||||
以上所有路径也都遵循 `$OPENCLAW_STATE_DIR`(状态目录覆盖)。完整参考:[/gateway/configuration](/zh-CN/gateway/configuration-reference#auth-storage)
|
||||
|
||||
有关静态密钥引用和运行时快照激活行为,请参见 [Secrets Management](/zh-CN/gateway/secrets)。
|
||||
关于静态 SecretRef 和运行时快照激活行为,请参见[密钥管理](/zh-CN/gateway/secrets)。
|
||||
|
||||
## Anthropic 旧版令牌兼容性
|
||||
|
||||
<Warning>
|
||||
Anthropic 的公开 Claude Code 文档指出,直接使用 Claude Code 会保持在
|
||||
Claude 订阅限制范围内,而 Anthropic 员工告诉我们,类似 OpenClaw 的 Claude
|
||||
CLI 用法现已再次被允许。因此,除非 Anthropic 发布新政策,
|
||||
否则 OpenClaw 将 Claude CLI 复用和 `claude -p` 用法视为该集成中被认可的方式。
|
||||
Anthropic 的公开 Claude Code 文档说明,直接使用 Claude Code 仍然受
|
||||
Claude 订阅额度约束,而 Anthropic 员工告诉我们,像 OpenClaw 这样使用 Claude
|
||||
CLI 的方式现在再次被允许。因此,除非 Anthropic 发布新的政策,
|
||||
否则 OpenClaw 会将 Claude CLI 复用和 `claude -p` 用法视为此集成中被认可的方式。
|
||||
|
||||
有关 Anthropic 当前直接使用 Claude Code 的套餐文档,请参见 [Using Claude Code
|
||||
with your Pro or Max
|
||||
plan](https://support.claude.com/en/articles/11145838-using-claude-code-with-your-pro-or-max-plan)
|
||||
和 [Using Claude Code with your Team or Enterprise
|
||||
plan](https://support.anthropic.com/en/articles/11845131-using-claude-code-with-your-team-or-enterprise-plan/)。
|
||||
关于 Anthropic 当前直接使用 Claude Code 的套餐文档,请参见 [在你的 Pro 或 Max
|
||||
套餐中使用 Claude Code](https://support.claude.com/en/articles/11145838-using-claude-code-with-your-pro-or-max-plan)
|
||||
以及 [在你的 Team 或 Enterprise
|
||||
套餐中使用 Claude Code](https://support.anthropic.com/en/articles/11845131-using-claude-code-with-your-team-or-enterprise-plan/)。
|
||||
|
||||
如果你想在 OpenClaw 中使用其他订阅式选项,请参见 [OpenAI
|
||||
Codex](/zh-CN/providers/openai)、[Qwen Cloud Coding
|
||||
@ -91,25 +90,25 @@ Plan](/zh-CN/providers/qwen)、[MiniMax Coding Plan](/zh-CN/providers/minimax)
|
||||
以及 [Z.AI / GLM Coding Plan](/zh-CN/providers/glm)。
|
||||
</Warning>
|
||||
|
||||
OpenClaw 还将 Anthropic setup-token 暴露为受支持的基于令牌的认证路径,但现在在可用时会优先使用 Claude CLI 复用和 `claude -p`。
|
||||
OpenClaw 也将 Anthropic setup-token 作为受支持的基于令牌的认证路径公开提供,但在可用时,现在更优先推荐复用 Claude CLI 和使用 `claude -p`。
|
||||
|
||||
## Anthropic Claude CLI 迁移
|
||||
|
||||
OpenClaw 现已再次支持复用 Anthropic Claude CLI。如果你在主机上已经有本地
|
||||
Claude 登录,onboarding / configure 可以直接复用它。
|
||||
OpenClaw 再次支持复用 Anthropic Claude CLI。如果主机上已经有本地
|
||||
Claude 登录,新手引导/配置可以直接复用它。
|
||||
|
||||
## OAuth 交换(登录如何工作)
|
||||
|
||||
OpenClaw 的交互式登录流程由 `@mariozechner/pi-ai` 实现,并接入到向导 / 命令中。
|
||||
OpenClaw 的交互式登录流程是在 `@mariozechner/pi-ai` 中实现的,并接入了向导/命令。
|
||||
|
||||
### Anthropic setup-token
|
||||
|
||||
流程形态:
|
||||
|
||||
1. 从 OpenClaw 启动 Anthropic setup-token 或 paste-token
|
||||
2. OpenClaw 将生成的 Anthropic 凭证存储到认证配置文件中
|
||||
3. 模型选择保持在 `anthropic/...`
|
||||
4. 现有的 Anthropic 认证配置文件仍可用于回滚 / 顺序控制
|
||||
1. 从 OpenClaw 启动 Anthropic setup-token,或粘贴令牌
|
||||
2. OpenClaw 将生成的 Anthropic 凭证存储到一个认证配置文件中
|
||||
3. 模型选择保持为 `anthropic/...`
|
||||
4. 现有的 Anthropic 认证配置文件仍可用于回退/顺序控制
|
||||
|
||||
### OpenAI Codex(ChatGPT OAuth)
|
||||
|
||||
@ -117,11 +116,11 @@ OpenAI Codex OAuth 已明确支持在 Codex CLI 之外使用,包括 OpenClaw
|
||||
|
||||
流程形态(PKCE):
|
||||
|
||||
1. 生成 PKCE verifier/challenge + 随机 `state`
|
||||
1. 生成 PKCE verifier/challenge 和随机 `state`
|
||||
2. 打开 `https://auth.openai.com/oauth/authorize?...`
|
||||
3. 尝试在 `http://127.0.0.1:1455/auth/callback` 捕获回调
|
||||
4. 如果无法绑定回调(或者你处于远程 / 无头环境),粘贴重定向 URL / code
|
||||
5. 在 `https://auth.openai.com/oauth/token` 交换
|
||||
4. 如果无法绑定回调(或者你处于远程/无头环境),则粘贴重定向 URL/代码
|
||||
5. 在 `https://auth.openai.com/oauth/token` 交换令牌
|
||||
6. 从访问令牌中提取 `accountId`,并存储 `{ access, refresh, expires, accountId }`
|
||||
|
||||
向导路径为 `openclaw onboard` → 认证选项 `openai-codex`。
|
||||
@ -132,55 +131,55 @@ OpenAI Codex OAuth 已明确支持在 Codex CLI 之外使用,包括 OpenClaw
|
||||
|
||||
在运行时:
|
||||
|
||||
- 如果 `expires` 还在未来 → 使用已存储的访问令牌
|
||||
- 如果已过期 → 刷新(在文件锁保护下)并覆盖已存储的凭证
|
||||
- 如果 `expires` 仍在未来 → 使用已存储的访问令牌
|
||||
- 如果已过期 → 刷新(在文件锁保护下),并覆盖已存储的凭证
|
||||
- 例外:某些外部 CLI 凭证仍由外部管理;OpenClaw
|
||||
会重新读取这些 CLI 认证存储,而不是使用复制来的刷新令牌。
|
||||
Codex CLI 初始化的范围被有意限制得更窄:它会植入一个空的
|
||||
`openai-codex:default` 配置文件,之后由 OpenClaw 拥有的刷新流程保持本地
|
||||
Codex CLI 引导的范围被有意收窄:它会初始化一个空的
|
||||
`openai-codex:default` 配置文件,然后由 OpenClaw 自主刷新的结果保持该本地
|
||||
配置文件为规范来源。
|
||||
|
||||
刷新流程是自动的;通常你不需要手动管理令牌。
|
||||
|
||||
## 多个账号(配置文件)+ 路由
|
||||
## 多个账户(配置文件)+ 路由
|
||||
|
||||
有两种模式:
|
||||
两种模式:
|
||||
|
||||
### 1)首选:分离的智能体
|
||||
|
||||
如果你希望“个人”和“工作”永不互相影响,请使用隔离的智能体(独立的会话 + 凭证 + 工作区):
|
||||
如果你希望“个人”和“工作”彼此完全隔离,请使用独立的智能体(独立会话 + 凭证 + 工作区):
|
||||
|
||||
```bash
|
||||
openclaw agents add work
|
||||
openclaw agents add personal
|
||||
```
|
||||
|
||||
然后按每个智能体配置认证(通过向导),并将聊天路由到正确的智能体。
|
||||
然后按每个智能体配置认证(向导),并将聊天路由到正确的智能体。
|
||||
|
||||
### 2)高级:单个智能体中的多个配置文件
|
||||
|
||||
`auth-profiles.json` 支持同一提供商的多个配置文件 ID。
|
||||
`auth-profiles.json` 支持同一提供商使用多个配置文件 ID。
|
||||
|
||||
选择使用哪个配置文件:
|
||||
|
||||
- 通过配置顺序(`auth.order`)进行全局选择
|
||||
- 通过 `/model ...@<profileId>` 按会话选择
|
||||
- 通过配置顺序全局选择(`auth.order`)
|
||||
- 通过 `/model ...@<profileId>` 按会话覆盖
|
||||
|
||||
示例(会话覆盖):
|
||||
|
||||
- `/model Opus@anthropic:work`
|
||||
|
||||
如何查看有哪些配置文件 ID:
|
||||
如何查看现有的配置文件 ID:
|
||||
|
||||
- `openclaw channels list --json`(显示 `auth[]`)
|
||||
|
||||
相关文档:
|
||||
|
||||
- [/concepts/model-failover](/zh-CN/concepts/model-failover)(轮换 + 冷却规则)
|
||||
- [/tools/slash-commands](/zh-CN/tools/slash-commands)(命令界面)
|
||||
- [模型故障切换](/zh-CN/concepts/model-failover)(轮换 + 冷却规则)
|
||||
- [斜杠命令](/zh-CN/tools/slash-commands)(命令界面)
|
||||
|
||||
## 相关内容
|
||||
|
||||
- [Authentication](/zh-CN/gateway/authentication) —— 模型提供商认证概览
|
||||
- [Secrets](/zh-CN/gateway/secrets) —— 凭证存储和 SecretRef
|
||||
- [Configuration Reference](/zh-CN/gateway/configuration-reference#auth-storage) —— 认证配置键
|
||||
- [认证](/zh-CN/gateway/authentication) — 模型提供商认证概览
|
||||
- [密钥](/zh-CN/gateway/secrets) — 凭证存储和 SecretRef
|
||||
- [配置参考](/zh-CN/gateway/configuration-reference#auth-storage) — 认证配置键
|
||||
|
||||
@ -1,190 +1,188 @@
|
||||
---
|
||||
read_when:
|
||||
- 解释流式传输或分块处理在渠道上的工作方式
|
||||
- 解释渠道上的流式传输或分块处理如何工作
|
||||
- 更改分块流式传输或渠道分块处理行为
|
||||
- 调试重复或过早的分块回复,或渠道预览流式传输
|
||||
summary: 流式传输 + 分块处理行为(分块回复、渠道预览流式传输、模式映射)
|
||||
title: 流式传输和分块处理
|
||||
x-i18n:
|
||||
generated_at: "2026-04-25T04:55:02Z"
|
||||
generated_at: "2026-04-25T05:54:11Z"
|
||||
model: gpt-5.4
|
||||
provider: openai
|
||||
source_hash: 5e81bc00f1f34de53e1d98309f23c057274787693ea4a44ac27c2db38cfa5b5a
|
||||
source_hash: 62ef14522254bace9af6966c97fdf16d7ac72e84dbb9d26af7d80f120715a650
|
||||
source_path: concepts/streaming.md
|
||||
workflow: 15
|
||||
---
|
||||
|
||||
# 流式传输 + 分块处理
|
||||
|
||||
OpenClaw 有两个独立的流式传输层:
|
||||
|
||||
- **分块流式传输(渠道):** 在助手写作时,随着完整的 **块** 完成而发出。这些是普通的渠道消息(不是 token 增量)。
|
||||
- **预览流式传输(Telegram/Discord/Slack):** 在生成过程中更新一个临时的 **预览消息**。
|
||||
- **分块流式传输(渠道):** 在助手写作时,发送已完成的 **块**。这些是普通的渠道消息(不是 token 增量)。
|
||||
- **预览流式传输(Telegram/Discord/Slack):** 在生成过程中更新一条临时的 **预览消息**。
|
||||
|
||||
目前,渠道消息 **没有真正的 token 增量流式传输**。预览流式传输是基于消息的(发送 + 编辑/追加)。
|
||||
当前**没有真正的 token 增量流式传输**发送到渠道消息。预览流式传输是基于消息的(发送 + 编辑/追加)。
|
||||
|
||||
## 分块流式传输(渠道消息)
|
||||
|
||||
分块流式传输会在助手输出可用时,以较粗粒度的块发送出去。
|
||||
分块流式传输会在助手输出可用时,以较粗粒度的块发送内容。
|
||||
|
||||
```text
|
||||
模型输出
|
||||
```
|
||||
Model output
|
||||
└─ text_delta/events
|
||||
├─ (blockStreamingBreak=text_end)
|
||||
│ └─ 随着缓冲区增长,chunker 发出块
|
||||
└─ (blockStreamingBreak=message_end)
|
||||
└─ chunker 在 message_end 时刷新
|
||||
└─ 渠道发送(分块回复)
|
||||
├─ (blockStreamingBreak=text_end)
|
||||
│ └─ chunker emits blocks as buffer grows
|
||||
└─ (blockStreamingBreak=message_end)
|
||||
└─ chunker flushes at message_end
|
||||
└─ channel send (block replies)
|
||||
```
|
||||
|
||||
图例:
|
||||
|
||||
- `text_delta/events`:模型流事件(对于非流式模型,可能较为稀疏)。
|
||||
- `chunker`:应用最小/最大边界 + 断点偏好的 `EmbeddedBlockChunker`。
|
||||
- `channel send`:实际发出的出站消息(分块回复)。
|
||||
- `text_delta/events`:模型流事件(对于非流式模型,事件可能较少)。
|
||||
- `chunker`:`EmbeddedBlockChunker`,应用最小/最大边界以及断点偏好。
|
||||
- `channel send`:实际发出的消息(分块回复)。
|
||||
|
||||
**控制项:**
|
||||
|
||||
- `agents.defaults.blockStreamingDefault`:`"on"`/`"off"`(默认关闭)。
|
||||
- 渠道覆盖:`*.blockStreaming`(以及每账户变体)可按渠道强制设为 `"on"`/`"off"`。
|
||||
- 渠道覆盖项:`*.blockStreaming`(以及每个账号的变体),用于按渠道强制设为 `"on"`/`"off"`。
|
||||
- `agents.defaults.blockStreamingBreak`:`"text_end"` 或 `"message_end"`。
|
||||
- `agents.defaults.blockStreamingChunk`:`{ minChars, maxChars, breakPreference? }`。
|
||||
- `agents.defaults.blockStreamingCoalesce`:`{ minChars?, maxChars?, idleMs? }`(发送前合并流式块)。
|
||||
- 渠道硬上限:`*.textChunkLimit`(例如 `channels.whatsapp.textChunkLimit`)。
|
||||
- 渠道分块模式:`*.chunkMode`(默认 `length`;`newline` 会先按空行,也就是段落边界拆分,再按长度分块)。
|
||||
- Discord 软上限:`channels.discord.maxLinesPerMessage`(默认 17),会拆分过高的回复以避免 UI 裁剪。
|
||||
- 渠道分块模式:`*.chunkMode`(默认 `length`,`newline` 会先按空行即段落边界拆分,再按长度分块)。
|
||||
- Discord 软上限:`channels.discord.maxLinesPerMessage`(默认 17),会拆分过高的回复以避免 UI 截断。
|
||||
|
||||
**边界语义:**
|
||||
|
||||
- `text_end`:一旦 chunker 发出块就立即流式发送;每次 `text_end` 时刷新。
|
||||
- `text_end`:只要 chunker 产出块就立即流式发送;在每个 `text_end` 时刷新。
|
||||
- `message_end`:等待助手消息完成后,再刷新缓冲输出。
|
||||
|
||||
即使使用 `message_end`,如果缓冲文本超过 `maxChars`,仍然会使用 chunker,因此它可能在结束时发出多个块。
|
||||
即使是 `message_end`,如果缓冲文本超过 `maxChars`,仍然会使用 chunker,因此它可能在结尾产出多个块。
|
||||
|
||||
### 分块流式传输中的媒体投递
|
||||
|
||||
`MEDIA:` 指令是普通的投递元数据。当分块流式传输提前发送一个媒体块时,OpenClaw 会为当前轮次记住这次投递。如果最终的助手载荷重复包含相同的媒体 URL,最终投递会去掉重复媒体,而不是再次发送附件。
|
||||
`MEDIA:` 指令是普通的投递元数据。当分块流式传输提前发送了一个媒体块时,OpenClaw 会为该轮次记住这次投递。如果最终的助手负载重复了相同的媒体 URL,最终投递会去掉重复媒体,而不是再次发送附件。
|
||||
|
||||
完全重复的最终载荷会被抑制。如果最终载荷在已经流式发送过的媒体周围又增加了不同的文本,OpenClaw 仍然会发送这些新文本,同时保持媒体只投递一次。这样可以避免在 Telegram 等渠道中,当智能体在流式传输期间发出 `MEDIA:`,而提供商又在完整回复中再次包含它时,出现重复的语音消息或文件。
|
||||
完全重复的最终负载会被抑制。如果最终负载在已经流式发送过的媒体周围新增了不同的文本,OpenClaw 仍会发送这些新文本,同时保持媒体只投递一次。这可以避免在 Telegram 等渠道中,当智能体在流式传输期间输出 `MEDIA:` 且提供商也在完成回复中包含它时,出现重复的语音笔记或文件。
|
||||
|
||||
## 分块处理算法(低/高边界)
|
||||
## 分块算法(低/高边界)
|
||||
|
||||
块分块处理由 `EmbeddedBlockChunker` 实现:
|
||||
分块逻辑由 `EmbeddedBlockChunker` 实现:
|
||||
|
||||
- **低边界:** 在缓冲区达到 `minChars` 之前不发出(除非被强制)。
|
||||
- **高边界:** 优先在 `maxChars` 之前拆分;如果被强制,则在 `maxChars` 处拆分。
|
||||
- **低边界:** 在缓冲区达到 `minChars` 之前不发送(除非被强制刷新)。
|
||||
- **高边界:** 优先在 `maxChars` 之前断开;如果被强制,则在 `maxChars` 处断开。
|
||||
- **断点偏好:** `paragraph` → `newline` → `sentence` → `whitespace` → 硬断开。
|
||||
- **代码围栏:** 绝不在围栏内部拆分;如果必须在 `maxChars` 处强制拆分,会先关闭再重新打开围栏,以保持 Markdown 有效。
|
||||
- **代码围栏:** 绝不在围栏内部拆分;如果在 `maxChars` 处被强制拆分,会先关闭再重新打开围栏,以保持 Markdown 有效。
|
||||
|
||||
`maxChars` 会被限制到渠道的 `textChunkLimit`,因此你不能超过每个渠道的上限。
|
||||
|
||||
## 聚合(合并流式块)
|
||||
## 合并(合并流式块)
|
||||
|
||||
启用分块流式传输时,OpenClaw 可以在发送前 **合并连续的块分片**。这样既能提供渐进式输出,又能减少“单行刷屏”。
|
||||
启用分块流式传输时,OpenClaw 可以在发送前**合并连续的块分片**。这样既能提供渐进式输出,又能减少“单行刷屏”。
|
||||
|
||||
- 聚合会等待 **空闲间隔**(`idleMs`)后再刷新。
|
||||
- 缓冲区受 `maxChars` 限制,超出时会刷新。
|
||||
- `minChars` 会阻止过小的片段发送,直到累积到足够文本(最终刷新总会发送剩余文本)。
|
||||
- 合并会等待**空闲间隔**(`idleMs`)后再刷新。
|
||||
- 缓冲区受 `maxChars` 限制,超过时会刷新。
|
||||
- `minChars` 会阻止过小片段被提前发送,直到积累了足够的文本(最终刷新时始终会发送剩余文本)。
|
||||
- 连接符由 `blockStreamingChunk.breakPreference` 推导而来(`paragraph` → `\n\n`,`newline` → `\n`,`sentence` → 空格)。
|
||||
- 可通过 `*.blockStreamingCoalesce` 使用渠道覆盖(包括每账户配置)。
|
||||
- 对于 Signal/Slack/Discord,默认的聚合 `minChars` 会提升到 1500,除非被覆盖。
|
||||
- 可通过 `*.blockStreamingCoalesce` 提供渠道覆盖项(包括每账号配置)。
|
||||
- 除非被覆盖,否则 Signal/Slack/Discord 的默认合并 `minChars` 会提升到 1500。
|
||||
|
||||
## 块之间更像人类的节奏
|
||||
|
||||
启用分块流式传输时,你可以在块回复之间(第一个块之后)加入 **随机暂停**。这会让多气泡回复感觉更自然。
|
||||
启用分块流式传输时,你可以在各个分块回复之间加入**随机暂停**(首个块之后)。这样多气泡回复会显得更自然。
|
||||
|
||||
- 配置:`agents.defaults.humanDelay`(可通过 `agents.list[].humanDelay` 按智能体覆盖)。
|
||||
- 模式:`off`(默认)、`natural`(800–2500ms)、`custom`(`minMs`/`maxMs`)。
|
||||
- 仅适用于 **分块回复**,不适用于最终回复或工具摘要。
|
||||
- 仅适用于**分块回复**,不适用于最终回复或工具摘要。
|
||||
|
||||
## “流式发送分块还是一次性发送全部”
|
||||
## “流式发送分块还是最后一次性发送”
|
||||
|
||||
它映射为:
|
||||
这对应为:
|
||||
|
||||
- **流式发送分块:** `blockStreamingDefault: "on"` + `blockStreamingBreak: "text_end"`(边生成边发出)。非 Telegram 渠道还需要设置 `*.blockStreaming: true`。
|
||||
- **在结尾一次性流式发送全部:** `blockStreamingBreak: "message_end"`(刷新一次;如果内容很长,可能仍会拆成多个块)。
|
||||
- **流式发送分块:** `blockStreamingDefault: "on"` + `blockStreamingBreak: "text_end"`(边生成边发送)。非 Telegram 渠道还需要 `*.blockStreaming: true`。
|
||||
- **在结尾一次性流式发送全部内容:** `blockStreamingBreak: "message_end"`(刷新一次;如果非常长,可能仍会分成多个块)。
|
||||
- **不使用分块流式传输:** `blockStreamingDefault: "off"`(只发送最终回复)。
|
||||
|
||||
**渠道说明:** 除非显式将 `*.blockStreaming` 设为 `true`,否则分块流式传输 **默认关闭**。渠道可以在没有分块回复的情况下使用实时预览流式传输(`channels.<channel>.streaming`)。
|
||||
**渠道说明:** 除非显式设置 `*.blockStreaming` 为 `true`,否则分块流式传输**默认关闭**。渠道可以在没有分块回复的情况下流式发送实时预览(`channels.<channel>.streaming`)。
|
||||
|
||||
配置位置提醒:`blockStreaming*` 默认值位于 `agents.defaults` 下,而不是根配置。
|
||||
|
||||
## 预览流式传输模式
|
||||
|
||||
规范键名:`channels.<channel>.streaming`
|
||||
规范键:`channels.<channel>.streaming`
|
||||
|
||||
模式:
|
||||
|
||||
- `off`:禁用预览流式传输。
|
||||
- `partial`:使用单个预览,并用最新文本替换它。
|
||||
- `partial`:单一预览,用最新文本替换。
|
||||
- `block`:以分块/追加的方式更新预览。
|
||||
- `progress`:生成期间显示进度/状态预览,完成时显示最终答案。
|
||||
- `progress`:生成期间显示进度/状态预览,完成时再发送最终答案。
|
||||
|
||||
### 渠道映射
|
||||
|
||||
| 渠道 | `off` | `partial` | `block` | `progress` |
|
||||
| Channel | `off` | `partial` | `block` | `progress` |
|
||||
| ---------- | ----- | --------- | ------- | ----------------- |
|
||||
| Telegram | ✅ | ✅ | ✅ | 映射为 `partial` |
|
||||
| Discord | ✅ | ✅ | ✅ | 映射为 `partial` |
|
||||
| Slack | ✅ | ✅ | ✅ | ✅ |
|
||||
| Mattermost | ✅ | ✅ | ✅ | ✅ |
|
||||
| Telegram | ✅ | ✅ | ✅ | 映射为 `partial` |
|
||||
| Discord | ✅ | ✅ | ✅ | 映射为 `partial` |
|
||||
| Slack | ✅ | ✅ | ✅ | ✅ |
|
||||
| Mattermost | ✅ | ✅ | ✅ | ✅ |
|
||||
|
||||
仅适用于 Slack:
|
||||
仅 Slack:
|
||||
|
||||
- `channels.slack.streaming.nativeTransport` 在 `channels.slack.streaming.mode="partial"` 时切换 Slack 原生流式 API 调用(默认:`true`)。
|
||||
- Slack 原生流式传输和 Slack 助手线程状态都需要一个回复线程目标;顶级私信不会显示这种线程式预览。
|
||||
- 当 `channels.slack.streaming.mode="partial"` 时,`channels.slack.streaming.nativeTransport` 控制是否使用 Slack 原生流式 API 调用(默认:`true`)。
|
||||
- Slack 原生流式传输和 Slack 助手线程状态都需要一个回复线程目标;顶层私信不会显示这种线程式预览。
|
||||
|
||||
旧键迁移:
|
||||
|
||||
- Telegram:`streamMode` 和布尔值 `streaming` 会自动迁移到枚举 `streaming`。
|
||||
- Discord:`streamMode` 和布尔值 `streaming` 会自动迁移到枚举 `streaming`。
|
||||
- Slack:`streamMode` 会自动迁移到 `streaming.mode`;布尔值 `streaming` 会自动迁移到 `streaming.mode` 加 `streaming.nativeTransport`;旧的 `nativeStreaming` 会自动迁移到 `streaming.nativeTransport`。
|
||||
- Telegram:`streamMode` 和布尔值 `streaming` 会自动迁移为 `streaming` 枚举。
|
||||
- Discord:`streamMode` 和布尔值 `streaming` 会自动迁移为 `streaming` 枚举。
|
||||
- Slack:`streamMode` 会自动迁移为 `streaming.mode`;布尔值 `streaming` 会自动迁移为 `streaming.mode` 加 `streaming.nativeTransport`;旧的 `nativeStreaming` 会自动迁移为 `streaming.nativeTransport`。
|
||||
|
||||
### 运行时行为
|
||||
|
||||
Telegram:
|
||||
|
||||
- 在私信和群组/话题中,使用 `sendMessage` + `editMessageText` 更新预览。
|
||||
- 当 Telegram 的分块流式传输被显式启用时,会跳过预览流式传输(以避免双重流式传输)。
|
||||
- `/reasoning stream` 可以把推理内容写入预览。
|
||||
- 当 Telegram 分块流式传输被显式启用时,会跳过预览流式传输(以避免双重流式传输)。
|
||||
- `/reasoning stream` 可以将 reasoning 写入预览。
|
||||
|
||||
Discord:
|
||||
|
||||
- 使用发送 + 编辑预览消息。
|
||||
- `block` 模式使用草稿分块处理(`draftChunk`)。
|
||||
- 当 Discord 的分块流式传输被显式启用时,会跳过预览流式传输。
|
||||
- 最终媒体、错误和显式回复载荷会取消待处理的预览,而不会刷新新的草稿,然后使用正常投递。
|
||||
- `block` 模式使用草稿分块(`draftChunk`)。
|
||||
- 当 Discord 分块流式传输被显式启用时,会跳过预览流式传输。
|
||||
- 最终媒体、错误和显式回复负载会取消待处理的预览而不刷新新的草稿,然后使用正常投递。
|
||||
|
||||
Slack:
|
||||
|
||||
- `partial` 在可用时可以使用 Slack 原生流式传输(`chat.startStream`/`append`/`stop`)。
|
||||
- `block` 使用追加式草稿预览。
|
||||
- `progress` 使用状态预览文本,然后发送最终答案。
|
||||
- 原生预览流式传输和草稿预览流式传输会抑制当前轮次的分块回复,因此 Slack 回复只会通过一种投递路径进行流式传输。
|
||||
- 最终媒体/错误载荷和 `progress` 最终结果不会创建一次性的草稿消息;只有可以编辑预览的文本/块最终结果,才会刷新待处理的草稿文本。
|
||||
- `progress` 使用状态预览文本,然后再发送最终答案。
|
||||
- 原生和草稿预览流式传输会抑制该轮次的分块回复,因此一条 Slack 回复只会通过一种投递路径流式发送。
|
||||
- 最终媒体/错误负载以及 progress 最终结果不会创建一次性草稿消息;只有能够编辑预览的文本/块最终结果才会刷新待处理的草稿文本。
|
||||
|
||||
Mattermost:
|
||||
|
||||
- 将 thinking、工具活动和部分回复文本流式写入单个草稿预览帖子,在最终答案可以安全发送时原地完成。
|
||||
- 如果预览帖子已被删除,或在最终化时不可用,则回退为发送一个新的最终帖子。
|
||||
- 最终媒体/错误载荷会在正常投递前取消待处理的预览更新,而不是刷新一个临时预览帖子。
|
||||
- 将思考过程、工具活动和部分回复文本流式写入同一条草稿预览帖子,并在最终答案可以安全发送时原地完成。
|
||||
- 如果预览帖子已被删除或在最终化时不可用,则会回退为发送一条新的最终帖子。
|
||||
- 最终媒体/错误负载会在正常投递前取消待处理的预览更新,而不是刷新一条临时预览帖子。
|
||||
|
||||
Matrix:
|
||||
|
||||
- 当最终文本可以复用预览事件时,草稿预览会原地完成。
|
||||
- 仅媒体、错误以及回复目标不匹配的最终结果,会在正常投递前取消待处理的预览更新;如果已经出现陈旧预览,则会被撤销。
|
||||
- 仅媒体、错误以及回复目标不匹配的最终结果会在正常投递前取消待处理的预览更新;已经可见的陈旧预览会被撤回。
|
||||
|
||||
### 工具进度预览更新
|
||||
|
||||
预览流式传输还可以包含 **工具进度** 更新 —— 比如“正在搜索网页”“正在读取文件”或“正在调用工具”这样的短状态行,在工具运行期间显示在同一个预览消息中,先于最终回复出现。这样可以让多步骤工具轮次在视觉上保持活跃,而不是在首次 thinking 预览和最终答案之间保持沉默。
|
||||
预览流式传输还可以包含**工具进度**更新——例如“正在搜索网络”“正在读取文件”或“正在调用工具”之类的简短状态行——在工具运行期间,这些内容会显示在同一条预览消息中,并先于最终回复出现。这样可以让多步骤工具轮次在视觉上保持活跃,而不是在第一次思考预览和最终答案之间沉默无声。
|
||||
|
||||
支持的界面:
|
||||
支持的表面:
|
||||
|
||||
- 当预览流式传输处于激活状态时,**Discord**、**Slack** 和 **Telegram** 默认会把工具进度流式写入实时预览编辑中。
|
||||
- 自 `v2026.4.22` 起,Telegram 已默认启用工具进度预览更新;保持启用即可保留这一已发布行为。
|
||||
- **Mattermost** 已经会把工具活动合并到它的单个草稿预览帖子中(见上文)。
|
||||
- 工具进度编辑遵循当前激活的预览流式传输模式;当预览流式传输为 `off`,或消息已被分块流式传输接管时,会跳过这些编辑。
|
||||
- 如果你想保留预览流式传输,但隐藏工具进度行,可将该渠道的 `streaming.preview.toolProgress` 设为 `false`。如果你想完全禁用预览编辑,请将 `streaming.mode` 设为 `off`。
|
||||
- 当预览流式传输处于活动状态时,**Discord**、**Slack** 和 **Telegram** 默认会将工具进度流式写入实时预览编辑中。
|
||||
- 从 `v2026.4.22` 起,Telegram 已默认启用工具进度预览更新;保持启用可保留这一已发布行为。
|
||||
- **Mattermost** 已经会将工具活动整合进它的单一草稿预览帖子中(见上文)。
|
||||
- 工具进度编辑遵循当前激活的预览流式传输模式;当预览流式传输为 `off`,或分块流式传输已经接管该消息时,会跳过这些编辑。
|
||||
- 若要保留预览流式传输但隐藏工具进度行,请将该渠道的 `streaming.preview.toolProgress` 设为 `false`。若要完全禁用预览编辑,请将 `streaming.mode` 设为 `off`。
|
||||
|
||||
示例:
|
||||
|
||||
@ -205,6 +203,6 @@ Matrix:
|
||||
|
||||
## 相关内容
|
||||
|
||||
- [Messages](/zh-CN/concepts/messages) — 消息生命周期与投递
|
||||
- [Retry](/zh-CN/concepts/retry) — 投递失败时的重试行为
|
||||
- [Channels](/zh-CN/channels) — 各渠道的流式传输支持
|
||||
- [消息](/zh-CN/concepts/messages) — 消息生命周期和投递
|
||||
- [重试](/zh-CN/concepts/retry) — 投递失败时的重试行为
|
||||
- [渠道](/zh-CN/channels) — 各渠道的流式传输支持
|
||||
|
||||
@ -1,20 +1,20 @@
|
||||
---
|
||||
read_when:
|
||||
- 了解如何配置 OpenClaw
|
||||
- 查找配置示例
|
||||
- 首次设置 OpenClaw
|
||||
summary: 常见 OpenClaw 设置的符合 schema 的配置示例
|
||||
- 学习如何配置 OpenClaw。
|
||||
- 正在查找配置示例。
|
||||
- 首次设置 OpenClaw。
|
||||
summary: 常见 OpenClaw 配置场景的 schema 准确示例
|
||||
title: 配置示例
|
||||
x-i18n:
|
||||
generated_at: "2026-04-24T03:15:28Z"
|
||||
generated_at: "2026-04-25T05:54:11Z"
|
||||
model: gpt-5.4
|
||||
provider: openai
|
||||
source_hash: 909cb2a80a4bc31438a387d49ad9893bbe54b299686a8c7c1b2baae40bf1130f
|
||||
source_hash: 2f31f70459d6232d2aefe668440312bb1800f18de0ef3c2783befa1de05f25f6
|
||||
source_path: gateway/configuration-examples.md
|
||||
workflow: 15
|
||||
---
|
||||
|
||||
以下示例与当前配置 schema 保持一致。要查看完整参考和逐字段说明,请参见[配置](/zh-CN/gateway/configuration)。
|
||||
以下示例与当前配置 schema 保持一致。完整参考和各字段说明,请参见[配置](/zh-CN/gateway/configuration)。
|
||||
|
||||
## 快速开始
|
||||
|
||||
@ -27,9 +27,9 @@ x-i18n:
|
||||
}
|
||||
```
|
||||
|
||||
保存到 `~/.openclaw/openclaw.json`,然后你就可以通过该号码向机器人发送私信。
|
||||
保存到 `~/.openclaw/openclaw.json` 后,你就可以用这个号码向机器人发送私信。
|
||||
|
||||
### 推荐的入门配置
|
||||
### 推荐入门配置
|
||||
|
||||
```json5
|
||||
{
|
||||
@ -57,7 +57,7 @@ x-i18n:
|
||||
|
||||
```json5
|
||||
{
|
||||
// 环境 + shell
|
||||
// 环境变量 + shell
|
||||
env: {
|
||||
OPENROUTER_API_KEY: "sk-or-...",
|
||||
vars: {
|
||||
@ -69,7 +69,7 @@ x-i18n:
|
||||
},
|
||||
},
|
||||
|
||||
// 凭证配置元数据(密钥存储在 auth-profiles.json 中)
|
||||
// Auth 配置文件元数据(密钥保存在 auth-profiles.json 中)
|
||||
auth: {
|
||||
profiles: {
|
||||
"anthropic:default": { provider: "anthropic", mode: "api_key" },
|
||||
@ -139,7 +139,7 @@ x-i18n:
|
||||
maxBytes: 20971520,
|
||||
models: [
|
||||
{ provider: "openai", model: "gpt-4o-mini-transcribe" },
|
||||
// 可选 CLI 回退(Whisper 二进制文件):
|
||||
// 可选的 CLI 回退方案(Whisper 二进制文件):
|
||||
// { type: "cli", command: "whisper", args: ["--model", "base", "{{MediaPath}}"] }
|
||||
],
|
||||
timeoutSeconds: 120,
|
||||
@ -251,7 +251,7 @@ x-i18n:
|
||||
"anthropic/claude-sonnet-4-6": { alias: "sonnet" },
|
||||
"openai/gpt-5.4": { alias: "gpt" },
|
||||
},
|
||||
skills: ["github", "weather"], // 会被未设置 list[].skills 的智能体继承
|
||||
skills: ["github", "weather"], // 由省略 list[].skills 的智能体继承
|
||||
thinkingDefault: "low",
|
||||
verboseDefault: "off",
|
||||
elevatedDefault: "on",
|
||||
@ -291,7 +291,7 @@ x-i18n:
|
||||
},
|
||||
sandbox: {
|
||||
mode: "non-main",
|
||||
scope: "session", // 相比旧版 perSession: true,更推荐使用此项
|
||||
scope: "session", // 优先于旧版 perSession: true
|
||||
workspaceRoot: "~/.openclaw/sandboxes",
|
||||
docker: {
|
||||
image: "openclaw-sandbox:bookworm-slim",
|
||||
@ -311,14 +311,14 @@ x-i18n:
|
||||
id: "main",
|
||||
default: true,
|
||||
// 继承 defaults.skills -> github, weather
|
||||
thinkingDefault: "high", // 每个智能体的 thinking 覆盖
|
||||
reasoningDefault: "on", // 每个智能体的推理可见性
|
||||
fastModeDefault: false, // 每个智能体的快速模式
|
||||
thinkingDefault: "high", // 每个智能体单独的 thinking 覆盖
|
||||
reasoningDefault: "on", // 每个智能体单独的推理可见性
|
||||
fastModeDefault: false, // 每个智能体单独的快速模式
|
||||
},
|
||||
{
|
||||
id: "quick",
|
||||
skills: [], // 此智能体不使用任何 Skills
|
||||
fastModeDefault: true, // 此智能体始终以快速模式运行
|
||||
skills: [], // 这个智能体没有 Skills
|
||||
fastModeDefault: true, // 这个智能体始终以快速模式运行
|
||||
thinkingDefault: "off",
|
||||
},
|
||||
],
|
||||
@ -372,7 +372,7 @@ x-i18n:
|
||||
},
|
||||
},
|
||||
|
||||
// Cron 作业
|
||||
// Cron 任务
|
||||
cron: {
|
||||
enabled: true,
|
||||
store: "~/.openclaw/cron/cron.json",
|
||||
@ -466,7 +466,7 @@ x-i18n:
|
||||
|
||||
## 常见模式
|
||||
|
||||
### 共享的 Skills 基线 + 单个覆盖
|
||||
### 共享 Skills 基线,并为其中一个进行覆盖
|
||||
|
||||
```json5
|
||||
{
|
||||
@ -485,7 +485,7 @@ x-i18n:
|
||||
|
||||
- `agents.defaults.skills` 是共享基线。
|
||||
- `agents.list[].skills` 会替换某个智能体的该基线。
|
||||
- 当某个智能体不应看到任何 Skills 时,使用 `skills: []`。
|
||||
- 如果某个智能体不应看到任何 Skills,请使用 `skills: []`。
|
||||
|
||||
### 多平台设置
|
||||
|
||||
@ -508,9 +508,27 @@ x-i18n:
|
||||
}
|
||||
```
|
||||
|
||||
### 受信任节点网络自动批准
|
||||
|
||||
除非你控制网络路径,否则请保持设备配对为手动模式。对于专用实验室或 tailnet 子网,你可以通过精确的 CIDR 或 IP,选择性启用首次节点设备自动批准:
|
||||
|
||||
```json5
|
||||
{
|
||||
gateway: {
|
||||
nodes: {
|
||||
pairing: {
|
||||
autoApproveCidrs: ["192.168.1.0/24", "fd00:1234:5678::/64"],
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
未设置时,此功能保持关闭。它仅适用于没有请求作用域的全新 `role: node` 配对。操作员/浏览器客户端,以及 role、scope、metadata 或公钥升级,仍然需要手动批准。
|
||||
|
||||
### 安全私信模式(共享收件箱 / 多用户私信)
|
||||
|
||||
如果不止一个人可以向你的机器人发送私信(`allowFrom` 中有多个条目、为多个人批准配对,或者 `dmPolicy: "open"`),请启用**安全私信模式**,这样默认情况下,不同发送者的私信就不会共享同一个上下文:
|
||||
如果有多个人可以向你的机器人发送私信(`allowFrom` 中有多个条目、为多个人批准了配对,或 `dmPolicy: "open"`),请启用**安全私信模式**,这样来自不同发送者的私信默认不会共享同一个上下文:
|
||||
|
||||
```json5
|
||||
{
|
||||
@ -534,8 +552,8 @@ x-i18n:
|
||||
}
|
||||
```
|
||||
|
||||
对于 Discord / Slack / Google Chat / Microsoft Teams / Mattermost / IRC,发送者授权默认优先基于 ID。
|
||||
只有在你明确接受该风险时,才启用各渠道的 `dangerouslyAllowNameMatching: true`,以允许直接使用可变的名称 / 邮箱 / 昵称进行匹配。
|
||||
对于 Discord/Slack/Google Chat/Microsoft Teams/Mattermost/IRC,发送者授权默认优先基于 ID。
|
||||
只有在你明确接受该风险时,才应通过各渠道的 `dangerouslyAllowNameMatching: true` 启用直接的、可变的姓名/邮箱/昵称匹配。
|
||||
|
||||
### Anthropic API 密钥 + MiniMax 回退
|
||||
|
||||
@ -596,7 +614,7 @@ x-i18n:
|
||||
}
|
||||
```
|
||||
|
||||
### 仅使用本地模型
|
||||
### 仅本地模型
|
||||
|
||||
```json5
|
||||
{
|
||||
@ -631,11 +649,11 @@ x-i18n:
|
||||
## 提示
|
||||
|
||||
- 如果你设置了 `dmPolicy: "open"`,对应的 `allowFrom` 列表必须包含 `"*"`。
|
||||
- 提供商 ID 各不相同(电话号码、用户 ID、渠道 ID)。请参阅提供商文档以确认格式。
|
||||
- 可稍后添加的可选部分:`web`、`browser`、`ui`、`discovery`、`canvasHost`、`talk`、`signal`、`imessage`。
|
||||
- 提供商 ID 各不相同(电话号码、用户 ID、渠道 ID)。请参阅提供商文档确认格式。
|
||||
- 可稍后添加的可选部分包括:`web`、`browser`、`ui`、`discovery`、`canvasHost`、`talk`、`signal`、`imessage`。
|
||||
- 更深入的设置说明,请参见[提供商](/zh-CN/providers)和[故障排除](/zh-CN/gateway/troubleshooting)。
|
||||
|
||||
## 相关
|
||||
## 相关内容
|
||||
|
||||
- [Configuration reference](/zh-CN/gateway/configuration-reference)
|
||||
- [Configuration](/zh-CN/gateway/configuration)
|
||||
- [配置参考](/zh-CN/gateway/configuration-reference)
|
||||
- [配置](/zh-CN/gateway/configuration)
|
||||
|
||||
@ -1,61 +1,61 @@
|
||||
---
|
||||
read_when:
|
||||
- 你需要精确到字段级别的配置语义或默认值
|
||||
- 你正在验证渠道、模型、Gateway 网关 或工具配置块
|
||||
summary: Gateway 网关 配置参考,涵盖核心 OpenClaw 键名、默认值,以及指向专用子系统参考文档的链接
|
||||
- 你正在验证 channel、model、Gateway 网关或工具配置块
|
||||
summary: 用于核心 OpenClaw 键、默认值以及指向各专用子系统参考文档链接的 Gateway 网关配置参考
|
||||
title: 配置参考
|
||||
x-i18n:
|
||||
generated_at: "2026-04-25T04:55:00Z"
|
||||
generated_at: "2026-04-25T05:54:11Z"
|
||||
model: gpt-5.4
|
||||
provider: openai
|
||||
source_hash: 2953146dc071c5fb5c9e7cdf628f92a4c12b3f30d21815626ed43de0bf39193f
|
||||
source_hash: 6fc32c7387a8ece01020342186b52202d954a44c6db3fa827a5ed4302e995af7
|
||||
source_path: gateway/configuration-reference.md
|
||||
workflow: 15
|
||||
---
|
||||
|
||||
`~/.openclaw/openclaw.json` 的核心配置参考。若需面向任务的概览,请参见 [配置](/zh-CN/gateway/configuration)。
|
||||
`~/.openclaw/openclaw.json` 的核心配置参考。若要查看面向任务的概览,请参阅[配置](/zh-CN/gateway/configuration)。
|
||||
|
||||
本页介绍 OpenClaw 的主要配置面,并在某个子系统有自己更深入的参考文档时提供链接。它**不会**尝试在单个页面内联所有由渠道 / 插件拥有的命令目录,也不会内联所有深层 memory / 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 面验证配置文档基线哈希
|
||||
|
||||
专用深入参考:
|
||||
专用深度参考:
|
||||
|
||||
- [Memory 配置参考](/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):当前内置 + 内置打包命令目录
|
||||
- 对应渠道 / 插件页面:用于渠道特定的命令面
|
||||
- [Memory 配置参考](/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 会使用安全默认值。
|
||||
配置格式为 **JSON5**(允许注释和尾随逗号)。所有字段都是可选的——OpenClaw 在省略时会使用安全默认值。
|
||||
|
||||
---
|
||||
|
||||
## 渠道
|
||||
|
||||
每个渠道的配置键已移至专门页面——请参见
|
||||
每个渠道的配置键已移至专用页面——请参阅
|
||||
[配置 — 渠道](/zh-CN/gateway/config-channels),了解 `channels.*`,
|
||||
其中包括 Slack、Discord、Telegram、WhatsApp、Matrix、iMessage 以及其他
|
||||
其中包括 Slack、Discord、Telegram、WhatsApp、Matrix、iMessage 及其他
|
||||
内置渠道(认证、访问控制、多账号、提及门控)。
|
||||
|
||||
## 智能体默认值、多智能体、会话和消息
|
||||
|
||||
已移至专门页面——请参见
|
||||
已移至专用页面——请参阅
|
||||
[配置 — 智能体](/zh-CN/gateway/config-agents),了解:
|
||||
|
||||
- `agents.defaults.*`(工作区、模型、思考、心跳、memory、媒体、skills、沙箱)
|
||||
- `multiAgent.*`(多智能体路由与绑定)
|
||||
- `session.*`(会话生命周期、压缩、修剪)
|
||||
- `messages.*`(消息投递、TTS、Markdown 渲染)
|
||||
- `agents.defaults.*`(工作区、模型、thinking、heartbeat、memory、媒体、Skills、沙箱)
|
||||
- `multiAgent.*`(多智能体路由和绑定)
|
||||
- `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 设置已移至专门页面——请参见
|
||||
工具策略、实验性开关、由 provider 支持的工具配置,以及自定义
|
||||
provider / base-URL 设置已移至专用页面——请参阅
|
||||
[配置 — 工具和自定义提供商](/zh-CN/gateway/config-tools)。
|
||||
|
||||
## Skills
|
||||
@ -83,12 +83,12 @@ x-i18n:
|
||||
}
|
||||
```
|
||||
|
||||
- `allowBundled`:仅针对内置 skills 的可选允许列表(托管 / 工作区 skills 不受影响)。
|
||||
- `load.extraDirs`:额外的共享 skill 根目录(优先级最低)。
|
||||
- `install.preferBrew`:为 true 时,如果可用 `brew`,则优先使用 Homebrew 安装器,然后再回退到其他安装器类型。
|
||||
- `install.nodeManager`:用于 `metadata.openclaw.install` 规范的 Node 安装器偏好(`npm` | `pnpm` | `yarn` | `bun`)。
|
||||
- `entries.<skillKey>.enabled: false`:即使某个 skill 已内置 / 已安装,也会将其禁用。
|
||||
- `entries.<skillKey>.apiKey`:为声明主要环境变量的 skill 提供的便捷字段(明文字符串或 SecretRef 对象)。
|
||||
- `allowBundled`:仅对内置 Skills 生效的可选允许列表(托管 / 工作区 Skills 不受影响)。
|
||||
- `load.extraDirs`:额外的共享 Skills 根目录(优先级最低)。
|
||||
- `install.preferBrew`:为 `true` 时,若 `brew` 可用,则优先使用 Homebrew 安装器,然后才回退到其他安装器类型。
|
||||
- `install.nodeManager`:`metadata.openclaw.install` 规范的 Node 安装器偏好(`npm` | `pnpm` | `yarn` | `bun`)。
|
||||
- `entries.<skillKey>.enabled: false`:即使某个 Skill 已内置 / 已安装,也会禁用它。
|
||||
- `entries.<skillKey>.apiKey`:为声明了主环境变量的 Skills 提供的便捷字段(明文字符串或 SecretRef 对象)。
|
||||
|
||||
---
|
||||
|
||||
@ -117,44 +117,44 @@ x-i18n:
|
||||
```
|
||||
|
||||
- 从 `~/.openclaw/extensions`、`<workspace>/.openclaw/extensions` 以及 `plugins.load.paths` 加载。
|
||||
- 发现机制接受原生 OpenClaw 插件,以及兼容的 Codex bundle 和 Claude bundle,其中包括无 manifest 的 Claude 默认布局 bundle。
|
||||
- **配置更改需要重启 Gateway 网关。**
|
||||
- `allow`:可选允许列表(仅加载列出的插件)。`deny` 优先生效。
|
||||
- `plugins.entries.<id>.apiKey`:插件级 API 密钥便捷字段(当插件支持时)。
|
||||
- `plugins.entries.<id>.env`:插件作用域的环境变量映射。
|
||||
- `plugins.entries.<id>.hooks.allowPromptInjection`:当为 `false` 时,core 会阻止 `before_prompt_build`,并忽略旧版 `before_agent_start` 中会修改提示词的字段,同时保留旧版 `modelOverride` 和 `providerOverride`。适用于原生插件钩子以及受支持的 bundle 提供的钩子目录。
|
||||
- `plugins.entries.<id>.hooks.allowConversationAccess`:当为 `true` 时,受信任的非内置插件可从类型化钩子(如 `llm_input`、`llm_output` 和 `agent_end`)读取原始对话内容。
|
||||
- `plugins.entries.<id>.subagent.allowModelOverride`:显式信任此插件,使其可以为后台子智能体运行请求按次执行的 `provider` 和 `model` 覆盖。
|
||||
- `plugins.entries.<id>.subagent.allowedModels`:受信任子智能体覆盖可使用的规范 `provider/model` 目标的可选允许列表。仅在你有意允许任意模型时使用 `"*"`。
|
||||
- `plugins.entries.<id>.config`:插件定义的配置对象(若可用,则由原生 OpenClaw 插件 schema 验证)。
|
||||
- 渠道插件的账号 / 运行时设置位于 `channels.<id>` 下,应由该插件 manifest 的 `channelConfigs` 元数据描述,而不是由中央 OpenClaw 选项注册表描述。
|
||||
- `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 base URL(默认:`https://api.firecrawl.dev`)。
|
||||
- 发现机制接受原生 OpenClaw 插件,以及兼容的 Codex bundles 和 Claude bundles,包括无 manifest 的 Claude 默认布局 bundles。
|
||||
- **配置变更需要重启 gateway。**
|
||||
- `allow`:可选允许列表(仅加载列出的插件)。`deny` 优先。
|
||||
- `plugins.entries.<id>.apiKey`:插件级 API key 便捷字段(当插件支持时)。
|
||||
- `plugins.entries.<id>.env`:插件作用域环境变量映射。
|
||||
- `plugins.entries.<id>.hooks.allowPromptInjection`:当为 `false` 时,核心会阻止 `before_prompt_build`,并忽略旧版 `before_agent_start` 中会修改提示词的字段,同时保留旧版 `modelOverride` 和 `providerOverride`。适用于原生插件钩子以及受支持的 bundle 提供钩子目录。
|
||||
- `plugins.entries.<id>.hooks.allowConversationAccess`:当为 `true` 时,受信任的非内置插件可以从 `llm_input`、`llm_output` 和 `agent_end` 等类型化钩子中读取原始对话内容。
|
||||
- `plugins.entries.<id>.subagent.allowModelOverride`:显式信任该插件,使其可为后台子智能体运行请求按次运行的 `provider` 和 `model` 覆盖。
|
||||
- `plugins.entries.<id>.subagent.allowedModels`:受信任子智能体覆盖的规范 `provider/model` 目标可选允许列表。仅当你明确要允许任意模型时才使用 `"*"`。
|
||||
- `plugins.entries.<id>.config`:插件定义的配置对象(在可用时由原生 OpenClaw 插件 schema 验证)。
|
||||
- 渠道插件的账号 / 运行时设置位于 `channels.<id>` 下,应由所属插件的 manifest `channelConfigs` 元数据描述,而不是由中心化的 OpenClaw 选项注册表描述。
|
||||
- `plugins.entries.firecrawl.config.webFetch`:Firecrawl Web 抓取 provider 设置。
|
||||
- `apiKey`:Firecrawl API key(接受 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`)。
|
||||
- `plugins.entries.xai.config.xSearch`:xAI X Search(Grok 网页搜索)设置。
|
||||
- `enabled`:启用 X Search 提供商。
|
||||
- `model`:搜索使用的 Grok 模型(例如 `"grok-4-1-fast"`)。
|
||||
- `plugins.entries.memory-core.config.dreaming`:memory dreaming 设置。关于阶段和阈值,请参见 [Dreaming](/zh-CN/concepts/dreaming)。
|
||||
- `maxAgeMs`:最大缓存时长(毫秒,默认:`172800000` / 2 天)。
|
||||
- `timeoutSeconds`:抓取请求超时秒数(默认:`60`)。
|
||||
- `plugins.entries.xai.config.xSearch`:xAI X Search(Grok Web 搜索)设置。
|
||||
- `enabled`:启用 X Search provider。
|
||||
- `model`:用于搜索的 Grok 模型(例如 `"grok-4-1-fast"`)。
|
||||
- `plugins.entries.memory-core.config.dreaming`:memory dreaming 设置。有关阶段和阈值,请参阅 [Dreaming](/zh-CN/concepts/dreaming)。
|
||||
- `enabled`:dreaming 总开关(默认 `false`)。
|
||||
- `frequency`:每次完整 dreaming 扫描的 cron 周期(默认 `"0 3 * * *"`)。
|
||||
- `frequency`:每次完整 dreaming 扫描的 cron 频率(默认 `"0 3 * * *"`)。
|
||||
- 阶段策略和阈值属于实现细节(不是面向用户的配置键)。
|
||||
- 完整 memory 配置见 [Memory 配置参考](/zh-CN/reference/memory-config):
|
||||
- 完整的 memory 配置位于 [Memory 配置参考](/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`:选择活动的 memory 插件 id,或使用 `"none"` 禁用 memory 插件。
|
||||
- `plugins.slots.contextEngine`:选择活动的上下文引擎插件 id;默认值为 `"legacy"`,除非你安装并选择了其他引擎。
|
||||
- 已启用的 Claude bundle 插件还可以从 `settings.json` 提供内嵌 Pi 默认值;OpenClaw 会将其作为已净化的智能体设置应用,而不是作为原始 OpenClaw 配置补丁应用。
|
||||
- `plugins.slots.memory`:选择活动 memory 插件 id,或使用 `"none"` 禁用 memory 插件。
|
||||
- `plugins.slots.contextEngine`:选择活动上下文引擎插件 id;默认值为 `"legacy"`,除非你安装并选择了其他引擎。
|
||||
- `plugins.installs`:由 CLI 管理的安装元数据,供 `openclaw plugins update` 使用。
|
||||
- 包含 `source`、`spec`、`sourcePath`、`installPath`、`version`、`resolvedName`、`resolvedVersion`、`resolvedSpec`、`integrity`、`shasum`、`resolvedAt`、`installedAt`。
|
||||
- 包括 `source`、`spec`、`sourcePath`、`installPath`、`version`、`resolvedName`、`resolvedVersion`、`resolvedSpec`、`integrity`、`shasum`、`resolvedAt`、`installedAt`。
|
||||
- 将 `plugins.installs.*` 视为托管状态;优先使用 CLI 命令,而不是手动编辑。
|
||||
|
||||
请参见 [插件](/zh-CN/tools/plugin)。
|
||||
请参阅[插件](/zh-CN/tools/plugin)。
|
||||
|
||||
---
|
||||
|
||||
@ -205,25 +205,25 @@ x-i18n:
|
||||
```
|
||||
|
||||
- `evaluateEnabled: false` 会禁用 `act:evaluate` 和 `wait --fn`。
|
||||
- `tabCleanup` 会在空闲超时后,或当某个会话超过标签页上限时,回收被跟踪的主智能体标签页。将 `idleMinutes: 0` 或 `maxTabsPerSession: 0` 设为 0,可禁用对应的单项清理模式。
|
||||
- 未设置时,`ssrfPolicy.dangerouslyAllowPrivateNetwork` 为禁用状态,因此浏览器导航默认保持严格模式。
|
||||
- 仅当你明确信任私有网络浏览器导航时,才设置 `ssrfPolicy.dangerouslyAllowPrivateNetwork: true`。
|
||||
- 在严格模式下,远程 CDP 配置文件端点(`profiles.*.cdpUrl`)在可达性 / 发现检查期间也会受到相同的私有网络阻止策略约束。
|
||||
- `ssrfPolicy.allowPrivateNetwork` 仍作为旧版别名受支持。
|
||||
- 在严格模式下,使用 `ssrfPolicy.hostnameAllowlist` 和 `ssrfPolicy.allowedHostnames` 来设置显式例外。
|
||||
- 远程配置文件为仅附加模式(禁用 start / stop / reset)。
|
||||
- `tabCleanup` 会在空闲时间后,或当某个会话超出其标签页上限时,回收已跟踪的主智能体标签页。将 `idleMinutes: 0` 或 `maxTabsPerSession: 0` 设为 0 可分别禁用这些单独的清理模式。
|
||||
- `ssrfPolicy.dangerouslyAllowPrivateNetwork` 在未设置时为禁用状态,因此浏览器导航默认保持严格。
|
||||
- 仅当你明确受信任私有网络浏览器导航时,才设置 `ssrfPolicy.dangerouslyAllowPrivateNetwork: true`。
|
||||
- 在严格模式下,远程 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,并且可以在选定主机上附加,或通过已连接的浏览器节点附加。
|
||||
当你的提供商提供直接的 DevTools WebSocket URL 时,请使用 WS(S)。
|
||||
- `existing-session` 配置文件使用 Chrome MCP 而不是 CDP,并且可以在所选主机上或通过已连接的浏览器节点进行附加。
|
||||
- `existing-session` 配置文件可以设置 `userDataDir`,以定位特定的基于 Chromium 的浏览器配置文件,例如 Brave 或 Edge。
|
||||
- `existing-session` 配置文件保留当前 Chrome MCP 路由限制:基于 snapshot/ref 的操作而不是基于 CSS 选择器的定位、单文件上传钩子、无对话框超时覆盖、无 `wait --load networkidle`,以及不支持 `responsebody`、PDF 导出、下载拦截或批量操作。
|
||||
- 本地托管的 `openclaw` 配置文件会自动分配 `cdpPort` 和 `cdpUrl`;仅在远程 CDP 场景下显式设置 `cdpUrl`。
|
||||
- 本地托管配置文件可以设置 `executablePath`,以覆盖该配置文件的全局 `browser.executablePath`。使用此项可让一个配置文件运行在 Chrome 中,另一个运行在 Brave 中。
|
||||
- 自动检测顺序:如果默认浏览器基于 Chromium,则优先使用默认浏览器 → Chrome → Brave → Edge → Chromium → Chrome Canary。
|
||||
- `existing-session` 配置文件保留当前 Chrome MCP 路由限制:使用 snapshot / ref 驱动的操作,而不是 CSS 选择器定位;单文件上传钩子;不支持对话框超时覆盖;不支持 `wait --load networkidle`;也不支持 `responsebody`、PDF 导出、下载拦截或批量操作。
|
||||
- 本地托管的 `openclaw` 配置文件会自动分配 `cdpPort` 和 `cdpUrl`;仅在远程 CDP 场景下才显式设置 `cdpUrl`。
|
||||
- 本地托管配置文件可以设置 `executablePath`,以覆盖该配置文件的全局 `browser.executablePath`。可用它让一个配置文件运行在 Chrome 中,而另一个运行在 Brave 中。
|
||||
- 自动检测顺序:默认浏览器(如果基于 Chromium)→ Chrome → Brave → Edge → Chromium → Chrome Canary。
|
||||
- `browser.executablePath` 接受 `~` 作为你的操作系统主目录。
|
||||
- 控制服务:仅 loopback(端口从 `gateway.port` 派生,默认 `18791`)。
|
||||
- `extraArgs` 会向本地 Chromium 启动追加额外启动标志(例如 `--disable-gpu`、窗口尺寸参数或调试标志)。
|
||||
- 控制服务:仅 loopback(端口由 `gateway.port` 派生,默认 `18791`)。
|
||||
- `extraArgs` 会向本地 Chromium 启动追加额外的启动标志(例如 `--disable-gpu`、窗口大小设置或调试标志)。
|
||||
|
||||
---
|
||||
|
||||
@ -241,8 +241,8 @@ x-i18n:
|
||||
}
|
||||
```
|
||||
|
||||
- `seamColor`:原生应用 UI 外壳的强调色(Talk 模式气泡着色等)。
|
||||
- `assistant`:Control UI 身份覆盖。回退到当前活动智能体身份。
|
||||
- `seamColor`:原生应用 UI 外观的强调色(Talk 模式气泡色调等)。
|
||||
- `assistant`:Control UI 身份覆盖。会回退到活动智能体身份。
|
||||
|
||||
---
|
||||
|
||||
@ -289,12 +289,20 @@ x-i18n:
|
||||
// password: "your-password",
|
||||
},
|
||||
trustedProxies: ["10.0.0.1"],
|
||||
// 可选。默认值为 false。
|
||||
// 可选。默认 false。
|
||||
allowRealIpFallback: false,
|
||||
nodes: {
|
||||
pairing: {
|
||||
// 可选。默认未设置 / 禁用。
|
||||
autoApproveCidrs: ["192.168.1.0/24", "fd00:1234:5678::/64"],
|
||||
},
|
||||
allowCommands: ["canvas.navigate"],
|
||||
denyCommands: ["system.run"],
|
||||
},
|
||||
tools: {
|
||||
// 额外的 /tools/invoke HTTP 拒绝项
|
||||
// 额外的 /tools/invoke HTTP deny
|
||||
deny: ["browser"],
|
||||
// 从默认 HTTP 拒绝列表中移除工具
|
||||
// 从默认 HTTP deny 列表中移除工具
|
||||
allow: ["gateway"],
|
||||
},
|
||||
push: {
|
||||
@ -309,56 +317,53 @@ x-i18n:
|
||||
}
|
||||
```
|
||||
|
||||
<Accordion title="Gateway 网关 字段详情">
|
||||
<Accordion title="Gateway 网关字段详情">
|
||||
|
||||
- `mode`:`local`(运行 Gateway 网关)或 `remote`(连接到远程 Gateway 网关)。只有在 `local` 模式下,Gateway 网关 才会启动,否则会拒绝启动。
|
||||
- `port`:用于 WS + HTTP 的单一多路复用端口。优先级:`--port` > `OPENCLAW_GATEWAY_PORT` > `gateway.port` > `18789`。
|
||||
- `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"`)以监听所有接口。
|
||||
- **认证**:默认必需。非 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` 的身份头(参见 [受信任代理认证](/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`。
|
||||
- 来自浏览器 origin 的 WS 认证尝试始终会启用限流,且不会豁免 loopback(作为针对基于浏览器的 localhost 暴力破解的纵深防御)。
|
||||
- 在 loopback 上,这些来自浏览器 origin 的锁定会按标准化后的 `Origin`
|
||||
值隔离,因此一个 localhost origin 的重复失败不会自动
|
||||
锁定另一个 origin。
|
||||
- `tailscale.mode`:`serve`(仅 tailnet,loopback bind)或 `funnel`(公开访问,需要认证)。
|
||||
- `controlUi.allowedOrigins`:用于 Gateway 网关 WebSocket 连接的显式浏览器 origin 允许列表。当预期浏览器客户端来自非 loopback origin 时,此项是必需的。
|
||||
- `controlUi.dangerouslyAllowHostHeaderOriginFallback`:危险模式,为有意依赖 Host 头 origin 策略的部署启用基于 Host 头的 origin 回退。
|
||||
- **旧版 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`(包括 SecretRef),请显式设置 `gateway.auth.mode` 为 `token` 或 `password`。若两者都已配置但未设置 mode,启动以及服务安装 / 修复流程都会失败。
|
||||
- `gateway.auth.mode: "none"`:显式无认证模式。仅用于受信任的本地 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`:可选的认证失败限制器。按客户端 IP 和 auth 范围生效(共享密钥和 device-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 的重复失败不会自动锁定另一个 origin。
|
||||
- `tailscale.mode`:`serve`(仅 tailnet,loopback bind)或 `funnel`(公开,需要 auth)。
|
||||
- `controlUi.allowedOrigins`:用于 Gateway 网关 WebSocket 连接的显式浏览器 origin 允许列表。当预期浏览器客户端来自非 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`:客户端进程环境中的紧急放行覆盖项,允许对受信任私有网络 IP 使用明文 `ws://`;默认仍仅允许在 loopback 上使用明文。没有对应的 `openclaw.json`
|
||||
配置项,且浏览器私有网络配置(例如
|
||||
`browser.ssrfPolicy.dangerouslyAllowPrivateNetwork`)也不会影响 Gateway 网关
|
||||
WebSocket 客户端。
|
||||
- `gateway.remote.token` / `.password` 是远程客户端凭证字段。它们本身不会配置 Gateway 网关 认证。
|
||||
- `gateway.push.apns.relay.baseUrl`:供官方 / TestFlight iOS 构建在向 Gateway 网关 发布基于 relay 的注册后使用的外部 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.<provider>.healthMonitor.enabled`:每个渠道单独退出健康监视器重启,同时保持全局监视器启用。
|
||||
- `channels.<provider>.accounts.<accountId>.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 拒绝列表中移除工具名。
|
||||
- `OPENCLAW_ALLOW_INSECURE_PRIVATE_WS=1`:客户端进程环境变量级别的紧急放行覆盖,允许对受信任私有网络 IP 使用明文 `ws://`;默认仍然只允许对 loopback 使用明文。没有对应的 `openclaw.json` 配置项,且诸如 `browser.ssrfPolicy.dangerouslyAllowPrivateNetwork` 之类的浏览器私有网络配置不会影响 Gateway 网关 WebSocket 客户端。
|
||||
- `gateway.remote.token` / `.password` 是远程客户端凭证字段。它们本身不会配置 gateway auth。
|
||||
- `gateway.push.apns.relay.baseUrl`:外部 APNs relay 的基础 HTTPS URL,供官方 / TestFlight iOS 构建在向 gateway 发布基于 relay 的注册之后使用。此 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.<provider>.healthMonitor.enabled`:按渠道禁用健康监控重启,同时保留全局监控启用。
|
||||
- `channels.<provider>.accounts.<accountId>.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.nodes.pairing.autoApproveCidrs`:可选的 CIDR / IP 允许列表,用于在未请求作用域时自动批准首次节点设备配对。未设置时为禁用状态。它不会自动批准 operator / 浏览器 / Control UI / WebChat 配对,也不会自动批准角色、作用域、元数据或公钥升级。
|
||||
- `gateway.nodes.allowCommands` / `gateway.nodes.denyCommands`:在配对和允许列表评估之后,对已声明节点命令进行全局允许 / 拒绝整形。
|
||||
- `gateway.tools.deny`:对 HTTP `POST /tools/invoke` 额外阻止的工具名称(扩展默认 deny 列表)。
|
||||
- `gateway.tools.allow`:从默认 HTTP deny 列表中移除工具名称。
|
||||
|
||||
</Accordion>
|
||||
|
||||
### 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`
|
||||
@ -366,12 +371,12 @@ x-i18n:
|
||||
- `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 origin 设置;参见 [受信任代理认证](/zh-CN/gateway/trusted-proxy-auth#tls-termination-and-hsts))
|
||||
- 可选的响应加固标头:
|
||||
- `gateway.http.securityHeaders.strictTransportSecurity`(仅对你控制的 HTTPS origin 设置;参见 [Trusted Proxy Auth](/zh-CN/gateway/trusted-proxy-auth#tls-termination-and-hsts))
|
||||
|
||||
### 多实例隔离
|
||||
|
||||
在同一主机上运行多个 Gateway 网关 实例时,请使用唯一端口和状态目录:
|
||||
在一台主机上运行多个 gateways 时,请使用唯一的端口和状态目录:
|
||||
|
||||
```bash
|
||||
OPENCLAW_CONFIG_PATH=~/.openclaw/a.json \
|
||||
@ -381,7 +386,7 @@ openclaw gateway --port 19001
|
||||
|
||||
便捷标志:`--dev`(使用 `~/.openclaw-dev` + 端口 `19001`)、`--profile <name>`(使用 `~/.openclaw-<name>`)。
|
||||
|
||||
参见 [多个 Gateway 网关](/zh-CN/gateway/multiple-gateways)。
|
||||
请参阅[多个 Gateway 网关](/zh-CN/gateway/multiple-gateways)。
|
||||
|
||||
### `gateway.tls`
|
||||
|
||||
@ -399,11 +404,11 @@ openclaw gateway --port 19001
|
||||
}
|
||||
```
|
||||
|
||||
- `enabled`:在 Gateway 网关 监听器处启用 TLS 终止(HTTPS / WSS)(默认:`false`)。
|
||||
- `autoGenerate`:当未配置显式文件时,自动生成本地自签名证书 / 密钥对;仅适用于本地 / 开发场景。
|
||||
- `enabled`:在 gateway 监听器上启用 TLS 终止(HTTPS / WSS)(默认:`false`)。
|
||||
- `autoGenerate`:当未配置显式文件时,自动生成本地自签名证书 / 密钥对;仅用于本地 / 开发环境。
|
||||
- `certPath`:TLS 证书文件的文件系统路径。
|
||||
- `keyPath`:TLS 私钥文件的文件系统路径;应限制文件权限。
|
||||
- `caPath`:用于客户端验证或自定义信任链的可选 CA bundle 路径。
|
||||
- `keyPath`:TLS 私钥文件的文件系统路径;请限制文件权限。
|
||||
- `caPath`:可选的 CA bundle 路径,用于客户端验证或自定义信任链。
|
||||
|
||||
### `gateway.reload`
|
||||
|
||||
@ -419,17 +424,17 @@ openclaw gateway --port 19001
|
||||
}
|
||||
```
|
||||
|
||||
- `mode`:控制运行时如何应用配置编辑。
|
||||
- `mode`:控制如何在运行时应用配置编辑。
|
||||
- `"off"`:忽略实时编辑;更改需要显式重启。
|
||||
- `"restart"`:配置变更时始终重启 Gateway 网关 进程。
|
||||
- `"restart"`:配置变更时始终重启 gateway 进程。
|
||||
- `"hot"`:在不重启的情况下于进程内应用更改。
|
||||
- `"hybrid"`(默认):先尝试热重载;如有需要则回退为重启。
|
||||
- `debounceMs`:应用配置变更前的防抖窗口(毫秒)(非负整数)。
|
||||
- `deferralTimeoutMs`:在强制重启前等待进行中操作完成的最长时间(毫秒)(默认:`300000` = 5 分钟)。
|
||||
- `debounceMs`:在应用配置更改前的防抖窗口(毫秒,非负整数)。
|
||||
- `deferralTimeoutMs`:在强制重启前,等待进行中操作完成的最长时间(毫秒,默认:`300000` = 5 分钟)。
|
||||
|
||||
---
|
||||
|
||||
## 钩子
|
||||
## Hooks
|
||||
|
||||
```json5
|
||||
{
|
||||
@ -463,15 +468,15 @@ openclaw gateway --port 19001
|
||||
```
|
||||
|
||||
认证:`Authorization: Bearer <token>` 或 `x-openclaw-token: <token>`。
|
||||
不接受查询字符串中的 hook token。
|
||||
拒绝使用查询字符串 hook token。
|
||||
|
||||
验证和安全说明:
|
||||
验证与安全说明:
|
||||
|
||||
- `hooks.enabled=true` 需要一个非空的 `hooks.token`。
|
||||
- `hooks.enabled=true` 要求 `hooks.token` 为非空。
|
||||
- `hooks.token` 必须与 `gateway.auth.token` **不同**;复用 Gateway 网关 token 会被拒绝。
|
||||
- `hooks.path` 不能是 `/`;请使用专用子路径,例如 `/hooks`。
|
||||
- `hooks.path` 不能为 `/`;请使用专用子路径,例如 `/hooks`。
|
||||
- 如果 `hooks.allowRequestSessionKey=true`,请约束 `hooks.allowedSessionKeyPrefixes`(例如 `["hook:"]`)。
|
||||
- 如果某个 mapping 或 preset 使用模板化的 `sessionKey`,请设置 `hooks.allowedSessionKeyPrefixes` 和 `hooks.allowRequestSessionKey=true`。静态 mapping 键不需要此显式启用。
|
||||
- 如果某个映射或预设使用模板化 `sessionKey`,请设置 `hooks.allowedSessionKeyPrefixes` 和 `hooks.allowRequestSessionKey=true`。静态映射键不需要此显式启用。
|
||||
|
||||
**端点:**
|
||||
|
||||
@ -479,30 +484,30 @@ openclaw gateway --port 19001
|
||||
- `POST /hooks/agent` → `{ message, name?, agentId?, sessionKey?, wakeMode?, deliver?, channel?, to?, model?, thinking?, timeoutSeconds? }`
|
||||
- 仅当 `hooks.allowRequestSessionKey=true`(默认:`false`)时,才接受请求负载中的 `sessionKey`。
|
||||
- `POST /hooks/<name>` → 通过 `hooks.mappings` 解析
|
||||
- 模板渲染后的 mapping `sessionKey` 值会被视为外部提供,因此同样要求 `hooks.allowRequestSessionKey=true`。
|
||||
- 通过模板渲染得到的映射 `sessionKey` 值会被视为外部提供,因此同样要求 `hooks.allowRequestSessionKey=true`。
|
||||
|
||||
<Accordion title="Mapping 详情">
|
||||
<Accordion title="映射详情">
|
||||
|
||||
- `match.path` 匹配 `/hooks` 之后的子路径(例如 `/hooks/gmail` → `gmail`)。
|
||||
- `match.source` 匹配通用路径中的某个负载字段。
|
||||
- `match.source` 匹配通用路径的某个负载字段。
|
||||
- 像 `{{messages[0].subject}}` 这样的模板会从负载中读取。
|
||||
- `transform` 可以指向一个返回 hook 动作的 JS / TS 模块。
|
||||
- `transform.module` 必须是相对路径,并且必须位于 `hooks.transformsDir` 内(绝对路径和路径穿越都会被拒绝)。
|
||||
- `transform` 可以指向一个返回 hook action 的 JS / TS 模块。
|
||||
- `transform.module` 必须是相对路径,并且必须位于 `hooks.transformsDir` 内部(绝对路径和路径穿越会被拒绝)。
|
||||
- `agentId` 路由到特定智能体;未知 ID 会回退到默认值。
|
||||
- `allowedAgentIds`:限制显式路由(`*` 或省略 = 允许全部,`[]` = 全部拒绝)。
|
||||
- `defaultSessionKey`:可选的固定会话键,用于未显式提供 `sessionKey` 的 hook 智能体运行。
|
||||
- `allowRequestSessionKey`:允许 `/hooks/agent` 调用方以及模板驱动的 mapping 会话键设置 `sessionKey`(默认:`false`)。
|
||||
- `allowedSessionKeyPrefixes`:显式 `sessionKey` 值(请求 + mapping)的可选前缀允许列表,例如 `["hook:"]`。当任一 mapping 或 preset 使用模板化 `sessionKey` 时,它会变为必填项。
|
||||
- `deliver: true` 会将最终回复发送到某个渠道;`channel` 默认为 `last`。
|
||||
- `model` 会覆盖此次 hook 运行的 LLM(如果设置了模型目录,则必须被允许)。
|
||||
- `defaultSessionKey`:可选的固定会话键,用于没有显式 `sessionKey` 的 hook 智能体运行。
|
||||
- `allowRequestSessionKey`:允许 `/hooks/agent` 调用方以及模板驱动的映射会话键设置 `sessionKey`(默认:`false`)。
|
||||
- `allowedSessionKeyPrefixes`:显式 `sessionKey` 值(请求 + 映射)的可选前缀允许列表,例如 `["hook:"]`。当任意映射或预设使用模板化 `sessionKey` 时,它将成为必需项。
|
||||
- `deliver: true` 会将最终回复发送到某个渠道;`channel` 默认值为 `last`。
|
||||
- `model` 会覆盖此次 hook 运行使用的 LLM(若设置了模型目录,则该模型必须被允许)。
|
||||
|
||||
</Accordion>
|
||||
|
||||
### Gmail 集成
|
||||
|
||||
- 内置 Gmail preset 使用 `sessionKey: "hook:gmail:{{messages[0].id}}"`。
|
||||
- 如果你保留这种按消息路由的方式,请设置 `hooks.allowRequestSessionKey: true`,并约束 `hooks.allowedSessionKeyPrefixes` 以匹配 Gmail 命名空间,例如 `["hook:", "hook:gmail:"]`。
|
||||
- 如果你需要 `hooks.allowRequestSessionKey: false`,请用静态 `sessionKey` 覆盖 preset,而不是使用默认的模板化值。
|
||||
- 内置 Gmail 预设使用 `sessionKey: "hook:gmail:{{messages[0].id}}"`。
|
||||
- 如果你保留这种按消息路由方式,请设置 `hooks.allowRequestSessionKey: true`,并将 `hooks.allowedSessionKeyPrefixes` 约束为匹配 Gmail 命名空间,例如 `["hook:", "hook:gmail:"]`。
|
||||
- 如果你需要 `hooks.allowRequestSessionKey: false`,请用静态 `sessionKey` 覆盖预设,而不是使用默认的模板化值。
|
||||
|
||||
```json5
|
||||
{
|
||||
@ -525,8 +530,8 @@ openclaw gateway --port 19001
|
||||
}
|
||||
```
|
||||
|
||||
- 配置后,Gateway 网关 会在启动时自动启动 `gog gmail watch serve`。设置 `OPENCLAW_SKIP_GMAIL_WATCHER=1` 可禁用。
|
||||
- 不要在 Gateway 网关 旁边单独运行另一个 `gog gmail watch serve`。
|
||||
- 配置后,Gateway 网关会在启动时自动启动 `gog gmail watch serve`。设置 `OPENCLAW_SKIP_GMAIL_WATCHER=1` 可禁用。
|
||||
- 不要在 Gateway 网关之外另外运行一个独立的 `gog gmail watch serve`。
|
||||
|
||||
---
|
||||
|
||||
@ -542,18 +547,18 @@ openclaw gateway --port 19001
|
||||
}
|
||||
```
|
||||
|
||||
- 通过 Gateway 网关 端口下的 HTTP 提供可由智能体编辑的 HTML / CSS / JS 和 A2UI:
|
||||
- 在 Gateway 网关端口下通过 HTTP 提供可由智能体编辑的 HTML / CSS / JS 和 A2UI:
|
||||
- `http://<gateway-host>:<gateway.port>/__openclaw__/canvas/`
|
||||
- `http://<gateway-host>:<gateway.port>/__openclaw__/a2ui/`
|
||||
- 仅限本地:保持 `gateway.bind: "loopback"`(默认)。
|
||||
- 非 loopback bind:canvas 路由与其他 Gateway 网关 HTTP 面相同,需要 Gateway 网关 认证(token / password / trusted-proxy)。
|
||||
- 节点 WebView 通常不会发送认证头;在节点配对并连接后,Gateway 网关 会通告节点作用域的 capability URL,以便访问 canvas / A2UI。
|
||||
- Capability URL 绑定到当前活动节点 WS 会话,并且会很快过期。不使用基于 IP 的回退。
|
||||
- 会将 live-reload 客户端注入到所提供的 HTML 中。
|
||||
- 仅本地:保持 `gateway.bind: "loopback"`(默认)。
|
||||
- 非 loopback bind:canvas 路由需要 Gateway 网关认证(token / password / trusted-proxy),与其他 Gateway 网关 HTTP 面相同。
|
||||
- 节点 WebView 通常不会发送认证标头;节点配对并连接后,Gateway 网关会为 canvas / A2UI 访问公布节点作用域 capability URL。
|
||||
- Capability URL 绑定到活动节点 WS 会话,并且过期很快。不使用基于 IP 的回退。
|
||||
- 会向所提供的 HTML 中注入实时重载客户端。
|
||||
- 为空时会自动创建初始 `index.html`。
|
||||
- 同时还会在 `/__openclaw__/a2ui/` 提供 A2UI。
|
||||
- 更改需要重启 Gateway 网关。
|
||||
- 对于大型目录或 `EMFILE` 错误,请禁用 live reload。
|
||||
- 也会在 `/__openclaw__/a2ui/` 提供 A2UI。
|
||||
- 更改需要重启 gateway。
|
||||
- 对于大型目录或出现 `EMFILE` 错误时,请禁用实时重载。
|
||||
|
||||
---
|
||||
|
||||
@ -575,7 +580,7 @@ openclaw gateway --port 19001
|
||||
- `full`:包含 `cliPath` + `sshPort`。
|
||||
- 主机名默认为 `openclaw`。可通过 `OPENCLAW_MDNS_HOSTNAME` 覆盖。
|
||||
|
||||
### 广域网(DNS-SD)
|
||||
### 广域(DNS-SD)
|
||||
|
||||
```json5
|
||||
{
|
||||
@ -585,7 +590,7 @@ openclaw gateway --port 19001
|
||||
}
|
||||
```
|
||||
|
||||
会在 `~/.openclaw/dns/` 下写入一个单播 DNS-SD 区域。若要实现跨网络设备发现,请配合 DNS 服务器(推荐 CoreDNS)+ Tailscale split DNS。
|
||||
会在 `~/.openclaw/dns/` 下写入单播 DNS-SD 区域。对于跨网络设备发现,请配合 DNS 服务器(推荐 CoreDNS)+ Tailscale split DNS 使用。
|
||||
|
||||
设置:`openclaw dns setup --apply`。
|
||||
|
||||
@ -610,14 +615,14 @@ openclaw gateway --port 19001
|
||||
}
|
||||
```
|
||||
|
||||
- 仅当进程环境中缺少对应键时,才会应用内联环境变量。
|
||||
- `.env` 文件:当前工作目录中的 `.env` + `~/.openclaw/.env`(两者都不会覆盖现有变量)。
|
||||
- 只有当进程环境中缺少该键时,才会应用内联环境变量。
|
||||
- `.env` 文件:当前工作目录 `.env` + `~/.openclaw/.env`(两者都不会覆盖现有变量)。
|
||||
- `shellEnv`:从你的登录 shell 配置文件导入缺失的预期键名。
|
||||
- 完整优先级请参见 [环境](/zh-CN/help/environment)。
|
||||
- 完整优先级请参阅[环境](/zh-CN/help/environment)。
|
||||
|
||||
### 环境变量替换
|
||||
|
||||
可以在任何配置字符串中使用 `${VAR_NAME}` 引用环境变量:
|
||||
可在任意配置字符串中使用 `${VAR_NAME}` 引用环境变量:
|
||||
|
||||
```json5
|
||||
{
|
||||
@ -628,9 +633,9 @@ openclaw gateway --port 19001
|
||||
```
|
||||
|
||||
- 仅匹配大写名称:`[A-Z_][A-Z0-9_]*`。
|
||||
- 缺失 / 为空的变量会在加载配置时抛出错误。
|
||||
- 使用 `$${VAR}` 来转义为字面量 `${VAR}`。
|
||||
- 可与 `$include` 一起使用。
|
||||
- 缺失 / 为空的变量会在加载配置时报错。
|
||||
- 使用 `$${VAR}` 可转义为字面量 `${VAR}`。
|
||||
- 可与 `$include` 配合使用。
|
||||
|
||||
---
|
||||
|
||||
@ -652,15 +657,15 @@ SecretRef 是增量支持的:明文值仍然可用。
|
||||
- `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` 引用也包含在运行时解析和审计覆盖范围内。
|
||||
- `secrets apply` 面向受支持的 `openclaw.json` 凭证路径。
|
||||
- `auth-profiles.json` 中的 ref 也包含在运行时解析和审计覆盖范围中。
|
||||
|
||||
### Secret 提供商配置
|
||||
### Secret providers 配置
|
||||
|
||||
```json5
|
||||
{
|
||||
@ -690,14 +695,14 @@ SecretRef 是增量支持的:明文值仍然可用。
|
||||
|
||||
说明:
|
||||
|
||||
- `file` 提供商支持 `mode: "json"` 和 `mode: "singleValue"`(在 `singleValue` 模式下,`id` 必须为 `"value"`)。
|
||||
- 当无法验证 Windows ACL 时,file 和 exec 提供商路径会以关闭方式失败。仅在路径受信任但无法验证时,将 `allowInsecurePath: true` 设为 true。
|
||||
- `exec` 提供商要求使用绝对 `command` 路径,并通过 stdin / stdout 传输协议负载。
|
||||
- `file` provider 支持 `mode: "json"` 和 `mode: "singleValue"`(在 `singleValue` 模式下,`id` 必须为 `"value"`)。
|
||||
- 当 Windows ACL 验证不可用时,文件和 exec provider 路径会以关闭失败方式处理。仅对无法验证但受信任的路径设置 `allowInsecurePath: true`。
|
||||
- `exec` provider 要求使用绝对 `command` 路径,并通过 stdin / stdout 传输协议负载。
|
||||
- 默认情况下,符号链接命令路径会被拒绝。设置 `allowSymlinkCommand: true` 可允许符号链接路径,同时仍会验证解析后的目标路径。
|
||||
- 如果配置了 `trustedDirs`,受信任目录检查会应用到解析后的目标路径。
|
||||
- 如果配置了 `trustedDirs`,则受信任目录检查会应用到解析后的目标路径。
|
||||
- 默认情况下,`exec` 子进程环境是最小化的;请通过 `passEnv` 显式传递所需变量。
|
||||
- Secret 引用会在激活时解析为内存中的快照,之后请求路径只读取该快照。
|
||||
- 激活期间会应用活动表面过滤:已启用表面上的未解析引用会导致启动 / 重载失败,而非活动表面会被跳过并记录诊断信息。
|
||||
- Secret ref 会在激活时解析为内存快照,之后请求路径只读取该快照。
|
||||
- 激活期间会应用活动面过滤:启用表面上的未解析 ref 会导致启动 / 重载失败,而非活动表面会被跳过并给出诊断信息。
|
||||
|
||||
---
|
||||
|
||||
@ -719,13 +724,13 @@ SecretRef 是增量支持的:明文值仍然可用。
|
||||
}
|
||||
```
|
||||
|
||||
- 每个智能体的 profile 存储在 `<agentDir>/auth-profiles.json`。
|
||||
- `auth-profiles.json` 支持值级引用(静态凭证模式中 `api_key` 使用 `keyRef`,`token` 使用 `tokenRef`)。
|
||||
- OAuth 模式 profile(`auth.profiles.<id>.mode = "oauth"`)不支持由 SecretRef 支持的 auth-profile 凭证。
|
||||
- 静态运行时凭证来自内存中的已解析快照;发现旧版静态 `auth.json` 条目时会被清理。
|
||||
- 按智能体划分的 profile 存储在 `<agentDir>/auth-profiles.json`。
|
||||
- `auth-profiles.json` 支持静态凭证模式的值级 ref(`api_key` 使用 `keyRef`,`token` 使用 `tokenRef`)。
|
||||
- OAuth 模式 profile(`auth.profiles.<id>.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)。
|
||||
- 请参阅 [OAuth](/zh-CN/concepts/oauth)。
|
||||
- Secrets 运行时行为以及 `audit/configure/apply` 工具:请参阅[Secrets 管理](/zh-CN/gateway/secrets)。
|
||||
|
||||
### `auth.cooldowns`
|
||||
|
||||
@ -747,20 +752,15 @@ SecretRef 是增量支持的:明文值仍然可用。
|
||||
}
|
||||
```
|
||||
|
||||
- `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`:对 overloaded 错误,在切换到模型回退之前,同一提供商 auth-profile 允许轮换的最大次数(默认:`1`)。例如 `ModelNotReadyException` 这样的提供商忙碌形态会归入此类。
|
||||
- `overloadedBackoffMs`:在重试 overloaded 提供商 / profile 轮换之前的固定延迟(毫秒)(默认:`0`)。
|
||||
- `rateLimitedProfileRotations`:对 rate-limit 错误,在切换到模型回退之前,同一提供商 auth-profile 允许轮换的最大次数(默认:`1`)。该 rate-limit 类别包括提供商特定文本,例如 `Too many concurrent requests`、`ThrottlingException`、`concurrency limit reached`、`workers_ai ... quota limit exceeded` 和 `resource exhausted`。
|
||||
- `billingBackoffHours`:当某个 profile 因真实的计费 / 余额不足错误而失败时的基础退避时长(小时,默认:`5`)。即使在 `401` / `403` 响应上,明确的计费文本仍可能归入这里,但 provider 特定的文本匹配器仍只作用于拥有它们的 provider(例如 OpenRouter 的 `Key limit exceeded`)。可重试的 HTTP `402` 用量窗口或 organization / workspace 支出限制消息,则仍归入 `rate_limit` 路径。
|
||||
- `billingBackoffHoursByProvider`:可选的按 provider 覆盖的计费退避时长(小时)。
|
||||
- `billingMaxHours`:计费退避指数增长的上限(小时,默认:`24`)。
|
||||
- `authPermanentBackoffMinutes`:高置信度 `auth_permanent` 失败的基础退避时长(分钟,默认:`10`)。
|
||||
- `authPermanentMaxMinutes`:`auth_permanent` 退避增长的上限(分钟,默认:`60`)。
|
||||
- `failureWindowHours`:用于退避计数器的滚动窗口(小时,默认:`24`)。
|
||||
- `overloadedProfileRotations`:对于过载错误,在切换到模型回退之前,同一 provider 内允许的最大 auth-profile 轮换次数(默认:`1`)。诸如 `ModelNotReadyException` 这样的 provider 忙碌形态归入这里。
|
||||
- `overloadedBackoffMs`:在重试某个过载的 provider / profile 轮换之前的固定延迟(毫秒,默认:`0`)。
|
||||
- `rateLimitedProfileRotations`:对于速率限制错误,在切换到模型回退之前,同一 provider 内允许的最大 auth-profile 轮换次数(默认:`1`)。该 rate-limit 类别包括 provider 形态的文本,例如 `Too many concurrent requests`、`ThrottlingException`、`concurrency limit reached`、`workers_ai ... quota limit exceeded` 和 `resource exhausted`。
|
||||
|
||||
---
|
||||
|
||||
@ -780,13 +780,13 @@ SecretRef 是增量支持的:明文值仍然可用。
|
||||
```
|
||||
|
||||
- 默认日志文件:`/tmp/openclaw/openclaw-YYYY-MM-DD.log`。
|
||||
- 设置 `logging.file` 以使用固定路径。
|
||||
- 设置 `logging.file` 可使用稳定路径。
|
||||
- 使用 `--verbose` 时,`consoleLevel` 会提升到 `debug`。
|
||||
- `maxFileBytes`:在抑制写入之前,日志文件允许的最大大小(字节)(正整数;默认:`524288000` = 500 MB)。生产部署请使用外部日志轮转。
|
||||
- `maxFileBytes`:在抑制写入前允许的最大日志文件大小(字节,正整数;默认:`524288000` = 500 MB)。生产部署请使用外部日志轮转。
|
||||
|
||||
---
|
||||
|
||||
## 诊断
|
||||
## Diagnostics
|
||||
|
||||
```json5
|
||||
{
|
||||
@ -827,21 +827,21 @@ SecretRef 是增量支持的:明文值仍然可用。
|
||||
}
|
||||
```
|
||||
|
||||
- `enabled`:仪表化输出的总开关(默认:`true`)。
|
||||
- `enabled`:instrumentation 输出总开关(默认:`true`)。
|
||||
- `flags`:启用定向日志输出的标志字符串数组(支持像 `"telegram.*"` 或 `"*"` 这样的通配符)。
|
||||
- `stuckSessionWarnMs`:当某个会话仍处于处理状态时,发出卡住会话警告的年龄阈值(毫秒)。
|
||||
- `stuckSessionWarnMs`:当会话仍处于处理中状态时,发出卡住会话警告的时长阈值(毫秒)。
|
||||
- `otel.enabled`:启用 OpenTelemetry 导出管线(默认:`false`)。
|
||||
- `otel.endpoint`:OTel 导出的 collector URL。
|
||||
- `otel.protocol`:`"http/protobuf"`(默认)或 `"grpc"`。
|
||||
- `otel.headers`:随 OTel 导出请求发送的额外 HTTP / gRPC 元数据头。
|
||||
- `otel.headers`:随 OTel 导出请求发送的额外 HTTP / gRPC 元数据标头。
|
||||
- `otel.serviceName`:资源属性使用的服务名。
|
||||
- `otel.traces` / `otel.metrics` / `otel.logs`:启用 trace、metrics 或日志导出。
|
||||
- `otel.sampleRate`:trace 采样率,范围 `0`–`1`。
|
||||
- `otel.traces` / `otel.metrics` / `otel.logs`:启用 trace、metrics 或 log 导出。
|
||||
- `otel.sampleRate`:trace 采样率 `0`–`1`。
|
||||
- `otel.flushIntervalMs`:定期刷新 telemetry 的间隔(毫秒)。
|
||||
- `otel.captureContent`:用于 OTEL span 属性的原始内容采集显式启用项。默认关闭。布尔值 `true` 会采集非 system 消息 / 工具内容;对象形式则允许你显式启用 `inputMessages`、`outputMessages`、`toolInputs`、`toolOutputs` 和 `systemPrompt`。
|
||||
- `cacheTrace.enabled`:记录嵌入式运行的缓存跟踪快照(默认:`false`)。
|
||||
- `otel.captureContent`:显式启用用于 OTEL span 属性的原始内容捕获。默认关闭。布尔值 `true` 会捕获非 system 的消息 / 工具内容;对象形式则允许你显式启用 `inputMessages`、`outputMessages`、`toolInputs`、`toolOutputs` 和 `systemPrompt`。
|
||||
- `cacheTrace.enabled`:为嵌入式运行记录缓存跟踪快照(默认:`false`)。
|
||||
- `cacheTrace.filePath`:缓存跟踪 JSONL 的输出路径(默认:`$OPENCLAW_STATE_DIR/logs/cache-trace.jsonl`)。
|
||||
- `cacheTrace.includeMessages` / `includePrompt` / `includeSystem`:控制缓存跟踪输出中包含哪些内容(默认全部为 `true`)。
|
||||
- `cacheTrace.includeMessages` / `includePrompt` / `includeSystem`:控制缓存跟踪输出包含哪些内容(默认全为 `true`)。
|
||||
|
||||
---
|
||||
|
||||
@ -863,12 +863,12 @@ SecretRef 是增量支持的:明文值仍然可用。
|
||||
}
|
||||
```
|
||||
|
||||
- `channel`:npm / git 安装的发布渠道——`"stable"`、`"beta"` 或 `"dev"`。
|
||||
- `checkOnStart`:Gateway 网关 启动时检查 npm 更新(默认:`true`)。
|
||||
- `auto.enabled`:为 package 安装启用后台自动更新(默认:`false`)。
|
||||
- `auto.stableDelayHours`:稳定渠道自动应用前的最小时延(小时)(默认:`6`;最大:`168`)。
|
||||
- `auto.stableJitterHours`:稳定渠道额外的发布扩散窗口(小时)(默认:`12`;最大:`168`)。
|
||||
- `auto.betaCheckIntervalHours`:beta 渠道检查运行的频率(小时)(默认:`1`;最大:`24`)。
|
||||
- `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`)。
|
||||
|
||||
---
|
||||
|
||||
@ -901,22 +901,22 @@ SecretRef 是增量支持的:明文值仍然可用。
|
||||
}
|
||||
```
|
||||
|
||||
- `enabled`:全局 ACP 功能开关(默认:`false`)。
|
||||
- `dispatch.enabled`:ACP 会话轮次分发的独立开关(默认:`true`)。设为 `false` 可在阻止执行的同时保留 ACP 命令可用。
|
||||
- `backend`:默认 ACP 运行时后端 id(必须与已注册的 ACP 运行时插件匹配)。
|
||||
- `defaultAgent`:当生成过程未指定显式目标时,ACP 的回退目标智能体 id。
|
||||
- `allowedAgents`:允许用于 ACP 运行时会话的智能体 id 允许列表;空值表示无额外限制。
|
||||
- `maxConcurrentSessions`:同时活跃的 ACP 会话最大数量。
|
||||
- `enabled`:全局 ACP 功能门控(默认:`false`)。
|
||||
- `dispatch.enabled`:ACP 会话轮次分发的独立门控(默认:`true`)。设为 `false` 可在阻止执行的同时保留 ACP 命令可用。
|
||||
- `backend`:默认 ACP 运行时 backend id(必须匹配已注册的 ACP 运行时插件)。
|
||||
- `defaultAgent`:当 spawn 未指定显式目标时,ACP 目标智能体 id 的回退值。
|
||||
- `allowedAgents`:允许用于 ACP 运行时会话的智能体 id 允许列表;为空表示没有额外限制。
|
||||
- `maxConcurrentSessions`:同时处于活动状态的 ACP 会话最大数量。
|
||||
- `stream.coalesceIdleMs`:流式文本的空闲合并刷新窗口(毫秒)。
|
||||
- `stream.maxChunkChars`:在拆分流式分块投影前允许的最大块大小。
|
||||
- `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 运行时环境时运行的可选安装命令。
|
||||
- `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 运行时环境时执行的可选安装命令。
|
||||
|
||||
---
|
||||
|
||||
@ -936,7 +936,7 @@ SecretRef 是增量支持的:明文值仍然可用。
|
||||
- `"random"`(默认):轮换的有趣 / 季节性标语。
|
||||
- `"default"`:固定的中性标语(`All your chats, one OpenClaw.`)。
|
||||
- `"off"`:不显示标语文本(仍显示 banner 标题 / 版本)。
|
||||
- 如需隐藏整个 banner(不只是标语),请设置环境变量 `OPENCLAW_HIDE_BANNER=1`。
|
||||
- 若要隐藏整个 banner(而不仅是标语),请设置环境变量 `OPENCLAW_HIDE_BANNER=1`。
|
||||
|
||||
---
|
||||
|
||||
@ -960,13 +960,13 @@ SecretRef 是增量支持的:明文值仍然可用。
|
||||
|
||||
## 身份
|
||||
|
||||
请参见 [智能体默认值](/zh-CN/gateway/config-agents#agent-defaults) 下的 `agents.list` 身份字段。
|
||||
请参阅[智能体默认值](/zh-CN/gateway/config-agents#agent-defaults)中的 `agents.list` 身份字段。
|
||||
|
||||
---
|
||||
|
||||
## Bridge protocol(旧版节点,历史参考)(旧版,已移除)
|
||||
## Bridge 协议(旧版节点,历史参考)(旧版,已移除)
|
||||
|
||||
当前构建版本不再包含 TCP bridge。节点通过 Gateway 网关 WebSocket 连接。`bridge.*` 键已不再属于配置 schema 的一部分(在移除之前,验证会失败;`openclaw doctor --fix` 可以剥离未知键)。
|
||||
当前构建已不再包含 TCP bridge。节点通过 Gateway 网关 WebSocket 连接。`bridge.*` 键已不再属于配置 schema 的一部分(在移除前会导致验证失败;`openclaw doctor --fix` 可以移除未知键)。
|
||||
|
||||
<Accordion title="旧版 bridge 配置(历史参考)">
|
||||
|
||||
@ -1006,11 +1006,11 @@ SecretRef 是增量支持的:明文值仍然可用。
|
||||
}
|
||||
```
|
||||
|
||||
- `sessionRetention`:在从 `sessions.json` 修剪之前,已完成的隔离 cron 运行会话保留多长时间。同时也控制已归档的已删除 cron transcript 的清理。默认:`24h`;设为 `false` 可禁用。
|
||||
- `runLog.maxBytes`:每个运行日志文件(`cron/runs/<jobId>.jsonl`)在修剪前允许的最大大小。默认:`2_000_000` 字节。
|
||||
- `runLog.keepLines`:触发运行日志修剪时保留的最新行数。默认:`2000`。
|
||||
- `webhookToken`:用于 cron webhook POST 投递(`delivery.mode = "webhook"`)的 bearer token;若省略,则不会发送认证头。
|
||||
- `webhook`:已弃用的旧版回退 webhook URL(http / https),仅用于仍保留 `notify: true` 的已存储任务。
|
||||
- `sessionRetention`:在从 `sessions.json` 中清理之前,已完成的隔离 cron 运行会话要保留多久。也控制已归档、已删除 cron 转录的清理。默认:`24h`;设为 `false` 可禁用。
|
||||
- `runLog.maxBytes`:触发清理前每个运行日志文件(`cron/runs/<jobId>.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`
|
||||
|
||||
@ -1026,11 +1026,11 @@ SecretRef 是增量支持的:明文值仍然可用。
|
||||
}
|
||||
```
|
||||
|
||||
- `maxAttempts`:one-shot cron 任务在瞬时错误下的最大重试次数(默认:`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"`。省略时会重试所有瞬时类型。
|
||||
|
||||
仅适用于 one-shot cron 任务。周期性任务使用单独的失败处理方式。
|
||||
仅适用于一次性 cron 作业。循环作业使用单独的失败处理机制。
|
||||
|
||||
### `cron.failureAlert`
|
||||
|
||||
@ -1048,11 +1048,11 @@ SecretRef 是增量支持的:明文值仍然可用。
|
||||
}
|
||||
```
|
||||
|
||||
- `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`
|
||||
|
||||
@ -1069,16 +1069,16 @@ SecretRef 是增量支持的:明文值仍然可用。
|
||||
}
|
||||
```
|
||||
|
||||
- 所有 cron 任务失败通知的默认目标位置。
|
||||
- 所有作业共用的 cron 失败通知默认目标。
|
||||
- `mode`:`"announce"` 或 `"webhook"`;当存在足够的目标数据时,默认值为 `"announce"`。
|
||||
- `channel`:announce 投递的渠道覆盖值。`"last"` 会复用上次已知的投递渠道。
|
||||
- `to`:显式的 announce 目标或 webhook URL。在 webhook 模式下为必填项。
|
||||
- `accountId`:可选的投递账号覆盖值。
|
||||
- 每个任务的 `delivery.failureDestination` 会覆盖此全局默认值。
|
||||
- 当全局和每个任务的失败目标位置都未设置时,已通过 `announce` 投递的任务在失败时会回退到其主 announce 目标。
|
||||
- `delivery.failureDestination` 仅对 `sessionTarget="isolated"` 的任务受支持,除非该任务的主 `delivery.mode` 为 `"webhook"`。
|
||||
- `channel`:用于 announce 交付的渠道覆盖。`"last"` 会复用最后一次已知的交付渠道。
|
||||
- `to`:显式的 announce 目标或 webhook URL。在 webhook 模式下为必需。
|
||||
- `accountId`:用于交付的可选账号覆盖。
|
||||
- 按作业的 `delivery.failureDestination` 会覆盖这个全局默认值。
|
||||
- 当全局和按作业的失败目标都未设置时,已经通过 `announce` 交付的作业在失败时会回退到该主要 announce 目标。
|
||||
- `delivery.failureDestination` 仅在 `sessionTarget="isolated"` 的作业中受支持,除非该作业的主要 `delivery.mode` 是 `"webhook"`。
|
||||
|
||||
参见 [Cron Jobs](/zh-CN/automation/cron-jobs)。隔离的 cron 执行会作为[后台任务](/zh-CN/automation/tasks)进行跟踪。
|
||||
请参阅 [Cron Jobs](/zh-CN/automation/cron-jobs)。隔离的 cron 执行会作为[后台任务](/zh-CN/automation/tasks)进行跟踪。
|
||||
|
||||
---
|
||||
|
||||
@ -1086,28 +1086,28 @@ SecretRef 是增量支持的:明文值仍然可用。
|
||||
|
||||
在 `tools.media.models[].args` 中展开的模板占位符:
|
||||
|
||||
| Variable | 说明 |
|
||||
| ------------------ | ---- |
|
||||
| `{{Body}}` | 完整的入站消息正文 |
|
||||
| `{{RawBody}}` | 原始正文(不含历史记录 / 发送者包装) |
|
||||
| 变量 | 描述 |
|
||||
| ------------------ | ------------------------------------------------- |
|
||||
| `{{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"` |
|
||||
| `{{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 等) |
|
||||
| `{{SenderName}}` | 发送者显示名称(尽力而为) |
|
||||
| `{{SenderE164}}` | 发送者电话号码(尽力而为) |
|
||||
| `{{Provider}}` | provider 提示(whatsapp、telegram、discord 等) |
|
||||
|
||||
---
|
||||
|
||||
@ -1128,20 +1128,20 @@ SecretRef 是增量支持的:明文值仍然可用。
|
||||
|
||||
**合并行为:**
|
||||
|
||||
- 单个文件:替换其所在的包含对象。
|
||||
- 单文件:替换所在的包含对象。
|
||||
- 文件数组:按顺序深度合并(后者覆盖前者)。
|
||||
- 同级键:在 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,会提供清晰的错误消息。
|
||||
- 同级键:在 includes 之后合并(覆盖 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)_
|
||||
|
||||
## 相关
|
||||
## 相关内容
|
||||
|
||||
- [配置](/zh-CN/gateway/configuration)
|
||||
- [配置示例](/zh-CN/gateway/configuration-examples)
|
||||
|
||||
@ -3,43 +3,43 @@ read_when:
|
||||
- 在没有 macOS UI 的情况下实现节点配对审批
|
||||
- 为批准远程节点添加 CLI 流程
|
||||
- 使用节点管理扩展 Gateway 网关协议
|
||||
summary: 用于 iOS 和其他远程节点的 Gateway 网关持有节点配对(方案 B)
|
||||
title: Gateway 网关持有的配对
|
||||
summary: 适用于 iOS 和其他远程节点的 Gateway 网关托管节点配对(方案 B)
|
||||
title: Gateway 网关托管配对
|
||||
x-i18n:
|
||||
generated_at: "2026-04-24T18:08:41Z"
|
||||
generated_at: "2026-04-25T05:54:20Z"
|
||||
model: gpt-5.4
|
||||
provider: openai
|
||||
source_hash: cab16e08e670f883fcaac9d1496ede02c5816a12a848f4f8032620092aff4ca4
|
||||
source_hash: 3b512fbf97e7557a1f467732f1b68d8c1b8183695e436b3f87b4c4aca1478cb5
|
||||
source_path: gateway/pairing.md
|
||||
workflow: 15
|
||||
---
|
||||
|
||||
在 Gateway 网关持有的配对中,**Gateway 网关** 是决定哪些节点
|
||||
可以加入的事实来源。UI(macOS 应用、未来的客户端)只是用于
|
||||
在 Gateway 网关托管配对中,**Gateway 网关** 是决定哪些节点
|
||||
允许加入的事实来源。UI(macOS 应用、未来客户端)只是用于
|
||||
批准或拒绝待处理请求的前端。
|
||||
|
||||
**重要:** WS 节点在 `connect` 期间使用 **设备配对**(角色为 `node`)。
|
||||
`node.pair.*` 是一个独立的配对存储,**不会**控制 WS 握手。
|
||||
只有显式调用 `node.pair.*` 的客户端才会使用这条流程。
|
||||
**重要:** WS 节点在 `connect` 期间使用**设备配对**(角色 `node`)。
|
||||
`node.pair.*` 是单独的配对存储,**不会**控制 WS 握手。
|
||||
只有显式调用 `node.pair.*` 的客户端才使用此流程。
|
||||
|
||||
## 概念
|
||||
|
||||
- **待处理请求**:某个节点请求加入;需要批准。
|
||||
- **已配对节点**:已获批准并已签发 auth token 的节点。
|
||||
- **传输层**:Gateway 网关 WS 端点会转发请求,但不决定
|
||||
成员资格。(旧版 TCP bridge 支持已移除。)
|
||||
- **已配对节点**:已批准并已签发认证令牌的节点。
|
||||
- **传输**:Gateway 网关 WS 端点会转发请求,但不决定
|
||||
成员资格。(旧版 TCP bridge 支持已被移除。)
|
||||
|
||||
## 配对如何工作
|
||||
|
||||
1. 一个节点连接到 Gateway 网关 WS,并请求配对。
|
||||
2. Gateway 网关存储一个**待处理请求**,并发出 `node.pair.requested`。
|
||||
3. 你批准或拒绝该请求(通过 CLI 或 UI)。
|
||||
4. 批准后,Gateway 网关会签发一个**新 token**(重新配对时 token 会轮换)。
|
||||
5. 节点使用该 token 重新连接,此时即为“已配对”。
|
||||
1. 节点连接到 Gateway 网关 WS 并请求配对。
|
||||
2. Gateway 网关存储一个**待处理请求**并发出 `node.pair.requested`。
|
||||
3. 你批准或拒绝该请求(CLI 或 UI)。
|
||||
4. 批准后,Gateway 网关签发一个**新令牌**(重新配对时令牌会轮换)。
|
||||
5. 节点使用该令牌重新连接,现在即为“已配对”。
|
||||
|
||||
待处理请求会在 **5 分钟** 后自动过期。
|
||||
|
||||
## CLI 工作流程(适合无界面环境)
|
||||
## CLI 工作流(适合无头环境)
|
||||
|
||||
```bash
|
||||
openclaw nodes pending
|
||||
@ -49,56 +49,56 @@ openclaw nodes status
|
||||
openclaw nodes rename --node <id|name|ip> --name "Living Room iPad"
|
||||
```
|
||||
|
||||
`nodes status` 会显示已配对 / 已连接的节点及其能力。
|
||||
`nodes status` 会显示已配对/已连接节点及其能力。
|
||||
|
||||
## API 界面(Gateway 网关协议)
|
||||
## API surface(Gateway 网关协议)
|
||||
|
||||
事件:
|
||||
|
||||
- `node.pair.requested` — 当创建新的待处理请求时发出。
|
||||
- `node.pair.resolved` — 当请求被批准 / 拒绝 / 过期时发出。
|
||||
- `node.pair.requested` — 创建新的待处理请求时发出。
|
||||
- `node.pair.resolved` — 请求被批准/拒绝/过期时发出。
|
||||
|
||||
方法:
|
||||
|
||||
- `node.pair.request` — 创建或复用一个待处理请求。
|
||||
- `node.pair.request` — 创建或复用待处理请求。
|
||||
- `node.pair.list` — 列出待处理 + 已配对节点(`operator.pairing`)。
|
||||
- `node.pair.approve` — 批准一个待处理请求(签发 token)。
|
||||
- `node.pair.reject` — 拒绝一个待处理请求。
|
||||
- `node.pair.approve` — 批准待处理请求(签发令牌)。
|
||||
- `node.pair.reject` — 拒绝待处理请求。
|
||||
- `node.pair.verify` — 验证 `{ nodeId, token }`。
|
||||
|
||||
说明:
|
||||
|
||||
- `node.pair.request` 对每个节点是幂等的:重复调用会返回相同的
|
||||
待处理请求。
|
||||
- 对同一待处理节点的重复请求还会刷新已存储的节点
|
||||
元数据,以及最新的 allowlist 声明命令快照,以便操作员查看。
|
||||
- 批准时**总是**生成一个全新的 token;绝不会从
|
||||
`node.pair.request` 返回 token。
|
||||
- 请求可包含 `silent: true`,作为自动批准流程的提示。
|
||||
- `node.pair.approve` 会使用待处理请求中声明的命令来强制执行
|
||||
额外的批准范围:
|
||||
- 对同一个待处理节点的重复请求还会刷新已存储的节点
|
||||
元数据,以及最新的已加入允许名单的声明命令快照,便于运维人员查看。
|
||||
- 批准**始终**会生成一个新的令牌;`node.pair.request`
|
||||
永远不会返回令牌。
|
||||
- 请求可以包含 `silent: true`,作为自动批准流程的提示。
|
||||
- `node.pair.approve` 使用待处理请求的声明命令来强制执行
|
||||
额外的批准作用域:
|
||||
- 无命令请求:`operator.pairing`
|
||||
- 非 exec 命令请求:`operator.pairing` + `operator.write`
|
||||
- `system.run` / `system.run.prepare` / `system.which` 请求:
|
||||
`operator.pairing` + `operator.admin`
|
||||
|
||||
重要:
|
||||
重要说明:
|
||||
|
||||
- 节点配对是一个信任 / 身份流程,加上 token 签发。
|
||||
- 它**不会**按节点固定实时节点命令界面。
|
||||
- 实时节点命令来自节点在连接后声明的内容,并在应用
|
||||
Gateway 网关的全局节点命令策略(`gateway.nodes.allowCommands` /
|
||||
`denyCommands`)后生效。
|
||||
- 每节点的 `system.run` allow/ask 策略位于节点上的
|
||||
`exec.approvals.node.*` 中,而不在配对记录里。
|
||||
- 节点配对是信任/身份流程加令牌签发。
|
||||
- 它**不会**按节点固定在线节点命令 surface。
|
||||
- 在线节点命令来自节点在连接后声明的内容,随后再应用
|
||||
网关的全局节点命令策略(`gateway.nodes.allowCommands` /
|
||||
`denyCommands`)。
|
||||
- 每个节点的 `system.run` allow/ask 策略位于节点端的
|
||||
`exec.approvals.node.*` 中,而不在配对记录中。
|
||||
|
||||
## 节点命令门控(2026.3.31+)
|
||||
|
||||
<Warning>
|
||||
**破坏性变更:** 从 `2026.3.31` 开始,在节点配对获得批准之前,节点命令将被禁用。仅靠设备配对已不足以暴露已声明的节点命令。
|
||||
**Breaking change:** 从 `2026.3.31` 开始,在节点配对获批前,节点命令将被禁用。仅靠设备配对已不足以暴露已声明的节点命令。
|
||||
</Warning>
|
||||
|
||||
当一个节点首次连接时,会自动请求配对。在该配对请求被批准之前,来自该节点的所有待处理节点命令都会被过滤,不会执行。一旦通过配对批准建立了信任关系,该节点声明的命令就会在正常命令策略约束下变为可用。
|
||||
当节点首次连接时,会自动请求配对。在配对请求获批之前,该节点的所有待处理节点命令都会被过滤,且不会执行。一旦通过配对批准建立信任,节点声明的命令就会在正常命令策略约束下变为可用。
|
||||
|
||||
这意味着:
|
||||
|
||||
@ -108,47 +108,74 @@ openclaw nodes rename --node <id|name|ip> --name "Living Room iPad"
|
||||
## 节点事件信任边界(2026.3.31+)
|
||||
|
||||
<Warning>
|
||||
**破坏性变更:** 由节点发起的运行现在会保留在一个收缩后的受信任界面内。
|
||||
**Breaking change:** 节点发起的运行现在会保留在缩减后的受信任 surface 内。
|
||||
</Warning>
|
||||
|
||||
由节点发起的摘要及相关会话事件会被限制在预期的受信任界面内。此前依赖更广泛宿主机或会话工具访问权限的通知驱动或节点触发流程,可能需要调整。此项加固确保节点事件无法升级为超出节点信任边界所允许范围的宿主机级工具访问。
|
||||
节点发起的摘要和相关会话事件会被限制在预期的受信任 surface 内。此前依赖更广泛主机或会话工具访问的通知驱动或节点触发流程,可能需要调整。此加固措施确保节点事件无法升级为超出节点信任边界所允许范围的主机级工具访问。
|
||||
|
||||
## 自动批准(macOS 应用)
|
||||
|
||||
macOS 应用可选择尝试执行一次**静默批准**,前提是:
|
||||
macOS 应用在以下情况下可以选择尝试**静默批准**:
|
||||
|
||||
- 请求被标记为 `silent`,并且
|
||||
- 应用能够使用同一用户验证与 Gateway 网关宿主机的 SSH 连接。
|
||||
- 应用能够使用相同用户验证到网关主机的 SSH 连接。
|
||||
|
||||
如果静默批准失败,则会回退到正常的“批准 / 拒绝”提示。
|
||||
如果静默批准失败,则会回退到常规的“批准/拒绝”提示。
|
||||
|
||||
## Trusted-CIDR 设备自动批准
|
||||
|
||||
默认情况下,`role: node` 的 WS 设备配对仍需手动处理。对于
|
||||
Gateway 网关已经信任网络路径的私有节点网络,运维人员可以
|
||||
通过显式 CIDR 或精确 IP 选择启用:
|
||||
|
||||
```json5
|
||||
{
|
||||
gateway: {
|
||||
nodes: {
|
||||
pairing: {
|
||||
autoApproveCidrs: ["192.168.1.0/24"],
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
安全边界:
|
||||
|
||||
- 当未设置 `gateway.nodes.pairing.autoApproveCidrs` 时禁用。
|
||||
- 不存在通用的 LAN 或私有网络自动批准模式。
|
||||
- 只有没有请求作用域的全新 `role: node` 设备配对才符合条件。
|
||||
- 运维人员、浏览器、Control UI 和 WebChat 客户端仍然需要手动批准。
|
||||
- 角色、作用域、元数据和公钥升级仍然需要手动处理。
|
||||
- 同主机 local loopback trusted-proxy 标头路径不符合条件,因为
|
||||
本地调用方可以伪造该路径。
|
||||
|
||||
## 元数据升级自动批准
|
||||
|
||||
当一个已经配对的设备重新连接,并且只有非敏感元数据发生变化
|
||||
(例如显示名称或客户端平台提示)时,OpenClaw 会将其视为
|
||||
`metadata-upgrade`。静默自动批准的范围很窄:它仅适用于
|
||||
那些已经通过 loopback 上共享 token 或密码证明持有权的
|
||||
受信任本地 CLI / 辅助工具重新连接。浏览器 / Control UI 客户端以及远程
|
||||
客户端仍然使用显式重新批准流程。范围升级(从 read 到
|
||||
write/admin)和公钥变更**不**符合元数据升级自动批准条件——它们仍然需要显式重新批准请求。
|
||||
当某个已配对设备重新连接,并且仅包含非敏感元数据
|
||||
变更(例如显示名称或客户端平台提示)时,OpenClaw 会将其视为
|
||||
`metadata-upgrade`。静默自动批准范围很窄:它仅适用于已经通过
|
||||
loopback 上的共享令牌或密码持有证明的受信任本地 CLI/辅助程序重连。
|
||||
浏览器/Control UI 客户端和远程客户端仍使用显式重新批准流程。
|
||||
作用域升级(从 read 到 write/admin)以及公钥变更**不**符合
|
||||
元数据升级自动批准条件——它们仍保持为显式重新批准请求。
|
||||
|
||||
## QR 配对辅助
|
||||
## QR 配对辅助工具
|
||||
|
||||
`/pair qr` 会将配对负载渲染为结构化媒体,以便移动端和
|
||||
浏览器客户端可以直接扫描。
|
||||
`/pair qr` 会将配对负载渲染为结构化媒体,方便移动端和
|
||||
浏览器客户端直接扫描。
|
||||
|
||||
删除设备时,还会一并清理该设备 id 的所有陈旧待处理配对请求,因此在撤销后,`nodes pending` 不会显示孤立条目。
|
||||
删除某个设备时,也会清理该设备 id 的所有陈旧待处理配对请求,因此
|
||||
`nodes pending` 不会在撤销后显示孤立条目。
|
||||
|
||||
## 本地性与转发头
|
||||
## 本地性和转发标头
|
||||
|
||||
只有当原始套接字
|
||||
和任何上游代理证据都一致时,Gateway 网关配对才会将一个连接视为 loopback。
|
||||
如果某个请求到达 loopback,但携带了指向非本地来源的
|
||||
`X-Forwarded-For` / `X-Forwarded-Host` / `X-Forwarded-Proto` 头,
|
||||
那么这些转发头证据会使 loopback 本地性声明失效。
|
||||
此时,配对路径需要显式批准,而不会静默地将该请求视为同主机连接。关于
|
||||
operator auth 上的等效规则,参见
|
||||
[受信任代理认证](/zh-CN/gateway/trusted-proxy-auth)。
|
||||
只有当原始 socket 和任何上游代理证据都一致时,Gateway 网关配对
|
||||
才会将某个连接视为 loopback。如果请求通过 loopback 到达,
|
||||
但携带了指向非本地来源的 `X-Forwarded-For` / `X-Forwarded-Host` / `X-Forwarded-Proto`
|
||||
标头,那么这些转发标头证据会使 loopback 本地性声明失效。
|
||||
此时配对路径将要求显式批准,而不会静默地将该请求视为同主机连接。参见
|
||||
[Trusted Proxy Auth](/zh-CN/gateway/trusted-proxy-auth) 了解运维人员认证中的对应规则。
|
||||
|
||||
## 存储(本地、私有)
|
||||
|
||||
@ -161,14 +188,14 @@ operator auth 上的等效规则,参见
|
||||
|
||||
安全说明:
|
||||
|
||||
- Token 属于密钥;请将 `paired.json` 视为敏感文件。
|
||||
- 轮换 token 需要重新批准(或删除节点条目)。
|
||||
- 令牌属于机密;请将 `paired.json` 视为敏感文件。
|
||||
- 轮换令牌需要重新批准(或删除该节点条目)。
|
||||
|
||||
## 传输层行为
|
||||
## 传输行为
|
||||
|
||||
- 传输层是**无状态**的;它不存储成员资格。
|
||||
- 传输是**无状态**的;它不会存储成员资格。
|
||||
- 如果 Gateway 网关离线或配对被禁用,节点将无法配对。
|
||||
- 如果 Gateway 网关处于远程模式,配对仍然会针对远程 Gateway 网关的存储进行。
|
||||
- 如果 Gateway 网关处于远程模式,配对仍会针对远程 Gateway 网关的存储进行。
|
||||
|
||||
## 相关内容
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -1,22 +1,22 @@
|
||||
---
|
||||
read_when:
|
||||
- 故障排除中心将你引导到这里,以进行更深入的诊断
|
||||
- 你需要基于稳定症状的操作手册章节,并包含精确命令
|
||||
summary: Gateway 网关、渠道、自动化、节点和浏览器的深度故障排除操作手册
|
||||
- 故障排除中心将你引导到这里,以进行更深入的诊断。
|
||||
- 你需要按症状组织、结构稳定,并包含精确命令的运行手册章节。
|
||||
summary: Gateway 网关、渠道、自动化、节点和浏览器的深度故障排除手册
|
||||
title: 故障排除
|
||||
x-i18n:
|
||||
generated_at: "2026-04-25T03:24:34Z"
|
||||
generated_at: "2026-04-25T05:54:46Z"
|
||||
model: gpt-5.4
|
||||
provider: openai
|
||||
source_hash: 14565a260226cbd3c78e1449621da5ff0bb8f580d3f10345a7d8650db9f706a8
|
||||
source_hash: c2270f05cf34592269894278e1eb75b8d47c02a4ff1c74bf62afb3d8f4fc4640
|
||||
source_path: gateway/troubleshooting.md
|
||||
workflow: 15
|
||||
---
|
||||
|
||||
# Gateway 网关故障排除
|
||||
|
||||
此页面是深度操作手册。
|
||||
如果你想先使用快速分诊流程,请从 [/help/troubleshooting](/zh-CN/help/troubleshooting) 开始。
|
||||
本页是深度运行手册。
|
||||
如果你想先走快速分诊流程,请从 [/help/troubleshooting](/zh-CN/help/troubleshooting) 开始。
|
||||
|
||||
## 命令阶梯
|
||||
|
||||
@ -33,10 +33,10 @@ openclaw channels status --probe
|
||||
预期的健康信号:
|
||||
|
||||
- `openclaw gateway status` 显示 `Runtime: running`、`Connectivity probe: ok` 和一行 `Capability: ...`。
|
||||
- `openclaw doctor` 报告没有阻塞性的配置或服务问题。
|
||||
- `openclaw channels status --probe` 显示每个账号的实时传输状态,并且在支持的情况下,显示诸如 `works` 或 `audit ok` 之类的探测/审计结果。
|
||||
- `openclaw doctor` 报告没有阻塞性的配置/服务问题。
|
||||
- `openclaw channels status --probe` 显示每个账号的实时传输状态,并在支持的情况下显示探测/审计结果,例如 `works` 或 `audit ok`。
|
||||
|
||||
## Anthropic 429:长上下文需要额外用量资格
|
||||
## Anthropic 429:长上下文需要额外配额
|
||||
|
||||
当日志/错误中包含以下内容时,使用本节:
|
||||
`HTTP 429: rate_limit_error: Extra usage is required for long context requests`。
|
||||
@ -47,30 +47,30 @@ openclaw models status
|
||||
openclaw config get agents.defaults.models
|
||||
```
|
||||
|
||||
检查以下内容:
|
||||
请检查:
|
||||
|
||||
- 所选的 Anthropic Opus/Sonnet 模型设置了 `params.context1m: true`。
|
||||
- 当前的 Anthropic 凭证不具备长上下文用量资格。
|
||||
- 只有在需要走 1M beta 路径的长会话/模型运行中,请求才会失败。
|
||||
- 所选的 Anthropic Opus/Sonnet 模型是否设置了 `params.context1m: true`。
|
||||
- 当前的 Anthropic 凭证是否没有资格使用长上下文。
|
||||
- 请求是否仅在需要走 1M beta 路径的长会话/模型运行中失败。
|
||||
|
||||
修复选项:
|
||||
|
||||
1. 为该模型禁用 `context1m`,回退到普通上下文窗口。
|
||||
2. 使用具备长上下文请求资格的 Anthropic 凭证,或切换到 Anthropic API key。
|
||||
3. 配置回退模型,以便在 Anthropic 长上下文请求被拒绝时,运行仍可继续。
|
||||
2. 使用有资格发起长上下文请求的 Anthropic 凭证,或切换到 Anthropic API key。
|
||||
3. 配置回退模型,这样在 Anthropic 长上下文请求被拒绝时,运行仍可继续。
|
||||
|
||||
相关内容:
|
||||
|
||||
- [/providers/anthropic](/zh-CN/providers/anthropic)
|
||||
- [/reference/token-use](/zh-CN/reference/token-use)
|
||||
- [/help/faq-first-run#why-am-i-seeing-http-429-ratelimiterror-from-anthropic](/zh-CN/help/faq-first-run#why-am-i-seeing-http-429-ratelimiterror-from-anthropic)
|
||||
- [Anthropic](/zh-CN/providers/anthropic)
|
||||
- [Token 使用和成本](/zh-CN/reference/token-use)
|
||||
- [为什么我会看到来自 Anthropic 的 HTTP 429?](/zh-CN/help/faq-first-run#why-am-i-seeing-http-429-ratelimiterror-from-anthropic)
|
||||
|
||||
## 本地 OpenAI 兼容后端可通过直接探测,但智能体运行失败
|
||||
## 本地 OpenAI-compatible 后端直接探测通过,但智能体运行失败
|
||||
|
||||
在以下情况中使用本节:
|
||||
当出现以下情况时,使用本节:
|
||||
|
||||
- `curl ... /v1/models` 可用
|
||||
- 很小的直接 `/v1/chat/completions` 调用可用
|
||||
- `curl ... /v1/models` 正常
|
||||
- 很小的直接 `/v1/chat/completions` 调用正常
|
||||
- OpenClaw 模型运行仅在正常智能体轮次中失败
|
||||
|
||||
```bash
|
||||
@ -82,34 +82,34 @@ openclaw infer model run --model <provider/model> --prompt "hi" --json
|
||||
openclaw logs --follow
|
||||
```
|
||||
|
||||
检查以下内容:
|
||||
请检查:
|
||||
|
||||
- 直接的小请求成功,但 OpenClaw 运行仅在较大提示词下失败
|
||||
- 后端报错,提示 `messages[].content` 预期是字符串
|
||||
- 后端仅在较大 prompt token 数量或完整智能体运行时提示词下崩溃
|
||||
- 直接的小请求成功,但 OpenClaw 运行只在更大的提示词下失败
|
||||
- 后端报错 `messages[].content` 期望是字符串
|
||||
- 后端崩溃只出现在更大的提示 token 数或完整智能体运行时提示词下
|
||||
|
||||
常见特征:
|
||||
|
||||
- `messages[...].content: invalid type: sequence, expected a string` → 后端拒绝结构化的 Chat Completions 内容分段。修复方式:设置 `models.providers.<provider>.models[].compat.requiresStringContent: true`。
|
||||
- 直接的小请求成功,但 OpenClaw 智能体运行因后端/模型崩溃而失败(例如某些 `inferrs` 构建中的 Gemma)→ OpenClaw 传输层很可能已经正确;是后端在更大的 Agent Runtimes 提示词形态下失败。
|
||||
- 禁用工具后失败有所减少,但未消失 → 工具 schema 是压力来源之一,但剩余问题仍然是上游模型/服务器容量不足或后端 bug。
|
||||
- `messages[...].content: invalid type: sequence, expected a string` → 后端拒绝结构化的 Chat Completions 内容片段。修复方式:设置 `models.providers.<provider>.models[].compat.requiresStringContent: true`。
|
||||
- 很小的直接请求成功,但 OpenClaw 智能体运行因后端/模型崩溃而失败(例如某些 `inferrs` 构建上的 Gemma)→ OpenClaw 传输层很可能已经正确;失败的是后端在处理更大的智能体运行时提示词形态时崩溃。
|
||||
- 禁用工具后失败减少但未消失 → 工具 schema 确实增加了压力,但剩余问题仍然是上游模型/服务器容量限制或后端 bug。
|
||||
|
||||
修复选项:
|
||||
|
||||
1. 为仅接受字符串 Chat Completions 内容的后端设置 `compat.requiresStringContent: true`。
|
||||
2. 为无法可靠处理 OpenClaw 工具 schema 接口的模型/后端设置 `compat.supportsTools: false`。
|
||||
3. 尽可能降低提示词压力:更小的工作区引导、更短的会话历史、更轻量的本地模型,或使用对长上下文支持更强的后端。
|
||||
4. 如果直接的小请求持续通过,但 OpenClaw 智能体轮次仍在后端内部崩溃,请将其视为上游服务器/模型限制,并向上游提交复现,附上它能够接受的载荷形态。
|
||||
1. 为仅支持字符串的 Chat Completions 后端设置 `compat.requiresStringContent: true`。
|
||||
2. 为无法可靠处理 OpenClaw 工具 schema 表面的模型/后端设置 `compat.supportsTools: false`。
|
||||
3. 在可能的情况下减轻提示词压力:更小的工作区引导、更短的会话历史、更轻量的本地模型,或改用长上下文支持更强的后端。
|
||||
4. 如果很小的直接请求持续通过,而 OpenClaw 智能体轮次仍在后端内部崩溃,请将其视为上游服务器/模型限制,并在上游提交一个包含已接受负载形态的复现。
|
||||
|
||||
相关内容:
|
||||
|
||||
- [/gateway/local-models](/zh-CN/gateway/local-models)
|
||||
- [/gateway/configuration](/zh-CN/gateway/configuration)
|
||||
- [/gateway/configuration-reference#openai-compatible-endpoints](/zh-CN/gateway/configuration-reference#openai-compatible-endpoints)
|
||||
- [本地模型](/zh-CN/gateway/local-models)
|
||||
- [配置](/zh-CN/gateway/configuration)
|
||||
- [OpenAI-compatible 端点](/zh-CN/gateway/configuration-reference#openai-compatible-endpoints)
|
||||
|
||||
## 没有回复
|
||||
|
||||
如果渠道已上线但没有任何响应,在重新连接任何内容之前,请先检查路由和策略。
|
||||
如果渠道在线但没有任何响应,在重新连接任何东西之前,先检查路由和策略。
|
||||
|
||||
```bash
|
||||
openclaw status
|
||||
@ -119,27 +119,27 @@ openclaw config get channels
|
||||
openclaw logs --follow
|
||||
```
|
||||
|
||||
检查以下内容:
|
||||
请检查:
|
||||
|
||||
- 私信发送者的配对仍在等待中。
|
||||
- 私信发送者是否处于待配对状态。
|
||||
- 群组提及门控(`requireMention`、`mentionPatterns`)。
|
||||
- 渠道/群组 allowlist 不匹配。
|
||||
- 渠道/群组 allowlist 是否不匹配。
|
||||
|
||||
常见特征:
|
||||
|
||||
- `drop guild message (mention required` → 群消息在被提及之前会被忽略。
|
||||
- `drop guild message (mention required` → 群组消息在被提及之前会被忽略。
|
||||
- `pairing request` → 发送者需要批准。
|
||||
- `blocked` / `allowlist` → 发送者/渠道被策略过滤。
|
||||
|
||||
相关内容:
|
||||
|
||||
- [/channels/troubleshooting](/zh-CN/channels/troubleshooting)
|
||||
- [/channels/pairing](/zh-CN/channels/pairing)
|
||||
- [/channels/groups](/zh-CN/channels/groups)
|
||||
- [渠道故障排除](/zh-CN/channels/troubleshooting)
|
||||
- [配对](/zh-CN/channels/pairing)
|
||||
- [群组](/zh-CN/channels/groups)
|
||||
|
||||
## Dashboard 控制 UI 连接问题
|
||||
## Dashboard / Control UI 连接问题
|
||||
|
||||
当 dashboard/控制 UI 无法连接时,请验证 URL、认证模式和安全上下文相关假设。
|
||||
当 dashboard/Control UI 无法连接时,检查 URL、认证模式和安全上下文假设。
|
||||
|
||||
```bash
|
||||
openclaw gateway status
|
||||
@ -149,36 +149,36 @@ openclaw doctor
|
||||
openclaw gateway status --json
|
||||
```
|
||||
|
||||
检查以下内容:
|
||||
请检查:
|
||||
|
||||
- 正确的探测 URL 和 dashboard URL。
|
||||
- 客户端与 Gateway 网关之间的认证模式/token 不匹配。
|
||||
- 在需要设备身份的情况下使用了 HTTP。
|
||||
- 探测 URL 和 dashboard URL 是否正确。
|
||||
- 客户端与 Gateway 网关之间的认证模式/token 是否不匹配。
|
||||
- 在需要设备身份的场景下是否使用了 HTTP。
|
||||
|
||||
常见特征:
|
||||
|
||||
- `device identity required` → 非安全上下文,或缺少设备认证。
|
||||
- `origin not allowed` → 浏览器的 `Origin` 不在 `gateway.controlUi.allowedOrigins` 中(或者你正从非 loopback 的浏览器 origin 连接,但没有显式 allowlist)。
|
||||
- `device nonce required` / `device nonce mismatch` → 客户端未完成基于挑战的设备认证流程(`connect.challenge` + `device.nonce`)。
|
||||
- `device signature invalid` / `device signature expired` → 客户端为当前握手签署了错误的载荷(或使用了过期时间戳)。
|
||||
- 带有 `canRetryWithDeviceToken=true` 的 `AUTH_TOKEN_MISMATCH` → 客户端可以使用缓存的设备 token 执行一次可信重试。
|
||||
- 该缓存 token 重试会复用与已配对设备 token 一起存储的缓存 scope 集合。显式 `deviceToken` / 显式 `scopes` 调用方则保留它们请求的 scope 集合。
|
||||
- 在该重试路径之外,连接认证优先级为:显式共享 token/password 优先,然后是显式 `deviceToken`,再然后是存储的设备 token,最后是 bootstrap token。
|
||||
- 在异步 Tailscale Serve Control UI 路径上,同一 `{scope, ip}` 的失败尝试会在限流器记录失败之前被串行化。因此,同一客户端的两个并发错误重试中,第二次可能会显示 `retry later`,而不是两个普通的不匹配错误。
|
||||
- 来自浏览器 origin 的 loopback 客户端如果出现 `too many failed authentication attempts (retry later)` → 来自同一归一化 `Origin` 的重复失败会被暂时锁定;另一个 localhost origin 会使用单独的桶。
|
||||
- 在那次重试之后反复出现 `unauthorized` → 共享 token/设备 token 已漂移;如有需要,请刷新 token 配置并重新批准/轮换设备 token。
|
||||
- `gateway connect failed:` → 主机/端口/URL 目标错误。
|
||||
- `origin not allowed` → 浏览器 `Origin` 不在 `gateway.controlUi.allowedOrigins` 中(或者你正在从非 loopback 浏览器来源连接,但没有显式 allowlist)。
|
||||
- `device nonce required` / `device nonce mismatch` → 客户端没有完成基于挑战的设备认证流程(`connect.challenge` + `device.nonce`)。
|
||||
- `device signature invalid` / `device signature expired` → 客户端为当前握手签署了错误的负载(或使用了过期时间戳)。
|
||||
- `AUTH_TOKEN_MISMATCH` 且 `canRetryWithDeviceToken=true` → 客户端可以使用缓存的设备 token 执行一次受信任的重试。
|
||||
- 该缓存 token 重试会复用与配对设备 token 一起存储的缓存 scope 集合。显式 `deviceToken` / 显式 `scopes` 调用方则保留它们请求的 scope 集合。
|
||||
- 在该重试路径之外,连接认证优先级依次为:显式共享 token/password、显式 `deviceToken`、已存储的设备 token、bootstrap token。
|
||||
- 在异步 Tailscale Serve Control UI 路径上,相同 `{scope, ip}` 的失败尝试会在限流器记录失败之前串行化。因此,同一客户端两个错误的并发重试,第二次可能会显示 `retry later`,而不是两个普通的不匹配错误。
|
||||
- 来自浏览器来源 loopback 客户端的 `too many failed authentication attempts (retry later)` → 来自同一标准化 `Origin` 的重复失败会被临时锁定;另一个 localhost 来源会使用单独的 bucket。
|
||||
- 在该重试之后反复出现 `unauthorized` → 共享 token/设备 token 漂移;如有需要,请刷新 token 配置并重新批准/轮换设备 token。
|
||||
- `gateway connect failed:` → host/port/url 目标错误。
|
||||
|
||||
### 认证细节代码速查表
|
||||
### 认证详细代码速查表
|
||||
|
||||
使用失败的 `connect` 响应中的 `error.details.code` 来选择下一步操作:
|
||||
使用失败的 `connect` 响应中的 `error.details.code` 来决定下一步操作:
|
||||
|
||||
| 细节代码 | 含义 | 建议操作 |
|
||||
| 详细代码 | 含义 | 建议操作 |
|
||||
| ---------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `AUTH_TOKEN_MISSING` | 客户端未发送所需的共享 token。 | 在客户端中粘贴/设置 token 并重试。对于 dashboard 路径:`openclaw config get gateway.auth.token`,然后将其粘贴到 Control UI 设置中。 |
|
||||
| `AUTH_TOKEN_MISMATCH` | 共享 token 与 Gateway 网关认证 token 不匹配。 | 如果 `canRetryWithDeviceToken=true`,允许一次可信重试。缓存 token 重试会复用已存储、已批准的 scope;显式 `deviceToken` / `scopes` 调用方保留其请求的 scope。如果仍然失败,请运行 [token 漂移恢复检查清单](/zh-CN/cli/devices#token-drift-recovery-checklist)。 |
|
||||
| `AUTH_DEVICE_TOKEN_MISMATCH` | 缓存的每设备 token 已过期或被撤销。 | 使用 [devices CLI](/zh-CN/cli/devices) 轮换/重新批准设备 token,然后重新连接。 |
|
||||
| `PAIRING_REQUIRED` | 设备身份需要批准。检查 `error.details.reason`,可能的值包括 `not-paired`、`scope-upgrade`、`role-upgrade` 或 `metadata-upgrade`,并在存在时使用 `requestId` / `remediationHint`。 | 批准待处理请求:`openclaw devices list`,然后 `openclaw devices approve <requestId>`。Scope/角色升级在你审查所请求的访问权限后,也使用同一流程。 |
|
||||
| `AUTH_TOKEN_MISSING` | 客户端没有发送必需的共享 token。 | 在客户端中粘贴/设置 token,然后重试。对于 dashboard 路径:`openclaw config get gateway.auth.token`,然后将其粘贴到 Control UI 设置中。 |
|
||||
| `AUTH_TOKEN_MISMATCH` | 共享 token 与 Gateway 网关认证 token 不匹配。 | 如果 `canRetryWithDeviceToken=true`,允许执行一次受信任的重试。缓存 token 重试会复用已存储且已批准的 scopes;显式 `deviceToken` / `scopes` 调用方保留请求的 scopes。如果仍然失败,请运行 [token 漂移恢复清单](/zh-CN/cli/devices#token-drift-recovery-checklist)。 |
|
||||
| `AUTH_DEVICE_TOKEN_MISMATCH` | 按设备缓存的 token 已过期或被撤销。 | 使用 [devices CLI](/zh-CN/cli/devices) 轮换/重新批准设备 token,然后重新连接。 |
|
||||
| `PAIRING_REQUIRED` | 设备身份需要批准。检查 `error.details.reason` 是否为 `not-paired`、`scope-upgrade`、`role-upgrade` 或 `metadata-upgrade`,并在存在时使用 `requestId` / `remediationHint`。 | 批准待处理请求:`openclaw devices list`,然后 `openclaw devices approve <requestId>`。在你审核请求的访问权限后,scope/role 升级也使用相同流程。 |
|
||||
|
||||
设备认证 v2 迁移检查:
|
||||
|
||||
@ -188,61 +188,61 @@ openclaw doctor
|
||||
openclaw gateway status
|
||||
```
|
||||
|
||||
如果日志显示 nonce/signature 错误,请更新发起连接的客户端并验证它:
|
||||
如果日志显示 nonce/signature 错误,请更新正在连接的客户端,并验证它:
|
||||
|
||||
1. 等待 `connect.challenge`
|
||||
2. 对绑定该 challenge 的载荷进行签名
|
||||
3. 使用同一个 challenge nonce 发送 `connect.params.device.nonce`
|
||||
2. 对绑定 challenge 的负载进行签名
|
||||
3. 发送 `connect.params.device.nonce`,并使用相同的 challenge nonce
|
||||
|
||||
如果 `openclaw devices rotate` / `revoke` / `remove` 被意外拒绝:
|
||||
|
||||
- 已配对设备 token 会话只能管理**它们自己的**设备,除非调用方还具有 `operator.admin`
|
||||
- `openclaw devices rotate --scope ...` 只能请求调用方当前会话已持有的 operator scope
|
||||
- 配对设备 token 会话只能管理**它们自己的**设备,除非调用方还具有 `operator.admin`
|
||||
- `openclaw devices rotate --scope ...` 只能请求调用方会话当前已经持有的 operator scopes
|
||||
|
||||
相关内容:
|
||||
|
||||
- [/web/control-ui](/zh-CN/web/control-ui)
|
||||
- [/gateway/configuration](/zh-CN/gateway/configuration)(Gateway 网关认证模式)
|
||||
- [/gateway/trusted-proxy-auth](/zh-CN/gateway/trusted-proxy-auth)
|
||||
- [/gateway/remote](/zh-CN/gateway/remote)
|
||||
- [/cli/devices](/zh-CN/cli/devices)
|
||||
- [Control UI](/zh-CN/web/control-ui)
|
||||
- [配置](/zh-CN/gateway/configuration)(Gateway 网关认证模式)
|
||||
- [受信任代理认证](/zh-CN/gateway/trusted-proxy-auth)
|
||||
- [远程访问](/zh-CN/gateway/remote)
|
||||
- [设备](/zh-CN/cli/devices)
|
||||
|
||||
## Gateway 网关服务未运行
|
||||
|
||||
当服务已安装但进程无法保持运行时,使用本节。
|
||||
当服务已安装但进程无法持续运行时,使用本节。
|
||||
|
||||
```bash
|
||||
openclaw gateway status
|
||||
openclaw status
|
||||
openclaw logs --follow
|
||||
openclaw doctor
|
||||
openclaw gateway status --deep # 也扫描系统级服务
|
||||
openclaw gateway status --deep # 也会扫描系统级服务
|
||||
```
|
||||
|
||||
检查以下内容:
|
||||
请检查:
|
||||
|
||||
- `Runtime: stopped`,并带有退出提示。
|
||||
- `Runtime: stopped` 以及退出提示。
|
||||
- 服务配置不匹配(`Config (cli)` 与 `Config (service)`)。
|
||||
- 端口/监听器冲突。
|
||||
- 使用 `--deep` 时发现额外的 launchd/systemd/schtasks 安装。
|
||||
- 端口/监听冲突。
|
||||
- 使用 `--deep` 时是否存在额外的 launchd/systemd/schtasks 安装。
|
||||
- `Other gateway-like services detected (best effort)` 清理提示。
|
||||
|
||||
常见特征:
|
||||
|
||||
- `Gateway start blocked: set gateway.mode=local` 或 `existing config is missing gateway.mode` → 未启用本地 Gateway 网关模式,或者配置文件被破坏并丢失了 `gateway.mode`。修复方式:在你的配置中设置 `gateway.mode="local"`,或重新运行 `openclaw onboard --mode local` / `openclaw setup` 以重新写入预期的本地模式配置。如果你通过 Podman 运行 OpenClaw,默认配置路径是 `~/.openclaw/openclaw.json`。
|
||||
- `refusing to bind gateway ... without auth` → 在没有有效 Gateway 网关认证路径的情况下尝试绑定非 loopback 地址(token/password,或在已配置时使用 trusted-proxy)。
|
||||
- `Gateway start blocked: set gateway.mode=local` 或 `existing config is missing gateway.mode` → 未启用本地 Gateway 网关模式,或者配置文件被覆盖并丢失了 `gateway.mode`。修复:在你的配置中设置 `gateway.mode="local"`,或者重新运行 `openclaw onboard --mode local` / `openclaw setup`,重新写入预期的本地模式配置。如果你通过 Podman 运行 OpenClaw,默认配置路径是 `~/.openclaw/openclaw.json`。
|
||||
- `refusing to bind gateway ... without auth` → 非 loopback 绑定时,没有有效的 gateway 认证路径(token/password,或在已配置情况下的 trusted-proxy)。
|
||||
- `another gateway instance is already listening` / `EADDRINUSE` → 端口冲突。
|
||||
- `Other gateway-like services detected (best effort)` → 存在过期或并行的 launchd/systemd/schtasks 单元。大多数配置应当每台机器只保留一个 Gateway 网关;如果你确实需要多个,请隔离端口 + 配置/状态/工作区。参见 [/gateway#multiple-gateways-same-host](/zh-CN/gateway#multiple-gateways-same-host)。
|
||||
- `Other gateway-like services detected (best effort)` → 存在陈旧或并行的 launchd/systemd/schtasks 单元。大多数部署应当每台机器只保留一个 Gateway 网关;如果你确实需要多个,请隔离端口 + 配置/状态/工作区。参见 [/gateway#multiple-gateways-same-host](/zh-CN/gateway#multiple-gateways-same-host)。
|
||||
|
||||
相关内容:
|
||||
|
||||
- [/gateway/background-process](/zh-CN/gateway/background-process)
|
||||
- [/gateway/configuration](/zh-CN/gateway/configuration)
|
||||
- [/gateway/doctor](/zh-CN/gateway/doctor)
|
||||
- [后台执行和进程工具](/zh-CN/gateway/background-process)
|
||||
- [配置](/zh-CN/gateway/configuration)
|
||||
- [Doctor](/zh-CN/gateway/doctor)
|
||||
|
||||
## Gateway 网关已恢复最近一次已知正常配置
|
||||
## Gateway 网关已恢复最后一次已知正确配置
|
||||
|
||||
当 Gateway 网关可以启动,但日志显示它恢复了 `openclaw.json` 时,使用本节。
|
||||
当 Gateway 网关能够启动,但日志显示它恢复了 `openclaw.json` 时,使用本节。
|
||||
|
||||
```bash
|
||||
openclaw logs --follow
|
||||
@ -251,21 +251,21 @@ openclaw config validate
|
||||
openclaw doctor
|
||||
```
|
||||
|
||||
检查以下内容:
|
||||
请检查:
|
||||
|
||||
- `Config auto-restored from last-known-good`
|
||||
- `gateway: invalid config was restored from last-known-good backup`
|
||||
- `config reload restored last-known-good config after invalid-config`
|
||||
- 在活动配置旁边是否存在带时间戳的 `openclaw.json.clobbered.*` 文件
|
||||
- 是否有一个主智能体系统事件以 `Config recovery warning` 开头
|
||||
- 活动配置旁边是否存在带时间戳的 `openclaw.json.clobbered.*` 文件
|
||||
- 是否存在一条以 `Config recovery warning` 开头的主智能体系统事件
|
||||
|
||||
发生了什么:
|
||||
|
||||
- 被拒绝的配置在启动或热重载期间未通过校验。
|
||||
- OpenClaw 将被拒绝的载荷保留为 `.clobbered.*`。
|
||||
- 活动配置已从最近一次通过校验的 last-known-good 副本中恢复。
|
||||
- 被拒绝的配置在启动或热重载期间未通过验证。
|
||||
- OpenClaw 将被拒绝的负载保留为 `.clobbered.*`。
|
||||
- 活动配置已从最后一次验证通过的最后一次已知正确副本恢复。
|
||||
- 下一次主智能体轮次会收到警告,不要盲目重写被拒绝的配置。
|
||||
- 如果所有校验问题都位于 `plugins.entries.<id>...` 下,OpenClaw 将不会恢复整个文件。插件本地失败会继续显式报错,而无关的用户设置会保留在活动配置中。
|
||||
- 如果所有验证问题都位于 `plugins.entries.<id>...` 之下,OpenClaw 不会恢复整个文件。插件本地失败会继续显式暴露,而不相关的用户设置会保留在活动配置中。
|
||||
|
||||
检查并修复:
|
||||
|
||||
@ -279,29 +279,29 @@ openclaw doctor
|
||||
|
||||
常见特征:
|
||||
|
||||
- 存在 `.clobbered.*` → 外部直接编辑或启动读取时的内容已被恢复。
|
||||
- 存在 `.rejected.*` → OpenClaw 自身发起的配置写入在提交前未通过 schema 或 clobber 检查。
|
||||
- `Config write rejected:` → 该写入尝试删除必需结构、显著缩小文件,或持久化无效配置。
|
||||
- `missing-meta-vs-last-good`、`gateway-mode-missing-vs-last-good` 或 `size-drop-vs-last-good:*` → 启动时将当前文件视为已被破坏,因为与 last-known-good 备份相比,它丢失了字段或文件大小明显变小。
|
||||
- `Config last-known-good promotion skipped` → 候选内容中包含被脱敏的 secret 占位符,例如 `***`。
|
||||
- 存在 `.clobbered.*` → 外部直接编辑或启动时读取的内容已被恢复。
|
||||
- 存在 `.rejected.*` → 一次由 OpenClaw 发起的配置写入在提交前未通过 schema 或 clobber 检查。
|
||||
- `Config write rejected:` → 该写入尝试删除必需结构、大幅缩小文件,或持久化无效配置。
|
||||
- `missing-meta-vs-last-good`、`gateway-mode-missing-vs-last-good` 或 `size-drop-vs-last-good:*` → 启动时将当前文件视为被覆盖,因为与最后一次已知正确备份相比,它丢失了字段或体积变小。
|
||||
- `Config last-known-good promotion skipped` → 候选配置中包含已脱敏的密钥占位符,例如 `***`。
|
||||
|
||||
修复选项:
|
||||
|
||||
1. 如果恢复后的活动配置是正确的,就保留它。
|
||||
2. 仅从 `.clobbered.*` 或 `.rejected.*` 中复制你真正想要的键,然后通过 `openclaw config set` 或 `config.patch` 应用它们。
|
||||
3. 在重启之前运行 `openclaw config validate`。
|
||||
4. 如果你手动编辑,请保留完整的 JSON5 配置,而不仅仅是你想更改的局部对象。
|
||||
2. 仅从 `.clobbered.*` 或 `.rejected.*` 中复制你真正想要的键,然后用 `openclaw config set` 或 `config.patch` 应用。
|
||||
3. 重启前运行 `openclaw config validate`。
|
||||
4. 如果你手动编辑,请保留完整的 JSON5 配置,而不是只保留你想修改的部分对象。
|
||||
|
||||
相关内容:
|
||||
|
||||
- [/gateway/configuration#strict-validation](/zh-CN/gateway/configuration#strict-validation)
|
||||
- [/gateway/configuration#config-hot-reload](/zh-CN/gateway/configuration#config-hot-reload)
|
||||
- [/cli/config](/zh-CN/cli/config)
|
||||
- [/gateway/doctor](/zh-CN/gateway/doctor)
|
||||
- [配置:严格验证](/zh-CN/gateway/configuration#strict-validation)
|
||||
- [配置:热重载](/zh-CN/gateway/configuration#config-hot-reload)
|
||||
- [配置](/zh-CN/cli/config)
|
||||
- [Doctor](/zh-CN/gateway/doctor)
|
||||
|
||||
## Gateway 网关探测警告
|
||||
|
||||
当 `openclaw gateway probe` 能探测到目标,但仍然打印警告块时,使用本节。
|
||||
当 `openclaw gateway probe` 确实探测到了某些内容,但仍然打印出一段警告时,使用本节。
|
||||
|
||||
```bash
|
||||
openclaw gateway probe
|
||||
@ -309,28 +309,28 @@ openclaw gateway probe --json
|
||||
openclaw gateway probe --ssh user@gateway-host
|
||||
```
|
||||
|
||||
检查以下内容:
|
||||
请检查:
|
||||
|
||||
- JSON 输出中的 `warnings[].code` 和 `primaryTargetId`。
|
||||
- 该警告是否与 SSH 回退、多个 Gateway 网关、缺少 scope,或未解析的认证引用有关。
|
||||
- 警告是否与 SSH 回退、多个 Gateway 网关、缺失 scopes,或未解析的认证引用有关。
|
||||
|
||||
常见特征:
|
||||
|
||||
- `SSH tunnel failed to start; falling back to direct probes.` → SSH 设置失败,但命令仍尝试了直接配置的目标/loopback 目标。
|
||||
- `multiple reachable gateways detected` → 有多个目标作出响应。通常这意味着有意配置了多个 Gateway 网关,或者存在过期/重复的监听器。
|
||||
- `Read-probe diagnostics are limited by gateway scopes (missing operator.read)` → 连接成功了,但详细 RPC 受 scope 限制;请配对设备身份,或使用具有 `operator.read` 的凭证。
|
||||
- `Capability: pairing-pending` 或 `gateway closed (1008): pairing required` → Gateway 网关已响应,但此客户端在获得正常 operator 访问权限之前仍需要配对/批准。
|
||||
- 未解析的 `gateway.auth.*` / `gateway.remote.*` SecretRef 警告文本 → 在此命令路径中,失败目标所需的认证材料不可用。
|
||||
- `SSH tunnel failed to start; falling back to direct probes.` → SSH 设置失败,但命令仍然尝试了直接配置目标/loopback 目标。
|
||||
- `multiple reachable gateways detected` → 有多个目标响应。通常这意味着有意的多 Gateway 网关部署,或存在陈旧/重复监听器。
|
||||
- `Read-probe diagnostics are limited by gateway scopes (missing operator.read)` → 连接成功了,但详细 RPC 受 scope 限制;请配对设备身份,或使用带有 `operator.read` 的凭证。
|
||||
- `Capability: pairing-pending` 或 `gateway closed (1008): pairing required` → Gateway 网关已响应,但该客户端在获得正常 operator 访问前仍需配对/批准。
|
||||
- 无法解析的 `gateway.auth.*` / `gateway.remote.*` SecretRef 警告文本 → 在该命令路径中,失败目标所需的认证材料不可用。
|
||||
|
||||
相关内容:
|
||||
|
||||
- [/cli/gateway](/zh-CN/cli/gateway)
|
||||
- [/gateway#multiple-gateways-same-host](/zh-CN/gateway#multiple-gateways-same-host)
|
||||
- [/gateway/remote](/zh-CN/gateway/remote)
|
||||
- [Gateway 网关](/zh-CN/cli/gateway)
|
||||
- [同一主机上的多个 Gateway 网关](/zh-CN/gateway#multiple-gateways-same-host)
|
||||
- [远程访问](/zh-CN/gateway/remote)
|
||||
|
||||
## 渠道已连接但消息不流转
|
||||
## 渠道已连接,但消息不流动
|
||||
|
||||
如果渠道状态显示已连接,但消息流转中断,请重点检查策略、权限和渠道特有的投递规则。
|
||||
如果渠道状态显示已连接,但消息流是死的,请重点检查策略、权限和渠道特定的投递规则。
|
||||
|
||||
```bash
|
||||
openclaw channels status --probe
|
||||
@ -340,28 +340,28 @@ openclaw logs --follow
|
||||
openclaw config get channels
|
||||
```
|
||||
|
||||
检查以下内容:
|
||||
请检查:
|
||||
|
||||
- 私信策略(`pairing`、`allowlist`、`open`、`disabled`)。
|
||||
- 群组 allowlist 和提及要求。
|
||||
- 缺失的渠道 API 权限/scope。
|
||||
- 是否缺少渠道 API 权限/scopes。
|
||||
|
||||
常见特征:
|
||||
|
||||
- `mention required` → 消息被群组提及策略忽略。
|
||||
- `pairing` / 待批准痕迹 → 发送者尚未获批。
|
||||
- `missing_scope`, `not_in_channel`, `Forbidden`, `401/403` → 渠道认证/权限问题。
|
||||
- `mention required` → 消息因群组提及策略而被忽略。
|
||||
- `pairing` / 待批准相关痕迹 → 发送者尚未获批。
|
||||
- `missing_scope`、`not_in_channel`、`Forbidden`、`401/403` → 渠道认证/权限问题。
|
||||
|
||||
相关内容:
|
||||
|
||||
- [/channels/troubleshooting](/zh-CN/channels/troubleshooting)
|
||||
- [/channels/whatsapp](/zh-CN/channels/whatsapp)
|
||||
- [/channels/telegram](/zh-CN/channels/telegram)
|
||||
- [/channels/discord](/zh-CN/channels/discord)
|
||||
- [渠道故障排除](/zh-CN/channels/troubleshooting)
|
||||
- [WhatsApp](/zh-CN/channels/whatsapp)
|
||||
- [Telegram](/zh-CN/channels/telegram)
|
||||
- [Discord](/zh-CN/channels/discord)
|
||||
|
||||
## Cron 和 heartbeat 投递
|
||||
|
||||
如果 cron 或 heartbeat 未运行或未投递,请先验证调度器状态,再检查投递目标。
|
||||
如果 cron 或 heartbeat 没有运行,或没有成功投递,请先验证调度器状态,再检查投递目标。
|
||||
|
||||
```bash
|
||||
openclaw cron status
|
||||
@ -371,9 +371,9 @@ openclaw system heartbeat last
|
||||
openclaw logs --follow
|
||||
```
|
||||
|
||||
检查以下内容:
|
||||
请检查:
|
||||
|
||||
- Cron 已启用,且存在下一次唤醒时间。
|
||||
- Cron 是否启用,以及是否存在下次唤醒时间。
|
||||
- 作业运行历史状态(`ok`、`skipped`、`error`)。
|
||||
- Heartbeat 跳过原因(`quiet-hours`、`requests-in-flight`、`alerts-disabled`、`empty-heartbeat-file`、`no-tasks-due`)。
|
||||
|
||||
@ -381,21 +381,21 @@ openclaw logs --follow
|
||||
|
||||
- `cron: scheduler disabled; jobs will not run automatically` → cron 已禁用。
|
||||
- `cron: timer tick failed` → 调度器 tick 失败;请检查文件/日志/运行时错误。
|
||||
- `heartbeat skipped` 且 `reason=quiet-hours` → 当前在活跃时段窗口之外。
|
||||
- `heartbeat skipped` 且 `reason=quiet-hours` → 当前在活跃时间窗口之外。
|
||||
- `heartbeat skipped` 且 `reason=empty-heartbeat-file` → `HEARTBEAT.md` 存在,但只包含空行 / Markdown 标题,因此 OpenClaw 会跳过模型调用。
|
||||
- `heartbeat skipped` 且 `reason=no-tasks-due` → `HEARTBEAT.md` 包含一个 `tasks:` 块,但本次 tick 没有任何任务到期。
|
||||
- `heartbeat: unknown accountId` → heartbeat 投递目标的账号 id 无效。
|
||||
- `heartbeat skipped` 且 `reason=dm-blocked` → heartbeat 目标被解析为私信风格的目标,而 `agents.defaults.heartbeat.directPolicy`(或每个智能体的覆盖配置)被设置为 `block`。
|
||||
- `heartbeat skipped` 且 `reason=dm-blocked` → heartbeat 目标被解析为私信式目的地,而 `agents.defaults.heartbeat.directPolicy`(或按智能体覆盖项)被设置为 `block`。
|
||||
|
||||
相关内容:
|
||||
|
||||
- [/automation/cron-jobs#troubleshooting](/zh-CN/automation/cron-jobs#troubleshooting)
|
||||
- [/automation/cron-jobs](/zh-CN/automation/cron-jobs)
|
||||
- [/gateway/heartbeat](/zh-CN/gateway/heartbeat)
|
||||
- [计划任务:故障排除](/zh-CN/automation/cron-jobs#troubleshooting)
|
||||
- [计划任务](/zh-CN/automation/cron-jobs)
|
||||
- [Heartbeat](/zh-CN/gateway/heartbeat)
|
||||
|
||||
## 已配对节点的工具失败
|
||||
## 已配对节点上的工具失败
|
||||
|
||||
如果节点已配对但工具失败,请分别排查前台状态、权限和批准状态。
|
||||
如果某个节点已配对,但工具失败,请分别排查前台状态、权限状态和批准状态。
|
||||
|
||||
```bash
|
||||
openclaw nodes status
|
||||
@ -405,28 +405,28 @@ openclaw logs --follow
|
||||
openclaw status
|
||||
```
|
||||
|
||||
检查以下内容:
|
||||
请检查:
|
||||
|
||||
- 节点在线,并具有预期能力。
|
||||
- 相机/麦克风/定位/屏幕的操作系统权限授权。
|
||||
- 节点是否在线,并具备预期能力。
|
||||
- 相机/麦克风/定位/屏幕的操作系统权限是否已授予。
|
||||
- Exec 批准和 allowlist 状态。
|
||||
|
||||
常见特征:
|
||||
|
||||
- `NODE_BACKGROUND_UNAVAILABLE` → 节点应用必须处于前台。
|
||||
- `NODE_BACKGROUND_UNAVAILABLE` → 节点应用必须位于前台。
|
||||
- `*_PERMISSION_REQUIRED` / `LOCATION_PERMISSION_REQUIRED` → 缺少操作系统权限。
|
||||
- `SYSTEM_RUN_DENIED: approval required` → Exec 批准待处理。
|
||||
- `SYSTEM_RUN_DENIED: approval required` → exec 批准待处理。
|
||||
- `SYSTEM_RUN_DENIED: allowlist miss` → 命令被 allowlist 阻止。
|
||||
|
||||
相关内容:
|
||||
|
||||
- [/nodes/troubleshooting](/zh-CN/nodes/troubleshooting)
|
||||
- [/nodes/index](/zh-CN/nodes/index)
|
||||
- [/tools/exec-approvals](/zh-CN/tools/exec-approvals)
|
||||
- [节点故障排除](/zh-CN/nodes/troubleshooting)
|
||||
- [节点](/zh-CN/nodes/index)
|
||||
- [Exec 批准](/zh-CN/tools/exec-approvals)
|
||||
|
||||
## 浏览器工具失败
|
||||
|
||||
当浏览器工具操作失败,但 Gateway 网关本身健康时,使用本节。
|
||||
当 Gateway 网关本身健康,但浏览器工具操作仍然失败时,使用本节。
|
||||
|
||||
```bash
|
||||
openclaw browser status
|
||||
@ -436,46 +436,46 @@ openclaw logs --follow
|
||||
openclaw doctor
|
||||
```
|
||||
|
||||
检查以下内容:
|
||||
请检查:
|
||||
|
||||
- 是否设置了 `plugins.allow`,并且其中包含 `browser`。
|
||||
- 是否已设置 `plugins.allow`,并且其中包含 `browser`。
|
||||
- 浏览器可执行文件路径是否有效。
|
||||
- CDP 配置文件是否可达。
|
||||
- `existing-session` / `user` 配置文件所需的本地 Chrome 是否可用。
|
||||
- 对于 `existing-session` / `user` 配置文件,本地 Chrome 是否可用。
|
||||
|
||||
常见特征:
|
||||
|
||||
- `unknown command "browser"` 或 `unknown command 'browser'` → 内置的浏览器插件被 `plugins.allow` 排除了。
|
||||
- 在 `browser.enabled=true` 的情况下,浏览器工具缺失/不可用 → `plugins.allow` 排除了 `browser`,因此插件根本没有加载。
|
||||
- `unknown command "browser"` 或 `unknown command 'browser'` → 内置 browser 插件被 `plugins.allow` 排除。
|
||||
- 当 `browser.enabled=true` 时 browser 工具缺失 / 不可用 → `plugins.allow` 排除了 `browser`,因此插件根本没有加载。
|
||||
- `Failed to start Chrome CDP on port` → 浏览器进程启动失败。
|
||||
- `browser.executablePath not found` → 配置的路径无效。
|
||||
- `browser.cdpUrl must be http(s) or ws(s)` → 配置的 CDP URL 使用了不受支持的协议,例如 `file:` 或 `ftp:`。
|
||||
- `browser.cdpUrl has invalid port` → 配置的 CDP URL 端口错误或超出范围。
|
||||
- `Could not find DevToolsActivePort for chrome` → Chrome MCP existing-session 还无法附加到所选浏览器数据目录。打开浏览器检查页面,启用远程调试,保持浏览器开启,批准第一次附加提示,然后重试。如果不需要已登录状态,优先使用托管的 `openclaw` 配置文件。
|
||||
- `No Chrome tabs found for profile="user"` → Chrome MCP 附加配置文件没有打开的本地 Chrome 标签页。
|
||||
- `Remote CDP for profile "<name>" is not reachable` → 配置的远程 CDP 端点从 Gateway 网关主机不可达。
|
||||
- `Browser attachOnly is enabled ... not reachable` 或 `Browser attachOnly is enabled and CDP websocket ... is not reachable` → 仅附加配置文件没有可达目标,或者 HTTP 端点已有响应,但 CDP WebSocket 仍无法打开。
|
||||
- `Playwright is not available in this gateway build; '<feature>' is unsupported.` → 当前 Gateway 网关安装缺少内置浏览器插件所需的 `playwright-core` 运行时依赖;运行 `openclaw doctor --fix`,然后重启 Gateway 网关。ARIA 快照和基础页面截图仍可工作,但导航、AI 快照、基于 CSS 选择器的元素截图以及 PDF 导出仍不可用。
|
||||
- `fullPage is not supported for element screenshots` → 截图请求同时混用了 `--full-page` 和 `--ref` 或 `--element`。
|
||||
- `element screenshots are not supported for existing-session profiles; use ref from snapshot.` → Chrome MCP / `existing-session` 截图调用必须使用页面捕获或快照 `--ref`,不能使用 CSS `--element`。
|
||||
- `existing-session file uploads do not support element selectors; use ref/inputRef.` → Chrome MCP 文件上传钩子需要使用快照引用,而不是 CSS 选择器。
|
||||
- `existing-session file uploads currently support one file at a time.` → 在 Chrome MCP 配置文件上,每次调用只发送一个上传文件。
|
||||
- `existing-session dialog handling does not support timeoutMs.` → Chrome MCP 配置文件上的对话框钩子不支持 `timeoutMs` 覆盖。
|
||||
- `existing-session type does not support timeoutMs overrides.` → 对 `profile="user"` / Chrome MCP existing-session 配置文件上的 `act:type`,不要传 `timeoutMs`,或者在需要自定义超时时使用托管/CDP 浏览器配置文件。
|
||||
- `existing-session evaluate does not support timeoutMs overrides.` → 对 `profile="user"` / Chrome MCP existing-session 配置文件上的 `act:evaluate`,不要传 `timeoutMs`,或者在需要自定义超时时使用托管/CDP 浏览器配置文件。
|
||||
- `response body is not supported for existing-session profiles yet.` → `responsebody` 目前仍需要托管浏览器或原始 CDP 配置文件。
|
||||
- attach-only 或远程 CDP 配置文件上的陈旧 viewport / dark-mode / locale / offline 覆盖状态 → 运行 `openclaw browser stop --browser-profile <name>` 关闭活动控制会话并释放 Playwright/CDP 模拟状态,而无需重启整个 Gateway 网关。
|
||||
- `browser.cdpUrl has invalid port` → 配置的 CDP URL 端口无效或超出范围。
|
||||
- `Could not find DevToolsActivePort for chrome` → Chrome MCP existing-session 还无法附加到所选的浏览器数据目录。请打开浏览器的 inspect 页面,启用远程调试,保持浏览器打开,批准首次附加提示,然后重试。如果不需要登录状态,优先使用受管的 `openclaw` profile。
|
||||
- `No Chrome tabs found for profile="user"` → Chrome MCP 附加 profile 没有打开的本地 Chrome 标签页。
|
||||
- `Remote CDP for profile "<name>" is not reachable` → 配置的远程 CDP 端点无法从 Gateway 网关主机访问。
|
||||
- `Browser attachOnly is enabled ... not reachable` 或 `Browser attachOnly is enabled and CDP websocket ... is not reachable` → attach-only profile 没有可访问的目标,或者 HTTP 端点虽然有响应,但 CDP WebSocket 仍然无法打开。
|
||||
- `Playwright is not available in this gateway build; '<feature>' is unsupported.` → 当前 Gateway 网关安装缺少内置 browser 插件的 `playwright-core` 运行时依赖;运行 `openclaw doctor --fix`,然后重启 Gateway 网关。ARIA 快照和基础页面截图仍然可以使用,但导航、AI 快照、基于 CSS 选择器的元素截图以及 PDF 导出仍不可用。
|
||||
- `fullPage is not supported for element screenshots` → 截图请求同时使用了 `--full-page` 和 `--ref` 或 `--element`。
|
||||
- `element screenshots are not supported for existing-session profiles; use ref from snapshot.` → Chrome MCP / `existing-session` 的截图调用必须使用页面捕获或快照 `--ref`,而不是 CSS `--element`。
|
||||
- `existing-session file uploads do not support element selectors; use ref/inputRef.` → Chrome MCP 上传钩子需要使用快照引用,而不是 CSS 选择器。
|
||||
- `existing-session file uploads currently support one file at a time.` → 在 Chrome MCP profiles 上,每次调用只发送一个上传文件。
|
||||
- `existing-session dialog handling does not support timeoutMs.` → Chrome MCP profiles 上的对话框钩子不支持超时覆盖。
|
||||
- `existing-session type does not support timeoutMs overrides.` → 对于 `profile="user"` / Chrome MCP existing-session profiles 上的 `act:type`,请省略 `timeoutMs`;如果需要自定义超时,请使用受管或 CDP 浏览器 profile。
|
||||
- `existing-session evaluate does not support timeoutMs overrides.` → 对于 `profile="user"` / Chrome MCP existing-session profiles 上的 `act:evaluate`,请省略 `timeoutMs`;如果需要自定义超时,请使用受管或 CDP 浏览器 profile。
|
||||
- `response body is not supported for existing-session profiles yet.` → `responsebody` 目前仍需要受管浏览器或原始 CDP profile。
|
||||
- attach-only 或远程 CDP profiles 上出现陈旧的 viewport / dark-mode / locale / offline 覆盖状态 → 运行 `openclaw browser stop --browser-profile <name>`,关闭当前控制会话并释放 Playwright/CDP 模拟状态,而无需重启整个 Gateway 网关。
|
||||
|
||||
相关内容:
|
||||
|
||||
- [/tools/browser-linux-troubleshooting](/zh-CN/tools/browser-linux-troubleshooting)
|
||||
- [/tools/browser](/zh-CN/tools/browser)
|
||||
- [浏览器故障排除](/zh-CN/tools/browser-linux-troubleshooting)
|
||||
- [浏览器(OpenClaw 托管)](/zh-CN/tools/browser)
|
||||
|
||||
## 如果你升级后突然出现问题
|
||||
|
||||
大多数升级后的故障,都是配置漂移,或者现在开始强制执行更严格的默认值。
|
||||
大多数升级后的故障都与配置漂移或现在开始强制执行的更严格默认值有关。
|
||||
|
||||
### 1) 认证和 URL 覆盖行为发生了变化
|
||||
### 1) 认证和 URL 覆盖行为已更改
|
||||
|
||||
```bash
|
||||
openclaw gateway status
|
||||
@ -484,9 +484,9 @@ openclaw config get gateway.remote.url
|
||||
openclaw config get gateway.auth.mode
|
||||
```
|
||||
|
||||
要检查的内容:
|
||||
检查项:
|
||||
|
||||
- 如果 `gateway.mode=remote`,CLI 调用可能正在访问远程目标,而你的本地服务其实是正常的。
|
||||
- 如果 `gateway.mode=remote`,CLI 调用可能会指向远程端,而你的本地服务其实是正常的。
|
||||
- 显式 `--url` 调用不会回退到已存储的凭证。
|
||||
|
||||
常见特征:
|
||||
@ -494,7 +494,7 @@ openclaw config get gateway.auth.mode
|
||||
- `gateway connect failed:` → URL 目标错误。
|
||||
- `unauthorized` → 端点可达,但认证错误。
|
||||
|
||||
### 2) 绑定和认证防护规则更加严格
|
||||
### 2) 绑定和认证护栏更严格了
|
||||
|
||||
```bash
|
||||
openclaw config get gateway.bind
|
||||
@ -504,17 +504,17 @@ openclaw gateway status
|
||||
openclaw logs --follow
|
||||
```
|
||||
|
||||
要检查的内容:
|
||||
检查项:
|
||||
|
||||
- 非 loopback 绑定(`lan`、`tailnet`、`custom`)需要有效的 Gateway 网关认证路径:共享 token/password 认证,或者正确配置的非 loopback `trusted-proxy` 部署。
|
||||
- 旧键名如 `gateway.token` 不能替代 `gateway.auth.token`。
|
||||
- 非 loopback 绑定(`lan`、`tailnet`、`custom`)需要有效的 gateway 认证路径:共享 token/password 认证,或正确配置的非 loopback `trusted-proxy` 部署。
|
||||
- 像 `gateway.token` 这样的旧键不会替代 `gateway.auth.token`。
|
||||
|
||||
常见特征:
|
||||
|
||||
- `refusing to bind gateway ... without auth` → 非 loopback 绑定没有有效的 Gateway 网关认证路径。
|
||||
- 当运行时已启动,但 `Connectivity probe: failed` → Gateway 网关存活,但使用当前 auth/url 无法访问。
|
||||
- `refusing to bind gateway ... without auth` → 非 loopback 绑定缺少有效的 gateway 认证路径。
|
||||
- 运行时已启动,但 `Connectivity probe: failed` → Gateway 网关存活,但使用当前认证/url 无法访问。
|
||||
|
||||
### 3) 配对和设备身份状态发生了变化
|
||||
### 3) 配对和设备身份状态已更改
|
||||
|
||||
```bash
|
||||
openclaw devices list
|
||||
@ -523,17 +523,17 @@ openclaw logs --follow
|
||||
openclaw doctor
|
||||
```
|
||||
|
||||
要检查的内容:
|
||||
检查项:
|
||||
|
||||
- dashboard/节点是否存在待处理的设备批准。
|
||||
- 在策略或身份变更后,是否存在待处理的私信配对批准。
|
||||
- dashboard/节点是否存在待批准的设备请求。
|
||||
- 策略或身份变化后,私信配对是否有待批准项。
|
||||
|
||||
常见特征:
|
||||
|
||||
- `device identity required` → 设备认证未满足。
|
||||
- `pairing required` → 发送者/设备必须先获批。
|
||||
|
||||
如果检查后服务配置和运行时仍然不一致,请从同一个 profile/状态目录重新安装服务元数据:
|
||||
如果完成以上检查后,服务配置和运行时仍然不一致,请使用相同的 profile/状态目录重新安装服务元数据:
|
||||
|
||||
```bash
|
||||
openclaw gateway install --force
|
||||
@ -542,12 +542,12 @@ openclaw gateway restart
|
||||
|
||||
相关内容:
|
||||
|
||||
- [/gateway/pairing](/zh-CN/gateway/pairing)
|
||||
- [/gateway/authentication](/zh-CN/gateway/authentication)
|
||||
- [/gateway/background-process](/zh-CN/gateway/background-process)
|
||||
- [Gateway 网关管理的配对](/zh-CN/gateway/pairing)
|
||||
- [认证](/zh-CN/gateway/authentication)
|
||||
- [后台执行和进程工具](/zh-CN/gateway/background-process)
|
||||
|
||||
## 相关内容
|
||||
|
||||
- [Gateway 网关操作手册](/zh-CN/gateway)
|
||||
- [Gateway 网关运行手册](/zh-CN/gateway)
|
||||
- [Doctor](/zh-CN/gateway/doctor)
|
||||
- [常见问题](/zh-CN/help/faq)
|
||||
|
||||
@ -1,54 +1,54 @@
|
||||
---
|
||||
read_when:
|
||||
- 配对或重新连接 Android 节点
|
||||
- 配对或重新连接 Android node
|
||||
- 调试 Android Gateway 网关发现或认证
|
||||
- 验证各客户端之间的聊天记录一致性
|
||||
summary: Android 应用(节点):连接操作手册 + Connect/Chat/Voice/Canvas 命令入口面
|
||||
- 验证不同客户端之间的聊天历史一致性
|
||||
summary: Android 应用(node):连接运行手册 + Connect/Chat/Voice/Canvas 命令界面
|
||||
title: Android 应用
|
||||
x-i18n:
|
||||
generated_at: "2026-04-24T03:18:22Z"
|
||||
generated_at: "2026-04-25T05:54:52Z"
|
||||
model: gpt-5.4
|
||||
provider: openai
|
||||
source_hash: 31b538a5bf45e78fde34e77a31384295b3e96f2fff6b3adfe37e5c569d858472
|
||||
source_hash: 789de91275a11e63878ba670b9f316538d6b4731c22ec491b2c802f1cd14dcec
|
||||
source_path: platforms/android.md
|
||||
workflow: 15
|
||||
---
|
||||
|
||||
> **注意:** Android 应用尚未公开发布。源代码已在 [OpenClaw 仓库](https://github.com/openclaw/openclaw) 的 `apps/android` 目录中提供。你可以使用 Java 17 和 Android SDK 自行构建(`./gradlew :app:assemblePlayDebug`)。构建说明请参见 [apps/android/README.md](https://github.com/openclaw/openclaw/blob/main/apps/android/README.md)。
|
||||
> **注意:** Android 应用尚未公开发布。源代码可在 [OpenClaw 仓库](https://github.com/openclaw/openclaw) 的 `apps/android` 下获取。你可以使用 Java 17 和 Android SDK 自行构建(`./gradlew :app:assemblePlayDebug`)。构建说明请参见 [apps/android/README.md](https://github.com/openclaw/openclaw/blob/main/apps/android/README.md)。
|
||||
|
||||
## 支持概览
|
||||
|
||||
- 角色:配套节点应用(Android 不承载 Gateway 网关)。
|
||||
- 需要 Gateway 网关:是(在 macOS、Linux 或 Windows 的 WSL2 上运行)。
|
||||
- 角色:配套 node 应用(Android 不承载 Gateway 网关)。
|
||||
- 是否需要 Gateway 网关:是(在 macOS、Linux 或通过 WSL2 的 Windows 上运行)。
|
||||
- 安装:[入门指南](/zh-CN/start/getting-started) + [配对](/zh-CN/channels/pairing)。
|
||||
- Gateway 网关:[操作手册](/zh-CN/gateway) + [配置](/zh-CN/gateway/configuration)。
|
||||
- 协议:[Gateway 网关协议](/zh-CN/gateway/protocol)(节点 + 控制平面)。
|
||||
- Gateway 网关:[运行手册](/zh-CN/gateway) + [配置](/zh-CN/gateway/configuration)。
|
||||
- 协议:[Gateway protocol](/zh-CN/gateway/protocol)(nodes + 控制平面)。
|
||||
|
||||
## 系统控制
|
||||
|
||||
系统控制(launchd/systemd)位于 Gateway 网关主机上。参见 [Gateway 网关](/zh-CN/gateway)。
|
||||
系统控制(launchd/systemd)位于 Gateway 网关主机上。请参见 [Gateway 网关](/zh-CN/gateway)。
|
||||
|
||||
## 连接操作手册
|
||||
## 连接运行手册
|
||||
|
||||
Android 节点应用 ⇄(mDNS/NSD + WebSocket)⇄ **Gateway 网关**
|
||||
Android node 应用 ⇄(mDNS/NSD + WebSocket)⇄ **Gateway 网关**
|
||||
|
||||
Android 直接连接到 Gateway 网关 WebSocket,并使用设备配对(`role: node`)。
|
||||
|
||||
对于 Tailscale 或公共主机,Android 需要安全端点:
|
||||
对于 Tailscale 或公网主机,Android 需要安全端点:
|
||||
|
||||
- 首选:使用 `https://<magicdns>` / `wss://<magicdns>` 的 Tailscale Serve / Funnel
|
||||
- 同样支持:任何其他具有真实 TLS 端点的 `wss://` Gateway 网关 URL
|
||||
- 明文 `ws://` 仍然支持私有局域网地址 / `.local` 主机,以及 `localhost`、`127.0.0.1` 和 Android 模拟器桥接地址(`10.0.2.2`)
|
||||
- 首选:Tailscale Serve / Funnel,使用 `https://<magicdns>` / `wss://<magicdns>`
|
||||
- 同样支持:任何其他带真实 TLS 端点的 `wss://` Gateway 网关 URL
|
||||
- 明文 `ws://` 仍支持私有局域网地址 / `.local` 主机,以及 `localhost`、`127.0.0.1` 和 Android 模拟器桥接地址(`10.0.2.2`)
|
||||
|
||||
### 前置条件
|
||||
### 前提条件
|
||||
|
||||
- 你可以在“主”机器上运行 Gateway 网关。
|
||||
- Android 设备/模拟器可以访问 gateway WebSocket:
|
||||
- 通过同一局域网中的 mDNS/NSD,**或**
|
||||
- 通过同一 Tailscale tailnet 中的 Wide-Area Bonjour / 单播 DNS-SD(见下文),**或**
|
||||
- 手动指定 gateway 主机/端口(回退方案)
|
||||
- tailnet/公共网络移动端配对**不**使用原始 tailnet IP `ws://` 端点。请改用 Tailscale Serve 或其他 `wss://` URL。
|
||||
- 你可以在 gateway 机器上运行 CLI(`openclaw`)(或通过 SSH 运行)。
|
||||
- Android 设备/模拟器可以访问 Gateway 网关 WebSocket:
|
||||
- 位于同一局域网并使用 mDNS/NSD,**或**
|
||||
- 位于同一 Tailscale tailnet,并使用 Wide-Area Bonjour / 单播 DNS-SD(见下文),**或**
|
||||
- 手动指定 Gateway 网关主机/端口(回退方案)
|
||||
- tailnet/公网移动配对**不**使用原始 tailnet IP `ws://` 端点。请改用 Tailscale Serve 或其他 `wss://` URL。
|
||||
- 你可以在 Gateway 网关机器上运行 CLI(`openclaw`)(或通过 SSH 运行)。
|
||||
|
||||
### 1)启动 Gateway 网关
|
||||
|
||||
@ -56,65 +56,65 @@ Android 直接连接到 Gateway 网关 WebSocket,并使用设备配对(`role
|
||||
openclaw gateway --port 18789 --verbose
|
||||
```
|
||||
|
||||
确认日志中出现类似内容:
|
||||
在日志中确认你能看到类似以下内容:
|
||||
|
||||
- `listening on ws://0.0.0.0:18789`
|
||||
|
||||
对于通过 Tailscale 进行远程 Android 访问,优先使用 Serve/Funnel,而不是原始 tailnet 绑定:
|
||||
对于通过 Tailscale 的远程 Android 访问,优先使用 Serve/Funnel,而不是原始 tailnet 绑定:
|
||||
|
||||
```bash
|
||||
openclaw gateway --tailscale serve
|
||||
```
|
||||
|
||||
这会为 Android 提供一个安全的 `wss://` / `https://` 端点。普通的 `gateway.bind: "tailnet"` 设置不足以支持首次远程 Android 配对,除非你另外终止 TLS。
|
||||
这会为 Android 提供安全的 `wss://` / `https://` 端点。单独使用普通的 `gateway.bind: "tailnet"` 设置,不足以完成首次远程 Android 配对,除非你另外终止 TLS。
|
||||
|
||||
### 2)验证发现(可选)
|
||||
### 2)验证设备发现(可选)
|
||||
|
||||
在 gateway 机器上运行:
|
||||
在 Gateway 网关机器上运行:
|
||||
|
||||
```bash
|
||||
dns-sd -B _openclaw-gw._tcp local.
|
||||
```
|
||||
|
||||
更多调试说明:[Bonjour](/zh-CN/gateway/bonjour)。
|
||||
更多调试说明: [Bonjour](/zh-CN/gateway/bonjour)。
|
||||
|
||||
如果你还配置了广域发现域,请对照运行:
|
||||
如果你还配置了广域设备发现域,请对比以下命令结果:
|
||||
|
||||
```bash
|
||||
openclaw gateway discover --json
|
||||
```
|
||||
|
||||
这会在一次执行中显示 `local.` 和已配置的广域域名,并使用解析后的
|
||||
服务端点,而不是仅使用 TXT 提示。
|
||||
它会一次性显示 `local.` 和已配置的广域域名,并使用已解析的
|
||||
服务端点,而不是仅依赖 TXT 提示。
|
||||
|
||||
#### 通过单播 DNS-SD 进行 tailnet(维也纳 ⇄ 伦敦)发现
|
||||
#### 通过单播 DNS-SD 进行 tailnet(维也纳 ⇄ 伦敦)设备发现
|
||||
|
||||
Android 的 NSD/mDNS 发现无法跨网络工作。如果你的 Android 节点和 gateway 位于不同网络,但通过 Tailscale 连接,请改用 Wide-Area Bonjour / 单播 DNS-SD。
|
||||
Android NSD/mDNS 设备发现不会跨网络。如果你的 Android node 和 Gateway 网关位于不同网络,但都连接到了 Tailscale,请改用 Wide-Area Bonjour / 单播 DNS-SD。
|
||||
|
||||
仅靠发现不足以完成 tailnet/公共网络 Android 配对。发现出来的路由仍然需要一个安全端点(`wss://` 或 Tailscale Serve):
|
||||
仅有设备发现并不足以支持 tailnet/公网 Android 配对。发现到的路由仍然需要安全端点(`wss://` 或 Tailscale Serve):
|
||||
|
||||
1. 在 gateway 主机上设置一个 DNS-SD 区域(例如 `openclaw.internal.`),并发布 `_openclaw-gw._tcp` 记录。
|
||||
1. 在 Gateway 网关主机上设置一个 DNS-SD 区域(例如 `openclaw.internal.`),并发布 `_openclaw-gw._tcp` 记录。
|
||||
2. 为你选择的域配置 Tailscale split DNS,并指向该 DNS 服务器。
|
||||
|
||||
详细信息和 CoreDNS 配置示例请参见:[Bonjour](/zh-CN/gateway/bonjour)。
|
||||
详情和示例 CoreDNS 配置: [Bonjour](/zh-CN/gateway/bonjour)。
|
||||
|
||||
### 3)从 Android 连接
|
||||
|
||||
在 Android 应用中:
|
||||
|
||||
- 应用通过**前台服务**(持久通知)保持与 gateway 的连接。
|
||||
- 打开 **Connect** 选项卡。
|
||||
- 应用通过**前台服务**(持久通知)保持与 Gateway 网关的连接。
|
||||
- 打开 **Connect** 标签页。
|
||||
- 使用 **Setup Code** 或 **Manual** 模式。
|
||||
- 如果发现机制被阻止,请在 **Advanced controls** 中手动输入主机/端口。对于私有局域网主机,`ws://` 仍可使用。对于 Tailscale/公共主机,请打开 TLS 并使用 `wss://` / Tailscale Serve 端点。
|
||||
- 如果设备发现被阻止,请在 **Advanced controls** 中手动输入主机/端口。对于私有局域网主机,`ws://` 仍然可用。对于 Tailscale/公网主机,请启用 TLS,并使用 `wss://` / Tailscale Serve 端点。
|
||||
|
||||
首次配对成功后,Android 会在启动时自动重连:
|
||||
首次成功配对后,Android 会在启动时自动重连:
|
||||
|
||||
- 手动端点(如果已启用),否则
|
||||
- 上一次发现到的 gateway(尽力而为)。
|
||||
- 若已启用,则使用手动端点,否则
|
||||
- 使用最近发现的 Gateway 网关(尽力而为)。
|
||||
|
||||
### 4)批准配对(CLI)
|
||||
|
||||
在 gateway 机器上运行:
|
||||
在 Gateway 网关机器上:
|
||||
|
||||
```bash
|
||||
openclaw devices list
|
||||
@ -122,11 +122,30 @@ openclaw devices approve <requestId>
|
||||
openclaw devices reject <requestId>
|
||||
```
|
||||
|
||||
配对详情:[配对](/zh-CN/channels/pairing)。
|
||||
配对详情: [配对](/zh-CN/channels/pairing)。
|
||||
|
||||
### 5)验证节点已连接
|
||||
可选:如果 Android node 始终只会从严格受控的子网连接,
|
||||
你可以通过显式 CIDR 或精确 IP,启用首次 node 自动批准:
|
||||
|
||||
- 通过节点状态:
|
||||
```json5
|
||||
{
|
||||
gateway: {
|
||||
nodes: {
|
||||
pairing: {
|
||||
autoApproveCidrs: ["192.168.1.0/24"],
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
此功能默认禁用。它仅适用于全新的 `role: node` 配对,并且
|
||||
没有请求任何 scope。操作员/浏览器配对,以及任何角色、scope、元数据或
|
||||
公钥变更,仍然需要手动批准。
|
||||
|
||||
### 5)验证 node 已连接
|
||||
|
||||
- 通过 nodes 状态:
|
||||
|
||||
```bash
|
||||
openclaw nodes status
|
||||
@ -140,52 +159,58 @@ openclaw devices reject <requestId>
|
||||
|
||||
### 6)聊天 + 历史记录
|
||||
|
||||
Android Chat 选项卡支持选择会话(默认 `main`,以及其他现有会话):
|
||||
Android Chat 标签页支持会话选择(默认 `main`,以及其他已有会话):
|
||||
|
||||
- 历史记录:`chat.history`(显示层已规范化;内联指令标签会从可见文本中移除,纯文本工具调用 XML 载荷——包括 `<tool_call>...</tool_call>`、`<function_call>...</function_call>`、`<tool_calls>...</tool_calls>`、`<function_calls>...</function_calls>`,以及被截断的工具调用块——和泄漏出来的 ASCII/全角模型控制 token 都会被移除,纯静默 token 的 assistant 行,例如精确的 `NO_REPLY` / `no_reply`,会被省略,超大行则可能被占位符替代)
|
||||
- 历史记录:`chat.history`(显示归一化;可见文本中的内联指令标签会被
|
||||
去除,纯文本工具调用 XML 负载(包括
|
||||
`<tool_call>...</tool_call>`、`<function_call>...</function_call>`、
|
||||
`<tool_calls>...</tool_calls>`、`<function_calls>...</function_calls>`,以及
|
||||
被截断的工具调用块)和泄露的 ASCII/全角模型控制令牌
|
||||
会被移除,纯静默令牌的助手行,例如精确的 `NO_REPLY` /
|
||||
`no_reply`,会被省略,过大的行则可能会被占位符替代)
|
||||
- 发送:`chat.send`
|
||||
- 推送更新(尽力而为):`chat.subscribe` → `event:"chat"`
|
||||
|
||||
### 7)Canvas + 相机
|
||||
|
||||
#### Gateway 网关 Canvas Host(推荐用于 Web 内容)
|
||||
#### Gateway Canvas Host(推荐用于 Web 内容)
|
||||
|
||||
如果你希望节点显示智能体可以在磁盘上编辑的真实 HTML/CSS/JS,请让节点指向 Gateway 网关 canvas host。
|
||||
如果你希望 node 显示智能体可在磁盘上编辑的真实 HTML/CSS/JS 内容,请让 node 指向 Gateway 网关 canvas host。
|
||||
|
||||
注意:节点从 Gateway 网关 HTTP 服务器加载 canvas(与 `gateway.port` 使用同一端口,默认 `18789`)。
|
||||
注意:nodes 从 Gateway 网关 HTTP 服务器加载 canvas(与 `gateway.port` 使用同一端口,默认 `18789`)。
|
||||
|
||||
1. 在 gateway 主机上创建 `~/.openclaw/workspace/canvas/index.html`。
|
||||
1. 在 Gateway 网关主机上创建 `~/.openclaw/workspace/canvas/index.html`。
|
||||
|
||||
2. 将节点导航到该地址(局域网):
|
||||
2. 将 node 导航到该页面(局域网):
|
||||
|
||||
```bash
|
||||
openclaw nodes invoke --node "<Android Node>" --command canvas.navigate --params '{"url":"http://<gateway-hostname>.local:18789/__openclaw__/canvas/"}'
|
||||
```
|
||||
|
||||
Tailnet(可选):如果两个设备都在 Tailscale 上,可使用 MagicDNS 名称或 tailnet IP 代替 `.local`,例如 `http://<gateway-magicdns>:18789/__openclaw__/canvas/`。
|
||||
tailnet(可选):如果两台设备都在 Tailscale 上,请使用 MagicDNS 名称或 tailnet IP 替代 `.local`,例如 `http://<gateway-magicdns>:18789/__openclaw__/canvas/`。
|
||||
|
||||
该服务器会向 HTML 注入 live-reload 客户端,并在文件变更时自动刷新。
|
||||
该服务器会向 HTML 注入实时重载客户端,并在文件变更时重新加载。
|
||||
A2UI host 位于 `http://<gateway-host>:18789/__openclaw__/a2ui/`。
|
||||
|
||||
Canvas 命令(仅前台):
|
||||
|
||||
- `canvas.eval`、`canvas.snapshot`、`canvas.navigate`(使用 `{"url":""}` 或 `{"url":"/"}` 返回默认脚手架)。`canvas.snapshot` 返回 `{ format, base64 }`(默认 `format="jpeg"`)。
|
||||
- A2UI:`canvas.a2ui.push`、`canvas.a2ui.reset`(`canvas.a2ui.pushJSONL` 为旧别名)
|
||||
- `canvas.eval`、`canvas.snapshot`、`canvas.navigate`(使用 `{"url":""}` 或 `{"url":"/"}` 可返回默认脚手架)。`canvas.snapshot` 返回 `{ format, base64 }`(默认 `format="jpeg"`)。
|
||||
- A2UI:`canvas.a2ui.push`、`canvas.a2ui.reset`(`canvas.a2ui.pushJSONL` 为旧版别名)
|
||||
|
||||
相机命令(仅前台;受权限控制):
|
||||
|
||||
- `camera.snap`(jpg)
|
||||
- `camera.clip`(mp4)
|
||||
|
||||
参数和 CLI 辅助命令请参见 [相机节点](/zh-CN/nodes/camera)。
|
||||
参数和 CLI 辅助命令请参见 [Camera node](/zh-CN/nodes/camera)。
|
||||
|
||||
### 8)Voice + 扩展的 Android 命令入口面
|
||||
### 8)语音 + 扩展 Android 命令界面
|
||||
|
||||
- Voice:Android 在 Voice 选项卡中使用单一的麦克风开/关流程,支持转录捕获和 `talk.speak` 播放。仅当 `talk.speak` 不可用时,才使用本地系统 TTS。应用离开前台时,Voice 会停止。
|
||||
- Voice 唤醒/说话模式切换目前已从 Android UX/runtime 中移除。
|
||||
- 其他 Android 命令家族(可用性取决于设备 + 权限):
|
||||
- 语音:Android 在 Voice 标签页中使用单一麦克风开/关流程,支持转录捕获和 `talk.speak` 播放。仅当 `talk.speak` 不可用时,才使用本地系统 TTS。应用离开前台时,语音会停止。
|
||||
- 语音唤醒/通话模式切换目前已从 Android UX/运行时中移除。
|
||||
- 其他 Android 命令族(是否可用取决于设备 + 权限):
|
||||
- `device.status`、`device.info`、`device.permissions`、`device.health`
|
||||
- `notifications.list`、`notifications.actions`(参见下方 [通知转发](#notification-forwarding))
|
||||
- `notifications.list`、`notifications.actions`(见下方 [通知转发](#notification-forwarding))
|
||||
- `photos.latest`
|
||||
- `contacts.search`、`contacts.add`
|
||||
- `calendar.events`、`calendar.add`
|
||||
@ -193,34 +218,35 @@ Canvas 命令(仅前台):
|
||||
- `sms.search`
|
||||
- `motion.activity`、`motion.pedometer`
|
||||
|
||||
## Assistant 入口点
|
||||
## 助手入口点
|
||||
|
||||
Android 支持从系统 Assistant 触发器启动 OpenClaw(Google
|
||||
Assistant)。完成配置后,长按 Home 键或说“Hey Google, ask
|
||||
OpenClaw...”会打开应用,并将提示词传入聊天输入框。
|
||||
Android 支持通过系统助手触发器启动 OpenClaw(Google
|
||||
Assistant)。配置完成后,长按 Home 键或说“Hey Google, ask
|
||||
OpenClaw...”即可打开应用,并将提示词传入聊天输入框。
|
||||
|
||||
这使用在应用清单中声明的 Android **App Actions** 元数据。Gateway 网关侧不需要
|
||||
额外配置——assistant intent 完全由 Android 应用处理,并作为普通聊天消息转发。
|
||||
这使用的是在应用清单中声明的 Android **App Actions** 元数据。Gateway 网关侧
|
||||
无需额外配置——助手 intent 完全由 Android 应用处理,并作为普通聊天消息转发。
|
||||
|
||||
<Note>
|
||||
App Actions 的可用性取决于设备、Google Play Services 版本,以及用户是否将 OpenClaw 设置为默认 assistant 应用。
|
||||
App Actions 的可用性取决于设备、Google Play Services 版本,
|
||||
以及用户是否已将 OpenClaw 设为默认助手应用。
|
||||
</Note>
|
||||
|
||||
## 通知转发
|
||||
|
||||
Android 可以将设备通知作为事件转发到 gateway。你可以使用多项控制来限定转发哪些通知以及何时转发。
|
||||
Android 可以将设备通知作为事件转发到 Gateway 网关。有多项控制项可让你限定转发哪些通知以及何时转发。
|
||||
|
||||
| 键 | 类型 | 说明 |
|
||||
| 键名 | 类型 | 说明 |
|
||||
| -------------------------------- | -------------- | ------------------------------------------------------------------------------------------------- |
|
||||
| `notifications.allowPackages` | string[] | 只转发来自这些包名的通知。如果设置了该项,所有其他包都会被忽略。 |
|
||||
| `notifications.allowPackages` | string[] | 仅转发来自这些包名的通知。如果已设置,所有其他包都会被忽略。 |
|
||||
| `notifications.denyPackages` | string[] | 永不转发来自这些包名的通知。在 `allowPackages` 之后应用。 |
|
||||
| `notifications.quietHours.start` | string (HH:mm) | 静默时段窗口开始时间(设备本地时间)。在该窗口期间会抑制通知。 |
|
||||
| `notifications.quietHours.start` | string (HH:mm) | 静默时段窗口开始时间(设备本地时间)。在该窗口期间通知会被抑制。 |
|
||||
| `notifications.quietHours.end` | string (HH:mm) | 静默时段窗口结束时间。 |
|
||||
| `notifications.rateLimit` | number | 每个包每分钟最多转发的通知数量。超出的通知会被丢弃。 |
|
||||
| `notifications.rateLimit` | number | 每个包每分钟允许转发的最大通知数。超出的通知会被丢弃。 |
|
||||
|
||||
通知选择器还对转发的通知事件采用了更安全的行为,以防止意外转发敏感系统通知。
|
||||
通知选择器对转发的通知事件也采用了更安全的行为,避免意外转发敏感的系统通知。
|
||||
|
||||
配置示例:
|
||||
示例配置:
|
||||
|
||||
```json5
|
||||
{
|
||||
@ -243,5 +269,5 @@ Android 可以将设备通知作为事件转发到 gateway。你可以使用多
|
||||
## 相关内容
|
||||
|
||||
- [iOS 应用](/zh-CN/platforms/ios)
|
||||
- [节点](/zh-CN/nodes)
|
||||
- [Android 节点故障排除](/zh-CN/nodes/troubleshooting)
|
||||
- [Nodes](/zh-CN/nodes)
|
||||
- [Android node 故障排除](/zh-CN/nodes/troubleshooting)
|
||||
|
||||
@ -6,29 +6,29 @@ read_when:
|
||||
summary: iOS 节点应用:连接到 Gateway 网关、配对、canvas 和故障排除
|
||||
title: iOS 应用
|
||||
x-i18n:
|
||||
generated_at: "2026-04-23T22:59:25Z"
|
||||
generated_at: "2026-04-25T05:54:50Z"
|
||||
model: gpt-5.4
|
||||
provider: openai
|
||||
source_hash: 87eaa706993bec9434bf22e18022af711b8398efff11c7fba4887aba46041ed3
|
||||
source_hash: ad0088cd135168248cfad10c24715f74117a66efaa52a572579c04f96a806538
|
||||
source_path: platforms/ios.md
|
||||
workflow: 15
|
||||
---
|
||||
|
||||
可用性:内部预览。iOS 应用尚未公开分发。
|
||||
|
||||
## 它的作用
|
||||
## 功能说明
|
||||
|
||||
- 通过 WebSocket 连接到 Gateway 网关(LAN 或 tailnet)。
|
||||
- 暴露节点能力:Canvas、屏幕快照、相机捕获、位置、Talk 模式、语音唤醒。
|
||||
- 接收 `node.invoke` 命令并上报节点状态事件。
|
||||
- 接收 `node.invoke` 命令并上报节点 Status 事件。
|
||||
|
||||
## 要求
|
||||
|
||||
- 另一台设备上正在运行的 Gateway 网关(macOS、Linux,或通过 WSL2 运行的 Windows)。
|
||||
- Gateway 网关运行在另一台设备上(macOS、Linux,或通过 WSL2 运行的 Windows)。
|
||||
- 网络路径:
|
||||
- 通过 Bonjour 在同一 LAN 内,**或**
|
||||
- 通过单播 DNS-SD 在 tailnet 上(示例域名:`openclaw.internal.`),**或**
|
||||
- 手动填写 host/port(回退方式)。
|
||||
- 通过 Bonjour 处于同一 LAN,**或**
|
||||
- 通过单播 DNS-SD 处于 tailnet(示例域名:`openclaw.internal.`),**或**
|
||||
- 手动输入主机/端口(回退方案)。
|
||||
|
||||
## 快速开始(配对 + 连接)
|
||||
|
||||
@ -38,18 +38,38 @@ x-i18n:
|
||||
openclaw gateway --port 18789
|
||||
```
|
||||
|
||||
2. 在 iOS 应用中,打开“设置”并选择一个已发现的 Gateway 网关(或启用“手动主机”并输入 host/port)。
|
||||
2. 在 iOS 应用中,打开“设置”并选择一个已发现的网关(或启用“手动主机”并输入主机/端口)。
|
||||
|
||||
3. 在 Gateway 网关主机上批准配对请求:
|
||||
3. 在网关主机上批准配对请求:
|
||||
|
||||
```bash
|
||||
openclaw devices list
|
||||
openclaw devices approve <requestId>
|
||||
```
|
||||
|
||||
如果应用在身份验证详情(角色/作用域/公钥)发生变化后重试配对,之前待处理的请求会被替换,并创建新的 `requestId`。
|
||||
如果应用使用变更后的认证详情(角色/作用域/公钥)重试配对,
|
||||
之前的待处理请求会被替换,并创建新的 `requestId`。
|
||||
请在批准前再次运行 `openclaw devices list`。
|
||||
|
||||
可选:如果 iOS 节点始终从严格受控的子网连接,
|
||||
你可以通过显式 CIDR 或精确 IP 选择启用首次节点自动批准:
|
||||
|
||||
```json5
|
||||
{
|
||||
gateway: {
|
||||
nodes: {
|
||||
pairing: {
|
||||
autoApproveCidrs: ["192.168.1.0/24"],
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
此功能默认禁用。它仅适用于没有请求作用域的全新 `role: node` 配对。
|
||||
运维人员/浏览器配对,以及任何角色、作用域、元数据或
|
||||
公钥变更,仍然需要手动批准。
|
||||
|
||||
4. 验证连接:
|
||||
|
||||
```bash
|
||||
@ -57,12 +77,12 @@ openclaw nodes status
|
||||
openclaw gateway call node.list --params "{}"
|
||||
```
|
||||
|
||||
## 官方构建的 relay 支持 push
|
||||
## 官方构建的中继支持推送
|
||||
|
||||
官方分发的 iOS 构建使用外部 push relay,而不是将原始 APNs
|
||||
token 直接发布给 Gateway 网关。
|
||||
官方分发的 iOS 构建会使用外部推送中继,而不是将原始 APNs
|
||||
令牌发布到网关。
|
||||
|
||||
Gateway 网关端要求:
|
||||
Gateway 网关侧要求:
|
||||
|
||||
```json5
|
||||
{
|
||||
@ -80,76 +100,82 @@ Gateway 网关端要求:
|
||||
|
||||
流程工作方式:
|
||||
|
||||
- iOS 应用使用 App Attest 和应用回执向 relay 注册。
|
||||
- relay 返回一个不透明的 relay handle,以及一个按注册作用域划分的发送授权。
|
||||
- iOS 应用会获取已配对 Gateway 网关的身份,并将其包含在 relay 注册中,因此该 relay 支持的注册会被委托给该特定 Gateway 网关。
|
||||
- 应用通过 `push.apns.register` 将该 relay 支持的注册转发给已配对的 Gateway 网关。
|
||||
- Gateway 网关会将该已存储的 relay handle 用于 `push.test`、后台唤醒和唤醒提示。
|
||||
- Gateway 网关的 relay base URL 必须与官方/TestFlight iOS 构建中内置的 relay URL 一致。
|
||||
- 如果应用之后连接到另一个 Gateway 网关,或连接到一个使用不同 relay base URL 的构建,它会刷新 relay 注册,而不是重用旧绑定。
|
||||
- iOS 应用使用 App Attest 和应用回执向中继注册。
|
||||
- 中继返回一个不透明的中继句柄以及一个注册作用域的发送授权。
|
||||
- iOS 应用会获取已配对 Gateway 网关的身份,并将其包含在中继注册中,因此该中继支持的注册会委派给这个特定的 Gateway 网关。
|
||||
- 应用通过 `push.apns.register` 将该中继支持的注册转发给已配对的 Gateway 网关。
|
||||
- Gateway 网关会将这个已存储的中继句柄用于 `push.test`、后台唤醒和唤醒提示。
|
||||
- Gateway 网关中继基础 URL 必须与官方/TestFlight iOS 构建中内置的中继 URL 匹配。
|
||||
- 如果应用之后连接到不同的 Gateway 网关,或连接到使用不同中继基础 URL 的构建,它会刷新中继注册,而不是复用旧绑定。
|
||||
|
||||
对于这一路径,Gateway 网关**不**需要的内容:
|
||||
对于此路径,Gateway 网关**不**需要:
|
||||
|
||||
- 不需要部署级 relay token。
|
||||
- 对于官方/TestFlight relay 支持的发送,不需要直接 APNs key。
|
||||
- 不需要部署范围的中继令牌。
|
||||
- 官方/TestFlight 中继支持发送不需要直接 APNs 密钥。
|
||||
|
||||
预期的操作员流程:
|
||||
预期的运维流程:
|
||||
|
||||
1. 安装官方/TestFlight iOS 构建。
|
||||
2. 在 Gateway 网关上设置 `gateway.push.apns.relay.baseUrl`。
|
||||
3. 将应用与 Gateway 网关配对,并等待其完成连接。
|
||||
4. 在应用拿到 APNs token、操作员会话已连接且 relay 注册成功后,应用会自动发布 `push.apns.register`。
|
||||
5. 此后,`push.test`、重新连接唤醒和唤醒提示就可以使用已存储的 relay 支持注册。
|
||||
2. 在网关上设置 `gateway.push.apns.relay.baseUrl`。
|
||||
3. 将应用与网关配对,并等待它完成连接。
|
||||
4. 在应用获得 APNs 令牌、运维会话已连接且中继注册成功后,应用会自动发布 `push.apns.register`。
|
||||
5. 之后,`push.test`、重连唤醒和唤醒提示都可以使用已存储的中继支持注册。
|
||||
|
||||
兼容性说明:
|
||||
|
||||
- `OPENCLAW_APNS_RELAY_BASE_URL` 仍可作为 Gateway 网关的临时环境变量覆盖项。
|
||||
- `OPENCLAW_APNS_RELAY_BASE_URL` 仍可作为网关的临时环境变量覆盖。
|
||||
|
||||
## 身份验证与信任流程
|
||||
## 认证和信任流
|
||||
|
||||
relay 的存在,是为了强制执行两个约束,而这两个约束是官方 iOS 构建直接在 Gateway 网关上使用 APNs 无法提供的:
|
||||
设置中继是为了强制执行两个约束,而网关直连 APNs 无法为
|
||||
官方 iOS 构建提供这些约束:
|
||||
|
||||
- 只有通过 Apple 分发的真实 OpenClaw iOS 构建才能使用托管 relay。
|
||||
- Gateway 网关只能为已与该特定 Gateway 网关配对的 iOS 设备发送 relay 支持的 push。
|
||||
- 只有通过 Apple 分发的真实 OpenClaw iOS 构建才能使用托管中继。
|
||||
- Gateway 网关只能为与该特定 Gateway 网关配对的 iOS 设备发送中继支持的推送。
|
||||
|
||||
逐跳说明:
|
||||
|
||||
1. `iOS app -> gateway`
|
||||
- 应用首先通过正常的 Gateway 网关身份验证流程与 Gateway 网关配对。
|
||||
- 这样应用会获得一个已认证的节点会话以及一个已认证的操作员会话。
|
||||
- 操作员会话用于调用 `gateway.identity.get`。
|
||||
- 应用首先通过常规 Gateway 网关认证流与网关配对。
|
||||
- 这会给应用一个已认证的节点会话和一个已认证的运维会话。
|
||||
- 运维会话用于调用 `gateway.identity.get`。
|
||||
|
||||
2. `iOS app -> relay`
|
||||
- 应用通过 HTTPS 调用 relay 注册端点。
|
||||
- 注册包含 App Attest 证明以及应用回执。
|
||||
- relay 会验证 bundle ID、App Attest 证明和 Apple 回执,并要求使用官方/生产分发路径。
|
||||
- 这就是为什么本地 Xcode/dev 构建无法使用托管 relay。虽然本地构建也可能已签名,但它不满足 relay 所要求的官方 Apple 分发证明。
|
||||
- 应用通过 HTTPS 调用中继注册端点。
|
||||
- 注册包含 App Attest 证明和应用回执。
|
||||
- 中继会验证 bundle ID、App Attest 证明和 Apple 回执,并要求使用
|
||||
官方/生产分发路径。
|
||||
- 这就是为什么本地 Xcode/开发构建无法使用托管中继。本地构建也许已签名,
|
||||
但它不满足中继所要求的官方 Apple 分发证明。
|
||||
|
||||
3. `gateway identity delegation`
|
||||
- 在 relay 注册之前,应用会通过 `gateway.identity.get` 获取已配对 Gateway 网关的身份。
|
||||
- 应用会将该 Gateway 网关身份包含在 relay 注册负载中。
|
||||
- relay 返回一个 relay handle 和一个按注册作用域划分的发送授权,并将其委托给该 Gateway 网关身份。
|
||||
- 在中继注册之前,应用会从
|
||||
`gateway.identity.get` 获取已配对 Gateway 网关的身份。
|
||||
- 应用会在中继注册负载中包含该 Gateway 网关身份。
|
||||
- 中继会返回一个中继句柄和一个注册作用域的发送授权,并将其委派给
|
||||
该 Gateway 网关身份。
|
||||
|
||||
4. `gateway -> relay`
|
||||
- Gateway 网关会存储来自 `push.apns.register` 的 relay handle 和发送授权。
|
||||
- 在执行 `push.test`、重新连接唤醒和唤醒提示时,Gateway 网关会使用自己的设备身份对发送请求签名。
|
||||
- relay 会根据注册时委托的 Gateway 网关身份,同时验证已存储的发送授权和 Gateway 网关签名。
|
||||
- 即使其他 Gateway 网关设法获得了该 handle,也无法重用该已存储注册。
|
||||
- Gateway 网关会存储来自 `push.apns.register` 的中继句柄和发送授权。
|
||||
- 在 `push.test`、重连唤醒和唤醒提示时,Gateway 网关会使用其
|
||||
自身设备身份对发送请求进行签名。
|
||||
- 中继会根据注册时委派的 Gateway 网关身份,验证已存储的发送授权和 Gateway 网关签名。
|
||||
- 其他 Gateway 网关即使设法获取了该句柄,也无法复用该已存储注册。
|
||||
|
||||
5. `relay -> APNs`
|
||||
- relay 持有生产 APNs 凭证,以及官方构建的原始 APNs token。
|
||||
- 对于 relay 支持的官方构建,Gateway 网关永远不会存储原始 APNs token。
|
||||
- relay 代表已配对 Gateway 网关,向 APNs 发送最终 push。
|
||||
- 中继持有官方构建的生产 APNs 凭证和原始 APNs 令牌。
|
||||
- 对于中继支持的官方构建,Gateway 网关永远不会存储原始 APNs 令牌。
|
||||
- 中继代表已配对的 Gateway 网关向 APNs 发送最终推送。
|
||||
|
||||
创建这种设计的原因:
|
||||
创建此设计的原因:
|
||||
|
||||
- 将生产 APNs 凭证留在用户 Gateway 网关之外。
|
||||
- 避免在 Gateway 网关上存储官方构建的原始 APNs token。
|
||||
- 只允许官方/TestFlight OpenClaw 构建使用托管 relay。
|
||||
- 防止某个 Gateway 网关向属于另一 Gateway 网关的 iOS 设备发送唤醒 push。
|
||||
- 让生产 APNs 凭证不出现在用户 Gateway 网关中。
|
||||
- 避免在 Gateway 网关上存储官方构建的原始 APNs 令牌。
|
||||
- 仅允许官方/TestFlight OpenClaw 构建使用托管中继。
|
||||
- 防止某个 Gateway 网关向属于其他 Gateway 网关的 iOS 设备发送唤醒推送。
|
||||
|
||||
本地/手动构建仍使用直连 APNs。如果你在没有 relay 的情况下测试这些构建,
|
||||
Gateway 网关仍然需要直连 APNs 凭证:
|
||||
本地/手动构建仍然使用直连 APNs。如果你在没有中继的情况下测试这些构建,
|
||||
Gateway 网关仍然需要直接 APNs 凭证:
|
||||
|
||||
```bash
|
||||
export OPENCLAW_APNS_TEAM_ID="TEAMID"
|
||||
@ -157,9 +183,9 @@ export OPENCLAW_APNS_KEY_ID="KEYID"
|
||||
export OPENCLAW_APNS_PRIVATE_KEY_P8="$(cat /path/to/AuthKey_KEYID.p8)"
|
||||
```
|
||||
|
||||
这些是 Gateway 网关主机运行时环境变量,不是 Fastlane 设置。`apps/ios/fastlane/.env` 仅存储
|
||||
App Store Connect / TestFlight 身份验证,例如 `ASC_KEY_ID` 和 `ASC_ISSUER_ID`;它不配置
|
||||
本地 iOS 构建的直连 APNs 投递。
|
||||
这些是 Gateway 网关主机运行时环境变量,而不是 Fastlane 设置。`apps/ios/fastlane/.env` 只存储
|
||||
App Store Connect / TestFlight 认证信息,例如 `ASC_KEY_ID` 和 `ASC_ISSUER_ID`;它不会为本地 iOS 构建配置
|
||||
直连 APNs 投递。
|
||||
|
||||
推荐的 Gateway 网关主机存储方式:
|
||||
|
||||
@ -173,21 +199,23 @@ export OPENCLAW_APNS_PRIVATE_KEY_PATH="$HOME/.openclaw/credentials/apns/AuthKey_
|
||||
|
||||
不要提交 `.p8` 文件,也不要将其放在仓库检出目录下。
|
||||
|
||||
## 发现路径
|
||||
## 设备发现路径
|
||||
|
||||
### Bonjour(LAN)
|
||||
|
||||
iOS 应用会在 `local.` 上浏览 `_openclaw-gw._tcp`,并在已配置时浏览相同的广域 DNS-SD 发现域。同一 LAN 上的 Gateway 网关会自动从 `local.` 出现;跨网络发现则可使用已配置的广域域名,而无需改变信标类型。
|
||||
iOS 应用会在 `local.` 上浏览 `_openclaw-gw._tcp`,并且在已配置时,也会浏览相同的
|
||||
广域 DNS-SD 设备发现域。同一 LAN 上的 Gateway 网关会通过 `local.` 自动出现;
|
||||
跨网络设备发现可以使用已配置的广域域名,而无需更改 beacon 类型。
|
||||
|
||||
### Tailnet(跨网络)
|
||||
|
||||
如果 mDNS 被阻止,请使用一个单播 DNS-SD 区域(选择一个域名;示例:
|
||||
`openclaw.internal.`)和 Tailscale 拆分 DNS。
|
||||
如果 mDNS 被阻止,请使用单播 DNS-SD 区域(选择一个域名;示例:
|
||||
`openclaw.internal.`)以及 Tailscale split DNS。
|
||||
CoreDNS 示例请参见 [Bonjour](/zh-CN/gateway/bonjour)。
|
||||
|
||||
### 手动 host/port
|
||||
### 手动主机/端口
|
||||
|
||||
在“设置”中启用**手动主机**,并输入 Gateway 网关 host + port(默认 `18789`)。
|
||||
在“设置”中,启用**手动主机**并输入 Gateway 网关主机 + 端口(默认 `18789`)。
|
||||
|
||||
## Canvas + A2UI
|
||||
|
||||
@ -199,10 +227,10 @@ openclaw nodes invoke --node "iOS Node" --command canvas.navigate --params '{"ur
|
||||
|
||||
说明:
|
||||
|
||||
- Gateway 网关 canvas host 提供 `/__openclaw__/canvas/` 和 `/__openclaw__/a2ui/`。
|
||||
- 它由 Gateway 网关 HTTP 服务器提供(与 `gateway.port` 相同端口,默认 `18789`)。
|
||||
- 当广播了 canvas host URL 时,iOS 节点会在连接后自动导航到 A2UI。
|
||||
- 使用 `canvas.navigate` 和 `{"url":""}` 可返回内置脚手架。
|
||||
- Gateway 网关 canvas 主机会提供 `/__openclaw__/canvas/` 和 `/__openclaw__/a2ui/`。
|
||||
- 它由 Gateway 网关 HTTP 服务器提供(与 `gateway.port` 使用相同端口,默认 `18789`)。
|
||||
- 当广播了 canvas 主机 URL 时,iOS 节点会在连接时自动导航到 A2UI。
|
||||
- 使用 `canvas.navigate` 和 `{"url":""}` 返回内置 scaffold。
|
||||
|
||||
### Canvas eval / snapshot
|
||||
|
||||
@ -216,15 +244,15 @@ openclaw nodes invoke --node "iOS Node" --command canvas.snapshot --params '{"ma
|
||||
|
||||
## 语音唤醒 + Talk 模式
|
||||
|
||||
- 语音唤醒和 Talk 模式可在“设置”中使用。
|
||||
- iOS 可能会挂起后台音频;当应用不处于活动状态时,请将语音功能视为尽力而为。
|
||||
- 语音唤醒和 Talk 模式可在“设置”中启用。
|
||||
- iOS 可能会暂停后台音频;当应用未处于活动状态时,请将语音功能视为尽力而为。
|
||||
|
||||
## 常见错误
|
||||
|
||||
- `NODE_BACKGROUND_UNAVAILABLE`:将 iOS 应用切换到前台(canvas/相机/屏幕命令需要它)。
|
||||
- `A2UI_HOST_NOT_CONFIGURED`:Gateway 网关未广播 canvas host URL;请检查 [Gateway 网关配置](/zh-CN/gateway/configuration) 中的 `canvasHost`。
|
||||
- `A2UI_HOST_NOT_CONFIGURED`:Gateway 网关没有广播 canvas 主机 URL;请检查 [Gateway 网关配置](/zh-CN/gateway/configuration) 中的 `canvasHost`。
|
||||
- 配对提示始终不出现:运行 `openclaw devices list` 并手动批准。
|
||||
- 重装后重新连接失败:Keychain 配对 token 已被清除;请重新配对该节点。
|
||||
- 重新安装后重连失败:Keychain 配对令牌已被清除;请重新配对该节点。
|
||||
|
||||
## 相关文档
|
||||
|
||||
|
||||
@ -1,92 +1,80 @@
|
||||
---
|
||||
read_when:
|
||||
- 你想使用内置的 Codex app-server harness
|
||||
- 你需要 Codex harness 配置示例
|
||||
- 你希望仅使用 Codex 的部署在无法使用时直接失败,而不是回退到 PI
|
||||
summary: 通过内置的 Codex app-server harness 运行 OpenClaw 嵌入式智能体轮次
|
||||
- 你想使用内置的 Codex app-server harness。
|
||||
- 你需要 Codex harness 配置示例。
|
||||
- 你希望仅使用 Codex 的部署在无法使用时直接失败,而不是回退到 Pi。
|
||||
summary: 通过内置的 Codex app-server harness 运行 OpenClaw 内嵌智能体回合
|
||||
title: Codex harness
|
||||
x-i18n:
|
||||
generated_at: "2026-04-25T03:42:12Z"
|
||||
generated_at: "2026-04-25T05:55:05Z"
|
||||
model: gpt-5.4
|
||||
provider: openai
|
||||
source_hash: 67f1bc703e8e45c60f7062f00cd1d68fde146785db649709e9eddce48d0a9941
|
||||
source_hash: 5458c8501338361a001c3457235d2a9abfc7e24709f2e50185bc31b92bbadb3b
|
||||
source_path: plugins/codex-harness.md
|
||||
workflow: 15
|
||||
---
|
||||
|
||||
内置的 `codex` 插件让 OpenClaw 可以通过 Codex app-server 运行嵌入式智能体轮次,而不是使用内置的 PI harness。
|
||||
内置的 `codex` 插件可让 OpenClaw 通过 Codex app-server,而不是内置的 Pi harness,来运行内嵌智能体回合。
|
||||
|
||||
当你希望 Codex 接管底层智能体会话时,请使用它:模型发现、原生线程恢复、原生压缩以及 app-server 执行。OpenClaw 仍然负责聊天渠道、会话文件、模型选择、工具、批准、媒体传递,以及可见的转录镜像。
|
||||
当你希望 Codex 接管底层智能体会话时,请使用此方式:模型发现、原生线程恢复、原生压缩,以及 app-server 执行。OpenClaw 仍然负责聊天渠道、会话文件、模型选择、工具、审批、媒体传递,以及可见的转录镜像。
|
||||
|
||||
如果你正在了解整体结构,请先阅读 [Agent Runtimes](/zh-CN/concepts/agent-runtimes)。简短来说:
|
||||
`openai/gpt-5.5` 是模型引用,`codex` 是运行时,而 Telegram、
|
||||
Discord、Slack 或其他渠道仍然是通信界面。
|
||||
如果你正在建立整体认识,请先阅读 [Agent Runtimes](/zh-CN/concepts/agent-runtimes)。简而言之:
|
||||
`openai/gpt-5.5` 是模型引用,`codex` 是运行时,而 Telegram、Discord、Slack 或其他渠道仍然是通信界面。
|
||||
|
||||
原生 Codex 轮次会将 OpenClaw 插件钩子作为公共兼容层保留。
|
||||
这些是进程内的 OpenClaw 钩子,不是 Codex `hooks.json` 命令钩子:
|
||||
原生 Codex 回合会将 OpenClaw 插件钩子保留为公共兼容层。
|
||||
这些是 OpenClaw 进程内钩子,不是 Codex `hooks.json` 命令钩子:
|
||||
|
||||
- `before_prompt_build`
|
||||
- `before_compaction`, `after_compaction`
|
||||
- `llm_input`, `llm_output`
|
||||
- `before_tool_call`, `after_tool_call`
|
||||
- `before_message_write`,用于镜像转录记录
|
||||
- `before_compaction`、`after_compaction`
|
||||
- `llm_input`、`llm_output`
|
||||
- `before_tool_call`、`after_tool_call`
|
||||
- 用于镜像转录记录的 `before_message_write`
|
||||
- `agent_end`
|
||||
|
||||
插件还可以注册与运行时无关的工具结果中间件,在 OpenClaw 执行工具之后、结果返回给 Codex 之前,重写 OpenClaw 动态工具结果。这与公共
|
||||
`tool_result_persist` 插件钩子不同,后者会转换由 OpenClaw 持有的转录工具结果写入。
|
||||
插件还可以注册与运行时无关的工具结果中间件,在 OpenClaw 执行工具之后、结果返回给 Codex 之前,重写 OpenClaw 动态工具结果。这与公共 `tool_result_persist` 插件钩子不同,后者会转换由 OpenClaw 持有的转录工具结果写入。
|
||||
|
||||
关于插件钩子语义本身,请参阅 [Plugin hooks](/zh-CN/plugins/hooks)
|
||||
和 [Plugin guard behavior](/zh-CN/tools/plugin)。
|
||||
有关插件钩子语义本身,请参见 [插件钩子](/zh-CN/plugins/hooks)
|
||||
和 [插件保护行为](/zh-CN/tools/plugin)。
|
||||
|
||||
该 harness 默认关闭。新配置应保持 OpenAI 模型引用的规范形式为
|
||||
`openai/gpt-*`,并在需要原生 app-server 执行时显式强制设置
|
||||
`embeddedHarness.runtime: "codex"` 或 `OPENCLAW_AGENT_RUNTIME=codex`。
|
||||
为了兼容,旧版 `codex/*` 模型引用仍会自动选择该 harness,但由运行时支持的旧版提供商前缀不会显示为普通的模型/提供商选项。
|
||||
该 harness 默认关闭。新配置应保持 OpenAI 模型引用采用规范形式 `openai/gpt-*`,并在希望使用原生 app-server 执行时,显式强制设置 `embeddedHarness.runtime: "codex"` 或 `OPENCLAW_AGENT_RUNTIME=codex`。旧版 `codex/*` 模型引用仍会为了兼容性自动选择该 harness,但由运行时支持的旧版 provider 前缀不会显示为普通模型/提供商选项。
|
||||
|
||||
## 选择正确的模型前缀
|
||||
|
||||
OpenAI 系列路由对前缀很敏感。当你希望通过 PI 使用 Codex OAuth 时,请使用 `openai-codex/*`;当你希望直接使用 OpenAI API,或在强制使用原生 Codex app-server harness 时,请使用 `openai/*`:
|
||||
OpenAI 系列路由对前缀非常敏感。当你希望通过 Pi 使用 Codex OAuth 时,请使用 `openai-codex/*`;当你希望直接访问 OpenAI API,或者你正在强制使用原生 Codex app-server harness 时,请使用 `openai/*`:
|
||||
|
||||
| Model ref | Runtime path | Use when |
|
||||
| ----------------------------------------------------- | -------------------------------------------- | ------------------------------------------------------------------------- |
|
||||
| `openai/gpt-5.4` | OpenAI provider 通过 OpenClaw/PI 管线 | 你希望通过 `OPENAI_API_KEY` 使用当前的 OpenAI Platform API 直接访问。 |
|
||||
| `openai-codex/gpt-5.5` | OpenAI Codex OAuth 通过 OpenClaw/PI | 你希望使用默认 PI 运行器配合 ChatGPT/Codex 订阅认证。 |
|
||||
| `openai/gpt-5.5` + `embeddedHarness.runtime: "codex"` | Codex app-server harness | 你希望嵌入式智能体轮次使用原生 Codex app-server 执行。 |
|
||||
| 模型引用 | 运行时路径 | 使用场景 |
|
||||
| ----------------------------------------------------- | ---------------------------------------------- | ------------------------------------------------------------------------- |
|
||||
| `openai/gpt-5.4` | 通过 OpenClaw/Pi 管线路径的 OpenAI provider | 你希望通过 `OPENAI_API_KEY` 访问当前的 OpenAI Platform API。 |
|
||||
| `openai-codex/gpt-5.5` | 通过 OpenClaw/Pi 的 OpenAI Codex OAuth | 你希望使用默认 Pi 运行器搭配 ChatGPT/Codex 订阅身份验证。 |
|
||||
| `openai/gpt-5.5` + `embeddedHarness.runtime: "codex"` | Codex app-server harness | 你希望内嵌智能体回合通过原生 Codex app-server 执行。 |
|
||||
|
||||
在 OpenClaw 中,GPT-5.5 当前仅支持订阅/OAuth。PI OAuth 请使用
|
||||
`openai-codex/gpt-5.5`,或者在 Codex app-server harness 下使用
|
||||
`openai/gpt-5.5`。一旦 OpenAI 在公共 API 上启用 GPT-5.5,
|
||||
`openai/gpt-5.5` 的直接 API 密钥访问也会受到支持。
|
||||
目前在 OpenClaw 中,GPT-5.5 仅支持订阅/OAuth。对于 Pi OAuth,请使用 `openai-codex/gpt-5.5`;对于 Codex app-server harness,请使用 `openai/gpt-5.5`。一旦 OpenAI 在公共 API 上启用 GPT-5.5,`openai/gpt-5.5` 也将支持直接 API key 访问。
|
||||
|
||||
旧版 `codex/gpt-*` 引用仍然作为兼容别名被接受。Doctor
|
||||
兼容性迁移会将旧版主运行时引用重写为规范模型引用,并将运行时策略单独记录;而仅用于回退的旧版引用则保持不变,因为运行时是为整个智能体容器配置的。新的 PI Codex OAuth 配置应使用 `openai-codex/gpt-*`;新的原生
|
||||
app-server harness 配置应使用 `openai/gpt-*`,并配合
|
||||
旧版 `codex/gpt-*` 引用仍作为兼容别名被接受。Doctor 兼容迁移会将旧版主运行时引用重写为规范模型引用,并单独记录运行时策略;而仅作为回退的旧版引用则保持不变,因为运行时是针对整个智能体容器配置的。新的 Pi Codex OAuth 配置应使用 `openai-codex/gpt-*`;新的原生 app-server harness 配置应使用 `openai/gpt-*` 加上
|
||||
`embeddedHarness.runtime: "codex"`。
|
||||
|
||||
`agents.defaults.imageModel` 也遵循同样的前缀划分。当图像理解应通过 OpenAI Codex OAuth 提供商路径运行时,请使用
|
||||
`openai-codex/gpt-*`。当图像理解应通过受限的 Codex app-server 轮次运行时,请使用 `codex/gpt-*`。Codex app-server 模型必须声明支持图像输入;仅文本的 Codex 模型会在媒体轮次开始前失败。
|
||||
`agents.defaults.imageModel` 也遵循同样的前缀划分。若图像理解应通过 OpenAI Codex OAuth provider 路径运行,请使用 `openai-codex/gpt-*`。若图像理解应通过受限的 Codex app-server 回合运行,请使用 `codex/gpt-*`。Codex app-server 模型必须声明支持图像输入;仅文本的 Codex 模型会在媒体回合开始前失败。
|
||||
|
||||
使用 `/status` 来确认当前会话的实际 harness。如果结果出乎你的预期,请为 `agents/harness` 子系统启用调试日志,并检查 Gateway 网关 的结构化 `agent harness selected` 记录。它包含已选择的 harness id、选择原因、运行时/回退策略,以及在 `auto` 模式下每个插件候选项的支持结果。
|
||||
使用 `/status` 可确认当前会话的实际 harness。如果选择结果出乎意料,请为 `agents/harness` 子系统启用调试日志,并检查网关的结构化 `agent harness selected` 记录。它包含所选 harness id、选择原因、运行时/回退策略,以及在 `auto` 模式下每个插件候选项的支持结果。
|
||||
|
||||
Harness 选择不是实时会话控制。当嵌入式轮次运行时,OpenClaw 会在该会话上记录选中的 harness id,并在同一会话 id 的后续轮次中继续使用它。当你希望未来的会话使用其他 harness 时,请更改 `embeddedHarness` 配置或
|
||||
`OPENCLAW_AGENT_RUNTIME`;在将现有对话从 PI 切换到 Codex 之前,请使用 `/new` 或 `/reset` 启动一个全新的会话。这样可以避免同一份转录通过两个不兼容的原生会话系统重放。
|
||||
Harness 选择不是实时会话控制。当某个内嵌回合运行时,OpenClaw 会将所选 harness id 记录到该会话中,并在同一会话 id 的后续回合中继续使用它。当你希望未来会话使用其他 harness 时,请更改 `embeddedHarness` 配置或 `OPENCLAW_AGENT_RUNTIME`;在将现有对话从 Pi 切换到 Codex 之前,请使用 `/new` 或 `/reset` 启动新会话。这样可避免通过两个不兼容的原生会话系统重放同一份转录。
|
||||
|
||||
在引入 harness 固定之前创建的旧会话,只要已有转录历史,就会被视为固定到 PI。更改配置后,使用 `/new` 或 `/reset` 才能让该对话切换到 Codex。
|
||||
在 harness 固定机制出现之前创建的旧会话,一旦已有转录历史,就会被视为固定到 Pi。更改配置后,如需让该对话切换到 Codex,请使用 `/new` 或 `/reset`。
|
||||
|
||||
`/status` 会显示实际的模型运行时。默认的 PI harness 显示为
|
||||
`/status` 会显示实际模型运行时。默认 Pi harness 显示为
|
||||
`Runtime: OpenClaw Pi Default`,而 Codex app-server harness 显示为
|
||||
`Runtime: OpenAI Codex`。
|
||||
|
||||
## 要求
|
||||
|
||||
- OpenClaw,且内置的 `codex` 插件可用。
|
||||
- OpenClaw,且内置 `codex` 插件可用。
|
||||
- Codex app-server `0.118.0` 或更高版本。
|
||||
- app-server 进程可用的 Codex 认证。
|
||||
- app-server 进程可用的 Codex 身份验证。
|
||||
|
||||
该插件会阻止较旧版本或无版本的 app-server 握手。这可确保
|
||||
OpenClaw 始终运行在已测试过的协议接口上。
|
||||
该插件会阻止较旧或未标明版本的 app-server 握手。这样可确保
|
||||
OpenClaw 仅运行在它已测试过的协议接口上。
|
||||
|
||||
对于实时和 Docker 冒烟测试,认证通常来自 `OPENAI_API_KEY`,以及可选的 Codex CLI 文件,例如 `~/.codex/auth.json` 和
|
||||
对于实时和 Docker 冒烟测试,身份验证通常来自 `OPENAI_API_KEY`,以及可选的 Codex CLI 文件,例如 `~/.codex/auth.json` 和
|
||||
`~/.codex/config.toml`。请使用与你本地 Codex app-server 相同的认证材料。
|
||||
|
||||
## 最小配置
|
||||
@ -128,21 +116,19 @@ OpenClaw 始终运行在已测试过的协议接口上。
|
||||
}
|
||||
```
|
||||
|
||||
如果旧配置将 `agents.defaults.model` 或某个智能体模型设置为
|
||||
`codex/<model>`,仍会自动启用内置的 `codex` 插件。新配置应优先使用
|
||||
`openai/<model>`,并配合上面显式的 `embeddedHarness` 条目。
|
||||
仍将 `agents.defaults.model` 或某个智能体模型设置为 `codex/<model>` 的旧配置,依然会自动启用内置 `codex` 插件。新配置应优先使用 `openai/<model>` 加上上面的显式 `embeddedHarness` 条目。
|
||||
|
||||
## 将 Codex 与其他模型一起使用
|
||||
|
||||
如果同一个智能体需要在 Codex 和非 Codex 提供商模型之间自由切换,请不要全局设置 `runtime: "codex"`。强制运行时会应用到该智能体或会话的每一个嵌入式轮次。如果你在该运行时被强制时选择了 Anthropic 模型,OpenClaw 仍会尝试 Codex harness,并以失败关闭,而不会悄悄通过 PI 路由该轮次。
|
||||
如果同一个智能体需要在 Codex 和非 Codex provider 模型之间自由切换,请不要全局设置 `runtime: "codex"`。强制运行时会应用到该智能体或会话的每个内嵌回合。如果在运行时被强制时选择了 Anthropic 模型,OpenClaw 仍会尝试 Codex harness,并以失败关闭,而不是悄悄通过 Pi 路由该回合。
|
||||
|
||||
请改用以下其中一种形式:
|
||||
请改用以下结构之一:
|
||||
|
||||
- 将 Codex 放在一个专用智能体上,并设置 `embeddedHarness.runtime: "codex"`。
|
||||
- 将默认智能体保持为 `runtime: "auto"` 并使用 PI 回退,以满足普通的混合提供商使用场景。
|
||||
- 仅为兼容性使用旧版 `codex/*` 引用。新配置应优先使用 `openai/*` 并配合显式的 Codex 运行时策略。
|
||||
- 将 Codex 放到一个专用智能体上,并设置 `embeddedHarness.runtime: "codex"`。
|
||||
- 让默认智能体保持 `runtime: "auto"`,并使用 Pi 回退,以支持普通的混合 provider 使用场景。
|
||||
- 仅将旧版 `codex/*` 引用用于兼容性。新配置应优先使用 `openai/*` 加显式 Codex 运行时策略。
|
||||
|
||||
例如,下面的配置会让默认智能体保持常规自动选择,并新增一个单独的 Codex 智能体:
|
||||
例如,下面的配置让默认智能体保持正常自动选择,同时添加一个单独的 Codex 智能体:
|
||||
|
||||
```json5
|
||||
{
|
||||
@ -179,16 +165,15 @@ OpenClaw 始终运行在已测试过的协议接口上。
|
||||
}
|
||||
```
|
||||
|
||||
采用这种形式时:
|
||||
采用这种结构时:
|
||||
|
||||
- 默认的 `main` 智能体使用常规提供商路径和 PI 兼容回退。
|
||||
- 默认的 `main` 智能体使用普通 provider 路径和 Pi 兼容回退。
|
||||
- `codex` 智能体使用 Codex app-server harness。
|
||||
- 如果 `codex` 智能体缺少 Codex 或不受支持,该轮次会失败,而不是悄悄使用 PI。
|
||||
- 如果对于 `codex` 智能体来说,Codex 缺失或不受支持,则该回合会失败,而不是悄悄改用 Pi。
|
||||
|
||||
## 仅 Codex 部署
|
||||
|
||||
当你需要证明每一个嵌入式智能体轮次都使用 Codex 时,请强制使用 Codex harness。显式插件运行时默认不会回退到 PI,因此
|
||||
`fallback: "none"` 是可选的,但通常作为文档说明很有用:
|
||||
当你需要证明每个内嵌智能体回合都使用 Codex 时,请强制使用 Codex harness。显式插件运行时默认不使用 Pi 回退,因此 `fallback: "none"` 是可选的,但通常有助于作为文档说明:
|
||||
|
||||
```json5
|
||||
{
|
||||
@ -204,18 +189,18 @@ OpenClaw 始终运行在已测试过的协议接口上。
|
||||
}
|
||||
```
|
||||
|
||||
环境覆盖:
|
||||
环境变量覆盖:
|
||||
|
||||
```bash
|
||||
OPENCLAW_AGENT_RUNTIME=codex openclaw gateway run
|
||||
```
|
||||
|
||||
在强制使用 Codex 的情况下,如果 Codex 插件被禁用、app-server 版本过旧,或 app-server 无法启动,OpenClaw 会尽早失败。只有当你明确希望缺失的 harness 选择由 PI 处理时,才设置
|
||||
强制使用 Codex 时,如果 Codex 插件被禁用、app-server 版本过旧,或者 app-server 无法启动,OpenClaw 会尽早失败。仅当你明确希望缺失 harness 选择时由 Pi 接管,才设置
|
||||
`OPENCLAW_AGENT_HARNESS_FALLBACK=pi`。
|
||||
|
||||
## 按智能体配置 Codex
|
||||
## 按智能体使用 Codex
|
||||
|
||||
你可以让某一个智能体仅使用 Codex,而默认智能体仍保留正常的自动选择:
|
||||
你可以让某一个智能体仅使用 Codex,而默认智能体保持正常自动选择:
|
||||
|
||||
```json5
|
||||
{
|
||||
@ -246,12 +231,11 @@ OPENCLAW_AGENT_RUNTIME=codex openclaw gateway run
|
||||
}
|
||||
```
|
||||
|
||||
使用普通会话命令来切换智能体和模型。`/new` 会创建一个新的
|
||||
OpenClaw 会话,而 Codex harness 会根据需要创建或恢复其 sidecar app-server 线程。`/reset` 会清除该线程的 OpenClaw 会话绑定,并让下一轮再次根据当前配置解析 harness。
|
||||
使用普通会话命令来切换智能体和模型。`/new` 会创建一个新的 OpenClaw 会话,而 Codex harness 会按需创建或恢复其 sidecar app-server 线程。`/reset` 会清除该线程的 OpenClaw 会话绑定,并让下一回合根据当前配置重新解析 harness。
|
||||
|
||||
## 模型发现
|
||||
|
||||
默认情况下,Codex 插件会向 app-server 查询可用模型。如果发现失败或超时,它会使用内置的回退目录,其中包括:
|
||||
默认情况下,Codex 插件会向 app-server 请求可用模型。如果发现失败或超时,它会使用内置回退目录,其中包含:
|
||||
|
||||
- GPT-5.5
|
||||
- GPT-5.4 mini
|
||||
@ -296,9 +280,9 @@ OpenClaw 会话,而 Codex harness 会根据需要创建或恢复其 sidecar ap
|
||||
}
|
||||
```
|
||||
|
||||
## App-server 连接和策略
|
||||
## App-server 连接与策略
|
||||
|
||||
默认情况下,插件会用以下命令在本地启动 Codex:
|
||||
默认情况下,插件会通过以下方式在本地启动 Codex:
|
||||
|
||||
```bash
|
||||
codex app-server --listen stdio://
|
||||
@ -306,9 +290,9 @@ codex app-server --listen stdio://
|
||||
|
||||
默认情况下,OpenClaw 会以 YOLO 模式启动本地 Codex harness 会话:
|
||||
`approvalPolicy: "never"`、`approvalsReviewer: "user"`,以及
|
||||
`sandbox: "danger-full-access"`。这是用于自主心跳的受信本地操作员姿态:Codex 可以使用 shell 和网络工具,而不会停在无人响应的原生批准提示上。
|
||||
`sandbox: "danger-full-access"`。这是可信本地操作员姿态,也用于自治心跳:Codex 可以使用 shell 和网络工具,而不会卡在无人响应的原生审批提示上。
|
||||
|
||||
若要选择使用由 Codex guardian 审核的批准,请设置 `appServer.mode:
|
||||
若要启用由 Codex guardian 审核的审批,请设置 `appServer.mode:
|
||||
"guardian"`:
|
||||
|
||||
```json5
|
||||
@ -329,14 +313,13 @@ codex app-server --listen stdio://
|
||||
}
|
||||
```
|
||||
|
||||
Guardian 模式使用 Codex 的原生自动审核批准路径。当 Codex 请求离开沙箱、在工作区外写入,或添加网络访问等权限时,Codex 会将该批准请求路由给原生审核器,而不是人工提示。审核器会应用 Codex 的风险框架,并批准或拒绝该具体请求。当你希望比 YOLO 模式有更多保护措施,但仍需要无人值守的智能体持续推进时,请使用 Guardian。
|
||||
Guardian 模式会使用 Codex 的原生自动审核审批路径。当 Codex 请求离开沙箱、在工作区之外写入,或添加诸如网络访问之类的权限时,Codex 会将该审批请求路由给原生审核器,而不是向人工发出提示。审核器会应用 Codex 的风险框架,并批准或拒绝具体请求。如果你希望比 YOLO 模式拥有更多防护措施,但仍需要无人值守的智能体持续推进,请使用 Guardian。
|
||||
|
||||
`guardian` 预设会展开为 `approvalPolicy: "on-request"`、
|
||||
`approvalsReviewer: "auto_review"` 和 `sandbox: "workspace-write"`。
|
||||
各个策略字段仍然会覆盖 `mode`,因此高级部署可以将该预设与显式选择混合使用。较旧的 `guardian_subagent` 审核器值仍然作为兼容别名被接受,但新配置应使用
|
||||
`auto_review`。
|
||||
单独的策略字段仍会覆盖 `mode`,因此高级部署可以将该预设与显式选项混合使用。较旧的 `guardian_subagent` 审核器值仍作为兼容别名被接受,但新配置应使用 `auto_review`。
|
||||
|
||||
对于已经在运行的 app-server,请使用 WebSocket 传输:
|
||||
对于已经运行中的 app-server,请使用 WebSocket 传输:
|
||||
|
||||
```json5
|
||||
{
|
||||
@ -360,22 +343,22 @@ Guardian 模式使用 Codex 的原生自动审核批准路径。当 Codex 请求
|
||||
|
||||
支持的 `appServer` 字段:
|
||||
|
||||
| Field | Default | Meaning |
|
||||
| ------------------- | ---------------------------------------- | ------------------------------------------------------------------------------------------------------------ |
|
||||
| `transport` | `"stdio"` | `"stdio"` 会生成 Codex;`"websocket"` 会连接到 `url`。 |
|
||||
| `command` | `"codex"` | 用于 stdio 传输的可执行文件。 |
|
||||
| `args` | `["app-server", "--listen", "stdio://"]` | 用于 stdio 传输的参数。 |
|
||||
| `url` | unset | WebSocket app-server URL。 |
|
||||
| `authToken` | unset | 用于 WebSocket 传输的 Bearer token。 |
|
||||
| `headers` | `{}` | 额外的 WebSocket 标头。 |
|
||||
| `requestTimeoutMs` | `60000` | app-server 控制平面调用的超时时间。 |
|
||||
| `mode` | `"yolo"` | 用于 YOLO 或 guardian 审核执行的预设。 |
|
||||
| `approvalPolicy` | `"never"` | 发送到线程启动/恢复/轮次的原生 Codex 批准策略。 |
|
||||
| `sandbox` | `"danger-full-access"` | 发送到线程启动/恢复的原生 Codex 沙箱模式。 |
|
||||
| `approvalsReviewer` | `"user"` | 使用 `"auto_review"` 让 Codex 审核原生批准提示。`guardian_subagent` 仍然是旧版别名。 |
|
||||
| `serviceTier` | unset | 可选的 Codex app-server 服务层级:`"fast"`、`"flex"` 或 `null`。无效的旧版值会被忽略。 |
|
||||
| 字段 | 默认值 | 含义 |
|
||||
| ------------------- | ---------------------------------------- | --------------------------------------------------------------------------------------------------------- |
|
||||
| `transport` | `"stdio"` | `"stdio"` 会启动 Codex;`"websocket"` 会连接到 `url`。 |
|
||||
| `command` | `"codex"` | 用于 stdio 传输的可执行文件。 |
|
||||
| `args` | `["app-server", "--listen", "stdio://"]` | 用于 stdio 传输的参数。 |
|
||||
| `url` | 未设置 | WebSocket app-server URL。 |
|
||||
| `authToken` | 未设置 | 用于 WebSocket 传输的 Bearer token。 |
|
||||
| `headers` | `{}` | 额外的 WebSocket 请求头。 |
|
||||
| `requestTimeoutMs` | `60000` | app-server 控制平面调用的超时时间。 |
|
||||
| `mode` | `"yolo"` | 用于 YOLO 或 guardian 审核执行的预设。 |
|
||||
| `approvalPolicy` | `"never"` | 发送到线程启动/恢复/回合的原生 Codex 审批策略。 |
|
||||
| `sandbox` | `"danger-full-access"` | 发送到线程启动/恢复的原生 Codex 沙箱模式。 |
|
||||
| `approvalsReviewer` | `"user"` | 使用 `"auto_review"` 让 Codex 审核原生审批提示。`guardian_subagent` 仍保留为旧版别名。 |
|
||||
| `serviceTier` | 未设置 | 可选的 Codex app-server 服务层级:`"fast"`、`"flex"` 或 `null`。无效的旧版值会被忽略。 |
|
||||
|
||||
当对应的配置字段未设置时,较旧的环境变量仍可作为本地测试的回退方案使用:
|
||||
较旧的环境变量在对应配置字段未设置时,仍可作为本地测试的回退方案:
|
||||
|
||||
- `OPENCLAW_CODEX_APP_SERVER_BIN`
|
||||
- `OPENCLAW_CODEX_APP_SERVER_ARGS`
|
||||
@ -384,9 +367,10 @@ Guardian 模式使用 Codex 的原生自动审核批准路径。当 Codex 请求
|
||||
- `OPENCLAW_CODEX_APP_SERVER_SANDBOX`
|
||||
|
||||
`OPENCLAW_CODEX_APP_SERVER_GUARDIAN=1` 已被移除。请改用
|
||||
`plugins.entries.codex.config.appServer.mode: "guardian"`,或者在一次性本地测试中使用 `OPENCLAW_CODEX_APP_SERVER_MODE=guardian`。对于可重复的部署,更推荐使用配置,因为它能将插件行为与 Codex harness 其余设置保存在同一个经过审查的文件中。
|
||||
`plugins.entries.codex.config.appServer.mode: "guardian"`,或在一次性本地测试中使用
|
||||
`OPENCLAW_CODEX_APP_SERVER_MODE=guardian`。对于可重复部署,更推荐使用配置,因为这样能将插件行为与 Codex harness 其余设置保存在同一个经过审查的文件中。
|
||||
|
||||
## 常见配方
|
||||
## 常用方案
|
||||
|
||||
使用默认 stdio 传输的本地 Codex:
|
||||
|
||||
@ -402,7 +386,7 @@ Guardian 模式使用 Codex 的原生自动审核批准路径。当 Codex 请求
|
||||
}
|
||||
```
|
||||
|
||||
仅 Codex harness 验证:
|
||||
仅使用 Codex 的 harness 验证:
|
||||
|
||||
```json5
|
||||
{
|
||||
@ -424,7 +408,7 @@ Guardian 模式使用 Codex 的原生自动审核批准路径。当 Codex 请求
|
||||
}
|
||||
```
|
||||
|
||||
由 guardian 审核的 Codex 批准:
|
||||
由 Guardian 审核的 Codex 审批:
|
||||
|
||||
```json5
|
||||
{
|
||||
@ -446,7 +430,7 @@ Guardian 模式使用 Codex 的原生自动审核批准路径。当 Codex 请求
|
||||
}
|
||||
```
|
||||
|
||||
带显式标头的远程 app-server:
|
||||
带显式请求头的远程 app-server:
|
||||
|
||||
```json5
|
||||
{
|
||||
@ -469,131 +453,126 @@ Guardian 模式使用 Codex 的原生自动审核批准路径。当 Codex 请求
|
||||
}
|
||||
```
|
||||
|
||||
模型切换仍由 OpenClaw 控制。当一个 OpenClaw 会话附加到现有的 Codex 线程时,下一轮会再次将当前选择的
|
||||
OpenAI 模型、提供商、批准策略、沙箱和服务层级发送到
|
||||
app-server。从 `openai/gpt-5.5` 切换到 `openai/gpt-5.2` 会保留线程绑定,但会要求 Codex 使用新选择的模型继续运行。
|
||||
模型切换仍由 OpenClaw 控制。当某个 OpenClaw 会话附加到现有 Codex 线程时,下一回合会再次将当前选定的 OpenAI 模型、provider、审批策略、沙箱和服务层级发送到 app-server。从 `openai/gpt-5.5` 切换到 `openai/gpt-5.2` 会保留线程绑定,但会要求 Codex 继续使用新选择的模型。
|
||||
|
||||
## Codex 命令
|
||||
|
||||
内置插件将 `/codex` 注册为已授权的斜杠命令。它是通用的,适用于任何支持 OpenClaw 文本命令的渠道。
|
||||
内置插件将 `/codex` 注册为授权的斜杠命令。它是通用命令,可在任何支持 OpenClaw 文本命令的渠道上使用。
|
||||
|
||||
常见形式:
|
||||
|
||||
- `/codex status` 显示实时 app-server 连接状态、模型、账户、速率限制、MCP 服务器和 Skills。
|
||||
- `/codex models` 列出实时 Codex app-server 模型。
|
||||
- `/codex threads [filter]` 列出最近的 Codex 线程。
|
||||
- `/codex resume <thread-id>` 将当前 OpenClaw 会话附加到现有的 Codex 线程。
|
||||
- `/codex resume <thread-id>` 将当前 OpenClaw 会话附加到现有 Codex 线程。
|
||||
- `/codex compact` 请求 Codex app-server 压缩已附加的线程。
|
||||
- `/codex review` 为已附加的线程启动 Codex 原生审查。
|
||||
- `/codex review` 为已附加线程启动 Codex 原生审核。
|
||||
- `/codex account` 显示账户和速率限制状态。
|
||||
- `/codex mcp` 列出 Codex app-server MCP 服务器状态。
|
||||
- `/codex skills` 列出 Codex app-server Skills。
|
||||
|
||||
`/codex resume` 会写入与 harness 用于普通轮次相同的 sidecar 绑定文件。在下一条消息中,OpenClaw 会恢复该 Codex 线程,将当前选定的 OpenClaw 模型传入 app-server,并保持扩展历史记录处于启用状态。
|
||||
`/codex resume` 会写入与 harness 在普通回合中使用的同一个 sidecar 绑定文件。在下一条消息中,OpenClaw 会恢复该 Codex 线程,将当前选定的 OpenClaw 模型传入 app-server,并保持启用扩展历史记录。
|
||||
|
||||
该命令接口要求 Codex app-server `0.118.0` 或更高版本。如果未来版本或自定义的 app-server 未暴露对应的 JSON-RPC 方法,各个控制方法会显示为 `unsupported by this Codex app-server`。
|
||||
该命令面要求 Codex app-server `0.118.0` 或更高版本。如果未来版本或自定义 app-server 未暴露某个 JSON-RPC 方法,各个控制方法将显示为 `unsupported by this Codex app-server`。
|
||||
|
||||
## 钩子边界
|
||||
|
||||
Codex harness 有三层钩子:
|
||||
|
||||
| Layer | Owner | Purpose |
|
||||
| 层级 | 所有者 | 目的 |
|
||||
| ------------------------------------- | ------------------------ | ------------------------------------------------------------------- |
|
||||
| OpenClaw plugin hooks | OpenClaw | 在 PI 和 Codex harness 之间提供产品/插件兼容性。 |
|
||||
| Codex app-server extension middleware | OpenClaw bundled plugins | 围绕 OpenClaw 动态工具的每轮适配器行为。 |
|
||||
| Codex native hooks | Codex | 来自 Codex 配置的底层 Codex 生命周期和原生工具策略。 |
|
||||
| OpenClaw 插件钩子 | OpenClaw | 在 Pi 和 Codex harness 之间提供产品/插件兼容性。 |
|
||||
| Codex app-server 扩展中间件 | OpenClaw 内置插件 | 围绕 OpenClaw 动态工具的逐回合适配器行为。 |
|
||||
| Codex 原生钩子 | Codex | 来自 Codex 配置的底层 Codex 生命周期和原生工具策略。 |
|
||||
|
||||
OpenClaw 不会使用项目级或全局的 Codex `hooks.json` 文件来路由
|
||||
OpenClaw 插件行为。对于受支持的原生工具和权限桥接,OpenClaw 会为每个线程注入 Codex 配置,用于 `PreToolUse`、`PostToolUse` 和
|
||||
`PermissionRequest`。其他 Codex 钩子,例如 `SessionStart`、
|
||||
`UserPromptSubmit` 和 `Stop`,仍然属于 Codex 级控制;在 v1 合约中,它们不会作为 OpenClaw 插件钩子暴露。
|
||||
OpenClaw 不会使用项目级或全局 Codex `hooks.json` 文件来路由 OpenClaw 插件行为。对于受支持的原生工具和权限桥接,OpenClaw 会为每个线程注入 Codex 配置,以支持 `PreToolUse`、`PostToolUse` 和 `PermissionRequest`。其他 Codex 钩子,例如 `SessionStart`、
|
||||
`UserPromptSubmit` 和 `Stop`,仍属于 Codex 级控制;它们在 v1 合约中不会作为 OpenClaw 插件钩子暴露。
|
||||
|
||||
对于 OpenClaw 动态工具,Codex 发出调用请求后,由 OpenClaw 执行该工具,因此 OpenClaw 会在 harness 适配器中触发其拥有的插件和中间件行为。对于 Codex 原生工具,Codex 持有规范工具记录。OpenClaw 可以镜像选定事件,但无法重写原生 Codex 线程,除非 Codex 通过 app-server 或原生钩子回调暴露该操作。
|
||||
对于 OpenClaw 动态工具,Codex 请求调用后由 OpenClaw 执行该工具,因此 OpenClaw 会在 harness 适配器中触发其拥有的插件和中间件行为。对于 Codex 原生工具,Codex 持有规范的工具记录。OpenClaw 可以镜像选定事件,但除非 Codex 通过 app-server 或原生钩子回调暴露该操作,否则无法重写原生 Codex 线程。
|
||||
|
||||
压缩和 LLM 生命周期投影来自 Codex app-server 通知以及 OpenClaw 适配器状态,而不是原生 Codex 钩子命令。OpenClaw 的
|
||||
`before_compaction`、`after_compaction`、`llm_input` 和
|
||||
`llm_output` 事件属于适配器级观察结果,而不是对 Codex 内部请求或压缩负载的逐字节捕获。
|
||||
压缩和 LLM 生命周期投影来自 Codex app-server 通知和 OpenClaw 适配器状态,而不是原生 Codex 钩子命令。OpenClaw 的 `before_compaction`、`after_compaction`、`llm_input` 和
|
||||
`llm_output` 事件属于适配器级观察结果,并不是对 Codex 内部请求或压缩载荷的逐字节捕获。
|
||||
|
||||
Codex 原生 `hook/started` 和 `hook/completed` app-server 通知会被投影为 `codex_app_server.hook` 智能体事件,用于轨迹记录和调试。它们不会调用 OpenClaw 插件钩子。
|
||||
Codex 原生 `hook/started` 和 `hook/completed` app-server 通知会被投影为用于轨迹和调试的 `codex_app_server.hook` 智能体事件。它们不会调用 OpenClaw 插件钩子。
|
||||
|
||||
## V1 支持合约
|
||||
|
||||
Codex 模式并不是在底层换了一个模型调用的 PI。Codex 拥有更多原生模型循环的控制权,而 OpenClaw 会围绕这一边界适配它的插件和会话接口。
|
||||
Codex 模式并不是仅仅把底层模型调用换成另一个模型的 Pi。Codex 拥有更多原生模型循环的控制权,而 OpenClaw 会围绕该边界适配其插件和会话界面。
|
||||
|
||||
Codex 运行时 v1 中支持的内容:
|
||||
Codex 运行时 v1 中受支持的内容:
|
||||
|
||||
| Surface | Support | Why |
|
||||
| --------------------------------------- | --------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------ |
|
||||
| 通过 Codex 的 OpenAI 模型循环 | 支持 | Codex app-server 负责 OpenAI 轮次、原生线程恢复以及原生工具续接。 |
|
||||
| OpenClaw 渠道路由和交付 | 支持 | Telegram、Discord、Slack、WhatsApp、iMessage 以及其他渠道仍然位于模型运行时之外。 |
|
||||
| OpenClaw 动态工具 | 支持 | Codex 会请求 OpenClaw 执行这些工具,因此 OpenClaw 仍在执行路径中。 |
|
||||
| 提示词和上下文插件 | 支持 | OpenClaw 会在启动或恢复线程之前构建提示词覆盖层,并将上下文投影到 Codex 轮次中。 |
|
||||
| 上下文引擎生命周期 | 支持 | 组装、摄取或轮次后的维护,以及上下文引擎压缩协调,都会为 Codex 轮次运行。 |
|
||||
| 动态工具钩子 | 支持 | `before_tool_call`、`after_tool_call` 和工具结果中间件会围绕由 OpenClaw 持有的动态工具运行。 |
|
||||
| 生命周期钩子 | 作为适配器观察结果受到支持 | `llm_input`、`llm_output`、`agent_end`、`before_compaction` 和 `after_compaction` 会使用真实的 Codex 模式负载触发。 |
|
||||
| 原生 shell 和 patch 的阻止或观察 | 通过原生钩子中继支持 | 对已提交的原生工具接口,`PreToolUse` 和 `PostToolUse` 会被中继。支持阻止,不支持参数重写。 |
|
||||
| 原生权限策略 | 通过原生钩子中继支持 | 在运行时暴露该能力的情况下,Codex `PermissionRequest` 可以通过 OpenClaw 策略进行路由。 |
|
||||
| app-server 轨迹捕获 | 支持 | OpenClaw 会记录它发送给 app-server 的请求以及接收到的 app-server 通知。 |
|
||||
| 界面 | 支持情况 | 原因 |
|
||||
| ------------------------------------- | ------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------ |
|
||||
| 通过 Codex 的 OpenAI 模型循环 | 支持 | Codex app-server 负责 OpenAI 回合、原生线程恢复和原生工具续接。 |
|
||||
| OpenClaw 渠道路由和传递 | 支持 | Telegram、Discord、Slack、WhatsApp、iMessage 和其他渠道仍位于模型运行时之外。 |
|
||||
| OpenClaw 动态工具 | 支持 | Codex 会请求 OpenClaw 执行这些工具,因此 OpenClaw 仍处于执行路径中。 |
|
||||
| 提示词和上下文插件 | 支持 | OpenClaw 会在启动或恢复线程前构建提示词叠层,并将上下文投影到 Codex 回合中。 |
|
||||
| 上下文引擎生命周期 | 支持 | 装配、摄取或回合后维护,以及上下文引擎压缩协调,都会在 Codex 回合中运行。 |
|
||||
| 动态工具钩子 | 支持 | `before_tool_call`、`after_tool_call` 和工具结果中间件会围绕由 OpenClaw 持有的动态工具运行。 |
|
||||
| 生命周期钩子 | 以适配器观察形式支持 | `llm_input`、`llm_output`、`agent_end`、`before_compaction` 和 `after_compaction` 会以真实的 Codex 模式载荷触发。 |
|
||||
| 原生 shell 和 patch 的阻止或观察 | 通过原生钩子中继支持 | 已提交的原生工具界面会中继 Codex `PreToolUse` 和 `PostToolUse`。支持阻止,但不支持参数重写。 |
|
||||
| 原生权限策略 | 通过原生钩子中继支持 | 在运行时暴露该能力的情况下,Codex `PermissionRequest` 可通过 OpenClaw 策略进行路由。 |
|
||||
| App-server 轨迹捕获 | 支持 | OpenClaw 会记录它发送给 app-server 的请求,以及它从 app-server 接收到的通知。 |
|
||||
|
||||
Codex 运行时 v1 中不支持的内容:
|
||||
|
||||
| Surface | V1 边界 | 未来路径 |
|
||||
| --------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------- |
|
||||
| 原生工具参数变更 | Codex 原生 pre-tool 钩子可以阻止调用,但 OpenClaw 不会重写 Codex 原生工具参数。 | 需要 Codex 钩子/模式支持替换工具输入。 |
|
||||
| 可编辑的 Codex 原生转录历史 | Codex 持有规范的原生线程历史。OpenClaw 持有一个镜像,并可以投影未来上下文,但不应修改不受支持的内部实现。 | 如果需要原生线程修补,则添加显式的 Codex app-server API。 |
|
||||
| 用于 Codex 原生工具记录的 `tool_result_persist` | 该钩子转换的是由 OpenClaw 持有的转录写入,而不是 Codex 原生工具记录。 | 可以镜像经过转换的记录,但规范重写需要 Codex 支持。 |
|
||||
| 丰富的原生压缩元数据 | OpenClaw 能观察到压缩开始和完成,但不会收到稳定的保留/丢弃列表、token 增量或摘要负载。 | 需要更丰富的 Codex 压缩事件。 |
|
||||
| 压缩干预 | 在 Codex 模式下,当前的 OpenClaw 压缩钩子处于通知级别。 | 如果插件需要否决或重写原生压缩,则添加 Codex 压缩前/后钩子。 |
|
||||
| 停止或最终答案门控 | Codex 具有原生停止钩子,但 OpenClaw 不会将最终答案门控作为 v1 插件合约公开。 | 未来可以提供带有循环和超时保护的可选原语。 |
|
||||
| 作为已承诺 v1 接口的原生 MCP 钩子对等能力 | 该中继是通用的,但 OpenClaw 尚未对原生 MCP 前/后钩子行为进行版本门控并完成端到端测试。 | 一旦受支持的 app-server 协议下限覆盖这些负载,就添加 OpenClaw MCP 中继测试和文档。 |
|
||||
| 逐字节模型 API 请求捕获 | OpenClaw 可以捕获 app-server 请求和通知,但 Codex 核心会在内部构建最终的 OpenAI API 请求。 | 需要 Codex 模型请求跟踪事件或调试 API。 |
|
||||
| 界面 | V1 边界 | 未来路径 |
|
||||
| --------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------- |
|
||||
| 原生工具参数变更 | Codex 原生 pre-tool 钩子可以阻止调用,但 OpenClaw 不会重写 Codex 原生工具参数。 | 需要 Codex 钩子/schema 支持替换后的工具输入。 |
|
||||
| 可编辑的 Codex 原生转录历史 | Codex 持有规范的原生线程历史。OpenClaw 持有镜像并可以投影未来上下文,但不应修改不受支持的内部实现。 | 如果需要原生线程手术能力,需要添加显式的 Codex app-server API。 |
|
||||
| 面向 Codex 原生工具记录的 `tool_result_persist` | 该钩子会转换由 OpenClaw 持有的转录写入,而不是 Codex 原生工具记录。 | 可以镜像转换后的记录,但规范性重写仍需要 Codex 支持。 |
|
||||
| 丰富的原生压缩元数据 | OpenClaw 可以观察压缩开始和完成,但不会接收到稳定的保留/丢弃列表、token 增量或摘要载荷。 | 需要更丰富的 Codex 压缩事件。 |
|
||||
| 压缩干预 | 当前在 Codex 模式下,OpenClaw 的压缩钩子仅处于通知级别。 | 如果插件需要否决或重写原生压缩,则需添加 Codex pre/post compaction 钩子。 |
|
||||
| 停止或最终答案门控 | Codex 有原生停止钩子,但 OpenClaw 未将最终答案门控作为 v1 插件合约公开。 | 未来可提供带循环与超时保护的可选原语。 |
|
||||
| 作为已承诺 v1 界面的原生 MCP 钩子对等能力 | 中继是通用的,但 OpenClaw 尚未对原生 MCP pre/post 钩子行为进行端到端版本门控和测试。 | 一旦受支持的 app-server 协议下限覆盖这些载荷,就添加 OpenClaw MCP 中继测试和文档。 |
|
||||
| 逐字节的模型 API 请求捕获 | OpenClaw 可以捕获 app-server 请求和通知,但最终的 OpenAI API 请求由 Codex 核心在内部构建。 | 需要 Codex 的模型请求追踪事件或调试 API。 |
|
||||
|
||||
## 工具、媒体和压缩
|
||||
## 工具、媒体与压缩
|
||||
|
||||
Codex harness 只会改变底层的嵌入式智能体执行器。
|
||||
Codex harness 只改变底层内嵌智能体执行器。
|
||||
|
||||
OpenClaw 仍然会构建工具列表,并从 harness 接收动态工具结果。文本、图像、视频、音乐、TTS、批准和消息工具输出,仍然通过常规的 OpenClaw 传递路径流转。
|
||||
OpenClaw 仍会构建工具列表,并从 harness 接收动态工具结果。文本、图像、视频、音乐、TTS、审批以及消息工具输出,仍通过 OpenClaw 的正常传递路径处理。
|
||||
|
||||
原生钩子中继有意保持通用,但 v1 支持合约仅限于 OpenClaw 已测试的 Codex 原生工具和权限路径。不要假设未来的每个 Codex 钩子事件都会成为 OpenClaw 插件接口,除非运行时合约明确命名了它。
|
||||
原生钩子中继是有意保持通用的,但 v1 支持合约仅限于 OpenClaw 已测试的 Codex 原生工具与权限路径。在运行时合约明确命名之前,不要假设未来任何 Codex 钩子事件都会成为 OpenClaw 插件界面。
|
||||
|
||||
当 Codex 将 `_meta.codex_approval_kind` 标记为
|
||||
`"mcp_tool_call"` 时,Codex MCP 工具批准引导会通过 OpenClaw 的插件批准流程进行路由。Codex 的 `request_user_input` 提示会被发送回原始聊天,接下来排队的后续消息会回答该原生服务器请求,而不是被作为额外上下文引导。其他 MCP 引导请求仍然会以失败关闭。
|
||||
`"mcp_tool_call"` 时,Codex MCP 工具审批引导会通过 OpenClaw 的插件审批流程进行路由。Codex 的 `request_user_input` 提示会被发回原始聊天,之后排队的下一条跟进消息将用于回答该原生服务器请求,而不是被作为额外上下文引导。其他 MCP 引导请求仍会以失败关闭。
|
||||
|
||||
当所选模型使用 Codex harness 时,原生线程压缩会委托给 Codex app-server。OpenClaw 会保留一个转录镜像,用于渠道历史、搜索、`/new`、`/reset` 以及未来的模型或 harness 切换。该镜像包括用户提示、最终助手文本,以及当 app-server 发出时的轻量级 Codex 推理或计划记录。目前,OpenClaw 只记录原生压缩开始和完成信号。它尚未公开人类可读的压缩摘要,也未提供可审计的列表来说明 Codex 在压缩后保留了哪些条目。
|
||||
当所选模型使用 Codex harness 时,原生线程压缩会委托给 Codex app-server。OpenClaw 会保留一个转录镜像,用于渠道历史、搜索、`/new`、`/reset`,以及未来的模型或 harness 切换。该镜像包括用户提示、最终助手文本,以及 app-server 发出时的轻量级 Codex 推理或计划记录。目前,OpenClaw 只记录原生压缩开始和完成信号。它尚未提供可供人阅读的压缩摘要,也无法审计 Codex 在压缩后保留了哪些条目。
|
||||
|
||||
由于 Codex 持有规范的原生线程,`tool_result_persist` 当前不会重写 Codex 原生工具结果记录。它只在 OpenClaw 正在写入由 OpenClaw 持有的会话转录工具结果时生效。
|
||||
由于 Codex 持有规范的原生线程,`tool_result_persist` 目前不会重写 Codex 原生工具结果记录。它仅在 OpenClaw 写入 OpenClaw 持有的会话转录工具结果时适用。
|
||||
|
||||
媒体生成不需要 PI。图像、视频、音乐、PDF、TTS 和媒体理解会继续使用相应的提供商/模型设置,例如
|
||||
`agents.defaults.imageGenerationModel`、`videoGenerationModel`、`pdfModel` 和 `messages.tts`。
|
||||
媒体生成不需要 Pi。图像、视频、音乐、PDF、TTS 和媒体理解仍继续使用对应的提供商/模型设置,例如 `agents.defaults.imageGenerationModel`、`videoGenerationModel`、`pdfModel` 和 `messages.tts`。
|
||||
|
||||
## 故障排除
|
||||
|
||||
**Codex 没有作为普通 `/model` 提供商出现:** 这对新配置来说是预期行为。请选择一个 `openai/gpt-*` 模型,并设置
|
||||
`embeddedHarness.runtime: "codex"`(或使用旧版 `codex/*` 引用),启用 `plugins.entries.codex.enabled`,并检查
|
||||
`plugins.allow` 是否排除了 `codex`。
|
||||
**Codex 没有作为普通 `/model` provider 出现:** 对于新配置,这是预期行为。请选择一个 `openai/gpt-*` 模型,并设置
|
||||
`embeddedHarness.runtime: "codex"`(或使用旧版 `codex/*` 引用),启用
|
||||
`plugins.entries.codex.enabled`,并检查 `plugins.allow` 是否排除了
|
||||
`codex`。
|
||||
|
||||
**OpenClaw 使用了 PI 而不是 Codex:** 当没有 Codex harness 声明接管运行时,`runtime: "auto"` 仍可能使用 PI 作为兼容后端。测试时请设置 `embeddedHarness.runtime: "codex"` 以强制选择 Codex。现在,强制的 Codex 运行时会直接失败,而不会回退到 PI,除非你显式设置了
|
||||
`embeddedHarness.fallback: "pi"`。一旦选中了 Codex app-server,其失败会直接暴露,而不会再经过额外的回退配置。
|
||||
**OpenClaw 使用的是 Pi 而不是 Codex:** `runtime: "auto"` 在没有 Codex harness 声明接管运行时,仍可能使用 Pi 作为兼容后端。测试时请设置
|
||||
`embeddedHarness.runtime: "codex"` 以强制选择 Codex。现在,强制使用 Codex 运行时会直接失败,而不是回退到 Pi,除非你显式设置
|
||||
`embeddedHarness.fallback: "pi"`。一旦选中了 Codex app-server,其失败会直接暴露,不需要额外的回退配置。
|
||||
|
||||
**app-server 被拒绝:** 请升级 Codex,确保 app-server 握手报告的版本为 `0.118.0` 或更高。
|
||||
**app-server 被拒绝:** 请升级 Codex,使 app-server 握手报告版本
|
||||
`0.118.0` 或更高。
|
||||
|
||||
**模型发现很慢:** 降低 `plugins.entries.codex.config.discovery.timeoutMs`
|
||||
**模型发现过慢:** 降低 `plugins.entries.codex.config.discovery.timeoutMs`
|
||||
或禁用发现。
|
||||
|
||||
**WebSocket 传输立即失败:** 请检查 `appServer.url`、
|
||||
`authToken`,以及远程 app-server 是否使用相同版本的 Codex app-server 协议。
|
||||
**WebSocket 传输立即失败:** 请检查 `appServer.url`、`authToken`,以及远程 app-server 是否使用相同版本的 Codex app-server 协议。
|
||||
|
||||
**非 Codex 模型使用了 PI:** 除非你为该智能体强制设置了
|
||||
`embeddedHarness.runtime: "codex"`,或选择了旧版 `codex/*`
|
||||
引用,否则这是预期行为。在 `auto` 模式下,普通的 `openai/gpt-*` 和其他提供商引用会保持走其常规提供商路径。如果你强制设置了 `runtime: "codex"`,那么该智能体的每一个嵌入式轮次都必须是 Codex 支持的 OpenAI 模型。
|
||||
**非 Codex 模型使用了 Pi:** 这是预期行为,除非你为该智能体强制设置了
|
||||
`embeddedHarness.runtime: "codex"`,或者选择了旧版 `codex/*` 引用。普通的 `openai/gpt-*` 和其他 provider 引用在 `auto` 模式下会保持使用它们的正常 provider 路径。如果你强制设置 `runtime: "codex"`,则该智能体的每个内嵌回合都必须使用 Codex 支持的 OpenAI 模型。
|
||||
|
||||
## 相关内容
|
||||
|
||||
- [Agent harness plugins](/zh-CN/plugins/sdk-agent-harness)
|
||||
- [Agent Runtimes](/zh-CN/concepts/agent-runtimes)
|
||||
- [Model Providers](/zh-CN/concepts/model-providers)
|
||||
- [模型提供商](/zh-CN/concepts/model-providers)
|
||||
- [OpenAI provider](/zh-CN/providers/openai)
|
||||
- [Status](/zh-CN/cli/status)
|
||||
- [Plugin hooks](/zh-CN/plugins/hooks)
|
||||
- [Configuration Reference](/zh-CN/gateway/configuration-reference)
|
||||
- [插件钩子](/zh-CN/plugins/hooks)
|
||||
- [配置参考](/zh-CN/gateway/configuration-reference)
|
||||
- [测试](/zh-CN/help/testing-live#live-codex-app-server-harness-smoke)
|
||||
|
||||
86
docs/zh-CN/plugins/compatibility.md
Normal file
86
docs/zh-CN/plugins/compatibility.md
Normal file
@ -0,0 +1,86 @@
|
||||
---
|
||||
read_when:
|
||||
- 你维护一个 OpenClaw 插件
|
||||
- 你看到一个插件兼容性警告
|
||||
- 你正在规划插件 SDK 或清单迁移
|
||||
summary: 插件兼容性契约、弃用元数据和迁移预期
|
||||
title: 插件兼容性
|
||||
x-i18n:
|
||||
generated_at: "2026-04-25T05:55:10Z"
|
||||
model: gpt-5.4
|
||||
provider: openai
|
||||
source_hash: 02e0cdbc763eed5a38b303fc44202ddd36e58bce43dc29b6348db3f5fea66f26
|
||||
source_path: plugins/compatibility.md
|
||||
workflow: 15
|
||||
---
|
||||
|
||||
OpenClaw 在移除旧版插件契约之前,会先通过具名兼容性适配器保持这些旧契约继续可用。这样可以在 SDK、清单、设置、配置和 Agent Runtimes 契约演进的同时,保护现有的内置插件和外部插件。
|
||||
|
||||
## 兼容性注册表
|
||||
|
||||
插件兼容性契约会在核心注册表 `src/plugins/compat/registry.ts` 中跟踪。
|
||||
|
||||
每条记录包含:
|
||||
|
||||
- 稳定的兼容性代码
|
||||
- 状态:`active`、`deprecated`、`removal-pending` 或 `removed`
|
||||
- 归属方:SDK、配置、设置、渠道、提供商、插件执行、Agent Runtimes 或核心
|
||||
- 适用时的引入日期和弃用日期
|
||||
- 替代指引
|
||||
- 覆盖旧行为和新行为的文档、诊断和测试
|
||||
|
||||
该注册表是维护者规划和未来插件检查器校验的依据。如果面向插件的行为发生变化,请在添加适配器的同一次变更中添加或更新兼容性记录。
|
||||
|
||||
## 插件检查器包
|
||||
|
||||
插件检查器应位于核心 OpenClaw 仓库之外,作为一个由版本化兼容性契约和清单契约支持的独立包/仓库。
|
||||
|
||||
首日 CLI 应为:
|
||||
|
||||
```sh
|
||||
openclaw-plugin-inspector ./my-plugin
|
||||
```
|
||||
|
||||
它应输出:
|
||||
|
||||
- 清单 / schema 校验
|
||||
- 正在检查的契约兼容性版本
|
||||
- install / source 元数据检查
|
||||
- 冷路径导入检查
|
||||
- 弃用和兼容性警告
|
||||
|
||||
在 CI 注解中使用 `--json` 以获得稳定的机器可读输出。OpenClaw 核心应公开检查器可消费的契约和夹具,但不应从主 `openclaw` 包发布检查器二进制文件。
|
||||
|
||||
## 弃用策略
|
||||
|
||||
OpenClaw 不应在引入替代方案的同一版本中移除已文档化的插件契约。
|
||||
|
||||
迁移顺序如下:
|
||||
|
||||
1. 添加新契约。
|
||||
2. 通过具名兼容性适配器保留旧行为继续可用。
|
||||
3. 在插件作者可以采取行动时发出诊断或警告。
|
||||
4. 记录替代方案和时间线。
|
||||
5. 同时测试旧路径和新路径。
|
||||
6. 等待已公布的迁移窗口结束。
|
||||
7. 只有在获得显式破坏性版本批准后才移除。
|
||||
|
||||
弃用记录必须包含警告开始日期、替代方案、文档链接,以及在已知情况下的目标移除日期。
|
||||
|
||||
## 当前兼容性范围
|
||||
|
||||
当前兼容性记录包括:
|
||||
|
||||
- 旧版宽泛 SDK 导入,例如 `openclaw/plugin-sdk/compat`
|
||||
- 旧版仅钩子插件形态和 `before_agent_start`
|
||||
- 内置插件 allowlist 和启用行为
|
||||
- 旧版 provider / channel 环境变量清单元数据
|
||||
- 正在由清单贡献所有权替代的激活提示
|
||||
- 当公共命名转向 `agentRuntime` 时,`embeddedHarness` 和 `agent-harness` 命名别名
|
||||
- 当注册表优先的 `channelConfigs` 元数据落地时,生成的内置渠道配置元数据回退
|
||||
|
||||
新插件代码应优先使用注册表和具体迁移指南中列出的替代方案。现有插件可以继续使用兼容路径,直到文档、诊断和发布说明公布移除窗口。
|
||||
|
||||
## 发布说明
|
||||
|
||||
发布说明应包含即将到来的插件弃用信息,并附带目标日期和迁移文档链接。这类预警必须在兼容路径转为 `removal-pending` 或 `removed` 之前发出。
|
||||
@ -1,36 +1,36 @@
|
||||
---
|
||||
read_when:
|
||||
- 你想让一个 OpenClaw 智能体加入一个 Google Meet 通话
|
||||
- 你想让一个 OpenClaw 智能体创建一个新的 Google Meet 通话
|
||||
- 你希望 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-25T04:09:49Z"
|
||||
generated_at: "2026-04-25T05:55:29Z"
|
||||
model: gpt-5.4
|
||||
provider: openai
|
||||
source_hash: 57162f6a4de4ccbbfd6ec61c91e33c1aed1c9c523e30415ccf6c54dca1563aac
|
||||
source_hash: c96496a06d00e719ecd0af4b8edf1423cbbc37f7773672e2456baaf06c7ca0ec
|
||||
source_path: plugins/google-meet.md
|
||||
workflow: 15
|
||||
---
|
||||
|
||||
OpenClaw 的 Google Meet 参会支持——该插件在设计上是显式的:
|
||||
|
||||
- 它只会加入一个明确的 `https://meet.google.com/...` URL。
|
||||
- 它可以通过 Google Meet API 创建一个新的 Meet 空间,然后加入返回的 URL。
|
||||
- 它只会加入显式的 `https://meet.google.com/...` URL。
|
||||
- 它可以通过 Google Meet API 创建新的 Meet 空间,然后加入返回的 URL。
|
||||
- `realtime` 语音是默认模式。
|
||||
- 当需要更深层的推理或工具时,实时语音可以回调到完整的 OpenClaw 智能体。
|
||||
- 智能体通过 `mode` 选择加入行为:使用 `realtime` 进行实时收听/回话,或使用 `transcribe` 在不启用实时语音桥接的情况下加入/控制浏览器。
|
||||
- 认证起始方式可以是个人 Google OAuth,或一个已经登录的 Chrome 配置文件。
|
||||
- 没有自动的同意提示播报。
|
||||
- 当需要更深层推理或工具时,实时语音可以回调完整的 OpenClaw 智能体。
|
||||
- 智能体通过 `mode` 选择加入行为:实时听讲/回话使用 `realtime`,加入/控制浏览器但不启用实时语音桥接则使用 `transcribe`。
|
||||
- 认证起点是个人 Google OAuth,或已登录的 Chrome 配置文件。
|
||||
- 没有自动同意声明。
|
||||
- 默认的 Chrome 音频后端是 `BlackHole 2ch`。
|
||||
- Chrome 可以在本地运行,也可以在配对的节点主机上运行。
|
||||
- Twilio 接受拨入号码,以及可选的 PIN 或 DTMF 序列。
|
||||
- Chrome 可以在本地运行,也可以在已配对的节点主机上运行。
|
||||
- Twilio 接受拨入号码以及可选的 PIN 或 DTMF 序列。
|
||||
- CLI 命令是 `googlemeet`;`meet` 保留给更广泛的智能体电话会议工作流。
|
||||
|
||||
## 快速开始
|
||||
|
||||
安装本地音频依赖,并配置一个后端实时语音提供商。OpenAI 是默认选项;Google Gemini Live 也可与 `realtime.provider: "google"` 一起使用:
|
||||
安装本地音频依赖,并配置一个后端实时语音提供商。默认使用 OpenAI;Google Gemini Live 也可配合 `realtime.provider: "google"` 使用:
|
||||
|
||||
```bash
|
||||
brew install blackhole-2ch sox
|
||||
@ -39,20 +39,20 @@ export OPENAI_API_KEY=sk-...
|
||||
export GEMINI_API_KEY=...
|
||||
```
|
||||
|
||||
`blackhole-2ch` 会安装 `BlackHole 2ch` 虚拟音频设备。Homebrew 的安装程序要求重启后,macOS 才会公开该设备:
|
||||
`blackhole-2ch` 会安装 `BlackHole 2ch` 虚拟音频设备。Homebrew 的安装程序需要重启后,macOS 才会暴露该设备:
|
||||
|
||||
```bash
|
||||
sudo reboot
|
||||
```
|
||||
|
||||
重启后,验证这两部分都已就绪:
|
||||
重启后,验证这两项:
|
||||
|
||||
```bash
|
||||
system_profiler SPAudioDataType | grep -i BlackHole
|
||||
command -v rec play
|
||||
```
|
||||
|
||||
启用该插件:
|
||||
启用插件:
|
||||
|
||||
```json5
|
||||
{
|
||||
@ -73,7 +73,9 @@ command -v rec play
|
||||
openclaw googlemeet setup
|
||||
```
|
||||
|
||||
设置输出旨在便于智能体读取。它会报告 Chrome 配置文件、音频桥接、节点固定、延迟的实时介绍,以及在配置了 Twilio 委派时,`voice-call` 插件和 Twilio 凭证是否已就绪。将任何 `ok: false` 的检查都视为要求智能体加入之前的阻塞项。对脚本或机器可读输出,请使用 `openclaw googlemeet setup --json`。
|
||||
设置输出是为智能体可读而设计的。它会报告 Chrome 配置文件、音频桥接、节点固定、延迟实时引导,以及在配置了 Twilio 委托时,`voice-call` 插件和 Twilio 凭证是否已就绪。
|
||||
在请求智能体加入之前,将任何 `ok: false` 检查都视为阻塞项。
|
||||
脚本或机器可读输出请使用 `openclaw googlemeet setup --json`。
|
||||
|
||||
加入会议:
|
||||
|
||||
@ -92,7 +94,7 @@ openclaw googlemeet join https://meet.google.com/abc-defg-hij
|
||||
}
|
||||
```
|
||||
|
||||
创建一个新会议并加入:
|
||||
创建新会议并加入:
|
||||
|
||||
```bash
|
||||
openclaw googlemeet create --transport chrome-node --mode realtime
|
||||
@ -106,13 +108,14 @@ openclaw googlemeet create --no-join
|
||||
|
||||
`googlemeet create` 有两条路径:
|
||||
|
||||
- API 创建:当已配置 Google Meet OAuth 凭证时使用。这是最确定性的路径,不依赖浏览器 UI 状态。
|
||||
- 浏览器后备路径:当缺少 OAuth 凭证时使用。OpenClaw 会使用固定的 Chrome 节点,打开 `https://meet.google.com/new`,等待 Google 重定向到真实的会议代码 URL,然后返回该 URL。此路径要求节点上的 OpenClaw Chrome 配置文件已经登录 Google。浏览器自动化会处理 Meet 自身的首次麦克风提示;该提示不会被视为 Google 登录失败。
|
||||
加入和创建流程还会尽量复用现有的 Meet 标签页,而不是打开新标签页。匹配时会忽略诸如 `authuser` 之类无害的 URL 查询字符串,因此智能体重试时应聚焦已打开的会议,而不是创建第二个 Chrome 标签页。
|
||||
- API 创建:当配置了 Google Meet OAuth 凭证时使用。这是最确定性的路径,不依赖浏览器 UI 状态。
|
||||
- 浏览器回退:当不存在 OAuth 凭证时使用。OpenClaw 会使用固定的 Chrome 节点,打开 `https://meet.google.com/new`,等待 Google 重定向到真实的会议代码 URL,然后返回该 URL。此路径要求节点上的 OpenClaw Chrome 配置文件已经登录 Google。
|
||||
浏览器自动化会处理 Meet 自身首次运行的麦克风提示;该提示不会被视为 Google 登录失败。
|
||||
加入和创建流程也会在打开新标签页前尝试复用现有 Meet 标签页。匹配会忽略无害的 URL 查询字符串,例如 `authuser`,因此智能体重试时应聚焦已打开的会议,而不是创建第二个 Chrome 标签页。
|
||||
|
||||
命令/工具输出包含一个 `source` 字段(`api` 或 `browser`),这样智能体就可以解释使用的是哪条路径。`create` 默认会加入新会议,并返回 `joined: true` 以及加入会话。若只想生成 URL,请在 CLI 中使用 `create --no-join`,或向工具传递 `"join": false`。
|
||||
命令/工具输出包含 `source` 字段(`api` 或 `browser`),这样智能体可以解释使用了哪条路径。`create` 默认会加入新会议,并返回 `joined: true` 以及加入会话。若只想生成 URL,可在 CLI 上使用 `create --no-join`,或向工具传入 `"join": false`。
|
||||
|
||||
或者告诉智能体:“创建一个 Google Meet,用实时语音加入,然后把链接发给我。” 智能体应调用 `google_meet`,使用 `action: "create"`,然后分享返回的 `meetingUri`。
|
||||
或者直接告诉智能体:“创建一个 Google Meet,用实时语音加入它,然后把链接发给我。” 智能体应以 `action: "create"` 调用 `google_meet`,然后分享返回的 `meetingUri`。
|
||||
|
||||
```json
|
||||
{
|
||||
@ -122,21 +125,21 @@ openclaw googlemeet create --no-join
|
||||
}
|
||||
```
|
||||
|
||||
若要进行仅观察/浏览器控制的加入,请设置 `"mode": "transcribe"`。这不会启动双向实时模型桥接,因此它不会在会议中回话。
|
||||
对于仅观察/仅浏览器控制的加入,将 `"mode"` 设为 `"transcribe"`。这不会启动双工实时模型桥接,因此它不会在会议中回话。
|
||||
|
||||
在实时会话期间,`google_meet` 状态会包含浏览器和音频桥接的健康信息,例如 `inCall`、`manualActionRequired`、`providerConnected`、`realtimeReady`、`audioInputActive`、`audioOutputActive`、最近输入/输出时间戳、字节计数以及桥接关闭状态。如果出现安全的 Meet 页面提示,浏览器自动化会在可以时处理它。登录、主持人准入,以及浏览器/操作系统权限提示会作为手动操作上报,并附带原因和消息,供智能体转达。
|
||||
在实时会话期间,`google_meet` 状态包括浏览器和音频桥接健康信息,例如 `inCall`、`manualActionRequired`、`providerConnected`、`realtimeReady`、`audioInputActive`、`audioOutputActive`、最后输入/输出时间戳、字节计数和桥接关闭状态。如果出现安全的 Meet 页面提示,浏览器自动化会在可能时处理它。登录、主持人准入以及浏览器/操作系统权限提示会被报告为需要手动操作,并附带原因和供智能体转达的消息。
|
||||
|
||||
Chrome 会以已登录的 Chrome 配置文件身份加入。在 Meet 中,选择 `BlackHole 2ch` 作为 OpenClaw 使用的麦克风/扬声器路径。为了获得干净的双工音频,请使用单独的虚拟设备或类似 Loopback 的音频图;单个 BlackHole 设备足以完成首次冒烟测试,但可能会产生回声。
|
||||
Chrome 会以已登录的 Chrome 配置文件身份加入。在 Meet 中,选择 `BlackHole 2ch` 作为 OpenClaw 使用的麦克风/扬声器路径。为了获得干净的双工音频,请使用单独的虚拟设备或 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 密钥,或模型提供商设置。
|
||||
- Parallels macOS VM:OpenClaw CLI / 节点主机、Google Chrome、SoX、BlackHole 2ch,以及一个已登录 Google 的 Chrome 配置文件。
|
||||
- VM 中不需要:Gateway 网关服务、智能体配置、OpenAI / GPT 密钥或模型提供商设置。
|
||||
|
||||
安装 VM 依赖:
|
||||
|
||||
@ -144,7 +147,7 @@ Chrome 会以已登录的 Chrome 配置文件身份加入。在 Meet 中,选
|
||||
brew install blackhole-2ch sox
|
||||
```
|
||||
|
||||
安装 BlackHole 后重启 VM,这样 macOS 才会公开 `BlackHole 2ch`:
|
||||
安装 BlackHole 后重启 VM,使 macOS 暴露 `BlackHole 2ch`:
|
||||
|
||||
```bash
|
||||
sudo reboot
|
||||
@ -157,7 +160,7 @@ system_profiler SPAudioDataType | grep -i BlackHole
|
||||
command -v rec play
|
||||
```
|
||||
|
||||
在 VM 中安装或更新 OpenClaw,然后在那里启用内置插件:
|
||||
在 VM 中安装或更新 OpenClaw,然后在其中启用该内置插件:
|
||||
|
||||
```bash
|
||||
openclaw plugins enable google-meet
|
||||
@ -169,14 +172,14 @@ openclaw plugins enable google-meet
|
||||
openclaw node run --host <gateway-host> --port 18789 --display-name parallels-macos
|
||||
```
|
||||
|
||||
如果 `<gateway-host>` 是一个局域网 IP,并且你没有使用 TLS,那么除非你明确允许该受信任私有网络,否则节点会拒绝明文 WebSocket:
|
||||
如果 `<gateway-host>` 是局域网 IP,且你未使用 TLS,那么除非你为该受信任私有网络显式选择加入,否则节点会拒绝该明文 WebSocket:
|
||||
|
||||
```bash
|
||||
OPENCLAW_ALLOW_INSECURE_PRIVATE_WS=1 \
|
||||
openclaw node run --host <gateway-lan-ip> --port 18789 --display-name parallels-macos
|
||||
```
|
||||
|
||||
将节点安装为 LaunchAgent 时也使用相同的环境变量:
|
||||
当你将节点安装为 LaunchAgent 时,也要使用相同的环境变量:
|
||||
|
||||
```bash
|
||||
OPENCLAW_ALLOW_INSECURE_PRIVATE_WS=1 \
|
||||
@ -184,7 +187,7 @@ OPENCLAW_ALLOW_INSECURE_PRIVATE_WS=1 \
|
||||
openclaw node restart
|
||||
```
|
||||
|
||||
`OPENCLAW_ALLOW_INSECURE_PRIVATE_WS=1` 是进程环境变量,不是 `openclaw.json` 设置。`openclaw node install` 会在安装命令中存在该变量时,将其存储到 LaunchAgent 环境中。
|
||||
`OPENCLAW_ALLOW_INSECURE_PRIVATE_WS=1` 是进程环境,而不是 `openclaw.json` 设置。当该环境变量出现在安装命令中时,`openclaw node install` 会将其存储到 LaunchAgent 环境中。
|
||||
|
||||
在 Gateway 网关主机上批准该节点:
|
||||
|
||||
@ -193,7 +196,7 @@ openclaw devices list
|
||||
openclaw devices approve <requestId>
|
||||
```
|
||||
|
||||
确认 Gateway 网关能看到该节点,并且它同时声明了 `googlemeet.chrome` 和浏览器能力/`browser.proxy`:
|
||||
确认 Gateway 网关能看到该节点,并且它通告了 `googlemeet.chrome` 以及浏览器能力 / `browser.proxy`:
|
||||
|
||||
```bash
|
||||
openclaw nodes status
|
||||
@ -229,62 +232,62 @@ openclaw nodes status
|
||||
}
|
||||
```
|
||||
|
||||
现在从 Gateway 网关主机正常加入:
|
||||
现在可以从 Gateway 网关主机正常加入:
|
||||
|
||||
```bash
|
||||
openclaw googlemeet join https://meet.google.com/abc-defg-hij
|
||||
```
|
||||
|
||||
或者让智能体使用 `google_meet` 工具,并设置 `transport: "chrome-node"`。
|
||||
或者要求智能体使用 `google_meet` 工具,并指定 `transport: "chrome-node"`。
|
||||
|
||||
若要进行一次单命令冒烟测试,以创建或复用会话、说出一段已知短语并打印会话健康状态:
|
||||
对于一个一条命令即可完成的烟雾测试——创建或复用会话、播放已知短语,并打印会话健康状态:
|
||||
|
||||
```bash
|
||||
openclaw googlemeet test-speech https://meet.google.com/abc-defg-hij
|
||||
```
|
||||
|
||||
在加入过程中,OpenClaw 浏览器自动化会填写访客名称、点击 Join/Ask to join,并在出现该提示时接受 Meet 的首次运行 “Use microphone” 选择。在仅浏览器创建会议期间,如果 Meet 没有公开使用麦克风按钮,它也可以在不使用麦克风的情况下继续越过同一提示。
|
||||
如果浏览器配置文件未登录、Meet 正在等待主持人准入、Chrome 需要麦克风/摄像头权限,或者 Meet 卡在自动化无法解决的提示上,加入/`test-speech` 结果会报告 `manualActionRequired: true`,并附带 `manualActionReason` 和 `manualActionMessage`。智能体应停止重试加入,报告该精确消息以及当前的 `browserUrl`/`browserTitle`,并且只在手动浏览器操作完成后再重试。
|
||||
在加入期间,OpenClaw 浏览器自动化会填写访客名、点击 Join / Ask to join,并在出现提示时接受 Meet 首次运行的 “Use microphone” 选择。在仅浏览器创建会议期间,如果 Meet 没有暴露 use-microphone 按钮,它也可以在不使用麦克风的情况下继续通过相同提示。
|
||||
如果浏览器配置文件未登录、Meet 正在等待主持人准入、Chrome 需要麦克风/摄像头权限,或者 Meet 卡在自动化无法解决的提示上,则 join / test-speech 结果会报告 `manualActionRequired: true`,并带有 `manualActionReason` 和 `manualActionMessage`。智能体应停止重试加入,报告该确切消息以及当前的 `browserUrl` / `browserTitle`,并且只在手动浏览器操作完成后再重试。
|
||||
|
||||
如果省略了 `chromeNode.node`,只有在恰好有一个已连接节点同时声明了 `googlemeet.chrome` 和浏览器控制时,OpenClaw 才会自动选择。如果连接了多个具备能力的节点,请将 `chromeNode.node` 设置为节点 id、显示名称或远程 IP。
|
||||
如果省略 `chromeNode.node`,则只有在恰好有一个已连接节点同时通告 `googlemeet.chrome` 和浏览器控制时,OpenClaw 才会自动选择它。如果连接了多个有能力的节点,请将 `chromeNode.node` 设为节点 id、显示名称或远程 IP。
|
||||
|
||||
常见故障检查:
|
||||
常见失败检查:
|
||||
|
||||
- `No connected Google Meet-capable node`:在 VM 中启动 `openclaw node run`,批准配对,并确保已在 VM 中运行 `openclaw plugins enable google-meet` 和 `openclaw plugins enable browser`。同时确认 Gateway 网关主机通过 `gateway.nodes.allowCommands: ["googlemeet.chrome", "browser.proxy"]` 允许这两个节点命令。
|
||||
- `No connected Google Meet-capable node`:在 VM 中启动 `openclaw node run`,批准配对,并确保已在 VM 中运行 `openclaw plugins enable google-meet` 和 `openclaw plugins enable browser`。同时确认 Gateway 网关主机允许这两个节点命令,设置为 `gateway.nodes.allowCommands: ["googlemeet.chrome", "browser.proxy"]`。
|
||||
- `BlackHole 2ch audio device not found on the node`:在 VM 中安装 `blackhole-2ch` 并重启 VM。
|
||||
- Chrome 已打开但无法加入:在 VM 中登录浏览器配置文件,或者保持设置 `chrome.guestName` 以访客身份加入。访客自动加入通过节点浏览器代理使用 OpenClaw 浏览器自动化;请确保节点浏览器配置指向你想使用的配置文件,例如 `browser.defaultProfile: "user"` 或一个已命名的现有会话配置文件。
|
||||
- 重复的 Meet 标签页:保持启用 `chrome.reuseExistingTab: true`。OpenClaw 会在打开新标签页前激活相同 Meet URL 的现有标签页,而浏览器会议创建也会在打开新标签页前复用正在进行中的 `https://meet.google.com/new` 或 Google 账号提示标签页。
|
||||
- 没有音频:在 Meet 中,将麦克风/扬声器路由到 OpenClaw 使用的虚拟音频设备路径;使用单独的虚拟设备或类似 Loopback 的路由方式,以获得干净的双工音频。
|
||||
- Chrome 打开了但无法加入:在 VM 内的浏览器配置文件中登录,或者保持设置 `chrome.guestName` 以进行访客加入。访客自动加入通过节点浏览器代理使用 OpenClaw 浏览器自动化;请确保节点浏览器配置指向你想使用的配置文件,例如 `browser.defaultProfile: "user"` 或某个已存在会话的命名配置文件。
|
||||
- 重复的 Meet 标签页:保持启用 `chrome.reuseExistingTab: true`。OpenClaw 会在打开新标签页前激活同一 Meet URL 的现有标签页,而浏览器会议创建也会复用进行中的 `https://meet.google.com/new` 或 Google 账户提示标签页,而不是再打开一个。
|
||||
- 没有音频:在 Meet 中,将麦克风/扬声器路由到 OpenClaw 使用的虚拟音频设备路径;要获得干净的双工音频,请使用单独的虚拟设备或 Loopback 风格路由。
|
||||
|
||||
## 安装说明
|
||||
|
||||
Chrome 实时默认设置使用两个外部工具:
|
||||
Chrome 实时默认值使用两个外部工具:
|
||||
|
||||
- `sox`:命令行音频工具。该插件使用它的 `rec` 和 `play` 命令,作为默认的 8 kHz G.711 mu-law 音频桥接。
|
||||
- `blackhole-2ch`:macOS 虚拟音频驱动。它会创建 `BlackHole 2ch` 音频设备,供 Chrome/Meet 路由使用。
|
||||
- `sox`:命令行音频工具。该插件使用其 `rec` 和 `play` 命令来实现默认的 8 kHz G.711 mu-law 音频桥接。
|
||||
- `blackhole-2ch`:macOS 虚拟音频驱动。它会创建 `BlackHole 2ch` 音频设备,供 Chrome / Meet 路由使用。
|
||||
|
||||
OpenClaw 不会内置或重新分发这两个软件包。文档要求用户通过 Homebrew 将它们作为主机依赖安装。SoX 的许可为 `LGPL-2.0-only AND GPL-2.0-only`;BlackHole 的许可为 GPL-3.0。如果你构建了一个将 BlackHole 与 OpenClaw 一起打包的安装程序或设备,请审查 BlackHole 上游许可条款,或从 Existential Audio 获取单独许可。
|
||||
OpenClaw 不捆绑也不重新分发这两个包。文档要求用户通过 Homebrew 将其安装为主机依赖。SoX 的许可证为 `LGPL-2.0-only AND GPL-2.0-only`;BlackHole 为 GPL-3.0。如果你构建了一个捆绑 BlackHole 和 OpenClaw 的安装程序或设备,请审查 BlackHole 上游许可条款,或向 Existential Audio 获取单独许可。
|
||||
|
||||
## 传输方式
|
||||
|
||||
### Chrome
|
||||
|
||||
Chrome 传输方式会在 Google Chrome 中打开 Meet URL,并以已登录的 Chrome 配置文件身份加入。在 macOS 上,插件会在启动前检查 `BlackHole 2ch`。如果进行了配置,它还会在打开 Chrome 前运行音频桥接健康检查命令和启动命令。当 Chrome/音频位于 Gateway 网关主机上时使用 `chrome`;当 Chrome/音频位于配对节点上(例如 Parallels macOS VM)时使用 `chrome-node`。
|
||||
Chrome 传输会在 Google Chrome 中打开 Meet URL,并以已登录的 Chrome 配置文件身份加入。在 macOS 上,插件会在启动前检查 `BlackHole 2ch`。如果已配置,它还会在打开 Chrome 前运行音频桥接健康检查命令和启动命令。当 Chrome / 音频位于 Gateway 网关主机上时使用 `chrome`;当 Chrome / 音频位于已配对节点(例如 Parallels macOS VM)上时使用 `chrome-node`。
|
||||
|
||||
```bash
|
||||
openclaw googlemeet join https://meet.google.com/abc-defg-hij --transport chrome
|
||||
openclaw googlemeet join https://meet.google.com/abc-defg-hij --transport chrome-node
|
||||
```
|
||||
|
||||
将 Chrome 的麦克风和扬声器音频通过本地 OpenClaw 音频桥接进行路由。如果未安装 `BlackHole 2ch`,加入会因设置错误而失败,而不是在没有音频路径的情况下静默加入。
|
||||
通过本地 OpenClaw 音频桥接路由 Chrome 麦克风和扬声器音频。如果未安装 `BlackHole 2ch`,加入会以设置错误失败,而不是在没有音频路径的情况下静默加入。
|
||||
|
||||
### Twilio
|
||||
|
||||
Twilio 传输方式是一个严格的拨号计划,并委派给 Voice Call 插件。它不会解析 Meet 页面来查找电话号码。
|
||||
Twilio 传输是一种严格的拨号方案,并委托给 Voice Call 插件。它不会解析 Meet 页面中的电话号码。
|
||||
|
||||
当无法使用 Chrome 参会,或者你希望使用电话拨入作为后备方案时,请使用此方式。Google Meet 必须为该会议公开一个电话拨入号码和 PIN;OpenClaw 不会从 Meet 页面中发现这些信息。
|
||||
当无法使用 Chrome 参会,或你希望使用电话拨入作为回退方案时,请使用此方式。Google Meet 必须为该会议提供电话拨入号码和 PIN;OpenClaw 不会从 Meet 页面中发现这些信息。
|
||||
|
||||
在 Gateway 网关主机上启用 Voice Call 插件,而不是在 Chrome 节点上:
|
||||
在 Gateway 网关主机上启用 Voice Call 插件,而不是在 Chrome 节点上启用:
|
||||
|
||||
```json5
|
||||
{
|
||||
@ -309,7 +312,7 @@ Twilio 传输方式是一个严格的拨号计划,并委派给 Voice Call 插
|
||||
}
|
||||
```
|
||||
|
||||
通过环境或配置提供 Twilio 凭证。使用环境变量可以避免将密钥放入 `openclaw.json`:
|
||||
通过环境变量或配置提供 Twilio 凭证。使用环境变量可以避免将密钥写入 `openclaw.json`:
|
||||
|
||||
```bash
|
||||
export TWILIO_ACCOUNT_SID=AC...
|
||||
@ -317,9 +320,9 @@ export TWILIO_AUTH_TOKEN=...
|
||||
export TWILIO_FROM_NUMBER=+15550001234
|
||||
```
|
||||
|
||||
启用 `voice-call` 后,请重启或重新加载 Gateway 网关;在 Gateway 网关进程重新加载之前,插件配置更改不会出现在已运行的进程中。
|
||||
启用 `voice-call` 后,请重启或重新加载 Gateway 网关;插件配置变更在重新加载之前不会出现在已运行的 Gateway 网关进程中。
|
||||
|
||||
然后进行验证:
|
||||
然后验证:
|
||||
|
||||
```bash
|
||||
openclaw config validate
|
||||
@ -327,7 +330,7 @@ openclaw plugins list | grep -E 'google-meet|voice-call'
|
||||
openclaw googlemeet setup
|
||||
```
|
||||
|
||||
当 Twilio 委派配置完成后,`googlemeet setup` 会包含成功的 `twilio-voice-call-plugin` 和 `twilio-voice-call-credentials` 检查。
|
||||
当 Twilio 委托接线完成后,`googlemeet setup` 会包含成功的 `twilio-voice-call-plugin` 和 `twilio-voice-call-credentials` 检查。
|
||||
|
||||
```bash
|
||||
openclaw googlemeet join https://meet.google.com/abc-defg-hij \
|
||||
@ -336,7 +339,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 \
|
||||
@ -347,7 +350,7 @@ openclaw googlemeet join https://meet.google.com/abc-defg-hij \
|
||||
|
||||
## OAuth 和预检
|
||||
|
||||
对于创建 Meet 链接来说,OAuth 是可选的,因为 `googlemeet create` 可以回退到浏览器自动化。当你希望使用官方 API 创建、空间解析或 Meet Media API 预检时,请配置 OAuth。
|
||||
对于创建 Meet 链接,OAuth 是可选的,因为 `googlemeet create` 可以回退到浏览器自动化。当你希望使用官方 API 创建、空间解析或 Meet Media API 预检时,请配置 OAuth。
|
||||
|
||||
Google Meet API 访问优先使用个人 OAuth 客户端。配置 `oauth.clientId`,并可选配置 `oauth.clientSecret`,然后运行:
|
||||
|
||||
@ -355,20 +358,19 @@ Google Meet API 访问优先使用个人 OAuth 客户端。配置 `oauth.clientI
|
||||
openclaw googlemeet auth login --json
|
||||
```
|
||||
|
||||
该命令会打印一个包含刷新令牌的 `oauth` 配置块。它使用 PKCE、位于 `http://localhost:8085/oauth2callback` 的 localhost 回调,以及通过 `--manual` 进行的手动复制/粘贴流程。
|
||||
该命令会打印一个包含刷新令牌的 `oauth` 配置块。它使用 PKCE、位于 `http://localhost:8085/oauth2callback` 的本地回调,以及使用 `--manual` 的手动复制/粘贴流程。
|
||||
|
||||
OAuth 同意内容包括 Meet 空间创建、Meet 空间读取访问权限,以及 Meet 会议媒体读取访问权限。如果你在会议创建支持上线之前就已经完成认证,请重新运行 `openclaw googlemeet auth login --json`,以便刷新令牌具有 `meetings.space.created` 作用域。
|
||||
OAuth 同意范围包括 Meet 空间创建、Meet 空间读取访问和 Meet 会议媒体读取访问。如果你在支持会议创建功能之前就已完成认证,请重新运行 `openclaw googlemeet auth login --json`,以便让刷新令牌具备 `meetings.space.created` scope。
|
||||
|
||||
浏览器后备路径不需要 OAuth 凭证。在该模式下,Google 认证来自所选节点上已登录的 Chrome 配置文件,而不是来自 OpenClaw 配置。
|
||||
浏览器回退不需要 OAuth 凭证。在该模式下,Google 认证来自所选节点上已登录的 Chrome 配置文件,而不是 OpenClaw 配置。
|
||||
|
||||
接受以下环境变量作为后备:
|
||||
接受以下环境变量作为回退:
|
||||
|
||||
- `OPENCLAW_GOOGLE_MEET_CLIENT_ID` 或 `GOOGLE_MEET_CLIENT_ID`
|
||||
- `OPENCLAW_GOOGLE_MEET_CLIENT_SECRET` 或 `GOOGLE_MEET_CLIENT_SECRET`
|
||||
- `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`
|
||||
|
||||
@ -378,7 +380,7 @@ OAuth 同意内容包括 Meet 空间创建、Meet 空间读取访问权限,以
|
||||
openclaw googlemeet resolve-space --meeting https://meet.google.com/abc-defg-hij
|
||||
```
|
||||
|
||||
在进行媒体相关工作前运行预检:
|
||||
在进行媒体工作前运行预检:
|
||||
|
||||
```bash
|
||||
openclaw googlemeet preflight --meeting https://meet.google.com/abc-defg-hij
|
||||
@ -390,9 +392,9 @@ openclaw googlemeet preflight --meeting https://meet.google.com/abc-defg-hij
|
||||
openclaw googlemeet create
|
||||
```
|
||||
|
||||
该命令会打印新的 `meeting uri`、来源以及加入会话。有 OAuth 凭证时,它会使用官方 Google Meet API。没有 OAuth 凭证时,它会使用固定的 Chrome 节点中已登录的浏览器配置文件作为后备。智能体可以使用 `google_meet` 工具并传入 `action: "create"` 来一步完成创建和加入。若只创建 URL,请传入 `"join": false`。
|
||||
该命令会打印新的 `meeting uri`、来源和加入会话。使用 OAuth 凭证时,它会使用官方 Google Meet API。没有 OAuth 凭证时,它会回退为使用固定 Chrome 节点上已登录的浏览器配置文件。智能体可以使用 `google_meet` 工具,通过 `action: "create"` 一步完成创建和加入。如果只需要创建 URL,请传入 `"join": false`。
|
||||
|
||||
来自浏览器后备路径的 JSON 输出示例:
|
||||
浏览器回退的示例 JSON 输出:
|
||||
|
||||
```json
|
||||
{
|
||||
@ -412,7 +414,7 @@ openclaw googlemeet create
|
||||
}
|
||||
```
|
||||
|
||||
如果浏览器后备路径在能够创建 URL 之前遇到 Google 登录或 Meet 权限阻塞,Gateway 网关方法会返回失败响应,而 `google_meet` 工具会返回结构化详细信息,而不是纯字符串:
|
||||
如果浏览器回退在创建 URL 之前遇到 Google 登录或 Meet 权限阻塞,Gateway 网关方法会返回失败响应,而 `google_meet` 工具会返回结构化细节,而不是纯字符串:
|
||||
|
||||
```json
|
||||
{
|
||||
@ -430,9 +432,9 @@ openclaw googlemeet create
|
||||
}
|
||||
```
|
||||
|
||||
当智能体看到 `manualActionRequired: true` 时,它应报告 `manualActionMessage`,以及浏览器节点/标签页上下文,并停止打开新的 Meet 标签页,直到操作员完成浏览器步骤。
|
||||
当智能体看到 `manualActionRequired: true` 时,应报告 `manualActionMessage` 以及浏览器节点/标签页上下文,并在操作员完成浏览器步骤之前停止打开新的 Meet 标签页。
|
||||
|
||||
来自 API 创建的 JSON 输出示例:
|
||||
API 创建的示例 JSON 输出:
|
||||
|
||||
```json
|
||||
{
|
||||
@ -453,13 +455,13 @@ openclaw googlemeet create
|
||||
}
|
||||
```
|
||||
|
||||
创建 Meet 默认会加入会议。即使使用 Chrome 或 Chrome-node 传输方式,仍然需要一个已登录 Google 的 Chrome 配置文件才能通过浏览器加入。如果该配置文件已退出登录,OpenClaw 会报告 `manualActionRequired: true` 或浏览器后备路径错误,并要求操作员在重试前完成 Google 登录。
|
||||
创建 Meet 默认会加入。Chrome 或 Chrome 节点传输仍然需要一个已登录 Google 的 Chrome 配置文件,才能通过浏览器加入。如果该配置文件已退出登录,OpenClaw 会报告 `manualActionRequired: true` 或浏览器回退错误,并要求操作员先完成 Google 登录再重试。
|
||||
|
||||
只有在确认你的 Cloud 项目、OAuth 主体以及会议参与者都已加入用于 Meet 媒体 API 的 Google Workspace Developer Preview Program 之后,才设置 `preview.enrollmentAcknowledged: true`。
|
||||
只有在确认你的 Cloud 项目、OAuth principal 和会议参与者都已加入 Meet media APIs 的 Google Workspace Developer Preview Program 后,才设置 `preview.enrollmentAcknowledged: true`。
|
||||
|
||||
## 配置
|
||||
|
||||
常见的 Chrome 实时路径只需要启用插件、BlackHole、SoX,以及后端实时语音提供商密钥。OpenAI 是默认值;设置 `realtime.provider: "google"` 可使用 Google Gemini Live:
|
||||
常见的 Chrome 实时路径只需要启用插件、安装 BlackHole、SoX,以及一个后端实时语音提供商密钥。默认使用 OpenAI;设置 `realtime.provider: "google"` 可改用 Google Gemini Live:
|
||||
|
||||
```bash
|
||||
brew install blackhole-2ch sox
|
||||
@ -487,20 +489,20 @@ export GEMINI_API_KEY=...
|
||||
|
||||
- `defaultTransport: "chrome"`
|
||||
- `defaultMode: "realtime"`
|
||||
- `chromeNode.node`:`chrome-node` 的可选节点 id/名称/IP
|
||||
- `chromeNode.node`:`chrome-node` 的可选节点 id / 名称 / IP
|
||||
- `chrome.audioBackend: "blackhole-2ch"`
|
||||
- `chrome.guestName: "OpenClaw Agent"`:在已退出登录的 Meet 访客页面上使用的名称
|
||||
- `chrome.autoJoin: true`:在 `chrome-node` 上通过 OpenClaw 浏览器自动化尽力填写访客名称并点击 Join Now
|
||||
- `chrome.autoJoin: true`:通过 OpenClaw 浏览器自动化,在 `chrome-node` 上尽力填写访客名并点击 Join Now
|
||||
- `chrome.reuseExistingTab: true`:激活现有 Meet 标签页,而不是打开重复标签页
|
||||
- `chrome.waitForInCallMs: 20000`:等待 Meet 标签页报告已在通话中,然后再触发实时介绍
|
||||
- `chrome.audioInputCommand`:将 8 kHz G.711 mu-law 音频写入 stdout 的 SoX `rec` 命令
|
||||
- `chrome.audioOutputCommand`:从 stdin 读取 8 kHz G.711 mu-law 音频的 SoX `play` 命令
|
||||
- `chrome.waitForInCallMs: 20000`:等待 Meet 标签页报告已进入通话,然后再触发实时引导
|
||||
- `chrome.audioInputCommand`:SoX `rec` 命令,将 8 kHz G.711 mu-law 音频写入 stdout
|
||||
- `chrome.audioOutputCommand`:SoX `play` 命令,从 stdin 读取 8 kHz G.711 mu-law 音频
|
||||
- `realtime.provider: "openai"`
|
||||
- `realtime.toolPolicy: "safe-read-only"`
|
||||
- `realtime.instructions`:简短的口头回复,较复杂的答案使用 `openclaw_agent_consult`
|
||||
- `realtime.introMessage`:当实时桥接连接时播放的简短口头就绪检查;将其设置为 `""` 可静默加入
|
||||
- `realtime.instructions`:简短口语回复,较深入回答使用 `openclaw_agent_consult`
|
||||
- `realtime.introMessage`:实时桥接连接时的简短口头就绪检查;设为 `""` 可静默加入
|
||||
|
||||
可选覆盖项:
|
||||
可选覆盖:
|
||||
|
||||
```json5
|
||||
{
|
||||
@ -529,7 +531,7 @@ export GEMINI_API_KEY=...
|
||||
}
|
||||
```
|
||||
|
||||
仅限 Twilio 的配置:
|
||||
仅 Twilio 配置:
|
||||
|
||||
```json5
|
||||
{
|
||||
@ -544,7 +546,7 @@ export GEMINI_API_KEY=...
|
||||
}
|
||||
```
|
||||
|
||||
`voiceCall.enabled` 默认为 `true`;使用 Twilio 传输方式时,它会将实际的 PSTN 呼叫和 DTMF 委派给 Voice Call 插件。如果未启用 `voice-call`,Google Meet 仍然可以验证并记录拨号计划,但无法发起 Twilio 呼叫。
|
||||
`voiceCall.enabled` 默认为 `true`;使用 Twilio 传输时,它会将实际 PSTN 呼叫和 DTMF 委托给 Voice Call 插件。如果未启用 `voice-call`,Google Meet 仍然可以校验并记录拨号方案,但无法发起 Twilio 呼叫。
|
||||
|
||||
## 工具
|
||||
|
||||
@ -559,17 +561,17 @@ export GEMINI_API_KEY=...
|
||||
}
|
||||
```
|
||||
|
||||
当 Chrome 运行在 Gateway 网关主机上时,使用 `transport: "chrome"`。当 Chrome 运行在配对节点上(例如 Parallels VM)时,使用 `transport: "chrome-node"`。在这两种情况下,实时模型和 `openclaw_agent_consult` 都运行在 Gateway 网关主机上,因此模型凭证会保留在那里。
|
||||
当 Chrome 运行在 Gateway 网关主机上时,使用 `transport: "chrome"`。当 Chrome 运行在已配对节点(例如 Parallels VM)上时,使用 `transport: "chrome-node"`。这两种情况下,实时模型和 `openclaw_agent_consult` 都运行在 Gateway 网关主机上,因此模型凭证会保留在那里。
|
||||
|
||||
使用 `action: "status"` 可列出活动会话或检查某个会话 ID。使用 `action: "speak"` 并提供 `sessionId` 和 `message`,可让实时智能体立即发言。使用 `action: "test_speech"` 可创建或复用会话、触发一段已知短语,并在 Chrome 主机能够报告时返回 `inCall` 健康状态。使用 `action: "leave"` 可将会话标记为已结束。
|
||||
使用 `action: "status"` 列出活动会话或检查某个会话 ID。使用带有 `sessionId` 和 `message` 的 `action: "speak"`,让实时智能体立即说话。使用 `action: "test_speech"` 创建或复用会话、触发已知短语,并在 Chrome 主机能够报告时返回 `inCall` 健康状态。使用 `action: "leave"` 将会话标记为已结束。
|
||||
|
||||
`status` 在可用时包含 Chrome 健康信息:
|
||||
`status` 在可用时会包含 Chrome 健康信息:
|
||||
|
||||
- `inCall`:Chrome 看起来已经进入 Meet 通话
|
||||
- `inCall`:Chrome 看起来已在 Meet 通话中
|
||||
- `micMuted`:尽力检测的 Meet 麦克风状态
|
||||
- `manualActionRequired` / `manualActionReason` / `manualActionMessage`:浏览器配置文件需要手动登录、Meet 主持人准入、权限处理,或浏览器控制修复后语音功能才能工作
|
||||
- `manualActionRequired` / `manualActionReason` / `manualActionMessage`:浏览器配置文件需要手动登录、Meet 主持人准入、权限授予,或浏览器控制修复后语音才能工作
|
||||
- `providerConnected` / `realtimeReady`:实时语音桥接状态
|
||||
- `lastInputAt` / `lastOutputAt`:桥接最近接收到或发送音频的时间
|
||||
- `lastInputAt` / `lastOutputAt`:桥接上次接收或发送音频的时间
|
||||
|
||||
```json
|
||||
{
|
||||
@ -581,25 +583,25 @@ export GEMINI_API_KEY=...
|
||||
|
||||
## 实时智能体咨询
|
||||
|
||||
Chrome 实时模式针对实时语音循环进行了优化。实时语音提供商会听取会议音频,并通过配置的音频桥接发声。当实时模型需要更深层推理、当前信息或普通 OpenClaw 工具时,它可以调用 `openclaw_agent_consult`。
|
||||
Chrome 实时模式针对实时语音循环做了优化。实时语音提供商会听取会议音频,并通过已配置的音频桥接说话。当实时模型需要更深层的推理、最新信息或常规 OpenClaw 工具时,它可以调用 `openclaw_agent_consult`。
|
||||
|
||||
咨询工具会在后台运行常规 OpenClaw 智能体,结合最近的会议转录上下文,并向实时语音会话返回简洁的口头回答。随后,语音模型可以将该回答再说回会议中。它与 Voice Call 共用同一个实时咨询工具。
|
||||
咨询工具会在后台运行常规 OpenClaw 智能体,附带最近的会议转录上下文,并向实时语音会话返回简洁的口语回答。然后语音模型就可以把该回答说回会议中。它使用与 Voice Call 相同的共享实时咨询工具。
|
||||
|
||||
`realtime.toolPolicy` 控制咨询运行方式:
|
||||
|
||||
- `safe-read-only`:公开咨询工具,并将常规智能体限制为使用 `read`、`web_search`、`web_fetch`、`x_search`、`memory_search` 和 `memory_get`。
|
||||
- `owner`:公开咨询工具,并允许常规智能体使用正常的智能体工具策略。
|
||||
- `none`:不向实时语音模型公开咨询工具。
|
||||
- `safe-read-only`:暴露咨询工具,并将常规智能体限制为 `read`、`web_search`、`web_fetch`、`x_search`、`memory_search` 和 `memory_get`。
|
||||
- `owner`:暴露咨询工具,并允许常规智能体使用正常的智能体工具策略。
|
||||
- `none`:不向实时语音模型暴露咨询工具。
|
||||
|
||||
咨询会话键按 Meet 会话隔离,因此在同一场会议期间,后续咨询调用可以复用之前的咨询上下文。
|
||||
咨询会话键按 Meet 会话进行作用域划分,因此后续咨询调用可以在同一会议期间复用先前的咨询上下文。
|
||||
|
||||
要在 Chrome 完全加入通话后强制执行一次口头就绪检查:
|
||||
要在 Chrome 完全加入通话后强制进行一次口头就绪检查:
|
||||
|
||||
```bash
|
||||
openclaw googlemeet speak meet_... "Say exactly: I'm here and listening."
|
||||
```
|
||||
|
||||
对于完整的加入并发言冒烟测试:
|
||||
如需完整的“加入并发言”烟雾测试:
|
||||
|
||||
```bash
|
||||
openclaw googlemeet test-speech https://meet.google.com/abc-defg-hij \
|
||||
@ -607,9 +609,9 @@ openclaw googlemeet test-speech https://meet.google.com/abc-defg-hij \
|
||||
--message "Say exactly: I'm here and listening."
|
||||
```
|
||||
|
||||
## 实时测试检查清单
|
||||
## 在线测试检查清单
|
||||
|
||||
在将会议交给无人值守的智能体之前,请使用以下顺序:
|
||||
在把会议交给无人值守智能体之前,请使用以下顺序:
|
||||
|
||||
```bash
|
||||
openclaw googlemeet setup
|
||||
@ -619,15 +621,15 @@ openclaw googlemeet test-speech https://meet.google.com/abc-defg-hij \
|
||||
--message "Say exactly: Google Meet speech test complete."
|
||||
```
|
||||
|
||||
预期的 Chrome-node 状态:
|
||||
预期的 Chrome 节点状态:
|
||||
|
||||
- `googlemeet setup` 全部为绿色。
|
||||
- 当 `chrome-node` 是默认传输方式或某个节点已固定时,`googlemeet setup` 包含 `chrome-node-connected`。
|
||||
- 当 Chrome 节点是默认传输方式或固定了节点时,`googlemeet setup` 会包含 `chrome-node-connected`。
|
||||
- `nodes status` 显示所选节点已连接。
|
||||
- 所选节点同时声明了 `googlemeet.chrome` 和 `browser.proxy`。
|
||||
- Meet 标签页已加入通话,并且 `test-speech` 返回带有 `inCall: true` 的 Chrome 健康状态。
|
||||
- 所选节点通告了 `googlemeet.chrome` 和 `browser.proxy`。
|
||||
- Meet 标签页加入了通话,并且 `test-speech` 返回的 Chrome 健康状态中包含 `inCall: true`。
|
||||
|
||||
对于远程 Chrome 主机,例如 Parallels macOS VM,这是在更新 Gateway 网关或 VM 后最简短且安全的检查:
|
||||
对于远程 Chrome 主机,例如 Parallels macOS VM,在更新 Gateway 网关或 VM 后,这是最短且安全的检查方式:
|
||||
|
||||
```bash
|
||||
openclaw googlemeet setup
|
||||
@ -638,9 +640,9 @@ openclaw nodes invoke \
|
||||
--params '{"action":"setup"}'
|
||||
```
|
||||
|
||||
这证明 Gateway 网关插件已加载,VM 节点已使用当前令牌连接,并且 Meet 音频桥接可用,随后智能体才会打开真实的会议标签页。
|
||||
这可以证明 Gateway 网关插件已加载、VM 节点使用当前令牌已连接,以及 Meet 音频桥接在智能体打开真实会议标签页之前可用。
|
||||
|
||||
对于 Twilio 冒烟测试,请使用一个公开电话拨入详情的会议:
|
||||
对于 Twilio 烟雾测试,请使用一个会暴露电话拨入详情的会议:
|
||||
|
||||
```bash
|
||||
openclaw googlemeet setup
|
||||
@ -655,7 +657,7 @@ openclaw googlemeet join https://meet.google.com/abc-defg-hij \
|
||||
- `googlemeet setup` 包含绿色的 `twilio-voice-call-plugin` 和 `twilio-voice-call-credentials` 检查。
|
||||
- Gateway 网关重新加载后,CLI 中可用 `voicecall`。
|
||||
- 返回的会话具有 `transport: "twilio"` 和一个 `twilio.voiceCallId`。
|
||||
- `googlemeet leave <sessionId>` 会挂断已委派的语音呼叫。
|
||||
- `googlemeet leave <sessionId>` 会挂断被委托的语音通话。
|
||||
|
||||
## 故障排除
|
||||
|
||||
@ -668,9 +670,10 @@ openclaw plugins list | grep google-meet
|
||||
openclaw googlemeet setup
|
||||
```
|
||||
|
||||
如果你刚刚编辑了 `plugins.entries.google-meet`,请重启或重新加载 Gateway 网关。运行中的智能体只能看到由当前 Gateway 网关进程注册的插件工具。
|
||||
如果你刚刚编辑了 `plugins.entries.google-meet`,请重启或重新加载 Gateway 网关。
|
||||
正在运行的智能体只能看到当前 Gateway 网关进程已注册的插件工具。
|
||||
|
||||
### 没有已连接的具备 Google Meet 能力的节点
|
||||
### 没有已连接的 Google Meet 可用节点
|
||||
|
||||
在节点主机上运行:
|
||||
|
||||
@ -689,7 +692,8 @@ openclaw devices approve <requestId>
|
||||
openclaw nodes status
|
||||
```
|
||||
|
||||
该节点必须已连接,并列出 `googlemeet.chrome` 以及 `browser.proxy`。Gateway 网关配置还必须允许这些节点命令:
|
||||
该节点必须处于已连接状态,并列出 `googlemeet.chrome` 和 `browser.proxy`。
|
||||
Gateway 网关配置必须允许这些节点命令:
|
||||
|
||||
```json5
|
||||
{
|
||||
@ -701,7 +705,7 @@ openclaw nodes status
|
||||
}
|
||||
```
|
||||
|
||||
如果 `googlemeet setup` 的 `chrome-node-connected` 检查失败,或者 Gateway 网关日志报告 `gateway token mismatch`,请使用当前 Gateway 网关令牌重新安装或重启该节点。对于局域网 Gateway 网关,这通常意味着:
|
||||
如果 `googlemeet setup` 的 `chrome-node-connected` 失败,或者 Gateway 网关日志报告 `gateway token mismatch`,请使用当前 Gateway 网关令牌重新安装或重启节点。对于局域网 Gateway 网关,这通常意味着:
|
||||
|
||||
```bash
|
||||
OPENCLAW_ALLOW_INSECURE_PRIVATE_WS=1 \
|
||||
@ -712,39 +716,40 @@ OPENCLAW_ALLOW_INSECURE_PRIVATE_WS=1 \
|
||||
--force
|
||||
```
|
||||
|
||||
然后重新加载节点服务,并重新运行:
|
||||
然后重新加载节点服务,并再次运行:
|
||||
|
||||
```bash
|
||||
openclaw googlemeet setup
|
||||
openclaw nodes status --connected
|
||||
```
|
||||
|
||||
### 浏览器已打开,但智能体无法加入
|
||||
### 浏览器打开了,但智能体无法加入
|
||||
|
||||
运行 `googlemeet test-speech` 并检查返回的 Chrome 健康状态。如果它报告 `manualActionRequired: true`,请将 `manualActionMessage` 展示给操作员,并在浏览器操作完成前停止重试。
|
||||
|
||||
常见的手动操作包括:
|
||||
常见手动操作:
|
||||
|
||||
- 登录 Chrome 配置文件。
|
||||
- 通过 Meet 主持人账号准许访客进入。
|
||||
- 当 Chrome 的原生权限提示出现时,授予 Chrome 麦克风/摄像头权限。
|
||||
- 通过 Meet 主持人账户准入该访客。
|
||||
- 当 Chrome 原生权限提示出现时,授予 Chrome 麦克风/摄像头权限。
|
||||
- 关闭或修复卡住的 Meet 权限对话框。
|
||||
|
||||
不要仅仅因为 Meet 显示 “Do you want people to hear you in the meeting?” 就报告“未登录”。这是 Meet 的音频选择过渡页;在可用时,OpenClaw 会通过浏览器自动化点击 **Use microphone**,并继续等待真正的会议状态。对于仅创建 URL 的浏览器后备路径,OpenClaw 可能会点击 **Continue without microphone**,因为创建 URL 不需要实时音频路径。
|
||||
不要仅因为 Meet 显示 “Do you want people to hear you in the meeting?” 就报告“未登录”。这是 Meet 的音频选择过渡页;OpenClaw 会在可用时通过浏览器自动化点击 **Use microphone**,并继续等待真实会议状态。对于仅创建的浏览器回退,由于创建 URL 不需要实时音频路径,OpenClaw 可能会点击 **Continue without microphone**。
|
||||
|
||||
### 会议创建失败
|
||||
|
||||
当配置了 OAuth 凭证时,`googlemeet create` 会首先使用 Google Meet API 的 `spaces.create` 端点。没有 OAuth 凭证时,它会回退到固定的 Chrome 节点浏览器。请确认:
|
||||
当配置了 OAuth 凭证时,`googlemeet create` 会首先使用 Google Meet API 的 `spaces.create` 端点。
|
||||
没有 OAuth 凭证时,它会回退到固定的 Chrome 节点浏览器。请确认:
|
||||
|
||||
- 对于 API 创建:已配置 `oauth.clientId` 和 `oauth.refreshToken`,或者存在匹配的 `OPENCLAW_GOOGLE_MEET_*` 环境变量。
|
||||
- 对于 API 创建:刷新令牌是在添加创建支持之后生成的。较旧的令牌可能缺少 `meetings.space.created` 作用域;请重新运行 `openclaw googlemeet auth login --json` 并更新插件配置。
|
||||
- 对于浏览器后备路径:`defaultTransport: "chrome-node"` 和 `chromeNode.node` 指向一个已连接的节点,该节点具备 `browser.proxy` 和 `googlemeet.chrome`。
|
||||
- 对于浏览器后备路径:该节点上的 OpenClaw Chrome 配置文件已登录 Google,并且可以打开 `https://meet.google.com/new`。
|
||||
- 对于浏览器后备路径:重试时会复用现有的 `https://meet.google.com/new` 或 Google 账号提示标签页,而不是打开新标签页。如果智能体超时,请重试工具调用,而不是手动再打开一个 Meet 标签页。
|
||||
- 对于浏览器后备路径:如果工具返回 `manualActionRequired: true`,请使用返回的 `browser.nodeId`、`browser.targetId`、`browserUrl` 和 `manualActionMessage` 来指导操作员。在该操作完成前,不要循环重试。
|
||||
- 对于浏览器后备路径:如果 Meet 显示 “Do you want people to hear you in the meeting?”,请保持标签页打开。OpenClaw 应该会通过浏览器自动化点击 **Use microphone**,或者在仅创建的后备路径中点击 **Continue without microphone**,然后继续等待生成的 Meet URL。如果无法做到,错误中应提到 `meet-audio-choice-required`,而不是 `google-login-required`。
|
||||
- 对于 API 创建:已配置 `oauth.clientId` 和 `oauth.refreshToken`,或存在匹配的 `OPENCLAW_GOOGLE_MEET_*` 环境变量。
|
||||
- 对于 API 创建:刷新令牌是在添加创建支持之后签发的。较旧的令牌可能缺少 `meetings.space.created` scope;请重新运行 `openclaw googlemeet auth login --json` 并更新插件配置。
|
||||
- 对于浏览器回退:`defaultTransport: "chrome-node"`,并且 `chromeNode.node` 指向一个已连接且具备 `browser.proxy` 和 `googlemeet.chrome` 的节点。
|
||||
- 对于浏览器回退:该节点上的 OpenClaw Chrome 配置文件已登录 Google,并且可以打开 `https://meet.google.com/new`。
|
||||
- 对于浏览器回退:重试会复用现有的 `https://meet.google.com/new` 或 Google 账户提示标签页,而不是打开新标签页。如果智能体超时,请重试工具调用,而不是手动再打开一个 Meet 标签页。
|
||||
- 对于浏览器回退:如果工具返回 `manualActionRequired: true`,请使用返回的 `browser.nodeId`、`browser.targetId`、`browserUrl` 和 `manualActionMessage` 来指导操作员。在该操作完成之前,不要循环重试。
|
||||
- 对于浏览器回退:如果 Meet 显示 “Do you want people to hear you in the meeting?”,请保持标签页打开。OpenClaw 应该通过浏览器自动化点击 **Use microphone**,或者对于仅创建回退点击 **Continue without microphone**,然后继续等待生成的 Meet URL。如果它无法这样做,错误中应提到 `meet-audio-choice-required`,而不是 `google-login-required`。
|
||||
|
||||
### 智能体已加入,但不说话
|
||||
### 智能体加入了,但不说话
|
||||
|
||||
检查实时路径:
|
||||
|
||||
@ -753,31 +758,33 @@ openclaw googlemeet setup
|
||||
openclaw googlemeet doctor
|
||||
```
|
||||
|
||||
使用 `mode: "realtime"` 进行收听/回话。`mode: "transcribe"` 则是有意不启动双向实时语音桥接。
|
||||
对于听讲/回话,请使用 `mode: "realtime"`。`mode: "transcribe"` 按设计不会启动双工实时语音桥接。
|
||||
|
||||
还要验证:
|
||||
另外还要验证:
|
||||
|
||||
- Gateway 网关主机上有可用的实时提供商密钥,例如 `OPENAI_API_KEY` 或 `GEMINI_API_KEY`。
|
||||
- Chrome 主机上可以看到 `BlackHole 2ch`。
|
||||
- Chrome 主机上存在 `rec` 和 `play`。
|
||||
- 在 Chrome 主机上能看到 `BlackHole 2ch`。
|
||||
- 在 Chrome 主机上存在 `rec` 和 `play`。
|
||||
- Meet 的麦克风和扬声器已通过 OpenClaw 使用的虚拟音频路径进行路由。
|
||||
|
||||
`googlemeet doctor [session-id]` 会打印会话、节点、通话内状态、手动操作原因、实时提供商连接、`realtimeReady`、音频输入/输出活动、最近音频时间戳、字节计数以及浏览器 URL。当你需要原始 JSON 时,请使用 `googlemeet status [session-id]`。
|
||||
`googlemeet doctor [session-id]` 会打印会话、节点、是否在通话中、手动操作原因、实时提供商连接、`realtimeReady`、音频输入/输出活动、最后音频时间戳、字节计数和浏览器 URL。
|
||||
当你需要原始 JSON 时,请使用 `googlemeet status [session-id]`。
|
||||
|
||||
如果智能体超时,而你能看到一个已打开的 Meet 标签页,请在不打开新标签页的情况下检查该标签页:
|
||||
如果某个智能体超时,而你已经能看到一个已打开的 Meet 标签页,请在不再打开新标签页的情况下检查该标签页:
|
||||
|
||||
```bash
|
||||
openclaw googlemeet recover-tab
|
||||
openclaw googlemeet recover-tab https://meet.google.com/abc-defg-hij
|
||||
```
|
||||
|
||||
对应的工具操作是 `recover_current_tab`。它会聚焦并检查配置的 Chrome 节点上现有的 Meet 标签页。它不会打开新标签页,也不会创建新会话;它会报告当前阻塞项,例如登录、准入、权限或音频选择状态。CLI 命令会与已配置的 Gateway 网关通信,因此 Gateway 网关必须正在运行,且 Chrome 节点必须已连接。
|
||||
等效的工具操作是 `recover_current_tab`。它会聚焦并检查已配置 Chrome 节点上的现有 Meet 标签页。它不会打开新标签页,也不会创建新会话;它会报告当前阻塞项,例如登录、准入、权限或音频选择状态。该 CLI 命令会与已配置的 Gateway 网关通信,因此 Gateway 网关必须正在运行,并且 Chrome 节点必须已连接。
|
||||
|
||||
### Twilio 设置检查失败
|
||||
|
||||
当 `voice-call` 未被允许或未启用时,`twilio-voice-call-plugin` 会失败。请将其添加到 `plugins.allow`,启用 `plugins.entries.voice-call`,并重新加载 Gateway 网关。
|
||||
当 `voice-call` 不在 allow 列表中或未启用时,`twilio-voice-call-plugin` 会失败。
|
||||
请将它添加到 `plugins.allow`,启用 `plugins.entries.voice-call`,并重新加载 Gateway 网关。
|
||||
|
||||
当 Twilio 后端缺少 account SID、auth token 或主叫号码时,`twilio-voice-call-credentials` 会失败。请在 Gateway 网关主机上设置这些值:
|
||||
当 Twilio 后端缺少 account SID、auth token 或 caller number 时,`twilio-voice-call-credentials` 会失败。请在 Gateway 网关主机上设置这些变量:
|
||||
|
||||
```bash
|
||||
export TWILIO_ACCOUNT_SID=AC...
|
||||
@ -793,7 +800,7 @@ openclaw voicecall setup
|
||||
openclaw voicecall smoke
|
||||
```
|
||||
|
||||
默认情况下,`voicecall smoke` 仅用于就绪性检查。若要对特定号码进行 dry-run:
|
||||
`voicecall smoke` 默认仅进行就绪性检查。要对特定号码进行 dry-run:
|
||||
|
||||
```bash
|
||||
openclaw voicecall smoke --to "+15555550123"
|
||||
@ -805,9 +812,9 @@ openclaw voicecall smoke --to "+15555550123"
|
||||
openclaw voicecall smoke --to "+15555550123" --yes
|
||||
```
|
||||
|
||||
### Twilio 呼叫已开始,但始终未进入会议
|
||||
### Twilio 通话开始了,但始终没有进入会议
|
||||
|
||||
确认 Meet 事件公开了电话拨入详情。传入准确的拨入号码和 PIN,或自定义 DTMF 序列:
|
||||
确认 Meet 事件提供了电话拨入详情。传入准确的拨入号码和 PIN,或自定义 DTMF 序列:
|
||||
|
||||
```bash
|
||||
openclaw googlemeet join https://meet.google.com/abc-defg-hij \
|
||||
@ -820,19 +827,21 @@ openclaw googlemeet join https://meet.google.com/abc-defg-hij \
|
||||
|
||||
## 说明
|
||||
|
||||
Google Meet 的官方媒体 API 偏向接收,因此向 Meet 通话中发言仍然需要一个参会者路径。该插件会清楚地保留这条边界:Chrome 处理浏览器参会和本地音频路由;Twilio 处理电话拨入参会。
|
||||
Google Meet 的官方媒体 API 偏向接收,因此要在 Meet 通话中说话,仍然需要通过参会者路径。这个插件让这一边界保持可见:
|
||||
Chrome 负责浏览器参会和本地音频路由;Twilio 负责电话拨入参会。
|
||||
|
||||
Chrome 实时模式需要以下之一:
|
||||
Chrome 实时模式需要以下两种方式之一:
|
||||
|
||||
- `chrome.audioInputCommand` 加 `chrome.audioOutputCommand`:OpenClaw 拥有实时模型桥接,并在这些命令与所选实时语音提供商之间传输 8 kHz G.711 mu-law 音频。
|
||||
- `chrome.audioInputCommand` 加上 `chrome.audioOutputCommand`:OpenClaw 拥有实时模型桥接,并在这些命令与所选实时语音提供商之间传输 8 kHz G.711 mu-law 音频。
|
||||
- `chrome.audioBridgeCommand`:一个外部桥接命令拥有整个本地音频路径,并且必须在启动或验证其守护进程后退出。
|
||||
|
||||
为了获得干净的双工音频,请将 Meet 输出和 Meet 麦克风分别路由到单独的虚拟设备,或使用类似 Loopback 的虚拟设备图。单个共享的 BlackHole 设备可能会将其他参与者的声音回送到通话中。
|
||||
为了获得干净的双工音频,请将 Meet 输出和 Meet 麦克风路由到不同的虚拟设备,或使用 Loopback 风格的虚拟设备图。单个共享的 BlackHole 设备可能会把其他参会者的声音回传到通话中。
|
||||
|
||||
`googlemeet speak` 会触发 Chrome 会话的活动实时音频桥接。`googlemeet leave` 会停止该桥接。对于通过 Voice Call 插件委派的 Twilio 会话,`leave` 也会挂断底层语音呼叫。
|
||||
`googlemeet speak` 会触发 Chrome 会话的活动实时音频桥接。
|
||||
`googlemeet leave` 会停止该桥接。对于通过 Voice Call 插件委托的 Twilio 会话,`leave` 也会挂断底层语音通话。
|
||||
|
||||
## 相关内容
|
||||
|
||||
- [Voice call 插件](/zh-CN/plugins/voice-call)
|
||||
- [Talk 模式](/zh-CN/nodes/talk)
|
||||
- [Voice call plugin](/zh-CN/plugins/voice-call)
|
||||
- [Talk mode](/zh-CN/nodes/talk)
|
||||
- [构建插件](/zh-CN/plugins/building-plugins)
|
||||
|
||||
@ -1,26 +1,29 @@
|
||||
---
|
||||
read_when:
|
||||
- 你正在构建一个插件,它需要 `before_tool_call`、`before_agent_reply`、消息钩子或生命周期钩子
|
||||
- 你需要从插件中拦截、改写或要求批准工具调用
|
||||
- 你正在构建一个需要 `before_tool_call`、`before_agent_reply`、消息钩子或生命周期钩子的插件
|
||||
- 你需要通过插件阻止、重写或要求批准工具调用
|
||||
- 你正在内部钩子和插件钩子之间做选择
|
||||
summary: 插件钩子:拦截智能体、工具、消息、会话以及 Gateway 网关生命周期事件
|
||||
summary: 插件钩子:拦截智能体、工具、消息、会话和 Gateway 网关生命周期事件
|
||||
title: 插件钩子
|
||||
x-i18n:
|
||||
generated_at: "2026-04-24T20:10:22Z"
|
||||
generated_at: "2026-04-25T05:55:26Z"
|
||||
model: gpt-5.4
|
||||
provider: openai
|
||||
source_hash: e880a8eb3b69e67450ddedd40e0356645e0cbd1825d8846a069d972b7e0c858c
|
||||
source_hash: f263fb9064811de79fc4744ce13c5a7b9afb2d3b00330975426348af3411dc76
|
||||
source_path: plugins/hooks.md
|
||||
workflow: 15
|
||||
---
|
||||
|
||||
插件钩子是 OpenClaw 插件的进程内扩展点。当插件需要检查或更改智能体运行、工具调用、消息流、会话生命周期、子智能体路由、安装流程或 Gateway 网关启动时,请使用它们。
|
||||
插件钩子是 OpenClaw 插件的进程内扩展点。当插件需要检查或更改智能体运行、工具调用、消息流、
|
||||
会话生命周期、子智能体路由、安装流程或 Gateway 网关启动时,请使用它们。
|
||||
|
||||
如果你想要一个由操作员安装的轻量 `HOOK.md` 脚本来处理命令和 Gateway 网关事件,例如 `/new`、`/reset`、`/stop`、`agent:bootstrap` 或 `gateway:startup`,请改用 [内部钩子](/zh-CN/automation/hooks)。
|
||||
如果你想使用一个由运维人员安装的小型 `HOOK.md` 脚本来处理命令和 Gateway 网关事件,例如
|
||||
`/new`、`/reset`、`/stop`、`agent:bootstrap` 或 `gateway:startup`,
|
||||
请改用 [内部钩子](/zh-CN/automation/hooks)。
|
||||
|
||||
## 快速开始
|
||||
|
||||
在你的插件入口中使用 `api.on(...)` 注册带类型的插件钩子:
|
||||
从你的插件入口中使用 `api.on(...)` 注册带类型的插件钩子:
|
||||
|
||||
```typescript
|
||||
import { definePluginEntry } from "openclaw/plugin-sdk/plugin-entry";
|
||||
@ -52,42 +55,44 @@ export default definePluginEntry({
|
||||
});
|
||||
```
|
||||
|
||||
钩子处理器会按照 `priority` 的降序依次运行。同一优先级的钩子会保持注册顺序。
|
||||
钩子处理器按 `priority` 降序依次运行。相同优先级的钩子
|
||||
会保持注册顺序。
|
||||
|
||||
## 钩子目录
|
||||
|
||||
钩子按其扩展的功能面分组。以 **粗体** 标出的名称接受决策结果(阻止、取消、覆盖或要求批准);其余钩子仅用于观察。
|
||||
钩子按其扩展的 surface 分组。**加粗**的名称接受一个
|
||||
决策结果(阻止、取消、覆盖或要求批准);其余都仅用于观察。
|
||||
|
||||
**智能体轮次**
|
||||
|
||||
- `before_model_resolve` — 在加载会话消息之前覆盖提供商或模型
|
||||
- `before_prompt_build` — 在模型调用之前添加动态上下文或系统提示文本
|
||||
- `before_agent_start` — 仅用于兼容性的合并阶段;优先使用上面的两个钩子
|
||||
- **`before_agent_reply`** — 使用合成回复或静默来短路模型轮次
|
||||
- `before_model_resolve` — 在加载会话消息前覆盖提供商或模型
|
||||
- `before_prompt_build` — 在模型调用前添加动态上下文或系统提示词文本
|
||||
- `before_agent_start` — 仅用于兼容性的组合阶段;优先使用上面的两个钩子
|
||||
- **`before_agent_reply`** — 用合成回复或静默来短路模型轮次
|
||||
- `agent_end` — 观察最终消息、成功状态和运行时长
|
||||
|
||||
**对话观察**
|
||||
|
||||
- `llm_input` — 观察提供商输入(系统提示、提示词、历史记录)
|
||||
- `llm_input` — 观察提供商输入(系统提示词、提示词、历史)
|
||||
- `llm_output` — 观察提供商输出
|
||||
|
||||
**工具**
|
||||
|
||||
- **`before_tool_call`** — 重写工具参数、阻止执行或要求批准
|
||||
- `after_tool_call` — 观察工具结果、错误和耗时
|
||||
- `after_tool_call` — 观察工具结果、错误和持续时间
|
||||
- **`tool_result_persist`** — 重写根据工具结果生成的助手消息
|
||||
- **`before_message_write`** — 检查或阻止进行中的消息写入(少见)
|
||||
- **`before_message_write`** — 检查或阻止正在进行的消息写入(少见)
|
||||
|
||||
**消息与投递**
|
||||
**消息和投递**
|
||||
|
||||
- **`inbound_claim`** — 在智能体路由之前声明一条入站消息(合成回复)
|
||||
- **`inbound_claim`** — 在智能体路由前认领入站消息(合成回复)
|
||||
- `message_received` — 观察入站内容、发送者、线程和元数据
|
||||
- **`message_sending`** — 重写出站内容或取消投递
|
||||
- `message_sent` — 观察出站投递成功或失败
|
||||
- **`before_dispatch`** — 在交给渠道之前检查或重写一条出站分发
|
||||
- **`reply_dispatch`** — 参与最终回复分发流水线
|
||||
- **`before_dispatch`** — 在交给渠道前检查或重写出站派发
|
||||
- **`reply_dispatch`** — 参与最终回复派发流水线
|
||||
|
||||
**会话与压缩**
|
||||
**会话和压缩**
|
||||
|
||||
- `session_start` / `session_end` — 跟踪会话生命周期边界
|
||||
- `before_compaction` / `after_compaction` — 观察或标注压缩周期
|
||||
@ -99,18 +104,19 @@ export default definePluginEntry({
|
||||
|
||||
**生命周期**
|
||||
|
||||
- `gateway_start` / `gateway_stop` — 随 Gateway 网关启动或停止由插件拥有的服务
|
||||
- **`before_install`** — 检查 Skills 或插件安装扫描,并可选择阻止安装
|
||||
- `gateway_start` / `gateway_stop` — 随 Gateway 网关启动或停止插件自有服务
|
||||
- **`before_install`** — 检查 Skills 或插件安装扫描,并可选择阻止
|
||||
|
||||
## 工具调用策略
|
||||
|
||||
`before_tool_call` 会接收:
|
||||
`before_tool_call` 接收:
|
||||
|
||||
- `event.toolName`
|
||||
- `event.params`
|
||||
- 可选的 `event.runId`
|
||||
- 可选的 `event.toolCallId`
|
||||
- 上下文字段,例如 `ctx.agentId`、`ctx.sessionKey`、`ctx.sessionId`,以及诊断字段 `ctx.trace`
|
||||
- 上下文字段,例如 `ctx.agentId`、`ctx.sessionKey`、`ctx.sessionId`,以及
|
||||
诊断字段 `ctx.trace`
|
||||
|
||||
它可以返回:
|
||||
|
||||
@ -135,25 +141,33 @@ type BeforeToolCallResult = {
|
||||
|
||||
规则:
|
||||
|
||||
- `block: true` 是终止性的,并会跳过较低优先级的处理器。
|
||||
- `block: false` 会被视为未作出决策。
|
||||
- `params` 会重写用于执行的工具参数。
|
||||
- `requireApproval` 会暂停智能体运行,并通过插件批准机制向用户发起请求。`/approve` 命令既可批准 exec 批准,也可批准插件批准。
|
||||
- 即使较高优先级的钩子请求了批准,较低优先级的 `block: true` 仍然可以阻止执行。
|
||||
- `onResolution` 会接收已解析的批准决定——`allow-once`、`allow-always`、`deny`、`timeout` 或 `cancelled`。
|
||||
- `block: true` 是终止性的,并会跳过更低优先级的处理器。
|
||||
- `block: false` 会被视为没有决策。
|
||||
- `params` 会重写执行时使用的工具参数。
|
||||
- `requireApproval` 会暂停智能体运行,并通过插件
|
||||
批准机制向用户发起请求。`/approve` 命令既可以批准 exec,也可以批准插件批准请求。
|
||||
- 即使更高优先级的钩子请求了批准,更低优先级的 `block: true`
|
||||
仍然可以阻止执行。
|
||||
- `onResolution` 会接收最终的批准决策——`allow-once`、
|
||||
`allow-always`、`deny`、`timeout` 或 `cancelled`。
|
||||
|
||||
## 提示词与模型钩子
|
||||
## 提示词和模型钩子
|
||||
|
||||
对于新插件,请使用按阶段划分的钩子:
|
||||
新插件请使用分阶段钩子:
|
||||
|
||||
- `before_model_resolve`:只接收当前提示词和附件元数据。返回 `providerOverride` 或 `modelOverride`。
|
||||
- `before_prompt_build`:接收当前提示词和会话消息。返回 `prependContext`、`systemPrompt`、`prependSystemContext` 或 `appendSystemContext`。
|
||||
- `before_model_resolve`:仅接收当前提示词和附件
|
||||
元数据。返回 `providerOverride` 或 `modelOverride`。
|
||||
- `before_prompt_build`:接收当前提示词和会话消息。
|
||||
返回 `prependContext`、`systemPrompt`、`prependSystemContext` 或
|
||||
`appendSystemContext`。
|
||||
|
||||
`before_agent_start` 仍然保留用于兼容性。优先使用上面的显式钩子,这样你的插件就不会依赖旧版合并阶段。
|
||||
`before_agent_start` 仍然保留用于兼容性。优先使用上面的显式钩子,
|
||||
这样你的插件就不会依赖旧的组合阶段。
|
||||
|
||||
当 OpenClaw 能识别当前活动运行时,`before_agent_start` 和 `agent_end` 会包含 `event.runId`。同一个值也可通过 `ctx.runId` 获取。
|
||||
当 OpenClaw 能识别当前活动运行时,`before_agent_start` 和 `agent_end`
|
||||
会包含 `event.runId`。同一个值也可通过 `ctx.runId` 获取。
|
||||
|
||||
需要 `llm_input`、`llm_output` 或 `agent_end` 的非内置插件必须设置:
|
||||
需要 `llm_input`、`llm_output` 或 `agent_end` 的非内置插件,必须设置:
|
||||
|
||||
```json
|
||||
{
|
||||
@ -169,52 +183,77 @@ type BeforeToolCallResult = {
|
||||
}
|
||||
```
|
||||
|
||||
可修改提示词的钩子可以按插件禁用,方式是设置 `plugins.entries.<id>.hooks.allowPromptInjection=false`。
|
||||
可以按插件禁用会修改提示词的钩子,方式为
|
||||
`plugins.entries.<id>.hooks.allowPromptInjection=false`。
|
||||
|
||||
## 消息钩子
|
||||
|
||||
对渠道级路由和投递策略,请使用消息钩子:
|
||||
将消息钩子用于渠道级路由和投递策略:
|
||||
|
||||
- `message_received`:观察入站内容、发送者、`threadId`、`messageId`、`senderId`、可选的运行/会话关联以及元数据。
|
||||
- `message_received`:观察入站内容、发送者、`threadId`、`messageId`、
|
||||
`senderId`、可选的运行/会话关联信息,以及元数据。
|
||||
- `message_sending`:重写 `content` 或返回 `{ cancel: true }`。
|
||||
- `message_sent`:观察最终成功或失败。
|
||||
|
||||
消息钩子的上下文会在可用时公开稳定的关联字段:
|
||||
`ctx.sessionKey`、`ctx.runId`、`ctx.messageId`、`ctx.senderId`、`ctx.trace`、`ctx.traceId`、`ctx.spanId`、`ctx.parentSpanId` 和 `ctx.callDepth`。在读取旧版元数据之前,优先使用这些一等字段。
|
||||
对于纯音频 TTS 回复,即使渠道负载中没有可见文本/说明,
|
||||
`content` 也可能包含隐藏的朗读转录文本。重写该 `content`
|
||||
只会更新钩子可见的转录文本;它不会渲染为媒体说明。
|
||||
|
||||
优先使用带类型的 `threadId` 和 `replyToId` 字段,而不是使用特定于渠道的元数据。
|
||||
消息钩子上下文会在可用时暴露稳定的关联字段:
|
||||
`ctx.sessionKey`、`ctx.runId`、`ctx.messageId`、`ctx.senderId`、`ctx.trace`、
|
||||
`ctx.traceId`、`ctx.spanId`、`ctx.parentSpanId` 和 `ctx.callDepth`。在读取旧版元数据之前,
|
||||
优先使用这些一等字段。
|
||||
|
||||
在使用渠道特定元数据之前,优先使用带类型的 `threadId` 和 `replyToId` 字段。
|
||||
|
||||
决策规则:
|
||||
|
||||
- 带有 `cancel: true` 的 `message_sending` 是终止性的。
|
||||
- 带有 `cancel: false` 的 `message_sending` 会被视为未作出决策。
|
||||
- 被重写的 `content` 会继续传递给较低优先级的钩子,除非后续钩子取消投递。
|
||||
- 带有 `cancel: false` 的 `message_sending` 会被视为没有决策。
|
||||
- 被重写的 `content` 会继续传递给更低优先级的钩子,除非后续钩子
|
||||
取消了投递。
|
||||
|
||||
## 安装钩子
|
||||
|
||||
`before_install` 会在内置的 Skills 和插件安装扫描之后运行。返回额外发现项,或返回 `{ block: true, blockReason }` 来停止安装。
|
||||
`before_install` 会在内置的 Skills 和插件安装扫描之后运行。
|
||||
返回额外发现项,或返回 `{ block: true, blockReason }` 以停止
|
||||
安装。
|
||||
|
||||
`block: true` 是终止性的。`block: false` 会被视为未作出决策。
|
||||
`block: true` 是终止性的。`block: false` 会被视为没有决策。
|
||||
|
||||
## Gateway 网关生命周期
|
||||
|
||||
对需要 Gateway 网关拥有状态的插件服务,请使用 `gateway_start`。上下文会公开 `ctx.config`、`ctx.workspaceDir` 和 `ctx.getCron?.()`,用于检查和更新 cron。使用 `gateway_stop` 清理长时间运行的资源。
|
||||
将 `gateway_start` 用于需要 Gateway 网关自有状态的插件服务。该
|
||||
上下文会暴露 `ctx.config`、`ctx.workspaceDir` 和 `ctx.getCron?.()`,用于
|
||||
检查和更新 cron。使用 `gateway_stop` 清理长时间运行的资源。
|
||||
|
||||
不要依赖内部的 `gateway:startup` 钩子来运行由插件拥有的运行时服务。
|
||||
不要依赖内部的 `gateway:startup` 钩子来管理插件自有运行时
|
||||
服务。
|
||||
|
||||
## 即将弃用的内容
|
||||
|
||||
有少量与钩子相邻的功能面已被弃用,但仍受支持。请在下一个主要版本发布之前完成迁移:
|
||||
少量与钩子相邻的 surface 已被弃用,但仍受支持。请在下一个主要版本前
|
||||
完成迁移:
|
||||
|
||||
- **`inbound_claim` 和 `message_received` 处理器中的纯文本渠道信封**。请读取 `BodyForAgent` 和结构化的用户上下文块,而不是解析扁平信封文本。参见 [纯文本渠道信封 → BodyForAgent](/zh-CN/plugins/sdk-migration#active-deprecations)。
|
||||
- **`before_agent_start`** 仍保留用于兼容性。新插件应使用 `before_model_resolve` 和 `before_prompt_build`,而不是合并阶段。
|
||||
- **`before_tool_call` 中的 `onResolution`** 现在使用带类型的 `PluginApprovalResolution` 联合类型(`allow-once` / `allow-always` / `deny` / `timeout` / `cancelled`),而不是自由形式的 `string`。
|
||||
- **`inbound_claim` 和 `message_received` 处理器中的纯文本渠道信封**。
|
||||
请读取 `BodyForAgent` 和结构化用户上下文块,
|
||||
而不是解析扁平信封文本。参见
|
||||
[纯文本渠道信封 → BodyForAgent](/zh-CN/plugins/sdk-migration#active-deprecations)。
|
||||
- **`before_agent_start`** 仍保留用于兼容性。新插件应使用
|
||||
`before_model_resolve` 和 `before_prompt_build`,而不是这个组合
|
||||
阶段。
|
||||
- **`before_tool_call` 中的 `onResolution`** 现在使用带类型的
|
||||
`PluginApprovalResolution` 联合类型(`allow-once` / `allow-always` / `deny` /
|
||||
`timeout` / `cancelled`),而不是自由形式的 `string`。
|
||||
|
||||
完整列表——包括 memory 能力注册、提供商 thinking 配置文件、外部身份验证提供商、提供商发现类型、任务运行时访问器,以及 `command-auth` → `command-status` 重命名——请参见 [插件 SDK 迁移 → 当前弃用项](/zh-CN/plugins/sdk-migration#active-deprecations)。
|
||||
完整列表——包括 memory 能力注册、提供商 thinking
|
||||
profile、外部认证提供商、提供商发现类型、任务运行时
|
||||
访问器,以及 `command-auth` → `command-status` 重命名——请参见
|
||||
[插件 SDK 迁移 → 当前弃用项](/zh-CN/plugins/sdk-migration#active-deprecations)。
|
||||
|
||||
## 相关内容
|
||||
|
||||
- [Plugin SDK migration](/zh-CN/plugins/sdk-migration) — 当前弃用项和移除时间线
|
||||
- [插件 SDK 迁移](/zh-CN/plugins/sdk-migration) — 当前弃用项和移除时间线
|
||||
- [构建插件](/zh-CN/plugins/building-plugins)
|
||||
- [插件 SDK 概览](/zh-CN/plugins/sdk-overview)
|
||||
- [插件入口点](/zh-CN/plugins/sdk-entrypoints)
|
||||
|
||||
@ -1,24 +1,24 @@
|
||||
---
|
||||
read_when:
|
||||
- 你需要从插件调用核心辅助工具(TTS、STT、图像生成、网页搜索、子智能体、节点)
|
||||
- 你想了解 `api.runtime` 暴露了什么
|
||||
- 你正在从插件代码中访问配置、智能体或媒体辅助工具
|
||||
- 你需要从插件调用核心辅助工具(TTS、STT、图像生成、Web 搜索、子智能体、节点)
|
||||
- 你想了解 `api.runtime` 暴露了哪些内容
|
||||
- 你正在从插件代码访问配置、智能体或媒体辅助工具
|
||||
sidebarTitle: Runtime Helpers
|
||||
summary: '`api.runtime` —— 可供插件使用的注入式运行时辅助工具'
|
||||
summary: api.runtime —— 提供给插件的注入式运行时辅助工具
|
||||
title: 插件运行时辅助工具
|
||||
x-i18n:
|
||||
generated_at: "2026-04-25T03:16:17Z"
|
||||
generated_at: "2026-04-25T05:55:40Z"
|
||||
model: gpt-5.4
|
||||
provider: openai
|
||||
source_hash: f8c3e5d4db970299c4c6f9f703a63bc42f244627989f1b3489adf43aa87c8952
|
||||
source_hash: e9f1a56faf33ac18ea7e4b14f70d6f3a73c8b88481aeb0ee77035a17a03f15ce
|
||||
source_path: plugins/sdk-runtime.md
|
||||
workflow: 15
|
||||
---
|
||||
|
||||
每个插件在注册期间都会注入 `api.runtime` 对象,本文档是它的参考说明。请使用这些辅助工具,而不是直接导入宿主内部实现。
|
||||
提供给每个插件在注册期间注入的 `api.runtime` 对象参考。请使用这些辅助工具,而不是直接导入宿主内部实现。
|
||||
|
||||
<Tip>
|
||||
**想看操作演练?** 请参阅 [渠道插件](/zh-CN/plugins/sdk-channel-plugins) 或 [提供商插件](/zh-CN/plugins/sdk-provider-plugins) 中的分步指南,这些指南会在实际上下文中展示这些辅助工具的用法。
|
||||
**想看操作演示?** 请参见 [渠道插件](/zh-CN/plugins/sdk-channel-plugins) 或 [提供商插件](/zh-CN/plugins/sdk-provider-plugins) 的分步指南,这些指南会在上下文中展示这些辅助工具的使用方式。
|
||||
</Tip>
|
||||
|
||||
```typescript
|
||||
@ -31,28 +31,28 @@ register(api) {
|
||||
|
||||
### `api.runtime.agent`
|
||||
|
||||
智能体身份、目录与会话管理。
|
||||
智能体身份、目录和会话管理。
|
||||
|
||||
```typescript
|
||||
// 解析智能体的工作目录
|
||||
// Resolve the agent's working directory
|
||||
const agentDir = api.runtime.agent.resolveAgentDir(cfg);
|
||||
|
||||
// 解析智能体工作区
|
||||
// Resolve agent workspace
|
||||
const workspaceDir = api.runtime.agent.resolveAgentWorkspaceDir(cfg);
|
||||
|
||||
// 获取智能体身份
|
||||
// Get agent identity
|
||||
const identity = api.runtime.agent.resolveAgentIdentity(cfg);
|
||||
|
||||
// 获取默认思考级别
|
||||
// Get default thinking level
|
||||
const thinking = api.runtime.agent.resolveThinkingDefault(cfg, provider, model);
|
||||
|
||||
// 获取智能体超时时间
|
||||
// Get agent timeout
|
||||
const timeoutMs = api.runtime.agent.resolveAgentTimeoutMs(cfg);
|
||||
|
||||
// 确保工作区存在
|
||||
// Ensure workspace exists
|
||||
await api.runtime.agent.ensureAgentWorkspace(cfg);
|
||||
|
||||
// 运行一次嵌入式智能体轮次
|
||||
// Run an embedded agent turn
|
||||
const agentDir = api.runtime.agent.resolveAgentDir(cfg);
|
||||
const result = await api.runtime.agent.runEmbeddedAgent({
|
||||
sessionId: "my-plugin:task-1",
|
||||
@ -64,11 +64,11 @@ const result = await api.runtime.agent.runEmbeddedAgent({
|
||||
});
|
||||
```
|
||||
|
||||
`runEmbeddedAgent(...)` 是一个中立辅助工具,用于从插件代码中启动一次普通的 OpenClaw 智能体轮次。它使用与渠道触发回复相同的 provider / model 解析逻辑,以及相同的 Agent harness 选择方式。
|
||||
`runEmbeddedAgent(...)` 是从插件代码启动普通 OpenClaw 智能体轮次的中立辅助工具。它使用与渠道触发回复相同的 provider/模型解析和 agent-harness 选择。
|
||||
|
||||
`runEmbeddedPiAgent(...)` 仍然保留为兼容性别名。
|
||||
`runEmbeddedPiAgent(...)` 仍保留为兼容性别名。
|
||||
|
||||
**会话存储辅助工具** 位于 `api.runtime.agent.session` 下:
|
||||
**会话存储辅助工具**位于 `api.runtime.agent.session` 下:
|
||||
|
||||
```typescript
|
||||
const storePath = api.runtime.agent.session.resolveStorePath(cfg);
|
||||
@ -79,11 +79,11 @@ const filePath = api.runtime.agent.session.resolveSessionFilePath(cfg, sessionId
|
||||
|
||||
### `api.runtime.agent.defaults`
|
||||
|
||||
默认模型和提供商常量:
|
||||
默认模型和 provider 常量:
|
||||
|
||||
```typescript
|
||||
const model = api.runtime.agent.defaults.model; // 例如 "anthropic/claude-sonnet-4-6"
|
||||
const provider = api.runtime.agent.defaults.provider; // 例如 "anthropic"
|
||||
const model = api.runtime.agent.defaults.model; // e.g. "anthropic/claude-sonnet-4-6"
|
||||
const provider = api.runtime.agent.defaults.provider; // e.g. "anthropic"
|
||||
```
|
||||
|
||||
### `api.runtime.subagent`
|
||||
@ -91,38 +91,38 @@ const provider = api.runtime.agent.defaults.provider; // 例如 "anthropic"
|
||||
启动并管理后台子智能体运行。
|
||||
|
||||
```typescript
|
||||
// 启动一个子智能体运行
|
||||
// Start a subagent run
|
||||
const { runId } = await api.runtime.subagent.run({
|
||||
sessionKey: "agent:main:subagent:search-helper",
|
||||
message: "Expand this query into focused follow-up searches.",
|
||||
provider: "openai", // 可选覆盖
|
||||
model: "gpt-4.1-mini", // 可选覆盖
|
||||
provider: "openai", // optional override
|
||||
model: "gpt-4.1-mini", // optional override
|
||||
deliver: false,
|
||||
});
|
||||
|
||||
// 等待完成
|
||||
// Wait for completion
|
||||
const result = await api.runtime.subagent.waitForRun({ runId, timeoutMs: 30000 });
|
||||
|
||||
// 读取会话消息
|
||||
// Read session messages
|
||||
const { messages } = await api.runtime.subagent.getSessionMessages({
|
||||
sessionKey: "agent:main:subagent:search-helper",
|
||||
limit: 10,
|
||||
});
|
||||
|
||||
// 删除会话
|
||||
// Delete a session
|
||||
await api.runtime.subagent.deleteSession({
|
||||
sessionKey: "agent:main:subagent:search-helper",
|
||||
});
|
||||
```
|
||||
|
||||
<Warning>
|
||||
模型覆盖(`provider` / `model`)需要操作员在配置中显式启用 `plugins.entries.<id>.subagent.allowModelOverride: true`。
|
||||
不受信任的插件仍然可以运行子智能体,但其覆盖请求会被拒绝。
|
||||
模型覆盖(`provider`/`model`)需要操作员在配置中通过 `plugins.entries.<id>.subagent.allowModelOverride: true` 显式启用。
|
||||
不受信任的插件仍然可以运行子智能体,但覆盖请求会被拒绝。
|
||||
</Warning>
|
||||
|
||||
### `api.runtime.nodes`
|
||||
|
||||
列出已连接节点,并从 Gateway 网关加载的插件代码或插件 CLI 命令中调用节点宿主命令。当某个插件拥有配对设备上的本地工作时,请使用此功能,例如另一台 Mac 上的浏览器桥接或音频桥接。
|
||||
列出已连接节点,并从 Gateway 网关加载的插件代码或插件 CLI 命令中调用节点主机命令。当插件在已配对设备上拥有本地工作时,请使用此功能,例如在另一台 Mac 上的浏览器或音频桥接。
|
||||
|
||||
```typescript
|
||||
const { nodes } = await api.runtime.nodes.list({ connected: true });
|
||||
@ -135,11 +135,11 @@ const result = await api.runtime.nodes.invoke({
|
||||
});
|
||||
```
|
||||
|
||||
在 Gateway 网关内部,这个运行时是进程内调用。在插件 CLI 命令中,它会通过 RPC 调用已配置的 Gateway 网关,因此像 `openclaw googlemeet recover-tab` 这样的命令也可以从终端检查已配对的节点。节点命令仍然会经过正常的 Gateway 网关节点配对、命令允许列表以及节点本地命令处理流程。
|
||||
在 Gateway 网关内部,此运行时是进程内的。在插件 CLI 命令中,它会通过 RPC 调用已配置的 Gateway 网关,因此像 `openclaw googlemeet recover-tab` 这样的命令可以从终端检查已配对节点。节点命令仍然会经过正常的 Gateway 网关节点配对、命令允许列表和节点本地命令处理。
|
||||
|
||||
### `api.runtime.taskFlow`
|
||||
|
||||
将 Task Flow 运行时绑定到现有的 OpenClaw 会话键或受信任的工具上下文,然后在不需要每次调用都传入所有者的情况下创建和管理 Task Flows。
|
||||
将 Task Flow 运行时绑定到现有 OpenClaw 会话键或受信任工具上下文,然后在无需每次调用都传入所有者的情况下创建和管理 Task Flows。
|
||||
|
||||
```typescript
|
||||
const taskFlow = api.runtime.taskFlow.fromToolContext(ctx);
|
||||
@ -166,70 +166,70 @@ const waiting = taskFlow.setWaiting({
|
||||
});
|
||||
```
|
||||
|
||||
当你已经从自己的绑定层中获得受信任的 OpenClaw 会话键时,请使用 `bindSession({ sessionKey, requesterOrigin })`。不要从原始用户输入中进行绑定。
|
||||
当你已经从自己的绑定层获得受信任的 OpenClaw 会话键时,请使用 `bindSession({ sessionKey, requesterOrigin })`。不要从原始用户输入进行绑定。
|
||||
|
||||
### `api.runtime.tts`
|
||||
|
||||
文本转语音。
|
||||
文本转语音合成。
|
||||
|
||||
```typescript
|
||||
// 标准 TTS
|
||||
// Standard TTS
|
||||
const clip = await api.runtime.tts.textToSpeech({
|
||||
text: "Hello from OpenClaw",
|
||||
cfg: api.config,
|
||||
});
|
||||
|
||||
// 面向电话场景优化的 TTS
|
||||
// Telephony-optimized TTS
|
||||
const telephonyClip = await api.runtime.tts.textToSpeechTelephony({
|
||||
text: "Hello from OpenClaw",
|
||||
cfg: api.config,
|
||||
});
|
||||
|
||||
// 列出可用语音
|
||||
// List available voices
|
||||
const voices = await api.runtime.tts.listVoices({
|
||||
provider: "elevenlabs",
|
||||
cfg: api.config,
|
||||
});
|
||||
```
|
||||
|
||||
使用核心 `messages.tts` 配置和 provider 选择逻辑。返回 PCM 音频缓冲区和采样率。
|
||||
使用核心 `messages.tts` 配置和 provider 选择。返回 PCM 音频缓冲区 + 采样率。
|
||||
|
||||
### `api.runtime.mediaUnderstanding`
|
||||
|
||||
图像、音频和视频分析。
|
||||
|
||||
```typescript
|
||||
// 描述图像
|
||||
// Describe an image
|
||||
const image = await api.runtime.mediaUnderstanding.describeImageFile({
|
||||
filePath: "/tmp/inbound-photo.jpg",
|
||||
cfg: api.config,
|
||||
agentDir: "/tmp/agent",
|
||||
});
|
||||
|
||||
// 转写音频
|
||||
// Transcribe audio
|
||||
const { text } = await api.runtime.mediaUnderstanding.transcribeAudioFile({
|
||||
filePath: "/tmp/inbound-audio.ogg",
|
||||
cfg: api.config,
|
||||
mime: "audio/ogg", // 可选,用于无法推断 MIME 时
|
||||
mime: "audio/ogg", // optional, for when MIME cannot be inferred
|
||||
});
|
||||
|
||||
// 描述视频
|
||||
// Describe a video
|
||||
const video = await api.runtime.mediaUnderstanding.describeVideoFile({
|
||||
filePath: "/tmp/inbound-video.mp4",
|
||||
cfg: api.config,
|
||||
});
|
||||
|
||||
// 通用文件分析
|
||||
// Generic file analysis
|
||||
const result = await api.runtime.mediaUnderstanding.runFile({
|
||||
filePath: "/tmp/inbound-file.pdf",
|
||||
cfg: api.config,
|
||||
});
|
||||
```
|
||||
|
||||
如果没有生成输出(例如输入被跳过),则返回 `{ text: undefined }`。
|
||||
当没有生成输出时(例如跳过输入),返回 `{ text: undefined }`。
|
||||
|
||||
<Info>
|
||||
`api.runtime.stt.transcribeAudioFile(...)` 仍然保留为 `api.runtime.mediaUnderstanding.transcribeAudioFile(...)` 的兼容性别名。
|
||||
`api.runtime.stt.transcribeAudioFile(...)` 仍保留为 `api.runtime.mediaUnderstanding.transcribeAudioFile(...)` 的兼容性别名。
|
||||
</Info>
|
||||
|
||||
### `api.runtime.imageGeneration`
|
||||
@ -247,7 +247,7 @@ const providers = api.runtime.imageGeneration.listProviders({ cfg: api.config })
|
||||
|
||||
### `api.runtime.webSearch`
|
||||
|
||||
网页搜索。
|
||||
Web 搜索。
|
||||
|
||||
```typescript
|
||||
const providers = api.runtime.webSearch.listProviders({ config: api.config });
|
||||
@ -260,7 +260,7 @@ const result = await api.runtime.webSearch.search({
|
||||
|
||||
### `api.runtime.media`
|
||||
|
||||
底层媒体工具。
|
||||
底层媒体辅助工具。
|
||||
|
||||
```typescript
|
||||
const webMedia = await api.runtime.media.loadWebMedia(url);
|
||||
@ -285,7 +285,7 @@ const pngQrFile = await api.runtime.media.writeQrPngTempFile("https://openclaw.a
|
||||
|
||||
### `api.runtime.config`
|
||||
|
||||
配置加载与写入。
|
||||
配置加载和写入。
|
||||
|
||||
```typescript
|
||||
const cfg = await api.runtime.config.loadConfig();
|
||||
@ -294,7 +294,7 @@ await api.runtime.config.writeConfigFile(cfg);
|
||||
|
||||
### `api.runtime.system`
|
||||
|
||||
系统级工具。
|
||||
系统级辅助工具。
|
||||
|
||||
```typescript
|
||||
await api.runtime.system.enqueueSystemEvent(event);
|
||||
@ -327,7 +327,7 @@ const childLogger = api.runtime.logging.getChildLogger({ plugin: "my-plugin" },
|
||||
|
||||
### `api.runtime.modelAuth`
|
||||
|
||||
模型和提供商凭证解析。
|
||||
模型和 provider 认证解析。
|
||||
|
||||
```typescript
|
||||
const auth = await api.runtime.modelAuth.getApiKeyForModel({ model, cfg });
|
||||
@ -357,9 +357,9 @@ api.runtime.tools.registerMemoryCli(/* ... */);
|
||||
|
||||
### `api.runtime.channel`
|
||||
|
||||
渠道专用运行时辅助工具(在加载渠道插件时可用)。
|
||||
渠道特定运行时辅助工具(在加载渠道插件时可用)。
|
||||
|
||||
`api.runtime.channel.mentions` 是使用运行时注入的内置渠道插件共享的入站提及策略接口:
|
||||
`api.runtime.channel.mentions` 是供使用运行时注入的内置渠道插件共享的入站 mention 策略能力面:
|
||||
|
||||
```typescript
|
||||
const mentionMatch = api.runtime.channel.mentions.matchesMentionWithExplicit(text, {
|
||||
@ -386,7 +386,7 @@ const decision = api.runtime.channel.mentions.resolveInboundMentionDecision({
|
||||
});
|
||||
```
|
||||
|
||||
可用的提及辅助工具包括:
|
||||
可用的 mention 辅助工具:
|
||||
|
||||
- `buildMentionRegexes`
|
||||
- `matchesMentionPatterns`
|
||||
@ -394,11 +394,11 @@ const decision = api.runtime.channel.mentions.resolveInboundMentionDecision({
|
||||
- `implicitMentionKindWhen`
|
||||
- `resolveInboundMentionDecision`
|
||||
|
||||
`api.runtime.channel.mentions` 有意不暴露较旧的 `resolveMentionGating*` 兼容性辅助工具。请优先使用标准化的 `{ facts, policy }` 路径。
|
||||
`api.runtime.channel.mentions` 有意不暴露旧版的 `resolveMentionGating*` 兼容辅助工具。请优先使用规范化的 `{ facts, policy }` 路径。
|
||||
|
||||
## 存储运行时引用
|
||||
|
||||
使用 `createPluginRuntimeStore` 存储运行时引用,以便在 `register` 回调之外使用:
|
||||
使用 `createPluginRuntimeStore` 来存储运行时引用,以便在 `register` 回调之外使用:
|
||||
|
||||
```typescript
|
||||
import { createPluginRuntimeStore } from "openclaw/plugin-sdk/runtime-store";
|
||||
@ -409,7 +409,7 @@ const store = createPluginRuntimeStore<PluginRuntime>({
|
||||
errorMessage: "my-plugin runtime not initialized",
|
||||
});
|
||||
|
||||
// 在你的入口点中
|
||||
// In your entry point
|
||||
export default defineChannelPluginEntry({
|
||||
id: "my-plugin",
|
||||
name: "My Plugin",
|
||||
@ -418,34 +418,34 @@ export default defineChannelPluginEntry({
|
||||
setRuntime: store.setRuntime,
|
||||
});
|
||||
|
||||
// 在其他文件中
|
||||
// In other files
|
||||
export function getRuntime() {
|
||||
return store.getRuntime(); // 如果未初始化则抛出异常
|
||||
return store.getRuntime(); // throws if not initialized
|
||||
}
|
||||
|
||||
export function tryGetRuntime() {
|
||||
return store.tryGetRuntime(); // 如果未初始化则返回 null
|
||||
return store.tryGetRuntime(); // returns null if not initialized
|
||||
}
|
||||
```
|
||||
|
||||
对于 runtime-store 标识,优先使用 `pluginId`。更底层的 `key` 形式适用于不常见的情况:某个插件有意需要多个运行时槽位。
|
||||
优先使用 `pluginId` 作为 runtime-store 标识。更底层的 `key` 形式适用于少见情况,即某个插件有意需要多个运行时槽位。
|
||||
|
||||
## 其他顶层 `api` 字段
|
||||
|
||||
除了 `api.runtime` 之外,API 对象还提供:
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
| ------------------------ | ------------------------- | -------------------------------------------------------------------------------------------- |
|
||||
| `api.id` | `string` | 插件 id |
|
||||
| `api.name` | `string` | 插件显示名称 |
|
||||
| `api.config` | `OpenClawConfig` | 当前配置快照(如果可用,则为活动的内存中运行时快照) |
|
||||
| `api.pluginConfig` | `Record<string, unknown>` | 来自 `plugins.entries.<id>.config` 的插件专用配置 |
|
||||
| `api.logger` | `PluginLogger` | 作用域化日志记录器(`debug`、`info`、`warn`、`error`) |
|
||||
| `api.registrationMode` | `PluginRegistrationMode` | 当前加载模式;`"setup-runtime"` 是完整入口启动 / 设置之前的轻量级启动 / 设置窗口 |
|
||||
| `api.resolvePath(input)` | `(string) => string` | 解析相对于插件根目录的路径 |
|
||||
| 字段 | 类型 | 说明 |
|
||||
| ------------------------ | ------------------------- | ------------------------------------------------------------------------------------------- |
|
||||
| `api.id` | `string` | 插件 id |
|
||||
| `api.name` | `string` | 插件显示名称 |
|
||||
| `api.config` | `OpenClawConfig` | 当前配置快照(可用时为活动中的内存运行时快照) |
|
||||
| `api.pluginConfig` | `Record<string, unknown>` | 来自 `plugins.entries.<id>.config` 的插件专用配置 |
|
||||
| `api.logger` | `PluginLogger` | 作用域日志记录器(`debug`、`info`、`warn`、`error`) |
|
||||
| `api.registrationMode` | `PluginRegistrationMode` | 当前加载模式;`"setup-runtime"` 是完整入口启动/设置前的轻量预启动/设置窗口 |
|
||||
| `api.resolvePath(input)` | `(string) => string` | 解析相对于插件根目录的路径 |
|
||||
|
||||
## 相关内容
|
||||
|
||||
- [SDK 概览](/zh-CN/plugins/sdk-overview) -- 子路径参考
|
||||
- [SDK 入口点](/zh-CN/plugins/sdk-entrypoints) -- `definePluginEntry` 选项
|
||||
- [插件架构内部机制](/zh-CN/plugins/architecture) -- 能力模型与注册表
|
||||
- [SDK 概览](/zh-CN/plugins/sdk-overview) — 子路径参考
|
||||
- [插件入口点](/zh-CN/plugins/sdk-entrypoints) — `definePluginEntry` 选项
|
||||
- [插件架构内部机制](/zh-CN/plugins/architecture) — 能力模型和注册表
|
||||
|
||||
@ -1,16 +1,16 @@
|
||||
---
|
||||
read_when:
|
||||
- 你正在为插件添加设置向导
|
||||
- 你正在为插件添加一个设置向导
|
||||
- 你需要了解 `setup-entry.ts` 与 `index.ts` 的区别
|
||||
- 你正在定义插件配置 schema 或 `package.json` 中的 openclaw 元数据
|
||||
sidebarTitle: Setup and Config
|
||||
summary: 设置向导、`setup-entry.ts`、配置 schema 和 `package.json` 元数据
|
||||
title: 插件设置与配置
|
||||
summary: 设置向导、setup-entry.ts、配置 schema 和 package.json 元数据
|
||||
title: 插件设置和配置
|
||||
x-i18n:
|
||||
generated_at: "2026-04-25T00:43:28Z"
|
||||
generated_at: "2026-04-25T05:55:40Z"
|
||||
model: gpt-5.4
|
||||
provider: openai
|
||||
source_hash: d27bba27f8bd7b8469cfc9dc8d65b12242eef9e04e1c20e5192e51ada6512491
|
||||
source_hash: 487cff34e0f9ae307a7c920dfc3cb0a8bbf2cac5e137abd8be4d1fbed19200ca
|
||||
source_path: plugins/sdk-setup.md
|
||||
workflow: 15
|
||||
---
|
||||
@ -19,14 +19,14 @@ x-i18n:
|
||||
(`openclaw.plugin.json`)、设置入口和配置 schema 的参考文档。
|
||||
|
||||
<Tip>
|
||||
**在找操作指南?** 操作型文档会在具体上下文中讲解打包:
|
||||
**想看操作指南?** 操作型指南会在上下文中介绍打包:
|
||||
[渠道插件](/zh-CN/plugins/sdk-channel-plugins#step-1-package-and-manifest) 和
|
||||
[提供商插件](/zh-CN/plugins/sdk-provider-plugins#step-1-package-and-manifest)。
|
||||
</Tip>
|
||||
|
||||
## 包元数据
|
||||
|
||||
你的 `package.json` 需要包含一个 `openclaw` 字段,用来告诉插件系统
|
||||
你的 `package.json` 需要一个 `openclaw` 字段,用来告诉插件系统
|
||||
你的插件提供了什么:
|
||||
|
||||
**渠道插件:**
|
||||
@ -69,47 +69,47 @@ x-i18n:
|
||||
}
|
||||
```
|
||||
|
||||
如果你要将插件发布到外部的 ClawHub,这些 `compat` 和 `build`
|
||||
字段是必需的。规范的发布代码片段位于
|
||||
如果你要将插件作为外部包发布到 ClawHub,这些 `compat` 和 `build`
|
||||
字段是必填的。规范的发布片段位于
|
||||
`docs/snippets/plugin-publish/`。
|
||||
|
||||
### `openclaw` 字段
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
| ------------ | ---------- | --------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `extensions` | `string[]` | 入口文件(相对于包根目录) |
|
||||
| `setupEntry` | `string` | 仅用于设置的轻量入口(可选) |
|
||||
| `channel` | `object` | 用于设置、选择器、快速开始和状态界面的渠道目录元数据 |
|
||||
| `providers` | `string[]` | 此插件注册的提供商 id |
|
||||
| `install` | `object` | 安装提示:`npmSpec`、`localPath`、`defaultChoice`、`minHostVersion`、`expectedIntegrity`、`allowInvalidConfigRecovery` |
|
||||
| `startup` | `object` | 启动行为标志 |
|
||||
| `extensions` | `string[]` | 入口点文件(相对于包根目录) |
|
||||
| `setupEntry` | `string` | 仅用于设置的轻量级入口(可选) |
|
||||
| `channel` | `object` | 用于设置、选择器、快速开始和 Status 界面的渠道目录元数据 |
|
||||
| `providers` | `string[]` | 该插件注册的 provider ID |
|
||||
| `install` | `object` | 安装提示:`npmSpec`、`localPath`、`defaultChoice`、`minHostVersion`、`expectedIntegrity`、`allowInvalidConfigRecovery` |
|
||||
| `startup` | `object` | 启动行为标志 |
|
||||
|
||||
### `openclaw.channel`
|
||||
|
||||
`openclaw.channel` 是廉价的包元数据,用于在运行时加载前支持渠道发现和设置
|
||||
界面。
|
||||
`openclaw.channel` 是轻量级包元数据,用于在运行时加载之前进行渠道发现和设置
|
||||
界面展示。
|
||||
|
||||
| 字段 | 类型 | 含义 |
|
||||
| -------------------------------------- | ---------- | ----------------------------------------------------------------------------- |
|
||||
| `id` | `string` | 规范渠道 id。 |
|
||||
| `label` | `string` | 主要渠道标签。 |
|
||||
| `selectionLabel` | `string` | 当需要与 `label` 不同时,用于选择器 / 设置的标签。 |
|
||||
| `detailLabel` | `string` | 用于更丰富的渠道目录和状态界面的次级详情标签。 |
|
||||
| `docsPath` | `string` | 用于设置和选择链接的文档路径。 |
|
||||
| `docsLabel` | `string` | 当需要不同于渠道 id 时,用于文档链接的覆盖标签。 |
|
||||
| `blurb` | `string` | 简短的新手引导 / 目录说明。 |
|
||||
| `order` | `number` | 在渠道目录中的排序顺序。 |
|
||||
| `aliases` | `string[]` | 用于渠道选择的额外查找别名。 |
|
||||
| `preferOver` | `string[]` | 此渠道应优先于的较低优先级插件 / 渠道 id。 |
|
||||
| `systemImage` | `string` | 用于渠道 UI 目录的可选图标 / system-image 名称。 |
|
||||
| `selectionDocsPrefix` | `string` | 在选择界面中文档链接前显示的前缀文本。 |
|
||||
| `selectionDocsOmitLabel` | `boolean` | 在选择文案中直接显示文档路径,而不是带标签的文档链接。 |
|
||||
| `selectionExtras` | `string[]` | 附加在选择文案中的额外简短字符串。 |
|
||||
| `markdownCapable` | `boolean` | 将渠道标记为支持 Markdown,用于出站格式决策。 |
|
||||
| `exposure` | `object` | 控制渠道在设置、已配置列表和文档界面中的可见性。 |
|
||||
| `quickstartAllowFrom` | `boolean` | 让此渠道加入标准快速开始 `allowFrom` 设置流程。 |
|
||||
| `forceAccountBinding` | `boolean` | 即使只存在一个账户,也要求显式账户绑定。 |
|
||||
| `preferSessionLookupForAnnounceTarget` | `boolean` | 为此渠道解析 announce 目标时优先使用会话查找。 |
|
||||
| `id` | `string` | 规范渠道 ID。 |
|
||||
| `label` | `string` | 主渠道标签。 |
|
||||
| `selectionLabel` | `string` | 当需要与 `label` 不同时,用于选择器/设置的标签。 |
|
||||
| `detailLabel` | `string` | 用于更丰富渠道目录和 Status 界面的次级详情标签。 |
|
||||
| `docsPath` | `string` | 用于设置和选择链接的文档路径。 |
|
||||
| `docsLabel` | `string` | 当文档链接标签需要与渠道 ID 不同时,使用该覆盖标签。 |
|
||||
| `blurb` | `string` | 简短的新手引导/目录说明。 |
|
||||
| `order` | `number` | 在渠道目录中的排序顺序。 |
|
||||
| `aliases` | `string[]` | 渠道选择的额外查找别名。 |
|
||||
| `preferOver` | `string[]` | 该渠道应优先于的低优先级插件/渠道 ID。 |
|
||||
| `systemImage` | `string` | 用于渠道 UI 目录的可选图标/system-image 名称。 |
|
||||
| `selectionDocsPrefix` | `string` | 在选择界面中文档链接前显示的前缀文本。 |
|
||||
| `selectionDocsOmitLabel` | `boolean` | 在选择文案中直接显示文档路径,而不是带标签的文档链接。 |
|
||||
| `selectionExtras` | `string[]` | 附加到选择文案中的额外短字符串。 |
|
||||
| `markdownCapable` | `boolean` | 将该渠道标记为支持 Markdown,以供出站格式化决策使用。 |
|
||||
| `exposure` | `object` | 控制渠道在设置、已配置列表和文档界面中的可见性。 |
|
||||
| `quickstartAllowFrom` | `boolean` | 允许该渠道使用标准快速开始 `allowFrom` 设置流程。 |
|
||||
| `forceAccountBinding` | `boolean` | 即使只存在一个账户,也要求显式账户绑定。 |
|
||||
| `preferSessionLookupForAnnounceTarget` | `boolean` | 为该渠道解析公告目标时,优先使用会话查找。 |
|
||||
|
||||
示例:
|
||||
|
||||
@ -143,11 +143,11 @@ x-i18n:
|
||||
|
||||
`exposure` 支持:
|
||||
|
||||
- `configured`:在已配置 / 状态类列表界面中包含该渠道
|
||||
- `setup`:在交互式设置 / 配置选择器中包含该渠道
|
||||
- `docs`:将该渠道标记为在文档 / 导航界面中面向公开
|
||||
- `configured`:在已配置/Status 风格的列表界面中包含该渠道
|
||||
- `setup`:在交互式设置/配置选择器中包含该渠道
|
||||
- `docs`:将该渠道标记为面向公开的文档/导航界面内容
|
||||
|
||||
`showConfigured` 和 `showInSetup` 仍作为旧版别名受支持。建议优先使用
|
||||
`showConfigured` 和 `showInSetup` 仍作为旧版别名受支持。推荐使用
|
||||
`exposure`。
|
||||
|
||||
### `openclaw.install`
|
||||
@ -156,26 +156,27 @@ x-i18n:
|
||||
|
||||
| 字段 | 类型 | 含义 |
|
||||
| ---------------------------- | -------------------- | -------------------------------------------------------------------------------- |
|
||||
| `npmSpec` | `string` | 用于安装 / 更新流程的规范 npm 规范。 |
|
||||
| `localPath` | `string` | 本地开发或内置安装路径。 |
|
||||
| `defaultChoice` | `"npm"` \| `"local"` | 当两者都可用时,首选的安装来源。 |
|
||||
| `minHostVersion` | `string` | 最低支持的 OpenClaw 版本,格式为 `>=x.y.z`。 |
|
||||
| `expectedIntegrity` | `string` | 预期的 npm 分发完整性字符串,通常为 `sha512-...`,用于固定版本安装。 |
|
||||
| `allowInvalidConfigRecovery` | `boolean` | 允许内置插件重装流程从特定的陈旧配置故障中恢复。 |
|
||||
| `npmSpec` | `string` | 安装/更新流程中使用的规范 npm spec。 |
|
||||
| `localPath` | `string` | 本地开发或内置安装路径。 |
|
||||
| `defaultChoice` | `"npm"` \| `"local"` | 当两者都可用时,优先的安装来源。 |
|
||||
| `minHostVersion` | `string` | 最低支持的 OpenClaw 版本,格式为 `>=x.y.z`。 |
|
||||
| `expectedIntegrity` | `string` | 预期的 npm dist integrity 字符串,通常为 `sha512-...`,用于固定版本安装。 |
|
||||
| `allowInvalidConfigRecovery` | `boolean` | 允许内置插件重装流程恢复某些特定的陈旧配置故障。 |
|
||||
|
||||
交互式新手引导也会使用 `openclaw.install` 来支持按需安装
|
||||
界面。如果你的插件在运行时加载前就暴露提供商认证选项或渠道设置 / 目录
|
||||
元数据,新手引导就可以显示该选择、提示选择 npm 或本地安装、安装或启用插件,然后继续选定流程。Npm 新手引导选项需要可信的目录元数据,以及注册表中的
|
||||
`npmSpec`;精确版本和 `expectedIntegrity` 是可选的固定项。如果
|
||||
存在 `expectedIntegrity`,安装 / 更新流程会强制校验它。请将“显示什么”
|
||||
元数据保存在 `openclaw.plugin.json` 中,将“如何安装”
|
||||
元数据保存在 `package.json` 中。
|
||||
界面。如果你的插件在运行时加载前就暴露 provider 认证选项或渠道设置/目录
|
||||
元数据,新手引导就可以显示该选项,提示选择 npm 还是本地安装,
|
||||
安装或启用插件,然后继续所选流程。Npm 新手引导选项需要受信任的目录元数据,
|
||||
并带有 registry `npmSpec`;精确版本和 `expectedIntegrity` 是可选的固定项。如果
|
||||
存在 `expectedIntegrity`,安装/更新流程会强制校验它。请将“显示什么”
|
||||
元数据保留在 `openclaw.plugin.json` 中,而“如何安装”
|
||||
元数据保留在 `package.json` 中。
|
||||
|
||||
如果设置了 `minHostVersion`,安装和清单注册表加载都会强制执行它。
|
||||
较旧的宿主会跳过该插件;无效的版本字符串会被拒绝。
|
||||
旧版本宿主会跳过该插件;无效的版本字符串会被拒绝。
|
||||
|
||||
对于固定版本的 npm 安装,请在 `npmSpec` 中保留精确版本,并添加
|
||||
预期的构件完整性:
|
||||
预期制品完整性值:
|
||||
|
||||
```json
|
||||
{
|
||||
@ -189,13 +190,15 @@ x-i18n:
|
||||
}
|
||||
```
|
||||
|
||||
`allowInvalidConfigRecovery` 不是对损坏配置的通用绕过方式。它
|
||||
仅用于狭义的内置插件恢复,以便重装 / 设置可以修复已知的升级遗留问题,例如缺失的内置插件路径,或该插件对应的陈旧 `channels.<id>`
|
||||
条目。如果配置因无关原因损坏,安装仍会默认拒绝,并提示操作员运行 `openclaw doctor --fix`。
|
||||
`allowInvalidConfigRecovery` 不是针对损坏配置的通用绕过开关。它
|
||||
仅用于狭义的内置插件恢复场景,这样重装/设置就可以修复已知的升级遗留问题,
|
||||
例如缺失的内置插件路径,或同一插件对应的陈旧 `channels.<id>`
|
||||
条目。如果配置因无关原因损坏,安装
|
||||
仍会默认失败关闭,并提示操作员运行 `openclaw doctor --fix`。
|
||||
|
||||
### 延迟完整加载
|
||||
|
||||
渠道插件可通过以下方式选择延迟加载:
|
||||
渠道插件可以通过以下配置选择延迟加载:
|
||||
|
||||
```json
|
||||
{
|
||||
@ -209,24 +212,23 @@ x-i18n:
|
||||
}
|
||||
```
|
||||
|
||||
启用后,即使对于已配置的渠道,OpenClaw 在监听前的启动
|
||||
阶段也只会加载 `setupEntry`。完整入口会在
|
||||
Gateway 网关开始监听之后加载。
|
||||
启用后,OpenClaw 在监听前启动阶段只会加载 `setupEntry`,即使是
|
||||
已经配置好的渠道也是如此。完整入口会在 Gateway 网关开始监听后再加载。
|
||||
|
||||
<Warning>
|
||||
仅当你的 `setupEntry` 在 Gateway 网关开始监听之前就注册了所有必需内容时,才启用延迟加载(渠道注册、HTTP 路由、
|
||||
Gateway 网关方法)。如果完整入口拥有必需的启动能力,请保持默认行为。
|
||||
只有当你的 `setupEntry` 在 Gateway 网关开始监听前就注册了所需的一切内容时,
|
||||
才应启用延迟加载(渠道注册、HTTP 路由、Gateway 网关方法)。如果完整入口拥有必需的启动能力,请保留默认行为。
|
||||
</Warning>
|
||||
|
||||
如果你的设置 / 完整入口会注册 Gateway 网关 RPC 方法,请将它们保留在
|
||||
插件专用前缀下。保留的核心管理命名空间(`config.*`、
|
||||
`exec.approvals.*`、`wizard.*`、`update.*`)仍归核心所有,并始终解析为
|
||||
`operator.admin`。
|
||||
如果你的设置/完整入口注册了 Gateway 网关 RPC 方法,请将它们放在
|
||||
插件专属前缀下。保留的核心管理命名空间(`config.*`、
|
||||
`exec.approvals.*`、`wizard.*`、`update.*`)仍归核心所有,并始终解析
|
||||
到 `operator.admin`。
|
||||
|
||||
## 插件清单
|
||||
|
||||
每个原生插件都必须在包根目录中提供一个 `openclaw.plugin.json`。
|
||||
OpenClaw 使用它在不执行插件代码的情况下验证配置。
|
||||
每个原生插件都必须在包根目录提供一个 `openclaw.plugin.json`。
|
||||
OpenClaw 用它在不执行插件代码的情况下验证配置。
|
||||
|
||||
```json
|
||||
{
|
||||
@ -261,7 +263,7 @@ OpenClaw 使用它在不执行插件代码的情况下验证配置。
|
||||
}
|
||||
```
|
||||
|
||||
即使插件没有任何配置,也必须提供 schema。空 schema 是有效的:
|
||||
即使插件没有任何配置,也必须提供一个 schema。空 schema 也是有效的:
|
||||
|
||||
```json
|
||||
{
|
||||
@ -273,7 +275,7 @@ OpenClaw 使用它在不执行插件代码的情况下验证配置。
|
||||
}
|
||||
```
|
||||
|
||||
完整 schema 参考请参见[插件清单](/zh-CN/plugins/manifest)。
|
||||
完整 schema 参考请参见 [插件清单](/zh-CN/plugins/manifest)。
|
||||
|
||||
## ClawHub 发布
|
||||
|
||||
@ -284,14 +286,14 @@ clawhub package publish your-org/your-plugin --dry-run
|
||||
clawhub package publish your-org/your-plugin
|
||||
```
|
||||
|
||||
旧版仅用于 Skills 的发布别名只适用于 Skills。插件包
|
||||
应始终使用 `clawhub package publish`。
|
||||
旧版仅 Skills 的发布别名是给 Skills 用的。插件包应当
|
||||
始终使用 `clawhub package publish`。
|
||||
|
||||
## 设置入口
|
||||
|
||||
`setup-entry.ts` 文件是 `index.ts` 的轻量替代方案,
|
||||
当 OpenClaw 仅需要设置界面时会加载它(新手引导、配置修复、
|
||||
已禁用渠道检查)。
|
||||
`setup-entry.ts` 文件是 `index.ts` 的轻量级替代方案,
|
||||
当 OpenClaw 只需要设置界面时(新手引导、配置修复、
|
||||
已禁用渠道检查),会加载它。
|
||||
|
||||
```typescript
|
||||
// setup-entry.ts
|
||||
@ -301,80 +303,78 @@ import { myChannelPlugin } from "./src/channel.js";
|
||||
export default defineSetupPluginEntry(myChannelPlugin);
|
||||
```
|
||||
|
||||
这样可以避免在设置流程中加载较重的运行时代码(加密库、CLI 注册、
|
||||
这可以避免在设置流程中加载重量级运行时代码(加密库、CLI 注册、
|
||||
后台服务)。
|
||||
|
||||
对于将设置安全导出保存在 sidecar 模块中的内置工作区渠道,
|
||||
可以使用来自
|
||||
`openclaw/plugin-sdk/channel-entry-contract` 的
|
||||
如果内置工作区渠道将设置安全的导出放在侧车模块中,
|
||||
可以使用
|
||||
`openclaw/plugin-sdk/channel-entry-contract` 提供的
|
||||
`defineBundledChannelSetupEntry(...)`,而不是
|
||||
`defineSetupPluginEntry(...)`。
|
||||
该内置契约也支持可选的
|
||||
`runtime` 导出,这样设置时的运行时接线就可以保持轻量且明确。
|
||||
|
||||
**OpenClaw 在以下情况下会使用 `setupEntry` 而不是完整入口:**
|
||||
该内置契约还支持可选的
|
||||
`runtime` 导出,以便让设置阶段的运行时接线保持轻量且显式。
|
||||
|
||||
- 渠道已禁用,但需要设置 / 新手引导界面
|
||||
- 渠道已启用但尚未配置
|
||||
**OpenClaw 在以下情况下会使用 `setupEntry`,而不是完整入口:**
|
||||
|
||||
- 渠道已禁用,但仍需要设置/新手引导界面
|
||||
- 渠道已启用,但尚未配置
|
||||
- 已启用延迟加载(`deferConfiguredChannelFullLoadUntilAfterListen`)
|
||||
|
||||
**`setupEntry` 必须注册的内容:**
|
||||
|
||||
- 渠道插件对象(通过 `defineSetupPluginEntry`)
|
||||
- 在 Gateway 网关监听之前所需的任何 HTTP 路由
|
||||
- Gateway 网关监听前所需的任何 HTTP 路由
|
||||
- 启动期间所需的任何 Gateway 网关方法
|
||||
|
||||
这些启动期 Gateway 网关方法仍应避免使用保留的核心管理
|
||||
这些启动阶段的 Gateway 网关方法仍应避免使用保留的核心管理
|
||||
命名空间,例如 `config.*` 或 `update.*`。
|
||||
|
||||
**`setupEntry` 不应包含的内容:**
|
||||
|
||||
- CLI 注册
|
||||
- 后台服务
|
||||
- 较重的运行时导入(加密、SDK)
|
||||
- 重量级运行时导入(加密、SDK)
|
||||
- 仅在启动后才需要的 Gateway 网关方法
|
||||
|
||||
### 窄范围设置辅助导入
|
||||
### 窄化的设置辅助导入
|
||||
|
||||
对于仅设置的高频路径,如果你只需要部分设置能力,
|
||||
请优先使用更窄的设置辅助导入面,而不是更宽泛的
|
||||
对于仅设置的热路径,若你只需要设置界面的一部分,
|
||||
优先使用窄化的设置辅助接缝,而不是更宽泛的
|
||||
`plugin-sdk/setup` 总入口:
|
||||
|
||||
| 导入路径 | 适用场景 | 关键导出 |
|
||||
| 导入路径 | 用途 | 关键导出 |
|
||||
| ---------------------------------- | ----------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `plugin-sdk/setup-runtime` | 在 `setupEntry` / 延迟渠道启动中仍可用的设置时运行时辅助工具 | `createPatchedAccountSetupAdapter`, `createEnvPatchedAccountSetupAdapter`, `createSetupInputPresenceValidator`, `noteChannelLookupFailure`, `noteChannelLookupSummary`, `promptResolvedAllowFrom`, `splitSetupEntries`, `createAllowlistSetupWizardProxy`, `createDelegatedSetupWizardProxy` |
|
||||
| `plugin-sdk/setup-runtime` | 在 `setupEntry` / 延迟渠道启动中仍可用的设置期运行时辅助工具 | `createPatchedAccountSetupAdapter`, `createEnvPatchedAccountSetupAdapter`, `createSetupInputPresenceValidator`, `noteChannelLookupFailure`, `noteChannelLookupSummary`, `promptResolvedAllowFrom`, `splitSetupEntries`, `createAllowlistSetupWizardProxy`, `createDelegatedSetupWizardProxy` |
|
||||
| `plugin-sdk/setup-adapter-runtime` | 具备环境感知能力的账户设置适配器 | `createEnvPatchedAccountSetupAdapter` |
|
||||
| `plugin-sdk/setup-tools` | 设置 / 安装 CLI / 归档 / 文档辅助工具 | `formatCliCommand`, `detectBinary`, `extractArchive`, `resolveBrewExecutable`, `formatDocsLink`, `CONFIG_DIR` |
|
||||
| `plugin-sdk/setup-tools` | 设置/安装 CLI/归档/文档辅助工具 | `formatCliCommand`, `detectBinary`, `extractArchive`, `resolveBrewExecutable`, `formatDocsLink`, `CONFIG_DIR` |
|
||||
|
||||
当你需要完整的共享设置工具箱时,请使用更宽泛的
|
||||
`plugin-sdk/setup` 导入面,包括诸如
|
||||
`moveSingleAccountChannelSectionToDefaultAccount(...)` 之类的配置补丁辅助工具。
|
||||
`plugin-sdk/setup` 接缝,其中包括配置补丁辅助函数,例如
|
||||
`moveSingleAccountChannelSectionToDefaultAccount(...)`。
|
||||
|
||||
这些设置补丁适配器在导入时仍然适合高频路径。它们对内置
|
||||
单账户提升契约导入面的查找是惰性的,因此导入
|
||||
`plugin-sdk/setup-runtime` 不会在适配器真正使用之前急切加载
|
||||
内置契约导入面发现逻辑。
|
||||
这些设置补丁适配器在导入时仍然是热路径安全的。它们内置的
|
||||
单账户提升契约界面查找是惰性的,因此导入
|
||||
`plugin-sdk/setup-runtime` 不会在适配器真正使用前,急切加载内置契约界面发现逻辑。
|
||||
|
||||
### 渠道自有的单账户提升
|
||||
|
||||
当一个渠道从单账户顶层配置升级到
|
||||
`channels.<id>.accounts.*` 时,默认共享行为会将提升后的
|
||||
账户作用域值移动到 `accounts.default` 中。
|
||||
当某个渠道从单账户顶层配置升级为
|
||||
`channels.<id>.accounts.*` 时,默认共享行为是将被提升的
|
||||
账户级值移入 `accounts.default`。
|
||||
|
||||
内置渠道可以通过其设置
|
||||
契约导入面缩小或覆盖该提升行为:
|
||||
内置渠道可以通过其设置契约界面缩小或覆盖这种提升行为:
|
||||
|
||||
- `singleAccountKeysToMove`:应移动到
|
||||
提升后账户中的额外顶层键
|
||||
- `namedAccountPromotionKeys`:当命名账户已存在时,仅这些
|
||||
键会移动到提升后的账户中;共享策略 / 投递键保留在
|
||||
渠道根级别
|
||||
- `resolveSingleAccountPromotionTarget(...)`:选择由哪个现有账户
|
||||
接收提升后的值
|
||||
- `singleAccountKeysToMove`:额外的顶层键,这些键应移入
|
||||
被提升的账户
|
||||
- `namedAccountPromotionKeys`:当已存在命名账户时,只有这些
|
||||
键会移入被提升的账户;共享策略/投递键保留在渠道根部
|
||||
- `resolveSingleAccountPromotionTarget(...)`:选择哪个现有账户
|
||||
接收被提升的值
|
||||
|
||||
Matrix 是当前的内置示例。如果恰好只存在一个已命名的 Matrix 账户,
|
||||
或者 `defaultAccount` 指向一个现有的非规范键,例如 `Ops`,
|
||||
则提升会保留该账户,而不是创建新的
|
||||
Matrix 是当前的内置示例。如果已经恰好存在一个命名的 Matrix 账户,
|
||||
或者如果 `defaultAccount` 指向某个现有的非规范键,例如 `Ops`,
|
||||
提升过程会保留该账户,而不是新建一个
|
||||
`accounts.default` 条目。
|
||||
|
||||
## 配置 schema
|
||||
@ -395,9 +395,9 @@ Matrix 是当前的内置示例。如果恰好只存在一个已命名的 Matrix
|
||||
}
|
||||
```
|
||||
|
||||
你的插件会在注册期间通过 `api.pluginConfig` 接收此配置。
|
||||
在注册期间,你的插件会通过 `api.pluginConfig` 接收到这份配置。
|
||||
|
||||
对于渠道专属配置,请改用渠道配置段:
|
||||
对于渠道专属配置,请改用渠道配置节:
|
||||
|
||||
```json5
|
||||
{
|
||||
@ -412,8 +412,8 @@ Matrix 是当前的内置示例。如果恰好只存在一个已命名的 Matrix
|
||||
|
||||
### 构建渠道配置 schema
|
||||
|
||||
使用 `buildChannelConfigSchema` 可将一个 Zod schema 转换为
|
||||
由插件自有配置工件使用的 `ChannelConfigSchema` 包装器:
|
||||
使用 `buildChannelConfigSchema` 将 Zod schema 转换为
|
||||
插件自有配置制品所使用的 `ChannelConfigSchema` 包装器:
|
||||
|
||||
```typescript
|
||||
import { z } from "zod";
|
||||
@ -430,8 +430,9 @@ const configSchema = buildChannelConfigSchema(accountSchema);
|
||||
```
|
||||
|
||||
对于第三方插件,冷路径契约仍然是插件清单:
|
||||
将生成的 JSON Schema 镜像到 `openclaw.plugin.json#channelConfigs` 中,
|
||||
这样配置 schema、设置和 UI 界面就可以在不加载运行时代码的情况下检查 `channels.<id>`。
|
||||
请将生成的 JSON Schema 镜像到 `openclaw.plugin.json#channelConfigs` 中,
|
||||
这样配置 schema、设置和 UI 界面就可以在不加载运行时代码的情况下检查
|
||||
`channels.<id>`。
|
||||
|
||||
## 设置向导
|
||||
|
||||
@ -470,22 +471,22 @@ const setupWizard: ChannelSetupWizard = {
|
||||
```
|
||||
|
||||
`ChannelSetupWizard` 类型支持 `credentials`、`textInputs`、
|
||||
`dmPolicy`、`allowFrom`、`groupAccess`、`prepare`、`finalize` 等。
|
||||
完整示例可参见内置插件包(例如 Discord 插件的 `src/channel.setup.ts`)。
|
||||
`dmPolicy`、`allowFrom`、`groupAccess`、`prepare`、`finalize` 等内容。
|
||||
完整示例请参见内置插件包(例如 Discord 插件的 `src/channel.setup.ts`)。
|
||||
|
||||
对于只需要标准
|
||||
`note -> prompt -> parse -> merge -> patch` 流程的私信 allowlist 提示,
|
||||
请优先使用来自 `openclaw/plugin-sdk/setup` 的共享设置
|
||||
辅助工具:`createPromptParsedAllowFromForAccount(...)`、
|
||||
`note -> prompt -> parse -> merge -> patch` 流程的私信允许列表提示,
|
||||
优先使用 `openclaw/plugin-sdk/setup` 中的共享设置
|
||||
辅助函数:`createPromptParsedAllowFromForAccount(...)`、
|
||||
`createTopLevelChannelParsedAllowFromPrompt(...)` 和
|
||||
`createNestedChannelParsedAllowFromPrompt(...)`。
|
||||
|
||||
对于仅在标签、分数和可选附加行上有所不同的渠道设置状态块,
|
||||
请优先使用 `openclaw/plugin-sdk/setup` 中的
|
||||
`createStandardChannelSetupStatus(...)`,而不是在
|
||||
每个插件中手写同样的 `status` 对象。
|
||||
对于只在标签、分数和可选额外行上变化的渠道设置 Status 区块,
|
||||
优先使用 `openclaw/plugin-sdk/setup` 中的
|
||||
`createStandardChannelSetupStatus(...)`,而不是在每个插件中手写相同的
|
||||
`status` 对象。
|
||||
|
||||
对于只应在特定上下文中出现的可选设置界面,请使用
|
||||
对于仅应在特定上下文中出现的可选设置界面,请使用
|
||||
`openclaw/plugin-sdk/channel-setup` 中的
|
||||
`createOptionalChannelSetupSurface`:
|
||||
|
||||
@ -503,25 +504,25 @@ const setupSurface = createOptionalChannelSetupSurface({
|
||||
|
||||
`plugin-sdk/channel-setup` 还暴露了更底层的
|
||||
`createOptionalChannelSetupAdapter(...)` 和
|
||||
`createOptionalChannelSetupWizard(...)` 构建器,以便你只需要该
|
||||
可选安装界面的一半时使用。
|
||||
`createOptionalChannelSetupWizard(...)` 构建器,以便在你只需要其中一半
|
||||
可选安装界面时使用。
|
||||
|
||||
生成的可选适配器 / 向导在真正的配置写入上会默认拒绝。
|
||||
它们会在 `validateInput`、
|
||||
`applyAccountConfig` 和 `finalize` 之间复用同一条需要安装的消息,并在设置了 `docsPath` 时附加文档链接。
|
||||
生成的可选适配器/向导在真实配置写入时会默认失败关闭。它们会在
|
||||
`validateInput`、`applyAccountConfig` 和 `finalize` 之间复用同一条
|
||||
“需要安装”的消息,并在设置了 `docsPath` 时附加文档链接。
|
||||
|
||||
对于基于二进制的设置 UI,请优先使用共享委托辅助工具,而不是
|
||||
把相同的二进制 / 状态胶水逻辑复制到每个渠道中:
|
||||
对于基于二进制的设置 UI,请优先使用共享的委托辅助函数,而不是
|
||||
在每个渠道中重复同样的二进制/Status 粘合逻辑:
|
||||
|
||||
- `createDetectedBinaryStatus(...)`:用于仅在标签、
|
||||
提示、分数和二进制检测上不同的状态块
|
||||
- `createDetectedBinaryStatus(...)`:用于只在标签、
|
||||
提示、分数和二进制检测上变化的 Status 区块
|
||||
- `createCliPathTextInput(...)`:用于基于路径的文本输入
|
||||
- `createDelegatedSetupWizardStatusResolvers(...)`、
|
||||
`createDelegatedPrepare(...)`、`createDelegatedFinalize(...)` 和
|
||||
`createDelegatedResolveConfigured(...)`:用于 `setupEntry` 需要延迟转发到
|
||||
更重型完整向导的情况
|
||||
- `createDelegatedTextInputShouldPrompt(...)`:用于 `setupEntry` 只需要
|
||||
委托一个 `textInputs[*].shouldPrompt` 决策的情况
|
||||
`createDelegatedResolveConfigured(...)`:当 `setupEntry` 需要惰性转发到
|
||||
更重的完整向导时使用
|
||||
- `createDelegatedTextInputShouldPrompt(...)`:当 `setupEntry` 只需要
|
||||
委托 `textInputs[*].shouldPrompt` 决策时使用
|
||||
|
||||
## 发布与安装
|
||||
|
||||
@ -531,42 +532,41 @@ const setupSurface = createOptionalChannelSetupSurface({
|
||||
openclaw plugins install @myorg/openclaw-my-plugin
|
||||
```
|
||||
|
||||
OpenClaw 会先尝试 ClawHub,然后自动回退到 npm。你也可以显式强制使用 ClawHub:
|
||||
OpenClaw 会先尝试 ClawHub,失败后自动回退到 npm。你也可以显式强制使用 ClawHub:
|
||||
|
||||
```bash
|
||||
openclaw plugins install clawhub:@myorg/openclaw-my-plugin # ClawHub only
|
||||
openclaw plugins install clawhub:@myorg/openclaw-my-plugin # 仅 ClawHub
|
||||
```
|
||||
|
||||
没有对应的 `npm:` 覆盖方式。当你希望在 ClawHub 回退后走 npm 路径时,
|
||||
请使用普通 npm 包规范:
|
||||
没有对应的 `npm:` 覆盖前缀。如果你想在 ClawHub 回退之后走 npm 路径,
|
||||
请直接使用普通的 npm 包 spec:
|
||||
|
||||
```bash
|
||||
openclaw plugins install @myorg/openclaw-my-plugin
|
||||
```
|
||||
|
||||
**仓库内插件:** 放在内置插件工作区树下,它们会在构建期间自动
|
||||
被发现。
|
||||
**仓库内插件:** 放在内置插件工作区树下,即可在构建期间自动
|
||||
发现。
|
||||
|
||||
**用户可以安装:**
|
||||
**用户可执行安装:**
|
||||
|
||||
```bash
|
||||
openclaw plugins install <package-name>
|
||||
```
|
||||
|
||||
<Info>
|
||||
对于来源于 npm 的安装,`openclaw plugins install` 会运行
|
||||
对于来自 npm 的安装,`openclaw plugins install` 会运行
|
||||
`npm install --ignore-scripts`(不执行生命周期脚本)。请保持插件依赖
|
||||
树为纯 JS / TS,并避免依赖需要 `postinstall` 构建的包。
|
||||
树为纯 JS/TS,并避免使用需要 `postinstall` 构建的包。
|
||||
</Info>
|
||||
|
||||
内置的 OpenClaw 自有插件是唯一的启动修复例外:当
|
||||
打包安装检测到某个插件已通过插件配置、旧版渠道配置或其
|
||||
内置默认启用清单而被启用时,启动流程会在导入前安装该插件缺失的
|
||||
运行时依赖。第三方插件不应依赖启动期安装;
|
||||
请继续使用显式插件安装器。
|
||||
只有 OpenClaw 自有的内置插件才是启动修复的例外:当某个打包安装发现
|
||||
某插件已通过插件配置、旧版渠道配置或其内置默认启用清单被启用时,
|
||||
启动过程会在导入前先安装该插件缺失的运行时依赖。第三方插件
|
||||
不应依赖启动时安装;请继续使用显式插件安装器。
|
||||
|
||||
## 相关内容
|
||||
|
||||
- [SDK 入口点](/zh-CN/plugins/sdk-entrypoints) -- `definePluginEntry` 和 `defineChannelPluginEntry`
|
||||
- [插件清单](/zh-CN/plugins/manifest) -- 完整清单 schema 参考
|
||||
- [构建插件](/zh-CN/plugins/building-plugins) -- 分步入门指南
|
||||
- [SDK 概览](/zh-CN/plugins/sdk-entrypoints) — `definePluginEntry` 和 `defineChannelPluginEntry`
|
||||
- [插件清单](/zh-CN/plugins/manifest) — 完整清单 schema 参考
|
||||
- [构建插件](/zh-CN/plugins/building-plugins) — 分步入门指南
|
||||
|
||||
@ -1,30 +1,29 @@
|
||||
---
|
||||
read_when:
|
||||
- 你想从 OpenClaw 发起一个呼出语音通话
|
||||
- 你想从 OpenClaw 发起一个出站语音通话
|
||||
- 你正在配置或开发语音通话插件
|
||||
summary: 语音通话插件:通过 Twilio/Telnyx/Plivo 进行呼出 + 呼入通话(插件安装 + 配置 + CLI)
|
||||
summary: 语音通话插件:通过 Twilio/Telnyx/Plivo 进行出站 + 入站通话(插件安装 + 配置 + CLI)
|
||||
title: 语音通话插件
|
||||
x-i18n:
|
||||
generated_at: "2026-04-25T04:54:59Z"
|
||||
generated_at: "2026-04-25T05:55:57Z"
|
||||
model: gpt-5.4
|
||||
provider: openai
|
||||
source_hash: 54fff21558f5a8788f85a91ed84a60a3d74a4fa8da8edbe81a23adc9a9065e2f
|
||||
source_hash: bb396c6e346590b742c4d0f0e4f9653982da78fc40b9650760ed10d6fcd5710c
|
||||
source_path: plugins/voice-call.md
|
||||
workflow: 15
|
||||
---
|
||||
|
||||
# 语音通话(插件)
|
||||
|
||||
通过插件为 OpenClaw 提供语音通话。支持呼出通知,以及带有呼入策略的多轮对话。
|
||||
OpenClaw 的语音通话通过插件实现。支持出站通知以及带入站策略的
|
||||
多轮对话。
|
||||
|
||||
当前提供商:
|
||||
|
||||
- `twilio`(Programmable Voice + Media Streams)
|
||||
- `telnyx`(Call Control v2)
|
||||
- `plivo`(Voice API + XML transfer + GetInput speech)
|
||||
- `mock`(开发环境 / 无网络)
|
||||
- `mock`(开发/无网络)
|
||||
|
||||
快速理解模型:
|
||||
快速心智模型:
|
||||
|
||||
- 安装插件
|
||||
- 重启 Gateway 网关
|
||||
@ -33,13 +32,13 @@ x-i18n:
|
||||
|
||||
## 运行位置(本地 vs 远程)
|
||||
|
||||
语音通话插件运行在 **Gateway 网关进程内部**。
|
||||
Voice Call 插件运行在 **Gateway 网关进程内部**。
|
||||
|
||||
如果你使用远程 Gateway 网关,请在 **运行 Gateway 网关的机器** 上安装 / 配置该插件,然后重启 Gateway 网关以加载它。
|
||||
如果你使用远程 Gateway 网关,请在**运行 Gateway 网关的机器**上安装/配置该插件,然后重启 Gateway 网关以加载它。
|
||||
|
||||
## 安装
|
||||
|
||||
### 选项 A:从 npm 安装(推荐)
|
||||
### 方案 A:从 npm 安装(推荐)
|
||||
|
||||
```bash
|
||||
openclaw plugins install @openclaw/voice-call
|
||||
@ -47,7 +46,7 @@ openclaw plugins install @openclaw/voice-call
|
||||
|
||||
之后重启 Gateway 网关。
|
||||
|
||||
### 选项 B:从本地文件夹安装(开发环境,不复制文件)
|
||||
### 方案 B:从本地文件夹安装(开发,无需复制)
|
||||
|
||||
```bash
|
||||
PLUGIN_SRC=./path/to/local/voice-call-plugin
|
||||
@ -68,8 +67,8 @@ cd "$PLUGIN_SRC" && pnpm install
|
||||
"voice-call": {
|
||||
enabled: true,
|
||||
config: {
|
||||
provider: "twilio", // or "telnyx" | "plivo" | "mock"
|
||||
fromNumber: "+15550001234", // or TWILIO_FROM_NUMBER for Twilio
|
||||
provider: "twilio", // 或 "telnyx" | "plivo" | "mock"
|
||||
fromNumber: "+15550001234", // 或 Twilio 的 TWILIO_FROM_NUMBER
|
||||
toNumber: "+15550005678",
|
||||
|
||||
twilio: {
|
||||
@ -80,8 +79,8 @@ cd "$PLUGIN_SRC" && pnpm install
|
||||
telnyx: {
|
||||
apiKey: "...",
|
||||
connectionId: "...",
|
||||
// Telnyx webhook public key from the Telnyx Mission Control Portal
|
||||
// (Base64 string; can also be set via TELNYX_PUBLIC_KEY).
|
||||
// 来自 Telnyx Mission Control Portal 的 Telnyx webhook 公钥
|
||||
// (Base64 字符串;也可通过 TELNYX_PUBLIC_KEY 设置)。
|
||||
publicKey: "...",
|
||||
},
|
||||
|
||||
@ -90,19 +89,19 @@ cd "$PLUGIN_SRC" && pnpm install
|
||||
authToken: "...",
|
||||
},
|
||||
|
||||
// Webhook server
|
||||
// Webhook 服务器
|
||||
serve: {
|
||||
port: 3334,
|
||||
path: "/voice/webhook",
|
||||
},
|
||||
|
||||
// Webhook security (recommended for tunnels/proxies)
|
||||
// Webhook 安全性(推荐用于隧道/代理)
|
||||
webhookSecurity: {
|
||||
allowedHosts: ["voice.example.com"],
|
||||
trustedProxyIPs: ["100.64.0.1"],
|
||||
},
|
||||
|
||||
// Public exposure (pick one)
|
||||
// 公开暴露方式(选择一种)
|
||||
// publicUrl: "https://example.ngrok.app/voice/webhook",
|
||||
// tunnel: { provider: "ngrok" },
|
||||
// tailscale: { mode: "funnel", path: "/voice/webhook" }
|
||||
@ -113,11 +112,11 @@ cd "$PLUGIN_SRC" && pnpm install
|
||||
|
||||
streaming: {
|
||||
enabled: true,
|
||||
provider: "openai", // optional; first registered realtime transcription provider when unset
|
||||
provider: "openai", // 可选;未设置时使用第一个已注册的实时转写提供商
|
||||
streamPath: "/voice/stream",
|
||||
providers: {
|
||||
openai: {
|
||||
apiKey: "sk-...", // optional if OPENAI_API_KEY is set
|
||||
apiKey: "sk-...", // 如果已设置 OPENAI_API_KEY,则可选
|
||||
model: "gpt-4o-transcribe",
|
||||
silenceDurationMs: 800,
|
||||
vadThreshold: 0.5,
|
||||
@ -131,7 +130,7 @@ cd "$PLUGIN_SRC" && pnpm install
|
||||
|
||||
realtime: {
|
||||
enabled: false,
|
||||
provider: "google", // optional; first registered realtime voice provider when unset
|
||||
provider: "google", // 可选;未设置时使用第一个已注册的实时语音提供商
|
||||
toolPolicy: "safe-read-only",
|
||||
providers: {
|
||||
google: {
|
||||
@ -153,18 +152,25 @@ cd "$PLUGIN_SRC" && pnpm install
|
||||
openclaw voicecall setup
|
||||
```
|
||||
|
||||
默认输出在聊天日志和终端会话中都易于阅读。它会检查插件是否已启用、提供商和凭证是否存在、Webhook 暴露是否已配置,以及是否只启用了一个音频模式。脚本使用时可执行 `openclaw voicecall setup --json`。
|
||||
默认输出在聊天日志和终端会话中都易于阅读。它会检查
|
||||
插件是否已启用、提供商和凭证是否存在、webhook
|
||||
暴露是否已配置,以及是否只启用了一个音频模式。脚本请使用
|
||||
`openclaw voicecall setup --json`。
|
||||
|
||||
对于 Twilio、Telnyx 和 Plivo,设置必须解析为公共 Webhook URL。如果已配置的 `publicUrl`、隧道 URL、Tailscale URL 或 serve 回退地址解析到 loopback 或私有网络空间,则 setup 会失败,而不会启动一个无法接收真实运营商 Webhook 的提供商。
|
||||
对于 Twilio、Telnyx 和 Plivo,设置必须能解析为公开可访问的 webhook URL。如果
|
||||
已配置的 `publicUrl`、隧道 URL、Tailscale URL 或 serve 回退地址解析为
|
||||
loopback 或私有网络空间,设置会失败,而不是启动一个无法接收真实运营商 webhook 的
|
||||
提供商。
|
||||
|
||||
若要进行一个不出意外的冒烟测试,请运行:
|
||||
如需进行一次无意外的冒烟测试,请运行:
|
||||
|
||||
```bash
|
||||
openclaw voicecall smoke
|
||||
openclaw voicecall smoke --to "+15555550123"
|
||||
```
|
||||
|
||||
第二个命令仍然是一次 dry run。添加 `--yes` 以发起一个简短的呼出通知电话:
|
||||
第二个命令仍然是演练模式。添加 `--yes` 以发起一次简短的出站
|
||||
通知呼叫:
|
||||
|
||||
```bash
|
||||
openclaw voicecall smoke --to "+15555550123" --yes
|
||||
@ -172,49 +178,61 @@ openclaw voicecall smoke --to "+15555550123" --yes
|
||||
|
||||
说明:
|
||||
|
||||
- Twilio/Telnyx 需要一个 **可被公网访问的** Webhook URL。
|
||||
- Plivo 需要一个 **可被公网访问的** Webhook URL。
|
||||
- `mock` 是一个本地开发用提供商(无网络调用)。
|
||||
- 如果旧配置仍在使用 `provider: "log"`、`twilio.from` 或旧版 `streaming.*` OpenAI 键,请运行 `openclaw doctor --fix` 来重写它们。
|
||||
- 除非 `skipSignatureVerification` 为 true,否则 Telnyx 需要 `telnyx.publicKey`(或 `TELNYX_PUBLIC_KEY`)。
|
||||
- Twilio/Telnyx 需要一个**可公开访问**的 webhook URL。
|
||||
- Plivo 需要一个**可公开访问**的 webhook URL。
|
||||
- `mock` 是本地开发提供商(不发起网络调用)。
|
||||
- 如果旧配置仍使用 `provider: "log"`、`twilio.from` 或旧版 `streaming.*` OpenAI 键,请运行 `openclaw doctor --fix` 进行重写。
|
||||
- Telnyx 要求设置 `telnyx.publicKey`(或 `TELNYX_PUBLIC_KEY`),除非 `skipSignatureVerification` 为 true。
|
||||
- `skipSignatureVerification` 仅用于本地测试。
|
||||
- 如果你使用 ngrok 免费层,请将 `publicUrl` 设置为确切的 ngrok URL;签名验证始终会强制执行。
|
||||
- `tunnel.allowNgrokFreeTierLoopbackBypass: true` 仅在 `tunnel.provider="ngrok"` 且 `serve.bind` 为 loopback(ngrok 本地代理)时,允许 Twilio Webhook 使用无效签名。仅用于本地开发。
|
||||
- Ngrok 免费层 URL 可能会变化或增加中间页行为;如果 `publicUrl` 漂移,Twilio 签名校验将失败。在生产环境中,优先使用稳定域名或 Tailscale funnel。
|
||||
- `realtime.enabled` 会启动完整的语音到语音实时对话;不要与 `streaming.enabled` 同时启用。
|
||||
- 流式传输安全默认值:
|
||||
- `streaming.preStartTimeoutMs` 会关闭那些从未发送有效 `start` 帧的套接字。
|
||||
- `streaming.maxPendingConnections` 限制未认证预启动套接字的总数。
|
||||
- `streaming.maxPendingConnectionsPerIp` 限制每个源 IP 的未认证预启动套接字数量。
|
||||
- `streaming.maxConnections` 限制打开的媒体流套接字总数(待处理 + 活动)。
|
||||
- 运行时回退目前仍接受这些旧的 voice-call 键,但重写路径是 `openclaw doctor --fix`,该兼容垫片只是临时方案。
|
||||
- 如果你使用 ngrok 免费层,请将 `publicUrl` 设置为精确的 ngrok URL;签名验证始终会强制执行。
|
||||
- `tunnel.allowNgrokFreeTierLoopbackBypass: true` 仅在 `tunnel.provider="ngrok"` 且 `serve.bind` 为 loopback(ngrok 本地代理)时,允许带无效签名的 Twilio webhook。仅用于本地开发。
|
||||
- Ngrok 免费层 URL 可能会变化或添加中间页行为;如果 `publicUrl` 漂移,Twilio 签名将会失败。生产环境中,优先使用稳定域名或 Tailscale funnel。
|
||||
- `realtime.enabled` 会启动完整的语音到语音对话;不要与 `streaming.enabled` 同时启用。
|
||||
- 分块流式传输安全默认值:
|
||||
- `streaming.preStartTimeoutMs` 会关闭那些始终未发送有效 `start` 帧的 socket。
|
||||
- `streaming.maxPendingConnections` 限制未认证、启动前 socket 的总数。
|
||||
- `streaming.maxPendingConnectionsPerIp` 限制每个源 IP 的未认证、启动前 socket 数量。
|
||||
- `streaming.maxConnections` 限制打开的媒体流 socket 总数(待启动 + 活动)。
|
||||
- 运行时回退目前仍接受这些旧的 voice-call 键,但重写路径是 `openclaw doctor --fix`,兼容垫片只是临时的。
|
||||
|
||||
## 实时语音对话
|
||||
|
||||
`realtime` 为实时通话音频选择一个全双工实时语音提供商。
|
||||
|
||||
它与 `streaming` 分开,后者只会把音频转发给实时转写提供商。
|
||||
它与 `streaming` 分开,后者仅将音频转发给实时
|
||||
转写提供商。
|
||||
|
||||
当前运行时行为:
|
||||
|
||||
- `realtime.enabled` 支持用于 Twilio Media Streams。
|
||||
- `realtime.enabled` 不能与 `streaming.enabled` 组合使用。
|
||||
- `realtime.provider` 是可选的。未设置时,语音通话会使用第一个已注册的实时语音提供商。
|
||||
- 内置的实时语音提供商包括 Google Gemini Live(`google`)和 OpenAI(`openai`),它们由各自的提供商插件注册。
|
||||
- 提供商拥有的原始配置位于 `realtime.providers.<providerId>` 下。
|
||||
- 默认情况下,语音通话会暴露共享的 `openclaw_agent_consult` 实时工具。当来电者请求更深入的推理、当前信息或普通 OpenClaw 工具时,实时模型可以调用它。
|
||||
- `realtime.provider` 是可选的。若未设置,Voice Call 会使用第一个
|
||||
已注册的实时语音提供商。
|
||||
- 内置的实时语音提供商包括 Google Gemini Live(`google`)和
|
||||
OpenAI(`openai`),由各自的 provider 插件注册。
|
||||
- 提供商自有的原始配置位于 `realtime.providers.<providerId>` 下。
|
||||
- Voice Call 默认暴露共享的 `openclaw_agent_consult` 实时工具。
|
||||
当来电者请求更深层次的推理、最新信息或普通 OpenClaw 工具时,实时模型可以调用它。
|
||||
- `realtime.toolPolicy` 控制 consult 运行:
|
||||
- `safe-read-only`:暴露 consult 工具,并将常规智能体限制为使用 `read`、`web_search`、`web_fetch`、`x_search`、`memory_search` 和 `memory_get`。
|
||||
- `owner`:暴露 consult 工具,并允许常规智能体使用普通智能体工具策略。
|
||||
- `none`:不暴露 consult 工具。自定义 `realtime.tools` 仍会透传给实时提供商。
|
||||
- Consult 会话键会在可用时复用现有语音会话,然后回退到来电 / 被叫电话号码,以便后续 consult 调用在通话期间保持上下文。
|
||||
- 如果 `realtime.provider` 指向未注册的提供商,或根本没有注册任何实时语音提供商,语音通话会记录一条警告并跳过实时媒体,而不是让整个插件失败。
|
||||
- `safe-read-only`:暴露 consult 工具,并将常规智能体限制为
|
||||
`read`、`web_search`、`web_fetch`、`x_search`、`memory_search` 和
|
||||
`memory_get`。
|
||||
- `owner`:暴露 consult 工具,并让常规智能体使用正常的
|
||||
智能体工具策略。
|
||||
- `none`:不暴露 consult 工具。自定义 `realtime.tools` 仍会
|
||||
透传给实时提供商。
|
||||
- Consult 会话键会在可用时复用现有语音会话,然后
|
||||
回退到来电方/被叫方电话号码,以便后续 consult 调用在通话期间保持
|
||||
上下文。
|
||||
- 如果 `realtime.provider` 指向未注册的提供商,或者根本没有注册任何实时
|
||||
语音提供商,Voice Call 会记录警告并跳过
|
||||
实时媒体,而不是让整个插件失败。
|
||||
|
||||
Google Gemini Live 实时默认值:
|
||||
|
||||
- API 密钥:`realtime.providers.google.apiKey`、`GEMINI_API_KEY` 或 `GOOGLE_GENERATIVE_AI_API_KEY`
|
||||
- API 密钥:`realtime.providers.google.apiKey`、`GEMINI_API_KEY` 或
|
||||
`GOOGLE_GENERATIVE_AI_API_KEY`
|
||||
- 模型:`gemini-2.5-flash-native-audio-preview-12-2025`
|
||||
- 语音:`Kore`
|
||||
- 声音:`Kore`
|
||||
|
||||
示例:
|
||||
|
||||
@ -271,27 +289,32 @@ Google Gemini Live 实时默认值:
|
||||
}
|
||||
```
|
||||
|
||||
有关特定提供商的实时语音选项,请参阅 [Google provider](/zh-CN/providers/google) 和 [OpenAI provider](/zh-CN/providers/openai)。
|
||||
有关提供商特定的实时语音选项,请参见 [Google provider](/zh-CN/providers/google) 和 [OpenAI provider](/zh-CN/providers/openai)。
|
||||
|
||||
## 流式转写
|
||||
## 实时分块流式转写
|
||||
|
||||
`streaming` 为实时通话音频选择一个实时转写提供商。
|
||||
|
||||
当前运行时行为:
|
||||
|
||||
- `streaming.provider` 是可选的。未设置时,语音通话会使用第一个已注册的实时转写提供商。
|
||||
- 内置的实时转写提供商包括 Deepgram(`deepgram`)、ElevenLabs(`elevenlabs`)、Mistral(`mistral`)、OpenAI(`openai`)和 xAI(`xai`),它们由各自的提供商插件注册。
|
||||
- 提供商拥有的原始配置位于 `streaming.providers.<providerId>` 下。
|
||||
- 如果 `streaming.provider` 指向未注册的提供商,或根本没有注册任何实时转写提供商,语音通话会记录一条警告并跳过媒体流式传输,而不是让整个插件失败。
|
||||
- `streaming.provider` 是可选的。若未设置,Voice Call 会使用第一个
|
||||
已注册的实时转写提供商。
|
||||
- 内置的实时转写提供商包括 Deepgram(`deepgram`)、
|
||||
ElevenLabs(`elevenlabs`)、Mistral(`mistral`)、OpenAI(`openai`)和 xAI
|
||||
(`xai`),由各自的 provider 插件注册。
|
||||
- 提供商自有的原始配置位于 `streaming.providers.<providerId>` 下。
|
||||
- 如果 `streaming.provider` 指向未注册的提供商,或根本没有注册任何实时
|
||||
转写提供商,Voice Call 会记录警告,并
|
||||
跳过媒体流,而不是让整个插件失败。
|
||||
|
||||
OpenAI 流式转写默认值:
|
||||
OpenAI 分块流式转写默认值:
|
||||
|
||||
- API 密钥:`streaming.providers.openai.apiKey` 或 `OPENAI_API_KEY`
|
||||
- 模型:`gpt-4o-transcribe`
|
||||
- `silenceDurationMs`:`800`
|
||||
- `vadThreshold`:`0.5`
|
||||
|
||||
xAI 流式转写默认值:
|
||||
xAI 分块流式转写默认值:
|
||||
|
||||
- API 密钥:`streaming.providers.xai.apiKey` 或 `XAI_API_KEY`
|
||||
- 端点:`wss://api.x.ai/v1/stt`
|
||||
@ -314,7 +337,7 @@ xAI 流式转写默认值:
|
||||
streamPath: "/voice/stream",
|
||||
providers: {
|
||||
openai: {
|
||||
apiKey: "sk-...", // optional if OPENAI_API_KEY is set
|
||||
apiKey: "sk-...", // 如果已设置 OPENAI_API_KEY,则可选
|
||||
model: "gpt-4o-transcribe",
|
||||
silenceDurationMs: 800,
|
||||
vadThreshold: 0.5,
|
||||
@ -342,7 +365,7 @@ xAI 流式转写默认值:
|
||||
streamPath: "/voice/stream",
|
||||
providers: {
|
||||
xai: {
|
||||
apiKey: "${XAI_API_KEY}", // optional if XAI_API_KEY is set
|
||||
apiKey: "${XAI_API_KEY}", // 如果已设置 XAI_API_KEY,则可选
|
||||
endpointingMs: 800,
|
||||
language: "en",
|
||||
},
|
||||
@ -355,7 +378,7 @@ xAI 流式转写默认值:
|
||||
}
|
||||
```
|
||||
|
||||
旧键仍可由 `openclaw doctor --fix` 自动迁移:
|
||||
旧键仍会被 `openclaw doctor --fix` 自动迁移:
|
||||
|
||||
- `streaming.sttProvider` → `streaming.provider`
|
||||
- `streaming.openaiApiKey` → `streaming.providers.openai.apiKey`
|
||||
@ -363,14 +386,17 @@ xAI 流式转写默认值:
|
||||
- `streaming.silenceDurationMs` → `streaming.providers.openai.silenceDurationMs`
|
||||
- `streaming.vadThreshold` → `streaming.providers.openai.vadThreshold`
|
||||
|
||||
## 过期通话清理器
|
||||
## 陈旧通话清理器
|
||||
|
||||
使用 `staleCallReaperSeconds` 来结束那些始终未收到终止 Webhook 的通话(例如,始终未完成的通知模式通话)。默认值为 `0`(禁用)。
|
||||
使用 `staleCallReaperSeconds` 结束那些从未收到终态 webhook 的通话
|
||||
(例如始终未完成的 notify 模式通话)。默认值为 `0`
|
||||
(禁用)。
|
||||
|
||||
推荐范围:
|
||||
|
||||
- **生产环境:** 对于通知式流程,使用 `120`–`300` 秒。
|
||||
- 将此值保持为 **高于 `maxDurationSeconds`**,这样正常通话才能完成。一个不错的起始值是 `maxDurationSeconds + 30–60` 秒。
|
||||
- **生产环境:** 对于 notify 风格流程,使用 `120`–`300` 秒。
|
||||
- 将此值保持为**高于 `maxDurationSeconds`**,以便正常通话能够
|
||||
完成。一个不错的起始值是 `maxDurationSeconds + 30–60` 秒。
|
||||
|
||||
示例:
|
||||
|
||||
@ -389,25 +415,30 @@ xAI 流式转写默认值:
|
||||
}
|
||||
```
|
||||
|
||||
## Webhook 安全
|
||||
## Webhook 安全性
|
||||
|
||||
当代理或隧道位于 Gateway 网关前面时,插件会重建公共 URL 以进行签名验证。这些选项用于控制哪些转发头会被信任。
|
||||
当 Gateway 网关前面有代理或隧道时,插件会重建
|
||||
用于签名验证的公开 URL。这些选项控制哪些转发
|
||||
标头会被信任。
|
||||
|
||||
`webhookSecurity.allowedHosts` 允许通过转发头传递的主机名白名单。
|
||||
`webhookSecurity.allowedHosts` 会将转发标头中的主机加入允许名单。
|
||||
|
||||
`webhookSecurity.trustForwardingHeaders` 在没有允许列表的情况下信任转发头。
|
||||
`webhookSecurity.trustForwardingHeaders` 会在没有允许名单的情况下信任转发标头。
|
||||
|
||||
`webhookSecurity.trustedProxyIPs` 仅在请求远程 IP 与列表匹配时才信任转发头。
|
||||
仅当请求远程 IP 与列表匹配时,`webhookSecurity.trustedProxyIPs` 才会信任转发标头。
|
||||
|
||||
Twilio 和 Plivo 启用了 Webhook 重放保护。被重放的有效 Webhook 请求会被确认,但会跳过副作用处理。
|
||||
Twilio 和 Plivo 启用了 webhook 重放保护。被重放的有效 webhook
|
||||
请求会被确认,但不会执行副作用。
|
||||
|
||||
Twilio 对话轮次在 `<Gather>` 回调中包含每轮专用令牌,因此过期 / 重放的语音回调无法满足较新的待处理转写轮次。
|
||||
Twilio 对话轮次在 `<Gather>` 回调中包含每轮令牌,因此
|
||||
陈旧/重放的语音回调无法满足较新的待处理转录轮次。
|
||||
|
||||
当提供商要求的签名头缺失时,未认证的 Webhook 请求会在读取正文之前被拒绝。
|
||||
如果缺少提供商要求的签名标头,未认证的 webhook 请求会在读取请求体之前被拒绝。
|
||||
|
||||
voice-call Webhook 在签名验证之前使用共享的预认证 body 配置文件(64 KB / 5 秒)以及基于每个 IP 的并发上限。
|
||||
voice-call webhook 使用共享的预认证请求体配置(64 KB / 5 秒),
|
||||
并在签名验证前对每个 IP 设置进行中的请求数量上限。
|
||||
|
||||
使用稳定公共主机的示例:
|
||||
使用稳定公开主机的示例:
|
||||
|
||||
```json5
|
||||
{
|
||||
@ -428,7 +459,9 @@ voice-call Webhook 在签名验证之前使用共享的预认证 body 配置文
|
||||
|
||||
## 用于通话的 TTS
|
||||
|
||||
语音通话会使用核心 `messages.tts` 配置来实现通话中的流式语音。你可以在插件配置下使用 **相同结构** 覆盖它 —— 它会与 `messages.tts` 进行深度合并。
|
||||
Voice Call 对通话中的
|
||||
流式语音使用核心 `messages.tts` 配置。你可以在插件配置下使用
|
||||
**相同结构**进行覆盖——它会与 `messages.tts` 进行深度合并。
|
||||
|
||||
```json5
|
||||
{
|
||||
@ -446,12 +479,13 @@ voice-call Webhook 在签名验证之前使用共享的预认证 body 配置文
|
||||
|
||||
说明:
|
||||
|
||||
- 插件配置中的旧版 `tts.<provider>` 键(`openai`、`elevenlabs`、`microsoft`、`edge`)可由 `openclaw doctor --fix` 修复;提交的配置应使用 `tts.providers.<provider>`。
|
||||
- **Microsoft speech 会被语音通话忽略**(电话音频需要 PCM;当前 Microsoft 传输方式不暴露电话用 PCM 输出)。
|
||||
- 启用 Twilio 媒体流时会使用核心 TTS;否则通话会回退到提供商原生语音。
|
||||
- 如果 Twilio 媒体流已处于活动状态,语音通话不会回退到 TwiML `<Say>`。在该状态下,如果电话 TTS 不可用,则播放请求会失败,而不是混用两条播放路径。
|
||||
- 当电话 TTS 回退到次级提供商时,语音通话会记录一条包含提供商链(`from`、`to`、`attempts`)的警告,以便调试。
|
||||
- 当 Twilio 插话或流拆除清除待处理 TTS 队列时,排队的播放请求会结束,而不会让正在等待播放完成的来电者一直挂起。
|
||||
- 插件配置中的旧版 `tts.<provider>` 键(`openai`、`elevenlabs`、`microsoft`、`edge`)会由 `openclaw doctor --fix` 修复;已提交的配置应使用 `tts.providers.<provider>`。
|
||||
- **Microsoft speech 会被语音通话忽略**(电话音频需要 PCM;当前 Microsoft 传输不暴露电话 PCM 输出)。
|
||||
- 当启用 Twilio 媒体流时,会使用核心 TTS;否则通话会回退到提供商原生语音。
|
||||
- 如果 Twilio 媒体流已经处于活动状态,Voice Call 不会回退到 TwiML `<Say>`。在这种状态下,如果电话 TTS 不可用,播放请求会失败,而不是混用两条播放路径。
|
||||
- 当电话 TTS 回退到次级提供商时,Voice Call 会记录一条包含提供商链(`from`、`to`、`attempts`)的警告,便于调试。
|
||||
- 当 Twilio 插话或流拆除清除待处理 TTS 队列时,排队中的
|
||||
播放请求会正常结束,而不会让等待播放完成的来电者一直挂起。
|
||||
|
||||
### 更多示例
|
||||
|
||||
@ -470,7 +504,7 @@ voice-call Webhook 在签名验证之前使用共享的预认证 body 配置文
|
||||
}
|
||||
```
|
||||
|
||||
仅为通话覆盖为 ElevenLabs(其他地方保留核心默认值):
|
||||
仅为通话覆盖为 ElevenLabs(其他地方保持核心默认值):
|
||||
|
||||
```json5
|
||||
{
|
||||
@ -495,7 +529,7 @@ voice-call Webhook 在签名验证之前使用共享的预认证 body 配置文
|
||||
}
|
||||
```
|
||||
|
||||
仅覆盖通话使用的 OpenAI 模型(深度合并示例):
|
||||
仅为通话覆盖 OpenAI 模型(深度合并示例):
|
||||
|
||||
```json5
|
||||
{
|
||||
@ -518,9 +552,9 @@ voice-call Webhook 在签名验证之前使用共享的预认证 body 配置文
|
||||
}
|
||||
```
|
||||
|
||||
## 呼入通话
|
||||
## 入站通话
|
||||
|
||||
呼入策略默认值为 `disabled`。要启用呼入通话,请设置:
|
||||
入站策略默认是 `disabled`。要启用入站通话,请设置:
|
||||
|
||||
```json5
|
||||
{
|
||||
@ -530,9 +564,13 @@ voice-call Webhook 在签名验证之前使用共享的预认证 body 配置文
|
||||
}
|
||||
```
|
||||
|
||||
`inboundPolicy: "allowlist"` 是一种低保障的来电显示筛选方式。插件会规范化提供商给出的 `From` 值,并将其与 `allowFrom` 进行比较。Webhook 验证可以验证提供商投递和载荷完整性,但不能证明 PSTN/VoIP 来电号码的归属权。请将 `allowFrom` 视为来电显示过滤,而不是强来电身份认证。
|
||||
`inboundPolicy: "allowlist"` 是一种低保障的来电显示筛选机制。插件
|
||||
会对提供商提供的 `From` 值进行标准化,并将其与 `allowFrom` 进行比较。
|
||||
webhook 验证可以认证提供商投递和负载完整性,但
|
||||
不能证明 PSTN/VoIP 来电号码的所有权。请将 `allowFrom` 视为
|
||||
来电显示过滤,而不是强来电者身份验证。
|
||||
|
||||
自动响应使用智能体系统。可通过以下项进行调整:
|
||||
自动响应使用智能体系统。可通过以下项进行调优:
|
||||
|
||||
- `responseModel`
|
||||
- `responseSystemPrompt`
|
||||
@ -540,78 +578,83 @@ voice-call Webhook 在签名验证之前使用共享的预认证 body 配置文
|
||||
|
||||
### 语音输出约定
|
||||
|
||||
对于自动响应,语音通话会向系统提示附加一个严格的语音输出约定:
|
||||
对于自动响应,Voice Call 会向系统提示词追加一个严格的语音输出约定:
|
||||
|
||||
- `{"spoken":"..."}`
|
||||
|
||||
然后语音通话会以防御式方式提取语音文本:
|
||||
随后 Voice Call 会以防御性方式提取语音文本:
|
||||
|
||||
- 忽略标记为推理 / 错误内容的载荷。
|
||||
- 解析直接 JSON、围栏 JSON 或内联 `"spoken"` 键。
|
||||
- 回退为纯文本,并删除可能的规划 / 元信息引导段落。
|
||||
- 忽略被标记为推理/错误内容的负载。
|
||||
- 解析直接 JSON、带围栏的 JSON 或内联 `"spoken"` 键。
|
||||
- 回退到纯文本,并移除可能属于规划/元信息的开头段落。
|
||||
|
||||
这样可以让语音播放聚焦于面向来电者的文本,并避免将规划文本泄漏到音频中。
|
||||
这样可以让语音播放聚焦于面向来电者的文本,并避免将规划文本泄露到音频中。
|
||||
|
||||
### 对话启动行为
|
||||
|
||||
对于呼出的 `conversation` 通话,首条消息处理与实时播放状态绑定:
|
||||
对于出站 `conversation` 通话,首条消息处理与实时播放状态绑定:
|
||||
|
||||
- 仅当初始问候正在主动播放时,才会抑制插话队列清除和自动响应。
|
||||
- 如果初始播放失败,通话会返回 `listening` 状态,且初始消息会继续保留在队列中等待重试。
|
||||
- Twilio 流式传输的初始播放会在流连接时立即开始,无额外延迟。
|
||||
- 插话会中止当前播放,并清除那些已排队但尚未开始播放的 Twilio TTS 条目。被清除的条目会以已跳过状态结束,因此后续响应逻辑可以继续,而不必等待那些永远不会播放的音频。
|
||||
- 实时语音对话使用实时流自身的开场轮次。语音通话不会为该初始消息发送旧版 `<Say>` TwiML 更新,因此呼出的 `<Connect><Stream>` 会话会保持附着状态。
|
||||
- 只有在初始问候语正在实际播放时,才会抑制插话队列清理和自动响应。
|
||||
- 如果初始播放失败,通话会回到 `listening`,初始消息仍保留在队列中以供重试。
|
||||
- Twilio 流式传输的初始播放会在流连接时启动,无需额外延迟。
|
||||
- 插话会中止当前播放,并清除那些已排队但尚未开始播放的 Twilio
|
||||
TTS 条目。被清除的条目会以已跳过状态结束,因此后续响应逻辑
|
||||
可以继续,而不必等待那些永远不会播放的音频。
|
||||
- 实时语音对话使用实时流自己的开场轮次。Voice Call 不会为该初始消息发送旧版 `<Say>` TwiML 更新,因此出站 `<Connect><Stream>` 会话会保持连接。
|
||||
|
||||
### Twilio 流断开宽限期
|
||||
|
||||
当 Twilio 媒体流断开时,语音通话会等待 `2000ms` 后再自动结束通话:
|
||||
当 Twilio 媒体流断开时,Voice Call 会等待 `2000ms`,然后才自动结束通话:
|
||||
|
||||
- 如果流在该时间窗口内重新连接,则自动结束会被取消。
|
||||
- 如果宽限期过后仍未重新注册任何流,则该通话会被结束,以防止通话卡在活动状态。
|
||||
- 如果流在该时间窗口内重新连接,则会取消自动结束。
|
||||
- 如果宽限期后仍未重新注册流,则会结束该通话,以防出现卡住的活动通话。
|
||||
|
||||
## CLI
|
||||
|
||||
```bash
|
||||
openclaw voicecall call --to "+15555550123" --message "Hello from OpenClaw"
|
||||
openclaw voicecall start --to "+15555550123" # alias for call
|
||||
openclaw voicecall start --to "+15555550123" # call 的别名
|
||||
openclaw voicecall continue --call-id <id> --message "Any questions?"
|
||||
openclaw voicecall speak --call-id <id> --message "One moment"
|
||||
openclaw voicecall dtmf --call-id <id> --digits "ww123456#"
|
||||
openclaw voicecall end --call-id <id>
|
||||
openclaw voicecall status --call-id <id>
|
||||
openclaw voicecall tail
|
||||
openclaw voicecall latency # summarize turn latency from logs
|
||||
openclaw voicecall latency # 从日志汇总轮次延迟
|
||||
openclaw voicecall expose --mode funnel
|
||||
```
|
||||
|
||||
`latency` 会从默认的 voice-call 存储路径读取 `calls.jsonl`。使用 `--file <path>` 指向其他日志文件,使用 `--last <n>` 将分析限制为最后 N 条记录(默认 200)。输出包括轮次延迟和监听等待时间的 p50/p90/p99。
|
||||
`latency` 会从默认的 voice-call 存储路径读取 `calls.jsonl`。使用
|
||||
`--file <path>` 指向其他日志,并使用 `--last <n>` 将分析限制
|
||||
为最后 N 条记录(默认 200)。输出包括轮次
|
||||
延迟和监听等待时间的 p50/p90/p99。
|
||||
|
||||
## 智能体工具
|
||||
|
||||
工具名称:`voice_call`
|
||||
|
||||
操作:
|
||||
动作:
|
||||
|
||||
- `initiate_call`(message, to?, mode?)
|
||||
- `continue_call`(callId, message)
|
||||
- `speak_to_user`(callId, message)
|
||||
- `send_dtmf`(callId, digits)
|
||||
- `initiate_call`(message、to?、mode?)
|
||||
- `continue_call`(callId、message)
|
||||
- `speak_to_user`(callId、message)
|
||||
- `send_dtmf`(callId、digits)
|
||||
- `end_call`(callId)
|
||||
- `get_status`(callId)
|
||||
|
||||
此仓库提供了对应的 skill 文档,路径为 `skills/voice-call/SKILL.md`。
|
||||
此仓库在 `skills/voice-call/SKILL.md` 中附带了匹配的 Skills 文档。
|
||||
|
||||
## Gateway 网关 RPC
|
||||
|
||||
- `voicecall.initiate`(`to?`, `message`, `mode?`)
|
||||
- `voicecall.continue`(`callId`, `message`)
|
||||
- `voicecall.speak`(`callId`, `message`)
|
||||
- `voicecall.dtmf`(`callId`, `digits`)
|
||||
- `voicecall.initiate`(`to?`、`message`、`mode?`)
|
||||
- `voicecall.continue`(`callId`、`message`)
|
||||
- `voicecall.speak`(`callId`、`message`)
|
||||
- `voicecall.dtmf`(`callId`、`digits`)
|
||||
- `voicecall.end`(`callId`)
|
||||
- `voicecall.status`(`callId`)
|
||||
|
||||
## 相关内容
|
||||
|
||||
- [Text-to-speech](/zh-CN/tools/tts)
|
||||
- [Talk mode](/zh-CN/nodes/talk)
|
||||
- [Voice wake](/zh-CN/nodes/voicewake)
|
||||
- [文本转语音](/zh-CN/tools/tts)
|
||||
- [Talk 模式](/zh-CN/nodes/talk)
|
||||
- [语音唤醒](/zh-CN/nodes/voicewake)
|
||||
|
||||
@ -1,39 +1,39 @@
|
||||
---
|
||||
read_when:
|
||||
- 你想通过缓存保留来降低提示词 Token 成本
|
||||
- 你需要在多智能体设置中为每个智能体提供缓存行为
|
||||
- 你正在同时调优心跳和 `cache-ttl` 清理策略
|
||||
summary: 提示缓存控制项、合并顺序、提供商行为和调优模式
|
||||
title: 提示缓存
|
||||
- 你想通过保留缓存来降低提示词 token 成本。
|
||||
- 你需要在多智能体设置中为每个智能体配置缓存行为。
|
||||
- 你正在同时调优 heartbeat 和 cache-ttl 修剪。
|
||||
summary: 提示词缓存控制项、合并顺序、提供商行为和调优模式
|
||||
title: 提示词缓存
|
||||
x-i18n:
|
||||
generated_at: "2026-04-25T02:55:41Z"
|
||||
generated_at: "2026-04-25T05:56:03Z"
|
||||
model: gpt-5.4
|
||||
provider: openai
|
||||
source_hash: 6a37a4283b9f45e0575bbe69ad27830b4c1c434193f0b3795208cdda37c49526
|
||||
source_hash: 4f3d1a5751ca0cab4c5b83c8933ec732b58c60d430e00c24ae9a75036aa0a6a3
|
||||
source_path: reference/prompt-caching.md
|
||||
workflow: 15
|
||||
---
|
||||
|
||||
提示缓存意味着模型提供商可以在多轮之间复用未变化的提示前缀(通常是 system/developer 指令和其他稳定上下文),而不是每次都重新处理这些内容。只要上游 API 直接暴露这些计数器,OpenClaw 就会将提供商的用量统一规范为 `cacheRead` 和 `cacheWrite`。
|
||||
提示词缓存意味着模型提供商可以在多轮之间复用未变化的提示词前缀(通常是 system/developer 指令和其他稳定上下文),而不是每次都重新处理它们。只要上游 API 直接暴露这些计数器,OpenClaw 就会将提供商的使用量标准化为 `cacheRead` 和 `cacheWrite`。
|
||||
|
||||
当实时会话快照缺少这些缓存计数器时,状态界面也可以从最近一次转录记录的 usage 日志中恢复缓存计数,因此即使发生部分会话元数据丢失,`/status` 仍能继续显示缓存相关行。现有的非零实时缓存值仍然优先于转录回退值。
|
||||
Status 表面在实时会话快照缺少缓存计数器时,也可以从最近的 transcript 使用日志中恢复这些计数,因此即使发生了部分会话元数据丢失,`/status` 仍然可以继续显示缓存行。已有的非零实时缓存值仍然优先于 transcript 回退值。
|
||||
|
||||
这为什么重要:更低的 Token 成本、更快的响应速度,以及对长时间运行会话而言更可预测的性能。如果没有缓存,即使大部分输入没有变化,重复提示也会在每一轮都支付完整的提示成本。
|
||||
这为什么重要:更低的 token 成本、更快的响应,以及对长时间运行会话来说更可预测的性能。如果没有缓存,即使大部分输入没有变化,重复的提示词在每一轮也都要支付完整的提示词成本。
|
||||
|
||||
本页介绍所有会影响提示复用和 Token 成本的缓存相关控制项。
|
||||
下面的章节涵盖了所有会影响提示词复用和 token 成本的缓存相关控制项。
|
||||
|
||||
提供商参考:
|
||||
|
||||
- Anthropic 提示缓存:[https://platform.claude.com/docs/en/build-with-claude/prompt-caching](https://platform.claude.com/docs/en/build-with-claude/prompt-caching)
|
||||
- OpenAI 提示缓存:[https://developers.openai.com/api/docs/guides/prompt-caching](https://developers.openai.com/api/docs/guides/prompt-caching)
|
||||
- OpenAI API 标头和请求 ID:[https://developers.openai.com/api/reference/overview](https://developers.openai.com/api/reference/overview)
|
||||
- Anthropic 请求 ID 和错误:[https://platform.claude.com/docs/en/api/errors](https://platform.claude.com/docs/en/api/errors)
|
||||
- Anthropic prompt caching:[https://platform.claude.com/docs/en/build-with-claude/prompt-caching](https://platform.claude.com/docs/en/build-with-claude/prompt-caching)
|
||||
- OpenAI prompt caching:[https://developers.openai.com/api/docs/guides/prompt-caching](https://developers.openai.com/api/docs/guides/prompt-caching)
|
||||
- OpenAI API headers and request IDs:[https://developers.openai.com/api/reference/overview](https://developers.openai.com/api/reference/overview)
|
||||
- Anthropic request IDs and errors:[https://platform.claude.com/docs/en/api/errors](https://platform.claude.com/docs/en/api/errors)
|
||||
|
||||
## 主要控制项
|
||||
|
||||
### `cacheRetention`(全局默认、模型级和每个智能体)
|
||||
### `cacheRetention`(全局默认、模型级和按智能体)
|
||||
|
||||
将缓存保留设置为适用于所有模型的全局默认值:
|
||||
为所有模型设置全局默认的缓存保留:
|
||||
|
||||
```yaml
|
||||
agents:
|
||||
@ -65,13 +65,13 @@ agents:
|
||||
|
||||
配置合并顺序:
|
||||
|
||||
1. `agents.defaults.params`(全局默认值——适用于所有模型)
|
||||
1. `agents.defaults.params`(全局默认 —— 适用于所有模型)
|
||||
2. `agents.defaults.models["provider/model"].params`(按模型覆盖)
|
||||
3. `agents.list[].params`(匹配的智能体 id;按键覆盖)
|
||||
|
||||
### `contextPruning.mode: "cache-ttl"`
|
||||
|
||||
在缓存 TTL 窗口之后清理旧的工具结果上下文,这样在空闲后发起请求时就不会重新缓存过大的历史记录。
|
||||
在缓存 TTL 窗口之后修剪旧的工具结果上下文,这样空闲后的请求就不会重新缓存过大的历史记录。
|
||||
|
||||
```yaml
|
||||
agents:
|
||||
@ -81,11 +81,11 @@ agents:
|
||||
ttl: "1h"
|
||||
```
|
||||
|
||||
完整行为请参见[会话清理](/zh-CN/concepts/session-pruning)。
|
||||
完整行为请参见 [会话修剪](/zh-CN/concepts/session-pruning)。
|
||||
|
||||
### 心跳保温
|
||||
### Heartbeat 保温
|
||||
|
||||
心跳可以保持缓存窗口处于“热”状态,并减少空闲间隔后重复发生的缓存写入。
|
||||
Heartbeat 可以让缓存窗口保持温热,并减少空闲间隔后的重复缓存写入。
|
||||
|
||||
```yaml
|
||||
agents:
|
||||
@ -94,87 +94,91 @@ agents:
|
||||
every: "55m"
|
||||
```
|
||||
|
||||
也支持在 `agents.list[].heartbeat` 中为每个智能体设置心跳。
|
||||
也支持通过 `agents.list[].heartbeat` 为每个智能体设置 heartbeat。
|
||||
|
||||
## 提供商行为
|
||||
|
||||
### Anthropic(直连 API)
|
||||
|
||||
- 支持 `cacheRetention`。
|
||||
- 对于 Anthropic API 密钥认证配置文件,当未设置时,OpenClaw 会为 Anthropic 模型引用预设 `cacheRetention: "short"`。
|
||||
- 对于 Anthropic API-key auth profiles,当未设置时,OpenClaw 会为 Anthropic 模型引用预填 `cacheRetention: "short"`。
|
||||
- Anthropic 原生 Messages 响应会同时暴露 `cache_read_input_tokens` 和 `cache_creation_input_tokens`,因此 OpenClaw 可以同时显示 `cacheRead` 和 `cacheWrite`。
|
||||
- 对于原生 Anthropic 请求,`cacheRetention: "short"` 会映射为默认的 5 分钟临时缓存,而 `cacheRetention: "long"` 仅会在直连 `api.anthropic.com` 主机时升级为 1 小时 TTL。
|
||||
- 对于原生 Anthropic 请求,`cacheRetention: "short"` 会映射到默认的 5 分钟 ephemeral cache,而 `cacheRetention: "long"` 仅在直连 `api.anthropic.com` 主机时升级为 1 小时 TTL。
|
||||
|
||||
### OpenAI(直连 API)
|
||||
|
||||
- 在受支持的较新模型上,提示缓存是自动的。OpenClaw 不需要注入块级缓存标记。
|
||||
- OpenClaw 使用 `prompt_cache_key` 来保持多轮之间的缓存路由稳定,并且只有在直连 OpenAI 主机上选择 `cacheRetention: "long"` 时,才会使用 `prompt_cache_retention: "24h"`。
|
||||
- 对于 OpenAI 兼容的 Completions 提供商,只有当其模型配置显式设置 `compat.supportsPromptCacheKey: true` 时,才会接收 `prompt_cache_key`;`cacheRetention: "none"` 仍会抑制它。
|
||||
- OpenAI 通过 `usage.prompt_tokens_details.cached_tokens`(或 Responses API 事件中的 `input_tokens_details.cached_tokens`)暴露缓存的提示 Token。OpenClaw 会将其映射为 `cacheRead`。
|
||||
- OpenAI 不会暴露单独的缓存写入 Token 计数器,因此即使提供商正在预热缓存,在 OpenAI 路径上 `cacheWrite` 仍保持为 `0`。
|
||||
- OpenAI 会返回有用的追踪和限速标头,例如 `x-request-id`、`openai-processing-ms` 和 `x-ratelimit-*`,但缓存命中统计应来自 usage 负载,而不是标头。
|
||||
- 在实践中,OpenAI 的行为通常更像是初始前缀缓存,而不是 Anthropic 那种可移动的完整历史复用。对于稳定的长前缀文本轮次,在当前实时探测中,缓存 Token 常常会停留在接近 `4864` 的平台值;而对工具密集型或 MCP 风格的转录,即使完全重复,也常常停留在接近 `4608` 个缓存 Token。
|
||||
- 支持的较新模型会自动启用提示词缓存。OpenClaw 不需要注入块级缓存标记。
|
||||
- OpenClaw 使用 `prompt_cache_key` 来让缓存路由在多轮之间保持稳定,并且仅当在直连 OpenAI 主机上选择 `cacheRetention: "long"` 时,才使用 `prompt_cache_retention: "24h"`。
|
||||
- OpenAI-compatible Completions 提供商只有在其模型配置显式设置 `compat.supportsPromptCacheKey: true` 时才会收到 `prompt_cache_key`;`cacheRetention: "none"` 仍会抑制它。
|
||||
- OpenAI 响应通过 `usage.prompt_tokens_details.cached_tokens`(或 Responses API 事件中的 `input_tokens_details.cached_tokens`)暴露缓存的提示词 token。OpenClaw 将其映射为 `cacheRead`。
|
||||
- OpenAI 不暴露单独的缓存写入 token 计数器,因此在 OpenAI 路径上,即使提供商正在预热缓存,`cacheWrite` 也仍然保持为 `0`。
|
||||
- OpenAI 会返回有用的追踪和限流头,例如 `x-request-id`、`openai-processing-ms` 和 `x-ratelimit-*`,但缓存命中统计应来自使用量负载,而不是响应头。
|
||||
- 实际上,OpenAI 的行为通常更像初始前缀缓存,而不是 Anthropic 式的移动全历史复用。在当前实时探测中,稳定的长前缀文本轮次通常会停在接近 `4864` 的 cached token 平台,而工具密集型或 MCP 风格的 transcript 即使完全重复,也通常停在接近 `4608` cached token。
|
||||
|
||||
### Anthropic Vertex
|
||||
|
||||
- Vertex AI 上的 Anthropic 模型(`anthropic-vertex/*`)对 `cacheRetention` 的支持方式与直连 Anthropic 相同。
|
||||
- `cacheRetention: "long"` 会在 Vertex AI 端点上映射为真实的 1 小时提示缓存 TTL。
|
||||
- `cacheRetention: "long"` 会在 Vertex AI 端点上映射为真实的 1 小时提示词缓存 TTL。
|
||||
- `anthropic-vertex` 的默认缓存保留策略与直连 Anthropic 的默认值一致。
|
||||
- Vertex 请求会经过具备边界感知能力的缓存整形流程,因此缓存复用会与提供商实际接收到的内容保持一致。
|
||||
- Vertex 请求会通过具备边界感知的缓存塑形进行路由,以便缓存复用与提供商实际收到的内容保持一致。
|
||||
|
||||
### Amazon Bedrock
|
||||
|
||||
- Anthropic Claude 模型引用(`amazon-bedrock/*anthropic.claude*`)支持显式透传 `cacheRetention`。
|
||||
- 非 Anthropic 的 Bedrock 模型会在运行时被强制设置为 `cacheRetention: "none"`。
|
||||
|
||||
### OpenRouter Anthropic 模型
|
||||
### OpenRouter 模型
|
||||
|
||||
对于 `openrouter/anthropic/*` 模型引用,只有当请求仍指向已验证的 OpenRouter 路由(默认端点上的 `openrouter`,或任何解析到 `openrouter.ai` 的提供商 / base URL)时,OpenClaw 才会在 system/developer 提示块上注入 Anthropic 的 `cache_control`,以提高提示缓存复用。
|
||||
对于 `openrouter/anthropic/*` 模型引用,OpenClaw 会在 system/developer 提示词块上注入 Anthropic 的 `cache_control`,以改进提示词缓存复用,但前提是请求仍然指向已验证的 OpenRouter 路由(默认端点上的 `openrouter`,或任何解析到 `openrouter.ai` 的 provider/base URL)。
|
||||
|
||||
如果你将模型改为指向任意 OpenAI 兼容代理 URL,OpenClaw 就会停止注入这些 OpenRouter 专用的 Anthropic 缓存标记。
|
||||
对于 `openrouter/deepseek/*`、`openrouter/moonshot*/*` 和 `openrouter/zai/*` 模型引用,允许使用 `contextPruning.mode: "cache-ttl"`,因为 OpenRouter 会自动处理提供商侧的提示词缓存。OpenClaw 不会向这些请求注入 Anthropic `cache_control` 标记。
|
||||
|
||||
DeepSeek 的缓存构建是尽力而为的,可能需要几秒钟。紧接着的后续请求仍可能显示 `cached_tokens: 0`;请在短暂延迟后,用相同前缀重复请求来验证,并使用 `usage.prompt_tokens_details.cached_tokens` 作为缓存命中信号。
|
||||
|
||||
如果你把模型重新指向任意一个 OpenAI-compatible 代理 URL,OpenClaw 就会停止注入这些 OpenRouter 专用的 Anthropic 缓存标记。
|
||||
|
||||
### 其他提供商
|
||||
|
||||
如果提供商不支持这种缓存模式,`cacheRetention` 将不会生效。
|
||||
如果提供商不支持这种缓存模式,`cacheRetention` 就不会产生效果。
|
||||
|
||||
### Google Gemini 直连 API
|
||||
|
||||
- 直连 Gemini 传输(`api: "google-generative-ai"`)会通过上游 `cachedContentTokenCount` 报告缓存命中;OpenClaw 会将其映射为 `cacheRead`。
|
||||
- 当在直连 Gemini 模型上设置 `cacheRetention` 时,OpenClaw 会在 Google AI Studio 运行中自动创建、复用并刷新用于 system 提示的 `cachedContents` 资源。这意味着你不再需要手动预先创建缓存内容句柄。
|
||||
- 你仍然可以通过已配置模型中的 `params.cachedContent`(或旧版 `params.cached_content`)传入一个预先存在的 Gemini 缓存内容句柄。
|
||||
- 这与 Anthropic/OpenAI 的提示前缀缓存不同。对于 Gemini,OpenClaw 管理的是提供商原生的 `cachedContents` 资源,而不是在请求中注入缓存标记。
|
||||
- 直连 Gemini 传输(`api: "google-generative-ai"`)通过上游 `cachedContentTokenCount` 报告缓存命中;OpenClaw 将其映射为 `cacheRead`。
|
||||
- 当在直连 Gemini 模型上设置 `cacheRetention` 时,OpenClaw 会自动为 Google AI Studio 运行创建、复用和刷新 system prompt 的 `cachedContents` 资源。这意味着你不再需要手动预先创建 cached-content handle。
|
||||
- 你仍然可以通过已配置模型上的 `params.cachedContent`(或旧键 `params.cached_content`)传入一个已存在的 Gemini cached-content handle。
|
||||
- 这与 Anthropic/OpenAI 的提示词前缀缓存不同。对于 Gemini,OpenClaw 管理的是提供商原生的 `cachedContents` 资源,而不是向请求中注入缓存标记。
|
||||
|
||||
### Gemini CLI JSON 用量
|
||||
### Gemini CLI JSON 使用量
|
||||
|
||||
- Gemini CLI JSON 输出也可以通过 `stats.cached` 暴露缓存命中;OpenClaw 会将其映射为 `cacheRead`。
|
||||
- 如果 CLI 省略了直接的 `stats.input` 值,OpenClaw 会通过 `stats.input_tokens - stats.cached` 推导输入 Token。
|
||||
- 这只是用量规范化。它并不意味着 OpenClaw 正在为 Gemini CLI 创建 Anthropic/OpenAI 风格的提示缓存标记。
|
||||
- Gemini CLI JSON 输出也可以通过 `stats.cached` 暴露缓存命中;OpenClaw 将其映射为 `cacheRead`。
|
||||
- 如果 CLI 省略了直接的 `stats.input` 值,OpenClaw 会用 `stats.input_tokens - stats.cached` 推导输入 token。
|
||||
- 这只是使用量标准化。这并不意味着 OpenClaw 正在为 Gemini CLI 创建 Anthropic/OpenAI 风格的提示词缓存标记。
|
||||
|
||||
## 系统提示缓存边界
|
||||
## 系统提示词缓存边界
|
||||
|
||||
OpenClaw 会将 system 提示拆分为**稳定前缀**和**易变后缀**,两者之间通过一个内部缓存前缀边界分隔。边界之上的内容(工具定义、Skills 元数据、工作区文件和其他相对静态的上下文)会按顺序组织,以便在多轮之间保持字节级一致。边界之下的内容(例如 `HEARTBEAT.md`、运行时时间戳和其他每轮元数据)则允许发生变化,而不会使已缓存的前缀失效。
|
||||
OpenClaw 会将 system prompt 拆分为一个**稳定前缀**和一个**易变后缀**,两者之间由一个内部缓存前缀边界分隔。边界之上的内容(工具定义、Skills 元数据、工作区文件以及其他相对静态的上下文)会按顺序组织,以便在多轮之间保持字节级一致。边界之下的内容(例如 `HEARTBEAT.md`、运行时时间戳和其他按轮次变化的元数据)允许变化,而不会使缓存前缀失效。
|
||||
|
||||
关键设计选择:
|
||||
|
||||
- 稳定的工作区项目上下文文件会排列在 `HEARTBEAT.md` 之前,因此心跳抖动不会破坏稳定前缀。
|
||||
- 该边界会应用于 Anthropic 系列、OpenAI 系列、Google 和 CLI 传输整形,因此所有受支持的提供商都能从同样的前缀稳定性中受益。
|
||||
- Codex Responses 和 Anthropic Vertex 请求会经过具备边界感知能力的缓存整形流程,因此缓存复用会与提供商实际接收到的内容保持一致。
|
||||
- system 提示指纹会进行规范化处理(空白、换行符、hook 添加的上下文、运行时能力排序),因此在语义未变化的情况下,多轮之间可以共享 KV/缓存。
|
||||
- 稳定的工作区项目上下文文件会排在 `HEARTBEAT.md` 之前,因此 heartbeat 抖动不会破坏稳定前缀。
|
||||
- 这个边界会应用到 Anthropic 系列、OpenAI 系列、Google 和 CLI 传输塑形中,因此所有受支持的提供商都能从同样的前缀稳定性中受益。
|
||||
- Codex Responses 和 Anthropic Vertex 请求会通过具备边界感知的缓存塑形进行路由,以便缓存复用与提供商实际收到的内容保持一致。
|
||||
- system prompt 指纹会被标准化(空白、换行、hook 添加的上下文、运行时能力排序),因此语义上未变化的提示词可以在多轮之间共享 KV/cache。
|
||||
|
||||
如果你在配置或工作区变更之后看到意外的 `cacheWrite` 峰值,请检查该变更是落在缓存边界之上还是之下。将易变内容移到边界之下(或使其稳定)通常可以解决这个问题。
|
||||
如果你在某次配置或工作区变更后看到意外的 `cacheWrite` 激增,请检查该变更落在缓存边界的上方还是下方。将易变内容移到边界下方(或让它变稳定)通常可以解决这个问题。
|
||||
|
||||
## OpenClaw 的缓存稳定性保护机制
|
||||
## OpenClaw 的缓存稳定性保护
|
||||
|
||||
在请求到达提供商之前,OpenClaw 还会让若干对缓存敏感的负载形态保持确定性:
|
||||
在请求到达提供商之前,OpenClaw 还会让几种对缓存敏感的负载形态保持确定性:
|
||||
|
||||
- Bundle MCP 工具目录会在工具注册之前按确定性顺序排序,因此 `listTools()` 顺序变化不会扰动工具块,也不会破坏提示缓存前缀。
|
||||
- 旧版会话中带有持久化图片块的内容会保留**最近 3 个已完成轮次**的完整内容;更早且已经处理过的图片块可能会被替换为一个标记,这样后续以图片为主的跟进就不会重复发送大量陈旧负载。
|
||||
- Bundle MCP 工具目录会在工具注册前按确定性顺序排序,因此 `listTools()` 顺序变化不会扰动工具块,也不会破坏提示词缓存前缀。
|
||||
- 带有已持久化图像块的旧会话会保留**最近 3 个已完成轮次**不变;更早且已经处理过的图像块可能会被替换为一个标记,这样高图像密度的后续轮次就不会反复重新发送体积庞大的旧负载。
|
||||
|
||||
## 调优模式
|
||||
|
||||
### 混合流量(推荐默认值)
|
||||
### 混合流量(推荐默认)
|
||||
|
||||
为主智能体保持长期基线缓存,而对突发型通知智能体禁用缓存:
|
||||
让主智能体保持长期基线,对突发型通知智能体禁用缓存:
|
||||
|
||||
```yaml
|
||||
agents:
|
||||
@ -197,64 +201,64 @@ agents:
|
||||
|
||||
### 成本优先基线
|
||||
|
||||
- 将基线设置为 `cacheRetention: "short"`。
|
||||
- 将基线 `cacheRetention` 设为 `short`。
|
||||
- 启用 `contextPruning.mode: "cache-ttl"`。
|
||||
- 仅对那些能从热缓存中受益的智能体,将心跳保持在你的 TTL 之下。
|
||||
- 仅为真正能从温热缓存中受益的智能体,将 heartbeat 保持在 TTL 以下。
|
||||
|
||||
## 缓存诊断
|
||||
|
||||
OpenClaw 为嵌入式智能体运行提供了专用的缓存追踪诊断。
|
||||
OpenClaw 为嵌入式智能体运行公开了专用的缓存追踪诊断。
|
||||
|
||||
对于常规的面向用户诊断,当实时会话条目中没有 `cacheRead` / `cacheWrite` 计数器时,`/status` 和其他 usage 汇总可以使用最新的转录 usage 条目作为回退来源。
|
||||
对于普通的面向用户诊断,当实时会话条目中没有 `cacheRead` / `cacheWrite` 计数器时,`/status` 和其他使用量摘要可以使用最新的 transcript 使用量条目作为回退来源。
|
||||
|
||||
## 实时回归测试
|
||||
|
||||
OpenClaw 保留了一个统一的实时缓存回归门禁,用于覆盖重复前缀、工具轮次、图片轮次、MCP 风格工具转录,以及一个 Anthropic 无缓存对照组。
|
||||
OpenClaw 维护了一个组合式的实时缓存回归门控,用于覆盖重复前缀、工具轮次、图像轮次、MCP 风格工具 transcript,以及一个 Anthropic 无缓存对照组。
|
||||
|
||||
- `src/agents/live-cache-regression.live.test.ts`
|
||||
- `src/agents/live-cache-regression-baseline.ts`
|
||||
|
||||
使用以下命令运行窄范围实时门禁:
|
||||
使用以下命令运行这个窄范围的实时门控:
|
||||
|
||||
```sh
|
||||
OPENCLAW_LIVE_TEST=1 OPENCLAW_LIVE_CACHE_TEST=1 pnpm test:live:cache
|
||||
```
|
||||
|
||||
基线文件会存储最近一次观察到的实时数值,以及测试使用的提供商特定回归下限。
|
||||
运行器还会使用每次运行全新的会话 ID 和提示命名空间,因此先前的缓存状态不会污染当前的回归样本。
|
||||
基线文件保存最近观察到的实时数值,以及测试所使用的按提供商划分的回归下限。
|
||||
运行器还会使用每次运行全新的会话 ID 和提示词命名空间,这样之前的缓存状态就不会污染当前的回归样本。
|
||||
|
||||
这些测试有意不在所有提供商之间使用完全相同的成功标准。
|
||||
这些测试有意不对所有提供商使用完全相同的成功标准。
|
||||
|
||||
### Anthropic 实时期望
|
||||
### Anthropic 实时预期
|
||||
|
||||
- 预期通过 `cacheWrite` 看到显式的预热写入。
|
||||
- 由于 Anthropic 缓存控制会在整个对话过程中推进缓存断点,因此在重复轮次中预期可以复用几乎完整的历史记录。
|
||||
- 当前实时断言仍然对稳定、工具和图片路径使用较高的命中率阈值。
|
||||
- 预期在重复轮次中能复用接近完整历史,因为 Anthropic 的缓存控制会沿着对话推进缓存断点。
|
||||
- 当前实时断言仍然对稳定、工具和图像路径使用较高的命中率阈值。
|
||||
|
||||
### OpenAI 实时期望
|
||||
### OpenAI 实时预期
|
||||
|
||||
- 仅预期有 `cacheRead`。`cacheWrite` 保持为 `0`。
|
||||
- 将重复轮次中的缓存复用视为提供商特定的平台值,而不是 Anthropic 式的可移动完整历史复用。
|
||||
- 当前实时断言对 `gpt-5.4-mini` 上观察到的实时行为使用保守的下限检查:
|
||||
- 预期只有 `cacheRead`。`cacheWrite` 会保持为 `0`。
|
||||
- 应将重复轮次的缓存复用视为提供商特定的平台值,而不是 Anthropic 式的移动全历史复用。
|
||||
- 当前实时断言使用基于 `gpt-5.4-mini` 实际实时行为得出的保守下限检查:
|
||||
- 稳定前缀:`cacheRead >= 4608`,命中率 `>= 0.90`
|
||||
- 工具转录:`cacheRead >= 4096`,命中率 `>= 0.85`
|
||||
- 图片转录:`cacheRead >= 3840`,命中率 `>= 0.82`
|
||||
- MCP 风格转录:`cacheRead >= 4096`,命中率 `>= 0.85`
|
||||
- 工具 transcript:`cacheRead >= 4096`,命中率 `>= 0.85`
|
||||
- 图像 transcript:`cacheRead >= 3840`,命中率 `>= 0.82`
|
||||
- MCP 风格 transcript:`cacheRead >= 4096`,命中率 `>= 0.85`
|
||||
|
||||
在 2026-04-04 的最新一次合并实时验证中,结果为:
|
||||
2026-04-04 的最新组合式实时验证结果为:
|
||||
|
||||
- 稳定前缀:`cacheRead=4864`,命中率 `0.966`
|
||||
- 工具转录:`cacheRead=4608`,命中率 `0.896`
|
||||
- 图片转录:`cacheRead=4864`,命中率 `0.954`
|
||||
- MCP 风格转录:`cacheRead=4608`,命中率 `0.891`
|
||||
- 工具 transcript:`cacheRead=4608`,命中率 `0.896`
|
||||
- 图像 transcript:`cacheRead=4864`,命中率 `0.954`
|
||||
- MCP 风格 transcript:`cacheRead=4608`,命中率 `0.891`
|
||||
|
||||
该合并门禁最近一次本地墙钟时间约为 `88s`。
|
||||
该组合门控最近一次本地墙钟时间约为 `88s`。
|
||||
|
||||
这些断言之所以不同,原因在于:
|
||||
这些断言为何不同:
|
||||
|
||||
- Anthropic 会暴露明确的缓存断点,以及可移动的会话历史复用。
|
||||
- OpenAI 的提示缓存仍然对精确前缀敏感,但在实时 Responses 流量中,可有效复用的前缀可能会比完整提示更早进入平台期。
|
||||
- 因此,如果用单一的跨提供商百分比阈值来比较 Anthropic 和 OpenAI,就会产生误报回归。
|
||||
- Anthropic 暴露了显式缓存断点和移动式对话历史复用。
|
||||
- OpenAI 提示词缓存仍然对精确前缀敏感,但在实时 Responses 流量中,可复用的有效前缀可能会比完整提示词更早进入平台值。
|
||||
- 因此,如果用一个跨提供商的统一百分比阈值去比较 Anthropic 和 OpenAI,就会产生误报回归。
|
||||
|
||||
### `diagnostics.cacheTrace` 配置
|
||||
|
||||
@ -262,10 +266,10 @@ OPENCLAW_LIVE_TEST=1 OPENCLAW_LIVE_CACHE_TEST=1 pnpm test:live:cache
|
||||
diagnostics:
|
||||
cacheTrace:
|
||||
enabled: true
|
||||
filePath: "~/.openclaw/logs/cache-trace.jsonl" # optional
|
||||
includeMessages: false # default true
|
||||
includePrompt: false # default true
|
||||
includeSystem: false # default true
|
||||
filePath: "~/.openclaw/logs/cache-trace.jsonl" # 可选
|
||||
includeMessages: false # 默认 true
|
||||
includePrompt: false # 默认 true
|
||||
includeSystem: false # 默认 true
|
||||
```
|
||||
|
||||
默认值:
|
||||
@ -280,33 +284,33 @@ diagnostics:
|
||||
- `OPENCLAW_CACHE_TRACE=1` 启用缓存追踪。
|
||||
- `OPENCLAW_CACHE_TRACE_FILE=/path/to/cache-trace.jsonl` 覆盖输出路径。
|
||||
- `OPENCLAW_CACHE_TRACE_MESSAGES=0|1` 切换是否捕获完整消息负载。
|
||||
- `OPENCLAW_CACHE_TRACE_PROMPT=0|1` 切换是否捕获提示文本。
|
||||
- `OPENCLAW_CACHE_TRACE_SYSTEM=0|1` 切换是否捕获 system 提示。
|
||||
- `OPENCLAW_CACHE_TRACE_PROMPT=0|1` 切换是否捕获提示词文本。
|
||||
- `OPENCLAW_CACHE_TRACE_SYSTEM=0|1` 切换是否捕获 system prompt。
|
||||
|
||||
### 要检查的内容
|
||||
### 检查什么
|
||||
|
||||
- 缓存追踪事件采用 JSONL 格式,并包含诸如 `session:loaded`、`prompt:before`、`stream:context` 和 `session:after` 之类的分阶段快照。
|
||||
- 每轮缓存 Token 的影响可以通过常规 usage 界面中的 `cacheRead` 和 `cacheWrite` 查看(例如 `/usage full` 和会话 usage 汇总)。
|
||||
- 对于 Anthropic,当缓存处于激活状态时,预期会看到 `cacheRead` 和 `cacheWrite` 两者。
|
||||
- 对于 OpenAI,缓存命中时预期会看到 `cacheRead`,而 `cacheWrite` 保持为 `0`;OpenAI 不会发布单独的缓存写入 Token 字段。
|
||||
- 如果你需要请求追踪,请将请求 ID 和限速标头与缓存指标分开记录。OpenClaw 当前的缓存追踪输出侧重于提示 / 会话形态和规范化的 Token usage,而不是原始提供商响应标头。
|
||||
- 缓存追踪事件是 JSONL,包含诸如 `session:loaded`、`prompt:before`、`stream:context` 和 `session:after` 这样的分阶段快照。
|
||||
- 每轮缓存 token 的影响可以通过常规使用量表面中的 `cacheRead` 和 `cacheWrite` 看见(例如 `/usage full` 和会话使用量摘要)。
|
||||
- 对于 Anthropic,在缓存生效时,预期同时看到 `cacheRead` 和 `cacheWrite`。
|
||||
- 对于 OpenAI,预期在缓存命中时看到 `cacheRead`,而 `cacheWrite` 保持为 `0`;OpenAI 不公布单独的缓存写入 token 字段。
|
||||
- 如果你需要请求追踪,请将请求 ID 和限流响应头与缓存指标分开记录。OpenClaw 当前的缓存追踪输出聚焦于提示词/会话形态和标准化 token 使用量,而不是原始提供商响应头。
|
||||
|
||||
## 快速故障排除
|
||||
|
||||
- 大多数轮次都出现较高的 `cacheWrite`:检查 system 提示输入中是否包含易变内容,并确认模型 / 提供商支持你的缓存设置。
|
||||
- Anthropic 上 `cacheWrite` 较高:通常意味着缓存断点落在了每次请求都会变化的内容上。
|
||||
- OpenAI 的 `cacheRead` 偏低:确认稳定前缀位于最前面,重复前缀至少有 1024 个 Token,并且对于应共享缓存的轮次复用了同一个 `prompt_cache_key`。
|
||||
- 大多数轮次上 `cacheWrite` 很高:检查 system prompt 输入中是否有易变内容,并确认模型/提供商支持你的缓存设置。
|
||||
- Anthropic 上 `cacheWrite` 很高:通常意味着缓存断点落在每次请求都会变化的内容上。
|
||||
- OpenAI 上 `cacheRead` 很低:确认稳定前缀位于最前面、重复前缀至少有 1024 个 token,并且应该共享缓存的轮次复用了相同的 `prompt_cache_key`。
|
||||
- `cacheRetention` 没有效果:确认模型键与 `agents.defaults.models["provider/model"]` 匹配。
|
||||
- 带有缓存设置的 Bedrock Nova/Mistral 请求:运行时强制设为 `none` 属于预期行为。
|
||||
- 带缓存设置的 Bedrock Nova/Mistral 请求:预期会在运行时被强制设为 `none`。
|
||||
|
||||
相关文档:
|
||||
|
||||
- [Anthropic](/zh-CN/providers/anthropic)
|
||||
- [Token 使用和成本](/zh-CN/reference/token-use)
|
||||
- [会话清理](/zh-CN/concepts/session-pruning)
|
||||
- [会话修剪](/zh-CN/concepts/session-pruning)
|
||||
- [Gateway 网关配置参考](/zh-CN/gateway/configuration-reference)
|
||||
|
||||
## 相关内容
|
||||
|
||||
- [Token 使用和成本](/zh-CN/reference/token-use)
|
||||
- [API 使用和成本](/zh-CN/reference/api-usage-costs)
|
||||
- [API 使用量和成本](/zh-CN/reference/api-usage-costs)
|
||||
|
||||
@ -1,32 +1,32 @@
|
||||
---
|
||||
read_when:
|
||||
- 更改 Control UI 中的智能体输出渲染方式
|
||||
- 调试 `[embed ...]`、`MEDIA:`、回复或音频呈现指令
|
||||
- 更改 Control UI 中的助手输出渲染方式
|
||||
- 调试 `[embed ...]`、`MEDIA:`、reply 或音频呈现指令
|
||||
summary: 用于嵌入、媒体、音频提示和回复的富输出短代码协议
|
||||
title: 富输出协议
|
||||
x-i18n:
|
||||
generated_at: "2026-04-25T04:54:58Z"
|
||||
generated_at: "2026-04-25T05:56:22Z"
|
||||
model: gpt-5.4
|
||||
provider: openai
|
||||
source_hash: 3ccd0698d88aae86d8f857f4f16f999d161e08542bf6d02bbd54a4a23bdbd5a8
|
||||
source_hash: 643d1594d05174abf984f06c76a675670968c42c7260e7b73821f346e3f683df
|
||||
source_path: reference/rich-output-protocol.md
|
||||
workflow: 15
|
||||
---
|
||||
|
||||
智能体输出可以携带一小组传递/渲染指令:
|
||||
助手输出可以携带一小组投递/渲染指令:
|
||||
|
||||
- `MEDIA:` 用于附件传递
|
||||
- `MEDIA:` 用于附件投递
|
||||
- `[[audio_as_voice]]` 用于音频呈现提示
|
||||
- `[[reply_to_current]]` / `[[reply_to:<id>]]` 用于回复元数据
|
||||
- `[embed ...]` 用于 Control UI 富渲染
|
||||
|
||||
这些指令彼此独立。`MEDIA:` 和回复/语音标签仍然是传递元数据;`[embed ...]` 是仅限 Web 的富渲染路径。
|
||||
这些指令彼此独立。`MEDIA:` 和 reply/voice 标签仍然是投递元数据;`[embed ...]` 是仅限 Web 的富渲染路径。
|
||||
|
||||
启用分块流式传输后,`MEDIA:` 仍然是单次会话回合的单次传递元数据。如果同一个媒体 URL 在流式块中发送,并在最终智能体载荷中重复出现,OpenClaw 会只传递一次附件,并从最终载荷中移除重复项。
|
||||
启用分块流式传输时,`MEDIA:` 对于单个轮次仍然是单次投递元数据。如果同一个媒体 URL 已在流式块中发送,又在最终助手载荷中重复出现,OpenClaw 只会投递一次附件,并从最终载荷中移除重复项。
|
||||
|
||||
## `[embed ...]`
|
||||
|
||||
`[embed ...]` 是面向智能体、用于 Control UI 的唯一富渲染语法。
|
||||
`[embed ...]` 是面向智能体的、用于 Control UI 的唯一富渲染语法。
|
||||
|
||||
自闭合示例:
|
||||
|
||||
@ -37,15 +37,15 @@ x-i18n:
|
||||
规则:
|
||||
|
||||
- `[view ...]` 不再适用于新的输出。
|
||||
- Embed 短代码只会在智能体消息界面中渲染。
|
||||
- 只会渲染由 URL 支持的嵌入。请使用 `ref="..."` 或 `url="..."`。
|
||||
- embed 短代码仅在助手消息界面中渲染。
|
||||
- 仅渲染基于 URL 的 embed。请使用 `ref="..."` 或 `url="..."`。
|
||||
- 块形式的内联 HTML embed 短代码不会被渲染。
|
||||
- Web UI 会从可见文本中移除该短代码,并以内联方式渲染嵌入内容。
|
||||
- `MEDIA:` 不是 embed 的别名,不应用于富嵌入渲染。
|
||||
- Web UI 会从可见文本中移除该短代码,并以内联方式渲染 embed。
|
||||
- `MEDIA:` 不是 embed 别名,不应用于富 embed 渲染。
|
||||
|
||||
## 存储的渲染形态
|
||||
## 存储的渲染结构
|
||||
|
||||
标准化/存储后的智能体内容块是一个结构化的 `canvas` 项:
|
||||
规范化/存储后的助手内容块是一个结构化的 `canvas` 项:
|
||||
|
||||
```json
|
||||
{
|
||||
@ -62,7 +62,7 @@ x-i18n:
|
||||
}
|
||||
```
|
||||
|
||||
已存储/已渲染的富块会直接使用这个 `canvas` 形态。`present_view` 不会被识别。
|
||||
已存储/已渲染的富块直接使用这种 `canvas` 结构。`present_view` 不会被识别。
|
||||
|
||||
## 相关内容
|
||||
|
||||
|
||||
@ -1,48 +1,46 @@
|
||||
---
|
||||
read_when:
|
||||
- 你需要调试会话 ID、转录记录 JSONL,或 `sessions.json` 字段
|
||||
- 你正在更改自动压缩行为,或添加“预压缩”清理逻辑
|
||||
- 你想要实现内存刷新或静默系统轮次
|
||||
summary: 深入解析:会话存储 + 转录记录、生命周期,以及(自动)压缩内部机制
|
||||
- 你需要调试会话 id、转录 JSONL 或 `sessions.json` 字段。
|
||||
- 你正在更改自动压缩行为,或添加“压缩前”清理逻辑。
|
||||
- 你想实现内存刷新或静默系统回合。
|
||||
summary: 深入解析:会话存储 + 转录、生命周期,以及(自动)压缩内部机制
|
||||
title: 会话管理深入解析
|
||||
x-i18n:
|
||||
generated_at: "2026-04-25T03:06:21Z"
|
||||
generated_at: "2026-04-25T05:56:36Z"
|
||||
model: gpt-5.4
|
||||
provider: openai
|
||||
source_hash: eea076da8eecf01a4d88e6d693d936701beb9e57438ea8bfdeede5a3cb549a43
|
||||
source_hash: f15b8cf4b1deb947b292c6931257218d7147c11c963e7bf2689b6d1f77ea8159
|
||||
source_path: reference/session-management-compaction.md
|
||||
workflow: 15
|
||||
---
|
||||
|
||||
# 会话管理与压缩(深入解析)
|
||||
|
||||
本文档解释了 OpenClaw 如何端到端管理会话:
|
||||
本页解释 OpenClaw 如何端到端管理会话:
|
||||
|
||||
- **会话路由**(入站消息如何映射到 `sessionKey`)
|
||||
- **会话存储**(`sessions.json`)及其跟踪内容
|
||||
- **转录记录持久化**(`*.jsonl`)及其结构
|
||||
- **转录记录清理**(运行前针对特定提供商的修复)
|
||||
- **上下文限制**(上下文窗口 vs 跟踪的令牌数)
|
||||
- **压缩**(手动 + 自动压缩)以及在哪里挂接预压缩工作
|
||||
- **转录持久化**(`*.jsonl`)及其结构
|
||||
- **转录清理**(运行前针对不同提供商的特定修正)
|
||||
- **上下文限制**(上下文窗口与已跟踪 token)
|
||||
- **压缩**(手动 + 自动压缩)以及应在何处挂接压缩前工作
|
||||
- **静默清理**(例如不应产生用户可见输出的内存写入)
|
||||
|
||||
如果你想先了解更高层级的概览,请从以下内容开始:
|
||||
如果你想先看更高层的概览,请从以下内容开始:
|
||||
|
||||
- [/concepts/session](/zh-CN/concepts/session)
|
||||
- [/concepts/compaction](/zh-CN/concepts/compaction)
|
||||
- [/concepts/memory](/zh-CN/concepts/memory)
|
||||
- [/concepts/memory-search](/zh-CN/concepts/memory-search)
|
||||
- [/concepts/session-pruning](/zh-CN/concepts/session-pruning)
|
||||
- [/reference/transcript-hygiene](/zh-CN/reference/transcript-hygiene)
|
||||
- [会话管理](/zh-CN/concepts/session)
|
||||
- [压缩](/zh-CN/concepts/compaction)
|
||||
- [内存概览](/zh-CN/concepts/memory)
|
||||
- [内存搜索](/zh-CN/concepts/memory-search)
|
||||
- [会话修剪](/zh-CN/concepts/session-pruning)
|
||||
- [转录清理](/zh-CN/reference/transcript-hygiene)
|
||||
|
||||
---
|
||||
|
||||
## 事实来源:Gateway 网关
|
||||
## 真实来源:Gateway 网关
|
||||
|
||||
OpenClaw 的设计围绕一个拥有会话状态的单一 **Gateway 网关进程**。
|
||||
OpenClaw 围绕一个单一的 **Gateway 网关进程** 设计,它负责持有会话状态。
|
||||
|
||||
- UI(macOS 应用、Web Control UI、TUI)应查询 Gateway 网关以获取会话列表和令牌计数。
|
||||
- 在远程模式下,会话文件位于远程主机上;“检查你本地 Mac 上的文件”并不能反映 Gateway 网关实际使用的内容。
|
||||
- UI(macOS 应用、Web Control UI、TUI)应向 Gateway 网关查询会话列表和 token 计数。
|
||||
- 在远程模式下,会话文件位于远程主机上;“检查你本地 Mac 上的文件”并不能反映 Gateway 网关 实际使用的内容。
|
||||
|
||||
---
|
||||
|
||||
@ -52,47 +50,47 @@ OpenClaw 通过两层来持久化会话:
|
||||
|
||||
1. **会话存储(`sessions.json`)**
|
||||
- 键值映射:`sessionKey -> SessionEntry`
|
||||
- 体积小、可变、可安全编辑(或删除条目)
|
||||
- 跟踪会话元数据(当前会话 id、最近活动时间、开关、令牌计数器等)
|
||||
- 小型、可变、可安全编辑(或删除条目)
|
||||
- 跟踪会话元数据(当前会话 id、最近活动、切换项、token 计数器等)
|
||||
|
||||
2. **转录记录(`<sessionId>.jsonl`)**
|
||||
- 采用树结构的仅追加转录记录(条目包含 `id` + `parentId`)
|
||||
2. **转录(`<sessionId>.jsonl`)**
|
||||
- 带树状结构的仅追加转录(条目具有 `id` + `parentId`)
|
||||
- 存储实际对话 + 工具调用 + 压缩摘要
|
||||
- 用于为后续轮次重建模型上下文
|
||||
- 用于为后续回合重建模型上下文
|
||||
|
||||
---
|
||||
|
||||
## 磁盘上的位置
|
||||
## 磁盘位置
|
||||
|
||||
在 Gateway 网关主机上,按智能体分别存储:
|
||||
在 Gateway 网关主机上,按智能体划分:
|
||||
|
||||
- 存储:`~/.openclaw/agents/<agentId>/sessions/sessions.json`
|
||||
- 转录记录:`~/.openclaw/agents/<agentId>/sessions/<sessionId>.jsonl`
|
||||
- Telegram 话题会话:`.../<sessionId>-topic-<threadId>.jsonl`
|
||||
- 转录:`~/.openclaw/agents/<agentId>/sessions/<sessionId>.jsonl`
|
||||
- Telegram 主题会话:`.../<sessionId>-topic-<threadId>.jsonl`
|
||||
|
||||
OpenClaw 通过 `src/config/sessions.ts` 解析这些路径。
|
||||
|
||||
---
|
||||
|
||||
## 存储维护和磁盘控制
|
||||
## 存储维护与磁盘控制
|
||||
|
||||
会话持久化为 `sessions.json` 和转录记录产物提供了自动维护控制(`session.maintenance`):
|
||||
会话持久化为 `sessions.json` 和转录产物提供了自动维护控制(`session.maintenance`):
|
||||
|
||||
- `mode`:`warn`(默认)或 `enforce`
|
||||
- `pruneAfter`:陈旧条目的保留期限截止时间(默认 `30d`)
|
||||
- `pruneAfter`:陈旧条目的存活时间截止值(默认 `30d`)
|
||||
- `maxEntries`:`sessions.json` 中的条目上限(默认 `500`)
|
||||
- `rotateBytes`:当 `sessions.json` 过大时进行轮转(默认 `10mb`)
|
||||
- `resetArchiveRetention`:`*.reset.<timestamp>` 转录记录归档的保留期(默认:与 `pruneAfter` 相同;`false` 禁用清理)
|
||||
- `maxDiskBytes`:可选的会话目录空间预算
|
||||
- `resetArchiveRetention`:`*.reset.<timestamp>` 转录归档的保留时间(默认:与 `pruneAfter` 相同;`false` 表示禁用清理)
|
||||
- `maxDiskBytes`:可选的会话目录预算
|
||||
- `highWaterBytes`:清理后的可选目标值(默认是 `maxDiskBytes` 的 `80%`)
|
||||
|
||||
磁盘预算清理的执行顺序(`mode: "enforce"`):
|
||||
|
||||
1. 先删除最旧的归档或孤立转录记录产物。
|
||||
2. 如果仍高于目标值,则驱逐最旧的会话条目及其转录记录文件。
|
||||
1. 先删除最旧的归档或孤立转录产物。
|
||||
2. 如果仍高于目标值,则驱逐最旧的会话条目及其转录文件。
|
||||
3. 持续执行,直到使用量小于或等于 `highWaterBytes`。
|
||||
|
||||
在 `mode: "warn"` 下,OpenClaw 会报告潜在的驱逐操作,但不会修改存储或文件。
|
||||
在 `mode: "warn"` 下,OpenClaw 会报告潜在的驱逐操作,但不会修改存储/文件。
|
||||
|
||||
按需运行维护:
|
||||
|
||||
@ -103,104 +101,107 @@ openclaw sessions cleanup --enforce
|
||||
|
||||
---
|
||||
|
||||
## Cron 会话和运行日志
|
||||
## Cron 会话与运行日志
|
||||
|
||||
隔离的 cron 运行也会创建会话条目和转录记录,并且它们有专用的保留控制:
|
||||
隔离的 cron 运行也会创建会话条目/转录,并且它们有专门的保留控制:
|
||||
|
||||
- `cron.sessionRetention`(默认 `24h`)会从会话存储中清理旧的隔离 cron 运行会话(`false` 禁用)。
|
||||
- `cron.runLog.maxBytes` + `cron.runLog.keepLines` 会清理 `~/.openclaw/cron/runs/<jobId>.jsonl` 文件(默认分别为 `2_000_000` 字节和 `2000` 行)。
|
||||
- `cron.sessionRetention`(默认 `24h`)会从会话存储中修剪旧的隔离 cron 运行会话(`false` 表示禁用)。
|
||||
- `cron.runLog.maxBytes` + `cron.runLog.keepLines` 会修剪 `~/.openclaw/cron/runs/<jobId>.jsonl` 文件(默认值分别为 `2_000_000` 字节和 `2000` 行)。
|
||||
|
||||
当 cron 强制创建新的隔离运行会话时,它会在写入新行之前清理旧的
|
||||
`cron:<jobId>` 会话条目。它会保留安全的偏好设置,例如 thinking/fast/verbose 设置、标签以及用户明确选择的模型/auth 覆盖。它会丢弃环境对话上下文,例如渠道/群组路由、发送或队列策略、提权、来源和 ACP 运行时绑定,这样新的隔离运行就不会继承旧运行中过期的传递或运行时权限。
|
||||
|
||||
---
|
||||
|
||||
## 会话键(`sessionKey`)
|
||||
|
||||
`sessionKey` 用于标识你处于 _哪个对话桶_ 中(路由 + 隔离)。
|
||||
`sessionKey` 用于标识你处于哪个 _对话桶_ 中(路由 + 隔离)。
|
||||
|
||||
常见模式:
|
||||
|
||||
- 主/直接聊天(每个智能体):`agent:<agentId>:<mainKey>`(默认 `main`)
|
||||
- 主/直接聊天(按智能体):`agent:<agentId>:<mainKey>`(默认 `main`)
|
||||
- 群组:`agent:<agentId>:<channel>:group:<id>`
|
||||
- 房间/渠道(Discord/Slack):`agent:<agentId>:<channel>:channel:<id>` 或 `...:room:<id>`
|
||||
- Cron:`cron:<job.id>`
|
||||
- Webhook:`hook:<uuid>`(除非被覆盖)
|
||||
|
||||
规范规则记录在 [/concepts/session](/zh-CN/concepts/session) 中。
|
||||
规范规则记录在 [/concepts/session](/zh-CN/concepts/session)。
|
||||
|
||||
---
|
||||
|
||||
## 会话 id(`sessionId`)
|
||||
|
||||
每个 `sessionKey` 都指向一个当前的 `sessionId`(持续承接对话的转录记录文件)。
|
||||
每个 `sessionKey` 都指向一个当前 `sessionId`(持续该对话的转录文件)。
|
||||
|
||||
经验规则:
|
||||
|
||||
- **重置**(`/new`、`/reset`)会为该 `sessionKey` 创建新的 `sessionId`。
|
||||
- **每日重置**(默认在 Gateway 网关主机本地时间凌晨 4:00)会在越过重置边界后的下一条消息到来时创建新的 `sessionId`。
|
||||
- **空闲过期**(`session.reset.idleMinutes` 或旧版 `session.idleMinutes`)会在空闲窗口后有消息到达时创建新的 `sessionId`。如果同时配置了每日重置和空闲过期,则以先到期者为准。
|
||||
- **线程父级分叉保护**(`session.parentForkMaxTokens`,默认 `100000`)会在父会话已经过大时跳过父转录记录分叉;新线程将从头开始。设为 `0` 可禁用。
|
||||
- **每日重置**(默认在 Gateway 网关主机本地时间凌晨 4:00)会在越过重置边界后的下一条消息时创建新的 `sessionId`。
|
||||
- **空闲过期**(`session.reset.idleMinutes` 或旧版 `session.idleMinutes`)会在消息于空闲窗口之后到达时创建新的 `sessionId`。当每日重置与空闲过期同时配置时,以先到期者为准。
|
||||
- **线程父级分叉保护**(`session.parentForkMaxTokens`,默认 `100000`)会在父会话已过大时跳过父转录分叉;新线程将从头开始。设置为 `0` 可禁用。
|
||||
|
||||
实现细节:该决策发生在 `src/auto-reply/reply/session.ts` 中的 `initSessionState()`。
|
||||
实现细节:此决策发生在 `src/auto-reply/reply/session.ts` 中的 `initSessionState()`。
|
||||
|
||||
---
|
||||
|
||||
## 会话存储结构(`sessions.json`)
|
||||
## 会话存储 schema(`sessions.json`)
|
||||
|
||||
该存储的值类型是 `src/config/sessions.ts` 中的 `SessionEntry`。
|
||||
存储的值类型是 `src/config/sessions.ts` 中的 `SessionEntry`。
|
||||
|
||||
关键字段(并非完整列表):
|
||||
关键字段(非完整列表):
|
||||
|
||||
- `sessionId`:当前转录记录 id(除非设置了 `sessionFile`,否则文件名由此派生)
|
||||
- `sessionId`:当前转录 id(除非设置了 `sessionFile`,否则文件名由此派生)
|
||||
- `updatedAt`:最近活动时间戳
|
||||
- `sessionFile`:可选的显式转录记录路径覆盖
|
||||
- `chatType`:`direct | group | room`(帮助 UI 和发送策略)
|
||||
- `provider`, `subject`, `room`, `space`, `displayName`:用于群组/渠道标签的元数据
|
||||
- 开关:
|
||||
- `thinkingLevel`, `verboseLevel`, `reasoningLevel`, `elevatedLevel`
|
||||
- `sessionFile`:可选的显式转录路径覆盖
|
||||
- `chatType`:`direct | group | room`(有助于 UI 和发送策略)
|
||||
- `provider`、`subject`、`room`、`space`、`displayName`:用于群组/渠道标签的元数据
|
||||
- 切换项:
|
||||
- `thinkingLevel`、`verboseLevel`、`reasoningLevel`、`elevatedLevel`
|
||||
- `sendPolicy`(按会话覆盖)
|
||||
- 模型选择:
|
||||
- `providerOverride`, `modelOverride`, `authProfileOverride`
|
||||
- 令牌计数器(尽力而为 / 依赖提供商):
|
||||
- `inputTokens`, `outputTokens`, `totalTokens`, `contextTokens`
|
||||
- `compactionCount`:此会话键完成自动压缩的次数
|
||||
- `memoryFlushAt`:最近一次预压缩内存刷新的时间戳
|
||||
- `memoryFlushCompactionCount`:最近一次刷新运行时对应的压缩次数
|
||||
- `providerOverride`、`modelOverride`、`authProfileOverride`
|
||||
- token 计数器(尽力而为 / 依赖提供商):
|
||||
- `inputTokens`、`outputTokens`、`totalTokens`、`contextTokens`
|
||||
- `compactionCount`:该 `sessionKey` 完成自动压缩的次数
|
||||
- `memoryFlushAt`:最近一次压缩前内存刷新时间戳
|
||||
- `memoryFlushCompactionCount`:最近一次刷新运行时的压缩计数
|
||||
|
||||
该存储可安全编辑,但 Gateway 网关才是权威:随着会话运行,它可能会重写或重新填充条目。
|
||||
该存储可安全编辑,但 Gateway 网关 才是权威:随着会话运行,它可能会重写或重新填充条目。
|
||||
|
||||
---
|
||||
|
||||
## 转录记录结构(`*.jsonl`)
|
||||
## 转录结构(`*.jsonl`)
|
||||
|
||||
转录记录由 `@mariozechner/pi-coding-agent` 的 `SessionManager` 管理。
|
||||
转录由 `@mariozechner/pi-coding-agent` 的 `SessionManager` 管理。
|
||||
|
||||
该文件是 JSONL:
|
||||
文件采用 JSONL 格式:
|
||||
|
||||
- 第一行:会话头(`type: "session"`,包含 `id`、`cwd`、`timestamp`、可选的 `parentSession`)
|
||||
- 然后:带有 `id` + `parentId` 的会话条目(树结构)
|
||||
- 之后:带有 `id` + `parentId` 的会话条目(树结构)
|
||||
|
||||
值得注意的条目类型:
|
||||
|
||||
- `message`:用户/助手/`toolResult` 消息
|
||||
- `custom_message`:由扩展注入并且 _会_ 进入模型上下文的消息(可对 UI 隐藏)
|
||||
- `message`:用户/助手/toolResult 消息
|
||||
- `custom_message`:由扩展注入、且 _会_ 进入模型上下文的消息(可在 UI 中隐藏)
|
||||
- `custom`:_不会_ 进入模型上下文的扩展状态
|
||||
- `compaction`:持久化的压缩摘要,带有 `firstKeptEntryId` 和 `tokensBefore`
|
||||
- `branch_summary`:在导航树分支时持久化的摘要
|
||||
|
||||
OpenClaw 有意**不**“修复”转录记录;Gateway 网关使用 `SessionManager` 读取/写入它们。
|
||||
OpenClaw 有意 **不** “修正”转录;Gateway 网关 使用 `SessionManager` 读写它们。
|
||||
|
||||
---
|
||||
|
||||
## 上下文窗口 vs 跟踪的令牌数
|
||||
## 上下文窗口与已跟踪 token
|
||||
|
||||
有两个不同的概念需要注意:
|
||||
这里有两个不同但都重要的概念:
|
||||
|
||||
1. **模型上下文窗口**:每个模型的硬上限(模型可见的令牌数)
|
||||
2. **会话存储计数器**:写入 `sessions.json` 的滚动统计数据(用于 `/status` 和仪表板)
|
||||
1. **模型上下文窗口**:每个模型的硬上限(模型可见的 token)
|
||||
2. **会话存储计数器**:写入 `sessions.json` 的滚动统计信息(用于 `/status` 和仪表盘)
|
||||
|
||||
如果你正在调整限制:
|
||||
如果你要调优限制:
|
||||
|
||||
- 上下文窗口来自模型目录(也可通过配置覆盖)。
|
||||
- 存储中的 `contextTokens` 是运行时估算/报告值;不要将其视为严格保证。
|
||||
- 上下文窗口来自模型目录(并且可以通过配置覆盖)。
|
||||
- 存储中的 `contextTokens` 是运行时估算/报告值;不要把它当作严格保证。
|
||||
|
||||
更多信息,请参见 [/token-use](/zh-CN/reference/token-use)。
|
||||
|
||||
@ -208,38 +209,38 @@ OpenClaw 有意**不**“修复”转录记录;Gateway 网关使用 `SessionMa
|
||||
|
||||
## 压缩:它是什么
|
||||
|
||||
压缩会把较早的对话总结为转录记录中持久化的 `compaction` 条目,并保持最近的消息不变。
|
||||
压缩会把较早的对话总结成转录中的持久化 `compaction` 条目,并保留最近消息不变。
|
||||
|
||||
压缩之后,后续轮次将看到:
|
||||
压缩后,后续回合会看到:
|
||||
|
||||
- 压缩摘要
|
||||
- `firstKeptEntryId` 之后的消息
|
||||
|
||||
压缩是**持久化的**(不同于会话修剪)。参见 [/concepts/session-pruning](/zh-CN/concepts/session-pruning)。
|
||||
|
||||
## 压缩分块边界和工具配对
|
||||
## 压缩分块边界与工具配对
|
||||
|
||||
当 OpenClaw 将较长的转录记录拆分为压缩分块时,它会让
|
||||
助手工具调用与其对应的 `toolResult` 条目保持配对。
|
||||
当 OpenClaw 将较长的转录拆分为多个压缩分块时,它会保持
|
||||
助手工具调用与其匹配的 `toolResult` 条目成对出现。
|
||||
|
||||
- 如果按令牌占比分割的边界落在工具调用和其结果之间,OpenClaw
|
||||
会将边界移动到助手工具调用消息处,而不是将这对条目拆开。
|
||||
- 如果尾部的工具结果块原本会把分块推到超出目标值,
|
||||
OpenClaw 会保留这个待处理的工具块,并让未总结的尾部保持完整。
|
||||
- 已中止/出错的工具调用块不会让待处理分割持续保持打开状态。
|
||||
- 如果 token 占比分割点恰好落在工具调用和其结果之间,OpenClaw
|
||||
会将边界移动到助手工具调用消息,而不是将这一对拆开。
|
||||
- 如果尾部的 tool-result 块本来会把分块推到超出目标大小,
|
||||
OpenClaw 会保留这个待处理工具块,并保持未总结的尾部完整。
|
||||
- 已中止/出错的工具调用块不会阻止待处理分割继续进行。
|
||||
|
||||
---
|
||||
|
||||
## 自动压缩何时发生(Pi 运行时)
|
||||
|
||||
在嵌入式 Pi 智能体中,自动压缩会在两种情况下触发:
|
||||
在内嵌 Pi 智能体中,自动压缩会在两种情况下触发:
|
||||
|
||||
1. **溢出恢复**:模型返回上下文溢出错误
|
||||
(`request_too_large`、`context length exceeded`、`input exceeds the maximum
|
||||
number of tokens`、`input token count exceeds the maximum number of input
|
||||
tokens`、`input is too long for the model`、`ollama error: context length
|
||||
exceeded` 以及类似的提供商风格变体)→ 压缩 → 重试。
|
||||
2. **阈值维护**:在一次成功轮次之后,当:
|
||||
exceeded`,以及类似的提供商风格变体)→ 压缩 → 重试。
|
||||
2. **阈值维护**:在成功回合之后,当:
|
||||
|
||||
`contextTokens > contextWindow - reserveTokens`
|
||||
|
||||
@ -248,7 +249,7 @@ exceeded` 以及类似的提供商风格变体)→ 压缩 → 重试。
|
||||
- `contextWindow` 是模型的上下文窗口
|
||||
- `reserveTokens` 是为提示词 + 下一次模型输出预留的余量
|
||||
|
||||
这些是 Pi 运行时语义(OpenClaw 会消费这些事件,但由 Pi 决定何时压缩)。
|
||||
这些属于 Pi 运行时语义(OpenClaw 会消费这些事件,但由 Pi 决定何时压缩)。
|
||||
|
||||
---
|
||||
|
||||
@ -266,17 +267,17 @@ Pi 的压缩设置位于 Pi settings 中:
|
||||
}
|
||||
```
|
||||
|
||||
OpenClaw 还会为嵌入式运行强制执行一个安全下限:
|
||||
OpenClaw 还会为内嵌运行强制设置一个安全下限:
|
||||
|
||||
- 如果 `compaction.reserveTokens < reserveTokensFloor`,OpenClaw 会将其提高。
|
||||
- 默认下限为 `20000` 个令牌。
|
||||
- 默认下限为 `20000` token。
|
||||
- 设置 `agents.defaults.compaction.reserveTokensFloor: 0` 可禁用该下限。
|
||||
- 如果它已经更高,OpenClaw 不会更改。
|
||||
- 手动 `/compact` 会遵循显式的 `agents.defaults.compaction.keepRecentTokens`,
|
||||
并保留 Pi 的最近尾部切点。若未显式设置保留预算,
|
||||
手动压缩仍然是一个硬检查点,重建后的上下文会从新的摘要开始。
|
||||
- 如果它本来就更高,OpenClaw 会保持不变。
|
||||
- 手动 `/compact` 会遵循显式的 `agents.defaults.compaction.keepRecentTokens`
|
||||
并保留 Pi 最近尾部截断点。若未显式设置保留预算,
|
||||
手动压缩仍然是一个硬检查点,重建后的上下文将从新的摘要开始。
|
||||
|
||||
原因:为多轮“清理”工作(如内存写入)预留足够余量,避免在压缩变得不可避免之前就耗尽空间。
|
||||
原因:在压缩变得不可避免之前,为多回合“清理”工作(例如内存写入)留出足够余量。
|
||||
|
||||
实现:`src/agents/pi-settings.ts` 中的 `ensurePiCompactionReserveTokens()`
|
||||
(由 `src/agents/pi-embedded-runner.ts` 调用)。
|
||||
@ -285,93 +286,92 @@ OpenClaw 还会为嵌入式运行强制执行一个安全下限:
|
||||
|
||||
## 可插拔压缩提供商
|
||||
|
||||
插件可以通过插件 API 上的 `registerCompactionProvider()` 注册压缩提供商。当 `agents.defaults.compaction.provider` 设置为某个已注册的提供商 id 时,safeguard 扩展会将摘要生成委托给该提供商,而不是使用内置的 `summarizeInStages` 流水线。
|
||||
插件可以通过插件 API 上的 `registerCompactionProvider()` 注册压缩提供商。当 `agents.defaults.compaction.provider` 设置为已注册的提供商 id 时,保护扩展会将摘要生成委托给该提供商,而不是使用内置的 `summarizeInStages` 流水线。
|
||||
|
||||
- `provider`:已注册压缩提供商插件的 id。留空则使用默认的 LLM 摘要生成。
|
||||
- `provider`:已注册压缩提供商插件的 id。不设置时使用默认 LLM 摘要。
|
||||
- 设置 `provider` 会强制使用 `mode: "safeguard"`。
|
||||
- 提供商接收的压缩指令和标识符保留策略,与内置路径相同。
|
||||
- safeguard 仍会在提供商输出后保留最近轮次和拆分轮次的后缀上下文。
|
||||
- 内置的 safeguard 摘要生成会用新消息对先前摘要重新提炼,
|
||||
而不是原样保留完整的旧摘要。
|
||||
- 提供商会接收与内置路径相同的压缩指令和标识符保留策略。
|
||||
- 在提供商输出之后,safeguard 仍会保留最近回合和拆分回合的后缀上下文。
|
||||
- 内置 safeguard 摘要会使用新消息重新提炼先前的摘要,
|
||||
而不是逐字保留完整旧摘要。
|
||||
- safeguard 模式默认启用摘要质量审计;设置
|
||||
`qualityGuard.enabled: false` 可跳过输出格式错误时的重试行为。
|
||||
- 如果提供商失败或返回空结果,OpenClaw 会自动回退到内置的 LLM 摘要生成。
|
||||
- 中止/超时信号会被重新抛出(不会被吞掉),以尊重调用方的取消操作。
|
||||
`qualityGuard.enabled: false` 可跳过“输出格式错误时重试”行为。
|
||||
- 如果提供商失败或返回空结果,OpenClaw 会自动回退到内置 LLM 摘要。
|
||||
- 中止/超时信号会被重新抛出(不会被吞掉),以遵循调用方取消操作。
|
||||
|
||||
源码:`src/plugins/compaction-provider.ts`、`src/agents/pi-hooks/compaction-safeguard.ts`。
|
||||
来源:`src/plugins/compaction-provider.ts`、`src/agents/pi-hooks/compaction-safeguard.ts`。
|
||||
|
||||
---
|
||||
|
||||
## 用户可见的界面
|
||||
## 用户可见界面
|
||||
|
||||
你可以通过以下方式观察压缩和会话状态:
|
||||
|
||||
- `/status`(在任何聊天会话中)
|
||||
- `openclaw status`(CLI)
|
||||
- `openclaw sessions` / `sessions --json`
|
||||
- 详细模式:`🧹 Auto-compaction complete` + 压缩次数
|
||||
- 详细模式:`🧹 Auto-compaction complete` + 压缩计数
|
||||
|
||||
---
|
||||
|
||||
## 静默清理(`NO_REPLY`)
|
||||
|
||||
OpenClaw 支持用于后台任务的“静默”轮次,在这些场景中,用户不应看到中间输出。
|
||||
OpenClaw 支持用于后台任务的“静默”回合,在这些场景中用户不应看到中间输出。
|
||||
|
||||
约定如下:
|
||||
约定:
|
||||
|
||||
- 助手以精确的静默标记 `NO_REPLY` /
|
||||
`no_reply` 开始其输出,以表示“不要向用户发送回复”。
|
||||
- OpenClaw 会在交付层剥离/抑制该标记。
|
||||
- 对精确静默标记的抑制不区分大小写,因此当整个载荷仅为该静默标记时,`NO_REPLY` 和
|
||||
- 助手会以精确的静默 token `NO_REPLY` /
|
||||
`no_reply` 开始其输出,以表示“不要向用户传递回复”。
|
||||
- OpenClaw 会在传递层剥离/抑制这一内容。
|
||||
- 对精确静默 token 的抑制是大小写不敏感的,因此当整个载荷仅包含这个静默 token 时,`NO_REPLY` 和
|
||||
`no_reply` 都会生效。
|
||||
- 这仅用于真正的后台/不交付轮次;它不是普通可执行用户请求的快捷方式。
|
||||
- 这仅适用于真正的后台/无传递回合;它不是普通可执行用户请求的快捷方式。
|
||||
|
||||
从 `2026.1.10` 起,如果某个部分分块以 `NO_REPLY` 开头,OpenClaw 还会抑制**草稿/输入中流式传输**,这样静默操作就不会在轮次中途泄露部分输出。
|
||||
从 `2026.1.10` 开始,如果部分分块以 `NO_REPLY` 开头,OpenClaw 还会抑制**草稿/输入中流式传输**,这样静默操作就不会在回合中途泄露部分输出。
|
||||
|
||||
---
|
||||
|
||||
## 预压缩“内存刷新”(已实现)
|
||||
## 压缩前“内存刷新”(已实现)
|
||||
|
||||
目标:在自动压缩发生之前,运行一个静默的智能体轮次,将持久状态写入磁盘(例如智能体工作区中的 `memory/YYYY-MM-DD.md`),这样压缩就无法擦除关键上下文。
|
||||
目标:在自动压缩发生之前,运行一个静默的智能体回合,将持久状态写入磁盘(例如智能体工作区中的 `memory/YYYY-MM-DD.md`),这样压缩就无法抹掉关键上下文。
|
||||
|
||||
OpenClaw 使用**阈值前刷新**方法:
|
||||
|
||||
1. 监控会话上下文使用量。
|
||||
2. 当它越过“软阈值”(低于 Pi 的压缩阈值)时,向智能体运行一条静默的
|
||||
“现在写入内存”指令。
|
||||
3. 使用精确的静默标记 `NO_REPLY` / `no_reply`,这样用户将
|
||||
2. 当其越过一个“软阈值”(低于 Pi 的压缩阈值)时,向智能体运行一个静默的
|
||||
“立即写入内存”指令。
|
||||
3. 使用精确的静默 token `NO_REPLY` / `no_reply`,这样用户
|
||||
看不到任何内容。
|
||||
|
||||
配置(`agents.defaults.compaction.memoryFlush`):
|
||||
|
||||
- `enabled`(默认:`true`)
|
||||
- `softThresholdTokens`(默认:`4000`)
|
||||
- `prompt`(用于刷新轮次的用户消息)
|
||||
- `systemPrompt`(附加到刷新轮次的额外系统提示词)
|
||||
- `prompt`(用于刷新回合的用户消息)
|
||||
- `systemPrompt`(附加到刷新回合的额外系统提示词)
|
||||
|
||||
说明:
|
||||
|
||||
- 默认的 prompt/system prompt 包含 `NO_REPLY` 提示,以抑制
|
||||
交付。
|
||||
- 默认的 prompt/systemPrompt 包含 `NO_REPLY` 提示,以抑制
|
||||
传递。
|
||||
- 每个压缩周期只运行一次刷新(在 `sessions.json` 中跟踪)。
|
||||
- 刷新仅对嵌入式 Pi 会话运行(CLI 后端会跳过它)。
|
||||
- 当会话工作区为只读时会跳过刷新(`workspaceAccess: "ro"` 或 `"none"`)。
|
||||
- 有关工作区文件布局和写入模式,请参见 [Memory](/zh-CN/concepts/memory)。
|
||||
- 仅对内嵌 Pi 会话运行刷新(CLI 后端会跳过)。
|
||||
- 当会话工作区为只读时(`workspaceAccess: "ro"` 或 `"none"`),会跳过刷新。
|
||||
- 工作区文件布局和写入模式请参见[内存](/zh-CN/concepts/memory)。
|
||||
|
||||
Pi 还会在扩展 API 中公开一个 `session_before_compact` 钩子,但 OpenClaw 的
|
||||
刷新逻辑目前位于 Gateway 网关端。
|
||||
Pi 也会在扩展 API 中暴露 `session_before_compact` 钩子,但目前 OpenClaw 的刷新逻辑位于 Gateway 网关 侧。
|
||||
|
||||
---
|
||||
|
||||
## 故障排除检查清单
|
||||
## 故障排除清单
|
||||
|
||||
- 会话键不对?从 [/concepts/session](/zh-CN/concepts/session) 开始,并在 `/status` 中确认 `sessionKey`。
|
||||
- 存储与转录记录不匹配?确认 Gateway 网关主机,以及 `openclaw status` 提供的存储路径。
|
||||
- 压缩过于频繁?检查:
|
||||
- 模型上下文窗口(太小)
|
||||
- 压缩设置(对于模型窗口而言,`reserveTokens` 过高可能导致更早压缩)
|
||||
- 工具结果膨胀:启用/调整会话修剪
|
||||
- 静默轮次仍有泄露?确认回复以 `NO_REPLY` 开头(不区分大小写的精确标记),并且你使用的是包含流式抑制修复的构建版本。
|
||||
- 会话键不对?先查看 [/concepts/session](/zh-CN/concepts/session),并在 `/status` 中确认 `sessionKey`。
|
||||
- 存储与转录不匹配?确认 Gateway 网关主机,以及 `openclaw status` 中的存储路径。
|
||||
- 压缩过于频繁?请检查:
|
||||
- 模型上下文窗口(是否过小)
|
||||
- 压缩设置(对于模型窗口来说,`reserveTokens` 过高会导致更早压缩)
|
||||
- tool-result 膨胀:启用/调优会话修剪
|
||||
- 静默回合仍然泄露?请确认回复以 `NO_REPLY` 开头(大小写不敏感的精确 token),并且你使用的是包含流式抑制修复的构建版本。
|
||||
|
||||
## 相关内容
|
||||
|
||||
|
||||
@ -1,43 +1,43 @@
|
||||
---
|
||||
read_when:
|
||||
- 你正在调试与转录结构相关的提供商请求拒绝问题
|
||||
- 你正在更改转录清理或工具调用修复逻辑
|
||||
- 你正在调查跨提供商的工具调用 ID 不匹配问题
|
||||
summary: 参考:提供商特定的转录清理和修复规则
|
||||
- 你正在调试与转录结构相关的 provider 请求拒绝问题
|
||||
- 你正在修改转录清理或工具调用修复逻辑
|
||||
- 你正在调查跨 provider 的工具调用 id 不匹配问题
|
||||
summary: 参考:provider 特定的转录清理与修复规则
|
||||
title: 转录清理规范
|
||||
x-i18n:
|
||||
generated_at: "2026-04-25T05:01:43Z"
|
||||
generated_at: "2026-04-25T05:56:41Z"
|
||||
model: gpt-5.4
|
||||
provider: openai
|
||||
source_hash: db11e07d086f5aa3591f8cf456fc06c1cee1041552d2c4865f41bfeb98a00355
|
||||
source_hash: 00cac47fb9a238e3cb8b6ea69b47210685ca6769a31973b4aeef1d18e75d78e6
|
||||
source_path: reference/transcript-hygiene.md
|
||||
workflow: 15
|
||||
---
|
||||
|
||||
本文档说明了在一次运行开始前(构建模型上下文时)应用于转录的**提供商特定修复**。这些是为满足严格提供商要求而进行的**内存中**调整。这些清理步骤**不会**重写磁盘上存储的 JSONL 转录;不过,在加载会话之前,单独的会话文件修复过程可能会通过丢弃无效行来重写格式错误的 JSONL 文件。发生修复时,原始文件会在会话文件旁边生成备份。
|
||||
本文档说明在运行前(构建模型上下文时)应用于转录的**provider 特定修复**。这些是用于满足严格 provider 要求的**仅内存**调整。这些清理步骤**不会**重写磁盘上存储的 JSONL 转录;不过,在加载会话之前,单独的会话文件修复过程可能会通过丢弃无效行来重写格式错误的 JSONL 文件。发生修复时,原始文件会在会话文件旁边生成备份。
|
||||
|
||||
范围包括:
|
||||
|
||||
- 仅运行时的提示上下文,不进入用户可见的转录轮次
|
||||
- 工具调用 ID 清理
|
||||
- 仅运行时的提示上下文保持不进入用户可见的转录轮次
|
||||
- 工具调用 id 清理
|
||||
- 工具调用输入验证
|
||||
- 工具结果配对修复
|
||||
- 轮次验证 / 排序
|
||||
- 思考签名清理
|
||||
- 图像负载清理
|
||||
- 用户输入来源标记(用于跨会话路由的提示)
|
||||
- 轮次验证/排序
|
||||
- thought signature 清理
|
||||
- 图像载荷清理
|
||||
- 用户输入来源标记(用于跨会话路由提示)
|
||||
|
||||
如果你需要了解转录存储细节,请参见:
|
||||
如果你需要转录存储细节,请参见:
|
||||
|
||||
- [/reference/session-management-compaction](/zh-CN/reference/session-management-compaction)
|
||||
- [会话管理深入解析](/zh-CN/reference/session-management-compaction)
|
||||
|
||||
---
|
||||
|
||||
## 全局规则:运行时上下文不是用户转录
|
||||
|
||||
运行时 / 系统上下文可以添加到某一轮的模型提示中,但它不是终端用户编写的内容。OpenClaw 会为 Gateway 网关回复、排队的后续步骤、ACP、CLI 和嵌入式 Pi 运行保留一个单独的、面向转录的提示正文。存储的可见用户轮次使用该转录正文,而不是经过运行时增强的提示。
|
||||
运行时/系统上下文可以添加到某个轮次的模型提示中,但它不是最终用户撰写的内容。OpenClaw 会为 Gateway 网关回复、排队的后续操作、ACP、CLI 和嵌入式 Pi 运行保留一个单独的、面向转录的提示正文。存储的可见用户轮次使用该转录正文,而不是运行时增强后的提示。
|
||||
|
||||
对于已经持久化了运行时包装内容的旧版会话,Gateway 网关历史记录界面会在将消息返回给 WebChat、TUI、REST 或 SSE 客户端之前应用显示投影。
|
||||
对于已经持久化了运行时包装器的旧会话,Gateway 网关历史记录界面会在将消息返回给 WebChat、TUI、REST 或 SSE 客户端之前应用显示投影。
|
||||
|
||||
---
|
||||
|
||||
@ -46,11 +46,11 @@ x-i18n:
|
||||
所有转录清理都集中在嵌入式运行器中:
|
||||
|
||||
- 策略选择:`src/agents/transcript-policy.ts`
|
||||
- 清理 / 修复应用:`src/agents/pi-embedded-runner/replay-history.ts` 中的 `sanitizeSessionHistory`
|
||||
- 清理/修复应用:`src/agents/pi-embedded-runner/replay-history.ts` 中的 `sanitizeSessionHistory`
|
||||
|
||||
该策略使用 `provider`、`modelApi` 和 `modelId` 来决定要应用哪些规则。
|
||||
该策略使用 `provider`、`modelApi` 和 `modelId` 来决定应用哪些规则。
|
||||
|
||||
与转录清理分开的是,会话文件会在加载前按需进行修复:
|
||||
与转录清理分开的是,会话文件会在加载前按需修复:
|
||||
|
||||
- `src/agents/session-file-repair.ts` 中的 `repairSessionFileIfNeeded`
|
||||
- 从 `run/attempt.ts` 和 `compact.ts`(嵌入式运行器)调用
|
||||
@ -59,21 +59,21 @@ x-i18n:
|
||||
|
||||
## 全局规则:图像清理
|
||||
|
||||
图像负载始终会被清理,以防止因大小限制导致提供商端拒绝请求(对过大的 base64 图像进行缩放 / 重新压缩)。
|
||||
图像载荷始终会被清理,以防止因大小限制导致 provider 侧拒绝(对过大的 base64 图像进行缩放/重新压缩)。
|
||||
|
||||
这也有助于控制视觉模型中的图像驱动型 token 压力。较低的最大尺寸通常会减少 token 使用量;较高的尺寸则能保留更多细节。
|
||||
这也有助于控制视觉能力模型下由图像驱动的 token 压力。较低的最大尺寸通常会减少 token 使用;较高的尺寸则保留更多细节。
|
||||
|
||||
实现:
|
||||
|
||||
- `src/agents/pi-embedded-helpers/images.ts` 中的 `sanitizeSessionMessagesImages`
|
||||
- `src/agents/tool-images.ts` 中的 `sanitizeContentBlocksImages`
|
||||
- 最大图像边长可通过 `agents.defaults.imageMaxDimensionPx` 配置(默认值:`1200`)。
|
||||
- 最大图像边长可通过 `agents.defaults.imageMaxDimensionPx` 配置(默认:`1200`)。
|
||||
|
||||
---
|
||||
|
||||
## 全局规则:格式错误的工具调用
|
||||
|
||||
缺少 `input` 和 `arguments` 的 assistant 工具调用块会在构建模型上下文之前被丢弃。这样可以防止因部分持久化的工具调用而导致提供商拒绝请求(例如,在速率限制失败之后)。
|
||||
缺少 `input` 和 `arguments` 的助手工具调用块会在构建模型上下文之前被丢弃。这可防止 provider 因部分持久化的工具调用而拒绝请求(例如,在速率限制失败之后)。
|
||||
|
||||
实现:
|
||||
|
||||
@ -84,49 +84,49 @@ x-i18n:
|
||||
|
||||
## 全局规则:跨会话输入来源
|
||||
|
||||
当一个智能体通过 `sessions_send` 向另一个会话发送提示时(包括智能体到智能体的回复 / 通知步骤),OpenClaw 会在持久化创建的用户轮次时写入:
|
||||
当智能体通过 `sessions_send` 向另一个会话发送提示时(包括智能体到智能体的 reply/announce 步骤),OpenClaw 会在追加转录时将创建的用户轮次持久化为:
|
||||
|
||||
- `message.provenance.kind = "inter_session"`
|
||||
|
||||
该元数据会在追加到转录时写入,不会改变角色
|
||||
(为兼容提供商,`role: "user"` 保持不变)。转录读取器可以使用此信息,避免将路由的内部提示当作终端用户编写的指令。
|
||||
该元数据会在转录追加时写入,不会更改角色
|
||||
(为了 provider 兼容性,仍保留 `role: "user"`)。转录读取器可以利用这一点,避免将路由的内部提示视为最终用户撰写的指令。
|
||||
|
||||
在上下文重建期间,OpenClaw 还会在内存中为这些用户轮次添加一个简短的 `[Inter-session message]` 标记前缀,以便模型将其与外部终端用户指令区分开来。
|
||||
在重建上下文期间,OpenClaw 还会在内存中为这些用户轮次前置一个简短的 `[Inter-session message]` 标记,以便模型将其与外部最终用户指令区分开来。
|
||||
|
||||
---
|
||||
|
||||
## 提供商矩阵(当前行为)
|
||||
## provider 矩阵(当前行为)
|
||||
|
||||
**OpenAI / OpenAI Codex**
|
||||
|
||||
- 仅图像清理。
|
||||
- 对于 OpenAI Responses / Codex 转录,丢弃孤立的推理签名(后面没有内容块的独立推理项),并在模型路由切换后丢弃可重放的 OpenAI 推理内容。
|
||||
- 不进行工具调用 ID 清理。
|
||||
- 对于 OpenAI Responses/Codex 转录,丢弃孤立的 reasoning signature(后面没有内容块的独立 reasoning 项),并在模型路由切换后丢弃可重放的 OpenAI reasoning。
|
||||
- 不做工具调用 id 清理。
|
||||
- 工具结果配对修复可能会移动真实匹配的输出,并为缺失的工具调用合成 Codex 风格的 `aborted` 输出。
|
||||
- 不进行轮次验证或重排序。
|
||||
- 会为缺失的 OpenAI Responses 系列工具输出合成 `aborted`,以匹配 Codex 重放归一化。
|
||||
- 不剥离思考签名。
|
||||
- 不做轮次验证或重排序。
|
||||
- 缺失的 OpenAI Responses 系列工具输出会被合成为 `aborted`,以匹配 Codex 重放规范化。
|
||||
- 不剥离 thought signature。
|
||||
|
||||
**Google(Generative AI / Gemini CLI / Antigravity)**
|
||||
|
||||
- 工具调用 ID 清理:严格字母数字格式。
|
||||
- 工具调用 id 清理:严格字母数字。
|
||||
- 工具结果配对修复和合成工具结果。
|
||||
- 轮次验证(Gemini 风格的轮次交替)。
|
||||
- Google 轮次顺序修复(如果历史记录以 assistant 开头,则预置一个极小的 user 引导消息)。
|
||||
- Antigravity Claude:规范化思考签名;丢弃未签名的思考块。
|
||||
- 轮次验证(Gemini 风格轮次交替)。
|
||||
- Google 轮次顺序修复(如果历史以 assistant 开头,则前置一个极小的 user 引导项)。
|
||||
- Antigravity Claude:规范化 thinking signature;丢弃未签名的 thinking 块。
|
||||
|
||||
**Anthropic / Minimax(Anthropic 兼容)**
|
||||
**Anthropic / MiniMax(Anthropic 兼容)**
|
||||
|
||||
- 工具结果配对修复和合成工具结果。
|
||||
- 轮次验证(合并连续的用户轮次以满足严格交替要求)。
|
||||
- 轮次验证(合并连续的 user 轮次以满足严格交替要求)。
|
||||
|
||||
**Mistral(包括基于 model-id 的检测)**
|
||||
|
||||
- 工具调用 ID 清理:strict9(长度为 9 的字母数字)。
|
||||
- 工具调用 id 清理:strict9(长度为 9 的字母数字)。
|
||||
|
||||
**OpenRouter Gemini**
|
||||
|
||||
- 思考签名清理:剥离非 base64 的 `thought_signature` 值(保留 base64)。
|
||||
- thought signature 清理:剥离非 base64 的 `thought_signature` 值(保留 base64)。
|
||||
|
||||
**其他所有情况**
|
||||
|
||||
@ -136,21 +136,20 @@ x-i18n:
|
||||
|
||||
## 历史行为(2026.1.22 之前)
|
||||
|
||||
在 2026.1.22 版本发布之前,OpenClaw 会应用多层转录清理:
|
||||
在 2026.1.22 版本之前,OpenClaw 应用了多层转录清理:
|
||||
|
||||
- 一个 **transcript-sanitize extension** 会在每次构建上下文时运行,并且可以:
|
||||
- 修复工具使用 / 结果配对。
|
||||
- 清理工具调用 ID(包括一种会保留下划线 `_` / 连字符 `-` 的非严格模式)。
|
||||
- 运行器也会执行提供商特定清理,从而造成重复处理。
|
||||
- 还有一些额外变更发生在提供商策略之外,包括:
|
||||
- 在持久化前从 assistant 文本中剥离 `<final>` 标签。
|
||||
- 丢弃空的 assistant 错误轮次。
|
||||
- 在工具调用后裁剪 assistant 内容。
|
||||
- 每次构建上下文时都会运行一个 **transcript-sanitize 扩展**,其可以:
|
||||
- 修复工具使用/结果配对。
|
||||
- 清理工具调用 id(包括保留 `_`/`-` 的非严格模式)。
|
||||
- 运行器还会执行 provider 特定清理,从而导致重复处理。
|
||||
- 另外还有一些发生在 provider 策略之外的变更,包括:
|
||||
- 在持久化前从助手文本中剥离 `<final>` 标签。
|
||||
- 丢弃空的助手错误轮次。
|
||||
- 在工具调用后裁剪助手内容。
|
||||
|
||||
这种复杂性导致了跨提供商回归问题(尤其是 `openai-responses`
|
||||
`call_id|fc_id` 配对)。2026.1.22 的清理工作移除了该扩展,将逻辑集中到运行器中,并让 OpenAI 在图像清理之外保持**不触碰**。
|
||||
这种复杂性导致了跨 provider 的回归问题(尤其是 `openai-responses` 的 `call_id|fc_id` 配对)。2026.1.22 的清理移除了该扩展,将逻辑集中到运行器中,并让 OpenAI 除图像清理之外保持**不触碰**。
|
||||
|
||||
## 相关内容
|
||||
|
||||
- [会话管理](/zh-CN/concepts/session)
|
||||
- [会话裁剪](/zh-CN/concepts/session-pruning)
|
||||
- [会话清理](/zh-CN/concepts/session-pruning)
|
||||
|
||||
@ -1,26 +1,26 @@
|
||||
---
|
||||
read_when:
|
||||
- 为 Claude Code / Codex / Gemini CLI 安装或配置 `acpx harness`
|
||||
- 启用 `plugin-tools` 或 OpenClaw-tools MCP bridge
|
||||
- 为 Claude Code / Codex / Gemini CLI 安装或配置 acpx harness
|
||||
- 启用 plugin-tools 或 OpenClaw-tools MCP bridge
|
||||
- 配置 ACP 权限模式
|
||||
summary: 设置 ACP 智能体:`acpx harness` 配置、插件设置、权限
|
||||
title: ACP 智能体——设置
|
||||
summary: 设置 ACP 智能体:acpx harness 配置、插件设置、权限
|
||||
title: ACP 智能体 — 设置
|
||||
x-i18n:
|
||||
generated_at: "2026-04-25T04:14:04Z"
|
||||
generated_at: "2026-04-25T05:56:52Z"
|
||||
model: gpt-5.4
|
||||
provider: openai
|
||||
source_hash: 5ddbcfb035f1d0a1902b49b9b292511adf496a35dd3bfd4c008cc335bbce0ebe
|
||||
source_hash: a6c23d8245c4893c48666096a296820e003685252cedee7df41ea7a2be1f4bf0
|
||||
source_path: tools/acp-agents-setup.md
|
||||
workflow: 15
|
||||
---
|
||||
|
||||
关于概览、操作员运行手册和概念,请参阅 [ACP 智能体](/zh-CN/tools/acp-agents)。
|
||||
本页介绍 `acpx harness` 配置、MCP bridges 的插件设置,以及
|
||||
权限配置。
|
||||
关于概览、操作员运行手册和概念,请参见 [ACP 智能体](/zh-CN/tools/acp-agents)。
|
||||
|
||||
## `acpx harness` 支持(当前)
|
||||
以下各节介绍 acpx harness 配置、MCP bridge 的插件设置以及权限配置。
|
||||
|
||||
当前 `acpx` 内置的 harness 别名:
|
||||
## acpx harness 支持(当前)
|
||||
|
||||
当前 acpx 内置 harness 别名:
|
||||
|
||||
- `claude`
|
||||
- `codex`
|
||||
@ -37,20 +37,20 @@ x-i18n:
|
||||
- `pi`
|
||||
- `qwen`
|
||||
|
||||
当 OpenClaw 使用 `acpx` 后端时,除非你的 `acpx` 配置定义了自定义智能体别名,否则应优先将这些值用于 `agentId`。
|
||||
如果你的本地 Cursor 安装仍将 ACP 暴露为 `agent acp`,请在你的 `acpx` 配置中覆盖 `cursor` 智能体命令,而不要更改内置默认值。
|
||||
当 OpenClaw 使用 acpx 后端时,除非你的 acpx 配置定义了自定义智能体别名,否则优先将这些值用于 `agentId`。
|
||||
如果你的本地 Cursor 安装仍将 ACP 暴露为 `agent acp`,请在 acpx 配置中覆盖 `cursor` 智能体命令,而不是修改内置默认值。
|
||||
|
||||
直接使用 `acpx` CLI 时,也可以通过 `--agent <command>` 指向任意适配器,但这个原始逃生口是 `acpx` CLI 功能(不是常规的 OpenClaw `agentId` 路径)。
|
||||
直接使用 acpx CLI 也可以通过 `--agent <command>` 定位任意适配器,但这个原始逃生口是 acpx CLI 的功能(不是普通的 OpenClaw `agentId` 路径)。
|
||||
|
||||
## 必需配置
|
||||
|
||||
ACP 核心基线配置:
|
||||
核心 ACP 基线:
|
||||
|
||||
```json5
|
||||
{
|
||||
acp: {
|
||||
enabled: true,
|
||||
// 可选。默认值为 true;设为 false 可暂停 ACP 分发,同时保留 /acp 控制。
|
||||
// Optional. Default is true; set false to pause ACP dispatch while keeping /acp controls.
|
||||
dispatch: { enabled: true },
|
||||
backend: "acpx",
|
||||
defaultAgent: "codex",
|
||||
@ -82,7 +82,7 @@ ACP 核心基线配置:
|
||||
}
|
||||
```
|
||||
|
||||
线程绑定配置依赖具体的渠道适配器。以下是 Discord 的示例:
|
||||
线程绑定配置是渠道适配器专属的。Discord 示例:
|
||||
|
||||
```json5
|
||||
{
|
||||
@ -104,17 +104,17 @@ ACP 核心基线配置:
|
||||
}
|
||||
```
|
||||
|
||||
如果线程绑定的 ACP 派生不起作用,请先验证适配器功能标志:
|
||||
如果线程绑定的 ACP 启动不工作,请先检查适配器功能开关:
|
||||
|
||||
- Discord:`channels.discord.threadBindings.spawnAcpSessions=true`
|
||||
|
||||
当前会话绑定不需要创建子线程。它们需要一个活动的会话上下文,以及一个暴露 ACP 会话绑定的渠道适配器。
|
||||
|
||||
请参阅 [Configuration Reference](/zh-CN/gateway/configuration-reference)。
|
||||
请参见 [配置参考](/zh-CN/gateway/configuration-reference)。
|
||||
|
||||
## `acpx` 后端的插件设置
|
||||
## acpx 后端的插件设置
|
||||
|
||||
全新安装默认启用内置的 `acpx` 运行时插件,因此 ACP
|
||||
全新安装时会默认启用内置的 `acpx` 运行时插件,因此 ACP
|
||||
通常无需手动安装插件即可工作。
|
||||
|
||||
先执行:
|
||||
@ -124,7 +124,7 @@ ACP 核心基线配置:
|
||||
```
|
||||
|
||||
如果你禁用了 `acpx`、通过 `plugins.allow` / `plugins.deny` 拒绝了它,或者想
|
||||
切换到本地开发检出,请使用显式插件路径:
|
||||
切换到本地开发检出版本,请使用显式插件路径:
|
||||
|
||||
```bash
|
||||
openclaw plugins install acpx
|
||||
@ -143,11 +143,11 @@ openclaw plugins install ./path/to/local/acpx-plugin
|
||||
/acp doctor
|
||||
```
|
||||
|
||||
### `acpx` 命令和版本配置
|
||||
### acpx 命令和版本配置
|
||||
|
||||
默认情况下,内置的 `acpx` 插件使用其插件本地固定版本的二进制文件(插件包内的 `node_modules/.bin/acpx`)。启动时会将后端注册为未就绪,并由后台任务验证 `acpx --version`;如果该二进制文件缺失或版本不匹配,则会运行 `npm install --omit=dev --no-save acpx@<pinned>` 并重新验证。整个过程中,Gateway 网关始终保持非阻塞。
|
||||
默认情况下,内置 `acpx` 插件使用其插件本地固定二进制(插件包内的 `node_modules/.bin/acpx`)。启动时会将后端注册为未就绪,并由后台任务验证 `acpx --version`;如果二进制缺失或版本不匹配,它会运行 `npm install --omit=dev --no-save acpx@<pinned>` 并重新验证。整个过程中 Gateway 网关始终保持非阻塞。
|
||||
|
||||
在插件配置中覆盖命令或版本:
|
||||
可在插件配置中覆盖命令或版本:
|
||||
|
||||
```json
|
||||
{
|
||||
@ -165,23 +165,23 @@ openclaw plugins install ./path/to/local/acpx-plugin
|
||||
}
|
||||
```
|
||||
|
||||
- `command` 接受绝对路径、相对路径(从 OpenClaw 工作区解析)或命令名。
|
||||
- `command` 接受绝对路径、相对路径(相对于 OpenClaw 工作区解析)或命令名。
|
||||
- `expectedVersion: "any"` 会禁用严格版本匹配。
|
||||
- 自定义 `command` 路径会禁用插件本地自动安装。
|
||||
|
||||
请参阅 [Plugins](/zh-CN/tools/plugin)。
|
||||
请参见 [插件](/zh-CN/tools/plugin)。
|
||||
|
||||
### 自动依赖安装
|
||||
|
||||
当你通过 `npm install -g openclaw` 全局安装 OpenClaw 时,`acpx`
|
||||
运行时依赖(特定平台的二进制文件)会通过 `postinstall` 钩子自动安装。如果自动安装失败,Gateway 网关仍会正常启动,并通过 `openclaw acp doctor` 报告缺失的依赖。
|
||||
当你通过 `npm install -g openclaw` 全局安装 OpenClaw 时,acpx
|
||||
运行时依赖(平台特定二进制)会通过 postinstall 钩子自动安装。如果自动安装失败,Gateway 网关仍会正常启动,并通过 `openclaw acp doctor` 报告缺失的依赖。
|
||||
|
||||
### 插件工具 MCP bridge
|
||||
### Plugin tools MCP bridge
|
||||
|
||||
默认情况下,ACPX 会话**不会**向 ACP harness 暴露 OpenClaw 插件注册的工具。
|
||||
默认情况下,ACPX 会话**不会**向 ACP harness 暴露 OpenClaw 插件已注册的工具。
|
||||
|
||||
如果你希望 Codex 或 Claude Code 等 ACP 智能体能够调用已安装的
|
||||
OpenClaw 插件工具,例如内存回忆/存储,请启用专用 bridge:
|
||||
如果你希望 Codex 或 Claude Code 之类的 ACP 智能体调用已安装的
|
||||
OpenClaw 插件工具,例如 memory recall/store,请启用专用 bridge:
|
||||
|
||||
```bash
|
||||
openclaw config set plugins.entries.acpx.config.pluginToolsMcpBridge true
|
||||
@ -190,22 +190,22 @@ openclaw config set plugins.entries.acpx.config.pluginToolsMcpBridge true
|
||||
它的作用:
|
||||
|
||||
- 在 ACPX 会话引导中注入一个名为 `openclaw-plugin-tools` 的内置 MCP 服务器。
|
||||
- 暴露已安装并已启用的 OpenClaw 插件所注册的插件工具。
|
||||
- 保持该功能为显式启用,且默认关闭。
|
||||
- 暴露已安装并启用的 OpenClaw 插件已注册的插件工具。
|
||||
- 使该功能保持显式启用,且默认关闭。
|
||||
|
||||
安全和信任说明:
|
||||
安全性和信任说明:
|
||||
|
||||
- 这会扩大 ACP harness 的工具暴露面。
|
||||
- ACP 智能体只能访问 Gateway 网关中已处于活动状态的插件工具。
|
||||
- 应将此视为与允许这些插件在 OpenClaw 本身中执行相同的信任边界。
|
||||
- 这会扩大 ACP harness 的工具界面。
|
||||
- ACP 智能体只能访问 Gateway 网关中已激活的插件工具。
|
||||
- 应将其视为与允许这些插件在 OpenClaw 本身中执行相同的信任边界。
|
||||
- 启用前请审查已安装的插件。
|
||||
|
||||
自定义 `mcpServers` 仍会像以前一样工作。内置的 `plugin-tools` bridge 是一个
|
||||
额外的按需启用便利功能,而不是通用 MCP 服务器配置的替代品。
|
||||
自定义 `mcpServers` 仍与之前一样可用。内置的 plugin-tools bridge 是
|
||||
额外的显式便利功能,不是通用 MCP 服务器配置的替代品。
|
||||
|
||||
### OpenClaw 工具 MCP bridge
|
||||
### OpenClaw tools MCP bridge
|
||||
|
||||
默认情况下,ACPX 会话也**不会**通过 MCP 暴露内置的 OpenClaw 工具。当 ACP 智能体需要某些选定的内置工具(如 `cron`)时,请启用单独的核心工具 bridge:
|
||||
默认情况下,ACPX 会话也**不会**通过 MCP 暴露内置 OpenClaw 工具。当 ACP 智能体需要某些选定的内置工具(例如 `cron`)时,请启用单独的核心工具 bridge:
|
||||
|
||||
```bash
|
||||
openclaw config set plugins.entries.acpx.config.openClawToolsMcpBridge true
|
||||
@ -214,55 +214,53 @@ openclaw config set plugins.entries.acpx.config.openClawToolsMcpBridge true
|
||||
它的作用:
|
||||
|
||||
- 在 ACPX 会话引导中注入一个名为 `openclaw-tools` 的内置 MCP 服务器。
|
||||
- 暴露选定的内置 OpenClaw 工具。初始服务器暴露 `cron`。
|
||||
- 保持核心工具暴露为显式启用,且默认关闭。
|
||||
- 暴露选定的内置 OpenClaw 工具。初始服务器暴露的是 `cron`。
|
||||
- 使核心工具暴露保持显式启用,且默认关闭。
|
||||
|
||||
### 运行时超时配置
|
||||
|
||||
内置的 `acpx` 插件默认将嵌入式运行时轮次的超时时间设置为 120 秒。
|
||||
这会给 Gemini CLI 等较慢的 harness 足够时间来完成
|
||||
ACP 启动和初始化。如果你的主机需要不同的运行时限制,可以覆盖它:
|
||||
内置 `acpx` 插件默认将嵌入式运行时轮次超时设置为 120 秒。这样可以给 Gemini CLI 之类较慢的 harness 足够时间完成 ACP 启动和初始化。如果你的主机需要不同的运行时限制,可以覆盖它:
|
||||
|
||||
```bash
|
||||
openclaw config set plugins.entries.acpx.config.timeoutSeconds 180
|
||||
```
|
||||
|
||||
更改此值后,请重启 Gateway 网关。
|
||||
更改此值后请重启 Gateway 网关。
|
||||
|
||||
### 健康探针智能体配置
|
||||
|
||||
内置的 `acpx` 插件在判断嵌入式运行时后端是否就绪时,会探测一个 harness 智能体。如果设置了 `acp.allowedAgents`,则默认使用第一个允许的智能体;否则默认使用 `codex`。如果你的部署需要使用不同的 ACP 智能体来执行健康检查,请显式设置探针智能体:
|
||||
内置 `acpx` 插件在决定嵌入式运行时后端是否就绪时,会探测一个 harness 智能体。如果设置了 `acp.allowedAgents`,默认会使用第一个允许的智能体;否则默认使用 `codex`。如果你的部署需要使用不同的 ACP 智能体进行健康检查,请显式设置探针智能体:
|
||||
|
||||
```bash
|
||||
openclaw config set plugins.entries.acpx.config.probeAgent claude
|
||||
```
|
||||
|
||||
更改此值后,请重启 Gateway 网关。
|
||||
更改此值后请重启 Gateway 网关。
|
||||
|
||||
## 权限配置
|
||||
|
||||
ACP 会话以非交互模式运行——没有 TTY 可用于批准或拒绝文件写入和 shell 执行权限提示。`acpx` 插件提供了两个配置键,用于控制权限的处理方式:
|
||||
ACP 会话以非交互方式运行——没有 TTY 可以批准或拒绝文件写入和 shell 执行权限提示。acpx 插件提供了两个配置键,用于控制权限处理方式:
|
||||
|
||||
这些 ACPX harness 权限独立于 OpenClaw 执行批准,也独立于 CLI 后端供应商绕过标志,例如 Claude CLI `--permission-mode bypassPermissions`。ACPX `approve-all` 是 ACP 会话在 harness 层面的紧急放行开关。
|
||||
这些 ACPX harness 权限与 OpenClaw exec 批准机制分离,也与 CLI 后端供应商绕过标志分离,例如 Claude CLI 的 `--permission-mode bypassPermissions`。ACPX 的 `approve-all` 是 ACP 会话的 harness 级紧急开关。
|
||||
|
||||
### `permissionMode`
|
||||
|
||||
控制 harness 智能体在不提示的情况下可以执行哪些操作。
|
||||
控制 harness 智能体在无需提示的情况下可执行哪些操作。
|
||||
|
||||
| 值 | 行为 |
|
||||
| --------------- | ------------------------------------------- |
|
||||
| `approve-all` | 自动批准所有文件写入和 shell 命令。 |
|
||||
| `approve-reads` | 仅自动批准读取;写入和执行仍需要提示。 |
|
||||
| `deny-all` | 拒绝所有权限提示。 |
|
||||
| 值 | 行为 |
|
||||
| --------------- | --------------------------------------------------------- |
|
||||
| `approve-all` | 自动批准所有文件写入和 shell 命令。 |
|
||||
| `approve-reads` | 仅自动批准读取;写入和 exec 需要提示。 |
|
||||
| `deny-all` | 拒绝所有权限提示。 |
|
||||
|
||||
### `nonInteractivePermissions`
|
||||
|
||||
控制在本应显示权限提示、但没有可用交互式 TTY 时的行为(ACP 会话始终如此)。
|
||||
控制本应显示权限提示、但没有可交互 TTY 可用时会发生什么(ACP 会话始终如此)。
|
||||
|
||||
| 值 | 行为 |
|
||||
| 值 | 行为 |
|
||||
| ------ | ----------------------------------------------------------------- |
|
||||
| `fail` | 以 `AcpRuntimeError` 中止会话。**(默认)** |
|
||||
| `deny` | 静默拒绝该权限并继续(优雅降级)。 |
|
||||
| `fail` | 使用 `AcpRuntimeError` 中止会话。**(默认)** |
|
||||
| `deny` | 静默拒绝该权限并继续(平滑降级)。 |
|
||||
|
||||
### 配置
|
||||
|
||||
@ -273,14 +271,14 @@ openclaw config set plugins.entries.acpx.config.permissionMode approve-all
|
||||
openclaw config set plugins.entries.acpx.config.nonInteractivePermissions fail
|
||||
```
|
||||
|
||||
更改这些值后,请重启 Gateway 网关。
|
||||
更改这些值后请重启 Gateway 网关。
|
||||
|
||||
> **重要:** OpenClaw 当前默认使用 `permissionMode=approve-reads` 和 `nonInteractivePermissions=fail`。在非交互式 ACP 会话中,任何触发权限提示的写入或执行操作都可能因 `AcpRuntimeError: Permission prompt unavailable in non-interactive mode` 而失败。
|
||||
> **重要:** OpenClaw 当前默认使用 `permissionMode=approve-reads` 和 `nonInteractivePermissions=fail`。在非交互式 ACP 会话中,任何触发权限提示的写入或 exec 都可能失败,并报错 `AcpRuntimeError: Permission prompt unavailable in non-interactive mode`。
|
||||
>
|
||||
> 如果你需要限制权限,请将 `nonInteractivePermissions` 设置为 `deny`,这样会话会优雅降级,而不是崩溃。
|
||||
> 如果你需要限制权限,请将 `nonInteractivePermissions` 设置为 `deny`,这样会话会平滑降级,而不是崩溃。
|
||||
|
||||
## 相关内容
|
||||
|
||||
- [ACP 智能体](/zh-CN/tools/acp-agents) —— 概览、操作员运行手册、概念
|
||||
- [Sub-agents](/zh-CN/tools/subagents)
|
||||
- [Multi-agent routing](/zh-CN/concepts/multi-agent)
|
||||
- [ACP 智能体](/zh-CN/tools/acp-agents) — 概览、操作员运行手册、概念
|
||||
- [子智能体](/zh-CN/tools/subagents)
|
||||
- [多智能体路由](/zh-CN/concepts/multi-agent)
|
||||
|
||||
@ -1,19 +1,19 @@
|
||||
---
|
||||
read_when: Browser control fails on Linux, especially with snap Chromium
|
||||
summary: 修复 Linux 上 OpenClaw 浏览器控制中 Chrome/Brave/Edge/Chromium 的 CDP 启动问题
|
||||
summary: 修复 Linux 上 OpenClaw 浏览器控制中 Chrome / Brave / Edge / Chromium 的 CDP 启动问题
|
||||
title: 浏览器故障排除
|
||||
x-i18n:
|
||||
generated_at: "2026-04-23T23:04:10Z"
|
||||
generated_at: "2026-04-25T05:56:47Z"
|
||||
model: gpt-5.4
|
||||
provider: openai
|
||||
source_hash: e6f59048d6a5b587b8d6c9ac0d32b3215f68a7e39192256b28f22936cab752e1
|
||||
source_hash: 4b972e9f611962b60c76088487a8db628bc1cbf8447f73f75d33606f177c701a
|
||||
source_path: tools/browser-linux-troubleshooting.md
|
||||
workflow: 15
|
||||
---
|
||||
|
||||
## 问题:“Failed to start Chrome CDP on port 18800”
|
||||
## 问题:“在端口 18800 上启动 Chrome CDP 失败”
|
||||
|
||||
OpenClaw 的浏览器控制服务器在启动 Chrome/Brave/Edge/Chromium 时失败,并出现以下错误:
|
||||
OpenClaw 的浏览器控制服务器在启动 Chrome / Brave / Edge / Chromium 时失败,并报出如下错误:
|
||||
|
||||
```
|
||||
{"error":"Error: Failed to start Chrome CDP on port 18800 for profile \"openclaw\"."}
|
||||
@ -21,25 +21,30 @@ OpenClaw 的浏览器控制服务器在启动 Chrome/Brave/Edge/Chromium 时失
|
||||
|
||||
### 根本原因
|
||||
|
||||
在 Ubuntu(以及许多 Linux 发行版)上,默认的 Chromium 安装是一个**snap 包**。Snap 的 AppArmor 沙箱限制会干扰 OpenClaw 启动和监控浏览器进程的方式。
|
||||
在 Ubuntu(以及许多 Linux 发行版)上,默认的 Chromium 安装是 **snap 包**。Snap 的 AppArmor 限制会干扰 OpenClaw 启动和监控浏览器进程的方式。
|
||||
|
||||
`apt install chromium` 命令安装的是一个重定向到 snap 的占位包:
|
||||
`apt install chromium` 命令安装的是一个会重定向到 snap 的存根包:
|
||||
|
||||
```
|
||||
Note, selecting 'chromium-browser' instead of 'chromium'
|
||||
chromium-browser is already the newest version (2:1snap1-0ubuntu2).
|
||||
```
|
||||
|
||||
这**不是真正的浏览器**——它只是一个包装器。
|
||||
这**不是**真正的浏览器——它只是一个包装器。
|
||||
|
||||
其他常见的 Linux 启动失败:
|
||||
|
||||
- `The profile appears to be in use by another Chromium process` 表示 Chrome 在托管配置文件目录中发现了陈旧的 `Singleton*` 锁文件。当锁指向已退出的进程或不同主机上的进程时,OpenClaw 会移除这些锁并重试一次。
|
||||
- `Missing X server or $DISPLAY` 表示 OpenClaw 正在尝试在没有桌面会话的主机上启动一个可见浏览器。请使用 `browser.headless: true`、启动 `Xvfb`,或在真实桌面会话中运行 OpenClaw。
|
||||
|
||||
### 解决方案 1:安装 Google Chrome(推荐)
|
||||
|
||||
安装官方的 Google Chrome `.deb` 包,它不会被 snap 沙箱限制:
|
||||
安装官方 Google Chrome `.deb` 包,它不会受到 snap 的沙箱限制:
|
||||
|
||||
```bash
|
||||
wget https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb
|
||||
sudo dpkg -i google-chrome-stable_current_amd64.deb
|
||||
sudo apt --fix-broken install -y # 如果有依赖错误
|
||||
sudo apt --fix-broken install -y # if there are dependency errors
|
||||
```
|
||||
|
||||
然后更新你的 OpenClaw 配置(`~/.openclaw/openclaw.json`):
|
||||
@ -55,9 +60,9 @@ sudo apt --fix-broken install -y # 如果有依赖错误
|
||||
}
|
||||
```
|
||||
|
||||
### 解决方案 2:使用 Snap Chromium 的仅附加模式
|
||||
### 解决方案 2:以仅附加模式使用 Snap Chromium
|
||||
|
||||
如果你必须使用 snap 版 Chromium,请将 OpenClaw 配置为附加到手动启动的浏览器:
|
||||
如果你必须使用 snap Chromium,请将 OpenClaw 配置为附加到一个手动启动的浏览器:
|
||||
|
||||
1. 更新配置:
|
||||
|
||||
@ -117,40 +122,40 @@ curl -s http://127.0.0.1:18791/tabs
|
||||
|
||||
### 配置参考
|
||||
|
||||
| 选项 | 说明 | 默认值 |
|
||||
| 选项 | 描述 | 默认值 |
|
||||
| ------------------------ | -------------------------------------------------------------------- | ----------------------------------------------------------- |
|
||||
| `browser.enabled` | 启用浏览器控制 | `true` |
|
||||
| `browser.executablePath` | Chromium 内核浏览器二进制路径(Chrome/Brave/Edge/Chromium) | 自动检测(若默认浏览器基于 Chromium,则优先使用) |
|
||||
| `browser.executablePath` | 基于 Chromium 的浏览器二进制路径(Chrome / Brave / Edge / Chromium) | 自动检测(优先选择默认浏览器,如果它基于 Chromium) |
|
||||
| `browser.headless` | 无 GUI 运行 | `false` |
|
||||
| `browser.noSandbox` | 添加 `--no-sandbox` 标志(某些 Linux 设置需要) | `false` |
|
||||
| `browser.attachOnly` | 不启动浏览器,只附加到现有实例 | `false` |
|
||||
| `browser.attachOnly` | 不启动浏览器,只附加到现有浏览器 | `false` |
|
||||
| `browser.cdpPort` | Chrome DevTools Protocol 端口 | `18800` |
|
||||
|
||||
### 问题:“No Chrome tabs found for profile="user"”
|
||||
### 问题:“未找到 profile=\"user\" 的 Chrome 标签页”
|
||||
|
||||
你正在使用 `existing-session` / Chrome MCP 配置文件。OpenClaw 可以看到本地 Chrome,
|
||||
但没有可附加的已打开标签页。
|
||||
你正在使用 `existing-session` / Chrome MCP profile。OpenClaw 可以看到本地 Chrome,
|
||||
但没有可供附加的打开标签页。
|
||||
|
||||
修复方式:
|
||||
修复选项:
|
||||
|
||||
1. **使用托管浏览器:** `openclaw browser start --browser-profile openclaw`
|
||||
(或设置 `browser.defaultProfile: "openclaw"`)。
|
||||
2. **使用 Chrome MCP:** 确保本地 Chrome 正在运行,且至少有一个打开的标签页,然后使用 `--browser-profile user` 重试。
|
||||
2. **使用 Chrome MCP:** 确保本地 Chrome 正在运行且至少打开了一个标签页,然后使用 `--browser-profile user` 重试。
|
||||
|
||||
说明:
|
||||
|
||||
- `user` 仅适用于宿主机。对于 Linux 服务器、容器或远程宿主,请优先使用 CDP 配置文件。
|
||||
- `user` / 其他 `existing-session` 配置文件仍保留当前 Chrome MCP 限制:
|
||||
基于 ref 的操作、单文件上传 hook、无对话框超时覆盖、无
|
||||
`wait --load networkidle`,以及不支持 `responsebody`、PDF 导出、下载
|
||||
拦截或批量操作。
|
||||
- 本地 `openclaw` 配置文件会自动分配 `cdpPort`/`cdpUrl`;只有远程 CDP 才需要手动设置这些值。
|
||||
- 远程 CDP 配置文件接受 `http://`、`https://`、`ws://` 和 `wss://`。
|
||||
当你使用 `/json/version` 发现时,请使用 HTTP(S);如果你的浏览器
|
||||
服务直接提供 DevTools socket URL,则使用 WS(S)。
|
||||
- `user` 仅限主机本地。对于 Linux 服务器、容器或远程主机,请优先使用 CDP profiles。
|
||||
- `user` / 其他 `existing-session` profiles 保留当前的 Chrome MCP 限制:
|
||||
基于 ref 的操作、单文件上传钩子、不支持对话框超时覆盖、不支持
|
||||
`wait --load networkidle`,也不支持 `responsebody`、PDF 导出、下载拦截
|
||||
或批量操作。
|
||||
- 本地 `openclaw` profiles 会自动分配 `cdpPort` / `cdpUrl`;仅在远程 CDP 场景中才设置这些值。
|
||||
- 远程 CDP profiles 接受 `http://`、`https://`、`ws://` 和 `wss://`。
|
||||
对 `/json/version` 发现请使用 HTTP(S),或者当你的浏览器
|
||||
服务提供直接的 DevTools socket URL 时使用 WS(S)。
|
||||
|
||||
## 相关内容
|
||||
|
||||
- [Browser](/zh-CN/tools/browser)
|
||||
- [浏览器登录](/zh-CN/tools/browser-login)
|
||||
- [浏览器](/zh-CN/tools/browser)
|
||||
- [Browser 登录](/zh-CN/tools/browser-login)
|
||||
- [Browser WSL2 故障排除](/zh-CN/tools/browser-wsl2-windows-remote-cdp-troubleshooting)
|
||||
|
||||
@ -1,40 +1,39 @@
|
||||
---
|
||||
read_when:
|
||||
- 添加由智能体控制的浏览器自动化
|
||||
- 调试为什么 openclaw 会干扰你自己的 Chrome
|
||||
- 在 macOS 应用中实现浏览器设置 + 生命周期
|
||||
summary: 集成的浏览器控制服务 + 操作命令
|
||||
title: 浏览器(由 OpenClaw 管理)
|
||||
- 调试为什么 OpenClaw 会干扰你自己的 Chrome
|
||||
- 在 macOS 应用中实现浏览器设置和生命周期
|
||||
summary: 集成浏览器控制服务 + 操作命令
|
||||
title: 浏览器(OpenClaw 托管)
|
||||
x-i18n:
|
||||
generated_at: "2026-04-25T04:54:58Z"
|
||||
generated_at: "2026-04-25T05:56:56Z"
|
||||
model: gpt-5.4
|
||||
provider: openai
|
||||
source_hash: cdcc8c16f474f5265bcbd38bcc3266ad3bad9e61d378750427baa69349fefd89
|
||||
source_hash: e150084059ae485cfb83ef70fd9d5d3ca46c5bd42431df3667857192009ec14c
|
||||
source_path: tools/browser.md
|
||||
workflow: 15
|
||||
---
|
||||
|
||||
OpenClaw 可以运行一个**专用的 Chrome/Brave/Edge/Chromium 配置文件**,由智能体控制。
|
||||
它与你的个人浏览器隔离,并通过 Gateway 网关内部的小型本地控制服务进行管理
|
||||
(仅限 loopback)。
|
||||
OpenClaw 可以运行一个**专用的 Chrome/Brave/Edge/Chromium profile**,由智能体进行控制。
|
||||
它与你的个人浏览器隔离,并通过 Gateway 网关内部一个小型本地控制服务进行管理
|
||||
(仅 loopback)。
|
||||
|
||||
初学者视角:
|
||||
面向初学者的理解方式:
|
||||
|
||||
- 把它理解成一个**独立的、仅供智能体使用的浏览器**。
|
||||
- `openclaw` 配置文件**不会**接触你的个人浏览器配置文件。
|
||||
- 你可以把它看作一个**独立的、仅供智能体使用的浏览器**。
|
||||
- `openclaw` profile **不会**触碰你的个人浏览器 profile。
|
||||
- 智能体可以在一条安全通道中**打开标签页、读取页面、点击和输入**。
|
||||
- 内置的 `user` 配置文件会通过 Chrome MCP 附加到你真实的已登录 Chrome 会话。
|
||||
- 内置的 `user` profile 会通过 Chrome MCP 附加到你真实的、已登录的 Chrome 会话。
|
||||
|
||||
## 你将获得什么
|
||||
|
||||
- 一个名为 **openclaw** 的独立浏览器配置文件(默认使用橙色强调色)。
|
||||
- 可预测的标签页控制(列出/打开/聚焦/关闭)。
|
||||
- 一个名为 **openclaw** 的独立浏览器 profile(默认使用橙色强调色)。
|
||||
- 确定性的标签页控制(列出/打开/聚焦/关闭)。
|
||||
- 智能体操作(点击/输入/拖动/选择)、快照、截图、PDF。
|
||||
- 一个内置的 `browser-automation` Skills,在启用浏览器插件时,会教智能体使用快照、稳定标签页、过期引用和手动阻塞恢复循环。
|
||||
- 可选的多配置文件支持(`openclaw`、`work`、`remote`、……)。
|
||||
- 一个内置的 `browser-automation` Skill,在启用 browser 插件时,它会教智能体使用 snapshot、stable-tab、stale-ref 和 manual-blocker 恢复循环。
|
||||
- 可选的多 profile 支持(`openclaw`、`work`、`remote`,等等)。
|
||||
|
||||
这个浏览器**不是**你的日常主力浏览器。它是一个安全、隔离的界面,用于
|
||||
智能体自动化和验证。
|
||||
这个浏览器**不是**你的日常主力浏览器。它是一个安全、隔离的表面,用于智能体自动化和验证。
|
||||
|
||||
## 快速开始
|
||||
|
||||
@ -46,14 +45,14 @@ openclaw browser --browser-profile openclaw open https://example.com
|
||||
openclaw browser --browser-profile openclaw snapshot
|
||||
```
|
||||
|
||||
如果你看到 “Browser disabled”,请在配置中启用它(见下文),然后重启
|
||||
如果你看到“Browser disabled”,请在配置中启用它(见下文),然后重启
|
||||
Gateway 网关。
|
||||
|
||||
如果根本没有 `openclaw browser`,或者智能体提示浏览器工具不可用,请跳转到 [缺少浏览器命令或工具](/zh-CN/tools/browser#missing-browser-command-or-tool)。
|
||||
如果 `openclaw browser` 完全不存在,或者智能体提示 browser 工具不可用,请跳转到 [缺少 browser 命令或工具](/zh-CN/tools/browser#missing-browser-command-or-tool)。
|
||||
|
||||
## 插件控制
|
||||
|
||||
默认的 `browser` 工具是一个内置插件。你可以禁用它,并替换为另一个注册相同 `browser` 工具名称的插件:
|
||||
默认的 `browser` 工具是一个内置插件。若要用另一个注册相同 `browser` 工具名的插件来替换它,请禁用该插件:
|
||||
|
||||
```json5
|
||||
{
|
||||
@ -67,22 +66,22 @@ Gateway 网关。
|
||||
}
|
||||
```
|
||||
|
||||
默认值需要同时设置 `plugins.entries.browser.enabled` **和** `browser.enabled=true`。如果只禁用插件,会整体移除 `openclaw browser` CLI、`browser.request` Gateway 网关方法、智能体工具和控制服务;你的 `browser.*` 配置会保持不变,以供替代方案使用。
|
||||
默认情况下,需要同时满足 `plugins.entries.browser.enabled` **以及** `browser.enabled=true`。仅禁用插件会整体移除 `openclaw browser` CLI、`browser.request` Gateway 网关方法、智能体工具和控制服务;你的 `browser.*` 配置会保持不变,以供替代实现使用。
|
||||
|
||||
浏览器配置变更需要重启 Gateway 网关,这样插件才能重新注册其服务。
|
||||
浏览器配置更改需要重启 Gateway 网关,这样插件才能重新注册其服务。
|
||||
|
||||
## 智能体指引
|
||||
|
||||
浏览器插件提供两层智能体指引:
|
||||
browser 插件提供两个层级的智能体指引:
|
||||
|
||||
- `browser` 工具说明中包含精简的常驻契约:选择正确的配置文件、在同一标签页中保持引用、使用 `tabId`/标签来定位标签页,以及在执行多步骤任务时加载浏览器 Skills。
|
||||
- 内置的 `browser-automation` Skills 包含更完整的操作循环:先检查状态/标签页、给任务标签页加标签、执行操作前先做快照、UI 变化后重新获取快照、遇到过期引用时重试恢复一次,并在遇到登录/2FA/captcha 或摄像头/麦克风阻塞时,报告为需要手动操作,而不是猜测处理。
|
||||
- `browser` 工具说明承载了紧凑、始终启用的约定:选择正确的 profile,在同一标签页上保持 refs,使用 `tabId`/labels 进行标签页定向,并在多步骤任务中加载 browser Skill。
|
||||
- 内置的 `browser-automation` Skill 承载了更长的操作循环:先检查状态/标签页,为任务标签页打标签,在操作前创建快照,在 UI 变化后重新创建快照,恢复一次 stale refs,并将登录/2FA/captcha 或摄像头/麦克风阻塞报告为需要手动操作,而不是猜测。
|
||||
|
||||
当插件启用时,插件内置的 Skills 会列在智能体可用 Skills 中。完整的 Skills 指令按需加载,因此日常轮次不会承担完整的 token 成本。
|
||||
当插件启用时,插件内置的 Skills 会列在智能体可用 Skills 中。完整的 Skill 指令会按需加载,因此常规轮次不会支付完整的 token 成本。
|
||||
|
||||
## 缺少浏览器命令或工具
|
||||
## 缺少 browser 命令或工具
|
||||
|
||||
如果升级后 `openclaw browser` 无法识别、缺少 `browser.request`,或者智能体报告浏览器工具不可用,通常原因是 `plugins.allow` 列表中遗漏了 `browser`。请添加它:
|
||||
如果升级后 `openclaw browser` 变成未知命令、`browser.request` 丢失,或者智能体报告 browser 工具不可用,通常原因是 `plugins.allow` 列表中遗漏了 `browser`。把它加上:
|
||||
|
||||
```json5
|
||||
{
|
||||
@ -92,21 +91,20 @@ Gateway 网关。
|
||||
}
|
||||
```
|
||||
|
||||
`browser.enabled=true`、`plugins.entries.browser.enabled=true` 和 `tools.alsoAllow: ["browser"]` 不能替代允许列表成员资格——允许列表控制插件是否加载,而工具策略只有在加载后才会运行。彻底移除 `plugins.allow` 也会恢复默认行为。
|
||||
`browser.enabled=true`、`plugins.entries.browser.enabled=true` 和 `tools.alsoAllow: ["browser"]` 都不能替代 allowlist 成员资格 —— allowlist 决定插件是否加载,而工具策略只会在加载后才运行。完全移除 `plugins.allow` 也会恢复默认行为。
|
||||
|
||||
## 配置文件:`openclaw` 与 `user`
|
||||
## Profiles:`openclaw` 与 `user`
|
||||
|
||||
- `openclaw`:受管理、隔离的浏览器(不需要扩展)。
|
||||
- `user`:内置 Chrome MCP 附加配置文件,用于接入你**真实已登录的 Chrome**
|
||||
会话。
|
||||
- `openclaw`:受管、隔离的浏览器(不需要扩展)。
|
||||
- `user`:内置的 Chrome MCP 附加 profile,用于你的**真实已登录 Chrome** 会话。
|
||||
|
||||
对于智能体浏览器工具调用:
|
||||
对于智能体 browser 工具调用:
|
||||
|
||||
- 默认:使用隔离的 `openclaw` 浏览器。
|
||||
- 当已有登录会话很重要,且用户就在电脑前可以点击/批准任何附加提示时,优先使用 `profile="user"`。
|
||||
- 当你想使用特定浏览器模式时,`profile` 是显式覆盖项。
|
||||
- 当现有登录会话很重要,并且用户就在电脑前可以点击/批准任何附加提示时,优先使用 `profile="user"`。
|
||||
- `profile` 是你希望指定某种特定浏览器模式时的显式覆盖项。
|
||||
|
||||
如果你希望默认使用受管理模式,请设置 `browser.defaultProfile: "openclaw"`。
|
||||
如果你希望默认使用受管模式,请设置 `browser.defaultProfile: "openclaw"`。
|
||||
|
||||
## 配置
|
||||
|
||||
@ -117,18 +115,18 @@ Gateway 网关。
|
||||
browser: {
|
||||
enabled: true, // 默认:true
|
||||
ssrfPolicy: {
|
||||
// dangerouslyAllowPrivateNetwork: true, // 仅在受信任的私有网络访问场景中启用
|
||||
// dangerouslyAllowPrivateNetwork: true, // 仅在受信任的私有网络访问场景下启用
|
||||
// allowPrivateNetwork: true, // 旧别名
|
||||
// hostnameAllowlist: ["*.example.com", "example.com"],
|
||||
// allowedHostnames: ["localhost"],
|
||||
},
|
||||
// cdpUrl: "http://127.0.0.1:18792", // 旧版单配置文件覆盖项
|
||||
// cdpUrl: "http://127.0.0.1:18792", // 旧的单 profile 覆盖项
|
||||
remoteCdpTimeoutMs: 1500, // 远程 CDP HTTP 超时(毫秒)
|
||||
remoteCdpHandshakeTimeoutMs: 3000, // 远程 CDP WebSocket 握手超时(毫秒)
|
||||
tabCleanup: {
|
||||
enabled: true, // 默认:true
|
||||
idleMinutes: 120, // 设为 0 以禁用空闲清理
|
||||
maxTabsPerSession: 8, // 设为 0 以禁用每会话上限
|
||||
idleMinutes: 120, // 设为 0 可禁用空闲清理
|
||||
maxTabsPerSession: 8, // 设为 0 可禁用每会话上限
|
||||
sweepMinutes: 5,
|
||||
},
|
||||
defaultProfile: "openclaw",
|
||||
@ -164,36 +162,36 @@ Gateway 网关。
|
||||
|
||||
<AccordionGroup>
|
||||
|
||||
<Accordion title="端口与可达性">
|
||||
<Accordion title="端口和可达性">
|
||||
|
||||
- 控制服务绑定到 loopback,端口由 `gateway.port` 派生而来(默认 `18791` = gateway + 2)。覆盖 `gateway.port` 或 `OPENCLAW_GATEWAY_PORT` 会同步移动同一组派生端口。
|
||||
- 本地 `openclaw` 配置文件会自动分配 `cdpPort`/`cdpUrl`;只有远程 CDP 才需要设置这些值。未设置时,`cdpUrl` 默认使用受管理的本地 CDP 端口。
|
||||
- 控制服务会绑定到 loopback,端口由 `gateway.port` 推导而来(默认 `18791` = gateway + 2)。覆盖 `gateway.port` 或 `OPENCLAW_GATEWAY_PORT` 会让同一族中的派生端口一起变化。
|
||||
- 本地 `openclaw` profiles 会自动分配 `cdpPort`/`cdpUrl`;只有远程 CDP 才需要设置这些值。未设置时,`cdpUrl` 默认指向受管本地 CDP 端口。
|
||||
- `remoteCdpTimeoutMs` 适用于远程(非 loopback)CDP HTTP 可达性检查;`remoteCdpHandshakeTimeoutMs` 适用于远程 CDP WebSocket 握手。
|
||||
- `tabCleanup` 是对主智能体浏览器会话所打开标签页的尽力清理。子智能体、cron 和 ACP 生命周期清理仍会在会话结束时关闭其显式跟踪的标签页;主会话会保留活跃标签页以便重复利用,然后在后台关闭空闲或超出的已跟踪标签页。
|
||||
- `tabCleanup` 是对由主智能体 browser 会话打开的标签页进行尽力而为的清理。子智能体、cron 和 ACP 生命周期清理仍会在会话结束时关闭它们显式跟踪的标签页;主会话会让活动标签页保持可复用,然后在后台关闭空闲或超出上限的已跟踪标签页。
|
||||
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="SSRF 策略">
|
||||
|
||||
- 浏览器导航和打开标签页会在导航前进行 SSRF 防护,并在导航完成后的最终 `http(s)` URL 上尽力再次检查。
|
||||
- browser navigation 和 open-tab 会在导航前经过 SSRF 防护,并在之后对最终的 `http(s)` URL 进行尽力而为的复检。
|
||||
- 在严格 SSRF 模式下,远程 CDP 端点发现和 `/json/version` 探测(`cdpUrl`)也会被检查。
|
||||
- Gateway 网关/提供商的 `HTTP_PROXY`、`HTTPS_PROXY`、`ALL_PROXY` 和 `NO_PROXY` 环境变量不会自动代理由 OpenClaw 管理的浏览器。受管理的 Chrome 默认直连启动,因此提供商代理设置不会削弱浏览器的 SSRF 检查。
|
||||
- 如果你要代理受管理浏览器本身,请通过 `browser.extraArgs` 传递显式的 Chrome 代理标志,例如 `--proxy-server=...` 或 `--proxy-pac-url=...`。在严格 SSRF 模式下,除非你明确启用了私有网络浏览器访问,否则显式浏览器代理路由会被阻止。
|
||||
- `browser.ssrfPolicy.dangerouslyAllowPrivateNetwork` 默认关闭;只有在明确可信任私有网络浏览器访问时才应启用。
|
||||
- Gateway 网关/提供商的 `HTTP_PROXY`、`HTTPS_PROXY`、`ALL_PROXY` 和 `NO_PROXY` 环境变量不会自动代理 OpenClaw 托管的浏览器。受管 Chrome 默认直接启动,因此提供商代理设置不会削弱 browser SSRF 检查。
|
||||
- 如果要代理受管浏览器本身,请通过 `browser.extraArgs` 传入显式 Chrome 代理标志,例如 `--proxy-server=...` 或 `--proxy-pac-url=...`。严格 SSRF 模式会阻止显式 browser 代理路由,除非你明确启用了私有网络 browser 访问。
|
||||
- `browser.ssrfPolicy.dangerouslyAllowPrivateNetwork` 默认关闭;仅在你明确受信任私有网络 browser 访问时启用。
|
||||
- `browser.ssrfPolicy.allowPrivateNetwork` 仍然作为旧别名受支持。
|
||||
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="配置文件行为">
|
||||
<Accordion title="Profile 行为">
|
||||
|
||||
- `attachOnly: true` 表示绝不启动本地浏览器;仅在浏览器已经运行时附加。
|
||||
- `headless` 可以在全局或每个本地受管理配置文件上设置。每个配置文件的值会覆盖 `browser.headless`,因此一个本地启动的配置文件可以保持无头,而另一个仍然可见。
|
||||
- `executablePath` 也可以在全局或每个本地受管理配置文件上设置。每个配置文件的值会覆盖 `browser.executablePath`,因此不同的受管理配置文件可以启动不同的 Chromium 系浏览器。
|
||||
- `color`(顶层和每个配置文件级别)会为浏览器 UI 着色,这样你可以看出当前激活的是哪个配置文件。
|
||||
- 默认配置文件是 `openclaw`(受管理的独立模式)。使用 `defaultProfile: "user"` 可切换为已登录的用户浏览器。
|
||||
- 自动检测顺序:如果系统默认浏览器是 Chromium 系,则优先使用它;否则按 Chrome → Brave → Edge → Chromium → Chrome Canary 的顺序检测。
|
||||
- `attachOnly: true` 表示绝不启动本地浏览器;只有在浏览器已经运行时才附加。
|
||||
- `headless` 可以在全局或按本地受管 profile 设置。按 profile 的值会覆盖 `browser.headless`,因此一个本地启动的 profile 可以保持 headless,而另一个仍然可见。
|
||||
- `executablePath` 也可以在全局或按本地受管 profile 设置。按 profile 的值会覆盖 `browser.executablePath`,因此不同的受管 profiles 可以启动不同的 Chromium 系浏览器。
|
||||
- `color`(顶层和按 profile)会给浏览器 UI 加上色调,这样你可以看出当前活动的是哪个 profile。
|
||||
- 默认 profile 是 `openclaw`(受管独立模式)。使用 `defaultProfile: "user"` 可切换为已登录用户浏览器。
|
||||
- 自动检测顺序:系统默认浏览器(如果它是 Chromium 系);否则 Chrome → Brave → Edge → Chromium → Chrome Canary。
|
||||
- `driver: "existing-session"` 使用 Chrome DevTools MCP,而不是原始 CDP。不要为该驱动设置 `cdpUrl`。
|
||||
- 当 existing-session 配置文件需要附加到非默认的 Chromium 用户配置文件(Brave、Edge 等)时,请设置 `browser.profiles.<name>.userDataDir`。
|
||||
- 当一个 existing-session profile 应附加到非默认 Chromium 用户 profile(Brave、Edge 等)时,请设置 `browser.profiles.<name>.userDataDir`。
|
||||
|
||||
</Accordion>
|
||||
|
||||
@ -202,8 +200,8 @@ Gateway 网关。
|
||||
## 使用 Brave(或其他 Chromium 系浏览器)
|
||||
|
||||
如果你的**系统默认**浏览器是 Chromium 系(Chrome/Brave/Edge 等),
|
||||
OpenClaw 会自动使用它。设置 `browser.executablePath` 可以覆盖自动检测。
|
||||
`~` 会展开为你的操作系统主目录:
|
||||
OpenClaw 会自动使用它。设置 `browser.executablePath` 可覆盖
|
||||
自动检测。`~` 会展开为你的操作系统主目录:
|
||||
|
||||
```bash
|
||||
openclaw config set browser.executablePath "/usr/bin/google-chrome"
|
||||
@ -242,46 +240,50 @@ openclaw config set browser.profiles.work.executablePath "/Applications/Google C
|
||||
</Tab>
|
||||
</Tabs>
|
||||
|
||||
每个配置文件级别的 `executablePath` 只会影响由 OpenClaw 启动的本地受管理配置文件。`existing-session` 配置文件则会附加到一个已经运行的浏览器,而远程 CDP 配置文件使用的是 `cdpUrl` 后面的浏览器。
|
||||
按 profile 设置的 `executablePath` 只影响 OpenClaw 启动的本地受管 profiles。`existing-session` profiles 会附加到一个已经运行的浏览器,而远程 CDP profiles 会使用 `cdpUrl` 背后的浏览器。
|
||||
|
||||
## 本地控制与远程控制
|
||||
|
||||
- **本地控制(默认):** Gateway 网关启动 loopback 控制服务,并可启动本地浏览器。
|
||||
- **远程控制(节点主机):** 在拥有浏览器的那台机器上运行节点主机;Gateway 网关会将浏览器操作代理过去。
|
||||
- **本地控制(默认):** Gateway 网关启动 loopback 控制服务,并且可以启动本地浏览器。
|
||||
- **远程控制(节点主机):** 在拥有浏览器的机器上运行一个节点主机;Gateway 网关会把 browser 操作代理给它。
|
||||
- **远程 CDP:** 设置 `browser.profiles.<name>.cdpUrl`(或 `browser.cdpUrl`)以附加到远程 Chromium 系浏览器。在这种情况下,OpenClaw 不会启动本地浏览器。
|
||||
- `headless` 只影响由 OpenClaw 启动的本地受管理配置文件。它不会重启或更改 existing-session 或远程 CDP 浏览器。
|
||||
- `executablePath` 遵循相同的本地受管理配置文件规则。对正在运行的本地受管理配置文件修改它,会将该配置文件标记为需要重启/协调,以便下次启动时使用新的二进制文件。
|
||||
- `headless` 只影响 OpenClaw 启动的本地受管 profiles。它不会重启或更改 existing-session 或远程 CDP 浏览器。
|
||||
- `executablePath` 也遵循同样的本地受管 profile 规则。在正在运行的本地受管 profile 上修改它,会将该 profile 标记为需要重启/对齐,以便下次启动时使用新的二进制文件。
|
||||
|
||||
停止行为因配置文件模式而异:
|
||||
停止行为会因 profile 模式而不同:
|
||||
|
||||
- 本地受管理配置文件:`openclaw browser stop` 会停止由 OpenClaw 启动的浏览器进程
|
||||
- 仅附加和远程 CDP 配置文件:`openclaw browser stop` 会关闭当前控制会话,并释放 Playwright/CDP 仿真覆盖项(视口、配色方案、语言区域、时区、离线模式及类似状态),即使 OpenClaw 并未启动任何浏览器进程
|
||||
- 本地受管 profiles:`openclaw browser stop` 会停止由 OpenClaw 启动的浏览器进程
|
||||
- attach-only 和远程 CDP profiles:`openclaw browser stop` 会关闭当前控制会话,并释放 Playwright/CDP 模拟覆盖状态(viewport、color scheme、locale、timezone、offline mode 以及类似状态),即使 OpenClaw 实际上并未启动任何浏览器进程
|
||||
|
||||
远程 CDP URL 可以包含认证信息:
|
||||
|
||||
- 查询参数 token(例如 `https://provider.example?token=<token>`)
|
||||
- HTTP Basic 认证(例如 `https://user:pass@provider.example`)
|
||||
|
||||
OpenClaw 在调用 `/json/*` 端点以及连接 CDP WebSocket 时会保留这些认证信息。对于 token,优先使用环境变量或密钥管理器,而不是将它们提交到配置文件中。
|
||||
OpenClaw 在调用 `/json/*` 端点和连接到 CDP WebSocket 时会保留这些认证信息。
|
||||
对于 token,优先使用环境变量或密钥管理器,而不是把它们提交到配置文件中。
|
||||
|
||||
## 节点浏览器代理(默认零配置)
|
||||
## 节点 browser 代理(默认零配置)
|
||||
|
||||
如果你在拥有浏览器的那台机器上运行一个**节点主机**,OpenClaw 可以将浏览器工具调用自动路由到该节点,而无需任何额外的浏览器配置。
|
||||
如果你在拥有浏览器的那台机器上运行了一个**节点主机**,OpenClaw 就可以
|
||||
自动将 browser 工具调用路由到该节点,而无需额外的 browser 配置。
|
||||
这是远程 Gateway 网关的默认路径。
|
||||
|
||||
说明:
|
||||
|
||||
- 节点主机会通过一个**代理命令**暴露其本地浏览器控制服务器。
|
||||
- 配置文件来自节点自身的 `browser.profiles` 配置(与本地相同)。
|
||||
- `nodeHost.browserProxy.allowProfiles` 是可选项。留空即可保留旧版/默认行为:所有已配置的配置文件都可通过代理访问,包括配置文件创建/删除路由。
|
||||
- 如果你设置了 `nodeHost.browserProxy.allowProfiles`,OpenClaw 会将其视为最小权限边界:只有允许列表中的配置文件可作为目标,并且持久化配置文件创建/删除路由会在代理界面上被阻止。
|
||||
- 如果你不想启用它,可以禁用:
|
||||
- 节点主机会通过一个**代理命令**暴露其本地 browser 控制服务器。
|
||||
- Profiles 来自该节点自己的 `browser.profiles` 配置(与本地相同)。
|
||||
- `nodeHost.browserProxy.allowProfiles` 是可选项。保持为空即可沿用旧版/默认行为:所有已配置的 profiles 都仍然可以通过代理访问,包括 profile 创建/删除路由。
|
||||
- 如果你设置了 `nodeHost.browserProxy.allowProfiles`,OpenClaw 会将其视为最小权限边界:只有 allowlist 中的 profiles 才能被定向,而且持久化的 profile 创建/删除路由会在代理表面上被阻止。
|
||||
- 如果你不想使用它,可以禁用:
|
||||
- 在节点上:`nodeHost.browserProxy.enabled=false`
|
||||
- 在网关上:`gateway.nodes.browser.mode="off"`
|
||||
- 在 Gateway 网关上:`gateway.nodes.browser.mode="off"`
|
||||
|
||||
## Browserless(托管远程 CDP)
|
||||
|
||||
[Browserless](https://browserless.io) 是一个托管的 Chromium 服务,可通过 HTTPS 和 WebSocket 暴露 CDP 连接 URL。OpenClaw 可以使用这两种形式,不过对于远程浏览器配置文件,最简单的选项是使用 Browserless 连接文档中提供的直接 WebSocket URL。
|
||||
[Browserless](https://browserless.io) 是一个托管的 Chromium 服务,它通过 HTTPS 和 WebSocket 暴露
|
||||
CDP 连接 URL。OpenClaw 两种形式都可以使用,但对于远程浏览器 profile,
|
||||
最简单的选项是使用 Browserless 连接文档中的直接 WebSocket URL。
|
||||
|
||||
示例:
|
||||
|
||||
@ -305,23 +307,37 @@ OpenClaw 在调用 `/json/*` 端点以及连接 CDP WebSocket 时会保留这些
|
||||
说明:
|
||||
|
||||
- 将 `<BROWSERLESS_API_KEY>` 替换为你真实的 Browserless token。
|
||||
- 选择与你的 Browserless 账户匹配的区域端点(见其文档)。
|
||||
- 如果 Browserless 给你的是一个 HTTPS 基础 URL,你可以将其转换为 `wss://` 以进行直接 CDP 连接,或者保留该 HTTPS URL,让 OpenClaw 发现 `/json/version`。
|
||||
- 选择与你的 Browserless 账户匹配的区域端点(参见其文档)。
|
||||
- 如果 Browserless 提供给你的是一个 HTTPS 基础 URL,你可以将其转换为
|
||||
`wss://` 以建立直接 CDP 连接,也可以保留 HTTPS URL,让 OpenClaw
|
||||
去发现 `/json/version`。
|
||||
|
||||
## 直接 WebSocket CDP 提供商
|
||||
|
||||
有些托管浏览器服务暴露的是**直接 WebSocket** 端点,而不是标准的基于 HTTP 的 CDP 发现(`/json/version`)。OpenClaw 接受三种 CDP URL 形式,并会自动选择正确的连接策略:
|
||||
一些托管浏览器服务暴露的是**直接 WebSocket** 端点,而不是
|
||||
标准的基于 HTTP 的 CDP 发现(`/json/version`)。OpenClaw 接受三种
|
||||
CDP URL 形态,并自动选择正确的连接策略:
|
||||
|
||||
- **HTTP(S) 发现** — `http://host[:port]` 或 `https://host[:port]`。
|
||||
OpenClaw 会调用 `/json/version` 来发现 WebSocket 调试器 URL,然后进行连接。不会回退到 WebSocket。
|
||||
- **直接 WebSocket 端点** — `ws://host[:port]/devtools/<kind>/<id>` 或
|
||||
`wss://...`,路径为 `/devtools/browser|page|worker|shared_worker|service_worker/<id>`。
|
||||
OpenClaw 会直接通过 WebSocket 握手连接,并完全跳过 `/json/version`。
|
||||
- **裸 WebSocket 根路径** — `ws://host[:port]` 或 `wss://host[:port]`,且没有 `/devtools/...` 路径(例如 [Browserless](https://browserless.io)、[Browserbase](https://www.browserbase.com))。OpenClaw 会先尝试 HTTP `/json/version` 发现(将协议规范化为 `http`/`https`);如果发现结果返回 `webSocketDebuggerUrl`,则使用它,否则 OpenClaw 会回退为在裸根路径上直接进行 WebSocket 握手。这样,指向本地 Chrome 的裸 `ws://` 也能连接,因为 Chrome 只接受来自 `/json/version` 中特定目标路径的 WebSocket 升级。
|
||||
- **HTTP(S) 发现** — `http://host[:port]` 或 `https://host[:port]`。
|
||||
OpenClaw 会调用 `/json/version` 来发现 WebSocket debugger URL,
|
||||
然后建立连接。不会回退到 WebSocket。
|
||||
- **直接 WebSocket 端点** — `ws://host[:port]/devtools/<kind>/<id>` 或
|
||||
`wss://...`,并带有 `/devtools/browser|page|worker|shared_worker|service_worker/<id>`
|
||||
路径。OpenClaw 会直接通过 WebSocket 握手连接,并完全跳过
|
||||
`/json/version`。
|
||||
- **裸 WebSocket 根路径** — `ws://host[:port]` 或 `wss://host[:port]`,且没有
|
||||
`/devtools/...` 路径(例如 [Browserless](https://browserless.io),
|
||||
[Browserbase](https://www.browserbase.com))。OpenClaw 会先尝试 HTTP
|
||||
`/json/version` 发现(将协议规范化为 `http`/`https`);
|
||||
如果发现结果返回了 `webSocketDebuggerUrl`,就使用它,否则 OpenClaw
|
||||
会回退为对裸根路径进行直接 WebSocket 握手。这让指向本地 Chrome 的裸 `ws://`
|
||||
仍然可以连接,因为 Chrome 只接受位于
|
||||
`/json/version` 返回的特定按目标路径上的 WebSocket 升级。
|
||||
|
||||
### Browserbase
|
||||
|
||||
[Browserbase](https://www.browserbase.com) 是一个云平台,用于运行无头浏览器,内置 CAPTCHA 求解、隐身模式和住宅代理。
|
||||
[Browserbase](https://www.browserbase.com) 是一个云平台,用于运行
|
||||
无头浏览器,内置 CAPTCHA 求解、隐身模式和住宅代理。
|
||||
|
||||
```json5
|
||||
{
|
||||
@ -342,67 +358,78 @@ OpenClaw 在调用 `/json/*` 端点以及连接 CDP WebSocket 时会保留这些
|
||||
|
||||
说明:
|
||||
|
||||
- [注册](https://www.browserbase.com/sign-up),并从 [Overview dashboard](https://www.browserbase.com/overview) 复制你的 **API Key**。
|
||||
- [注册](https://www.browserbase.com/sign-up),然后从 [概览仪表板](https://www.browserbase.com/overview) 复制你的 **API Key**。
|
||||
- 将 `<BROWSERBASE_API_KEY>` 替换为你真实的 Browserbase API key。
|
||||
- Browserbase 会在 WebSocket 连接时自动创建浏览器会话,因此不需要手动创建会话步骤。
|
||||
- 免费层每月允许一个并发会话和一个浏览器小时。付费方案限制请参见 [pricing](https://www.browserbase.com/pricing)。
|
||||
- 完整的 API 参考、SDK 指南和集成示例请参见 [Browserbase docs](https://docs.browserbase.com)。
|
||||
- Browserbase 会在 WebSocket 连接时自动创建浏览器会话,因此
|
||||
不需要手动创建会话。
|
||||
- 免费层允许一个并发会话以及每月一个浏览器小时。
|
||||
付费计划限制请参见 [定价](https://www.browserbase.com/pricing)。
|
||||
- 完整 API 参考、SDK 指南和集成示例请参见 [Browserbase 文档](https://docs.browserbase.com)。
|
||||
|
||||
## 安全性
|
||||
## 安全
|
||||
|
||||
关键概念:
|
||||
关键点:
|
||||
|
||||
- 浏览器控制仅限 loopback;访问通过 Gateway 网关认证或节点配对进行。
|
||||
- 独立的 loopback 浏览器 HTTP API **仅使用共享密钥认证**:gateway token bearer 认证、`x-openclaw-password`,或带有已配置网关密码的 HTTP Basic 认证。
|
||||
- Tailscale Serve 身份头,以及 `gateway.auth.mode: "trusted-proxy"`,**不能**为这个独立的 loopback 浏览器 API 提供认证。
|
||||
- 如果启用了浏览器控制且未配置任何共享密钥认证,OpenClaw 会在启动时自动生成 `gateway.auth.token`,并将其持久化到配置中。
|
||||
- 当 `gateway.auth.mode` 已经是 `password`、`none` 或 `trusted-proxy` 时,OpenClaw **不会**自动生成该 token。
|
||||
- 请将 Gateway 网关和任何节点主机保留在私有网络中(Tailscale);避免公开暴露。
|
||||
- 将远程 CDP URL/token 视为敏感信息;优先使用环境变量或密钥管理器。
|
||||
- 独立的 loopback 浏览器 HTTP API **只**使用共享密钥认证:
|
||||
gateway token bearer auth、`x-openclaw-password`,或者使用已配置
|
||||
gateway password 的 HTTP Basic auth。
|
||||
- Tailscale Serve 身份头和 `gateway.auth.mode: "trusted-proxy"`
|
||||
**不能**对这个独立的 loopback 浏览器 API 进行认证。
|
||||
- 如果启用了浏览器控制,但没有配置共享密钥认证,OpenClaw
|
||||
会在启动时自动生成 `gateway.auth.token` 并将其持久化到配置中。
|
||||
- 如果 `gateway.auth.mode` 已经是
|
||||
`password`、`none` 或 `trusted-proxy`,OpenClaw **不会**自动生成该 token。
|
||||
- 将 Gateway 网关和任何节点主机保留在私有网络(Tailscale)中;避免公开暴露。
|
||||
- 将远程 CDP URL/token 视为密钥;优先使用环境变量或密钥管理器。
|
||||
|
||||
远程 CDP 提示:
|
||||
|
||||
- 尽可能优先使用加密端点(HTTPS 或 WSS)和短期 token。
|
||||
- 避免将长期 token 直接嵌入配置文件。
|
||||
- 避免将长期 token 直接写入配置文件。
|
||||
|
||||
## 配置文件(多浏览器)
|
||||
## Profiles(多浏览器)
|
||||
|
||||
OpenClaw 支持多个命名配置文件(路由配置)。配置文件可以是:
|
||||
OpenClaw 支持多个命名 profiles(路由配置)。Profiles 可以是:
|
||||
|
||||
- **openclaw-managed**:一个专用的 Chromium 系浏览器实例,拥有自己的用户数据目录和 CDP 端口
|
||||
- **remote**:一个显式的 CDP URL(运行在其他地方的 Chromium 系浏览器)
|
||||
- **existing session**:通过 Chrome DevTools MCP 自动连接你现有的 Chrome 配置文件
|
||||
- **OpenClaw 托管**:一个专用的 Chromium 系浏览器实例,带有自己的用户数据目录 + CDP 端口
|
||||
- **远程**:一个显式的 CDP URL(在其他地方运行的 Chromium 系浏览器)
|
||||
- **现有会话**:通过 Chrome DevTools MCP 自动连接到你现有的 Chrome profile
|
||||
|
||||
默认值:
|
||||
|
||||
- 如果缺失,会自动创建 `openclaw` 配置文件。
|
||||
- `user` 配置文件是内置的,用于 Chrome MCP existing-session 附加。
|
||||
- 除 `user` 之外,existing-session 配置文件需要显式启用;请使用 `--driver existing-session` 创建它们。
|
||||
- 如果缺失,会自动创建 `openclaw` profile。
|
||||
- `user` profile 是内置的,用于 Chrome MCP existing-session 附加。
|
||||
- 除 `user` 外,existing-session profiles 需要显式启用;使用 `--driver existing-session` 创建它们。
|
||||
- 本地 CDP 端口默认从 **18800–18899** 分配。
|
||||
- 删除配置文件会将其本地数据目录移到废纸篓。
|
||||
- 删除 profile 会将其本地数据目录移到回收站。
|
||||
|
||||
所有控制端点都接受 `?profile=<name>`;CLI 使用 `--browser-profile`。
|
||||
|
||||
## 通过 Chrome DevTools MCP 使用 existing-session
|
||||
## 通过 Chrome DevTools MCP 使用现有会话
|
||||
|
||||
OpenClaw 也可以通过官方 Chrome DevTools MCP 服务器附加到一个正在运行的 Chromium 系浏览器配置文件。这样可以复用该浏览器配置文件中已经打开的标签页和登录状态。
|
||||
OpenClaw 还可以通过
|
||||
官方 Chrome DevTools MCP 服务器附加到一个正在运行的 Chromium 系浏览器 profile。
|
||||
这会复用该浏览器 profile 中已经打开的标签页和登录状态。
|
||||
|
||||
官方背景与设置参考:
|
||||
官方背景和设置参考:
|
||||
|
||||
- [Chrome for Developers: Use Chrome DevTools MCP with your browser session](https://developer.chrome.com/blog/chrome-devtools-mcp-debug-your-browser-session)
|
||||
- [Chrome for Developers:使用 Chrome DevTools MCP 调试你的浏览器会话](https://developer.chrome.com/blog/chrome-devtools-mcp-debug-your-browser-session)
|
||||
- [Chrome DevTools MCP README](https://github.com/ChromeDevTools/chrome-devtools-mcp)
|
||||
|
||||
内置配置文件:
|
||||
内置 profile:
|
||||
|
||||
- `user`
|
||||
|
||||
可选:如果你想使用不同的名称、颜色或浏览器数据目录,可以创建你自己的自定义 existing-session 配置文件。
|
||||
可选:如果你想使用不同的名称、颜色或浏览器数据目录,
|
||||
可以创建你自己的自定义 existing-session profile。
|
||||
|
||||
默认行为:
|
||||
|
||||
- 内置的 `user` 配置文件使用 Chrome MCP 自动连接,目标是默认的本地 Google Chrome 配置文件。
|
||||
- 内置的 `user` profile 使用 Chrome MCP 自动连接,目标是
|
||||
默认的本地 Google Chrome profile。
|
||||
|
||||
对于 Brave、Edge、Chromium 或非默认 Chrome 配置文件,请使用 `userDataDir`:
|
||||
对于 Brave、Edge、Chromium 或非默认 Chrome profile,请使用 `userDataDir`:
|
||||
|
||||
```json5
|
||||
{
|
||||
@ -431,7 +458,7 @@ OpenClaw 也可以通过官方 Chrome DevTools MCP 服务器附加到一个正
|
||||
- Brave:`brave://inspect/#remote-debugging`
|
||||
- Edge:`edge://inspect/#remote-debugging`
|
||||
|
||||
实时附加冒烟测试:
|
||||
实时附加 smoke 测试:
|
||||
|
||||
```bash
|
||||
openclaw browser --browser-profile user start
|
||||
@ -446,45 +473,54 @@ openclaw browser --browser-profile user snapshot --format ai
|
||||
- `status` 显示 `transport: chrome-mcp`
|
||||
- `status` 显示 `running: true`
|
||||
- `tabs` 列出你已经打开的浏览器标签页
|
||||
- `snapshot` 返回所选实时标签页中的 refs
|
||||
- `snapshot` 返回来自所选活动标签页的 refs
|
||||
|
||||
如果附加失败,请检查:
|
||||
如果附加不起作用,需要检查:
|
||||
|
||||
- 目标 Chromium 系浏览器版本为 `144+`
|
||||
- 已在该浏览器的 inspect 页面启用远程调试
|
||||
- 浏览器显示了附加同意提示,且你已接受
|
||||
- `openclaw doctor` 会迁移旧的基于扩展的浏览器配置,并检查默认自动连接配置文件所需的 Chrome 是否已在本地安装,但它无法替你启用浏览器端的远程调试
|
||||
- 该浏览器的 inspect 页面中已启用远程调试
|
||||
- 浏览器显示了附加同意提示,并且你已接受
|
||||
- `openclaw doctor` 会迁移旧的基于扩展的浏览器配置,并检查
|
||||
对于默认自动连接 profiles,Chrome 是否已在本地安装,但它不能替你
|
||||
启用浏览器侧的远程调试
|
||||
|
||||
智能体使用:
|
||||
|
||||
- 当你需要用户已登录的浏览器状态时,使用 `profile="user"`。
|
||||
- 如果你使用自定义 existing-session 配置文件,请传入该显式配置文件名称。
|
||||
- 仅当用户在电脑前可以批准附加提示时才选择此模式。
|
||||
- 如果你使用的是自定义 existing-session profile,请传入那个显式 profile 名称。
|
||||
- 只有当用户就在电脑前可以批准附加提示时,才应选择这种模式。
|
||||
- Gateway 网关或节点主机可以启动 `npx chrome-devtools-mcp@latest --autoConnect`
|
||||
|
||||
说明:
|
||||
|
||||
- 与隔离的 `openclaw` 配置文件相比,这条路径风险更高,因为它可以在你已登录的浏览器会话中执行操作。
|
||||
- 这条路径比隔离的 `openclaw` profile 风险更高,因为它可以
|
||||
在你已登录的浏览器会话内执行操作。
|
||||
- 对于这个驱动,OpenClaw 不会启动浏览器;它只会附加。
|
||||
- OpenClaw 在这里使用官方的 Chrome DevTools MCP `--autoConnect` 流程。如果设置了 `userDataDir`,它会被透传,以定位到该用户数据目录。
|
||||
- existing-session 可以附加到所选主机上,也可以通过已连接的浏览器节点附加。如果 Chrome 位于其他地方且没有连接浏览器节点,请改用远程 CDP 或节点主机。
|
||||
- OpenClaw 在这里使用官方的 Chrome DevTools MCP `--autoConnect` 流程。如果
|
||||
设置了 `userDataDir`,它会被透传,以定位到该用户数据目录。
|
||||
- Existing-session 可以附加到选定主机上,或通过已连接的
|
||||
browser 节点附加。如果 Chrome 位于别处且没有连接 browser 节点,请改用
|
||||
远程 CDP 或节点主机。
|
||||
|
||||
<Accordion title="existing-session 功能限制">
|
||||
<Accordion title="Existing-session 功能限制">
|
||||
|
||||
与受管理的 `openclaw` 配置文件相比,existing-session 驱动限制更多:
|
||||
与受管的 `openclaw` profile 相比,existing-session 驱动受到更多限制:
|
||||
|
||||
- **截图** — 支持页面截图和 `--ref` 元素截图;不支持 CSS `--element` 选择器。`--full-page` 不能与 `--ref` 或 `--element` 组合使用。页面截图或基于 ref 的元素截图不需要 Playwright。
|
||||
- **操作** — `click`、`type`、`hover`、`scrollIntoView`、`drag` 和 `select` 需要使用快照 refs(不支持 CSS 选择器)。`click` 仅支持鼠标左键。`type` 不支持 `slowly=true`;请使用 `fill` 或 `press`。`press` 不支持 `delayMs`。`type`、`hover`、`scrollIntoView`、`drag`、`select`、`fill` 和 `evaluate` 不支持按调用设置超时。`select` 接受单个值。
|
||||
- **等待 / 上传 / 对话框** — `wait --url` 支持精确、子串和 glob 模式;不支持 `wait --load networkidle`。上传钩子需要 `ref` 或 `inputRef`,每次只支持一个文件,不支持 CSS `element`。对话框钩子不支持超时覆盖。
|
||||
- **仅受管理模式支持的功能** — 批量操作、PDF 导出、下载拦截和 `responsebody` 仍然需要受管理浏览器路径。
|
||||
- **截图** —— 页面捕获和 `--ref` 元素捕获可用;CSS `--element` 选择器不可用。`--full-page` 不能与 `--ref` 或 `--element` 组合使用。页面或基于 ref 的元素截图不需要 Playwright。
|
||||
- **操作** —— `click`、`type`、`hover`、`scrollIntoView`、`drag` 和 `select` 需要 snapshot refs(不支持 CSS 选择器)。`click` 仅支持左键。`type` 不支持 `slowly=true`;请使用 `fill` 或 `press`。`press` 不支持 `delayMs`。`type`、`hover`、`scrollIntoView`、`drag`、`select`、`fill` 和 `evaluate` 不支持按调用设置超时。`select` 仅接受单个值。
|
||||
- **等待 / 上传 / 对话框** —— `wait --url` 支持精确、子串和 glob 模式;不支持 `wait --load networkidle`。上传钩子需要 `ref` 或 `inputRef`,一次一个文件,不支持 CSS `element`。对话框钩子不支持超时覆盖。
|
||||
- **仅受管功能** —— 批量操作、PDF 导出、下载拦截和 `responsebody` 仍然需要受管浏览器路径。
|
||||
|
||||
</Accordion>
|
||||
|
||||
## 隔离保证
|
||||
|
||||
- **专用用户数据目录**:绝不会接触你的个人浏览器配置文件。
|
||||
- **专用端口**:避免使用 `9222`,以防与开发工作流冲突。
|
||||
- **可预测的标签页控制**:`tabs` 会先返回 `suggestedTargetId`,然后是稳定的 `tabId` 句柄(如 `t1`)、可选标签以及原始 `targetId`。智能体应复用 `suggestedTargetId`;原始 id 仍会保留,用于调试和兼容性。
|
||||
- **专用用户数据目录**:绝不会触碰你的个人浏览器 profile。
|
||||
- **专用端口**:避开 `9222`,以防与开发工作流冲突。
|
||||
- **确定性的标签页控制**:`tabs` 会先返回 `suggestedTargetId`,然后是
|
||||
稳定的 `tabId` 句柄(如 `t1`)、可选标签以及原始 `targetId`。
|
||||
智能体应复用 `suggestedTargetId`;原始 id 仍然保留,用于
|
||||
调试和兼容性。
|
||||
|
||||
## 浏览器选择
|
||||
|
||||
@ -496,9 +532,9 @@ openclaw browser --browser-profile user snapshot --format ai
|
||||
4. Chromium
|
||||
5. Chrome Canary
|
||||
|
||||
你可以使用 `browser.executablePath` 覆盖它。
|
||||
你可以使用 `browser.executablePath` 覆盖。
|
||||
|
||||
平台说明:
|
||||
平台:
|
||||
|
||||
- macOS:检查 `/Applications` 和 `~/Applications`。
|
||||
- Linux:查找 `google-chrome`、`brave`、`microsoft-edge`、`chromium` 等。
|
||||
@ -506,23 +542,25 @@ openclaw browser --browser-profile user snapshot --format ai
|
||||
|
||||
## 控制 API(可选)
|
||||
|
||||
为了便于脚本编写和调试,Gateway 网关暴露了一个小型的**仅限 loopback 的 HTTP 控制 API**,以及与之匹配的 `openclaw browser` CLI(快照、refs、wait 增强功能、JSON 输出、调试工作流)。完整参考请参见
|
||||
[Browser control API](/zh-CN/tools/browser-control)。
|
||||
为了便于脚本编写和调试,Gateway 网关暴露了一个小型的**仅 loopback 的 HTTP
|
||||
控制 API**,以及与之对应的 `openclaw browser` CLI(快照、refs、wait
|
||||
增强、JSON 输出、调试工作流)。完整参考请参见
|
||||
[Browser 控制 API](/zh-CN/tools/browser-control)。
|
||||
|
||||
## 故障排除
|
||||
|
||||
对于 Linux 特定问题(尤其是 snap Chromium),请参见
|
||||
对于 Linux 特有问题(尤其是 snap Chromium),请参见
|
||||
[浏览器故障排除](/zh-CN/tools/browser-linux-troubleshooting)。
|
||||
|
||||
对于 WSL2 Gateway 网关 + Windows Chrome 分离主机设置,请参见
|
||||
对于 WSL2 Gateway 网关 + Windows Chrome 分离主机部署,请参见
|
||||
[WSL2 + Windows + 远程 Chrome CDP 故障排除](/zh-CN/tools/browser-wsl2-windows-remote-cdp-troubleshooting)。
|
||||
|
||||
### CDP 启动失败与导航 SSRF 阻止
|
||||
### CDP 启动失败 vs 导航 SSRF 阻止
|
||||
|
||||
这是两种不同的故障类型,对应不同的代码路径。
|
||||
这是两类不同的故障,它们指向不同的代码路径。
|
||||
|
||||
- **CDP 启动或就绪失败** 表示 OpenClaw 无法确认浏览器控制平面处于健康状态。
|
||||
- **导航 SSRF 阻止** 表示浏览器控制平面是健康的,但某个页面导航目标被策略拒绝。
|
||||
- **CDP 启动或就绪失败** 表示 OpenClaw 无法确认浏览器控制平面是健康的。
|
||||
- **导航 SSRF 阻止** 表示浏览器控制平面是健康的,但页面导航目标因策略被拒绝。
|
||||
|
||||
常见示例:
|
||||
|
||||
@ -532,7 +570,7 @@ openclaw browser --browser-profile user snapshot --format ai
|
||||
- 导航 SSRF 阻止:
|
||||
- 当 `start` 和 `tabs` 仍然可用时,`open`、`navigate`、snapshot 或打开标签页流程因浏览器/网络策略错误而失败
|
||||
|
||||
使用以下最小序列来区分这两种情况:
|
||||
使用下面这组最小命令来区分这两类问题:
|
||||
|
||||
```bash
|
||||
openclaw browser --browser-profile openclaw start
|
||||
@ -540,48 +578,48 @@ openclaw browser --browser-profile openclaw tabs
|
||||
openclaw browser --browser-profile openclaw open https://example.com
|
||||
```
|
||||
|
||||
如何理解结果:
|
||||
如何解读结果:
|
||||
|
||||
- 如果 `start` 失败并显示 `not reachable after start`,请先排查 CDP 就绪状态。
|
||||
- 如果 `start` 成功但 `tabs` 失败,说明控制平面仍然不健康。应将其视为 CDP 可达性问题,而不是页面导航问题。
|
||||
- 如果 `start` 和 `tabs` 成功,但 `open` 或 `navigate` 失败,说明浏览器控制平面已经就绪,故障出在导航策略或目标页面。
|
||||
- 如果 `start`、`tabs` 和 `open` 都成功,说明基础的受管理浏览器控制路径是健康的。
|
||||
- 如果 `start` 以 `not reachable after start` 失败,先排查 CDP 就绪问题。
|
||||
- 如果 `start` 成功,但 `tabs` 失败,则控制平面仍然不健康。应将其视为 CDP 可达性问题,而不是页面导航问题。
|
||||
- 如果 `start` 和 `tabs` 成功,但 `open` 或 `navigate` 失败,则浏览器控制平面已启动,故障位于导航策略或目标页面。
|
||||
- 如果 `start`、`tabs` 和 `open` 都成功,则基础受管浏览器控制路径是健康的。
|
||||
|
||||
重要行为细节:
|
||||
|
||||
- 即使你没有配置 `browser.ssrfPolicy`,浏览器配置默认也会使用一个失败即关闭的 SSRF 策略对象。
|
||||
- 对于本地 loopback `openclaw` 受管理配置文件,CDP 健康检查会有意跳过对 OpenClaw 自身本地控制平面的浏览器 SSRF 可达性强制检查。
|
||||
- 导航保护是独立的。`start` 或 `tabs` 成功,并不意味着之后的 `open` 或 `navigate` 目标一定被允许。
|
||||
- 即使你没有配置 `browser.ssrfPolicy`,浏览器配置默认也会采用 fail-closed 的 SSRF 策略对象。
|
||||
- 对于本地 loopback 的 `openclaw` 受管 profile,CDP 健康检查会有意跳过对 OpenClaw 自身本地控制平面的 browser SSRF 可达性强制检查。
|
||||
- 导航保护是独立的。`start` 或 `tabs` 成功,并不意味着后续的 `open` 或 `navigate` 目标一定被允许。
|
||||
|
||||
安全建议:
|
||||
|
||||
- 默认情况下**不要**放宽浏览器 SSRF 策略。
|
||||
- 优先使用精确的主机例外,例如 `hostnameAllowlist` 或 `allowedHostnames`,而不是宽泛地开放私有网络访问。
|
||||
- 仅在明确受信任、确实需要且已审核私有网络浏览器访问的环境中,才使用 `dangerouslyAllowPrivateNetwork: true`。
|
||||
- **不要**默认放宽 browser SSRF 策略。
|
||||
- 优先使用像 `hostnameAllowlist` 或 `allowedHostnames` 这样的窄范围主机例外,而不是广泛开放私有网络访问。
|
||||
- 仅在明确受信任、确实需要并已审查私有网络 browser 访问的环境中,才使用 `dangerouslyAllowPrivateNetwork: true`。
|
||||
|
||||
## 智能体工具 + 控制方式
|
||||
## 智能体工具 + 控制如何工作
|
||||
|
||||
智能体获得**一个工具**用于浏览器自动化:
|
||||
智能体会获得**一个工具**用于浏览器自动化:
|
||||
|
||||
- `browser` — doctor/status/start/stop/tabs/open/focus/close/snapshot/screenshot/navigate/act
|
||||
|
||||
映射关系如下:
|
||||
|
||||
- `browser snapshot` 返回稳定的 UI 树(AI 或 ARIA)。
|
||||
- `browser act` 使用 snapshot 的 `ref` ID 来执行点击/输入/拖动/选择。
|
||||
- `browser screenshot` 捕获像素内容(整页、元素或带标签的 refs)。
|
||||
- `browser doctor` 检查 Gateway 网关、插件、配置文件、浏览器和标签页的就绪状态。
|
||||
- `browser` 支持:
|
||||
- `profile` 用于选择命名浏览器配置文件(openclaw、chrome 或远程 CDP)。
|
||||
- `target`(`sandbox` | `host` | `node`)用于选择浏览器所在位置。
|
||||
- 在沙箱隔离会话中,`target: "host"` 需要 `agents.defaults.sandbox.browser.allowHostControl=true`。
|
||||
- 如果省略 `target`:沙箱隔离会话默认使用 `sandbox`,非沙箱会话默认使用 `host`。
|
||||
- 如果已连接支持浏览器的节点,工具可能会自动路由到它,除非你固定指定 `target="host"` 或 `target="node"`。
|
||||
- `browser snapshot` 返回一个稳定的 UI 树(AI 或 ARIA)。
|
||||
- `browser act` 使用 snapshot 的 `ref` ID 来执行 click/type/drag/select。
|
||||
- `browser screenshot` 捕获像素(整页、元素或带标签的 refs)。
|
||||
- `browser doctor` 检查 Gateway 网关、插件、profile、浏览器和标签页就绪状态。
|
||||
- `browser` 接受:
|
||||
- `profile`,用于选择命名浏览器 profile(openclaw、chrome 或远程 CDP)。
|
||||
- `target`(`sandbox` | `host` | `node`),用于选择浏览器所在位置。
|
||||
- 在沙箱会话中,`target: "host"` 需要 `agents.defaults.sandbox.browser.allowHostControl=true`。
|
||||
- 如果省略 `target`:沙箱会话默认是 `sandbox`,非沙箱会话默认是 `host`。
|
||||
- 如果已连接具备浏览器能力的节点,工具可能会自动路由到该节点,除非你显式固定 `target="host"` 或 `target="node"`。
|
||||
|
||||
这样可以让智能体行为保持确定性,并避免脆弱的选择器。
|
||||
这样可以让智能体保持确定性,并避免脆弱的选择器。
|
||||
|
||||
## 相关内容
|
||||
|
||||
- [工具概览](/zh-CN/tools) — 所有可用的智能体工具
|
||||
- [沙箱隔离](/zh-CN/gateway/sandboxing) — 沙箱隔离环境中的浏览器控制
|
||||
- [安全性](/zh-CN/gateway/security) — 浏览器控制的风险与加固
|
||||
- [沙箱隔离](/zh-CN/gateway/sandboxing) — 沙箱环境中的浏览器控制
|
||||
- [安全](/zh-CN/gateway/security) — 浏览器控制的风险与加固
|
||||
|
||||
@ -7,20 +7,24 @@ sidebarTitle: Install and Configure
|
||||
summary: 安装、配置和管理 OpenClaw 插件
|
||||
title: 插件
|
||||
x-i18n:
|
||||
generated_at: "2026-04-25T03:42:32Z"
|
||||
generated_at: "2026-04-25T05:57:05Z"
|
||||
model: gpt-5.4
|
||||
provider: openai
|
||||
source_hash: ec77f80d0f68dbb4d0ce7b53bdbce642bce933afe3f20bc1eb99eb1301f2461a
|
||||
source_hash: 54a902eabd90e54e769429770cd56e1d89a8bb50aff4b9ed8a9f68d6685b77a8
|
||||
source_path: tools/plugin.md
|
||||
workflow: 15
|
||||
---
|
||||
|
||||
插件通过新增能力来扩展 OpenClaw:渠道、模型提供商、Agent harnesses、工具、Skills、语音、实时转录、实时语音、媒体理解、图像生成、视频生成、网页抓取、网页搜索等。有些插件属于**核心**(随 OpenClaw 一起发布),另一些则是**外部**(由社区发布到 npm)。
|
||||
插件通过新增能力来扩展 OpenClaw:渠道、模型提供商、
|
||||
Agent harnesses、工具、Skills、语音、实时转写、实时
|
||||
语音、媒体理解、图像生成、视频生成、web 抓取、web
|
||||
搜索等等。有些插件是**核心**插件(随 OpenClaw 一起提供),另一些
|
||||
是**外部**插件(由社区发布到 npm)。
|
||||
|
||||
## 快速开始
|
||||
|
||||
<Steps>
|
||||
<Step title="查看已加载的内容">
|
||||
<Step title="查看已加载内容">
|
||||
```bash
|
||||
openclaw plugins list
|
||||
```
|
||||
@ -43,12 +47,12 @@ x-i18n:
|
||||
openclaw gateway restart
|
||||
```
|
||||
|
||||
然后在你的配置文件中通过 `plugins.entries.\<id\>.config` 进行配置。
|
||||
然后在你的配置文件中于 `plugins.entries.\<id\>.config` 下进行配置。
|
||||
|
||||
</Step>
|
||||
</Steps>
|
||||
|
||||
如果你更喜欢使用聊天原生控制方式,请启用 `commands.plugins: true` 并使用:
|
||||
如果你更喜欢原生聊天控制,请启用 `commands.plugins: true` 并使用:
|
||||
|
||||
```text
|
||||
/plugin install clawhub:@openclaw/voice-call
|
||||
@ -57,20 +61,19 @@ x-i18n:
|
||||
```
|
||||
|
||||
安装路径使用与 CLI 相同的解析器:本地路径/归档文件、显式
|
||||
`clawhub:<pkg>`,或裸包规范(优先 ClawHub,然后回退到 npm)。
|
||||
`clawhub:<pkg>`,或裸包规格(先 ClawHub,后 npm 回退)。
|
||||
|
||||
如果配置无效,安装通常会以失败关闭的方式结束,并提示你使用
|
||||
`openclaw doctor --fix`。唯一的恢复例外是一个针对选择加入
|
||||
`openclaw.install.allowInvalidConfigRecovery`
|
||||
的插件所提供的、范围很窄的内置插件重新安装路径。
|
||||
如果配置无效,安装通常会以封闭失败方式结束,并提示你使用
|
||||
`openclaw doctor --fix`。唯一的恢复例外是一个针对选择启用了
|
||||
`openclaw.install.allowInvalidConfigRecovery` 的插件的狭窄内置插件
|
||||
重装路径。
|
||||
|
||||
打包后的 OpenClaw 安装不会急切安装每个内置插件的
|
||||
运行时依赖树。当某个 OpenClaw 自有的内置插件因
|
||||
插件配置、旧版渠道配置或默认启用的清单而处于活动状态时,
|
||||
启动修复只会在导入它之前修复该插件声明的运行时依赖。
|
||||
显式禁用仍然优先:`plugins.entries.<id>.enabled: false`、
|
||||
打包版 OpenClaw 安装不会急切安装每个内置插件的
|
||||
运行时依赖树。当某个 OpenClaw 自有内置插件因为插件配置、
|
||||
旧版渠道配置或默认启用的清单而处于活动状态时,启动修复只会在导入它之前
|
||||
修复该插件声明的运行时依赖。显式禁用仍然优先:`plugins.entries.<id>.enabled: false`、
|
||||
`plugins.deny`、`plugins.enabled: false` 和 `channels.<id>.enabled: false`
|
||||
会阻止该插件/渠道自动执行内置运行时依赖修复。
|
||||
都会阻止该插件/渠道的自动内置运行时依赖修复。
|
||||
外部插件和自定义加载路径仍然必须通过
|
||||
`openclaw plugins install` 安装。
|
||||
|
||||
@ -78,56 +81,56 @@ x-i18n:
|
||||
|
||||
OpenClaw 可识别两种插件格式:
|
||||
|
||||
| 格式 | 工作方式 | 示例 |
|
||||
| ---------- | ------------------------------------------------------------------ | ------------------------------------------------------ |
|
||||
| **原生** | `openclaw.plugin.json` + 运行时模块;在进程内执行 | 官方插件、社区 npm 包 |
|
||||
| **Bundle** | 与 Codex/Claude/Cursor 兼容的布局;映射到 OpenClaw 功能 | `.codex-plugin/`、`.claude-plugin/`、`.cursor-plugin/` |
|
||||
| 格式 | 工作方式 | 示例 |
|
||||
| ---------- | ---------------------------------------------------------- | ------------------------------------------------------ |
|
||||
| **Native** | `openclaw.plugin.json` + 运行时模块;在进程内执行 | 官方插件、社区 npm 包 |
|
||||
| **Bundle** | 与 Codex/Claude/Cursor 兼容的布局;映射为 OpenClaw 功能 | `.codex-plugin/`、`.claude-plugin/`、`.cursor-plugin/` |
|
||||
|
||||
这两种格式都会显示在 `openclaw plugins list` 中。有关 bundle 详情,请参阅 [插件包](/zh-CN/plugins/bundles)。
|
||||
两者都会显示在 `openclaw plugins list` 中。有关 bundle 详情,请参见 [Plugin Bundles](/zh-CN/plugins/bundles)。
|
||||
|
||||
如果你正在编写原生插件,请从 [构建插件](/zh-CN/plugins/building-plugins)
|
||||
如果你要编写 Native 插件,请从 [构建插件](/zh-CN/plugins/building-plugins)
|
||||
和 [插件 SDK 概览](/zh-CN/plugins/sdk-overview) 开始。
|
||||
|
||||
## 官方插件
|
||||
|
||||
### 可安装(npm)
|
||||
|
||||
| 插件 | 包名 | 文档 |
|
||||
| 插件 | 包 | 文档 |
|
||||
| --------------- | ---------------------- | ------------------------------------ |
|
||||
| Matrix | `@openclaw/matrix` | [Matrix](/zh-CN/channels/matrix) |
|
||||
| Microsoft Teams | `@openclaw/msteams` | [Microsoft Teams](/zh-CN/channels/msteams) |
|
||||
| Nostr | `@openclaw/nostr` | [Nostr](/zh-CN/channels/nostr) |
|
||||
| Voice Call | `@openclaw/voice-call` | [Voice Call](/zh-CN/plugins/voice-call) |
|
||||
| Zalo | `@openclaw/zalo` | [Zalo](/zh-CN/channels/zalo) |
|
||||
| Zalo Personal | `@openclaw/zalouser` | [Zalo Personal](/zh-CN/plugins/zalouser) |
|
||||
| Matrix | `@openclaw/matrix` | [Matrix](/zh-CN/channels/matrix) |
|
||||
| Microsoft Teams | `@openclaw/msteams` | [Microsoft Teams](/zh-CN/channels/msteams) |
|
||||
| Nostr | `@openclaw/nostr` | [Nostr](/zh-CN/channels/nostr) |
|
||||
| Voice Call | `@openclaw/voice-call` | [Voice Call](/zh-CN/plugins/voice-call) |
|
||||
| Zalo | `@openclaw/zalo` | [Zalo](/zh-CN/channels/zalo) |
|
||||
| Zalo Personal | `@openclaw/zalouser` | [Zalo Personal](/zh-CN/plugins/zalouser) |
|
||||
|
||||
### 核心(随 OpenClaw 一起发布)
|
||||
### 核心(随 OpenClaw 一起提供)
|
||||
|
||||
<AccordionGroup>
|
||||
<Accordion title="模型提供商(默认启用)">
|
||||
`anthropic`, `byteplus`, `cloudflare-ai-gateway`, `github-copilot`, `google`,
|
||||
`huggingface`, `kilocode`, `kimi-coding`, `minimax`, `mistral`, `qwen`,
|
||||
`moonshot`, `nvidia`, `openai`, `opencode`, `opencode-go`, `openrouter`,
|
||||
`qianfan`, `synthetic`, `together`, `venice`,
|
||||
`vercel-ai-gateway`, `volcengine`, `xiaomi`, `zai`
|
||||
`anthropic`、`byteplus`、`cloudflare-ai-gateway`、`github-copilot`、`google`、
|
||||
`huggingface`、`kilocode`、`kimi-coding`、`minimax`、`mistral`、`qwen`、
|
||||
`moonshot`、`nvidia`、`openai`、`opencode`、`opencode-go`、`openrouter`、
|
||||
`qianfan`、`synthetic`、`together`、`venice`、
|
||||
`vercel-ai-gateway`、`volcengine`、`xiaomi`、`zai`
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="Memory 插件">
|
||||
- `memory-core` — 内置内存搜索(通过 `plugins.slots.memory` 默认启用)
|
||||
- `memory-lancedb` — 按需安装的长期记忆,带自动召回/捕获(设置 `plugins.slots.memory = "memory-lancedb"`)
|
||||
- `memory-core` — 内置 memory 搜索(通过 `plugins.slots.memory` 默认启用)
|
||||
- `memory-lancedb` — 按需安装的长期 memory,带自动 recall/capture(设置 `plugins.slots.memory = "memory-lancedb"`)
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="语音提供商(默认启用)">
|
||||
`elevenlabs`, `microsoft`
|
||||
`elevenlabs`、`microsoft`
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="其他">
|
||||
- `browser` — 用于浏览器工具、`openclaw browser` CLI、`browser.request` Gateway 网关方法、浏览器运行时以及默认浏览器控制服务的内置浏览器插件(默认启用;替换前请先禁用)
|
||||
- `copilot-proxy` — VS Code Copilot Proxy 桥接器(默认禁用)
|
||||
- `browser` — browser 工具、`openclaw browser` CLI、`browser.request` gateway 方法、browser 运行时以及默认 browser 控制服务的内置 browser 插件(默认启用;替换前请先禁用)
|
||||
- `copilot-proxy` — VS Code Copilot Proxy bridge(默认禁用)
|
||||
</Accordion>
|
||||
</AccordionGroup>
|
||||
|
||||
在寻找第三方插件?请参阅 [社区插件](/zh-CN/plugins/community)。
|
||||
在找第三方插件?请参见 [社区插件](/zh-CN/plugins/community)。
|
||||
|
||||
## 配置
|
||||
|
||||
@ -145,36 +148,35 @@ OpenClaw 可识别两种插件格式:
|
||||
}
|
||||
```
|
||||
|
||||
| 字段 | 描述 |
|
||||
| ---------------- | --------------------------------------------------------- |
|
||||
| `enabled` | 主开关(默认:`true`) |
|
||||
| `allow` | 插件允许列表(可选) |
|
||||
| `deny` | 插件拒绝列表(可选;拒绝优先) |
|
||||
| `load.paths` | 额外的插件文件/目录 |
|
||||
| `slots` | 独占槽位选择器(例如 `memory`、`contextEngine`) |
|
||||
| `entries.\<id\>` | 每个插件的开关 + 配置 |
|
||||
| 字段 | 描述 |
|
||||
| ---------------- | -------------------------------------------------- |
|
||||
| `enabled` | 主开关(默认:`true`) |
|
||||
| `allow` | 插件允许名单(可选) |
|
||||
| `deny` | 插件拒绝名单(可选;拒绝优先) |
|
||||
| `load.paths` | 额外的插件文件/目录 |
|
||||
| `slots` | 独占插槽选择器(例如 `memory`、`contextEngine`) |
|
||||
| `entries.\<id\>` | 每个插件的开关 + 配置 |
|
||||
|
||||
配置更改**需要重启 Gateway 网关**。如果 Gateway 网关以启用配置
|
||||
watch + 进程内重启的方式运行(默认的 `openclaw gateway` 路径),
|
||||
那么在配置写入完成后,通常会在稍后自动执行该重启。
|
||||
对于原生插件运行时代码或生命周期钩子,不存在受支持的热重载路径;
|
||||
在期望更新后的 `register(api)` 代码、`api.on(...)` 钩子、工具、服务或
|
||||
提供商/运行时钩子生效之前,请重启为实时渠道提供服务的 Gateway 网关进程。
|
||||
配置更改**需要重启网关**。如果 Gateway 网关以配置监视 + 进程内重启启用方式运行(默认的 `openclaw gateway` 路径),该
|
||||
重启通常会在配置写入完成后不久自动执行。
|
||||
对于 Native 插件运行时代码或生命周期
|
||||
钩子,没有受支持的热重载路径;请重启正在为实时渠道提供服务的 Gateway 网关进程,然后再期待更新后的 `register(api)` 代码、`api.on(...)` 钩子、工具、服务或
|
||||
provider/运行时钩子生效。
|
||||
|
||||
`openclaw plugins list` 是本地 CLI/配置快照。其中显示某个插件为
|
||||
`loaded`,表示该插件可从该次 CLI 调用所见的配置/文件中被发现并加载。
|
||||
这并不能证明一个已经在运行的远程 Gateway 网关子进程
|
||||
已经重启并进入相同的插件代码。在使用包装进程的 VPS/容器环境中,
|
||||
请向实际的 `openclaw gateway run` 进程发送重启,或
|
||||
对正在运行的 Gateway 网关使用 `openclaw gateway restart`。
|
||||
`openclaw plugins list` 是本地 CLI/配置快照。其中某个插件显示为
|
||||
`loaded`,意味着从该次 CLI 调用所见的配置/文件来看,该插件是可发现且可加载的。
|
||||
这并不能证明一个已经运行中的远程 Gateway 网关子进程
|
||||
已经重启并加载到了相同的插件代码。在 VPS/容器设置中,请将重启信号发送给实际的
|
||||
`openclaw gateway run` 进程,或对正在运行的 Gateway 网关使用
|
||||
`openclaw gateway restart`。
|
||||
|
||||
<Accordion title="插件状态:disabled 与 missing 与 invalid">
|
||||
<Accordion title="插件状态:disabled vs missing vs invalid">
|
||||
- **Disabled**:插件存在,但启用规则将其关闭。配置会被保留。
|
||||
- **Missing**:配置引用了某个插件 id,但设备发现未找到该插件。
|
||||
- **Invalid**:插件存在,但其配置与声明的 schema 不匹配。
|
||||
- **Missing**:配置引用了一个插件 id,但设备发现未找到该插件。
|
||||
- **Invalid**:插件存在,但其配置不匹配已声明的 schema。
|
||||
</Accordion>
|
||||
|
||||
## 设备发现和优先级
|
||||
## 发现和优先级
|
||||
|
||||
OpenClaw 按以下顺序扫描插件(先匹配者优先):
|
||||
|
||||
@ -192,50 +194,47 @@ OpenClaw 按以下顺序扫描插件(先匹配者优先):
|
||||
</Step>
|
||||
|
||||
<Step title="内置插件">
|
||||
随 OpenClaw 一起发布。许多插件默认启用(模型提供商、语音)。
|
||||
其他插件则需要显式启用。
|
||||
随 OpenClaw 一起提供。许多默认启用(模型提供商、语音)。
|
||||
其他则需要显式启用。
|
||||
</Step>
|
||||
</Steps>
|
||||
|
||||
### 启用规则
|
||||
|
||||
- `plugins.enabled: false` 会禁用所有插件
|
||||
- `plugins.deny` 总是优先于 allow
|
||||
- `plugins.deny` 始终优先于 allow
|
||||
- `plugins.entries.\<id\>.enabled: false` 会禁用该插件
|
||||
- 来自工作区的插件**默认禁用**(必须显式启用)
|
||||
- 工作区来源的插件**默认禁用**(必须显式启用)
|
||||
- 内置插件遵循内建的默认启用集合,除非被覆盖
|
||||
- 独占槽位可以为该槽位强制启用所选插件
|
||||
- 独占插槽可以强制启用为该插槽选中的插件
|
||||
- 某些内置的选择加入型插件会在配置命名了
|
||||
某个插件拥有的表面时自动启用,例如提供商模型引用、渠道配置或 harness
|
||||
插件自有 surface 时自动启用,例如 provider 模型引用、渠道配置或 harness
|
||||
运行时
|
||||
- OpenAI 系列的 Codex 路由保持独立的插件边界:
|
||||
`openai-codex/*` 属于 OpenAI 插件,而内置的 Codex
|
||||
- OpenAI 系列 Codex 路由保持独立插件边界:
|
||||
`openai-codex/*` 属于 OpenAI 插件,而内置 Codex
|
||||
app-server 插件则通过 `embeddedHarness.runtime: "codex"` 或旧版
|
||||
`codex/*` 模型引用来选择
|
||||
|
||||
## 运行时钩子故障排除
|
||||
|
||||
如果某个插件出现在 `plugins list` 中,但 `register(api)` 的副作用
|
||||
或钩子没有在实时聊天流量中运行,请先检查以下内容:
|
||||
如果某个插件出现在 `plugins list` 中,但 `register(api)` 副作用或钩子
|
||||
在实时聊天流量中没有运行,请先检查以下内容:
|
||||
|
||||
- 运行 `openclaw gateway status --deep --require-rpc`,并确认活动的
|
||||
Gateway 网关 URL、配置文件、配置路径和进程
|
||||
就是你正在编辑的那一组。
|
||||
- 在插件安装/配置/代码变更后重启正在运行的 Gateway 网关。在包装器
|
||||
容器中,PID 1 可能只是一个 supervisor;请重启或向子进程
|
||||
`openclaw gateway run` 发送信号。
|
||||
- 运行 `openclaw gateway status --deep --require-rpc` 并确认活动中的
|
||||
Gateway 网关 URL、profile、配置路径和进程就是你正在编辑的那些。
|
||||
- 在插件安装/配置/代码更改后重启实时 Gateway 网关。在包装器
|
||||
容器中,PID 1 可能只是一个 supervisor;请重启或向子
|
||||
`openclaw gateway run` 进程发送信号。
|
||||
- 使用 `openclaw plugins inspect <id> --json` 确认钩子注册和
|
||||
诊断信息。像 `llm_input`、
|
||||
`llm_output` 和 `agent_end` 这样的非内置会话钩子
|
||||
需要
|
||||
诊断信息。非内置的对话钩子,例如 `llm_input`、
|
||||
`llm_output` 和 `agent_end`,需要设置
|
||||
`plugins.entries.<id>.hooks.allowConversationAccess=true`。
|
||||
- 对于模型切换,优先使用 `before_model_resolve`。它会在智能体轮次的
|
||||
模型解析之前运行;`llm_output` 只会在某次模型尝试产生 assistant 输出之后运行。
|
||||
- 若要证明会话中实际生效的模型,请使用 `openclaw sessions` 或
|
||||
Gateway 网关的会话/状态表面;调试提供商负载时,
|
||||
请使用 `--raw-stream --raw-stream-path <path>` 启动 Gateway 网关。
|
||||
- 对于模型切换,优先使用 `before_model_resolve`。它会在智能体轮次的模型解析之前运行;`llm_output` 只有在某次模型尝试产生助手输出后才会运行。
|
||||
- 如需证明会话的实际模型,请使用 `openclaw sessions` 或
|
||||
Gateway 网关会话/Status surface;在调试 provider 负载时,请使用
|
||||
`--raw-stream --raw-stream-path <path>` 启动 Gateway 网关。
|
||||
|
||||
## 插件槽位(独占类别)
|
||||
## 插件插槽(独占类别)
|
||||
|
||||
某些类别是独占的(同一时间只能有一个处于活动状态):
|
||||
|
||||
@ -250,29 +249,29 @@ OpenClaw 按以下顺序扫描插件(先匹配者优先):
|
||||
}
|
||||
```
|
||||
|
||||
| 槽位 | 控制内容 | 默认值 |
|
||||
| --------------- | --------------------- | ------------------- |
|
||||
| `memory` | 活动的内存插件 | `memory-core` |
|
||||
| `contextEngine` | 活动的上下文引擎 | `legacy`(内置) |
|
||||
| 插槽 | 控制内容 | 默认值 |
|
||||
| ---------------- | ---------------------- | ------------------- |
|
||||
| `memory` | 活动中的 memory 插件 | `memory-core` |
|
||||
| `contextEngine` | 活动中的上下文引擎 | `legacy`(内置) |
|
||||
|
||||
## CLI 参考
|
||||
|
||||
```bash
|
||||
openclaw plugins list # 精简清单
|
||||
openclaw plugins list --enabled # 仅显示已加载的插件
|
||||
openclaw plugins list --verbose # 每个插件的详细信息行
|
||||
openclaw plugins list --json # 机器可读的清单
|
||||
openclaw plugins list # 紧凑清单
|
||||
openclaw plugins list --enabled # 仅显示已加载插件
|
||||
openclaw plugins list --verbose # 每个插件的详细行
|
||||
openclaw plugins list --json # 机器可读清单
|
||||
openclaw plugins inspect <id> # 深度详情
|
||||
openclaw plugins inspect <id> --json # 机器可读格式
|
||||
openclaw plugins inspect <id> --json # 机器可读
|
||||
openclaw plugins inspect --all # 全局表格
|
||||
openclaw plugins info <id> # inspect 的别名
|
||||
openclaw plugins info <id> # inspect 别名
|
||||
openclaw plugins doctor # 诊断
|
||||
|
||||
openclaw plugins install <package> # 安装(优先 ClawHub,然后 npm)
|
||||
openclaw plugins install <package> # 安装(先 ClawHub,后 npm)
|
||||
openclaw plugins install clawhub:<pkg> # 仅从 ClawHub 安装
|
||||
openclaw plugins install <spec> --force # 原地覆盖现有安装
|
||||
openclaw plugins install <spec> --force # 覆盖现有安装
|
||||
openclaw plugins install <path> # 从本地路径安装
|
||||
openclaw plugins install -l <path> # 链接(不复制),用于开发
|
||||
openclaw plugins install -l <path> # link(不复制),用于开发
|
||||
openclaw plugins install <plugin> --marketplace <source>
|
||||
openclaw plugins install <plugin> --marketplace https://github.com/<owner>/<repo>
|
||||
openclaw plugins install <spec> --pin # 记录精确解析后的 npm spec
|
||||
@ -289,61 +288,61 @@ openclaw plugins enable <id>
|
||||
openclaw plugins disable <id>
|
||||
```
|
||||
|
||||
内置插件随 OpenClaw 一起发布。许多插件默认启用(例如
|
||||
内置模型提供商、内置语音提供商以及内置浏览器
|
||||
插件)。其他内置插件仍然需要执行 `openclaw plugins enable <id>`。
|
||||
内置插件随 OpenClaw 一起提供。许多默认启用(例如
|
||||
内置模型提供商、内置语音提供商,以及内置 browser
|
||||
插件)。其他内置插件仍然需要 `openclaw plugins enable <id>`。
|
||||
|
||||
`--force` 会原地覆盖已安装的插件或 hook 包。对于受跟踪 npm
|
||||
`--force` 会原地覆盖现有已安装插件或 hook pack。对于已跟踪的 npm
|
||||
插件的常规升级,请使用 `openclaw plugins update <id-or-npm-spec>`。
|
||||
它不支持与 `--link` 一起使用,因为后者会复用源路径,
|
||||
而不是复制到受管理的安装目标中。
|
||||
|
||||
当已经设置了 `plugins.allow` 时,`openclaw plugins install` 会在启用插件之前
|
||||
将已安装插件的 id 添加到该 allowlist 中,因此重启后安装内容
|
||||
可以立即被加载。
|
||||
当已经设置了 `plugins.allow` 时,`openclaw plugins install` 会先将
|
||||
已安装插件 id 添加到该允许名单中,然后再启用它,这样插件在重启后
|
||||
即可立即加载。
|
||||
|
||||
`openclaw plugins update <id-or-npm-spec>` 适用于受跟踪的安装。
|
||||
传入带有 dist-tag 或精确版本的 npm 包 spec 时,会将包名解析回
|
||||
受跟踪的插件记录,并记录新的 spec 以供后续更新使用。
|
||||
传入不带版本的包名时,会将精确 pin 的安装切回到
|
||||
注册表的默认发布线。如果已安装的 npm 插件已经与
|
||||
解析出的版本和记录的制品标识一致,OpenClaw 会跳过这次更新,
|
||||
不会下载、重新安装或重写配置。
|
||||
`openclaw plugins update <id-or-npm-spec>` 适用于已跟踪安装。传入
|
||||
带 dist-tag 或精确版本的 npm 包 spec 时,会将包名解析回
|
||||
已跟踪的插件记录,并记录新的 spec 以供后续更新。
|
||||
传入不带版本的包名时,会将一个精确固定版本的安装切回
|
||||
注册表的默认发布线。如果已安装的 npm 插件已经匹配
|
||||
解析后的版本和记录的工件身份,OpenClaw 会跳过更新,不会下载、
|
||||
重新安装或重写配置。
|
||||
|
||||
`--pin` 仅适用于 npm。它不支持与 `--marketplace` 一起使用,因为
|
||||
marketplace 安装会持久化 marketplace 来源元数据,而不是 npm spec。
|
||||
marketplace 安装会持久化 marketplace 源元数据,而不是 npm spec。
|
||||
|
||||
`--dangerously-force-unsafe-install` 是一种紧急覆盖开关,用于处理内置危险代码扫描器产生的误报。
|
||||
它允许插件安装和插件更新在遇到内置 `critical` 发现后继续进行,但
|
||||
仍然不会绕过插件 `before_install` 策略阻止或扫描失败阻止。
|
||||
`--dangerously-force-unsafe-install` 是用于处理内置危险代码扫描器
|
||||
误报的紧急覆盖开关。它允许插件安装
|
||||
和插件更新在遇到内置 `critical` 发现后继续执行,但仍然
|
||||
不会绕过插件 `before_install` 策略阻止或扫描失败阻止。
|
||||
|
||||
此 CLI 标志仅适用于插件安装/更新流程。由 Gateway 网关支持的 Skills
|
||||
依赖安装则使用对应的 `dangerouslyForceUnsafeInstall` 请求覆盖字段,
|
||||
而 `openclaw skills install` 仍然是独立的 ClawHub
|
||||
Skills 下载/安装流程。
|
||||
这个 CLI 标志仅适用于插件安装/更新流程。Gateway 网关支持的 Skills
|
||||
依赖安装则使用匹配的 `dangerouslyForceUnsafeInstall` 请求覆盖,
|
||||
而 `openclaw skills install` 仍然是单独的 ClawHub Skills 下载/安装流程。
|
||||
|
||||
兼容的 bundle 会参与相同的插件 list/inspect/enable/disable
|
||||
流程。当前运行时支持包括 bundle Skills、Claude command-skills、
|
||||
兼容的 bundle 也参与相同的插件 list/inspect/enable/disable 流程。
|
||||
当前运行时支持包括 bundle Skills、Claude command-Skills、
|
||||
Claude `settings.json` 默认值、Claude `.lsp.json` 和清单声明的
|
||||
`lspServers` 默认值、Cursor command-skills,以及兼容的 Codex hook
|
||||
`lspServers` 默认值、Cursor command-Skills,以及兼容的 Codex hook
|
||||
目录。
|
||||
|
||||
`openclaw plugins inspect <id>` 还会报告检测到的 bundle 功能,以及
|
||||
由 bundle 支持插件提供的受支持或不受支持的 MCP 和 LSP server 条目。
|
||||
`openclaw plugins inspect <id>` 还会报告已检测到的 bundle 能力,以及
|
||||
由 bundle 支持的插件中的受支持或不受支持的 MCP 和 LSP server 条目。
|
||||
|
||||
Marketplace 来源可以是来自
|
||||
`~/.claude/plugins/known_marketplaces.json` 的 Claude 已知 marketplace 名称、
|
||||
本地 marketplace 根目录或 `marketplace.json` 路径、类似 `owner/repo` 的
|
||||
GitHub 简写、GitHub 仓库 URL,或 git URL。对于远程 marketplaces,
|
||||
插件条目必须保持在克隆后的 marketplace 仓库内部,并且只能使用相对路径来源。
|
||||
Marketplace 源可以是来自
|
||||
`~/.claude/plugins/known_marketplaces.json` 的 Claude 已知 marketplace 名称、本地 marketplace 根目录或
|
||||
`marketplace.json` 路径、像 `owner/repo` 这样的 GitHub 简写、GitHub 仓库
|
||||
URL,或 git URL。对于远程 marketplaces,插件条目必须保持在
|
||||
克隆的 marketplace 仓库内部,并且只能使用相对路径源。
|
||||
|
||||
完整详情请参阅 [`openclaw plugins` CLI 参考](/zh-CN/cli/plugins)。
|
||||
完整详情请参见 [`openclaw plugins` CLI 参考](/zh-CN/cli/plugins)。
|
||||
|
||||
## 插件 API 概览
|
||||
|
||||
原生插件会导出一个暴露 `register(api)` 的入口对象。较旧的
|
||||
插件仍可能使用 `activate(api)` 作为旧版别名,但新插件应使用
|
||||
`register`。
|
||||
Native 插件会导出一个暴露 `register(api)` 的入口对象。较旧的
|
||||
插件仍可能使用 `activate(api)` 作为旧版别名,但新插件应当
|
||||
使用 `register`。
|
||||
|
||||
```typescript
|
||||
export default definePluginEntry({
|
||||
@ -363,72 +362,72 @@ export default definePluginEntry({
|
||||
});
|
||||
```
|
||||
|
||||
OpenClaw 会加载入口对象,并在插件激活期间调用 `register(api)`。
|
||||
对于较旧的插件,加载器仍会回退到 `activate(api)`,
|
||||
但内置插件和新的外部插件应将 `register` 视为公开契约。
|
||||
OpenClaw 会加载该入口对象,并在插件
|
||||
激活期间调用 `register(api)`。加载器仍会为旧插件回退到 `activate(api)`,
|
||||
但内置插件和新的外部插件应将 `register` 视为
|
||||
公开契约。
|
||||
|
||||
`api.registrationMode` 会告诉插件其入口被加载的原因:
|
||||
`api.registrationMode` 会告诉插件其入口为何被加载:
|
||||
|
||||
| 模式 | 含义 |
|
||||
| 模式 | 含义 |
|
||||
| --------------- | -------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `full` | 运行时激活。注册工具、钩子、服务、命令、路由及其他实时副作用。 |
|
||||
| `discovery` | 只读能力发现。注册提供商和元数据;可信插件入口代码可能会被加载,但应跳过实时副作用。 |
|
||||
| `setup-only` | 通过轻量级设置入口加载渠道设置元数据。 |
|
||||
| `setup-runtime` | 需要运行时入口的渠道设置加载。 |
|
||||
| `cli-metadata` | 仅收集 CLI 命令元数据。 |
|
||||
| `full` | 运行时激活。注册工具、钩子、服务、命令、路由及其他实时副作用。 |
|
||||
| `discovery` | 只读能力发现。注册提供商和元数据;可信插件入口代码可能会被加载,但要跳过实时副作用。 |
|
||||
| `setup-only` | 通过轻量级设置入口加载渠道设置元数据。 |
|
||||
| `setup-runtime` | 加载渠道设置,同时也需要运行时入口。 |
|
||||
| `cli-metadata` | 仅收集 CLI 命令元数据。 |
|
||||
|
||||
会打开 socket、数据库、后台 worker 或长生命周期
|
||||
客户端的插件入口,应使用 `api.registrationMode === "full"` 来保护这些副作用。
|
||||
设备发现加载会与激活加载分开缓存,并且不会替代正在运行的 Gateway 网关注册表。
|
||||
设备发现是非激活式的,而不是免导入的:
|
||||
OpenClaw 可能会对可信插件入口或渠道插件模块求值,以构建
|
||||
快照。请保持模块顶层轻量且无副作用,并将网络客户端、
|
||||
子进程、监听器、凭证读取和服务启动移动到完整运行时路径之后。
|
||||
那些会打开 socket、数据库、后台 worker 或长生命周期
|
||||
客户端的插件入口,应当使用 `api.registrationMode === "full"` 保护这些副作用。
|
||||
设备发现加载会与激活加载分开缓存,并且不会替换正在运行的 Gateway 网关注册表。
|
||||
设备发现是非激活的,而不是免导入的:OpenClaw 可能会执行可信的插件入口或渠道插件模块以构建
|
||||
快照。请保持模块顶层轻量且无副作用,并将
|
||||
网络客户端、子进程、监听器、凭证读取和服务启动移动到完整运行时路径之后。
|
||||
|
||||
常见注册方法:
|
||||
|
||||
| 方法 | 注册内容 |
|
||||
| --------------------------------------- | --------------------------- |
|
||||
| `registerProvider` | 模型提供商(LLM) |
|
||||
| `registerChannel` | 聊天渠道 |
|
||||
| `registerTool` | 智能体工具 |
|
||||
| `registerHook` / `on(...)` | 生命周期钩子 |
|
||||
| `registerSpeechProvider` | 文本转语音 / STT |
|
||||
| `registerRealtimeTranscriptionProvider` | 流式 STT |
|
||||
| `registerRealtimeVoiceProvider` | 双工实时语音 |
|
||||
| `registerMediaUnderstandingProvider` | 图像/音频分析 |
|
||||
| `registerImageGenerationProvider` | 图像生成 |
|
||||
| `registerMusicGenerationProvider` | 音乐生成 |
|
||||
| `registerVideoGenerationProvider` | 视频生成 |
|
||||
| `registerWebFetchProvider` | 网页抓取 / 抓取提供商 |
|
||||
| `registerWebSearchProvider` | 网页搜索 |
|
||||
| `registerHttpRoute` | HTTP 端点 |
|
||||
| `registerCommand` / `registerCli` | CLI 命令 |
|
||||
| `registerContextEngine` | 上下文引擎 |
|
||||
| `registerService` | 后台服务 |
|
||||
| 方法 | 注册内容 |
|
||||
| ------------------------------------- | --------------------------- |
|
||||
| `registerProvider` | 模型提供商(LLM) |
|
||||
| `registerChannel` | 聊天渠道 |
|
||||
| `registerTool` | 智能体工具 |
|
||||
| `registerHook` / `on(...)` | 生命周期钩子 |
|
||||
| `registerSpeechProvider` | 文本转语音 / STT |
|
||||
| `registerRealtimeTranscriptionProvider` | 实时分块流式 STT |
|
||||
| `registerRealtimeVoiceProvider` | 双工实时语音 |
|
||||
| `registerMediaUnderstandingProvider` | 图像/音频分析 |
|
||||
| `registerImageGenerationProvider` | 图像生成 |
|
||||
| `registerMusicGenerationProvider` | 音乐生成 |
|
||||
| `registerVideoGenerationProvider` | 视频生成 |
|
||||
| `registerWebFetchProvider` | Web 抓取 / 抓取提供商 |
|
||||
| `registerWebSearchProvider` | Web 搜索 |
|
||||
| `registerHttpRoute` | HTTP 端点 |
|
||||
| `registerCommand` / `registerCli` | CLI 命令 |
|
||||
| `registerContextEngine` | 上下文引擎 |
|
||||
| `registerService` | 后台服务 |
|
||||
|
||||
类型化生命周期钩子的钩子守卫行为:
|
||||
带类型生命周期钩子的守卫行为:
|
||||
|
||||
- `before_tool_call`:`{ block: true }` 是终止性的;较低优先级的处理器会被跳过。
|
||||
- `before_tool_call`:`{ block: false }` 是无操作,不会清除更早的阻止。
|
||||
- `before_install`:`{ block: true }` 是终止性的;较低优先级的处理器会被跳过。
|
||||
- `before_install`:`{ block: false }` 是无操作,不会清除更早的阻止。
|
||||
- `message_sending`:`{ cancel: true }` 是终止性的;较低优先级的处理器会被跳过。
|
||||
- `message_sending`:`{ cancel: false }` 是无操作,不会清除更早的取消。
|
||||
- `before_tool_call`:`{ block: true }` 是终止性的;会跳过更低优先级的处理器。
|
||||
- `before_tool_call`:`{ block: false }` 是空操作,不会清除先前的阻止。
|
||||
- `before_install`:`{ block: true }` 是终止性的;会跳过更低优先级的处理器。
|
||||
- `before_install`:`{ block: false }` 是空操作,不会清除先前的阻止。
|
||||
- `message_sending`:`{ cancel: true }` 是终止性的;会跳过更低优先级的处理器。
|
||||
- `message_sending`:`{ cancel: false }` 是空操作,不会清除先前的取消。
|
||||
|
||||
原生 Codex app-server 会将桥接的 Codex 原生工具事件回传到这个
|
||||
钩子表面。插件可以通过 `before_tool_call` 阻止原生 Codex 工具,
|
||||
Native Codex app-server 运行时会将桥接的 Codex 原生工具事件回传到这个
|
||||
钩子 surface。插件可以通过 `before_tool_call` 阻止原生 Codex 工具,
|
||||
通过 `after_tool_call` 观察结果,并参与 Codex
|
||||
`PermissionRequest` 批准。该桥接目前尚不会重写 Codex 原生工具
|
||||
参数。Codex 运行时支持边界的精确范围位于
|
||||
`PermissionRequest` 批准。该桥目前还不会重写 Codex 原生工具
|
||||
参数。精确的 Codex 运行时支持边界位于
|
||||
[Codex harness v1 支持契约](/zh-CN/plugins/codex-harness#v1-support-contract)。
|
||||
|
||||
有关完整的类型化钩子行为,请参阅 [SDK 概览](/zh-CN/plugins/sdk-overview#hook-decision-semantics)。
|
||||
有关完整的带类型钩子行为,请参见 [SDK 概览](/zh-CN/plugins/sdk-overview#hook-decision-semantics)。
|
||||
|
||||
## 相关内容
|
||||
|
||||
- [构建插件](/zh-CN/plugins/building-plugins) — 创建你自己的插件
|
||||
- [插件包](/zh-CN/plugins/bundles) — Codex/Claude/Cursor bundle 兼容性
|
||||
- [Plugin Bundles](/zh-CN/plugins/bundles) — 与 Codex/Claude/Cursor 的 bundle 兼容性
|
||||
- [插件清单](/zh-CN/plugins/manifest) — 清单 schema
|
||||
- [注册工具](/zh-CN/plugins/building-plugins#registering-agent-tools) — 在插件中添加智能体工具
|
||||
- [插件内部机制](/zh-CN/plugins/architecture) — 能力模型和加载流水线
|
||||
|
||||
@ -1,24 +1,24 @@
|
||||
---
|
||||
read_when:
|
||||
- 你希望通过智能体进行后台/并行工作
|
||||
- 你想通过智能体执行后台 / 并行工作
|
||||
- 你正在更改 `sessions_spawn` 或子智能体工具策略
|
||||
- 你正在实现或排查线程绑定的子智能体会话
|
||||
summary: 子智能体:生成独立的智能体运行,并将结果回报给请求者聊天界面
|
||||
- 你正在实现或排查绑定到线程的子智能体会话
|
||||
summary: 子智能体:启动隔离的智能体运行,并将结果通知回请求者聊天中
|
||||
title: 子智能体
|
||||
x-i18n:
|
||||
generated_at: "2026-04-25T04:42:23Z"
|
||||
generated_at: "2026-04-25T05:57:09Z"
|
||||
model: gpt-5.4
|
||||
provider: openai
|
||||
source_hash: 2e73ae032cb4de08a69069db6384280582b7eec27c033075d8124c97aa9b2447
|
||||
source_hash: b262edf46b9c823dcf0ad6514e560d2d1a718e9081015ea8bb5c081206b88fce
|
||||
source_path: tools/subagents.md
|
||||
workflow: 15
|
||||
---
|
||||
|
||||
子智能体是从现有智能体运行中生成的后台智能体运行。它们在各自独立的会话中运行(`agent:<agentId>:subagent:<uuid>`),并在完成时,将其结果**通报**回请求者聊天渠道。每个子智能体运行都会作为一个[后台任务](/zh-CN/automation/tasks)进行跟踪。
|
||||
子智能体是在现有智能体运行中启动的后台智能体运行。它们在自己的会话中运行(`agent:<agentId>:subagent:<uuid>`),并在完成时将结果**通知**回请求者聊天渠道。每次子智能体运行都会作为一个[后台任务](/zh-CN/automation/tasks)进行跟踪。
|
||||
|
||||
## 斜杠命令
|
||||
## Slash 命令
|
||||
|
||||
使用 `/subagents` 来检查或控制**当前会话**的子智能体运行:
|
||||
使用 `/subagents` 可检查或控制**当前会话**的子智能体运行:
|
||||
|
||||
- `/subagents list`
|
||||
- `/subagents kill <id|#|all>`
|
||||
@ -30,7 +30,7 @@ x-i18n:
|
||||
|
||||
线程绑定控制:
|
||||
|
||||
这些命令适用于支持持久线程绑定的渠道。请参见下面的**支持线程的渠道**。
|
||||
这些命令适用于支持持久线程绑定的渠道。请参阅下方的**支持线程的渠道**。
|
||||
|
||||
- `/focus <subagent-label|session-key|session-id|session-label>`
|
||||
- `/unfocus`
|
||||
@ -38,139 +38,140 @@ x-i18n:
|
||||
- `/session idle <duration|off>`
|
||||
- `/session max-age <duration|off>`
|
||||
|
||||
`/subagents info` 会显示运行元数据(状态、时间戳、会话 id、转录路径、清理情况)。
|
||||
使用 `sessions_history` 获取一个有边界且经过安全过滤的回顾视图;当你需要原始完整转录时,请检查磁盘上的转录路径。
|
||||
`/subagents info` 会显示运行元数据(状态、时间戳、会话 id、转录路径、清理信息)。
|
||||
使用 `sessions_history` 可查看有界且经过安全过滤的回忆视图;当你需要原始完整转录时,请检查磁盘上的转录路径。
|
||||
|
||||
### 生成行为
|
||||
### 启动行为
|
||||
|
||||
`/subagents spawn` 作为用户命令启动一个后台子智能体,而不是内部中继;当运行完成时,它会向请求者聊天发送一条最终完成更新。
|
||||
`/subagents spawn` 会以用户命令而非内部中继的形式启动一个后台子智能体,并在运行完成时向请求者聊天发送一条最终完成更新。
|
||||
|
||||
- 生成命令是非阻塞的;它会立即返回一个运行 id。
|
||||
- 完成时,子智能体会向请求者聊天渠道通报一条摘要/结果消息。
|
||||
- 完成通知采用推送方式。生成后,不要仅为了等待其完成而循环轮询 `/subagents list`、`sessions_list` 或 `sessions_history`;仅在调试或干预时按需检查状态。
|
||||
- 完成时,OpenClaw 会尽力在通报清理流程继续之前,关闭该子智能体会话打开并被跟踪的浏览器标签页/进程。
|
||||
- 对于手动生成,投递具有弹性:
|
||||
- OpenClaw 会先使用稳定的幂等键尝试直接 `agent` 投递。
|
||||
- 如果直接投递失败,则回退到队列路由。
|
||||
- 如果队列路由仍不可用,则在最终放弃前,使用短时指数退避重试通报。
|
||||
- 完成投递会保留已解析的请求者路由:
|
||||
- 在线程绑定或会话绑定的完成路由可用时,优先使用它们
|
||||
- 如果完成来源只提供一个渠道,OpenClaw 会从请求者会话的已解析路由(`lastChannel` / `lastTo` / `lastAccountId`)中补齐缺失的 target/account,以便直接投递仍然可用
|
||||
- 向请求者会话交接完成结果时,使用的是运行时生成的内部上下文(不是用户编写的文本),其中包括:
|
||||
- `Result`(最新可见的 `assistant` 回复文本;否则为已清理的最新 `tool`/`toolResult` 文本;终止且失败的运行不会复用已捕获的回复文本)
|
||||
- spawn 命令是非阻塞的;它会立即返回一个运行 id。
|
||||
- 完成后,子智能体会将摘要 / 结果消息通知回请求者聊天渠道。
|
||||
- 完成交付采用推送方式。启动后,不要仅为了等待其完成而循环轮询 `/subagents list`、`sessions_list` 或 `sessions_history`;仅在调试或干预时按需查看状态。
|
||||
- 完成后,OpenClaw 会尽力关闭由该子智能体会话打开的已跟踪浏览器标签页 / 进程,然后再继续通知清理流程。
|
||||
- 对于手动启动,交付具备弹性:
|
||||
- OpenClaw 会先尝试使用稳定的幂等键进行直接 `agent` 交付。
|
||||
- 如果直接交付失败,会回退到队列路由。
|
||||
- 如果队列路由仍不可用,则在最终放弃前,会用短指数退避重试通知。
|
||||
- 完成交付会保留已解析的请求者路由:
|
||||
- 当可用时,线程绑定或对话绑定的完成路由优先
|
||||
- 如果完成来源只提供了一个 channel,OpenClaw 会从请求者会话已解析的路由(`lastChannel` / `lastTo` / `lastAccountId`)中补齐缺失的 target / account,以便直接交付仍可工作
|
||||
- 交接回请求者会话的完成内容是运行时生成的内部上下文(不是用户撰写的文本),其中包括:
|
||||
- `Result`(最新可见的 `assistant` 回复文本;否则使用经过净化的最新 `tool` / `toolResult` 文本;终态失败运行不会复用已捕获的回复文本)
|
||||
- `Status`(`completed successfully` / `failed` / `timed out` / `unknown`)
|
||||
- 紧凑的运行时/Token 统计信息
|
||||
- 一条投递说明,告知请求者智能体用正常的助手语气重写(而不是转发原始内部元数据)
|
||||
- `--model` 和 `--thinking` 会覆盖该特定运行的默认值。
|
||||
- 完成后,使用 `info`/`log` 检查详细信息和输出。
|
||||
- `/subagents spawn` 是一次性模式(`mode: "run"`)。对于持久的线程绑定会话,请使用带有 `thread: true` 和 `mode: "session"` 的 `sessions_spawn`。
|
||||
- 对于 ACP harness 会话(Codex、Claude Code、Gemini CLI),请使用带有 `runtime: "acp"` 的 `sessions_spawn`,并参见 [ACP Agents](/zh-CN/tools/acp-agents),尤其是在调试完成通知或智能体到智能体循环时的 [ACP 投递模型](/zh-CN/tools/acp-agents#delivery-model)。
|
||||
- 紧凑的运行时 / token 统计
|
||||
- 一条交付指令,告诉请求者智能体用正常的助手语气重写,而不是转发原始内部元数据
|
||||
- `--model` 和 `--thinking` 会覆盖该次运行的默认值。
|
||||
- 完成后,可使用 `info` / `log` 查看详细信息和输出。
|
||||
- `/subagents spawn` 是一次性模式(`mode: "run"`)。对于持久的线程绑定会话,请使用带 `thread: true` 和 `mode: "session"` 的 `sessions_spawn`。
|
||||
- 对于 ACP harness 会话(Codex、Claude Code、Gemini CLI),请使用 `runtime: "acp"` 的 `sessions_spawn`,并参阅 [ACP Agents](/zh-CN/tools/acp-agents),尤其是在调试完成交付或智能体到智能体循环时查看其中的 [ACP delivery model](/zh-CN/tools/acp-agents#delivery-model)。
|
||||
|
||||
主要目标:
|
||||
|
||||
- 并行处理“研究 / 长任务 / 慢工具”工作,而不会阻塞主运行。
|
||||
- 默认保持子智能体隔离(会话隔离 + 可选沙箱隔离)。
|
||||
- 让工具接口难以被误用:子智能体默认**不会**获得会话工具。
|
||||
- 并行处理“研究 / 长任务 / 慢工具”工作,而不阻塞主运行。
|
||||
- 默认保持子智能体隔离(会话分离 + 可选沙箱隔离)。
|
||||
- 保持工具面不易被误用:子智能体默认**不**具备 session 工具。
|
||||
- 支持可配置的嵌套深度,以实现编排器模式。
|
||||
|
||||
成本说明:默认情况下,每个子智能体都有其**自己的**上下文和 Token 用量。对于高负载或重复性任务,请为子智能体设置更便宜的模型,并让你的主智能体保持使用更高质量的模型。你可以通过 `agents.defaults.subagents.model` 或按智能体覆盖进行配置。当子级确实需要请求者当前的转录内容时,智能体可以在该次生成中请求 `context: "fork"`。
|
||||
成本说明:每个子智能体默认都有其**自己的**上下文和 token 用量。对于重型或重复性任务,请为子智能体设置更便宜的模型,而让你的主智能体保留较高质量的模型。你可以通过 `agents.defaults.subagents.model` 或按智能体覆盖来配置这一点。当子智能体确实需要请求者当前转录时,智能体可在该次启动中请求 `context: "fork"`。
|
||||
|
||||
## 上下文模式
|
||||
|
||||
原生子智能体默认以隔离方式启动,除非调用方明确要求分叉当前转录。
|
||||
原生子智能体默认以隔离方式启动,除非调用方明确要求 fork
|
||||
当前转录。
|
||||
|
||||
| 模式 | 何时使用 | 行为 |
|
||||
| ---------- | ------------------------------------------------------------------------ | ------------------------------------------------------------------------------- |
|
||||
| `isolated` | 全新的研究、独立实现、慢工具工作,或任何可以在任务文本中简要说明的内容 | 创建一个干净的子级转录。这是默认值,并且可保持较低的 Token 使用量。 |
|
||||
| `fork` | 依赖当前对话、先前工具结果,或请求者转录中已有的细致说明的工作 | 在子级启动前,将请求者转录分支到子会话中。 |
|
||||
| 模式 | 使用时机 | 行为 |
|
||||
| ---------- | -------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------- |
|
||||
| `isolated` | 新的研究、独立实现、慢工具工作,或任何可以在任务文本中简要说明的内容 | 创建一个干净的子转录。这是默认值,并可保持较低 token 用量。 |
|
||||
| `fork` | 工作依赖当前对话、先前工具结果,或已存在于请求者转录中的细致说明 | 在子智能体启动前,将请求者转录分支到子会话中。 |
|
||||
|
||||
请谨慎使用 `fork`。它适用于对上下文敏感的委派,而不是替代清晰任务提示的写法。
|
||||
谨慎使用 `fork`。它用于上下文敏感的委派,而不是替代编写清晰的任务提示词。
|
||||
|
||||
## 工具
|
||||
|
||||
使用 `sessions_spawn`:
|
||||
|
||||
- 启动一个子智能体运行(`deliver: false`,全局 lane:`subagent`)
|
||||
- 然后执行通报步骤,并将通报回复发布到请求者聊天渠道
|
||||
- 默认模型:继承调用方,除非你设置了 `agents.defaults.subagents.model`(或按智能体设置 `agents.list[].subagents.model`);显式设置的 `sessions_spawn.model` 仍然优先。
|
||||
- 默认 thinking:继承调用方,除非你设置了 `agents.defaults.subagents.thinking`(或按智能体设置 `agents.list[].subagents.thinking`);显式设置的 `sessions_spawn.thinking` 仍然优先。
|
||||
- 默认运行超时:如果省略 `sessions_spawn.runTimeoutSeconds`,OpenClaw 会在已设置时使用 `agents.defaults.subagents.runTimeoutSeconds`;否则回退为 `0`(无超时)。
|
||||
- 然后运行一个通知步骤,并将通知回复发布到请求者聊天渠道
|
||||
- 默认模型:继承调用方,除非你设置了 `agents.defaults.subagents.model`(或按智能体设置 `agents.list[].subagents.model`);显式的 `sessions_spawn.model` 仍然优先。
|
||||
- 默认 thinking:继承调用方,除非你设置了 `agents.defaults.subagents.thinking`(或按智能体设置 `agents.list[].subagents.thinking`);显式的 `sessions_spawn.thinking` 仍然优先。
|
||||
- 默认运行超时:如果省略 `sessions_spawn.runTimeoutSeconds`,OpenClaw 会在已设置时使用 `agents.defaults.subagents.runTimeoutSeconds`;否则回退到 `0`(无超时)。
|
||||
|
||||
工具参数:
|
||||
|
||||
- `task`(必需)
|
||||
- `task`(必填)
|
||||
- `label?`(可选)
|
||||
- `agentId?`(可选;如果允许,可在另一个智能体 id 下生成)
|
||||
- `agentId?`(可选;若被允许,可在另一个智能体 id 下启动)
|
||||
- `model?`(可选;覆盖子智能体模型;无效值会被跳过,子智能体将使用默认模型运行,并在工具结果中给出警告)
|
||||
- `thinking?`(可选;覆盖子智能体运行的 thinking 级别)
|
||||
- `runTimeoutSeconds?`(默认为已设置时使用 `agents.defaults.subagents.runTimeoutSeconds`,否则为 `0`;设置后,子智能体运行会在 N 秒后中止)
|
||||
- `thread?`(默认为 `false`;当为 `true` 时,请求为该子智能体会话启用渠道线程绑定)
|
||||
- `runTimeoutSeconds?`(若已设置则默认为 `agents.defaults.subagents.runTimeoutSeconds`,否则为 `0`;设置后,子智能体运行会在 N 秒后中止)
|
||||
- `thread?`(默认 `false`;为 `true` 时,会为该子智能体会话请求渠道线程绑定)
|
||||
- `mode?`(`run|session`)
|
||||
- 默认是 `run`
|
||||
- 如果 `thread: true` 且省略 `mode`,默认值变为 `session`
|
||||
- 如果 `thread: true` 且省略 `mode`,默认变为 `session`
|
||||
- `mode: "session"` 要求 `thread: true`
|
||||
- `cleanup?`(`delete|keep`,默认为 `keep`)
|
||||
- `sandbox?`(`inherit|require`,默认为 `inherit`;`require` 会在目标子级运行时未启用沙箱隔离时拒绝生成)
|
||||
- `context?`(`isolated|fork`,默认为 `isolated`;仅限原生子智能体)
|
||||
- `isolated` 会创建一个干净的子级转录,并且是默认值。
|
||||
- `fork` 会将请求者当前的转录分支到子会话中,使子级以相同的对话上下文启动。
|
||||
- 仅当子级需要当前转录时才使用 `fork`。对于范围明确的工作,请省略 `context`。
|
||||
- `sessions_spawn` **不**接受渠道投递参数(`target`、`channel`、`to`、`threadId`、`replyTo`、`transport`)。如需投递,请从生成的运行中使用 `message`/`sessions_send`。
|
||||
- `cleanup?`(`delete|keep`,默认 `keep`)
|
||||
- `sandbox?`(`inherit|require`,默认 `inherit`;如果目标子运行时未处于沙箱隔离中,则 `require` 会拒绝启动)
|
||||
- `context?`(`isolated|fork`,默认 `isolated`;仅适用于原生子智能体)
|
||||
- `isolated` 会创建一个干净的子转录,并且是默认值。
|
||||
- `fork` 会将请求者当前转录分支到子会话中,使子智能体从相同的对话上下文开始。
|
||||
- 仅当子智能体需要当前转录时才使用 `fork`。对于范围明确的工作,请省略 `context`。
|
||||
- `sessions_spawn` **不**接受渠道交付参数(`target`、`channel`、`to`、`threadId`、`replyTo`、`transport`)。若要交付,请从已启动运行中使用 `message` / `sessions_send`。
|
||||
|
||||
## 线程绑定会话
|
||||
|
||||
当某个渠道启用了线程绑定时,子智能体可以保持绑定到一个线程,从而使该线程中的后续用户消息持续路由到同一个子智能体会话。
|
||||
当某个渠道启用了线程绑定时,子智能体可以持续绑定到某个线程,因此该线程中的后续用户消息会继续路由到同一个子智能体会话。
|
||||
|
||||
### 支持线程的渠道
|
||||
|
||||
- Discord(当前唯一支持的渠道):支持持久的线程绑定子智能体会话(`sessions_spawn` 配合 `thread: true`),手动线程控制(`/focus`、`/unfocus`、`/agents`、`/session idle`、`/session max-age`),以及适配器键 `channels.discord.threadBindings.enabled`、`channels.discord.threadBindings.idleHours`、`channels.discord.threadBindings.maxAgeHours` 和 `channels.discord.threadBindings.spawnSubagentSessions`。
|
||||
- Discord(目前唯一支持的渠道):支持持久的线程绑定子智能体会话(带 `thread: true` 的 `sessions_spawn`)、手动线程控制(`/focus`、`/unfocus`、`/agents`、`/session idle`、`/session max-age`),以及适配器键 `channels.discord.threadBindings.enabled`、`channels.discord.threadBindings.idleHours`、`channels.discord.threadBindings.maxAgeHours` 和 `channels.discord.threadBindings.spawnSubagentSessions`。
|
||||
|
||||
快速流程:
|
||||
|
||||
1. 使用带有 `thread: true` 的 `sessions_spawn` 进行生成(并可选使用 `mode: "session"`)。
|
||||
2. OpenClaw 在当前活动渠道中创建一个线程,或将一个线程绑定到该会话目标。
|
||||
3. 该线程中的回复和后续消息会路由到绑定的会话。
|
||||
4. 使用 `/session idle` 检查/更新不活动自动取消聚焦,并使用 `/session max-age` 控制硬性上限。
|
||||
1. 使用带 `thread: true` 的 `sessions_spawn` 进行启动(可选再加上 `mode: "session"`)。
|
||||
2. OpenClaw 会在活动渠道中创建一个线程,或将某个线程绑定到该会话目标。
|
||||
3. 该线程中的回复和后续消息会路由到已绑定会话。
|
||||
4. 使用 `/session idle` 检查 / 更新无活动自动取消焦点设置,使用 `/session max-age` 控制硬性上限。
|
||||
5. 使用 `/unfocus` 手动解除绑定。
|
||||
|
||||
手动控制:
|
||||
|
||||
- `/focus <target>` 将当前线程(或创建一个线程)绑定到某个子智能体/会话目标。
|
||||
- `/unfocus` 移除当前已绑定线程的绑定。
|
||||
- `/focus <target>` 将当前线程(或创建一个线程)绑定到某个子智能体 / 会话目标。
|
||||
- `/unfocus` 移除当前已绑定线程的绑定关系。
|
||||
- `/agents` 列出活动运行和绑定状态(`thread:<id>` 或 `unbound`)。
|
||||
- `/session idle` 和 `/session max-age` 仅适用于已聚焦的绑定线程。
|
||||
|
||||
配置开关:
|
||||
|
||||
- 全局默认值:`session.threadBindings.enabled`、`session.threadBindings.idleHours`、`session.threadBindings.maxAgeHours`
|
||||
- 渠道覆盖和生成自动绑定键是适配器特定的。请参见上面的**支持线程的渠道**。
|
||||
- 渠道覆盖和启动自动绑定键为适配器特定项。请参阅上方的**支持线程的渠道**。
|
||||
|
||||
当前适配器详情请参见[配置参考](/zh-CN/gateway/configuration-reference)和[斜杠命令](/zh-CN/tools/slash-commands)。
|
||||
请参阅[配置参考](/zh-CN/gateway/configuration-reference)和 [Slash commands](/zh-CN/tools/slash-commands) 了解当前适配器详情。
|
||||
|
||||
允许列表:
|
||||
|
||||
- `agents.list[].subagents.allowAgents`:可通过 `agentId` 定向的智能体 id 列表(`["*"]` 表示允许任意)。默认值:仅请求者智能体。
|
||||
- `agents.defaults.subagents.allowAgents`:当请求者智能体未设置自己的 `subagents.allowAgents` 时,使用的默认目标智能体允许列表。
|
||||
- 沙箱继承保护:如果请求者会话是沙箱隔离的,`sessions_spawn` 会拒绝那些会以非沙箱方式运行的目标。
|
||||
- `agents.defaults.subagents.requireAgentId` / `agents.list[].subagents.requireAgentId`:当为 true 时,阻止省略 `agentId` 的 `sessions_spawn` 调用(强制显式选择配置文件)。默认值:false。
|
||||
- `agents.defaults.subagents.allowAgents`:当请求者智能体未设置自己的 `subagents.allowAgents` 时使用的默认目标智能体允许列表。
|
||||
- 沙箱隔离继承保护:如果请求者会话处于沙箱隔离中,`sessions_spawn` 会拒绝那些将以非沙箱隔离方式运行的目标。
|
||||
- `agents.defaults.subagents.requireAgentId` / `agents.list[].subagents.requireAgentId`:为 true 时,阻止省略 `agentId` 的 `sessions_spawn` 调用(强制显式 profile 选择)。默认值:false。
|
||||
|
||||
发现:
|
||||
设备发现:
|
||||
|
||||
- 使用 `agents_list` 查看当前哪些智能体 id 被允许用于 `sessions_spawn`。
|
||||
- 使用 `agents_list` 查看当前哪些智能体 id 允许用于 `sessions_spawn`。
|
||||
|
||||
自动归档:
|
||||
|
||||
- 子智能体会话会在 `agents.defaults.subagents.archiveAfterMinutes` 后自动归档(默认值:60)。
|
||||
- 子智能体会话会在 `agents.defaults.subagents.archiveAfterMinutes` 之后自动归档(默认:60)。
|
||||
- 归档使用 `sessions.delete`,并将转录重命名为 `*.deleted.<timestamp>`(同一文件夹)。
|
||||
- `cleanup: "delete"` 会在通报后立即归档(仍会通过重命名保留转录)。
|
||||
- 自动归档是尽力而为的;如果 Gateway 网关重启,待处理计时器会丢失。
|
||||
- `cleanup: "delete"` 会在通知后立即归档(仍然会通过重命名保留转录)。
|
||||
- 自动归档是尽力而为的;如果 gateway 重启,待处理计时器会丢失。
|
||||
- `runTimeoutSeconds` **不会**自动归档;它只会停止运行。会话会保留直到自动归档。
|
||||
- 自动归档同样适用于深度 1 和深度 2 的会话。
|
||||
- 浏览器清理与归档清理是分开的:当运行结束时,即使保留了转录/会话记录,被跟踪的浏览器标签页/进程也会尽力关闭。
|
||||
- 自动归档对深度 1 和深度 2 会话同样适用。
|
||||
- 浏览器清理与归档清理是分开的:即使保留转录 / 会话记录,已跟踪的浏览器标签页 / 进程也会在运行结束时尽力关闭。
|
||||
|
||||
## 嵌套子智能体
|
||||
|
||||
默认情况下,子智能体不能生成它们自己的子智能体(`maxSpawnDepth: 1`)。你可以通过设置 `maxSpawnDepth: 2` 来启用一级嵌套,这允许**编排器模式**:主智能体 → 编排器子智能体 → 工作子-子智能体。
|
||||
默认情况下,子智能体不能再启动自己的子智能体(`maxSpawnDepth: 1`)。你可以通过设置 `maxSpawnDepth: 2` 启用一层嵌套,这样就允许**编排器模式**:主智能体 → 编排器子智能体 → worker 子子智能体。
|
||||
|
||||
### 如何启用
|
||||
|
||||
@ -179,125 +180,129 @@ x-i18n:
|
||||
agents: {
|
||||
defaults: {
|
||||
subagents: {
|
||||
maxSpawnDepth: 2, // 允许子智能体生成子级(默认值:1)
|
||||
maxChildrenPerAgent: 5, // 每个智能体会话的最大活动子级数(默认值:5)
|
||||
maxConcurrent: 8, // 全局并发 lane 上限(默认值:8)
|
||||
runTimeoutSeconds: 900, // 省略时 sessions_spawn 的默认超时(0 = 无超时)
|
||||
maxSpawnDepth: 2, // allow sub-agents to spawn children (default: 1)
|
||||
maxChildrenPerAgent: 5, // max active children per agent session (default: 5)
|
||||
maxConcurrent: 8, // global concurrency lane cap (default: 8)
|
||||
runTimeoutSeconds: 900, // default timeout for sessions_spawn when omitted (0 = no timeout)
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
### 深度级别
|
||||
### 深度层级
|
||||
|
||||
| 深度 | 会话键形状 | 角色 | 可以生成子级? |
|
||||
| ----- | -------------------------------------------- | --------------------------------------------- | ------------------------------ |
|
||||
| 0 | `agent:<id>:main` | 主智能体 | 始终可以 |
|
||||
| 1 | `agent:<id>:subagent:<uuid>` | 子智能体(当允许深度 2 时为编排器) | 仅当 `maxSpawnDepth >= 2` 时 |
|
||||
| 2 | `agent:<id>:subagent:<uuid>:subagent:<uuid>` | 子-子智能体(叶子工作者) | 永不 |
|
||||
| 深度 | 会话键形态 | 角色 | 可否继续启动? |
|
||||
| ----- | -------------------------------------------- | --------------------------------------------- | ---------------------------- |
|
||||
| 0 | `agent:<id>:main` | 主智能体 | 始终可以 |
|
||||
| 1 | `agent:<id>:subagent:<uuid>` | 子智能体(当允许深度 2 时可作为编排器) | 仅当 `maxSpawnDepth >= 2` |
|
||||
| 2 | `agent:<id>:subagent:<uuid>:subagent:<uuid>` | 子子智能体(叶子 worker) | 永不可以 |
|
||||
|
||||
### 通报链
|
||||
### 通知链
|
||||
|
||||
结果会沿链路向上返回:
|
||||
|
||||
1. 深度 2 工作者完成 → 向其父级(深度 1 编排器)通报
|
||||
2. 深度 1 编排器接收通报、综合结果、完成 → 向主智能体通报
|
||||
3. 主智能体接收通报并投递给用户
|
||||
1. 深度 2 worker 完成 → 通知其父级(深度 1 编排器)
|
||||
2. 深度 1 编排器接收通知、综合结果并完成 → 通知主智能体
|
||||
3. 主智能体接收通知并交付给用户
|
||||
|
||||
每一层只能看到其直接子级的通报。
|
||||
每一层只会看到来自其直接子级的通知。
|
||||
|
||||
操作指导:
|
||||
操作指引:
|
||||
|
||||
- 启动一次子级工作后,等待完成事件,而不是围绕 `sessions_list`、`sessions_history`、`/subagents list` 或 `exec` sleep 命令构建轮询循环。
|
||||
- `sessions_list` 和 `/subagents list` 会将子会话关系聚焦在实时工作上:活动中的子级保持附着,已结束的子级会在一个短暂的最近窗口内保持可见,而仅存储中的陈旧子级链接会在其新鲜度窗口过后被忽略。这可以防止旧的 `spawnedBy` / `parentSessionKey` 元数据在重启后“复活”幽灵子级。
|
||||
- 如果某个子级完成事件在你已经发送最终答案之后才到达,正确的后续操作是精确的静默令牌 `NO_REPLY` / `no_reply`。
|
||||
- 启动子任务一次后,等待完成事件,而不要围绕 `sessions_list`、`sessions_history`、`/subagents list` 或 `exec` sleep 命令构建轮询循环。
|
||||
- `sessions_list` 和 `/subagents list` 会将子会话关系聚焦于实时工作:仍在运行的子级保持附着,已结束的子级会在一个较短的最近窗口内保持可见,而仅存在于存储中的陈旧子链接会在其新鲜度窗口过后被忽略。这样可以防止旧的 `spawnedBy` / `parentSessionKey` 元数据在重启后重新唤出幽灵子级。
|
||||
- 如果某个子级完成事件在你已经发送最终答案后才到达,正确的后续处理是精确的静默 token:`NO_REPLY` / `no_reply`。
|
||||
|
||||
### 按深度划分的工具策略
|
||||
|
||||
- 角色和控制范围会在生成时写入会话元数据。这可以防止扁平化或恢复后的会话键意外重新获得编排器权限。
|
||||
- **深度 1(编排器,当 `maxSpawnDepth >= 2` 时)**:获得 `sessions_spawn`、`subagents`、`sessions_list`、`sessions_history`,以便管理其子级。其他会话/系统工具仍然被拒绝。
|
||||
- **深度 1(叶子节点,当 `maxSpawnDepth == 1` 时)**:没有会话工具(当前默认行为)。
|
||||
- **深度 2(叶子工作者)**:没有会话工具 —— 在深度 2 时,`sessions_spawn` 始终被拒绝。不能再生成更多子级。
|
||||
- 角色和控制范围会在启动时写入会话元数据。这样可防止扁平化或恢复后的会话键意外重新获得编排器权限。
|
||||
- **深度 1(编排器,当 `maxSpawnDepth >= 2` 时)**:获得 `sessions_spawn`、`subagents`、`sessions_list`、`sessions_history`,以便管理其子级。其他 session / system 工具仍被拒绝。
|
||||
- **深度 1(叶子节点,当 `maxSpawnDepth == 1` 时)**:不提供 session 工具(当前默认行为)。
|
||||
- **深度 2(叶子 worker)**:不提供 session 工具——在深度 2 上始终拒绝 `sessions_spawn`。不能继续启动子级。
|
||||
|
||||
### 按智能体划分的生成限制
|
||||
### 按智能体的启动上限
|
||||
|
||||
每个智能体会话(任意深度)同时最多只能拥有 `maxChildrenPerAgent`(默认值:5)个活动子级。这可以防止单个编排器失控式扇出。
|
||||
每个智能体会话(任意深度)同时最多只能拥有 `maxChildrenPerAgent`(默认:5)个活动子级。这可防止单个编排器无限扇出。
|
||||
|
||||
### 级联停止
|
||||
|
||||
停止一个深度 1 编排器会自动停止其所有深度 2 子级:
|
||||
|
||||
- 在主聊天中使用 `/stop` 会停止所有深度 1 智能体,并级联到它们的深度 2 子级。
|
||||
- `/subagents kill <id>` 会停止指定的子智能体,并级联到其子级。
|
||||
- `/subagents kill all` 会停止该请求者的所有子智能体,并执行级联停止。
|
||||
- `/subagents kill <id>` 会停止指定子智能体,并级联到其子级。
|
||||
- `/subagents kill all` 会停止该请求者的所有子智能体,并执行级联。
|
||||
|
||||
## 认证
|
||||
## 身份验证
|
||||
|
||||
子智能体认证按**智能体 id**解析,而不是按会话类型:
|
||||
子智能体身份验证按**智能体 id** 解析,而不是按会话类型:
|
||||
|
||||
- 子智能体会话键为 `agent:<agentId>:subagent:<uuid>`。
|
||||
- 认证存储从该智能体的 `agentDir` 加载。
|
||||
- 主智能体的认证配置文件会作为**回退**合并进来;发生冲突时,智能体配置文件优先于主配置文件。
|
||||
- auth 存储从该智能体的 `agentDir` 加载。
|
||||
- 主智能体的 auth profiles 会作为**回退**合并进来;若发生冲突,智能体 profile 优先于主智能体 profile。
|
||||
|
||||
注意:该合并是追加式的,因此主配置文件始终可作为回退使用。尚不支持每个智能体完全隔离的认证。
|
||||
注意:这种合并是增量式的,因此主智能体 profile 始终可作为回退使用。目前尚不支持每个智能体完全隔离的 auth。
|
||||
|
||||
## 通报
|
||||
## 通知
|
||||
|
||||
子智能体通过通报步骤回报结果:
|
||||
子智能体通过一个通知步骤回传结果:
|
||||
|
||||
- 通报步骤在子智能体会话内部运行(而不是请求者会话)。
|
||||
- 如果子智能体的回复严格等于 `ANNOUNCE_SKIP`,则不会发布任何内容。
|
||||
- 如果最新的助手文本是精确的静默令牌 `NO_REPLY` / `no_reply`,即使之前存在可见进度,也会抑制通报输出。
|
||||
- 否则,投递方式取决于请求者深度:
|
||||
- 顶层请求者会话使用带外部投递(`deliver=true`)的后续 `agent` 调用
|
||||
- 嵌套的请求者子智能体会话接收内部后续注入(`deliver=false`),以便编排器可以在会话内综合子级结果
|
||||
- 如果某个嵌套的请求者子智能体会话已不存在,OpenClaw 会在可用时回退到该会话的请求者
|
||||
- 对于顶层请求者会话,完成模式的直接投递会先解析任何已绑定的会话/线程路由和 hook 覆盖,然后从请求者会话的已存储路由中补齐缺失的渠道目标字段。这可以确保即使完成来源只标识了渠道,完成通知仍会到达正确的聊天/主题。
|
||||
- 在构建嵌套完成结果时,子级完成聚合被限定在当前请求者运行范围内,以防止陈旧的先前运行子级输出泄露到当前通报中。
|
||||
- 当渠道适配器可用时,通报回复会保留线程/主题路由。
|
||||
- 通报上下文会被规范化为一个稳定的内部事件块:
|
||||
- 通知步骤在子智能体会话内部运行(不是在请求者会话中)。
|
||||
- 如果子智能体精确回复 `ANNOUNCE_SKIP`,则不会发布任何内容。
|
||||
- 如果最新的 assistant 文本是精确的静默 token `NO_REPLY` / `no_reply`,即使之前存在可见进度,也会抑制通知输出。
|
||||
- 否则,交付方式取决于请求者深度:
|
||||
- 顶层请求者会话使用带外部交付(`deliver=true`)的后续 `agent` 调用
|
||||
- 嵌套的请求者子智能体会话接收内部后续注入(`deliver=false`),以便编排器可在会话内综合子级结果
|
||||
- 如果嵌套的请求者子智能体会话已不存在,OpenClaw 会在可用时回退到该会话的请求者
|
||||
- 对于顶层请求者会话,完成模式下的直接交付会先解析任意已绑定的对话 / 线程路由和 hook 覆盖,然后从请求者会话存储的路由中补齐缺失的 channel-target 字段。这样即使完成来源只标识了 channel,也能将完成结果发送到正确的聊天 / 主题中。
|
||||
- 在构建嵌套完成结果时,子级完成聚合会限定在当前请求者运行范围内,以防止先前运行的陈旧子级输出泄漏到当前通知中。
|
||||
- 在渠道适配器支持的情况下,通知回复会保留线程 / 主题路由。
|
||||
- 通知上下文会被规范化为稳定的内部事件块:
|
||||
- 来源(`subagent` 或 `cron`)
|
||||
- 子级会话键/id
|
||||
- 通报类型 + 任务标签
|
||||
- 子会话 key / id
|
||||
- 通知类型 + 任务标签
|
||||
- 从运行时结果派生的状态行(`success`、`error`、`timeout` 或 `unknown`)
|
||||
- 从最新可见助手文本中选取的结果内容;否则使用经过清理的最新 `tool`/`toolResult` 文本;终止且失败的运行会报告失败状态,而不会重放已捕获的回复文本
|
||||
- 一条后续说明,描述何时回复、何时保持静默
|
||||
- 从最新可见 assistant 文本中选取的结果内容;若无,则使用经过净化的最新 `tool` / `toolResult` 文本;终态失败运行会报告失败状态,而不会重放已捕获的回复文本
|
||||
- 一条后续指令,说明何时回复、何时保持静默
|
||||
- `Status` 不是从模型输出推断的;它来自运行时结果信号。
|
||||
- 超时时,如果子级只执行到了工具调用,通报可以将该历史压缩为简短的部分进度摘要,而不是重放原始工具输出。
|
||||
- 超时时,如果子级只执行到了工具调用,通知可以将这段历史压缩为简短的部分进度摘要,而不是重放原始工具输出。
|
||||
|
||||
通报负载在末尾包含一行统计信息(即使已包装也是如此):
|
||||
通知负载在结尾包含一行统计信息(即使被包裹也是如此):
|
||||
|
||||
- 运行时长(例如 `runtime 5m12s`)
|
||||
- Token 用量(输入/输出/总计)
|
||||
- 估算成本(当已配置模型定价 `models.providers.*.models[].cost` 时)
|
||||
- `sessionKey`、`sessionId` 和转录路径(这样主智能体可以通过 `sessions_history` 获取历史记录,或在磁盘上检查文件)
|
||||
- Token 使用量(input / output / total)
|
||||
- 当配置了模型定价(`models.providers.*.models[].cost`)时的预估成本
|
||||
- `sessionKey`、`sessionId` 和转录路径(便于主智能体通过 `sessions_history` 获取历史,或在磁盘上检查文件)
|
||||
- 内部元数据仅用于编排;面向用户的回复应以正常助手语气重写。
|
||||
|
||||
`sessions_history` 是更安全的编排路径:
|
||||
|
||||
- 助手回顾会先进行规范化:
|
||||
- 移除 thinking 标签
|
||||
- 移除 `<relevant-memories>` / `<relevant_memories>` 脚手架块
|
||||
- 移除纯文本工具调用 XML 负载块,例如 `<tool_call>...</tool_call>`、`<function_call>...</function_call>`、`<tool_calls>...</tool_calls>` 和 `<function_calls>...</function_calls>`,包括那些从未正常闭合的截断负载
|
||||
- 移除降级的工具调用/结果脚手架和历史上下文标记
|
||||
- 移除泄露的模型控制令牌,例如 `<|assistant|>`、其他 ASCII `<|...|>` 令牌,以及全角 `<|...|>` 变体
|
||||
- 移除格式错误的 MiniMax 工具调用 XML
|
||||
- 类似凭证/Token 的文本会被打码
|
||||
- assistant 回忆会先进行规范化:
|
||||
- 去除 thinking 标签
|
||||
- 去除 `<relevant-memories>` / `<relevant_memories>` 脚手架块
|
||||
- 去除纯文本工具调用 XML 负载块,例如 `<tool_call>...</tool_call>`、
|
||||
`<function_call>...</function_call>`、`<tool_calls>...</tool_calls>` 和
|
||||
`<function_calls>...</function_calls>`,包括那些从未正常闭合的截断负载
|
||||
- 去除降级后的工具调用 / 结果脚手架和历史上下文标记
|
||||
- 去除泄漏的模型控制 token,例如 `<|assistant|>`、其他 ASCII
|
||||
`<|...|>` token,以及全角 `<|...|>` 变体
|
||||
- 去除格式错误的 MiniMax 工具调用 XML
|
||||
- 类似凭证 / token 的文本会被脱敏
|
||||
- 长内容块可能会被截断
|
||||
- 非常大的历史记录可能会丢弃较旧的行,或将超大的行替换为 `[sessions_history omitted: message too large]`
|
||||
- 当你需要逐字节完整转录时,回退方式是在磁盘上检查原始转录
|
||||
- 对于非常大的历史,可能会丢弃较旧行,或用
|
||||
`[sessions_history omitted: message too large]` 替换过大的某一行
|
||||
- 当你需要逐字节的完整转录时,回退方案是在磁盘上检查原始转录
|
||||
|
||||
## 工具策略(子智能体工具)
|
||||
|
||||
默认情况下,子智能体会获得**除会话工具**和系统工具之外的**所有工具**:
|
||||
默认情况下,子智能体获得**除 session 工具和 system 工具之外的所有工具**:
|
||||
|
||||
- `sessions_list`
|
||||
- `sessions_history`
|
||||
- `sessions_send`
|
||||
- `sessions_spawn`
|
||||
|
||||
这里的 `sessions_history` 仍然是一个有边界、经过清理的回顾视图;它不是原始转录转储。
|
||||
这里的 `sessions_history` 仍然是一个有界、经过净化的回忆视图;它不是原始转录转储。
|
||||
|
||||
当 `maxSpawnDepth >= 2` 时,深度 1 的编排器子智能体还会额外获得 `sessions_spawn`、`subagents`、`sessions_list` 和 `sessions_history`,以便管理其子级。
|
||||
|
||||
@ -317,7 +322,7 @@ x-i18n:
|
||||
tools: {
|
||||
// deny 优先
|
||||
deny: ["gateway", "cron"],
|
||||
// 如果设置 allow,则变为仅允许 allow 中的工具(deny 仍优先)
|
||||
// 如果设置了 allow,则变为仅允许列表(deny 仍优先)
|
||||
// allow: ["read", "exec", "process"]
|
||||
},
|
||||
},
|
||||
@ -329,31 +334,31 @@ x-i18n:
|
||||
|
||||
子智能体使用专用的进程内队列 lane:
|
||||
|
||||
- Lane 名称:`subagent`
|
||||
- 并发数:`agents.defaults.subagents.maxConcurrent`(默认值 `8`)
|
||||
- lane 名称:`subagent`
|
||||
- 并发数:`agents.defaults.subagents.maxConcurrent`(默认 `8`)
|
||||
|
||||
## 存活性与恢复
|
||||
|
||||
OpenClaw 不会将缺少 `endedAt` 永久视为某个子智能体仍然存活的证明。超过陈旧运行窗口、且未结束的运行,将不再在 `/subagents list`、状态摘要、后代完成门控以及按会话的并发检查中计为活动/待处理。
|
||||
OpenClaw 不会将缺少 `endedAt` 视为子智能体仍然存活的永久性证据。超过陈旧运行窗口的未结束运行,在 `/subagents list`、状态摘要、后代完成门控以及按会话并发检查中,将不再计为活动 / 待处理。
|
||||
|
||||
在 Gateway 网关重启后,陈旧的未结束恢复运行会被修剪,除非其子会话被标记为 `abortedLastRun: true`。这些因重启而中止的子会话仍可通过子智能体孤儿恢复流程恢复,该流程会在清除中止标记之前发送一条合成的恢复消息。
|
||||
Gateway 网关重启后,陈旧且未结束的已恢复运行会被清理,除非其子会话被标记为 `abortedLastRun: true`。这些因重启而中止的子会话仍可通过子智能体孤儿恢复流程找回;该流程会先发送一条合成恢复消息,然后清除该中止标记。
|
||||
|
||||
## 停止
|
||||
|
||||
- 在请求者聊天中发送 `/stop` 会中止请求者会话,并停止从中生成的所有活动子智能体运行,同时级联到嵌套子级。
|
||||
- `/subagents kill <id>` 会停止指定的子智能体,并级联到其子级。
|
||||
- 在请求者聊天中发送 `/stop` 会中止请求者会话,并停止由其启动的所有活动子智能体运行,同时级联到嵌套子级。
|
||||
- `/subagents kill <id>` 会停止指定子智能体,并级联到其子级。
|
||||
|
||||
## 限制
|
||||
|
||||
- 子智能体通报是**尽力而为**的。如果 Gateway 网关重启,待处理的“回传通报”工作将丢失。
|
||||
- 子智能体仍共享同一个 Gateway 网关进程资源;请将 `maxConcurrent` 视为一个安全阀。
|
||||
- 子智能体通知是**尽力而为**的。如果 gateway 重启,待处理的“通知回传”工作会丢失。
|
||||
- 子智能体仍共享同一个 gateway 进程资源;请将 `maxConcurrent` 视为安全阀。
|
||||
- `sessions_spawn` 始终是非阻塞的:它会立即返回 `{ status: "accepted", runId, childSessionKey }`。
|
||||
- 子智能体上下文仅注入 `AGENTS.md` + `TOOLS.md`(不包含 `SOUL.md`、`IDENTITY.md`、`USER.md`、`HEARTBEAT.md` 或 `BOOTSTRAP.md`)。
|
||||
- 最大嵌套深度为 5(`maxSpawnDepth` 范围:1–5)。对于大多数使用场景,建议使用深度 2。
|
||||
- `maxChildrenPerAgent` 限制每个会话的活动子级数(默认值:5,范围:1–20)。
|
||||
- 子智能体上下文只注入 `AGENTS.md` + `TOOLS.md`(不注入 `SOUL.md`、`IDENTITY.md`、`USER.md`、`HEARTBEAT.md` 或 `BOOTSTRAP.md`)。
|
||||
- 最大嵌套深度为 5(`maxSpawnDepth` 范围:1–5)。大多数使用场景推荐使用深度 2。
|
||||
- `maxChildrenPerAgent` 限制每个会话的活动子级数量(默认:5,范围:1–20)。
|
||||
|
||||
## 相关内容
|
||||
|
||||
- [ACP 智能体](/zh-CN/tools/acp-agents)
|
||||
- [多智能体沙箱工具](/zh-CN/tools/multi-agent-sandbox-tools)
|
||||
- [智能体发送](/zh-CN/tools/agent-send)
|
||||
- [Agent send](/zh-CN/tools/agent-send)
|
||||
|
||||
@ -2,23 +2,23 @@
|
||||
read_when:
|
||||
- 你想通过浏览器操作 Gateway 网关
|
||||
- 你想在不使用 SSH 隧道的情况下通过 Tailnet 访问
|
||||
summary: Gateway 网关的浏览器控制 UI(聊天、节点、配置)
|
||||
summary: Gateway 网关的基于浏览器的 Control UI(聊天、节点、配置)
|
||||
title: Control UI
|
||||
x-i18n:
|
||||
generated_at: "2026-04-25T00:45:03Z"
|
||||
generated_at: "2026-04-25T05:57:09Z"
|
||||
model: gpt-5.4
|
||||
provider: openai
|
||||
source_hash: 827c4faec9e3e76b7956c2e5e6d882db09f5fa7495b236ac95062476d4c51235
|
||||
source_hash: 0c41605af9972b2ec0a8f23724f0279c1890740b150b37814d2f879a466d36b0
|
||||
source_path: web/control-ui.md
|
||||
workflow: 15
|
||||
---
|
||||
|
||||
Control UI 是一个由 Gateway 网关提供服务的小型 **Vite + Lit** 单页应用:
|
||||
Control UI 是一个由 Gateway 网关提供的小型 **Vite + Lit** 单页应用:
|
||||
|
||||
- 默认地址:`http://<host>:18789/`
|
||||
- 默认:`http://<host>:18789/`
|
||||
- 可选前缀:设置 `gateway.controlUi.basePath`(例如 `/openclaw`)
|
||||
|
||||
它会**直接连接到同一端口上的 Gateway 网关 WebSocket**。
|
||||
它会在同一端口上**直接与 Gateway 网关 WebSocket 通信**。
|
||||
|
||||
## 快速打开(本地)
|
||||
|
||||
@ -28,24 +28,22 @@ Control UI 是一个由 Gateway 网关提供服务的小型 **Vite + Lit** 单
|
||||
|
||||
如果页面无法加载,请先启动 Gateway 网关:`openclaw gateway`。
|
||||
|
||||
认证会在 WebSocket 握手期间通过以下方式提供:
|
||||
认证信息会在 WebSocket 握手期间通过以下方式提供:
|
||||
|
||||
- `connect.params.auth.token`
|
||||
- `connect.params.auth.password`
|
||||
- 当 `gateway.auth.allowTailscale: true` 时使用 Tailscale Serve 身份标头
|
||||
- 当 `gateway.auth.mode: "trusted-proxy"` 时使用受信任代理身份标头
|
||||
- 当 `gateway.auth.allowTailscale: true` 时使用 Tailscale Serve 身份头
|
||||
- 当 `gateway.auth.mode: "trusted-proxy"` 时使用 trusted-proxy 身份头
|
||||
|
||||
仪表板设置面板会为当前浏览器标签页会话保存一个 token
|
||||
以及所选的 Gateway 网关 URL;密码不会被持久化。新手引导通常会在首次连接时为共享密钥认证生成一个 gateway token,但当 `gateway.auth.mode` 为 `"password"` 时,也可以使用密码认证。
|
||||
仪表板设置面板会为当前浏览器标签页会话和所选网关 URL 保留一个 token;password 不会被持久化。新手引导通常会在首次连接时为共享密钥认证生成一个网关 token,但当 `gateway.auth.mode` 为 `"password"` 时,也可以使用 password 认证。
|
||||
|
||||
## 设备配对(首次连接)
|
||||
|
||||
当你从新的浏览器或设备连接到 Control UI 时,Gateway 网关
|
||||
需要进行**一次性配对批准**——即使你已经位于同一个 Tailnet 中,并启用了 `gateway.auth.allowTailscale: true`。这是防止未经授权访问的安全措施。
|
||||
当你从新的浏览器或设备连接到 Control UI 时,Gateway 网关要求进行**一次性配对批准**——即使你位于同一个 Tailnet 中,且 `gateway.auth.allowTailscale: true` 也是如此。这是一项安全措施,用于防止未授权访问。
|
||||
|
||||
**你会看到:** “disconnected (1008): pairing required”
|
||||
**你会看到的内容:**“已断开连接(1008):需要配对”
|
||||
|
||||
**要批准该设备:**
|
||||
**批准设备的方法:**
|
||||
|
||||
```bash
|
||||
# List pending requests
|
||||
@ -55,139 +53,102 @@ openclaw devices list
|
||||
openclaw devices approve <requestId>
|
||||
```
|
||||
|
||||
如果浏览器在认证详情(角色 / scope / 公钥)变更后重试配对,
|
||||
之前的待处理请求会被取代,并创建一个新的 `requestId`。
|
||||
批准前请重新运行 `openclaw devices list`。
|
||||
如果浏览器在认证详情(角色/作用域/公钥)发生变化后重试配对,之前待处理的请求会被替代,并创建新的 `requestId`。
|
||||
请在批准前重新运行 `openclaw devices list`。
|
||||
|
||||
如果浏览器已经完成配对,而你又将其从只读访问改为
|
||||
写入 / 管理员访问,这会被视为一次审批升级,而不是静默重连。
|
||||
OpenClaw 会保持旧审批继续有效,阻止更高权限的重连,
|
||||
并要求你显式批准新的 scope 集合。
|
||||
如果浏览器已经配对,而你又将其从只读访问改为写入/管理员访问,这会被视为批准升级,而不是静默重连。OpenClaw 会保持旧批准继续有效,阻止更高权限的重连,并要求你显式批准新的作用域集合。
|
||||
|
||||
一旦批准,该设备就会被记住,除非你通过 `openclaw devices revoke --device <id> --role <role>` 撤销它,否则不会再次要求批准。有关 token 轮换和撤销,请参见
|
||||
[Devices CLI](/zh-CN/cli/devices)。
|
||||
一旦获得批准,设备就会被记住,除非你使用 `openclaw devices revoke --device <id> --role <role>` 撤销它,否则无需再次批准。有关 token 轮换和撤销,请参见 [Devices CLI](/zh-CN/cli/devices)。
|
||||
|
||||
**说明:**
|
||||
|
||||
- 直接的本地 local loopback 浏览器连接(`127.0.0.1` / `localhost`)会
|
||||
自动批准。
|
||||
- Tailnet 和 LAN 浏览器连接即使来自同一台机器,
|
||||
仍然需要显式批准。
|
||||
- 每个浏览器配置文件都会生成唯一的设备 ID,因此切换浏览器或
|
||||
清除浏览器数据都需要重新配对。
|
||||
- 直接的本地 local loopback 浏览器连接(`127.0.0.1` / `localhost`)会被自动批准。
|
||||
- Tailnet 和局域网浏览器连接即使来自同一台机器,仍然需要显式批准。
|
||||
- 每个浏览器配置文件都会生成唯一的设备 ID,因此切换浏览器或清除浏览器数据都会需要重新配对。
|
||||
|
||||
## 个人身份(浏览器本地)
|
||||
|
||||
Control UI 支持按浏览器存储的个人身份(显示名称和
|
||||
头像),用于为共享会话中的出站消息附加归属信息。它
|
||||
存储在浏览器存储中,作用域仅限当前浏览器配置文件,不会
|
||||
同步到其他设备,也不会在服务端持久化,除了你实际发送消息时
|
||||
消息上正常的转录作者元数据。清除站点数据或切换浏览器后,
|
||||
它会重置为空。
|
||||
Control UI 支持按浏览器设置个人身份(显示名称和头像),用于在共享会话中为发送的消息附加归属信息。它存储在浏览器存储中,作用域限定为当前浏览器配置文件,不会同步到其他设备,也不会在服务器端持久化,除了你实际发送消息所附带的常规转录作者元数据之外。清除站点数据或切换浏览器后,它会重置为空。
|
||||
|
||||
## 运行时配置端点
|
||||
|
||||
Control UI 会从
|
||||
`/__openclaw/control-ui-config.json` 获取其运行时设置。该端点受与其余 HTTP 界面相同的 gateway 认证保护:未认证的浏览器无法获取它,而成功获取则要求已经具备有效的 gateway
|
||||
token / password、Tailscale Serve 身份,或受信任代理身份。
|
||||
Control UI 会从 ` /__openclaw/control-ui-config.json` 获取其运行时设置。该端点受与其余 HTTP 能力面相同的网关认证保护:未认证的浏览器无法获取它,而成功获取需要满足以下之一:已有有效的网关 token/password、Tailscale Serve 身份,或 trusted-proxy 身份。
|
||||
|
||||
## 语言支持
|
||||
|
||||
Control UI 可以在首次加载时根据你的浏览器语言环境进行本地化。
|
||||
如果你之后想覆盖它,请打开 **Overview -> Gateway Access -> Language**。语言选择器位于 Gateway Access 卡片中,而不在外观设置下。
|
||||
Control UI 可以在首次加载时根据你的浏览器语言环境进行本地化。若要之后覆盖它,请打开 **概览 -> Gateway Access -> Language**。语言选择器位于 Gateway Access 卡片中,而不是在外观设置下。
|
||||
|
||||
- 支持的语言环境:`en`, `zh-CN`, `zh-TW`, `pt-BR`, `de`, `es`, `ja-JP`, `ko`, `fr`, `tr`, `uk`, `id`, `pl`, `th`
|
||||
- 非英语翻译会在浏览器中延迟加载。
|
||||
- 所选语言环境会保存在浏览器存储中,并在将来访问时复用。
|
||||
- 缺失的翻译键会回退到英语。
|
||||
- 支持的语言环境:`en`、`zh-CN`、`zh-TW`、`pt-BR`、`de`、`es`、`ja-JP`、`ko`、`fr`、`tr`、`uk`、`id`、`pl`、`th`
|
||||
- 非英文翻译会在浏览器中按需懒加载。
|
||||
- 所选语言环境会保存到浏览器存储中,并在之后访问时复用。
|
||||
- 缺失的翻译键会回退到英文。
|
||||
|
||||
## 当前可执行的功能
|
||||
## 它目前可以做什么
|
||||
|
||||
- 通过 Gateway 网关 WS 与模型聊天(`chat.history`、`chat.send`、`chat.abort`、`chat.inject`)
|
||||
- 通过 WebRTC 直接从浏览器连接到 OpenAI Realtime。Gateway 网关
|
||||
通过 `talk.realtime.session` 生成一个短期 Realtime 客户端密钥;浏览器将麦克风音频直接发送到 OpenAI,并通过 `chat.send` 将
|
||||
`openclaw_agent_consult` 工具调用中继回去,以供配置的更大 OpenClaw 模型使用。
|
||||
- 在聊天中流式显示工具调用和实时工具输出卡片(智能体事件)
|
||||
- 渠道:内置渠道以及内置 / 外部插件渠道的状态、QR 登录和每渠道配置(`channels.status`、`web.login.*`、`config.patch`)
|
||||
- 实例:在线列表与刷新(`system-presence`)
|
||||
- 会话:列表以及按会话设置 model / thinking / fast / verbose / trace / reasoning 覆盖(`sessions.list`、`sessions.patch`)
|
||||
- Dreams:Dreaming 状态、启用 / 禁用开关,以及 Dream Diary 读取器(`doctor.memory.status`、`doctor.memory.dreamDiary`、`config.patch`)
|
||||
- Cron 作业:列出 / 添加 / 编辑 / 运行 / 启用 / 禁用 + 运行历史(`cron.*`)
|
||||
- Skills:状态、启用 / 禁用、安装、API key 更新(`skills.*`)
|
||||
- 通过 WebRTC 直接在浏览器中与 OpenAI Realtime 通信。Gateway 网关会通过 `talk.realtime.session` 签发短期有效的 Realtime 客户端密钥;浏览器会将麦克风音频直接发送给 OpenAI,并通过 `chat.send` 将 `openclaw_agent_consult` 工具调用中继回已配置的更大 OpenClaw 模型。
|
||||
- 在聊天中流式显示工具调用 + 实时工具输出卡片(智能体事件)
|
||||
- 渠道:内置以及内置/外部插件渠道的状态、二维码登录和每渠道配置(`channels.status`、`web.login.*`、`config.patch`)
|
||||
- 实例:在线状态列表 + 刷新(`system-presence`)
|
||||
- 会话:列表 + 每会话模型/thinking/fast/verbose/trace/reasoning 覆盖(`sessions.list`、`sessions.patch`)
|
||||
- Dreams:Dreaming 状态、启用/禁用开关,以及 Dream Diary 读取器(`doctor.memory.status`、`doctor.memory.dreamDiary`、`config.patch`)
|
||||
- Cron 作业:列表/添加/编辑/运行/启用/禁用 + 运行历史(`cron.*`)
|
||||
- Skills:状态、启用/禁用、安装、API 密钥更新(`skills.*`)
|
||||
- 节点:列表 + 能力(`node.list`)
|
||||
- Exec 审批:编辑 gateway 或节点 allowlist + 为 `exec host=gateway/node` 设置 ask 策略(`exec.approvals.*`)
|
||||
- 配置:查看 / 编辑 `~/.openclaw/openclaw.json`(`config.get`、`config.set`)
|
||||
- 配置:带校验地应用 + 重启(`config.apply`),并唤醒最近活跃的会话
|
||||
- Exec 审批:编辑 Gateway 网关或节点允许列表 + 为 `exec host=gateway/node` 询问策略(`exec.approvals.*`)
|
||||
- 配置:查看/编辑 `~/.openclaw/openclaw.json`(`config.get`、`config.set`)
|
||||
- 配置:带验证的应用 + 重启(`config.apply`),并唤醒最近活跃的会话
|
||||
- 配置写入包含 base-hash 保护,以防覆盖并发编辑
|
||||
- 配置写入(`config.set` / `config.apply` / `config.patch`)还会在写入前对提交配置负载中的活动 SecretRef 执行预检解析;无法解析的活动已提交引用会在写入前被拒绝
|
||||
- 配置 schema + 表单渲染(`config.schema` / `config.schema.lookup`,
|
||||
包括字段 `title` / `description`、匹配的 UI 提示、直接子项
|
||||
摘要、嵌套对象 / 通配符 / 数组 / 组合节点上的文档元数据,
|
||||
以及在可用时的插件 + 渠道 schema);仅当快照支持安全的原始 round-trip 时,
|
||||
才提供 Raw JSON 编辑器
|
||||
- 如果某个快照无法安全地进行原始 round-trip,Control UI 会强制使用表单模式,并对该快照禁用 Raw 模式
|
||||
- Raw JSON 编辑器中的“Reset to saved”会保留原始编写形态(格式、注释、`$include` 布局),而不是重新渲染扁平化快照,因此当快照可以安全 round-trip 时,外部编辑在重置后仍会保留
|
||||
- 结构化 SecretRef 对象值会在表单文本输入中以只读方式渲染,以防对象到字符串的意外损坏
|
||||
- 调试:状态 / 健康 / 模型快照 + 事件日志 + 手动 RPC 调用(`status`、`health`、`models.list`)
|
||||
- 日志:带过滤 / 导出的 gateway 文件日志实时 tail(`logs.tail`)
|
||||
- 更新:执行 package / git 更新 + 重启(`update.run`),并附带重启报告
|
||||
- 配置写入(`config.set`/`config.apply`/`config.patch`)还会对提交的配置载荷中的活动 SecretRef 解析进行预检;未解析的活动已提交引用会在写入前被拒绝
|
||||
- 配置 schema + 表单渲染(`config.schema` / `config.schema.lookup`,包括字段 `title` / `description`、匹配的 UI 提示、直接子项摘要、嵌套对象/通配符/数组/组合节点上的文档元数据,以及在可用时的插件 + 渠道 schema);仅当快照支持安全的原始往返时,才提供 Raw JSON 编辑器
|
||||
- 如果某个快照无法安全地进行原始往返,Control UI 会强制使用表单模式,并为该快照禁用原始模式
|
||||
- Raw JSON 编辑器中的“重置为已保存”会保留原始编写的结构(格式、注释、`$include` 布局),而不是重新渲染扁平化快照,因此当快照可以安全往返时,外部编辑在重置后仍会保留
|
||||
- 结构化 SecretRef 对象值会在表单文本输入中以只读方式渲染,以防止对象被意外损坏为字符串
|
||||
- 调试:状态/健康/模型快照 + 事件日志 + 手动 RPC 调用(`status`、`health`、`models.list`)
|
||||
- 日志:带过滤/导出的 Gateway 网关文件日志实时 tail(`logs.tail`)
|
||||
- 更新:运行 package/git 更新 + 重启(`update.run`),并附带重启报告
|
||||
|
||||
Cron 作业面板说明:
|
||||
|
||||
- 对于隔离作业,投递默认是 announce 摘要。如果你希望仅内部运行,可以切换为 none。
|
||||
- 选择 announce 时会出现渠道 / 目标字段。
|
||||
- Webhook 模式使用 `delivery.mode = "webhook"`,并将 `delivery.to` 设为有效的 HTTP(S) webhook URL。
|
||||
- 对于主会话作业,webhook 和 none 投递模式都可用。
|
||||
- 高级编辑控件包括运行后删除、清除智能体覆盖、cron 精确 / 错开选项、
|
||||
智能体 model / thinking 覆盖,以及尽力而为投递开关。
|
||||
- 表单校验以内联方式显示字段级错误;在修复前,无效值会禁用保存按钮。
|
||||
- 设置 `cron.webhookToken` 可发送专用 bearer token;如果省略,webhook 将不会带认证标头。
|
||||
- 已弃用回退:带有 `notify: true` 的旧存储作业在迁移前仍可使用 `cron.webhook`。
|
||||
- 对于独立作业,投递默认是 announce 摘要。如果你只想进行内部运行,可以切换为 none。
|
||||
- 选择 announce 后会显示渠道/目标字段。
|
||||
- Webhook 模式使用 `delivery.mode = "webhook"`,并将 `delivery.to` 设置为有效的 HTTP(S) webhook URL。
|
||||
- 对于主会话作业,可用的投递模式有 webhook 和 none。
|
||||
- 高级编辑控件包括运行后删除、清除智能体覆盖、cron 精确/错峰选项、智能体模型/thinking 覆盖,以及尽力投递切换。
|
||||
- 表单验证为内联字段级错误;在修复前,无效值会禁用保存按钮。
|
||||
- 设置 `cron.webhookToken` 可发送专用 bearer token;若省略,则 webhook 会在不带认证头的情况下发送。
|
||||
- 已弃用的回退:已存储的旧版作业使用 `notify: true` 时,在迁移前仍可使用 `cron.webhook`。
|
||||
|
||||
## 聊天行为
|
||||
|
||||
- `chat.send` 是**非阻塞**的:它会立即确认并返回 `{ runId, status: "started" }`,响应则通过 `chat` 事件流式传输。
|
||||
- 使用相同的 `idempotencyKey` 重发时,运行中会返回 `{ status: "in_flight" }`,完成后返回 `{ status: "ok" }`。
|
||||
- 出于 UI 安全考虑,`chat.history` 响应有大小限制。当转录条目过大时,Gateway 网关可能会截断较长文本字段、省略较重的元数据块,并用占位符替换超大消息(`[chat.history omitted: message too large]`)。
|
||||
- 助手 / 生成的图像会以托管媒体引用形式持久化,并通过已认证的 Gateway 网关媒体 URL 返回,因此重新加载时不依赖聊天历史响应中仍保留原始 base64 图像负载。
|
||||
- `chat.history` 还会从可见助手文本中去除仅用于显示的内联指令标签(例如 `[[reply_to_*]]` 和 `[[audio_as_voice]]`)、纯文本工具调用 XML 负载(包括 `<tool_call>...</tool_call>`、`<function_call>...</function_call>`、`<tool_calls>...</tool_calls>`、`<function_calls>...</function_calls>` 以及被截断的工具调用块),以及泄露的 ASCII / 全角模型控制 token,并省略其全部可见文本仅为精确静默 token `NO_REPLY` / `no_reply` 的助手条目。
|
||||
- `chat.inject` 会向会话转录追加一条助手备注,并广播一个 `chat` 事件用于仅 UI 更新(不触发智能体运行,也不进行渠道投递)。
|
||||
- 聊天头部的 model 和 thinking 选择器会立即通过 `sessions.patch` 修补活动会话;它们是持久的会话覆盖,不是单轮发送选项。
|
||||
- 当最新的 Gateway 网关会话用量报告显示上下文压力较高时,聊天
|
||||
编辑器区域会显示上下文提示,并且在建议压缩级别下,
|
||||
会显示一个 compact 按钮,用于运行正常的会话压缩流程。过期的 token
|
||||
快照会被隐藏,直到 Gateway 网关再次报告新的用量。
|
||||
- Talk 模式使用已注册的实时语音提供商,该提供商支持浏览器
|
||||
WebRTC 会话。请配置 OpenAI:`talk.provider: "openai"` 并设置
|
||||
`talk.providers.openai.apiKey`,或复用 Voice Call 的实时提供商配置。浏览器绝不会接收到标准 OpenAI API key;它只会收到短期 Realtime 客户端密钥。Google Live 实时语音支持后端 Voice Call 和 Google Meet bridge,但暂不支持此浏览器
|
||||
WebRTC 路径。Realtime 会话提示词由 Gateway 网关组装;
|
||||
`talk.realtime.session` 不接受调用方提供的指令覆盖。
|
||||
- 在聊天编辑器中,Talk 控件是麦克风听写按钮旁边的
|
||||
波纹按钮。当 Talk 启动时,编辑器状态行会显示
|
||||
`Connecting Talk...`,音频连接后显示
|
||||
`Talk live`,或者当实时工具调用通过 `chat.send` 咨询已配置的
|
||||
更大模型时显示 `Asking OpenClaw...`。
|
||||
- `chat.send` 是**非阻塞**的:它会立即确认并返回 `{ runId, status: "started" }`,随后响应通过 `chat` 事件流式传输。
|
||||
- 使用相同的 `idempotencyKey` 重发时,如果仍在运行中会返回 `{ status: "in_flight" }`,完成后则返回 `{ status: "ok" }`。
|
||||
- 出于 UI 安全考虑,`chat.history` 响应有大小限制。当转录条目过大时,Gateway 网关可能会截断长文本字段、省略较重的元数据块,并用占位符替换超大消息(`[chat.history omitted: message too large]`)。
|
||||
- 助手/生成的图像会作为受管媒体引用持久化,并通过已认证的 Gateway 网关媒体 URL 提供,因此页面重新加载不依赖于聊天历史响应中仍保留原始 base64 图像载荷。
|
||||
- `chat.history` 还会从可见助手文本中剥离仅用于显示的内联指令标签(例如 `[[reply_to_*]]` 和 `[[audio_as_voice]]`)、纯文本工具调用 XML 载荷(包括 `<tool_call>...</tool_call>`、`<function_call>...</function_call>`、`<tool_calls>...</tool_calls>`、`<function_calls>...</function_calls>` 以及截断的工具调用块),以及泄露的 ASCII/全角模型控制 token,并省略那些其全部可见文本仅为精确静默 token `NO_REPLY` / `no_reply` 的助手条目。
|
||||
- 在活跃发送期间以及最终历史刷新期间,如果 `chat.history` 短暂返回较旧快照,聊天视图会保留本地乐观显示的用户/助手消息;一旦 Gateway 网关历史记录追上,这些本地消息就会被规范转录替换。
|
||||
- `chat.inject` 会向会话转录追加一条助手说明,并广播一个 `chat` 事件以进行仅 UI 更新(不触发智能体运行,也不投递到渠道)。
|
||||
- 聊天头部中的模型和 thinking 选择器会立即通过 `sessions.patch` 修补当前活动会话;它们是持久的会话覆盖,而不是单轮发送选项。
|
||||
- 当新的 Gateway 网关会话用量报告显示上下文压力较高时,聊天输入区会显示上下文提示;在建议的压缩级别下,还会显示一个 compact 按钮,用于运行正常的会话压缩路径。过期的 token 快照会被隐藏,直到 Gateway 网关再次报告新鲜用量。
|
||||
- Talk 模式使用一个已注册的 realtime 语音 provider,该 provider 支持浏览器 WebRTC 会话。可配置 OpenAI:`talk.provider: "openai"` 加 `talk.providers.openai.apiKey`,或复用 Voice Call realtime provider 配置。浏览器永远不会收到标准 OpenAI API 密钥;它只会收到临时 Realtime 客户端密钥。Google Live realtime 语音支持后端 Voice Call 和 Google Meet 桥接,但尚不支持此浏览器 WebRTC 路径。Realtime 会话提示由 Gateway 网关组装;`talk.realtime.session` 不接受调用方提供的指令覆盖。
|
||||
- 在聊天输入区中,Talk 控件是位于麦克风听写按钮旁边的波形按钮。Talk 启动时,输入区状态行会显示 `Connecting Talk...`,音频连接后显示 `Talk live`,或者当 realtime 工具调用正通过 `chat.send` 查询已配置的更大模型时显示 `Asking OpenClaw...`。
|
||||
- 停止:
|
||||
- 点击 **Stop**(调用 `chat.abort`)
|
||||
- 当某个运行处于活动状态时,普通后续消息会排队。点击已排队消息上的 **Steer** 可将该后续消息注入到当前运行轮次中。
|
||||
- 输入 `/stop`(或独立中止短语,如 `stop`、`stop action`、`stop run`、`stop openclaw`、`please stop`)进行带外中止
|
||||
- `chat.abort` 支持 `{ sessionKey }`(无需 `runId`)以中止该会话的所有活动运行
|
||||
- 当某次运行处于活跃状态时,普通后续消息会排队。点击排队消息上的 **Steer** 可将该后续消息注入到当前运行轮次中。
|
||||
- 输入 `/stop`(或独立中止短语,例如 `stop`、`stop action`、`stop run`、`stop openclaw`、`please stop`)可进行带外中止
|
||||
- `chat.abort` 支持 `{ sessionKey }`(无 `runId`),可中止该会话的所有活动运行
|
||||
- 中止后的部分保留:
|
||||
- 当某个运行被中止时,部分助手文本仍可能显示在 UI 中
|
||||
- 当存在缓冲输出时,Gateway 网关会将中止的部分助手文本持久化到转录历史中
|
||||
- 持久化条目包含中止元数据,以便转录消费者区分中止的部分输出与正常完成输出
|
||||
- 当某次运行被中止时,部分助手文本仍可能显示在 UI 中
|
||||
- 当存在缓冲输出时,Gateway 网关会将已中止的部分助手文本持久化到转录历史中
|
||||
- 持久化条目包含中止元数据,以便转录使用方区分中止的部分输出与正常完成输出
|
||||
|
||||
## 托管嵌入
|
||||
|
||||
助手消息可以通过 `[embed ...]`
|
||||
短代码以内联方式渲染托管的网页内容。iframe 沙箱策略由
|
||||
`gateway.controlUi.embedSandbox` 控制:
|
||||
助手消息可以使用 `[embed ...]` 短代码以内联方式渲染托管 Web 内容。iframe 沙箱策略由 `gateway.controlUi.embedSandbox` 控制:
|
||||
|
||||
- `strict`:禁用托管嵌入中的脚本执行
|
||||
- `scripts`:允许交互式嵌入,同时保持源隔离;这是
|
||||
默认值,通常足以支持自包含的浏览器游戏 / 小部件
|
||||
- `trusted`:在 `allow-scripts` 的基础上再添加 `allow-same-origin`,用于同站点
|
||||
文档有意需要更高权限的场景
|
||||
- `scripts`:允许交互式嵌入,同时保持源隔离;这是默认值,通常已足够支持自包含的浏览器游戏/小组件
|
||||
- `trusted`:在 `allow-scripts` 之上再添加 `allow-same-origin`,用于有意需要更高权限的同站点文档
|
||||
|
||||
示例:
|
||||
|
||||
@ -201,19 +162,16 @@ Cron 作业面板说明:
|
||||
}
|
||||
```
|
||||
|
||||
仅当嵌入的文档确实需要同源
|
||||
行为时才使用 `trusted`。对于大多数由智能体生成的游戏和交互式画布,`scripts` 是
|
||||
更安全的选择。
|
||||
仅当嵌入文档确实需要 same-origin 行为时才使用 `trusted`。
|
||||
对于大多数由智能体生成的游戏和交互式 canvas,`scripts` 是更安全的选择。
|
||||
|
||||
默认情况下,绝对外部 `http(s)` 嵌入 URL 仍会被阻止。如果你
|
||||
确实想让 `[embed url="https://..."]` 加载第三方页面,请设置
|
||||
`gateway.controlUi.allowExternalEmbedUrls: true`。
|
||||
默认情况下,绝对外部 `http(s)` embed URL 仍会被阻止。如果你确实希望 `[embed url="https://..."]` 加载第三方页面,请设置 `gateway.controlUi.allowExternalEmbedUrls: true`。
|
||||
|
||||
## Tailnet 访问(推荐)
|
||||
|
||||
### 集成式 Tailscale Serve(首选)
|
||||
|
||||
将 Gateway 网关保留在 local loopback 上,并让 Tailscale Serve 通过 HTTPS 代理它:
|
||||
让 Gateway 网关保持绑定到 loopback,并通过 Tailscale Serve 使用 HTTPS 进行代理:
|
||||
|
||||
```bash
|
||||
openclaw gateway --tailscale serve
|
||||
@ -223,17 +181,9 @@ openclaw gateway --tailscale serve
|
||||
|
||||
- `https://<magicdns>/`(或你配置的 `gateway.controlUi.basePath`)
|
||||
|
||||
默认情况下,当 `gateway.auth.allowTailscale` 为 `true` 时,Control UI / WebSocket Serve 请求可以通过 Tailscale 身份标头
|
||||
(`tailscale-user-login`)进行认证。OpenClaw
|
||||
会通过 `tailscale whois` 解析 `x-forwarded-for` 地址并与标头匹配来验证身份,并且仅当
|
||||
请求到达 local loopback 且带有 Tailscale 的 `x-forwarded-*` 标头时才接受这些身份。若你希望即使对于 Serve 流量也要求显式共享密钥
|
||||
凭证,请设置
|
||||
`gateway.auth.allowTailscale: false`。然后使用 `gateway.auth.mode: "token"` 或
|
||||
`"password"`。
|
||||
对于该异步 Serve 身份路径,来自同一客户端 IP
|
||||
和认证 scope 的失败认证尝试会在速率限制写入前被串行化。因此,同一浏览器的并发错误重试
|
||||
在第二个请求上可能会显示 `retry later`,而不是两个普通不匹配并行竞争。
|
||||
无 token 的 Serve 认证假设 gateway 主机是可信的。如果该主机上可能运行不受信任的本地代码,请要求使用 token / password 认证。
|
||||
默认情况下,当 `gateway.auth.allowTailscale` 为 `true` 时,Control UI/WebSocket Serve 请求可以通过 Tailscale 身份头(`tailscale-user-login`)进行认证。OpenClaw 会通过 `tailscale whois` 解析 `x-forwarded-for` 地址并将其与该头进行匹配来验证身份,并且仅在请求命中 loopback 且带有 Tailscale 的 `x-forwarded-*` 头时接受这些头。如果你希望即使对 Serve 流量也要求显式共享密钥凭证,请设置 `gateway.auth.allowTailscale: false`。然后使用 `gateway.auth.mode: "token"` 或 `"password"`。
|
||||
对于该异步 Serve 身份路径,来自同一客户端 IP 和认证作用域的失败认证尝试会在写入速率限制之前进行串行化。因此,同一浏览器的并发错误重试中,第二个请求可能会显示 `retry later`,而不是两个普通不匹配请求并行竞争。
|
||||
无 token 的 Serve 认证假定网关主机是受信任的。如果该主机上可能运行不受信任的本地代码,请要求使用 token/password 认证。
|
||||
|
||||
### 绑定到 tailnet + token
|
||||
|
||||
@ -245,25 +195,22 @@ openclaw gateway --bind tailnet --token "$(openssl rand -hex 32)"
|
||||
|
||||
- `http://<tailscale-ip>:18789/`(或你配置的 `gateway.controlUi.basePath`)
|
||||
|
||||
将匹配的共享密钥粘贴到 UI 设置中(会作为
|
||||
`connect.params.auth.token` 或 `connect.params.auth.password` 发送)。
|
||||
将匹配的共享密钥粘贴到 UI 设置中(作为 `connect.params.auth.token` 或 `connect.params.auth.password` 发送)。
|
||||
|
||||
## 不安全的 HTTP
|
||||
|
||||
如果你通过纯 HTTP 打开仪表板(`http://<lan-ip>` 或 `http://<tailscale-ip>`),
|
||||
浏览器会运行在**非安全上下文**中,并阻止 WebCrypto。默认情况下,
|
||||
OpenClaw **会阻止**没有设备身份的 Control UI 连接。
|
||||
如果你通过纯 HTTP 打开仪表板(`http://<lan-ip>` 或 `http://<tailscale-ip>`),浏览器会运行在**非安全上下文**中,并阻止 WebCrypto。默认情况下,OpenClaw 会**阻止**没有设备身份的 Control UI 连接。
|
||||
|
||||
文档化的例外情况:
|
||||
文档中记录的例外情况:
|
||||
|
||||
- 使用 `gateway.controlUi.allowInsecureAuth=true` 的仅 localhost 不安全 HTTP 兼容模式
|
||||
- 通过 `gateway.auth.mode: "trusted-proxy"` 成功完成的操作员 Control UI 认证
|
||||
- 紧急兜底 `gateway.controlUi.dangerouslyDisableDeviceAuth=true`
|
||||
- 通过 `gateway.auth.mode: "trusted-proxy"` 成功进行的 operator Control UI 认证
|
||||
- 紧急破窗选项 `gateway.controlUi.dangerouslyDisableDeviceAuth=true`
|
||||
|
||||
**推荐修复方法:** 使用 HTTPS(Tailscale Serve)或在本地打开 UI:
|
||||
**推荐修复方式:**使用 HTTPS(Tailscale Serve)或在本地打开 UI:
|
||||
|
||||
- `https://<magicdns>/`(Serve)
|
||||
- `http://127.0.0.1:18789/`(在 gateway 主机上)
|
||||
- `http://127.0.0.1:18789/`(在网关主机上)
|
||||
|
||||
**不安全认证开关行为:**
|
||||
|
||||
@ -277,14 +224,13 @@ OpenClaw **会阻止**没有设备身份的 Control UI 连接。
|
||||
}
|
||||
```
|
||||
|
||||
`allowInsecureAuth` 仅是一个本地兼容性开关:
|
||||
`allowInsecureAuth` 只是一个本地兼容性开关:
|
||||
|
||||
- 它允许 localhost Control UI 会话在
|
||||
非安全 HTTP 上下文中无需设备身份即可继续。
|
||||
- 它允许 localhost Control UI 会话在非安全 HTTP 上下文中无需设备身份继续进行。
|
||||
- 它不会绕过配对检查。
|
||||
- 它不会放宽远程(非 localhost)设备身份要求。
|
||||
|
||||
**仅限紧急兜底:**
|
||||
**仅限紧急破窗:**
|
||||
|
||||
```json5
|
||||
{
|
||||
@ -296,55 +242,54 @@ OpenClaw **会阻止**没有设备身份的 Control UI 连接。
|
||||
}
|
||||
```
|
||||
|
||||
`dangerouslyDisableDeviceAuth` 会禁用 Control UI 设备身份检查,并且是严重的安全降级。紧急使用后请尽快恢复。
|
||||
`dangerouslyDisableDeviceAuth` 会禁用 Control UI 设备身份检查,这是严重的安全降级。紧急使用后请尽快恢复。
|
||||
|
||||
受信任代理说明:
|
||||
trusted-proxy 说明:
|
||||
|
||||
- 成功的受信任代理认证可以允许**操作员** Control UI 会话在
|
||||
无设备身份的情况下接入
|
||||
- 成功的 trusted-proxy 认证可以允许**operator** Control UI 会话在没有设备身份的情况下进入
|
||||
- 这**不**适用于 node 角色的 Control UI 会话
|
||||
- 同主机的 local loopback 反向代理仍然不能满足受信任代理认证;请参见
|
||||
[受信任代理认证](/zh-CN/gateway/trusted-proxy-auth)
|
||||
- 同主机 loopback 反向代理仍然不能满足 trusted-proxy 认证;参见
|
||||
[Trusted proxy auth](/zh-CN/gateway/trusted-proxy-auth)
|
||||
|
||||
有关 HTTPS 设置指导,请参见 [Tailscale](/zh-CN/gateway/tailscale)。
|
||||
HTTPS 设置指导请参见 [Tailscale](/zh-CN/gateway/tailscale)。
|
||||
|
||||
## 内容安全策略
|
||||
|
||||
Control UI 使用严格的 `img-src` 策略:仅允许**同源**资源和 `data:` URL。远程 `http(s)` 及协议相对图片 URL 会被浏览器拒绝,并且不会发起网络请求。
|
||||
Control UI 采用严格的 `img-src` 策略:只允许**同源**资源和 `data:` URL。远程 `http(s)` 和协议相对的图像 URL 会被浏览器拒绝,并且不会发起网络获取请求。
|
||||
|
||||
这在实际中的含义是:
|
||||
这在实践中的含义是:
|
||||
|
||||
- 在相对路径下提供的头像和图片(例如 `/avatars/<id>`)仍可正常渲染。
|
||||
- 内联 `data:image/...` URL 仍可正常渲染(对协议内负载很有用)。
|
||||
- 由渠道元数据发出的远程头像 URL 会在 Control UI 的头像辅助层中被剥离,并替换为内置 logo / badge,因此受损或恶意渠道无法强制操作员浏览器发起任意远程图片请求。
|
||||
- 在相对路径下提供的头像和图像(例如 `/avatars/<id>`)仍然可以渲染。
|
||||
- 内联 `data:image/...` URL 仍然可以渲染(适用于协议内载荷)。
|
||||
- 由渠道元数据发出的远程头像 URL 会在 Control UI 的头像辅助工具中被剥离,并替换为内置 logo/badge,因此被攻破或恶意的渠道无法强迫 operator 浏览器发起任意远程图像请求。
|
||||
|
||||
你无需做任何改动即可获得此行为——它始终启用且不可配置。
|
||||
你无需做任何更改即可获得此行为——它始终启用,且不可配置。
|
||||
|
||||
## 头像路由认证
|
||||
|
||||
当 gateway 认证已配置时,Control UI 头像端点需要与其余 API 相同的 gateway token:
|
||||
配置了网关认证后,Control UI 头像端点需要与其余 API 相同的网关 token:
|
||||
|
||||
- `GET /avatar/<agentId>` 仅向已认证调用方返回头像图片。`GET /avatar/<agentId>?meta=1` 在相同规则下返回头像元数据。
|
||||
- 对任一路由的未认证请求都会被拒绝(与相邻的 assistant-media 路由保持一致)。这可防止头像路由在其他方面已受保护的主机上泄露智能体身份。
|
||||
- Control UI 本身在获取头像时会以 bearer 标头形式转发 gateway token,并使用已认证的 blob URL,因此图像仍可在仪表板中渲染。
|
||||
- `GET /avatar/<agentId>` 仅向已认证调用方返回头像图像。`GET /avatar/<agentId>?meta=1` 在相同规则下返回头像元数据。
|
||||
- 对这两个路由的未认证请求都会被拒绝(与相邻的助手媒体路由一致)。这可防止头像路由在其他方面受保护的主机上泄露智能体身份。
|
||||
- Control UI 本身会在获取头像时以 bearer 头转发网关 token,并使用已认证的 blob URL,因此图像仍可在仪表板中渲染。
|
||||
|
||||
如果你禁用了 gateway 认证(不建议在共享主机上这样做),头像路由也会变为未认证状态,与 gateway 其余部分保持一致。
|
||||
如果你禁用了网关认证(不建议在共享主机上这样做),头像路由也会变为未认证状态,这与网关其余部分保持一致。
|
||||
|
||||
## 构建 UI
|
||||
|
||||
Gateway 网关从 `dist/control-ui` 提供静态文件。使用以下命令构建:
|
||||
Gateway 网关从 `dist/control-ui` 提供静态文件。构建方式如下:
|
||||
|
||||
```bash
|
||||
pnpm ui:build
|
||||
```
|
||||
|
||||
可选的绝对 base(当你需要固定资源 URL 时):
|
||||
可选的绝对 base(当你希望使用固定资源 URL 时):
|
||||
|
||||
```bash
|
||||
OPENCLAW_CONTROL_UI_BASE_PATH=/openclaw/ pnpm ui:build
|
||||
```
|
||||
|
||||
用于本地开发(独立 dev server):
|
||||
用于本地开发(独立 dev 服务器):
|
||||
|
||||
```bash
|
||||
pnpm ui:dev
|
||||
@ -352,20 +297,18 @@ pnpm ui:dev
|
||||
|
||||
然后将 UI 指向你的 Gateway 网关 WS URL(例如 `ws://127.0.0.1:18789`)。
|
||||
|
||||
## 调试 / 测试:dev server + 远程 Gateway 网关
|
||||
## 调试/测试:dev 服务器 + 远程 Gateway 网关
|
||||
|
||||
Control UI 是静态文件;WebSocket 目标可配置,并且可以
|
||||
不同于 HTTP 源。当你希望在本地运行 Vite dev server,
|
||||
但 Gateway 网关运行在其他地方时,这会很方便。
|
||||
Control UI 是静态文件;WebSocket 目标可配置,并且可以与 HTTP 来源不同。当你希望在本地运行 Vite dev 服务器,而 Gateway 网关运行在其他地方时,这非常有用。
|
||||
|
||||
1. 启动 UI dev server:`pnpm ui:dev`
|
||||
2. 打开如下 URL:
|
||||
1. 启动 UI dev 服务器:`pnpm ui:dev`
|
||||
2. 打开类似以下的 URL:
|
||||
|
||||
```text
|
||||
http://localhost:5173/?gatewayUrl=ws://<gateway-host>:18789
|
||||
```
|
||||
|
||||
可选的一次性认证(如需要):
|
||||
可选的一次性认证(如有需要):
|
||||
|
||||
```text
|
||||
http://localhost:5173/?gatewayUrl=wss://<gateway-host>:18789#token=<gateway-token>
|
||||
@ -373,20 +316,17 @@ http://localhost:5173/?gatewayUrl=wss://<gateway-host>:18789#token=<gateway-toke
|
||||
|
||||
说明:
|
||||
|
||||
- `gatewayUrl` 会在加载后存储到 `localStorage` 中,并从 URL 中移除。
|
||||
- 应尽可能通过 URL 片段(`#token=...`)传递 `token`。片段不会发送到服务器,这样可以避免请求日志和 Referer 泄露。出于兼容性,旧版 `?token=` 查询参数仍会被导入一次,但仅作为回退,并会在启动后立即剥离。
|
||||
- `gatewayUrl` 会在加载后存储到 localStorage 中,并从 URL 中移除。
|
||||
- 应尽可能通过 URL 片段(`#token=...`)传递 `token`。片段不会发送到服务器,这可避免请求日志和 Referer 泄露。旧版 `?token=` 查询参数仍会出于兼容性被导入一次,但仅作为回退,并会在启动后立即移除。
|
||||
- `password` 仅保存在内存中。
|
||||
- 设置了 `gatewayUrl` 时,UI 不会回退到配置或环境凭证。
|
||||
- 设置了 `gatewayUrl` 后,UI 不会回退到配置或环境凭证。
|
||||
请显式提供 `token`(或 `password`)。缺少显式凭证会报错。
|
||||
- 当 Gateway 网关位于 TLS 后面时(Tailscale Serve、HTTPS 代理等),请使用 `wss://`。
|
||||
- `gatewayUrl` 仅在顶层窗口中接受(非嵌入式),以防止点击劫持。
|
||||
- 非 local loopback 的 Control UI 部署必须显式设置 `gateway.controlUi.allowedOrigins`
|
||||
(完整 origin)。这包括远程开发设置。
|
||||
- 除了严格受控的本地测试外,不要使用 `gateway.controlUi.allowedOrigins: ["*"]`。
|
||||
它表示允许任意浏览器 origin,而不是“匹配我正在
|
||||
使用的任意主机”。
|
||||
- `gateway.controlUi.dangerouslyAllowHostHeaderOriginFallback=true` 会启用
|
||||
Host 标头 origin 回退模式,但这是危险的安全模式。
|
||||
- `gatewayUrl` 仅在顶层窗口中接受(不能嵌入),以防止点击劫持。
|
||||
- 非 loopback 的 Control UI 部署必须显式设置 `gateway.controlUi.allowedOrigins`(完整 origin)。这也包括远程开发设置。
|
||||
- 除非是严格受控的本地测试,否则不要使用 `gateway.controlUi.allowedOrigins: ["*"]`。
|
||||
这表示允许任意浏览器 origin,而不是“匹配我正在使用的任何主机”。
|
||||
- `gateway.controlUi.dangerouslyAllowHostHeaderOriginFallback=true` 会启用 Host 头 origin 回退模式,但这是危险的安全模式。
|
||||
|
||||
示例:
|
||||
|
||||
@ -400,11 +340,11 @@ http://localhost:5173/?gatewayUrl=wss://<gateway-host>:18789#token=<gateway-toke
|
||||
}
|
||||
```
|
||||
|
||||
远程访问设置详情: [远程访问](/zh-CN/gateway/remote)。
|
||||
远程访问设置详情:参见 [远程访问](/zh-CN/gateway/remote)。
|
||||
|
||||
## 相关内容
|
||||
|
||||
- [Dashboard](/zh-CN/web/dashboard) — Gateway 网关仪表板
|
||||
- [Dashboard](/zh-CN/web/dashboard) — 网关仪表板
|
||||
- [WebChat](/zh-CN/web/webchat) — 基于浏览器的聊天界面
|
||||
- [TUI](/zh-CN/web/tui) — 终端用户界面
|
||||
- [健康检查](/zh-CN/gateway/health) — Gateway 网关健康监控
|
||||
- [Health Checks](/zh-CN/gateway/health) — 网关健康监控
|
||||
|
||||
Loading…
Reference in New Issue
Block a user