From c6f525429995da0325bb4e1b89cef467cf4b4c09 Mon Sep 17 00:00:00 2001 From: "openclaw-docs-i18n[bot]" Date: Tue, 21 Apr 2026 20:38:41 +0000 Subject: [PATCH] chore(i18n): refresh zh-CN translations --- docs/zh-CN/channels/msteams.md | 404 ++++++------ docs/zh-CN/channels/qqbot.md | 110 ++-- docs/zh-CN/channels/telegram.md | 436 +++++++------ docs/zh-CN/plan/ui-channels.md | 261 ++++++++ docs/zh-CN/plugins/architecture.md | 725 +++++++++++---------- docs/zh-CN/plugins/manifest.md | 310 +++++---- docs/zh-CN/plugins/message-presentation.md | 326 +++++++++ docs/zh-CN/plugins/sdk-overview.md | 384 +++++------ docs/zh-CN/plugins/skill-workshop.md | 708 ++++++++++++++++++++ docs/zh-CN/tools/skills.md | 256 ++++---- docs/zh-CN/tools/web.md | 181 +++-- 11 files changed, 2726 insertions(+), 1375 deletions(-) create mode 100644 docs/zh-CN/plan/ui-channels.md create mode 100644 docs/zh-CN/plugins/message-presentation.md create mode 100644 docs/zh-CN/plugins/skill-workshop.md diff --git a/docs/zh-CN/channels/msteams.md b/docs/zh-CN/channels/msteams.md index 6f947d901..66f487f19 100644 --- a/docs/zh-CN/channels/msteams.md +++ b/docs/zh-CN/channels/msteams.md @@ -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**(等待约 1–2 分钟) ### 第 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 ### 选项 B:Azure 托管身份 -使用 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 --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`。进行本地开发时请使用隧道: **选项 A:ngrok** @@ -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 **选项 A:Azure 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 设置之前已正常工作 -**选项 B:Teams(安装应用后)** +**选项 B:Teams(安装应用之后)** -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://: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[""].historyLimit`。 +- 私信历史可通过 `channels.msteams.dmHistoryLimit`(用户轮次)限制。每用户覆盖项:`channels.msteams.dms[""].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: - **选项 A(Teams 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 ID(Azure AD)**App Registration** 中,添加 Microsoft Graph **Application permissions**: +1. 在 Entra ID(Azure 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..replyStyle`:按团队覆盖。 - `channels.msteams.teams..requireMention`:按团队覆盖。 -- `channels.msteams.teams..tools`:按团队的默认工具策略覆盖(`allow`/`deny`/`alsoAllow`),在缺少渠道覆盖时使用。 -- `channels.msteams.teams..toolsBySender`:按团队的默认按发送者工具策略覆盖(支持 `"*"` 通配符)。 +- `channels.msteams.teams..tools`:按团队的默认工具策略覆盖(`allow`/`deny`/`alsoAllow`),当缺少渠道覆盖时使用。 +- `channels.msteams.teams..toolsBySender`:按团队、按发送者的默认工具策略覆盖(支持 `"*"` 通配符)。 - `channels.msteams.teams..channels..replyStyle`:按渠道覆盖。 - `channels.msteams.teams..channels..requireMention`:按渠道覆盖。 - `channels.msteams.teams..channels..tools`:按渠道的工具策略覆盖(`allow`/`deny`/`alsoAllow`)。 -- `channels.msteams.teams..channels..toolsBySender`:按渠道的按发送者工具策略覆盖(支持 `"*"` 通配符)。 +- `channels.msteams.teams..channels..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::msteams:channel:` - `agent::msteams:group:` -## 回复样式:线程 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 ID(Azure AD)→ App Registration 中添加 Graph API 权限: - - `Sites.ReadWrite.All`(Application)- 上传文件到 SharePoint +1. 在 Entra ID(Azure 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: ...` -- 投票由 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:", - 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”:** 该应用仍安装在另一个团队/聊天中。请先找到并卸载,或等待 5–10 分钟完成传播。 +- **“Icon file cannot be empty”:** manifest 引用了 0 字节的图标文件。请创建有效的 PNG 图标(`outline.png` 为 32x32,`color.png` 为 192x192)。 +- **“webApplicationInfo.Id already in use”:** 该应用仍安装在另一个团队/聊天中。请先找到并卸载,或等待 5–10 分钟让变更传播。 - **上传时出现 “Something went wrong”:** 请改为通过 [https://admin.teams.microsoft.com](https://admin.teams.microsoft.com) 上传,打开浏览器 DevTools(F12)→ 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) — 访问模型和安全加固 diff --git a/docs/zh-CN/channels/qqbot.md b/docs/zh-CN/channels/qqbot.md index 4e3fc41c7..4a9cd1e95 100644 --- a/docs/zh-CN/channels/qqbot.md +++ b/docs/zh-CN/channels/qqbot.md @@ -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 API(WebSocket 网关)连接到 OpenClaw。该插件支持 C2C 私聊、群 @ 消息以及频道消息,并支持丰富媒体(图片、语音、视频、文件)。 +QQ Bot 通过官方 QQ Bot API(WebSocket 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 ...` 仅提供 - AppSecret;AppID 必须已在配置或 `QQBOT_APP_ID` 中设置。 -- `clientSecret` 也接受 SecretRef 输入,而不只是明文字符串。 +- 环境变量回退仅适用于默认 QQ Bot 账户。 +- `openclaw channels add --channel qqbot --token-file ...` 仅提供 AppSecret;AppID 必须已在配置中设置,或通过 `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,并且对应提供商可访问。 diff --git a/docs/zh-CN/channels/telegram.md b/docs/zh-CN/channels/telegram.md index 93727145c..a6575695a 100644 --- a/docs/zh-CN/channels/telegram.md +++ b/docs/zh-CN/channels/telegram.md @@ -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 --- # Telegram(Bot API) -状态:通过 grammY 支持用于机器人私信和群组的生产就绪。长轮询是默认模式;Webhook 模式为可选。 +状态:基于 grammY 的机器人私信 + 群组支持已可用于生产环境。默认模式为长轮询;webhook 模式为可选。 Telegram 的默认私信策略是配对。 - 跨渠道诊断和修复操作手册。 + 跨渠道诊断与修复手册。 - 完整的渠道配置模式和示例。 + 完整的渠道配置模式与示例。 @@ -32,9 +32,9 @@ x-i18n: - 打开 Telegram 并与 **@BotFather** 对话(确认用户名严格为 `@BotFather`)。 + 打开 Telegram 并与 **@BotFather** 聊天(确认用户名严格为 `@BotFather`)。 - 运行 `/newbot`,按照提示操作,并保存令牌。 + 运行 `/newbot`,按提示操作,并保存令牌。 @@ -71,31 +71,31 @@ openclaw pairing approve telegram - 将机器人添加到你的群组,然后设置 `channels.telegram.groups` 和 `groupPolicy` 以匹配你的访问模型。 + 将机器人添加到你的群组中,然后设置 `channels.telegram.groups` 和 `groupPolicy`,使其与你的访问模型匹配。 -令牌解析顺序与账户相关。实际生效时,配置值优先于环境变量回退,并且 `TELEGRAM_BOT_TOKEN` 仅适用于默认账户。 +令牌解析顺序是账户感知的。实际行为是,配置中的值优先于环境变量回退,而 `TELEGRAM_BOT_TOKEN` 仅适用于默认账户。 -## Telegram 端设置 +## Telegram 侧设置 Telegram 机器人默认启用 **隐私模式**,这会限制它们能接收到的群组消息。 - 如果机器人必须看到所有群组消息,可以选择以下任一方式: + 如果机器人必须看到所有群组消息,可以采用以下任一方式: - 通过 `/setprivacy` 禁用隐私模式,或 - 将机器人设为群组管理员。 - 切换隐私模式后,请在每个群组中移除并重新添加该机器人,以便 Telegram 应用更改。 + 切换隐私模式后,请在每个群组中移除并重新添加机器人,以便 Telegram 应用该更改。 - 管理员身份在 Telegram 群组设置中控制。 + 管理员状态在 Telegram 群组设置中控制。 管理员机器人会接收所有群组消息,这对于始终在线的群组行为很有用。 @@ -103,13 +103,13 @@ openclaw pairing approve telegram - - `/setjoingroups`:允许/禁止加入群组 + - `/setjoingroups`:允许/拒绝加入群组 - `/setprivacy`:控制群组可见性行为 -## 访问控制和激活 +## 访问控制与激活 @@ -120,23 +120,23 @@ openclaw pairing approve telegram - `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 curl "https://api.telegram.org/bot/getUpdates" ``` - 第三方方法(隐私性较低):`@userinfobot` 或 `@getidsbot`。 + 第三方方法(隐私性较差):`@userinfobot` 或 `@getidsbot`。 - - 以下两个控制项会共同生效: + + 有两个控制项会一起生效: 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/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/getUpdates" } ``` - 示例:只允许某个特定群组中的指定用户: + 示例:仅允许某个特定群组中的特定用户: ```json5 { @@ -209,11 +209,11 @@ curl "https://api.telegram.org/bot/getUpdates" ``` - 常见错误:`groupAllowFrom` 不是 Telegram 群组允许列表。 + 常见错误:`groupAllowFrom` 不是 Telegram 群组 allowlist。 - 将 `-1001234567890` 这类负数 Telegram 群组或超级群组聊天 ID 放在 `channels.telegram.groups` 下。 - - 当你想限制已允许群组中哪些人可以触发机器人时,将类似 `8734062810` 的 Telegram 用户 ID 放在 `groupAllowFrom` 下。 - - 仅当你希望已允许群组中的任意成员都能与机器人对话时,才使用 `groupAllowFrom: ["*"]`。 + - 当你想限制允许群组中哪些人可以触发机器人时,将 `8734062810` 这类 Telegram 用户 ID 放在 `groupAllowFrom` 下。 + - 仅当你希望允许群组中的任意成员都能与机器人对话时,才使用 `groupAllowFrom: ["*"]`。 @@ -233,9 +233,9 @@ curl "https://api.telegram.org/bot/getUpdates" - `/activation always` - `/activation mention` - 这些只会更新会话状态。要持久化,请使用配置。 + 这些只更新会话状态。若要持久化,请使用配置。 - 持久配置示例: + 持久化配置示例: ```json5 { @@ -249,11 +249,11 @@ curl "https://api.telegram.org/bot/getUpdates" } ``` - 获取群组聊天 ID: + 获取群组聊天 ID 的方法: - 将群组消息转发给 `@userinfobot` / `@getidsbot` - 或从 `openclaw logs --follow` 中读取 `chat.id` - - 或查看 Bot API `getUpdates` + - 或检查 Bot API `getUpdates` @@ -262,11 +262,11 @@ curl "https://api.telegram.org/bot/getUpdates" - Telegram 由 Gateway 网关进程持有。 - 路由是确定性的:Telegram 入站回复会回到 Telegram(模型不会选择渠道)。 -- 入站消息会标准化为共享渠道信封格式,包含回复元数据和媒体占位符。 +- 入站消息会被规范化为共享渠道信封格式,并附带回复元数据与媒体占位符。 - 群组会话按群组 ID 隔离。论坛话题会追加 `:topic:` 以保持话题隔离。 - 私信消息可以携带 `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/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/getUpdates" - 类 Markdown 文本会被渲染为 Telegram 安全的 HTML。 - 原始模型 HTML 会被转义,以减少 Telegram 解析失败。 - - 如果 Telegram 拒绝解析后的 HTML,OpenClaw 会以纯文本重试。 + - 如果 Telegram 拒绝解析后的 HTML,OpenClaw 会重试纯文本。 - 链接预览默认启用,可通过 `channels.telegram.linkPreview: false` 禁用。 + 链接预览默认启用,可以通过 `channels.telegram.linkPreview: false` 禁用。 - Telegram 命令菜单注册在启动时通过 `setMyCommands` 处理。 + Telegram 命令菜单注册会在启动时通过 `setMyCommands` 处理。 原生命令默认值: @@ -338,7 +338,7 @@ curl "https://api.telegram.org/bot/getUpdates" 规则: - - 名称会被标准化(去掉前导 `/`,转为小写) + - 名称会被规范化(去掉前导 `/`,并转为小写) - 有效模式:`a-z`、`0-9`、`_`,长度 `1..32` - 自定义命令不能覆盖原生命令 - 冲突/重复项会被跳过并记录日志 @@ -346,37 +346,37 @@ curl "https://api.telegram.org/bot/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 ` 用于显式批准 - 当只有一个待处理请求时,使用 `/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)。 - 配置内联键盘范围: + 配置内联键盘作用范围: ```json5 { @@ -450,24 +450,24 @@ curl "https://api.telegram.org/bot/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) - Telegram 支持在生成的输出中使用显式回复线程标签: + Telegram 支持在生成输出中使用显式回复线程标签: - `[[reply_to_current]]` 回复触发消息 - `[[reply_to:]]` 回复指定的 Telegram 消息 ID @@ -478,7 +478,7 @@ curl "https://api.telegram.org/bot/getUpdates" - `first` - `all` - 注意:`off` 会禁用隐式回复线程。显式 `[[reply_to_*]]` 标签仍会被遵循。 + 注意:`off` 会禁用隐式回复线程。显式 `[[reply_to_*]]` 标签仍会生效。 @@ -490,15 +490,15 @@ curl "https://api.telegram.org/bot/getUpdates" - 话题配置路径: `channels.telegram.groups..topics.` - 通用话题(`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/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/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/getUpdates" } ``` - 这当前仅适用于群组和超级群组中的论坛话题。 + 目前这仅适用于群组和超级群组中的论坛话题。 **从聊天中生成线程绑定的 ACP**: - - `/acp spawn --thread here|auto` 可以将当前 Telegram 话题绑定到新的 ACP 会话。 - - 后续该话题中的消息会直接路由到已绑定的 ACP 会话(无需 `/acp steer`)。 - - 成功绑定后,OpenClaw 会将生成确认消息固定在该话题中。 + - `/acp spawn --thread here|auto` 可以将当前 Telegram 话题绑定到一个新的 ACP 会话。 + - 后续的话题消息会直接路由到已绑定的 ACP 会话(无需 `/acp steer`)。 + - 绑定成功后,OpenClaw 会在该话题中固定生成确认消息。 - 需要 `channels.telegram.threadBindings.spawnAcpSessions=true`。 模板上下文包括: @@ -594,10 +594,10 @@ curl "https://api.telegram.org/bot/getUpdates" ### 音频消息 - Telegram 区分语音便笺和音频文件。 + Telegram 区分语音留言和音频文件。 - - 默认:音频文件行为 - - 在智能体回复中添加标签 `[[audio_as_voice]]` 可强制按语音便笺发送 + - 默认:按音频文件处理 + - 在智能体回复中添加标签 `[[audio_as_voice]]` 可强制按语音留言发送 消息动作示例: @@ -627,15 +627,15 @@ curl "https://api.telegram.org/bot/getUpdates" } ``` - 视频便笺不支持说明文字;提供的消息文本会单独发送。 + 视频便笺不支持说明文字;如果提供了消息文本,会单独发送。 ### 贴纸 入站贴纸处理: - - 静态 `WEBP`:会下载并处理(占位符 ``) - - 动画 `TGS`:跳过 - - 视频 `WEBM`:跳过 + - 静态 WEBP:会下载并处理(占位符 ``) + - 动态 TGS:跳过 + - 视频 WEBM:跳过 贴纸上下文字段: @@ -649,7 +649,7 @@ curl "https://api.telegram.org/bot/getUpdates" - `~/.openclaw/telegram/sticker-cache.json` - 贴纸会尽可能只描述一次并缓存,以减少重复的视觉调用。 + 贴纸会在可能时描述一次并缓存,以减少重复的视觉调用。 启用贴纸动作: @@ -690,7 +690,7 @@ curl "https://api.telegram.org/bot/getUpdates" - Telegram 表情回应会以 `message_reaction` 更新形式到达(独立于消息负载)。 + Telegram 表情回应会作为 `message_reaction` 更新到达(独立于消息载荷)。 启用后,OpenClaw 会将如下系统事件加入队列: @@ -698,34 +698,34 @@ curl "https://api.telegram.org/bot/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`。 - `ackReaction` 会在 OpenClaw 处理入站消息时发送一个确认 emoji。 + `ackReaction` 会在 OpenClaw 处理入站消息期间发送一个确认 emoji。 解析顺序: - `channels.telegram.accounts..ackReaction` - `channels.telegram.ackReaction` - `messages.ackReaction` - - 智能体身份 emoji 回退值(`agents.list[].identity.emoji`,否则为 `"👀"`) + - 智能体身份 emoji 回退(`agents.list[].identity.emoji`,否则为 "👀") 说明: - - Telegram 需要 unicode emoji(例如 `"👀"`)。 + - Telegram 需要 unicode emoji(例如 "👀")。 - 使用 `""` 可为某个渠道或账户禁用该表情回应。 @@ -738,7 +738,7 @@ curl "https://api.telegram.org/bot/getUpdates" - 群组迁移事件(`migrate_to_chat_id`),用于更新 `channels.telegram.groups` - `/config set` 和 `/config unset`(需要启用命令) - 禁用: + 禁用方式: ```json5 { @@ -752,37 +752,37 @@ curl "https://api.telegram.org/bot/getUpdates" - + 默认:长轮询。 - 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`)。 - - `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[""].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 投票创建,同时保留普通发送 - - Telegram 支持在审批人私信中进行执行审批,并且可以选择在发起审批的聊天或话题中发布审批提示。 + + 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) ## 错误回复控制 -当智能体遇到投递或提供商错误时,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 \ ## 故障排除 - + - 如果 `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`。 - - 当 `channels.telegram.groups` 存在时,必须列出该群组(或包含 `"*"`) + - 当存在 `channels.telegram.groups` 时,必须列出该群组(或包含 `"*"`) - 验证机器人是否已加入群组 - 查看日志:`openclaw logs --follow` 以获取跳过原因 @@ -912,20 +916,20 @@ openclaw message poll --channel telegram --target -1001234567890:topic:42 \ - 授权你的发送者身份(配对和/或数字 `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 可达性存在问题 - - 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..network.dangerouslyAllowPrivateNetwork`。 - - 如果你的代理将 Telegram 媒体主机解析到 `198.18.x.x`,请先保持该危险标志关闭。Telegram 媒体默认已经允许 RFC 2544 基准测试地址段。 + - 如果你的代理将 Telegram 媒体主机解析为 `198.18.x.x`,请先保持 + 该危险标志关闭。Telegram 媒体默认已经允许 RFC 2544 + 基准测试范围。 `channels.telegram.network.dangerouslyAllowPrivateNetwork` 会削弱 Telegram - 媒体 SSRF 防护。仅应在受信任、由操作员控制的代理环境中使用,例如 Clash、Mihomo 或 Surge 的 fake-IP 路由,这些环境会合成 RFC 2544 基准测试地址段之外的私有或特殊用途响应。对于普通公共互联网下的 Telegram 访问,请保持关闭。 + 媒体 SSRF 防护。仅在可信的、由操作员控制的代理 + 环境中使用它,例如 Clash、Mihomo 或 Surge 的假 IP 路由, + 并且这些环境会在 RFC 2544 基准测试范围之外合成私有或特殊用途地址的场景。对于普通公共互联网的 Telegram 访问,请保持关闭。 - 环境变量覆盖(临时): - `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..groupPolicy`:群组级 `groupPolicy` 覆盖(`open | allowlist | disabled`)。 +- `channels.telegram.groups`:每群组默认值 + allowlist(使用 `"*"` 作为全局默认值)。 + - `channels.telegram.groups..groupPolicy`:按群组覆盖 `groupPolicy`(`open | allowlist | disabled`)。 - `channels.telegram.groups..requireMention`:提及门控默认值。 - `channels.telegram.groups..skills`:Skills 过滤器(省略 = 所有 Skills,空值 = 无)。 - - `channels.telegram.groups..allowFrom`:按群组设置的发送者允许列表覆盖。 + - `channels.telegram.groups..allowFrom`:按群组覆盖发送者 allowlist。 - `channels.telegram.groups..systemPrompt`:该群组的额外系统提示词。 - - `channels.telegram.groups..enabled`:当为 `false` 时禁用该群组。 - - `channels.telegram.groups..topics..*`:按话题设置的覆盖(群组字段 + 仅话题字段 `agentId`)。 - - `channels.telegram.groups..topics..agentId`:将此话题路由到特定智能体(覆盖群组级和绑定路由)。 -- `channels.telegram.groups..topics..groupPolicy`:话题级 `groupPolicy` 覆盖(`open | allowlist | disabled`)。 -- `channels.telegram.groups..topics..requireMention`:话题级提及门控覆盖。 -- 顶层 `bindings[]` 中带有 `type: "acp"` 且在 `match.peer.id` 中使用规范话题 ID `chatId:topic:topicId`:持久 ACP 话题绑定字段(见 [ACP 智能体](/zh-CN/tools/acp-agents#channel-specific-settings))。 -- `channels.telegram.direct..topics..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..execApprovals`:按账户设置的 Telegram 执行审批路由和审批人授权覆盖。 + - `channels.telegram.groups..enabled`:为 `false` 时禁用该群组。 + - `channels.telegram.groups..topics..*`:按话题覆盖(群组字段 + 仅话题字段 `agentId`)。 + - `channels.telegram.groups..topics..agentId`:将该话题路由到特定智能体(覆盖群组级和绑定路由)。 +- `channels.telegram.groups..topics..groupPolicy`:按话题覆盖 `groupPolicy`(`open | allowlist | disabled`)。 +- `channels.telegram.groups..topics..requireMention`:按话题覆盖提及门控。 +- 顶层 `bindings[]` 中使用 `type: "acp"`,并在 `match.peer.id` 中使用规范话题 ID `chatId:topic:topicId`:持久 ACP 话题绑定字段(参见 [ACP 智能体](/zh-CN/tools/acp-agents#channel-specific-settings))。 +- `channels.telegram.direct..topics..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..execApprovals`:按账户覆盖 Telegram exec 批准路由和批准者授权。 - `channels.telegram.capabilities.inlineButtons`:`off | dm | group | all | allowlist`(默认:allowlist)。 - `channels.telegram.accounts..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 调用的代理 URL(SOCKS/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` diff --git a/docs/zh-CN/plan/ui-channels.md b/docs/zh-CN/plan/ui-channels.md new file mode 100644 index 000000000..24e521a4b --- /dev/null +++ b/docs/zh-CN/plan/ui-channels.md @@ -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; +}; +``` + +核心行为: + +- 解析目标渠道和运行时适配器。 +- 查询其呈现能力。 +- 在渲染前降级不受支持的块。 +- 调用 `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 布局分离? diff --git a/docs/zh-CN/plugins/architecture.md b/docs/zh-CN/plugins/architecture.md index a92e15587..af6a5257b 100644 --- a/docs/zh-CN/plugins/architecture.md +++ b/docs/zh-CN/plugins/architecture.md @@ -1,17 +1,17 @@ --- read_when: - 构建或调试原生 OpenClaw 插件 - - 理解插件能力模型或归属边界 - - 处理插件加载流程或注册表 + - 了解插件能力模型或归属边界 + - 处理插件加载流水线或注册表 - 实现提供商运行时钩子或渠道插件 sidebarTitle: Internals -summary: 插件内部机制:能力模型、归属、契约、加载流程和运行时辅助工具 +summary: 插件内部机制:能力模型、归属、契约、加载流水线和运行时辅助工具 title: 插件内部机制 x-i18n: - generated_at: "2026-04-21T08:24:18Z" + generated_at: "2026-04-21T20:34:47Z" model: gpt-5.4 provider: openai - source_hash: 4b1fb42e659d4419033b317e88563a59b3ddbfad0523f32225c868c8e828fd16 + source_hash: 69080a1d0e496b321a6fd5a3e925108c3a03c41710073f8f23af13933a091e28 source_path: plugins/architecture.md workflow: 15 --- @@ -19,21 +19,21 @@ x-i18n: # 插件内部机制 - 这是**深度架构参考**。如需实用指南,请参见: - - [安装和使用插件](/zh-CN/tools/plugin) — 用户指南 - - [入门指南](/zh-CN/plugins/building-plugins) — 第一个插件教程 - - [渠道插件](/zh-CN/plugins/sdk-channel-plugins) — 构建一个消息渠道 - - [提供商插件](/zh-CN/plugins/sdk-provider-plugins) — 构建一个模型提供商 - - [SDK 概览](/zh-CN/plugins/sdk-overview) — 导入映射和注册 API + 这是**深度架构参考**。如需实用指南,请参阅: + - [安装和使用插件](/zh-CN/tools/plugin) —— 用户指南 + - [入门指南](/zh-CN/plugins/building-plugins) —— 第一个插件教程 + - [渠道插件](/zh-CN/plugins/sdk-channel-plugins) —— 构建一个消息渠道 + - [提供商插件](/zh-CN/plugins/sdk-provider-plugins) —— 构建一个模型提供商 + - [SDK 概览](/zh-CN/plugins/sdk-overview) —— 导入映射和注册 API 本页介绍 OpenClaw 插件系统的内部架构。 ## 公共能力模型 -能力是 OpenClaw 内部公共的**原生插件**模型。每个原生 OpenClaw 插件都会针对一种或多种能力类型进行注册: +能力是 OpenClaw 内部公开的**原生插件**模型。每个原生 OpenClaw 插件都会针对一种或多种能力类型进行注册: -| 能力 | 注册方式 | 示例插件 | +| 能力 | 注册方法 | 示例插件 | | ---------------------- | ------------------------------------------------ | ------------------------------------ | | 文本推理 | `api.registerProvider(...)` | `openai`, `anthropic` | | CLI 推理后端 | `api.registerCliBackend(...)` | `openai`, `anthropic` | @@ -48,46 +48,46 @@ x-i18n: | 网页搜索 | `api.registerWebSearchProvider(...)` | `google` | | 渠道 / 消息传递 | `api.registerChannel(...)` | `msteams`, `matrix` | -如果一个插件注册了零个能力,但提供了钩子、工具或服务,它就是一个**仅钩子的旧版**插件。该模式目前仍然被完全支持。 +一个插件如果注册了零个能力,但提供了钩子、工具或服务,则属于**仅钩子**插件。这种模式目前仍然得到完整支持。 ### 外部兼容性立场 -能力模型已经在核心中落地,并且今天已被内置 / 原生插件使用,但外部插件的兼容性仍需要比“它已导出,因此它已冻结”更严格的标准。 +能力模型已经在核心中落地,并且今天已被内置 / 原生插件使用,但外部插件兼容性仍需要比“已导出,因此已冻结”更严格的标准。 -当前指引: +当前指导原则: -- **现有外部插件:** 保持基于钩子的集成继续工作;将此视为兼容性的基线 -- **新的内置 / 原生插件:** 优先使用显式能力注册,而不是面向供应商的特殊访问或新的仅钩子设计 -- **采用能力注册的外部插件:** 允许这样做,但除非文档明确将某个契约标记为稳定,否则应将能力相关的辅助接口视为仍在演进中 +- **现有外部插件:** 保持基于钩子的集成继续可用;将此视为兼容性基线 +- **新的内置 / 原生插件:** 优先使用显式能力注册,而不是依赖供应商特定的深层接入或新的仅钩子设计 +- **采用能力注册的外部插件:** 允许,但除非文档明确将某个契约标记为稳定,否则应将能力专用的辅助接口视为仍在演进中 -实践规则: +实用规则: - 能力注册 API 是预期的发展方向 -- 在过渡期间,旧版钩子仍然是对外部插件来说最安全、最不容易破坏兼容性的路径 -- 导出的辅助子路径并不完全等价;优先使用文档化的狭义契约,而不是偶然暴露出的辅助导出 +- 在过渡期间,传统钩子仍然是外部插件最安全、最不易破坏兼容性的路径 +- 导出的辅助子路径并不都等价;优先使用文档化的精简契约,而不是偶然暴露出来的辅助导出 ### 插件形态 -OpenClaw 会根据每个已加载插件的实际注册行为对其进行形态分类,而不只是依据静态元数据: +OpenClaw 会根据每个已加载插件的实际注册行为来将其归类为某种形态(而不只是依据静态元数据): - **plain-capability** —— 只注册一种能力类型(例如仅提供商插件 `mistral`) - **hybrid-capability** —— 注册多种能力类型(例如 `openai` 同时拥有文本推理、语音、媒体理解和图像生成) -- **hook-only** —— 只注册钩子(类型化或自定义),不注册能力、工具、命令或服务 +- **hook-only** —— 只注册钩子(类型化钩子或自定义钩子),不注册能力、工具、命令或服务 - **non-capability** —— 注册工具、命令、服务或路由,但不注册能力 -使用 `openclaw plugins inspect ` 可查看插件的形态和能力拆分。详情参见 [CLI 参考](/cli/plugins#inspect)。 +使用 `openclaw plugins inspect ` 可查看插件的形态和能力明细。详见 [CLI 参考](/cli/plugins#inspect)。 -### 旧版钩子 +### 传统钩子 -`before_agent_start` 钩子仍作为仅钩子插件的兼容路径被支持。现实中的旧版插件仍然依赖它。 +`before_agent_start` 钩子仍然作为仅钩子插件的兼容路径受到支持。现实中的传统插件仍然依赖它。 方向如下: -- 保持其继续工作 -- 在文档中将其标注为旧版 -- 对模型 / 提供商覆盖工作,优先使用 `before_model_resolve` -- 对提示词变更工作,优先使用 `before_prompt_build` -- 只有在真实使用下降且 fixture 覆盖证明迁移安全后才移除 +- 保持其可用 +- 将其文档化为传统机制 +- 对于模型 / 提供商覆盖工作,优先使用 `before_model_resolve` +- 对于提示词变更工作,优先使用 `before_prompt_build` +- 仅当实际使用量下降,且夹具覆盖证明迁移安全后,才考虑移除 ### 兼容性信号 @@ -95,57 +95,57 @@ OpenClaw 会根据每个已加载插件的实际注册行为对其进行形态 | 信号 | 含义 | | -------------------------- | ------------------------------------------------------------ | -| **配置有效** | 配置解析正常,且插件可解析 | -| **兼容性提示** | 插件使用了受支持但较旧的模式(例如 `hook-only`) | -| **旧版警告** | 插件使用了 `before_agent_start`,该接口已弃用 | -| **硬错误** | 配置无效,或插件加载失败 | +| **config valid** | 配置解析正常,插件解析成功 | +| **compatibility advisory** | 插件使用受支持但较旧的模式(例如 `hook-only`) | +| **legacy warning** | 插件使用了已弃用的 `before_agent_start` | +| **hard error** | 配置无效,或插件加载失败 | -`hook-only` 和 `before_agent_start` 目前都不会导致你的插件损坏——`hook-only` 只是提示,而 `before_agent_start` 只会触发警告。这些信号也会出现在 `openclaw status --all` 和 `openclaw plugins doctor` 中。 +`hook-only` 和 `before_agent_start` 目前都不会导致你的插件失效 —— `hook-only` 只是提示性信息,而 `before_agent_start` 只会触发警告。这些信号也会出现在 `openclaw status --all` 和 `openclaw plugins doctor` 中。 ## 架构概览 OpenClaw 的插件系统有四层: 1. **清单 + 设备发现** - OpenClaw 会从配置路径、工作区根目录、全局扩展根目录和内置扩展中查找候选插件。设备发现会先读取原生的 `openclaw.plugin.json` 清单以及受支持的 bundle 清单。 -2. **启用 + 校验** - 核心决定已发现的插件是启用、禁用、阻止,还是被选中用于某个排他性槽位,例如 memory。 + OpenClaw 会从已配置路径、工作区根目录、全局扩展根目录以及内置扩展中查找候选插件。设备发现会先读取原生 `openclaw.plugin.json` 清单以及受支持的 bundle 清单。 +2. **启用 + 验证** + 核心决定某个已发现插件是启用、禁用、屏蔽,还是被选中用于某个独占槽位(例如 memory)。 3. **运行时加载** - 原生 OpenClaw 插件通过 `jiti` 在进程内加载,并将能力注册到中央注册表中。兼容的 bundle 会被标准化为注册表记录,而无需导入运行时代码。 -4. **表面消费** + 原生 OpenClaw 插件通过 `jiti` 在进程内加载,并将能力注册到中央注册表中。兼容的 bundle 会被规范化为注册表记录,而不会导入运行时代码。 +4. **表面消费** OpenClaw 的其余部分会读取注册表,以暴露工具、渠道、提供商设置、钩子、HTTP 路由、CLI 命令和服务。 -对于插件 CLI,根命令发现被拆分为两个阶段: +对于插件 CLI,根命令设备发现被拆分为两个阶段: -- 解析时元数据来自 `registerCli(..., { descriptors: [...] })` -- 真正的插件 CLI 模块可以保持惰性,并在首次调用时再注册 +- 解析阶段的元数据来自 `registerCli(..., { descriptors: [...] })` +- 实际的插件 CLI 模块可以保持惰性加载,并在首次调用时完成注册 -这样可以让插件拥有的 CLI 代码保留在插件内部,同时仍允许 OpenClaw 在解析前预留根命令名称。 +这样既能让插件拥有自己的 CLI 代码,又能让 OpenClaw 在解析之前预留根命令名称。 重要的设计边界是: -- 设备发现 + 配置校验应当能够仅通过**清单 / schema 元数据**工作,而不执行插件代码 -- 原生运行时行为来自插件模块的 `register(api)` 路径 +- 设备发现 + 配置验证应当能够仅依赖**清单 / schema 元数据**完成,而无需执行插件代码 +- 原生运行时行为则来自插件模块中的 `register(api)` 路径 -这种拆分使 OpenClaw 能够在完整运行时激活之前,就校验配置、解释缺失 / 已禁用的插件,并构建 UI / schema 提示。 +这种拆分使 OpenClaw 能够在完整运行时尚未激活之前,就验证配置、解释插件缺失 / 禁用原因,并构建 UI / schema 提示。 -### 渠道插件与共享消息工具 +### 渠道插件和共享 message 工具 -对于常规聊天操作,渠道插件不需要单独注册发送 / 编辑 / 反应工具。OpenClaw 在核心中保留了一个共享的 `message` 工具,而渠道插件负责其背后的渠道特定发现和执行。 +渠道插件不需要为常规聊天操作单独注册发送 / 编辑 / 响应工具。OpenClaw 在核心中保留一个共享的 `message` 工具,而渠道插件负责其背后的渠道专用设备发现和执行。 当前边界如下: -- 核心拥有共享 `message` 工具宿主、提示词接线、会话 / 线程簿记和执行分发 -- 渠道插件拥有作用域化的动作发现、能力发现以及任何渠道特定的 schema 片段 -- 渠道插件拥有提供商特定的会话对话语法,例如对话 id 如何编码线程 id 或从父对话继承 +- 核心拥有共享 `message` 工具宿主、提示词接线、会话 / 线程簿记以及执行分发 +- 渠道插件拥有作用域化的动作发现、能力发现,以及任何渠道专用的 schema 片段 +- 渠道插件拥有提供商专用的会话对话语法,例如对话 id 如何编码线程 id,或如何从父对话继承 - 渠道插件通过其动作适配器执行最终动作 -对于渠道插件,SDK 接口是 `ChannelMessageActionAdapter.describeMessageTool(...)`。这个统一的发现调用让插件可以一起返回其可见动作、能力和 schema 贡献,从而避免这些部分彼此漂移。 +对于渠道插件,SDK 接口是 `ChannelMessageActionAdapter.describeMessageTool(...)`。这个统一的发现调用允许插件一起返回其可见动作、能力和 schema 贡献,从而避免这些部分彼此漂移。 -当某个渠道特定的消息工具参数携带媒体来源,例如本地路径或远程媒体 URL 时,插件还应当从 `describeMessageTool(...)` 返回 `mediaSourceParams`。核心使用这份显式列表来应用沙箱路径规范化和出站媒体访问提示,而无需对插件拥有的参数名进行硬编码。 -这里优先使用按动作划分的映射,而不是整个渠道共用的扁平列表,这样仅用于 profile 的媒体参数就不会在 `send` 之类的不相关动作上被规范化。 +当某个渠道专用 message 工具参数携带媒体源,例如本地路径或远程媒体 URL 时,插件还应当从 `describeMessageTool(...)` 返回 `mediaSourceParams`。核心使用这份显式列表来应用沙箱路径规范化和出站媒体访问提示,而不是硬编码插件拥有的参数名称。 +这里应优先使用按动作划分的映射,而不是整个渠道范围的扁平列表,这样仅用于 profile 的媒体参数就不会在 `send` 之类的不相关动作上被规范化。 -核心会将运行时作用域传入该发现步骤。重要字段包括: +核心会在该发现步骤中传入运行时作用域。重要字段包括: - `accountId` - `currentChannelId` @@ -156,31 +156,32 @@ OpenClaw 的插件系统有四层: - `agentId` - 受信任的入站 `requesterSenderId` -这对于上下文敏感的插件很重要。渠道可以根据活动账户、当前房间 / 线程 / 消息或受信任的请求者身份来隐藏或暴露消息动作,而不需要在核心 `message` 工具中硬编码渠道特定分支。 +这对于上下文敏感的插件很重要。渠道可以根据当前账号、当前房间 / 线程 / 消息,或受信任的请求方身份来隐藏或暴露 message 动作,而无需在核心 `message` 工具中硬编码渠道专用分支。 -这也是为什么嵌入式运行器路由变更仍然属于插件工作:运行器负责将当前聊天 / 会话身份转发到插件发现边界,以便共享 `message` 工具在当前轮次暴露正确的渠道自有表面。 +这也是为什么嵌入式运行器路由变更仍然属于插件工作:运行器负责将当前聊天 / 会话身份转发到插件发现边界,以便共享 `message` 工具为当前轮次暴露正确的渠道自有表面。 -对于渠道自有的执行辅助工具,内置插件应将执行运行时保留在它们自己的扩展模块中。核心不再拥有位于 `src/agents/tools` 下的 Discord、Slack、Telegram 或 WhatsApp 消息动作运行时。我们不会发布单独的 `plugin-sdk/*-action-runtime` 子路径,内置插件应直接从其扩展自有模块导入自己的本地运行时代码。 +对于渠道自有的执行辅助工具,内置插件应将执行运行时保留在各自的扩展模块中。核心不再拥有位于 `src/agents/tools` 下的 Discord、Slack、Telegram 或 WhatsApp message-action 运行时。 +我们不会发布单独的 `plugin-sdk/*-action-runtime` 子路径,内置插件应直接从其扩展自有模块导入本地运行时代码。 -同样的边界也适用于一般情况下以提供商命名的 SDK 接缝:核心不应导入面向 Slack、Discord、Signal、WhatsApp 或类似扩展的渠道特定便利 barrel。如果核心需要某种行为,要么消费内置插件自己的 `api.ts` / `runtime-api.ts` barrel,要么将该需求提升为共享 SDK 中一个狭义的通用能力。 +同样的边界也适用于一般情况下以提供商命名的 SDK 接缝:核心不应导入 Slack、Discord、Signal、WhatsApp 或类似扩展的渠道专用便捷 barrel。若核心需要某种行为,要么消费该内置插件自己的 `api.ts` / `runtime-api.ts` barrel,要么将该需求提升为共享 SDK 中的精简通用能力。 对于投票,当前有两条执行路径: -- `outbound.sendPoll` 是适用于符合通用投票模型渠道的共享基线 -- `actions.handleAction("poll")` 是针对渠道特定投票语义或额外投票参数的首选路径 +- `outbound.sendPoll` 是适用于符合通用投票模型渠道的共享基线路径 +- `actions.handleAction("poll")` 是渠道专用投票语义或额外投票参数的首选路径 -现在,核心会在插件投票分发拒绝该动作之后,才回退到共享投票解析,因此插件自有的投票处理器可以接受渠道特定的投票字段,而不会先被通用投票解析器阻挡。 +现在,核心会在插件投票分发拒绝该动作之后,才回退到共享投票解析,因此插件自有的投票处理器可以接受渠道专用投票字段,而不会先被通用投票解析器阻拦。 -完整启动顺序请参见[加载流程](#load-pipeline)。 +完整启动顺序请参见 [加载流水线](#load-pipeline)。 ## 能力归属模型 -OpenClaw 将原生插件视为**公司**或**功能**的归属边界,而不是一堆无关集成的杂物袋。 +OpenClaw 将一个原生插件视为某个**公司**或某个**功能**的归属边界,而不是一堆无关集成的杂物包。 这意味着: - 一个公司插件通常应拥有该公司的所有 OpenClaw 对外表面 -- 一个功能插件通常应拥有其引入的完整功能表面 +- 一个功能插件通常应拥有它所引入的完整功能表面 - 渠道应消费共享的核心能力,而不是临时重新实现提供商行为 示例: @@ -192,49 +193,49 @@ OpenClaw 将原生插件视为**公司**或**功能**的归属边界,而不是 - 内置的 `firecrawl` 插件拥有 Firecrawl 网页抓取行为 - 内置的 `minimax`、`mistral`、`moonshot` 和 `zai` 插件拥有它们各自的媒体理解后端 - 内置的 `qwen` 插件拥有 Qwen 文本提供商行为,以及媒体理解和视频生成行为 -- `voice-call` 插件是一个功能插件:它拥有通话传输、工具、CLI、路由和 Twilio 媒体流桥接,但它会消费共享的语音以及实时转录和实时语音能力,而不是直接导入供应商插件 +- `voice-call` 插件是一个功能插件:它拥有通话传输、工具、CLI、路由以及 Twilio 媒体流桥接,但它消费共享的语音以及实时转录和实时语音能力,而不是直接导入供应商插件 预期的最终状态是: -- 即使 OpenAI 同时涵盖文本模型、语音、图像以及未来的视频,它也应存在于同一个插件中 -- 其他供应商也可以对其自身的表面区域采用同样方式 +- 即使 OpenAI 横跨文本模型、语音、图像以及未来的视频,它也只存在于一个插件中 +- 其他供应商也可以用同样方式统一管理自己的表面区域 - 渠道并不关心哪个供应商插件拥有该提供商;它们消费的是由核心暴露的共享能力契约 -这是关键区别: +这就是关键区别: - **plugin** = 归属边界 -- **capability** = 多个插件可实现或消费的核心契约 +- **capability** = 可由多个插件实现或消费的核心契约 -因此,如果 OpenClaw 添加了视频这样的新领域,首要问题不是“哪个提供商应该硬编码视频处理?”首要问题是“核心的视频能力契约是什么?”一旦该契约存在,供应商插件就可以针对它进行注册,而渠道 / 功能插件也可以消费它。 +因此,如果 OpenClaw 新增一个如视频这样的新领域,第一个问题不应是“哪个提供商应该硬编码处理视频?”。第一个问题应当是“核心视频能力契约是什么?” 一旦该契约存在,供应商插件就可以针对它注册,而渠道 / 功能插件则可以消费它。 如果该能力尚不存在,通常正确的做法是: 1. 在核心中定义缺失的能力 -2. 通过插件 API / 运行时以类型化方式暴露它 -3. 让渠道 / 功能对接这个能力 +2. 以类型化方式通过插件 API / 运行时暴露它 +3. 让渠道 / 功能围绕该能力完成接线 4. 让供应商插件注册实现 -这样可以在保持归属明确的同时,避免核心行为依赖单一供应商或某条一次性的插件特定代码路径。 +这样既能保持归属清晰,又能避免核心行为依赖单一供应商或某条一次性的插件专用代码路径。 ### 能力分层 -在决定代码应放在哪里时,使用以下思维模型: +在决定代码应放在哪里时,可使用以下思维模型: - **核心能力层**:共享编排、策略、回退、配置合并规则、交付语义和类型化契约 -- **供应商插件层**:供应商特定 API、认证、模型目录、语音合成、图像生成、未来的视频后端、用量端点 -- **渠道 / 功能插件层**:Slack / Discord / voice-call / 等集成,它们消费核心能力并将其呈现在某个表面上 +- **供应商插件层**:供应商专用 API、认证、模型目录、语音合成、图像生成、未来的视频后端、用量端点 +- **渠道 / 功能插件层**:Slack / Discord / voice-call 等集成,它们消费核心能力并在某个表面上呈现出来 -例如,TTS 遵循如下结构: +例如,TTS 遵循以下结构: -- 核心拥有回复时 TTS 策略、回退顺序、偏好和渠道交付 -- `openai`、`elevenlabs` 和 `microsoft` 拥有各自的合成实现 +- 核心拥有回复时 TTS 策略、回退顺序、偏好和渠道投递 +- `openai`、`elevenlabs` 和 `microsoft` 拥有合成实现 - `voice-call` 消费电话 TTS 运行时辅助工具 -未来的能力也应优先采用同样的模式。 +对于未来的能力,也应优先采用同样的模式。 ### 多能力公司插件示例 -从外部看,一个公司插件应当体现出内聚性。如果 OpenClaw 拥有针对模型、语音、实时转录、实时语音、媒体理解、图像生成、视频生成、网页抓取和网页搜索的共享契约,那么一个供应商就可以在一个地方拥有其全部表面: +一个公司插件从外部看应当是连贯一致的。如果 OpenClaw 为模型、语音、实时转录、实时语音、媒体理解、图像生成、视频生成、网页抓取和网页搜索提供共享契约,那么某个供应商就可以在一个地方拥有它的所有表面: ```ts import type { OpenClawPluginDefinition } from "openclaw/plugin-sdk/plugin-entry"; @@ -290,150 +291,154 @@ export default plugin; 重要的不是确切的辅助函数名称,而是这种结构: -- 一个插件拥有该供应商表面 +- 一个插件拥有供应商表面 - 核心仍然拥有能力契约 - 渠道和功能插件消费 `api.runtime.*` 辅助工具,而不是供应商代码 -- 契约测试可以断言该插件已注册它声称拥有的能力 +- 契约测试可以断言该插件确实注册了它声称拥有的能力 ### 能力示例:视频理解 -OpenClaw 已经将图像 / 音频 / 视频理解视为一个共享能力。在这里同样适用相同的归属模型: +OpenClaw 已经将图像 / 音频 / 视频理解视为一种共享能力。相同的归属模型也适用于这里: 1. 核心定义媒体理解契约 -2. 供应商插件按适用情况注册 `describeImage`、`transcribeAudio` 和 `describeVideo` -3. 渠道和功能插件消费共享的核心行为,而不是直接连接到供应商代码 +2. 供应商插件根据适用情况注册 `describeImage`、`transcribeAudio` 和 `describeVideo` +3. 渠道和功能插件消费共享核心行为,而不是直接连接到供应商代码 -这样可以避免将某个提供商的视频假设固化进核心。插件拥有供应商表面;核心拥有能力契约和回退行为。 +这样可以避免把某个提供商对视频的假设烘焙进核心。插件拥有供应商表面;核心拥有能力契约和回退行为。 -视频生成已经使用同样的顺序:核心拥有类型化能力契约和运行时辅助工具,而供应商插件针对它注册 `api.registerVideoGenerationProvider(...)` 实现。 +视频生成已经采用了同样的顺序:核心拥有类型化能力契约和运行时辅助工具,而供应商插件则针对它注册 `api.registerVideoGenerationProvider(...)` 实现。 -需要一个具体的发布检查清单?参见 [能力扩展手册](/zh-CN/plugins/architecture)。 +需要一份具体的发布检查清单吗?请参见 [能力扩展手册](/zh-CN/plugins/architecture)。 ## 契约与强制执行 -插件 API 表面在 `OpenClawPluginApi` 中被有意设计为类型化且集中化。该契约定义了受支持的注册点,以及插件可以依赖的运行时辅助工具。 +插件 API 表面被有意设计为类型化,并集中在 `OpenClawPluginApi` 中。该契约定义了受支持的注册点,以及插件可依赖的运行时辅助工具。 -其重要性在于: +这很重要,因为: -- 插件作者获得一个稳定的内部标准 -- 核心可以拒绝重复归属,例如两个插件注册相同的 provider id -- 启动时可以为格式错误的注册暴露可操作的诊断信息 -- 契约测试可以强制内置插件归属并防止无声漂移 +- 插件作者可以获得一个稳定的统一内部标准 +- 核心可以拒绝重复归属,例如两个插件注册相同的提供商 id +- 启动过程可以为格式错误的注册提供可执行的诊断信息 +- 契约测试可以强制校验内置插件的归属关系,防止静默漂移 -有两层强制机制: +强制执行分为两层: -1. **运行时注册强制** - 插件加载时,插件注册表会校验注册内容。示例:重复的 provider id、重复的 speech provider id 以及格式错误的注册,不会导致未定义行为,而是生成插件诊断信息。 -2. **契约测试** - 在测试运行期间,内置插件会被捕获到契约注册表中,以便 OpenClaw 可以明确断言归属。如今这被用于模型提供商、语音提供商、网页搜索提供商和内置注册归属。 +1. **运行时注册强制执行** + 插件注册表会在插件加载时验证各项注册。例如:重复的提供商 id、重复的语音提供商 id,以及格式错误的注册,都会产生插件诊断,而不是导致未定义行为。 +2. **契约测试** + 内置插件会在测试运行期间被捕获到契约注册表中,以便 OpenClaw 显式断言归属关系。当前这用于模型提供商、语音提供商、网页搜索提供商以及内置注册归属。 -实际效果是,OpenClaw 会预先知道哪个插件拥有哪个表面。这让核心和渠道能够无缝组合,因为归属是声明出来的、类型化的并且可测试,而不是隐含的。 +实际效果是,OpenClaw 可以预先知道哪个插件拥有哪个表面。这样核心和渠道便能无缝组合,因为归属是声明式、类型化且可测试的,而不是隐式的。 -### 什么应该属于契约 +### 什么内容应该属于契约 -好的插件契约应当是: +好的插件契约应当具备以下特征: -- 类型化的 -- 小而精的 -- 能力特定的 +- 类型化 +- 小而精 +- 能力专用 - 由核心拥有 - 可被多个插件复用 -- 能被渠道 / 功能消费,而无需了解供应商细节 +- 渠道 / 功能无需了解供应商知识即可消费 -不好的插件契约包括: +糟糕的插件契约则是: -- 隐藏在核心中的供应商特定策略 +- 隐藏在核心中的供应商专用策略 - 绕过注册表的一次性插件逃生口 -- 渠道代码直接深入供应商实现 +- 渠道代码直接深入某个供应商实现 - 不属于 `OpenClawPluginApi` 或 `api.runtime` 的临时运行时对象 如果拿不准,就提升抽象层级:先定义能力,再让插件接入它。 ## 执行模型 -原生 OpenClaw 插件会与 Gateway 网关**在同一进程内**运行。它们不是沙箱隔离的。一个已加载的原生插件与核心代码具有相同的进程级信任边界。 +原生 OpenClaw 插件与 Gateway 网关**运行在同一进程内**。它们不经过沙箱隔离。一个已加载的原生插件与核心代码具有相同的进程级信任边界。 -其影响包括: +这意味着: - 原生插件可以注册工具、网络处理器、钩子和服务 -- 原生插件中的 bug 可能导致 gateway 崩溃或不稳定 +- 原生插件中的 bug 可能导致网关崩溃或不稳定 - 恶意原生插件等同于在 OpenClaw 进程内部执行任意代码 -兼容 bundle 默认更安全,因为 OpenClaw 当前将它们视为元数据 / 内容包。在当前版本中,这主要指内置 Skills。 +兼容 bundle 默认更安全,因为 OpenClaw 当前将它们视为元数据 / 内容包。在当前版本中,这主要意味着内置 Skills。 -对于非内置插件,请使用 allowlist 和显式的安装 / 加载路径。将工作区插件视为开发时代码,而不是生产环境默认值。 +对于非内置插件,请使用 allowlist 和显式安装 / 加载路径。应将工作区插件视为开发期代码,而不是生产默认项。 -对于内置工作区包名,默认应让插件 id 以 npm 名称中的 `@openclaw/` 为锚点,或者使用批准的类型化后缀,例如 `-provider`、`-plugin`、`-speech`、`-sandbox` 或 `-media-understanding`,当该包有意暴露更狭义的插件角色时可这样命名。 +对于内置工作区包名,应让插件 id 默认锚定在 npm 名称中:`@openclaw/`;或者在包有意暴露更窄的插件角色时,使用获批的类型化后缀,例如 `-provider`、`-plugin`、`-speech`、`-sandbox` 或 `-media-understanding`。 重要的信任说明: -- `plugins.allow` 信任的是**插件 id**,而不是来源出处。 -- 与内置插件具有相同 id 的工作区插件,在启用 / 加入 allowlist 后,会有意遮蔽该内置副本。 -- 这是一种正常且有用的行为,适用于本地开发、补丁测试和热修复。 +- `plugins.allow` 信任的是**插件 id**,而不是来源证明。 +- 如果某个工作区插件与某个内置插件拥有相同 id,那么当该工作区插件被启用 / 加入 allowlist 时,它会有意遮蔽内置副本。 +- 这属于正常且有用的行为,适用于本地开发、补丁测试和热修复。 ## 导出边界 -OpenClaw 导出的是能力,而不是实现层面的便利工具。 +OpenClaw 导出的是能力,而不是实现便利函数。 -保持能力注册为公共接口。收紧非契约辅助导出: +应保持能力注册为公共接口,同时裁剪非契约辅助导出: -- 内置插件特定的辅助子路径 +- 内置插件专用的辅助子路径 - 不打算作为公共 API 的运行时管线子路径 -- 供应商特定的便利辅助函数 -- 属于实现细节的设置 / 新手引导辅助工具 +- 供应商专用的便捷辅助函数 +- 属于实现细节的设置 / 新手引导辅助函数 -出于兼容性和内置插件维护的需要,一些内置插件辅助子路径仍保留在生成的 SDK 导出映射中。当前示例包括 `plugin-sdk/feishu`、`plugin-sdk/feishu-setup`、`plugin-sdk/zalo`、`plugin-sdk/zalo-setup` 以及若干 `plugin-sdk/matrix*` 接缝。应将它们视为保留的实现细节导出,而不是新第三方插件推荐采用的 SDK 模式。 +出于兼容性和内置插件维护需要,一些内置插件辅助子路径仍然保留在生成的 SDK 导出映射中。当前示例包括 `plugin-sdk/feishu`、`plugin-sdk/feishu-setup`、`plugin-sdk/zalo`、`plugin-sdk/zalo-setup` 以及若干 `plugin-sdk/matrix*` 接缝。应将这些视为保留的实现细节导出,而不是新第三方插件推荐采用的 SDK 模式。 -## 加载流程 +## 加载流水线 在启动时,OpenClaw 大致会执行以下步骤: 1. 发现候选插件根目录 -2. 读取原生或兼容 bundle 的清单与包元数据 +2. 读取原生或兼容 bundle 的清单以及包元数据 3. 拒绝不安全的候选项 4. 规范化插件配置(`plugins.enabled`、`allow`、`deny`、`entries`、`slots`、`load.paths`) -5. 决定每个候选项的启用状态 +5. 为每个候选项决定启用状态 6. 通过 `jiti` 加载已启用的原生模块 -7. 调用原生 `register(api)`(或 `activate(api)`——旧版别名)钩子,并将注册内容收集到插件注册表中 +7. 调用原生 `register(api)`(或 `activate(api)` —— 一个传统别名)钩子,并将注册项收集到插件注册表中 8. 将注册表暴露给命令 / 运行时表面 -`activate` 是 `register` 的旧版别名——加载器会解析存在的那个(`def.register ?? def.activate`),并在相同时间点调用它。所有内置插件都使用 `register`;新插件优先使用 `register`。 +`activate` 是 `register` 的传统别名 —— 加载器会解析两者中存在的那个(`def.register ?? def.activate`),并在相同位置调用它。所有内置插件都使用 `register`;新插件请优先使用 `register`。 -安全闸门发生在**运行时执行之前**。当入口逃离插件根目录、路径对所有人可写,或者对于非内置插件而言路径归属看起来可疑时,候选项会被阻止。 +安全门发生在**运行时执行之前**。当出现以下情况时,候选项会被阻止: + +- 入口逃逸出插件根目录 +- 路径对所有用户可写 +- 对于非内置插件,路径归属看起来可疑 ### Manifest-first 行为 -清单是控制平面的事实来源。OpenClaw 用它来: +清单是控制平面的真实来源。OpenClaw 使用它来: - 标识插件 - 发现声明的渠道 / Skills / 配置 schema 或 bundle 能力 -- 校验 `plugins.entries..config` +- 验证 `plugins.entries..config` - 增强 Control UI 标签 / 占位符 - 显示安装 / 目录元数据 -- 在不加载插件运行时的情况下保留轻量激活和设置描述符 +- 在不加载插件运行时的情况下,保留轻量激活和设置描述符 对于原生插件,运行时模块是数据平面部分。它会注册实际行为,例如钩子、工具、命令或提供商流程。 -可选的清单 `activation` 和 `setup` 区块仍属于控制平面。它们是仅元数据的描述符,用于激活规划和设置发现;它们不会替代运行时注册、`register(...)` 或 `setupEntry`。 -首批实时激活消费者现在会使用清单中的命令、渠道和提供商提示,在更广泛的注册表实体化之前缩小插件加载范围: +可选的清单 `activation` 和 `setup` 块仍属于控制平面。它们只是用于激活规划和设置发现的纯元数据描述符;它们不会替代运行时注册、`register(...)` 或 `setupEntry`。 +第一批真实激活消费者现在会使用清单中的命令、渠道和提供商提示,在更广泛的注册表实体化之前先缩小插件加载范围: -- CLI 加载会缩小到拥有所请求主命令的插件 -- 渠道设置 / 插件解析会缩小到拥有所请求 channel id 的插件 -- 显式提供商设置 / 运行时解析会缩小到拥有所请求 provider id 的插件 +- CLI 加载会收窄到拥有所请求主命令的插件 +- 渠道设置 / 插件解析会收窄到拥有所请求渠道 id 的插件 +- 显式提供商设置 / 运行时解析会收窄到拥有所请求提供商 id 的插件 -设置发现现在会优先使用由描述符拥有的 id,例如 `setup.providers` 和 `setup.cliBackends`,以便在回退到 `setup-api` 之前先缩小候选插件范围;而 `setup-api` 则用于那些仍然需要设置时运行时钩子的插件。如果多个已发现插件声明了相同的规范化 setup provider 或 CLI backend id,设置查找会拒绝这个存在歧义的归属者,而不是依赖发现顺序。 +设置发现现在会优先使用由描述符拥有的 id,例如 `setup.providers` 和 `setup.cliBackends`,以便在回退到 `setup-api` 之前先缩小候选插件范围;`setup-api` 仅用于那些仍然需要设置期运行时钩子的插件。如果多个已发现插件声明了相同的规范化 setup 提供商或 CLI 后端 id,则 setup 查找会拒绝这个存在歧义的归属者,而不是依赖发现顺序。 ### 加载器会缓存什么 -OpenClaw 会在进程内维护短生命周期缓存,用于: +OpenClaw 会为以下内容保留短期的进程内缓存: -- 发现结果 +- 设备发现结果 - 清单注册表数据 - 已加载的插件注册表 -这些缓存可以减少突发式启动和重复命令的开销。可以将它们安全地理解为短生命周期的性能缓存,而不是持久化存储。 +这些缓存可减少突发启动和重复命令带来的开销。可以安全地将它们视为短期性能缓存,而不是持久化机制。 性能说明: @@ -446,9 +451,9 @@ OpenClaw 会在进程内维护短生命周期缓存,用于: 注册表会跟踪: -- 插件记录(身份、来源、出处、状态、诊断) +- 插件记录(身份、来源、源头、状态、诊断) - 工具 -- 旧版钩子和类型化钩子 +- 传统钩子和类型化钩子 - 渠道 - 提供商 - Gateway 网关 RPC 处理器 @@ -457,16 +462,16 @@ OpenClaw 会在进程内维护短生命周期缓存,用于: - 后台服务 - 插件自有命令 -然后,核心功能从这个注册表中读取,而不是直接与插件模块通信。这使加载保持单向: +然后,核心功能会从这个注册表中读取,而不是直接与插件模块通信。这样可保持加载方向单向: - 插件模块 -> 注册表注册 - 核心运行时 -> 注册表消费 -这种分离对于可维护性很重要。这意味着大多数核心表面只需要一个集成点:“读取注册表”,而不是“为每个插件模块做特殊处理”。 +这种分离对可维护性很重要。这意味着大多数核心表面只需要一个集成点:“读取注册表”,而不是“为每个插件模块写特殊分支”。 ## 对话绑定回调 -绑定对话的插件可以在审批结果确定后作出响应。 +绑定某个对话的插件可以在批准结果确定后做出响应。 使用 `api.onConversationBindingResolved(...)` 可在绑定请求被批准或拒绝后接收回调: @@ -488,85 +493,86 @@ export default { }; ``` -回调负载字段包括: +回调负载字段: - `status`:`"approved"` 或 `"denied"` - `decision`:`"allow-once"`、`"allow-always"` 或 `"deny"` -- `binding`:已批准请求对应的已解析绑定 -- `request`:原始请求摘要、detach 提示、sender id 和对话元数据 +- `binding`:针对已批准请求的已解析绑定 +- `request`:原始请求摘要、detach 提示、发送者 id 和对话元数据 -这个回调仅用于通知。它不会改变谁被允许绑定对话,并且会在核心审批处理完成后运行。 +这个回调仅用于通知。它不会改变谁有权绑定某个对话,并且它会在核心批准处理完成后运行。 ## 提供商运行时钩子 提供商插件现在有两层: -- 清单元数据:`providerAuthEnvVars` 用于在运行时加载前进行轻量级提供商环境变量认证查找,`providerAuthAliases` 用于共享认证的提供商变体,`channelEnvVars` 用于在运行时加载前进行轻量级渠道环境变量 / 设置查找,以及 `providerAuthChoices` 用于在运行时加载前提供轻量级新手引导 / 认证选项标签和 CLI 标志元数据 -- 配置时钩子:`catalog` / 旧版 `discovery` 以及 `applyConfigDefaults` +- 清单元数据:`providerAuthEnvVars` 用于在运行时加载前进行低成本的提供商环境变量认证查找,`providerAuthAliases` 用于共享认证的提供商变体,`channelEnvVars` 用于在运行时加载前进行低成本的渠道环境变量 / 设置查找,以及 `providerAuthChoices` 用于在运行时加载前提供低成本的新手引导 / 认证选项标签和 CLI flag 元数据 +- 配置期钩子:`catalog` / 传统 `discovery` 以及 `applyConfigDefaults` - 运行时钩子:`normalizeModelId`、`normalizeTransport`、`normalizeConfig`、`applyNativeStreamingUsageCompat`、`resolveConfigApiKey`、`resolveSyntheticAuth`、`resolveExternalAuthProfiles`、`shouldDeferSyntheticProfileAuth`、`resolveDynamicModel`、`prepareDynamicModel`、`normalizeResolvedModel`、`contributeResolvedModelCompat`、`capabilities`、`normalizeToolSchemas`、`inspectToolSchemas`、`resolveReasoningOutputMode`、`prepareExtraParams`、`createStreamFn`、`wrapStreamFn`、`resolveTransportTurnState`、`resolveWebSocketSessionPolicy`、`formatApiKey`、`refreshOAuth`、`buildAuthDoctorHint`、`matchesContextOverflowError`、`classifyFailoverReason`、`isCacheTtlEligible`、`buildMissingAuthMessage`、`suppressBuiltInModel`、`augmentModelCatalog`、`resolveThinkingProfile`、`isBinaryThinking`、`supportsXHighThinking`、`resolveDefaultThinkingLevel`、`isModernModelRef`、`prepareRuntimeAuth`、`resolveUsageAuth`、`fetchUsageSnapshot`、`createEmbeddingProvider`、`buildReplayPolicy`、`sanitizeReplayHistory`、`validateReplayTurns`、`onModelSelected` -OpenClaw 仍然拥有通用智能体循环、故障切换、转录处理和工具策略。这些钩子是在无需整套自定义推理传输的情况下,为提供商特定行为提供扩展表面的方式。 +OpenClaw 仍然拥有通用智能体循环、故障切换、转录处理和工具策略。这些钩子是提供商专用行为的扩展表面,而无需构建完整的自定义推理传输层。 -当提供商具有基于环境变量的凭证,并且通用认证 / 状态 / 模型选择器路径需要在不加载插件运行时的情况下看到它们时,请使用清单中的 `providerAuthEnvVars`。当一个 provider id 应复用另一个 provider id 的环境变量、认证配置文件、基于配置的认证以及 API 密钥新手引导选项时,请使用清单中的 `providerAuthAliases`。当新手引导 / 认证选项 CLI 表面需要在不加载提供商运行时的情况下知道该提供商的 choice id、分组标签和简单的单标志认证接线时,请使用清单中的 `providerAuthChoices`。将提供商运行时 `envVars` 保留用于面向操作人员的提示,例如新手引导标签或 OAuth client-id / client-secret 设置变量。 +当某个提供商具有基于环境变量的凭证,且通用认证 / 状态 / 模型选择器路径需要在不加载插件运行时的情况下识别它时,请使用清单中的 `providerAuthEnvVars`。当某个提供商 id 需要复用另一个提供商 id 的环境变量、认证配置文件、基于配置的认证以及 API key 新手引导选项时,请使用清单中的 `providerAuthAliases`。当新手引导 / 认证选项 CLI 表面需要在不加载提供商运行时的情况下了解该提供商的选项 id、分组标签和简单的单 flag 认证接线时,请使用清单中的 `providerAuthChoices`。保留提供商运行时的 `envVars` 用于面向操作员的提示,例如新手引导标签或 OAuth client-id / client-secret 设置变量。 -当某个渠道具有基于环境变量驱动的认证或设置,并且通用 shell 环境变量回退、配置 / 状态检查或设置提示需要在不加载渠道运行时的情况下看到它时,请使用清单中的 `channelEnvVars`。 +当某个渠道具有由环境变量驱动的认证或设置,且通用 shell 环境变量回退、配置 / 状态检查或设置提示需要在不加载渠道运行时的情况下识别它时,请使用清单中的 `channelEnvVars`。 -### 钩子顺序与使用方式 +### 钩子顺序和用法 -对于模型 / 提供商插件,OpenClaw 大致按如下顺序调用钩子。“何时使用”这一列是快速决策指南。 +对于模型 / 提供商插件,OpenClaw 会大致按以下顺序调用钩子。 +“何时使用”这一列是快速决策指南。 | # | 钩子 | 作用 | 何时使用 | | --- | --------------------------------- | -------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------- | -| 1 | `catalog` | 在生成 `models.json` 期间将提供商配置发布到 `models.providers` 中 | 提供商拥有目录或基础 URL 默认值 | -| 2 | `applyConfigDefaults` | 在配置实体化期间应用提供商自有的全局配置默认值 | 默认值依赖认证模式、环境变量或提供商模型家族语义 | +| 1 | `catalog` | 在生成 `models.json` 时,将提供商配置发布到 `models.providers` 中 | 提供商拥有目录或基础 `base URL` 默认值 | +| 2 | `applyConfigDefaults` | 在配置实体化期间应用由提供商拥有的全局配置默认值 | 默认值依赖认证模式、环境变量或提供商模型家族语义 | | -- | _(内置模型查找)_ | OpenClaw 会先尝试常规注册表 / 目录路径 | _(不是插件钩子)_ | -| 3 | `normalizeModelId` | 在查找前规范化旧版或预览版 model-id 别名 | 提供商拥有在规范模型解析前进行的别名清理 | -| 4 | `normalizeTransport` | 在通用模型组装前规范化提供商家族的 `api` / `baseUrl` | 提供商拥有同一传输家族中自定义 provider id 的传输清理逻辑 | -| 5 | `normalizeConfig` | 在运行时 / 提供商解析前规范化 `models.providers.` | 提供商需要将配置清理逻辑与插件放在一起;内置的 Google 家族辅助工具也会为受支持的 Google 配置项提供兜底 | -| 6 | `applyNativeStreamingUsageCompat` | 对配置提供商应用原生分块流式传输用量兼容性重写 | 提供商需要基于端点驱动的原生分块流式传输用量元数据修复 | -| 7 | `resolveConfigApiKey` | 在运行时认证加载前,为配置提供商解析环境变量标记认证 | 提供商拥有自己的环境变量标记 API 密钥解析逻辑;`amazon-bedrock` 这里也有一个内置的 AWS 环境变量标记解析器 | -| 8 | `resolveSyntheticAuth` | 在不持久化明文的情况下暴露本地 / 自托管或基于配置的认证 | 提供商可使用合成 / 本地凭证标记运行 | -| 9 | `resolveExternalAuthProfiles` | 叠加提供商自有的外部认证配置文件;默认 `persistence` 为面向 CLI / 应用自有凭证的 `runtime-only` | 提供商会复用外部认证凭证,而不持久化复制出来的 refresh token | -| 10 | `shouldDeferSyntheticProfileAuth` | 将已存储的合成配置文件占位符优先级下调到环境变量 / 基于配置的认证之后 | 提供商存储了不应优先生效的合成占位配置文件 | -| 11 | `resolveDynamicModel` | 为尚未存在于本地注册表中的提供商自有 model id 提供同步回退 | 提供商接受任意上游 model id | -| 12 | `prepareDynamicModel` | 进行异步预热,然后再次运行 `resolveDynamicModel` | 提供商在解析未知 id 前需要网络元数据 | -| 13 | `normalizeResolvedModel` | 在嵌入式运行器使用已解析模型前进行最终重写 | 提供商需要进行传输重写,但仍使用核心传输 | -| 14 | `contributeResolvedModelCompat` | 为位于另一个兼容传输后的供应商模型提供兼容性标志 | 提供商能在代理传输上识别自己的模型,而不接管该提供商 | -| 15 | `capabilities` | 由共享核心逻辑使用的提供商自有转录 / 工具元数据 | 提供商需要处理转录 / 提供商家族特有行为 | -| 16 | `normalizeToolSchemas` | 在嵌入式运行器看到工具 schema 之前对其进行规范化 | 提供商需要处理传输家族 schema 清理 | -| 17 | `inspectToolSchemas` | 在规范化后暴露提供商自有的 schema 诊断信息 | 提供商希望给出关键字警告,而不需要教核心了解提供商特定规则 | -| 18 | `resolveReasoningOutputMode` | 选择原生还是带标签的推理输出契约 | 提供商需要使用带标签的推理 / 最终输出,而不是原生字段 | -| 19 | `prepareExtraParams` | 在通用流包装器之前对请求参数进行规范化 | 提供商需要默认请求参数或按提供商清理参数 | -| 20 | `createStreamFn` | 用自定义传输完全替换常规流路径 | 提供商需要自定义线路协议,而不只是包装器 | -| 21 | `wrapStreamFn` | 在应用通用包装器之后再包裹流 | 提供商需要请求头 / 请求体 / 模型兼容性包装器,但不需要自定义传输 | -| 22 | `resolveTransportTurnState` | 附加原生的逐轮传输头或元数据 | 提供商希望通用传输发送提供商原生的轮次身份 | -| 23 | `resolveWebSocketSessionPolicy` | 附加原生 WebSocket 头或会话冷却策略 | 提供商希望通用 WS 传输可调整会话头或回退策略 | -| 24 | `formatApiKey` | 认证配置文件格式化器:已存储配置文件会变为运行时 `apiKey` 字符串 | 提供商存储了额外认证元数据,并需要自定义运行时 token 形态 | -| 25 | `refreshOAuth` | 用于自定义刷新端点或刷新失败策略的 OAuth 刷新覆盖 | 提供商不适配共享的 `pi-ai` 刷新器 | -| 26 | `buildAuthDoctorHint` | 在 OAuth 刷新失败时追加修复提示 | 提供商需要在刷新失败后提供自有的认证修复指引 | +| 3 | `normalizeModelId` | 在查找前规范化传统或预览版模型 id 别名 | 提供商在规范模型解析前拥有别名清理逻辑 | +| 4 | `normalizeTransport` | 在通用模型组装前规范化提供商家族的 `api` / `baseUrl` | 提供商拥有同一传输家族中自定义提供商 id 的传输清理逻辑 | +| 5 | `normalizeConfig` | 在运行时 / 提供商解析前规范化 `models.providers.` | 提供商需要由插件持有的配置清理逻辑;内置的 Google 家族辅助工具也会为受支持的 Google 配置项提供兜底 | +| 6 | `applyNativeStreamingUsageCompat` | 对配置提供商应用原生流式用量兼容性重写 | 提供商需要基于端点的原生流式用量元数据修正 | +| 7 | `resolveConfigApiKey` | 在运行时认证加载前,为配置提供商解析 env-marker 认证 | 提供商拥有自己的 env-marker API key 解析逻辑;`amazon-bedrock` 在这里也有一个内置的 AWS env-marker 解析器 | +| 8 | `resolveSyntheticAuth` | 在不持久化明文的情况下暴露本地 / 自托管或基于配置的认证 | 提供商可以使用 synthetic / 本地凭证标记运行 | +| 9 | `resolveExternalAuthProfiles` | 叠加提供商拥有的外部认证配置文件;默认 `persistence` 为 `runtime-only`,适用于 CLI / 应用自有凭证 | 提供商会复用外部认证凭证,而不持久化复制过来的 refresh token | +| 10 | `shouldDeferSyntheticProfileAuth` | 将已存储的 synthetic 配置文件占位符降级到环境变量 / 基于配置的认证之后 | 提供商会存储 synthetic 占位配置文件,而这些配置文件不应获得更高优先级 | +| 11 | `resolveDynamicModel` | 对尚未存在于本地注册表中的提供商自有模型 id 进行同步回退解析 | 提供商接受任意上游模型 id | +| 12 | `prepareDynamicModel` | 异步预热,然后再次运行 `resolveDynamicModel` | 提供商在解析未知 id 之前需要网络元数据 | +| 13 | `normalizeResolvedModel` | 在嵌入式运行器使用已解析模型之前做最终重写 | 提供商需要传输重写,但仍使用核心传输 | +| 14 | `contributeResolvedModelCompat` | 为位于另一个兼容传输后的供应商模型提供兼容性标记 | 提供商能够在代理传输上识别自己的模型,而无需接管该提供商 | +| 15 | `capabilities` | 由共享核心逻辑使用的提供商自有转录 / 工具元数据 | 提供商需要转录 / 提供商家族特殊处理 | +| 16 | `normalizeToolSchemas` | 在嵌入式运行器看到工具 schema 之前进行规范化 | 提供商需要传输家族级 schema 清理 | +| 17 | `inspectToolSchemas` | 在规范化后暴露提供商自有的 schema 诊断信息 | 提供商希望给出关键字警告,而不必让核心学习提供商专用规则 | +| 18 | `resolveReasoningOutputMode` | 选择原生还是带标签的推理输出契约 | 提供商需要带标签的推理 / 最终输出,而不是原生字段 | +| 19 | `prepareExtraParams` | 在通用流选项包装器之前进行请求参数规范化 | 提供商需要默认请求参数或逐提供商参数清理 | +| 20 | `createStreamFn` | 用自定义传输完全替换常规流路径 | 提供商需要自定义线协议,而不仅仅是一个包装器 | +| 21 | `wrapStreamFn` | 在应用完通用包装器后对流进行包装 | 提供商需要请求头 / 请求体 / 模型兼容性包装器,但不需要自定义传输 | +| 22 | `resolveTransportTurnState` | 附加原生的逐轮传输请求头或元数据 | 提供商希望通用传输发送提供商原生的轮次身份信息 | +| 23 | `resolveWebSocketSessionPolicy` | 附加原生 WebSocket 请求头或会话冷却策略 | 提供商希望通用 WebSocket 传输调整会话请求头或回退策略 | +| 24 | `formatApiKey` | 认证配置文件格式化器:已存储配置文件会变成运行时 `apiKey` 字符串 | 提供商存储额外认证元数据,并需要自定义运行时 token 形态 | +| 25 | `refreshOAuth` | 针对自定义刷新端点或刷新失败策略的 OAuth 刷新覆盖 | 提供商不适配共享的 `pi-ai` 刷新器 | +| 26 | `buildAuthDoctorHint` | 在 OAuth 刷新失败时追加修复提示 | 提供商在刷新失败后需要提供商自有的认证修复指导 | | 27 | `matchesContextOverflowError` | 提供商自有的上下文窗口溢出匹配器 | 提供商存在通用启发式无法识别的原始溢出错误 | -| 28 | `classifyFailoverReason` | 提供商自有的故障切换原因分类 | 提供商可将原始 API / 传输错误映射为限流 / 过载等原因 | -| 29 | `isCacheTtlEligible` | 面向代理 / 回程提供商的提示词缓存策略 | 提供商需要代理特定的缓存 TTL 限制逻辑 | -| 30 | `buildMissingAuthMessage` | 替代通用缺失认证恢复消息 | 提供商需要提供商特定的缺失认证恢复提示 | -| 31 | `suppressBuiltInModel` | 过时上游模型抑制,并可附带面向用户的错误提示 | 提供商需要隐藏过时的上游条目,或用供应商提示替换它们 | -| 32 | `augmentModelCatalog` | 在发现后追加合成 / 最终目录条目 | 提供商需要在 `models list` 和选择器中添加合成的前向兼容条目 | -| 33 | `resolveThinkingProfile` | 为特定模型设置 `/think` 级别、显示标签和默认值 | 提供商为选定模型提供自定义思考层级或二元标签 | -| 34 | `isBinaryThinking` | 开 / 关推理切换兼容性钩子 | 提供商只暴露二元的思考开 / 关 | -| 35 | `supportsXHighThinking` | `xhigh` 推理支持兼容性钩子 | 提供商希望仅在部分模型上支持 `xhigh` | +| 28 | `classifyFailoverReason` | 提供商自有的故障切换原因分类 | 提供商可以将原始 API / 传输错误映射为速率限制 / 过载等原因 | +| 29 | `isCacheTtlEligible` | 面向代理 / 回传提供商的提示词缓存策略 | 提供商需要代理专用的缓存 TTL 门控 | +| 30 | `buildMissingAuthMessage` | 替换通用的缺失认证恢复消息 | 提供商需要提供商专用的缺失认证恢复提示 | +| 31 | `suppressBuiltInModel` | 过时上游模型抑制,以及可选的面向用户错误提示 | 提供商需要隐藏过时的上游条目,或用供应商提示替换它们 | +| 32 | `augmentModelCatalog` | 在发现后追加 synthetic / 最终目录条目 | 提供商需要在 `models list` 和选择器中添加 synthetic 前向兼容条目 | +| 33 | `resolveThinkingProfile` | 设置模型专用的 `/think` 级别、显示标签和默认值 | 提供商为选定模型暴露自定义 thinking 阶梯或二元标签 | +| 34 | `isBinaryThinking` | 开 / 关式推理切换兼容性钩子 | 提供商只暴露二元 thinking 开 / 关 | +| 35 | `supportsXHighThinking` | `xhigh` 推理支持兼容性钩子 | 提供商只希望在部分模型上支持 `xhigh` | | 36 | `resolveDefaultThinkingLevel` | 默认 `/think` 级别兼容性钩子 | 提供商拥有某个模型家族的默认 `/think` 策略 | -| 37 | `isModernModelRef` | 用于实时配置文件筛选和 smoke 选择的现代模型匹配器 | 提供商拥有实时 / smoke 首选模型匹配逻辑 | -| 38 | `prepareRuntimeAuth` | 在推理前最后时刻将已配置凭证交换为实际运行时 token / key | 提供商需要进行 token 交换或使用短生命周期请求凭证 | -| 39 | `resolveUsageAuth` | 为 `/usage` 及相关状态表面解析用量 / 计费凭证 | 提供商需要自定义用量 / 配额 token 解析,或使用不同的用量凭证 | -| 40 | `fetchUsageSnapshot` | 在认证解析完成后获取并规范化提供商特定的用量 / 配额快照 | 提供商需要提供商特定的用量端点或负载解析器 | -| 41 | `createEmbeddingProvider` | 为 memory / 搜索构建提供商自有的 embedding 适配器 | memory embedding 行为应归属于提供商插件 | -| 42 | `buildReplayPolicy` | 返回一个控制该提供商转录处理方式的重放策略 | 提供商需要自定义转录策略(例如剥离 thinking 块) | -| 43 | `sanitizeReplayHistory` | 在通用转录清理后重写重放历史 | 提供商需要在共享压缩辅助工具之外执行提供商特定的重放重写 | -| 44 | `validateReplayTurns` | 在嵌入式运行器之前对重放轮次进行最终校验或重塑 | 提供商传输在通用清理后需要更严格的轮次校验 | -| 45 | `onModelSelected` | 在模型被选中后运行提供商自有的副作用 | 当模型变为活动状态时,提供商需要遥测或提供商自有状态 | +| 37 | `isModernModelRef` | 用于实时配置文件过滤和 smoke 选择的现代模型匹配器 | 提供商拥有 live / smoke 首选模型匹配逻辑 | +| 38 | `prepareRuntimeAuth` | 在推理开始前,将已配置的凭证交换为实际运行时 token / key | 提供商需要 token 交换或短期请求凭证 | +| 39 | `resolveUsageAuth` | 为 `/usage` 及相关状态表面解析用量 / 计费凭证 | 提供商需要自定义用量 / 配额 token 解析,或需要不同的用量凭证 | +| 40 | `fetchUsageSnapshot` | 在认证解析完成后获取并规范化提供商专用的用量 / 配额快照 | 提供商需要提供商专用的用量端点或负载解析器 | +| 41 | `createEmbeddingProvider` | 为 memory / 搜索构建提供商自有的嵌入适配器 | Memory 嵌入行为应归属于提供商插件 | +| 42 | `buildReplayPolicy` | 返回一个控制该提供商转录处理方式的重放策略 | 提供商需要自定义转录策略(例如移除 thinking 块) | +| 43 | `sanitizeReplayHistory` | 在通用转录清理之后重写重放历史 | 提供商需要超出共享压缩辅助工具范围之外的提供商专用重放重写 | +| 44 | `validateReplayTurns` | 在嵌入式运行器之前,对重放轮次进行最终验证或重塑 | 提供商传输在通用清理之后需要更严格的轮次验证 | +| 45 | `onModelSelected` | 在模型被选中后运行提供商自有的后置副作用 | 当某个模型变为活跃状态时,提供商需要遥测或提供商自有状态 | -`normalizeModelId`、`normalizeTransport` 和 `normalizeConfig` 会先检查匹配到的提供商插件,然后再继续落到其他支持钩子的提供商插件,直到其中某个插件实际修改了 model id 或 transport / config。这样可以让别名 / 兼容性提供商 shim 正常工作,而不要求调用方知道哪个内置插件拥有这次重写。如果没有任何提供商钩子重写受支持的 Google 家族配置项,内置的 Google 配置规范化器仍会应用这类兼容性清理。 +`normalizeModelId`、`normalizeTransport` 和 `normalizeConfig` 会先检查已匹配的提供商插件,然后继续传递给其他具备这些钩子能力的提供商插件,直到某个插件实际改写了模型 id 或传输 / 配置为止。这样可以让别名 / 兼容性提供商 shim 继续工作,而不要求调用方知道哪个内置插件拥有这次改写。如果没有任何提供商钩子改写某个受支持的 Google 家族配置项,那么内置的 Google 配置规范化器仍会执行该兼容性清理。 -如果提供商需要完全自定义的线路协议或自定义请求执行器,那是另一类扩展。这些钩子适用于仍运行在 OpenClaw 常规推理循环上的提供商行为。 +如果某个提供商需要完全自定义的线协议或自定义请求执行器,那属于另一类扩展。这些钩子适用于仍在 OpenClaw 常规推理循环上运行的提供商行为。 ### 提供商示例 @@ -624,29 +630,29 @@ api.registerProvider({ ### 内置示例 -- Anthropic 使用 `resolveDynamicModel`、`capabilities`、`buildAuthDoctorHint`、`resolveUsageAuth`、`fetchUsageSnapshot`、`isCacheTtlEligible`、`resolveThinkingProfile`、`applyConfigDefaults`、`isModernModelRef` 和 `wrapStreamFn`,因为它拥有 Claude 4.6 前向兼容、提供商家族提示、认证修复指引、用量端点集成、提示词缓存资格、认证感知的配置默认值、Claude 默认 / 自适应思考策略,以及针对 beta 头、`/fast` / `serviceTier` 和 `context1m` 的 Anthropic 特定流整形。 -- Anthropic 的 Claude 特定流辅助工具目前保留在内置插件自身公开的 `api.ts` / `contract-api.ts` 接缝中。该包表面导出的是 `wrapAnthropicProviderStream`、`resolveAnthropicBetas`、`resolveAnthropicFastMode`、`resolveAnthropicServiceTier` 以及更底层的 Anthropic 包装器构建工具,而不是围绕某个提供商的 beta 头规则去扩展通用 SDK。 -- OpenAI 使用 `resolveDynamicModel`、`normalizeResolvedModel` 和 `capabilities`,以及 `buildMissingAuthMessage`、`suppressBuiltInModel`、`augmentModelCatalog`、`resolveThinkingProfile` 和 `isModernModelRef`,因为它拥有 GPT-5.4 前向兼容、直接的 OpenAI `openai-completions` -> `openai-responses` 规范化、面向 Codex 的认证提示、Spark 抑制、合成 OpenAI 列表行,以及 GPT-5 思考 / 实时模型策略;`openai-responses-defaults` 流家族拥有共享的原生 OpenAI Responses 包装器,用于 attribution 头、`/fast` / `serviceTier`、文本详细度、原生 Codex Web 搜索、推理兼容负载整形和 Responses 上下文管理。 -- OpenRouter 使用 `catalog`,以及 `resolveDynamicModel` 和 `prepareDynamicModel`,因为该提供商是透传式的,并且可能会在 OpenClaw 的静态目录更新之前暴露新的 model id;它还使用 `capabilities`、`wrapStreamFn` 和 `isCacheTtlEligible`,以便将提供商特定请求头、路由元数据、推理补丁和提示词缓存策略保留在核心之外。它的重放策略来自 `passthrough-gemini` 家族,而 `openrouter-thinking` 流家族拥有代理推理注入以及对不受支持模型 / `auto` 的跳过逻辑。 -- GitHub Copilot 使用 `catalog`、`auth`、`resolveDynamicModel` 和 `capabilities`,以及 `prepareRuntimeAuth` 和 `fetchUsageSnapshot`,因为它需要提供商自有的设备登录、模型回退行为、Claude 转录特性、GitHub token -> Copilot token 交换以及提供商自有的用量端点。 -- OpenAI Codex 使用 `catalog`、`resolveDynamicModel`、`normalizeResolvedModel`、`refreshOAuth` 和 `augmentModelCatalog`,以及 `prepareExtraParams`、`resolveUsageAuth` 和 `fetchUsageSnapshot`,因为它仍运行在核心 OpenAI 传输之上,但拥有其 transport / base URL 规范化、OAuth 刷新回退策略、默认传输选择、合成 Codex 目录条目和 ChatGPT 用量端点集成;它与直接 OpenAI 共享同一个 `openai-responses-defaults` 流家族。 -- Google AI Studio 和 Gemini CLI OAuth 使用 `resolveDynamicModel`、`buildReplayPolicy`、`sanitizeReplayHistory`、`resolveReasoningOutputMode`、`wrapStreamFn` 和 `isModernModelRef`,因为 `google-gemini` 重放家族拥有 Gemini 3.1 前向兼容回退、原生 Gemini 重放校验、bootstrap 重放清理、带标签的推理输出模式和现代模型匹配,而 `google-thinking` 流家族拥有 Gemini thinking 负载规范化;Gemini CLI OAuth 还使用 `formatApiKey`、`resolveUsageAuth` 和 `fetchUsageSnapshot` 来处理 token 格式化、token 解析和 quota 端点接线。 -- Anthropic Vertex 通过 `anthropic-by-model` 重放家族使用 `buildReplayPolicy`,这样 Claude 特定的重放清理就能只限定在 Claude id 范围内,而不是作用于每个 `anthropic-messages` 传输。 -- Amazon Bedrock 使用 `buildReplayPolicy`、`matchesContextOverflowError`、`classifyFailoverReason` 和 `resolveThinkingProfile`,因为它拥有针对 Anthropic-on-Bedrock 流量的 Bedrock 特定限流 / 未就绪 / 上下文溢出错误分类;其重放策略仍与同一个仅限 Claude 的 `anthropic-by-model` 防护共享。 -- OpenRouter、Kilocode、Opencode 和 Opencode Go 通过 `passthrough-gemini` 重放家族使用 `buildReplayPolicy`,因为它们通过 OpenAI 兼容传输代理 Gemini 模型,并且需要 Gemini thought-signature 清理,而不需要原生 Gemini 重放校验或 bootstrap 重写。 -- MiniMax 通过 `hybrid-anthropic-openai` 重放家族使用 `buildReplayPolicy`,因为一个提供商同时拥有 Anthropic-message 和 OpenAI 兼容语义;它会在 Anthropic 侧保留仅限 Claude 的 thinking 块丢弃逻辑,同时将推理输出模式覆盖回原生,而 `minimax-fast-mode` 流家族拥有共享流路径上的 fast-mode 模型重写。 -- Moonshot 使用 `catalog`、`resolveThinkingProfile` 和 `wrapStreamFn`,因为它仍使用共享 OpenAI 传输,但需要提供商自有的 thinking 负载规范化;`moonshot-thinking` 流家族将配置加 `/think` 状态映射到其原生的二元 thinking 负载。 -- Kilocode 使用 `catalog`、`capabilities`、`wrapStreamFn` 和 `isCacheTtlEligible`,因为它需要提供商自有请求头、推理负载规范化、Gemini 转录提示和 Anthropic 缓存 TTL 限制;`kilocode-thinking` 流家族会在共享代理流路径上保留 Kilo thinking 注入,同时跳过 `kilo/auto` 和其他不支持显式推理负载的代理 model id。 -- Z.AI 使用 `resolveDynamicModel`、`prepareExtraParams`、`wrapStreamFn`、`isCacheTtlEligible`、`resolveThinkingProfile`、`isModernModelRef`、`resolveUsageAuth` 和 `fetchUsageSnapshot`,因为它拥有 GLM-5 回退、`tool_stream` 默认值、二元 thinking UX、现代模型匹配,以及用量认证和 quota 获取;`tool-stream-default-on` 流家族会把默认开启的 `tool_stream` 包装器保留在逐提供商手写胶水代码之外。 -- xAI 使用 `normalizeResolvedModel`、`normalizeTransport`、`contributeResolvedModelCompat`、`prepareExtraParams`、`wrapStreamFn`、`resolveSyntheticAuth`、`resolveDynamicModel` 和 `isModernModelRef`,因为它拥有原生 xAI Responses 传输规范化、Grok fast-mode 别名重写、默认 `tool_stream`、严格工具 / 推理负载清理、面向插件自有工具的回退认证复用、前向兼容的 Grok 模型解析,以及提供商自有兼容性补丁,例如 xAI 工具 schema 配置、受支持 schema 关键字、原生 `web_search` 和 HTML 实体工具调用参数解码。 -- Mistral、OpenCode Zen 和 OpenCode Go 只使用 `capabilities`,以便将转录 / 工具特性保留在核心之外。 -- 仅目录型内置提供商,例如 `byteplus`、`cloudflare-ai-gateway`、`huggingface`、`kimi-coding`、`nvidia`、`qianfan`、`synthetic`、`together`、`venice`、`vercel-ai-gateway` 和 `volcengine`,只使用 `catalog`。 -- Qwen 为其文本提供商使用 `catalog`,并为其多模态表面共享媒体理解和视频生成注册。 -- MiniMax 和 Xiaomi 使用 `catalog` 加上用量钩子,因为它们的 `/usage` 行为归插件拥有,尽管推理仍通过共享传输运行。 +- Anthropic 使用 `resolveDynamicModel`、`capabilities`、`buildAuthDoctorHint`、`resolveUsageAuth`、`fetchUsageSnapshot`、`isCacheTtlEligible`、`resolveThinkingProfile`、`applyConfigDefaults`、`isModernModelRef` 和 `wrapStreamFn`,因为它拥有 Claude 4.6 前向兼容、提供商家族提示、认证修复指导、用量端点集成、提示词缓存资格、感知认证状态的配置默认值、Claude 默认 / 自适应 thinking 策略,以及面向 beta 请求头、`/fast` / `serviceTier` 和 `context1m` 的 Anthropic 专用流整形。 +- Anthropic 的 Claude 专用流辅助工具目前仍保留在该内置插件自己的公共 `api.ts` / `contract-api.ts` 接缝中。该包表面导出 `wrapAnthropicProviderStream`、`resolveAnthropicBetas`、`resolveAnthropicFastMode`、`resolveAnthropicServiceTier` 以及更底层的 Anthropic 包装器构建器,而不是为了某一个提供商的 beta 请求头规则去扩展通用 SDK。 +- OpenAI 使用 `resolveDynamicModel`、`normalizeResolvedModel` 和 `capabilities`,以及 `buildMissingAuthMessage`、`suppressBuiltInModel`、`augmentModelCatalog`、`resolveThinkingProfile` 和 `isModernModelRef`,因为它拥有 GPT-5.4 前向兼容、直接 OpenAI `openai-completions` -> `openai-responses` 规范化、具备 Codex 感知能力的认证提示、Spark 抑制、synthetic OpenAI 列表条目,以及 GPT-5 thinking / live-model 策略;`openai-responses-defaults` 流家族则拥有共享的原生 OpenAI Responses 包装器,用于处理 attribution 请求头、`/fast` / `serviceTier`、文本冗长度、原生 Codex 网页搜索、reasoning-compat 负载整形和 Responses 上下文管理。 +- OpenRouter 使用 `catalog` 以及 `resolveDynamicModel` 和 `prepareDynamicModel`,因为这个提供商是透传型的,并且可能会在 OpenClaw 静态目录更新之前暴露新的模型 id;它还使用 `capabilities`、`wrapStreamFn` 和 `isCacheTtlEligible`,以便将提供商专用的请求头、路由元数据、reasoning 补丁和提示词缓存策略保留在核心之外。它的重放策略来自 `passthrough-gemini` 家族,而 `openrouter-thinking` 流家族则拥有代理推理注入和不受支持模型 / `auto` 跳过逻辑。 +- GitHub Copilot 使用 `catalog`、`auth`、`resolveDynamicModel` 和 `capabilities`,以及 `prepareRuntimeAuth` 和 `fetchUsageSnapshot`,因为它需要提供商自有的设备登录、模型回退行为、Claude 转录特殊处理、GitHub token -> Copilot token 交换,以及提供商自有的用量端点。 +- OpenAI Codex 使用 `catalog`、`resolveDynamicModel`、`normalizeResolvedModel`、`refreshOAuth` 和 `augmentModelCatalog`,以及 `prepareExtraParams`、`resolveUsageAuth` 和 `fetchUsageSnapshot`,因为它仍运行在核心 OpenAI 传输之上,但拥有自己的传输 / `baseUrl` 规范化、OAuth 刷新回退策略、默认传输选择、synthetic Codex 目录条目以及 ChatGPT 用量端点集成;它与直接 OpenAI 共享同一个 `openai-responses-defaults` 流家族。 +- Google AI Studio 和 Gemini CLI OAuth 使用 `resolveDynamicModel`、`buildReplayPolicy`、`sanitizeReplayHistory`、`resolveReasoningOutputMode`、`wrapStreamFn` 和 `isModernModelRef`,因为 `google-gemini` 重放家族拥有 Gemini 3.1 前向兼容回退、原生 Gemini 重放验证、bootstrap 重放清理、带标签的推理输出模式,以及现代模型匹配;而 `google-thinking` 流家族拥有 Gemini thinking 负载规范化。Gemini CLI OAuth 还使用 `formatApiKey`、`resolveUsageAuth` 和 `fetchUsageSnapshot` 来处理 token 格式化、token 解析和配额端点接线。 +- Anthropic Vertex 通过 `anthropic-by-model` 重放家族使用 `buildReplayPolicy`,以便让 Claude 专用重放清理只作用于 Claude id,而不是所有 `anthropic-messages` 传输。 +- Amazon Bedrock 使用 `buildReplayPolicy`、`matchesContextOverflowError`、`classifyFailoverReason` 和 `resolveThinkingProfile`,因为它拥有面向 Anthropic-on-Bedrock 流量的 Bedrock 专用限流 / 未就绪 / 上下文溢出错误分类;其重放策略仍与相同的 Claude 专用 `anthropic-by-model` 防护共享。 +- OpenRouter、Kilocode、Opencode 和 Opencode Go 通过 `passthrough-gemini` 重放家族使用 `buildReplayPolicy`,因为它们通过 OpenAI 兼容传输代理 Gemini 模型,并且需要 Gemini thought-signature 清理,而不需要原生 Gemini 重放验证或 bootstrap 重写。 +- MiniMax 通过 `hybrid-anthropic-openai` 重放家族使用 `buildReplayPolicy`,因为同一个提供商同时拥有 Anthropic-message 和 OpenAI 兼容语义;它会在 Anthropic 侧保留 Claude 专用的 thinking 块丢弃逻辑,同时将推理输出模式覆盖回原生模式,而 `minimax-fast-mode` 流家族则拥有共享流路径上的 fast-mode 模型重写。 +- Moonshot 使用 `catalog`、`resolveThinkingProfile` 和 `wrapStreamFn`,因为它仍使用共享 OpenAI 传输,但需要提供商自有的 thinking 负载规范化;`moonshot-thinking` 流家族会将配置与 `/think` 状态映射到其原生的二元 thinking 负载。 +- Kilocode 使用 `catalog`、`capabilities`、`wrapStreamFn` 和 `isCacheTtlEligible`,因为它需要提供商自有的请求头、reasoning 负载规范化、Gemini 转录提示以及 Anthropic 缓存 TTL 门控;`kilocode-thinking` 流家族会在共享代理流路径上保留 Kilo thinking 注入,同时跳过 `kilo/auto` 和其他不支持显式推理负载的代理模型 id。 +- Z.AI 使用 `resolveDynamicModel`、`prepareExtraParams`、`wrapStreamFn`、`isCacheTtlEligible`、`resolveThinkingProfile`、`isModernModelRef`、`resolveUsageAuth` 和 `fetchUsageSnapshot`,因为它拥有 GLM-5 回退、`tool_stream` 默认值、二元 thinking UX、现代模型匹配,以及用量认证 + 配额获取;`tool-stream-default-on` 流家族则让默认开启的 `tool_stream` 包装器不必散落在各提供商的手写 glue 代码中。 +- xAI 使用 `normalizeResolvedModel`、`normalizeTransport`、`contributeResolvedModelCompat`、`prepareExtraParams`、`wrapStreamFn`、`resolveSyntheticAuth`、`resolveDynamicModel` 和 `isModernModelRef`,因为它拥有原生 xAI Responses 传输规范化、Grok fast-mode 别名重写、默认 `tool_stream`、strict-tool / reasoning-payload 清理、用于插件自有工具的回退认证复用、前向兼容的 Grok 模型解析,以及由提供商自有的兼容性补丁,例如 xAI 工具 schema 配置、受支持性不足的 schema 关键字、原生 `web_search` 和 HTML 实体工具调用参数解码。 +- Mistral、OpenCode Zen 和 OpenCode Go 仅使用 `capabilities`,以将转录 / 工具特殊处理保留在核心之外。 +- 仅目录型的内置提供商,如 `byteplus`、`cloudflare-ai-gateway`、`huggingface`、`kimi-coding`、`nvidia`、`qianfan`、`synthetic`、`together`、`venice`、`vercel-ai-gateway` 和 `volcengine`,仅使用 `catalog`。 +- Qwen 为其文本提供商使用 `catalog`,并为其多模态表面使用共享的媒体理解和视频生成注册。 +- MiniMax 和 Xiaomi 同时使用 `catalog` 和用量钩子,因为即使推理仍通过共享传输运行,它们的 `/usage` 行为仍归插件所有。 ## 运行时辅助工具 -插件可以通过 `api.runtime` 访问部分核心辅助工具。以 TTS 为例: +插件可以通过 `api.runtime` 访问部分核心辅助工具。对于 TTS: ```ts const clip = await api.runtime.tts.textToSpeech({ @@ -667,11 +673,11 @@ const voices = await api.runtime.tts.listVoices({ 说明: -- `textToSpeech` 返回适用于文件 / 语音便签表面的常规核心 TTS 输出负载。 +- `textToSpeech` 返回常规核心 TTS 输出负载,适用于文件 / 语音便签表面。 - 使用核心 `messages.tts` 配置和提供商选择。 -- 返回 PCM 音频缓冲区 + 采样率。插件必须为提供商重新采样 / 编码。 -- `listVoices` 对每个提供商来说是可选的。可将其用于供应商自有的语音选择器或设置流程。 -- 语音列表可以包含更丰富的元数据,例如区域设置、性别和个性标签,以供具备提供商感知能力的选择器使用。 +- 返回 PCM 音频缓冲区 + 采样率。插件必须为提供商完成重采样 / 编码。 +- `listVoices` 对每个提供商来说都是可选的。可将其用于供应商自有的语音选择器或设置流程。 +- 语音列表可以包含更丰富的元数据,例如 locale、gender 和 personality 标签,以支持具备提供商感知能力的选择器。 - 目前 OpenAI 和 ElevenLabs 支持电话场景。Microsoft 不支持。 插件也可以通过 `api.registerSpeechProvider(...)` 注册语音提供商。 @@ -694,10 +700,10 @@ api.registerSpeechProvider({ 说明: -- 将 TTS 策略、回退和回复交付保留在核心中。 -- 对供应商自有的合成行为使用语音提供商。 -- 旧版 Microsoft `edge` 输入会被规范化为 `microsoft` provider id。 -- 首选的归属模型是面向公司的:随着 OpenClaw 增加这些能力契约,一个供应商插件可以同时拥有文本、语音、图像和未来的媒体提供商。 +- 将 TTS 策略、回退和回复投递保留在核心中。 +- 使用语音提供商来承载供应商自有的合成行为。 +- 传统的 Microsoft `edge` 输入会被规范化为 `microsoft` 提供商 id。 +- 首选的归属模型是面向公司的:随着 OpenClaw 增加这些能力契约,一个供应商插件可以统一拥有文本、语音、图像和未来媒体提供商。 对于图像 / 音频 / 视频理解,插件会注册一个类型化的媒体理解提供商,而不是通用的键 / 值包: @@ -736,7 +742,7 @@ const video = await api.runtime.mediaUnderstanding.describeVideoFile({ }); ``` -对于音频转录,插件既可以使用媒体理解运行时,也可以使用旧版 STT 别名: +对于音频转录,插件既可以使用媒体理解运行时,也可以使用较旧的 STT 别名: ```ts const { text } = await api.runtime.mediaUnderstanding.transcribeAudioFile({ @@ -751,10 +757,10 @@ const { text } = await api.runtime.mediaUnderstanding.transcribeAudioFile({ - `api.runtime.mediaUnderstanding.*` 是图像 / 音频 / 视频理解的首选共享表面。 - 使用核心媒体理解音频配置(`tools.media.audio`)和提供商回退顺序。 -- 当未产生转录输出时返回 `{ text: undefined }`(例如输入被跳过 / 不受支持)。 +- 当未产生任何转录输出时,返回 `{ text: undefined }`(例如输入被跳过 / 不受支持)。 - `api.runtime.stt.transcribeAudioFile(...)` 仍保留为兼容性别名。 -插件也可以通过 `api.runtime.subagent` 启动后台子智能体运行: +插件还可以通过 `api.runtime.subagent` 启动后台子智能体运行: ```ts const result = await api.runtime.subagent.run({ @@ -768,13 +774,13 @@ const result = await api.runtime.subagent.run({ 说明: -- `provider` 和 `model` 是每次运行可选的覆盖项,不是持久性的会话更改。 -- OpenClaw 只会为受信任调用方启用这些覆盖字段。 -- 对于插件自有的回退运行,操作员必须通过 `plugins.entries..subagent.allowModelOverride: true` 显式选择启用。 -- 使用 `plugins.entries..subagent.allowedModels` 将受信任插件限制为特定的规范 `provider/model` 目标,或者设为 `"*"` 以显式允许任意目标。 -- 不受信任插件的子智能体运行仍然可用,但覆盖请求会被拒绝,而不是静默回退。 +- `provider` 和 `model` 是每次运行的可选覆盖项,不是持久性会话变更。 +- OpenClaw 仅对受信任调用方接受这些覆盖字段。 +- 对于插件自有的回退运行,操作员必须通过 `plugins.entries..subagent.allowModelOverride: true` 显式启用。 +- 使用 `plugins.entries..subagent.allowedModels` 可将受信任插件限制为特定规范化 `provider/model` 目标,或使用 `"*"` 显式允许任意目标。 +- 不受信任的插件子智能体运行仍然可用,但覆盖请求会被拒绝,而不是静默回退。 -对于网页搜索,插件可以消费共享运行时辅助工具,而不必深入到智能体工具接线中: +对于网页搜索,插件可以消费共享运行时辅助工具,而不是深入接入智能体工具接线: ```ts const providers = api.runtime.webSearch.listProviders({ @@ -795,7 +801,7 @@ const result = await api.runtime.webSearch.search({ 说明: - 将提供商选择、凭证解析和共享请求语义保留在核心中。 -- 对供应商特定的搜索传输使用网页搜索提供商。 +- 使用网页搜索提供商来承载供应商专用的搜索传输。 - 对于需要搜索行为但不依赖智能体工具包装器的功能 / 渠道插件,`api.runtime.webSearch.*` 是首选共享表面。 ### `api.runtime.imageGeneration` @@ -816,7 +822,7 @@ const providers = api.runtime.imageGeneration.listProviders({ ## Gateway 网关 HTTP 路由 -插件可以通过 `api.registerHttpRoute(...)` 暴露 HTTP 端点。 +插件可以使用 `api.registerHttpRoute(...)` 暴露 HTTP 端点。 ```ts api.registerHttpRoute({ @@ -834,153 +840,158 @@ api.registerHttpRoute({ 路由字段: - `path`:Gateway 网关 HTTP 服务器下的路由路径。 -- `auth`:必填。使用 `"gateway"` 表示要求常规 Gateway 网关认证,或使用 `"plugin"` 表示由插件管理认证 / webhook 验证。 +- `auth`:必填。使用 `"gateway"` 以要求普通网关认证,或使用 `"plugin"` 以进行插件管理的认证 / webhook 验证。 - `match`:可选。`"exact"`(默认)或 `"prefix"`。 -- `replaceExisting`:可选。允许同一插件替换自己已有的路由注册。 -- `handler`:当路由处理了请求时返回 `true`。 +- `replaceExisting`:可选。允许同一插件替换其已有路由注册。 +- `handler`:当路由已处理请求时返回 `true`。 说明: - `api.registerHttpHandler(...)` 已被移除,并会导致插件加载错误。请改用 `api.registerHttpRoute(...)`。 - 插件路由必须显式声明 `auth`。 -- 若 `path + match` 完全冲突,则除非设置 `replaceExisting: true`,否则会被拒绝;并且一个插件不能替换另一个插件的路由。 +- 除非设置 `replaceExisting: true`,否则精确的 `path + match` 冲突会被拒绝,且一个插件不能替换另一个插件的路由。 - 不同 `auth` 级别的重叠路由会被拒绝。仅在相同认证级别内保留 `exact` / `prefix` 贯穿链。 -- `auth: "plugin"` 路由**不会**自动接收操作员运行时作用域。它们用于插件管理的 webhook / 签名校验,而不是特权 Gateway 网关辅助调用。 -- `auth: "gateway"` 路由会在 Gateway 网关请求运行时作用域内运行,但该作用域被有意设计得较为保守: +- `auth: "plugin"` 路由**不会**自动接收操作员运行时作用域。它们用于插件管理的 webhook / 签名验证,而不是特权 Gateway 网关辅助调用。 +- `auth: "gateway"` 路由会在 Gateway 网关请求运行时作用域中运行,但该作用域有意保持保守: - 共享密钥 bearer 认证(`gateway.auth.mode = "token"` / `"password"`)会将插件路由运行时作用域固定为 `operator.write`,即使调用方发送了 `x-openclaw-scopes` - - 带有受信任身份的 HTTP 模式(例如 `trusted-proxy` 或私有入口上的 `gateway.auth.mode = "none"`)只会在该头显式存在时才采纳 `x-openclaw-scopes` - - 如果这些带身份的插件路由请求中缺少 `x-openclaw-scopes`,运行时作用域会回退为 `operator.write` -- 实际规则:不要假设一个使用 gateway 认证的插件路由天然就是管理员表面。如果你的路由需要仅管理员可用的行为,请要求使用带身份的认证模式,并文档化显式的 `x-openclaw-scopes` 请求头契约。 + - 受信任的带身份 HTTP 模式(例如 `trusted-proxy`,或私有入口上的 `gateway.auth.mode = "none"`)仅在显式存在该请求头时才接受 `x-openclaw-scopes` + - 如果这些带身份的插件路由请求中不存在 `x-openclaw-scopes`,运行时作用域会回退到 `operator.write` +- 实用规则:不要假设 gateway-auth 插件路由天然就是管理员表面。如果你的路由需要仅管理员可用的行为,请要求使用带身份的认证模式,并记录显式的 `x-openclaw-scopes` 请求头契约。 ## 插件 SDK 导入路径 在编写插件时,请使用 SDK 子路径,而不是单体式的 `openclaw/plugin-sdk` 导入: - `openclaw/plugin-sdk/plugin-entry` 用于插件注册原语。 -- `openclaw/plugin-sdk/core` 用于通用共享的面向插件契约。 -- `openclaw/plugin-sdk/config-schema` 用于根 `openclaw.json` 的 Zod schema 导出(`OpenClawSchema`)。 -- 稳定的渠道原语,例如 `openclaw/plugin-sdk/channel-setup`、`openclaw/plugin-sdk/setup-runtime`、`openclaw/plugin-sdk/setup-adapter-runtime`、`openclaw/plugin-sdk/setup-tools`、`openclaw/plugin-sdk/channel-pairing`、`openclaw/plugin-sdk/channel-contract`、`openclaw/plugin-sdk/channel-feedback`、`openclaw/plugin-sdk/channel-inbound`、`openclaw/plugin-sdk/channel-lifecycle`、`openclaw/plugin-sdk/channel-reply-pipeline`、`openclaw/plugin-sdk/command-auth`、`openclaw/plugin-sdk/secret-input` 和 `openclaw/plugin-sdk/webhook-ingress`,用于共享设置 / 认证 / 回复 / webhook 接线。`channel-inbound` 是防抖、提及匹配、入站提及策略辅助工具、信封格式化和入站信封上下文辅助工具的共享归属位置。`channel-setup` 是狭义的可选安装设置接缝。`setup-runtime` 是 `setupEntry` / 延迟启动使用的运行时安全设置表面,其中包括可安全导入的设置补丁适配器。`setup-adapter-runtime` 是具备环境变量感知能力的账户设置适配器接缝。`setup-tools` 是小型 CLI / 归档 / 文档辅助工具接缝(`formatCliCommand`、`detectBinary`、`extractArchive`、`resolveBrewExecutable`、`formatDocsLink`、`CONFIG_DIR`)。 -- 领域子路径,例如 `openclaw/plugin-sdk/channel-config-helpers`、`openclaw/plugin-sdk/allow-from`、`openclaw/plugin-sdk/channel-config-schema`、`openclaw/plugin-sdk/telegram-command-config`、`openclaw/plugin-sdk/channel-policy`、`openclaw/plugin-sdk/approval-gateway-runtime`、`openclaw/plugin-sdk/approval-handler-adapter-runtime`、`openclaw/plugin-sdk/approval-handler-runtime`、`openclaw/plugin-sdk/approval-runtime`、`openclaw/plugin-sdk/config-runtime`、`openclaw/plugin-sdk/infra-runtime`、`openclaw/plugin-sdk/agent-runtime`、`openclaw/plugin-sdk/lazy-runtime`、`openclaw/plugin-sdk/reply-history`、`openclaw/plugin-sdk/routing`、`openclaw/plugin-sdk/status-helpers`、`openclaw/plugin-sdk/text-runtime`、`openclaw/plugin-sdk/runtime-store` 和 `openclaw/plugin-sdk/directory-runtime`,用于共享运行时 / 配置辅助工具。`telegram-command-config` 是 Telegram 自定义命令规范化 / 校验的狭义公共接缝,即使内置 Telegram 契约表面暂时不可用,它也仍然可用。`text-runtime` 是共享的文本 / Markdown / 日志接缝,包括对智能体可见文本的剥离、Markdown 渲染 / 分块辅助工具、脱敏辅助工具、指令标签辅助工具和安全文本工具。 -- 面向审批的渠道接缝应优先使用插件上的单一 `approvalCapability` 契约。然后核心通过这一项能力来读取审批认证、交付、渲染、原生路由和惰性原生处理器行为,而不是将审批行为混杂到无关的插件字段中。 -- `openclaw/plugin-sdk/channel-runtime` 已弃用,当前仅作为旧版插件的兼容性 shim 保留。新代码应改为导入更狭义的通用原语,仓库代码也不应再新增对该 shim 的导入。 -- 内置扩展内部实现仍然是私有的。外部插件应仅使用 `openclaw/plugin-sdk/*` 子路径。OpenClaw 核心 / 测试代码可以使用插件包根目录下仓库内公开的入口点,例如 `index.js`、`api.js`、`runtime-api.js`、`setup-entry.js`,以及诸如 `login-qr-api.js` 这类范围狭窄的文件。绝不要从核心或另一个扩展中导入某个插件包的 `src/*`。 +- `openclaw/plugin-sdk/core` 用于通用的共享插件侧契约。 +- `openclaw/plugin-sdk/config-schema` 用于根 `openclaw.json` Zod schema 导出(`OpenClawSchema`)。 +- 稳定的渠道原语,如 `openclaw/plugin-sdk/channel-setup`、`openclaw/plugin-sdk/setup-runtime`、`openclaw/plugin-sdk/setup-adapter-runtime`、`openclaw/plugin-sdk/setup-tools`、`openclaw/plugin-sdk/channel-pairing`、`openclaw/plugin-sdk/channel-contract`、`openclaw/plugin-sdk/channel-feedback`、`openclaw/plugin-sdk/channel-inbound`、`openclaw/plugin-sdk/channel-lifecycle`、`openclaw/plugin-sdk/channel-reply-pipeline`、`openclaw/plugin-sdk/command-auth`、`openclaw/plugin-sdk/secret-input` 和 `openclaw/plugin-sdk/webhook-ingress`,用于共享设置 / 认证 / 回复 / webhook 接线。`channel-inbound` 是 debounce、mention 匹配、入站 mention 策略辅助工具、envelope 格式化以及入站 envelope 上下文辅助工具的共享归属位置。`channel-setup` 是精简的可选安装设置接缝。`setup-runtime` 是供 `setupEntry` / 延迟启动使用的运行时安全设置表面,其中包括导入安全的设置补丁适配器。`setup-adapter-runtime` 是具备环境变量感知能力的账号设置适配器接缝。`setup-tools` 是精简的 CLI / 压缩包 / 文档辅助工具接缝(`formatCliCommand`、`detectBinary`、`extractArchive`、`resolveBrewExecutable`、`formatDocsLink`、`CONFIG_DIR`)。 +- 领域子路径,如 `openclaw/plugin-sdk/channel-config-helpers`、`openclaw/plugin-sdk/allow-from`、`openclaw/plugin-sdk/channel-config-schema`、`openclaw/plugin-sdk/telegram-command-config`、`openclaw/plugin-sdk/channel-policy`、`openclaw/plugin-sdk/approval-gateway-runtime`、`openclaw/plugin-sdk/approval-handler-adapter-runtime`、`openclaw/plugin-sdk/approval-handler-runtime`、`openclaw/plugin-sdk/approval-runtime`、`openclaw/plugin-sdk/config-runtime`、`openclaw/plugin-sdk/infra-runtime`、`openclaw/plugin-sdk/agent-runtime`、`openclaw/plugin-sdk/lazy-runtime`、`openclaw/plugin-sdk/reply-history`、`openclaw/plugin-sdk/routing`、`openclaw/plugin-sdk/status-helpers`、`openclaw/plugin-sdk/text-runtime`、`openclaw/plugin-sdk/runtime-store` 和 `openclaw/plugin-sdk/directory-runtime`,用于共享运行时 / 配置辅助工具。`telegram-command-config` 是 Telegram 自定义命令规范化 / 验证的精简公共接缝,即使内置 Telegram 契约表面暂时不可用,它也仍然可用。`text-runtime` 是共享的文本 / Markdown / 日志接缝,其中包括 assistant 可见文本剥离、Markdown 渲染 / 分块辅助工具、脱敏辅助工具、directive-tag 辅助工具以及安全文本工具。 +- 审批专用渠道接缝应优先使用插件上的单一 `approvalCapability` 契约。然后,核心会通过这一个能力读取审批认证、投递、渲染、原生路由和惰性原生处理器行为,而不是把审批行为混入不相关的插件字段中。 +- `openclaw/plugin-sdk/channel-runtime` 已弃用,目前仅作为旧插件的兼容性 shim 保留。新代码应导入更窄的通用原语,仓库代码也不应再新增对该 shim 的导入。 +- 内置扩展内部机制仍然是私有的。外部插件应只使用 `openclaw/plugin-sdk/*` 子路径。OpenClaw 核心 / 测试代码可以使用插件包根目录下的仓库公共入口点,例如 `index.js`、`api.js`、`runtime-api.js`、`setup-entry.js`,以及精确限定范围的文件,例如 `login-qr-api.js`。绝不要从核心或其他扩展中导入某个插件包的 `src/*`。 - 仓库入口点拆分: `/api.js` 是辅助工具 / 类型 barrel, `/runtime-api.js` 是仅运行时 barrel, `/index.js` 是内置插件入口, `/setup-entry.js` 是设置插件入口。 - 当前内置提供商示例: - - Anthropic 使用 `api.js` / `contract-api.js` 提供 Claude 流辅助工具,例如 `wrapAnthropicProviderStream`、beta 头辅助工具和 `service_tier` 解析。 + - Anthropic 使用 `api.js` / `contract-api.js` 提供 Claude 流辅助工具,例如 `wrapAnthropicProviderStream`、beta 请求头辅助工具和 `service_tier` 解析。 - OpenAI 使用 `api.js` 提供提供商构建器、默认模型辅助工具和实时提供商构建器。 - - OpenRouter 使用 `api.js` 提供其提供商构建器以及新手引导 / 配置辅助工具,而 `register.runtime.js` 仍可为仓库内部使用重新导出通用 `plugin-sdk/provider-stream` 辅助工具。 -- 由 facade 加载的公共入口点会在存在活动运行时配置快照时优先使用它;如果 OpenClaw 尚未提供运行时快照,则回退到磁盘上的已解析配置文件。 -- 通用共享原语仍是首选的公共插件 SDK 契约。仍然存在一小组保留的、带内置渠道品牌的辅助工具接缝用于兼容性。应将这些视为内置维护 / 兼容性接缝,而不是新的第三方导入目标;新的跨渠道契约仍应落在通用 `plugin-sdk/*` 子路径或插件本地 `api.js` / `runtime-api.js` barrel 上。 + - OpenRouter 使用 `api.js` 提供其提供商构建器以及新手引导 / 配置辅助工具,而 `register.runtime.js` 仍可为了仓库本地用途重新导出通用 `plugin-sdk/provider-stream` 辅助工具。 +- 通过 facade 加载的公共入口点会优先使用当前激活的运行时配置快照;如果 OpenClaw 尚未提供运行时快照,则回退到磁盘上解析出的配置文件。 +- 通用共享原语仍然是首选的公共插件 SDK 契约。当前仍存在一小组保留的、带内置渠道品牌的辅助工具接缝,用于兼容性。应将这些视为内置维护 / 兼容性接缝,而不是新的第三方导入目标;新的跨渠道契约仍应落在通用 `plugin-sdk/*` 子路径或插件本地 `api.js` / `runtime-api.js` barrel 上。 兼容性说明: -- 新代码应避免使用根级 `openclaw/plugin-sdk` barrel。 -- 优先使用狭义且稳定的原语。较新的 setup / pairing / reply / feedback / contract / inbound / threading / command / secret-input / webhook / infra / allowlist / status / message-tool 子路径,是新内置插件和外部插件工作的预期契约。目标解析 / 匹配应放在 `openclaw/plugin-sdk/channel-targets`。消息动作闸门和 reaction message-id 辅助工具应放在 `openclaw/plugin-sdk/channel-actions`。 -- 默认情况下,内置扩展特定的辅助工具 barrel 不是稳定接口。如果某个辅助工具仅被某个内置扩展需要,应将其保留在该扩展本地的 `api.js` 或 `runtime-api.js` 接缝后面,而不是提升到 `openclaw/plugin-sdk/` 中。 -- 新的共享辅助工具接缝应当是通用的,而不是带渠道品牌的。共享目标解析应放在 `openclaw/plugin-sdk/channel-targets`;渠道特定内部实现则保留在归属插件本地的 `api.js` 或 `runtime-api.js` 接缝后面。 -- `image-generation`、`media-understanding` 和 `speech` 这类能力特定子路径之所以存在,是因为今天的内置 / 原生插件正在使用它们。但这并不自动意味着每个导出的辅助工具都是长期冻结的外部契约。 +- 新代码应避免使用根级别的 `openclaw/plugin-sdk` barrel。 +- 优先使用精简且稳定的原语。较新的 setup / pairing / reply / feedback / contract / inbound / threading / command / secret-input / webhook / infra / allowlist / status / message-tool 子路径,是新的内置和外部插件工作的预期契约。 + target 解析 / 匹配应归属于 `openclaw/plugin-sdk/channel-targets`。 + message 动作门控和 reaction message-id 辅助工具应归属于 `openclaw/plugin-sdk/channel-actions`。 +- 内置扩展专用的辅助 barrel 默认并不稳定。如果某个辅助工具只被某个内置扩展需要,应将其保留在该扩展本地的 `api.js` 或 `runtime-api.js` 接缝之后,而不是把它提升到 `openclaw/plugin-sdk/` 中。 +- 新的共享辅助工具接缝应是通用的,而不是带渠道品牌的。共享 target 解析应归属于 `openclaw/plugin-sdk/channel-targets`;渠道专用内部机制则应保留在归属插件本地的 `api.js` 或 `runtime-api.js` 接缝之后。 +- `image-generation`、`media-understanding` 和 `speech` 这类能力专用子路径之所以存在,是因为今天的内置 / 原生插件正在使用它们。它们的存在本身并不意味着其中每个导出的辅助工具都是长期冻结的外部契约。 -## 消息工具 schema +## Message 工具 schema -插件应拥有渠道特定的 `describeMessageTool(...)` schema 贡献。将提供商特定字段保留在插件中,而不是放入共享核心。 +对于 reaction、已读和投票等非消息原语,插件应拥有渠道专用的 `describeMessageTool(...)` schema 贡献。共享发送展示应使用通用 `MessagePresentation` 契约,而不是提供商原生的 button、component、block 或 card 字段。 +关于该契约、回退规则、提供商映射以及插件作者检查清单,请参见 [Message Presentation](/zh-CN/plugins/message-presentation)。 -对于可移植的共享 schema 片段,请复用通过 `openclaw/plugin-sdk/channel-actions` 导出的通用辅助工具: +具备发送能力的插件通过消息能力声明其渲染能力: -- `createMessageToolButtonsSchema()` 用于按钮网格样式负载 -- `createMessageToolCardSchema()` 用于结构化卡片负载 +- `presentation` 用于语义化展示块(`text`、`context`、`divider`、`buttons`、`select`) +- `delivery-pin` 用于固定投递请求 -如果某个 schema 形状只对一个提供商有意义,请在该插件自己的源码中定义它,而不是将其提升到共享 SDK 中。 +核心会决定是原生渲染该展示,还是将其降级为文本。 +不要从通用 message 工具中暴露提供商原生 UI 逃生口。 +为兼容现有第三方插件,面向传统原生 schema 的已弃用 SDK 辅助工具仍然会导出,但新插件不应使用它们。 -## 渠道目标解析 +## 渠道 target 解析 -渠道插件应拥有渠道特定的目标语义。保持共享出站宿主通用,并使用消息适配器表面承载提供商规则: +渠道插件应拥有渠道专用的 target 语义。保持共享出站宿主通用化,并通过消息适配器表面来承载提供商规则: -- `messaging.inferTargetChatType({ to })` 用于在目录查找之前决定一个规范化目标应被视为 `direct`、`group` 还是 `channel` -- `messaging.targetResolver.looksLikeId(raw, normalized)` 用于告诉核心某个输入是否应跳过目录搜索,直接进入类似 id 的解析 -- `messaging.targetResolver.resolveTarget(...)` 是在规范化后或目录未命中后,核心需要最终由提供商拥有的解析结果时,插件的回退路径 -- `messaging.resolveOutboundSessionRoute(...)` 在目标解析完成后,拥有提供商特定的会话路由构建 +- `messaging.inferTargetChatType({ to })` 决定某个规范化 target 在目录查找前应被视为 `direct`、`group` 还是 `channel` +- `messaging.targetResolver.looksLikeId(raw, normalized)` 告诉核心某个输入是否应直接跳转到类似 id 的解析,而不是进行目录搜索 +- `messaging.targetResolver.resolveTarget(...)` 是在规范化之后或目录未命中之后,核心需要进行最终提供商自有解析时的插件回退 +- `messaging.resolveOutboundSessionRoute(...)` 在 target 解析完成后拥有提供商专用的会话路由构造逻辑 -推荐拆分方式: +推荐拆分: -- 对于应在搜索 peers / groups 之前发生的类别决策,使用 `inferTargetChatType` -- 对于“将其视为显式 / 原生目标 id”的检查,使用 `looksLikeId` -- 对于提供商特定的规范化回退,使用 `resolveTarget`,而不是把它用于广义目录搜索 -- 将 chat id、thread id、JID、handle 和 room id 这类提供商原生 id 保留在 `target` 值或提供商特定参数中,而不是放在通用 SDK 字段中 +- 对于应在搜索 peer / group 之前发生的类别决策,使用 `inferTargetChatType` +- 对于“将其视为显式 / 原生 target id”的判断,使用 `looksLikeId` +- 对于提供商专用的规范化回退,使用 `resolveTarget`,而不是让它承担广泛的目录搜索 +- 将 chat id、thread id、JID、handle 和 room id 这类提供商原生 id 保留在 `target` 值或提供商专用参数中,而不是放在通用插件 SDK 字段里 ## 基于配置的目录 -如果插件会从配置派生目录条目,应将该逻辑保留在插件内部,并复用 `openclaw/plugin-sdk/directory-runtime` 中的共享辅助工具。 +对于从配置派生目录条目的插件,应将该逻辑保留在插件内部,并复用 `openclaw/plugin-sdk/directory-runtime` 中的共享辅助工具。 -当某个渠道需要基于配置的 peers / groups 时,请使用这种方式,例如: +当某个渠道需要基于配置的 peer / group 时,请使用这一模式,例如: -- 基于 allowlist 的私信 peers -- 已配置的渠道 / 分组映射 -- 账户作用域的静态目录回退 +- 基于 allowlist 的私信 peer +- 已配置的渠道 / group 映射 +- 按账号划分的静态目录回退 `directory-runtime` 中的共享辅助工具只处理通用操作: - 查询过滤 -- 限制应用 +- limit 应用 - 去重 / 规范化辅助工具 - 构建 `ChannelDirectoryEntry[]` -渠道特定的账户检查和 id 规范化应保留在插件实现中。 +渠道专用的账号检查和 id 规范化应保留在插件实现中。 ## 提供商目录 -提供商插件可以通过 `registerProvider({ catalog: { run(...) { ... } } })` 为推理定义模型目录。 +提供商插件可以通过 `registerProvider({ catalog: { run(...) { ... } } })` 定义用于推理的模型目录。 -`catalog.run(...)` 返回与 OpenClaw 写入 `models.providers` 相同的结构: +`catalog.run(...)` 返回的结构与 OpenClaw 写入 `models.providers` 的结构相同: -- `{ provider }` 表示一个提供商条目 -- `{ providers }` 表示多个提供商条目 +- `{ provider }` 用于单个提供商条目 +- `{ providers }` 用于多个提供商条目 -当插件拥有提供商特定 model id、base URL 默认值或受认证控制的模型元数据时,请使用 `catalog`。 +当插件拥有提供商专用模型 id、基础 `base URL` 默认值或受认证门控的模型元数据时,请使用 `catalog`。 -`catalog.order` 控制插件目录相对于 OpenClaw 内置隐式提供商的合并时机: +`catalog.order` 控制某个插件目录相对于 OpenClaw 内置隐式提供商的合并时机: -- `simple`:普通 API 密钥或环境变量驱动的提供商 -- `profile`:当认证配置文件存在时出现的提供商 +- `simple`:普通 API key 或环境变量驱动的提供商 +- `profile`:当存在认证配置文件时出现的提供商 - `paired`:合成多个相关提供商条目的提供商 - `late`:最后一轮,在其他隐式提供商之后 -后出现的提供商会在键冲突时胜出,因此插件可以有意覆盖具有相同 provider id 的内置提供商条目。 +后出现的提供商会在键冲突时胜出,因此插件可以有意用相同提供商 id 覆盖某个内置提供商条目。 兼容性: -- `discovery` 仍可作为旧版别名使用 +- `discovery` 仍可作为传统别名使用 - 如果同时注册了 `catalog` 和 `discovery`,OpenClaw 会使用 `catalog` ## 只读渠道检查 -如果你的插件注册了一个渠道,除 `resolveAccount(...)` 外,优先同时实现 `plugin.config.inspectAccount(cfg, accountId)`。 +如果你的插件注册了一个渠道,请优先在实现 `resolveAccount(...)` 的同时实现 `plugin.config.inspectAccount(cfg, accountId)`。 -原因: +原因如下: -- `resolveAccount(...)` 是运行时路径。它可以假设凭证已被完整实体化,并且在缺少必需 secret 时快速失败。 -- 只读命令路径,例如 `openclaw status`、`openclaw status --all`、`openclaw channels status`、`openclaw channels resolve`,以及 doctor / 配置修复流程,不应为了描述配置而必须实体化运行时凭证。 +- `resolveAccount(...)` 是运行时路径。它可以假定凭证已被完整实体化,并在缺少必要 secret 时快速失败。 +- 只读命令路径,例如 `openclaw status`、`openclaw status --all`、`openclaw channels status`、`openclaw channels resolve`,以及 doctor / 配置修复流程,不应为了描述配置而不得不实体化运行时凭证。 推荐的 `inspectAccount(...)` 行为: -- 只返回描述性的账户状态。 +- 仅返回描述性的账号状态。 - 保留 `enabled` 和 `configured`。 - 在相关时包含凭证来源 / 状态字段,例如: - `tokenSource`、`tokenStatus` - `botTokenSource`、`botTokenStatus` - `appTokenSource`、`appTokenStatus` - `signingSecretSource`、`signingSecretStatus` -- 你不需要为了报告只读可用性而返回原始 token 值。返回 `tokenStatus: "available"`(以及匹配的来源字段)就足以满足状态类命令。 -- 当凭证通过 SecretRef 配置但在当前命令路径中不可用时,使用 `configured_unavailable`。 +- 你无需为了报告只读可用性而返回原始 token 值。返回 `tokenStatus: "available"`(以及对应的来源字段)就足以支持状态类命令。 +- 当某个凭证通过 SecretRef 配置,但在当前命令路径中不可用时,请使用 `configured_unavailable`。 -这样只读命令就可以报告“已配置,但在当前命令路径中不可用”,而不是崩溃或错误地报告该账户未配置。 +这样可让只读命令报告“已配置,但在当前命令路径中不可用”,而不是崩溃或错误地将账号报告为未配置。 -## 包 pack +## Package 包 -插件目录可以包含带有 `openclaw.extensions` 的 `package.json`: +一个插件目录可以包含带有 `openclaw.extensions` 的 `package.json`: ```json { @@ -992,37 +1003,39 @@ api.registerHttpRoute({ } ``` -每个条目都会成为一个插件。如果 pack 列出了多个扩展,插件 id 将变为 `name/`。 +每个条目都会变成一个插件。如果该 pack 列出了多个扩展,则插件 id 会变成 `name/`。 -如果你的插件导入了 npm 依赖,请在该目录中安装它们,以确保 `node_modules` 可用(`npm install` / `pnpm install`)。 +如果你的插件导入了 npm 依赖,请在该目录中安装它们,以便 `node_modules` 可用(`npm install` / `pnpm install`)。 -安全护栏:每个 `openclaw.extensions` 条目在解析符号链接后都必须保留在插件目录内。任何逃离包目录的条目都会被拒绝。 +安全护栏:每个 `openclaw.extensions` 条目在解析符号链接后都必须保留在插件目录内。任何逃逸出包目录的条目都会被拒绝。 -安全说明:`openclaw plugins install` 会使用 `npm install --omit=dev --ignore-scripts` 安装插件依赖(不运行生命周期脚本,运行时不安装开发依赖)。请保持插件依赖树为“纯 JS / TS”,并避免需要 `postinstall` 构建的包。 +安全说明:`openclaw plugins install` 会使用 `npm install --omit=dev --ignore-scripts` 安装插件依赖(无生命周期脚本,运行时也不安装开发依赖)。请保持插件依赖树为“纯 JS / TS”,并避免需要 `postinstall` 构建的包。 -可选项:`openclaw.setupEntry` 可以指向一个轻量级、仅用于设置的模块。当 OpenClaw 需要为一个已禁用的渠道插件提供设置表面,或者某个渠道插件已启用但尚未配置时,它会加载 `setupEntry` 而不是完整插件入口。这样在你的主插件入口还会接线工具、钩子或其他仅运行时代码时,可以让启动和设置更轻量。 +可选:`openclaw.setupEntry` 可以指向一个轻量级、仅用于设置的模块。 +当 OpenClaw 需要为某个已禁用的渠道插件提供设置表面,或者某个渠道插件虽然已启用但尚未完成配置时,它会加载 `setupEntry`,而不是完整的插件入口。这样当你的主插件入口还会接入工具、钩子或其他仅运行时代码时,就能让启动和设置过程更轻量。 -可选项:`openclaw.startup.deferConfiguredChannelFullLoadUntilAfterListen` 可以让一个渠道插件在 Gateway 网关的 pre-listen 启动阶段,即使渠道已经配置完成,也选择加入同一个 `setupEntry` 路径。 +可选:`openclaw.startup.deferConfiguredChannelFullLoadUntilAfterListen` 可以让某个渠道插件在 Gateway 网关的 pre-listen 启动阶段也采用同样的 `setupEntry` 路径,即使该渠道已经配置完成。 -只有在 `setupEntry` 完全覆盖 Gateway 网关开始监听之前必须存在的启动表面时,才使用此项。实际来说,这意味着设置入口必须注册启动所依赖的每个渠道自有能力,例如: +仅当 `setupEntry` 能完全覆盖 Gateway 网关开始监听前必须存在的启动表面时,才应使用此选项。实际来说,这意味着 setup 入口必须注册启动所依赖的每一项渠道自有能力,例如: - 渠道注册本身 - 任何必须在 Gateway 网关开始监听前可用的 HTTP 路由 -- 任何必须在同一时间窗口内存在的 gateway 方法、工具或服务 +- 在同一时间窗口内必须存在的任何 Gateway 网关方法、工具或服务 -如果你的完整入口仍然拥有任何必需的启动能力,请不要启用此标志。保持插件采用默认行为,并让 OpenClaw 在启动期间加载完整入口。 +如果你的完整入口仍然拥有任何必需的启动能力,就不要启用这个标志。保持插件采用默认行为,并让 OpenClaw 在启动期间加载完整入口。 -内置渠道也可以发布仅设置用的契约表面辅助工具,供核心在完整渠道运行时加载前查询。当前的设置提升表面包括: +内置渠道还可以发布仅设置期的契约表面辅助工具,以便核心在完整渠道运行时加载前进行查询。当前的设置提升表面包括: - `singleAccountKeysToMove` - `namedAccountPromotionKeys` - `resolveSingleAccountPromotionTarget(...)` -当核心需要在不加载完整插件入口的情况下,将旧版单账户渠道配置提升到 `channels..accounts.*` 时,会使用该表面。Matrix 是当前的内置示例:当命名账户已存在时,它只会将 auth / bootstrap 键移动到一个已命名的提升账户中,并且可以保留一个已配置的非规范默认账户键,而不是总是创建 `accounts.default`。 +当核心需要在不加载完整插件入口的情况下,将传统的单账号渠道配置提升到 `channels..accounts.*` 中时,就会使用这套表面。 +Matrix 是当前的内置示例:当已存在命名账号时,它只会把认证 / bootstrap 键移动到某个已命名的提升后账号中,并且它可以保留某个已配置的非规范默认账号键,而不是总是创建 `accounts.default`。 -这些设置补丁适配器让内置契约表面发现保持惰性。导入时间保持轻量;提升表面只会在首次使用时加载,而不是在模块导入时重新进入内置渠道启动。 +这些设置补丁适配器可让内置契约表面发现保持惰性。导入时保持轻量;提升表面只会在首次使用时才加载,而不会在模块导入时重新进入内置渠道启动。 -当这些启动表面包含 gateway RPC 方法时,请将它们保留在插件特定前缀下。核心管理命名空间(`config.*`、`exec.approvals.*`、`wizard.*`、`update.*`)仍然保留,并且始终解析为 `operator.admin`,即使某个插件请求了更窄的作用域也是如此。 +当这些启动表面包含 Gateway 网关 RPC 方法时,请将它们保留在插件专用前缀下。核心管理命名空间(`config.*`、`exec.approvals.*`、`wizard.*`、`update.*`)仍然保留,并且始终解析为 `operator.admin`,即使某个插件请求了更窄的作用域。 示例: @@ -1041,7 +1054,7 @@ api.registerHttpRoute({ ### 渠道目录元数据 -渠道插件可以通过 `openclaw.channel` 声明 setup / 发现元数据,并通过 `openclaw.install` 声明安装提示。这样可以让核心目录保持无数据状态。 +渠道插件可以通过 `openclaw.channel` 宣传设置 / 发现元数据,并通过 `openclaw.install` 提供安装提示。这样可让核心目录保持无数据状态。 示例: @@ -1056,7 +1069,7 @@ api.registerHttpRoute({ "selectionLabel": "Nextcloud Talk (self-hosted)", "docsPath": "/channels/nextcloud-talk", "docsLabel": "nextcloud-talk", - "blurb": "Self-hosted chat via Nextcloud Talk webhook bots.", + "blurb": "通过 Nextcloud Talk webhook 机器人提供自托管聊天。", "order": 65, "aliases": ["nc-talk", "nc"] }, @@ -1069,34 +1082,34 @@ api.registerHttpRoute({ } ``` -除了最小示例之外,其他有用的 `openclaw.channel` 字段还包括: +除了最小示例之外,`openclaw.channel` 还有一些有用字段: - `detailLabel`:用于更丰富目录 / 状态表面的次级标签 - `docsLabel`:覆盖文档链接的链接文本 - `preferOver`:此目录条目应优先于的低优先级插件 / 渠道 id -- `selectionDocsPrefix`、`selectionDocsOmitLabel`、`selectionExtras`:选择表面文案控制 -- `markdownCapable`:将该渠道标记为支持 Markdown,以便进行出站格式决策 -- `exposure.configured`:设为 `false` 时,在已配置渠道列表表面中隐藏该渠道 -- `exposure.setup`:设为 `false` 时,在交互式设置 / 配置选择器中隐藏该渠道 -- `exposure.docs`:将该渠道标记为内部 / 私有,用于文档导航表面 -- `showConfigured` / `showInSetup`:出于兼容性仍接受的旧版别名;优先使用 `exposure` -- `quickstartAllowFrom`:让该渠道选择加入标准快速开始 `allowFrom` 流程 -- `forceAccountBinding`:即使只有一个账户存在,也要求显式账户绑定 -- `preferSessionLookupForAnnounceTarget`:在解析 announce 目标时优先使用会话查找 +- `selectionDocsPrefix`、`selectionDocsOmitLabel`、`selectionExtras`:选择表面的文案控制字段 +- `markdownCapable`:将该渠道标记为支持 Markdown,以供出站格式决策使用 +- `exposure.configured`:当设为 `false` 时,在已配置渠道列表表面中隐藏该渠道 +- `exposure.setup`:当设为 `false` 时,在交互式设置 / 配置选择器中隐藏该渠道 +- `exposure.docs`:在文档导航表面中将该渠道标记为内部 / 私有 +- `showConfigured` / `showInSetup`:为兼容性仍接受的传统别名;优先使用 `exposure` +- `quickstartAllowFrom`:让该渠道接入标准快速开始 `allowFrom` 流程 +- `forceAccountBinding`:即使只存在一个账号,也要求显式账号绑定 +- `preferSessionLookupForAnnounceTarget`:在解析 announce target 时优先使用会话查找 -OpenClaw 还可以合并**外部渠道目录**(例如 MPM 注册表导出)。将 JSON 文件放到以下任一位置即可: +OpenClaw 还可以合并**外部渠道目录**(例如某个 MPM 注册表导出)。将一个 JSON 文件放到以下任一位置: - `~/.openclaw/mpm/plugins.json` - `~/.openclaw/mpm/catalog.json` - `~/.openclaw/plugins/catalog.json` -或者,将 `OPENCLAW_PLUGIN_CATALOG_PATHS`(或 `OPENCLAW_MPM_CATALOG_PATHS`)指向一个或多个 JSON 文件(以逗号 / 分号 / `PATH` 分隔)。每个文件应包含 `{ "entries": [ { "name": "@scope/pkg", "openclaw": { "channel": {...}, "install": {...} } } ] }`。解析器也接受 `"packages"` 或 `"plugins"` 作为 `"entries"` 键的旧版别名。 +或者将 `OPENCLAW_PLUGIN_CATALOG_PATHS`(或 `OPENCLAW_MPM_CATALOG_PATHS`)指向一个或多个 JSON 文件(以逗号 / 分号 / `PATH` 分隔)。每个文件应包含 `{ "entries": [ { "name": "@scope/pkg", "openclaw": { "channel": {...}, "install": {...} } } ] }`。解析器也接受 `"packages"` 或 `"plugins"` 作为 `"entries"` 键的传统别名。 ## 上下文引擎插件 -上下文引擎插件拥有会话上下文编排,负责摄取、组装和压缩。通过 `api.registerContextEngine(id, factory)` 在你的插件中注册它们,然后使用 `plugins.slots.contextEngine` 选择活动引擎。 +上下文引擎插件拥有会话上下文编排,包括摄取、组装和压缩。请在你的插件中通过 `api.registerContextEngine(id, factory)` 注册它们,然后使用 `plugins.slots.contextEngine` 选择激活的引擎。 -当你的插件需要替换或扩展默认上下文管线,而不仅仅是添加 memory 搜索或钩子时,请使用这种方式。 +当你的插件需要替换或扩展默认上下文流水线,而不只是增加 memory 搜索或钩子时,请使用这一机制。 ```ts import { buildMemorySystemPromptAddition } from "openclaw/plugin-sdk/core"; @@ -1124,7 +1137,7 @@ export default function (api) { } ``` -如果你的引擎**不**拥有压缩算法,请仍然实现 `compact()`,并显式委托它: +如果你的引擎**不**拥有压缩算法,请保留 `compact()` 的实现,并显式委托它: ```ts import { @@ -1161,37 +1174,37 @@ export default function (api) { ## 添加新能力 -当插件需要当前 API 无法容纳的行为时,不要通过私有深入访问绕过插件系统。请添加缺失的能力。 +当某个插件需要当前 API 无法很好承载的行为时,不要通过私有深层接入绕过插件系统。应添加缺失的能力。 推荐顺序: 1. 定义核心契约 - 决定哪些共享行为应由核心拥有:策略、回退、配置合并、生命周期、面向渠道的语义以及运行时辅助工具形态。 + 决定哪些共享行为应由核心拥有:策略、回退、配置合并、生命周期、面向渠道的语义,以及运行时辅助工具形态。 2. 添加类型化的插件注册 / 运行时表面 - 以最小但有用的类型化能力表面扩展 `OpenClawPluginApi` 和 / 或 `api.runtime`。 + 使用最小但有用的类型化能力表面扩展 `OpenClawPluginApi` 和 / 或 `api.runtime`。 3. 接线核心 + 渠道 / 功能消费者 - 渠道和功能插件应通过核心消费这一新能力,而不是直接导入某个供应商实现。 + 渠道和功能插件应通过核心消费新能力,而不是直接导入某个供应商实现。 4. 注册供应商实现 然后由供应商插件针对该能力注册其后端。 5. 添加契约覆盖 - 添加测试,使归属和注册形态能长期保持明确。 + 添加测试,以便让归属和注册形态在长期演进中保持明确。 -这就是 OpenClaw 如何在保持明确立场的同时,不会被硬编码进某个提供商的世界观。具体的文件检查清单和完整示例,请参见[能力扩展手册](/zh-CN/plugins/architecture)。 +这正是 OpenClaw 在保持主张性的同时,不会被硬编码进某一个提供商世界观的方式。具体文件检查清单和完整示例,请参见[能力扩展手册](/zh-CN/plugins/architecture)。 ### 能力检查清单 -当你添加一个新能力时,实现通常应同时涉及以下表面: +当你添加一个新能力时,实现通常应同时触及以下表面: - `src//types.ts` 中的核心契约类型 - `src//runtime.ts` 中的核心运行器 / 运行时辅助工具 - `src/plugins/types.ts` 中的插件 API 注册表面 - `src/plugins/registry.ts` 中的插件注册表接线 -- 当功能 / 渠道插件需要消费该能力时,位于 `src/plugins/runtime/*` 中的插件运行时暴露层 +- 当功能 / 渠道插件需要消费它时,`src/plugins/runtime/*` 中的插件运行时暴露 - `src/test-utils/plugin-registration.ts` 中的捕获 / 测试辅助工具 - `src/plugins/contracts/registry.ts` 中的归属 / 契约断言 - `docs/` 中面向操作员 / 插件的文档 -如果这些表面中缺了某一个,通常说明这个能力还没有被完整集成。 +如果这些表面中缺少某一项,通常意味着该能力尚未真正完成集成。 ### 能力模板 @@ -1227,7 +1240,7 @@ const clip = await api.runtime.videoGeneration.generate({ expect(findVideoGenerationProviderIdsForPlugin("openai")).toEqual(["openai"]); ``` -这样规则就保持简单: +这样规则就很简单: - 核心拥有能力契约 + 编排 - 供应商插件拥有供应商实现 diff --git a/docs/zh-CN/plugins/manifest.md b/docs/zh-CN/plugins/manifest.md index d9a47b3e4..af878b066 100644 --- a/docs/zh-CN/plugins/manifest.md +++ b/docs/zh-CN/plugins/manifest.md @@ -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 对它们进行校验。 -对于兼容 bundle,OpenClaw 目前会在布局符合 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。 | | `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` | OpenClaw 可在不加载插件代码的情况下检查的低成本 provider 认证环境变量元数据。 | -| `providerAuthAliases` | 否 | `Record` | 应复用另一个 provider id 进行认证查找的 provider id,例如共享基础 provider API key 和认证配置文件的 coding provider。 | -| `channelEnvVars` | 否 | `Record` | OpenClaw 可在不加载插件代码的情况下检查的低成本渠道环境变量元数据。将其用于基于环境变量的渠道设置或认证界面,以便通用启动 / 配置辅助功能能够识别。 | -| `providerAuthChoices` | 否 | `object[]` | 用于新手引导选择器、首选 provider 解析和简单 CLI flag 接线的低成本认证选项元数据。 | -| `activation` | 否 | `object` | 用于 provider、命令、渠道、路由和能力触发加载的低成本激活提示。仅为元数据;插件运行时仍拥有实际行为。 | -| `setup` | 否 | `object` | 设备发现和设置界面可在不加载插件运行时的情况下检查的低成本设置 / 新手引导描述符。 | -| `qaRunners` | 否 | `object[]` | 共享 `openclaw qa` 宿主在插件运行时加载前使用的低成本 QA 运行器描述符。 | -| `contracts` | 否 | `object` | 针对语音、实时转录、实时语音、媒体理解、图像生成、音乐生成、视频生成、网页抓取、Web 搜索和工具归属的静态内置能力快照。 | -| `channelConfigs` | 否 | `Record` | 由清单拥有的渠道配置元数据,在运行时加载前合并到设备发现和校验界面中。 | +| `commandAliases` | 否 | `object[]` | 由此插件拥有的命令名称,应在运行时加载前生成具备插件感知的配置与 CLI 诊断信息。 | +| `providerAuthEnvVars` | 否 | `Record` | OpenClaw 可在不加载插件代码的情况下检查的轻量级提供商认证环境变量元数据。 | +| `providerAuthAliases` | 否 | `Record` | 应复用另一个提供商 id 进行认证查找的提供商 id,例如共享基础提供商 API key 和认证配置文件的 coding 提供商。 | +| `channelEnvVars` | 否 | `Record` | OpenClaw 可在不加载插件代码的情况下检查的轻量级渠道环境变量元数据。将其用于通用启动 / 配置辅助工具需要识别的、由环境变量驱动的渠道设置或认证界面。 | +| `providerAuthChoices` | 否 | `object[]` | 用于新手引导选择器、首选提供商解析和简单 CLI 标志接线的轻量级认证选项元数据。 | +| `activation` | 否 | `object` | 用于提供商、命令、渠道、路由和由能力触发加载的轻量级激活提示。仅为元数据;实际行为仍由插件运行时负责。 | +| `setup` | 否 | `object` | 供设备发现和设置界面在不加载插件运行时的情况下检查的轻量级设置 / 新手引导描述符。 | +| `qaRunners` | 否 | `object[]` | 由共享 `openclaw qa` 主机在插件运行时加载前使用的轻量级 QA 运行器描述符。 | +| `contracts` | 否 | `object` | 用于 speech、实时转写、实时语音、媒体理解、图像生成、音乐生成、视频生成、web-fetch、Web 搜索和工具归属的静态内置能力快照。 | +| `channelConfigs` | 否 | `Record` | 由清单拥有的渠道配置元数据,在运行时加载前合并到设备发现与校验界面中。 | | `skills` | 否 | `string[]` | 要加载的 Skills 目录,相对于插件根目录。 | | `name` | 否 | `string` | 人类可读的插件名称。 | -| `description` | 否 | `string` | 在插件界面中显示的简短摘要。 | +| `description` | 否 | `string` | 显示在插件界面中的简短摘要。 | | `version` | 否 | `string` | 信息性插件版本。 | | `uiHints` | 否 | `Record` | 配置字段的 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 `。 | -| `cliDescription` | 否 | `string` | 用于 CLI 帮助中的描述。 | +| `groupId` | 否 | `string` | 用于对相关选项进行分组的可选分组 id。 | +| `groupLabel` | 否 | `string` | 该分组的面向用户标签。 | +| `groupHint` | 否 | `string` | 该分组的简短帮助文本。 | +| `optionKey` | 否 | `string` | 用于简单单标志认证流程的内部选项键。 | +| `cliFlag` | 否 | `string` | CLI 标志名称,例如 `--openrouter-api-key`。 | +| `cliOption` | 否 | `string` | 完整的 CLI 选项形式,例如 `--openrouter-api-key `。 | +| `cliDescription` | 否 | `string` | 在 CLI 帮助中使用的描述。 | | `onboardingScopes` | 否 | `Array<"text-inference" \| "image-generation">` | 此选项应出现在哪些新手引导界面中。如果省略,默认值为 `["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.` 的 JSON Schema。每个已声明的渠道配置条目都必须提供。 | -| `uiHints` | `Record` | 该渠道配置部分可选的 UI 标签 / 占位符 / 敏感性提示。 | +| `uiHints` | `Record` | 该渠道配置部分的可选 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.` 条目。无关的配置错误仍会阻止安装,并将操作人员引导到 `openclaw doctor --fix`。 +`openclaw.install.allowInvalidConfigRecovery` 的设计范围刻意很窄。它不会让任意损坏的配置变得可安装。当前它只允许安装流程从特定的陈旧内置插件升级故障中恢复,例如缺失的内置插件路径,或同一内置插件对应的陈旧 `channels.` 条目。无关的配置错误仍会阻止安装,并将运维人员引导到 `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.` 中显式固定的路径 +2. **内置** —— 随 OpenClaw 一起发布的插件 +3. **全局安装** —— 安装到全局 OpenClaw 插件根目录的插件 +4. **工作区** —— 相对于当前工作区发现的插件 + +影响: + +- 工作区中某个内置插件的 fork 或陈旧副本不会覆盖内置构建版本。 +- 若要真正用本地插件覆盖内置插件,请通过 `plugins.entries.` 固定它,使其凭优先级获胜,而不是依赖工作区发现。 +- 被丢弃的重复项会被记录日志,这样 Doctor 和启动诊断就能指出被舍弃的副本。 ## JSON Schema 要求 @@ -524,35 +548,39 @@ OpenClaw 应用以下优先级: ## 校验行为 -- 未知的 `channels.*` 键是**错误**,除非该渠道 id 由某个插件清单声明。 -- `plugins.entries.`、`plugins.allow`、`plugins.deny` 和 `plugins.slots.*` 必须引用**可发现的**插件 id。未知 id 是**错误**。 -- 如果某个插件已安装,但其清单或 schema 缺失或损坏,校验将失败,Doctor 会报告该插件错误。 -- 如果插件配置存在,但插件**已禁用**,则配置会被保留,并在 Doctor + 日志中显示**警告**。 +- 未知的 `channels.*` 键会被视为**错误**,除非该渠道 id 已由某个插件清单声明。 +- `plugins.entries.`、`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 `)。 ## 相关内容 -- [构建插件](/zh-CN/plugins/building-plugins) — 插件快速开始 +- [构建插件](/zh-CN/plugins/building-plugins) — 插件入门指南 - [插件架构](/zh-CN/plugins/architecture) — 内部架构 - [插件 SDK 概览](/zh-CN/plugins/sdk-overview) — 插件 SDK 参考 diff --git a/docs/zh-CN/plugins/message-presentation.md b/docs/zh-CN/plugins/message-presentation.md new file mode 100644 index 000000000..6e18b273d --- /dev/null +++ b/docs/zh-CN/plugins/message-presentation.md @@ -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) diff --git a/docs/zh-CN/plugins/sdk-overview.md b/docs/zh-CN/plugins/sdk-overview.md index 47553861b..253b9e9ac 100644 --- a/docs/zh-CN/plugins/sdk-overview.md +++ b/docs/zh-CN/plugins/sdk-overview.md @@ -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 是插件与核心之间的类型化契约。本页是关于**导入什么**以及**你可以注册什么**的参考。 - **在找操作指南?** + **在找操作指南吗?** - 第一个插件?从 [入门指南](/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) ## 导入约定 @@ -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 类型 | @@ -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 辅助函数 | - + | 子路径 | 关键导出 | | --- | --- | | `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` | 请求体大小 / 超时辅助函数 | - + | 子路径 | 关键导出 | | --- | --- | | `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 的实验性受信任插件 surface:harness 类型、活跃运行 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` | - + | 子路径 | 关键导出 | | --- | --- | - | `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 子路径,而核心在确实存在跨渠道需求时,应使用这些插 | 子路径 | 关键导出 | | --- | --- | - | `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 辅助接口 | - - | 类别 | 当前子路径 | 预期用途 | + + | 系列 | 当前子路径 | 预期用途 | | --- | --- | --- | - | 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` | @@ -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.` 相同的结构。 -- 用户配置仍然优先生效。OpenClaw 会先将 `agents.defaults.cliBackends.` 合并到插件默认值之上,再运行 CLI。 -- 当某个后端在合并后需要进行兼容性重写时,使用 `normalizeConfig` - (例如规范化旧版 flag 结构)。 +- 用户配置仍然优先生效。OpenClaw 会在运行 CLI 之前,将 `agents.defaults.cliBackends.` 合并到插件默认值之上。 +- 当后端在合并后需要兼容性重写时,使用 `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` | 来自 `plugins.entries..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 # 仅用于轻量级设置的入口点(可选) ``` - 不要在生产代码中通过 `openclaw/plugin-sdk/` 导入你自己的插件。 - 内部导入应通过 `./api.ts` 或 - `./runtime-api.ts`。SDK 路径仅是外部契约。 + 永远不要在生产代码中通过 `openclaw/plugin-sdk/` + 导入你自己的插件。内部导入应通过 `./api.ts` 或 + `./runtime-api.ts`。SDK 路径仅是对外契约。 -通过 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 构建器以及新手引导 / 配置辅助函数 - 扩展生产代码也应避免导入 `openclaw/plugin-sdk/`。 - 如果某个辅助函数确实需要共享,请将它提升到中立的 SDK 子路径, + 扩展的生产代码也应避免导入 `openclaw/plugin-sdk/`。 + 如果某个辅助函数确实需要共享,请将其提升到中立的 SDK 子路径, 例如 `openclaw/plugin-sdk/speech`、`.../provider-model-shared` 或其他 - 面向能力的 surface,而不是让两个插件耦合在一起。 + 面向能力的接口,而不是将两个插件耦合在一起。 ## 相关内容 - [入口点](/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) — 深入的架构和能力模型 diff --git a/docs/zh-CN/plugins/skill-workshop.md b/docs/zh-CN/plugins/skill-workshop.md new file mode 100644 index 000000000..034d3c8b8 --- /dev/null +++ b/docs/zh-CN/plugins/skill-workshop.md @@ -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 +/skills//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` - 已写入 `/skills` +- `rejected` - 已被操作员 / 模型拒绝 +- `quarantined` - 因严重扫描发现而被阻止 + +状态按工作区存储在 Gateway 网关状态目录下: + +```text +/skill-workshop/.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 ` 时,请使用此操作。 + +### `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 +/skills// +``` + +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-workshop: applied ` +- `skill-workshop: quarantined ` +- `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) diff --git a/docs/zh-CN/tools/skills.md b/docs/zh-CN/tools/skills.md index 9e7bdaf59..f8e1bcfc2 100644 --- a/docs/zh-CN/tools/skills.md +++ b/docs/zh-CN/tools/skills.md @@ -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 --- # Skills(OpenClaw) -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**:`/.agents/skills` +1. **额外 Skill 文件夹**:通过 `skills.load.extraDirs` 配置 +2. **内置 Skills**:随安装一起提供(npm 包或 OpenClaw.app) +3. **托管/本地 Skills**:`~/.openclaw/skills` +4. **个人智能体 Skills**:`~/.agents/skills` +5. **项目智能体 Skills**:`/.agents/skills` 6. **工作区 Skills**:`/skills` -如果 skill 名称冲突,优先级如下: +如果 Skill 名称冲突,优先级如下: `/skills`(最高)→ `/.agents/skills` → `~/.agents/skills` → `~/.openclaw/skills` → 内置 Skills → `skills.load.extraDirs`(最低) -## 每个 agent 的 Skills 与共享 Skills +## 按智能体区分的 Skills 与共享 Skills 在**多智能体**设置中,每个智能体都有自己的工作区。这意味着: -- **每个 agent 独有的 Skills** 仅存在于该 agent 的 `/skills` 中。 -- **项目 agent Skills** 位于 `/.agents/skills`,会先于普通工作区 `skills/` 文件夹应用到该工作区。 -- **个人 agent Skills** 位于 `~/.agents/skills`,会应用到该机器上的所有工作区。 -- **共享 Skills** 位于 `~/.openclaw/skills`(托管式/本地),同一台机器上的**所有智能体**都可见。 -- 如果你希望多个智能体共用同一套 Skills,也可以通过 `skills.load.extraDirs` 添加**共享文件夹**(最低优先级)。 +- **按智能体区分的 Skills** 仅存在于该智能体的 `/skills` 中。 +- **项目智能体 Skills** 位于 `/.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 只会写入 `/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 ` -- 更新所有已安装的 skills: +- 更新所有已安装的 Skills: - `openclaw skills update --all` - 同步(扫描 + 发布更新): - `clawhub sync --all` -原生 `openclaw skills install` 会安装到当前活动工作区的 `skills/` 目录中。独立的 `clawhub` CLI 也会安装到当前工作目录下的 `./skills` 中(或者回退到已配置的 OpenClaw 工作区)。 -OpenClaw 会在下一个会话中将其识别为 `/skills`。 +原生 `openclaw skills install` 会安装到当前活动工作区的 `skills/` 目录中。单独的 `clawhub` CLI 也会安装到你当前工作目录下的 `./skills` 中(或者回退到配置的 OpenClaw 工作区)。 +OpenClaw 会在下一个会话中将其作为 `/skills` 加载。 ## 安全说明 -- 将第三方 skills 视为**不受信任的代码**。启用前请先阅读。 -- 对不受信任的输入和高风险工具,优先使用沙箱隔离运行。参见 [沙箱隔离](/zh-CN/gateway/sandboxing)。 -- 工作区和额外目录的 skill 发现只接受那些其解析后的真实路径仍位于已配置根目录内的 skill 根目录和 `SKILL.md` 文件。 -- 由 Gateway 网关支持的 skill 依赖安装(`skills.install`、新手引导以及 Skills 设置 UI)会在执行安装器元数据之前运行内置危险代码扫描器。默认情况下,`critical` 级别发现会阻止继续,除非调用方显式设置危险覆盖;可疑发现仍然只会发出警告。 -- `openclaw skills install ` 则不同:它会将一个 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 ` 不同:它会将一个 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: "", commandName: "", skillName: "" }`。 -## 门控规则(加载时过滤) +## 门控(加载时过滤) -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..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 CLI(brew)", }, ], }, @@ -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/`)。 +- 如果列出了多个安装器,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/`)。 -如果不存在 `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..env` 或 `skills.entries..apiKey` 应用到 +1. 读取 Skill 元数据。 +2. 将任何 `skills.entries..env` 或 `skills.entries..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 转义后的 ``、`` 和 `` 值的长度。 +- **基础开销(仅当 ≥1 个 Skill 时):** 195 个字符。 +- **每个 Skill:** 97 个字符 + XML 转义后的 ``、`` 和 `` 值的长度。 公式(字符数): @@ -330,17 +342,19 @@ total = 195 + Σ (97 + len(name_escaped) + len(description_escaped) + len(locati 说明: - XML 转义会将 `& < > " '` 扩展为实体(`&`、`<` 等),从而增加长度。 -- 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) — 插件系统概览 diff --git a/docs/zh-CN/tools/web.md b/docs/zh-CN/tools/web.md index 7cb09502f..baff612ad 100644 --- a/docs/zh-CN/tools/web.md +++ b/docs/zh-CN/tools/web.md @@ -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。 - `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)。 ## 快速开始 - 选择一个提供商并完成所需设置。有些提供商不需要密钥,而另一些则使用 API 密钥。详情请参阅下方各提供商页面。 + 选择一个提供商并完成所需设置。有些提供商无需密钥,而另一些则使用 API 密钥。详情请参见下方的提供商页面。 ```bash @@ -38,7 +38,7 @@ OpenClaw 还包含用于搜索 X(原 Twitter)帖子 的 `x_search`,以及 ``` 这会存储提供商以及所需的任何凭证。你也可以设置环境变量(例如 `BRAVE_API_KEY`),并对基于 API 的提供商跳过此步骤。 - + 智能体现在可以调用 `web_search`: ```javascript @@ -58,59 +58,59 @@ OpenClaw 还包含用于搜索 X(原 Twitter)帖子 的 `x_search`,以及 - 带摘要片段的结构化结果。支持 `llm-context` 模式、国家/语言筛选。提供免费套餐。 + 带摘要片段的结构化结果。支持 `llm-context` 模式、国家 / 语言筛选。提供免费层级。 - 无密钥回退选项。无需 API 密钥。基于非官方 HTML 集成。 + 无密钥回退。无需 API 密钥。基于非官方 HTML 集成。 - 神经网络 + 关键词搜索,并支持内容提取(高亮、文本、摘要)。 + 神经网络 + 关键词搜索,并支持内容提取(高亮、正文、摘要)。 - 结构化结果。最适合与 `firecrawl_search` 和 `firecrawl_scrape` 搭配使用,以进行深度提取。 + 结构化结果。最适合与 `firecrawl_search` 和 `firecrawl_scrape` 配合使用,以进行深度提取。 - 通过 Google Search grounding 提供带引用的 AI 综合回答。 + 通过 Google 搜索 grounding 提供带引用的 AI 综合答案。 - 通过 xAI web grounding 提供带引用的 AI 综合回答。 + 通过 xAI 网页 grounding 提供带引用的 AI 综合答案。 - 通过 Moonshot web search 提供带引用的 AI 综合回答。 + 通过 Moonshot 网页搜索提供带引用的 AI 综合答案。 通过 MiniMax Coding Plan 搜索 API 提供结构化结果。 - 通过你配置的 Ollama 主机进行无密钥搜索。需要执行 `ollama signin`。 + 通过你配置的 Ollama 主机进行无密钥搜索。需要先运行 `ollama signin`。 - 带内容提取控制和域名筛选的结构化结果。 + 带内容提取控制和域过滤的结构化结果。 - 自托管元搜索。无需 API 密钥。聚合 Google、Bing、DuckDuckGo 等搜索引擎。 + 自托管元搜索。无需 API 密钥。聚合 Google、Bing、DuckDuckGo 等搜索源。 - 结构化结果,支持搜索深度、主题筛选,以及用于 URL 提取的 `tavily_extract`。 + 带搜索深度、主题筛选以及用于 URL 提取的 `tavily_extract` 的结构化结果。 ### 提供商对比 -| 提供商 | 结果样式 | 筛选项 | 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 搜索,但当前模型不支持 Codex,OpenClaw 会继续保持正常的托管 `web_search` 行为。 +如果启用了原生 Codex 搜索,但当前模型不支持 Codex,OpenClaw 会保留正常的托管 `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(你将收到缺少密钥的错误提示,要求你进行配置)。 - 所有提供商密钥字段都支持 SecretRef 对象。在自动检测模式下,OpenClaw 只会解析已选中提供商的密钥——未选中的 SecretRef 会保持未激活状态。 + 所有提供商密钥字段都支持 SecretRef 对象。位于 `plugins.entries..config.webSearch.apiKey` 下、作用域限定到插件的 SecretRef,会对内置的 Exa、Firecrawl、Gemini、Grok、Kimi、Perplexity 和 Tavily 提供商进行解析,无论提供商是通过 `tools.web.search.provider` 显式选择,还是通过自动检测选中。在自动检测模式下,OpenClaw 只会解析被选中提供商的密钥——未被选中的 SecretRef 会保持不活跃,因此你可以同时配置多个提供商,而不必为未使用的提供商承担解析成本。 ## 配置 @@ -197,35 +197,33 @@ OpenClaw 还包含用于搜索 X(原 Twitter)帖子 的 `x_search`,以及 } ``` -特定于提供商的配置(API 密钥、基础 URL、模式)位于 -`plugins.entries..config.webSearch.*` 下。示例请参阅各提供商页面。 +提供商特定配置(API 密钥、base URL、模式)位于 +`plugins.entries..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 密钥 - 运行 `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)。 @@ -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 支持) | - 并非所有参数都适用于所有提供商。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`——高级选项请使用它们各自的专用工具。 ## x_search -`x_search` 使用 xAI 查询 X(原 Twitter)帖子,并返回带引用的 AI 综合回答。它接受自然语言查询以及可选的结构化筛选条件。OpenClaw 仅会在服务于此工具调用的请求上启用内置的 xAI `x_search` 工具。 +`x_search` 使用 xAI 查询 X(原 Twitter)帖子,并返回带引用的 AI 综合答案。它接受自然语言查询和可选的结构化筛选条件。OpenClaw 只会在服务此工具调用的请求中启用内置的 xAI `x_search` 工具。 - xAI 文档说明 `x_search` 支持关键词搜索、语义搜索、用户搜索和线程抓取。对于单条帖子的互动统计数据,例如转发、回复、收藏或浏览量,优先针对确切帖子 URL 或状态 ID 进行定向查询。宽泛的关键词搜索可能能找到正确的帖子,但返回的单帖元数据不够完整。一个好的模式是:先定位帖子,再运行第二次 `x_search` 查询,聚焦于该确切帖子。 + xAI 文档说明 `x_search` 支持关键词搜索、语义搜索、用户搜索和线程抓取。对于单条帖子的互动统计,例如转发、回复、收藏或浏览量,优先建议对准确的帖子 URL 或状态 ID 进行定向查找。宽泛的关键词搜索可能能找到正确帖子,但返回的单帖元数据可能不够完整。一个好的模式是:先定位帖子,再运行第二个聚焦该准确帖子的 `x_search` 查询。 ### 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 搜索