在线状态(Presence)

OpenClaw 的”在线状态”是一个轻量级、尽力而为的视图,展示:

  • Gateway 自身的信息
  • 连接到 Gateway 的客户端(Mac 应用、WebChat、CLI 等)

在线状态主要用于渲染 macOS 应用的 Instances 选项卡,以及帮助运维人员快速了解当前连接情况。

Presence 字段(显示哪些信息)

Presence 条目是结构化对象,包含以下字段:

  • instanceId(可选但强烈建议提供):稳定的客户端标识(通常取自 connect.client.instanceId
  • host:可读的主机名
  • ip:尽力获取的 IP 地址
  • version:客户端版本号
  • deviceFamily / modelIdentifier:硬件信息提示
  • modeuiwebchatclibackendprobetestnode
  • lastInputSeconds:距离上次用户输入的秒数(如果可知)
  • reasonselfconnectnode-connectedperiodic
  • ts:最后更新的时间戳(毫秒级 epoch)

数据来源(Presence 从哪来)

Presence 条目由多个来源产生,最终合并在一起。

1) Gateway 自身条目

Gateway 启动时会自动生成一条”self”条目,这样即使还没有客户端连接,UI 也能显示 Gateway 主机信息。

2) WebSocket 连接

每个 WS 客户端都以 connect 请求开始握手。握手成功后,Gateway 会为该连接创建或更新一条 Presence 条目。

为什么一次性 CLI 命令不会出现

CLI 经常只是为了执行一次性命令而短暂连接。为避免刷屏 Instances 列表,client.mode === "cli" 的连接不会生成 Presence 条目。

3) system-event 信标

客户端可以通过 system-event 方法发送更丰富的周期性信标。Mac 应用会通过这种方式上报主机名、IP 和 lastInputSeconds

4) 节点连接(role: node)

当节点以 role: node 通过 Gateway WebSocket 连接时,Gateway 会为该节点创建或更新一条 Presence 条目(与其他 WS 客户端流程相同)。

合并与去重规则(为什么 instanceId 重要)

Presence 条目存储在一个内存中的 map 里:

  • 条目以 presence key 为键。
  • 最佳的 key 是稳定的 instanceId(来自 connect.client.instanceId),它在重启后依然有效。
  • key 不区分大小写。

如果客户端重连时没有提供稳定的 instanceId,就可能在列表中出现重复行

TTL 与容量上限

Presence 本身就是临时性的:

  • TTL: 超过 5 分钟的条目会被清除
  • 最大条目数: 200(最旧的优先丢弃)

这确保了列表始终是新鲜的,也避免了无限制的内存增长。

远程/隧道场景(回环 IP)

当客户端通过 SSH 隧道或本地端口转发连接时,Gateway 可能会看到远程地址为 127.0.0.1。为了避免覆盖掉客户端上报的真实 IP,回环地址会被忽略。

消费方

macOS Instances 选项卡

macOS 应用渲染 system-presence 的输出,并根据最后更新的时间显示状态指示器(Active/Idle/Stale)。

调试技巧

  • 查看原始列表,可以向 Gateway 发起 system-presence 调用。
  • 如果看到重复条目:
    • 确认客户端在握手时发送了稳定的 client.instanceId
    • 确认周期性信标使用了相同的 instanceId
    • 检查连接生成的条目是否缺少 instanceId(缺少时出现重复是预期行为)