跳转到内容

Gateway(网关)Gateway(网关) 协议

Gateway(网关) WS 协议是 OpenClaw 的单一控制平面 + 节点传输。所有客户端(CLI、Web UI、macOS 应用、iOS/Android 节点、无头节点)均通过 WebSocket 连接,并在握手时声明其 role + scope

  • WebSocket,带有 JSON 载荷的文本帧。
  • 第一帧必须是一个 connect 请求。
  • 连接前的帧上限为 64 KiB。成功握手后,客户端应遵循 hello-ok.policy.maxPayloadhello-ok.policy.maxBufferedBytes 限制。如果启用了诊断功能,超大的入站帧和缓慢的出站缓冲区会在 Gateway 关闭或丢弃受影响的帧之前发出 payload.large 事件。这些事件包含大小、限制、表面和安全原因代码。它们不包含消息正文、附件内容、原始帧正文、令牌、Cookie 或机密值。

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。客户端应在其总体连接预算内重试该响应,而不是将其作为最终的握手失败呈现。

serverfeaturessnapshotpolicy 都是架构(src/gateway/protocol/schema/frames.ts)所必需的。auth 也是必需的,用于报告协商的角色/范围。pluginSurfaceUrls 是可选的,用于将插件表面名称(例如 canvas)映射到有作用域的托管 URL。

有作用域的插件表面 URL 可能会过期。节点可以调用 node.pluginSurface.refresh 并附带 { "surface": "canvas" },以接收 pluginSurfaceUrlsCanvas 中的新条目。实验性的 Canvas 插件重构不支持已弃用的 canvasHostUrlcanvasCapabilitynode.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.adminoperator.pairingoperator.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?}

具有副作用的方法需要幂等性键(请参阅架构)。

有关完整的操作员范围模型、批准时检查和共享密钥 语义,请参阅 操作员范围

  • operator = 控制平面客户端 (CLI/UI/automation)。
  • node = 功能主机 (camera/screen/canvas/system.run)。

常用范围:

  • operator.read
  • operator.write
  • operator.admin
  • operator.approvals
  • operator.pairing
  • operator.talk.secrets

带有 includeSecrets: truetalk.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.runsystem.run.preparesystem.which 的请求: operator.pairing + operator.admin

节点在连接时声明能力声明:

  • caps:高级功能类别,例如 cameracanvasscreenlocationvoicetalk
  • commands:用于调用的命令允许列表。
  • permissions:细粒度开关(例如 screen.recordcamera.capture)。

Gateway Gateway(网关) 将这些视为 声明 并强制执行服务器端允许列表。

  • system-presence 返回以设备身份为键的条目。
  • 存在条目包括 deviceIdrolesscopes,因此 UI 可以每个设备显示单行, 即使它同时以 operatornode 身份连接。
  • node.list 包括可选的 lastSeenAtMslastSeenReason 字段。已连接的节点将其 当前连接时间报告为 lastSeenAtMs,原因 connect;配对节点也可以在受信任节点事件更新其配对元数据时报告持久的后台存在。

节点可以使用 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 是一个封闭枚举:backgroundsilent_pushbg_app_refreshsignificant_locationmanualconnect。未知的触发字符串在持久化之前通过网关标准化为 background。该事件仅对已验证的节点设备会话持久化;无设备或未配对的会话返回 handled: false

成功的网关返回一个结构化结果:

{
"ok": true,
"event": "node.presence.alive",
"handled": true,
"reason": "persisted"
}

较旧的网关对于 node.event 可能仍会返回 { "ok": true };客户端应将其视为已确认的 RPC,而不是持久的在线状态持久化。

服务器推送的 WebSocket 广播事件是按范围限定的,以便配对范围或仅节点的会话不会被动接收会话内容。

  • 聊天、代理和工具结果帧(包括流式 agent 事件和工具调用结果)至少需要 operator.read。没有 operator.read 的会话将完全跳过这些帧。
  • 插件定义的 plugin.* 广播 根据插件注册方式的不同,被限制为 operator.writeoperator.admin
  • 状态和传输事件heartbeatpresencetick、连接/断开连接生命周期等)保持不受限制,以便每个经过身份验证的会话都能观察到传输的健康状况。
  • 未知的广播事件系列在默认情况下受范围限制(失效关闭),除非已注册的处理程序明确放宽了限制。

每个客户端连接都保留自己的每客户端序列号,因此即使不同的客户端看到的事件流具有不同的范围过滤子集,广播也能在该套接字上保持单调顺序。

公共 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-relaytranscription/gateway-relaystt-tts/managed-room 创建 Gateway 所有的 Talk 会话。对于 stt-tts/managed-room,传递 sessionKeyoperator.write 调用方还必须传递 spawnedBy 以实现作用域内的会话密钥可见性;无作用域的 sessionKey 创建和 brain: "direct-tools" 需要 operator.admin
  • talk.session.join 验证托管房间会话令牌,根据需要发出 session.readysession.replaced 事件,并返回房间/会话元数据以及最近的 Talk 事件,但不返回明文令牌或存储的令牌哈希。
  • talk.session.appendAudioGateway(网关) 将 base64 PCM 输入音频追加到 Gateway 所有的实时中继和转录会话中。
  • talk.session.startTurntalk.session.endTurntalk.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 使用 webrtcprovider-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.enabletts.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 向下钻取的直接子摘要。reloadKindrestarthotnone 之一,并反映了所请求路径的 Gateway(网关) 配置重新加载规划器。查找架构节点保留面向用户的文档和通用验证字段(titledescriptiontypeenumconstformatpattern、数字/字符串/数组/对象边界,以及诸如 additionalPropertiesdeprecatedreadOnlywriteOnly 之类的标志)。子摘要暴露 key、规范化的 pathtyperequiredhasChildren、可选的 reloadKind,以及匹配的 hint / hintPath
  • update.run 运行网关更新流程,并仅在更新本身成功时安排重启;具有会话的调用者可以包含 continuationMessage,以便启动通过重启继续队列恢复一个后续代理轮次。来自控制平面的包管理器更新使用分离的托管服务移交,而不是替换实时 Gateway(网关) 内的包树。已启动的移交返回 ok: true 以及 result.reason: "managed-service-handoff-started"handoff.status: "started";不可用或失败的移交返回 ok: false 以及 managed-service-handoff-unavailablemanaged-service-handoff-failed,并在需要手动 shell 更新时加上 handoff.command。在已启动的移交期间,重启哨兵可能会短暂报告 stats.reason: "restart-health-pending";继续操作将延迟,直到 CLI 验证已重启的 Gateway(网关) 并写入最终的 ok 哨兵。
  • update.status 返回最新的缓存更新重启哨兵,包括重启后的运行版本(如果可用)。
  • wizard.startwizard.nextwizard.statuswizard.cancel 通过 WS RPC 暴露新手引导向导。
Agent and workspace helpers
  • agents.list 返回已配置的 agent 条目,包括有效模型和运行时元数据。
  • agents.createagents.updateagents.delete 管理 agent 记录和工作区连接。
  • agents.files.listagents.files.getagents.files.set 管理为 agent 公开的引导工作区文件。
  • tasks.listtasks.gettasks.cancelGateway(网关) 向 SDK 和操作员客户端公开 Gateway(网关) 任务账本。
  • artifacts.listartifacts.getartifacts.download 为显式的 sessionKeyrunIdtaskId 范围公开源自脚本的工件摘要和下载。Run 和 task 查询在服务端解析所属会话,并且仅返回具有匹配来源的脚本媒体;不安全或本地 URL 源返回不支持的下载,而不是从服务端获取。
  • environments.listenvironments.statusGateway(网关) 向 SDK 客户端公开只读的 Gateway(网关) 本地和节点环境发现。
  • agent.identity.get 返回 agent 或会话的有效助手身份。
  • agent.wait 等待运行完成,并在可用时返回终端快照。
Session control
  • sessions.list 返回当前会话索引,包括配置了代理运行时后端时的逐行 agentRuntime 元数据。
  • sessions.subscribesessions.unsubscribe 切换当前 WebSocket 客户端的会话更改事件订阅。
  • sessions.messages.subscribesessions.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.resetsessions.deletesessions.compact 执行会话维护。
  • sessions.get 返回完整的存储会话行。
  • 聊天执行仍然使用 chat.historychat.sendchat.abortchat.injectchat.history 针对 UI 客户端进行了显示规范化:内联指令标签从可见文本中剥离,纯文本工具调用 XML 载荷(包括 `

和截断的工具调用块)以及泄漏的 ASCII/全角模型控制令牌被剥离,纯静默令牌助手行(如精确的NO_REPLY/no_reply`)被省略,过大的行可以用占位符替换。

设备配对和设备令牌
  • device.pair.list 返回待处理和已批准的配对设备。
  • device.pair.approvedevice.pair.rejectdevice.pair.remove 管理设备配对记录。
  • device.token.rotate 在已批准的角色和调用者范围内轮换配对的设备令牌。
  • device.token.revoke 在已批准的角色和调用者范围内撤销配对的设备令牌。
节点配对、调用和待处理工作
  • node.pair.requestnode.pair.listnode.pair.approvenode.pair.rejectnode.pair.removenode.pair.verify 涵盖节点配对和引导验证。
  • node.listnode.describe 返回已知/已连接的节点状态。
  • node.rename 更新配对节点标签。
  • node.invoke 将命令转发到已连接的节点。
  • node.invoke.result 返回调用请求的结果。
  • node.event 将节点发起的事件传回网关。
  • node.pending.pullnode.pending.ack 是已连接节点队列 API。
  • node.pending.enqueuenode.pending.drain 管理离线/断开节点的持久待处理工作。
审批系列
  • exec.approval.requestexec.approval.getexec.approval.listexec.approval.resolve 涵盖一次性执行审批请求以及待处理审批的查询/重放。
  • exec.approval.waitDecision 等待一个待处理的执行审批并返回最终决定(或在超时时返回 null)。
  • exec.approvals.getexec.approvals.set 管理网关执行审批策略快照。
  • exec.approvals.node.getexec.approvals.node.set 通过节点中继命令管理节点本地执行审批策略。
  • plugin.approval.requestplugin.approval.listplugin.approval.waitDecisionplugin.approval.resolve 涵盖插件定义的审批流程。
自动化、Skills 和工具
  • 自动化:wake 安排立即或下一次心跳唤醒文本注入;cron.getcron.listcron.statuscron.addcron.updatecron.removecron.runcron.runs 管理预定工作。
  • cron.runRPC 仍然是手动运行的入队式 RPC。需要完成语义的客户端应读取返回的 runId 并轮询 cron.runs
  • cron.runs 接受可选的非空 runId 过滤器,以便客户端可以跟踪一个排队的手动运行,而不会与同一作业的其他历史条目发生冲突。
  • Skills 和工具:commands.listskills.*tools.catalogtools.effectivetools.invoke
  • chat:UI 聊天更新,例如 chat.inject 和其他仅限对话记录的聊天事件。在协议 v4 中,增量载荷携带 deltaTextmessage 仍然是累积的助手快照。非前缀替换设置 replace=true 并使用 deltaText 作为替换文本。
  • session.messagesession.operationsession.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:插件批准生命周期。
  • 节点可以调用 skills.bins 来获取当前的可执行技能列表以进行自动允许检查。

操作员客户端可以通过任务账本 RPC 检查和取消 Gateway(网关) 后台任务记录。这些方法返回经过清理的任务摘要,而不是原始 运行时状态。

  • tasks.list 需要 operator.read
    • Params: 可选的 status ("queued""running""completed""failed""cancelled""timed_out") 或这些状态的数组, 可选 agentId、可选 sessionKey、可选 limit1500,以及可选字符串 cursor
    • Result: { "tasks": TaskSummary[], "nextCursor"?: string }
  • tasks.get 需要 operator.read
    • Params: { "taskId": string }
    • Result: { "task": TaskSummary }
    • 缺失的任务 ID 将返回 Gateway(网关) 的未找到错误格式。
  • tasks.cancel 需要 operator.write
    • Params: { "taskId": string, "reason"?: string }
    • Result: { "found": boolean, "cancelled": boolean, "reason"?: string, "task"?: TaskSummary }
    • found 报告账本是否具有匹配的任务。cancelled 报告运行时是否接受或记录了取消。

TaskSummary 包括 idstatus 以及可选元数据,如 kindruntimetitleagentIdsessionKeychildSessionKeyownerKeyrunIdtaskIdflowIdparentTaskIdsourceId、时间戳、进度、 终端摘要和经过清理的错误文本。

  • 操作员可以调用 commands.list (operator.read) 来获取代理的 运行时命令清单。
    • agentId 是可选的;省略它以读取默认代理工作区。
    • scope 控制主 name 针对哪个界面:
      • text 返回不带前缀 / 的主要文本命令令牌
      • native 和默认的 both 路径在可用时返回提供商感知的本机名称
    • textAliases 携带精确的斜杠别名,例如 /model/m
    • nativeName 携带提供商感知的本机命令名称(如果存在)。
    • provider 是可选的,仅影响本机命名以及本机插件命令的可用性。
    • includeArgs=false 省略响应中的序列化参数元数据。
  • 操作员可以调用 tools.catalog (operator.read) 来获取代理的运行时工具目录。响应包括分组的工具和来源元数据:
    • sourcecoreplugin
    • pluginId:插件所有者,当 source="plugin"
    • optional:插件工具是否为可选
  • 操作员可以调用 tools.effective (operator.read) 来获取会话的运行时有效工具清单。
    • sessionKey 是必需的。
    • 网关从服务端的会话派生受信任的运行时上下文,而不是接受调用者提供的身份验证或传递上下文。
    • 响应范围限定于会话,并反映了当前活跃对话可立即使用的内容,包括核心、插件和渠道工具。
  • 操作员可以调用 tools.invoke (operator.write) 通过与 /tools/invoke 相同的网关策略路径来调用一个可用工具。
    • name 是必需的。argssessionKeyagentIdconfirmidempotencyKey 是可选的。
    • 如果同时存在 sessionKeyagentId,解析出的会话代理必须匹配 agentId
    • 响应是一个面向 SDK 的信封,包含 oktoolName、可选的 output 和类型化 error 字段。批准或策略拒绝会在负载中返回 ok:false,而不是绕过网关工具策略管道。
  • 操作员可以调用 skills.status (operator.read) 来获取代理的可见技能清单。
    • agentId 是可选的;省略它以读取默认代理工作区。
    • 响应包括资格、缺失要求、配置检查以及经过清理的安装选项,且不暴露原始机密值。
  • 操作员可以调用 skills.searchskills.detail (operator.read) 来获取 ClawHub 发现元数据。
  • 操作员可以调用 skills.upload.beginskills.upload.chunkskills.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 操作。
  • 操作员可以以两种模式调用 skills.update (operator.admin):
    • ClawHub 模式更新默认 agent 工作区中一个已跟踪的 slug 或所有已跟踪的 ClawHub 安装。
    • 配置模式修补 skills.entries.<skillKey> 值,例如 enabledapiKeyenv

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=nodeexec.approval.request 必须包含 systemRunPlan(规范 argv/cwd/rawCommand/会话元数据)。缺少 systemRunPlan 的请求将被拒绝。
  • 批准后,转发的 node.invoke system.run 调用重用该规范 systemRunPlan 作为权威命令/cwd/会话上下文。
  • 如果调用方在 prepare 和最终批准的 system.run 转发之间改变了 commandrawCommandcwdagentIdsessionKey,网关将拒绝该运行,而不是信任被更改的 payload。
  • agent 请求可以包含 deliver=true 以请求出站投递。
  • bestEffortDeliver=false 保持严格行为:未解析或仅限内部的投递目标返回 INVALID_REQUEST
  • 当无法解析外部可投递路由时(例如内部/webchat 会话或模糊的多渠道配置),bestEffortDeliver=true 允许回退到仅会话执行。
  • 最终 agent 结果在请求投递时可能包含 result.deliveryStatus,使用与 openclaw agent --json --deliver 文档中相同的 sentsuppressedpartial_failedfailed 状态。
  • PROTOCOL_VERSION 位于 src/gateway/protocol/version.ts 中。
  • 客户端发送 minProtocol + maxProtocol;服务器将拒绝不包含其当前协议的范围。当前的客户端和服务器需要协议 v4。
  • Schemas + 模型是从 TypeBox 定义生成的:
    • pnpm protocol:gen
    • pnpm protocol:gen:swift
    • pnpm protocol:check

src/gateway/client.ts 中的参考客户端使用这些默认值。这些值在协议 v4 中是稳定的,并且是第三方客户端的预期基准。

常量默认值来源
PROTOCOL_VERSION4src/gateway/protocol/version.ts
MIN_CLIENT_PROTOCOL_VERSION4src/gateway/protocol/version.ts
请求超时(每次 RPC)30_000 毫秒src/gateway/client.ts (requestTimeoutMs)
预认证 / 连接质询超时15_000 毫秒src/gateway/handshake-timeouts.ts(配置/环境可以提高配对的服务器/客户端预算)
初始重连退避1_000 mssrc/gateway/client.ts (backoffMs)
最大重连退避30_000 mssrc/gateway/client.ts (scheduleReconnect)
设备令牌关闭后的快速重试限制250 mssrc/gateway/client.ts
Force-stop grace before terminate()250 msFORCE_STOP_TERMINATE_GRACE_MS
stopAndWait() default timeout1_000 msSTOP_AND_WAIT_TIMEOUT_MS
Default tick interval (pre hello-ok)30_000 mssrc/gateway/client.ts
心跳超时关闭code 4000 when silence exceeds tickIntervalMs * 2src/gateway/client.ts
MAX_PAYLOAD_BYTES25 * 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.token or connect.params.auth.password, depending on the configured auth mode.
  • Identity-bearing modes such as Tailscale Serve (gateway.auth.allowTailscale: true) or non-loopback gateway.auth.mode: "trusted-proxy" satisfy the connect auth check from request headers instead of connect.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.deviceToken and should be persisted by the client for future connects.
  • Clients should persist the primary hello-ok.auth.deviceToken after any successful connect.
  • 使用该已存储设备令牌重新连接也应重用为该令牌存储的已批准范围集。这保留了已授予的读取/探测/状态访问权限,并避免将重新连接静默地收窄为隐式仅管理员范围。
  • Client-side connect auth assembly (selectConnectAuth in src/gateway/client.ts):
    • auth.password 是正交的,设置时始终会被转发。
    • auth.token 按优先级顺序填充:首先是显式的共享令牌, 然后是显式的 deviceToken,最后是存储的每设备令牌(由 deviceId + role 键控)。
    • 仅当上述方法均未解析出 auth.token 时,才会发送 auth.bootstrapToken。共享令牌或任何已解析的设备令牌都会抑制其发送。
    • 在一次性 AUTH_TOKEN_MISMATCH 重试时,存储设备令牌的自动提升仅限于 受信任的端点 — 即环回地址,或具有固定 tlsFingerprintwss://。没有固定的公共 wss:// 不符合条件。
  • 内置设置代码引导返回主节点 hello-ok.auth.deviceToken 以及用于可信移动设备移交的 hello-ok.auth.deviceTokens 中的有界操作员令牌。该操作员令牌 不包括 operator.adminoperator.pairingoperator.talk.secrets
  • 当非基线设置代码引导等待批准时,PAIRING_REQUIRED 详细信息包括 recommendedNextStep: "wait_then_retry"retryable: truepauseReconnect: false。客户端应继续使用相同的 引导令牌重新连接,直到请求被批准或令牌失效。
  • 仅当连接在 wss:// 或环回/本地配对等可信传输上使用引导认证时, 才持久化 hello-ok.auth.deviceTokens
  • 如果客户端提供了 显式deviceToken 或显式的 scopes,则该 调用者请求的作用域集保持权威;仅当客户端重用存储的每设备令牌时,才会重用缓存的作用域。
  • 设备令牌可以通过 device.token.rotatedevice.token.revoke 轮换/吊销(需要 operator.pairing 作用域)。
  • device.token.rotate 返回轮换元数据。它仅在已使用该设备令牌进行身份验证的同一设备调用中回显新的 bearer 令牌,以便仅使用令牌的客户端可以在重新连接之前保存其替换令牌。共享/管理员轮换不会回显 bearer 令牌。
  • 令牌的签发、轮换和撤销始终受限于记录在该设备配对条目中的已批准角色集;令牌变更不能扩展或定位到配对批准从未授予的设备角色。
  • 对于配对设备令牌会话,设备管理是自限定的,除非调用者还具有 operator.admin:非管理员调用者只能删除/撤销/轮换其自己的设备条目。
  • device.token.rotatedevice.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 意味着设备令牌已被识别,但不涵盖所请求的角色/范围。客户端不应将其显示为无效令牌;应提示操作员重新配对或批准更窄/更广的范围协定。
  • 节点应包含从密钥对指纹派生的稳定设备标识 (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.challenge nonce 进行签名。

对于仍使用质询前签名行为的旧版客户端,connect 现在在 error.details.code 下返回稳定的 error.details.reasonDEVICE_AUTH_* 详细代码。

常见迁移失败:

消息details.codedetails.reason含义
device nonce requiredDEVICE_AUTH_NONCE_REQUIREDdevice-nonce-missing客户端省略了 device.nonce(或发送了空白值)。
device nonce mismatchDEVICE_AUTH_NONCE_MISMATCHdevice-nonce-mismatch客户端使用了过时/错误的 nonce 进行签名。
device signature invalidDEVICE_AUTH_SIGNATURE_INVALIDdevice-signature签名负载与 v2 负载不匹配。
device signature expiredDEVICE_AUTH_SIGNATURE_EXPIREDdevice-signature-stale签名时间戳超出允许的偏差范围。
device identity mismatchDEVICE_AUTH_DEVICE_ID_MISMATCHdevice-id-mismatchdevice.id 与公钥指纹不匹配。
device public key invalidDEVICE_AUTH_PUBLIC_KEY_INVALIDdevice-public-key公钥格式/规范化失败。

迁移目标:

  • 始终等待 connect.challenge
  • 对包含服务器 nonce 的 v2 负载进行签名。
  • connect.params.device.nonce 中发送相同的 nonce。
  • 首选签名负载是 v3,它除了设备/客户端/角色/范围/令牌/nonce 字段外,还绑定了 platformdeviceFamily
  • 出于兼容性原因,仍接受旧版 v2 签名,但在重新连接时,配对设备元数据固定仍然控制命令策略。
  • WS 连接支持 TLS。
  • 客户端可以选择固定网关证书指纹(请参阅 gateway.tls 配置加上 gateway.remote.tlsFingerprint 或 CLI --tls-fingerprint)。

该协议暴露了 完整的网关 API(状态、频道、模型、聊天、代理、会话、节点、审批等)。确切的界面由 src/gateway/protocol/schema.ts 中的 TypeBox 模式定义。