chore(i18n): refresh zh-CN translations
This commit is contained in:
parent
4653f3761d
commit
fbec7c5ae5
@ -1,28 +1,28 @@
|
||||
---
|
||||
read_when:
|
||||
- 你想管理智能体钩子
|
||||
- 你想检查钩子的可用性,或启用工作区钩子
|
||||
summary: '`openclaw hooks` 的 CLI 参考(智能体钩子)'
|
||||
- 你想要管理智能体钩子
|
||||
- 你想要检查钩子的可用性或启用工作区钩子
|
||||
summary: '`openclaw hooks`(智能体钩子)的 CLI 参考'
|
||||
title: 钩子
|
||||
x-i18n:
|
||||
generated_at: "2026-04-25T22:08:04Z"
|
||||
generated_at: "2026-04-27T06:55:58Z"
|
||||
model: gpt-5.4
|
||||
provider: openai
|
||||
source_hash: 874c3c7e7b603066209857e8b8b39bbe23eb8d1eda148025c74907c05bacd8f2
|
||||
source_hash: 71c03d264f07bab80af8237d3ac5366a221d17e54234597a66ecbacff3bab62d
|
||||
source_path: cli/hooks.md
|
||||
workflow: 15
|
||||
---
|
||||
|
||||
# `openclaw hooks`
|
||||
|
||||
管理智能体钩子(用于 `/new`、`/reset` 和 Gateway 网关启动等命令的事件驱动自动化)。
|
||||
管理智能体钩子(针对 `/new`、`/reset` 和 Gateway 网关启动等命令的事件驱动自动化)。
|
||||
|
||||
在不带任何子命令的情况下运行 `openclaw hooks`,等同于 `openclaw hooks list`。
|
||||
在不带子命令的情况下运行 `openclaw hooks`,等同于 `openclaw hooks list`。
|
||||
|
||||
相关内容:
|
||||
|
||||
- 钩子:[钩子](/zh-CN/automation/hooks)
|
||||
- 插件钩子:[Plugin hooks](/zh-CN/plugins/hooks)
|
||||
- 插件钩子:[插件钩子](/zh-CN/plugins/hooks)
|
||||
|
||||
## 列出所有钩子
|
||||
|
||||
@ -31,7 +31,7 @@ openclaw hooks list
|
||||
```
|
||||
|
||||
列出从工作区、托管、额外和内置目录中发现的所有钩子。
|
||||
在至少配置了一个内部钩子之前,Gateway 网关启动时不会加载内部钩子处理程序。
|
||||
在至少配置了一个内部钩子之前,Gateway 网关启动时不会加载内部钩子处理器。
|
||||
|
||||
**选项:**
|
||||
|
||||
@ -42,13 +42,13 @@ openclaw hooks list
|
||||
**示例输出:**
|
||||
|
||||
```
|
||||
Hooks (4/4 ready)
|
||||
Hooks(4/4 已就绪)
|
||||
|
||||
Ready:
|
||||
🚀 boot-md ✓ - Run BOOT.md on gateway startup
|
||||
📎 bootstrap-extra-files ✓ - Inject extra workspace bootstrap files during agent bootstrap
|
||||
📝 command-logger ✓ - Log all command events to a centralized audit file
|
||||
💾 session-memory ✓ - Save session context to memory when /new or /reset command is issued
|
||||
已就绪:
|
||||
🚀 boot-md ✓ - 在 Gateway 网关启动时运行 BOOT.md
|
||||
📎 bootstrap-extra-files ✓ - 在智能体引导期间注入额外的工作区引导文件
|
||||
📝 command-logger ✓ - 将所有命令事件记录到集中式审计文件
|
||||
💾 session-memory ✓ - 在发出 /new 或 /reset 命令时将会话上下文保存到 memory
|
||||
```
|
||||
|
||||
**示例(详细模式):**
|
||||
@ -92,28 +92,28 @@ openclaw hooks info session-memory
|
||||
**输出:**
|
||||
|
||||
```
|
||||
💾 session-memory ✓ Ready
|
||||
💾 session-memory ✓ 已就绪
|
||||
|
||||
Save session context to memory when /new or /reset command is issued
|
||||
在发出 /new 或 /reset 命令时将会话上下文保存到 memory
|
||||
|
||||
Details:
|
||||
详细信息:
|
||||
Source: openclaw-bundled
|
||||
Path: /path/to/openclaw/hooks/bundled/session-memory/HOOK.md
|
||||
Handler: /path/to/openclaw/hooks/bundled/session-memory/handler.ts
|
||||
Homepage: https://docs.openclaw.ai/automation/hooks#session-memory
|
||||
Events: command:new, command:reset
|
||||
|
||||
Requirements:
|
||||
要求:
|
||||
Config: ✓ workspace.dir
|
||||
```
|
||||
|
||||
## 检查钩子是否符合条件
|
||||
## 检查钩子可用性
|
||||
|
||||
```bash
|
||||
openclaw hooks check
|
||||
```
|
||||
|
||||
显示钩子符合条件状态的摘要(有多少已就绪,多少未就绪)。
|
||||
显示钩子可用性状态摘要(有多少已就绪,多少未就绪)。
|
||||
|
||||
**选项:**
|
||||
|
||||
@ -122,11 +122,11 @@ openclaw hooks check
|
||||
**示例输出:**
|
||||
|
||||
```
|
||||
Hooks Status
|
||||
Hooks 状态
|
||||
|
||||
Total hooks: 4
|
||||
Ready: 4
|
||||
Not ready: 0
|
||||
钩子总数:4
|
||||
已就绪:4
|
||||
未就绪:0
|
||||
```
|
||||
|
||||
## 启用钩子
|
||||
@ -135,9 +135,9 @@ Not ready: 0
|
||||
openclaw hooks enable <name>
|
||||
```
|
||||
|
||||
通过将特定钩子添加到你的配置中来启用它(默认是 `~/.openclaw/openclaw.json`)。
|
||||
通过将特定钩子添加到你的配置中(默认是 `~/.openclaw/openclaw.json`)来启用它。
|
||||
|
||||
**注意:** 工作区钩子默认处于禁用状态,必须先在这里或在配置中启用。由插件管理的钩子会在 `openclaw hooks list` 中显示为 `plugin:<id>`,不能在这里启用或禁用。请改为启用或禁用对应插件。
|
||||
**注意:** 工作区钩子默认禁用,需在这里或配置中启用。由插件管理的钩子会在 `openclaw hooks list` 中显示为 `plugin:<id>`,不能在这里启用或禁用。请改为启用或禁用对应插件。
|
||||
|
||||
**参数:**
|
||||
|
||||
@ -152,21 +152,20 @@ openclaw hooks enable session-memory
|
||||
**输出:**
|
||||
|
||||
```
|
||||
✓ Enabled hook: 💾 session-memory
|
||||
✓ 已启用钩子:💾 session-memory
|
||||
```
|
||||
|
||||
**它会执行以下操作:**
|
||||
|
||||
- 检查钩子是否存在且符合条件
|
||||
- 在你的配置中更新 `hooks.internal.entries.<name>.enabled = true`
|
||||
- 更新你配置中的 `hooks.internal.entries.<name>.enabled = true`
|
||||
- 将配置保存到磁盘
|
||||
|
||||
如果该钩子来自 `<workspace>/hooks/`,则必须完成这一步显式启用,
|
||||
Gateway 网关才会加载它。
|
||||
如果该钩子来自 `<workspace>/hooks/`,则必须执行此选择启用步骤,Gateway 网关才会加载它。
|
||||
|
||||
**启用后:**
|
||||
|
||||
- 重启 gateway,使钩子重新加载(在 macOS 上重启菜单栏应用,或在开发环境中重启你的 gateway 进程)。
|
||||
- 重启 Gateway 网关以重新加载钩子(在 macOS 上重启菜单栏应用,或在开发环境中重启你的 Gateway 网关进程)。
|
||||
|
||||
## 禁用钩子
|
||||
|
||||
@ -189,12 +188,12 @@ openclaw hooks disable command-logger
|
||||
**输出:**
|
||||
|
||||
```
|
||||
⏸ Disabled hook: 📝 command-logger
|
||||
⏸ 已禁用钩子:📝 command-logger
|
||||
```
|
||||
|
||||
**禁用后:**
|
||||
|
||||
- 重启 gateway,使钩子重新加载
|
||||
- 重启 Gateway 网关以重新加载钩子
|
||||
|
||||
## 说明
|
||||
|
||||
@ -204,24 +203,18 @@ openclaw hooks disable command-logger
|
||||
## 安装钩子包
|
||||
|
||||
```bash
|
||||
openclaw plugins install <package> # 优先 ClawHub,然后是 npm
|
||||
openclaw plugins install <package> --pin # 固定版本
|
||||
openclaw plugins install <path> # 本地路径
|
||||
openclaw plugins install <package> # ClawHub first, then npm
|
||||
openclaw plugins install <package> --pin # pin version
|
||||
openclaw plugins install <path> # local path
|
||||
```
|
||||
|
||||
通过统一的插件安装器安装钩子包。
|
||||
|
||||
`openclaw hooks install` 仍然可用,作为兼容性别名,但它会打印弃用警告,
|
||||
并转发到 `openclaw plugins install`。
|
||||
`openclaw hooks install` 仍然可用作兼容别名,但它会打印弃用警告,并转发到 `openclaw plugins install`。
|
||||
|
||||
Npm 规格必须是**仅注册表**形式(包名 + 可选的**精确版本**或
|
||||
**dist-tag**)。Git/URL/file 规格和 semver 范围会被拒绝。出于安全考虑,
|
||||
依赖安装会以项目本地方式运行,并使用 `--ignore-scripts`,即使你的
|
||||
shell 配置了全局 npm 安装设置也是如此。
|
||||
Npm 规格只支持**注册表来源**(包名 + 可选的**精确版本**或 **dist-tag**)。Git/URL/file 规格和 semver 范围会被拒绝。为确保安全,依赖安装会在项目本地使用 `--ignore-scripts` 运行,即使你的 shell 配置了全局 npm 安装设置也是如此。
|
||||
|
||||
裸规格和 `@latest` 会保持在稳定通道上。如果 npm 将其中任一解析为预发布版本,
|
||||
OpenClaw 会停止并要求你显式选择加入,例如使用 `@beta`/`@rc` 这样的
|
||||
预发布标签,或精确的预发布版本。
|
||||
裸规格和 `@latest` 会保持在稳定轨道上。如果 npm 将其中任一解析为预发布版本,OpenClaw 会停止并要求你通过预发布标签(例如 `@beta`/`@rc`)或精确的预发布版本显式选择加入。
|
||||
|
||||
**它会执行以下操作:**
|
||||
|
||||
@ -232,7 +225,7 @@ OpenClaw 会停止并要求你显式选择加入,例如使用 `@beta`/`@rc`
|
||||
**选项:**
|
||||
|
||||
- `-l, --link`:链接本地目录而不是复制(将其添加到 `hooks.internal.load.extraDirs`)
|
||||
- `--pin`:将 npm 安装记录为 `hooks.internal.installs` 中精确解析后的 `name@version`
|
||||
- `--pin`:将 npm 安装以精确解析后的 `name@version` 记录到 `hooks.internal.installs`
|
||||
|
||||
**支持的归档格式:** `.zip`、`.tgz`、`.tar.gz`、`.tar`
|
||||
|
||||
@ -252,7 +245,7 @@ openclaw plugins install @openclaw/my-hook-pack
|
||||
openclaw plugins install -l ./my-hook-pack
|
||||
```
|
||||
|
||||
已链接的钩子包会被视为来自操作员配置目录的托管钩子,而不是工作区钩子。
|
||||
已链接的钩子包会被视为来自运维者配置目录的托管钩子,而不是工作区钩子。
|
||||
|
||||
## 更新钩子包
|
||||
|
||||
@ -261,25 +254,22 @@ openclaw plugins update <id>
|
||||
openclaw plugins update --all
|
||||
```
|
||||
|
||||
通过统一的插件更新器更新被跟踪的基于 npm 的钩子包。
|
||||
通过统一的插件更新器更新已跟踪的基于 npm 的钩子包。
|
||||
|
||||
`openclaw hooks update` 仍然可用,作为兼容性别名,但它会打印弃用警告,
|
||||
并转发到 `openclaw plugins update`。
|
||||
`openclaw hooks update` 仍然可用作兼容别名,但它会打印弃用警告,并转发到 `openclaw plugins update`。
|
||||
|
||||
**选项:**
|
||||
|
||||
- `--all`:更新所有被跟踪的钩子包
|
||||
- `--dry-run`:显示将会发生的更改,但不实际写入
|
||||
- `--all`:更新所有已跟踪的钩子包
|
||||
- `--dry-run`:显示将会发生的更改,但不写入
|
||||
|
||||
当存在已存储的完整性哈希且获取到的制品哈希发生变化时,
|
||||
OpenClaw 会打印警告,并在继续前请求确认。在 CI/非交互式运行中,
|
||||
可使用全局 `--yes` 跳过提示。
|
||||
当存在已存储的完整性哈希且获取到的制品哈希发生变化时,OpenClaw 会打印警告,并在继续前请求确认。在 CI / 非交互式运行中,可使用全局 `--yes` 跳过提示。
|
||||
|
||||
## 内置钩子
|
||||
|
||||
### session-memory
|
||||
|
||||
当你发出 `/new` 或 `/reset` 时,将会话上下文保存到 memory 中。
|
||||
当你发出 `/new` 或 `/reset` 时,将会话上下文保存到 memory。
|
||||
|
||||
**启用:**
|
||||
|
||||
@ -305,7 +295,7 @@ openclaw hooks enable bootstrap-extra-files
|
||||
|
||||
### command-logger
|
||||
|
||||
将所有命令事件记录到集中式审计文件中。
|
||||
将所有命令事件记录到集中式审计文件。
|
||||
|
||||
**启用:**
|
||||
|
||||
@ -332,7 +322,7 @@ grep '"action":"new"' ~/.openclaw/logs/commands.log | jq .
|
||||
|
||||
### boot-md
|
||||
|
||||
在 gateway 启动时运行 `BOOT.md`(在渠道启动之后)。
|
||||
在 Gateway 网关启动时(渠道启动后)运行 `BOOT.md`。
|
||||
|
||||
**事件**:`gateway:startup`
|
||||
|
||||
|
||||
@ -1,15 +1,15 @@
|
||||
---
|
||||
read_when:
|
||||
- 你想要自动化的服务器部署,并进行安全加固
|
||||
- 你需要通过 VPN 访问的防火墙隔离设置
|
||||
- 你正在部署到远程 Debian/Ubuntu 服务器
|
||||
summary: 使用 Ansible、Tailscale VPN 和防火墙隔离实现自动化加固的 OpenClaw 安装
|
||||
- 你需要通过 VPN 访问的防火墙隔离式设置
|
||||
- 你要部署到远程 Debian/Ubuntu 服务器
|
||||
summary: 使用 Ansible、Tailscale VPN 和防火墙隔离实现自动化、强化安全的 OpenClaw 安装
|
||||
title: Ansible
|
||||
x-i18n:
|
||||
generated_at: "2026-04-20T18:29:36Z"
|
||||
generated_at: "2026-04-27T06:55:58Z"
|
||||
model: gpt-5.4
|
||||
provider: openai
|
||||
source_hash: 2a23374c971a1f3163dd18c32e553ebaad55b2542c1f25f49bcc9ae464d679e8
|
||||
source_hash: 2fa6c215bc2d4a9d032438bead4336bc10433eb8c40e206d72224c7009c7dabf
|
||||
source_path: install/ansible.md
|
||||
workflow: 15
|
||||
---
|
||||
@ -22,7 +22,7 @@ x-i18n:
|
||||
[openclaw-ansible](https://github.com/openclaw/openclaw-ansible) 仓库是 Ansible 部署的权威来源。本页仅提供快速概览。
|
||||
</Info>
|
||||
|
||||
## 前提条件
|
||||
## 先决条件
|
||||
|
||||
| 要求 | 详情 |
|
||||
| ----------- | --------------------------------------------------------- |
|
||||
@ -34,11 +34,11 @@ x-i18n:
|
||||
## 你将获得什么
|
||||
|
||||
- **防火墙优先的安全性** —— UFW + Docker 隔离(仅 SSH + Tailscale 可访问)
|
||||
- **Tailscale VPN** —— 无需公开暴露服务即可安全远程访问
|
||||
- **Docker** —— 隔离的沙箱容器,仅绑定到 localhost
|
||||
- **Tailscale VPN** —— 安全的远程访问,无需将服务公开暴露到互联网
|
||||
- **Docker** —— 隔离的沙箱容器,仅绑定 localhost
|
||||
- **纵深防御** —— 4 层安全架构
|
||||
- **Systemd 集成** —— 开机自动启动并带有加固配置
|
||||
- **一条命令即可完成设置** —— 几分钟内完成完整部署
|
||||
- **Systemd 集成** —— 开机自动启动并带有安全加固
|
||||
- **一条命令完成设置** —— 几分钟内完成完整部署
|
||||
|
||||
## 快速开始
|
||||
|
||||
@ -48,7 +48,7 @@ x-i18n:
|
||||
curl -fsSL https://raw.githubusercontent.com/openclaw/openclaw-ansible/main/install.sh | bash
|
||||
```
|
||||
|
||||
## 将安装的内容
|
||||
## 将安装哪些内容
|
||||
|
||||
Ansible playbook 会安装并配置:
|
||||
|
||||
@ -60,7 +60,7 @@ Ansible playbook 会安装并配置:
|
||||
6. **Systemd 服务** —— 自动启动并带有安全加固
|
||||
|
||||
<Note>
|
||||
Gateway 网关直接在主机上运行(不在 Docker 中)。智能体沙箱隔离是可选的;此 playbook 安装 Docker,因为它是默认的沙箱后端。详情及其他后端请参阅 [沙箱隔离](/zh-CN/gateway/sandboxing)。
|
||||
Gateway 网关直接在主机上运行(不在 Docker 中)。智能体沙箱隔离是可选的;此 playbook 安装 Docker 是因为它是默认的沙箱后端。详情和其他后端请参见 [沙箱隔离](/zh-CN/gateway/sandboxing)。
|
||||
</Note>
|
||||
|
||||
## 安装后设置
|
||||
@ -87,7 +87,7 @@ Gateway 网关直接在主机上运行(不在 Docker 中)。智能体沙箱
|
||||
```
|
||||
</Step>
|
||||
<Step title="连接到 Tailscale">
|
||||
加入你的 VPN mesh 以进行安全远程访问。
|
||||
加入你的 VPN mesh,以实现安全远程访问。
|
||||
</Step>
|
||||
</Steps>
|
||||
|
||||
@ -103,7 +103,7 @@ sudo journalctl -u openclaw -f
|
||||
# 重启 Gateway 网关
|
||||
sudo systemctl restart openclaw
|
||||
|
||||
# 提供商登录(以 openclaw 用户运行)
|
||||
# 提供商登录(以 openclaw 用户身份运行)
|
||||
sudo -i -u openclaw
|
||||
openclaw channels login
|
||||
```
|
||||
@ -123,16 +123,16 @@ openclaw channels login
|
||||
nmap -p- YOUR_SERVER_IP
|
||||
```
|
||||
|
||||
应该只有 22 端口(SSH)处于开放状态。所有其他服务(Gateway 网关、Docker)都已被锁定。
|
||||
应当只有端口 22(SSH)开放。所有其他服务(Gateway 网关、Docker)都已被锁定。
|
||||
|
||||
安装 Docker 是为了智能体沙箱(隔离的工具执行),而不是为了运行 Gateway 网关本身。有关沙箱配置,请参阅 [多智能体沙箱与工具](/zh-CN/tools/multi-agent-sandbox-tools)。
|
||||
安装 Docker 是为了智能体沙箱(隔离的工具执行),而不是为了运行 Gateway 网关本身。有关沙箱配置,请参见 [多智能体沙箱与工具](/zh-CN/tools/multi-agent-sandbox-tools)。
|
||||
|
||||
## 手动安装
|
||||
|
||||
如果你更希望手动控制自动化过程:
|
||||
如果你更喜欢手动控制自动化过程:
|
||||
|
||||
<Steps>
|
||||
<Step title="安装前提依赖">
|
||||
<Step title="安装先决条件">
|
||||
```bash
|
||||
sudo apt update && sudo apt install -y ansible git
|
||||
```
|
||||
@ -156,7 +156,7 @@ nmap -p- YOUR_SERVER_IP
|
||||
或者,直接运行,然后在之后手动执行设置脚本:
|
||||
```bash
|
||||
ansible-playbook playbook.yml --ask-become-pass
|
||||
# 然后运行:/tmp/openclaw-setup.sh
|
||||
# Then run: /tmp/openclaw-setup.sh
|
||||
```
|
||||
|
||||
</Step>
|
||||
@ -164,24 +164,24 @@ nmap -p- YOUR_SERVER_IP
|
||||
|
||||
## 更新
|
||||
|
||||
Ansible 安装器会将 OpenClaw 设置为手动更新。标准更新流程请参阅 [更新](/zh-CN/install/updating)。
|
||||
Ansible 安装器会将 OpenClaw 设置为手动更新。标准更新流程请参见 [更新](/zh-CN/install/updating)。
|
||||
|
||||
如需重新运行 Ansible playbook(例如用于配置变更):
|
||||
要重新运行 Ansible playbook(例如应用配置更改):
|
||||
|
||||
```bash
|
||||
cd openclaw-ansible
|
||||
./run-playbook.sh
|
||||
```
|
||||
|
||||
这是幂等的,可以安全地多次运行。
|
||||
这是幂等的,并且可以安全地多次运行。
|
||||
|
||||
## 故障排除
|
||||
|
||||
<AccordionGroup>
|
||||
<Accordion title="防火墙阻止了我的连接">
|
||||
- 请先确保你可以通过 Tailscale VPN 访问
|
||||
- 始终允许 SSH 访问(22 端口)
|
||||
- Gateway 网关按设计仅能通过 Tailscale 访问
|
||||
- 确保你可以先通过 Tailscale VPN 访问
|
||||
- 始终允许 SSH 访问(端口 22)
|
||||
- Gateway 网关按设计仅可通过 Tailscale 访问
|
||||
</Accordion>
|
||||
<Accordion title="服务无法启动">
|
||||
```bash
|
||||
@ -213,7 +213,7 @@ cd openclaw-ansible
|
||||
|
||||
</Accordion>
|
||||
<Accordion title="提供商登录失败">
|
||||
请确保你正在以 `openclaw` 用户身份运行:
|
||||
确保你是以 `openclaw` 用户身份运行:
|
||||
```bash
|
||||
sudo -i -u openclaw
|
||||
openclaw channels login
|
||||
@ -223,7 +223,7 @@ cd openclaw-ansible
|
||||
|
||||
## 高级配置
|
||||
|
||||
有关详细的安全架构和故障排除信息,请参阅 openclaw-ansible 仓库:
|
||||
有关详细的安全架构和故障排除信息,请参见 openclaw-ansible 仓库:
|
||||
|
||||
- [安全架构](https://github.com/openclaw/openclaw-ansible/blob/main/docs/security.md)
|
||||
- [技术细节](https://github.com/openclaw/openclaw-ansible/blob/main/docs/architecture.md)
|
||||
@ -234,4 +234,4 @@ cd openclaw-ansible
|
||||
- [openclaw-ansible](https://github.com/openclaw/openclaw-ansible) —— 完整部署指南
|
||||
- [Docker](/zh-CN/install/docker) —— 容器化的 Gateway 网关设置
|
||||
- [沙箱隔离](/zh-CN/gateway/sandboxing) —— 智能体沙箱配置
|
||||
- [多智能体沙箱与工具](/zh-CN/tools/multi-agent-sandbox-tools) —— 按智能体隔离
|
||||
- [多智能体沙箱与工具](/zh-CN/tools/multi-agent-sandbox-tools) —— 按智能体进行隔离
|
||||
|
||||
208
docs/zh-CN/pi.md
208
docs/zh-CN/pi.md
@ -1,30 +1,30 @@
|
||||
---
|
||||
read_when:
|
||||
- 了解 OpenClaw 中 Pi SDK 集成的设计
|
||||
- 修改 Pi 的智能体会话生命周期、工具或 provider 接线
|
||||
summary: OpenClaw 内嵌 Pi 智能体集成与会话生命周期的架构
|
||||
- 理解 OpenClaw 中 Pi SDK 集成设计
|
||||
- 修改 Pi 的智能体会话生命周期、工具能力或提供商接线逻辑
|
||||
summary: OpenClaw 内置 Pi 智能体集成的架构和会话生命周期
|
||||
title: Pi 集成架构
|
||||
x-i18n:
|
||||
generated_at: "2026-04-27T06:05:36Z"
|
||||
generated_at: "2026-04-27T06:55:56Z"
|
||||
model: gpt-5.4
|
||||
provider: openai
|
||||
source_hash: 42dff5d5a5d8a8c4af724c70a8864346f6ef9ff0b04dbc4fb3149685b2eb64cf
|
||||
source_hash: 0b155cd5296875f2f187c68c6929c48aba27cef047f0caad74f560bcde5533e5
|
||||
source_path: pi.md
|
||||
workflow: 15
|
||||
---
|
||||
|
||||
OpenClaw 与 [pi-coding-agent](https://github.com/badlogic/pi-mono/tree/main/packages/coding-agent) 及其同级包(`pi-ai`、`pi-agent-core`、`pi-tui`)集成,为其 AI 智能体能力提供支持。
|
||||
OpenClaw 通过集成 [pi-coding-agent](https://github.com/badlogic/pi-mono/tree/main/packages/coding-agent) 及其同级包(`pi-ai`、`pi-agent-core`、`pi-tui`)来驱动其 AI 智能体能力。
|
||||
|
||||
## 概览
|
||||
|
||||
OpenClaw 使用 pi SDK,将一个 AI 编码智能体嵌入到其消息 Gateway 网关架构中。OpenClaw 不会将 pi 作为子进程启动,也不会使用 RPC 模式,而是直接导入并通过 `createAgentSession()` 实例化 pi 的 `AgentSession`。这种嵌入式方法提供了:
|
||||
OpenClaw 使用 pi SDK 将一个 AI 编码智能体嵌入到其 Gateway 网关消息架构中。OpenClaw 并不是将 pi 作为子进程启动,也不是使用 RPC 模式,而是直接导入并通过 `createAgentSession()` 实例化 pi 的 `AgentSession`。这种嵌入式方式提供了:
|
||||
|
||||
- 对会话生命周期和事件处理的完整控制
|
||||
- 对会话生命周期和事件处理的完全控制
|
||||
- 自定义工具注入(消息、沙箱、渠道特定操作)
|
||||
- 按渠道/上下文进行系统提示自定义
|
||||
- 按渠道/上下文定制系统提示词
|
||||
- 支持分支/压缩的会话持久化
|
||||
- 带故障转移的多账号 auth profile 轮换
|
||||
- 与 provider 无关的模型切换
|
||||
- 支持故障转移的多账户认证配置轮换
|
||||
- 与提供商无关的模型切换
|
||||
|
||||
## 包依赖
|
||||
|
||||
@ -37,12 +37,12 @@ OpenClaw 使用 pi SDK,将一个 AI 编码智能体嵌入到其消息 Gateway
|
||||
}
|
||||
```
|
||||
|
||||
| 包 | 用途 |
|
||||
| ------------------- | ------------------------------------------------------------------------------------------------------ |
|
||||
| `pi-ai` | 核心 LLM 抽象:`Model`、`streamSimple`、消息类型、provider API |
|
||||
| `pi-agent-core` | Agent loop、工具执行、`AgentMessage` 类型 |
|
||||
| `pi-coding-agent` | 高级 SDK:`createAgentSession`、`SessionManager`、`AuthStorage`、`ModelRegistry`、内置工具 |
|
||||
| `pi-tui` | 终端 UI 组件(用于 OpenClaw 的本地 TUI 模式) |
|
||||
| 包 | 用途 |
|
||||
| ----------------- | ------------------------------------------------------------------------------------------------------ |
|
||||
| `pi-ai` | 核心 LLM 抽象:`Model`、`streamSimple`、消息类型、提供商 API |
|
||||
| `pi-agent-core` | Agent loop、工具执行、`AgentMessage` 类型 |
|
||||
| `pi-coding-agent` | 高层 SDK:`createAgentSession`、`SessionManager`、`AuthStorage`、`ModelRegistry`、内置工具 |
|
||||
| `pi-tui` | 终端 UI 组件(用于 OpenClaw 的本地 TUI 模式) |
|
||||
|
||||
## 文件结构
|
||||
|
||||
@ -52,67 +52,67 @@ src/agents/
|
||||
├── pi-embedded-runner/
|
||||
│ ├── run.ts # 主入口:runEmbeddedPiAgent()
|
||||
│ ├── run/
|
||||
│ │ ├── attempt.ts # 带会话设置的单次尝试逻辑
|
||||
│ │ ├── attempt.ts # 含会话设置的单次尝试逻辑
|
||||
│ │ ├── params.ts # RunEmbeddedPiAgentParams 类型
|
||||
│ │ ├── payloads.ts # 从运行结果构建响应载荷
|
||||
│ │ ├── images.ts # Vision 模型图像注入
|
||||
│ │ ├── payloads.ts # 从运行结果构建响应负载
|
||||
│ │ ├── images.ts # 视觉模型图像注入
|
||||
│ │ └── types.ts # EmbeddedRunAttemptResult
|
||||
│ ├── abort.ts # 中止错误检测
|
||||
│ ├── abort.ts # Abort 错误检测
|
||||
│ ├── cache-ttl.ts # 用于上下文裁剪的缓存 TTL 跟踪
|
||||
│ ├── compact.ts # 手动/自动压缩逻辑
|
||||
│ ├── extensions.ts # 为嵌入式运行加载 pi 扩展
|
||||
│ ├── extra-params.ts # provider 特定流式参数
|
||||
│ ├── google.ts # Google/Gemini 回合顺序修复
|
||||
│ ├── extra-params.ts # 提供商特定的流式参数
|
||||
│ ├── google.ts # Google/Gemini 轮次顺序修复
|
||||
│ ├── history.ts # 历史记录限制(私信 vs 群组)
|
||||
│ ├── lanes.ts # 会话/全局命令通道
|
||||
│ ├── logger.ts # 子系统日志记录器
|
||||
│ ├── model.ts # 通过 ModelRegistry 解析模型
|
||||
│ ├── runs.ts # 活动运行跟踪、中止、队列
|
||||
│ ├── sandbox-info.ts # 用于系统提示的沙箱信息
|
||||
│ ├── runs.ts # 活动运行跟踪、Abort、队列
|
||||
│ ├── sandbox-info.ts # 用于系统提示词的沙箱信息
|
||||
│ ├── session-manager-cache.ts # SessionManager 实例缓存
|
||||
│ ├── session-manager-init.ts # 会话文件初始化
|
||||
│ ├── system-prompt.ts # 系统提示构建器
|
||||
│ ├── tool-split.ts # 将工具拆分为 builtIn 与 custom
|
||||
│ ├── system-prompt.ts # 系统提示词构建器
|
||||
│ ├── tool-split.ts # 将工具拆分为 builtIn 和 custom
|
||||
│ ├── types.ts # EmbeddedPiAgentMeta、EmbeddedPiRunResult
|
||||
│ └── utils.ts # ThinkLevel 映射、错误说明
|
||||
│ └── utils.ts # ThinkLevel 映射、错误描述
|
||||
├── pi-embedded-subscribe.ts # 会话事件订阅/分发
|
||||
├── pi-embedded-subscribe.types.ts # SubscribeEmbeddedPiSessionParams
|
||||
├── pi-embedded-subscribe.handlers.ts # 事件处理器工厂
|
||||
├── pi-embedded-subscribe.handlers.lifecycle.ts
|
||||
├── pi-embedded-subscribe.handlers.types.ts
|
||||
├── pi-embedded-block-chunker.ts # 流式分块回复切分
|
||||
├── pi-embedded-messaging.ts # 消息工具发送跟踪
|
||||
├── pi-embedded-helpers.ts # 错误分类、回合验证
|
||||
├── pi-embedded-block-chunker.ts # 流式分块回复切块
|
||||
├── pi-embedded-messaging.ts # 消息工具已发送跟踪
|
||||
├── pi-embedded-helpers.ts # 错误分类、轮次校验
|
||||
├── pi-embedded-helpers/ # 辅助模块
|
||||
├── pi-embedded-utils.ts # 格式化工具
|
||||
├── pi-tools.ts # createOpenClawCodingTools()
|
||||
├── pi-tools.abort.ts # 工具的 AbortSignal 包装
|
||||
├── pi-tools.abort.ts # 工具的 AbortSignal 封装
|
||||
├── pi-tools.policy.ts # 工具允许列表/拒绝列表策略
|
||||
├── pi-tools.read.ts # Read 工具自定义
|
||||
├── pi-tools.schema.ts # 工具 schema 规范化
|
||||
├── pi-tools.read.ts # read 工具定制
|
||||
├── pi-tools.schema.ts # 工具 schema 标准化
|
||||
├── pi-tools.types.ts # AnyAgentTool 类型别名
|
||||
├── pi-tool-definition-adapter.ts # AgentTool -> ToolDefinition 适配器
|
||||
├── pi-settings.ts # 设置覆盖
|
||||
├── pi-hooks/ # 自定义 pi 钩子
|
||||
│ ├── compaction-safeguard.ts # Safeguard 扩展
|
||||
│ ├── compaction-safeguard.ts # 保护扩展
|
||||
│ ├── compaction-safeguard-runtime.ts
|
||||
│ ├── context-pruning.ts # 缓存 TTL 上下文裁剪扩展
|
||||
│ └── context-pruning/
|
||||
├── model-auth.ts # auth profile 解析
|
||||
├── auth-profiles.ts # 配置档存储、冷却、故障转移
|
||||
├── model-auth.ts # 认证配置解析
|
||||
├── auth-profiles.ts # 配置存储、冷却、故障转移
|
||||
├── model-selection.ts # 默认模型解析
|
||||
├── models-config.ts # models.json 生成
|
||||
├── model-catalog.ts # 模型目录缓存
|
||||
├── context-window-guard.ts # 上下文窗口验证
|
||||
├── context-window-guard.ts # 上下文窗口校验
|
||||
├── failover-error.ts # FailoverError 类
|
||||
├── defaults.ts # DEFAULT_PROVIDER、DEFAULT_MODEL
|
||||
├── system-prompt.ts # buildAgentSystemPrompt()
|
||||
├── system-prompt-params.ts # 系统提示参数解析
|
||||
├── system-prompt-params.ts # 系统提示词参数解析
|
||||
├── system-prompt-report.ts # 调试报告生成
|
||||
├── tool-summaries.ts # 工具描述摘要
|
||||
├── tool-policy.ts # 工具策略解析
|
||||
├── transcript-policy.ts # 转录验证策略
|
||||
├── skills.ts # Skills 快照/提示构建
|
||||
├── transcript-policy.ts # 转录校验策略
|
||||
├── skills.ts # Skills 快照/提示词构建
|
||||
├── skills/ # Skills 子系统
|
||||
├── sandbox.ts # 沙箱上下文解析
|
||||
├── sandbox/ # 沙箱子系统
|
||||
@ -134,7 +134,7 @@ src/agents/
|
||||
└── ...
|
||||
```
|
||||
|
||||
渠道特定的消息操作运行时现在位于插件自有扩展目录中,而不是 `src/agents/tools` 下,例如:
|
||||
渠道特定的消息操作运行时代码现在位于各插件自有的扩展目录中,而不再位于 `src/agents/tools` 下,例如:
|
||||
|
||||
- Discord 插件操作运行时文件
|
||||
- Slack 插件操作运行时文件
|
||||
@ -143,7 +143,7 @@ src/agents/
|
||||
|
||||
## 核心集成流程
|
||||
|
||||
### 1. 运行内嵌智能体
|
||||
### 1. 运行嵌入式智能体
|
||||
|
||||
主入口是 `pi-embedded-runner/run.ts` 中的 `runEmbeddedPiAgent()`:
|
||||
|
||||
@ -169,7 +169,7 @@ const result = await runEmbeddedPiAgent({
|
||||
|
||||
### 2. 创建会话
|
||||
|
||||
在 `runEmbeddedAttempt()`(由 `runEmbeddedPiAgent()` 调用)内部,会使用 pi SDK:
|
||||
在 `runEmbeddedAttempt()`(由 `runEmbeddedPiAgent()` 调用)内部,使用了 pi SDK:
|
||||
|
||||
```typescript
|
||||
import {
|
||||
@ -225,39 +225,39 @@ const subscription = subscribeEmbeddedPiSession({
|
||||
|
||||
处理的事件包括:
|
||||
|
||||
- `message_start` / `message_end` / `message_update`(流式文本/thinking)
|
||||
- `message_start` / `message_end` / `message_update`(流式文本/思维)
|
||||
- `tool_execution_start` / `tool_execution_update` / `tool_execution_end`
|
||||
- `turn_start` / `turn_end`
|
||||
- `agent_start` / `agent_end`
|
||||
- `compaction_start` / `compaction_end`
|
||||
|
||||
### 4. 提示输入
|
||||
### 4. 发送提示
|
||||
|
||||
设置完成后,会向会话发送提示:
|
||||
完成设置后,会向会话发送提示:
|
||||
|
||||
```typescript
|
||||
await session.prompt(effectivePrompt, { images: imageResult.images });
|
||||
```
|
||||
|
||||
SDK 会处理完整的 Agent loop:发送给 LLM、执行工具调用、流式返回响应。
|
||||
SDK 会处理完整的 Agent loop:发送到 LLM、执行工具调用、流式传输响应。
|
||||
|
||||
图像注入是提示局部的:OpenClaw 会从当前提示中加载图像引用,并仅通过该回合的 `images` 传入。它不会重新扫描更早的历史回合来重新注入图像载荷。
|
||||
图像注入是提示词局部的:OpenClaw 会从当前提示词中加载图像引用,并仅通过 `images` 为当前这一轮传递。它不会重新扫描更早的历史轮次来重新注入图像负载。
|
||||
|
||||
## 工具架构
|
||||
|
||||
### 工具流水线
|
||||
|
||||
1. **基础工具**:pi 的 `codingTools`(read、bash、edit、write)
|
||||
2. **自定义替换**:OpenClaw 用 `exec`/`process` 替换 bash,并为沙箱自定义 read/edit/write
|
||||
3. **OpenClaw 工具**:消息、browser、canvas、sessions、cron、gateway 等
|
||||
2. **自定义替换**:OpenClaw 用 `exec`/`process` 替换 bash,并为沙箱定制 read/edit/write
|
||||
3. **OpenClaw 工具**:消息、浏览器、画布、会话、cron、Gateway 网关等
|
||||
4. **渠道工具**:Discord/Telegram/Slack/WhatsApp 特定操作工具
|
||||
5. **策略过滤**:按配置档、provider、智能体、组、沙箱策略过滤工具
|
||||
6. **Schema 规范化**:为 Gemini/OpenAI 的特殊情况清理 schema
|
||||
7. **AbortSignal 包装**:为工具包装以支持 abort signal
|
||||
5. **策略过滤**:根据配置、提供商、智能体、群组、沙箱策略过滤工具
|
||||
6. **Schema 标准化**:针对 Gemini/OpenAI 的特殊情况清理 schema
|
||||
7. **AbortSignal 封装**:封装工具以遵循 Abort 信号
|
||||
|
||||
### 工具定义适配器
|
||||
|
||||
pi-agent-core 的 `AgentTool` 与 pi-coding-agent 的 `ToolDefinition` 在 `execute` 签名上不同。`pi-tool-definition-adapter.ts` 中的适配器会桥接两者:
|
||||
pi-agent-core 的 `AgentTool` 与 pi-coding-agent 的 `ToolDefinition` 在 `execute` 签名上不同。`pi-tool-definition-adapter.ts` 中的适配器负责桥接它们:
|
||||
|
||||
```typescript
|
||||
export function toToolDefinitions(tools: AnyAgentTool[]): ToolDefinition[] {
|
||||
@ -276,24 +276,24 @@ export function toToolDefinitions(tools: AnyAgentTool[]): ToolDefinition[] {
|
||||
|
||||
### 工具拆分策略
|
||||
|
||||
`splitSdkTools()` 会通过 `customTools` 传入所有工具:
|
||||
`splitSdkTools()` 通过 `customTools` 传递所有工具:
|
||||
|
||||
```typescript
|
||||
export function splitSdkTools(options: { tools: AnyAgentTool[]; sandboxEnabled: boolean }) {
|
||||
return {
|
||||
builtInTools: [], // 为空。我们会覆盖所有内容
|
||||
builtInTools: [], // 为空。我们覆盖所有内容
|
||||
customTools: toToolDefinitions(options.tools),
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
这可确保 OpenClaw 的策略过滤、沙箱集成和扩展工具集在不同 provider 间保持一致。
|
||||
这可确保 OpenClaw 的策略过滤、沙箱集成和扩展工具集在各个提供商之间保持一致。
|
||||
|
||||
## 系统提示构建
|
||||
## 系统提示词构建
|
||||
|
||||
系统提示在 `buildAgentSystemPrompt()`(`system-prompt.ts`)中构建。它会组装一个完整提示,包含 Tooling、Tool Call Style、安全护栏、OpenClaw CLI 参考、Skills、文档、工作区、沙箱、消息、回复标签、语音、静默回复、心跳、运行时元数据,以及在启用时加入的 Memory 和 Reactions,还可包含可选的上下文文件和额外系统提示内容。对于子智能体使用的最小提示模式,会裁剪这些部分。
|
||||
系统提示词在 `buildAgentSystemPrompt()`(`system-prompt.ts`)中构建。它会组装一个完整提示词,包含 Tooling、工具调用风格、安全护栏、OpenClaw CLI 参考、Skills、文档、工作区、沙箱、消息、回复标签、语气、静默回复、心跳、运行时元数据,以及在启用时包含的 Memory 和 Reactions,还包括可选的上下文文件和额外系统提示词内容。对于子智能体使用的最小提示词模式,会对这些部分进行裁剪。
|
||||
|
||||
该提示会在会话创建后通过 `applySystemPromptOverrideToSession()` 应用:
|
||||
系统提示词会在创建会话后通过 `applySystemPromptOverrideToSession()` 应用:
|
||||
|
||||
```typescript
|
||||
const systemPromptOverride = createSystemPromptOverride(appendPrompt);
|
||||
@ -304,17 +304,17 @@ applySystemPromptOverrideToSession(session, systemPromptOverride);
|
||||
|
||||
### 会话文件
|
||||
|
||||
会话是带树结构(通过 id/parentId 关联)的 JSONL 文件。pi 的 `SessionManager` 负责持久化:
|
||||
会话是具有树状结构的 JSONL 文件(通过 id/parentId 链接)。pi 的 `SessionManager` 负责持久化:
|
||||
|
||||
```typescript
|
||||
const sessionManager = SessionManager.open(params.sessionFile);
|
||||
```
|
||||
|
||||
OpenClaw 会用 `guardSessionManager()` 对其进行包装,以保证工具结果安全。
|
||||
OpenClaw 通过 `guardSessionManager()` 对其进行封装,以确保工具结果安全。
|
||||
|
||||
### 会话缓存
|
||||
|
||||
`session-manager-cache.ts` 会缓存 SessionManager 实例,以避免重复解析文件:
|
||||
`session-manager-cache.ts` 会缓存 `SessionManager` 实例,以避免重复解析文件:
|
||||
|
||||
```typescript
|
||||
await prewarmSessionFile(params.sessionFile);
|
||||
@ -324,15 +324,15 @@ trackSessionManagerAccess(params.sessionFile);
|
||||
|
||||
### 历史记录限制
|
||||
|
||||
`limitHistoryTurns()` 会根据渠道类型(私信 vs 群组)裁剪对话历史。
|
||||
`limitHistoryTurns()` 会根据渠道类型(私信还是群组)裁剪会话历史记录。
|
||||
|
||||
### 压缩
|
||||
|
||||
在上下文溢出时会触发自动压缩。常见的溢出特征包括
|
||||
自动压缩会在上下文溢出时触发。常见的溢出特征包括
|
||||
`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`。`compactEmbeddedPiSessionDirect()` 处理手动压缩:
|
||||
input tokens`、`input is too long for the model` 和 `ollama error: context
|
||||
length exceeded`。`compactEmbeddedPiSessionDirect()` 负责处理手动压缩:
|
||||
|
||||
```typescript
|
||||
const compactResult = await compactEmbeddedPiSessionDirect({
|
||||
@ -342,16 +342,16 @@ const compactResult = await compactEmbeddedPiSessionDirect({
|
||||
|
||||
## 认证与模型解析
|
||||
|
||||
### Auth Profiles
|
||||
### 认证配置
|
||||
|
||||
OpenClaw 维护一个 auth profile 存储,为每个 provider 提供多个 API key:
|
||||
OpenClaw 维护一个认证配置存储,为每个提供商保存多个 API 密钥:
|
||||
|
||||
```typescript
|
||||
const authStore = ensureAuthProfileStore(agentDir, { allowKeychainPrompt: false });
|
||||
const profileOrder = resolveAuthProfileOrder({ cfg, store: authStore, provider, preferredProfile });
|
||||
```
|
||||
|
||||
配置档会在失败时轮换,并跟踪冷却状态:
|
||||
配置会在失败时轮换,并带有冷却跟踪:
|
||||
|
||||
```typescript
|
||||
await markAuthProfileFailure({ store, profileId, reason, cfg, agentDir });
|
||||
@ -392,11 +392,11 @@ if (fallbackConfigured && isFailoverErrorMessage(errorText)) {
|
||||
|
||||
## Pi 扩展
|
||||
|
||||
OpenClaw 会加载自定义 pi 扩展以实现特定行为:
|
||||
OpenClaw 会加载自定义 pi 扩展以实现专门行为:
|
||||
|
||||
### 压缩保护
|
||||
|
||||
`src/agents/pi-hooks/compaction-safeguard.ts` 为压缩增加护栏,包括自适应 token 预算,以及工具失败和文件操作摘要:
|
||||
`src/agents/pi-hooks/compaction-safeguard.ts` 会为压缩添加护栏,包括自适应 token 预算,以及工具失败和文件操作摘要:
|
||||
|
||||
```typescript
|
||||
if (resolveCompactionMode(params.cfg) === "safeguard") {
|
||||
@ -407,7 +407,7 @@ if (resolveCompactionMode(params.cfg) === "safeguard") {
|
||||
|
||||
### 上下文裁剪
|
||||
|
||||
`src/agents/pi-hooks/context-pruning.ts` 实现基于缓存 TTL 的上下文裁剪:
|
||||
`src/agents/pi-hooks/context-pruning.ts` 实现了基于缓存 TTL 的上下文裁剪:
|
||||
|
||||
```typescript
|
||||
if (cfg?.agents?.defaults?.contextPruning?.mode === "cache-ttl") {
|
||||
@ -433,18 +433,18 @@ const blockChunker = blockChunking ? new EmbeddedBlockChunker(blockChunking) : n
|
||||
|
||||
### Thinking/Final 标签剥离
|
||||
|
||||
流式输出会经过处理,剥离 `<think>`/`<thinking>` 块,并提取 `<final>` 内容:
|
||||
流式输出会经过处理,以剥离 `<think>`/`<thinking>` 块并提取 `<final>` 内容:
|
||||
|
||||
```typescript
|
||||
const stripBlockTags = (text: string, state: { thinking: boolean; final: boolean }) => {
|
||||
// 剥离 <think>...</think> 内容
|
||||
// 如果 enforceFinalTag,则只返回 <final>...</final> 内容
|
||||
// 如果 enforceFinalTag 为 true,仅返回 <final>...</final> 内容
|
||||
};
|
||||
```
|
||||
|
||||
### 回复指令
|
||||
|
||||
会解析并提取 `[[media:url]]`、`[[voice]]`、`[[reply:id]]` 等回复指令:
|
||||
会解析并提取诸如 `[[media:url]]`、`[[voice]]`、`[[reply:id]]` 之类的回复指令:
|
||||
|
||||
```typescript
|
||||
const { text: cleanedText, mediaUrls, audioAsVoice, replyToId } = consumeReplyDirectives(chunk);
|
||||
@ -454,20 +454,20 @@ const { text: cleanedText, mediaUrls, audioAsVoice, replyToId } = consumeReplyDi
|
||||
|
||||
### 错误分类
|
||||
|
||||
`pi-embedded-helpers.ts` 会对错误进行分类,以便采取适当处理:
|
||||
`pi-embedded-helpers.ts` 会对错误进行分类,以便执行适当处理:
|
||||
|
||||
```typescript
|
||||
isContextOverflowError(errorText) // 上下文过大
|
||||
isCompactionFailureError(errorText) // 压缩失败
|
||||
isAuthAssistantError(lastAssistant) // 认证失败
|
||||
isRateLimitAssistantError(...) // 遭遇速率限制
|
||||
isFailoverAssistantError(...) // 应进行故障转移
|
||||
isRateLimitAssistantError(...) // 触发速率限制
|
||||
isFailoverAssistantError(...) // 应执行故障转移
|
||||
classifyFailoverReason(errorText) // "auth" | "rate_limit" | "quota" | "timeout" | ...
|
||||
```
|
||||
|
||||
### Thinking 级别回退
|
||||
|
||||
如果某个 thinking 级别不受支持,则会回退:
|
||||
如果某个 thinking 级别不受支持,就会回退:
|
||||
|
||||
```typescript
|
||||
const fallbackThinking = pickFallbackThinkingLevel({
|
||||
@ -482,7 +482,7 @@ if (fallbackThinking) {
|
||||
|
||||
## 沙箱集成
|
||||
|
||||
启用沙箱模式时,工具和路径都会受到约束:
|
||||
启用沙箱模式后,工具和路径都会受到约束:
|
||||
|
||||
```typescript
|
||||
const sandbox = await resolveSandboxContext({
|
||||
@ -494,17 +494,17 @@ const sandbox = await resolveSandboxContext({
|
||||
if (sandboxRoot) {
|
||||
// 使用沙箱隔离的 read/edit/write 工具
|
||||
// Exec 在容器中运行
|
||||
// Browser 使用桥接 URL
|
||||
// 浏览器使用 bridge URL
|
||||
}
|
||||
```
|
||||
|
||||
## Provider 特定处理
|
||||
## 提供商特定处理
|
||||
|
||||
### Anthropic
|
||||
|
||||
- 拒绝魔法字符串清理
|
||||
- 连续角色的回合验证
|
||||
- 严格的上游 Pi 工具参数验证
|
||||
- 针对连续角色的轮次校验
|
||||
- 严格的上游 Pi 工具参数校验
|
||||
|
||||
### Google/Gemini
|
||||
|
||||
@ -517,40 +517,40 @@ if (sandboxRoot) {
|
||||
|
||||
## TUI 集成
|
||||
|
||||
OpenClaw 还有一种本地 TUI 模式,会直接使用 pi-tui 组件:
|
||||
OpenClaw 还提供本地 TUI 模式,可直接使用 pi-tui 组件:
|
||||
|
||||
```typescript
|
||||
// src/tui/tui.ts
|
||||
import { ... } from "@mariozechner/pi-tui";
|
||||
```
|
||||
|
||||
这提供了与 pi 原生模式相似的交互式终端体验。
|
||||
这提供了类似于 pi 原生模式的交互式终端体验。
|
||||
|
||||
## 与 Pi CLI 的关键差异
|
||||
|
||||
| 方面 | Pi CLI | OpenClaw 内嵌版 |
|
||||
| --------------- | ----------------------- | ----------------------------------------------------------------------------------------------- |
|
||||
| 调用方式 | `pi` 命令 / RPC | 通过 `createAgentSession()` 使用 SDK |
|
||||
| 工具 | 默认编码工具 | 自定义 OpenClaw 工具套件 |
|
||||
| 系统提示 | AGENTS.md + 提示 | 按渠道/上下文动态生成 |
|
||||
| 会话存储 | `~/.pi/agent/sessions/` | `~/.openclaw/agents/<agentId>/sessions/`(或 `$OPENCLAW_STATE_DIR/agents/<agentId>/sessions/`) |
|
||||
| 认证 | 单一凭证 | 带轮换的多配置档 |
|
||||
| 扩展 | 从磁盘加载 | 程序化 + 磁盘路径 |
|
||||
| 事件处理 | TUI 渲染 | 基于回调(`onBlockReply` 等) |
|
||||
| 方面 | Pi CLI | OpenClaw 嵌入式 |
|
||||
| --------------- | ----------------------- | ---------------------------------------------------------------------------------------------- |
|
||||
| 调用方式 | `pi` 命令 / RPC | 通过 `createAgentSession()` 使用 SDK |
|
||||
| 工具 | 默认编码工具 | 自定义 OpenClaw 工具套件 |
|
||||
| 系统提示词 | AGENTS.md + 提示词 | 按渠道/上下文动态生成 |
|
||||
| 会话存储 | `~/.pi/agent/sessions/` | `~/.openclaw/agents/<agentId>/sessions/`(或 `$OPENCLAW_STATE_DIR/agents/<agentId>/sessions/`) |
|
||||
| 认证 | 单一凭证 | 支持轮换的多配置 |
|
||||
| 扩展 | 从磁盘加载 | 以编程方式 + 磁盘路径加载 |
|
||||
| 事件处理 | TUI 渲染 | 基于回调(`onBlockReply` 等) |
|
||||
|
||||
## 未来考虑
|
||||
|
||||
潜在的重构方向包括:
|
||||
潜在需要重构的领域:
|
||||
|
||||
1. **工具签名对齐**:当前需要在 pi-agent-core 和 pi-coding-agent 的签名之间适配
|
||||
2. **会话管理器包装**:`guardSessionManager` 增加了安全性,但也增加了复杂度
|
||||
1. **工具签名对齐**:目前仍在适配 pi-agent-core 与 pi-coding-agent 的签名差异
|
||||
2. **Session manager 封装**:`guardSessionManager` 增加了安全性,但也提高了复杂度
|
||||
3. **扩展加载**:可以更直接地使用 pi 的 `ResourceLoader`
|
||||
4. **流式处理器复杂度**:`subscribeEmbeddedPiSession` 已经变得较大
|
||||
5. **Provider 特殊情况**:存在许多 provider 特定代码路径,这些将来可能由 pi 统一处理
|
||||
4. **流式处理器复杂度**:`subscribeEmbeddedPiSession` 已变得较大
|
||||
5. **提供商特性差异**:存在许多提供商特定代码路径,未来可能由 pi 自身处理
|
||||
|
||||
## 测试
|
||||
|
||||
Pi 集成覆盖这些测试套件:
|
||||
Pi 集成覆盖了以下测试套件:
|
||||
|
||||
- `src/agents/pi-*.test.ts`
|
||||
- `src/agents/pi-auth-json.test.ts`
|
||||
@ -568,7 +568,7 @@ Pi 集成覆盖这些测试套件:
|
||||
|
||||
- `src/agents/pi-embedded-runner-extraparams.live.test.ts`(启用 `OPENCLAW_LIVE_TEST=1`)
|
||||
|
||||
有关当前运行命令,请参见 [Pi 开发工作流](/zh-CN/pi-dev)。
|
||||
如需查看当前运行命令,请参见 [Pi 开发工作流](/zh-CN/pi-dev)。
|
||||
|
||||
## 相关内容
|
||||
|
||||
|
||||
@ -2,64 +2,63 @@
|
||||
read_when:
|
||||
- 重构渠道消息 UI、交互式负载或原生渠道渲染器
|
||||
- 更改消息工具能力、投递提示或跨上下文标记
|
||||
- 调试 Discord Carbon 导入扇出或渠道插件运行时懒加载
|
||||
- 调试 Discord Carbon 导入扇出或渠道插件运行时惰性加载
|
||||
summary: 将语义消息呈现与渠道原生 UI 渲染器解耦。
|
||||
title: 渠道呈现重构计划
|
||||
x-i18n:
|
||||
generated_at: "2026-04-24T04:04:50Z"
|
||||
generated_at: "2026-04-27T06:55:56Z"
|
||||
model: gpt-5.4
|
||||
provider: openai
|
||||
source_hash: f983c4d14580e8a66744c7e5f23dd9846c11e926181a8441d60f346cec6d1eea
|
||||
source_hash: 5608e7806a2a20e73ee82f1b1f0fcbbb4c865232df984d3d98b91e5b721998f5
|
||||
source_path: plan/ui-channels.md
|
||||
workflow: 15
|
||||
---
|
||||
|
||||
## 状态
|
||||
## Status
|
||||
|
||||
已为共享智能体、CLI、插件能力以及出站投递界面实现:
|
||||
已为共享智能体、CLI、插件能力和出站投递表面完成实现:
|
||||
|
||||
- `ReplyPayload.presentation` 用于承载语义化消息 UI。
|
||||
- `ReplyPayload.delivery.pin` 用于承载已发送消息的置顶请求。
|
||||
- 共享消息操作现在暴露 `presentation`、`delivery` 和 `pin`,而不是提供商原生的 `components`、`blocks`、`buttons` 或 `card`。
|
||||
- 核心通过插件声明的出站能力来渲染或自动降级消息呈现。
|
||||
- Discord、Slack、Telegram、Mattermost、Microsoft Teams 和 Feishu 渲染器均已接入通用契约。
|
||||
- Discord 渠道控制平面代码不再导入基于 Carbon 的 UI 容器。
|
||||
- `ReplyPayload.presentation` 承载语义消息 UI。
|
||||
- `ReplyPayload.delivery.pin` 承载已发送消息的置顶请求。
|
||||
- 共享消息操作暴露 `presentation`、`delivery` 和 `pin`,而不是提供商原生的 `components`、`blocks`、`buttons` 或 `card`。
|
||||
- Core 通过插件声明的出站能力来渲染或自动降级 presentation。
|
||||
- Discord、Slack、Telegram、Mattermost、MS Teams 和 Feishu 渲染器会消费这一通用契约。
|
||||
- Discord 渠道控制平面代码不再导入由 Carbon 支持的 UI 容器。
|
||||
|
||||
规范文档现位于 [Message Presentation](/zh-CN/plugins/message-presentation)。
|
||||
请将本计划保留为历史实现背景;如果契约、渲染器或回退行为发生变化,
|
||||
请更新该规范指南。
|
||||
规范文档现位于 [消息呈现](/zh-CN/plugins/message-presentation)。
|
||||
请将此计划保留为历史实现背景;如契约、渲染器或回退行为发生变化,请更新规范指南。
|
||||
|
||||
## 问题
|
||||
## Problem
|
||||
|
||||
当前的渠道 UI 分散在多个不兼容的界面中:
|
||||
渠道 UI 当前分散在多个彼此不兼容的表面中:
|
||||
|
||||
- 核心通过 `buildCrossContextComponents` 拥有一个偏向 Discord 形态的跨上下文渲染钩子。
|
||||
- Discord `channel.ts` 可以导入原生 Carbon UI,例如 `DiscordUiContainer`,这会将运行时 UI 依赖拉入渠道插件控制平面。
|
||||
- 智能体和 CLI 暴露了原生负载逃逸口,例如 Discord `components`、Slack `blocks`、Telegram 或 Mattermost `buttons`,以及 Teams 或 Feishu `card`。
|
||||
- `ReplyPayload.channelData` 同时承载传输提示和原生 UI 封装。
|
||||
- 通用 `interactive` 模型已经存在,但它比 Discord、Slack、Teams、Feishu、LINE、Telegram 和 Mattermost 已经使用的更丰富布局要窄。
|
||||
- Core 通过 `buildCrossContextComponents` 拥有一个具备 Discord 形态的跨上下文渲染器钩子。
|
||||
- Discord `channel.ts` 可以导入原生 Carbon UI(通过 `DiscordUiContainer`),这会将运行时 UI 依赖拉入渠道插件控制平面。
|
||||
- 智能体和 CLI 暴露了原生负载逃生口,例如 Discord 的 `components`、Slack 的 `blocks`、Telegram 或 Mattermost 的 `buttons`,以及 Teams 或 Feishu 的 `card`。
|
||||
- `ReplyPayload.channelData` 同时承载传输提示和原生 UI 信封。
|
||||
- 通用 `interactive` 模型已经存在,但它比 Discord、Slack、Teams、Feishu、LINE、Telegram 和 Mattermost 已经使用的更丰富布局更窄。
|
||||
|
||||
这使核心感知了原生 UI 形态,削弱了插件运行时懒加载能力,也让智能体拥有了过多提供商专属方式来表达相同的消息意图。
|
||||
这使得 Core 需要感知原生 UI 形状,削弱了插件运行时的惰性加载,并让智能体拥有过多提供商特定的方式来表达相同的消息意图。
|
||||
|
||||
## 目标
|
||||
## Goals
|
||||
|
||||
- 核心根据声明的能力决定消息的最佳语义呈现方式。
|
||||
- 扩展声明能力,并将语义化呈现渲染为原生传输负载。
|
||||
- Core 根据声明的能力决定消息的最佳语义呈现方式。
|
||||
- 扩展声明能力,并将语义呈现渲染为原生传输负载。
|
||||
- Web 控制 UI 与聊天原生 UI 保持分离。
|
||||
- 共享智能体或 CLI 消息界面不暴露原生渠道负载。
|
||||
- 不受支持的呈现功能自动降级为最佳文本表示。
|
||||
- 诸如置顶已发送消息之类的投递行为应属于通用投递元数据,而不是呈现。
|
||||
- 原生渠道负载不通过共享智能体或 CLI 消息表面暴露。
|
||||
- 不受支持的呈现特性会自动降级为最佳文本表示。
|
||||
- 诸如置顶已发送消息之类的投递行为属于通用投递元数据,而不是呈现。
|
||||
|
||||
## 非目标
|
||||
## Non goals
|
||||
|
||||
- 不为 `buildCrossContextComponents` 提供向后兼容 shim。
|
||||
- 不公开 `components`、`blocks`、`buttons` 或 `card` 这类原生逃逸口。
|
||||
- 核心不导入渠道原生 UI 库。
|
||||
- 不为内置渠道提供提供商专属 SDK 接缝。
|
||||
- 不为 `buildCrossContextComponents` 提供向后兼容垫片。
|
||||
- 不为 `components`、`blocks`、`buttons` 或 `card` 提供公共原生逃生口。
|
||||
- Core 不导入渠道原生 UI 库。
|
||||
- 不为内置渠道提供提供商特定的 SDK 接缝。
|
||||
|
||||
## 目标模型
|
||||
## Target model
|
||||
|
||||
向 `ReplyPayload` 添加一个由核心拥有的 `presentation` 字段。
|
||||
向 `ReplyPayload` 添加一个由 Core 拥有的 `presentation` 字段。
|
||||
|
||||
```ts
|
||||
type MessagePresentationTone = "neutral" | "info" | "success" | "warning" | "danger";
|
||||
@ -90,17 +89,17 @@ type MessagePresentationOption = {
|
||||
};
|
||||
```
|
||||
|
||||
在迁移过程中,`interactive` 会变成 `presentation` 的一个子集:
|
||||
在迁移期间,`interactive` 会成为 `presentation` 的一个子集:
|
||||
|
||||
- `interactive` 文本块映射到 `presentation.blocks[].type = "text"`。
|
||||
- `interactive` 按钮块映射到 `presentation.blocks[].type = "buttons"`。
|
||||
- `interactive` 选择块映射到 `presentation.blocks[].type = "select"`。
|
||||
|
||||
外部智能体和 CLI schema 现在使用 `presentation`;`interactive` 仍作为现有回复生成器的内部遗留解析 / 渲染辅助器保留。
|
||||
外部智能体和 CLI schema 现在使用 `presentation`;`interactive` 仍保留为内部遗留解析/渲染辅助,以支持现有 reply 生产者。
|
||||
|
||||
## 投递元数据
|
||||
## Delivery metadata
|
||||
|
||||
为非 UI 的发送行为添加一个由核心拥有的 `delivery` 字段。
|
||||
为不属于 UI 的发送行为添加一个由 Core 拥有的 `delivery` 字段。
|
||||
|
||||
```ts
|
||||
type ReplyPayloadDelivery = {
|
||||
@ -118,14 +117,14 @@ type ReplyPayloadDelivery = {
|
||||
|
||||
- `delivery.pin = true` 表示置顶第一条成功投递的消息。
|
||||
- `notify` 默认值为 `false`。
|
||||
- `required` 默认值为 `false`;对于不支持的渠道或置顶失败的情况,会自动降级并继续投递。
|
||||
- 手动 `pin`、`unpin` 和 `list-pins` 消息操作仍用于现有消息。
|
||||
- `required` 默认值为 `false`;不支持的渠道或置顶失败时会自动降级,继续完成投递。
|
||||
- 手动 `pin`、`unpin` 和 `list-pins` 消息操作仍保留,用于现有消息。
|
||||
|
||||
当前的 Telegram ACP 话题绑定应从 `channelData.telegram.pin = true` 移至 `delivery.pin = true`。
|
||||
当前 Telegram ACP 主题绑定应从 `channelData.telegram.pin = true` 迁移到 `delivery.pin = true`。
|
||||
|
||||
## 运行时能力契约
|
||||
## Runtime capability contract
|
||||
|
||||
将呈现和投递渲染钩子添加到运行时出站适配器中,而不是控制平面渠道插件中。
|
||||
将 presentation 和 delivery 渲染钩子添加到运行时出站适配器,而不是控制平面渠道插件中。
|
||||
|
||||
```ts
|
||||
type ChannelPresentationCapabilities = {
|
||||
@ -163,16 +162,16 @@ type ChannelOutboundAdapter = {
|
||||
};
|
||||
```
|
||||
|
||||
核心行为:
|
||||
Core 行为:
|
||||
|
||||
- 解析目标渠道和运行时适配器。
|
||||
- 查询其呈现能力。
|
||||
- 在渲染前对不受支持的块进行降级。
|
||||
- 查询 presentation 能力。
|
||||
- 在渲染前降级不受支持的块。
|
||||
- 调用 `renderPresentation`。
|
||||
- 如果没有渲染器,则将呈现转换为文本回退。
|
||||
- 成功发送后,当请求了 `delivery.pin` 且渠道支持时,调用 `pinDeliveredMessage`。
|
||||
- 如果不存在渲染器,则将 presentation 转换为文本回退。
|
||||
- 成功发送后,当请求 `delivery.pin` 且渠道支持时,调用 `pinDeliveredMessage`。
|
||||
|
||||
## 渠道映射
|
||||
## Channel mapping
|
||||
|
||||
Discord:
|
||||
|
||||
@ -187,27 +186,27 @@ Slack:
|
||||
|
||||
Telegram:
|
||||
|
||||
- 将 text、context 和 dividers 渲染为文本。
|
||||
- 在已配置且目标界面允许时,将 actions 和 select 渲染为内联键盘。
|
||||
- 在禁用内联按钮时使用文本回退。
|
||||
- 将 ACP 话题置顶迁移到 `delivery.pin`。
|
||||
- 将 text、context 和 divider 渲染为文本。
|
||||
- 在配置允许且目标表面支持时,将 actions 和 select 渲染为内联键盘。
|
||||
- 当内联按钮被禁用时使用文本回退。
|
||||
- 将 ACP 主题置顶迁移到 `delivery.pin`。
|
||||
|
||||
Mattermost:
|
||||
|
||||
- 在已配置时将 actions 渲染为交互按钮。
|
||||
- 其他块使用文本回退。
|
||||
- 在配置允许时将 actions 渲染为交互按钮。
|
||||
- 其他块渲染为文本回退。
|
||||
|
||||
Microsoft Teams:
|
||||
MS Teams:
|
||||
|
||||
- 将 `presentation` 渲染为 Adaptive Cards。
|
||||
- 保留手动 pin / unpin / list-pins 操作。
|
||||
- 如果 Graph 对目标会话的支持足够可靠,可选择实现 `pinDeliveredMessage`。
|
||||
- 保留手动 pin/unpin/list-pins 操作。
|
||||
- 如果目标会话的 Graph 支持可靠,可选择实现 `pinDeliveredMessage`。
|
||||
|
||||
Feishu:
|
||||
|
||||
- 将 `presentation` 渲染为交互卡片。
|
||||
- 保留手动 pin / unpin / list-pins 操作。
|
||||
- 如果 API 行为足够可靠,可选择实现用于已发送消息置顶的 `pinDeliveredMessage`。
|
||||
- 将 `presentation` 渲染为交互式卡片。
|
||||
- 保留手动 pin/unpin/list-pins 操作。
|
||||
- 如果 API 行为可靠,可选择为已发送消息置顶实现 `pinDeliveredMessage`。
|
||||
|
||||
LINE:
|
||||
|
||||
@ -215,50 +214,50 @@ LINE:
|
||||
- 对不支持的块回退为文本。
|
||||
- 从 `channelData` 中移除 LINE UI 负载。
|
||||
|
||||
纯文本或能力受限的渠道:
|
||||
纯文本或能力有限的渠道:
|
||||
|
||||
- 使用保守格式将 presentation 转换为文本。
|
||||
|
||||
## 重构步骤
|
||||
## Refactor steps
|
||||
|
||||
1. 重新应用 Discord 发布修复:从基于 Carbon 的 UI 中拆分 `ui-colors.ts`,并从 `extensions/discord/src/channel.ts` 中移除 `DiscordUiContainer`。
|
||||
2. 向 `ReplyPayload`、出站负载规范化、投递摘要和 hook 负载中添加 `presentation` 和 `delivery`。
|
||||
3. 在一个窄范围的 SDK / 运行时子路径中添加 `MessagePresentation` schema 和解析辅助函数。
|
||||
4. 用语义化呈现能力替换消息能力中的 `buttons`、`cards`、`components` 和 `blocks`。
|
||||
5. 为呈现渲染和投递置顶添加运行时出站适配器钩子。
|
||||
6. 用 `buildCrossContextPresentation` 替换跨上下文组件构建逻辑。
|
||||
1. 重新应用 Discord 发布修复,将 `ui-colors.ts` 从由 Carbon 支持的 UI 中拆分出来,并从 `extensions/discord/src/channel.ts` 中移除 `DiscordUiContainer`。
|
||||
2. 将 `presentation` 和 `delivery` 添加到 `ReplyPayload`、出站负载规范化、投递摘要和钩子负载中。
|
||||
3. 在一个收窄的 SDK/运行时子路径中添加 `MessagePresentation` schema 和解析辅助函数。
|
||||
4. 用语义 presentation 能力替换消息能力中的 `buttons`、`cards`、`components` 和 `blocks`。
|
||||
5. 为 presentation 渲染和 delivery 置顶添加运行时出站适配器钩子。
|
||||
6. 用 `buildCrossContextPresentation` 替换跨上下文组件构造。
|
||||
7. 删除 `src/infra/outbound/channel-adapters.ts`,并从渠道插件类型中移除 `buildCrossContextComponents`。
|
||||
8. 修改 `maybeApplyCrossContextMarker`,使其附加 `presentation` 而不是原生参数。
|
||||
9. 更新插件分发发送路径,使其只消费语义化呈现和投递元数据。
|
||||
8. 修改 `maybeApplyCrossContextMarker`,使其附加 `presentation` 而非原生参数。
|
||||
9. 更新插件分发发送路径,使其仅消费语义 presentation 和 delivery 元数据。
|
||||
10. 移除智能体和 CLI 的原生负载参数:`components`、`blocks`、`buttons` 和 `card`。
|
||||
11. 移除创建原生 message-tool schema 的 SDK 辅助函数,替换为 presentation schema 辅助函数。
|
||||
12. 从 `channelData` 中移除 UI / 原生封装;在审查每个剩余字段前,仅保留传输元数据。
|
||||
13. 迁移 Discord、Slack、Telegram、Mattermost、Microsoft Teams、Feishu 和 LINE 渲染器。
|
||||
14. 更新 message CLI、渠道页面、插件 SDK 和能力扩展手册文档。
|
||||
11. 移除用于创建原生消息工具 schema 的 SDK 辅助函数,改为使用 presentation schema 辅助函数。
|
||||
12. 从 `channelData` 中移除 UI/原生信封;在审查完每个剩余字段之前,仅保留传输元数据。
|
||||
13. 迁移 Discord、Slack、Telegram、Mattermost、MS Teams、Feishu 和 LINE 渲染器。
|
||||
14. 更新消息 CLI、渠道页面、插件 SDK 和能力扩展手册文档。
|
||||
15. 对 Discord 和受影响的渠道入口点运行导入扇出分析。
|
||||
|
||||
在本次重构中,第 1-11 步以及第 13-14 步已为共享智能体、CLI、插件能力和出站适配器契约完成实现。第 12 步仍是针对提供商私有 `channelData` 传输封装的更深层内部清理工作。第 15 步仍属于后续验证项,前提是我们希望获得超出类型 / 测试门禁之外的量化导入扇出数据。
|
||||
在此次重构中,步骤 1-11 和 13-14 已针对共享智能体、CLI、插件能力和出站适配器契约实现。步骤 12 仍是针对提供商私有 `channelData` 传输信封的更深入内部清理工作。步骤 15 仍作为后续验证,前提是我们希望获得超出类型/测试门禁之外的量化导入扇出数据。
|
||||
|
||||
## 测试
|
||||
## Tests
|
||||
|
||||
添加或更新:
|
||||
|
||||
- Presentation 规范化测试。
|
||||
- 针对不受支持块的 presentation 自动降级测试。
|
||||
- 针对插件分发和核心投递路径的跨上下文标记测试。
|
||||
- 针对 Discord、Slack、Telegram、Mattermost、Microsoft Teams、Feishu、LINE 和文本回退的渠道渲染矩阵测试。
|
||||
- 面向插件分发和 Core 投递路径的跨上下文标记测试。
|
||||
- 针对 Discord、Slack、Telegram、Mattermost、MS Teams、Feishu、LINE 和文本回退的渠道渲染矩阵测试。
|
||||
- 证明原生字段已移除的消息工具 schema 测试。
|
||||
- 证明原生标志已移除的 CLI 测试。
|
||||
- 覆盖 Carbon 的 Discord 入口点导入懒加载回归测试。
|
||||
- 覆盖 Telegram 和通用回退的投递置顶测试。
|
||||
- 针对 Carbon 的 Discord 入口点导入惰性回归测试。
|
||||
- 涵盖 Telegram 和通用回退的 delivery 置顶测试。
|
||||
|
||||
## 未决问题
|
||||
## Open questions
|
||||
|
||||
- `delivery.pin` 是否应在第一阶段就为 Discord、Slack、Microsoft Teams 和 Feishu 实现,还是先只做 Telegram?
|
||||
- `delivery` 最终是否应吸收现有字段,例如 `replyToId`、`replyToCurrent`、`silent` 和 `audioAsVoice`,还是继续只聚焦于发送后的行为?
|
||||
- presentation 是否应直接支持图片或文件引用,还是媒体暂时继续与 UI 布局分离?
|
||||
- 第一阶段是否应为 Discord、Slack、MS Teams 和 Feishu 实现 `delivery.pin`,还是仅先支持 Telegram?
|
||||
- `delivery` 最终是否应吸收现有字段,例如 `replyToId`、`replyToCurrent`、`silent` 和 `audioAsVoice`,还是继续聚焦于发送后行为?
|
||||
- Presentation 是否应直接支持图片或文件引用,还是媒体暂时仍与 UI 布局分离?
|
||||
|
||||
## 相关内容
|
||||
## Related
|
||||
|
||||
- [渠道概览](/zh-CN/channels)
|
||||
- [消息呈现](/zh-CN/plugins/message-presentation)
|
||||
|
||||
@ -1,25 +1,25 @@
|
||||
---
|
||||
read_when:
|
||||
- 添加或修改消息卡片、按钮或选择器渲染
|
||||
- 构建支持富出站消息的渠道插件
|
||||
- 构建支持丰富出站消息的渠道插件
|
||||
- 更改消息工具的呈现方式或投递能力
|
||||
- 调试提供商特定的卡片 / 块 / 组件渲染回归问题
|
||||
summary: 渠道插件的语义化消息卡片、按钮、选择器、后备文本和投递提示
|
||||
- 调试提供商特定的卡片 / 区块 / 组件渲染回归问题
|
||||
summary: 渠道插件的语义化消息卡片、按钮、选择器、回退文本和投递提示
|
||||
title: 消息呈现
|
||||
x-i18n:
|
||||
generated_at: "2026-04-24T03:06:50Z"
|
||||
generated_at: "2026-04-27T06:55:59Z"
|
||||
model: gpt-5.4
|
||||
provider: openai
|
||||
source_hash: 1c8c3903101310de330017b34bc2f0d641f4c8ea2b80a30532736b4409716510
|
||||
source_hash: 23ef0eab890ee174c1433f72e84932a84a481f2bcf4b69bc793a2660ec94b10c
|
||||
source_path: plugins/message-presentation.md
|
||||
workflow: 15
|
||||
---
|
||||
|
||||
消息呈现是 OpenClaw 用于富出站聊天 UI 的共享契约。
|
||||
消息呈现是 OpenClaw 用于丰富出站聊天 UI 的共享契约。
|
||||
它让智能体、CLI 命令、审批流程和插件只需描述一次消息意图,
|
||||
而每个渠道插件都可以尽可能渲染为最佳的原生形态。
|
||||
同时每个渠道插件都可以尽可能渲染出最合适的原生形态。
|
||||
|
||||
对可移植的消息 UI,请使用 presentation:
|
||||
对可移植的消息 UI 使用 presentation:
|
||||
|
||||
- 文本区块
|
||||
- 简短的上下文 / 页脚文本
|
||||
@ -28,12 +28,12 @@ x-i18n:
|
||||
- 选择菜单
|
||||
- 卡片标题和语气
|
||||
|
||||
不要向共享消息工具中添加新的提供商原生字段,例如 Discord 的 `components`、Slack
|
||||
的 `blocks`、Telegram 的 `buttons`、Teams 的 `card` 或 Feishu 的 `card`。这些字段是由渠道插件负责生成的渲染输出。
|
||||
不要向共享消息工具中添加新的提供商原生字段,例如 Discord `components`、Slack
|
||||
`blocks`、Telegram `buttons`、Teams `card` 或 Feishu `card`。这些都是由渠道插件负责的渲染器输出。
|
||||
|
||||
## 契约
|
||||
|
||||
插件作者从以下位置导入公共契约:
|
||||
插件作者从以下位置导入公开契约:
|
||||
|
||||
```ts
|
||||
import type {
|
||||
@ -84,17 +84,17 @@ type ReplyPayloadDelivery = {
|
||||
按钮语义:
|
||||
|
||||
- `value` 是应用动作值;当渠道支持可点击控件时,它会通过该渠道现有的交互路径路由回来。
|
||||
- `url` 是链接按钮。它可以在没有 `value` 的情况下存在。
|
||||
- `label` 是必填项,也会用于文本后备内容。
|
||||
- `style` 是提示性信息。渲染器应将不支持的样式映射到安全的默认值,而不是导致发送失败。
|
||||
- `url` 是链接按钮。它可以在没有 `value` 的情况下单独存在。
|
||||
- `label` 是必填项,也会用于文本回退。
|
||||
- `style` 是建议性的。渲染器应将不受支持的样式映射为安全的默认值,而不是让发送失败。
|
||||
|
||||
选择器语义:
|
||||
|
||||
- `options[].value` 是被选中的应用值。
|
||||
- `placeholder` 是提示性信息;对于没有原生选择器支持的渠道,可能会被忽略。
|
||||
- 如果某个渠道不支持选择器,后备文本会列出这些标签。
|
||||
- `placeholder` 是建议性的,原生不支持选择器的渠道可以忽略它。
|
||||
- 如果某个渠道不支持选择器,回退文本会列出这些标签。
|
||||
|
||||
## 生产者示例
|
||||
## 生产方示例
|
||||
|
||||
简单卡片:
|
||||
|
||||
@ -116,7 +116,7 @@ type ReplyPayloadDelivery = {
|
||||
}
|
||||
```
|
||||
|
||||
仅 URL 的链接按钮:
|
||||
仅含 URL 的链接按钮:
|
||||
|
||||
```json
|
||||
{
|
||||
@ -166,7 +166,7 @@ openclaw message send --channel telegram \
|
||||
--pin
|
||||
```
|
||||
|
||||
使用显式 JSON 的置顶投递:
|
||||
带显式 JSON 的置顶投递:
|
||||
|
||||
```json
|
||||
{
|
||||
@ -204,8 +204,8 @@ const adapter: ChannelOutboundAdapter = {
|
||||
};
|
||||
```
|
||||
|
||||
能力字段刻意保持为简单的布尔值。它们描述的是渲染器可以交互化呈现什么,
|
||||
而不是每一个原生平台限制。渲染器仍然负责处理平台特定限制,例如最大按钮数、区块数和卡片大小。
|
||||
能力字段刻意保持为简单布尔值。它们描述的是渲染器能将哪些内容做成交互式,
|
||||
而不是每一个原生平台限制。渲染器仍然负责处理平台特定限制,例如最大按钮数量、区块数量和卡片大小。
|
||||
|
||||
## 核心渲染流程
|
||||
|
||||
@ -214,36 +214,36 @@ const adapter: ChannelOutboundAdapter = {
|
||||
1. 规范化 presentation 载荷。
|
||||
2. 解析目标渠道的出站适配器。
|
||||
3. 读取 `presentationCapabilities`。
|
||||
4. 当适配器能够渲染该载荷时,调用 `renderPresentation`。
|
||||
5. 当适配器不存在或无法渲染时,回退为保守的文本。
|
||||
6. 通过正常的渠道投递路径发送结果载荷。
|
||||
4. 当适配器可以渲染该载荷时,调用 `renderPresentation`。
|
||||
5. 当适配器缺失或无法渲染时,回退为保守的文本。
|
||||
6. 通过正常的渠道投递路径发送生成的载荷。
|
||||
7. 在第一条消息成功发送后,应用诸如 `delivery.pin` 之类的投递元数据。
|
||||
|
||||
核心负责后备行为,因此生产者可以保持渠道无关。渠道插件则负责原生渲染和交互处理。
|
||||
核心负责回退行为,因此生产方可以保持渠道无关。渠道插件则负责原生渲染和交互处理。
|
||||
|
||||
## 降级规则
|
||||
|
||||
Presentation 必须能在受限渠道上安全发送。
|
||||
Presentation 必须能安全地发送到能力受限的渠道。
|
||||
|
||||
后备文本包括:
|
||||
回退文本包含:
|
||||
|
||||
- `title` 作为第一行
|
||||
- `text` 区块作为普通段落
|
||||
- `context` 区块作为紧凑的上下文行
|
||||
- `divider` 区块作为视觉分隔符
|
||||
- 按钮标签,对于链接按钮还包括 URL
|
||||
- 选择器选项标签
|
||||
- 第一行的 `title`
|
||||
- 作为普通段落的 `text` 区块
|
||||
- 作为紧凑上下文行的 `context` 区块
|
||||
- 作为可视分隔符的 `divider` 区块
|
||||
- 按钮标签,包括链接按钮的 URL
|
||||
- 选择项标签
|
||||
|
||||
不受支持的原生控件应降级处理,而不是导致整个发送失败。
|
||||
不受支持的原生控件应当降级,而不是让整次发送失败。
|
||||
示例:
|
||||
|
||||
- 当 Telegram 的内联按钮被禁用时,会发送文本后备内容。
|
||||
- 没有选择器支持的渠道会将选择器选项列为文本。
|
||||
- 仅 URL 按钮会变成原生链接按钮,或者变成后备 URL 行。
|
||||
- 非必需的置顶失败不会导致已投递的消息失败。
|
||||
- 当 Telegram 的内联按钮被禁用时,发送文本回退。
|
||||
- 不支持选择器的渠道会将选择项列为文本。
|
||||
- 仅含 URL 的按钮会变成原生链接按钮,或者回退为一行 URL 文本。
|
||||
- 可选的置顶失败不会让已投递的消息失败。
|
||||
|
||||
主要的例外是 `delivery.pin.required: true`;如果置顶被请求为必需,
|
||||
而渠道无法置顶已发送的消息,则投递会报告失败。
|
||||
主要例外是 `delivery.pin.required: true`;如果请求将置顶设为必需,
|
||||
而该渠道无法置顶已发送消息,则投递会报告失败。
|
||||
|
||||
## 提供商映射
|
||||
|
||||
@ -251,36 +251,35 @@ Presentation 必须能在受限渠道上安全发送。
|
||||
|
||||
| 渠道 | 原生渲染目标 | 说明 |
|
||||
| --------------- | ----------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| Discord | Components 和组件容器 | 为现有提供商原生载荷生产者保留旧版 `channelData.discord.components`,但新的共享发送应使用 `presentation`。 |
|
||||
| Slack | Block Kit | 为现有提供商原生载荷生产者保留旧版 `channelData.slack.blocks`,但新的共享发送应使用 `presentation`。 |
|
||||
| Telegram | 文本加内联键盘 | 按钮 / 选择器需要目标表面支持内联按钮能力;否则使用文本后备。 |
|
||||
| Discord | Components 和 component containers | 为现有提供商原生载荷生产方保留旧版 `channelData.discord.components`,但新的共享发送应使用 `presentation`。 |
|
||||
| Slack | Block Kit | 为现有提供商原生载荷生产方保留旧版 `channelData.slack.blocks`,但新的共享发送应使用 `presentation`。 |
|
||||
| Telegram | 文本加内联键盘 | 按钮 / 选择器要求目标表面具备内联按钮能力;否则会使用文本回退。 |
|
||||
| Mattermost | 文本加交互式 props | 其他区块会降级为文本。 |
|
||||
| Microsoft Teams | Adaptive Cards | 当同时提供普通 `message` 文本和卡片时,普通 `message` 文本会一并包含。 |
|
||||
| Feishu | 交互式卡片 | 卡片头部可使用 `title`;正文会避免重复该标题。 |
|
||||
| 普通渠道 | 文本后备 | 没有渲染器的渠道仍会获得可读输出。 |
|
||||
| Microsoft Teams | Adaptive Cards | 当同时提供普通 `message` 文本和卡片时,卡片中会包含普通 `message` 文本。 |
|
||||
| Feishu | 交互式卡片 | 卡片头部可以使用 `title`;正文会避免重复该标题。 |
|
||||
| 纯文本渠道 | 文本回退 | 即使没有渲染器的渠道,也仍能获得可读输出。 |
|
||||
|
||||
提供商原生载荷兼容性只是为现有 reply 生产者提供的过渡便利。
|
||||
这并不是向共享原生字段中添加新字段的理由。
|
||||
对提供商原生载荷的兼容性,是为现有 reply 生产方提供的过渡性便利。
|
||||
这并不是添加新的共享原生字段的理由。
|
||||
|
||||
## Presentation 与 InteractiveReply
|
||||
|
||||
`InteractiveReply` 是较早的内部子集,供审批和交互辅助工具使用。
|
||||
它支持:
|
||||
`InteractiveReply` 是旧的内部子集,供审批和交互辅助工具使用。它支持:
|
||||
|
||||
- 文本
|
||||
- 按钮
|
||||
- 选择器
|
||||
|
||||
`MessagePresentation` 是规范的共享发送契约。它新增了:
|
||||
`MessagePresentation` 是标准的共享发送契约。它新增了:
|
||||
|
||||
- 标题
|
||||
- 语气
|
||||
- 上下文
|
||||
- 分隔线
|
||||
- 仅 URL 按钮
|
||||
- 仅含 URL 的按钮
|
||||
- 通过 `ReplyPayload.delivery` 提供的通用投递元数据
|
||||
|
||||
在桥接旧代码时,请使用 `openclaw/plugin-sdk/interactive-runtime` 中的辅助工具:
|
||||
在桥接旧代码时,使用 `openclaw/plugin-sdk/interactive-runtime` 中的辅助函数:
|
||||
|
||||
```ts
|
||||
import {
|
||||
@ -295,34 +294,33 @@ import {
|
||||
|
||||
## 投递置顶
|
||||
|
||||
置顶属于投递行为,不属于 presentation。请使用 `delivery.pin`,而不是
|
||||
`channelData.telegram.pin` 之类的提供商原生字段。
|
||||
置顶是投递行为,不是呈现。使用 `delivery.pin`,而不是提供商原生字段,例如 `channelData.telegram.pin`。
|
||||
|
||||
语义:
|
||||
|
||||
- `pin: true` 会置顶第一条成功投递的消息。
|
||||
- `pin.notify` 默认为 `false`。
|
||||
- `pin.required` 默认为 `false`。
|
||||
- 非必需的置顶失败会降级处理,并保留已发送消息不变。
|
||||
- 可选的置顶失败会降级,并保留已发送消息不变。
|
||||
- 必需的置顶失败会导致投递失败。
|
||||
- 分块消息会置顶第一个已投递的分块,而不是尾部分块。
|
||||
- 分块流式传输消息会置顶第一个已投递分块,而不是末尾分块。
|
||||
|
||||
对于提供商支持这些操作的现有消息,手动 `pin`、`unpin` 和 `pins` 消息动作仍然存在。
|
||||
|
||||
## 插件作者检查清单
|
||||
|
||||
- 当渠道能够渲染或安全降级语义化 presentation 时,在 `describeMessageTool(...)` 中声明 `presentation`。
|
||||
- 向运行时出站适配器添加 `presentationCapabilities`。
|
||||
- 当渠道可以渲染或安全降级语义化 presentation 时,在 `describeMessageTool(...)` 中声明 `presentation`。
|
||||
- 将 `presentationCapabilities` 添加到运行时出站适配器。
|
||||
- 在运行时代码中实现 `renderPresentation`,而不是在控制平面插件设置代码中实现。
|
||||
- 不要在高频的设置 / 目录路径中引入原生 UI 库。
|
||||
- 在渲染器和测试中保留平台限制处理。
|
||||
- 为不支持的按钮、选择器、URL 按钮、标题 / 文本重复,以及混合 `message` 加 `presentation` 发送添加后备测试。
|
||||
- 仅当提供商可以置顶已发送消息 id 时,才通过 `deliveryCapabilities.pin` 和 `pinDeliveredMessage` 添加置顶投递支持。
|
||||
- 不要通过共享消息动作 schema 暴露新的提供商原生卡片 / 区块 / 组件 / 按钮字段。
|
||||
- 不要将原生 UI 库放入高频的设置 / 目录路径中。
|
||||
- 在渲染器和测试中保留平台限制。
|
||||
- 为不受支持的按钮、选择器、URL 按钮、标题 / 文本重复,以及混合 `message` 加 `presentation` 发送添加回退测试。
|
||||
- 仅当提供商能够置顶已发送消息 id 时,才通过 `deliveryCapabilities.pin` 和 `pinDeliveredMessage` 添加置顶投递支持。
|
||||
- 不要通过共享消息动作 schema 暴露新的提供商原生 card / block / component / button 字段。
|
||||
|
||||
## 相关文档
|
||||
|
||||
- [Message CLI](/zh-CN/cli/message)
|
||||
- [消息 CLI](/zh-CN/cli/message)
|
||||
- [插件 SDK 概览](/zh-CN/plugins/sdk-overview)
|
||||
- [插件架构](/zh-CN/plugins/architecture-internals#message-tool-schemas)
|
||||
- [渠道呈现重构计划](/zh-CN/plan/ui-channels)
|
||||
|
||||
Loading…
Reference in New Issue
Block a user