Sessions and memory
セッション状態の認識
複数のセッションが同じ問題に取り組む場合(マネージャーが子に委任する、人間がワーカーセッションに直接介入する、2 つのエージェントが sessions_send を介して連携するなど)、各セッションは他のセッションについて前提を構築します。別のアクターが介入した瞬間に、それらの前提は古くなります。セッション状態認識は、その介入を検出し、影響を受けるセッションに一度だけ通知し、行動する前に低コストで状況を把握できるようにする仕組みです。
3 つの要素が連携します。
- 永続的なシグナルログは、セッションごとに選択された状態変更を記録します。
- ウォッチャーはターゲットごとのカーソルを保持し、集約された古い状態の通知を 1 件受け取ります。
- 調整は、
changesSinceを指定したsession_statusにより正確な差分を取得します。
シグナルログ
監視対象のセッションに重要な変更があると、OpenClaw は共有状態データベース(session_state_events)に型付きイベントを追加します。イベントにはメタデータと 1 行の要約が含まれますが、メッセージの内容は決して含まれません。
| 種類 | 記録されるタイミング | ウォッチャーへの通知 |
|---|---|---|
human_direct_message |
人間が監視対象のセッションにターンを直接送信したとき | あり |
upstream_missing |
採用されたセッションの上流ソースが消失したとき | あり |
goal_changed |
セッションのゴール状態が作成、更新、またはクリアされたとき | あり |
child_spawned |
サブエージェントまたは ACP 子セッションが作成されたとき | なし(カーソルを初期化) |
run_completed |
子の実行が正常に終了したとき | なし(ログのみ) |
run_failed |
子の実行が失敗、タイムアウト、またはキャンセルされたとき | なし(ログのみ) |
compacted |
セッションの履歴が Compaction されたとき | なし(ログのみ) |
adopted |
カタログセッションが OpenClaw に採用されたとき | なし(ログのみ) |
各イベントには、そのアクター(human、agent、または system)が記録されます。キャンセルまたはタイムアウトした子の実行は失敗として記録され、正確な結果(cancelled、timeout、または error)がイベントペイロードに保持されます。
セッションの状態バージョンは、単にそのログ内で最大のシーケンス番号であり、プルーニング後も残るセッションごとの永続的なヘッドで追跡されます。セッションに変更が記録されている場合、sessions_list の行には stateVersion が含まれます。session_status は常にこれを報告します。
ログのみの種類は通知ではなく調整履歴のために存在します。通常の子実行完了の配信は引き続きサブエージェントの通知が担当し、シグナルログが重複して配信することはありません。
ウォッチャー
ウォッチャーとは、ターゲット上のカーソル(session_watch_cursors)を保持するセッションです。カーソルは 2 つの方法で作成されます。
- 暗黙的(生成エッジ)。 セッションがサブエージェントまたは ACP 子を生成すると、親のカーソルは子の生成時のバージョンで自動的に初期化されます。親が手動で購読することはありません。
- 明示的(
sessions_send watch: true)。 任意のコーディネーターが、生成したものではないターゲットを監視できます。sessions_sendでwatch: trueを渡すと、送信が正常にディスパッチされた後、送信者は実際にメッセージを受信したセッションのウォッチャーとして登録されます。登録はターゲットの現在の状態バージョンから開始され、過去の履歴によって通知が生成されることはありません。パラメーターが設定されていた場合、ツールの結果はwatched: true|falseを報告します。
ウォッチャーの ID は、エージェント修飾されたセッションキーである必要があります。session.scope="global" では、共有された global キーがエージェント間で曖昧になるため、そのようなセッションには永続ログと changesSince は提供されますが、能動的な通知は提供されません。
監視は自動的にクリーンアップされます。カーソル行はシグナルログの保持期間に従って期限切れになり、ウォッチャーセッションがリセットされると削除され、いずれかのセッションが削除された場合にも削除されます。v1 には監視を解除する動詞はありません。
セッションカタログから採用された監視対象セッションは、上流で人間が直接行ったアクティビティについて一定間隔で確認されます。検出されたアクティビティは、他の人間による直接ターンと同じシグナルログおよびウォッチャーのフローに入ります。
採用されたセッションの上流ソースが外部で削除された場合、3 回連続して見つからないことが確認されると(モニターの約 3 ティック)、ウォッチャーに 1 件の upstream_missing シグナルが生成され、上流リンクが削除されます。そのカタログセッションを再度続行すると、新しいリンクが作成されます。
通知:多数ではなく 1 件
通知対象のイベントが発生し、ウォッチャーのカーソルが遅れている場合、そのウォッチャーは次のターンでシステム通知を 1 件受け取ります。
セッション "agent:main:subagent:child" が変更されました(別のアクター)。行動する前に調整してください: session_status sessionKey "agent:main:subagent:child" changesSince 12.メインセッションのウォッチャーは Heartbeat ウェイクによって即座に起動されます。ネストされたサブエージェントのウォッチャーは、次のターンで通知を受け取ります。
このプロトコルは、意図的にスパムを防止する設計になっています。
- ウォッチャーとターゲットのペアごとに保留中の通知は 1 件。 保留中は通知テキストがバイト単位で変化せず、システムイベントキューがそのテキストを基準に重複排除するため、同じターゲットに 20 件の変更が立て続けに発生しても、ウォッチャーのプロンプトには 1 行だけが生成されます。
- 固定されたウォーターマーク。 通知がキューに入ると、カーソルは通知済み位置を固定します。それ以降の重要なイベントは重要イベントのウォーターマークだけを進め、再通知は行いません。
- ドレイン時に確認し、処理が割り込んだ場合にのみ再開。 ウォッチャーのターンが通知を消費すると、カーソルが進みます。キューへの追加からドレインまでの間に重要なイベントがさらに到着した場合、残りに対して新しい通知がちょうど 1 件だけ生成されます。
- 自己抑制。 ウォッチャーが自身で発生させたイベントについて通知を受けることはありません。
- 再起動からの復旧。 保留中の通知はメモリ内キューに保持されます。Gateway の再起動後、起動時のスイープによって永続カーソルから通知が再実体化されます。
調整
通知は、ウォッチャーが何をすべきかを正確に示します。changesSince: <version> を指定した session_status は、そのバージョン以降の型付きイベントを最大 200 件返します。カーソルは進みません。
{ "stateVersion": 19, "stateChanges": { "events": [ { "sequence": 14, "kind": "human_direct_message", "actorType": "human", "summary": "Telegram 経由の人間のメッセージ" }, { "sequence": 19, "kind": "goal_changed", "actorType": "human", "summary": "ゴールが更新されました" } ], "historyGap": false }}historyGap: true は、要求されたバージョンが保持されている履歴より前であることを意味します。応答を正確な差分として扱うのではなく、セッション状態全体(sessions_history、session_status)を更新してください。ギャップシグナルは正確です。シーケンスの算術から推測されるのではなく、セッションごとのプルーニング済みウォーターマークから取得されます。
ストレージと制限
履歴は共有状態データベースに保存され、30 日間および 50,000 行に制限されます。セッションごとのヘッドはプルーニング後も単調増加を維持します。記録はベストエフォートです。追加に失敗した場合はログに記録されるだけで、元のターンが失敗することはありません。そのため、stateVersion はシグナルログのヘッドであり、トランザクション型の変更データキャプチャバージョンではありません。
現在の制限:
- 通知の配信では、1 つの Gateway プロセスが共有状態データベースを所有していることを前提とします。複数の Gateway は永続ログと
changesSinceを共有しますが、v1 ではプロセス間で通知をプッシュしません。 - Compaction イベントは組み込みランタイムの Compaction 所有者を対象とします。ネイティブハーネスのみの Compaction は完全には記録されません。
- キャンセル結果のペイロード詳細は、現在 ACP 子の実行によって生成されます。ネイティブのサブエージェントのキャンセルは一般的な失敗として表されます。
- 上流の自己エコー検出では、正規化されたユーザーテキストを比較します。セッションの直近 10 件の OpenClaw 側ユーザーメッセージのいずれかと一致する外部プロンプトは、自己エコーとして扱われます。
- ローカルの Claude JSONL 行が 1 行でも周期ごとのスキャン上限である 1 MiB を超えると、v1 ではそのセッションのカーソルがブロックされます。分類されていないバイトがスキップされることはありません。
- ペアリングされた Node の Claude チェックは、周期ごとに最新 50 件のトランスクリプト項目を分類します。それを超える大量の項目は、v1 のスキャン範囲外になる場合があります。
- ペアリングされた Node の Claude 履歴読み取りでは、スレッドが見つからないことを確定的に示す結果が公開されないため、v1 ではリモートの Claude の削除は
upstream_missingとして分類されません。 - 採用されていないカタログセッションは、v1 では認識レイヤーの対象外です。
- この機能より前に採用されたセッションには上流リンクがありません。上流の監視を開始するには、カタログからそのセッションを一度続行してください。
- 上流リンクでは、採用された各セッションキーが 1 つの所有エージェントに対応することを前提とします(採用ではデフォルトのストアエージェントが使用されます)。同じ外部スレッドを複数のエージェントが採用した場合、v1 では監視されません。