chore(i18n): refresh zh-CN translations

This commit is contained in:
openclaw-docs-i18n[bot] 2026-04-21 20:38:41 +00:00
parent 72ae355e0e
commit c6f5254299
11 changed files with 2726 additions and 1375 deletions

View File

@ -1,30 +1,30 @@
---
read_when:
- 正在开发 Microsoft Teams 渠道功能
- 开发 Microsoft Teams 渠道功能
summary: Microsoft Teams 机器人支持状态、功能和配置
title: Microsoft Teams
x-i18n:
generated_at: "2026-04-11T18:30:44Z"
generated_at: "2026-04-21T20:34:45Z"
model: gpt-5.4
provider: openai
source_hash: 3e6841a618fb030e4c2029b3652d45dedd516392e2ae17309ff46b93648ffb79
source_hash: ed973d8948bc5c5b44f5bc28f361e883389ececc70403c6631fb18ee1254d542
source_path: channels/msteams.md
workflow: 15
---
# Microsoft Teams
> “进入此地者,放弃一切希望。”
> “进入此地者,放弃一切希望。”
更新于2026-03-25
状态:支持文本私信附件;渠道/群组文件发送需要 `sharePointSiteId` + Graph 权限(参见[在群聊中发送文件](#sending-files-in-group-chats))。投票通过 Adaptive Cards 发送。消息操作公开了显式的 `upload-file`用于以文件为优先的发送。
状态:支持文本 + 私信附件;渠道/群组文件发送需要 `sharePointSiteId` + Graph 权限(参见[在群聊中发送文件](#sending-files-in-group-chats))。投票通过 Adaptive Cards 发送。消息操作显式提供 `upload-file` 用于以文件为优先的发送。
## 内置插件
Microsoft Teams 在当前的 OpenClaw 版本中作为内置插件提供,因此在正常的打包构建中不需要单独安装。
Microsoft Teams 在当前的 OpenClaw 版本中作为内置插件提供,因此在常规打包构建中无需单独安装。
如果你使用的是较旧的构建版本,或者是排除了内置 Teams 的自定义安装,请手动安装:
如果你使用的是较旧版本,或使用排除了内置 Teams 的自定义安装,请手动安装:
```bash
openclaw plugins install @openclaw/msteams
@ -38,14 +38,14 @@ openclaw plugins install ./path/to/local/msteams-plugin
详情:[插件](/zh-CN/tools/plugin)
## 快速开始(新手
## 快速设置(初学者
1. 确保 Microsoft Teams 插件可用。
- 当前打包的 OpenClaw 版本已内置
- 较旧/自定义安装可使用上述命令手动添加。
- 当前打包的 OpenClaw 版本已内置该插件
- 较旧版本/自定义安装可使用上述命令手动添加。
2. 创建一个 **Azure Bot**App ID + 客户端密钥 + tenant ID
3. 使用这些凭证配置 OpenClaw。
4. 通过公 URL 或隧道暴露 `/api/messages`(默认端口为 3978
4. 通过公 URL 或隧道暴露 `/api/messages`(默认端口为 3978
5. 安装 Teams 应用包并启动 Gateway 网关。
最小配置(客户端密钥):
@ -64,15 +64,15 @@ openclaw plugins install ./path/to/local/msteams-plugin
}
```
对于生产部署,建议使用[联合身份验证](#federated-authentication-certificate--managed-identity)(证书或托管身份)来替代客户端密钥。
对于生产部署,建议考虑使用[联合身份验证](#federated-authentication-certificate--managed-identity)(证书或托管身份)而不是客户端密钥。
注意:默认会阻止群聊(`channels.msteams.groupPolicy: "allowlist"`)。要允许群组回复,请设置 `channels.msteams.groupAllowFrom`(或使用 `groupPolicy: "open"` 以允许任成员,但默认仍需提及)。
注意:默认会阻止群聊(`channels.msteams.groupPolicy: "allowlist"`)。要允许群组回复,请设置 `channels.msteams.groupAllowFrom`(或使用 `groupPolicy: "open"` 以允许任成员,但默认仍需提及)。
## 目标
- 通过 Teams 私信、群聊或渠道与 OpenClaw 交互
- 保持路由可预测:回复始终返回消息到达时所在的渠道。
- 默认采用安全的渠道行为(除非另有配置,否则需要提及)。
- 通过 Teams 私信、群聊或渠道与 OpenClaw 对话
- 保持路由可预测:回复始终返回消息原先到达的渠道。
- 默认采用安全的渠道行为(除非另有配置,否则必须提及)。
## 配置写入
@ -90,17 +90,17 @@ openclaw plugins install ./path/to/local/msteams-plugin
**私信访问**
- 默认:`channels.msteams.dmPolicy = "pairing"`。未知发送者会被忽略,直到获得批准
- 默认:`channels.msteams.dmPolicy = "pairing"`。未知发送者在获批前会被忽略。
- `channels.msteams.allowFrom` 应使用稳定的 AAD 对象 ID。
- UPN/显示名称是可变的;默认禁用直接匹配,只有`channels.msteams.dangerouslyAllowNameMatching: true`才会启用。
- UPN/显示名称是可变的;默认禁用直接匹配,`channels.msteams.dangerouslyAllowNameMatching: true` 时启用。
- 当凭证允许时,向导可以通过 Microsoft Graph 将名称解析为 ID。
**群组访问**
- 默认:`channels.msteams.groupPolicy = "allowlist"`(除非你添加 `groupAllowFrom`,否则会被阻止)。未设置,可使用 `channels.defaults.groupPolicy` 覆盖默认值。
- 默认:`channels.msteams.groupPolicy = "allowlist"`(除非你添加 `groupAllowFrom`,否则会被阻止)。未设置,可使用 `channels.defaults.groupPolicy` 覆盖默认值。
- `channels.msteams.groupAllowFrom` 控制哪些发送者可以在群聊/渠道中触发(回退到 `channels.msteams.allowFrom`)。
- 设置 `groupPolicy: "open"` 可允许任意成员(默认仍需提及)。
- 若要**不允许任何渠道**,请设置 `channels.msteams.groupPolicy: "disabled"`
- 设置 `groupPolicy: "open"` 以允许任何成员(默认仍需提及)。
- 若要**完全不允许任何渠道**,请设置 `channels.msteams.groupPolicy: "disabled"`
示例:
@ -117,12 +117,12 @@ openclaw plugins install ./path/to/local/msteams-plugin
**Teams + 渠道允许列表**
- 通过在 `channels.msteams.teams` 下列出团队和渠道,限定群组/渠道回复范围。
- 通过在 `channels.msteams.teams` 下列出团队和渠道,限定群组/渠道回复范围。
- 键应使用稳定的团队 ID 和渠道会话 ID。
- 当 `groupPolicy="allowlist"` 且存在 teams 允许列表时,只接受列出的团队/渠道(默认需提及)。
- 配置向导接受 `Team/Channel` 条目,并会为你存。
- 启动时OpenClaw 会将团队/渠道和用户允许列表名称解析为 ID当 Graph 权限允许时)
并记录映射;无法解析的团队/渠道名称会按原样保留,但默认不会用于路由,除非启用了 `channels.msteams.dangerouslyAllowNameMatching: true`
- 当 `groupPolicy="allowlist"` 且存在 teams 允许列表时,仅接受列出的团队/渠道(仍需提及)。
- 配置向导接受 `Team/Channel` 条目,并会为你存储它们
- 启动时OpenClaw 会将团队/渠道及用户允许列表中的名称解析为 ID当 Graph 权限允许时)
并记录映射;未解析的团队/渠道名称会按输入保留,但默认在路由中忽略,除非启用 `channels.msteams.dangerouslyAllowNameMatching: true`
示例:
@ -146,62 +146,62 @@ openclaw plugins install ./path/to/local/msteams-plugin
## 工作原理
1. 确保 Microsoft Teams 插件可用。
- 当前打包的 OpenClaw 版本已内置
- 较旧/自定义安装可使用上述命令手动添加。
- 当前打包的 OpenClaw 版本已内置该插件
- 较旧版本/自定义安装可使用上述命令手动添加。
2. 创建一个 **Azure Bot**App ID + 密钥 + tenant ID
3. 构建一个**Teams 应用包**该包引用该机器人并包含下面的 RSC 权限。
4. 将 Teams 应用上传/安装到某个团队中(或安装到个人范围以用于私信)。
5. 在 `~/.openclaw/openclaw.json`(或使用环境变量)配置 `msteams`,然后启动 Gateway 网关。
3. 构建一个**Teams 应用包**其中引用该 bot并包含下方的 RSC 权限。
4. 将 Teams 应用上传/安装到某个团队中(或用于私信的个人范围)。
5. 在 `~/.openclaw/openclaw.json` 中配置 `msteams`(或使用环境变量),然后启动 Gateway 网关。
6. Gateway 网关默认在 `/api/messages` 上监听 Bot Framework webhook 流量。
## Azure Bot 设置(前条件)
## Azure Bot 设置(前条件)
在配置 OpenClaw 之前,你需要创建一个 Azure Bot 资源。
在配置 OpenClaw 之前,你需要创建一个 Azure Bot 资源。
### 第 1 步:创建 Azure Bot
1. 前往 [创建 Azure Bot](https://portal.azure.com/#create/Microsoft.AzureBot)
1. 前往 [Create Azure Bot](https://portal.azure.com/#create/Microsoft.AzureBot)
2. 填写 **Basics** 选项卡:
| 字段 | 值 |
| ------------------ | -------------------------------------------------------- |
| **Bot handle** | 你的机器人名称,例如 `openclaw-msteams`(必须唯一) |
| **Bot handle** | 你的 bot 名称,例如 `openclaw-msteams`(必须唯一) |
| **Subscription** | 选择你的 Azure 订阅 |
| **Resource group** | 新建或使用现有资源组 |
| **Pricing tier** | 开发/测试使用 **Free** |
| **Type of App** | **Single Tenant**(推荐 - 见下方说明) |
| **Type of App** | **Single Tenant**(推荐——见下方说明) |
| **Creation type** | **Create new Microsoft App ID** |
> **弃用通知:** 自 2025-07-31 之后,不再支持创建新的多租户机器人。新机器人请使用 **Single Tenant**
> **弃用通知:** 自 2025-07-31 之后,新建多租户 bot 已被弃用。新 bot 请使用 **Single Tenant**
3. 点击 **Review + create****Create**(等待约 12 分钟)
### 第 2 步:获取凭证
1. 进入你的 Azure Bot 资源 → **Configuration**
1. 前往你的 Azure Bot 资源 → **Configuration**
2. 复制 **Microsoft App ID** → 这就是你的 `appId`
3. 点击 **Manage Password**转到 App Registration
4. 在 **Certificates & secrets** **New client secret** → 复制 **Value** → 这就是你的 `appPassword`
5. 转到 **Overview** → 复制 **Directory (tenant) ID** → 这就是你的 `tenantId`
3. 点击 **Manage Password**前往应用注册
4. 在 **Certificates & secrets**点击 **New client secret** → 复制 **Value** → 这就是你的 `appPassword`
5. 前往 **Overview** → 复制 **Directory (tenant) ID** → 这就是你的 `tenantId`
### 第 3 步:配置消息端点
1. 在 Azure Bot 中 **Configuration**
1. 在 Azure Bot 中前往 **Configuration**
2. 将 **Messaging endpoint** 设置为你的 webhook URL
- 生产环境:`https://your-domain.com/api/messages`
- 本地开发:使用隧道(见下方[本地开发](#local-development-tunneling)
- 本地开发:使用隧道(见下方[本地开发](#local-development-tunneling)
### 第 4 步:启用 Teams 渠道
1. 在 Azure Bot 中 **Channels**
1. 在 Azure Bot 中前往 **Channels**
2. 点击 **Microsoft Teams** → Configure → Save
3. 接受服务条款
## 联合身份验证(证书 + 托管身份)
> 新增于 2026.3.24
> 添加于 2026.3.24
对于生产部署OpenClaw 支持将**联合身份验证**作为比客户端密钥更安全的替代方案。提供两种方法
对于生产部署OpenClaw 支持使用**联合身份验证**作为比客户端密钥更安全的替代方案。提供两种方式
### 选项 A基于证书的身份验证
@ -210,7 +210,7 @@ openclaw plugins install ./path/to/local/msteams-plugin
**设置:**
1. 生成或获取证书(带私钥的 PEM 格式)。
2. 在 Entra ID → App Registration → **Certificates & secrets****Certificates** 上传公钥证书。
2. 在 Entra ID → App Registration → **Certificates & secrets****Certificates** 上传公钥证书。
**配置:**
@ -236,22 +236,22 @@ openclaw plugins install ./path/to/local/msteams-plugin
### 选项 BAzure 托管身份
使用 Azure 托管身份实现无密码身份验证。这非常适合部署在 Azure 基础设施AKS、App Service、Azure VM上的场景,在这些环境中使用托管身份。
使用 Azure 托管身份实现无密码身份验证。这非常适合部署在 Azure 基础设施上的场景AKS、App Service、Azure VM即存在可用托管身份
**工作原理:**
1. 机器人 pod/VM 拥有托管身份(系统分配或用户分配)。
2. 一个**联合身份凭证**将该托管身份关联到 Entra ID 应用注册。
1. bot 所在的 pod/VM 拥有托管身份(系统分配或用户分配)。
2. **联合身份凭据**将该托管身份链接到 Entra ID 应用注册。
3. 运行时OpenClaw 使用 `@azure/identity` 从 Azure IMDS 端点(`169.254.169.254`)获取令牌。
4. 该令牌会传递给 Teams SDK,用于机器人身份验证。
4. 该令牌会传递给 Teams SDK 用于 bot 身份验证。
**前条件:**
**前条件:**
- 已启用托管身份的 Azure 基础设施AKS workload identity、App Service、VM
- 已在 Entra ID 应用注册上创建联合身份凭
- pod/VM 可通过网络访问 IMDS`169.254.169.254:80`
- 已在 Entra ID 应用注册上创建联合身份凭
- pod/VM 可访问 IMDS`169.254.169.254:80`
**配置(系统分配托管身份):**
**配置(系统分配托管身份):**
```json5
{
@ -268,7 +268,7 @@ openclaw plugins install ./path/to/local/msteams-plugin
}
```
**配置(用户分配托管身份):**
**配置(用户分配托管身份):**
```json5
{
@ -297,7 +297,7 @@ openclaw plugins install ./path/to/local/msteams-plugin
对于使用 workload identity 的 AKS 部署:
1. 在你的 AKS 集群上**启用 workload identity**。
2. 在 Entra ID 应用注册上**创建联合身份凭**
2. 在 Entra ID 应用注册上**创建联合身份凭**
```bash
az ad app federated-credential create --id <APP_OBJECT_ID> --parameters '{
@ -327,21 +327,21 @@ openclaw plugins install ./path/to/local/msteams-plugin
azure.workload.identity/use: "true"
```
5. **确保可通过网络访问** IMDS`169.254.169.254`)——如果使用了 NetworkPolicy请添加一条出口规则允许访问 `169.254.169.254/32` 的 80 端口流量。
5. **确保网络访问** IMDS`169.254.169.254`)——如果使用了 NetworkPolicy请添加一条出口规则允许访问 `169.254.169.254/32` 的 80 端口流量。
### 身份验证类型对比
| 方法 | 配置 | 优点 | 缺点 |
| -------------------- | ---------------------------------------------- | ---------------------------------- | ------------------------------------- |
| **客户端密钥** | `appPassword` | 设置简单 | 需要轮换密钥,安全性较低 |
| **证书** | `authType: "federated"` + `certificatePath` | 无需通过网络共享密钥 | 证书管理有额外开销 |
| **托管身份** | `authType: "federated"` + `useManagedIdentity` | 无密码无需管理密钥 | 需要 Azure 基础设施 |
| **证书** | `authType: "federated"` + `certificatePath` | 无需在网络上传输共享密钥 | 证书管理有额外开销 |
| **托管身份** | `authType: "federated"` + `useManagedIdentity` | 无密码无需管理密钥 | 需要 Azure 基础设施 |
**默认行为:** 当未设置 `authType`OpenClaw 默认使用客户端密钥身份验证。现有配置无需修改即可继续工作。
## 本地开发(隧道)
Teams 无法访问 `localhost`。本地开发时请使用隧道:
Teams 无法访问 `localhost`进行本地开发时请使用隧道:
**选项 Angrok**
@ -358,44 +358,44 @@ tailscale funnel 3978
# 使用你的 Tailscale funnel URL 作为消息端点
```
## Teams 开发者门户(替代方式
## Teams Developer Portal替代方案
你也可以使用 [Teams Developer Portal](https://dev.teams.microsoft.com/apps),而不是手动创建 manifest ZIP
1. 点击 **+ New app**
2. 填写基本信息(名称、描述、开发者信息)
3. 前往 **App features** → **Bot**
4. 选择 **Enter a bot ID manually**,然后粘贴你的 Azure Bot App ID
4. 选择 **Enter a bot ID manually**粘贴你的 Azure Bot App ID
5. 勾选作用域:**Personal**、**Team**、**Group Chat**
6. 点击 **Distribute** → **Download app package**
7. 在 Teams 中:**Apps** → **Manage your apps****Upload a custom app** → 选择该 ZIP
这通常比手动编辑 JSON manifest 更容易。
## 测试机器人
## 测试 Bot
**选项 AAzure Web Chat先验证 webhook**
1. 在 Azure Portal 中你的 Azure Bot 资源 → **Test in Web Chat**
2. 发送一条消息 —— 你应该能看到回复
3. 这可以在配置 Teams 之前确认你的 webhook 端点可正常工作
1. 在 Azure Portal 中前往你的 Azure Bot 资源 → **Test in Web Chat**
2. 发送一条消息——你应该会看到响应
3. 这可确认你的 webhook 端点在 Teams 设置之前已正常工作
**选项 BTeams安装应用后**
**选项 BTeams安装应用后)**
1. 安装 Teams 应用(旁加载或组织应用目录)
2. 在 Teams 中找到该机器人并发送一条私信
1. 安装 Teams 应用(旁加载或组织目录)
2. 在 Teams 中找到该 bot 并发送一条私信
3. 检查 Gateway 网关日志中的传入 activity
## 设置(最小纯文本)
1. **确保 Microsoft Teams 插件可用**
- 当前打包的 OpenClaw 版本已内置
- 较旧/自定义安装可手动添加:
- 当前打包的 OpenClaw 版本已内置该插件
- 较旧版本/自定义安装可手动添加:
- 从 npm`openclaw plugins install @openclaw/msteams`
- 从本地检出:`openclaw plugins install ./path/to/local/msteams-plugin`
2. **机器人注册**
- 创建一个 Azure Bot见上文,并记录
2. **Bot 注册**
- 创建一个 Azure Bot见上文并记下
- App ID
- 客户端密钥App password
- Tenant ID单租户
@ -406,7 +406,7 @@ tailscale funnel 3978
- `supportsFiles: true`(个人作用域文件处理所必需)。
- 添加 RSC 权限(见下文)。
- 创建图标:`outline.png`32x32`color.png`192x192
- 将三个文件一起打包成 zip`manifest.json`、`outline.png`、`color.png`。
- 将这三个文件一起打包为 zip`manifest.json`、`outline.png`、`color.png`。
4. **配置 OpenClaw**
@ -430,12 +430,12 @@ tailscale funnel 3978
- `MSTEAMS_TENANT_ID`
- `MSTEAMS_AUTH_TYPE`(可选:`"secret"` 或 `"federated"`
- `MSTEAMS_CERTIFICATE_PATH`(联合身份验证 + 证书)
- `MSTEAMS_CERTIFICATE_THUMBPRINT`(可选,身份验证不要
- `MSTEAMS_CERTIFICATE_THUMBPRINT`(可选,身份验证不要)
- `MSTEAMS_USE_MANAGED_IDENTITY`(联合身份验证 + 托管身份)
- `MSTEAMS_MANAGED_IDENTITY_CLIENT_ID`(仅适用于用户分配的 MI
- `MSTEAMS_MANAGED_IDENTITY_CLIENT_ID`(仅用户分配托管身份
5. **机器人端点**
- 将 Azure Bot Messaging Endpoint 设置为:
5. **Bot 端点**
- 将 Azure Bot Messaging Endpoint 设置为:
- `https://<host>:3978/api/messages`(或你选择的路径/端口)。
6. **运行 Gateway 网关**
@ -443,27 +443,27 @@ tailscale funnel 3978
## 成员信息操作
OpenClaw 为 Microsoft Teams 提供了一个由 Graph 支持的 `member-info` 操作,因此智能体和自动化可以直接通过 Microsoft Graph 解析渠道成员详情(显示名称、邮箱、角色)。
OpenClaw 为 Microsoft Teams 提供了基于 Graph 的 `member-info` 操作,因此智能体和自动化流程可以直接从 Microsoft Graph 解析渠道成员详细信息(显示名称、电子邮件、角色)。
要求:
- `Member.Read.Group` RSC 权限(已包含在推荐的 manifest 中)
- 对于跨团队查询:管理员同意的 `User.Read.All` Graph Application 权限
- 对于跨团队查询:需要授予管理员同意的 `User.Read.All` Graph Application 权限
操作受 `channels.msteams.actions.memberInfo` 控制(默认:当 Graph 凭证可用时启用)。
操作受 `channels.msteams.actions.memberInfo` 控制(默认:当 Graph 凭证可用时启用)。
## 历史上下文
- `channels.msteams.historyLimit` 控制会包装进提示词中的最近渠道/群组消息数量。
- 回退到 `messages.groupChat.historyLimit`。设为 `0` 可禁用(默认 50
- 获取到的线程历史会按发送者允许列表(`allowFrom` / `groupAllowFrom`)进行过滤,因此线程上下文预填充目前只会包含来自允许发送者的消息。
- 引用附件上下文(由 Teams 回复 HTML 派生的 `ReplyTo*`)当前会按接收到的内容传递。
- 回退到 `messages.groupChat.historyLimit`。设`0` 可禁用(默认值为 50
- 获取到的线程历史会按发送者允许列表(`allowFrom` / `groupAllowFrom`)进行过滤,因此线程上下文预填充仅包含允许发送者的消息。
- 引用的附件上下文(从 Teams 回复 HTML 派生的 `ReplyTo*`)目前会按接收时原样传递。
- 换句话说,允许列表控制谁可以触发智能体;目前只有特定的补充上下文路径会被过滤。
- 私信历史可通过 `channels.msteams.dmHistoryLimit`(用户轮次)限制。每用户覆盖:`channels.msteams.dms["<user_id>"].historyLimit`。
- 私信历史可通过 `channels.msteams.dmHistoryLimit`(用户轮次)限制。每用户覆盖`channels.msteams.dms["<user_id>"].historyLimit`。
## 当前 Teams RSC 权限Manifest
这些是我们 Teams 应用 manifest 中**现有的 resourceSpecific 权限**。它们只在安装该应用的团队/聊天内部生效。
这些是我们 Teams 应用 manifest 中**现有的 resourceSpecific 权限**。它们仅在安装了该应用的团队/聊天内部生效。
**用于渠道(团队作用域):**
@ -481,7 +481,7 @@ OpenClaw 为 Microsoft Teams 提供了一个由 Graph 支持的 `member-info`
## Teams Manifest 示例(已脱敏)
包含需字段的最小有效示例。请替换其中的 ID 和 URL。
包含需字段的最小有效示例。请替换其中的 ID 和 URL。
```json5
{
@ -529,129 +529,129 @@ OpenClaw 为 Microsoft Teams 提供了一个由 Graph 支持的 `member-info`
}
```
### Manifest 注意事项(必字段)
### Manifest 注意事项(必字段)
- `bots[].botId` **必须**与 Azure Bot App ID 匹配。
- `webApplicationInfo.id` **必须**与 Azure Bot App ID 匹配。
- `bots[].scopes` 必须包含你计划使用的入口`personal`、`team`、`groupChat`)。
- `bots[].supportsFiles: true` 是个人作用域文件处理所必需的
- 如果你想要渠道流量,`authorization.permissions.resourceSpecific` 必须包含渠道读取/发送权限。
- `bots[].scopes` 必须包含你计划使用的界面`personal`、`team`、`groupChat`)。
- `bots[].supportsFiles: true` 是个人作用域文件处理的必需项
- 如果你希望处理渠道流量,`authorization.permissions.resourceSpecific` 必须包含渠道读取/发送权限。
### 更新现有应用
要更新已安装的 Teams 应用(例如添加 RSC 权限):
如需更新一个已经安装的 Teams 应用(例如添加 RSC 权限):
1. 使用新设置更新你的 `manifest.json`
2. **递增 `version` 字段**(例如 `1.0.0``1.1.0`
3. **重新打包 zip**,包 manifest 和图标(`manifest.json`、`outline.png`、`color.png`
4. 上传新 zip
3. **重新打包 zip**,包 manifest 和图标(`manifest.json`、`outline.png`、`color.png`
4. 上传新 zip
- **选项 ATeams Admin Center** Teams Admin Center → Teams apps → Manage apps → 找到你的应用 → Upload new version
- **选项 B旁加载** 在 Teams 中 → Apps → Manage your apps → Upload a custom app
5. **对于团队渠道:** 在每个团队中重新安装该应用,以使新权限生效
6. **完全退出并重新启动 Teams**不是关闭窗口),以清除缓存的应用元数据
6. **完全退出并重新启动 Teams**(不仅仅是关闭窗口),以清除缓存的应用元数据
## 功能:仅 RSC 与 Graph
### 使用**Teams RSC**(已安装应用,无 Graph API 权限)
### 使用 **Teams RSC**(已安装应用,无 Graph API 权限)
可用:
- 读取渠道消息**文本**内容。
- 发送渠道消息**文本**内容。
- 读取渠道消息**文本**内容。
- 发送渠道消息**文本**内容。
- 接收**个人(私信)**文件附件。
不可用:
- 渠道/群组中的**图片或文件内容**payload 只包含 HTML 占位内容)。
- 渠道/群组中的**图片或文件内容**payload 只包含 HTML 占位)。
- 下载存储在 SharePoint/OneDrive 中的附件。
- 读取消息历史(超出实时 webhook 事件之外)。
- 读取消息历史(超出实时 webhook 事件范围)。
### 使用**Teams RSC + Microsoft Graph Application 权限**
### 使用 **Teams RSC + Microsoft Graph Application 权限**
新增:
新增能力
- 下载托管内容(粘贴到消息中的图片)。
- 下载存储在 SharePoint/OneDrive 中的文件附件。
- 通过 Graph 读取渠道/聊天消息历史。
### RSC 与 Graph API
### RSC 与 Graph API 对比
| 能力 | RSC 权限 | Graph API |
| ----------------------- | -------------------- | ----------------------------------- |
| **实时消息** | 是(通过 webhook | 否(仅轮询) |
| **历史消息** | 否 | 是(可查询历史) |
| **设置复杂度** | 仅应用 manifest | 需要管理员同意 + 令牌流程 |
| **离线可用** | 否(必须正在运行 | 是(可随时查询) |
| **离线可用** | 否(必须处于运行中 | 是(可随时查询) |
**结论:** RSC 用于实时监听Graph API 用于历史访问。如果你想在离线期间补回错过的消息,则需要带 `ChannelMessage.Read.All` 的 Graph API需要管理员同意
**结论:** RSC 用于实时监听Graph API 用于历史访问。如果你希望在离线期间补拉遗漏消息,则需要带有 `ChannelMessage.Read.All` 的 Graph API需要管理员同意
## 启用 Graph 的媒体 + 历史记录(渠道必需)
## 启用 Graph 的媒体 + 历史(渠道必需)
如果你需要**渠道**中的图片/文件,或者想获取**消息历史**,则必须启用 Microsoft Graph 权限并授予管理员同意。
如果你在**渠道**中需要图片/文件,或者想要获取**消息历史**,则必须启用 Microsoft Graph 权限并授予管理员同意。
1. 在 Entra IDAzure AD**App Registration** 中添加 Microsoft Graph **Application permissions**
1. 在 Entra IDAzure AD**App Registration** 中添加 Microsoft Graph **Application permissions**
- `ChannelMessage.Read.All`(渠道附件 + 历史)
- `Chat.Read.All``ChatMessage.Read.All`(群聊)
2. 为租户**授予管理员同意**。
3. 提升 Teams 应用**manifest version**,重新上传,并在 Teams 中**重新安装该应用**。
3. 提升 Teams 应用 **manifest 版本**,重新上传,并在 Teams 中**重新安装该应用**。
4. **完全退出并重新启动 Teams**,以清除缓存的应用元数据。
**用户提及的附加权限:** 对于当前会话中的用户,用户 @mentions 开箱即用。但是,如果你想动态搜索并提及**不在当前会话中**的用户,请添加 `User.Read.All`Application权限并授予管理员同意。
**用户提及的额外权限:** 对于对话中的用户,用户 @mentions 可直接使用。不过,如果你想动态搜索并提及**当前对话之外**的用户,请添加 `User.Read.All`Application权限并授予管理员同意。
## 已知限制
### Webhook 超时
Teams 通过 HTTP webhook 传递消息。如果处理耗时过长(例如 LLM 响应缓慢),你可能会看到:
Teams 通过 HTTP webhook 投递消息。如果处理耗时过长(例如 LLM 响应较慢),你可能会看到:
- Gateway 网关超时
- Teams 重试消息(导致重复)
- Teams 重试消息(导致重复)
- 回复丢失
OpenClaw 通过快速返回并主动发送回复来处理这一点,但响应非常慢时仍可能出现问题。
OpenClaw 会通过快速返回并主动发送回复来处理此问题,但响应极慢时仍可能出现问题。
### 格式化
Teams 的 Markdown 比 Slack 或 Discord 更受限
Teams 的 markdown 比 Slack 或 Discord 更受限制
- 基格式可用:**粗体**、_斜体_、`code`、链接
- 复杂 Markdown表格、嵌套列表可能无法正确渲染
- 支持用于投票和任意卡片发送的 Adaptive Cards见下文
- 基格式可用:**粗体**、_斜体_、`code`、链接
- 复杂 markdown表格、嵌套列表可能无法正确渲染
- 支持用于投票和语义化展示发送的 Adaptive Cards见下文
## 配置
关键设置(共享渠道模式见 `/gateway/configuration`
- `channels.msteams.enabled`:启用/禁用该渠道。
- `channels.msteams.appId`、`channels.msteams.appPassword`、`channels.msteams.tenantId`机器人凭证。
- `channels.msteams.appId`、`channels.msteams.appPassword`、`channels.msteams.tenantId`bot 凭证。
- `channels.msteams.webhook.port`(默认 `3978`
- `channels.msteams.webhook.path`(默认 `/api/messages`
- `channels.msteams.dmPolicy``pairing | allowlist | open | disabled`默认pairing
- `channels.msteams.allowFrom`:私信允许列表(推荐使用 AAD 对象 ID。当 Graph 访问可用时,向导会在设置期间将名称解析为 ID。
- `channels.msteams.dangerouslyAllowNameMatching`:紧急开关,用于重新启用可变 UPN/显示名称匹配以及直接使用团队/渠道名称进行路由。
- `channels.msteams.dangerouslyAllowNameMatching`:紧急开关,用于重新启用可变 UPN/显示名称匹配以及直接团队/渠道名称路由。
- `channels.msteams.textChunkLimit`:出站文本分块大小。
- `channels.msteams.chunkMode``length`(默认)或 `newline`会先按空行(段落边界)拆分,再按长度分块
- `channels.msteams.chunkMode``length`(默认)或 `newline`可在按长度分块前先按空行(段落边界)拆分
- `channels.msteams.mediaAllowHosts`:入站附件主机允许列表(默认包含 Microsoft/Teams 域名)。
- `channels.msteams.mediaAuthAllowHosts`:媒体重试时允许附加 Authorization 头的主机允许列表(默认包含 Graph + Bot Framework 主机)。
- `channels.msteams.requireMention`:在渠道/群组中要求 @mention(默认 true
- `channels.msteams.replyStyle``thread | top-level`(参见[回复样式](#reply-style-threads-vs-posts))。
- `channels.msteams.teams.<teamId>.replyStyle`:按团队覆盖。
- `channels.msteams.teams.<teamId>.requireMention`:按团队覆盖。
- `channels.msteams.teams.<teamId>.tools`:按团队的默认工具策略覆盖(`allow`/`deny`/`alsoAllow`缺少渠道覆盖时使用。
- `channels.msteams.teams.<teamId>.toolsBySender`:按团队的默认按发送者工具策略覆盖(支持 `"*"` 通配符)。
- `channels.msteams.teams.<teamId>.tools`:按团队的默认工具策略覆盖(`allow`/`deny`/`alsoAllow`缺少渠道覆盖时使用。
- `channels.msteams.teams.<teamId>.toolsBySender`:按团队、按发送者的默认工具策略覆盖(支持 `"*"` 通配符)。
- `channels.msteams.teams.<teamId>.channels.<conversationId>.replyStyle`:按渠道覆盖。
- `channels.msteams.teams.<teamId>.channels.<conversationId>.requireMention`:按渠道覆盖。
- `channels.msteams.teams.<teamId>.channels.<conversationId>.tools`:按渠道的工具策略覆盖(`allow`/`deny`/`alsoAllow`)。
- `channels.msteams.teams.<teamId>.channels.<conversationId>.toolsBySender`:按渠道的按发送者工具策略覆盖(支持 `"*"` 通配符)。
- `channels.msteams.teams.<teamId>.channels.<conversationId>.toolsBySender`:按渠道、按发送者的工具策略覆盖(支持 `"*"` 通配符)。
- `toolsBySender` 键应使用显式前缀:
`id:`、`e164:`、`username:`、`name:`(旧版无前缀键仍只映射到 `id:`)。
- `channels.msteams.actions.memberInfo`:启用或禁用由 Graph 支持的成员信息操作(默认:当 Graph 凭证可用时启用)。
- `channels.msteams.authType`:身份验证类型 —— `"secret"`(默认)或 `"federated"`
`id:`、`e164:`、`username:`、`name:`(旧版无前缀键仍只映射到 `id:`)。
- `channels.msteams.actions.memberInfo`:启用或禁用基于 Graph 的成员信息操作(默认:当 Graph 凭证可用时启用)。
- `channels.msteams.authType`:身份验证类型——`"secret"`(默认)或 `"federated"`
- `channels.msteams.certificatePath`PEM 证书文件路径(联合身份验证 + 证书身份验证)。
- `channels.msteams.certificateThumbprint`:证书指纹(可选,身份验证不要求)。
- `channels.msteams.useManagedIdentity`:启用托管身份身份验证(联合身份验证模式)。
- `channels.msteams.useManagedIdentity`:启用托管身份验证(联合模式)。
- `channels.msteams.managedIdentityClientId`:用户分配托管身份的客户端 ID。
- `channels.msteams.sharePointSiteId`:用于群聊/渠道文件上传的 SharePoint 站点 ID参见[在群聊中发送文件](#sending-files-in-group-chats))。
- `channels.msteams.sharePointSiteId`:用于群聊/渠道文件上传的 SharePoint 站点 ID参见[在群聊中发送文件](#sending-files-in-group-chats))。
## 路由与会话
@ -661,19 +661,19 @@ Teams 的 Markdown 比 Slack 或 Discord 更受限:
- `agent:<agentId>:msteams:channel:<conversationId>`
- `agent:<agentId>:msteams:group:<conversationId>`
## 回复样式:线程 vs 帖子
## 回复样式:线程帖子
Teams 最近在同一底层数据模型之上引入了两种渠道 UI 样式:
| 样式 | 描述 | 推荐的 `replyStyle` |
| ------------------------ | --------------------------------------------------------- | ------------------------ |
| **Posts**(经典) | 消息显示为卡片,下方带线程回复 | `thread`(默认) |
| **Posts**(经典) | 消息显示为卡片,下方带线程回复 | `thread`(默认) |
| **Threads**(类似 Slack | 消息线性流动,更像 Slack | `top-level` |
**问题:** Teams API 不会公开某个渠道使用的是哪种 UI 样式。如果你使用了错误的 `replyStyle`
**问题:** Teams API 不会暴露某个渠道使用的是哪种 UI 样式。如果你使用了错误的 `replyStyle`
- 在 Threads 风格渠道中使用 `thread` → 回复会以不自然的嵌套方式显示
- 在 Posts 风格渠道中使用 `top-level` → 回复会显示为单独的顶层帖子,而不是在线程中
- 在 Threads 风格渠道中使用 `thread` → 回复会以不自然的嵌套方式显示
- 在 Posts 风格的渠道中使用 `top-level` → 回复会作为单独的顶层帖子出现,而不是在线程中
**解决方案:** 根据渠道的实际设置,按渠道配置 `replyStyle`
@ -700,32 +700,32 @@ Teams 最近在同一底层数据模型之上引入了两种渠道 UI 样式:
**当前限制:**
- **私信:** 图片和文件附件通过 Teams 机器人文件 API 工作。
- **渠道/群组:** 附件存储在 M365 存储中SharePoint/OneDrive。webhook payload 只包含 HTML 占位内容,不包含实际文件字节。**下载渠道附件需要 Graph API 权限**。
- 对于显式的文件优先发送,请使用 `action=upload-file`,并配合 `media` / `filePath` / `path`;可选的 `message` 会作为附带文本/评论,`filename` 会覆盖上传名称。
- **私信:** 图片和文件附件可通过 Teams bot 文件 API 正常工作。
- **渠道/群组:** 附件存储在 M365 存储中SharePoint/OneDrive。webhook payload 仅包含 HTML 占位,不包含实际文件字节。**下载渠道附件需要 Graph API 权限**。
- 对于显式的文件优先发送,请使用 `action=upload-file`,并配合 `media` / `filePath` / `path`;可选的 `message` 将作为随附文本/评论,`filename` 会覆盖上传后的名称。
如果没有 Graph 权限,包含图片的渠道消息将仅作为文本接收(机器人无法访问图片内容)。
默认情况下OpenClaw 只会从 Microsoft/Teams 主机名下载媒体。可通过 `channels.msteams.mediaAllowHosts` 覆盖(使用 `["*"]` 可允许任意主机)。
Authorization 头会附加到 `channels.msteams.mediaAuthAllowHosts` 中的主机(默认包含 Graph + Bot Framework 主机)。请将该列表保持为严格范围(避免多租户后缀)。
如果没有 Graph 权限,带图片的渠道消息将作为仅文本接收bot 无法访问图片内容)。
默认情况下OpenClaw 从 Microsoft/Teams 主机名下载媒体。可通过 `channels.msteams.mediaAllowHosts` 覆盖(使用 `["*"]` 可允许任意主机)。
Authorization 头会附加到 `channels.msteams.mediaAuthAllowHosts` 中的主机(默认包含 Graph + Bot Framework 主机)。请保持此列表严格受限(避免多租户后缀)。
## 在群聊中发送文件
机器人可以在私信中使用 FileConsentCard 流程发送文件(内置支持)。但是,**在群聊/渠道中发送文件**需要额外设置:
Bot 可以通过 FileConsentCard 流程在私信中发送文件(内置支持)。但是,**在群聊/渠道中发送文件**需要额外设置:
| 上下文 | 文件发送方式 | 所需设置 |
| ------------------------ | -------------------------------------------- | ----------------------------------------------- |
| **私信** | FileConsentCard → 用户接受 → 机器人上传 | 开箱即用 |
| **私信** | FileConsentCard → 用户接受 → bot 上传 | 开箱即用 |
| **群聊/渠道** | 上传到 SharePoint → 分享链接 | 需要 `sharePointSiteId` + Graph 权限 |
| **图片(任意上下文)** | Base64 编码内联 | 开箱即用 |
### 为什么群聊需要 SharePoint
机器人没有个人 OneDrive 驱动器(`/me/drive` Graph API 端点不适用于应用身份)。要在群聊/渠道中发送文件,机器人需要上传到一个 **SharePoint 站点**,然后创建共享链接。
Bot 没有个人 OneDrive 驱动器(`/me/drive` Graph API 端点对应用身份不起作用)。要在群聊/渠道中发送文件bot 会上传到某个 **SharePoint 站点**创建共享链接。
### 设置
1. 在 Entra IDAzure AD→ App Registration 中添加 Graph API 权限:
- `Sites.ReadWrite.All`Application- 上传文件到 SharePoint
1. 在 Entra IDAzure AD→ App Registration 中添加 **Graph API 权限**
- `Sites.ReadWrite.All`Application- 将文件上传到 SharePoint
- `Chat.Read.All`Application- 可选,启用按用户共享链接
2. 为租户**授予管理员同意**。
@ -733,11 +733,11 @@ Authorization 头只会附加到 `channels.msteams.mediaAuthAllowHosts` 中的
3. **获取你的 SharePoint 站点 ID**
```bash
# 通过 Graph Explorer 或有效令牌的 curl
# 通过 Graph Explorer 或使用有效令牌的 curl
curl -H "Authorization: Bearer $TOKEN" \
"https://graph.microsoft.com/v1.0/sites/{hostname}:/{site-path}"
# 示例:站点位于 "contoso.sharepoint.com/sites/BotFiles"
# 示例:站点位于 "contoso.sharepoint.com/sites/BotFiles"
curl -H "Authorization: Bearer $TOKEN" \
"https://graph.microsoft.com/v1.0/sites/contoso.sharepoint.com:/sites/BotFiles"
@ -761,10 +761,10 @@ Authorization 头只会附加到 `channels.msteams.mediaAuthAllowHosts` 中的
| 权限 | 共享行为 |
| --------------------------------------- | --------------------------------------------------------- |
| `Sites.ReadWrite.All` only | 面向整个组织的共享链接(组织中的任何人都可访问) |
| `Sites.ReadWrite.All` 单独使用 | 组织范围共享链接(组织内任何人都可访问) |
| `Sites.ReadWrite.All` + `Chat.Read.All` | 按用户共享链接(仅聊天成员可访问) |
按用户共享更安全,因为只有聊天参与者可以访问该文件。如果缺少 `Chat.Read.All` 权限,机器人会回退为面向整个组织的共享。
按用户共享更安全,因为只有聊天参与者可以访问该文件。如果缺少 `Chat.Read.All` 权限,bot 会回退为组织范围共享。
### 回退行为
@ -777,22 +777,22 @@ Authorization 头只会附加到 `channels.msteams.mediaAuthAllowHosts` 中的
### 文件存储位置
上传的文件存储在已配置 SharePoint 站点默认文档库中的 `/OpenClawShared/` 文件夹
上传的文件存储在已配置 SharePoint 站点默认文档库中的 `/OpenClawShared/` 文件夹
## 投票Adaptive Cards
OpenClaw 将 Teams 投票作为 Adaptive Cards 发送Teams 没有原生投票 API
- CLI`openclaw message poll --channel msteams --target conversation:<id> ...`
- 投票由 Gateway 网关记录到 `~/.openclaw/msteams-polls.json`
- 投票结果由 Gateway 网关记录在 `~/.openclaw/msteams-polls.json`
- Gateway 网关必须保持在线才能记录投票。
- 目前不会自动发布结果摘要(如有需要,请检查存储文件)。
- 投票尚不会自动发布结果摘要(如有需要,请检查存储文件)。
## Adaptive Cards任意
## 展示卡片
使用 `message` 工具或 CLI 向 Teams 用户或会话发送任意 Adaptive Card JSON
使用 `message` 工具或 CLI,将语义化展示 payload 发送给 Teams 用户或会话。OpenClaw 会根据通用展示契约将其渲染为 Teams Adaptive Cards
`card` 参数接受一个 Adaptive Card JSON 对象。提供 `card` 时,消息文本为可选项。
`presentation` 参数接受语义化块。提供 `presentation` 时,消息文本为可选项。
**智能体工具:**
@ -801,10 +801,9 @@ OpenClaw 将 Teams 投票作为 Adaptive Cards 发送Teams 没有原生投票
action: "send",
channel: "msteams",
target: "user:<id>",
card: {
type: "AdaptiveCard",
version: "1.5",
body: [{ type: "TextBlock", text: "Hello!" }],
presentation: {
title: "Hello",
blocks: [{ type: "text", text: "Hello!" }],
},
}
```
@ -814,14 +813,14 @@ OpenClaw 将 Teams 投票作为 Adaptive Cards 发送Teams 没有原生投票
```bash
openclaw message send --channel msteams \
--target "conversation:19:abc...@thread.tacv2" \
--card '{"type":"AdaptiveCard","version":"1.5","body":[{"type":"TextBlock","text":"Hello!"}]}'
--presentation '{"title":"Hello","blocks":[{"type":"text","text":"Hello!"}]}'
```
有关卡片 schema 和示例,请参见 [Adaptive Cards documentation](https://adaptivecards.io/)。有关目标格式的详细信息,请参见下文的[目标格式](#target-formats)。
关于 target 格式的详细信息,参见下文的[目标格式](#target-formats)。
## 目标格式
MSTeams 目标使用前缀来区分用户和会话:
MSTeams target 使用前缀来区分用户和会话:
| 目标类型 | 格式 | 示例 |
| ------------------- | -------------------------------- | --------------------------------------------------- |
@ -833,18 +832,18 @@ MSTeams 目标使用前缀来区分用户和会话:
**CLI 示例:**
```bash
# 按 ID 向用户发送
# Send to a user by ID
openclaw message send --channel msteams --target "user:40a1a0ed-..." --message "Hello"
# 按显示名称向用户发送(会触发 Graph API 查找)
# Send to a user by display name (triggers Graph API lookup)
openclaw message send --channel msteams --target "user:John Smith" --message "Hello"
# 发送到群聊或渠道
# Send to a group chat or channel
openclaw message send --channel msteams --target "conversation:19:abc...@thread.tacv2" --message "Hello"
# 向会话发送 Adaptive Card
# Send a presentation card to a conversation
openclaw message send --channel msteams --target "conversation:19:abc...@thread.tacv2" \
--card '{"type":"AdaptiveCard","version":"1.5","body":[{"type":"TextBlock","text":"Hello"}]}'
--presentation '{"title":"Hello","blocks":[{"type":"text","text":"Hello"}]}'
```
**智能体工具示例:**
@ -863,20 +862,19 @@ openclaw message send --channel msteams --target "conversation:19:abc...@thread.
action: "send",
channel: "msteams",
target: "conversation:19:abc...@thread.tacv2",
card: {
type: "AdaptiveCard",
version: "1.5",
body: [{ type: "TextBlock", text: "Hello" }],
presentation: {
title: "Hello",
blocks: [{ type: "text", text: "Hello" }],
},
}
```
注意:如果没有 `user:` 前缀,名称默认会按群组/团队解析。按显示名称定位人员时,请始终使用 `user:`
注意:如果没有 `user:` 前缀,名称默认会按群组/团队解析。按显示名称定位用户时,请始终使用 `user:`
## 主动消息
- 只有在用户已经发生过交互之后,才可以发送**主动消息**,因为我们会在那时存储会话引用。
- `dmPolicy` 和允许列表限制,请参见 `/gateway/configuration`
- 只有在用户**交互之后**才可以发送主动消息,因为我们会在那时存储会话引用。
- 关 `dmPolicy` 和允许列表限制,请参见 `/gateway/configuration`
## 团队和渠道 ID常见陷阱
@ -898,67 +896,67 @@ https://teams.microsoft.com/l/channel/19%3A15bc...%40thread.tacv2/ChannelName?gr
渠道 ID对其进行 URL 解码)
```
**用于配置**
**用于配置:**
- 团队 ID = `/team/`的路径段URL 解码后,例如 `19:Bk4j...@thread.tacv2`
- 渠道 ID = `/channel/`的路径段URL 解码后)
- 团队 ID = `/team/` 后的路径段URL 解码后,例如 `19:Bk4j...@thread.tacv2`
- 渠道 ID = `/channel/` 后的路径段URL 解码后)
- **忽略** `groupId` 查询参数
## 私有渠道
机器人在私有渠道中的支持有限:
Bot 在私有渠道中的支持有限:
| 功能 | 标准渠道 | 私有渠道 |
| ---------------------------- | ----------------- | ---------------------- |
| 机器人安装 | 是 | 有限 |
| Bot 安装 | 是 | 有限 |
| 实时消息webhook | 是 | 可能不可用 |
| RSC 权限 | 是 | 行为可能不同 |
| @mentions | 是 | 如果机器人可访问 |
| @mentions | 是 | 如果 bot 可访问 |
| Graph API 历史记录 | 是 | 是(有权限时) |
**如果私有渠道不可用,可尝试以下变通方法**
**如果私有渠道不可用,可采用以下变通方案**
1. 使用标准渠道进行机器人交互
2. 使用私信 - 用户始终可以直接向机器人发送消息
3. 使用 Graph API 获取历史记录(需要 `ChannelMessage.Read.All`
1. 使用标准渠道进行 bot 交互
2. 使用私信——用户始终可以直接给 bot 发消息
3. 使用 Graph API 访问历史记录(需要 `ChannelMessage.Read.All`
## 故障排除
### 常见问题
- **渠道中图片不显示:** 缺少 Graph 权限或管理员同意。请重新安装 Teams 应用,并完全退出/重新打开 Teams。
- **渠道中没有响应:** 默认要求 mentions;请设置 `channels.msteams.requireMention=false`,或按团队/渠道配置。
- **版本不匹配Teams 仍显示旧 manifest** 删除并重新添加应用,然后完全退出 Teams 以刷新。
- **Webhook 返回 401 Unauthorized** 如果你在没有 Azure JWT 的情况下手动测试,这是预期行为 —— 说明端点可达,但身份验证失败。请使用 Azure Web Chat 进行正确测试。
- **渠道中没有响应:** 默认要求提及;请设置 `channels.msteams.requireMention=false`,或按团队/渠道进行配置。
- **版本不匹配Teams 仍显示旧 manifest** 删除并重新添加应用,然后完全退出 Teams 以刷新。
- **webhook 返回 401 Unauthorized** 在未携带 Azure JWT 的情况下手动测试时这是预期现象——说明端点可达,但身份验证失败。请使用 Azure Web Chat 正确测试。
### Manifest 上传错误
- **“Icon file cannot be empty”** manifest 引用了大小为 0 字节的图标文件。请创建有效的 PNG 图标(`outline.png` 为 32x32`color.png` 为 192x192
- **“webApplicationInfo.Id already in use”** 该应用仍安装在另一个团队/聊天中。请先找到并卸载,或等待 510 分钟完成传播。
- **“Icon file cannot be empty”** manifest 引用了 0 字节的图标文件。请创建有效的 PNG 图标(`outline.png` 为 32x32`color.png` 为 192x192
- **“webApplicationInfo.Id already in use”** 该应用仍安装在另一个团队/聊天中。请先找到并卸载,或等待 510 分钟让变更传播。
- **上传时出现 “Something went wrong”** 请改为通过 [https://admin.teams.microsoft.com](https://admin.teams.microsoft.com) 上传,打开浏览器 DevToolsF12→ Network 选项卡,并检查响应体中的实际错误。
- **旁加载失败:** 请尝试使用“Upload an app to your org's app catalog”而不是“Upload a custom app”—— 这通常可以绕过旁加载限制。
- **旁加载失败:** 请尝试使用 “Upload an app to your org's app catalog”而不是 “Upload a custom app”——这通常可以绕过旁加载限制。
### RSC 权限不起作用
### RSC 权限不生效
1. 验证 `webApplicationInfo.id` 与你的机器人 App ID 完全一致
1. 确认 `webApplicationInfo.id` 与你的 bot App ID 完全匹配
2. 重新上传应用,并在团队/聊天中重新安装
3. 检查你的组织管理员是否阻止了 RSC 权限
4. 确认你使用了正确的作用域:团队使用 `ChannelMessage.Read.Group`,群聊使用 `ChatMessage.Read.Chat`
## 参考资料
- [创建 Azure Bot](https://learn.microsoft.com/en-us/azure/bot-service/bot-service-quickstart-registration) - Azure Bot 设置指南
- [Create Azure Bot](https://learn.microsoft.com/en-us/azure/bot-service/bot-service-quickstart-registration) - Azure Bot 设置指南
- [Teams Developer Portal](https://dev.teams.microsoft.com/apps) - 创建/管理 Teams 应用
- [Teams 应用 manifest schema](https://learn.microsoft.com/en-us/microsoftteams/platform/resources/schema/manifest-schema)
- [使用 RSC 接收渠道消息](https://learn.microsoft.com/en-us/microsoftteams/platform/bots/how-to/conversations/channel-messages-with-rsc)
- [RSC 权限参考](https://learn.microsoft.com/en-us/microsoftteams/platform/graph-api/rsc/resource-specific-consent)
- [Teams 机器人文件处理](https://learn.microsoft.com/en-us/microsoftteams/platform/bots/how-to/bots-filesv4)(渠道/群组需要 Graph
- [主动消息](https://learn.microsoft.com/en-us/microsoftteams/platform/bots/how-to/conversations/send-proactive-messages)
- [Teams app manifest schema](https://learn.microsoft.com/en-us/microsoftteams/platform/resources/schema/manifest-schema)
- [Receive channel messages with RSC](https://learn.microsoft.com/en-us/microsoftteams/platform/bots/how-to/conversations/channel-messages-with-rsc)
- [RSC permissions reference](https://learn.microsoft.com/en-us/microsoftteams/platform/graph-api/rsc/resource-specific-consent)
- [Teams bot file handling](https://learn.microsoft.com/en-us/microsoftteams/platform/bots/how-to/bots-filesv4)(渠道/群组需要 Graph
- [Proactive messaging](https://learn.microsoft.com/en-us/microsoftteams/platform/bots/how-to/conversations/send-proactive-messages)
## 相关内容
- [渠道概览](/zh-CN/channels) — 所有受支持的渠道
- [配对](/zh-CN/channels/pairing) — 私信身份验证与配对流程
- [群组](/zh-CN/channels/groups) — 群聊行为与 mention 限制
- [渠道路由](/zh-CN/channels/channel-routing) — 消息的会话路由
- [安全](/zh-CN/gateway/security) — 访问模型与加固措施
- [Channels Overview](/zh-CN/channels) — 所有受支持的渠道
- [Pairing](/zh-CN/channels/pairing) — 私信身份验证和配对流程
- [Groups](/zh-CN/channels/groups) — 群聊行为和提及限制
- [Channel Routing](/zh-CN/channels/channel-routing) — 消息的会话路由
- [Security](/zh-CN/gateway/security) — 访问模型和安全加固

View File

@ -3,35 +3,34 @@ read_when:
- 你想将 OpenClaw 连接到 QQ
- 你需要设置 QQ Bot 凭证
- 你想使用 QQ Bot 群聊或私聊支持
summary: QQ Bot 设置、配置和使用方法
summary: QQ Bot 设置、配置和使用
title: QQ Bot
x-i18n:
generated_at: "2026-04-05T08:16:39Z"
generated_at: "2026-04-21T20:34:48Z"
model: gpt-5.4
provider: openai
source_hash: 0e58fb7b07c59ecbf80a1276368c4a007b45d84e296ed40cffe9845e0953696c
source_hash: 49a5ae5615935a435a69748a3c4465ae8c33d3ab84db5e37fd8beec70506ce36
source_path: channels/qqbot.md
workflow: 15
---
# QQ Bot
QQ Bot 通过官方 QQ Bot APIWebSocket 网关)连接到 OpenClaw。该插件支持 C2C 私聊、群 @ 消息以及频道消息,并支持富媒体(图片、语音、视频、文件)。
QQ Bot 通过官方 QQ Bot APIWebSocket Gateway 网关)连接到 OpenClaw。该插件支持 C2C 私聊、群 @消息以及频道消息,并支持富媒体(图片、语音、视频、文件)。
状态:内置插件。支持私信、群聊、频道和媒体。不支持表情回应和线程。
状态:内置插件。支持私信、群聊、频道以及媒体。不支持表情回应和话题线程。
## 内置插件
当前 OpenClaw 版本已内置 QQ Bot因此普通打包构建不需要单独执行 `openclaw plugins install` 步骤。
当前 OpenClaw 版本已内置 QQ Bot因此普通打包构建不需要单独执行 `openclaw plugins install` 步骤。
## 设置
1. 前往 [QQ Open Platform](https://q.qq.com/),使用你的手机 QQ 扫描二维码完成注册/登录。
1. 前往 [QQ 开放平台](https://q.qq.com/),使用手机 QQ 扫描二维码进行注册 / 登录。
2. 点击 **Create Bot** 创建一个新的 QQ 机器人。
3. 在机器人的设置页面找到 **AppID****AppSecret** 并复制它们。
> AppSecret 不会以明文存储——如果你离开该页面而没有保存它,
> 你将不得不重新生成一个新的。
> AppSecret 不会以明文存储——如果你在未保存的情况下离开页面,就必须重新生成一个新的。
4. 添加渠道:
@ -64,12 +63,12 @@ openclaw configure --section channels
}
```
默认账环境变量:
默认账环境变量:
- `QQBOT_APP_ID`
- `QQBOT_CLIENT_SECRET`
基于文件的 AppSecret
使用文件存储的 AppSecret
```json5
{
@ -85,12 +84,11 @@ openclaw configure --section channels
说明:
- 环境变量回退仅适用于默认 QQ Bot 账号。
- `openclaw channels add --channel qqbot --token-file ...` 仅提供
AppSecretAppID 必须已在配置或 `QQBOT_APP_ID` 中设置。
- `clientSecret` 也接受 SecretRef 输入,而不只是明文字符串。
- 环境变量回退仅适用于默认 QQ Bot 账户。
- `openclaw channels add --channel qqbot --token-file ...` 仅提供 AppSecretAppID 必须已在配置中设置,或通过 `QQBOT_APP_ID` 提供。
- `clientSecret` 也接受 SecretRef 输入,而不仅仅是明文字符串。
### 多账设置
### 多账设置
在单个 OpenClaw 实例下运行多个 QQ 机器人:
@ -113,7 +111,7 @@ openclaw configure --section channels
}
```
每个账号都会启动自己的 WebSocket 连接,并维护独立的 token 缓存(按 `appId` 隔离)。
每个账户都会启动自己的 WebSocket 连接,并维护独立的令牌缓存(按 `appId` 隔离)。
通过 CLI 添加第二个机器人:
@ -123,12 +121,12 @@ openclaw channels add --channel qqbot --account bot2 --token "222222222:secret-o
### 语音STT / TTS
STT 和 TTS 支持两级配置优先级回退:
STT 和 TTS 支持两级配置,并按优先级回退:
| 设置 | 插件专用 | 框架回退 |
| ------- | -------------------- | ----------------------------- |
| STT | `channels.qqbot.stt` | `tools.media.audio.models[0]` |
| TTS | `channels.qqbot.tts` | `messages.tts` |
| 设置 | 插件专用 | 框架回退 |
| ----- | -------------------- | ----------------------------- |
| STT | `channels.qqbot.stt` | `tools.media.audio.models[0]` |
| TTS | `channels.qqbot.tts` | `messages.tts` |
```json5
{
@ -148,10 +146,9 @@ STT 和 TTS 支持两级配置与优先级回退:
}
```
在任一项上设置 `enabled: false`将其禁用。
在任一项上设置 `enabled: false` 可禁用。
出站音频上传/转码行为也可通过
`channels.qqbot.audioFormatPolicy` 进行调优:
出站音频上传 / 转码行为也可以通过 `channels.qqbot.audioFormatPolicy` 进行调整:
- `sttDirectFormats`
- `uploadDirectFormats`
@ -159,33 +156,52 @@ STT 和 TTS 支持两级配置与优先级回退:
## 目标格式
| 格式 | 说明 |
| -------------------------- | ------------------ |
| `qqbot:c2c:OPENID` | 私聊C2C |
| `qqbot:group:GROUP_OPENID` | 群聊 |
| `qqbot:channel:CHANNEL_ID` | 频道 |
| 格式 | 说明 |
| -------------------------- | -------------- |
| `qqbot:c2c:OPENID` | 私聊C2C |
| `qqbot:group:GROUP_OPENID` | 群聊 |
| `qqbot:channel:CHANNEL_ID` | 频道 |
> 每个机器人都有自己的一组用户 OpenID。由机器人 A 接收到的 OpenID **不能**
> 用于通过机器人 B 发送消息。
> 每个机器人都有自己的一组用户 OpenID。由机器人 A 收到的 OpenID **不能** 用于通过机器人 B 发送消息。
## 斜杠命令
## Slash 命令
进入 AI 队列前会先拦截内置命令:
在 AI 队列前拦截内置命令:
| 命令 | 说明 |
| -------------- | ------------------------------------ |
| `/bot-ping` | 延迟测试 |
| `/bot-version` | 显示 OpenClaw 框架版本 |
| `/bot-help` | 列出所有命令 |
| `/bot-upgrade` | 显示 QQBot 升级指南链接 |
| `/bot-logs` | 将最近的 gateway 日志导出为文件 |
| 命令 | 说明 |
| -------------- | ------------------------------------------------------------------------------------------ |
| `/bot-ping` | 延迟测试 |
| `/bot-version` | 显示 OpenClaw 框架版本 |
| `/bot-help` | 列出所有命令 |
| `/bot-upgrade` | 显示 QQBot 升级指南链接 |
| `/bot-logs` | 将最近的 Gateway 网关日志导出为文件 |
| `/bot-approve` | 通过原生流程批准待处理的 QQ Bot 操作(例如,确认 C2C 或群组上传)。 |
在任意命令后追加 `?` 可查看用法帮助(例如 `/bot-upgrade ?`)。
在任意命令后附加 `?` 可查看用法帮助(例如 `/bot-upgrade ?`)。
## 引擎架构
QQ Bot 作为插件内的自包含引擎提供:
- 每个账户都拥有一个独立的资源栈WebSocket 连接、API 客户端、令牌缓存、媒体存储根目录),并以 `appId` 作为键。账户之间绝不会共享入站 / 出站状态。
- 多账户日志记录器会使用所属账户为日志行打标签,因此当你在一个 Gateway 网关下运行多个机器人时,诊断信息仍可彼此区分。
- 入站、出站和 Gateway 网关桥接路径共享 `~/.openclaw/media` 下的单一媒体负载根目录,因此上传、下载和转码缓存都会落在同一个受保护目录中,而不是按子系统分别存放。
- 凭证可以作为标准 OpenClaw 凭证快照的一部分进行备份和恢复;恢复后,引擎会为每个账户重新附加其资源栈,而无需重新进行二维码配对。
## 二维码新手引导
除了手动粘贴 `AppID:AppSecret` 外,该引擎还支持二维码新手引导流程,用于将 QQ Bot 连接到 OpenClaw
1. 运行 QQ Bot 设置路径(例如 `openclaw channels add --channel qqbot`),并在提示时选择二维码流程。
2. 使用与目标 QQ Bot 绑定的手机应用扫描生成的二维码。
3. 在手机上批准配对。OpenClaw 会将返回的凭证持久化到正确账户作用域下的 `credentials/` 中。
由机器人自身生成的批准提示(例如 QQ Bot API 暴露的“允许此操作?”流程)会以 OpenClaw 原生提示的形式显示,你可以使用 `/bot-approve` 接受,而不必通过原始 QQ 客户端回复。
## 故障排除
- **机器人回复 “gone to Mars”** 未配置凭证,或 Gateway 网关未启动。
- **没有入站消息:** 请验证 `appId``clientSecret` 是否正确,以及机器人是否已在 QQ Open Platform 上启用。
- **使用 `--token-file` 设置后仍显示未配置:** `--token-file` 仅设置 AppSecret。你仍然需要在配置中设置 `appId`,或设置 `QQBOT_APP_ID`
- **主动消息未送达:** 如果用户最近没有互动QQ 可能会拦截机器人主动发起的消息。
- **语音未转写:** 请确保已配置 STT且提供商可访问。
- **机器人回复“gone to Mars”** 未配置凭证,或 Gateway 网关未启动。
- **没有入站消息:** 请验证 `appId``clientSecret` 是否正确,并确认该机器人已在 QQ 开放平台启用。
- **使用 `--token-file` 设置后仍显示未配置:** `--token-file` 仅设置 AppSecret。你仍然需要在配置中设置 `appId`,或提供 `QQBOT_APP_ID`
- **主动消息未送达:** 如果用户近没有QQ 可能会拦截机器人主动发起的消息。
- **语音未转写:** 请确保已配置 STT对应提供商可访问。

View File

@ -1,30 +1,30 @@
---
read_when:
- 处理 Telegram 功能或 Webhook 时
- 正在处理 Telegram 功能或 webhook
summary: Telegram 机器人支持状态、功能和配置
title: Telegram
x-i18n:
generated_at: "2026-04-21T16:52:55Z"
generated_at: "2026-04-21T20:34:43Z"
model: gpt-5.4
provider: openai
source_hash: 816238b53942b319a300843db62ec1d4bf8d84bc11094010926ac9ad457c6d3d
source_hash: 1575c4e5e932a4a6330d57fa0d1639336aecdb8fa70d37d92dccd0d466d2fccb
source_path: channels/telegram.md
workflow: 15
---
# TelegramBot API
状态:通过 grammY 支持用于机器人私信和群组的生产就绪。长轮询是默认模式Webhook 模式为可选。
状态:基于 grammY 的机器人私信 + 群组支持已可用于生产环境。默认模式为长轮询webhook 模式为可选。
<CardGroup cols={3}>
<Card title="配对" icon="link" href="/zh-CN/channels/pairing">
Telegram 的默认私信策略是配对。
</Card>
<Card title="渠道故障排除" icon="wrench" href="/zh-CN/channels/troubleshooting">
跨渠道诊断和修复操作手册。
跨渠道诊断与修复手册。
</Card>
<Card title="Gateway 网关配置" icon="settings" href="/zh-CN/gateway/configuration">
完整的渠道配置模式示例。
完整的渠道配置模式示例。
</Card>
</CardGroup>
@ -32,9 +32,9 @@ x-i18n:
<Steps>
<Step title="在 BotFather 中创建机器人令牌">
打开 Telegram 并与 **@BotFather** 对话(确认用户名严格为 `@BotFather`)。
打开 Telegram 并与 **@BotFather** 聊天(确认用户名严格为 `@BotFather`)。
运行 `/newbot`,按提示操作,并保存令牌。
运行 `/newbot`,按提示操作,并保存令牌。
</Step>
@ -71,31 +71,31 @@ openclaw pairing approve telegram <CODE>
</Step>
<Step title="将机器人添加到群组">
将机器人添加到你的群组,然后设置 `channels.telegram.groups``groupPolicy` 以匹配你的访问模型
将机器人添加到你的群组,然后设置 `channels.telegram.groups``groupPolicy`,使其与你的访问模型匹配
</Step>
</Steps>
<Note>
令牌解析顺序与账户相关。实际生效时,配置值优先于环境变量回退,并且 `TELEGRAM_BOT_TOKEN` 仅适用于默认账户。
令牌解析顺序是账户感知的。实际行为是,配置中的值优先于环境变量回退,而 `TELEGRAM_BOT_TOKEN` 仅适用于默认账户。
</Note>
## Telegram 设置
## Telegram 设置
<AccordionGroup>
<Accordion title="隐私模式和群组可见性">
Telegram 机器人默认启用 **隐私模式**,这会限制它们能接收到的群组消息。
如果机器人必须看到所有群组消息,可以选择以下任一方式:
如果机器人必须看到所有群组消息,可以采用以下任一方式:
- 通过 `/setprivacy` 禁用隐私模式,或
- 将机器人设为群组管理员。
切换隐私模式后,请在每个群组中移除并重新添加机器人,以便 Telegram 应用更改。
切换隐私模式后,请在每个群组中移除并重新添加机器人,以便 Telegram 应用更改。
</Accordion>
<Accordion title="群组权限">
管理员身份在 Telegram 群组设置中控制。
管理员状态在 Telegram 群组设置中控制。
管理员机器人会接收所有群组消息,这对于始终在线的群组行为很有用。
@ -103,13 +103,13 @@ openclaw pairing approve telegram <CODE>
<Accordion title="有用的 BotFather 开关">
- `/setjoingroups`:允许/禁止加入群组
- `/setjoingroups`:允许/拒绝加入群组
- `/setprivacy`:控制群组可见性行为
</Accordion>
</AccordionGroup>
## 访问控制激活
## 访问控制激活
<Tabs>
<Tab title="私信策略">
@ -120,23 +120,23 @@ openclaw pairing approve telegram <CODE>
- `open`(要求 `allowFrom` 包含 `"*"`
- `disabled`
`channels.telegram.allowFrom` 接受数字 Telegram 用户 ID。`telegram:` / `tg:` 前缀会被接受并标准化。
`dmPolicy: "allowlist"``allowFrom` 为空时会阻止所有私信,并被配置校验拒绝。
设置时只会要求输入数字用户 ID。
如果你升级后发现配置中包含 `@username` 形式的允许列表条目,请运行 `openclaw doctor --fix` 进行解析(尽力而为;需要 Telegram 机器人令牌)。
如果你之前依赖配对存储的允许列表文件,在允许列表流程中(例如 `dmPolicy: "allowlist"` 还没有显式 ID 时),`openclaw doctor --fix` 可以将这些条目恢复到 `channels.telegram.allowFrom`
`channels.telegram.allowFrom` 接受数字形式的 Telegram 用户 ID。`telegram:` / `tg:` 前缀会被接受并规范化。
`dmPolicy: "allowlist"``allowFrom` 为空时会阻止所有私信,并被配置校验拒绝。
设置时只会要求填写数字用户 ID。
如果你已升级,且配置中包含 `@username` 形式的 allowlist 条目,请运行 `openclaw doctor --fix` 进行解析(尽力而为;需要 Telegram 机器人令牌)。
如果你之前依赖配对存储的 allowlist 文件,`openclaw doctor --fix` 可以在 allowlist 流程中将这些条目恢复到 `channels.telegram.allowFrom`(例如当 `dmPolicy: "allowlist"` 还没有显式 ID 时)
对于单所有者机器人,建议优先使用 `dmPolicy: "allowlist"` 并显式设置数字 `allowFrom` ID这样访问策略会稳定保存在配置中(而不是依赖此前的配对批准)。
对于单所有者机器人,建议优先使用 `dmPolicy: "allowlist"` 并显式设置数字 `allowFrom` ID以便将访问策略稳定保存在配置中(而不是依赖过去的配对批准)。
常见困惑:批准私信配对并不意味着“该发送者在所有地方都已获授权”。
配对只授予私信访问权限。群组发送者授权仍然来自显式配置的允许列表
如果你希望“我授权一次后,私信和群组命令都能工作”,请把你的数字 Telegram 用户 ID 放入 `channels.telegram.allowFrom`
常见误解:私信配对批准并不意味着“此发送者在所有地方都被授权”。
配对只授予私信访问权限。群组发送者授权仍然来自显式配置 allowlist
如果你希望“我授权一次后,私信和群组命令都能使用”,请将你的数字 Telegram 用户 ID 放入 `channels.telegram.allowFrom`
### 查找你的 Telegram 用户 ID
更安全的方法(无需第三方机器人):
1. 你的机器人发送私信。
1. 你的机器人发送私信。
2. 运行 `openclaw logs --follow`
3. 读取 `from.id`
@ -146,18 +146,18 @@ openclaw pairing approve telegram <CODE>
curl "https://api.telegram.org/bot<bot_token>/getUpdates"
```
第三方方法(隐私性较`@userinfobot` 或 `@getidsbot`
第三方方法(隐私性较`@userinfobot` 或 `@getidsbot`
</Tab>
<Tab title="群组策略和允许列表">
以下两个控制项会共同生效:
<Tab title="群组策略和 allowlist">
有两个控制项会一起生效:
1. **允许哪些群组**`channels.telegram.groups`
- 没有 `groups` 配置:
- `groupPolicy: "open"`:任何群组都可以通过群组 ID 检查
- `groupPolicy: "allowlist"`(默认):在你添加 `groups` 条目(或 `"*"`)之前,所有群组会被阻止
- 已配置 `groups`:其行为等同于允许列表(显式 ID 或 `"*"`
- 没有 `groups` 配置
- 如果 `groupPolicy: "open"`:任何群组都可以通过群组 ID 检查
- 如果 `groupPolicy: "allowlist"`(默认):在你添加 `groups` 条目(或 `"*"`)之前,群组会被阻止
- 配置了 `groups`:它会作为 allowlist 生效(显式 ID 或 `"*"`
2. **群组中允许哪些发送者**`channels.telegram.groupPolicy`
- `open`
@ -165,14 +165,14 @@ curl "https://api.telegram.org/bot<bot_token>/getUpdates"
- `disabled`
`groupAllowFrom` 用于群组发送者过滤。如果未设置Telegram 会回退到 `allowFrom`
`groupAllowFrom` 条目应为数字 Telegram 用户 ID`telegram:` / `tg:` 前缀会被标准化)。
不要把 Telegram 群组或超级群组聊天 ID 放在 `groupAllowFrom`。负数聊天 ID 应放在 `channels.telegram.groups` 下。
非数字条目会在发送者授权被忽略。
安全边界(`2026.2.25+`):群组发送者授权 **不会** 继承私信配对存储中的批准记录
配对仍然仅私信。对于群组,请设置 `groupAllowFrom` 或按群组/话题设置 `allowFrom`
如果 `groupAllowFrom` 未设置Telegram 会回退到配置中的 `allowFrom`,而不是配对存储。
所有者机器人的实用模式:将你的用户 ID 设置在 `channels.telegram.allowFrom` 中,保持 `groupAllowFrom` 未设置,并在 `channels.telegram.groups` 下允许目标群组。
运行时说明:如果 `channels.telegram` 完全缺失,运行时默认采用失败关闭的 `groupPolicy="allowlist"`,除非显式设置了 `channels.defaults.groupPolicy`
`groupAllowFrom` 条目应为数字形式的 Telegram 用户 ID`telegram:` / `tg:` 前缀会被规范化)。
不要将 Telegram 群组或超级群组聊天 ID 放入 `groupAllowFrom`。负数聊天 ID 应放在 `channels.telegram.groups` 下。
非数字条目会在发送者授权被忽略。
安全边界(`2026.2.25+`):群组发送者授权**不会**继承私信配对存储中的批准。
配对仍然仅适用于私信。对于群组,请设置 `groupAllowFrom` 或按群组/话题设置 `allowFrom`
如果未设置 `groupAllowFrom`Telegram 会回退到配置中的 `allowFrom`,而不是配对存储。
单所有者机器人的实用模式:将你的用户 ID 设置在 `channels.telegram.allowFrom` 中,不设置 `groupAllowFrom`,并在 `channels.telegram.groups` 下允许目标群组。
运行时说明:如果完全缺少 `channels.telegram`,运行时默认采用失败关闭的 `groupPolicy="allowlist"`,除非显式设置了 `channels.defaults.groupPolicy`
示例:允许某个特定群组中的任意成员:
@ -191,7 +191,7 @@ curl "https://api.telegram.org/bot<bot_token>/getUpdates"
}
```
示例:只允许某个特定群组中的指定用户:
示例:仅允许某个特定群组中的特定用户:
```json5
{
@ -209,11 +209,11 @@ curl "https://api.telegram.org/bot<bot_token>/getUpdates"
```
<Warning>
常见错误:`groupAllowFrom` 不是 Telegram 群组允许列表
常见错误:`groupAllowFrom` 不是 Telegram 群组 allowlist
- 将 `-1001234567890` 这类负数 Telegram 群组或超级群组聊天 ID 放在 `channels.telegram.groups` 下。
- 当你想限制允许群组中哪些人可以触发机器人时,将类似 `8734062810` Telegram 用户 ID 放在 `groupAllowFrom` 下。
- 仅当你希望允许群组中的任意成员都能与机器人对话时,才使用 `groupAllowFrom: ["*"]`
- 当你想限制允许群组中哪些人可以触发机器人时,将 `8734062810` 这类 Telegram 用户 ID 放在 `groupAllowFrom` 下。
- 仅当你希望允许群组中的任意成员都能与机器人对话时,才使用 `groupAllowFrom: ["*"]`
</Warning>
</Tab>
@ -233,9 +233,9 @@ curl "https://api.telegram.org/bot<bot_token>/getUpdates"
- `/activation always`
- `/activation mention`
这些只更新会话状态。要持久化,请使用配置。
这些只更新会话状态。要持久化,请使用配置。
持久配置示例:
持久配置示例:
```json5
{
@ -249,11 +249,11 @@ curl "https://api.telegram.org/bot<bot_token>/getUpdates"
}
```
获取群组聊天 ID
获取群组聊天 ID 的方法
- 将群组消息转发给 `@userinfobot` / `@getidsbot`
- 或从 `openclaw logs --follow` 中读取 `chat.id`
- 或查 Bot API `getUpdates`
- 或查 Bot API `getUpdates`
</Tab>
</Tabs>
@ -262,11 +262,11 @@ curl "https://api.telegram.org/bot<bot_token>/getUpdates"
- Telegram 由 Gateway 网关进程持有。
- 路由是确定性的Telegram 入站回复会回到 Telegram模型不会选择渠道
- 入站消息会标准化为共享渠道信封格式,包含回复元数据和媒体占位符。
- 入站消息会被规范化为共享渠道信封格式,并附带回复元数据与媒体占位符。
- 群组会话按群组 ID 隔离。论坛话题会追加 `:topic:<threadId>` 以保持话题隔离。
- 私信消息可以携带 `message_thread_id`OpenClaw 会使用线程感知的会话键进行路由,并为回复保留线程 ID。
- 长轮询使用带有按聊天/线程顺序处理的 grammY runner。整体 runner sink 并发度使用 `agents.defaults.maxConcurrent`
- 默认情况下,长轮询看门狗会在 120 秒内没有已完成的 `getUpdates` 存活信号后触发重启。仅当你的部署在长时间运行任务期间仍然出现误判的轮询卡死重启时,才增加 `channels.telegram.pollingStallThresholdMs`。该值以毫秒为单位,允许范围为 `30000``600000`;支持按账户覆盖。
- 长轮询使用带有每聊天/每线程顺序控制的 grammY runner。整体 runner sink 并发度使用 `agents.defaults.maxConcurrent`
- 默认情况下,如果在 120 秒内未完成 `getUpdates` 存活检查,就会触发长轮询 watchdog 重启。仅当你的部署在长时间运行任务期间仍然出现误报轮询卡住重启时,才增加 `channels.telegram.pollingStallThresholdMs`。该值以毫秒为单位,允许范围为 `30000``600000`;支持按账户覆盖。
- Telegram Bot API 不支持已读回执(`sendReadReceipts` 不适用)。
## 功能参考
@ -281,16 +281,16 @@ curl "https://api.telegram.org/bot<bot_token>/getUpdates"
要求:
- `channels.telegram.streaming``off | partial | block | progress`(默认:`partial`
- `progress` 在 Telegram 上会映射为 `partial`(与跨渠道命名保持兼容)
- `streaming.preview.toolProgress` 控制工具/进度更新是否复用同一被编辑的预览消息(默认:`true`)。设为 `false` 可保留单独的工具/进度消息。
- 旧版 `channels.telegram.streamMode` 和布尔 `streaming` 值会自动映射
- 在 Telegram 上`progress` 会映射为 `partial`(与跨渠道命名兼容)
- `streaming.preview.toolProgress` 控制工具/进度更新是否复用同一被编辑的预览消息(默认:`true`)。设`false` 可保留单独的工具/进度消息。
- 旧版 `channels.telegram.streamMode` 和布尔 `streaming` 值会自动映射
对于纯文本回复:
- 私信OpenClaw 会保留同一条预览消息,并在原地执行最终编辑(不会发送第二条消息)
- 群组/话题OpenClaw 会保留同一条预览消息,并在原地执行最终编辑(不会发送第二条消息)
- 私信OpenClaw 会保留同一个预览消息,并原地执行最终编辑(不会发送第二条消息)
- 群组/话题OpenClaw 会保留同一个预览消息,并原地执行最终编辑(不会发送第二条消息)
对于复杂回复(例如媒体负载OpenClaw 会回退到正常的最终投递,然后清理预览消息。
对于复杂回复(例如媒体载荷OpenClaw 会回退为正常的最终发送,然后清理预览消息。
预览流式传输与分块流式传输是分开的。当 Telegram 显式启用分块流式传输时OpenClaw 会跳过预览流,以避免双重流式传输。
@ -308,14 +308,14 @@ curl "https://api.telegram.org/bot<bot_token>/getUpdates"
- 类 Markdown 文本会被渲染为 Telegram 安全的 HTML。
- 原始模型 HTML 会被转义,以减少 Telegram 解析失败。
- 如果 Telegram 拒绝解析后的 HTMLOpenClaw 会以纯文本重试
- 如果 Telegram 拒绝解析后的 HTMLOpenClaw 会重试纯文本
链接预览默认启用,可通过 `channels.telegram.linkPreview: false` 禁用。
链接预览默认启用,可通过 `channels.telegram.linkPreview: false` 禁用。
</Accordion>
<Accordion title="原生命令和自定义命令">
Telegram 命令菜单注册在启动时通过 `setMyCommands` 处理。
Telegram 命令菜单注册在启动时通过 `setMyCommands` 处理。
原生命令默认值:
@ -338,7 +338,7 @@ curl "https://api.telegram.org/bot<bot_token>/getUpdates"
规则:
- 名称会被标准化(去掉前导 `/`转为小写)
- 名称会被规范化(去掉前导 `/`,并转为小写)
- 有效模式:`a-z`、`0-9`、`_`,长度 `1..32`
- 自定义命令不能覆盖原生命令
- 冲突/重复项会被跳过并记录日志
@ -346,37 +346,37 @@ curl "https://api.telegram.org/bot<bot_token>/getUpdates"
说明:
- 自定义命令仅是菜单项;它们不会自动实现行为
- 即使未显示在 Telegram 菜单中,插件/Skills 命令在手动输入时仍然可以工作
- 即使未显示在 Telegram 菜单中,plugin/skill 命令在手动输入时仍然可以工作
如果禁用了原生命令,内置命令会被移除。自定义/插件命令如果已配置,仍可能注册。
如果禁用了原生命令,内置命令会被移除。如果已配置,自定义/plugin 命令仍可能注册。
常见设置失败:
- `setMyCommands failed`报错 `BOT_COMMANDS_TOO_MUCH`,表示 Telegram 菜单在裁剪后仍然超出限制;请减少插件/Skills/自定义命令,或禁用 `channels.telegram.commands.native`
- `setMyCommands failed`出现 `BOT_COMMANDS_TOO_MUCH`,表示 Telegram 菜单在裁剪后仍然超出限制;请减少 plugin/skill/自定义命令,或禁用 `channels.telegram.commands.native`
- `setMyCommands failed` 且出现网络/fetch 错误,通常表示到 `api.telegram.org` 的出站 DNS/HTTPS 被阻止。
### 设备配对命令(`device-pair` 插件
### 设备配对命令(`device-pair` plugin
安装 `device-pair` 插件后:
安装 `device-pair` plugin 后:
1. `/pair` 生成设置代码
2. 在 iOS 应用中粘贴代码
2. 在 iOS 应用中粘贴代码
3. `/pair pending` 列出待处理请求(包括角色/作用域)
4. 批准请求:
- `/pair approve <requestId>` 用于显式批准
- 当只有一个待处理请求时,使用 `/pair approve`
- `/pair approve latest` 用于批准最近的请求
- `/pair approve latest` 用于最近一次请求
设置代码携带一个短期有效的 bootstrap 令牌。内置 bootstrap 交接会将主节点令牌保持为 `scopes: []`;任何交接出去的 operator 令牌都会被限制在 `operator.approvals`、`operator.read`、`operator.talk.secrets` 和 `operator.write` 范围内。Bootstrap 作用域检查使用角色前缀,因此该 operator 允许列表只会满足 operator 请求;非 operator 角色仍然需要其自身角色前缀下的作用域。
设置代码携带一个短时有效的引导令牌。内置的引导交接会将主节点令牌保持为 `scopes: []`;任何交接出的操作员令牌都只会限制在 `operator.approvals`、`operator.read`、`operator.talk.secrets` 和 `operator.write`。引导作用域检查带有角色前缀,因此该操作员 allowlist 只满足操作员请求;非操作员角色仍需要其自身角色前缀下的作用域。
如果设备在认证详情发生变化后重试(例如角色/作用域/公钥变化),之前的待处理请求会被替代,新请求会使用不同的 `requestId`。批准前请重新运行 `/pair pending`
如果设备在重试时更改了认证详情(例如角色/作用域/公钥),先前的待处理请求会被替代,新的请求会使用不同的 `requestId`。批准前请重新运行 `/pair pending`
更多详情:[配对](/zh-CN/channels/pairing#pair-via-telegram-recommended-for-ios)。
</Accordion>
<Accordion title="内联按钮">
配置内联键盘范围:
配置内联键盘作用范围:
```json5
{
@ -450,24 +450,24 @@ curl "https://api.telegram.org/bot<bot_token>/getUpdates"
- `editMessage``chatId`、`messageId`、`content`
- `createForumTopic``chatId`、`name`、可选的 `iconColor`、`iconCustomEmojiId`
渠道消息动作提供更易用的别名(`send`、`react`、`delete`、`edit`、`sticker`、`sticker-search`、`topic-create`)。
渠道消息动作提供更易用的别名(`send`、`react`、`delete`、`edit`、`sticker`、`sticker-search`、`topic-create`)。
门控控制项
控制开关
- `channels.telegram.actions.sendMessage`
- `channels.telegram.actions.deleteMessage`
- `channels.telegram.actions.reactions`
- `channels.telegram.actions.sticker`(默认:禁用)
注意:`edit` 和 `topic-create` 当前默认启用,没有单独的 `channels.telegram.actions.*` 开关。
运行时发送使用活动的配置/密钥快照(启动/重载时),因此动作路径不会在每次发送时临时重新解析 SecretRef。
注意:`edit` 和 `topic-create` 当前默认启用,没有单独的 `channels.telegram.actions.*` 开关。
运行时发送使用当前生效的配置/密钥快照(启动/重载时),因此动作路径不会在每次发送时临时重新解析 SecretRef。
移除表情回应的语义:[/tools/reactions](/zh-CN/tools/reactions)
</Accordion>
<Accordion title="回复线程标签">
Telegram 支持在生成输出中使用显式回复线程标签:
Telegram 支持在生成输出中使用显式回复线程标签:
- `[[reply_to_current]]` 回复触发消息
- `[[reply_to:<id>]]` 回复指定的 Telegram 消息 ID
@ -478,7 +478,7 @@ curl "https://api.telegram.org/bot<bot_token>/getUpdates"
- `first`
- `all`
注意:`off` 会禁用隐式回复线程。显式 `[[reply_to_*]]` 标签仍会被遵循
注意:`off` 会禁用隐式回复线程。显式 `[[reply_to_*]]` 标签仍会生效
</Accordion>
@ -490,15 +490,15 @@ curl "https://api.telegram.org/bot<bot_token>/getUpdates"
- 话题配置路径:
`channels.telegram.groups.<chatId>.topics.<threadId>`
通用话题(`threadId=1`)特殊情况:
常规话题(`threadId=1`)特殊情况:
- 发送消息时省略 `message_thread_id`Telegram 会拒绝 `sendMessage(...thread_id=1)`
- 输入状态动作仍然会包含 `message_thread_id`
- 发送消息时省略 `message_thread_id`Telegram 会拒绝 `sendMessage(...thread_id=1)`
- 输入中动作仍包含 `message_thread_id`
话题继承:除非被覆盖,话题条目会继承群组设置(`requireMention`、`allowFrom`、`skills`、`systemPrompt`、`enabled`、`groupPolicy`)。
`agentId` 仅限话题级,不会从群组默认值继承。
**按话题分配智能体路由**:每个话题都可以通过在话题配置中设置 `agentId` 路由到不同的智能体。这样每个话题都会拥有自己隔离的工作区、记忆和会话。示例:
**按话题路由智能体**:每个话题都可以通过在话题配置中设置 `agentId` 路由到不同的智能体。这样每个话题都会有自己独立的工作区、记忆和会话。示例:
```json5
{
@ -507,7 +507,7 @@ curl "https://api.telegram.org/bot<bot_token>/getUpdates"
groups: {
"-1001234567890": {
topics: {
"1": { agentId: "main" }, // 通用话题 → main 智能体
"1": { agentId: "main" }, // 常规话题 → main 智能体
"3": { agentId: "zu" }, // 开发话题 → zu 智能体
"5": { agentId: "coder" } // 代码审查 → coder 智能体
}
@ -518,11 +518,11 @@ curl "https://api.telegram.org/bot<bot_token>/getUpdates"
}
```
此后每个话题都有自己的会话键:`agent:zu:telegram:group:-1001234567890:topic:3`
此后每个话题都有自己的会话键:`agent:zu:telegram:group:-1001234567890:topic:3`
**持久 ACP 话题绑定**:论坛话题可以通过顶层类型化 ACP 绑定固定 ACP harness 会话:
**持久 ACP 话题绑定**:论坛话题可以通过顶层类型化 ACP 绑定固定 ACP harness 会话:
- `bindings[]`,其中 `type: "acp"``match.channel: "telegram"`
- `bindings[]` 中使用 `type: "acp"``match.channel: "telegram"`
示例:
@ -571,13 +571,13 @@ curl "https://api.telegram.org/bot<bot_token>/getUpdates"
}
```
这当前仅适用于群组和超级群组中的论坛话题。
目前这仅适用于群组和超级群组中的论坛话题。
**从聊天中生成线程绑定的 ACP**
- `/acp spawn <agent> --thread here|auto` 可以将当前 Telegram 话题绑定到新的 ACP 会话。
- 后续该话题中的消息会直接路由到已绑定的 ACP 会话(无需 `/acp steer`)。
- 成功绑定后OpenClaw 会将生成确认消息固定在该话题中
- `/acp spawn <agent> --thread here|auto` 可以将当前 Telegram 话题绑定到一个新的 ACP 会话。
- 后续的话题消息会直接路由到已绑定的 ACP 会话(无需 `/acp steer`)。
- 绑定成功后OpenClaw 会在该话题中固定生成确认消息
- 需要 `channels.telegram.threadBindings.spawnAcpSessions=true`
模板上下文包括:
@ -594,10 +594,10 @@ curl "https://api.telegram.org/bot<bot_token>/getUpdates"
<Accordion title="音频、视频和贴纸">
### 音频消息
Telegram 区分语音便笺和音频文件。
Telegram 区分语音留言和音频文件。
- 默认:音频文件行为
- 在智能体回复中添加标签 `[[audio_as_voice]]` 可强制按语音便笺发送
- 默认:按音频文件处理
- 在智能体回复中添加标签 `[[audio_as_voice]]` 可强制按语音留言发送
消息动作示例:
@ -627,15 +627,15 @@ curl "https://api.telegram.org/bot<bot_token>/getUpdates"
}
```
视频便笺不支持说明文字;提供的消息文本会单独发送。
视频便笺不支持说明文字;如果提供了消息文本,会单独发送。
### 贴纸
入站贴纸处理:
- 静态 `WEBP`:会下载并处理(占位符 `<media:sticker>`
- 动`TGS`:跳过
- 视频 `WEBM`:跳过
- 静态 WEBP会下载并处理占位符 `<media:sticker>`
- 动态 TGS:跳过
- 视频 WEBM跳过
贴纸上下文字段:
@ -649,7 +649,7 @@ curl "https://api.telegram.org/bot<bot_token>/getUpdates"
- `~/.openclaw/telegram/sticker-cache.json`
贴纸会尽可能只描述一次并缓存,以减少重复的视觉调用。
贴纸会在可能时描述一次并缓存,以减少重复的视觉调用。
启用贴纸动作:
@ -690,7 +690,7 @@ curl "https://api.telegram.org/bot<bot_token>/getUpdates"
</Accordion>
<Accordion title="表情回应通知">
Telegram 表情回应会`message_reaction` 更新形式到达(独立于消息负载)。
Telegram 表情回应会作为 `message_reaction` 更新到达(独立于消息载荷)。
启用后OpenClaw 会将如下系统事件加入队列:
@ -698,34 +698,34 @@ curl "https://api.telegram.org/bot<bot_token>/getUpdates"
配置:
- `channels.telegram.reactionNotifications`: `off | own | all`(默认:`own`
- `channels.telegram.reactionLevel`: `off | ack | minimal | extensive`(默认:`minimal`
- `channels.telegram.reactionNotifications``off | own | all`(默认:`own`
- `channels.telegram.reactionLevel``off | ack | minimal | extensive`(默认:`minimal`
说明:
- `own` 表示仅针对用户对机器人发送消息的表情回应(通过已发送消息缓存尽力识别)。
- `own` 表示仅处理用户对机器人已发送消息的表情回应(通过已发送消息缓存尽力实现)。
- 表情回应事件仍遵守 Telegram 访问控制(`dmPolicy`、`allowFrom`、`groupPolicy`、`groupAllowFrom`);未授权发送者会被丢弃。
- Telegram 不会在表情回应更新中提供线程 ID。
- 非论坛群组会路由到群组聊天会话
- 论坛群组会路由到群组的通用话题会话(`:topic:1`),而不是确切的原始话题
- 论坛群组会路由到群组常规话题会话(`:topic:1`),而不是确切的原始话题
用于轮询/Webhook 的 `allowed_updates` 会自动包含 `message_reaction`
轮询/webhook 的 `allowed_updates` 会自动包含 `message_reaction`
</Accordion>
<Accordion title="确认表情回应">
`ackReaction` 会在 OpenClaw 处理入站消息发送一个确认 emoji。
`ackReaction` 会在 OpenClaw 处理入站消息期间发送一个确认 emoji。
解析顺序:
- `channels.telegram.accounts.<accountId>.ackReaction`
- `channels.telegram.ackReaction`
- `messages.ackReaction`
- 智能体身份 emoji 回退`agents.list[].identity.emoji`,否则为 `"👀"`
- 智能体身份 emoji 回退(`agents.list[].identity.emoji`,否则为 "👀"
说明:
- Telegram 需要 unicode emoji例如 `"👀"`)。
- Telegram 需要 unicode emoji例如 "👀")。
- 使用 `""` 可为某个渠道或账户禁用该表情回应。
</Accordion>
@ -738,7 +738,7 @@ curl "https://api.telegram.org/bot<bot_token>/getUpdates"
- 群组迁移事件(`migrate_to_chat_id`),用于更新 `channels.telegram.groups`
- `/config set``/config unset`(需要启用命令)
禁用:
禁用方式
```json5
{
@ -752,37 +752,37 @@ curl "https://api.telegram.org/bot<bot_token>/getUpdates"
</Accordion>
<Accordion title="长轮询与 Webhook">
<Accordion title="长轮询与 webhook">
默认:长轮询。
Webhook 模式:
webhook 模式:
- 设置 `channels.telegram.webhookUrl`
- 设置 `channels.telegram.webhookSecret`(设置了 webhook URL 时必需
- 设置 `channels.telegram.webhookSecret`(设置 webhook URL 时必填
- 可选 `channels.telegram.webhookPath`(默认 `/telegram-webhook`
- 可选 `channels.telegram.webhookHost`(默认 `127.0.0.1`
- 可选 `channels.telegram.webhookPort`(默认 `8787`
Webhook 模式的默认本地监听器绑定到 `127.0.0.1:8787`
webhook 模式下的默认本地监听器绑定到 `127.0.0.1:8787`
如果你的公共端点不同,请在前面放置一个反向代理,并将 `webhookUrl` 指向该公共 URL。
当你确实需要外部入口时,请设置 `webhookHost`(例如 `0.0.0.0`)。
如果你的公开端点不同,请在前面放置一个反向代理,并将 `webhookUrl` 指向该公开 URL。
当你明确需要外部入站访问时,请设置 `webhookHost`(例如 `0.0.0.0`)。
</Accordion>
<Accordion title="限制、重试和 CLI 目标">
- `channels.telegram.textChunkLimit` 默认为 4000。
- `channels.telegram.chunkMode="newline"`在按长度拆分前优先按段落边界(空行)拆分。
- `channels.telegram.textChunkLimit` 默认为 4000。
- `channels.telegram.chunkMode="newline"` 会优先按段落边界(空行)分割,然后再按长度拆分。
- `channels.telegram.mediaMaxMb`(默认 100限制 Telegram 入站和出站媒体大小。
- `channels.telegram.timeoutSeconds` 会覆盖 Telegram API 客户端超时(若未设置,则使用 grammY 默认值)。
- `channels.telegram.pollingStallThresholdMs` 默认`120000`;仅在误报轮询卡死重启时才调整到 `30000``600000` 之间
- `channels.telegram.timeoutSeconds` 会覆盖 Telegram API 客户端超时时间(如果未设置,则使用 grammY 默认值)。
- `channels.telegram.pollingStallThresholdMs` 默认值为 `120000`;仅在误报轮询停滞重启时,才在 `30000``600000` 之间调整
- 群组上下文历史使用 `channels.telegram.historyLimit``messages.groupChat.historyLimit`(默认 50`0` 表示禁用。
- 回复/引用/转发的补充上下文当前会按接收到的内容传递。
- Telegram 允许列表主要用于限制谁可以触发智能体,而不是完整的补充上下文脱敏边界。
- 回复/引用/转发的补充上下文当前会按接收时的内容原样传递。
- Telegram allowlist 主要用于限制谁可以触发智能体,而不是完整的补充上下文脱敏边界。
- 私信历史控制:
- `channels.telegram.dmHistoryLimit`
- `channels.telegram.dms["<user_id>"].historyLimit`
- `channels.telegram.retry` 配置适用于 Telegram 发送辅助逻辑CLI/工具/动作)中的可恢复出站 API 错误。
- `channels.telegram.retry` 配置适用于 Telegram 发送辅助函数CLI/工具/动作),用于处理可恢复的出站 API 错误。
CLI 发送目标可以是数字聊天 ID 或用户名:
@ -801,75 +801,79 @@ openclaw message poll --channel telegram --target -1001234567890:topic:42 \
--poll-duration-seconds 300 --poll-public
```
Telegram 专投票标志:
Telegram 专投票标志:
- `--poll-duration-seconds`5-600
- `--poll-anonymous`
- `--poll-public`
- 用于论坛话题的 `--thread-id`(或使用 `:topic:` 目标)
- 论坛话题使用 `--thread-id`(或使用 `:topic:` 目标)
Telegram 发送还支持:
- `--buttons`:当 `channels.telegram.capabilities.inlineButtons` 允许时用于内联键盘
- `--force-document`:将出站图片和 GIF 作为文档发送,而不是压缩照片或动画媒体上传
- `--presentation`,配合 `buttons` 块用于内联键盘,前提是 `channels.telegram.capabilities.inlineButtons` 允许
- `--pin``--delivery '{"pin":true}'`,用于在机器人有权限固定消息的聊天中请求固定发送
- `--force-document`,用于将出站图片和 GIF 作为文档发送,而不是作为压缩照片或动画媒体上传
动作控:
动作控
- `channels.telegram.actions.sendMessage=false` 会禁用 Telegram 出站消息,包括投票
- `channels.telegram.actions.poll=false` 会禁用 Telegram 投票创建,同时保留普通发送功能
- `channels.telegram.actions.poll=false` 会禁用 Telegram 投票创建,同时保留普通发送
</Accordion>
<Accordion title="Telegram 中的执行审批">
Telegram 支持在审批人私信中进行执行审批,并且可以选择在发起审批的聊天或话题中发布审批提示。
<Accordion title="Telegram 中的 Exec 批准">
Telegram 支持在批准者私信中进行 exec 批准,并且可以选择在原始聊天或话题中发布批准提示。
配置路径:
- `channels.telegram.execApprovals.enabled`
- `channels.telegram.execApprovals.approvers`(可选;在可能的情况下会回退到从 `allowFrom` 和直接 `defaultTo` 推断出的数字所有者 ID
- `channels.telegram.execApprovals.approvers`(可选;如果可能,会回退到从 `allowFrom` 和私信 `defaultTo` 直接推断出的数字所有者 ID
- `channels.telegram.execApprovals.target``dm` | `channel` | `both`,默认:`dm`
- `agentFilter`、`sessionFilter`
审批人必须是数字 Telegram 用户 ID。当 `enabled` 未设置或为 `"auto"`,且至少能解析出一个审批人时Telegram 会自动启用原生执行审批;审批人可来自 `execApprovals.approvers`,也可来自账户的数字所有者配置(`allowFrom` 和私信 `defaultTo`)。设置 `enabled: false` 可显式禁用 Telegram 作为原生审批客户端。否则,审批请求会回退到其他已配置的审批路径或执行审批回退策略。
批准者必须是数字 Telegram 用户 ID。当 `enabled` 未设置或为 `"auto"`,且至少能解析出一个批准者时Telegram 会自动启用原生 exec 批准;该批准者可以来自 `execApprovals.approvers`,也可以来自账户的数字所有者配置(`allowFrom` 和私信 `defaultTo`)。如需显式禁用 Telegram 作为原生批准客户端,请设置 `enabled: false`。否则,批准请求会回退到其他已配置的批准路径或 exec 批准回退策略。
Telegram 也会渲染其他聊天渠道使用的共享审批按钮。原生 Telegram 适配器主要增加了审批人私信路由、渠道/话题扇出,以及投递前的输入状态提示。
当这些按钮存在时,它们是主要的审批 UX仅当工具结果表明聊天审批不可用或手动审批是唯一途径时OpenClaw
Telegram 也会渲染其他聊天渠道使用的共享批准按钮。原生 Telegram 适配器主要增加批准者私信路由、渠道/话题扇出,以及发送前的输入状态提示。
当这些按钮存在时,它们就是主要的批准 UX只有在工具结果表明聊天批准不可用或者手动批准是唯一途径时OpenClaw
才应包含手动 `/approve` 命令。
投递规则:
发送规则:
- `target: "dm"` 仅将审批提示发送到已解析的审批人私信
- `target: "channel"` 将提示发回发起审批的 Telegram 聊天/话题
- `target: "both"` 同时发送到审批人私信和发起审批的聊天/话题
- `target: "dm"` 仅将批准提示发送到已解析的批准者私信
- `target: "channel"` 将提示发回原始 Telegram 聊天/话题
- `target: "both"` 同时发送到批准者私信和原始聊天/话题
只有已解析的审批人可以批准或拒绝。非审批人不能使用 `/approve`,也不能使用 Telegram 批按钮。
只有已解析的批准者可以批准或拒绝。非批准者不能使用 `/approve`,也不能使用 Telegram 批按钮。
批解析行为:
解析行为:
- 带有 `plugin:` 前缀的 ID 始终通过插件审批解析。
- 其他审批 ID 会先尝试 `exec.approval.resolve`
- 如果 Telegram 也被授权用于插件审批,并且 Gateway 网关表示该执行审批未知/已过期Telegram 会再通过 `plugin.approval.resolve` 重试一次。
- 真实的执行审批拒绝/错误不会静默回退到插件审批解析。
- 带有 `plugin:` 前缀的 ID 始终通过 plugin 批准解析。
- 其他批准 ID 会先尝试 `exec.approval.resolve`
- 如果 Telegram 也被授权用于 plugin 批准,且 Gateway 网关表示
该 exec 批准未知/已过期Telegram 会通过
`plugin.approval.resolve` 再重试一次。
- 真正的 exec 批准拒绝/错误不会悄然回退到 plugin
批准解析。
渠道投递会在聊天中显示命令文本,因此仅应在受信任的群组/话题中启用 `channel``both`。当提示出现在论坛话题中时OpenClaw 会同时为审批提示和审批后的后续消息保留该话题。执行审批默认在 30 分钟后过期。
渠道内发送会在聊天中显示命令文本,因此仅在可信的群组/话题中启用 `channel``both`。当提示落在论坛话题中时OpenClaw 会同时为批准提示和批准后的后续消息保留该话题。Exec 批准默认在 30 分钟后过期。
内联审批按钮还依赖 `channels.telegram.capabilities.inlineButtons` 允许目标界面(`dm`、`group` 或 `all`)。
内联批准按钮也依赖 `channels.telegram.capabilities.inlineButtons` 允许目标表面(`dm`、`group` 或 `all`)。
相关文档:[执行审批](/zh-CN/tools/exec-approvals)
相关文档:[Exec 批准](/zh-CN/tools/exec-approvals)
</Accordion>
</AccordionGroup>
## 错误回复控制
当智能体遇到投递或提供商错误时Telegram 可以选择回复错误文本或抑制错误。两个配置键控制此行为:
当智能体遇到发送或提供商错误时Telegram 可以回复错误文本,也可以抑制错误回复。两个配置键控制此行为:
| Key | Values | Default | Description |
| ----------------------------------- | ----------------- | ------- | ----------------------------------------------------------------------------------------------- |
| `channels.telegram.errorPolicy` | `reply`, `silent` | `reply` | `reply` 向聊天发送一条友好的错误消息。`silent` 完全抑制错误回复。 |
| `channels.telegram.errorCooldownMs` | number (ms) | `60000` | 同一聊天发送错误回复的最小时间间隔。防止在故障期间出现错误刷屏。 |
| `channels.telegram.errorPolicy` | `reply`, `silent` | `reply` | `reply` 向聊天发送一条友好的错误消息。`silent` 完全抑制错误回复。 |
| `channels.telegram.errorCooldownMs` | number (ms) | `60000` | 同一聊天发送错误回复的最小时间间隔。防止在故障期间刷屏。 |
支持按账户、按群组和按话题覆盖(与其他 Telegram 配置键具有相同的继承规则)。
支持按账户、按群组和按话题覆盖(继承规则与其他 Telegram 配置键相同)。
```json5
{
@ -890,20 +894,20 @@ openclaw message poll --channel telegram --target -1001234567890:topic:42 \
## 故障排除
<AccordionGroup>
<Accordion title="机器人对未提及的群组消息没有响应">
<Accordion title="机器人不响应未提及的群组消息">
- 如果 `requireMention=false`Telegram 隐私模式必须允许完全可见。
- BotFather`/setprivacy` -> 禁用
- BotFather`/setprivacy` -> Disable
- 然后移除并重新将机器人添加到群组
- 当配置期接收未提及的群组消息时,`openclaw channels status` 会发出警告。
- `openclaw channels status --probe` 可以检查显式的数字群组 ID无法对通配符 `"*"` 进行成员资格探测。
- 当配置期接收未提及的群组消息时,`openclaw channels status` 会发出警告。
- `openclaw channels status --probe` 可以检查显式的数字群组 ID通配符 `"*"` 无法执行成员关系探测。
- 快速会话测试:`/activation always`。
</Accordion>
<Accordion title="机器人完全看不到群组消息">
- 当 `channels.telegram.groups` 存在时,必须列出该群组(或包含 `"*"`
- 当存在 `channels.telegram.groups` 时,必须列出该群组(或包含 `"*"`
- 验证机器人是否已加入群组
- 查看日志:`openclaw logs --follow` 以获取跳过原因
@ -912,20 +916,20 @@ openclaw message poll --channel telegram --target -1001234567890:topic:42 \
<Accordion title="命令部分生效或完全无效">
- 授权你的发送者身份(配对和/或数字 `allowFrom`
- 即使群组策略 `open`,命令授权仍然适用
- `setMyCommands failed`报错 `BOT_COMMANDS_TOO_MUCH` 表示原生命令菜单条目过多;请减少插件/Skills/自定义命令,或禁用原生菜单
- 即使群组策略 `open`,命令授权仍然适用
- `setMyCommands failed`出现 `BOT_COMMANDS_TOO_MUCH`,表示原生命令菜单条目过多;请减少 plugin/skill/自定义命令,或禁用原生菜单
- `setMyCommands failed` 且出现网络/fetch 错误,通常表示到 `api.telegram.org` 的 DNS/HTTPS 可达性存在问题
</Accordion>
<Accordion title="轮询或网络不稳定">
- Node 22+ + 自定义 fetch/proxy 在 AbortSignal 类型不匹配时可能触发立即中止行为。
- 某些主机会优先将 `api.telegram.org` 解析为 IPv6损坏的 IPv6 出站连接可能导致间歇性的 Telegram API 故障
- 如果日志包含 `TypeError: fetch failed``Network request for 'getUpdates' failed!`OpenClaw 现在会将其作为可恢复的网络错误进行重试。
- 如果日志包含 `Polling stall detected`默认情况下,当 120 秒内没有完成的长轮询存活信号时OpenClaw 会重启轮询并重建 Telegram 传输。
- 仅当长时间运行的 `getUpdates` 调用是健康的,但你的主机仍报告误判的轮询卡死重启时,才增加 `channels.telegram.pollingStallThresholdMs`。持续卡死通常指向主机与 `api.telegram.org` 之间的代理、DNS、IPv6 或 TLS 出站问题。
- 在直连出站/TLS 不稳定的 VPS 主机上,可通过 `channels.telegram.proxy` 路由 Telegram API 调用:
- Node 22+ + 自定义 fetch/proxy 可能会在 AbortSignal 类型不匹配时触发立即中止行为。
- 某些主机会优先将 `api.telegram.org` 解析为 IPv6损坏的 IPv6 出站连接会导致 Telegram API 间歇性失败
- 如果日志包含 `TypeError: fetch failed``Network request for 'getUpdates' failed!`OpenClaw 现在会将其作为可恢复的网络错误重试。
- 如果日志包含 `Polling stall detected`OpenClaw 默认会在 120 秒内没有完成长轮询存活检查时,重启轮询并重建 Telegram 传输。
- 只有当长时间运行的 `getUpdates` 调用本身是健康的,但你的主机仍然报告误报轮询停滞重启时,才增加 `channels.telegram.pollingStallThresholdMs`。持续停滞通常说明主机与 `api.telegram.org` 之间存在代理、DNS、IPv6 或 TLS 出站问题。
- 在直连出站/TLS 不稳定的 VPS 主机上,请通过 `channels.telegram.proxy` 转发 Telegram API 调用:
```yaml
channels:
@ -934,7 +938,7 @@ channels:
```
- Node 22+ 默认使用 `autoSelectFamily=true`WSL2 除外)和 `dnsResultOrder=ipv4first`
- 如果你的主机是 WSL2或明确在仅 IPv4 行为下工作更好,请强制设置地址族选择:
- 如果你的主机是 WSL2明确在仅 IPv4 行为下工作更好,请强制指定协议族选择:
```yaml
channels:
@ -943,7 +947,11 @@ channels:
autoSelectFamily: false
```
- RFC 2544 基准测试地址段响应(`198.18.0.0/15`)默认已允许用于 Telegram 媒体下载。如果受信任的 fake-IP 或透明代理在媒体下载期间将 `api.telegram.org` 重写到其他私有/内部/特殊用途地址,你可以选择启用仅适用于 Telegram 的绕过:
- RFC 2544 基准测试地址范围返回值(`198.18.0.0/15`)默认已经
被允许用于 Telegram 媒体下载。如果可信的假 IP 或
透明代理在媒体下载期间将 `api.telegram.org` 重写到其他
私有/内部/特殊用途地址,你可以选择启用
仅适用于 Telegram 的绕过:
```yaml
channels:
@ -952,20 +960,24 @@ channels:
dangerouslyAllowPrivateNetwork: true
```
- 同样的选择启用项也可按账户设置在
- 同样的显式启用也支持按账户设置,路径为
`channels.telegram.accounts.<accountId>.network.dangerouslyAllowPrivateNetwork`
- 如果你的代理将 Telegram 媒体主机解析到 `198.18.x.x`请先保持该危险标志关闭。Telegram 媒体默认已经允许 RFC 2544 基准测试地址段。
- 如果你的代理将 Telegram 媒体主机解析为 `198.18.x.x`,请先保持
该危险标志关闭。Telegram 媒体默认已经允许 RFC 2544
基准测试范围。
<Warning>
`channels.telegram.network.dangerouslyAllowPrivateNetwork` 会削弱 Telegram
媒体 SSRF 防护。仅应在受信任、由操作员控制的代理环境中使用,例如 Clash、Mihomo 或 Surge 的 fake-IP 路由,这些环境会合成 RFC 2544 基准测试地址段之外的私有或特殊用途响应。对于普通公共互联网下的 Telegram 访问,请保持关闭。
媒体 SSRF 防护。仅在可信的、由操作员控制的代理
环境中使用它,例如 Clash、Mihomo 或 Surge 的假 IP 路由,
并且这些环境会在 RFC 2544 基准测试范围之外合成私有或特殊用途地址的场景。对于普通公共互联网的 Telegram 访问,请保持关闭。
</Warning>
- 环境变量覆盖(临时):
- `OPENCLAW_TELEGRAM_DISABLE_AUTO_SELECT_FAMILY=1`
- `OPENCLAW_TELEGRAM_ENABLE_AUTO_SELECT_FAMILY=1`
- `OPENCLAW_TELEGRAM_DNS_RESULT_ORDER=ipv4first`
- 验证 DNS 响应
- 验证 DNS 返回结果
```bash
dig +short api.telegram.org A
@ -983,38 +995,38 @@ dig +short api.telegram.org AAAA
- `channels.telegram.enabled`:启用/禁用渠道启动。
- `channels.telegram.botToken`机器人令牌BotFather
- `channels.telegram.tokenFile`:从常规文件路径读取令牌。不接受符号链接。
- `channels.telegram.tokenFile`:从普通文件路径读取令牌。不接受符号链接。
- `channels.telegram.dmPolicy``pairing | allowlist | open | disabled`默认pairing
- `channels.telegram.allowFrom`:私信允许列表(数字 Telegram 用户 ID。`allowlist` 要求至少有一个发送者 ID。`open` 要求包含 `"*"`。`openclaw doctor --fix` 可以将旧版 `@username` 条目解析为 ID也可以在允许列表迁移流程中从配对存储文件恢复允许列表条目。
- `channels.telegram.allowFrom`:私信 allowlist数字 Telegram 用户 ID。`allowlist` 至少需要一个发送者 ID。`open` 需要 `"*"`。`openclaw doctor --fix` 可以将旧版 `@username` 条目解析为 ID也可以在 allowlist 迁移流程中从配对存储文件恢复 allowlist 条目。
- `channels.telegram.actions.poll`:启用或禁用 Telegram 投票创建(默认:启用;仍然需要 `sendMessage`)。
- `channels.telegram.defaultTo`:当未提供显式 `--reply-to`CLI `--deliver` 使用的默认 Telegram 目标。
- `channels.telegram.groupPolicy``open | allowlist | disabled`默认allowlist
- `channels.telegram.groupAllowFrom`:群组发送者允许列表(数字 Telegram 用户 ID。`openclaw doctor --fix` 可以将旧版 `@username` 条目解析为 ID。非数字条目在认证时会被忽略。群组认证不会使用私信配对存储回退`2026.2.25+`)。
- `channels.telegram.groupAllowFrom`:群组发送者 allowlist(数字 Telegram 用户 ID。`openclaw doctor --fix` 可以将旧版 `@username` 条目解析为 ID。非数字条目在认证时会被忽略。群组认证不会使用私信配对存储回退`2026.2.25+`)。
- 多账户优先级:
- 当配置了两个或更多账户 ID 时,请设置 `channels.telegram.defaultAccount`(或包含 `channels.telegram.accounts.default`以显式指定默认路由。
- 如果两者都未设置OpenClaw 会回退到第一个标准化后的账户 ID并且 `openclaw doctor` 会发出警告。
- 当配置了两个或更多账户 ID 时,请设置 `channels.telegram.defaultAccount`(或包含 `channels.telegram.accounts.default`)以显式指定默认路由。
- 如果两者都未设置OpenClaw 会回退到第一个规范化账户 ID并且 `openclaw doctor` 会发出警告。
- `channels.telegram.accounts.default.allowFrom``channels.telegram.accounts.default.groupAllowFrom` 仅适用于 `default` 账户。
- 当账户级值未设置时,命名账户会继承 `channels.telegram.allowFrom``channels.telegram.groupAllowFrom`
- 命名账户不会继承 `channels.telegram.accounts.default.allowFrom` / `groupAllowFrom`
- `channels.telegram.groups`按群组设置的默认值 + 允许列表(全局默认值使用 `"*"`)。
- `channels.telegram.groups.<id>.groupPolicy`群组级 `groupPolicy` 覆盖`open | allowlist | disabled`)。
- `channels.telegram.groups`每群组默认值 + allowlist使用 `"*"` 作为全局默认值)。
- `channels.telegram.groups.<id>.groupPolicy`按群组覆盖 `groupPolicy``open | allowlist | disabled`)。
- `channels.telegram.groups.<id>.requireMention`:提及门控默认值。
- `channels.telegram.groups.<id>.skills`Skills 过滤器(省略 = 所有 Skills空值 = 无)。
- `channels.telegram.groups.<id>.allowFrom`:按群组设置的发送者允许列表覆盖
- `channels.telegram.groups.<id>.allowFrom`:按群组覆盖发送者 allowlist
- `channels.telegram.groups.<id>.systemPrompt`:该群组的额外系统提示词。
- `channels.telegram.groups.<id>.enabled``false` 时禁用该群组。
- `channels.telegram.groups.<id>.topics.<threadId>.*`:按话题设置的覆盖(群组字段 + 仅话题字段 `agentId`)。
- `channels.telegram.groups.<id>.topics.<threadId>.agentId`:将话题路由到特定智能体(覆盖群组级和绑定路由)。
- `channels.telegram.groups.<id>.topics.<threadId>.groupPolicy`话题级 `groupPolicy` 覆盖`open | allowlist | disabled`)。
- `channels.telegram.groups.<id>.topics.<threadId>.requireMention`话题级提及门控覆盖
- 顶层 `bindings[]`带有 `type: "acp"``match.peer.id` 中使用规范话题 ID `chatId:topic:topicId`:持久 ACP 话题绑定字段(见 [ACP 智能体](/zh-CN/tools/acp-agents#channel-specific-settings))。
- `channels.telegram.direct.<id>.topics.<threadId>.agentId`:将私信话题路由到特定智能体(与论坛话题行为相同)。
- `channels.telegram.execApprovals.enabled`:为此账户启用 Telegram 作为基于聊天的原生执行审批客户端。
- `channels.telegram.execApprovals.approvers`:允许批准或拒绝执行请求的 Telegram 用户 ID。当 `channels.telegram.allowFrom` 或直接的 `channels.telegram.defaultTo` 已标识所有者时,此项可选。
- `channels.telegram.execApprovals.target``dm | channel | both`(默认:`dm`)。存在原始 Telegram 话题时,`channel` 和 `both` 会保留该话题。
- `channels.telegram.execApprovals.agentFilter`用于转发批提示的可选智能体 ID 过滤器。
- `channels.telegram.execApprovals.sessionFilter`用于转发批提示的可选会话键过滤器(子串或正则表达式)。
- `channels.telegram.accounts.<account>.execApprovals`:按账户设置的 Telegram 执行审批路由和审批人授权覆盖
- `channels.telegram.groups.<id>.enabled`:为 `false` 时禁用该群组。
- `channels.telegram.groups.<id>.topics.<threadId>.*`:按话题覆盖(群组字段 + 仅话题字段 `agentId`)。
- `channels.telegram.groups.<id>.topics.<threadId>.agentId`:将话题路由到特定智能体(覆盖群组级和绑定路由)。
- `channels.telegram.groups.<id>.topics.<threadId>.groupPolicy`按话题覆盖 `groupPolicy``open | allowlist | disabled`)。
- `channels.telegram.groups.<id>.topics.<threadId>.requireMention`按话题覆盖提及门控
- 顶层 `bindings[]`使用 `type: "acp"`,并`match.peer.id` 中使用规范话题 ID `chatId:topic:topicId`:持久 ACP 话题绑定字段(见 [ACP 智能体](/zh-CN/tools/acp-agents#channel-specific-settings))。
- `channels.telegram.direct.<id>.topics.<threadId>.agentId`:将私信话题路由到特定智能体(行为与论坛话题相同)。
- `channels.telegram.execApprovals.enabled`:为此账户启用 Telegram 作为基于聊天的 exec 批准客户端。
- `channels.telegram.execApprovals.approvers`:允许批准或拒绝 exec 请求的 Telegram 用户 ID。当 `channels.telegram.allowFrom` 或直接的 `channels.telegram.defaultTo`标识所有者时,此项可选。
- `channels.telegram.execApprovals.target``dm | channel | both`(默认:`dm`)。存在原始 Telegram 话题时,`channel` 和 `both` 会保留该话题。
- `channels.telegram.execApprovals.agentFilter`:转发批提示的可选智能体 ID 过滤器。
- `channels.telegram.execApprovals.sessionFilter`:转发批提示的可选会话键过滤器(子串或正则)。
- `channels.telegram.accounts.<account>.execApprovals`:按账户覆盖 Telegram exec 批准路由和批准者授权
- `channels.telegram.capabilities.inlineButtons``off | dm | group | all | allowlist`默认allowlist
- `channels.telegram.accounts.<account>.capabilities.inlineButtons`:按账户覆盖。
- `channels.telegram.commands.nativeSkills`:启用/禁用 Telegram 原生 Skills 命令。
@ -1022,41 +1034,41 @@ dig +short api.telegram.org AAAA
- `channels.telegram.textChunkLimit`:出站分块大小(字符数)。
- `channels.telegram.chunkMode``length`(默认)或 `newline`,表示在按长度分块前先按空行(段落边界)拆分。
- `channels.telegram.linkPreview`切换出站消息的链接预览默认true
- `channels.telegram.streaming``off | partial | block | progress`(实时流式预览;默认:`partial``progress` 映射为 `partial``block` 是兼容旧版预览模式。Telegram 预览流式传输使用单条预览消息并原地编辑
- `channels.telegram.streaming.preview.toolProgress`:当预览流式传输激活时,复用实时预览消息用于工具/进度更新(默认:`true`)。设为 `false` 可保留独的工具/进度消息。
- `channels.telegram.mediaMaxMb`Telegram 入站/出站媒体大小上限MB默认100
- `channels.telegram.retry`Telegram 发送辅助逻辑CLI/工具/动作)在可恢复出站 API 错误上的重试策略attempts、minDelayMs、maxDelayMs、jitter
- `channels.telegram.streaming``off | partial | block | progress`(实时流式预览;默认:`partial``progress` 映射为 `partial``block` 是旧版预览模式兼容值。Telegram 预览流式传输使用单个原地编辑的预览消息
- `channels.telegram.streaming.preview.toolProgress`:当预览流式传输启用时,复用实时预览消息用于工具/进度更新(默认:`true`)。设`false` 可保留独的工具/进度消息。
- `channels.telegram.mediaMaxMb`Telegram 入站/出站媒体上限MB默认100
- `channels.telegram.retry`Telegram 发送辅助函数CLI/工具/动作)在可恢复的出站 API 错误上的重试策略attempts、minDelayMs、maxDelayMs、jitter
- `channels.telegram.network.autoSelectFamily`:覆盖 Node `autoSelectFamily`true=启用false=禁用)。在 Node 22+ 上默认启用WSL2 默认禁用。
- `channels.telegram.network.dnsResultOrder`:覆盖 DNS 结果顺序(`ipv4first` 或 `verbatim`)。在 Node 22+ 上默认 `ipv4first`
- `channels.telegram.network.dangerouslyAllowPrivateNetwork`:危险的选择启用项,用于受信任的 fake-IP 或透明代理环境;当 Telegram 媒体下载`api.telegram.org` 解析到默认 RFC 2544 基准范围允许之外的私有/内部/特殊用途地址时使用
- `channels.telegram.network.dnsResultOrder`:覆盖 DNS 结果顺序(`ipv4first` 或 `verbatim`)。在 Node 22+ 上默认 `ipv4first`
- `channels.telegram.network.dangerouslyAllowPrivateNetwork`:危险的显式启用项,用于可信的假 IP 或透明代理环境;这些环境中 Telegram 媒体下载会`api.telegram.org` 解析到默认 RFC 2544 基准范围允许之外的私有/内部/特殊用途地址。
- `channels.telegram.proxy`Bot API 调用的代理 URLSOCKS/HTTP
- `channels.telegram.webhookUrl`:启用 Webhook 模式(需要 `channels.telegram.webhookSecret`)。
- `channels.telegram.webhookSecret`Webhook 密钥(设置了 webhookUrl 时必需)。
- `channels.telegram.webhookPath`:本地 Webhook 路径(默认 `/telegram-webhook`)。
- `channels.telegram.webhookHost`:本地 Webhook 绑定主机(默认 `127.0.0.1`)。
- `channels.telegram.webhookPort`:本地 Webhook 绑定端口(默认 `8787`)。
- `channels.telegram.actions.reactions`Telegram 工具表情回应门控
- `channels.telegram.actions.sendMessage`Telegram 工具消息发送门控
- `channels.telegram.actions.deleteMessage`Telegram 工具消息删除门控
- `channels.telegram.actions.sticker`Telegram 贴纸动作门控——发送和搜索默认false
- `channels.telegram.webhookUrl`:启用 webhook 模式(需要 `channels.telegram.webhookSecret`)。
- `channels.telegram.webhookSecret`webhook 密钥(设置 `webhookUrl` 时必填)。
- `channels.telegram.webhookPath`:本地 webhook 路径(默认 `/telegram-webhook`)。
- `channels.telegram.webhookHost`:本地 webhook 绑定主机(默认 `127.0.0.1`)。
- `channels.telegram.webhookPort`:本地 webhook 绑定端口(默认 `8787`)。
- `channels.telegram.actions.reactions`控制 Telegram 工具表情回应。
- `channels.telegram.actions.sendMessage`控制 Telegram 工具消息发送。
- `channels.telegram.actions.deleteMessage`控制 Telegram 工具消息删除。
- `channels.telegram.actions.sticker`控制 Telegram 贴纸动作——发送和搜索默认false
- `channels.telegram.reactionNotifications``off | own | all` —— 控制哪些表情回应会触发系统事件(未设置时默认:`own`)。
- `channels.telegram.reactionLevel``off | ack | minimal | extensive` —— 控制智能体的表情回应能力(未设置时默认:`minimal`)。
- `channels.telegram.errorPolicy``reply | silent` —— 控制错误回复行为(默认:`reply`)。支持按账户/群组/话题覆盖。
- `channels.telegram.errorCooldownMs`同一聊天发送错误回复的最小毫秒间隔(默认:`60000`)。防止在故障期间出现错误刷屏。
- `channels.telegram.errorCooldownMs`同一聊天发送错误回复的最小毫秒间隔(默认:`60000`)。防止在故障期间错误刷屏。
- [配置参考 - Telegram](/zh-CN/gateway/configuration-reference#telegram)
Telegram 专属的高信号字段:
Telegram 专高信号字段:
- 启动/认证:`enabled`、`botToken`、`tokenFile`、`accounts.*``tokenFile` 必须指向常规文件;符号链接会被拒绝
- 启动/认证:`enabled`、`botToken`、`tokenFile`、`accounts.*``tokenFile` 必须指向普通文件;不接受符号链接
- 访问控制:`dmPolicy`、`allowFrom`、`groupPolicy`、`groupAllowFrom`、`groups`、`groups.*.topics.*`、顶层 `bindings[]``type: "acp"`
- 执行审批`execApprovals`、`accounts.*.execApprovals`
- exec 批准`execApprovals`、`accounts.*.execApprovals`
- 命令/菜单:`commands.native`、`commands.nativeSkills`、`customCommands`
- 线程/回复:`replyToMode`
- 流式传输:`streaming`(预览)、`streaming.preview.toolProgress`、`blockStreaming`
- 格式化/投递`textChunkLimit`、`chunkMode`、`linkPreview`、`responsePrefix`
- 流式传输:`streaming`(预览)、`streaming.preview.toolProgress`、分块流式传输
- 格式化/发送`textChunkLimit`、`chunkMode`、`linkPreview`、`responsePrefix`
- 媒体/网络:`mediaMaxMb`、`timeoutSeconds`、`pollingStallThresholdMs`、`retry`、`network.autoSelectFamily`、`network.dangerouslyAllowPrivateNetwork`、`proxy`
- Webhook`webhookUrl`、`webhookSecret`、`webhookPath`、`webhookHost`
- webhook`webhookUrl`、`webhookSecret`、`webhookPath`、`webhookHost`
- 动作/能力:`capabilities.inlineButtons`、`actions.sendMessage|editMessage|deleteMessage|reactions|sticker`
- 表情回应:`reactionNotifications`、`reactionLevel`
- 错误:`errorPolicy`、`errorCooldownMs`

View File

@ -0,0 +1,261 @@
---
read_when:
- 重构渠道消息 UI、交互式负载或原生渠道渲染器
- 更改消息工具能力、传递提示或跨上下文标记
- 调试 Discord Carbon 导入扩散或渠道插件运行时惰性加载
summary: 将语义消息呈现与渠道原生 UI 渲染器解耦。
title: 渠道呈现重构计划
x-i18n:
generated_at: "2026-04-21T20:34:47Z"
model: gpt-5.4
provider: openai
source_hash: ed3c49f3cc55151992315599a05451fe499f2983d53d69dc58784e846f9f32ad
source_path: plan/ui-channels.md
workflow: 15
---
# 渠道呈现重构计划
## 状态
已在共享智能体、CLI、插件能力和出站传递层中实现
- `ReplyPayload.presentation` 承载语义化消息 UI。
- `ReplyPayload.delivery.pin` 承载已发送消息的置顶请求。
- 共享消息操作暴露 `presentation`、`delivery` 和 `pin`,而不是提供商原生的 `components`、`blocks`、`buttons` 或 `card`
- 核心通过插件声明的出站能力来渲染或自动降级消息呈现。
- Discord、Slack、Telegram、Mattermost、MS Teams 和 Feishu 渲染器消费这一通用契约。
- Discord 渠道控制平面代码不再导入由 Carbon 支持的 UI 容器。
规范文档现位于 [消息呈现](/zh-CN/plugins/message-presentation)。
保留此计划作为历史实现背景;如果契约、渲染器或回退行为发生变化,
请更新规范指南。
## 问题
当前渠道 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 已经使用的更丰富布局更窄。
这让核心了解原生 UI 形态,削弱了插件运行时的惰性加载,并且给智能体提供了过多用于表达相同消息意图的提供商特定方式。
## 目标
- 核心根据声明的能力,为消息决定最佳语义化呈现。
- 扩展声明能力,并将语义化呈现渲染为原生传输负载。
- Web 控制 UI 与聊天原生 UI 保持分离。
- 不通过共享智能体或 CLI 消息表面暴露原生渠道负载。
- 不支持的呈现特性会自动降级为最佳文本表示。
- 诸如将已发送消息置顶之类的传递行为属于通用传递元数据,而不是呈现。
## 非目标
- 不为 `buildCrossContextComponents` 提供向后兼容垫片。
- 不公开 `components`、`blocks`、`buttons` 或 `card` 的原生逃生口。
- 核心中不导入渠道原生 UI 库。
- 不为内置渠道提供提供商特定的 SDK 接缝。
## 目标模型
`ReplyPayload` 添加一个由核心拥有的 `presentation` 字段。
```ts
type MessagePresentationTone = "neutral" | "info" | "success" | "warning" | "danger";
type MessagePresentation = {
tone?: MessagePresentationTone;
title?: string;
blocks: MessagePresentationBlock[];
};
type MessagePresentationBlock =
| { type: "text"; text: string }
| { type: "context"; text: string }
| { type: "divider" }
| { type: "buttons"; buttons: MessagePresentationButton[] }
| { type: "select"; placeholder?: string; options: MessagePresentationOption[] };
type MessagePresentationButton = {
label: string;
value?: string;
url?: string;
style?: "primary" | "secondary" | "success" | "danger";
};
type MessagePresentationOption = {
label: string;
value: string;
};
```
在迁移期间,`interactive` 成为 `presentation` 的一个子集:
- `interactive` 文本块映射到 `presentation.blocks[].type = "text"`
- `interactive` 按钮块映射到 `presentation.blocks[].type = "buttons"`
- `interactive` 选择块映射到 `presentation.blocks[].type = "select"`
外部智能体和 CLI 模式现在使用 `presentation``interactive` 仍然作为内部遗留解析/渲染辅助,用于现有回复生产者。
## 传递元数据
为非 UI 的发送行为添加一个由核心拥有的 `delivery` 字段。
```ts
type ReplyPayloadDelivery = {
pin?:
| boolean
| {
enabled: boolean;
notify?: boolean;
required?: boolean;
};
};
```
语义:
- `delivery.pin = true` 表示置顶第一条成功送达的消息。
- `notify` 默认为 `false`
- `required` 默认为 `false`;对于不支持的渠道或置顶失败的情况,会自动降级为继续传递。
- 手动 `pin`、`unpin` 和 `list-pins` 消息操作仍保留,用于现有消息。
当前 Telegram ACP 主题绑定应从 `channelData.telegram.pin = true` 迁移到 `delivery.pin = true`
## 运行时能力契约
将呈现和传递渲染钩子添加到运行时出站适配器,而不是控制平面渠道插件中。
```ts
type ChannelPresentationCapabilities = {
supported: boolean;
buttons?: boolean;
selects?: boolean;
context?: boolean;
divider?: boolean;
tones?: MessagePresentationTone[];
};
type ChannelDeliveryCapabilities = {
pinSentMessage?: boolean;
};
type ChannelOutboundAdapter = {
presentationCapabilities?: ChannelPresentationCapabilities;
renderPresentation?: (params: {
payload: ReplyPayload;
presentation: MessagePresentation;
ctx: ChannelOutboundSendContext;
}) => ReplyPayload | null;
deliveryCapabilities?: ChannelDeliveryCapabilities;
pinDeliveredMessage?: (params: {
cfg: OpenClawConfig;
accountId?: string | null;
to: string;
threadId?: string | number | null;
messageId: string;
notify: boolean;
}) => Promise<void>;
};
```
核心行为:
- 解析目标渠道和运行时适配器。
- 查询其呈现能力。
- 在渲染前降级不受支持的块。
- 调用 `renderPresentation`
- 如果不存在渲染器,则将呈现转换为文本回退。
- 成功发送后,当请求了 `delivery.pin` 且渠道支持时,调用 `pinDeliveredMessage`
## 渠道映射
Discord
- 在仅运行时模块中,将 `presentation` 渲染为 components v2 和 Carbon 容器。
- 将强调色辅助函数保留在轻量模块中。
- 从渠道插件控制平面代码中移除 `DiscordUiContainer` 导入。
Slack
- 将 `presentation` 渲染为 Block Kit。
- 移除智能体和 CLI 的 `blocks` 输入。
Telegram
- 将 text、context 和 divider 渲染为文本。
- 在已配置且目标表面允许的情况下,将 actions 和 select 渲染为内联键盘。
- 当内联按钮被禁用时使用文本回退。
- 将 ACP 主题置顶迁移到 `delivery.pin`
Mattermost
- 在已配置的情况下,将 actions 渲染为交互式按钮。
- 其他块渲染为文本回退。
MS Teams
- 将 `presentation` 渲染为 Adaptive Cards。
- 保留手动 pin/unpin/list-pins 操作。
- 如果目标会话的 Graph 支持足够可靠,可选择实现 `pinDeliveredMessage`
Feishu
- 将 `presentation` 渲染为交互式卡片。
- 保留手动 pin/unpin/list-pins 操作。
- 如果 API 行为足够可靠,可选择为已发送消息置顶实现 `pinDeliveredMessage`
LINE
- 尽可能将 `presentation` 渲染为 Flex 或模板消息。
- 对不支持的块回退为文本。
- 从 `channelData` 中移除 LINE UI 负载。
纯文本或能力受限的渠道:
- 使用保守格式将呈现转换为文本。
## 重构步骤
1. 重新应用 Discord 发布修复,将 `ui-colors.ts` 从由 Carbon 支持的 UI 中拆分出来,并从 `extensions/discord/src/channel.ts` 中移除 `DiscordUiContainer`
2. 向 `ReplyPayload`、出站负载规范化、传递摘要和钩子负载中添加 `presentation``delivery`
3. 在一个窄范围的 SDK/运行时子路径中添加 `MessagePresentation` 模式和解析辅助函数。
4. 用语义化呈现能力替换消息能力 `buttons`、`cards`、`components` 和 `blocks`
5. 为呈现渲染和传递置顶添加运行时出站适配器钩子。
6. 用 `buildCrossContextPresentation` 替换跨上下文组件构建。
7. 删除 `src/infra/outbound/channel-adapters.ts`,并从渠道插件类型中移除 `buildCrossContextComponents`
8. 修改 `maybeApplyCrossContextMarker`,使其附加 `presentation` 而不是原生参数。
9. 更新插件分发发送路径,使其仅消费语义化呈现和传递元数据。
10. 移除智能体和 CLI 的原生负载参数:`components`、`blocks`、`buttons` 和 `card`
11. 移除创建原生消息工具模式的 SDK 辅助函数,改用呈现模式辅助函数替代。
12. 从 `channelData` 中移除 UI/原生封装;在审查完每个剩余字段之前,仅保留传输元数据。
13. 迁移 Discord、Slack、Telegram、Mattermost、MS Teams、Feishu 和 LINE 渲染器。
14. 更新消息 CLI、渠道页面、插件 SDK 和能力扩展手册的文档。
15. 对 Discord 和受影响的渠道入口点运行导入扩散分析。
在这次重构中共享智能体、CLI、插件能力和出站适配器契约已实现步骤 1-11 和 13-14。步骤 12 仍然是更深层的内部清理工作,用于清理提供商私有的 `channelData` 传输封装。步骤 15 仍是后续验证项,如果我们希望获得超出类型/测试门禁之外的量化导入扩散数据。
## 测试
添加或更新:
- 呈现规范化测试。
- 针对不受支持块的呈现自动降级测试。
- 用于插件分发和核心传递路径的跨上下文标记测试。
- 针对 Discord、Slack、Telegram、Mattermost、MS Teams、Feishu、LINE 和文本回退的渠道渲染矩阵测试。
- 证明原生字段已移除的消息工具模式测试。
- 证明原生标志已移除的 CLI 测试。
- 覆盖 Carbon 的 Discord 入口点导入惰性回归测试。
- 覆盖 Telegram 和通用回退的传递置顶测试。
## 开放问题
- 在第一阶段中,是否应为 Discord、Slack、MS Teams 和 Feishu 实现 `delivery.pin`,还是先仅支持 Telegram
- `delivery` 最终是否应吸收现有字段,如 `replyToId`、`replyToCurrent`、`silent` 和 `audioAsVoice`,还是暂时只聚焦于发送后的行为?
- 呈现是否应直接支持图像或文件引用,还是媒体目前仍与 UI 布局分离?

File diff suppressed because it is too large Load Diff

View File

@ -1,14 +1,14 @@
---
read_when:
- 你正在构建一个 OpenClaw 插件
- 你需要发布一个插件配置 schema或调试插件校验错误
- 你需要提供插件配置 schema或调试插件校验错误
summary: 插件清单 + JSON schema 要求(严格配置校验)
title: 插件清单
x-i18n:
generated_at: "2026-04-21T17:54:51Z"
generated_at: "2026-04-21T20:34:44Z"
model: gpt-5.4
provider: openai
source_hash: 304c08035724dfb1ce6349972729b621aafc00880d4d259db78c22b86e9056ba
source_hash: 3664a984ac283378e11a76a68dfa320dc4d5a2aa40d973c731eb31e87d6eeeef
source_path: plugins/manifest.md
workflow: 15
---
@ -17,42 +17,42 @@ x-i18n:
本页仅适用于**原生 OpenClaw 插件清单**。
如需了解兼容的 bundle 布局,请参见 [插件 bundle](/zh-CN/plugins/bundles)。
有关兼容的 bundle 布局,请参见[插件 bundles](/zh-CN/plugins/bundles)。
兼容的 bundle 格式使用不同的清单文件:
- Codex bundle`.codex-plugin/plugin.json`
- Claude bundle`.claude-plugin/plugin.json`,或不带清单文件的默认 Claude 组件布局
- Claude bundle`.claude-plugin/plugin.json`,或不带清单的默认 Claude 组件布局
- Cursor bundle`.cursor-plugin/plugin.json`
OpenClaw 也会自动检测这些 bundle 布局,但不会根据这里述的 `openclaw.plugin.json` schema 对它们进行校验。
OpenClaw 也会自动检测这些 bundle 布局,但不会根据这里述的 `openclaw.plugin.json` schema 对它们进行校验。
对于兼容 bundleOpenClaw 目前会在布局符合 OpenClaw 运行时预期时,读取 bundle 元数据,以及声明的 skill 根目录、Claude 命令根目录、Claude bundle `settings.json` 默认值、Claude bundle LSP 默认值和受支持的 hook pack
对于兼容 bundle当其布局符合 OpenClaw 运行时预期时OpenClaw 当前会读取 bundle 元数据,以及已声明的 skill 根目录、Claude 命令根目录、Claude bundle `settings.json` 默认值、Claude bundle LSP 默认值,以及受支持的 hook packs
每个原生 OpenClaw 插件**都必须**在**插件根目录**提供一个 `openclaw.plugin.json` 文件。OpenClaw 使用这个清单在**不执行插件代码的情况下**验证配置。缺失或无效的清单会被视为插件错误,并阻止配置校验。
每个原生 OpenClaw 插件**都必须**在**插件根目录**提供一个 `openclaw.plugin.json` 文件。OpenClaw 使用此清单在**不执行插件代码**的情况下校验配置。缺失或无效的清单会被视为插件错误,并阻止配置校验。
参见完整的插件系统指南:[插件](/zh-CN/tools/plugin)。
原生能力模型和当前外部兼容性指引,请参见:[能力模型](/zh-CN/plugins/architecture#public-capability-model)。
请参阅完整的插件系统指南:[插件](/zh-CN/tools/plugin)。
关原生能力模型和当前外部兼容性指引,请参见:[能力模型](/zh-CN/plugins/architecture#public-capability-model)。
## 这个文件的作用
## 文件的作用
`openclaw.plugin.json` 是 OpenClaw 在加载你的插件代码之前读取的元数据。
将它用于:
用于:
- 插件标识
- 配置校验
- 可在不启动插件运行时的情况下获取的认证和新手引导元数据
- 控制平面界面可在运行时加载前检查的低成本激活提示
- 设置 / 新手引导界面可在运行时加载前检查的低成本设置描述符
- 应在插件运行时加载前解析的别名自动启用元数据
- 应在插件运行时加载前自动激活插件的模型家族简写归属元数据
- 无需启动插件运行时即可获取的认证与新手引导元数据
- 供控制平面界面在运行时加载前检查的轻量级激活提示
- 供设置 / 新手引导界面在运行时加载前检查的轻量级设置描述符
- 应在插件运行时加载前解析的别名自动启用元数据
- 应在插件运行时加载前自动激活插件的简写模型家族归属元数据
- 用于内置兼容接线和契约覆盖的静态能力归属快照
- 共享 `openclaw qa` 宿主可在插件运行时加载前检查的低成本 QA 运行器元数据
- 应在不加载运行时的情况下合并进目录和校验界面的渠道专用配置元数据
- 供共享 `openclaw qa` 主机在插件运行时加载前检查的轻量级 QA 运行器元数据
- 应在不加载运行时的情况下合并进目录与校验界面的渠道专属配置元数据
- 配置 UI 提示
不要将它用于:
不要用于:
- 注册运行时行为
- 声明代码入口点
@ -142,60 +142,60 @@ OpenClaw 也会自动检测这些 bundle 布局,但不会根据这里所述的
| ----------------------------------- | -------- | -------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `id` | 是 | `string` | 规范插件 id。这是在 `plugins.entries.<id>` 中使用的 id。 |
| `configSchema` | 是 | `object` | 此插件配置的内联 JSON Schema。 |
| `enabledByDefault` | 否 | `true` | 将内置插件标记为默认启用。省略它,或将其设为任何非 `true` 的值,则该插件默认保持禁用。 |
| `legacyPluginIds` | 否 | `string[]` | 会规范化为此规范插件 id 的旧版 id。 |
| `autoEnableWhenConfiguredProviders` | 否 | `string[]` | 当认证、配置或模型引用提到这些 provider id 时,应自动启用此插件。 |
| `kind` | 否 | `"memory"` \| `"context-engine"` | 声明一个由 `plugins.slots.*` 使用的排他性插件种类。 |
| `channels` | 否 | `string[]` | 此插件拥有的渠道 id。用于设备发现和配置校验。 |
| `providers` | 否 | `string[]` | 由此插件拥有的 provider id。 |
| `enabledByDefault` | 否 | `true` | 将内置插件标记为默认启用。省略此字段,或设置为任何非 `true` 的值,则插件默认保持禁用。 |
| `legacyPluginIds` | 否 | `string[]` | 会规范化为此规范插件 id 的旧版 id。 |
| `autoEnableWhenConfiguredProviders` | 否 | `string[]` | 当认证、配置或模型引用提到这些提供商 id 时,应自动启用此插件。 |
| `kind` | 否 | `"memory"` \| `"context-engine"` | 声明用于 `plugins.slots.*` 的排他性插件类型。 |
| `channels` | 否 | `string[]` | 此插件拥有的渠道 id。用于设备发现和配置校验。 |
| `providers` | 否 | `string[]` | 此插件拥有的提供商 id。 |
| `modelSupport` | 否 | `object` | 由清单拥有的简写模型家族元数据,用于在运行时之前自动加载插件。 |
| `providerEndpoints` | 否 | `object[]` | 由清单拥有的 endpoint 主机 / `baseUrl` 元数据,用于 core 在 provider 运行时加载前对 provider 路由进行分类。 |
| `cliBackends` | 否 | `string[]` | 此插件拥有的 CLI 推理后端 id。用于根据显式配置引用在启动时自动激活。 |
| `syntheticAuthRefs` | 否 | `string[]` | 在运行时加载前进行冷启动模型发现期间,应探测其插件自有 synthetic auth hook 的 provider 或 CLI 后端引用。 |
| `providerEndpoints` | 否 | `object[]` | 由清单拥有的端点 host / `baseUrl` 元数据,用于核心在提供商运行时加载之前对提供商路由进行分类。 |
| `cliBackends` | 否 | `string[]` | 此插件拥有的 CLI 推理后端 id。用于根据显式配置引用在启动时自动激活。 |
| `syntheticAuthRefs` | 否 | `string[]` | 在运行时加载前进行冷启动模型发现期间,应探测其插件自有 synthetic auth hook 的提供商或 CLI 后端引用。 |
| `nonSecretAuthMarkers` | 否 | `string[]` | 由内置插件拥有的占位 API key 值表示非机密的本地、OAuth 或环境凭证状态。 |
| `commandAliases` | 否 | `object[]` | 由此插件拥有的命令名称,应在运行时加载前生成感知插件的配置和 CLI 诊断信息。 |
| `providerAuthEnvVars` | 否 | `Record<string, string[]>` | OpenClaw 可在不加载插件代码的情况下检查的低成本 provider 认证环境变量元数据。 |
| `providerAuthAliases` | 否 | `Record<string, string>` | 应复用另一个 provider id 进行认证查找的 provider id例如共享基础 provider API key 和认证配置文件的 coding provider。 |
| `channelEnvVars` | 否 | `Record<string, string[]>` | OpenClaw 可在不加载插件代码的情况下检查的低成本渠道环境变量元数据。将其用于基于环境变量的渠道设置或认证界面,以便通用启动 / 配置辅助功能能够识别。 |
| `providerAuthChoices` | 否 | `object[]` | 用于新手引导选择器、首选 provider 解析和简单 CLI flag 接线的低成本认证选项元数据。 |
| `activation` | 否 | `object` | 用于 provider、命令、渠道、路由和能力触发加载的低成本激活提示。仅为元数据插件运行时仍拥有实际行为。 |
| `setup` | 否 | `object` | 设备发现和设置界面可在不加载插件运行时的情况下检查的低成本设置 / 新手引导描述符。 |
| `qaRunners` | 否 | `object[]` | 共享 `openclaw qa` 宿主在插件运行时加载前使用的低成本 QA 运行器描述符。 |
| `contracts` | 否 | `object` | 针对语音、实时转录、实时语音、媒体理解、图像生成、音乐生成、视频生成、网页抓取、Web 搜索和工具归属的静态内置能力快照。 |
| `channelConfigs` | 否 | `Record<string, object>` | 由清单拥有的渠道配置元数据,在运行时加载前合并到设备发现校验界面中。 |
| `commandAliases` | 否 | `object[]` | 由此插件拥有的命令名称,应在运行时加载前生成具备插件感知的配置与 CLI 诊断信息。 |
| `providerAuthEnvVars` | 否 | `Record<string, string[]>` | OpenClaw 可在不加载插件代码的情况下检查的轻量级提供商认证环境变量元数据。 |
| `providerAuthAliases` | 否 | `Record<string, string>` | 应复用另一个提供商 id 进行认证查找的提供商 id例如共享基础提供商 API key 和认证配置文件的 coding 提供商。 |
| `channelEnvVars` | 否 | `Record<string, string[]>` | OpenClaw 可在不加载插件代码的情况下检查的轻量级渠道环境变量元数据。将其用于通用启动 / 配置辅助工具需要识别的、由环境变量驱动的渠道设置或认证界面。 |
| `providerAuthChoices` | 否 | `object[]` | 用于新手引导选择器、首选提供商解析和简单 CLI 标志接线的轻量级认证选项元数据。 |
| `activation` | 否 | `object` | 用于提供商、命令、渠道、路由和由能力触发加载的轻量级激活提示。仅为元数据;实际行为仍由插件运行时负责。 |
| `setup` | 否 | `object` | 供设备发现和设置界面在不加载插件运行时的情况下检查的轻量级设置 / 新手引导描述符。 |
| `qaRunners` | 否 | `object[]` | 由共享 `openclaw qa` 主机在插件运行时加载前使用的轻量级 QA 运行器描述符。 |
| `contracts` | 否 | `object` | 用于 speech、实时转写、实时语音、媒体理解、图像生成、音乐生成、视频生成、web-fetch、Web 搜索和工具归属的静态内置能力快照。 |
| `channelConfigs` | 否 | `Record<string, object>` | 由清单拥有的渠道配置元数据,在运行时加载前合并到设备发现校验界面中。 |
| `skills` | 否 | `string[]` | 要加载的 Skills 目录,相对于插件根目录。 |
| `name` | 否 | `string` | 人类可读的插件名称。 |
| `description` | 否 | `string` | 在插件界面中显示的简短摘要。 |
| `description` | 否 | `string` | 显示在插件界面中的简短摘要。 |
| `version` | 否 | `string` | 信息性插件版本。 |
| `uiHints` | 否 | `Record<string, object>` | 配置字段的 UI 标签、占位符和敏感性提示。 |
## `providerAuthChoices` 参考
每个 `providerAuthChoices` 条目描述一个新手引导或认证选项。
OpenClaw 会在 provider 运行时加载前读取它
OpenClaw 会在提供商运行时加载之前读取这些内容
| 字段 | 必填 | 类型 | 含义 |
| --------------------- | -------- | ----------------------------------------------- | -------------------------------------------------------------------------------------------------------- |
| `provider` | 是 | `string` | 此选项所属的 provider id。 |
| `method` | 是 | `string` | 要分到的认证方法 id。 |
| `choiceId` | 是 | `string` | 新手引导和 CLI 流程使用的稳定认证选项 id。 |
| `provider` | 是 | `string` | 此选项所属的提供商 id。 |
| `method` | 是 | `string` | 要分到的认证方法 id。 |
| `choiceId` | 是 | `string` | 新手引导和 CLI 流程使用的稳定认证选项 id。 |
| `choiceLabel` | 否 | `string` | 面向用户的标签。如果省略OpenClaw 会回退到 `choiceId`。 |
| `choiceHint` | 否 | `string` | 选择器中的简短助文本。 |
| `assistantPriority` | 否 | `number` | 在由助手驱动的交互式选择器中,值越小排序越靠前。 |
| `assistantVisibility` | 否 | `"visible"` \| `"manual-only"` | 在助手选择器中隐藏该选项,同时仍允许手动 CLI 选择。 |
| `choiceHint` | 否 | `string` | 选择器中的简短助文本。 |
| `assistantPriority` | 否 | `number` | 在由智能体驱动的交互式选择器中,值越小排序越靠前。 |
| `assistantVisibility` | 否 | `"visible"` \| `"manual-only"` | 在智能体选择器中隐藏该选项,同时仍允许手动通过 CLI 选择。 |
| `deprecatedChoiceIds` | 否 | `string[]` | 应将用户重定向到此替代选项的旧版选项 id。 |
| `groupId` | 否 | `string` | 用于对相关选项分组的可选组 id。 |
| `groupLabel` | 否 | `string` | 该分组面向用户标签。 |
| `groupHint` | 否 | `string` | 该分组的简短助文本。 |
| `optionKey` | 否 | `string` | 用于简单单 flag 认证流程的内部选项键。 |
| `cliFlag` | 否 | `string` | CLI flag 名称,例如 `--openrouter-api-key`。 |
| `cliOption` | 否 | `string` | 完整 CLI 选项形式,例如 `--openrouter-api-key <key>`。 |
| `cliDescription` | 否 | `string` | 用于 CLI 帮助中的描述。 |
| `groupId` | 否 | `string` | 用于对相关选项进行分组的可选组 id。 |
| `groupLabel` | 否 | `string` | 该分组面向用户标签。 |
| `groupHint` | 否 | `string` | 该分组的简短助文本。 |
| `optionKey` | 否 | `string` | 用于简单单标志认证流程的内部选项键。 |
| `cliFlag` | 否 | `string` | CLI 标志名称,例如 `--openrouter-api-key`。 |
| `cliOption` | 否 | `string` | 完整 CLI 选项形式,例如 `--openrouter-api-key <key>`。 |
| `cliDescription` | 否 | `string` | 在 CLI 帮助中使用的描述。 |
| `onboardingScopes` | 否 | `Array<"text-inference" \| "image-generation">` | 此选项应出现在哪些新手引导界面中。如果省略,默认值为 `["text-inference"]`。 |
## `commandAliases` 参考
当插件拥有一个运行时命令名称,而用户可能会错误地将其放入 `plugins.allow`,或尝试将其作为根 CLI 命令运行时,请使用 `commandAliases`。OpenClaw 使用此元数据进行诊断,而无需导入插件运行时代码
当插件拥有某个运行时命令名称,而用户可能会误将其放入 `plugins.allow`,或尝试将其作为根 CLI 命令运行时,请使用 `commandAliases`。OpenClaw 使用这些元数据在不导入插件运行时代码的情况下提供诊断信息
```json
{
@ -213,15 +213,15 @@ OpenClaw 会在 provider 运行时加载前读取它。
| ------------ | -------- | ----------------- | ----------------------------------------------------------------------- |
| `name` | 是 | `string` | 属于此插件的命令名称。 |
| `kind` | 否 | `"runtime-slash"` | 将该别名标记为聊天斜杠命令,而不是根 CLI 命令。 |
| `cliCommand` | 否 | `string` | 若存在,用于 CLI 操作时建议的相关根 CLI 命令。 |
| `cliCommand` | 否 | `string` | 若存在,用于建议 CLI 操作的相关根 CLI 命令。 |
## `activation` 参考
当插件可以低成本声明哪些控制平面事件应在后激活它时,请使用 `activation`
当插件可以低成本声明哪些控制平面事件应在后激活它时,请使用 `activation`
## `qaRunners` 参考
当插件在共享 `openclaw qa` 根命令下贡献一个或多个传输运行器时,请使用 `qaRunners`请保持此元数据低成本且静态;插件运行时仍通过导出 `qaRunnerCliRegistrations` 的轻量级 `runtime-api.ts` 界面拥有实际 CLI 注册逻辑
当插件在共享 `openclaw qa` 根命令下贡献一个或多个传输运行器时,请使用 `qaRunners`保持这些元数据轻量且静态;实际的 CLI 注册仍由插件运行时通过导出 `qaRunnerCliRegistrations` 的轻量级 `runtime-api.ts` 接口负责
```json
{
@ -237,9 +237,9 @@ OpenClaw 会在 provider 运行时加载前读取它。
| 字段 | 必填 | 类型 | 含义 |
| ------------- | -------- | -------- | ------------------------------------------------------------------ |
| `commandName` | 是 | `string` | 挂载在 `openclaw qa` 下的子命令,例如 `matrix`。 |
| `description` | 否 | `string` | 当共享宿主需要一个占位命令时使用的回退帮助文本。 |
| `description` | 否 | `string` | 当共享主机需要一个 stub 命令时使用的回退帮助文本。 |
这个块仅为元数据。它不会注册运行时行为,也不会替代 `register(...)`、`setupEntry` 或其他运行时 / 插件入口点。当前使用方会在更广泛的插件加载之前将其用作缩小范围的提示,因此缺少激活元数据通常只会带来性能损失;在旧版清单归属回退机制仍存在时,它不应改变正确性。
块仅为元数据。它不会注册运行时行为,也不会替代 `register(...)`、`setupEntry` 或其他运行时 / 插件入口点。当前使用方会在更广泛的插件加载之前将其作为收窄提示,因此缺少激活元数据通常只会带来性能损耗;在旧版清单归属回退仍存在时,它不应改变正确性。
```json
{
@ -255,21 +255,24 @@ OpenClaw 会在 provider 运行时加载前读取它。
| 字段 | 必填 | 类型 | 含义 |
| ---------------- | -------- | ---------------------------------------------------- | ----------------------------------------------------------------- |
| `onProviders` | 否 | `string[]` | 当被请求时应激活此插件的 provider id。 |
| `onProviders` | 否 | `string[]` | 请求这些提供商 id 时应激活此插件。 |
| `onCommands` | 否 | `string[]` | 应激活此插件的命令 id。 |
| `onChannels` | 否 | `string[]` | 应激活此插件的渠道 id。 |
| `onRoutes` | 否 | `string[]` | 应激活此插件的路由类型。 |
| `onCapabilities` | 否 | `Array<"provider" \| "channel" \| "tool" \| "hook">` | 控制平面激活规划使用的广义能力提示。 |
| `onCapabilities` | 否 | `Array<"provider" \| "channel" \| "tool" \| "hook">` | 用于控制平面激活规划的广义能力提示。 |
当前的实际使用方:
当前的在线使用方:
- 由命令触发的 CLI 规划会回退到旧版 `commandAliases[].cliCommand``commandAliases[].name`
- 由渠道触发的设置 / 渠道规划在缺少显式渠道激活元数据时,会回退到旧版 `channels[]` 归属
- 由 provider 触发的设置 / 运行时规划在缺少显式 provider 激活元数据时,会回退到旧版 `providers[]` 和顶层 `cliBackends[]` 归属
- 由命令触发的 CLI 规划会回退到旧版
`commandAliases[].cliCommand``commandAliases[].name`
- 由渠道触发的设置 / 渠道规划在缺少显式渠道激活元数据时,会回退到旧版 `channels[]`
归属
- 由提供商触发的设置 / 运行时规划在缺少显式提供商激活元数据时,会回退到旧版
`providers[]` 和顶层 `cliBackends[]` 归属
## `setup` 参考
当设置和新手引导界面需要在运行时加载前获取低成本的插件自有元数据时,请使用 `setup`
当设置和新手引导界面需要在运行时加载前获取由插件拥有的轻量级元数据时,请使用 `setup`
```json
{
@ -288,32 +291,32 @@ OpenClaw 会在 provider 运行时加载前读取它。
}
```
顶层 `cliBackends` 仍然有效,并继续描述 CLI 推理后端。`setup.cliBackends` 是用于控制平面 / 设置流程的设置专用描述符界面,应保持为纯元数据。
顶层 `cliBackends` 仍然有效,并继续描述 CLI 推理后端。`setup.cliBackends` 是用于控制平面 / 设置流程的设置专用描述符界面,应保持为纯元数据。
存在时,`setup.providers` 和 `setup.cliBackends` 是设置发现时首选的“描述符优先”查找界面。如果描述符只用于缩小候选插件范围,而设置仍需要更丰富的设置期运行时 hook请设置 `requiresRuntime: true`,并保留 `setup-api` 作为回退执行路径。
存在时,`setup.providers` 和 `setup.cliBackends` 是设置发现时首选的描述符优先查找界面。如果描述符只能缩小候选插件范围,而设置仍需要更丰富的设置期运行时 hook请设置 `requiresRuntime: true`,并保留 `setup-api` 作为回退执行路径。
由于设置查找可能会执行插件自有的 `setup-api` 代码,已发现插件中的规范化 `setup.providers[].id``setup.cliBackends[]` 值必须保持全局唯一。归属不明确时会采用失败关闭,而不是根据发现顺序选一个赢家
由于设置查找可能会执行插件自有的 `setup-api` 代码,规范化后的 `setup.providers[].id``setup.cliBackends[]` 值必须在已发现的插件之间保持唯一。归属不明确时会以封闭失败方式处理,而不是按发现顺序选出一个胜者
### `setup.providers` 参考
| 字段 | 必填 | 类型 | 含义 |
| ------------- | -------- | ---------- | ------------------------------------------------------------------------------------ |
| `id` | 是 | `string` | 在设置或新手引导期间暴露的 provider id。请保持规范化 id 全局唯一。 |
| `authMethods` | 否 | `string[]` | 此 provider 在不加载完整运行时的情况下支持的设置 / 认证方法 id。 |
| `id` | 是 | `string` | 在设置或新手引导期间暴露的提供商 id。保持规范化 id 在全局唯一。 |
| `authMethods` | 否 | `string[]` | 此提供商在不加载完整运行时的情况下支持的设置 / 认证方法 id。 |
| `envVars` | 否 | `string[]` | 通用设置 / 状态界面可在插件运行时加载前检查的环境变量。 |
### `setup` 字段
| 字段 | 必填 | 类型 | 含义 |
| ------------------ | -------- | ---------- | --------------------------------------------------------------------------------------------------- |
| `providers` | 否 | `object[]` | 在设置和新手引导期间暴露的 provider 设置描述符。 |
| `cliBackends` | 否 | `string[]` | 用于描述符优先设置查找的设置期后端 id。保持规范化 id 全局唯一。 |
| `providers` | 否 | `object[]` | 在设置和新手引导期间暴露的提供商设置描述符。 |
| `cliBackends` | 否 | `string[]` | 用于描述符优先设置查找的设置期后端 id。保持规范化 id 全局唯一。 |
| `configMigrations` | 否 | `string[]` | 由此插件设置界面拥有的配置迁移 id。 |
| `requiresRuntime` | 否 | `boolean` | 在描述符查找之后,设置是否仍需要执行 `setup-api`。 |
## `uiHints` 参考
`uiHints`一个从配置字段名称映射到小型渲染提示的映射
`uiHints` 是从配置字段名称到小型渲染提示的映射。
```json
{
@ -328,20 +331,20 @@ OpenClaw 会在 provider 运行时加载前读取它。
}
```
每个字段提示可包含:
每个字段提示可包含:
| 字段 | 类型 | 含义 |
| ------------- | ---------- | --------------------------------------- |
| `label` | `string` | 面向用户的字段标签。 |
| `help` | `string` | 简短助文本。 |
| `tags` | `string[]` | 可选 UI 标签。 |
| `help` | `string` | 简短助文本。 |
| `tags` | `string[]` | 可选 UI 标签。 |
| `advanced` | `boolean` | 将该字段标记为高级项。 |
| `sensitive` | `boolean` | 将该字段标记为机密或敏感。 |
| `sensitive` | `boolean` | 将该字段标记为机密或敏感。 |
| `placeholder` | `string` | 表单输入的占位文本。 |
## `contracts` 参考
`contracts` 用于 OpenClaw 可在不导入插件运行时的情况下读取静态能力归属元数据。
OpenClaw 可在不导入插件运行时的情况下读取静态能力归属元数据时使用 `contracts`
```json
{
@ -363,19 +366,19 @@ OpenClaw 会在 provider 运行时加载前读取它。
| 字段 | 类型 | 含义 |
| -------------------------------- | ---------- | -------------------------------------------------------------- |
| `speechProviders` | `string[]` | 此插件拥有的语音 provider id。 |
| `realtimeTranscriptionProviders` | `string[]` | 此插件拥有的实时转录 provider id。 |
| `realtimeVoiceProviders` | `string[]` | 此插件拥有的实时语音 provider id。 |
| `mediaUnderstandingProviders` | `string[]` | 此插件拥有的媒体理解 provider id。 |
| `imageGenerationProviders` | `string[]` | 此插件拥有的图像生成 provider id。 |
| `videoGenerationProviders` | `string[]` | 此插件拥有的视频生成 provider id。 |
| `webFetchProviders` | `string[]` | 此插件拥有的网页抓取 provider id。 |
| `webSearchProviders` | `string[]` | 此插件拥有的 Web 搜索 provider id。 |
| `tools` | `string[]` | 此插件为内置契约检查所拥有的智能体工具名称。 |
| `speechProviders` | `string[]` | 此插件拥有的语音提供商 id。 |
| `realtimeTranscriptionProviders` | `string[]` | 此插件拥有的实时转写提供商 id。 |
| `realtimeVoiceProviders` | `string[]` | 此插件拥有的实时语音提供商 id。 |
| `mediaUnderstandingProviders` | `string[]` | 此插件拥有的媒体理解提供商 id。 |
| `imageGenerationProviders` | `string[]` | 此插件拥有的图像生成提供商 id。 |
| `videoGenerationProviders` | `string[]` | 此插件拥有的视频生成提供商 id。 |
| `webFetchProviders` | `string[]` | 此插件拥有的 web-fetch 提供商 id。 |
| `webSearchProviders` | `string[]` | 此插件拥有的 Web 搜索提供商 id。 |
| `tools` | `string[]` | 此插件拥有的智能体工具名称,用于内置契约检查。 |
## `channelConfigs` 参考
当渠道插件需要在运行时加载前提供低成本配置元数据时,请使用 `channelConfigs`
当渠道插件需要在运行时加载前获取轻量级配置元数据时,请使用 `channelConfigs`
```json
{
@ -402,19 +405,19 @@ OpenClaw 会在 provider 运行时加载前读取它。
}
```
每个渠道条目可包含:
每个渠道条目可包含:
| 字段 | 类型 | 含义 |
| ------------- | ------------------------ | ----------------------------------------------------------------------------------------- |
| `schema` | `object` | `channels.<id>` 的 JSON Schema。每个已声明的渠道配置条目都必须提供。 |
| `uiHints` | `Record<string, object>` | 该渠道配置部分可选 UI 标签 / 占位符 / 敏感性提示。 |
| `uiHints` | `Record<string, object>` | 该渠道配置部分可选 UI 标签 / 占位符 / 敏感性提示。 |
| `label` | `string` | 当运行时元数据尚未就绪时,合并到选择器和检查界面中的渠道标签。 |
| `description` | `string` | 用于检查和目录界面的简短渠道描述。 |
| `description` | `string` | 用于检查和目录界面的简短渠道说明。 |
| `preferOver` | `string[]` | 在选择界面中,此渠道应优先于的旧版或较低优先级插件 id。 |
## `modelSupport` 参考
当 OpenClaw 应在插件运行时加载前,根据 `gpt-5.4``claude-sonnet-4.6` 之类的简写模型 id 推断你的 provider 插件时,请使用 `modelSupport`
当 OpenClaw 应在插件运行时加载前,根据诸如 `gpt-5.4``claude-sonnet-4.6` 之类的简写模型 id 推断你的提供商插件时,请使用 `modelSupport`
```json
{
@ -425,60 +428,64 @@ OpenClaw 会在 provider 运行时加载前读取它。
}
```
OpenClaw 应用以下优先级
OpenClaw 按以下优先级处理
- 显式 `provider/model` 引用使用所属 `providers` 清单元数据
- 显式 `provider/model` 引用使用所属 `providers` 清单元数据
- `modelPatterns` 优先于 `modelPrefixes`
- 如果一个非内置插件和一个内置插件都匹配,则非内置插件胜出
- 剩余的歧义会被忽略,直到用户或配置明确指定 provider
- 其余歧义会被忽略,直到用户或配置指定提供商
字段:
| 字段 | 类型 | 含义 |
| --------------- | ---------- | ------------------------------------------------------------------------------- |
| `modelPrefixes` | `string[]` | 使用 `startsWith` 针对简写模型 id 进行匹配的前缀。 |
| `modelPatterns` | `string[]` | 在移除配置文件后缀后,针对简写模型 id 进行匹配的正则表达式源码。 |
| `modelPrefixes` | `string[]` | 通过 `startsWith`简写模型 id 进行匹配的前缀。 |
| `modelPatterns` | `string[]` | 在移除 profile 后缀后,与简写模型 id 匹配的正则表达式源码。 |
旧版顶层能力键已弃用。请使用 `openclaw doctor --fix``speechProviders`、`realtimeTranscriptionProviders`、`realtimeVoiceProviders`、`mediaUnderstandingProviders`、`imageGenerationProviders`、`videoGenerationProviders`、`webFetchProviders` 和 `webSearchProviders` 移动到 `contracts` 下;普通清单加载不再将这些顶层字段视为能力归属。
旧版顶层能力键已弃用。请使用 `openclaw doctor --fix`
`speechProviders`、`realtimeTranscriptionProviders`、
`realtimeVoiceProviders`、`mediaUnderstandingProviders`、
`imageGenerationProviders`、`videoGenerationProviders`、
`webFetchProviders``webSearchProviders` 移到 `contracts` 下;正常的清单加载不再将这些顶层字段视为能力归属。
## 清单与 `package.json` 的区别
这两个文件承担不同的职责:
这两个文件承担不同职责:
| 文件 | 用途 |
| ---------------------- | -------------------------------------------------------------------------------------------------------------------------------- |
| `openclaw.plugin.json` | 必须在插件代码运行前存在的设备发现、配置校验、认证选项元数据 UI 提示 |
| `package.json` | npm 元数据、依赖安装,以及用于入口点、安装门、设置或目录元数据的 `openclaw` 块 |
| `openclaw.plugin.json` | 设备发现、配置校验、认证选项元数据,以及必须在插件代码运行前存在的 UI 提示 |
| `package.json` | npm 元数据、依赖安装,以及用于入口点、安装门、设置或目录元数据的 `openclaw` 配置块 |
如果你不确定某段元数据应放在哪里,请使用以下规则:
- 如果 OpenClaw 必须在加载插件代码前知道它,就放在 `openclaw.plugin.json`
- 如果它与打包、入口文件或 npm 安装行为有关,就放在 `package.json`
- 如果 OpenClaw 必须在加载插件代码前知道它,就把它放在 `openclaw.plugin.json`
- 如果它与打包、入口文件或 npm 安装行为有关,就把它放在 `package.json`
### 影响设备发现的 `package.json` 字段
### 影响设备发现的 `package.json` 字段
有些运行时前插件元数据有意放在 `package.json``openclaw` 块下,而不是 `openclaw.plugin.json` 中。
一些运行时前的插件元数据有意放在 `package.json``openclaw` 配置块下,而不是 `openclaw.plugin.json` 中。
重要示例:
| 字段 | 含义 |
| ----------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------- |
| `openclaw.extensions` | 声明原生插件入口点。 |
| `openclaw.setupEntry` | 在新手引导、延渠道启动以及只读渠道状态 / SecretRef 发现期间使用的轻量级仅设置入口点。 |
| `openclaw.channel` | 低成本渠道目录元数据,例如标签、文档路径、别名和选择文案。 |
| `openclaw.channel.configuredState` | 轻量级已配置状态检查器元数据,可在不加载完整渠道运行时的情况下回答“是否已存在仅基于环境变量设置?”。 |
| `openclaw.channel.persistedAuthState` | 轻量级持久化认证状态检查器元数据,可在不加载完整渠道运行时的情况下回答“是否已经有任何已登录状态?”。 |
| `openclaw.install.npmSpec` / `openclaw.install.localPath` | 内置和外部发布插件的安装 / 更新提示。 |
| `openclaw.setupEntry` | 在新手引导、延渠道启动以及只读渠道状态 / SecretRef 发现期间使用的轻量级仅设置入口点。 |
| `openclaw.channel` | 轻量级渠道目录元数据,例如标签、文档路径、别名和选择说明文案。 |
| `openclaw.channel.configuredState` | 轻量级已配置状态检查器元数据,可在不加载完整渠道运行时的情况下回答“是否已存在仅环境变量设置?”。 |
| `openclaw.channel.persistedAuthState` | 轻量级持久化认证状态检查器元数据,可在不加载完整渠道运行时的情况下回答“是否已有任何账号登录?”。 |
| `openclaw.install.npmSpec` / `openclaw.install.localPath` | 内置插件和外部发布插件的安装 / 更新提示。 |
| `openclaw.install.defaultChoice` | 当有多个安装来源可用时的首选安装路径。 |
| `openclaw.install.minHostVersion` | 最低支持的 OpenClaw 宿主版本,使用如 `>=2026.3.22` 这样的 semver 下限。 |
| `openclaw.install.allowInvalidConfigRecovery` | 当配置无效时,允许一个狭窄的内置插件重新安装恢复路径。 |
| `openclaw.install.minHostVersion` | 支持的最低 OpenClaw host 版本,使用如 `>=2026.3.22` 这样的 semver 下限。 |
| `openclaw.install.allowInvalidConfigRecovery` | 当配置无效时,允许一个受限的内置插件重装恢复路径。 |
| `openclaw.startup.deferConfiguredChannelFullLoadUntilAfterListen` | 允许仅设置的渠道界面在启动期间先于完整渠道插件加载。 |
`openclaw.install.minHostVersion` 会在安装和清单注册表加载期间强制执行。无效值会被拒绝;较新但有效的值会使该插件在较旧宿主上被跳过。
`openclaw.install.minHostVersion` 会在安装期间和清单注册表加载期间强制执行。无效值会被拒绝;较新但有效的值会使插件在旧 host 上被跳过。
当状态、渠道列表或 SecretRef 扫描需要在不加载完整运行时的情况下识别已配置账号时,渠道插件应提供 `openclaw.setupEntry`设置入口点应公开渠道元数据以及可安全用于设置的配置、状态和密钥适配器;网络客户端、Gateway 网关监听器和传输运行时保留在主扩展入口点中。
当状态、渠道列表或 SecretRef 扫描需要在不加载完整运行时的情况下识别已配置账号时,渠道插件应提供 `openclaw.setupEntry`该设置入口应暴露渠道元数据,以及适用于设置场景的安全配置、状态和密钥适配器;将网络客户端、Gateway 网关监听器和传输运行时保留在主扩展入口点中。
`openclaw.install.allowInvalidConfigRecovery`适用范围刻意很窄。它不会让任意损坏的配置变得可安装。当前它只允许安装流程从特定的陈旧内置插件升级失败中恢复,例如缺失的内置插件路径,或同一内置插件对应的陈旧 `channels.<id>` 条目。无关的配置错误仍会阻止安装,并将操作人员引导到 `openclaw doctor --fix`
`openclaw.install.allowInvalidConfigRecovery`设计范围刻意很窄。它不会让任意损坏的配置变得可安装。当前它只允许安装流程从特定的陈旧内置插件升级故障中恢复,例如缺失的内置插件路径,或同一内置插件对应的陈旧 `channels.<id>` 条目。无关的配置错误仍会阻止安装,并将运维人员引导到 `openclaw doctor --fix`
`openclaw.channel.persistedAuthState` 是一个微型检查器模块的包元数据:
@ -496,9 +503,9 @@ OpenClaw 应用以下优先级:
}
```
当设置、Doctor 或已配置状态流程需要在完整渠道插件加载前进行低成本的二元认证探测时,请使用它。目标导出应是一个只读取持久化状态的小函数;不要通过完整渠道运行时 barrel 暴露它。
当设置、Doctor 或已配置状态流程需要在完整渠道插件加载前进行廉价的认证是 / 否探测时,请使用它。目标导出应是一个只读取持久化状态的小函数;不要通过完整渠道运行时 barrel 转发它。
`openclaw.channel.configuredState`于低成本的仅环境变量已配置检查采用相同的结构:
`openclaw.channel.configuredState`廉价的仅环境变量已配置检查采用相同结构:
```json
{
@ -514,7 +521,24 @@ OpenClaw 应用以下优先级:
}
```
当渠道可以仅通过环境变量或其他微小的非运行时输入回答已配置状态时,请使用它。如果检查需要完整配置解析或真实渠道运行时,请将该逻辑保留在插件 `config.hasConfiguredState` hook 中。
当渠道可以仅根据环境变量或其他微小的非运行时输入回答已配置状态时,请使用它。如果检查需要完整的配置解析或真实渠道运行时,请改为将该逻辑保留在插件 `config.hasConfiguredState` hook 中。
## 设备发现优先级(重复的插件 id
OpenClaw 会从多个根目录发现插件(内置、全局安装、工作区、配置中显式选择的路径)。如果两个发现结果共享同一个 `id`,则只保留**优先级最高**的清单;较低优先级的重复项会被丢弃,而不是与其并行加载。
优先级从高到低如下:
1. **配置选择** —— 在 `plugins.entries.<id>` 中显式固定的路径
2. **内置** —— 随 OpenClaw 一起发布的插件
3. **全局安装** —— 安装到全局 OpenClaw 插件根目录的插件
4. **工作区** —— 相对于当前工作区发现的插件
影响:
- 工作区中某个内置插件的 fork 或陈旧副本不会覆盖内置构建版本。
- 若要真正用本地插件覆盖内置插件,请通过 `plugins.entries.<id>` 固定它,使其凭优先级获胜,而不是依赖工作区发现。
- 被丢弃的重复项会被记录日志,这样 Doctor 和启动诊断就能指出被舍弃的副本。
## JSON Schema 要求
@ -524,35 +548,39 @@ OpenClaw 应用以下优先级:
## 校验行为
- 未知的 `channels.*` 键是**错误**,除非该渠道 id 由某个插件清单声明。
- `plugins.entries.<id>`、`plugins.allow`、`plugins.deny` 和 `plugins.slots.*` 必须引用**可发现的**插件 id。未知 id 是**错误**。
- 如果某个插件已安装,但其清单或 schema 缺失或损坏校验将失败Doctor 会报告该插件错误。
- 如果插件配置存在,但插件**已禁用**,则配置会被保留,并在 Doctor + 日志中显示**警告**。
- 未知的 `channels.*` 键会被视为**错误**,除非该渠道 id 已由某个插件清单声明。
- `plugins.entries.<id>`、`plugins.allow`、`plugins.deny` 和 `plugins.slots.*`
必须引用**可发现的**插件 id。未知 id 会被视为**错误**。
- 如果某个插件已安装,但其清单或 schema 损坏或缺失校验将失败Doctor 会报告该插件错误。
- 如果插件配置存在,但插件处于**禁用**状态,该配置会被保留,并在 Doctor + 日志中显示**警告**。
完整的 `plugins.*` schema 参见[配置参考](/zh-CN/gateway/configuration)。
完整的 `plugins.*` schema 参见[配置参考](/zh-CN/gateway/configuration)。
## 说明
## 注意事项
- 对于原生 OpenClaw 插件,清单是**必需的**,包括从本地文件系统加载的插件。
- 运行时仍会单独加载插件模块;清单仅用于设备发现校验。
- 对于**原生 OpenClaw 插件**,清单是**必需的**,包括从本地文件系统加载的插件。
- 运行时仍会单独加载插件模块;清单仅用于设备发现 + 校验。
- 原生清单使用 JSON5 解析,因此支持注释、尾随逗号和未加引号的键,只要最终值仍然是一个对象即可。
- 清单加载器只会读取文档中说明的清单字段。避免在这里添加自定义顶层键。
- `providerAuthEnvVars` 是用于认证探测、环境变量标记校验以及类似 provider 认证界面的低成本元数据路径,这些场景不应仅为了检查环境变量名而启动插件运行时。
- `providerAuthAliases` 允许 provider 变体复用另一个 provider 的认证环境变量、认证配置文件、配置支持的认证以及 API key 新手引导选项,而无需在 core 中硬编码这种关系。
- `providerEndpoints` 允许 provider 插件拥有简单的 endpoint 主机 / `baseUrl` 匹配元数据。仅将其用于 core 已支持的 endpoint 类别;运行时行为仍由插件拥有。
- `syntheticAuthRefs` 是用于 provider 自有 synthetic auth hook 的低成本元数据路径,这些 hook 必须在运行时注册表存在之前,对冷启动模型发现可见。这里只列出那些其运行时 provider 或 CLI 后端实际实现了 `resolveSyntheticAuth` 的引用。
- `nonSecretAuthMarkers` 是用于内置插件自有占位 API key 的低成本元数据路径例如本地、OAuth 或环境凭证标记。core 会将这些视为非机密项,用于认证显示和密钥审计,而无需硬编码所属 provider。
- `channelEnvVars` 是用于 shell 环境变量回退、设置提示以及类似渠道界面的低成本元数据路径,这些场景不应仅为了检查环境变量名而启动插件运行时。
- `providerAuthChoices` 是用于认证选项选择器、`--auth-choice` 解析、首选 provider 映射以及在 provider 运行时加载前进行简单新手引导 CLI flag 注册的低成本元数据路径。对于需要 provider 代码的运行时向导元数据,请参见[provider 运行时 hook](/zh-CN/plugins/architecture#provider-runtime-hooks)。
- 排他性插件种类通过 `plugins.slots.*` 选择。
- 清单加载器只会读取文档中说明的清单字段。避免在此处添加自定义顶层键。
- `providerAuthEnvVars` 是用于认证探测、环境变量标记校验以及类似提供商认证界面的轻量级元数据路径,这些场景不应仅为了检查环境变量名称而启动插件运行时。
- `providerAuthAliases` 允许提供商变体复用另一个提供商的认证环境变量、认证配置文件、基于配置的认证以及 API key 新手引导选项,而无需在核心中硬编码这种关系。
- `providerEndpoints` 让提供商插件拥有简单端点 host / `baseUrl`
匹配元数据。仅将其用于核心已支持的端点类别;运行时行为仍由插件负责。
- `syntheticAuthRefs` 是用于提供商自有 synthetic auth hook 的轻量级元数据路径,这些 hook 必须在运行时注册表存在之前就能被冷启动模型发现看到。这里只列出那些其运行时提供商或 CLI 后端实际实现了 `resolveSyntheticAuth` 的引用。
- `nonSecretAuthMarkers` 是用于内置插件自有占位 API key 的轻量级元数据路径例如本地、OAuth 或环境凭证标记。核心会将这些值视为非机密,用于认证显示和密钥审计,而无需硬编码所属提供商。
- `channelEnvVars` 是用于 shell 环境变量回退、设置提示以及类似渠道界面的轻量级元数据路径,这些场景不应仅为了检查环境变量名称而启动插件运行时。
- `providerAuthChoices` 是用于认证选项选择器、`--auth-choice` 解析、首选提供商映射,以及在提供商运行时加载前注册简单新手引导 CLI 标志的轻量级元数据路径。有关需要提供商代码的运行时向导元数据,请参见
[提供商运行时 hooks](/zh-CN/plugins/architecture#provider-runtime-hooks)。
- 排他性插件类型通过 `plugins.slots.*` 选择。
- `kind: "memory"``plugins.slots.memory` 选择。
- `kind: "context-engine"``plugins.slots.contextEngine` 选择(默认值:内置 `legacy`)。
- 当插件不需要它们时,可以省略 `channels`、`providers`、`cliBackends` 和 `skills`
- 如果你的插件依赖原生模块,请记录构建步骤以及任何包管理器允许列表要求(例如 pnpm `allow-build-scripts`
- `kind: "context-engine"``plugins.slots.contextEngine`
选择(默认值:内置 `legacy`)。
- 当插件不需要 `channels`、`providers`、`cliBackends` 和 `skills` 时,可以省略这些字段。
- 如果你的插件依赖原生模块,请记录构建步骤以及任何包管理器 allowlist 要求(例如 pnpm `allow-build-scripts`
- `pnpm rebuild <package>`)。
## 相关内容
- [构建插件](/zh-CN/plugins/building-plugins) — 插件快速开始
- [构建插件](/zh-CN/plugins/building-plugins) — 插件入门指南
- [插件架构](/zh-CN/plugins/architecture) — 内部架构
- [插件 SDK 概览](/zh-CN/plugins/sdk-overview) — 插件 SDK 参考

View File

@ -0,0 +1,326 @@
---
read_when:
- 添加或修改消息卡片、按钮或选择器的渲染
- 构建支持丰富出站消息的渠道插件
- 更改消息工具的呈现方式或传递能力
- 调试提供商特定的卡片 / 区块 / 组件渲染回归问题
summary: 用于渠道插件的语义化消息卡片、按钮、选择器、回退文本和传递提示
title: 消息呈现
x-i18n:
generated_at: "2026-04-21T20:34:49Z"
model: gpt-5.4
provider: openai
source_hash: a6913b2b4331598a1396d19a572fba1fffde6cb9a6efa2192f30fe12404eb48d
source_path: plugins/message-presentation.md
workflow: 15
---
# 消息呈现
消息呈现是 OpenClaw 用于丰富出站聊天 UI 的共享契约。
它让智能体、CLI 命令、审批流程和插件只需描述一次消息意图,
同时每个渠道插件都可以尽可能渲染出最合适的原生形态。
将消息呈现用于可移植的消息 UI
- 文本区块
- 小型上下文 / 页脚文本
- 分隔线
- 按钮
- 选择菜单
- 卡片标题和语气
不要向共享消息工具中添加新的提供商原生字段,例如 Discord 的 `components`、Slack
`blocks`、Telegram 的 `buttons`、Teams 的 `card` 或 Feishu 的 `card`。这些字段属于由渠道插件负责的渲染器输出。
## 契约
插件作者从以下位置导入公开契约:
```ts
import type {
MessagePresentation,
ReplyPayloadDelivery,
} from "openclaw/plugin-sdk/interactive-runtime";
```
结构:
```ts
type MessagePresentation = {
title?: string;
tone?: "neutral" | "info" | "success" | "warning" | "danger";
blocks: MessagePresentationBlock[];
};
type MessagePresentationBlock =
| { type: "text"; text: string }
| { type: "context"; text: string }
| { type: "divider" }
| { type: "buttons"; buttons: MessagePresentationButton[] }
| { type: "select"; placeholder?: string; options: MessagePresentationOption[] };
type MessagePresentationButton = {
label: string;
value?: string;
url?: string;
style?: "primary" | "secondary" | "success" | "danger";
};
type MessagePresentationOption = {
label: string;
value: string;
};
type ReplyPayloadDelivery = {
pin?:
| boolean
| {
enabled: boolean;
notify?: boolean;
required?: boolean;
};
};
```
按钮语义:
- `value` 是应用动作值;当渠道支持可点击控件时,它会通过该渠道现有的交互路径路由回来。
- `url` 是链接按钮。它可以在没有 `value` 的情况下存在。
- `label` 是必填项,也会用于文本回退。
- `style` 是建议性的。渲染器应将不支持的样式映射为安全的默认值,而不是让发送失败。
选择菜单语义:
- `options[].value` 是选中的应用值。
- `placeholder` 是建议性的,在没有原生选择菜单支持的渠道中可能会被忽略。
- 如果某个渠道不支持选择菜单,回退文本会列出这些标签。
## 生产者示例
简单卡片:
```json
{
"title": "Deploy approval",
"tone": "warning",
"blocks": [
{ "type": "text", "text": "Canary is ready to promote." },
{ "type": "context", "text": "Build 1234, staging passed." },
{
"type": "buttons",
"buttons": [
{ "label": "Approve", "value": "deploy:approve", "style": "success" },
{ "label": "Decline", "value": "deploy:decline", "style": "danger" }
]
}
]
}
```
仅 URL 的链接按钮:
```json
{
"blocks": [
{ "type": "text", "text": "Release notes are ready." },
{
"type": "buttons",
"buttons": [{ "label": "Open notes", "url": "https://example.com/release" }]
}
]
}
```
选择菜单:
```json
{
"title": "Choose environment",
"blocks": [
{
"type": "select",
"placeholder": "Environment",
"options": [
{ "label": "Canary", "value": "env:canary" },
{ "label": "Production", "value": "env:prod" }
]
}
]
}
```
CLI 发送:
```bash
openclaw message send --channel slack \
--target channel:C123 \
--message "Deploy approval" \
--presentation '{"title":"Deploy approval","tone":"warning","blocks":[{"type":"text","text":"Canary is ready."},{"type":"buttons","buttons":[{"label":"Approve","value":"deploy:approve","style":"success"},{"label":"Decline","value":"deploy:decline","style":"danger"}]}]}'
```
置顶传递:
```bash
openclaw message send --channel telegram \
--target -1001234567890 \
--message "Topic opened" \
--pin
```
带显式 JSON 的置顶传递:
```json
{
"pin": {
"enabled": true,
"notify": true,
"required": false
}
}
```
## 渲染器契约
渠道插件在其出站适配器上声明渲染支持:
```ts
const adapter: ChannelOutboundAdapter = {
deliveryMode: "direct",
presentationCapabilities: {
supported: true,
buttons: true,
selects: true,
context: true,
divider: true,
},
deliveryCapabilities: {
pin: true,
},
renderPresentation({ payload, presentation, ctx }) {
return renderNativePayload(payload, presentation, ctx);
},
async pinDeliveredMessage({ target, messageId, pin }) {
await pinNativeMessage(target, messageId, { notify: pin.notify === true });
},
};
```
能力字段刻意保持为简单的布尔值。它们描述的是渲染器能够让哪些内容变为可交互,而不是原生平台的所有限制。渲染器仍然负责平台特定限制,例如最大按钮数、区块数和卡片大小。
## 核心渲染流程
`ReplyPayload` 或消息动作包含 `presentation` 时,核心会:
1. 规范化呈现负载。
2. 解析目标渠道的出站适配器。
3. 读取 `presentationCapabilities`
4. 当适配器可以渲染该负载时,调用 `renderPresentation`
5. 当适配器缺失或无法渲染时,回退为保守的文本。
6. 通过正常的渠道传递路径发送结果负载。
7. 在第一条消息成功发送后,应用 `delivery.pin` 等传递元数据。
核心负责回退行为,因此生产者可以保持渠道无关。渠道插件负责原生渲染和交互处理。
## 降级规则
消息呈现必须能够安全地发送到能力受限的渠道。
回退文本包括:
- 第一行中的 `title`
- 作为普通段落的 `text` 区块
- 作为紧凑上下文行的 `context` 区块
- 作为视觉分隔符的 `divider` 区块
- 按钮标签,链接按钮还包括其 URL
- 选择项标签
不受支持的原生控件应降级,而不是让整次发送失败。
示例:
- 当 Telegram 的内联按钮被禁用时,会发送文本回退。
- 没有选择菜单支持的渠道会以文本形式列出选择项。
- 仅 URL 的按钮会变为原生链接按钮,或变为回退 URL 行。
- 可选的置顶失败不会导致已传递的消息失败。
主要例外是 `delivery.pin.required: true`;如果请求将置顶设为必需,而渠道无法置顶已发送消息,则传递会报告失败。
## 提供商映射
当前内置渲染器:
| 渠道 | 原生渲染目标 | 说明 |
| --------------- | ----------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- |
| Discord | Components 和组件容器 | 为现有提供商原生负载生产者保留旧版 `channelData.discord.components`,但新的共享发送应使用 `presentation`。 |
| Slack | Block Kit | 为现有提供商原生负载生产者保留旧版 `channelData.slack.blocks`,但新的共享发送应使用 `presentation`。 |
| Telegram | 文本加内联键盘 | 按钮 / 选择菜单要求目标界面支持内联按钮能力;否则使用文本回退。 |
| Mattermost | 文本加交互式 props | 其他区块会降级为文本。 |
| Microsoft Teams | Adaptive Cards | 当同时提供普通 `message` 文本和卡片时,普通 `message` 文本也会一并包含。 |
| Feishu | 交互式卡片 | 卡片头部可以使用 `title`;正文会避免重复该标题。 |
| 纯文本渠道 | 文本回退 | 没有渲染器的渠道仍然会得到可读的输出。 |
提供商原生负载兼容性是为现有回复生产者提供的过渡性便利。
这并不是向共享层添加新的原生字段的理由。
## Presentation 与 InteractiveReply
`InteractiveReply` 是较早的内部子集,供审批和交互辅助工具使用。它支持:
- 文本
- 按钮
- 选择菜单
`MessagePresentation` 是标准的共享发送契约。它新增了:
- 标题
- 语气
- 上下文
- 分隔线
- 仅 URL 的按钮
- 通过 `ReplyPayload.delivery` 提供的通用传递元数据
桥接旧代码时,请使用 `openclaw/plugin-sdk/interactive-runtime` 中的辅助工具:
```ts
import {
interactiveReplyToPresentation,
normalizeMessagePresentation,
presentationToInteractiveReply,
renderMessagePresentationFallbackText,
} from "openclaw/plugin-sdk/interactive-runtime";
```
新代码应直接接受或生成 `MessagePresentation`
## 传递置顶
置顶属于传递行为,不属于消息呈现。请使用 `delivery.pin`,而不要使用 `channelData.telegram.pin` 之类的提供商原生字段。
语义:
- `pin: true` 会置顶第一条成功传递的消息。
- `pin.notify` 默认为 `false`
- `pin.required` 默认为 `false`
- 可选的置顶失败会降级,并保留已发送消息。
- 必需的置顶失败会导致传递失败。
- 分块消息会置顶第一个已传递分块,而不是尾部分块。
手动的 `pin`、`unpin` 和 `pins` 消息动作仍然存在,用于提供商支持这些操作的现有消息。
## 插件作者检查清单
- 当渠道可以渲染或安全降级语义化消息呈现时,在 `describeMessageTool(...)` 中声明 `presentation`
- 向运行时出站适配器添加 `presentationCapabilities`
- 在运行时代码中实现 `renderPresentation`,而不是在控制平面插件设置代码中实现。
- 不要将原生 UI 库放入高频的设置 / 目录路径中。
- 在渲染器和测试中保留平台限制。
- 为不受支持的按钮、选择菜单、URL 按钮、标题 / 文本重复,以及混合 `message``presentation` 发送添加回退测试。
- 仅当提供商可以置顶已发送消息 ID 时,才通过 `deliveryCapabilities.pin``pinDeliveredMessage` 添加置顶传递支持。
- 不要通过共享消息动作 schema 暴露新的提供商原生卡片 / 区块 / 组件 / 按钮字段。
## 相关文档
- [消息 CLI](/cli/message)
- [插件 SDK 概览](/zh-CN/plugins/sdk-overview)
- [插件架构](/zh-CN/plugins/architecture#message-tool-schemas)
- [渠道呈现重构计划](/zh-CN/plan/ui-channels)

View File

@ -1,29 +1,29 @@
---
read_when:
- 你需要知道应从哪个 SDK 子路径导入
- 你想查`OpenClawPluginApi` 上所有注册方法的参考文档
- 你正在查找一个特定的 SDK 导出内容
- 你需要知道应从哪个 SDK 子路径导入
- 你想查`OpenClawPluginApi` 上所有注册方法的参考说明
- 你正在查找某个特定的 SDK 导出项
sidebarTitle: SDK Overview
summary: 导入映射、注册 API 参考和 SDK 架构
title: 插件 SDK 概览
x-i18n:
generated_at: "2026-04-21T04:19:37Z"
generated_at: "2026-04-21T20:34:46Z"
model: gpt-5.4
provider: openai
source_hash: 4561c074bb45529cd94d9d23ce7820b668cbc4ff6317230fdd5a5f27c5f14c67
source_hash: 16ef34e4ad4550967d06ea6bd94b3400431c0fb536bf267cc4e8a09ec9483695
source_path: plugins/sdk-overview.md
workflow: 15
---
# 插件 SDK 概览
插件 SDK 是插件与核心之间的类型化契约。本页是关于**导入什么**以及**你可以注册什么**的参考文档
插件 SDK 是插件与核心之间的类型化契约。本页是关于**导入什么**以及**你可以注册什么**的参考。
<Tip>
**在找操作指南?**
**在找操作指南**
- 第一个插件?从 [入门指南](/zh-CN/plugins/building-plugins) 开始
- 渠道插件?参见 [渠道插件](/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>
## 导入约定
@ -35,26 +35,17 @@ import { definePluginEntry } from "openclaw/plugin-sdk/plugin-entry";
import { defineChannelPluginEntry } from "openclaw/plugin-sdk/channel-core";
```
每个子路径都是一个小型、独立的模块。这可以保持快速启动,并防止循环依赖问题。对于特定于渠道的入口 / 构建辅助函数,优先使用 `openclaw/plugin-sdk/channel-core`;将 `openclaw/plugin-sdk/core` 保留给更广泛的总入口 surface 以及共享辅助函数,例如 `buildChannelConfigSchema`
每个子路径都是一个小型、独立的模块。这可以保持快速启动,并防止循环依赖问题。对于特定于渠道的入口 / 构建辅助函数,优先使用 `openclaw/plugin-sdk/channel-core`;将 `openclaw/plugin-sdk/core` 保留给更广泛的总入口表面以及诸如 `buildChannelConfigSchema` 之类的共享辅助函数
不要添加或依赖以提供商命名的便捷 seam例如
`openclaw/plugin-sdk/slack`、`openclaw/plugin-sdk/discord`、
`openclaw/plugin-sdk/signal`、`openclaw/plugin-sdk/whatsapp`,或
带有渠道品牌的辅助 seam。内置插件应在它们自己的 `api.ts``runtime-api.ts` barrel 中组合通用
SDK 子路径,而核心在确实存在跨渠道需求时,应使用这些插件本地的 barrel或添加一个狭义的通用 SDK
契约。
不要添加或依赖带有提供商名称的便捷接口,例如 `openclaw/plugin-sdk/slack`、`openclaw/plugin-sdk/discord`、`openclaw/plugin-sdk/signal`、`openclaw/plugin-sdk/whatsapp`,或带有渠道品牌的辅助接口。内置插件应在它们自己的 `api.ts``runtime-api.ts` barrel 中组合通用 SDK 子路径,而核心应使用这些插件本地 barrel或者仅当需求确实跨渠道时添加一个狭义的通用 SDK 契约。
生成的导出映射仍然包含一小部分内置插件辅助 seam例如 `plugin-sdk/feishu`、`plugin-sdk/feishu-setup`、
`plugin-sdk/zalo`、`plugin-sdk/zalo-setup` 和 `plugin-sdk/matrix*`。这些
子路径仅用于内置插件维护和兼容性;它们被有意省略在下方的常用表格之外,也不是新的第三方插件推荐使用的导入路径。
生成的导出映射仍然包含一小组内置插件辅助接口,例如 `plugin-sdk/feishu`、`plugin-sdk/feishu-setup`、`plugin-sdk/zalo`、`plugin-sdk/zalo-setup` 以及 `plugin-sdk/matrix*`。这些子路径仅用于内置插件维护和兼容性;它们被有意省略在下面的常用表格之外,也不是新第三方插件的推荐导入路径。
## 子路径参考
最常用的子路径,按用途分组。生成的完整列表包含 200 多个子路径,位于
`scripts/lib/plugin-sdk-entrypoints.json`
最常用的子路径,按用途分组。完整的 200 多个子路径生成列表位于 `scripts/lib/plugin-sdk-entrypoints.json`
保留的内置插件辅助子路径仍会出现在该生成列表中。
除非某个文档页面明确将其标记为公开内容,否则请将它们视为实现细节 / 兼容性 surface。
保留的内置插件辅助子路径仍会出现在该生成列表中。除非某个文档页面明确将其作为公共接口推广,否则应将它们视为实现细节 / 兼容性接口。
### 插件入口点
@ -76,7 +67,7 @@ SDK 子路径,而核心在确实存在跨渠道需求时,应使用这些插
| `plugin-sdk/setup-runtime` | `createPatchedAccountSetupAdapter`、`createEnvPatchedAccountSetupAdapter`、`createSetupInputPresenceValidator`、`noteChannelLookupFailure`、`noteChannelLookupSummary`、`promptResolvedAllowFrom`、`splitSetupEntries`、`createAllowlistSetupWizardProxy`、`createDelegatedSetupWizardProxy` |
| `plugin-sdk/setup-adapter-runtime` | `createEnvPatchedAccountSetupAdapter` |
| `plugin-sdk/setup-tools` | `formatCliCommand`、`detectBinary`、`extractArchive`、`resolveBrewExecutable`、`formatDocsLink`、`CONFIG_DIR` |
| `plugin-sdk/account-core` | 多账户 config / action-gate 辅助函数、默认账户回退辅助函数 |
| `plugin-sdk/account-core` | 多账户配置 / action-gate 辅助函数、默认账户回退辅助函数 |
| `plugin-sdk/account-id` | `DEFAULT_ACCOUNT_ID`、account-id 规范化辅助函数 |
| `plugin-sdk/account-resolution` | 账户查找 + 默认回退辅助函数 |
| `plugin-sdk/account-helpers` | 狭义的账户列表 / 账户操作辅助函数 |
@ -84,39 +75,39 @@ SDK 子路径,而核心在确实存在跨渠道需求时,应使用这些插
| `plugin-sdk/channel-reply-pipeline` | `createChannelReplyPipeline` |
| `plugin-sdk/channel-config-helpers` | `createHybridChannelConfigAdapter` |
| `plugin-sdk/channel-config-schema` | 渠道配置 schema 类型 |
| `plugin-sdk/telegram-command-config` | Telegram 自定义命令规范化 / 验证辅助函数,带有内置契约回退 |
| `plugin-sdk/command-gating` | 狭义命令授权 gate 辅助函数 |
| `plugin-sdk/telegram-command-config` | Telegram 自定义命令规范化 / 验证辅助函数,带有内置契约回退 |
| `plugin-sdk/command-gating` | 狭义命令授权门控辅助函数 |
| `plugin-sdk/channel-policy` | `resolveChannelGroupRequireMention` |
| `plugin-sdk/channel-lifecycle` | `createAccountStatusSink` |
| `plugin-sdk/inbound-envelope` | 共享入站路由 + envelope 构建辅助函数 |
| `plugin-sdk/inbound-reply-dispatch` | 共享入站记录与分发辅助函数 |
| `plugin-sdk/messaging-targets` | 目标解析 / 匹配辅助函数 |
| `plugin-sdk/outbound-media` | 共享出站媒体加载辅助函数 |
| `plugin-sdk/outbound-runtime` | 出站身份、发送委托和载规划辅助函数 |
| `plugin-sdk/outbound-runtime` | 出站身份、发送委托和载规划辅助函数 |
| `plugin-sdk/poll-runtime` | 狭义投票规范化辅助函数 |
| `plugin-sdk/thread-bindings-runtime` | 线程绑定生命周期和适配器辅助函数 |
| `plugin-sdk/agent-media-payload` | 旧版智能体媒体载构建器 |
| `plugin-sdk/conversation-runtime` | 话 / 线程绑定、配对和已配置绑定辅助函数 |
| `plugin-sdk/agent-media-payload` | 旧版智能体媒体载构建器 |
| `plugin-sdk/conversation-runtime` | 话 / 线程绑定、配对和已配置绑定辅助函数 |
| `plugin-sdk/runtime-config-snapshot` | 运行时配置快照辅助函数 |
| `plugin-sdk/runtime-group-policy` | 运行时群组策略解析辅助函数 |
| `plugin-sdk/channel-status` | 共享渠道状态快照 / 摘要辅助函数 |
| `plugin-sdk/channel-config-primitives` | 狭义渠道配置 schema 基元 |
| `plugin-sdk/channel-config-writes` | 渠道配置写入授权辅助函数 |
| `plugin-sdk/channel-plugin-common` | 共享渠道插件序言导出 |
| `plugin-sdk/channel-plugin-common` | 共享渠道插件前导导出 |
| `plugin-sdk/allowlist-config-edit` | allowlist 配置编辑 / 读取辅助函数 |
| `plugin-sdk/group-access` | 共享群组访问决策辅助函数 |
| `plugin-sdk/direct-dm` | 共享直接私信认证 / 守卫辅助函数 |
| `plugin-sdk/interactive-runtime` | 交互式回复载荷规范化 / 归约辅助函数 |
| `plugin-sdk/channel-inbound` | 入站去抖动、提及匹配、提及策略辅助函数和 envelope 辅助函数的兼容性 barrel |
| `plugin-sdk/channel-mention-gating` | 不包含更广泛入站运行时 surface 的狭义提及策略辅助函数 |
| `plugin-sdk/interactive-runtime` | 语义化消息呈现、投递和旧版交互式回复辅助函数。请参阅 [消息呈现](/zh-CN/plugins/message-presentation) |
| `plugin-sdk/channel-inbound` | 用于入站去抖动、提及匹配、提及策略辅助函数和 envelope 辅助函数的兼容性 barrel |
| `plugin-sdk/channel-mention-gating` | 不包含更广泛入站运行时表面的狭义提及策略辅助函数 |
| `plugin-sdk/channel-location` | 渠道位置上下文和格式化辅助函数 |
| `plugin-sdk/channel-logging` | 用于入站丢弃和 typing / ack 失败的渠道日志辅助函数 |
| `plugin-sdk/channel-send-result` | 回复结果类型 |
| `plugin-sdk/channel-actions` | `createMessageToolButtonsSchema`、`createMessageToolCardSchema` |
| `plugin-sdk/channel-actions` | 渠道消息操作辅助函数,以及为插件兼容性保留的已弃用原生 schema 辅助函数 |
| `plugin-sdk/channel-targets` | 目标解析 / 匹配辅助函数 |
| `plugin-sdk/channel-contract` | 渠道契约类型 |
| `plugin-sdk/channel-feedback` | 反馈 / reaction 接线 |
| `plugin-sdk/channel-secret-runtime` | 狭义 secret 契约辅助函数,例如 `collectSimpleChannelFieldAssignments`、`getChannelSurface`、`pushAssignment` secret target 类型 |
| `plugin-sdk/channel-secret-runtime` | 狭义 secret 契约辅助函数,例如 `collectSimpleChannelFieldAssignments`、`getChannelSurface`、`pushAssignment` 以及 secret target 类型 |
</Accordion>
<Accordion title="提供商子路径">
@ -124,120 +115,120 @@ SDK 子路径,而核心在确实存在跨渠道需求时,应使用这些插
| --- | --- |
| `plugin-sdk/provider-entry` | `defineSingleProviderPluginEntry` |
| `plugin-sdk/provider-setup` | 精选的本地 / 自托管提供商设置辅助函数 |
| `plugin-sdk/self-hosted-provider-setup` | 专注于 OpenAI 兼容自托管提供商的设置辅助函数 |
| `plugin-sdk/self-hosted-provider-setup` | 面向 OpenAI 兼容自托管提供商设置的聚焦辅助函数 |
| `plugin-sdk/cli-backend` | CLI 后端默认值 + watchdog 常量 |
| `plugin-sdk/provider-auth-runtime` | 提供商插件的运行时 API 密钥解析辅助函数 |
| `plugin-sdk/provider-auth-api-key` | API 密钥新手引导 / profile 写入辅助函数,例如 `upsertApiKeyProfile` |
| `plugin-sdk/provider-auth-runtime` | 面向提供商插件的运行时 API key 解析辅助函数 |
| `plugin-sdk/provider-auth-api-key` | API key 新手引导 / 配置文件写入辅助函数,例如 `upsertApiKeyProfile` |
| `plugin-sdk/provider-auth-result` | 标准 OAuth 认证结果构建器 |
| `plugin-sdk/provider-auth-login` | 提供商插件共享交互式登录辅助函数 |
| `plugin-sdk/provider-auth-login` | 面向提供商插件共享交互式登录辅助函数 |
| `plugin-sdk/provider-env-vars` | 提供商认证环境变量查找辅助函数 |
| `plugin-sdk/provider-auth` | `createProviderApiKeyAuthMethod`、`ensureApiKeyFromOptionEnvOrPrompt`、`upsertAuthProfile`、`upsertApiKeyProfile`、`writeOAuthCredentials` |
| `plugin-sdk/provider-model-shared` | `ProviderReplayFamily`、`buildProviderReplayFamilyHooks`、`normalizeModelCompat`、共享 replay-policy 构建器、提供商 endpoint 辅助函数,以及模型 ID 规范化辅助函数,例如 `normalizeNativeXaiModelId` |
| `plugin-sdk/provider-model-shared` | `ProviderReplayFamily`、`buildProviderReplayFamilyHooks`、`normalizeModelCompat`、共享 replay-policy 构建器、provider-endpoint 辅助函数,以及诸如 `normalizeNativeXaiModelId` 之类的 model-id 规范化辅助函数 |
| `plugin-sdk/provider-catalog-shared` | `findCatalogTemplate`、`buildSingleProviderApiKeyCatalog`、`supportsNativeStreamingUsageCompat`、`applyProviderNativeStreamingUsageCompat` |
| `plugin-sdk/provider-http` | 通用提供商 HTTP / endpoint 能力辅助函数 |
| `plugin-sdk/provider-web-fetch-contract` | 狭义 web-fetch config / selection 契约辅助函数,例如 `enablePluginInConfig``WebFetchProviderPlugin` |
| `plugin-sdk/provider-http` | 通用提供商 HTTP / endpoint capability 辅助函数 |
| `plugin-sdk/provider-web-fetch-contract` | 狭义 web-fetch 配置 / 选择契约辅助函数,例如 `enablePluginInConfig``WebFetchProviderPlugin` |
| `plugin-sdk/provider-web-fetch` | web-fetch 提供商注册 / 缓存辅助函数 |
| `plugin-sdk/provider-web-search-config-contract` | 适用于不需要插件启用接线的提供商的狭义 web-search config / credential 辅助函数 |
| `plugin-sdk/provider-web-search-contract` | 狭义 web-search config / credential 契约辅助函数,例如 `createWebSearchProviderContractFields`、`enablePluginInConfig`、`resolveProviderWebSearchPluginConfig` 以及有作用域的 credential setter / getter |
| `plugin-sdk/provider-web-search-config-contract` | 面向不需要插件启用接线的提供商的狭义 web-search 配置 / 凭证辅助函数 |
| `plugin-sdk/provider-web-search-contract` | 狭义 web-search 配置 / 凭证契约辅助函数,例如 `createWebSearchProviderContractFields`、`enablePluginInConfig`、`resolveProviderWebSearchPluginConfig` 以及有作用域的凭证 setter / getter |
| `plugin-sdk/provider-web-search` | web-search 提供商注册 / 缓存 / 运行时辅助函数 |
| `plugin-sdk/provider-tools` | `ProviderToolCompatFamily`、`buildProviderToolCompatFamilyHooks`、Gemini schema 清理 + diagnostics以及 xAI 兼容辅助函数,例`resolveXaiModelCompatPatch` / `applyXaiModelCompat` |
| `plugin-sdk/provider-usage` | `fetchClaudeUsage` |
| `plugin-sdk/provider-stream` | `ProviderStreamFamily`、`buildProviderStreamFamilyHooks`、`composeProviderStreamWrappers`、流包装器类型,以及共享 Anthropic / Bedrock / Google / Kilocode / Moonshot / OpenAI / OpenRouter / Z.A.I / MiniMax / Copilot 包装器辅助函数 |
| `plugin-sdk/provider-transport-runtime` | 原生提供商传输辅助函数,例如受保护的 fetch、传输消息转换和可写传输事件流 |
| `plugin-sdk/provider-tools` | `ProviderToolCompatFamily`、`buildProviderToolCompatFamilyHooks`、Gemini schema 清理 + diagnostics以及`resolveXaiModelCompatPatch` / `applyXaiModelCompat` 之类的 xAI 兼容辅助函数 |
| `plugin-sdk/provider-usage` | `fetchClaudeUsage` 及类似项 |
| `plugin-sdk/provider-stream` | `ProviderStreamFamily`、`buildProviderStreamFamilyHooks`、`composeProviderStreamWrappers`、流包装器类型,以及共享 Anthropic / Bedrock / Google / Kilocode / Moonshot / OpenAI / OpenRouter / Z.A.I / MiniMax / Copilot 包装器辅助函数 |
| `plugin-sdk/provider-transport-runtime` | 原生提供商传输辅助函数,例如 guarded fetch、transport message transforms 和可写 transport event streams |
| `plugin-sdk/provider-onboard` | 新手引导配置补丁辅助函数 |
| `plugin-sdk/global-singleton` | 进程本地 singleton / map / cache 辅助函数 |
</Accordion>
<Accordion title="认证安全子路径">
<Accordion title="认证安全子路径">
| 子路径 | 关键导出 |
| --- | --- |
| `plugin-sdk/command-auth` | `resolveControlCommandGate`、命令注册表辅助函数、发送者授权辅助函数 |
| `plugin-sdk/command-status` | 命令 / 帮助消息构建器,例如 `buildCommandsMessagePaginated``buildHelpMessage` |
| `plugin-sdk/approval-auth-runtime` | 审批人解析和同聊天 action-auth 辅助函数 |
| `plugin-sdk/approval-client-runtime` | 原生 exec 审批 profile / filter 辅助函数 |
| `plugin-sdk/approval-delivery-runtime` | 原生审批能力 / 传递适配器 |
| `plugin-sdk/approval-gateway-runtime` | 共享审批 Gateway 网关解析辅助函数 |
| `plugin-sdk/approval-handler-adapter-runtime` | 用于热渠道入口点的轻量级原生审批适配器加载辅助函数 |
| `plugin-sdk/approval-handler-runtime` | 更广泛的审批处理器运行时辅助函数;如果更狭义的 adapter / gateway seam 已足够,优先使用它们 |
| `plugin-sdk/approval-native-runtime` | 原生审批目标 + 账户绑定辅助函数 |
| `plugin-sdk/approval-reply-runtime` | exec / 插件审批回复载荷辅助函数 |
| `plugin-sdk/command-auth-native` | 原生命令认证 + 原生会话目标辅助函数 |
| `plugin-sdk/approval-auth-runtime` | approver 解析和同聊天 action-auth 辅助函数 |
| `plugin-sdk/approval-client-runtime` | 原生 exec approval 配置文件 / 过滤器辅助函数 |
| `plugin-sdk/approval-delivery-runtime` | 原生 approval capability / delivery 适配器 |
| `plugin-sdk/approval-gateway-runtime` | 共享 approval Gateway 网关解析辅助函数 |
| `plugin-sdk/approval-handler-adapter-runtime` | 面向热渠道入口点的轻量级原生 approval adapter 加载辅助函数 |
| `plugin-sdk/approval-handler-runtime` | 更广泛的 approval handler 运行时辅助函数;如果更狭义的 adapter / gateway 接口已足够,优先使用它们 |
| `plugin-sdk/approval-native-runtime` | 原生 approval target + account-binding 辅助函数 |
| `plugin-sdk/approval-reply-runtime` | exec / plugin approval 回复负载辅助函数 |
| `plugin-sdk/command-auth-native` | 原生命令认证 + 原生 session-target 辅助函数 |
| `plugin-sdk/command-detection` | 共享命令检测辅助函数 |
| `plugin-sdk/command-surface` | 命令体规范化和命令 surface 辅助函数 |
| `plugin-sdk/command-surface` | 命令体规范化和 command-surface 辅助函数 |
| `plugin-sdk/allow-from` | `formatAllowFromLowercase` |
| `plugin-sdk/channel-secret-runtime` | 用于渠道 / 插件 secret surface 的狭义 secret 契约收集辅助函数 |
| `plugin-sdk/secret-ref-runtime` | 用于 secret 契约 / 配置解析的狭义 `coerceSecretRef` 和 SecretRef 类型辅助函数 |
| `plugin-sdk/channel-secret-runtime` | 面向渠道 / 插件 secret surface 的狭义 secret-contract 收集辅助函数 |
| `plugin-sdk/secret-ref-runtime` | 用于 secret-contract / 配置解析的狭义 `coerceSecretRef` 和 SecretRef 类型辅助函数 |
| `plugin-sdk/security-runtime` | 共享信任、私信门控、外部内容和 secret 收集辅助函数 |
| `plugin-sdk/ssrf-policy` | 主机 allowlist 和私有网络 SSRF 策略辅助函数 |
| `plugin-sdk/ssrf-dispatcher` | 不含广泛基础设施运行时 surface 的狭义 pinned-dispatcher 辅助函数 |
| `plugin-sdk/ssrf-runtime` | pinned-dispatcher、受 SSRF 保护的 fetch 和 SSRF 策略辅助函数 |
| `plugin-sdk/ssrf-dispatcher` | 不包含广泛基础设施运行时表面的狭义 pinned-dispatcher 辅助函数 |
| `plugin-sdk/ssrf-runtime` | pinned-dispatcher、SSRF 防护 fetch 和 SSRF 策略辅助函数 |
| `plugin-sdk/secret-input` | secret 输入解析辅助函数 |
| `plugin-sdk/webhook-ingress` | Webhook 请求 / 目标辅助函数 |
| `plugin-sdk/webhook-ingress` | webhook 请求 / target 辅助函数 |
| `plugin-sdk/webhook-request-guards` | 请求体大小 / 超时辅助函数 |
</Accordion>
<Accordion title="运行时存储子路径">
<Accordion title="运行时存储子路径">
| 子路径 | 关键导出 |
| --- | --- |
| `plugin-sdk/runtime` | 广泛的运行时 / 日志 / 备份 / 插件安装辅助函数 |
| `plugin-sdk/runtime-env` | 狭义运行时环境、logger、超时、重试和退避辅助函数 |
| `plugin-sdk/channel-runtime-context` | 通用渠道运行时上下文注册和查找辅助函数 |
| `plugin-sdk/runtime-env` | 狭义运行时 env、logger、timeout、retry 和 backoff 辅助函数 |
| `plugin-sdk/channel-runtime-context` | 通用渠道 runtime-context 注册和查找辅助函数 |
| `plugin-sdk/runtime-store` | `createPluginRuntimeStore` |
| `plugin-sdk/plugin-runtime` | 共享插件命令 / hook / HTTP / 交互式辅助函数 |
| `plugin-sdk/hook-runtime` | 共享 webhook / 内部 hook 管道辅助函数 |
| `plugin-sdk/plugin-runtime` | 共享插件命令 / hook / http / interactive 辅助函数 |
| `plugin-sdk/hook-runtime` | 共享 webhook / 内部 hook pipeline 辅助函数 |
| `plugin-sdk/lazy-runtime` | 延迟运行时导入 / 绑定辅助函数,例如 `createLazyRuntimeModule`、`createLazyRuntimeMethod` 和 `createLazyRuntimeSurface` |
| `plugin-sdk/process-runtime` | 进程 exec 辅助函数 |
| `plugin-sdk/cli-runtime` | CLI 格式化、等待和版本辅助函数 |
| `plugin-sdk/gateway-runtime` | Gateway 网关客户端和渠道状态补丁辅助函数 |
| `plugin-sdk/config-runtime` | 配置加载 / 写入辅助函数 |
| `plugin-sdk/telegram-command-config` | Telegram 命令名称 / 描述规范化及重复 / 冲突检查,即使内置 Telegram 契约 surface 不可用时也是如此 |
| `plugin-sdk/text-autolink-runtime` | 不含广泛 text-runtime barrel 的文件引用自动链接检测 |
| `plugin-sdk/approval-runtime` | exec / 插件审批辅助函数、审批能力构建器、认证 / profile 辅助函数、原生路由 / 运行时辅助函数 |
| `plugin-sdk/reply-runtime` | 共享入站 / 回复运行时辅助函数、分块、分发、心跳、回复规划器 |
| `plugin-sdk/reply-dispatch-runtime` | 狭义回复分发 / 完成辅助函数 |
| `plugin-sdk/reply-history` | 共享短窗口回复历史辅助函数,例如 `buildHistoryContext`、`recordPendingHistoryEntry` 和 `clearHistoryEntriesIfEnabled` |
| `plugin-sdk/telegram-command-config` | Telegram 命令名称 / 描述规范化及重复 / 冲突检查,即使内置 Telegram 契约接口不可用时也可使用 |
| `plugin-sdk/text-autolink-runtime` | 不依赖广泛 `text-runtime` barrel 的文件引用自动链接检测 |
| `plugin-sdk/approval-runtime` | exec / plugin approval 辅助函数、approval-capability 构建器、认证 / 配置文件辅助函数、原生路由 / 运行时辅助函数 |
| `plugin-sdk/reply-runtime` | 共享入站 / 回复运行时辅助函数、chunking、dispatch、heartbeat、reply planner |
| `plugin-sdk/reply-dispatch-runtime` | 狭义回复 dispatch / finalize 辅助函数 |
| `plugin-sdk/reply-history` | 共享短窗口 reply-history 辅助函数,例如 `buildHistoryContext`、`recordPendingHistoryEntry` 和 `clearHistoryEntriesIfEnabled` |
| `plugin-sdk/reply-reference` | `createReplyReferencePlanner` |
| `plugin-sdk/reply-chunking` | 狭义文本 / Markdown 分块辅助函数 |
| `plugin-sdk/session-store-runtime` | 会话存储路径 + updated-at 辅助函数 |
| `plugin-sdk/state-paths` | 状态 / OAuth 目录路径辅助函数 |
| `plugin-sdk/routing` | 路由 / 会话键 / 账户绑定辅助函数,例如 `resolveAgentRoute`、`buildAgentSessionKey` 和 `resolveDefaultAgentBoundAccountId` |
| `plugin-sdk/status-helpers` | 共享渠道 / 账户状态摘要辅助函数、运行时状态默认值和问题元数据辅助函数 |
| `plugin-sdk/reply-chunking` | 狭义文本 / Markdown chunking 辅助函数 |
| `plugin-sdk/session-store-runtime` | 会话存储路径 + `updated-at` 辅助函数 |
| `plugin-sdk/state-paths` | state / OAuth 目录路径辅助函数 |
| `plugin-sdk/routing` | 路由 / session-key / account 绑定辅助函数,例如 `resolveAgentRoute`、`buildAgentSessionKey` 和 `resolveDefaultAgentBoundAccountId` |
| `plugin-sdk/status-helpers` | 共享渠道 / 账户状态摘要辅助函数、运行时状态默认值和 issue 元数据辅助函数 |
| `plugin-sdk/target-resolver-runtime` | 共享目标解析器辅助函数 |
| `plugin-sdk/string-normalization-runtime` | slug / 字符串规范化辅助函数 |
| `plugin-sdk/request-url` | 从 fetch / 类请求输入中提取字符串 URL |
| `plugin-sdk/run-command` | 带计时功能的命令运行器,输出规范化的 stdout / stderr 结果 |
| `plugin-sdk/param-readers` | 用工具 / CLI 参数读取器 |
| `plugin-sdk/tool-payload` | 从工具结果对象中提取规范化载荷 |
| `plugin-sdk/tool-send` | 从工具参数中提取规范发送目标字段 |
| `plugin-sdk/request-url` | 从 fetch / request 类输入中提取字符串 URL |
| `plugin-sdk/run-command` | 带计时的命令运行器,输出规范化的 stdout / stderr 结果 |
| `plugin-sdk/param-readers` | 用工具 / CLI 参数读取器 |
| `plugin-sdk/tool-payload` | 从工具结果对象中提取规范化 payload |
| `plugin-sdk/tool-send` | 从工具参数中提取规范发送目标字段 |
| `plugin-sdk/temp-path` | 共享临时下载路径辅助函数 |
| `plugin-sdk/logging-core` | 子系统 logger 和脱敏辅助函数 |
| `plugin-sdk/markdown-table-runtime` | Markdown 表格模式辅助函数 |
| `plugin-sdk/json-store` | 小型 JSON 状态读取 / 写入辅助函数 |
| `plugin-sdk/file-lock` | 可重入文件锁辅助函数 |
| `plugin-sdk/persistent-dedupe` | 基于磁盘的去重缓存辅助函数 |
| `plugin-sdk/acp-runtime` | ACP 运行时 / 会话和回复分发辅助函数 |
| `plugin-sdk/acp-binding-resolve-runtime` | 不生命周期启动导入的只读 ACP 绑定解析 |
| `plugin-sdk/agent-config-primitives` | 狭义智能体运行时配置 schema 基元 |
| `plugin-sdk/persistent-dedupe` | 磁盘支持的去重缓存辅助函数 |
| `plugin-sdk/acp-runtime` | ACP 运行时 / 会话和 reply-dispatch 辅助函数 |
| `plugin-sdk/acp-binding-resolve-runtime` | 不引入生命周期启动导入的只读 ACP 绑定解析 |
| `plugin-sdk/agent-config-primitives` | 狭义智能体运行时 config-schema 基元 |
| `plugin-sdk/boolean-param` | 宽松布尔参数读取器 |
| `plugin-sdk/dangerous-name-runtime` | 危险名称匹配解析辅助函数 |
| `plugin-sdk/device-bootstrap` | 设备引导和配对令牌辅助函数 |
| `plugin-sdk/device-bootstrap` | 设备 bootstrap 和配对 token 辅助函数 |
| `plugin-sdk/extension-shared` | 共享被动渠道、状态和环境代理辅助基元 |
| `plugin-sdk/models-provider-runtime` | `/models` 命令 / 提供商回复辅助函数 |
| `plugin-sdk/skill-commands-runtime` | Skills 命令列表辅助函数 |
| `plugin-sdk/native-command-registry` | 原生命令注册表 / 构建 / 序列化辅助函数 |
| `plugin-sdk/agent-harness` | 用于底层智能体 harness 的实验性受信任插件 surfaceharness 类型、活跃运行 steer / abort 辅助函数、OpenClaw 工具桥接辅助函数和尝试结果工具 |
| `plugin-sdk/agent-harness` | 面向低层智能体 harness 的实验性受信任插件接口harness 类型、active-run steer / abort 辅助函数、OpenClaw 工具桥接辅助函数和 attempt result 工具 |
| `plugin-sdk/provider-zai-endpoint` | Z.A.I endpoint 检测辅助函数 |
| `plugin-sdk/infra-runtime` | 系统事件 / 心跳辅助函数 |
| `plugin-sdk/infra-runtime` | 系统事件 / heartbeat 辅助函数 |
| `plugin-sdk/collection-runtime` | 小型有界缓存辅助函数 |
| `plugin-sdk/diagnostic-runtime` | 诊断标志和事件辅助函数 |
| `plugin-sdk/diagnostic-runtime` | diagnostic 标志和事件辅助函数 |
| `plugin-sdk/error-runtime` | 错误图、格式化、共享错误分类辅助函数、`isApprovalNotFoundError` |
| `plugin-sdk/fetch-runtime` | 封装的 fetch、代理和固定查找辅助函数 |
| `plugin-sdk/runtime-fetch` | 不含代理 / 受保护 fetch 导入的、感知 dispatcher 的运行时 fetch |
| `plugin-sdk/response-limit-runtime` | 不含广泛媒体运行时 surface 的有界响应体读取器 |
| `plugin-sdk/session-binding-runtime` | 不含已配置绑定路由或配对存储的当前会话绑定状态 |
| `plugin-sdk/session-store-runtime` | 不广泛配置写入 / 维护导入的会话存储读取辅助函数 |
| `plugin-sdk/context-visibility-runtime` | 不含广泛配置 / 安全导入的上下文可见性解析和补充上下文过滤 |
| `plugin-sdk/string-coerce-runtime` | 不含 Markdown / 日志导入的狭义基础记录 / 字符串强制转换和规范化辅助函数 |
| `plugin-sdk/fetch-runtime` | 封装的 fetch、proxy 和 pinned 查找辅助函数 |
| `plugin-sdk/runtime-fetch` | 具备 dispatcher 感知的运行时 fetch不引入 proxy / guarded-fetch 导入 |
| `plugin-sdk/response-limit-runtime` | 有界响应体读取器,不依赖广泛媒体运行时表面 |
| `plugin-sdk/session-binding-runtime` | 当前对话绑定状态,含已配置绑定路由或配对存储 |
| `plugin-sdk/session-store-runtime` | 不引入广泛配置写入 / 维护导入的会话存储读取辅助函数 |
| `plugin-sdk/context-visibility-runtime` | 上下文可见性解析和补充上下文过滤,不引入广泛配置 / 安全导入 |
| `plugin-sdk/string-coerce-runtime` | 狭义原始记录 / 字符串强制转换和规范化辅助函数,不引入 markdown / logging 导入 |
| `plugin-sdk/host-runtime` | 主机名和 SCP 主机规范化辅助函数 |
| `plugin-sdk/retry-runtime` | 重试配置和重试运行器辅助函数 |
| `plugin-sdk/agent-runtime` | 智能体目录 / 身份 / 工作区辅助函数 |
@ -245,26 +236,26 @@ SDK 子路径,而核心在确实存在跨渠道需求时,应使用这些插
| `plugin-sdk/keyed-async-queue` | `KeyedAsyncQueue` |
</Accordion>
<Accordion title="能力测试子路径">
<Accordion title="能力测试子路径">
| 子路径 | 关键导出 |
| --- | --- |
| `plugin-sdk/media-runtime` | 共享媒体获取 / 转换 / 存储辅助函数,以及媒体载构建器 |
| `plugin-sdk/media-generation-runtime` | 共享媒体生成故障切换辅助函数、候选项选择和缺失模型消息 |
| `plugin-sdk/media-runtime` | 共享媒体获取 / 转换 / 存储辅助函数,以及媒体载构建器 |
| `plugin-sdk/media-generation-runtime` | 共享媒体生成故障转移辅助函数、候选项选择和缺失模型消息 |
| `plugin-sdk/media-understanding` | 媒体理解提供商类型,以及面向提供商的图像 / 音频辅助导出 |
| `plugin-sdk/text-runtime` | 共享文本 / Markdown / 日志辅助函数,例如 assistant-visible-text 剥离、Markdown 渲染 / 分块 / 表格辅助函数、脱敏辅助函数、directive-tag 辅助函数和安全文本工具 |
| `plugin-sdk/text-chunking` | 出站文本分块辅助函数 |
| `plugin-sdk/speech` | 语音提供商类型,以及面向提供商的指令、注册表和验证辅助函数 |
| `plugin-sdk/speech-core` | 共享语音提供商类型、注册表、指令和规范化辅助函数 |
| `plugin-sdk/text-runtime` | 共享文本 / Markdown / 日志辅助函数,例如对智能体可见文本剥离、Markdown 渲染 / chunking / 表格辅助函数、脱敏辅助函数、directive-tag 辅助函数和安全文本工具 |
| `plugin-sdk/text-chunking` | 出站文本 chunking 辅助函数 |
| `plugin-sdk/speech` | 语音提供商类型,以及面向提供商的 directive、注册表和验证辅助函数 |
| `plugin-sdk/speech-core` | 共享语音提供商类型、注册表、directive 和规范化辅助函数 |
| `plugin-sdk/realtime-transcription` | 实时转录提供商类型和注册表辅助函数 |
| `plugin-sdk/realtime-voice` | 实时语音提供商类型和注册表辅助函数 |
| `plugin-sdk/image-generation` | 图像生成提供商类型 |
| `plugin-sdk/image-generation-core` | 共享图像生成类型、故障切换、认证和注册表辅助函数 |
| `plugin-sdk/image-generation-core` | 共享图像生成类型、故障转移、认证和注册表辅助函数 |
| `plugin-sdk/music-generation` | 音乐生成提供商 / 请求 / 结果类型 |
| `plugin-sdk/music-generation-core` | 共享音乐生成类型、故障切换辅助函数、提供商查找和 model-ref 解析 |
| `plugin-sdk/music-generation-core` | 共享音乐生成类型、故障转移辅助函数、提供商查找和 model-ref 解析 |
| `plugin-sdk/video-generation` | 视频生成提供商 / 请求 / 结果类型 |
| `plugin-sdk/video-generation-core` | 共享视频生成类型、故障切换辅助函数、提供商查找和 model-ref 解析 |
| `plugin-sdk/webhook-targets` | Webhook 目标注册表和路由安装辅助函数 |
| `plugin-sdk/webhook-path` | Webhook 路径规范化辅助函数 |
| `plugin-sdk/video-generation-core` | 共享视频生成类型、故障转移辅助函数、提供商查找和 model-ref 解析 |
| `plugin-sdk/webhook-targets` | webhook target 注册表和路由安装辅助函数 |
| `plugin-sdk/webhook-path` | webhook 路径规范化辅助函数 |
| `plugin-sdk/web-media` | 共享远程 / 本地媒体加载辅助函数 |
| `plugin-sdk/zod` | 为插件 SDK 使用者重新导出的 `zod` |
| `plugin-sdk/testing` | `installCommonResolveTargetErrorCases`、`shouldAckReaction` |
@ -273,38 +264,38 @@ SDK 子路径,而核心在确实存在跨渠道需求时,应使用这些插
<Accordion title="Memory 子路径">
| 子路径 | 关键导出 |
| --- | --- |
| `plugin-sdk/memory-core` | 用于管理器 / 配置 / 文件 / CLI 辅助函数的内置 memory-core helper surface |
| `plugin-sdk/memory-core` | 用于 manager / config / file / CLI 辅助函数的内置 memory-core 辅助接口 |
| `plugin-sdk/memory-core-engine-runtime` | Memory 索引 / 搜索运行时 facade |
| `plugin-sdk/memory-core-host-engine-foundation` | Memory host foundation engine 导出 |
| `plugin-sdk/memory-core-host-engine-embeddings` | Memory host embedding 契约、注册表访问、本地提供商以及通用批处理 / 远程辅助函数 |
| `plugin-sdk/memory-core-host-engine-embeddings` | Memory host embedding 契约、注册表访问、本地 provider 以及通用 batch / remote 辅助函数 |
| `plugin-sdk/memory-core-host-engine-qmd` | Memory host QMD engine 导出 |
| `plugin-sdk/memory-core-host-engine-storage` | Memory host storage engine 导出 |
| `plugin-sdk/memory-core-host-multimodal` | Memory host 多模态辅助函数 |
| `plugin-sdk/memory-core-host-query` | Memory host 查询辅助函数 |
| `plugin-sdk/memory-core-host-multimodal` | Memory host multimodal 辅助函数 |
| `plugin-sdk/memory-core-host-query` | Memory host query 辅助函数 |
| `plugin-sdk/memory-core-host-secret` | Memory host secret 辅助函数 |
| `plugin-sdk/memory-core-host-events` | Memory host 事件日志辅助函数 |
| `plugin-sdk/memory-core-host-status` | Memory host 状态辅助函数 |
| `plugin-sdk/memory-core-host-events` | Memory host event journal 辅助函数 |
| `plugin-sdk/memory-core-host-status` | Memory host status 辅助函数 |
| `plugin-sdk/memory-core-host-runtime-cli` | Memory host CLI 运行时辅助函数 |
| `plugin-sdk/memory-core-host-runtime-core` | Memory host 核心运行时辅助函数 |
| `plugin-sdk/memory-core-host-runtime-files` | Memory host 文件 / 运行时辅助函数 |
| `plugin-sdk/memory-host-core` | Memory host 核心运行时辅助函数的供应商中立别名 |
| `plugin-sdk/memory-host-events` | Memory host 事件日志辅助函数的供应商中立别名 |
| `plugin-sdk/memory-host-files` | Memory host 文件 / 运行时辅助函数的供应商中立别名 |
| `plugin-sdk/memory-host-markdown` | 用于 memory 相邻插件的共享托管 Markdown 辅助函数 |
| `plugin-sdk/memory-host-search` | 用于访问 search-manager 的活动 Memory 运行时 facade |
| `plugin-sdk/memory-host-status` | Memory host 状态辅助函数的供应商中立别名 |
| `plugin-sdk/memory-lancedb` | 内置 memory-lancedb helper surface |
| `plugin-sdk/memory-host-core` | memory host 核心运行时辅助函数的供应商中立别名 |
| `plugin-sdk/memory-host-events` | memory host event journal 辅助函数的供应商中立别名 |
| `plugin-sdk/memory-host-files` | memory host 文件 / 运行时辅助函数的供应商中立别名 |
| `plugin-sdk/memory-host-markdown` | 面向 memory 邻近插件的共享 managed-markdown 辅助函数 |
| `plugin-sdk/memory-host-search` | 用于 search-manager 访问的 active Memory 运行时 facade |
| `plugin-sdk/memory-host-status` | memory host status 辅助函数的供应商中立别名 |
| `plugin-sdk/memory-lancedb` | 内置 memory-lancedb 辅助接口 |
</Accordion>
<Accordion title="保留的内置 helper 子路径">
| 类别 | 当前子路径 | 预期用途 |
<Accordion title="保留的内置辅助子路径">
| 系列 | 当前子路径 | 预期用途 |
| --- | --- | --- |
| Browser | `plugin-sdk/browser-cdp`, `plugin-sdk/browser-config-runtime`, `plugin-sdk/browser-config-support`, `plugin-sdk/browser-control-auth`, `plugin-sdk/browser-node-runtime`, `plugin-sdk/browser-profiles`, `plugin-sdk/browser-security-runtime`, `plugin-sdk/browser-setup-tools`, `plugin-sdk/browser-support` | 内置浏览器插件支持辅助函数(`browser-support` 仍是兼容性 barrel |
| Matrix | `plugin-sdk/matrix`, `plugin-sdk/matrix-helper`, `plugin-sdk/matrix-runtime-heavy`, `plugin-sdk/matrix-runtime-shared`, `plugin-sdk/matrix-runtime-surface`, `plugin-sdk/matrix-surface`, `plugin-sdk/matrix-thread-bindings` | 内置 Matrix helper / 运行时 surface |
| Line | `plugin-sdk/line`, `plugin-sdk/line-core`, `plugin-sdk/line-runtime`, `plugin-sdk/line-surface` | 内置 LINE helper / 运行时 surface |
| IRC | `plugin-sdk/irc`, `plugin-sdk/irc-surface` | 内置 IRC helper surface |
| 渠道特定辅助函数 | `plugin-sdk/googlechat`, `plugin-sdk/zalouser`, `plugin-sdk/bluebubbles`, `plugin-sdk/bluebubbles-policy`, `plugin-sdk/mattermost`, `plugin-sdk/mattermost-policy`, `plugin-sdk/feishu-conversation`, `plugin-sdk/msteams`, `plugin-sdk/nextcloud-talk`, `plugin-sdk/nostr`, `plugin-sdk/tlon`, `plugin-sdk/twitch` | 内置渠道兼容性 / helper seams |
| 认证 / 插件特定辅助函数 | `plugin-sdk/github-copilot-login`, `plugin-sdk/github-copilot-token`, `plugin-sdk/diagnostics-otel`, `plugin-sdk/diffs`, `plugin-sdk/llm-task`, `plugin-sdk/thread-ownership`, `plugin-sdk/voice-call` | 内置功能 / 插件 helper seams`plugin-sdk/github-copilot-token` 当前导出 `DEFAULT_COPILOT_API_BASE_URL`、`deriveCopilotApiBaseUrlFromToken` 和 `resolveCopilotApiToken` |
| Browser | `plugin-sdk/browser-cdp`, `plugin-sdk/browser-config-runtime`, `plugin-sdk/browser-config-support`, `plugin-sdk/browser-control-auth`, `plugin-sdk/browser-node-runtime`, `plugin-sdk/browser-profiles`, `plugin-sdk/browser-security-runtime`, `plugin-sdk/browser-setup-tools`, `plugin-sdk/browser-support` | 内置 Browser 插件支持辅助函数(`browser-support` 仍是兼容性 barrel |
| Matrix | `plugin-sdk/matrix`, `plugin-sdk/matrix-helper`, `plugin-sdk/matrix-runtime-heavy`, `plugin-sdk/matrix-runtime-shared`, `plugin-sdk/matrix-runtime-surface`, `plugin-sdk/matrix-surface`, `plugin-sdk/matrix-thread-bindings` | 内置 Matrix 辅助 / 运行时接口 |
| Line | `plugin-sdk/line`, `plugin-sdk/line-core`, `plugin-sdk/line-runtime`, `plugin-sdk/line-surface` | 内置 LINE 辅助 / 运行时接口 |
| IRC | `plugin-sdk/irc`, `plugin-sdk/irc-surface` | 内置 IRC 辅助接口 |
| 特定于渠道的辅助函数 | `plugin-sdk/googlechat`, `plugin-sdk/zalouser`, `plugin-sdk/bluebubbles`, `plugin-sdk/bluebubbles-policy`, `plugin-sdk/mattermost`, `plugin-sdk/mattermost-policy`, `plugin-sdk/feishu-conversation`, `plugin-sdk/msteams`, `plugin-sdk/nextcloud-talk`, `plugin-sdk/nostr`, `plugin-sdk/tlon`, `plugin-sdk/twitch` | 内置渠道兼容性 / 辅助接口 |
| 认证 / 特定于插件的辅助函数 | `plugin-sdk/github-copilot-login`, `plugin-sdk/github-copilot-token`, `plugin-sdk/diagnostics-otel`, `plugin-sdk/diffs`, `plugin-sdk/llm-task`, `plugin-sdk/thread-ownership`, `plugin-sdk/voice-call` | 内置功能 / 插件辅助接口`plugin-sdk/github-copilot-token` 当前导出 `DEFAULT_COPILOT_API_BASE_URL`、`deriveCopilotApiBaseUrlFromToken` 和 `resolveCopilotApiToken` |
</Accordion>
</AccordionGroup>
@ -314,54 +305,52 @@ SDK 子路径,而核心在确实存在跨渠道需求时,应使用这些插
### 能力注册
| 方法 | 注册内容 |
| 方法 | 注册内容 |
| ------------------------------------------------ | ------------------------------------- |
| `api.registerProvider(...)` | 文本推理LLM |
| `api.registerAgentHarness(...)` | 实验性层智能体执行器 |
| `api.registerAgentHarness(...)` | 实验性的低层智能体执行器 |
| `api.registerCliBackend(...)` | 本地 CLI 推理后端 |
| `api.registerChannel(...)` | 消息渠道 |
| `api.registerSpeechProvider(...)` | 文本转语音 / STT 合成 |
| `api.registerRealtimeTranscriptionProvider(...)` | 流式实时转录 |
| `api.registerRealtimeVoiceProvider(...)` | 双实时语音会话 |
| `api.registerRealtimeVoiceProvider(...)` | 双实时语音会话 |
| `api.registerMediaUnderstandingProvider(...)` | 图像 / 音频 / 视频分析 |
| `api.registerImageGenerationProvider(...)` | 图像生成 |
| `api.registerMusicGenerationProvider(...)` | 音乐生成 |
| `api.registerVideoGenerationProvider(...)` | 视频生成 |
| `api.registerWebFetchProvider(...)` | Web 抓取 / scrape 提供商 |
| `api.registerWebFetchProvider(...)` | Web 获取 / 抓取提供商 |
| `api.registerWebSearchProvider(...)` | Web 搜索 |
### 工具和命令
| 方法 | 注册内容 |
| 方法 | 注册内容 |
| ------------------------------- | --------------------------------------------- |
| `api.registerTool(tool, opts?)` | 智能体工具(必需或 `{ optional: true }` |
| `api.registerCommand(def)` | 自定义命令(绕过 LLM |
### 基础设施
| 方法 | 注册内容 |
| 方法 | 注册内容 |
| ---------------------------------------------- | --------------------------------------- |
| `api.registerHook(events, handler, opts?)` | 事件 hook |
| `api.registerHttpRoute(params)` | Gateway 网关 HTTP endpoint |
| `api.registerHttpRoute(params)` | Gateway 网关 HTTP 端点 |
| `api.registerGatewayMethod(name, handler)` | Gateway 网关 RPC 方法 |
| `api.registerCli(registrar, opts?)` | CLI 子命令 |
| `api.registerService(service)` | 后台服务 |
| `api.registerInteractiveHandler(registration)` | 交互处理器 |
| `api.registerMemoryPromptSupplement(builder)` | 附加的 memory 相邻提示词区段 |
| `api.registerMemoryCorpusSupplement(adapter)` | 附加的 Memory 搜索 / 读取语料库 |
| `api.registerInteractiveHandler(registration)` | 交互处理器 |
| `api.registerMemoryPromptSupplement(builder)` | 追加型 memory 邻近提示部分 |
| `api.registerMemoryCorpusSupplement(adapter)` | 追加型 memory 搜索 / 读取语料库 |
保留的核心管理命名空间(`config.*`、`exec.approvals.*`、`wizard.*`、
`update.*`)始终保持为 `operator.admin`,即使插件尝试为其分配更窄的
Gateway 网关方法作用域也是如此。对于插件自有方法,优先使用插件特定前缀。
保留的核心管理命名空间(`config.*`、`exec.approvals.*`、`wizard.*`、`update.*`)始终保持为 `operator.admin`,即使插件尝试分配更窄的 Gateway 网关方法作用域也是如此。对于插件拥有的方法,优先使用插件特定的前缀。
### CLI 注册元数据
`api.registerCli(registrar, opts?)` 接受两类顶层元数据:
- `commands`:由注册器拥有的显式命令根
- `descriptors`:用于根 CLI 帮助、路由和延迟插件 CLI 注册的解析命令描述符
- `commands`:由 registrar 拥有的显式命令根
- `descriptors`:用于根 CLI 帮助、路由和延迟插件 CLI 注册的解析命令描述符
如果你希望插件命令在正常的根 CLI 路径中保持延迟加载,请提供 `descriptors`,覆盖该注册器公开的每一个顶层命令根
如果你希望插件命令在常规根 CLI 路径中保持延迟加载,请提供覆盖该 registrar 暴露的每个顶层命令根的 `descriptors`
```typescript
api.registerCli(
@ -373,7 +362,7 @@ api.registerCli(
descriptors: [
{
name: "matrix",
description: "管理 Matrix 账户、验证、设备和 profile 状态",
description: "管理 Matrix 账户、验证、设备和配置文件状态",
hasSubcommands: true,
},
],
@ -381,60 +370,55 @@ api.registerCli(
);
```
仅在你不需要延迟根 CLI 注册时,才单独使用 `commands`
这种预加载兼容路径仍受支持,但它不会安装基于描述符的占位符来进行解析时的延迟加载。
仅当你不需要延迟根 CLI 注册时,才单独使用 `commands`。这种急切兼容路径仍受支持,但它不会安装由 descriptor 支持的占位符来实现解析期延迟加载。
### CLI 后端注册
`api.registerCliBackend(...)` 允许插件拥有本地 AI CLI 后端(例如 `codex-cli`)的默认配置。
- 后端 `id` 会成为模型引用中的提供商前缀,例如 `codex-cli/gpt-5`
- 后端 `id` 会成为模型引用中的 provider 前缀,例如 `codex-cli/gpt-5`
- 后端 `config` 使用与 `agents.defaults.cliBackends.<id>` 相同的结构。
- 用户配置仍然优先生效。OpenClaw 会先将 `agents.defaults.cliBackends.<id>` 合并到插件默认值之上,再运行 CLI。
- 当某个后端在合并后需要进行兼容性重写时,使用 `normalizeConfig`
(例如规范化旧版 flag 结构)。
- 用户配置仍然优先生效。OpenClaw 会在运行 CLI 之前,将 `agents.defaults.cliBackends.<id>` 合并到插件默认值之上。
- 当后端在合并后需要兼容性重写时,使用 `normalizeConfig`(例如规范化旧版 flag 结构)。
### 独占槽位
| 方法 | 注册内容 |
| 方法 | 注册内容 |
| ------------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `api.registerContextEngine(id, factory)` | 上下文引擎(一次仅一个处于活动状态)。`assemble()` 回调会接收 `availableTools``citationsMode`,以便引擎可以定制提示词附加内容。 |
| `api.registerContextEngine(id, factory)` | 上下文引擎(同一时间仅一个处于活动状态)。`assemble()` 回调会接收 `availableTools``citationsMode`,以便引擎定制提示补充内容。 |
| `api.registerMemoryCapability(capability)` | 统一 Memory 能力 |
| `api.registerMemoryPromptSection(builder)` | Memory 提示词区段构建器 |
| `api.registerMemoryFlushPlan(resolver)` | Memory flush 计划解析器 |
| `api.registerMemoryPromptSection(builder)` | Memory 提示部分构建器 |
| `api.registerMemoryFlushPlan(resolver)` | Memory flush plan 解析器 |
| `api.registerMemoryRuntime(runtime)` | Memory 运行时适配器 |
### Memory embedding 适配器
| 方法 | 注册内容 |
| 方法 | 注册内容 |
| ---------------------------------------------- | ---------------------------------------------- |
| `api.registerMemoryEmbeddingProvider(adapter)` | 当前活动插件的 Memory embedding 适配器 |
| `api.registerMemoryEmbeddingProvider(adapter)` | 活动插件的 Memory embedding 适配器 |
- `registerMemoryCapability` 是首选的独占 Memory 插件 API。
- `registerMemoryCapability` 还可以公开 `publicArtifacts.listArtifacts(...)`
这样配套插件就可以通过 `openclaw/plugin-sdk/memory-host-core` 使用导出的 Memory artifact而不需要深入某个特定 Memory 插件的私有布局。
- `registerMemoryPromptSection`、`registerMemoryFlushPlan` 和
`registerMemoryRuntime` 是兼容旧版的独占 Memory 插件 API。
- `registerMemoryEmbeddingProvider` 允许活动 Memory 插件注册一个或多个 embedding 适配器 id例如 `openai`、`gemini` 或插件自定义的 id
- 用户配置,例如 `agents.defaults.memorySearch.provider`
`agents.defaults.memorySearch.fallback`,会根据这些已注册的适配器 id 进行解析。
- `registerMemoryCapability` 还可以暴露 `publicArtifacts.listArtifacts(...)`,这样配套插件就可以通过 `openclaw/plugin-sdk/memory-host-core` 使用导出的 Memory artifact而不必深入某个特定 Memory 插件的私有布局。
- `registerMemoryPromptSection`、`registerMemoryFlushPlan` 和 `registerMemoryRuntime` 是兼容旧版的独占 Memory 插件 API。
- `registerMemoryEmbeddingProvider` 允许活动 Memory 插件注册一个或多个 embedding adapter id例如 `openai`、`gemini` 或自定义的插件定义 id
- 用户配置,例如 `agents.defaults.memorySearch.provider``agents.defaults.memorySearch.fallback`,会根据这些已注册的 adapter id 进行解析。
### 事件生命周期
### 事件和生命周期
| 方法 | 作用 |
| -------------------------------------------- | ----------------------------- |
| `api.on(hookName, handler, opts?)` | 类型化生命周期 hook |
| `api.onConversationBindingResolved(handler)` | 话绑定回调 |
| `api.onConversationBindingResolved(handler)` | 话绑定回调 |
### Hook 决策语义
- `before_tool_call`:返回 `{ block: true }` 是终止性的。一旦任一处理器设置它,就会跳过较低优先级的处理器。
- `before_tool_call`:返回 `{ block: false }` 会被视为作出决策(与省略 `block` 相同),而不是覆盖。
- `before_install`:返回 `{ block: true }` 是终止性的。一旦任一处理器设置它,就会跳过较低优先级的处理器。
- `before_install`:返回 `{ block: false }` 会被视为作出决策(与省略 `block` 相同),而不是覆盖。
- `reply_dispatch`:返回 `{ handled: true, ... }` 是终止性的。一旦任一处理器声明已处理分发,就会跳过较低优先级的处理器以及默认模型分发路径。
- `message_sending`:返回 `{ cancel: true }` 是终止性的。一旦任一处理器设置它,就会跳过较低优先级的处理器。
- `message_sending`:返回 `{ cancel: false }` 会被视为作出决策(与省略 `cancel` 相同),而不是覆盖。
- `before_tool_call`:返回 `{ block: true }` 是终止性的。一旦任何处理器设置了它,就会跳过更低优先级的处理器。
- `before_tool_call`:返回 `{ block: false }` 会被视为没有作出决策(与省略 `block` 相同),而不是覆盖。
- `before_install`:返回 `{ block: true }` 是终止性的。一旦任何处理器设置了它,就会跳过更低优先级的处理器。
- `before_install`:返回 `{ block: false }` 会被视为没有作出决策(与省略 `block` 相同),而不是覆盖。
- `reply_dispatch`:返回 `{ handled: true, ... }` 是终止性的。一旦任何处理器声明已处理分发,就会跳过更低优先级的处理器以及默认的模型分发路径。
- `message_sending`:返回 `{ cancel: true }` 是终止性的。一旦任何处理器设置了它,就会跳过更低优先级的处理器。
- `message_sending`:返回 `{ cancel: false }` 会被视为没有作出决策(与省略 `cancel` 相同),而不是覆盖。
### API 对象字段
@ -449,8 +433,8 @@ api.registerCli(
| `api.config` | `OpenClawConfig` | 当前配置快照(可用时为活动的内存中运行时快照) |
| `api.pluginConfig` | `Record<string, unknown>` | 来自 `plugins.entries.<id>.config` 的插件特定配置 |
| `api.runtime` | `PluginRuntime` | [运行时辅助函数](/zh-CN/plugins/sdk-runtime) |
| `api.logger` | `PluginLogger` | 作用域 logger`debug`、`info`、`warn`、`error` |
| `api.registrationMode` | `PluginRegistrationMode` | 当前加载模式;`"setup-runtime"` 是完整入口启动 / 设置前的轻量级窗口 |
| `api.logger` | `PluginLogger` | 作用域 logger`debug`、`info`、`warn`、`error` |
| `api.registrationMode` | `PluginRegistrationMode` | 当前加载模式;`"setup-runtime"` 是完整入口启动 / 设置前的轻量级窗口 |
| `api.resolvePath(input)` | `(string) => string` | 解析相对于插件根目录的路径 |
## 内部模块约定
@ -460,46 +444,38 @@ api.registerCli(
```
my-plugin/
api.ts # 供外部使用者使用的公共导出
runtime-api.ts # 仅限内部的运行时导出
runtime-api.ts # 仅供内部使用的运行时导出
index.ts # 插件入口点
setup-entry.ts # 仅用于轻量设置的入口点(可选)
setup-entry.ts # 仅用于轻量设置的入口点(可选)
```
<Warning>
不要在生产代码中通过 `openclaw/plugin-sdk/<your-plugin>` 导入你自己的插件。
内部导入应通过 `./api.ts`
`./runtime-api.ts`。SDK 路径仅是外契约。
永远不要在生产代码中通过 `openclaw/plugin-sdk/<your-plugin>`
导入你自己的插件。内部导入应通过 `./api.ts`
`./runtime-api.ts`。SDK 路径仅是外契约。
</Warning>
通过 facade 加载的内置插件公共 surface`api.ts`、`runtime-api.ts`、
`index.ts`、`setup-entry.ts` 以及类似的公共入口文件)现在会在
OpenClaw 已经运行时优先使用活动运行时配置快照。如果运行时快照尚不存在,
它们会回退到磁盘上已解析的配置文件。
采用 facade 加载的内置插件公共接口(`api.ts`、`runtime-api.ts`、`index.ts`、`setup-entry.ts` 以及类似的公共入口文件)现在会在 OpenClaw 已经运行时优先使用活动运行时配置快照。如果运行时快照尚不存在,它们会回退到磁盘上已解析的配置文件。
当某个辅助函数是有意保持提供商特定、且暂时不属于通用 SDK
子路径时,提供商插件也可以公开一个狭义的插件本地契约 barrel。当前内置示例Anthropic 提供商将其 Claude
流辅助函数保留在自己的公共 `api.ts` / `contract-api.ts` seam 中,而不是把 Anthropic beta-header 和
`service_tier` 逻辑提升到通用的 `plugin-sdk/*` 契约中。
如果某个辅助函数明确是提供商特定的,并且尚不属于通用 SDK 子路径,提供商插件也可以暴露一个狭义的插件本地契约 barrel。当前的内置示例Anthropic 提供商将其 Claude 流辅助函数保留在自己的公共 `api.ts` / `contract-api.ts` 接口中,而不是将 Anthropic beta-header 和 `service_tier` 逻辑提升到通用 `plugin-sdk/*` 契约中。
其他当前内置示例:
其他当前的内置示例:
- `@openclaw/openai-provider``api.ts` 导出提供商构建器、
默认模型辅助函数和实时提供商构建器
- `@openclaw/openrouter-provider``api.ts` 导出提供商构建器以及
新手引导 / 配置辅助函数
- `@openclaw/openai-provider``api.ts` 导出 provider 构建器、默认模型辅助函数和实时 provider 构建器
- `@openclaw/openrouter-provider``api.ts` 导出 provider 构建器以及新手引导 / 配置辅助函数
<Warning>
扩展生产代码也应避免导入 `openclaw/plugin-sdk/<other-plugin>`
如果某个辅助函数确实需要共享,请将提升到中立的 SDK 子路径,
扩展生产代码也应避免导入 `openclaw/plugin-sdk/<other-plugin>`
如果某个辅助函数确实需要共享,请将提升到中立的 SDK 子路径,
例如 `openclaw/plugin-sdk/speech`、`.../provider-model-shared` 或其他
面向能力的 surface而不是让两个插件耦合在一起。
面向能力的接口,而不是将两个插件耦合在一起。
</Warning>
## 相关内容
- [入口点](/zh-CN/plugins/sdk-entrypoints) — `definePluginEntry``defineChannelPluginEntry` 选项
- [运行时辅助函数](/zh-CN/plugins/sdk-runtime) — 完整的 `api.runtime` 命名空间参考
- [设置配置](/zh-CN/plugins/sdk-setup) — 打包、manifest、配置 schema
- [设置配置](/zh-CN/plugins/sdk-setup) — 打包、manifest、配置 schema
- [测试](/zh-CN/plugins/sdk-testing) — 测试工具和 lint 规则
- [SDK 迁移](/zh-CN/plugins/sdk-migration) — 从已弃用 surface 迁移
- [插件内部机制](/zh-CN/plugins/architecture) — 深入的架构能力模型
- [SDK 迁移](/zh-CN/plugins/sdk-migration) — 从已弃用接口迁移
- [插件内部机制](/zh-CN/plugins/architecture) — 深入的架构能力模型

View File

@ -0,0 +1,708 @@
---
read_when:
- 你希望智能体将修正内容或可复用流程转换为工作区 Skills
- 你正在配置过程型 Skills 记忆
- 你正在调试 `skill_workshop` 工具行为
- 你正在决定是否启用自动创建 Skills
summary: 将可复用流程以工作区 Skills 的形式进行实验性捕获,并支持审核、批准、隔离和 Skills 热刷新
title: Skill Workshop 插件
x-i18n:
generated_at: "2026-04-21T20:35:14Z"
model: gpt-5.4
provider: openai
source_hash: 62dcb3e1a71999bfc39a95dc3d0984d3446c8a58f7d91a914dfc7256b4e79601
source_path: plugins/skill-workshop.md
workflow: 15
---
# Skill Workshop 插件
Skill Workshop **处于实验阶段**。默认禁用,其捕获启发式规则和审阅者提示可能会在不同版本之间发生变化,并且自动写入应仅在受信任的工作区中使用,且应先查看待处理模式的输出。
Skill Workshop 是用于工作区 Skills 的过程型记忆。它让智能体能够将可复用工作流、用户修正、来之不易的修复经验以及反复出现的陷阱,转换为以下位置下的 `SKILL.md` 文件:
```text
<workspace>/skills/<skill-name>/SKILL.md
```
这不同于长期记忆:
- **Memory** 存储事实、偏好、实体和过去的上下文。
- **Skills** 存储智能体在未来任务中应遵循的可复用流程。
- **Skill Workshop** 是从一次有用的交互到持久化工作区 skill 的桥梁,带有安全检查和可选批准。
当智能体学会如下流程时Skill Workshop 会很有用:
- 如何验证外部来源的动画 GIF 资源
- 如何替换截图资源并验证尺寸
- 如何运行仓库特定的 QA 场景
- 如何调试反复出现的提供商故障
- 如何修复过时的本地工作流说明
它不适用于:
- 像“用户喜欢蓝色”这样的事实
- 宽泛的自传式记忆
- 原始转录归档
- 密钥、凭证或隐藏提示文本
- 不会重复出现的一次性指令
## 默认状态
内置插件**处于实验阶段**,并且**默认禁用**,除非在 `plugins.entries.skill-workshop` 中显式启用。
插件清单未设置 `enabledByDefault: true`。插件配置 schema 中的 `enabled: true` 默认值仅在插件条目已被选中并加载后才会生效。
“实验阶段”意味着:
- 该插件已具备足够支持,可用于选择加入的测试和内部试用
- 提案存储、审阅阈值和捕获启发式规则可能会持续演进
- 建议将待批准作为起始模式
- 自动应用适用于受信任的个人 / 工作区设置,不适用于共享或高频接收不可信输入的环境
## 启用
最小安全配置:
```json5
{
plugins: {
entries: {
"skill-workshop": {
enabled: true,
config: {
autoCapture: true,
approvalPolicy: "pending",
reviewMode: "hybrid",
},
},
},
},
}
```
使用此配置时:
- `skill_workshop` 工具可用
- 明确的可复用修正会被排入待处理提案队列
- 基于阈值的审阅者流程可以提出 skill 更新建议
- 在待处理提案被应用之前,不会写入任何 skill 文件
仅在受信任的工作区中使用自动写入:
```json5
{
plugins: {
entries: {
"skill-workshop": {
enabled: true,
config: {
autoCapture: true,
approvalPolicy: "auto",
reviewMode: "hybrid",
},
},
},
},
}
```
`approvalPolicy: "auto"` 仍会使用相同的扫描器和隔离路径。它不会应用存在严重扫描发现的问题提案。
## 配置
| 键名 | 默认值 | 范围 / 取值 | 含义 |
| -------------------- | ----------- | -------------------------------------------- | ---------------------------------------------- |
| `enabled` | `true` | boolean | 在插件条目加载后启用该插件。 |
| `autoCapture` | `true` | boolean | 在智能体成功完成交互后启用交互后捕获 / 审阅。 |
| `approvalPolicy` | `"pending"` | `"pending"`, `"auto"` | 将提案加入队列,或自动写入安全提案。 |
| `reviewMode` | `"hybrid"` | `"off"`, `"heuristic"`, `"llm"`, `"hybrid"` | 选择显式修正捕获、LLM 审阅者、两者或都不用。 |
| `reviewInterval` | `15` | `1..200` | 在这么多次成功交互后运行审阅者。 |
| `reviewMinToolCalls` | `8` | `1..500` | 在观察到这么多次工具调用后运行审阅者。 |
| `reviewTimeoutMs` | `45000` | `5000..180000` | 内嵌审阅者运行的超时时间。 |
| `maxPending` | `50` | `1..200` | 每个工作区保留的待处理 / 已隔离提案最大数量。 |
| `maxSkillBytes` | `40000` | `1024..200000` | 生成的 skill / 支持文件的最大大小。 |
推荐配置档案:
```json5
// 保守:仅显式工具使用,不启用自动捕获。
{
autoCapture: false,
approvalPolicy: "pending",
reviewMode: "off",
}
```
```json5
// 先审阅:自动捕获,但需要批准。
{
autoCapture: true,
approvalPolicy: "pending",
reviewMode: "hybrid",
}
```
```json5
// 受信任自动化:立即写入安全提案。
{
autoCapture: true,
approvalPolicy: "auto",
reviewMode: "hybrid",
}
```
```json5
// 低成本:不调用审阅者 LLM仅使用显式修正短语。
{
autoCapture: true,
approvalPolicy: "pending",
reviewMode: "heuristic",
}
```
## 捕获路径
Skill Workshop 有三种捕获路径。
### 工具建议
当模型看到可复用流程,或用户要求它保存 / 更新某个 skill 时,可以直接调用 `skill_workshop`
这是最显式的路径,即使在 `autoCapture: false` 时也可工作。
### 启发式捕获
当启用 `autoCapture`,且 `reviewMode``heuristic``hybrid` 时,插件会扫描成功交互中的显式用户修正短语:
- `next time`
- `from now on`
- `remember to`
- `make sure to`
- `always ... use/check/verify/record/save/prefer`
- `prefer ... when/for/instead/use`
- `when asked`
启发式规则会根据最近匹配的用户指令创建提案。它会使用主题提示为常见工作流选择 skill 名称:
- 动画 GIF 任务 -> `animated-gif-workflow`
- 截图或资源任务 -> `screenshot-asset-workflow`
- QA 或场景任务 -> `qa-scenario-workflow`
- GitHub PR 任务 -> `github-pr-workflow`
- 回退 -> `learned-workflows`
启发式捕获是有意保持狭窄范围的。它适用于清晰的修正和可重复流程说明,不适用于通用的转录摘要。
### LLM 审阅者
当启用 `autoCapture`,且 `reviewMode``llm``hybrid` 时,插件会在达到阈值后运行一个紧凑的内嵌审阅者。
审阅者会接收:
- 最近的转录文本,限制为最后 12,000 个字符
- 最多 12 个现有工作区 Skills
- 每个现有 skill 最多 2,000 个字符
- 仅 JSON 指令
审阅者没有工具:
- `disableTools: true`
- `toolsAllow: []`
- `disableMessageTool: true`
它可以返回:
```json
{ "action": "none" }
```
或者返回一个 skill 提案:
```json
{
"action": "create",
"skillName": "media-asset-qa",
"title": "Media Asset QA",
"reason": "Reusable animated media acceptance workflow",
"description": "Validate externally sourced animated media before product use.",
"body": "## Workflow\n\n- Verify true animation.\n- Record attribution.\n- Store a local approved copy.\n- Verify in product UI before final reply."
}
```
它也可以向现有 skill 追加内容:
```json
{
"action": "append",
"skillName": "qa-scenario-workflow",
"title": "QA Scenario Workflow",
"reason": "Animated media QA needs reusable checks",
"description": "QA scenario workflow.",
"section": "Workflow",
"body": "- For animated GIF tasks, verify frame count and attribution before passing."
}
```
或者替换现有 skill 中的精确文本:
```json
{
"action": "replace",
"skillName": "screenshot-asset-workflow",
"title": "Screenshot Asset Workflow",
"reason": "Old validation missed image optimization",
"oldText": "- Replace the screenshot asset.",
"newText": "- Replace the screenshot asset, preserve dimensions, optimize the PNG, and run the relevant validation gate."
}
```
当相关 skill 已存在时,优先使用 `append``replace`。仅当没有任何现有 skill 适合时,才使用 `create`
## 提案生命周期
每个生成的更新都会成为一个提案,包含:
- `id`
- `createdAt`
- `updatedAt`
- `workspaceDir`
- 可选的 `agentId`
- 可选的 `sessionId`
- `skillName`
- `title`
- `reason`
- `source``tool`、`agent_end` 或 `reviewer`
- `status`
- `change`
- 可选的 `scanFindings`
- 可选的 `quarantineReason`
提案状态:
- `pending` - 等待批准
- `applied` - 已写入 `<workspace>/skills`
- `rejected` - 已被操作员 / 模型拒绝
- `quarantined` - 因严重扫描发现而被阻止
状态按工作区存储在 Gateway 网关状态目录下:
```text
<stateDir>/skill-workshop/<workspace-hash>.json
```
待处理和已隔离提案会按 skill 名称和变更负载去重。存储会保留最新的待处理 / 已隔离提案,最多不超过 `maxPending`
## 工具参考
该插件注册了一个智能体工具:
```text
skill_workshop
```
### `status`
按状态统计当前工作区中的提案数量。
```json
{ "action": "status" }
```
结果结构:
```json
{
"workspaceDir": "/path/to/workspace",
"pending": 1,
"quarantined": 0,
"applied": 3,
"rejected": 0
}
```
### `list_pending`
列出待处理提案。
```json
{ "action": "list_pending" }
```
列出其他状态:
```json
{ "action": "list_pending", "status": "applied" }
```
有效的 `status` 取值:
- `pending`
- `applied`
- `rejected`
- `quarantined`
### `list_quarantine`
列出已隔离提案。
```json
{ "action": "list_quarantine" }
```
当自动捕获看起来没有任何效果,而日志中提到 `skill-workshop: quarantined <skill>` 时,请使用此操作。
### `inspect`
按 id 获取提案。
```json
{
"action": "inspect",
"id": "proposal-id"
}
```
### `suggest`
创建一个提案。当使用 `approvalPolicy: "pending"` 时,默认会将其加入队列。
```json
{
"action": "suggest",
"skillName": "animated-gif-workflow",
"title": "Animated GIF Workflow",
"reason": "User established reusable GIF validation rules.",
"description": "Validate animated GIF assets before using them.",
"body": "## Workflow\n\n- Verify the URL resolves to image/gif.\n- Confirm it has multiple frames.\n- Record attribution and license.\n- Avoid hotlinking when a local asset is needed."
}
```
强制安全写入:
```json
{
"action": "suggest",
"apply": true,
"skillName": "animated-gif-workflow",
"description": "Validate animated GIF assets before using them.",
"body": "## Workflow\n\n- Verify true animation.\n- Record attribution."
}
```
即使在 `approvalPolicy: "auto"` 下也强制进入待处理状态:
```json
{
"action": "suggest",
"apply": false,
"skillName": "screenshot-asset-workflow",
"description": "Screenshot replacement workflow.",
"body": "## Workflow\n\n- Verify dimensions.\n- Optimize the PNG.\n- Run the relevant gate."
}
```
向某个章节追加内容:
```json
{
"action": "suggest",
"skillName": "qa-scenario-workflow",
"section": "Workflow",
"description": "QA scenario workflow.",
"body": "- For media QA, verify generated assets render and pass final assertions."
}
```
替换精确文本:
```json
{
"action": "suggest",
"skillName": "github-pr-workflow",
"oldText": "- Check the PR.",
"newText": "- Check unresolved review threads, CI status, linked issues, and changed files before deciding."
}
```
### `apply`
应用一个待处理提案。
```json
{
"action": "apply",
"id": "proposal-id"
}
```
`apply` 会拒绝已隔离提案:
```text
quarantined proposal cannot be applied
```
### `reject`
将提案标记为已拒绝。
```json
{
"action": "reject",
"id": "proposal-id"
}
```
### `write_support_file`
在现有或提议中的 skill 目录内写入一个支持文件。
允许的顶级支持目录:
- `references/`
- `templates/`
- `scripts/`
- `assets/`
示例:
```json
{
"action": "write_support_file",
"skillName": "release-workflow",
"relativePath": "references/checklist.md",
"body": "# Release Checklist\n\n- Run release docs.\n- Verify changelog.\n"
}
```
支持文件按工作区作用域管理,会进行路径检查、受 `maxSkillBytes` 的字节大小限制、经过扫描,并以原子方式写入。
## Skill 写入
Skill Workshop 仅会写入以下路径:
```text
<workspace>/skills/<normalized-skill-name>/
```
Skill 名称会被规范化:
- 转为小写
- 非 `[a-z0-9_-]` 的连续字符会变为 `-`
- 移除开头 / 结尾的非字母数字字符
- 最大长度为 80 个字符
- 最终名称必须匹配 `[a-z0-9][a-z0-9_-]{1,79}`
对于 `create`
- 如果 skill 不存在Skill Workshop 会写入一个新的 `SKILL.md`
- 如果已存在Skill Workshop 会将内容追加到 `## Workflow`
对于 `append`
- 如果 skill 已存在Skill Workshop 会追加到请求的章节
- 如果不存在Skill Workshop 会先创建一个最小 skill然后再追加
对于 `replace`
- skill 必须已经存在
- `oldText` 必须精确存在
- 只会替换第一个精确匹配项
所有写入都是原子的,并会立即刷新内存中的 Skills 快照,因此无需重启 Gateway 网关也能看到新的或更新后的 skill。
## 安全模型
Skill Workshop 会对生成的 `SKILL.md` 内容和支持文件进行安全扫描。
严重发现会将提案隔离:
| 规则 id | 阻止这类内容: |
| ------------------------------------- | ------------------------------------------------------------------ |
| `prompt-injection-ignore-instructions` | 告诉智能体忽略先前 / 更高优先级指令 |
| `prompt-injection-system` | 引用系统提示、开发者消息或隐藏指令 |
| `prompt-injection-tool` | 鼓励绕过工具权限 / 批准 |
| `shell-pipe-to-shell` | 包含将 `curl` / `wget` 通过管道传给 `sh`、`bash` 或 `zsh` 的内容 |
| `secret-exfiltration` | 看起来会通过网络发送 env / 进程环境数据 |
警告发现会被保留,但不会单独造成阻止:
| 规则 id | 警告内容: |
| ------------------- | ------------------------------ |
| `destructive-delete` | 宽泛的 `rm -rf` 风格命令 |
| `unsafe-permissions` | `chmod 777` 风格的权限使用 |
已隔离提案:
- 保留 `scanFindings`
- 保留 `quarantineReason`
- 会显示在 `list_quarantine`
- 不能通过 `apply` 应用
要从已隔离提案中恢复,请创建一个移除了不安全内容的新安全提案。不要手动编辑存储 JSON。
## 提示指导
启用后Skill Workshop 会注入一段简短提示,告诉智能体使用 `skill_workshop` 来保存持久化的过程型记忆。
该指导强调:
- 保存流程,而不是事实 / 偏好
- 用户修正
- 不明显但成功的流程
- 反复出现的陷阱
- 通过 append / replace 修复过时 / 过薄 / 错误的 skill
- 在长工具循环或艰难修复后保存可复用流程
- 使用简短的祈使句风格 skill 文本
- 不要转储转录内容
写入模式文本会随 `approvalPolicy` 改变:
- 待处理模式:将建议加入队列;仅在显式批准后应用
- 自动模式:在明确可复用时应用安全的工作区 skill 更新
## 成本和运行时行为
启发式捕获不会调用模型。
LLM 审阅会在当前 / 默认智能体模型上执行一个内嵌运行。它是基于阈值触发的,因此默认不会在每次交互时都运行。
审阅者:
- 在可用时使用相同的已配置提供商 / 模型上下文
- 否则回退到运行时智能体默认值
- 具有 `reviewTimeoutMs`
- 使用轻量级引导上下文
- 没有工具
- 不会直接写入任何内容
- 只能生成一个提案,然后该提案会经过常规扫描器以及批准 / 隔离路径
如果审阅者失败、超时或返回无效 JSON插件会记录一条 warning / debug 日志消息,并跳过该次审阅流程。
## 运行模式
当用户这样说时,请使用 Skill Workshop
- “next time, do X”
- “from now on, prefer Y”
- “make sure to verify Z”
- “save this as a workflow”
- “this took a while; remember the process”
- “update the local skill for this”
好的 skill 文本:
```markdown
## Workflow
- Verify the GIF URL resolves to `image/gif`.
- Confirm the file has multiple frames.
- Record source URL, license, and attribution.
- Store a local copy when the asset will ship with the product.
- Verify the local asset renders in the target UI before final reply.
```
差的 skill 文本:
```markdown
The user asked about a GIF and I searched two websites. Then one was blocked by
Cloudflare. The final answer said to check attribution.
```
不应保存差版本的原因:
- 呈现为转录内容形态
- 不是祈使句
- 包含嘈杂的一次性细节
- 没有告诉下一个智能体应该做什么
## 调试
检查插件是否已加载:
```bash
openclaw plugins list --enabled
```
在智能体 / 工具上下文中检查提案计数:
```json
{ "action": "status" }
```
检查待处理提案:
```json
{ "action": "list_pending" }
```
检查已隔离提案:
```json
{ "action": "list_quarantine" }
```
常见症状:
| 症状 | 可能原因 | 检查项 |
| ------------------------------------- | ----------------------------------------------------------------------------------- | -------------------------------------------------------------------- |
| 工具不可用 | 插件条目未启用 | `plugins.entries.skill-workshop.enabled``openclaw plugins list` |
| 没有出现自动提案 | `autoCapture: false`、`reviewMode: "off"`,或未达到阈值 | 配置、提案状态、Gateway 网关日志 |
| 启发式规则未捕获 | 用户措辞未匹配修正规则模式 | 使用显式 `skill_workshop.suggest` 或启用 LLM 审阅者 |
| 审阅者未创建提案 | 审阅者返回了 `none`、无效 JSON或已超时 | Gateway 网关日志、`reviewTimeoutMs`、阈值 |
| 提案未被应用 | `approvalPolicy: "pending"` | `list_pending`,然后执行 `apply` |
| 提案从待处理列表中消失 | 复用了重复提案、达到最大待处理裁剪上限,或已被应用 / 拒绝 / 隔离 | `status`、带状态过滤的 `list_pending`、`list_quarantine` |
| skill 文件存在,但模型没有使用它 | skill 快照未刷新,或 skill 门控将其排除 | `openclaw skills` 状态和工作区 skill 资格 |
相关日志:
- `skill-workshop: queued <skill>`
- `skill-workshop: applied <skill>`
- `skill-workshop: quarantined <skill>`
- `skill-workshop: heuristic capture skipped: ...`
- `skill-workshop: reviewer skipped: ...`
- `skill-workshop: reviewer found no update`
## QA 场景
基于仓库的 QA 场景:
- `qa/scenarios/plugins/skill-workshop-animated-gif-autocreate.md`
- `qa/scenarios/plugins/skill-workshop-pending-approval.md`
- `qa/scenarios/plugins/skill-workshop-reviewer-autonomous.md`
运行确定性覆盖:
```bash
pnpm openclaw qa suite \
--scenario skill-workshop-animated-gif-autocreate \
--scenario skill-workshop-pending-approval \
--concurrency 1
```
运行审阅者覆盖:
```bash
pnpm openclaw qa suite \
--scenario skill-workshop-reviewer-autonomous \
--concurrency 1
```
审阅者场景被有意单独拆分,因为它启用了 `reviewMode: "llm"` 并覆盖了内嵌审阅者流程。
## 何时不应启用自动应用
在以下情况下,避免使用 `approvalPolicy: "auto"`
- 工作区包含敏感流程
- 智能体正在处理不可信输入
- Skills 由一个较大的团队共享
- 你仍在调整提示或扫描规则
- 模型经常处理带有敌意的网页 / 邮件内容
请先使用待处理模式。仅在你审查过该工作区中智能体提出的 skill 类型之后,再切换到自动模式。
## 相关文档
- [Skills](/zh-CN/tools/skills)
- [插件](/zh-CN/tools/plugin)
- [测试](/zh-CN/reference/test)

View File

@ -1,57 +1,57 @@
---
read_when:
- 添加或修改 Skills
- 更改 Skills 门控或加载规则
summary: Skills托管式与工作区、门控规则,以及配置/环境变量连接方式
- 更改 Skills 门控或加载规则
summary: Skills托管与工作区、门控规则以及配置/环境变量接线
title: Skills
x-i18n:
generated_at: "2026-04-10T12:46:44Z"
generated_at: "2026-04-21T20:35:20Z"
model: gpt-5.4
provider: openai
source_hash: b1eaf130966950b6eb24f859d9a77ecbf81c6cb80deaaa6a3a79d2c16d83115d
source_hash: c2ff6a3a92bc3c1c3892620a00e2eb01c73364bc6388a3513943defa46e49749
source_path: tools/skills.md
workflow: 15
---
# SkillsOpenClaw
OpenClaw 使用与 **[AgentSkills](https://agentskills.io)** 兼容的技能文件夹来教会智能体如何使用工具。每个 skill 都是一个目录,其中包含带有 YAML frontmatter 和说明的 `SKILL.md`。OpenClaw 会加载**内置 Skills**以及可选的本地覆盖,并在加载时根据环境、配置和二进制文件是否存在进行筛选
OpenClaw 使用与 **[AgentSkills](https://agentskills.io)** 兼容的技能文件夹来教会智能体如何使用工具。每个 Skill 都是一个目录,包含带有 YAML frontmatter 和说明的 `SKILL.md`。OpenClaw 会加载**内置 Skills**以及可选的本地覆盖,并根据环境、配置和二进制文件是否存在,在加载时进行过滤
## 位置优先级
## 位置优先级
OpenClaw 会从以下来源加载 Skills
1. **额外 Skills 文件夹**:通过 `skills.load.extraDirs` 配置
2. **内置 Skills**:随安装一起提供npm 包或 OpenClaw.app
3. **托管/本地 Skills**`~/.openclaw/skills`
4. **个人 agent Skills**`~/.agents/skills`
5. **项目 agent Skills**`<workspace>/.agents/skills`
1. **额外 Skill 文件夹**:通过 `skills.load.extraDirs` 配置
2. **内置 Skills**随安装一起提供npm 包或 OpenClaw.app
3. **托管/本地 Skills**`~/.openclaw/skills`
4. **个人智能体 Skills**`~/.agents/skills`
5. **项目智能体 Skills**`<workspace>/.agents/skills`
6. **工作区 Skills**`<workspace>/skills`
如果 skill 名称冲突,优先级如下:
如果 Skill 名称冲突,优先级如下:
`<workspace>/skills`(最高)→ `<workspace>/.agents/skills``~/.agents/skills``~/.openclaw/skills` → 内置 Skills → `skills.load.extraDirs`(最低)
## 每个 agent 的 Skills 与共享 Skills
## 按智能体区分的 Skills 与共享 Skills
在**多智能体**设置中,每个智能体都有自己的工作区。这意味着:
- **每个 agent 独有的 Skills** 仅存在于该 agent `<workspace>/skills` 中。
- **项目 agent Skills** 位于 `<workspace>/.agents/skills`,会先于普通工作区 `skills/` 文件夹应用到该工作区。
- **个人 agent Skills** 位于 `~/.agents/skills`,会应用到该机器上的所有工作区。
- **共享 Skills** 位于 `~/.openclaw/skills`(托管/本地),同一台机器上的**所有智能体**可见。
- 如果你希望多个智能体共用同一套 Skills,也可以通过 `skills.load.extraDirs` 添加**共享文件夹**(最低优先级)。
- **按智能体区分的 Skills** 仅存在于该智能体`<workspace>/skills` 中。
- **项目智能体 Skills** 位于 `<workspace>/.agents/skills`,会先于普通工作区 `skills/` 文件夹应用到该工作区。
- **个人智能体 Skills** 位于 `~/.agents/skills`,适用于该机器上的所有工作区。
- **共享 Skills** 位于 `~/.openclaw/skills`(托管/本地),同一台机器上的**所有智能体**可见。
- 如果你想为多个智能体使用一个公共 Skill 包,也可以通过 `skills.load.extraDirs` 添加**共享文件夹**(最低优先级)。
如果同一个 skill 名称在多个位置都存在,则仍然适用常规优先级:工作区优先,然后是项目 agent Skills再然后是个人 agent Skills然后是托管式/本地,再然后是内置,最后是额外目录。
如果同一个 Skill 名称出现在多个位置,仍然遵循通常的优先级规则:工作区优先,然后是项目智能体 Skills再然后是个人智能体 Skills再然后是托管/本地 Skills然后是内置 Skills,最后是额外目录。
## 智能体 Skill 允许列表
## 智能体 Skill allowlists
Skill 的**位置**和 skill 的**可见性**是两套独立控制。
Skill 的**位置**和 Skill 的**可见性**是两种独立控制。
- 位置/优先级决定同名 skill 最终使用哪一份副本
- 智能体允许列表决定 agent 实际可以使用哪些可见 skills
- 位置/优先级决定了同名 Skill 中哪一个副本胜出
- 智能体 allowlists 决定了某个智能体实际上可以使用哪些可见 Skill
使用 `agents.defaults.skills` 作为共享基线,然后通过 `agents.list[].skills` 为每个 agent 覆盖:
使用 `agents.defaults.skills` 作为共享基线,然后通过 `agents.list[].skills` 为每个智能体覆盖:
```json5
{
@ -61,8 +61,8 @@ Skill 的**位置**和 skill 的**可见性**是两套独立控制。
},
list: [
{ id: "writer" }, // 继承 github、weather
{ id: "docs", skills: ["docs-search"] }, // 替换 defaults
{ id: "locked-down", skills: [] }, // 无 skills
{ id: "docs", skills: ["docs-search"] }, // 替换默认值
{ id: "locked-down", skills: [] }, // 无 Skills
],
},
}
@ -70,81 +70,90 @@ Skill 的**位置**和 skill 的**可见性**是两套独立控制。
规则:
- 如果默认不限制 skills省略 `agents.defaults.skills`
- 省略 `agents.defaults.skills` 表示默认不限制 Skills
- 省略 `agents.list[].skills` 表示继承 `agents.defaults.skills`
- 设置 `agents.list[].skills: []` 表示没有 skills。
- 非空的 `agents.list[].skills` 列表就是该 agent 的最终集合;它不会与 defaults 合并。
- 设置 `agents.list[].skills: []` 表示无 Skills。
- 非空的 `agents.list[].skills` 列表就是该智能体的最终集合;它不会与默认值合并。
OpenClaw 会在构建提示词、skill 斜杠命令发现、沙箱同步以及 skill 快照时应用 agent 的最终有效 skill 集合。
OpenClaw 会在提示词构建、Skill 斜杠命令发现、沙箱同步和 Skill 快照中应用智能体的有效 Skill 集合。
## 插件 + Skills
插件可以通过在 `openclaw.plugin.json` 中列出 `skills` 目录来附带自己的 Skills路径相对于插件根目录。插件启用后这些插件 Skills 就会加载。当前这些目录会被合并到与 `skills.load.extraDirs` 相同的低优先级路径中因此同名的内置、托管式、agent 或工作区 skill 都会覆盖它们。
你可以通过插件配置项上的 `metadata.openclaw.requires.config` 对它们进行门控。有关发现/配置,请参阅 [Plugins](/zh-CN/tools/plugin);有关这些 skills 所教授的工具界面,请参阅 [Tools](/zh-CN/tools)。
插件可以通过在 `openclaw.plugin.json` 中列出 `skills` 目录(相对于插件根目录的路径)来附带自己的 Skills。启用插件后插件 Skills 就会加载。当前,这些目录会被合并到与 `skills.load.extraDirs` 相同的低优先级路径中,因此同名的内置、托管、智能体或工作区 Skill 会覆盖它们。
你可以通过插件配置项上的 `metadata.openclaw.requires.config` 对其进行门控。有关发现/配置,请参见 [插件](/zh-CN/tools/plugin);有关这些 Skills 所教授的工具表面,请参见 [工具](/zh-CN/tools)。
## Skill Workshop
可选的实验性 Skill Workshop 插件可以根据智能体工作过程中观察到的可复用流程,创建或更新工作区 Skills。它默认禁用必须通过 `plugins.entries.skill-workshop` 显式启用。
Skill Workshop 只会写入 `<workspace>/skills`,会扫描生成内容,支持待审批或自动安全写入,会隔离不安全提案,并在成功写入后刷新 Skill 快照,以便无需重启 Gateway 网关 就能让新 Skill 生效。
当你希望将诸如“下次请核实 GIF 署名”这样的修正,或诸如媒体 QA 检查清单这样的宝贵工作流,变成可持续复用的流程指令时,可以使用它。建议从待审批开始;只有在受信任的工作区中并审查过其提案之后,才使用自动写入。完整指南:
[Skill Workshop 插件](/zh-CN/plugins/skill-workshop)。
## ClawHub安装 + 同步)
ClawHub 是 OpenClaw 的公共 Skills 注册表。可在 [https://clawhub.ai](https://clawhub.ai) 浏览。使用原生 `openclaw skills` 命令来发现/安装/更新 skills如果你需要发布/同步工作流,也可以使用独立的 `clawhub` CLI。
ClawHub 是 OpenClaw 的公 Skills 注册表。可在 [https://clawhub.ai](https://clawhub.ai) 浏览。使用原生 `openclaw skills` 命令来发现/安装/更新 Skills或者在你需要发布/同步工作流时使用单独`clawhub` CLI。
完整指南:[ClawHub](/zh-CN/tools/clawhub)。
常见流程:
- 将 skill 安装到你的工作区:
- 将一个 Skill 安装到你的工作区:
- `openclaw skills install <skill-slug>`
- 更新所有已安装的 skills
- 更新所有已安装的 Skills
- `openclaw skills update --all`
- 同步(扫描 + 发布更新):
- `clawhub sync --all`
原生 `openclaw skills install` 会安装到当前活动工作区的 `skills/` 目录中。独`clawhub` CLI 也会安装到当前工作目录下的 `./skills` 中(或者回退到配置的 OpenClaw 工作区)。
OpenClaw 会在下一个会话中将其识别为 `<workspace>/skills`
原生 `openclaw skills install` 会安装到当前活动工作区的 `skills/` 目录中。独的 `clawhub` CLI 也会安装到当前工作目录下的 `./skills` 中(或者回退到配置的 OpenClaw 工作区)。
OpenClaw 会在下一个会话中将其作为 `<workspace>/skills` 加载
## 安全说明
- 将第三方 skills 视为**不受信任的代码**。启用前请先阅读。
- 对不受信任输入和高风险工具,优先使用沙箱隔离运行。参见 [沙箱隔离](/zh-CN/gateway/sandboxing)。
- 工作区和额外目录的 skill 发现只接受那些其解析后的真实路径仍位于已配置根目录内的 skill 根目录和 `SKILL.md` 文件。
- 由 Gateway 网关支持的 skill 依赖安装(`skills.install`、新手引导以及 Skills 设置 UI会在执行安装器元数据之前运行内置危险代码扫描器。默认情况下`critical` 级别发现会阻止继续,除非调用方显式设置危险覆盖;可疑发现仍然只会发出警告。
- `openclaw skills install <slug>` 则不同:它会将一个 ClawHub skill 文件夹下载到工作区中,不会使用上述安装器元数据路径。
- `skills.entries.*.env``skills.entries.*.apiKey` 会将密钥注入该 agent 当前轮次的**宿主机**进程(而不是沙箱)。不要将密钥放进提示词和日志。
- 更完整的威胁模型和检查清单,参见 [Security](/zh-CN/gateway/security)。
- 将第三方 Skills 视为**不受信任代码**。启用前请先阅读。
- 对不受信任输入和高风险工具,优先使用沙箱隔离运行。参见 [沙箱隔离](/zh-CN/gateway/sandboxing)。
- 工作区和额外目录的 Skill 发现仅接受其解析后 realpath 仍位于已配置根目录内的 Skill 根目录和 `SKILL.md` 文件。
- 由 Gateway 网关 支持的 Skill 依赖安装(`skills.install`、新手引导以及 Skills 设置 UI会在执行安装器元数据之前运行内置危险代码扫描器。默认情况下`critical` 级别发现会阻止执行,除非调用方显式设置危险覆盖;可疑发现仍然只会发出警告。
- `openclaw skills install <slug>` 不同:它会将一个 ClawHub Skill 文件夹下载到工作区中,而不会使用上述安装器元数据路径。
- `skills.entries.*.env``skills.entries.*.apiKey` 会将密钥注入该智能体轮次的**宿主机**进程中(不是沙箱)。请让密钥远离提示词和日志。
- 更完整的威胁模型和检查清单,请参见 [安全](/zh-CN/gateway/security)。
## 格式AgentSkills + Pi 兼容)
## 格式AgentSkills + Pi 兼容)
`SKILL.md` 至少必须包含:
```markdown
---
name: image-lab
description: Generate or edit images via a provider-backed image workflow
description: 通过提供商支持的图像工作流生成或编辑图像
---
```
说明:
- 我们遵循 AgentSkills 规范中的布局和意图。
- 嵌入式 agent 使用的解析器仅支持**单行** frontmatter 键。
- 我们遵循 AgentSkills 规范的布局/意图。
- 嵌入式智能体使用的解析器仅支持**单行** frontmatter 键。
- `metadata` 应为**单行 JSON 对象**。
- 在说明中使用 `{baseDir}` 来引用 skill 文件夹路径。
- 可选 frontmatter 键:
- `homepage`作为“Website”显示在 macOS Skills UI 中的 URL也可通过 `metadata.openclaw.homepage` 提供)。
- `user-invocable``true|false`(默认:`true`)。当为 `true` 时,该 skill 会作为用户斜杠命令公开
- `disable-model-invocation``true|false`(默认:`false`)。当为 `true` 时,该 skill 会从模型提示词中排除(但仍可通过用户调用使用)。
- 在说明中使用 `{baseDir}` 来引用 Skill 文件夹路径。
- 可选 frontmatter 键:
- `homepage`在 macOS Skills UI 中显示为“Website”的 URL也支持通过 `metadata.openclaw.homepage` 设置)。
- `user-invocable``true|false`(默认:`true`)。`true` 时,该 Skill 会作为用户斜杠命令暴露
- `disable-model-invocation``true|false`(默认:`false`)。`true` 时,该 Skill 会从模型提示词中排除(但仍可通过用户调用使用)。
- `command-dispatch``tool`(可选)。设置为 `tool` 时,斜杠命令会绕过模型并直接分发到工具。
- `command-tool` — 当设置 `command-dispatch: tool` 时要调用的工具名称。
- `command-arg-mode``raw`(默认)。对于工具分发,会转发原始参数字符串给工具(核心不解析)。
- `command-tool` — 当设置 `command-dispatch: tool`要调用的工具名称。
- `command-arg-mode``raw`(默认)。对于工具分发,会将原始参数字符串转发给工具(核心不做解析)。
工具会使用以下参数调用:
`{ command: "<raw args>", commandName: "<slash command>", skillName: "<skill name>" }`
## 门控规则(加载时过滤)
## 门控(加载时过滤)
OpenClaw 会使用 `metadata`(单行 JSON在**加载时过滤 skills**
OpenClaw 会使用 `metadata`(单行 JSON在**加载时过滤 Skills**
```markdown
---
name: image-lab
description: Generate or edit images via a provider-backed image workflow
description: 通过提供商支持的图像工作流生成或编辑图像
metadata:
{
"openclaw":
@ -158,32 +167,32 @@ metadata:
`metadata.openclaw` 下的字段:
- `always: true` — 始终包含该 skill跳过其他门控
- `always: true` — 始终包含该 Skill跳过其他门控
- `emoji` — 可选 emoji供 macOS Skills UI 使用。
- `homepage` — 可选 URL作为“Website”显示在 macOS Skills UI 中。
- `os` — 可选平台列表(`darwin`、`linux`、`win32`)。如已设置,则该 skill 仅在这些操作系统上可用。
- `homepage` — 可选 URL在 macOS Skills UI 中显示为“Website”
- `os` — 可选平台列表(`darwin`、`linux`、`win32`)。如设置,该 Skill 仅在这些操作系统上可用。
- `requires.bins` — 列表;每一项都必须存在于 `PATH` 中。
- `requires.anyBins` — 列表;至少一项必须存在于 `PATH` 中。
- `requires.env` — 列表;环境变量必须存在,**或**在配置中提供。
- `requires.config``openclaw.json` 路径列表;这些路径必须为真值
- `requires.anyBins` — 列表;至少一项必须存在于 `PATH` 中。
- `requires.env` — 列表;环境变量必须存在,**或**在配置中提供。
- `requires.config`必须为真值的 `openclaw.json` 路径列表。
- `primaryEnv` — 与 `skills.entries.<name>.apiKey` 关联的环境变量名称。
- `install` — 可选安装器规范数组,供 macOS Skills UI 使用brew/node/go/uv/download
- `install` — 可选安装器规范数组,供 macOS Skills UI 使用brew/node/go/uv/download
关于沙箱隔离的说明:
- `requires.bins` 会在 skill 加载时于**宿主机**上检查。
- 如果某个 agent 运行在沙箱中,该二进制文件也必须存在于**容器内部**。
请通过 `agents.defaults.sandbox.docker.setupCommand`(或自定义镜像)进行安装。
- `requires.bins` 会在 Skill 加载时于**宿主机**上检查。
- 如果某个智能体处于沙箱隔离中,该二进制文件也必须**存在于容器内部**。
请通过 `agents.defaults.sandbox.docker.setupCommand`(或自定义镜像)安装
`setupCommand` 会在容器创建后运行一次。
安装软件包要网络出口、可写根文件系统以及沙箱中的 root 用户。
示例:`summarize` skill`skills/summarize/SKILL.md`)如果要在沙箱容器中运行,就需要容器内提供 `summarize` CLI
安装还要求沙箱内具备网络出口、可写根文件系统以及 root 用户。
例如,`summarize` Skill`skills/summarize/SKILL.md`)需要沙箱容器内存在 `summarize` CLI才能在那里运行
安装器示例:
```markdown
---
name: gemini
description: Use Gemini CLI for coding assistance and Google search lookups.
description: 使用 Gemini CLI 进行编码辅助和 Google 搜索查询。
metadata:
{
"openclaw":
@ -197,7 +206,7 @@ metadata:
"kind": "brew",
"formula": "gemini-cli",
"bins": ["gemini"],
"label": "Install Gemini CLI (brew)",
"label": "安装 Gemini CLIbrew",
},
],
},
@ -207,23 +216,23 @@ metadata:
说明:
- 如果列出了多个安装器Gateway 网关会选择**一个**首选方案(有 brew 时优先 brew否则优先 node
- 如果所有安装器都是 `download`OpenClaw 会列出每个条目,以便你查看所有可用制品
- 安装器规范可包含 `os: ["darwin"|"linux"|"win32"]`,用于按平台过滤选项。
- Node 安装遵循 `openclaw.json` 中的 `skills.install.nodeManager`默认npm可选npm/pnpm/yarn/bun
这只影响 **skill 安装**Gateway 网关运行时仍应使用 Node
不建议在 WhatsApp/Telegram 场景下使用 Bun
- Gateway 网关支持的安装器选择是基于偏好规则的,而不只是 node
当安装规范混合多种类型时,OpenClaw 会在启用 `skills.install.preferBrew` 且检测到 `brew` 时优先使用 Homebrew然后是 `uv`,再然后是已配置的 node 管理器,最后才是 `go``download` 等其他回退方案
- 如果每个安装规范都是 `download`OpenClaw 会展示所有下载选项,而不是收敛为一首选安装器。
- Go 安装:如果缺少 `go` 但存在 `brew`Gateway 网关会先通过 Homebrew 安装 Go并尽可能将 `GOBIN` 设为 Homebrew 的 `bin`
- 下载安装:`url`(必填)、`archive``tar.gz` | `tar.bz2` | `zip`)、`extract`(默认:检测到归档时自动提取)、`stripComponents`、`targetDir`(默认:`~/.openclaw/tools/<skillKey>`)。
- 如果列出了多个安装器Gateway 网关 会选择一个**首选**选项(如果可用则优先 brew否则 node
- 如果所有安装器都是 `download`OpenClaw 会列出每个条目,以便你查看可用工件
- 安装器规范可包含 `os: ["darwin"|"linux"|"win32"]`,用于按平台过滤选项。
- Node 安装遵循 `openclaw.json` 中的 `skills.install.nodeManager`默认npm可选npm/pnpm/yarn/bun
这只影响 **Skill 安装**Gateway 网关 运行时本身仍应使用 Node
对于 WhatsApp/Telegram不建议使用 Bun
- 由 Gateway 网关 支持的安装器选择是基于偏好驱动的,而不只是 node
当安装规范混合多种类型时,如果启用了 `skills.install.preferBrew` 且存在 `brew`OpenClaw 会优先选择 Homebrew然后是 `uv`,再然后是配置的 node 管理器,最后才是 `go``download` 等其他回退选项
- 如果每个安装规范都是 `download`OpenClaw 会展示所有下载选项,而不是收敛为一首选安装器。
- Go 安装:如果缺少 `go` 但存在 `brew`Gateway 网关 会先通过 Homebrew 安装 Go并尽可能将 `GOBIN`为 Homebrew 的 `bin`
- Download 安装:`url`(必填)、`archive``tar.gz` | `tar.bz2` | `zip`)、`extract`(默认:检测到归档时自动开启)、`stripComponents`、`targetDir`(默认:`~/.openclaw/tools/<skillKey>`)。
如果不存在 `metadata.openclaw`则该 skill 始终符合加载条件(除非它在配置中被禁用,或作为内置 skill`skills.allowBundled` 阻止)。
如果不存在 `metadata.openclaw`该 Skill 将始终符合条件(除非在配置中被禁用,或对于内置 Skills`skills.allowBundled` 阻止)。
## 配置覆盖(`~/.openclaw/openclaw.json`
可以切换内置/托管式 skills并为它们提供环境变量值:
可以为内置/托管 Skills 切换开关并提供环境变量值:
```json5
{
@ -247,61 +256,64 @@ metadata:
}
```
注意:如果 skill 名称包含连字符请给键名加引号JSON5 允许带引号的键)。
注意:如果 Skill 名称包含连字符请给键名加引号JSON5 允许带引号的键)。
如果你想在 OpenClaw 本身内部使用内置图像生成/编辑,请使用核心
`image_generate` 工具并配合 `agents.defaults.imageGenerationModel`,而不是使用某个内置 skill。这里的 skill 示例适用于自定义或第三方工作流。
如果你想直接在 OpenClaw 内部使用现成的图像生成/编辑功能,请使用核心
`image_generate` 工具并配合 `agents.defaults.imageGenerationModel`,而不是使用内置 Skill。这里的 Skill 示例适用于自定义或第三方工作流。
对于原生图像分析,请使用 `image` 工具并配合 `agents.defaults.imageModel`
对于原生图像生成/编辑,请使用 `image_generate` 并配合
`agents.defaults.imageGenerationModel`。如果你选择 `openai/*`、`google/*`、
`fal/*` 或其他提供商特定的图像模型,还需要添加该提供商的认证/API
`fal/*` 或其他提供商特定的图像模型,也请添加对应提供商的认证/API
密钥。
默认情况下,配置键与**skill 名称**一致。如果某个 skill 定义了
`metadata.openclaw.skillKey`则应`skills.entries` 下使用该键。
默认情况下,配置键与 **Skill 名称** 一致。如果某个 Skill 定义了
`metadata.openclaw.skillKey``skills.entries` 下使用该键。
规则:
- `enabled: false` 即使在该 skill 已内置/已安装的情况下,也会禁用它
- `enabled: false` 会禁用该 Skill即使它是内置/已安装的
- `env`**仅当**该变量尚未在进程中设置时才会注入。
- `apiKey`:为声明了 `metadata.openclaw.primaryEnv`skills 提供的便捷方式。
- `apiKey`:为声明了 `metadata.openclaw.primaryEnv`Skills 提供的便捷方式。
支持明文字符串或 SecretRef 对象(`{ source, provider, id }`)。
- `config`:用于自定义每个 skill 字段的可选字段包;自定义键必须放在这里。
- `allowBundled`:仅针对**内置** skills 的可选允许列表。如果设置了它,则只有列表中的内置 skills 符合条件(不影响托管式/工作区 Skills
- `config`:用于自定义每个 Skill 字段的可选配置包;自定义键必须放在这里。
- `allowBundled`:仅针对**内置** Skills 的可选 allowlist。如果设置了只有列表中的
内置 Skills 才符合条件(不影响托管/工作区 Skills
## 环境变量注入(每次 agent 运行)
## 环境变量注入(每次智能体运行)
当一次 agent 运行开始时OpenClaw 会:
当一次智能体运行开始时OpenClaw 会:
1. 读取 skill 元数据。
2. 将任 `skills.entries.<key>.env``skills.entries.<key>.apiKey` 应用到
1. 读取 Skill 元数据。
2. 将任 `skills.entries.<key>.env``skills.entries.<key>.apiKey` 应用到
`process.env`
3. 使用**符合条件** Skills 构建系统提示词。
4. 在运行结束后恢复原始环境。
3. 使用**符合条件** Skills 构建系统提示词。
4. 在运行结束后恢复原始环境变量
这是**限定在 agent 运行范围内**的,不是全局 shell 环境。
这是**限定在智能体运行范围内**的,不是全局 shell 环境。
对于内置的 `claude-cli` 后端OpenClaw 还会将相同的符合条件快照具体化为一个临时 Claude Code 插件,并通过 `--plugin-dir` 传入。随后 Claude Code 就可以使用其原生 skill 解析器,而 OpenClaw 仍然负责优先级、每个 agent 的允许列表、门控规则,以及
对于内置的 `claude-cli` 后端OpenClaw 还会将同样符合条件的快照实体化为一个临时 Claude Code 插件,并通过
`--plugin-dir` 传入。这样 Claude Code 就可以使用其原生 Skill 解析器,而 OpenClaw 仍然负责优先级、按智能体划分的 allowlists、门控以及
`skills.entries.*` 环境变量/API 密钥注入。其他 CLI 后端仅使用提示词目录。
## 会话快照(性能)
OpenClaw 会在会话开始时对符合条件的 Skills 进行快照,并在同一会话的后续轮次中复用该列表。对 skills 或配置的更改会在下一个新会话中生效。
OpenClaw 会在会话开始时对符合条件的 Skills 进行快照,并在同一会话的后续轮次中复用该列表。对 Skills 或配置的更改会在下一次新会话时生效。
启用 skills 监视器时或者当新的符合条件的远程节点出现时Skills 也可以在会话中途刷新(见下文)。你可以将其理解为一种**热重载**:刷新后的列表会在下一次 agent 轮次中生效。
当启用 Skills 监视器时或当出现新的符合条件的远程节点时Skills 也可以在会话中途刷新(见下文)。你可以将其视为一种**热重载**:刷新后的列表会在下一次智能体轮次中生效。
如果该会话的有效 agent skill 允许列表发生变化OpenClaw 会刷新快照,以便可见 Skills 始终与当前 agent 保持一致。
如果该会话的有效智能体 Skill allowlist 发生变化OpenClaw 会刷新快照,以便可见 Skills 始终与当前智能体保持一致。
## 远程 macOS 节点Linux Gateway 网关)
如果 Gateway 网关运行在 Linux 上,但已连接了一个**允许 `system.run` 的 macOS 节点**Exec approvals 安全设置不为 `deny`那么当该节点上存在所需二进制文件时OpenClaw 可以将仅限 macOS 的 skills 视为符合条件。智能体应通过 `exec` 工具并使用 `host=node` 来执行这些 skills。
如果 Gateway 网关 运行在 Linux 上,但连接了一个**允许 `system.run`** 的
**macOS 节点**Exec approvals 安全设置不为 `deny`当该节点上存在所需二进制文件时OpenClaw 可以将仅限 macOS 的 Skills 视为符合条件。智能体应通过 `exec` 工具并设置 `host=node` 来执行这些 Skills。
这依赖于节点报告其命令支持情况,并通过 `system.run` 完成二进制探测。如果该 macOS 节点之后离线,这些 skills 仍会保持可见;但在节点重新连接之前,调用可能会失败。
这依赖于节点报告其命令支持能力,以及通过 `system.run` 进行二进制探测。如果 macOS 节点随后离线,这些 Skills 仍会保持可见;在节点重新连接之前,调用可能会失败。
## Skills 监视器(自动刷新)
默认情况下OpenClaw 会监视 skill 文件夹,并在 `SKILL.md` 文件发生变化时更新 skills 快照。可在 `skills.load`配置:
默认情况下OpenClaw 会监视 Skill 文件夹,并在 `SKILL.md` 文件发生变化时更新 Skills 快照。请在 `skills.load` 下进行配置:
```json5
{
@ -316,10 +328,10 @@ OpenClaw 会在会话开始时对符合条件的 Skills 进行快照,并在同
## Token 影响Skills 列表)
有符合条件的 Skills 时OpenClaw 会将一份紧凑的可用 Skills XML 列表注入系统提示词中(通过 `pi-coding-agent` 中的 `formatSkillsForPrompt`)。其成本是确定性的:
存在符合条件的 Skills 时OpenClaw 会将一个紧凑的可用 Skills XML 列表注入系统提示词中(通过 `pi-coding-agent` 中的 `formatSkillsForPrompt`)。其开销是确定性的:
- **基础开销(仅在 ≥1 个 skill 时):** 195 个字符。
- **每个 skill** 97 个字符 + XML 转义后的 `<name>`、`<description>` 和 `<location>` 值的长度。
- **基础开销(仅当 ≥1 个 Skill 时):** 195 个字符。
- **每个 Skill** 97 个字符 + XML 转义后的 `<name>`、`<description>` 和 `<location>` 值的长度。
公式(字符数):
@ -330,17 +342,19 @@ total = 195 + Σ (97 + len(name_escaped) + len(description_escaped) + len(locati
说明:
- XML 转义会将 `& < > " '` 扩展为实体(`&amp;`、`&lt;` 等),从而增加长度。
- Token 数量会因模型分词器而异。一个粗略的 OpenAI 风格估算是约 4 个字符/Token因此**97 个字符 ≈ 24 个 Token**,再加上你实际字段内容的长度。
- Token 数量会因模型分词器而异。按 OpenAI 风格粗略估算,约为 4 个字符/Token因此**97 个字符 ≈ 24 个 Token** 每个 Skill,再加上你实际字段长度。
## 托管 Skills 生命周期
## 托管 Skills 生命周期
OpenClaw 会随安装包npm 包或 OpenClaw.app附带一组基础 Skills作为**内置 Skills**。`~/.openclaw/skills` 用于本地覆盖(例如,在不更改内置副本的情况下固定/修补某个 skill。工作区 Skills 由用户自行管理,并且在名称冲突时会覆盖两者。
OpenClaw 会将一组基线 Skills 作为安装的一部分以**内置 Skills**形式提供
npm 包或 OpenClaw.app。`~/.openclaw/skills` 用于本地覆盖
(例如,在不更改内置副本的情况下固定/修补某个 Skill。工作区 Skills 由用户拥有,并且在名称冲突时会覆盖两者。
## 配置参考
完整配置模式请参 [Skills 配置](/zh-CN/tools/skills-config)。
完整配置模式请参 [Skills 配置](/zh-CN/tools/skills-config)。
## 想找更多 Skills
## 想找更多 Skills
浏览 [https://clawhub.ai](https://clawhub.ai)。
@ -348,7 +362,7 @@ OpenClaw 会随安装包npm 包或 OpenClaw.app附带一组基础 Skills
## 相关内容
- [创建 Skills](/zh-CN/tools/creating-skills) — 构建自定义 skills
- [Skills 配置](/zh-CN/tools/skills-config) — skill 配置参考
- [斜杠命令](/zh-CN/tools/slash-commands) — 所有可用斜杠命令
- [Plugins](/zh-CN/tools/plugin) — 插件系统概览
- [创建 Skills](/zh-CN/tools/creating-skills) — 构建自定义 Skills
- [Skills 配置](/zh-CN/tools/skills-config) — Skill 配置参考
- [斜杠命令](/zh-CN/tools/slash-commands) — 所有可用斜杠命令
- [插件](/zh-CN/tools/plugin) — 插件系统概览

View File

@ -5,32 +5,32 @@ read_when:
- 你需要选择一个搜索提供商
- 你想了解自动检测和提供商回退机制
sidebarTitle: Web Search
summary: '`web_search`、`x_search` 和 `web_fetch` —— 搜索网络、搜索 X 帖子,或抓取页面内容'
summary: '`web_search`、`x_search` 和 `web_fetch`——搜索网页、搜索 X 帖子或抓取页面内容'
title: Web 搜索
x-i18n:
generated_at: "2026-04-21T01:06:28Z"
generated_at: "2026-04-21T20:35:30Z"
model: gpt-5.4
provider: openai
source_hash: 9e88a891ce28a5fe1baf4b9ce8565c59ba2d2695c63d77af232edd7f3fd2cd8a
source_hash: ec2517d660465f850b1cfdd255fbf512dc5c828b1ef22e3b24cec6aab097ebd5
source_path: tools/web.md
workflow: 15
---
# Web 搜索
`web_search` 工具使用你配置的提供商搜索网络并返回结果。结果按查询缓存 15 分钟(可配置)。
`web_search` 工具使用你已配置的提供商搜索网页并返回结果。结果会按查询缓存 15 分钟(可配置)。
OpenClaw 还包含用于搜索 X原 Twitter帖子 的 `x_search`,以及用于轻量级 URL 抓取的 `web_fetch`。在当前阶段,`web_fetch` 保持本地运行,而 `web_search``x_search` 可以在底层使用 xAI Responses。
OpenClaw 还包含用于搜索 X原 Twitter帖子 的 `x_search`,以及用于轻量级 URL 抓取的 `web_fetch`。在这一阶段,`web_fetch` 保持本地运行,而 `web_search``x_search` 可以在底层使用 xAI Responses。
<Info>
`web_search`一个轻量级 HTTP 工具,不是浏览器自动化。对于大量依赖 JS 的网站或需要登录的场景,请使用 [Web Browser](/zh-CN/tools/browser)。如抓取特定 URL请使用 [Web Fetch](/zh-CN/tools/web-fetch)。
`web_search` 是轻量级 HTTP 工具,不是浏览器自动化。对于大量依赖 JS 的网站或需要登录的场景,请使用 [Web Browser](/zh-CN/tools/browser)。如果要抓取特定 URL请使用 [Web Fetch](/zh-CN/tools/web-fetch)。
</Info>
## 快速开始
<Steps>
<Step title="选择提供商">
选择一个提供商并完成所需设置。有些提供商不需要密钥,而另一些则使用 API 密钥。详情请参阅下方各提供商页面。
选择一个提供商并完成所需设置。有些提供商无需密钥,而另一些则使用 API 密钥。详情请参见下方的提供商页面。
</Step>
<Step title="配置">
```bash
@ -38,7 +38,7 @@ OpenClaw 还包含用于搜索 X原 Twitter帖子 的 `x_search`,以及
```
这会存储提供商以及所需的任何凭证。你也可以设置环境变量(例如 `BRAVE_API_KEY`),并对基于 API 的提供商跳过此步骤。
</Step>
<Step title="使用">
<Step title="使用">
智能体现在可以调用 `web_search`
```javascript
@ -58,59 +58,59 @@ OpenClaw 还包含用于搜索 X原 Twitter帖子 的 `x_search`,以及
<CardGroup cols={2}>
<Card title="Brave Search" icon="shield" href="/zh-CN/tools/brave-search">
带摘要片段的结构化结果。支持 `llm-context` 模式、国家/语言筛选。提供免费套餐
带摘要片段的结构化结果。支持 `llm-context` 模式、国家 / 语言筛选。提供免费层级
</Card>
<Card title="DuckDuckGo" icon="bird" href="/zh-CN/tools/duckduckgo-search">
无密钥回退选项。无需 API 密钥。基于非官方 HTML 集成。
无密钥回退。无需 API 密钥。基于非官方 HTML 集成。
</Card>
<Card title="Exa" icon="brain" href="/zh-CN/tools/exa-search">
神经网络 + 关键词搜索,并支持内容提取(高亮、文、摘要)。
神经网络 + 关键词搜索,并支持内容提取(高亮、文、摘要)。
</Card>
<Card title="Firecrawl" icon="flame" href="/zh-CN/tools/firecrawl">
结构化结果。最适合与 `firecrawl_search``firecrawl_scrape` 配使用,以进行深度提取。
结构化结果。最适合与 `firecrawl_search``firecrawl_scrape`使用,以进行深度提取。
</Card>
<Card title="Gemini" icon="sparkles" href="/zh-CN/tools/gemini-search">
通过 Google Search grounding 提供带引用的 AI 综合回答
通过 Google 搜索 grounding 提供带引用的 AI 综合答案
</Card>
<Card title="Grok" icon="zap" href="/zh-CN/tools/grok-search">
通过 xAI web grounding 提供带引用的 AI 综合回答
通过 xAI 网页 grounding 提供带引用的 AI 综合答案
</Card>
<Card title="Kimi" icon="moon" href="/zh-CN/tools/kimi-search">
通过 Moonshot web search 提供带引用的 AI 综合回答
通过 Moonshot 网页搜索提供带引用的 AI 综合答案
</Card>
<Card title="MiniMax Search" icon="globe" href="/zh-CN/tools/minimax-search">
通过 MiniMax Coding Plan 搜索 API 提供结构化结果。
</Card>
<Card title="Ollama Web Search" icon="globe" href="/zh-CN/tools/ollama-search">
通过你配置的 Ollama 主机进行无密钥搜索。需要`ollama signin`
通过你配置的 Ollama 主机进行无密钥搜索。需要先运`ollama signin`
</Card>
<Card title="Perplexity" icon="search" href="/zh-CN/tools/perplexity-search">
带内容提取控制和域名筛选的结构化结果。
带内容提取控制和域过滤的结构化结果。
</Card>
<Card title="SearXNG" icon="server" href="/zh-CN/tools/searxng-search">
自托管元搜索。无需 API 密钥。聚合 Google、Bing、DuckDuckGo 等搜索引擎
自托管元搜索。无需 API 密钥。聚合 Google、Bing、DuckDuckGo 等搜索
</Card>
<Card title="Tavily" icon="globe" href="/zh-CN/tools/tavily">
结构化结果,支持搜索深度、主题筛选,以及用于 URL 提取的 `tavily_extract`
带搜索深度、主题筛选以及用于 URL 提取的 `tavily_extract` 的结构化结果
</Card>
</CardGroup>
### 提供商对比
| 提供商 | 结果样式 | 筛选 | API 密钥 |
| 提供商 | 结果样式 | 筛选条件 | API 密钥 |
| ----------------------------------------- | -------------------------- | ------------------------------------------------ | -------------------------------------------------------------------------------- |
| [Brave](/zh-CN/tools/brave-search) | 结构化摘要片段 | 国家、语言、时间、`llm-context` 模式 | `BRAVE_API_KEY` |
| [DuckDuckGo](/zh-CN/tools/duckduckgo-search) | 结构化摘要片段 | -- | 无(无密钥) |
| [Exa](/zh-CN/tools/exa-search) | 结构化 + 提取内容 | 神经/关键词模式、日期、内容提取 | `EXA_API_KEY` |
| [Firecrawl](/zh-CN/tools/firecrawl) | 结构化摘要片段 | 通过 `firecrawl_search` 工具 | `FIRECRAWL_API_KEY` |
| [Gemini](/zh-CN/tools/gemini-search) | AI 综合回答 + 引用 | -- | `GEMINI_API_KEY` |
| [Grok](/zh-CN/tools/grok-search) | AI 综合回答 + 引用 | -- | `XAI_API_KEY` |
| [Kimi](/zh-CN/tools/kimi-search) | AI 综合回答 + 引用 | -- | `KIMI_API_KEY` / `MOONSHOT_API_KEY` |
| [MiniMax Search](/zh-CN/tools/minimax-search) | 结构化摘要片段 | 区域(`global` / `cn` | `MINIMAX_CODE_PLAN_KEY` / `MINIMAX_CODING_API_KEY` |
| [Ollama Web Search](/zh-CN/tools/ollama-search) | 结构化摘要片段 | -- | 默认无;需要执行 `ollama signin`,并且可复用 Ollama 提供商的 bearer 认证 |
| [Perplexity](/zh-CN/tools/perplexity-search) | 结构化摘要片段 | 国家、语言、时间、域名、内容限制 | `PERPLEXITY_API_KEY` / `OPENROUTER_API_KEY` |
| [SearXNG](/zh-CN/tools/searxng-search) | 结构化摘要片段 | 类别、语言 | 无(自托管) |
| [Tavily](/zh-CN/tools/tavily) | 结构化摘要片段 | 通过 `tavily_search` 工具 | `TAVILY_API_KEY` |
| [Brave](/zh-CN/tools/brave-search) | 结构化摘要片段 | 国家、语言、时间、`llm-context` 模式 | `BRAVE_API_KEY` |
| [DuckDuckGo](/zh-CN/tools/duckduckgo-search) | 结构化摘要片段 | -- | 无(无密钥) |
| [Exa](/zh-CN/tools/exa-search) | 结构化 + 提取内容 | 神经 / 关键词模式、日期、内容提取 | `EXA_API_KEY` |
| [Firecrawl](/zh-CN/tools/firecrawl) | 结构化摘要片段 | 通过 `firecrawl_search` 工具 | `FIRECRAWL_API_KEY` |
| [Gemini](/zh-CN/tools/gemini-search) | AI 综合结果 + 引用 | -- | `GEMINI_API_KEY` |
| [Grok](/zh-CN/tools/grok-search) | AI 综合结果 + 引用 | -- | `XAI_API_KEY` |
| [Kimi](/zh-CN/tools/kimi-search) | AI 综合结果 + 引用 | -- | `KIMI_API_KEY` / `MOONSHOT_API_KEY` |
| [MiniMax Search](/zh-CN/tools/minimax-search) | 结构化摘要片段 | 区域(`global` / `cn` | `MINIMAX_CODE_PLAN_KEY` / `MINIMAX_CODING_API_KEY` |
| [Ollama Web Search](/zh-CN/tools/ollama-search) | 结构化摘要片段 | -- | 默认无;需要 `ollama signin`,并可复用 Ollama 提供商 bearer 凭证 |
| [Perplexity](/zh-CN/tools/perplexity-search) | 结构化摘要片段 | 国家、语言、时间、域名、内容限制 | `PERPLEXITY_API_KEY` / `OPENROUTER_API_KEY` |
| [SearXNG](/zh-CN/tools/searxng-search) | 结构化摘要片段 | 类别、语言 | 无(自托管) |
| [Tavily](/zh-CN/tools/tavily) | 结构化摘要片段 | 通过 `tavily_search` 工具 | `TAVILY_API_KEY` |
## 自动检测
@ -118,9 +118,9 @@ OpenClaw 还包含用于搜索 X原 Twitter帖子 的 `x_search`,以及
支持 Codex 的模型可以选择使用提供商原生的 Responses `web_search` 工具,而不是 OpenClaw 托管的 `web_search` 函数。
- 在 `tools.web.search.openaiCodex`进行配置
- 它仅对支持 Codex 的模型激活`openai-codex/*` 或使用 `api: "openai-codex-responses"` 的提供商)
- 对于非 Codex 模型,仍会使用托管的 `web_search`
- 在 `tools.web.search.openaiCodex` 下配置
- 它只会对支持 Codex 的模型启用`openai-codex/*` 或使用 `api: "openai-codex-responses"` 的提供商)
- 托管式 `web_search` 仍适用于非 Codex 模型
- `mode: "cached"` 是默认且推荐的设置
- `tools.web.search.enabled: false` 会同时禁用托管搜索和原生搜索
@ -147,15 +147,15 @@ OpenClaw 还包含用于搜索 X原 Twitter帖子 的 `x_search`,以及
}
```
如果启用原生 Codex 搜索,但当前模型不支持 CodexOpenClaw 会继续保持正常的托管 `web_search` 行为。
如果启用原生 Codex 搜索,但当前模型不支持 CodexOpenClaw 会保留正常的托管 `web_search` 行为。
## 设置 Web 搜索
文档和设置流程中的提供商列表按字母顺序排列。自动检测使用单独的优先级顺序。
文档和设置流程中的提供商列表按字母顺序排列。自动检测使用单独的优先级顺序。
如果未设置 `provider`OpenClaw 会按以下顺序检查提供商,并使用第一个已就绪的提供商:
首先是基于 API 的提供商:
优先检查基于 API 的提供商:
1. **Brave** -- `BRAVE_API_KEY``plugins.entries.brave.config.webSearch.apiKey`(顺序 10
2. **MiniMax Search** -- `MINIMAX_CODE_PLAN_KEY` / `MINIMAX_CODING_API_KEY``plugins.entries.minimax.config.webSearch.apiKey`(顺序 15
@ -167,16 +167,16 @@ OpenClaw 还包含用于搜索 X原 Twitter帖子 的 `x_search`,以及
8. **Exa** -- `EXA_API_KEY``plugins.entries.exa.config.webSearch.apiKey`(顺序 65
9. **Tavily** -- `TAVILY_API_KEY``plugins.entries.tavily.config.webSearch.apiKey`(顺序 70
之后是不需要密钥的回退项
之后是无密钥回退
10. **DuckDuckGo** -- 无需账号或 API 密钥的无密钥 HTML 回退(顺序 100
11. **Ollama Web 搜索** -- 通过你配置的 Ollama 主机进行无密钥回退;要求 Ollama 可访问,并已通过 `ollama signin` 登录;如果主机需要认证,也可以复用 Ollama 提供商的 bearer 认证(顺序 110
10. **DuckDuckGo** -- 无账号、无 API 密钥的 HTML 无密钥回退(顺序 100
11. **Ollama Web 搜索** -- 通过你配置的 Ollama 主机进行无密钥回退;要求 Ollama 可访问,并已通过 `ollama signin` 登录;如果主机需要,也可以复用 Ollama 提供商 bearer 凭证(顺序 110
12. **SearXNG** -- `SEARXNG_BASE_URL``plugins.entries.searxng.config.webSearch.baseUrl`(顺序 200
如果没有检测到任何提供商,它会回退到 Brave你会收到缺少密钥的错误提示,要求你进行配置)。
如果未检测到任何提供商,它会回退到 Brave你将收到缺少密钥的错误提示,要求你进行配置)。
<Note>
所有提供商密钥字段都支持 SecretRef 对象。在自动检测模式下OpenClaw 只会解析已选中提供商的密钥——未选中的 SecretRef 会保持未激活状态
所有提供商密钥字段都支持 SecretRef 对象。位于 `plugins.entries.<plugin>.config.webSearch.apiKey` 下、作用域限定到插件的 SecretRef会对内置的 Exa、Firecrawl、Gemini、Grok、Kimi、Perplexity 和 Tavily 提供商进行解析,无论提供商是通过 `tools.web.search.provider` 显式选择还是通过自动检测选中。在自动检测模式下OpenClaw 只会解析被选中提供商的密钥——未被选中的 SecretRef 会保持不活跃,因此你可以同时配置多个提供商,而不必为未使用的提供商承担解析成本
</Note>
## 配置
@ -197,35 +197,33 @@ OpenClaw 还包含用于搜索 X原 Twitter帖子 的 `x_search`,以及
}
```
特定于提供商的配置API 密钥、基础 URL、模式位于
`plugins.entries.<plugin>.config.webSearch.*` 下。示例请参各提供商页面。
提供商特定配置API 密钥、base URL、模式位于
`plugins.entries.<plugin>.config.webSearch.*` 下。示例请参各提供商页面。
`web_fetch` 的回退提供商选择是独立的:
- 使用 `tools.web.fetch.provider` 选择它
- 或省略该字段,让 OpenClaw 根据可用凭证自动检测第一个已就绪的 web-fetch 提供商
- 当前内置的 web-fetch 提供商是 Firecrawl配置位于
`plugins.entries.firecrawl.config.webFetch.*`
- 使用 `tools.web.fetch.provider` 进行选择
- 或省略该字段,让 OpenClaw 从可用凭证中自动检测第一个已就绪的 `web_fetch` 提供商
- 当前内置的 `web_fetch` 提供商是 Firecrawl配置位于 `plugins.entries.firecrawl.config.webFetch.*`
当你在 `openclaw onboard`
`openclaw configure --section web` 期间选择 **Kimi**OpenClaw 还可能询问:
`openclaw configure --section web` 中选择 **Kimi**OpenClaw 还可能会询问:
- Moonshot API 区域(`https://api.moonshot.ai/v1` 或 `https://api.moonshot.cn/v1`
- 默认的 Kimi Web 搜索模型(默认 `kimi-k2.6`
- 默认的 Kimi Web 搜索模型(默认 `kimi-k2.6`
对于 `x_search`,请配置 `plugins.entries.xai.config.xSearch.*`。它使用与 Grok Web 搜索相同的 `XAI_API_KEY` 回退机制
对于 `x_search`,请配置 `plugins.entries.xai.config.xSearch.*`。它使用与 Grok Web 搜索相同的 `XAI_API_KEY` 回退。
旧版 `tools.web.x_search.*` 配置会由 `openclaw doctor --fix` 自动迁移。
当你在 `openclaw onboard``openclaw configure --section web` 期间选择 Grok 时,
OpenClaw 还可以使用同一个密钥提供可选的 `x_search` 设置。
这是 Grok 路径中的一个单独后续步骤,而不是一个单独的顶级
Web 搜索提供商选项。如果你选择其他提供商OpenClaw 不会
显示 `x_search` 提示。
当你在 `openclaw onboard``openclaw configure --section web` 中选择 Grok 时,
OpenClaw 还可以提供可选的 `x_search` 设置,并使用同一个密钥。
这是 Grok 路径中的单独后续步骤,而不是单独的顶层 Web 搜索提供商选择。
如果你选择其他提供商OpenClaw 不会显示 `x_search` 提示。
### 存储 API 密钥
<Tabs>
<Tab title="配置文件">
运行 `openclaw configure --section web` 或直接设置密钥:
运行 `openclaw configure --section web`或直接设置密钥:
```json5
{
@ -251,8 +249,8 @@ Web 搜索提供商选项。如果你选择其他提供商OpenClaw 不会
export BRAVE_API_KEY="YOUR_KEY"
```
对于 Gateway 网关安装,请将放在 `~/.openclaw/.env` 中。
请参阅 [环境变量](/zh-CN/help/faq#env-vars-and-env-loading)。
对于 Gateway 网关安装,请将放在 `~/.openclaw/.env` 中。
参见 [环境变量](/zh-CN/help/faq#env-vars-and-env-loading)。
</Tab>
</Tabs>
@ -261,38 +259,39 @@ Web 搜索提供商选项。如果你选择其他提供商OpenClaw 不会
| 参数 | 说明 |
| --------------------- | ----------------------------------------------------- |
| `query` | 搜索查询(必填) |
| `count` | 返回结果数1-10默认5 |
| `country` | 2 位 ISO 国家代码(例如 `"US"`、`"DE"` |
| `language` | ISO 639-1 语言代码(例如 `"en"`、`"de"` |
| `search_lang` | 搜索语言代码(仅 Brave 支持) |
| `freshness` | 时间筛选:`day`、`week`、`month` 或 `year` |
| `date_after` | 此日期之后的结果YYYY-MM-DD |
| `date_before` | 此日期之前的结果YYYY-MM-DD |
| `ui_lang` | UI 语言代码(仅 Brave 支持) |
| `domain_filter` | 域名允许列表/拒绝列表数组(仅 Perplexity 支持) |
| `max_tokens` | 总内容预算,默认 25000仅 Perplexity 支持) |
| `max_tokens_per_page` | 每页 token 限制,默认 2048仅 Perplexity 支持) |
| `query` | 搜索查询(必填) |
| `count` | 返回结果数1-10默认5 |
| `country` | 2 字母 ISO 国家代码(例如 `"US"`、`"DE"` |
| `language` | ISO 639-1 语言代码(例如 `"en"`、`"de"` |
| `search_lang` | 搜索语言代码(仅 Brave 支持) |
| `freshness` | 时间筛选:`day`、`week`、`month` 或 `year` |
| `date_after` | 此日期之后的结果YYYY-MM-DD |
| `date_before` | 此日期之前的结果YYYY-MM-DD |
| `ui_lang` | UI 语言代码(仅 Brave 支持) |
| `domain_filter` | 域名允许列表 / 拒绝列表数组(仅 Perplexity 支持) |
| `max_tokens` | 总内容预算,默认 25000仅 Perplexity 支持) |
| `max_tokens_per_page` | 每页 token 限制,默认 2048仅 Perplexity 支持) |
<Warning>
并非所有参数都适用于所有提供商。Brave 的 `llm-context` 模式会拒绝 `ui_lang`、`freshness`、`date_after` 和 `date_before`
Gemini、Grok 和 Kimi 会返回一条带引用的 AI 综合回答。
它们接受 `count` 以保持共享工具兼容性,但这不会改变基于 grounding 的回答形态。
当你使用 Sonar/OpenRouter
并非所有参数都适用于所有提供商。Brave 的 `llm-context` 模式
会拒绝 `ui_lang`、`freshness`、`date_after` 和 `date_before`
Gemini、Grok 和 Kimi 会返回一条带引用的 AI 综合答案。它们会接受
`count` 以保持共享工具兼容性,但这不会改变 grounding 答案的结构。
当你使用 Sonar / OpenRouter
兼容路径(`plugins.entries.perplexity.config.webSearch.baseUrl` /
`model``OPENROUTER_API_KEY`Perplexity 的行为也是如此。
SearXNG 仅对受信任的私有网络或 loopback 主机接受 `http://`
SearXNG 端点必须使用 `https://`
Firecrawl 和 Tavily 通过 `web_search` 仅支持 `query``count`
—— 如需高级选项请使用它们各自的专用工具。
开的 SearXNG 端点必须使用 `https://`
Firecrawl 和 Tavily 通过 `web_search`
仅支持 `query``count`——高级选项请使用它们各自的专用工具。
</Warning>
## x_search
`x_search` 使用 xAI 查询 X原 Twitter帖子并返回带引用的 AI 综合回答。它接受自然语言查询以及可选的结构化筛选条件。OpenClaw 仅会在服务于此工具调用的请求上启用内置的 xAI `x_search` 工具。
`x_search` 使用 xAI 查询 X原 Twitter帖子并返回带引用的 AI 综合答案。它接受自然语言查询和可选的结构化筛选条件。OpenClaw 只会在服务此工具调用的请求中启用内置的 xAI `x_search` 工具。
<Note>
xAI 文档说明 `x_search` 支持关键词搜索、语义搜索、用户搜索和线程抓取。对于单条帖子的互动统计数据,例如转发、回复、收藏或浏览量,优先针对确切帖子 URL 或状态 ID 进行定向查询。宽泛的关键词搜索可能能找到正确的帖子,但返回的单帖元数据不够完整。一个好的模式是:先定位帖子,再运行第二次 `x_search` 查询,聚焦于该确切帖子
xAI 文档说明 `x_search` 支持关键词搜索、语义搜索、用户搜索和线程抓取。对于单条帖子的互动统计,例如转发、回复、收藏或浏览量,优先建议对准确的帖子 URL 或状态 ID 进行定向查找。宽泛的关键词搜索可能能找到正确帖子,但返回的单帖元数据可能不够完整。一个好的模式是:先定位帖子,再运行第二个聚焦该准确帖子的 `x_search` 查询
</Note>
### x_search 配置
@ -325,13 +324,13 @@ Web 搜索提供商选项。如果你选择其他提供商OpenClaw 不会
| 参数 | 说明 |
| ---------------------------- | ------------------------------------------------------ |
| `query` | 搜索查询(必填) |
| `allowed_x_handles` | 将结果限制为特定 X 账号 |
| `excluded_x_handles` | 排除特定 X 账号 |
| `from_date` | 仅包含此日期当日或之后的帖子YYYY-MM-DD |
| `to_date` | 仅包含此日期当日或之前的帖子YYYY-MM-DD |
| `enable_image_understanding` | 允许 xAI 分析匹配帖子所附带的图片 |
| `enable_video_understanding` | 允许 xAI 分析匹配帖子所附带的视频 |
| `query` | 搜索查询(必填) |
| `allowed_x_handles` | 将结果限制为特定 X 账号 |
| `excluded_x_handles` | 排除特定 X 账号 |
| `from_date` | 仅包含此日期当日或之后的帖子YYYY-MM-DD |
| `to_date` | 仅包含此日期当日或之前的帖子YYYY-MM-DD |
| `enable_image_understanding` | 让 xAI 检查匹配帖子附带的图片 |
| `enable_video_understanding` | 让 xAI 检查匹配帖子附带的视频 |
### x_search 示例
@ -392,6 +391,6 @@ await web_search({
## 相关内容
- [Web Fetch](/zh-CN/tools/web-fetch) -- 抓取 URL 并提取可读内容
- [Web Browser](/zh-CN/tools/browser) -- 用于大量依赖 JS 的网站的完整浏览器自动化
- [Grok Search](/zh-CN/tools/grok-search) -- 将 Grok `web_search` 提供商
- [Ollama Web Search](/zh-CN/tools/ollama-search) -- 通过你的 Ollama 主机进行无密钥 Web 搜索
- [Web Browser](/zh-CN/tools/browser) -- 用于重度依赖 JS 网站的完整浏览器自动化
- [Grok Search](/zh-CN/tools/grok-search) -- 将 Grok 作 `web_search` 提供商
- [Ollama Web 搜索](/zh-CN/tools/ollama-search) -- 通过你的 Ollama 主机进行无密钥 Web 搜索