网关如何报告哪些节点已连接,以及哪些服务器推送的事件会到达特定会话¶
在线状态¶
system-presence返回以设备身份为键的条目,包括deviceId、roles和scopes,因此当同一设备同时以操作员和节点身份连接时,UI 仍可按设备逐行显示。node.list包含可选的lastSeenAtMs和lastSeenReason。已连接的节点以connect作为原因报告当前连接时间;已配对的节点还可以通过受信任的节点事件报告持久的后台在线状态。
原生 macOS 节点还可以发送经过认证的 node.presence.activity 事件,其中包含受限的输入空闲时间以及可选的 source:app 表示与 OpenClaw 的交互,system 表示系统级的物理活动。仅限应用本地的报告不需要辅助功能权限;系统级报告则需要。省略 source 时保留旧有的系统级权限要求。网关基于自身时钟推导活动时间戳,通过 node.list 和 node.describe 暴露最新连接的 Mac,并向具有读取权限的客户端广播 node.presence 更新。
当系统级检测被禁用时,应用发送 { "action": "clear" },然后报告任何观察到的应用本地活动。当辅助功能权限丢失时,它回退到应用本地活动;如果未观察到任何活动,则清除样本。网关仅清除该确切认证节点连接的时间戳。早于此确认操作的网关会将其作为未处理事件返回,因此 Mac 节点会重连一次,让断开连接清理程序移除旧连接状态。关于选择、隐私、模型上下文和通知路由行为,请参阅活动计算机在线状态。
节点主机统计信息¶
已连接的 CLI 节点主机以及 macOS 应用共享的节点主机工作进程在连接后立即发送资源快照,此后每 60 秒发送一次。它们调用 node.event,使用 event: "node.host.stats" 和对象 payload(或其 JSON 编码形式 payloadJSON):
{
"event": "node.host.stats",
"payload": {
"cpuCount": 8,
"loadAverage": [1.25, 1.1, 0.9],
"memoryTotalBytes": 17179869184,
"memoryFreeBytes": 4294967296,
"diskTotalBytes": 1000000000000,
"diskAvailableBytes": 250000000000
}
}
cpuCount 是 1 到 4096 之间的整数。可选的 loadAverage 包含 1 分钟、5 分钟和 15 分钟的平均值,每个值都是有限数且介于 0 到 100000 之间。Windows 没有负载平均值;当三个读数均为零时,主机省略该字段。内存和磁盘值为非负整数字节,空闲或可用字节数不超过其总数。仅当主机可以读取包含其主目录的卷的容量时,磁盘字段才同时出现,这与工作进程的当前目录无关。
网关仅接受来自当前节点连接的更新,并使用自身的接收时间标记 updatedAtMs;节点从不发送时间戳。成功的更新会作为 hostStats 出现在 node.list 和 node.describe 中,并向具有读取权限的操作员广播 node.hostStats(包含 { nodeId, hostStats }),使用 dropIfSlow: true。统计信息面向操作员,不更新模型可见的节点上下文。收到后,网关将快照作为 lastHostStats 持久化到配对节点记录上。断开连接或重新连接而无需新快照时,先前的值保持不变。node.list 和 node.describe 在连接期间使用实时会话统计信息,离线时将保存的快照作为 hostStats 投影展示,并保持其原始 updatedAtMs,以便客户端能够显示最后已知的时效。
结构化 node.event 结果使用 reason: "updated"、"stale_connection" 或 "invalid_payload"。较旧的网关可能返回 handled: false;节点按正常节奏继续,不进行立即重试。
节点后台存活事件¶
节点调用 node.event,使用 event: "node.presence.alive" 来记录配对节点在后台唤醒期间仍然存活,但不将其标记为已连接:
{
"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。未知值规范化(normalize)为 background(src/shared/node-presence.ts)。该事件仅为已认证的节点设备会话持久化;无设备或未配对的会话返回 handled: false。
成功的网关返回结构化结果:
较旧的网关可能仅对 node.event 返回 { "ok": true };请将其视为已确认的 RPC,而非持久的在线状态持久化。
广播事件的范围限定¶
服务器推送的广播事件受范围限制(scope-gated),因此配对范围或仅节点会话不会被动接收会话内容(src/gateway/server-broadcast.ts):
- 聊天、代理和工具结果帧(流式
agent事件、工具结果事件)至少需要operator.read。没有该权限的会话会完全跳过这些帧。 - 插件定义的
plugin.*广播默认受operator.write或operator.admin限制;显式条目如plugin.approval.requested/plugin.approval.resolved则改用operator.approvals。 - 在线状态事件需要操作员读取权限(
operator.read,operator.write或operator.admin也可满足要求)。被监视会话(watched-session)引用会针对每个接收者进行过滤,包括在 hello 快照和system-presence回复中。 - 传输事件(如
heartbeat和tick)仍然对所有已认证会话可用。 - 未知的广播事件族默认受范围限制(fail-closed,即失败时关闭),除非注册的处理程序明确放宽限制。
每个客户端连接维护自己的每客户端序列号,因此即使不同客户端看到事件流中不同的范围过滤子集,广播在特定套接字上仍保持单调有序。
hello-ok.features.capabilities 声明增量式 wire 契约。原生客户端仅在存在 session-scoped-chat-metadata 时,才会在 chat.metadata 中发送 sessionKey;否则它们保留由稳定版 v2026.7.1-2 支持的仅 agent 请求。该旧响应描述的是 agent 范围的可用性,而不是某个会话所选的 profile。只有当最低支持的 Gateway 契约保证会话范围元数据时,才应弃用此协商。仅方法或事件的存在并不足够。
本页原文 Markdown:在 AtomGit 查看·内容源自开源项目 cl/openclaw