跳转至

传输与帧

在任何方法调用之前,线路上的内容如下:已发布的包、帧形状、负载限制,以及由 Gateway 控制的 WebRTC Talk 契约。

npm 包

有关已验证的稳定版本、精确版本命令和兼容性指南,请遵循安装这些包。 包发布版本独立于线路协议版本和根 openclaw CLI 发布版本。

  • @openclaw/gateway-protocol 发布模式、验证器、TypeScript 类型、轻量级帧和错误辅助函数,以及版本常量。其 tarball 将生成的 protocol.schema.json 机器可读契约作为可下载文件包含在内,而不是作为导出的导入子路径。
  • @openclaw/gateway-client 发布参考 Node 客户端,以及位于 @openclaw/gateway-client/browser 的浏览器安全入口。

有关应用生命周期指南,请参阅 构建 Gateway 客户端。对于将 Gateway 作为子进程监管的应用,请参阅 嵌入 OpenClaw。

传输与帧格式

  • WebSocket、文本帧、JSON 负载。
  • 第一帧必须是 connect 请求。
  • 默认预算允许每个解析后的客户端 IP 有 128 个未认证的未完成连接。成功认证或关闭会释放该槽位。 有关共享 NAT 行为和环境变量覆盖,请参阅认证前连接限制。
  • 连接前帧的上限为 64 KiB(MAX_PREAUTH_PAYLOAD_BYTES)。握手后,遵循 hello-ok.policy.maxPayload 和 hello-ok.policy.maxBufferedBytes。启用诊断时,在 Gateway 关闭或丢弃帧之前,超大的入站帧和缓慢的出站缓冲区会发出 payload.large 事件。这些事件携带 surface、字节大小、限制和安全原因代码,绝不携带消息正文、附件内容、原始帧字节、令牌、Cookie 或机密。
  • Gateway 不会协商 permessage-deflate。启用该扩展时,浏览器甚至可以压缩极小的请求;随后串行解压会在处理器调度之前,让每个请求排在繁忙的事件循环轮次之后,从而造成延迟。未压缩帧以更大的历史数据和名册带宽为代价,保持了对请求突发的高响应性。负载限制保持不变。

帧形状:

  • 请求:{type:"req", id, method, params, traceparent?, expectedProfileId?}
  • 响应:{type:"res", id, ok, payload|error}
  • 事件:{type:"event", event, payload, seq?, stateVersion?, recipientProfileId?}

实时文本在初始接收方快照之后使用追加增量。外层事件序列间隙表示客户端可能丢失了该基线的部分内容:在应用更多增量之前,应退役连接并重新连接。如果揭示间隙的帧是 chat 最终、中止或错误事件,请在间隙回调退役连接之前,交付其权威终止结果和提供的完整快照。这可以让已完成的运行正常结束,即使没有更多实时文本可供重放。重新连接后,更新会话订阅;Gateway 会为每个观察到的运行随下一个文本帧发送完整快照。运行本地负载序列可以跳过编号,因为文本会进行节奏控制和合并;它们不是外层连接序列。

在多个视图之间共享一个连接的客户端,必须让重建工作与其本地流所有者保持一致。新的本地监听器可能在线路快照已交付给另一个视图之后加入。请从该所有者的当前状态初始化它,或交付重建的本地快照,并在其连接或运行退役时清除该状态。仅持久化历史并不构成有序的实时文本基线。

认证后,客户端可以在每个请求帧中包含 W3C traceparent 字符串。Gateway 会将有效值作为该请求的子跟踪上下文继续传递。在 128 字符字段限制内,缺失或语法格式错误的值会保留默认的全新请求跟踪,并且不会导致 RPC 失败;更长的值会使请求帧无效。初始 connect 请求绝不会为后续帧建立跟踪上下文。在长连接上,为每个逻辑请求使用单独的 traceparent;不要将 WebSocket 本身视为一个跟踪。

响应错误使用 { code, message, details?, retryable?, retryAfterMs? }。已认证的操作员请求共享一个有界队列,用于启动 RPC 处理器。没有审批重放的小型 sessions.messages.subscribe 请求和 sessions.messages.unsubscribe 请求具有单独的有界等待容量,包括每连接限制。它们与其他请求保持相同的 FIFO 顺序和让出预算。名册快照和审批重放保留普通请求预算。 当等待容量耗尽时,Gateway 会在方法运行之前返回可重试的 UNAVAILABLE;请在请求预算内重试。已启动的请求会并发完成,因此响应可能乱序到达。

在协作式挂起期间,身份读取(agent.identity.get)会在共享的浏览器/CLI 客户端中等待阶段为 accepting 的 gateway.suspension。带有 details.reason: "gateway-suspending" 的可重试 UNAVAILABLE 也会使读取进入等待状态,如果错过恢复事件,则使用 retryAfterMs(60 秒)作为回退。原始请求的截止时间和取消仍然适用。断开连接会正常完成待处理的读取,并使用现有的重连退避。此身份读取策略既不会使写入进入等待状态,也不会重放写入。

普通 UI/SDK 请求可能比套接字断开连接存活更久,但无法在正在退役的 Gateway 实例中启动处理器。关闭会阻止新请求进入,并在释放其运行时之前等待待处理的处理器加载和授权完成。已启动的方法保留其自身的关闭行为;关闭不会等待每个 RPC 完成。在节点清理期间,精确的待处理节点进度和结果回复仍然可用,直到传输关闭封闭入口。

客户端应根据 code 和 details.code 进行分支处理;message 保持人类可读形式,除非兼容性说明另有规定,否则可能随时更改。方法级授权失败使用顶层 code: "FORBIDDEN",并附带结构化的缺失作用域详细信息:

  • 缺失作用域:{ code: "MISSING_SCOPE", missingScope, requiredScopes }。requiredScopes 是所请求操作的完整已知作用域集合。为兼容旧客户端,保留旧版 missing scope: <scope> 消息。

客户端应首先读取 details,仅将旧版消息用作兼容性回退。readMissingScopeError 和 readMissingScopeErrorDetails 从 @openclaw/gateway-protocol/gateway-error-details 导出;浏览器安全的 gateway 客户端从 @openclaw/gateway-client/browser 重新导出它们。

这些 schema 以 GatewayErrorDetailsSchema、MissingScopeErrorDetailsSchema 的形式从 @openclaw/gateway-protocol/schema 导出。HTTP 作用域失败会在 error.details 下镜像 MISSING_SCOPE 对象,并使用 HTTP 状态码 403。

具有副作用的方法需要幂等键(参见 schema)。

Profile 绑定

仅当 hello-ok.features.capabilities 包含 profile-binding-v1 时才使用 Profile 绑定。需要此契约的客户端在能力缺失时必须将其报告为不可用,而不是静默发送未绑定的操作。省略 expectedProfileId 的请求保持现有行为。

expectedProfileId 是认证请求帧上的可选不透明字符串,长度为 1 到 128 个字符。Gateway 会将其与认证主体的当前规范 Profile ID 进行精确比较。它不会对期望值进行修剪、折叠大小写或解析合并别名。从 users.self 获取该 ID;Gateway URL、账户标签、代理 ID 或会话密钥都不是 Profile ID。缺少已认证 Profile 无法满足此前置条件。

声明该能力的服务器会在 RPC 入口处以及返回响应负载之前检查此前置条件。提交时的重新验证因方法而异;该能力不承诺在任意方法或插件内部提供原子性。入口检查后跟异步工作本身并不构成提交保证。

结构化错误将 error.details.reason 设置为 EXPECTED_PROFILE_MISMATCH,并在 error.details.execution 中携带每次尝试的分类:

  • not_started:此尝试未启动任何执行。
  • may_have_executed:方法可能已在检测到不匹配之前运行;该错误不构成回滚的证据。

这两种分类都不会消除先前尝试的不确定性,也不会覆盖已知的确认(ACK)。在重试不确定的工作之前,请保留原始幂等键并核对先前的结果。普通的 socket 断开不会取消已接受的工作。

在已认证的操作者广播中,可选的 recipientProfileId 在发布时标识接收者的规范 Profile。它是每个接收者的帧事实,而非事件来源、运行所有者身份或授权许可。现有的事件权限和订阅仍然控制投递。将消费者同时绑定到其物理 Gateway 连接和所选 Profile;如果接收者字段缺失或不一致,则停止将该事件应用于该绑定视图或操作,并上报绑定失败。

此契约不涵盖预认证事件、节点事件投递、APNs 通知或进程内发布。它不会撤销 provider-direct 媒体或已签发的 WebRTC 凭据,也不承诺立即撤销保留的会话。

连接保活

已认证的控制连接使用 WebSocket ping/pong 保活机制。这与定时代理心跳是分开的;禁用代理心跳不会禁用连接监控。

排在传出数据之后的 ping 由传输不活跃状态决定,包括部分写入进度和传入流量。一旦其写入完成,对端将获得完整的 25 秒 pong 窗口;不相关的传入消息不会延长该窗口。周期性检查会关闭已过期的连接并释放其所有者。传输不活跃并不是独立的仅写截止时间:发送流量的对端可以保持排队的写入存活。现有的慢消费者缓冲区限制仍然适用。流式传输通道保留其流所有者生命周期策略。

Gateway 控制的 WebRTC Talk

talk.client.create 接受附加能力 gateway-control-v1。已发布的浏览器/Gateway 拥有的 WebRTC 路由首先尝试 OAuth,然后回退到 Platform API 密钥认证。直接的后端 socket 以及未列出的或私有实时路由需要 Platform API 密钥认证。成功的结果包括 clientControl: { owner: "gateway" }、clientSecret 中的 60 秒一次性 Gateway broker 令牌,以及相对路径 offerUrl: "/plugins/openai/realtime/calls"。

客户端仅携带 broker 令牌向该路由发送 application/sdp。它不得创建 provider 控制数据通道。Gateway 负责创建通话,在返回 answer SDP 之前附加 provider sideband,并拥有工具、转录、引导、取消和关闭的生命周期。省略该能力的客户端保留现有的浏览器会话行为。无法提供所请求所有者的 Gateway 或配置的认证路径会返回 UNAVAILABLE;它绝不会将请求降级为客户端拥有的控制。

如果 Gateway 连接丢失,或当前 voiceSessionId 的 talk.event 包含 talkEvent.type: "session.closed",客户端必须关闭其本地媒体对端。忽略其他通话的终止事件;仅出现可恢复的 session.error 并不构成关闭通知。

本页原文 Markdown:在 AtomGit 查看·内容源自开源项目 cl/openclaw