プレゼンス

OpenClawの「プレゼンス」は、以下の軽量なベストエフォート型ビューです:

  • Gateway自体
  • Gatewayに接続しているクライアント(macアプリ、WebChat、CLIなど)

主にmacOSアプリのインスタンスタブの表示や、運用者がすばやく状況を把握するために使われます。

プレゼンスのフィールド(表示内容)

プレゼンスエントリは以下のようなフィールドを持つ構造化オブジェクトです:

  • instanceId(省略可能だが強く推奨):安定したクライアント識別子(通常はconnect.client.instanceId
  • host:人間が読みやすいホスト名
  • ip:ベストエフォートのIPアドレス
  • version:クライアントのバージョン文字列
  • deviceFamily / modelIdentifier:ハードウェアのヒント情報
  • modeuiwebchatclibackendprobetestnodeなど
  • lastInputSeconds:「最後のユーザー入力からの経過秒数」(判明している場合)
  • reasonselfconnectnode-connectedperiodicなど
  • ts:最終更新タイムスタンプ(エポックからのミリ秒)

プロデューサー(プレゼンスの発生源)

プレゼンスエントリは複数のソースから生成され、マージされます。

1)Gatewayのselfエントリ

Gatewayは起動時に必ず「self」エントリをシードするため、クライアントが接続する前でもUIにゲートウェイホストが表示されます。

2)WebSocket接続

すべてのWSクライアントはconnectリクエストから始まります。ハンドシェイクが成功すると、Gatewayはその接続のプレゼンスエントリをアップサートします。

単発CLIコマンドが表示されない理由

CLIは短時間の単発コマンドで接続することが多いため、インスタンス一覧がスパムされるのを避けるため、client.mode === "cli"の場合はプレゼンスエントリに変換されません

3)system-eventビーコン

クライアントはsystem-eventメソッドを通じて、より詳細な定期ビーコンを送信できます。macアプリはこれを利用してホスト名、IP、lastInputSecondsを報告しています。

4)ノード接続(role: node)

ノードがrole: nodeでGateway WebSocketに接続すると、Gatewayはそのノードのプレゼンスエントリをアップサートします(他のWSクライアントと同じフロー)。

マージと重複排除のルール(instanceIdが重要な理由)

プレゼンスエントリは単一のインメモリマップに保存されます:

  • エントリはプレゼンスキーでキーイングされる
  • 最適なキーは、再起動しても維持される安定したinstanceIdconnect.client.instanceIdから取得)
  • キーは大文字小文字を区別しない

安定したinstanceIdなしでクライアントが再接続すると、重複行として表示される場合があります。

TTLとサイズ上限

プレゼンスは意図的に一時的なものです:

  • TTL: 5分以上前のエントリは削除される
  • 最大エントリ数: 200(古い順に削除)

これにより一覧が常に最新に保たれ、メモリが無制限に増加するのを防ぎます。

リモート/トンネル接続時の注意(ループバックIP)

クライアントがSSHトンネルやローカルポートフォワーディング経由で接続すると、Gatewayにはリモートアドレスが127.0.0.1として見える場合があります。クライアントが報告した正しいIPを上書きしないよう、ループバックのリモートアドレスは無視されます。

コンシューマー

macOSインスタンスタブ

macOSアプリはsystem-presenceの出力をレンダリングし、最終更新からの経過時間に基づいて小さなステータスインジケーター(Active/Idle/Stale)を表示します。

デバッグのヒント

  • 生データを確認するには、Gatewayに対してsystem-presenceを呼び出してください。
  • 重複が表示される場合:
    • クライアントがハンドシェイクで安定したclient.instanceIdを送信しているか確認
    • 定期ビーコンが同じinstanceIdを使っているか確認
    • 接続由来のエントリにinstanceIdがない場合は重複が想定される動作