Gateway(网关)Gateway(网关) 协议
Gateway(网关) WS 协议是 OpenClaw 的单一控制平面 + 节点传输。所有客户端(CLI、Web UI、macOS 应用、iOS/Android 节点、无头节点)均通过 WebSocket 连接,并在握手时声明其 role + scope。
- WebSocket,带有 JSON 载荷的文本帧。
- 第一帧必须是一个
connect请求。 - 连接前的帧上限为 64 KiB。成功握手后,客户端应遵循
hello-ok.policy.maxPayload和hello-ok.policy.maxBufferedBytes限制。如果启用了诊断功能,超大的入站帧和缓慢的出站缓冲区会在 Gateway 关闭或丢弃受影响的帧之前发出payload.large事件。这些事件包含大小、限制、表面和安全原因代码。它们不包含消息正文、附件内容、原始帧正文、令牌、Cookie 或机密值。
握手 (连接)
Section titled “握手 (连接)”Gateway(网关) 网关 → 客户端 (连接前挑战):
{ "type": "event", "event": "connect.challenge", "payload": { "nonce": "…", "ts": 1737264000000 }}客户端 → Gateway(网关) 网关:
{ "type": "req", "id": "…", "method": "connect", "params": { "minProtocol": 3, "maxProtocol": 4, "client": { "id": "cli", "version": "1.2.3", "platform": "macos", "mode": "operator" }, "role": "operator", "scopes": ["operator.read", "operator.write"], "caps": [], "commands": [], "permissions": {}, "auth": { "token": "…" }, "locale": "en-US", "userAgent": "openclaw-cli/1.2.3", "device": { "id": "device_fingerprint", "publicKey": "…", "signature": "…", "signedAt": 1737264000000, "nonce": "…" } }}Gateway(网关) 网关 → 客户端:
{ "type": "res", "id": "…", "ok": true, "payload": { "type": "hello-ok", "protocol": 4, "server": { "version": "…", "connId": "…" }, "features": { "methods": ["…"], "events": ["…"] }, "snapshot": { "…": "…" }, "auth": { "role": "operator", "scopes": ["operator.read", "operator.write"] }, "policy": { "maxPayload": 26214400, "maxBufferedBytes": 52428800, "tickIntervalMs": 15000 } }}当 Gateway(网关) 仍在完成启动 Sidecar 时,Gateway(网关)connect 请求可能会返回一个可重试的 UNAVAILABLE 错误,其中 details.reason 设置为 "startup-sidecars" 和 retryAfterMs。客户端应在其总体连接预算内重试该响应,而不是将其作为最终的握手失败呈现。
server、features、snapshot 和 policy 都是架构(src/gateway/protocol/schema/frames.ts)所必需的。auth 也是必需的,用于报告协商的角色/范围。pluginSurfaceUrls 是可选的,用于将插件表面名称(例如 canvas)映射到有作用域的托管 URL。
有作用域的插件表面 URL 可能会过期。节点可以调用 node.pluginSurface.refresh 并附带 { "surface": "canvas" },以接收 pluginSurfaceUrlsCanvas 中的新条目。实验性的 Canvas 插件重构不支持已弃用的 canvasHostUrl、canvasCapability 或 node.canvas.capability.refresh 兼容性路径;当前的本机客户端和 Gateway 必须使用插件表面。
当未颁发设备令牌时,hello-ok.auth 会报告协商的权限但不包含令牌字段:
{ "auth": { "role": "operator", "scopes": ["operator.read", "operator.write"] }}受信任的同一进程后端客户端(client.id: "gateway-client"、
client.mode: "backend")在使用共享网关令牌/密码进行身份验证时,可以在直接回环连接上省略 device。此路径保留用于内部控制平面 RPC,并防止过时的 CLI/设备配对基线阻塞本地后端工作(例如子代理会话更新)。远程客户端、浏览器源客户端、节点客户端以及显式的设备令牌/设备身份客户端仍使用正常的配对和范围升级检查。
当颁发设备令牌时,hello-ok 还包括:
{ "auth": { "deviceToken": "…", "role": "operator", "scopes": ["operator.read", "operator.write"] }}内置的 QR/设置代码引导是一个全新的移动设备交接路径。成功的 基线设置代码连接会返回一个主节点令牌加上一个有界的 操作员令牌:
{ "auth": { "deviceToken": "…", "role": "node", "scopes": [], "deviceTokens": [ { "deviceToken": "…", "role": "operator", "scopes": ["operator.approvals", "operator.read", "operator.write"] } ] }}操作员交接特意设计为有界的,以便 QR 新手引导可以在不授予 operator.admin、operator.pairing 或
operator.talk.secrets 的情况下启动移动操作员循环。这些范围需要单独的批准操作员
配对或令牌流程。客户端应仅在连接在可信传输(如 wss://)上
使用引导身份验证或环回/本地配对时才持久保存 hello-ok.auth.deviceTokens。
{ "type": "req", "id": "…", "method": "connect", "params": { "minProtocol": 3, "maxProtocol": 4, "client": { "id": "ios-node", "version": "1.2.3", "platform": "ios", "mode": "node" }, "role": "node", "scopes": [], "caps": ["camera", "canvas", "screen", "location", "voice"], "commands": ["camera.snap", "canvas.navigate", "screen.record", "location.get"], "permissions": { "camera.capture": true, "screen.record": false }, "auth": { "token": "…" }, "locale": "en-US", "userAgent": "openclaw-ios/1.2.3", "device": { "id": "device_fingerprint", "publicKey": "…", "signature": "…", "signedAt": 1737264000000, "nonce": "…" } }}- 请求:
{type:"req", id, method, params} - 响应:
{type:"res", id, ok, payload|error} - 事件:
{type:"event", event, payload, seq?, stateVersion?}
具有副作用的方法需要幂等性键(请参阅架构)。
角色 + 范围
Section titled “角色 + 范围”有关完整的操作员范围模型、批准时检查和共享密钥 语义,请参阅 操作员范围。
operator= 控制平面客户端 (CLI/UI/automation)。node= 功能主机 (camera/screen/canvas/system.run)。
范围(操作员)
Section titled “范围(操作员)”常用范围:
operator.readoperator.writeoperator.adminoperator.approvalsoperator.pairingoperator.talk.secrets
带有 includeSecrets: true 的 talk.config 需要 operator.talk.secrets
(或 operator.admin)。
插件注册的网关 RPC 方法可以请求自己的操作员范围,但
保留的核心管理前缀 (config.*, exec.approvals.*, wizard.*,
update.*) 始终解析为 operator.admin。
方法范围只是第一道关卡。通过 chat.send 访问的某些斜杠命令
会在此基础上应用更严格的命令级检查。例如,持久的
/config set 和 /config unset 写入需要 operator.admin。
node.pair.approve 在基础方法范围之上还有一个额外的批准时范围检查:
- 无命令请求:
operator.pairing - 带有非执行节点命令的请求:
operator.pairing+operator.write - 包含
system.run、system.run.prepare或system.which的请求:operator.pairing+operator.admin
能力/命令/权限(节点)
Section titled “能力/命令/权限(节点)”节点在连接时声明能力声明:
caps:高级功能类别,例如camera、canvas、screen、location、voice和talk。commands:用于调用的命令允许列表。permissions:细粒度开关(例如screen.record、camera.capture)。
Gateway Gateway(网关) 将这些视为 声明 并强制执行服务器端允许列表。
system-presence返回以设备身份为键的条目。- 存在条目包括
deviceId、roles和scopes,因此 UI 可以每个设备显示单行, 即使它同时以 operator 和 node 身份连接。 node.list包括可选的lastSeenAtMs和lastSeenReason字段。已连接的节点将其 当前连接时间报告为lastSeenAtMs,原因connect;配对节点也可以在受信任节点事件更新其配对元数据时报告持久的后台存在。
节点后台存活事件
Section titled “节点后台存活事件”节点可以使用 event: "node.presence.alive" 调用 node.event,以记录配对节点在后台唤醒期间处于活动状态,而不将其标记为已连接。
{ "event": "node.presence.alive", "payloadJSON": "{\"trigger\":\"silent_push\",\"sentAtMs\":1737264000000,\"displayName\":\"Peter's iPhone\",\"version\":\"2026.4.28\",\"platform\":\"iOS 18.4.0\",\"deviceFamily\":\"iPhone\",\"modelIdentifier\":\"iPhone17,1\",\"pushTransport\":\"relay\"}"}trigger 是一个封闭枚举:background、silent_push、bg_app_refresh、
significant_location、manual 或 connect。未知的触发字符串在持久化之前通过网关标准化为
background。该事件仅对已验证的节点设备会话持久化;无设备或未配对的会话返回 handled: false。
成功的网关返回一个结构化结果:
{ "ok": true, "event": "node.presence.alive", "handled": true, "reason": "persisted"}较旧的网关对于 node.event 可能仍会返回 { "ok": true };客户端应将其视为已确认的 RPC,而不是持久的在线状态持久化。
广播事件范围限定
Section titled “广播事件范围限定”服务器推送的 WebSocket 广播事件是按范围限定的,以便配对范围或仅节点的会话不会被动接收会话内容。
- 聊天、代理和工具结果帧(包括流式
agent事件和工具调用结果)至少需要operator.read。没有operator.read的会话将完全跳过这些帧。 - 插件定义的
plugin.*广播 根据插件注册方式的不同,被限制为operator.write或operator.admin。 - 状态和传输事件(
heartbeat、presence、tick、连接/断开连接生命周期等)保持不受限制,以便每个经过身份验证的会话都能观察到传输的健康状况。 - 未知的广播事件系列在默认情况下受范围限制(失效关闭),除非已注册的处理程序明确放宽了限制。
每个客户端连接都保留自己的每客户端序列号,因此即使不同的客户端看到的事件流具有不同的范围过滤子集,广播也能在该套接字上保持单调顺序。
常见 RPC 方法系列
Section titled “常见 RPC 方法系列”公共 WS 表面范围比上述握手/身份验证示例更广。这不是生成的转储——hello-ok.features.methods 是一个基于 src/gateway/server-methods-list.ts 加上加载的插件/渠道方法导出构建的保守发现列表。将其视为功能发现,而不是 src/gateway/server-methods/*.ts 的完整枚举。
系统和身份
health返回缓存或新探测的网关健康快照。diagnostics.stability返回最近的有界诊断稳定性记录器。它保留操作元数据,如事件名称、计数、字节大小、内存读数、队列/会话状态、渠道/插件名称和会话 ID。它不保留聊天文本、webhook 主体、工具输出、原始请求或响应主体、令牌、cookie 或秘密值。需要操作员读取范围。status返回/status风格的网关摘要;敏感字段仅包含在具有管理员范围的操作员客户端中。gateway.identity.get返回中继和配对流程使用的网关设备身份。system-presence返回连接的操作员/节点设备的当前在线状态快照。system-event追加系统事件并可以更新/广播在线状态上下文。last-heartbeat返回最新的持久化心跳事件。set-heartbeats切换网关上的心跳处理。
模型和用法
models.list返回运行时允许的模型目录。传递{ "view": "configured" }以获取选择器大小的已配置模型(agents.defaults.models优先,然后是models.providers.*.models),或传递{ "view": "all" }以获取完整目录。usage.status返回提供商使用窗口/剩余配额摘要。usage.cost返回日期范围内的汇总成本使用摘要。doctor.memory.status返回活动默认代理工作区的向量内存/缓存嵌入就绪状态。仅当调用方明确需要实时嵌入提供商 ping 时,才传递{ "probe": true }或{ "deep": true }。doctor.memory.remHarness返回面向远程控制平面客户端的、有界的只读 REM 预览。它可以包含工作区路径、内存片段、渲染的落地 markdown 和深度提升候选,因此调用方需要operator.read。sessions.usage返回每个会话的使用摘要。sessions.usage.timeseries返回单个会话的时间序列使用情况。sessions.usage.logs返回单个会话的使用日志条目。
渠道和登录助手
channels.status返回内置 + 捆绑的渠道/插件状态摘要。channels.logout登出特定的渠道/账户(在该渠道支持登出时)。web.login.start为当前支持二维码的 Web 渠道提供商启动二维码/Web 登录流程。web.login.wait等待该二维码/Web 登录流程完成,并在成功时启动该渠道。push.test向已注册的 iOS 节点发送测试 APNs 推送。voicewake.get返回存储的唤醒词触发器。voicewake.set更新唤醒词触发器并广播更改。
Messaging and logs
sendRPC 是用于在聊天运行器之外进行针对渠道/账户/线程发送的直接出站交付 RPC。logs.tail返回配置的网关文件日志尾部,并包含游标/限制和最大字节控制。
Talk and TTS
talk.catalog返回用于语音、流式转录和实时语音的只读 Talk 提供商目录。它包括提供商 ID、标签、配置状态、暴露的模型/语音 ID、规范模式、传输方式、brain 策略以及实时音频/功能标志,但不返回提供商密钥或修改全局配置。talk.config返回有效的 Talk 配置负载;includeSecrets需要operator.talk.secrets(或operator.admin)。talk.session.createGateway(网关) 为realtime/gateway-relay、transcription/gateway-relay或stt-tts/managed-room创建 Gateway 所有的 Talk 会话。对于stt-tts/managed-room,传递sessionKey的operator.write调用方还必须传递spawnedBy以实现作用域内的会话密钥可见性;无作用域的sessionKey创建和brain: "direct-tools"需要operator.admin。talk.session.join验证托管房间会话令牌,根据需要发出session.ready或session.replaced事件,并返回房间/会话元数据以及最近的 Talk 事件,但不返回明文令牌或存储的令牌哈希。talk.session.appendAudioGateway(网关) 将 base64 PCM 输入音频追加到 Gateway 所有的实时中继和转录会话中。talk.session.startTurn、talk.session.endTurn和talk.session.cancelTurn驱动托管房间的轮次生命周期,并在清除状态之前拒绝过时的轮次。talk.session.cancelOutputGateway(网关) 停止助手音频输出,主要用于 Gateway 中继会话中 VAD 控制的插入。talk.session.submitToolResultGateway(网关) 完成 Gateway 所有的实时中继会话发出的提供商工具调用。当最终结果随后出现时,传递options: { willContinue: true }以获取临时工具输出,或者当工具结果应满足提供商调用而不启动另一个实时助手响应时,传递options: { suppressResponse: true }。talk.session.closeGateway(网关) 关闭 Gateway 所有的中继、转录或托管房间会话,并发出终止 Talk 事件。talk.modeWebChat 为 WebChat/Control UI 客户端设置/广播当前的 Talk 模式状态。talk.client.create使用webrtc或provider-websocketGateway(网关) 创建客户端所有的实时提供商会话,而 Gateway 拥有配置、凭据、指令和工具策略。talk.client.toolCallGateway(网关) 允许客户端所有的实时传输将提供商工具调用转发到 Gateway 策略。第一个支持的工具是openclaw_agent_consult;客户端在提交特定于提供商的工具结果之前接收运行 ID 并等待正常的聊天生命周期事件。talk.event是用于实时、转录、STT/TTS、托管房间、电话和会议适配器的单一 Talk 事件渠道。talk.speak通过活动的 Talk 语音提供商合成语音。tts.status返回 TTS 启用状态、活动提供商、备用提供商和提供商配置状态。tts.providers返回可见的 TTS 提供商清单。tts.enable和tts.disable切换 TTS 首选项状态。tts.setProvider更新首选的 TTS 提供商。tts.convert运行一次性文本转语音转换。
Secrets, config, update, and wizard
secrets.reload重新解析活动的 SecretRefs,并仅在完全成功时交换运行时密钥状态。secrets.resolve解析特定命令/目标集的命令目标密钥分配。config.get返回当前配置快照和哈希。config.set写入经过验证的配置负载。config.patch合并部分配置更新。config.apply验证并替换完整的配置负载。config.schema返回控制 UI 和 CLI 工具使用的实时配置架构负载:架构、uiHints、版本和生成元数据,包括运行时可以加载时的插件和渠道架构元数据。该架构包括从 UI 使用的相同标签和帮助文本派生的字段title/description元数据,包括嵌套对象、通配符、数组项以及anyOf/oneOf/allOf组合分支(当存在匹配的字段文档时)。config.schema.lookup返回一个配置路径的范围限定查找负载:规范化路径、浅层架构节点、匹配的提示 +hintPath、可选的reloadKind,以及用于 UI/CLI 向下钻取的直接子摘要。reloadKind是restart、hot或none之一,并反映了所请求路径的 Gateway(网关) 配置重新加载规划器。查找架构节点保留面向用户的文档和通用验证字段(title、description、type、enum、const、format、pattern、数字/字符串/数组/对象边界,以及诸如additionalProperties、deprecated、readOnly、writeOnly之类的标志)。子摘要暴露key、规范化的path、type、required、hasChildren、可选的reloadKind,以及匹配的hint/hintPath。update.run运行网关更新流程,并仅在更新本身成功时安排重启;具有会话的调用者可以包含continuationMessage,以便启动通过重启继续队列恢复一个后续代理轮次。来自控制平面的包管理器更新使用分离的托管服务移交,而不是替换实时 Gateway(网关) 内的包树。已启动的移交返回ok: true以及result.reason: "managed-service-handoff-started"和handoff.status: "started";不可用或失败的移交返回ok: false以及managed-service-handoff-unavailable或managed-service-handoff-failed,并在需要手动 shell 更新时加上handoff.command。在已启动的移交期间,重启哨兵可能会短暂报告stats.reason: "restart-health-pending";继续操作将延迟,直到 CLI 验证已重启的 Gateway(网关) 并写入最终的ok哨兵。update.status返回最新的缓存更新重启哨兵,包括重启后的运行版本(如果可用)。wizard.start、wizard.next、wizard.status和wizard.cancel通过 WS RPC 暴露新手引导向导。
Agent and workspace helpers
agents.list返回已配置的 agent 条目,包括有效模型和运行时元数据。agents.create、agents.update和agents.delete管理 agent 记录和工作区连接。agents.files.list、agents.files.get和agents.files.set管理为 agent 公开的引导工作区文件。tasks.list、tasks.get和tasks.cancelGateway(网关) 向 SDK 和操作员客户端公开 Gateway(网关) 任务账本。artifacts.list、artifacts.get和artifacts.download为显式的sessionKey、runId或taskId范围公开源自脚本的工件摘要和下载。Run 和 task 查询在服务端解析所属会话,并且仅返回具有匹配来源的脚本媒体;不安全或本地 URL 源返回不支持的下载,而不是从服务端获取。environments.list和environments.statusGateway(网关) 向 SDK 客户端公开只读的 Gateway(网关) 本地和节点环境发现。agent.identity.get返回 agent 或会话的有效助手身份。agent.wait等待运行完成,并在可用时返回终端快照。
Session control
sessions.list返回当前会话索引,包括配置了代理运行时后端时的逐行agentRuntime元数据。sessions.subscribe和sessions.unsubscribe切换当前 WebSocket 客户端的会话更改事件订阅。sessions.messages.subscribe和sessions.messages.unsubscribe切换单个会话的转录/消息事件订阅。sessions.preview返回特定会话键的有界转录预览。sessions.describeGateway(网关) 返回精确会话键的一个 Gateway(网关) 会话行。sessions.resolve解析或规范化会话目标。sessions.create创建一个新的会话条目。sessions.send向现有会话发送消息。sessions.steer是活动会话的中断和引导变体。sessions.abort中止会话的活动工作。调用者可以传递key加上可选的runId,或者仅传递runIdGateway(网关) 给 Gateway(网关) 可以解析为会话的活动运行。sessions.patch更新会话元数据/覆盖,并报告解析的规范模型以及有效的agentRuntime。sessions.reset、sessions.delete和sessions.compact执行会话维护。sessions.get返回完整的存储会话行。- 聊天执行仍然使用
chat.history、chat.send、chat.abort和chat.inject。chat.history针对 UI 客户端进行了显示规范化:内联指令标签从可见文本中剥离,纯文本工具调用 XML 载荷(包括 `
…
、
…
、
…
、
…
和截断的工具调用块)以及泄漏的 ASCII/全角模型控制令牌被剥离,纯静默令牌助手行(如精确的NO_REPLY/no_reply`)被省略,过大的行可以用占位符替换。
设备配对和设备令牌
device.pair.list返回待处理和已批准的配对设备。device.pair.approve、device.pair.reject和device.pair.remove管理设备配对记录。device.token.rotate在已批准的角色和调用者范围内轮换配对的设备令牌。device.token.revoke在已批准的角色和调用者范围内撤销配对的设备令牌。
节点配对、调用和待处理工作
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将节点发起的事件传回网关。node.pending.pull和node.pending.ack是已连接节点队列 API。node.pending.enqueue和node.pending.drain管理离线/断开节点的持久待处理工作。
审批系列
exec.approval.request、exec.approval.get、exec.approval.list和exec.approval.resolve涵盖一次性执行审批请求以及待处理审批的查询/重放。exec.approval.waitDecision等待一个待处理的执行审批并返回最终决定(或在超时时返回null)。exec.approvals.get和exec.approvals.set管理网关执行审批策略快照。exec.approvals.node.get和exec.approvals.node.set通过节点中继命令管理节点本地执行审批策略。plugin.approval.request、plugin.approval.list、plugin.approval.waitDecision和plugin.approval.resolve涵盖插件定义的审批流程。
自动化、Skills 和工具
- 自动化:
wake安排立即或下一次心跳唤醒文本注入;cron.get、cron.list、cron.status、cron.add、cron.update、cron.remove、cron.run和cron.runs管理预定工作。 cron.runRPC 仍然是手动运行的入队式 RPC。需要完成语义的客户端应读取返回的runId并轮询cron.runs。cron.runs接受可选的非空runId过滤器,以便客户端可以跟踪一个排队的手动运行,而不会与同一作业的其他历史条目发生冲突。- Skills 和工具:
commands.list、skills.*、tools.catalog、tools.effective、tools.invoke。
常见事件系列
Section titled “常见事件系列”chat:UI 聊天更新,例如chat.inject和其他仅限对话记录的聊天事件。在协议 v4 中,增量载荷携带deltaText;message仍然是累积的助手快照。非前缀替换设置replace=true并使用deltaText作为替换文本。session.message、session.operation和session.tool:已订阅会话的对话记录、进行中的会话操作和事件流更新。sessions.changed:会话索引或元数据已更改。presence:系统在线快照更新。tick:定期保活/存活事件。health:网关健康快照更新。heartbeat:心跳事件流更新。cron:cron 运行/任务更改事件。shutdown:网关关闭通知。node.pair.requested/node.pair.resolved:节点配对生命周期。node.invoke.request:节点调用请求广播。device.pair.requested/device.pair.resolved:配对设备生命周期。voicewake.changed:唤醒词触发配置已更改。exec.approval.requested/exec.approval.resolved:执行批准生命周期。plugin.approval.requested/plugin.approval.resolved:插件批准生命周期。
节点辅助方法
Section titled “节点辅助方法”- 节点可以调用
skills.bins来获取当前的可执行技能列表以进行自动允许检查。
任务账本 RPC
Section titled “任务账本 RPC”操作员客户端可以通过任务账本 RPC 检查和取消 Gateway(网关) 后台任务记录。这些方法返回经过清理的任务摘要,而不是原始 运行时状态。
tasks.list需要operator.read。- Params: 可选的
status("queued"、"running"、"completed"、"failed"、"cancelled"或"timed_out") 或这些状态的数组, 可选agentId、可选sessionKey、可选limit从1到500,以及可选字符串cursor。 - Result:
{ "tasks": TaskSummary[], "nextCursor"?: string }。
- Params: 可选的
tasks.get需要operator.read。- Params:
{ "taskId": string }。 - Result:
{ "task": TaskSummary }。 - 缺失的任务 ID 将返回 Gateway(网关) 的未找到错误格式。
- Params:
tasks.cancel需要operator.write。- Params:
{ "taskId": string, "reason"?: string }。 - Result:
{ "found": boolean, "cancelled": boolean, "reason"?: string, "task"?: TaskSummary }。 found报告账本是否具有匹配的任务。cancelled报告运行时是否接受或记录了取消。
- Params:
TaskSummary 包括 id、status 以及可选元数据,如 kind、
runtime、title、agentId、sessionKey、childSessionKey、ownerKey、
runId、taskId、flowId、parentTaskId、sourceId、时间戳、进度、
终端摘要和经过清理的错误文本。
Operator helper methods
Section titled “Operator helper methods”- 操作员可以调用
commands.list(operator.read) 来获取代理的 运行时命令清单。agentId是可选的;省略它以读取默认代理工作区。scope控制主name针对哪个界面:text返回不带前缀/的主要文本命令令牌native和默认的both路径在可用时返回提供商感知的本机名称
textAliases携带精确的斜杠别名,例如/model和/m。nativeName携带提供商感知的本机命令名称(如果存在)。provider是可选的,仅影响本机命名以及本机插件命令的可用性。includeArgs=false省略响应中的序列化参数元数据。
- 操作员可以调用
tools.catalog(operator.read) 来获取代理的运行时工具目录。响应包括分组的工具和来源元数据:source:core或pluginpluginId:插件所有者,当source="plugin"时optional:插件工具是否为可选
- 操作员可以调用
tools.effective(operator.read) 来获取会话的运行时有效工具清单。sessionKey是必需的。- 网关从服务端的会话派生受信任的运行时上下文,而不是接受调用者提供的身份验证或传递上下文。
- 响应范围限定于会话,并反映了当前活跃对话可立即使用的内容,包括核心、插件和渠道工具。
- 操作员可以调用
tools.invoke(operator.write) 通过与/tools/invoke相同的网关策略路径来调用一个可用工具。name是必需的。args、sessionKey、agentId、confirm和idempotencyKey是可选的。- 如果同时存在
sessionKey和agentId,解析出的会话代理必须匹配agentId。 - 响应是一个面向 SDK 的信封,包含
ok、toolName、可选的output和类型化error字段。批准或策略拒绝会在负载中返回ok:false,而不是绕过网关工具策略管道。
- 操作员可以调用
skills.status(operator.read) 来获取代理的可见技能清单。agentId是可选的;省略它以读取默认代理工作区。- 响应包括资格、缺失要求、配置检查以及经过清理的安装选项,且不暴露原始机密值。
- 操作员可以调用
skills.search和skills.detail(operator.read) 来获取 ClawHub 发现元数据。 - 操作员可以调用
skills.upload.begin、skills.upload.chunk和skills.upload.commit(operator.admin) 在安装私有技能存档之前对其进行暂存。这是受信任客户端的单独管理员上传路径,而不是正常的 ClawHub 技能安装流程,并且默认处于禁用状态,除非启用了skills.install.allowUploadedArchives。skills.upload.begin({ kind: "skill-archive", slug, sizeBytes, sha256?, force?, idempotencyKey? })创建绑定到该 slug 和 force 值的上传。skills.upload.chunk({ uploadId, offset, dataBase64 })在精确的解码偏移量处追加字节。skills.upload.commit({ uploadId, sha256? })验证最终大小和 SHA-256。提交仅完成上传;它不会安装技能。- 上传的技能存档是包含
SKILL.md根目录的 zip 存档。存档的内部目录名称从不选择安装目标。
- 操作员可以以三种模式调用
skills.install(operator.admin):- ClawHub 模式:
{ source: "clawhub", slug, version?, force? }将技能文件夹安装到默认代理工作区skills/目录中。 - 上传模式:
{ source: "upload", uploadId, slug, force?, sha256?, timeoutMs? }将已提交的上传安装到默认代理工作区skills/<slug>目录。Slug 和 force 值必须与原始skills.upload.begin请求匹配。除非启用了skills.install.allowUploadedArchives,否则将拒绝此模式。该设置不影响 ClawHub 安装。 - Gateway(网关) 安装程序模式:
{ name, installId, dangerouslyForceUnsafeInstall?, timeoutMs? }在 Gateway 主机上运行声明的metadata.openclaw.install操作。
- ClawHub 模式:
- 操作员可以以两种模式调用
skills.update(operator.admin):- ClawHub 模式更新默认 agent 工作区中一个已跟踪的 slug 或所有已跟踪的 ClawHub 安装。
- 配置模式修补
skills.entries.<skillKey>值,例如enabled、apiKey和env。
models.list 视图
Section titled “models.list 视图”models.list 接受一个可选的 view 参数:
- 省略或
"default":当前运行时行为。如果配置了agents.defaults.models,响应为允许的目录,包括provider/*Gateway(网关) 条目的动态发现的模型。否则响应为完整的 Gateway 目录。 "configured":选择器大小的行为。如果配置了agents.defaults.models,它仍然优先,包括provider/*条目的提供商范围发现。如果没有允许列表,响应使用显式的models.providers.*.models条目,仅当不存在配置的模型行时才回退到完整目录。"all"Gateway(网关):完整的 Gateway 目录,绕过agents.defaults.models。将此用于诊断和发现 UI,而不是普通的模型选择器。
- 当执行请求需要批准时,网关广播
exec.approval.requested。 - 操作员客户端通过调用
exec.approval.resolve来解决(需要operator.approvals范围)。 - 对于
host=node,exec.approval.request必须包含systemRunPlan(规范argv/cwd/rawCommand/会话元数据)。缺少systemRunPlan的请求将被拒绝。 - 批准后,转发的
node.invoke system.run调用重用该规范systemRunPlan作为权威命令/cwd/会话上下文。 - 如果调用方在 prepare 和最终批准的
system.run转发之间改变了command、rawCommand、cwd、agentId或sessionKey,网关将拒绝该运行,而不是信任被更改的 payload。
代理投递回退
Section titled “代理投递回退”agent请求可以包含deliver=true以请求出站投递。bestEffortDeliver=false保持严格行为:未解析或仅限内部的投递目标返回INVALID_REQUEST。- 当无法解析外部可投递路由时(例如内部/webchat 会话或模糊的多渠道配置),
bestEffortDeliver=true允许回退到仅会话执行。 - 最终
agent结果在请求投递时可能包含result.deliveryStatus,使用与openclaw agent --json --deliver文档中相同的sent、suppressed、partial_failed和failed状态。
PROTOCOL_VERSION位于src/gateway/protocol/version.ts中。- 客户端发送
minProtocol+maxProtocol;服务器将拒绝不包含其当前协议的范围。当前的客户端和服务器需要协议 v4。 - Schemas + 模型是从 TypeBox 定义生成的:
pnpm protocol:genpnpm protocol:gen:swiftpnpm protocol:check
src/gateway/client.ts 中的参考客户端使用这些默认值。这些值在协议 v4 中是稳定的,并且是第三方客户端的预期基准。
| 常量 | 默认值 | 来源 |
|---|---|---|
PROTOCOL_VERSION | 4 | src/gateway/protocol/version.ts |
MIN_CLIENT_PROTOCOL_VERSION | 4 | src/gateway/protocol/version.ts |
| 请求超时(每次 RPC) | 30_000 毫秒 | src/gateway/client.ts (requestTimeoutMs) |
| 预认证 / 连接质询超时 | 15_000 毫秒 | 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 |
Force-stop grace before terminate() | 250 ms | FORCE_STOP_TERMINATE_GRACE_MS |
stopAndWait() default timeout | 1_000 ms | STOP_AND_WAIT_TIMEOUT_MS |
Default tick interval (pre hello-ok) | 30_000 ms | src/gateway/client.ts |
| 心跳超时关闭 | code 4000 when silence exceeds tickIntervalMs * 2 | src/gateway/client.ts |
MAX_PAYLOAD_BYTES | 25 * 1024 * 1024 (25 MB) | src/gateway/server-constants.ts |
The server advertises the effective policy.tickIntervalMs, policy.maxPayload,
and policy.maxBufferedBytes in hello-ok; clients should honor those values
rather than the pre-handshake defaults.
- Shared-secret gateway auth uses
connect.params.auth.tokenorconnect.params.auth.password, depending on the configured auth mode. - Identity-bearing modes such as Tailscale Serve
(
gateway.auth.allowTailscale: true) or non-loopbackgateway.auth.mode: "trusted-proxy"satisfy the connect auth check from request headers instead ofconnect.params.auth.*. - Private-ingress
gateway.auth.mode: "none"skips shared-secret connect auth entirely; do not expose that mode on public/untrusted ingress. - After pairing, the Gateway(网关) issues a device token scoped to the connection
role + scopes. It is returned in
hello-ok.auth.deviceTokenand should be persisted by the client for future connects. - Clients should persist the primary
hello-ok.auth.deviceTokenafter any successful connect. - 使用该已存储设备令牌重新连接也应重用为该令牌存储的已批准范围集。这保留了已授予的读取/探测/状态访问权限,并避免将重新连接静默地收窄为隐式仅管理员范围。
- Client-side connect auth assembly (
selectConnectAuthinsrc/gateway/client.ts):auth.password是正交的,设置时始终会被转发。auth.token按优先级顺序填充:首先是显式的共享令牌, 然后是显式的deviceToken,最后是存储的每设备令牌(由deviceId+role键控)。- 仅当上述方法均未解析出
auth.token时,才会发送auth.bootstrapToken。共享令牌或任何已解析的设备令牌都会抑制其发送。 - 在一次性
AUTH_TOKEN_MISMATCH重试时,存储设备令牌的自动提升仅限于 受信任的端点 — 即环回地址,或具有固定tlsFingerprint的wss://。没有固定的公共wss://不符合条件。
- 内置设置代码引导返回主节点
hello-ok.auth.deviceToken以及用于可信移动设备移交的hello-ok.auth.deviceTokens中的有界操作员令牌。该操作员令牌 不包括operator.admin、operator.pairing和operator.talk.secrets。 - 当非基线设置代码引导等待批准时,
PAIRING_REQUIRED详细信息包括recommendedNextStep: "wait_then_retry"、retryable: true和pauseReconnect: false。客户端应继续使用相同的 引导令牌重新连接,直到请求被批准或令牌失效。 - 仅当连接在
wss://或环回/本地配对等可信传输上使用引导认证时, 才持久化hello-ok.auth.deviceTokens。 - 如果客户端提供了 显式 的
deviceToken或显式的scopes,则该 调用者请求的作用域集保持权威;仅当客户端重用存储的每设备令牌时,才会重用缓存的作用域。 - 设备令牌可以通过
device.token.rotate和device.token.revoke轮换/吊销(需要operator.pairing作用域)。 device.token.rotate返回轮换元数据。它仅在已使用该设备令牌进行身份验证的同一设备调用中回显新的 bearer 令牌,以便仅使用令牌的客户端可以在重新连接之前保存其替换令牌。共享/管理员轮换不会回显 bearer 令牌。- 令牌的签发、轮换和撤销始终受限于记录在该设备配对条目中的已批准角色集;令牌变更不能扩展或定位到配对批准从未授予的设备角色。
- 对于配对设备令牌会话,设备管理是自限定的,除非调用者还具有
operator.admin:非管理员调用者只能删除/撤销/轮换其自己的设备条目。 device.token.rotate和device.token.revoke还会根据调用者当前的会话范围检查目标操作员令牌范围集。非管理员调用者不能轮换或撤销比其当前持有的范围更广的操作员令牌。- 身份验证失败包括
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_SCOPE_MISMATCH意味着设备令牌已被识别,但不涵盖所请求的角色/范围。客户端不应将其显示为无效令牌;应提示操作员重新配对或批准更窄/更广的范围协定。
设备身份 + 配对
Section titled “设备身份 + 配对”- 节点应包含从密钥对指纹派生的稳定设备标识 (
device.id)。 - 网关为每个设备 + 角色签发令牌。
- 除非启用了本地自动批准,否则需要针对新设备 ID 进行配对批准。
- 配对自动批准以直接本地环回连接为中心。
- OpenClaw 还有一个用于受信任的共享密钥辅助流的后端/容器本地狭窄自连接路径。
- 同主机 tailnet 或 LAN 连接在配对时仍被视为远程连接,并且需要批准。
- WS 客户端通常在
connect期间(操作员 + 节点)包含device标识。唯一的无设备操作员例外情况是显式信任路径:gateway.controlUi.allowInsecureAuth=true,用于仅限本地主机的不安全 HTTP 兼容性。- 成功的
gateway.auth.mode: "trusted-proxy"操作员控制 UI 身份验证。 gateway.controlUi.dangerouslyDisableDeviceAuth=true(应急,严重安全降级)。- 使用共享网关令牌/密码进行身份验证的直接回环
gateway-client后端 RPC。
- 所有连接必须对服务器提供的
connect.challengenonce 进行签名。
设备身份验证迁移诊断
Section titled “设备身份验证迁移诊断”对于仍使用质询前签名行为的旧版客户端,connect 现在在 error.details.code 下返回稳定的 error.details.reason 的 DEVICE_AUTH_* 详细代码。
常见迁移失败:
| 消息 | 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 | 公钥格式/规范化失败。 |
迁移目标:
- 始终等待
connect.challenge。 - 对包含服务器 nonce 的 v2 负载进行签名。
- 在
connect.params.device.nonce中发送相同的 nonce。 - 首选签名负载是
v3,它除了设备/客户端/角色/范围/令牌/nonce 字段外,还绑定了platform和deviceFamily。 - 出于兼容性原因,仍接受旧版
v2签名,但在重新连接时,配对设备元数据固定仍然控制命令策略。
TLS + 证书固定
Section titled “TLS + 证书固定”- WS 连接支持 TLS。
- 客户端可以选择固定网关证书指纹(请参阅
gateway.tls配置加上gateway.remote.tlsFingerprint或 CLI--tls-fingerprint)。
该协议暴露了 完整的网关 API(状态、频道、模型、聊天、代理、会话、节点、审批等)。确切的界面由 src/gateway/protocol/schema.ts 中的 TypeBox 模式定义。