Sessions and memory
工作階段狀態感知
當多個工作階段處理同一個問題時——例如管理者將工作委派給子工作階段、真人直接進入工作者工作階段,或兩個代理程式透過 sessions_send 協調——每個工作階段都會建立對其他工作階段的假設。一旦有其他參與者介入,這些假設便會立即過時。工作階段狀態感知是一套機制,用來偵測介入、向受影響的工作階段通知一次,並讓它能以低成本在行動前掌握最新狀況。
三個部分協同運作:
- 持久訊號日誌會記錄每個工作階段中選定的狀態變更。
- 監看器會保留各目標的游標,並接收一則合併後的狀態過時通知。
- 協調同步會透過帶有
changesSince的session_status擷取確切差異。
訊號日誌
當受監看的工作階段發生實質變更時,OpenClaw 會將具型別的事件附加至共享狀態資料庫(session_state_events)。事件包含中繼資料和單行摘要——絕不包含訊息內容。
| 類型 | 記錄時機 | 通知監看器 |
|---|---|---|
human_direct_message |
真人直接向受監看的工作階段傳送一輪訊息 | 是 |
goal_changed |
建立、更新或清除工作階段的目標狀態 | 是 |
child_spawned |
建立子代理程式或 ACP 子工作階段 | 否(設定游標) |
run_completed |
子執行成功結束 | 否(僅記錄日誌) |
run_failed |
子執行失敗、逾時或遭取消 | 否(僅記錄日誌) |
compacted |
工作階段的歷史記錄經過壓縮 | 否(僅記錄日誌) |
每個事件都會標示其參與者(human、agent 或 system)。遭取消和逾時的子執行會記錄為失敗,並在事件承載資料中保留確切結果(cancelled、timeout 或 error)。
工作階段的狀態版本就是其日誌中的最高序號,由可在修剪後保留的持久工作階段標頭追蹤。當工作階段已有記錄的變更時,sessions_list 資料列會包含 stateVersion;session_status 則一律會回報它。
僅記錄日誌的類型是為協調同步歷史而存在,不用於通知:一般的子執行完成傳遞仍由子代理程式公告負責,訊號日誌絕不會重複傳遞。
監看器
監看器是對目標保有游標(session_watch_cursors)的工作階段。游標來自兩個來源:
- 隱含(產生關聯)。 當工作階段產生子代理程式或 ACP 子工作階段時,父工作階段的游標會自動設定為子工作階段產生時的版本。父工作階段永遠不需手動訂閱。
- 明確(
sessions_send watch: true)。 任何協調者都可以監看非自行產生的目標:在sessions_send傳入watch: true,成功分派傳送作業後,傳送者便會註冊為實際收到訊息之工作階段的監看器。註冊會從目標目前的狀態版本開始——先前的歷史記錄絕不會產生通知。設定此參數時,工具結果會回報watched: true|false。
監看器身分必須是包含代理程式限定資訊的工作階段索引鍵。在 session.scope="global" 下,共享的 global 索引鍵對不同代理程式而言並不明確,因此這類工作階段具有持久日誌和 changesSince,但不會收到主動通知。
監看會自動清理:游標資料列會隨訊號日誌保留期限到期、在監看器工作階段重設時移除,並在任一工作階段刪除時一併刪除。v1 沒有取消監看的動詞。
通知:只發一則,而非多則
當符合通知資格的事件寫入,且監看器的游標落後時,監看器會在下一輪收到一則系統通知:
工作階段 "agent:main:subagent:child" 已變更(其他參與者)。請在行動前協調同步:session_status sessionKey "agent:main:subagent:child" changesSince 12。主要工作階段的監看器也會立即透過心跳偵測喚醒;巢狀子代理程式監看器則會在下一輪收到通知。
此通訊協定刻意採用防洗版設計:
- 每組監看器/目標配對只會有一則待處理通知。 通知文字在待處理期間維持位元組穩定,系統事件佇列會依此去除重複項目,因此即使同一目標快速變更二十次,監看器的提示中仍只會出現一行。
- 凍結水位標記。 通知排入佇列時,游標會凍結其已通知位置。後續實質事件只會推進實質水位標記,不會再次通知。
- 取出時確認,僅在工作交錯時重新開啟。 當監看器的一輪處理了通知後,游標便會前進。如果在排入佇列和取出之間又有更多實質事件抵達,剩餘事件只會再開啟一則新通知。
- 抑制自身通知。 監看器絕不會收到由自身所造成事件的通知。
- 重新啟動復原。 待處理通知位於記憶體內佇列;閘道重新啟動後,啟動掃描會根據持久游標重新具現化這些通知。
協調同步
通知會明確告知監看器應執行的動作。使用 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 是訊號日誌標頭,而非交易式變更資料擷取版本。
目前的限制:
- 通知傳遞假設由單一閘道程序擁有共享狀態資料庫。多個閘道會共用持久日誌和
changesSince,但 v1 不會跨程序推送通知。 - 壓縮事件涵蓋內嵌執行階段的壓縮擁有者;僅限原生測試框架的壓縮尚未完整記錄。
- 取消結果的承載資料詳細資訊目前由 ACP 子執行產生;原生子代理程式的取消則會呈現為一般失敗。