网关
Gateway 网关协议
Gateway 网关 WS 协议是 OpenClaw 的单一控制平面 + 节点传输协议。所有客户端(CLI、Web UI、macOS 应用、iOS/Android 节点、无头节点)都通过 WebSocket 连接,并在握手时声明它们的角色 + 作用域。
传输
- WebSocket,带 JSON 负载的文本帧。
- 第一帧必须是
connect请求。 - 连接前帧限制为 64 KiB。握手成功后,客户端应遵循
hello-ok.policy.maxPayload和hello-ok.policy.maxBufferedBytes限制。启用诊断后,超大的入站帧和缓慢的出站缓冲区会在 Gateway 网关关闭或丢弃受影响帧之前发出payload.large事件。这些事件会保留大小、限制、表面和安全原因代码。它们不会保留消息正文、附件内容、原始帧正文、令牌、Cookie 或机密值。
握手(connect)
Gateway 网关 → 客户端(连接前挑战):
{
"type": "event",
"event": "connect.challenge",
"payload": { "nonce": "…", "ts": 1737264000000 }
}
客户端 → Gateway 网关:
{
"type": "req",
"id": "…",
"method": "connect",
"params": {
"minProtocol": 4,
"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 时,connect 请求可能返回可重试的 UNAVAILABLE 错误,其中 details.reason 设置为 "startup-sidecars",并带有 retryAfterMs。客户端应在其整体连接预算内重试该响应,而不是将其呈现为终止性的握手失败。
server、features、snapshot 和 policy 都是 schema(src/gateway/protocol/schema/frames.ts)要求的字段。auth 也是必需字段,并报告协商后的角色/作用域。pluginSurfaceUrls 是可选字段,会将插件界面名称(例如 canvas)映射到限定作用域的托管 URL。
限定作用域的插件界面 URL 可能会过期。节点可以使用 { "surface": "canvas" } 调用 node.pluginSurface.refresh,以在 pluginSurfaceUrls 中收到新的条目。实验性的 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")在通过共享的 Gateway 网关令牌/密码进行认证时,可以在直接 local loopback 连接上省略 device。此路径保留给内部控制平面 RPC,并避免过期的 CLI/设备配对基线阻塞本地后端工作,例如子智能体会话更新。远程客户端、浏览器源客户端、节点客户端,以及显式设备令牌/设备身份客户端仍使用正常的配对和作用域升级检查。
当签发设备令牌时,hello-ok 还会包含:
{
"auth": {
"deviceToken": "…",
"role": "operator",
"scopes": ["operator.read", "operator.write"]
}
}
在受信任的 bootstrap 交接期间,hello-ok.auth 还可能在 deviceTokens 中包含额外的有界角色条目:
{
"auth": {
"deviceToken": "…",
"role": "node",
"scopes": [],
"deviceTokens": [
{
"deviceToken": "…",
"role": "operator",
"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 角色仍需要其自身角色前缀下的作用域。
节点示例
{
"type": "req",
"id": "…",
"method": "connect",
"params": {
"minProtocol": 4,
"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?}
具有副作用的方法需要幂等键(见 schema)。
角色 + 作用域
关于完整的 operator 作用域模型、审批时检查和共享密钥语义,请参阅 Operator 作用域。
角色
operator= 控制平面客户端(CLI/UI/自动化)。node= 能力主机(camera/screen/canvas/system.run)。
作用域(operator)
常用作用域:
operator.readoperator.writeoperator.adminoperator.approvalsoperator.pairingoperator.talk.secrets
带有 includeSecrets: true 的 talk.config 需要 operator.talk.secrets(或 operator.admin)。
插件注册的 Gateway 网关 RPC 方法可以请求自己的 operator 作用域,但保留的核心 admin 前缀(config.*、exec.approvals.*、wizard.*、update.*)始终解析为 operator.admin。
方法作用域只是第一道门槛。某些通过 chat.send 触达的斜杠命令会在其上应用更严格的命令级检查。例如,持久化的 /config set 和 /config unset 写入需要 operator.admin。
node.pair.approve 还会在基础方法作用域之上进行额外的审批时作用域检查:
- 无命令请求:
operator.pairing - 带有非 exec 节点命令的请求:
operator.pairing+operator.write - 包含
system.run、system.run.prepare或system.which的请求:operator.pairing+operator.admin
能力/命令/权限(节点)
节点在连接时声明能力声明:
caps:高级能力类别,例如camera、canvas、screen、location、voice和talk。commands:用于调用的命令允许列表。permissions:细粒度开关(例如screen.record、camera.capture)。
Gateway 网关将这些视为声明,并执行服务端允许列表。
在线状态
system-presence返回按设备身份键控的条目。- 在线状态条目包括
deviceId、roles和scopes,因此 UI 可以为每个设备显示单行,即使它同时以 operator 和 node 连接。 node.list包含可选的lastSeenAtMs和lastSeenReason字段。已连接节点会将其当前连接时间报告为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 是封闭枚举:background、silent_push、bg_app_refresh、significant_location、manual 或 connect。未知触发字符串会在持久化前由 Gateway 网关规范化为 background。该事件仅对已认证的节点设备会话持久化;无设备或未配对的会话会返回 handled: false。
成功的 Gateway 网关会返回结构化结果:
{
"ok": true,
"event": "node.presence.alive",
"handled": true,
"reason": "persisted"
}
较旧的 Gateway 网关仍可能为 node.event 返回 { "ok": true };客户端应将其视为已确认的 RPC,而不是持久在线状态的持久化。
广播事件作用域限定
服务端推送的 WebSocket 广播事件受作用域门控,因此仅配对作用域或仅节点的会话不会被动接收会话内容。
- 聊天、智能体和工具结果帧(包括流式
agent事件和工具调用结果)至少需要operator.read。没有operator.read的会话会完全跳过这些帧。 - 插件定义的
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 的完整枚举。
System and identity
health返回缓存的或新探测的 Gateway 网关健康快照。diagnostics.stability返回最近的有界诊断稳定性记录器。它会保留操作元数据,例如事件名称、计数、字节大小、内存读数、队列/会话状态、渠道/插件名称和会话 ID。它不会保留聊天文本、webhook 正文、工具输出、原始请求或响应正文、令牌、Cookie 或机密值。需要 operator read 作用域。status返回/status风格的 Gateway 网关摘要;敏感字段仅包含在 admin 作用域的 operator 客户端中。gateway.identity.get返回 relay 和配对流程使用的 Gateway 网关设备身份。system-presence返回已连接 operator/node 设备的当前在线状态快照。system-event追加系统事件,并可以更新/广播在线状态上下文。last-heartbeat返回最新的持久化 Heartbeat 事件。set-heartbeats切换 Gateway 网关上的 Heartbeat 处理。
Models 和用量
models.list返回运行时允许的模型目录。传入{ "view": "configured" }可获取适合选择器大小的已配置模型(先是agents.defaults.models,再是models.providers.*.models),或传入{ "view": "all" }获取完整目录。usage.status返回提供商用量窗口和剩余额度摘要。usage.cost返回某个日期范围内的聚合成本用量摘要。doctor.memory.status返回活动默认智能体工作区的向量记忆 / 缓存 embedding 就绪状态。只有当调用方明确需要实时 ping embedding 提供商时,才传入{ "probe": true }或{ "deep": true }。doctor.memory.remHarness为远程控制平面客户端返回一个有界、只读的 REM harness 预览。它可以包含工作区路径、记忆片段、渲染后的有依据 markdown,以及深度提升候选项,因此调用方需要operator.read。sessions.usage返回按会话划分的用量摘要。sessions.usage.timeseries返回一个会话的时间序列用量。sessions.usage.logs返回一个会话的用量日志条目。
渠道和登录辅助工具
channels.status返回内置 + 捆绑渠道/插件状态摘要。channels.logout会在渠道支持登出的情况下,登出特定渠道/账号。web.login.start为当前支持 QR 的 Web 渠道提供商启动 QR/web 登录流程。web.login.wait等待该 QR/web 登录流程完成,并在成功后启动渠道。push.test向已注册的 iOS 节点发送测试 APNs 推送。voicewake.get返回已存储的唤醒词触发器。voicewake.set更新唤醒词触发器并广播变更。
消息和日志
send是直接出站投递 RPC,用于在聊天运行器之外按渠道/账号/线程目标发送消息。logs.tail返回已配置的 Gateway 网关文件日志尾部内容,并带有游标/限制和最大字节控制。
Talk 和 TTS
talk.catalog返回只读 Talk 提供商目录,覆盖语音、流式转写和实时语音。它包含提供商 ID、标签、配置状态、公开的模型/语音 ID、规范模式、传输协议、brain 策略和实时音频/能力标志,且不会返回提供商 secret 或修改全局配置。talk.config返回有效的 Talk 配置载荷;includeSecrets需要operator.talk.secrets(或operator.admin)。talk.session.create为realtime/gateway-relay、transcription/gateway-relay或stt-tts/managed-room创建一个由 Gateway 网关拥有的 Talk 会话。brain: "direct-tools"需要operator.admin。talk.session.join校验 managed-room 会话令牌,按需发出session.ready或session.replaced事件,并返回房间/会话元数据以及最近的 Talk 事件,不包含明文令牌或已存储的令牌哈希。talk.session.appendAudio向 Gateway 网关拥有的实时中继和转写会话追加 base64 PCM 输入音频。talk.session.startTurn、talk.session.endTurn和talk.session.cancelTurn驱动 managed-room 轮次生命周期,并在状态清除前拒绝过期轮次。talk.session.cancelOutput停止助手音频输出,主要用于 Gateway 网关中继会话中由 VAD 门控的插话。talk.session.submitToolResult完成由 Gateway 网关拥有的实时中继会话发出的提供商工具调用。talk.session.close关闭 Gateway 网关拥有的中继、转写或 managed-room 会话,并发出终止 Talk 事件。talk.mode为 WebChat/Control UI 客户端设置/广播当前 Talk 模式状态。talk.client.create使用webrtc或provider-websocket创建客户端拥有的实时提供商会话,同时 Gateway 网关拥有配置、凭证、指令和工具策略。talk.client.toolCall允许客户端拥有的实时传输协议将提供商工具调用转发给 Gateway 网关策略。第一个支持的工具是openclaw_agent_consult;客户端会收到一个运行 ID,并在提交提供商特定工具结果前等待正常聊天生命周期事件。talk.event是用于实时、转写、STT/TTS、managed-room、电话和会议适配器的单一 Talk 事件渠道。talk.speak通过活动的 Talk 语音提供商合成语音。tts.status返回 TTS 启用状态、活动提供商、后备提供商以及提供商配置状态。tts.providers返回可见的 TTS 提供商清单。tts.enable和tts.disable切换 TTS 偏好设置状态。tts.setProvider更新首选 TTS 提供商。tts.convert执行一次性文本转语音转换。
Secret、配置、更新和向导
secrets.reload重新解析活动 SecretRef,并且只在完全成功时替换运行时 secret 状态。secrets.resolve为特定命令/目标集合解析命令目标 secret 分配。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 网关更新流程,并且只在更新本身成功时安排重启;带会话的调用方可以包含continuationMessage,以便启动后通过重启延续队列恢复一个后续智能体轮次。包管理器更新会在包替换后强制执行非延迟、无冷却时间的更新重启,因此旧 Gateway 网关进程不会继续从已替换的dist树中懒加载。update.status返回最新缓存的更新重启哨兵,包括可用时重启后的运行版本。wizard.start、wizard.next、wizard.status和wizard.cancel通过 WS RPC 暴露新手引导向导。
智能体和工作区辅助工具
agents.list返回已配置的智能体条目,包括有效模型和运行时元数据。agents.create、agents.update和agents.delete管理智能体记录和工作区布线。agents.files.list、agents.files.get和agents.files.set管理为智能体公开的引导工作区文件。artifacts.list、artifacts.get和artifacts.download为显式sessionKey、runId或taskId作用域公开从 transcript 派生的 artifact 摘要和下载。运行和任务查询在服务器端解析所属会话,并且只返回来源匹配的 transcript 媒体;不安全或本地 URL 来源会返回不支持的下载,而不是在服务器端抓取。environments.list和environments.status为 SDK 客户端公开只读 Gateway 网关本地和节点环境发现。agent.identity.get返回智能体或会话的有效助手身份。agent.wait等待运行完成,并在可用时返回终止快照。
会话控制
sessions.list返回当前会话索引,包括配置了智能体运行时后端时每行的agentRuntime元数据。sessions.subscribe和sessions.unsubscribe为当前 WS 客户端切换会话变更事件订阅。sessions.messages.subscribe和sessions.messages.unsubscribe为一个会话切换 transcript/消息事件订阅。sessions.preview返回特定会话键的有界 transcript 预览。sessions.describe返回精确会话键对应的一行 Gateway 网关会话。sessions.resolve解析或规范化会话目标。sessions.create创建新的会话条目。sessions.send向现有会话发送消息。sessions.steer是活动会话的中断并 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 载荷(包括<tool_call>...</tool_call>、<function_call>...</function_call>、<tool_calls>...</tool_calls>、<function_calls>...</function_calls>和被截断的工具调用块)以及泄漏的 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将节点发起的事件带回 Gateway 网关。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管理 Gateway 网关执行审批策略快照。exec.approvals.node.get和exec.approvals.node.set通过节点中继命令管理节点本地执行审批策略。plugin.approval.request、plugin.approval.list、plugin.approval.waitDecision和plugin.approval.resolve涵盖插件定义的审批流程。
自动化、Skills 和工具
- 自动化:
wake调度立即或下一次 Heartbeat 的唤醒文本注入;cron.list、cron.status、cron.add、cron.update、cron.remove、cron.run、cron.runs管理定时工作。 - Skills 和工具:
commands.list、skills.*、tools.catalog、tools.effective、tools.invoke。
常见事件族
chat:UI 聊天更新,例如chat.inject和其他仅用于转录记录的聊天 事件。session.message和session.tool:已订阅会话的转录记录/事件流更新。sessions.changed:会话索引或元数据已更改。presence:系统在线状态快照更新。tick:周期性保活/存活事件。health:Gateway 网关健康状况快照更新。heartbeat:Heartbeat 事件流更新。cron:cron 运行/作业变更事件。shutdown:Gateway 网关关闭通知。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获取当前技能可执行文件列表, 用于自动允许检查。
操作者辅助方法
- 操作者可以调用
commands.list(operator.read)获取某个智能体的运行时 命令清单。agentId是可选的;省略它会读取默认 Agent 工作区。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是必需的。- Gateway 网关会在服务器端从会话派生受信任的运行时上下文,而不是接受 调用方提供的认证或递送上下文。
- 响应按会话限定范围,并反映活跃对话当前可以使用的内容, 包括核心、插件和渠道工具。
- 操作者可以调用
tools.invoke(operator.write),通过与/tools/invoke相同的 Gateway 网关策略路径调用一个可用工具。name是必需的。args、sessionKey、agentId、confirm和idempotencyKey是可选的。- 如果
sessionKey和agentId都存在,解析出的会话智能体必须匹配agentId。 - 响应是面向 SDK 的信封,包含
ok、toolName、可选的output,以及带类型的error字段。审批或策略拒绝会在载荷中返回ok:false,而不是 绕过 Gateway 网关工具策略流水线。
- 操作者可以调用
skills.status(operator.read)获取某个智能体的可见 技能清单。agentId是可选的;省略它会读取默认 Agent 工作区。- 响应包含资格状态、缺失要求、配置检查,以及 已清理的安装选项,不会暴露原始密钥值。
- 操作者可以调用
skills.search和skills.detail(operator.read)获取 ClawHub 发现元数据。 - 操作者可以用两种模式调用
skills.install(operator.admin):- ClawHub 模式:
{ source: "clawhub", slug, version?, force? }将 技能文件夹安装到默认 Agent 工作区的skills/目录。 - Gateway 网关安装器模式:
{ name, installId, dangerouslyForceUnsafeInstall?, timeoutMs? }在 Gateway 网关主机上运行声明的metadata.openclaw.install操作。
- ClawHub 模式:
- 操作者可以用两种模式调用
skills.update(operator.admin):- ClawHub 模式会更新一个已跟踪的 slug,或默认 Agent 工作区中所有已跟踪的 ClawHub 安装项。
- 配置模式会修补
skills.entries.<skillKey>的值,例如enabled、apiKey和env。
models.list 视图
models.list 接受一个可选的 view 参数:
- 省略或
"default":当前运行时行为。如果已配置agents.defaults.models,响应就是允许的目录;否则响应是完整 Gateway 网关目录。 "configured":适合选择器大小的行为。如果已配置agents.defaults.models,它仍然优先生效。否则响应使用显式的models.providers.*.models条目,只有在不存在已配置模型行时才回退到完整目录。"all":完整 Gateway 网关目录,绕过agents.defaults.models。将它用于诊断和发现 UI,而不是常规模型选择器。
执行审批
- 当执行请求需要审批时,Gateway 网关会广播
exec.approval.requested。 - 操作者客户端通过调用
exec.approval.resolve进行处理(需要operator.approvals作用域)。 - 对于
host=node,exec.approval.request必须包含systemRunPlan(规范的argv/cwd/rawCommand/会话元数据)。缺少systemRunPlan的请求会被拒绝。 - 审批后,转发的
node.invoke system.run调用会复用该规范的systemRunPlan,作为权威命令/cwd/会话上下文。 - 如果调用方在准备阶段和最终获批的
system.run转发之间修改了command、rawCommand、cwd、agentId或sessionKey,Gateway 网关会拒绝运行,而不是信任被修改的载荷。
智能体递送回退
agent请求可以包含deliver=true来请求出站递送。bestEffortDeliver=false保持严格行为:无法解析或仅限内部的递送目标会返回INVALID_REQUEST。bestEffortDeliver=true允许在无法解析外部可递送路由时回退到仅会话执行(例如内部/webchat 会话或含糊的多渠道配置)。
版本控制
PROTOCOL_VERSION位于src/gateway/protocol/version.ts。- 客户端发送
minProtocol+maxProtocol;服务器会拒绝不匹配项。 - schema 和模型由 TypeBox 定义生成:
pnpm protocol:genpnpm protocol:gen:swiftpnpm protocol:check
客户端常量
src/gateway/client.ts 中的参考客户端使用这些默认值。这些值在
协议 v4 中保持稳定,并且是第三方客户端的预期基线。
| 常量 | 默认值 | 来源 |
|---|---|---|
PROTOCOL_VERSION |
4 |
src/gateway/protocol/version.ts |
| 请求超时(每个 RPC) | 30_000 ms |
src/gateway/client.ts(requestTimeoutMs) |
| 预认证/连接质询超时 | 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 |
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 |
MAX_PAYLOAD_BYTES |
25 * 1024 * 1024(25 MB) |
src/gateway/server-constants.ts |
服务器会在 hello-ok 中公布生效的 policy.tickIntervalMs、policy.maxPayload
和 policy.maxBufferedBytes;客户端应遵守这些值,而不是预握手默认值。
认证
- 共享密钥 Gateway 网关认证使用
connect.params.auth.token或connect.params.auth.password,具体取决于配置的认证模式。 - Tailscale Serve(
gateway.auth.allowTailscale: true)或非 loopbackgateway.auth.mode: "trusted-proxy"等携带身份的模式,会通过 请求标头满足 connect 认证检查,而不是使用connect.params.auth.*。 - 私有入口
gateway.auth.mode: "none"会完全跳过共享密钥 connect 认证; 不要在公开/不受信任的入口上暴露该模式。 - 配对后,Gateway 网关会签发一个作用域限定为连接角色 + 作用域的设备令牌。
它会在
hello-ok.auth.deviceToken中返回,并应由客户端持久保存以供后续连接使用。 - 客户端应在任何成功连接后持久保存主要的
hello-ok.auth.deviceToken。 - 使用该已存储设备令牌重新连接时,也应复用为该令牌存储的已批准作用域集合。 这样可以保留已授予的读取/探测/状态访问权限,并避免在重新连接时静默收窄为仅管理员的隐式作用域。
- 客户端侧 connect 认证组装(
selectConnectAuth位于src/gateway/client.ts):auth.password是正交的,并且在设置后始终会转发。auth.token按优先级顺序填充:先使用显式共享令牌, 然后使用显式deviceToken,再使用已存储的按设备令牌(按deviceId+role键控)。- 仅当上述内容都未解析出
auth.token时,才会发送auth.bootstrapToken。共享令牌或任何已解析的设备令牌都会抑制它。 - 在一次性
AUTH_TOKEN_MISMATCH重试中自动提升已存储设备令牌, 仅限于受信任端点:loopback,或带有固定tlsFingerprint的wss://。未固定指纹的公共wss://不符合条件。
- 额外的
hello-ok.auth.deviceTokens条目是引导交接令牌。 仅当连接在受信任传输上使用引导认证时才持久保存它们, 例如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还会根据调用方当前会话作用域检查目标 operator 令牌作用域集合。非管理员调用方不能轮换或撤销比自己已持有范围更广的 operator 令牌。- 认证失败包含
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的行为:- 受信任客户端可以尝试一次有界重试,并使用缓存的按设备令牌。
- 如果该重试失败,客户端应停止自动重连循环,并显示 operator 操作指导。
设备身份 + 配对
- 节点应包含稳定的设备身份(
device.id),该身份派生自 密钥对指纹。 - Gateway 网关按设备 + 角色签发令牌。
- 除非启用了本地自动批准,否则新的设备 ID 需要配对批准。
- 配对自动批准以直接 local loopback 连接为中心。
- OpenClaw 还为受信任的共享密钥辅助流程提供了一个狭窄的后端/容器本地自连接路径。
- 同主机 tailnet 或 LAN 连接在配对时仍被视为远程连接, 并需要批准。
- WS 客户端通常会在
connect期间包含device身份(operator + 节点)。唯一不带设备的 operator 例外是显式信任路径:gateway.controlUi.allowInsecureAuth=true,用于仅 localhost 的不安全 HTTP 兼容性。- 成功的
gateway.auth.mode: "trusted-proxy"operator Control UI 认证。 gateway.controlUi.dangerouslyDisableDeviceAuth=true(应急开关,严重降低安全性)。- 通过共享 Gateway 网关令牌/密码认证的 direct-loopback
gateway-client后端 RPC。
- 所有连接都必须签名服务器提供的
connect.challengenonce。
设备认证迁移诊断
对于仍使用挑战前签名行为的旧版客户端,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 |
公钥格式/规范化失败。 |
迁移目标:
- 始终等待
connect.challenge。 - 签名包含服务器 nonce 的 v2 载荷。
- 在
connect.params.device.nonce中发送同一个 nonce。 - 首选签名载荷是
v3,除了 device/client/role/scopes/token/nonce 字段之外, 它还绑定platform和deviceFamily。 - 为了兼容性,旧版
v2签名仍会被接受,但已配对设备 元数据固定仍会在重新连接时控制命令策略。
TLS + 固定
- WS 连接支持 TLS。
- 客户端可以选择固定 Gateway 网关证书指纹(参见
gateway.tls配置以及gateway.remote.tlsFingerprint或 CLI--tls-fingerprint)。
作用域
该协议暴露完整 Gateway 网关 API(状态、渠道、模型、聊天、
智能体、会话、节点、批准等)。确切表面由
src/gateway/protocol/schema.ts 中的 TypeBox schema 定义。