diff --git a/docs/zh-CN/concepts/openclaw-sdk.md b/docs/zh-CN/concepts/openclaw-sdk.md new file mode 100644 index 000000000..357ca3543 --- /dev/null +++ b/docs/zh-CN/concepts/openclaw-sdk.md @@ -0,0 +1,325 @@ +--- +read_when: + - 你正在设计或实现一个公开的 OpenClaw 应用 SDK + - 你正在将 OpenClaw 智能体 API 与 Cursor、Claude Agent SDK、OpenAI Agents、Google ADK、OpenCode、Codex 或 ACP 进行比较 + - 你需要判断某项功能应归属于公共应用 SDK、插件 SDK、Gateway 网关协议、ACP 后端,还是托管环境层。 +summary: 面向智能体运行、会话、任务、构件和托管环境的公共 OpenClaw 应用 SDK 设计提案 +title: OpenClaw SDK 设计 +x-i18n: + generated_at: "2026-04-29T23:55:15Z" + model: gpt-5.5 + provider: openai + source_hash: ffd4380e556e0e2e1218acaa9e5934e8b308b3420aa25a6d2598d35c7f9a7ab2 + source_path: concepts/openclaw-sdk.md + workflow: 16 +--- + +此页面是一份面向未来公开 **OpenClaw 应用 SDK** 的设计提案。它独立于现有的 [插件 SDK](/zh-CN/plugins/sdk-overview)。 + +插件 SDK 用于在 OpenClaw 内部运行并扩展提供商、渠道、工具、钩子和受信任运行时的代码。应用 SDK 应面向希望通过稳定公开 API 运行和观察 OpenClaw 智能体的外部应用、脚本、仪表板、CI 作业、IDE 扩展和自动化系统。 + +## Status + +架构草案。 + +本文档记录了对以下智能体 SDK 和运行时表面进行比较评审后得出的设计方向: + +| 项目 | 有用经验 | +| ------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| Cursor SDK cookbook | 最佳高层产品 API:`Agent`、`Run`、本地和云端运行时、流式传输、取消、模型发现、仓库、产物,以及云端拉取请求流程。 | +| Claude Agent SDK | 强大的双向会话客户端、中断和引导支持、权限模式、钩子、自定义工具、会话存储,以及可恢复的转录记录。 | +| OpenAI Agents SDK | 强大的工作流概念:交接、护栏、人工审批、追踪、运行状态、流式结果对象,以及中断后恢复。 | +| Google ADK | 强大的内部架构:运行器、会话服务、记忆服务、产物服务、凭证服务、插件、事件动作,以及长时间运行工具确认。 | +| OpenCode | 强大的客户端/服务器形态:生成的 API 客户端、REST 加 SSE、会话、工作区、工作树、权限、问题、文件、VCS、PTY、工具、智能体、Skills 和 MCP。 | +| Codex | 强大的本地运行时边界:审批、沙箱隔离、网络策略、本地和远程执行服务器、结构化协议事件,以及线程感知的应用服务器会话。 | +| ACP and acpx | 面向外部编码 harness 的强互操作层,支持命名会话、提示队列、协作式取消和运行时适配器。 | + +建议是在 OpenCode 风格的生成式 Gateway 网关客户端之上构建一个像 Cursor 一样简洁的公开外观,同时在适用处将 Claude、OpenAI Agents、ADK、Codex 和 ACP 概念作为内部设计参考。 + +## 目标 + +- 为应用开发者提供一个用于运行 OpenClaw 智能体的极小高层 API。 +- 保持本地优先的 OpenClaw 作为默认运行时。 +- 将云端或托管环境作为一个附加的环境提供商,而不是不同的智能体 API。 +- 保留现有 OpenClaw 边界:Gateway 网关拥有公开协议,插件 SDK 拥有进程内扩展,ACP 拥有外部 harness 互操作。 +- 将 `stream`、`wait`、`cancel`、`resume`、`fork`、产物、审批和后台任务作为一等操作支持。 +- 暴露稳定的标准化事件,同时为高级消费者保留运行时原生原始事件。 +- 让 SDK 权限、密钥转发、审批、沙箱隔离和远程环境保持显式。 +- 将公开契约保持在足够小的范围内,便于文档化、测试、版本化和生成。 + +## 非目标 + +- 不要将 `openclaw/plugin-sdk/*` 暴露为应用 SDK。 +- 不要让 ACP 成为唯一的运行时模型。 +- 不要要求先有云服务才能让 SDK 发挥作用。 +- 不要精确克隆 Cursor、Claude、OpenAI、ADK、OpenCode、Codex 或 ACP API。 +- 不要将无边界的 `any` 事件载荷作为唯一公开契约暴露。 +- 除非所选环境确实能够强制执行,否则不要承诺外部 harness 具有沙箱或网络隔离。 +- 不要让插件作者在插件运行时代码中依赖应用 SDK 对象。 + +## 当前 OpenClaw 契合度 + +OpenClaw 已经具备大部分底层基础: + +| 现有表面 | 它提供的能力 | +| --------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------ | +| [Agent loop](/zh-CN/concepts/agent-loop) | `agent` 和 `agent.wait` 运行生命周期、流式传输、超时和会话序列化。 | +| [Agent Runtimes](/zh-CN/concepts/agent-runtimes) | 提供商、模型、运行时和渠道分离。 | +| [ACP 智能体](/zh-CN/tools/acp-agents) | 面向 Claude Code、Cursor、Gemini CLI、OpenCode、显式 Codex ACP 以及类似工具的外部 harness 会话。 | +| [后台任务](/zh-CN/automation/tasks) | 面向 ACP、子智能体、cron、CLI 操作和异步媒体作业的分离式活动账本。 | +| [子智能体](/zh-CN/tools/subagents) | 隔离的后台智能体运行、可选的分叉上下文,以及回传到请求者会话。 | +| [Agent harness plugins](/zh-CN/plugins/sdk-agent-harness) | 面向 Codex 等嵌入式 harness 的受信任原生运行时注册。 | +| Gateway 网关协议 schema | 当前用于智能体参数、会话、订阅、中止、压缩和检查点的类型化方法与事件定义。 | + +缺口不是智能体执行。缺口是为这些组件提供一个稳定、友好的公开外观。 + +## 核心模型 + +应用 SDK 应使用一小组持久名词。 + +| 名词 | 含义 | +| ------------- | ------------------------------------------------------------------------------------------------------------------------ | +| `OpenClaw` | 客户端入口点。拥有 Gateway 网关发现、认证、低层客户端访问和命名空间工厂。 | +| `Agent` | 已配置的执行者。携带智能体 ID、默认模型、默认运行时、默认工具策略和面向应用的帮助函数。 | +| `Session` | 持久转录记录、路由、工作区、上下文和运行时绑定。 | +| `Run` | 一次提交的回合或任务。流式输出事件、等待结果、取消,并暴露产物。 | +| `Task` | 分离式或后台活动账本条目。涵盖子智能体、ACP 派生、cron 作业、CLI 运行和异步作业。 | +| `Artifact` | 文件、补丁、Diffs、媒体、日志、轨迹、拉取请求、截图和生成的包。 | +| `Environment` | 运行执行的位置:本地 Gateway 网关、本地工作区、节点主机、ACP harness、托管运行器,或未来的云工作区。 | +| `ToolSpace` | 生效的工具表面:OpenClaw 工具、MCP 服务器、渠道工具、应用工具、审批规则和工具元数据。 | +| `Approval` | 运行、工具、环境或 harness 请求的人工或策略决策。 | + +这些名词可以清晰映射到现有 OpenClaw 概念,但避免泄露 PI runner 内部机制、插件 harness 注册或 ACP 适配器细节等实现特定名称。 + +## 产品形态 + +高层 SDK 应具有如下使用体验: + +```typescript +import { OpenClaw } from "@openclaw/sdk"; + +const oc = new OpenClaw({ gateway: "auto" }); +const agent = await oc.agents.get("main"); + +const run = await agent.run({ + input: "Review this pull request and suggest the smallest safe fix.", + model: "openai/gpt-5.5", +}); + +for await (const event of run.events()) { + if (event.type === "assistant.delta") { + process.stdout.write(event.text); + } +} + +const result = await run.wait(); +console.log(result.status); +``` + +同一个应用也应能够使用持久会话: + +```typescript +const session = await oc.sessions.create({ + agentId: "main", + label: "release-review", +}); + +const run = await session.send("Prepare release notes from the current diff."); +await run.wait(); +``` + +当前实现说明:`@openclaw/sdk` 从目前已有的 Gateway 网关支撑表面开始。提供商限定的模型引用(如 `openai/gpt-5.5`)会被拆分为 Gateway 网关的 `provider` 和 `model` 覆盖项。每次运行的 `workspace`、`runtime`、`environment` 和 `approvals` 选择仍是设计目标;当调用者设置它们时,客户端会抛出错误,避免请求静默使用默认值执行。任务、产物、环境和通用工具调用帮助函数也已作为未来 API 形态搭建脚手架,并会在 Gateway 网关 RPC 存在之前抛出明确的不支持错误。 + +同一个 API 也应能够使用外部 ACP harness: + +```typescript +const run = await oc.runs.create({ + input: "Deep review this repository and return only high-risk findings.", + workspace: { cwd: process.cwd() }, + runtime: { type: "acp", harness: "claude" }, + mode: "task", +}); +``` + +托管环境不应改变顶层 API: + +```typescript +const run = await agent.run({ + input: "Run the full changed gate and summarize failures.", + workspace: { repo: "openclaw/openclaw", ref: "main" }, + runtime: { + type: "managed", + provider: "testbox", + timeoutMinutes: 90, + }, +}); +``` + +## 运行时选择 + +应用 SDK 应将运行时选择暴露为标准化联合类型: + +```typescript +type RuntimeSelection = + | "auto" + | { type: "embedded"; id: "pi" | "codex" | string } + | { type: "cli"; id: "claude-cli" | string } + | { type: "acp"; harness: "claude" | "cursor" | "gemini" | "opencode" | string } + | { type: "managed"; provider: "local" | "node" | "testbox" | "cloud" | string }; +``` + +规则: + +- `auto` 遵循 OpenClaw 运行时选择规则。 +- `embedded` 面向通过插件 SDK 注册的受信任进程内 harness,例如 `pi` 或 `codex`。 +- `cli` 面向可用的 OpenClaw 自有 CLI 后端执行。 +- `acp` 通过 ACP/acpx 面向外部 harness。 +- `managed` 面向环境提供商,并且仍可能在该环境内部运行嵌入式、CLI 或 ACP 运行时。 + +运行时选择对象应具有描述性。它不应成为隐藏密钥处理、沙箱策略或工作区预配的位置。 + +## 环境模型 + +环境是执行底座。它应保持显式,因为本地 CLI 运行、外部 harness、节点主机和云工作区具有不同的安全与生命周期属性。 + +```typescript +type EnvironmentSelection = + | { type: "local"; cwd?: string } + | { type: "gateway"; url?: string; cwd?: string } + | { type: "node"; nodeId: string; cwd?: string } + | { type: "managed"; provider: string; repo?: string; ref?: string } + | { type: "ephemeral"; provider: string; repo?: string; ref?: string }; +``` + +环境拥有: + +- checkout 或工作区准备 +- 进程和文件访问 +- 沙箱与网络强制执行 +- 环境变量和密钥引用 +- 日志、追踪和产物 +- 清理和保留 +- 运行时可用性 + +这种分离让托管智能体成为 SDK 的自然扩展。托管智能体是在托管环境中的一次普通运行,而不是特殊的产品分支。 + +详细的命名空间、事件、结果、审批、产物、安全、包和环境提供商契约位于 [OpenClaw SDK API 设计](/zh-CN/reference/openclaw-sdk-api-design)。 + +## Cookbook 计划 + +SDK 应随附 cookbook,而不只是参考文档。 + +推荐示例: + +| 示例 | 展示内容 | +| ---------------------------- | -------------------------------------------------------------------------------------------- | +| 快速开始 | 创建客户端、运行智能体、流式传输输出、等待结果。 | +| 编码智能体 CLI | 本地工作区、模型选择器、取消、审批、JSON 输出。 | +| 智能体仪表盘 | 会话、运行、后台任务、制品、事件重放、Status 过滤器。 | +| 应用构建器 | 智能体在预览服务器旁运行时编辑工作区。 | +| 拉取请求审查器 | 针对仓库引用运行,收集 diff 评论和制品。 | +| 审批控制台 | 订阅审批并从 UI 回复它们。 | +| ACP harness 运行器 | 使用同一个 `Run` API 通过 ACP 运行 Claude Code、Cursor、Gemini CLI 或 OpenCode。 | +| 托管环境提供商 | 准备工作区、流式传输事件、保存制品并清理的最小提供商。 | +| Slack 或 Discord 桥接 | 外部应用接收事件并发布进度摘要,而无需成为渠道插件。 | +| 多智能体研究 | 生成并行运行,收集制品,并综合成最终报告。 | + +手册示例应优先使用高层 API。低层生成的客户端示例属于高级章节。 + +## 分阶段实现 + +### 第 0 阶段:RFC 和词汇 + +- 就公开名词和名称达成一致。 +- 决定包名称。 +- 定义第一版事件分类。 +- 在文档中标明当前插件 SDK 有意保持独立。 + +### 第 1 阶段:低层生成客户端 + +- 从 Gateway 网关协议 schema 生成 TypeScript 客户端。 +- 优先覆盖 `agent`、`agent.wait`、会话、订阅、中止和任务。 +- 添加冒烟测试,验证生成的方法与 Gateway 网关方法名称和 schema 形状匹配。 +- 作为实验性或内部包发布。 + +### 第 2 阶段:高层运行 API + +- 添加 `OpenClaw`、`Agent`、`Session` 和 `Run`。 +- 支持 `run.events()`、`run.wait()` 和 `run.cancel()`。 +- 支持本地 Gateway 网关发现和显式 Gateway 网关 URL。 +- 支持持久会话和会话发送。 + +### 第 3 阶段:规范化事件投影 + +- 在 Gateway 网关侧现有原始事件旁添加规范化事件投影。 +- 在策略允许的地方保留原始运行时事件。 +- 添加重放游标和重连行为。 +- 将 PI、Codex、ACP 和任务事件映射到稳定的分类中。 + +### 第 4 阶段:制品和审批 + +- 添加制品列表和下载。 +- 添加审批订阅和响应辅助函数。 +- 添加问题订阅和响应辅助函数。 +- 添加手册审批控制台。 + +### 第 5 阶段:环境提供商 + +- 引入本地、节点和托管环境提供商契约。 +- 从已经在运维中存在的环境开始。 +- 添加工作区准备、日志、制品、超时、清理和保留。 + +### 第 6 阶段:云风格工作流 + +- 添加面向仓库和分支的运行。 +- 添加拉取请求制品。 +- 添加按仓库、分支、Status 和负责人分组的运行看板。 +- 添加长期运行的托管会话和保留策略。 + +## 可借鉴的设计选择 + +借鉴这些思路: + +- 来自 Cursor:`Agent` 加 `Run`、本地和云端对称、模型发现、制品,以及由手册驱动的新手引导。 +- 来自 Claude Agent SDK:双向客户端、中断、权限、钩子、自定义工具、会话存储和恢复语义。 +- 来自 OpenAI Agents:交接、护栏、人工审批恢复、追踪,以及结构化流式结果对象。 +- 来自 Google ADK:runner 后面的服务、事件动作、记忆、制品、凭证服务,以及围绕运行生命周期的插件拦截。 +- 来自 OpenCode:生成的协议客户端、REST 加 SSE、会话、工作区、问题、权限、文件、VCS、PTY、MCP、智能体和 Skills。 +- 来自 Codex:显式沙箱、审批、网络、本地和远程 exec,以及应用服务器线程边界。 +- 来自 ACP 和 acpx:基于适配器的外部 harness 互操作性和具名提示队列。 + +## 应避免的设计选择 + +避免这些陷阱: + +- 只是 Gateway 网关内部机制浅层转储的公开 SDK。 +- 导入插件 SDK 子路径的公开 SDK。 +- 事件只有 `stream` 加 `data` 的公开 SDK。 +- 让本地 OpenClaw 感觉像旧版模式的云优先 API。 +- 隐藏在模型 ID 前缀中的运行时选择。 +- 隐藏在环境映射中的密钥转发。 +- 每次运行的顶层都有 ACP 特定选项。 +- 所选运行时无法强制执行的沙箱标志。 +- 一个 SDK 对象试图同时充当提供商插件、渠道插件、应用客户端和托管 runner。 + +## 未决问题 + +- 初始包应该放在这个仓库中,还是放在单独的 SDK 仓库中? +- 生成的低层客户端是否应在高层包装器稳定之前公开发布? +- 第一个受支持的应用认证机制是什么:本地令牌、管理员令牌、OAuth 设备流,还是签名应用注册? +- SDK 默认应暴露多少会话消息历史? +- 托管环境是否只能在 Gateway 网关配置中配置,还是 SDK 调用方可以使用有作用域的令牌直接请求? +- 本地运行生成的制品适用哪些保留规则? +- 哪些事件载荷在交付给应用之前需要脱敏? +- `Run` 应该覆盖普通聊天轮次和分离任务,还是分离的后台工作应始终返回带有嵌套 `Run` 的 `Task` 包装器? + +## 相关文档 + +- [Agent loop](/zh-CN/concepts/agent-loop) +- [Agent Runtimes](/zh-CN/concepts/agent-runtimes) +- [会话](/zh-CN/concepts/session) +- [子智能体](/zh-CN/tools/subagents) +- [后台任务](/zh-CN/automation/tasks) +- [ACP 智能体](/zh-CN/tools/acp-agents) +- [Agent harness plugins](/zh-CN/plugins/sdk-agent-harness) +- [插件 SDK 概览](/zh-CN/plugins/sdk-overview) diff --git a/docs/zh-CN/gateway/protocol.md b/docs/zh-CN/gateway/protocol.md index f3cb9fc83..d4bfc9e28 100644 --- a/docs/zh-CN/gateway/protocol.md +++ b/docs/zh-CN/gateway/protocol.md @@ -2,29 +2,29 @@ read_when: - 实现或更新 Gateway 网关 WS 客户端 - 调试协议不匹配或连接失败 - - 正在重新生成协议架构/模型 -summary: Gateway 网关 WebSocket 协议:握手、帧、版本控制 + - 重新生成协议模式/模型 +summary: Gateway 网关 WebSocket 协议:握手、帧、版本管理 title: Gateway 网关协议 x-i18n: - generated_at: "2026-04-29T09:29:45Z" + generated_at: "2026-04-29T23:55:19Z" model: gpt-5.5 provider: openai - source_hash: 51647177913f9ba0bbbe4fffbe4e06ff120d5307d075f49cb99d363ac6ad0f11 + source_hash: c0d922e9b4b778c333873e551498b905461f30f944e809555b45669ae2f5c404 source_path: gateway/protocol.md workflow: 16 --- -Gateway 网关 WS 协议是 OpenClaw 的**唯一控制平面 + 节点传输协议**。所有客户端(CLI、Web UI、macOS 应用、iOS/Android 节点、无头节点)都通过 WebSocket 连接,并在握手时声明其**角色** + **范围**。 +Gateway 网关 WS 协议是 OpenClaw 的**单一控制平面 + 节点传输协议**。所有客户端(CLI、网页 UI、macOS 应用、iOS/Android 节点、无头节点)都通过 WebSocket 连接,并在握手时声明它们的**角色** + **作用域**。 -## 传输协议 +## 传输 - WebSocket,文本帧使用 JSON 负载。 - 第一帧**必须**是 `connect` 请求。 -- 连接前帧上限为 64 KiB。握手成功后,客户端应遵循 `hello-ok.policy.maxPayload` 和 `hello-ok.policy.maxBufferedBytes` 限制。启用诊断后,超大的入站帧和缓慢的出站缓冲区会在 Gateway 网关关闭或丢弃受影响帧之前发出 `payload.large` 事件。这些事件会保留大小、限制、表面和安全原因代码。它们不会保留消息正文、附件内容、原始帧正文、令牌、Cookie 或密钥值。 +- 连接前帧上限为 64 KiB。握手成功后,客户端应遵循 `hello-ok.policy.maxPayload` 和 `hello-ok.policy.maxBufferedBytes` 限制。启用诊断后,超大的入站帧和缓慢的出站缓冲区会在 Gateway 网关关闭或丢弃受影响的帧之前发出 `payload.large` 事件。这些事件会保留大小、限制、表面和安全原因代码。它们不会保留消息正文、附件内容、原始帧正文、令牌、Cookie 或密钥值。 ## 握手(connect) -Gateway 网关 → 客户端(连接前质询): +Gateway 网关 → 客户端(连接前挑战): ```json { @@ -95,9 +95,9 @@ Gateway 网关 → 客户端: } ``` -当 Gateway 网关仍在完成启动 sidecar 时,`connect` 请求可能返回可重试的 `UNAVAILABLE` 错误,其中 `details.reason` 设置为 `"startup-sidecars"` 并带有 `retryAfterMs`。客户端应在其总体连接预算内重试该响应,而不是将其暴露为终止性握手失败。 +当 Gateway 网关仍在完成启动 sidecar 时,`connect` 请求可能会返回可重试的 `UNAVAILABLE` 错误,其中 `details.reason` 设置为 `"startup-sidecars"`,并带有 `retryAfterMs`。客户端应在整体连接预算内重试该响应,而不是将其作为终止性的握手失败呈现。 -`server`、`features`、`snapshot` 和 `policy` 都是 schema(`src/gateway/protocol/schema/frames.ts`)要求的。`auth` 也是必需的,并报告协商后的角色/范围。`canvasHostUrl` 是可选的。 +`server`、`features`、`snapshot` 和 `policy` 都是 schema(`src/gateway/protocol/schema/frames.ts`)要求的字段。`auth` 也是必填字段,并报告协商后的角色/作用域。`canvasHostUrl` 是可选字段。 未签发设备令牌时,`hello-ok.auth` 会报告协商后的权限,不包含令牌字段: @@ -110,7 +110,7 @@ Gateway 网关 → 客户端: } ``` -受信任的同进程后端客户端(`client.id: "gateway-client"`、`client.mode: "backend"`)在使用共享 Gateway 网关令牌/密码进行身份验证时,可以在直接 local loopback 连接上省略 `device`。此路径仅保留给内部控制平面 RPC,并防止过期的 CLI/设备配对基线阻塞本地后端工作,例如子智能体会话更新。远程客户端、浏览器源客户端、节点客户端,以及显式设备令牌/设备身份客户端仍使用常规配对和范围升级检查。 +受信任的同进程后端客户端(`client.id: "gateway-client"`、`client.mode: "backend"`)在使用共享 Gateway 网关令牌/密码进行身份验证时,可在直接 loopback 连接上省略 `device`。此路径仅供内部控制平面 RPC 使用,并避免过期的 CLI/设备配对基线阻塞本地后端工作,例如子智能体会话更新。远程客户端、浏览器源客户端、节点客户端以及显式设备令牌/设备身份客户端仍使用正常的配对和作用域升级检查。 签发设备令牌时,`hello-ok` 还会包含: @@ -124,7 +124,7 @@ Gateway 网关 → 客户端: } ``` -在受信任的启动交接期间,`hello-ok.auth` 还可能在 `deviceTokens` 中包含额外的有界角色条目: +在受信任的 bootstrap 交接期间,`hello-ok.auth` 还可能在 `deviceTokens` 中包含其他有边界的角色条目: ```json { @@ -143,7 +143,7 @@ Gateway 网关 → 客户端: } ``` -对于内置节点/操作员启动流程,主节点令牌保持 `scopes: []`,任何交接的操作员令牌都保持受限于启动操作员允许列表(`operator.approvals`、`operator.read`、`operator.talk.secrets`、`operator.write`)。启动范围检查保持按角色前缀区分:操作员条目只满足操作员请求,非操作员角色仍需要其自身角色前缀下的范围。 +对于内置的节点/operator bootstrap 流,主节点令牌保持 `scopes: []`,任何交接的 operator 令牌都限制在 bootstrap operator 允许列表(`operator.approvals`、`operator.read`、`operator.talk.secrets`、`operator.write`)内。Bootstrap 作用域检查保持角色前缀:operator 条目只满足 operator 请求,非 operator 角色仍需要其自身角色前缀下的作用域。 ### 节点示例 @@ -180,7 +180,7 @@ Gateway 网关 → 客户端: } ``` -## 成帧 +## 分帧 - **请求**:`{type:"req", id, method, params}` - **响应**:`{type:"res", id, ok, payload|error}` @@ -188,16 +188,16 @@ Gateway 网关 → 客户端: 有副作用的方法需要**幂等键**(见 schema)。 -## 角色 + 范围 +## 角色 + 作用域 ### 角色 - `operator` = 控制平面客户端(CLI/UI/自动化)。 - `node` = 能力宿主(camera/screen/canvas/system.run)。 -### 范围(操作员) +### 作用域(operator) -常见范围: +常用作用域: - `operator.read` - `operator.write` @@ -208,11 +208,11 @@ Gateway 网关 → 客户端: 带有 `includeSecrets: true` 的 `talk.config` 需要 `operator.talk.secrets`(或 `operator.admin`)。 -插件注册的 Gateway 网关 RPC 方法可以请求自己的操作员范围,但保留的核心管理员前缀(`config.*`、`exec.approvals.*`、`wizard.*`、`update.*`)始终解析为 `operator.admin`。 +插件注册的 Gateway 网关 RPC 方法可以请求自己的 operator 作用域,但保留的核心 admin 前缀(`config.*`、`exec.approvals.*`、`wizard.*`、`update.*`)始终解析为 `operator.admin`。 -方法范围只是第一道门槛。一些通过 `chat.send` 触达的斜杠命令会在此基础上应用更严格的命令级检查。例如,持久化的 `/config set` 和 `/config unset` 写入需要 `operator.admin`。 +方法作用域只是第一道门。某些通过 `chat.send` 到达的斜杠命令会在其上应用更严格的命令级检查。例如,持久化的 `/config set` 和 `/config unset` 写入需要 `operator.admin`。 -`node.pair.approve` 在基础方法范围之上还有额外的批准时范围检查: +`node.pair.approve` 除基础方法作用域外,还在批准时增加额外的作用域检查: - 无命令请求:`operator.pairing` - 带有非 exec 节点命令的请求:`operator.pairing` + `operator.write` @@ -226,13 +226,13 @@ Gateway 网关 → 客户端: - `commands`:用于 invoke 的命令允许列表。 - `permissions`:细粒度开关(例如 `screen.record`、`camera.capture`)。 -Gateway 网关将这些视为**声明**,并执行服务器端允许列表。 +Gateway 网关将这些视为**声明**,并强制执行服务器端允许列表。 ## 在线状态 -- `system-presence` 返回按设备身份键控的条目。 -- 在线状态条目包含 `deviceId`、`roles` 和 `scopes`,因此即使设备同时以**操作员**和**节点**身份连接,UI 也可以为每个设备显示单行。 -- `node.list` 包含可选的 `lastSeenAtMs` 和 `lastSeenReason` 字段。已连接节点会将其当前连接时间报告为 `lastSeenAtMs`,原因是 `connect`;当受信任节点事件更新其配对元数据时,已配对节点也可以报告持久的后台在线状态。 +- `system-presence` 返回以设备身份为键的条目。 +- 在线状态条目包含 `deviceId`、`roles` 和 `scopes`,因此 UI 可以为每个设备显示一行,即使它同时以 **operator** 和 **node** 身份连接。 +- `node.list` 包含可选的 `lastSeenAtMs` 和 `lastSeenReason` 字段。已连接节点会将其当前连接时间报告为 `lastSeenAtMs`,原因为 `connect`;当受信任的节点事件更新其配对元数据时,已配对节点也可以报告持久的后台在线状态。 ### 节点后台存活事件 @@ -245,9 +245,9 @@ Gateway 网关将这些视为**声明**,并执行服务器端允许列表。 } ``` -`trigger` 是封闭枚举:`background`、`silent_push`、`bg_app_refresh`、`significant_location`、`manual` 或 `connect`。未知 trigger 字符串会在持久化前由 Gateway 网关规范化为 `background`。该事件仅对已认证的节点设备会话持久化;无设备或未配对会话返回 `handled: false`。 +`trigger` 是封闭枚举:`background`、`silent_push`、`bg_app_refresh`、`significant_location`、`manual` 或 `connect`。未知的 trigger 字符串会在持久化前由 Gateway 网关规范化为 `background`。该事件仅对经过身份验证的节点设备会话持久化;无设备或未配对会话会返回 `handled: false`。 -成功的 Gateway 网关返回结构化结果: +成功的 Gateway 网关会返回结构化结果: ```json { @@ -258,53 +258,53 @@ Gateway 网关将这些视为**声明**,并执行服务器端允许列表。 } ``` -旧版 Gateway 网关仍可能对 `node.event` 返回 `{ "ok": true }`;客户端应将其视为已确认的 RPC,而不是持久在线状态写入。 +较旧的 Gateway 网关仍可能为 `node.event` 返回 `{ "ok": true }`;客户端应将其视为已确认的 RPC,而不是持久在线状态的持久化。 -## 广播事件范围控制 +## 广播事件作用域限定 -服务器推送的 WebSocket 广播事件受范围控制,因此配对范围会话或仅节点会话不会被动接收会话内容。 +服务器推送的 WebSocket 广播事件会经过作用域门控,因此配对作用域或仅节点会话不会被动接收会话内容。 - **聊天、智能体和工具结果帧**(包括流式 `agent` 事件和工具调用结果)至少需要 `operator.read`。没有 `operator.read` 的会话会完全跳过这些帧。 -- **插件定义的 `plugin.*` 广播**会根据插件注册方式受 `operator.write` 或 `operator.admin` 控制。 -- **Status 和传输事件**(`heartbeat`、`presence`、`tick`、连接/断开生命周期等)保持不受限制,因此每个已认证会话都能观察传输健康状态。 -- **未知广播事件族**默认受范围控制(失败关闭),除非注册处理程序显式放宽它们。 +- **插件定义的 `plugin.*` 广播**会根据插件注册方式,以 `operator.write` 或 `operator.admin` 作为门控。 +- **Status 和传输事件**(`heartbeat`、`presence`、`tick`、连接/断开生命周期等)保持不受限制,因此每个经过身份验证的会话都可以观察传输健康状况。 +- **未知广播事件族**默认会经过作用域门控(故障关闭),除非注册的处理程序显式放宽它们。 -每个客户端连接都会保留自己的按客户端序列号,因此即使不同客户端看到事件流的不同范围过滤子集,广播也能在该 socket 上保持单调排序。 +每个客户端连接都会保留自己的每客户端序列号,因此即使不同客户端看到事件流中不同的作用域过滤子集,广播也会在该套接字上保持单调顺序。 ## 常见 RPC 方法族 -公共 WS 表面比上面的握手/身份验证示例更广。这不是生成的转储,`hello-ok.features.methods` 是一个保守的发现列表,由 `src/gateway/server-methods-list.ts` 加载的插件/渠道方法导出构建而来。将其视为功能发现,而不是 `src/gateway/server-methods/*.ts` 的完整枚举。 +公共 WS 表面比上面的握手/身份验证示例更广。这不是生成的转储 — `hello-ok.features.methods` 是一个保守的发现列表,由 `src/gateway/server-methods-list.ts` 加上已加载的插件/渠道方法导出构建而来。请将其视为功能发现,而不是 `src/gateway/server-methods/*.ts` 的完整枚举。 - `health` 返回缓存的或新探测的 Gateway 网关健康快照。 - - `diagnostics.stability` 返回最近的有界诊断稳定性记录器。它保留事件名称、计数、字节大小、内存读数、队列/会话状态、渠道/插件名称和会话 id 等操作元数据。它不会保留聊天文本、webhook 正文、工具输出、原始请求或响应正文、令牌、Cookie 或密钥值。需要操作员读取范围。 - - `status` 返回 `/status` 风格的 Gateway 网关摘要;敏感字段仅包含给管理员范围的操作员客户端。 + - `diagnostics.stability` 返回最近的有界诊断稳定性记录器。它保留事件名称、计数、字节大小、内存读数、队列/会话状态、渠道/插件名称和会话 ID 等运营元数据。它不会保留聊天文本、webhook 正文、工具输出、原始请求或响应正文、令牌、Cookie 或密钥值。需要 operator 读取作用域。 + - `status` 返回 `/status` 风格的 Gateway 网关摘要;敏感字段仅包含在 admin 作用域的 operator 客户端中。 - `gateway.identity.get` 返回 relay 和配对流程使用的 Gateway 网关设备身份。 - - `system-presence` 返回已连接操作员/节点设备的当前在线状态快照。 - - `system-event` 追加系统事件,并可以更新/广播在线状态上下文。 - - `last-heartbeat` 返回最新持久化的心跳事件。 - - `set-heartbeats` 切换 Gateway 网关上的心跳处理。 + - `system-presence` 返回当前已连接 operator/node 设备的在线状态快照。 + - `system-event` 追加系统事件,并可更新/广播在线状态上下文。 + - `last-heartbeat` 返回最新持久化的 Heartbeat 事件。 + - `set-heartbeats` 切换 Gateway 网关上的 Heartbeat 处理。 - - - `models.list` 返回运行时允许的模型目录。传入 `{ "view": "configured" }` 可获取适合选择器展示的已配置模型(先是 `agents.defaults.models`,然后是 `models.providers.*.models`),或传入 `{ "view": "all" }` 获取完整目录。 + + - `models.list` 返回运行时允许的模型目录。传入 `{ "view": "configured" }` 可获取适合选择器大小的已配置模型(先是 `agents.defaults.models`,然后是 `models.providers.*.models`),或传入 `{ "view": "all" }` 获取完整目录。 - `usage.status` 返回提供商用量窗口/剩余额度摘要。 - - `usage.cost` 返回某个日期范围的聚合成本用量摘要。 - - `doctor.memory.status` 返回活动默认 Agent 工作区的向量内存/缓存嵌入就绪状态。仅当调用方明确需要实时 ping 嵌入提供商时,才传入 `{ "probe": true }` 或 `{ "deep": true }`。 - - `doctor.memory.remHarness` 为远程控制平面客户端返回有界、只读的 REM harness 预览。它可以包含工作区路径、记忆片段、渲染后的有依据 markdown,以及深度提升候选项,因此调用方需要 `operator.read`。 + - `usage.cost` 返回某个日期范围内的聚合成本用量摘要。 + - `doctor.memory.status` 返回当前默认智能体工作区的向量记忆/缓存嵌入就绪状态。仅当调用方明确需要实时嵌入提供商 ping 时,才传入 `{ "probe": true }` 或 `{ "deep": true }`。 + - `doctor.memory.remHarness` 为远程控制平面客户端返回有界、只读的 REM harness 预览。它可以包含工作区路径、记忆片段、渲染后的有依据 Markdown,以及深度提升候选项,因此调用方需要 `operator.read`。 - `sessions.usage` 返回每个会话的用量摘要。 - - `sessions.usage.timeseries` 返回某个会话的时间序列用量。 - - `sessions.usage.logs` 返回某个会话的用量日志条目。 + - `sessions.usage.timeseries` 返回一个会话的时间序列用量。 + - `sessions.usage.logs` 返回一个会话的用量日志条目。 - - `channels.status` 返回内置 + 捆绑渠道/插件 Status 摘要。 - - `channels.logout` 在渠道支持登出的情况下,登出指定渠道/账号。 - - `web.login.start` 为当前支持二维码的网页渠道提供商启动二维码/网页登录流程。 - - `web.login.wait` 等待该二维码/网页登录流程完成,并在成功后启动渠道。 + - `channels.status` 返回内置 + 打包渠道/插件的 Status 摘要。 + - `channels.logout` 会在渠道支持登出的情况下登出指定渠道/账户。 + - `web.login.start` 为当前支持 QR 的 Web 渠道提供商启动 QR/Web 登录流程。 + - `web.login.wait` 等待该 QR/Web 登录流程完成,并在成功后启动渠道。 - `push.test` 向已注册的 iOS 节点发送测试 APNs 推送。 - `voicewake.get` 返回已存储的唤醒词触发器。 - `voicewake.set` 更新唤醒词触发器并广播变更。 @@ -312,16 +312,16 @@ Gateway 网关将这些视为**声明**,并执行服务器端允许列表。 - - `send` 是用于在聊天运行器之外,按渠道/账号/线程目标直接发送消息的出站投递 RPC。 - - `logs.tail` 返回已配置 Gateway 网关文件日志的尾部内容,并带有游标/限制和最大字节数控制。 + - `send` 是直接出站投递 RPC,用于在聊天运行器之外按渠道/账户/线程目标发送。 + - `logs.tail` 返回已配置的 Gateway 网关文件日志尾部内容,带 cursor/limit 和最大字节控制。 - `talk.config` 返回生效的 Talk 配置载荷;`includeSecrets` 需要 `operator.talk.secrets`(或 `operator.admin`)。 - `talk.mode` 为 WebChat/Control UI 客户端设置/广播当前 Talk 模式状态。 - - `talk.speak` 通过活动的 Talk 语音提供商合成语音。 - - `tts.status` 返回 TTS 启用状态、活动提供商、回退提供商和提供商配置状态。 + - `talk.speak` 通过当前 Talk 语音提供商合成语音。 + - `tts.status` 返回 TTS 启用状态、当前提供商、回退提供商,以及提供商配置状态。 - `tts.providers` 返回可见的 TTS 提供商清单。 - `tts.enable` 和 `tts.disable` 切换 TTS 偏好设置状态。 - `tts.setProvider` 更新首选 TTS 提供商。 @@ -330,61 +330,61 @@ Gateway 网关将这些视为**声明**,并执行服务器端允许列表。 - - `secrets.reload` 重新解析活动 SecretRefs,并且只有在完全成功时才交换运行时密钥状态。 - - `secrets.resolve` 为特定命令/目标集合解析面向命令目标的密钥分配。 + - `secrets.reload` 重新解析活动 SecretRefs,并且仅在完全成功时替换运行时密钥状态。 + - `secrets.resolve` 解析特定命令/目标集合的命令目标密钥分配。 - `config.get` 返回当前配置快照和哈希。 - `config.set` 写入经过验证的配置载荷。 - `config.patch` 合并部分配置更新。 - - `config.apply` 验证 + 替换完整配置载荷。 - - `config.schema` 返回 Control UI 和 CLI 工具使用的实时配置 schema 载荷:schema、`uiHints`、版本和生成元数据,包括运行时能够加载时的插件 + 渠道 schema 元数据。该 schema 包含字段 `title` / `description` 元数据,这些元数据来自 UI 使用的相同标签和帮助文本;当存在匹配的字段文档时,也包括嵌套对象、通配符、数组项,以及 `anyOf` / `oneOf` / `allOf` 组合分支。 - - `config.schema.lookup` 为一个配置路径返回路径范围限定的查找载荷:规范化路径、浅层 schema 节点、匹配的提示 + `hintPath`,以及用于 UI/CLI 下钻的直接子项摘要。查找 schema 节点保留面向用户的文档和常见验证字段(`title`、`description`、`type`、`enum`、`const`、`format`、`pattern`、数字/字符串/数组/对象边界,以及 `additionalProperties`、`deprecated`、`readOnly`、`writeOnly` 等标志)。子项摘要暴露 `key`、规范化后的 `path`、`type`、`required`、`hasChildren`,以及匹配的 `hint` / `hintPath`。 - - `update.run` 运行 Gateway 网关更新流程,并且仅当更新本身成功时才安排重启。 - - `update.status` 返回最新缓存的更新重启哨兵,包括可用时的重启后运行版本。 + - `config.apply` 验证并替换完整配置载荷。 + - `config.schema` 返回 Control UI 和 CLI 工具使用的实时配置 schema 载荷:schema、`uiHints`、版本和生成元数据;当运行时可以加载插件 + 渠道 schema 元数据时,也会包含这些元数据。该 schema 包含字段 `title` / `description` 元数据,这些元数据派生自 UI 使用的相同标签和帮助文本;当存在匹配的字段文档时,也包含嵌套对象、通配符、数组项,以及 `anyOf` / `oneOf` / `allOf` 组合分支。 + - `config.schema.lookup` 为一个配置路径返回路径范围的查找载荷:规范化路径、浅层 schema 节点、匹配的提示 + `hintPath`,以及供 UI/CLI 下钻使用的直接子项摘要。查找 schema 节点会保留面向用户的文档和常见验证字段(`title`、`description`、`type`、`enum`、`const`、`format`、`pattern`、数字/字符串/数组/对象边界,以及 `additionalProperties`、`deprecated`、`readOnly`、`writeOnly` 等标志)。子项摘要会公开 `key`、规范化后的 `path`、`type`、`required`、`hasChildren`,以及匹配的 `hint` / `hintPath`。 + - `update.run` 运行 Gateway 网关更新流程,并且仅在更新本身成功时安排重启。 + - `update.status` 返回最新缓存的更新重启哨兵;可用时包括重启后的运行版本。 - `wizard.start`、`wizard.next`、`wizard.status` 和 `wizard.cancel` 通过 WS RPC 暴露新手引导向导。 - `agents.list` 返回已配置的智能体条目,包括生效模型和运行时元数据。 - - `agents.create`、`agents.update` 和 `agents.delete` 管理智能体记录和工作区连线。 + - `agents.create`、`agents.update` 和 `agents.delete` 管理智能体记录和工作区接线。 - `agents.files.list`、`agents.files.get` 和 `agents.files.set` 管理为智能体暴露的引导工作区文件。 - - `agent.identity.get` 返回智能体或会话的生效助手身份。 + - `agent.identity.get` 返回某个智能体或会话的生效助手身份。 - `agent.wait` 等待运行完成,并在可用时返回终态快照。 - - `sessions.list` 返回当前会话索引;当配置了 Agent Runtimes 后端时,每一行都包含 `agentRuntime` 元数据。 + - `sessions.list` 返回当前会话索引;当配置了智能体运行时后端时,包括每行的 `agentRuntime` 元数据。 - `sessions.subscribe` 和 `sessions.unsubscribe` 为当前 WS 客户端切换会话变更事件订阅。 - `sessions.messages.subscribe` 和 `sessions.messages.unsubscribe` 为一个会话切换转录/消息事件订阅。 - `sessions.preview` 返回特定会话键的有界转录预览。 - `sessions.resolve` 解析或规范化会话目标。 - `sessions.create` 创建新的会话条目。 - `sessions.send` 向现有会话发送消息。 - - `sessions.steer` 是用于活动会话的中断并引导变体。 - - `sessions.abort` 中止会话的活动工作。 + - `sessions.steer` 是活动会话的中断并引导变体。 + - `sessions.abort` 中止某个会话的活动工作。调用方可以传入 `key` 加可选的 `runId`,也可以仅为 Gateway 网关能解析到会话的活动运行传入 `runId`。 - `sessions.patch` 更新会话元数据/覆盖项,并报告解析后的规范模型以及生效的 `agentRuntime`。 - `sessions.reset`、`sessions.delete` 和 `sessions.compact` 执行会话维护。 - - `sessions.get` 返回完整存储的会话行。 - - 聊天执行仍使用 `chat.history`、`chat.send`、`chat.abort` 和 `chat.inject`。`chat.history` 会为 UI 客户端做显示规范化:从可见文本中移除内联指令标签,移除纯文本工具调用 XML 载荷(包括 `...`、`...`、`...`、`...` 和被截断的工具调用块)以及泄漏的 ASCII/全角模型控制 token,省略纯静默 token 助手行(例如精确的 `NO_REPLY` / `no_reply`),并且过大的行可以替换为占位符。 + - `sessions.get` 返回完整的已存储会话行。 + - 聊天执行仍使用 `chat.history`、`chat.send`、`chat.abort` 和 `chat.inject`。`chat.history` 会为 UI 客户端做显示规范化:从可见文本中剥离内联指令标签,剥离纯文本工具调用 XML 载荷(包括 `...`、`...`、`...`、`...` 和被截断的工具调用块)以及泄漏的 ASCII/全角模型控制 token,省略精确为 `NO_REPLY` / `no_reply` 等纯静默 token 的助手行,并且可用占位符替换过大的行。 - `device.pair.list` 返回待处理和已批准的配对设备。 - `device.pair.approve`、`device.pair.reject` 和 `device.pair.remove` 管理设备配对记录。 - - `device.token.rotate` 在已批准角色和调用方范围边界内轮换配对设备 token。 - - `device.token.revoke` 在已批准角色和调用方范围边界内撤销配对设备 token。 + - `device.token.rotate` 在其已批准角色和调用方 scope 边界内轮换配对设备 token。 + - `device.token.revoke` 在其已批准角色和调用方 scope 边界内撤销配对设备 token。 - - `node.pair.request`、`node.pair.list`、`node.pair.approve`、`node.pair.reject`、`node.pair.remove` 和 `node.pair.verify` 涵盖节点配对和引导验证。 + - `node.pair.request`、`node.pair.list`、`node.pair.approve`、`node.pair.reject`、`node.pair.remove` 和 `node.pair.verify` 覆盖节点配对和引导验证。 - `node.list` 和 `node.describe` 返回已知/已连接节点状态。 - `node.rename` 更新配对节点标签。 - `node.invoke` 将命令转发到已连接节点。 - `node.invoke.result` 返回调用请求的结果。 - - `node.event` 将节点发起的事件带回 Gateway 网关。 + - `node.event` 将节点来源事件带回 Gateway 网关。 - `node.canvas.capability.refresh` 刷新限定范围的画布能力 token。 - `node.pending.pull` 和 `node.pending.ack` 是已连接节点队列 API。 - `node.pending.enqueue` 和 `node.pending.drain` 管理离线/断开连接节点的持久待处理工作。 @@ -392,16 +392,16 @@ Gateway 网关将这些视为**声明**,并执行服务器端允许列表。 - - `exec.approval.request`、`exec.approval.get`、`exec.approval.list` 和 `exec.approval.resolve` 涵盖一次性 exec 审批请求以及待处理审批查找/重放。 - - `exec.approval.waitDecision` 等待一个待处理 exec 审批并返回最终决定(超时时返回 `null`)。 + - `exec.approval.request`、`exec.approval.get`、`exec.approval.list` 和 `exec.approval.resolve` 覆盖一次性 exec 审批请求以及待处理审批查找/重放。 + - `exec.approval.waitDecision` 等待一个待处理 exec 审批,并返回最终决策(超时时返回 `null`)。 - `exec.approvals.get` 和 `exec.approvals.set` 管理 Gateway 网关 exec 审批策略快照。 - `exec.approvals.node.get` 和 `exec.approvals.node.set` 通过节点中继命令管理节点本地 exec 审批策略。 - - `plugin.approval.request`、`plugin.approval.list`、`plugin.approval.waitDecision` 和 `plugin.approval.resolve` 涵盖插件定义的审批流程。 + - `plugin.approval.request`、`plugin.approval.list`、`plugin.approval.waitDecision` 和 `plugin.approval.resolve` 覆盖插件定义的审批流程。 - - 自动化:`wake` 安排立即或下次心跳时注入唤醒文本;`cron.list`、`cron.status`、`cron.add`、`cron.update`、`cron.remove`、`cron.run`、`cron.runs` 管理计划任务。 + - 自动化:`wake` 安排一次立即或下一次 Heartbeat 的唤醒文本注入;`cron.list`、`cron.status`、`cron.add`、`cron.update`、`cron.remove`、`cron.run`、`cron.runs` 管理定时工作。 - Skills 和工具:`commands.list`、`skills.*`、`tools.catalog`、`tools.effective`。 @@ -412,17 +412,17 @@ Gateway 网关将这些视为**声明**,并执行服务器端允许列表。 - `chat`:UI 聊天更新,例如 `chat.inject` 和其他仅转录的聊天 事件。 - `session.message` 和 `session.tool`:已订阅会话的转录/事件流更新。 -- `sessions.changed`:会话索引或元数据已变更。 +- `sessions.changed`:会话索引或元数据已更改。 - `presence`:系统在线状态快照更新。 -- `tick`:周期性 keepalive / 存活事件。 +- `tick`:周期性 keepalive / liveness 事件。 - `health`:Gateway 网关健康快照更新。 -- `heartbeat`:心跳事件流更新。 +- `heartbeat`:Heartbeat 事件流更新。 - `cron`:cron 运行/作业变更事件。 - `shutdown`:Gateway 网关关闭通知。 - `node.pair.requested` / `node.pair.resolved`:节点配对生命周期。 - `node.invoke.request`:节点调用请求广播。 - `device.pair.requested` / `device.pair.resolved`:配对设备生命周期。 -- `voicewake.changed`:唤醒词触发器配置已变更。 +- `voicewake.changed`:唤醒词触发器配置已更改。 - `exec.approval.requested` / `exec.approval.resolved`:exec 审批 生命周期。 - `plugin.approval.requested` / `plugin.approval.resolved`:插件审批 @@ -430,65 +430,73 @@ Gateway 网关将这些视为**声明**,并执行服务器端允许列表。 ### 节点辅助方法 -- 节点可以调用 `skills.bins` 来获取当前技能可执行文件列表, +- 节点可以调用 `skills.bins` 来获取当前 Skills 可执行文件列表, 用于自动允许检查。 -### 操作员辅助方法 +### 操作者辅助方法 -- 操作者可以调用 `commands.list`(`operator.read`)来获取智能体的运行时命令清单。 - - `agentId` 是可选的;省略它可读取默认智能体工作区。 - - `scope` 控制主 `name` 面向哪个表面: +- 操作者可以调用 `commands.list`(`operator.read`)来获取智能体的运行时 + 命令清单。 + - `agentId` 是可选的;省略它可读取默认 Agent 工作区。 + - `scope` 控制主 `name` 目标对应的界面: - `text` 返回不带前导 `/` 的主文本命令令牌 - - `native` 和默认的 `both` 路径会在可用时返回感知提供商的原生命令名 + - `native` 和默认的 `both` 路径在可用时返回感知提供商的原生命令名 - `textAliases` 携带精确的斜杠别名,例如 `/model` 和 `/m`。 - `nativeName` 在存在时携带感知提供商的原生命令名。 - `provider` 是可选的,只影响原生命名以及原生插件命令可用性。 - - `includeArgs=false` 会从响应中省略序列化后的参数元数据。 + - `includeArgs=false` 会从响应中省略序列化的参数元数据。 - 操作者可以调用 `tools.catalog`(`operator.read`)来获取智能体的运行时工具目录。响应包含分组工具和来源元数据: - `source`:`core` 或 `plugin` - `pluginId`:当 `source="plugin"` 时的插件所有者 - `optional`:插件工具是否为可选 -- 操作者可以调用 `tools.effective`(`operator.read`)来获取会话的运行时生效工具清单。 +- 操作者可以调用 `tools.effective`(`operator.read`)来获取会话的运行时有效工具清单。 - `sessionKey` 是必需的。 - - Gateway 网关会从服务端会话派生可信运行时上下文,而不是接受调用方提供的鉴权或递送上下文。 - - 响应限定于会话范围,并反映当前活跃对话现在可以使用的内容,包括核心、插件和渠道工具。 -- 操作者可以调用 `skills.status`(`operator.read`)来获取智能体可见的技能清单。 - - `agentId` 是可选的;省略它可读取默认智能体工作区。 - - 响应包含资格状态、缺失要求、配置检查,以及经过清理的安装选项,不会暴露原始密钥值。 -- 操作者可以调用 `skills.search` 和 `skills.detail`(`operator.read`)获取 ClawHub 发现元数据。 -- 操作者可以通过两种模式调用 `skills.install`(`operator.admin`): - - ClawHub 模式:`{ source: "clawhub", slug, version?, force? }` 会将技能文件夹安装到默认智能体工作区的 `skills/` 目录。 - - Gateway 网关安装器模式:`{ name, installId, dangerouslyForceUnsafeInstall?, timeoutMs? }` 会在 Gateway 网关主机上运行声明的 `metadata.openclaw.install` 操作。 -- 操作者可以通过两种模式调用 `skills.update`(`operator.admin`): - - ClawHub 模式会更新一个已跟踪的 slug,或默认智能体工作区中的所有已跟踪 ClawHub 安装。 - - 配置模式会修补 `skills.entries.` 值,例如 `enabled`、`apiKey` 和 `env`。 + - Gateway 网关会从服务器端会话派生可信的运行时上下文,而不是接受调用方提供的鉴权或投递上下文。 + - 响应限定于会话范围,并反映当前活跃对话此刻可使用的内容,包括核心、插件和渠道工具。 +- 操作者可以调用 `skills.status`(`operator.read`)来获取智能体的可见 + skill 清单。 + - `agentId` 是可选的;省略它可读取默认 Agent 工作区。 + - 响应包含资格、缺失要求、配置检查,以及经过清理且不会暴露原始密钥值的安装选项。 +- 操作者可以调用 `skills.search` 和 `skills.detail`(`operator.read`)来获取 + ClawHub 发现元数据。 +- 操作者可以调用 `skills.install`(`operator.admin`),支持两种模式: + - ClawHub 模式:`{ source: "clawhub", slug, version?, force? }` 会将 + skill 文件夹安装到默认 Agent 工作区的 `skills/` 目录中。 + - Gateway 网关安装器模式:`{ name, installId, dangerouslyForceUnsafeInstall?, timeoutMs? }` + 会在 Gateway 网关主机上运行声明的 `metadata.openclaw.install` 动作。 +- 操作者可以调用 `skills.update`(`operator.admin`),支持两种模式: + - ClawHub 模式会更新默认 Agent 工作区中一个已跟踪的 slug,或所有已跟踪的 ClawHub 安装。 + - 配置模式会修补 `skills.entries.` 值,例如 `enabled`、 + `apiKey` 和 `env`。 ### `models.list` 视图 -`models.list` 接受可选的 `view` 参数: +`models.list` 接受一个可选的 `view` 参数: -- 省略或 `"default"`:当前运行时行为。如果已配置 `agents.defaults.models`,响应就是允许的目录;否则响应是完整的 Gateway 网关目录。 -- `"configured"`:适合选择器大小的行为。如果已配置 `agents.defaults.models`,它仍然优先。否则响应使用显式的 `models.providers.*.models` 条目,只有在不存在已配置模型行时才回退到完整目录。 -- `"all"`:完整的 Gateway 网关目录,会绕过 `agents.defaults.models`。将它用于诊断和发现 UI,而不是普通模型选择器。 +- 省略或 `"default"`:当前运行时行为。如果配置了 `agents.defaults.models`,响应就是允许的目录;否则响应就是完整的 Gateway 网关目录。 +- `"configured"`:适合选择器大小的行为。如果配置了 `agents.defaults.models`,它仍然优先。否则响应会使用显式的 `models.providers.*.models` 条目,只有在不存在已配置模型行时才回退到完整目录。 +- `"all"`:完整 Gateway 网关目录,绕过 `agents.defaults.models`。将它用于诊断和发现 UI,而不是常规模型选择器。 -## 执行批准 +## Exec 审批 -- 当执行请求需要批准时,Gateway 网关会广播 `exec.approval.requested`。 -- 操作者客户端通过调用 `exec.approval.resolve` 来解决(需要 `operator.approvals` 作用域)。 +- 当 exec 请求需要审批时,Gateway 网关会广播 `exec.approval.requested`。 +- 操作者客户端通过调用 `exec.approval.resolve` 进行处理(需要 `operator.approvals` scope)。 - 对于 `host=node`,`exec.approval.request` 必须包含 `systemRunPlan`(规范的 `argv`/`cwd`/`rawCommand`/会话元数据)。缺少 `systemRunPlan` 的请求会被拒绝。 -- 批准后,转发的 `node.invoke system.run` 调用会复用该规范 `systemRunPlan`,作为权威的命令/cwd/会话上下文。 -- 如果调用方在准备和最终获批的 `system.run` 转发之间修改了 `command`、`rawCommand`、`cwd`、`agentId` 或 `sessionKey`,Gateway 网关会拒绝本次运行,而不是信任被修改的载荷。 +- 审批后,转发的 `node.invoke system.run` 调用会复用该规范的 + `systemRunPlan`,作为权威命令/cwd/会话上下文。 +- 如果调用方在准备和最终获批的 `system.run` 转发之间篡改 `command`、`rawCommand`、`cwd`、`agentId` 或 + `sessionKey`,Gateway 网关会拒绝运行,而不是信任被篡改的 payload。 -## 智能体递送回退 +## 智能体投递回退 -- `agent` 请求可以包含 `deliver=true` 以请求出站递送。 -- `bestEffortDeliver=false` 保持严格行为:无法解析或仅限内部的递送目标会返回 `INVALID_REQUEST`。 -- `bestEffortDeliver=true` 允许在无法解析外部可递送路由时回退到仅会话执行(例如内部/webchat 会话,或存在歧义的多渠道配置)。 +- `agent` 请求可以包含 `deliver=true` 来请求出站投递。 +- `bestEffortDeliver=false` 保持严格行为:无法解析或仅限内部的投递目标会返回 `INVALID_REQUEST`。 +- `bestEffortDeliver=true` 允许在无法解析外部可投递路由时回退到仅会话执行(例如内部/webchat 会话或有歧义的多渠道配置)。 ## 版本控制 - `PROTOCOL_VERSION` 位于 `src/gateway/protocol/schema/protocol-schemas.ts`。 -- 客户端发送 `minProtocol` + `maxProtocol`;服务端会拒绝不匹配。 +- 客户端发送 `minProtocol` + `maxProtocol`;服务器会拒绝不匹配项。 - Schema + 模型由 TypeBox 定义生成: - `pnpm protocol:gen` - `pnpm protocol:gen:swift` @@ -496,99 +504,107 @@ Gateway 网关将这些视为**声明**,并执行服务器端允许列表。 ### 客户端常量 -`src/gateway/client.ts` 中的参考客户端使用这些默认值。这些值在协议 v3 中保持稳定,是第三方客户端的预期基线。 +`src/gateway/client.ts` 中的参考客户端使用这些默认值。值在协议 v3 中保持稳定,并且是第三方客户端的预期基线。 | 常量 | 默认值 | 来源 | | ----------------------------------------- | ----------------------------------------------------- | ------------------------------------------------------------------------------------------ | | `PROTOCOL_VERSION` | `3` | `src/gateway/protocol/schema/protocol-schemas.ts` | | 请求超时(每个 RPC) | `30_000` ms | `src/gateway/client.ts`(`requestTimeoutMs`) | -| 预鉴权/连接挑战超时 | `15_000` ms | `src/gateway/handshake-timeouts.ts`(配置/env 可以提高配对的服务端/客户端预算) | +| 预鉴权 / connect-challenge 超时 | `15_000` ms | `src/gateway/handshake-timeouts.ts`(配置/环境变量可以提高配对的服务器/客户端预算) | | 初始重连退避 | `1_000` ms | `src/gateway/client.ts`(`backoffMs`) | | 最大重连退避 | `30_000` ms | `src/gateway/client.ts`(`scheduleReconnect`) | -| 设备令牌关闭后的快速重试钳制 | `250` ms | `src/gateway/client.ts` | -| `terminate()` 前的强制停止宽限 | `250` ms | `FORCE_STOP_TERMINATE_GRACE_MS` | +| device-token 关闭后的快速重试限制 | `250` ms | `src/gateway/client.ts` | +| `terminate()` 前的强制停止宽限时间 | `250` ms | `FORCE_STOP_TERMINATE_GRACE_MS` | | `stopAndWait()` 默认超时 | `1_000` ms | `STOP_AND_WAIT_TIMEOUT_MS` | | 默认 tick 间隔(`hello-ok` 前) | `30_000` ms | `src/gateway/client.ts` | -| tick 超时关闭 | 静默超过 `tickIntervalMs * 2` 时使用代码 `4000` | `src/gateway/client.ts` | +| Tick 超时关闭 | 静默超过 `tickIntervalMs * 2` 时使用 code `4000` | `src/gateway/client.ts` | | `MAX_PAYLOAD_BYTES` | `25 * 1024 * 1024`(25 MB) | `src/gateway/server-constants.ts` | -服务端会在 `hello-ok` 中公布生效的 `policy.tickIntervalMs`、`policy.maxPayload` 和 `policy.maxBufferedBytes`;客户端应遵循这些值,而不是握手前的默认值。 +服务器会在 `hello-ok` 中通告有效的 `policy.tickIntervalMs`、`policy.maxPayload` +和 `policy.maxBufferedBytes`;客户端应遵守这些值,而不是握手前的默认值。 ## 鉴权 -- 共享密钥 Gateway 网关鉴权使用 `connect.params.auth.token` 或 `connect.params.auth.password`,具体取决于配置的鉴权模式。 -- 带身份的模式,例如 Tailscale Serve(`gateway.auth.allowTailscale: true`)或非 loopback 的 `gateway.auth.mode: "trusted-proxy"`,会通过请求标头满足连接鉴权检查,而不是使用 `connect.params.auth.*`。 -- 私有入口 `gateway.auth.mode: "none"` 会完全跳过共享密钥连接鉴权;不要在公共/不可信入口上暴露该模式。 -- 配对后,Gateway 网关会签发限定于连接角色 + 作用域的**设备令牌**。它会在 `hello-ok.auth.deviceToken` 中返回,客户端应持久化它以供未来连接使用。 +- 共享密钥 Gateway 网关鉴权会使用 `connect.params.auth.token` 或 + `connect.params.auth.password`,具体取决于已配置的鉴权模式。 +- 携带身份的模式(例如 Tailscale Serve + (`gateway.auth.allowTailscale: true`)或非 loopback 的 + `gateway.auth.mode: "trusted-proxy"`)会通过请求头满足连接鉴权检查,而不是通过 `connect.params.auth.*`。 +- 私有入口 `gateway.auth.mode: "none"` 会完全跳过共享密钥连接鉴权;不要在公开/不可信入口上暴露该模式。 +- 配对后,Gateway 网关会签发一个限定于连接 + role + scope 的**设备令牌**。它会在 `hello-ok.auth.deviceToken` 中返回,客户端应持久化它以供后续连接使用。 - 客户端应在任何成功连接后持久化主 `hello-ok.auth.deviceToken`。 -- 使用该**已存储**设备令牌重连时,也应复用为该令牌存储的已批准作用域集。这会保留已授予的读取/探测/status 访问权限,并避免将重连静默压缩为更窄的隐式仅管理员作用域。 +- 使用该**已存储**设备令牌重新连接时,也应复用为该令牌存储的已批准 scope 集。这会保留已经授予的读取/探测/Status 访问权限,并避免重连时静默收窄为隐式的仅管理员 scope。 - 客户端侧连接鉴权组装(`src/gateway/client.ts` 中的 `selectConnectAuth`): - - `auth.password` 是正交的,设置后始终会被转发。 - - `auth.token` 按优先级填充:首先是显式共享令牌,然后是显式 `deviceToken`,再是已存储的按设备令牌(由 `deviceId` + `role` 作为键)。 - - `auth.bootstrapToken` 仅在上述都未解析出 `auth.token` 时发送。共享令牌或任何已解析设备令牌都会抑制它。 - - 在一次性 `AUTH_TOKEN_MISMATCH` 重试中自动提升已存储设备令牌,仅限于**可信端点**:loopback,或带有固定 `tlsFingerprint` 的 `wss://`。未固定的公共 `wss://` 不符合条件。 -- 额外的 `hello-ok.auth.deviceTokens` 条目是 bootstrap 移交令牌。只有当连接在可信传输上使用 bootstrap 鉴权时才持久化它们,例如 `wss://` 或 loopback/local 配对。 -- 如果客户端提供**显式** `deviceToken` 或显式 `scopes`,则调用方请求的作用域集保持权威;只有当客户端复用已存储的按设备令牌时,才会复用缓存作用域。 -- 设备令牌可以通过 `device.token.rotate` 和 `device.token.revoke` 轮换/撤销(需要 `operator.pairing` 作用域)。 -- `device.token.rotate` 返回轮换元数据。它只会为已经使用该设备令牌鉴权的同设备调用回显替换 bearer 令牌,因此仅令牌客户端可以在重连前持久化它们的替换令牌。共享/管理员轮换不会回显 bearer 令牌。 -- 令牌签发、轮换和撤销始终限定在该设备配对条目中记录的已批准角色集内;令牌变更无法扩展到或面向配对批准从未授予的设备角色。 -- 对于已配对设备令牌会话,设备管理默认限定于自身,除非调用方同时拥有 `operator.admin`:非管理员调用方只能移除/撤销/轮换其**自己的**设备条目。 -- `device.token.rotate` 和 `device.token.revoke` 还会根据调用方当前会话作用域检查目标操作者令牌作用域集。非管理员调用方不能轮换或撤销比自己已持有范围更广的操作者令牌。 + - `auth.password` 是正交的,只要设置就始终会转发。 + - `auth.token` 按优先级填充:首先是显式共享令牌,然后是显式 `deviceToken`,然后是已存储的每设备令牌(按 `deviceId` + `role` 作为键)。 + - 只有当上述内容都未解析出 `auth.token` 时,才会发送 `auth.bootstrapToken`。共享令牌或任何已解析设备令牌都会抑制它。 + - 在一次性的 `AUTH_TOKEN_MISMATCH` 重试中,已存储设备令牌的自动提升仅限于**可信端点**—— + loopback,或带有固定 `tlsFingerprint` 的 `wss://`。未固定的公开 `wss://` + 不符合条件。 +- 额外的 `hello-ok.auth.deviceTokens` 条目是 bootstrap 交接令牌。只有在连接使用了 bootstrap 鉴权,且传输是可信传输(例如 `wss://` 或 loopback/本地配对)时,才持久化它们。 +- 如果客户端提供**显式** `deviceToken` 或显式 `scopes`,该调用方请求的 scope 集仍然是权威的;只有当客户端复用已存储的每设备令牌时,才会复用缓存的 scope。 +- 设备令牌可以通过 `device.token.rotate` 和 + `device.token.revoke` 轮换/吊销(需要 `operator.pairing` scope)。 +- `device.token.rotate` 返回轮换元数据。它只会在已经使用该设备令牌鉴权的同设备调用中回显替换后的 bearer token,以便仅使用令牌的客户端能在重连前持久化替换令牌。共享/管理员轮换不会回显 bearer token。 +- 令牌签发、轮换和吊销始终受限于记录在该设备配对条目中的已批准 role 集;令牌变更不能扩展或指定配对审批从未授予的设备 role。 +- 对于已配对设备令牌会话,设备管理是自限定范围的,除非调用方同时具有 `operator.admin`:非管理员调用方只能移除/吊销/轮换它们**自己**的设备条目。 +- `device.token.rotate` 和 `device.token.revoke` 还会根据调用方当前会话 scope 检查目标操作者令牌 scope 集。非管理员调用方不能轮换或吊销比自己已持有权限更宽的操作者令牌。 - 鉴权失败包含 `error.details.code` 以及恢复提示: - `error.details.canRetryWithDeviceToken`(布尔值) - `error.details.recommendedNextStep`(`retry_with_device_token`、`update_auth_configuration`、`update_auth_credentials`、`wait_then_retry`、`review_auth_configuration`) -- 客户端对 `AUTH_TOKEN_MISMATCH` 的行为: - - 可信客户端可以尝试一次有界重试,使用缓存的按设备令牌。 - - 如果该重试失败,客户端应停止自动重连循环,并向操作者显示操作指导。 +- `AUTH_TOKEN_MISMATCH` 的客户端行为: + - 可信客户端可以尝试使用缓存的每设备令牌进行一次有界重试。 + - 如果该重试失败,客户端应停止自动重连循环,并呈现操作者操作指引。 ## 设备身份 + 配对 - 节点应包含稳定的设备身份(`device.id`),该身份派生自密钥对指纹。 -- Gateway 网关按设备 + 角色颁发令牌。 -- 新设备 ID 需要配对批准,除非启用了本地自动批准。 +- Gateway 网关按设备 + 角色签发令牌。 +- 新设备 ID 需要配对批准,除非已启用本地自动批准。 - 配对自动批准以直接 local loopback 连接为中心。 -- OpenClaw 还为受信任的共享密钥辅助流程提供一条狭窄的后端/容器本地自连接路径。 -- 同主机的 tailnet 或 LAN 连接在配对时仍被视为远程连接,并且需要批准。 -- WS 客户端通常会在 `connect` 期间包含 `device` 身份(操作者 + 节点)。唯一不带设备的操作者例外是显式信任路径: +- OpenClaw 还为受信任的共享密钥辅助流程提供了一个狭窄的后端/容器本地自连接路径。 +- 同主机 tailnet 或 LAN 连接在配对时仍会被视为远程连接,并且需要批准。 +- WS 客户端通常会在 `connect` 期间包含 `device` 身份(操作员 + 节点)。唯一允许无设备操作员的例外是显式信任路径: - `gateway.controlUi.allowInsecureAuth=true`,用于仅限 localhost 的不安全 HTTP 兼容性。 - - 成功的 `gateway.auth.mode: "trusted-proxy"` 操作者 Control UI 身份验证。 - - `gateway.controlUi.dangerouslyDisableDeviceAuth=true`(紧急破例,严重降低安全性)。 - - 直接 loopback 的 `gateway-client` 后端 RPC,使用共享的 Gateway 网关令牌/密码进行身份验证。 -- 所有连接都必须签名服务器提供的 `connect.challenge` nonce。 + - 成功的 `gateway.auth.mode: "trusted-proxy"` 操作员 Control UI 认证。 + - `gateway.controlUi.dangerouslyDisableDeviceAuth=true`(应急开关,严重降低安全性)。 + - 使用共享 Gateway 网关令牌/密码认证的直接 loopback `gateway-client` 后端 RPC。 +- 所有连接都必须签署服务器提供的 `connect.challenge` nonce。 -### 设备身份验证迁移诊断 +### 设备认证迁移诊断 -对于仍使用挑战前签名行为的旧版客户端,`connect` 现在会在 `error.details.code` 下返回 `DEVICE_AUTH_*` 详情代码,并带有稳定的 `error.details.reason`。 +对于仍使用挑战前签名行为的旧客户端,`connect` 现在会在 `error.details.code` 下返回 `DEVICE_AUTH_*` 详情代码,并提供稳定的 `error.details.reason`。 常见迁移失败: | 消息 | details.code | details.reason | 含义 | | --------------------------- | -------------------------------- | ------------------------ | -------------------------------------------------- | -| `device nonce required` | `DEVICE_AUTH_NONCE_REQUIRED` | `device-nonce-missing` | 客户端省略了 `device.nonce`(或发送了空值)。 | -| `device nonce mismatch` | `DEVICE_AUTH_NONCE_MISMATCH` | `device-nonce-mismatch` | 客户端使用过期/错误的 nonce 进行了签名。 | -| `device signature invalid` | `DEVICE_AUTH_SIGNATURE_INVALID` | `device-signature` | 签名载荷与 v2 载荷不匹配。 | -| `device signature expired` | `DEVICE_AUTH_SIGNATURE_EXPIRED` | `device-signature-stale` | 签名时间戳超出允许的偏差范围。 | -| `device identity mismatch` | `DEVICE_AUTH_DEVICE_ID_MISMATCH` | `device-id-mismatch` | `device.id` 与公钥指纹不匹配。 | -| `device public key invalid` | `DEVICE_AUTH_PUBLIC_KEY_INVALID` | `device-public-key` | 公钥格式/规范化失败。 | +| `device nonce required` | `DEVICE_AUTH_NONCE_REQUIRED` | `device-nonce-missing` | 客户端省略了 `device.nonce`(或发送为空)。 | +| `device nonce mismatch` | `DEVICE_AUTH_NONCE_MISMATCH` | `device-nonce-mismatch` | 客户端使用过期/错误的 nonce 进行了签名。 | +| `device signature invalid` | `DEVICE_AUTH_SIGNATURE_INVALID` | `device-signature` | 签名载荷与 v2 载荷不匹配。 | +| `device signature expired` | `DEVICE_AUTH_SIGNATURE_EXPIRED` | `device-signature-stale` | 已签名时间戳超出允许偏差。 | +| `device identity mismatch` | `DEVICE_AUTH_DEVICE_ID_MISMATCH` | `device-id-mismatch` | `device.id` 与公钥指纹不匹配。 | +| `device public key invalid` | `DEVICE_AUTH_PUBLIC_KEY_INVALID` | `device-public-key` | 公钥格式/规范化失败。 | 迁移目标: - 始终等待 `connect.challenge`。 -- 签名包含服务器 nonce 的 v2 载荷。 +- 签署包含服务器 nonce 的 v2 载荷。 - 在 `connect.params.device.nonce` 中发送相同的 nonce。 -- 首选签名载荷是 `v3`,它除了设备/客户端/角色/范围/令牌/nonce 字段外,还绑定 `platform` 和 `deviceFamily`。 -- 为了兼容性,仍接受旧版 `v2` 签名,但配对设备元数据固定仍会控制重新连接时的命令策略。 +- 首选签名载荷是 `v3`,它除了设备/客户端/角色/作用域/令牌/nonce 字段外,还绑定 `platform` 和 `deviceFamily`。 +- 为兼容性仍接受旧版 `v2` 签名,但已配对设备的元数据固定仍会在重连时控制命令策略。 -## TLS + 证书固定 +## TLS + 固定 - WS 连接支持 TLS。 -- 客户端可以选择固定 Gateway 网关证书指纹(参见 `gateway.tls` 配置以及 `gateway.remote.tlsFingerprint` 或 CLI `--tls-fingerprint`)。 +- 客户端可以选择固定 Gateway 网关证书指纹(请参阅 `gateway.tls` 配置,以及 `gateway.remote.tlsFingerprint` 或 CLI `--tls-fingerprint`)。 ## 范围 -此协议暴露**完整的 Gateway 网关 API**(Status、渠道、模型、聊天、智能体、会话、节点、批准等)。确切的表面由 `src/gateway/protocol/schema.ts` 中的 TypeBox schema 定义。 +此协议暴露**完整 Gateway 网关 API**(Status、渠道、模型、聊天、智能体、会话、节点、批准等)。确切范围由 `src/gateway/protocol/schema.ts` 中的 TypeBox schema 定义。 ## 相关 -- [Bridge protocol](/zh-CN/gateway/bridge-protocol) +- [桥接协议](/zh-CN/gateway/bridge-protocol) - [Gateway 网关运行手册](/zh-CN/gateway) diff --git a/docs/zh-CN/reference/openclaw-sdk-api-design.md b/docs/zh-CN/reference/openclaw-sdk-api-design.md new file mode 100644 index 000000000..87f4252ea --- /dev/null +++ b/docs/zh-CN/reference/openclaw-sdk-api-design.md @@ -0,0 +1,370 @@ +--- +read_when: + - 你正在实现拟议的公开 OpenClaw 应用 SDK + - 如果你需要应用 SDK 的草案命名空间、事件、结果、工件、审批或安全契约 + - 你正在将 Gateway 网关协议资源与高级 OpenClaw SDK 包装器进行比较 +summary: 拟议的公开 OpenClaw 应用 SDK API、事件分类体系、工件、审批和包结构参考设计 +title: OpenClaw SDK API 设计 +x-i18n: + generated_at: "2026-04-29T23:55:20Z" + model: gpt-5.5 + provider: openai + source_hash: c4dd0123581f4ba8332b6af9c673467092082a16488a61b5cbeac1b33e9a5dd1 + source_path: reference/openclaw-sdk-api-design.md + workflow: 16 +--- + +本页是拟议公开 [OpenClaw SDK](/zh-CN/concepts/openclaw-sdk) 的详细 API 参考设计。它有意与[插件 SDK](/zh-CN/plugins/sdk-overview) 分开。 + +公开应用 SDK 应该分为两层构建: + +1. 一个低层生成式 Gateway 网关客户端。 +2. 一个高层易用封装,包含 `OpenClaw`、`Agent`、`Session`、`Run`、 + `Task`、`Artifact`、`Approval` 和 `Environment` 对象。 + +## 命名空间设计 + +低层命名空间应紧密对应 Gateway 网关资源: + +```typescript +oc.agents.list(); +oc.agents.get("main"); +oc.agents.create(...); +oc.agents.update(...); + +oc.sessions.list(); +oc.sessions.create(...); +oc.sessions.resolve(...); +oc.sessions.send(...); +oc.sessions.messages(...); +oc.sessions.fork(...); +oc.sessions.compact(...); +oc.sessions.abort(...); + +oc.runs.create(...); +oc.runs.get(runId); +oc.runs.events(runId, { after }); +oc.runs.wait(runId); +oc.runs.cancel(runId); + +oc.tasks.list(); // future API: current SDK throws unsupported +oc.tasks.get(taskId); // future API: current SDK throws unsupported +oc.tasks.cancel(taskId); // future API: current SDK throws unsupported +oc.tasks.events(taskId, { after }); // future API + +oc.models.list(); +oc.models.status(); // Gateway models.authStatus + +oc.tools.list(); +oc.tools.invoke(...); // future API: current SDK throws unsupported + +oc.artifacts.list({ runId }); // future API: current SDK throws unsupported +oc.artifacts.get(artifactId); // future API: current SDK throws unsupported +oc.artifacts.download(artifactId); // future API: current SDK throws unsupported + +oc.approvals.list(); +oc.approvals.respond(approvalId, ...); + +oc.environments.list(); // future API: current SDK throws unsupported +oc.environments.create(...); // future API: current SDK throws unsupported +oc.environments.status(environmentId); // future API: current SDK throws unsupported +oc.environments.delete(environmentId); // future API: current SDK throws unsupported +``` + +高层封装应返回能让常见流程更顺手的对象: + +```typescript +const run = await agent.run(inputOrParams); +await run.cancel(); +await run.wait(); + +for await (const event of run.events()) { + // normalized event stream +} + +const artifacts = await run.artifacts.list(); +const session = await run.session(); +``` + +## 事件契约 + +公开 SDK 应暴露带版本、可重放、规范化的事件。 + +```typescript +type OpenClawEvent = { + version: 1; + id: string; + ts: number; + type: OpenClawEventType; + runId?: string; + sessionId?: string; + sessionKey?: string; + taskId?: string; + agentId?: string; + data: unknown; + raw?: unknown; +}; +``` + +`id` 是重放游标。消费者应能够通过 `events({ after: id })` 重新连接,并在保留策略允许时接收错过的事件。 + +推荐的规范化事件族: + +| 事件 | 含义 | +| --------------------- | ----------------------------------------------------------- | +| `run.created` | 运行已接受。 | +| `run.queued` | 运行正在等待会话通道、运行时或环境。 | +| `run.started` | 运行时已开始执行。 | +| `run.completed` | 运行已成功完成。 | +| `run.failed` | 运行因错误结束。 | +| `run.cancelled` | 运行已取消。 | +| `run.timed_out` | 运行超出了其超时时间。 | +| `assistant.delta` | 助手文本增量。 | +| `assistant.message` | 完整助手消息或替换内容。 | +| `thinking.delta` | 在策略允许暴露时的推理或计划增量。 | +| `tool.call.started` | 工具调用已开始。 | +| `tool.call.delta` | 工具调用流式传输了进度或部分输出。 | +| `tool.call.completed` | 工具调用已成功返回。 | +| `tool.call.failed` | 工具调用失败。 | +| `approval.requested` | 某个运行或工具需要批准。 | +| `approval.resolved` | 批准已被授予、拒绝、过期或取消。 | +| `question.requested` | 运行时向用户或宿主应用请求输入。 | +| `question.answered` | 宿主应用已提供答案。 | +| `artifact.created` | 新工件可用。 | +| `artifact.updated` | 现有工件已更改。 | +| `session.created` | 会话已创建。 | +| `session.updated` | 会话元数据已更改。 | +| `session.compacted` | 会话压缩已发生。 | +| `task.updated` | 后台任务状态已更改。 | +| `git.branch` | 运行时观察到或更改了分支状态。 | +| `git.diff` | 运行时产生或更改了 diff。 | +| `git.pr` | 运行时打开、更新或关联了拉取请求。 | + +运行时原生载荷应可通过 `raw` 获取,但应用在普通 UI 中不应需要解析 `raw`。 + +## 结果契约 + +`Run.wait()` 应返回稳定的结果信封: + +```typescript +type RunResult = { + runId: string; + status: "accepted" | "completed" | "failed" | "cancelled" | "timed_out"; + sessionId?: string; + sessionKey?: string; + taskId?: string; + startedAt?: string | number; + endedAt?: string | number; + output?: { + text?: string; + messages?: SDKMessage[]; + }; + usage?: { + inputTokens?: number; + outputTokens?: number; + totalTokens?: number; + costUsd?: number; + }; + artifacts?: ArtifactSummary[]; + error?: SDKError; +}; +``` + +结果应朴素且稳定。时间戳值保留 Gateway 网关形状,因此当前由生命周期支持的运行通常报告 epoch 毫秒数,而适配器仍可能暴露 ISO 字符串。富 UI、工具轨迹和运行时原生细节应放在事件和工件中。 + +`accepted` 是非终态等待结果:它表示 Gateway 网关等待截止时间在运行产生生命周期结束/错误之前已到期。不得将其视为 `timed_out`;`timed_out` 专用于超出自身运行时超时时间的运行。 + +## 批准和问题 + +批准必须是一等概念,因为编码智能体会不断跨越安全边界。 + +```typescript +run.onApproval(async (request) => { + if (request.kind === "tool" && request.toolName === "exec") { + return request.approveOnce({ reason: "CI command allowed by policy" }); + } + + return request.askUser(); +}); +``` + +批准事件应携带: + +- 批准 id +- 运行 id 和会话 id +- 请求类型 +- 请求动作摘要 +- 工具名称或环境动作 +- 风险级别 +- 可用决策 +- 过期时间 +- 决策是否可复用 + +问题与批准是分开的。问题向用户或宿主应用询问信息。批准请求执行某个动作的权限。 + +## ToolSpace 模型 + +应用需要在不导入插件内部机制的情况下理解工具表面。 + +```typescript +const tools = await run.toolSpace(); + +for (const tool of tools.list()) { + console.log(tool.name, tool.source, tool.requiresApproval); +} +``` + +SDK 应暴露: + +- 规范化工具元数据 +- 来源:OpenClaw、MCP、插件、渠道、运行时或应用 +- 架构摘要 +- 批准策略 +- 运行时兼容性 +- 工具是否隐藏、只读、可写或可由宿主调用 + +通过 SDK 调用工具应是显式且有作用域的。大多数应用应运行智能体,而不是直接调用任意工具。 + +## 工件模型 + +工件应覆盖不只是文件。 + +```typescript +type ArtifactSummary = { + id: string; + runId?: string; + sessionId?: string; + type: + | "file" + | "patch" + | "diff" + | "log" + | "media" + | "screenshot" + | "trajectory" + | "pull_request" + | "workspace"; + title?: string; + mimeType?: string; + sizeBytes?: number; + createdAt: string; + expiresAt?: string; +}; +``` + +常见示例: + +- 文件编辑和生成的文件 +- patch 包 +- VCS diff +- 截图和媒体输出 +- 日志和跟踪包 +- 拉取请求链接 +- 运行时轨迹 +- 托管环境工作区快照 + +工件访问应支持脱敏、保留策略和下载 URL,而不假定每个工件都是普通本地文件。 + +## 安全模型 + +应用 SDK 必须明确权限。 + +推荐的令牌作用域: + +| 作用域 | 允许的操作 | +| ------------------- | ----------------------------------------------------- | +| `agent.read` | 列出并检查智能体。 | +| `agent.run` | 启动运行。 | +| `session.read` | 读取会话元数据和消息。 | +| `session.write` | 创建会话、向会话发送内容、分叉、压缩和中止会话。 | +| `task.read` | 读取后台任务状态。 | +| `task.write` | 取消或修改任务通知策略。 | +| `approval.respond` | 批准或拒绝请求。 | +| `tools.invoke` | 直接调用已暴露的工具。 | +| `artifacts.read` | 列出并下载工件。 | +| `environment.write` | 创建或销毁托管环境。 | +| `admin` | 管理操作。 | + +默认值: + +- 默认不转发密钥 +- 不允许不受限制的环境变量透传 +- 使用密钥引用而不是密钥值 +- 显式沙箱和网络策略 +- 显式远程环境保留策略 +- 宿主执行需要批准,除非策略证明可以例外 +- 原始运行时事件在离开 Gateway 网关之前会被脱敏,除非调用方拥有更强的诊断作用域 + +## 托管环境提供商 + +托管智能体应实现为环境提供商。 + +```typescript +type EnvironmentProvider = { + id: string; + capabilities: { + checkout?: boolean; + sandbox?: boolean; + networkPolicy?: boolean; + secrets?: boolean; + artifacts?: boolean; + logs?: boolean; + pullRequests?: boolean; + longRunning?: boolean; + }; +}; +``` + +第一个实现不需要是托管 SaaS。它可以面向现有节点主机、临时工作区、CI 风格的运行器或 Testbox 风格的环境。重要契约是: + +1. 准备工作区 +2. 绑定安全环境和密钥 +3. 启动运行 +4. 流式传输事件 +5. 收集工件 +6. 按策略清理或保留 + +一旦这部分稳定,托管云服务就可以实现同一个提供商契约。 + +## 包结构 + +推荐的包: + +| 包 | 用途 | +| ----------------------- | ------------------------------------------------------------- | +| `@openclaw/sdk` | 公开高层 SDK 和生成式低层 Gateway 网关客户端。 | +| `@openclaw/sdk-react` | 用于仪表盘和应用构建者的可选 React hooks。 | +| `@openclaw/sdk-testing` | 用于应用集成的测试辅助工具和伪 Gateway 网关服务器。 | + +仓库已经为插件提供 `openclaw/plugin-sdk/*`。保持该命名空间分离,以避免插件作者和应用开发者混淆。 + +## 生成式客户端策略 + +低层客户端应从带版本的 Gateway 网关协议架构生成,然后由手写的易用类进行封装。 + +分层: + +1. Gateway 网关模式的事实来源。 +2. 生成的底层 TypeScript 客户端。 +3. 用于外部输入和事件载荷的运行时验证器。 +4. 高层 `OpenClaw`、`Agent`、`Session`、`Run`、`Task` 和 `Artifact` + 封装器。 +5. 手册示例和集成测试。 + +优点: + +- 协议漂移清晰可见 +- 测试可以将生成的方法与 Gateway 网关导出进行比较 +- 应用 SDK 保持独立于插件 SDK 内部机制 +- 底层消费者仍可完整访问协议 +- 高层消费者获得小型产品 API + +## 相关文档 + +- [OpenClaw SDK 设计](/zh-CN/concepts/openclaw-sdk) +- [Gateway 网关 RPC 参考](/zh-CN/reference/rpc) +- [Agent loop](/zh-CN/concepts/agent-loop) +- [Agent Runtimes](/zh-CN/concepts/agent-runtimes) +- [后台任务](/zh-CN/automation/tasks) +- [ACP 智能体](/zh-CN/tools/acp-agents) +- [插件 SDK 概览](/zh-CN/plugins/sdk-overview)