Session Management & Compaction (Deep Dive)
本文件說明 OpenClaw 如何端到端管理工作階段:- 工作階段路由(傳入訊息如何對應到一個
sessionKey) - 工作階段儲存庫(
sessions.json)及其追蹤內容 - Transcript persistence (
*.jsonl) and its structure - 逐字稿衛生(在執行前的提供者特定修正)
- 上下文限制(上下文視窗 vs 追蹤的權杖)
- Compaction (manual + auto-compaction) and where to hook pre-compaction work
- 無聲例行整理(例如不應產生使用者可見輸出的記憶體寫入)
Source of truth: the Gateway
OpenClaw 的設計以單一 Gateway process 為核心,負責擁有工作階段狀態。- UI(macOS app、Web Control UI、TUI)應向 Gateway 閘道器查詢工作階段清單與權杖計數。
- 在遠端模式下,工作階段檔案位於遠端主機;「檢查你本機 Mac 的檔案」不會反映 Gateway 閘道器實際使用的內容。
兩層持久化
OpenClaw 以兩層方式持久化工作階段:-
工作階段儲存庫(
sessions.json)- 鍵/值對映:
sessionKey -> SessionEntry - 小型、可變更、可安全編輯(或刪除項目)
- Tracks session metadata (current session id, last activity, toggles, token counters, etc.)
- 鍵/值對映:
-
逐字稿(
<sessionId>.jsonl)- 具有樹狀結構的附加寫入逐字稿(項目具有
id+parentId) - 儲存實際對話 + 工具呼叫 + 壓縮摘要
- 用於重建未來回合的模型上下文
- 具有樹狀結構的附加寫入逐字稿(項目具有
磁碟上的位置
在 Gateway 閘道器主機上,依代理程式區分:- 儲存庫:
~/.openclaw/agents/<agentId>/sessions/sessions.json - 逐字稿:
~/.openclaw/agents/<agentId>/sessions/<sessionId>.jsonl- Telegram 主題工作階段:
.../<sessionId>-topic-<threadId>.jsonl
- Telegram 主題工作階段:
src/config/sessions.ts 解析這些路徑。
工作階段金鑰(sessionKey)
sessionKey 用來識別你所在的「對話桶」(路由 + 隔離)。
常見模式:
- 主要/直接聊天(每個代理程式):
agent:<agentId>:<mainKey>(預設main) - 群組:
agent:<agentId>:<channel>:group:<id> - 房間/頻道(Discord/Slack):
agent:<agentId>:<channel>:channel:<id>或...:room:<id> - Cron:
cron:<job.id> - Webhook:
hook:<uuid>(除非被覆寫)
工作階段 ID(sessionId)
每個 sessionKey 都指向一個目前的 sessionId(持續該對話的逐字稿檔案)。
Rules of thumb:
- 重設(
/new、/reset)會為該sessionKey建立新的sessionId。 - 每日重設(預設為 Gateway 閘道器主機的當地時間凌晨 4:00)會在重設邊界後的下一則訊息建立新的
sessionId。 - 閒置到期(
session.reset.idleMinutes或舊版session.idleMinutes)在超過閒置視窗後收到訊息時建立新的sessionId。若同時設定每日 + 閒置,以先到期者為準。 When daily + idle are both configured, whichever expires first wins. When daily + idle are both configured, whichever expires first wins.
src/auto-reply/reply/session.ts 中的 initSessionState()。
Session store schema (sessions.json)
儲存庫的值型別為 src/config/sessions.ts 中的 SessionEntry。
主要欄位(非完整):
sessionId:目前逐字稿 ID(除非設定sessionFile,否則檔名由此衍生)updatedAt:最後活動時間戳sessionFile:可選的逐字稿路徑覆寫chatType:direct | group | room(協助 UI 與傳送政策)provider、subject、room、space、displayName:群組/頻道標示的中繼資料- 切換開關:
thinkingLevel、verboseLevel、reasoningLevel、elevatedLevelsendPolicy(每個工作階段的覆寫)
- 模型選擇:
providerOverride、modelOverride、authProfileOverride
- 權杖計數器(盡力而為/依提供者而異):
inputTokens、outputTokens、totalTokens、contextTokens
compactionCount:此工作階段金鑰完成自動壓縮的次數memoryFlushAt:上一次壓縮前記憶體寫入的時間戳memoryFlushCompactionCount:上一次寫入執行時的壓縮計數
Transcript structure (*.jsonl)
逐字稿由 @mariozechner/pi-coding-agent 的 SessionManager 管理。
檔案為 JSONL:
- 第一行:工作階段標頭(
type: "session",包含id、cwd、timestamp,以及可選的parentSession) - 接著:具有
id+parentId(樹狀)的工作階段項目
message:使用者/助理/toolResult 訊息custom_message:由擴充注入、會進入模型上下文的訊息(可在 UI 中隱藏)custom:不會進入模型上下文的擴充狀態compaction:具有firstKeptEntryId與tokensBefore的持久化壓縮摘要branch_summary:在樹分支導覽時的持久化摘要
SessionManager 來讀寫它們。
上下文視窗 vs 追蹤的權杖
有兩個不同概念需要注意:- 模型上下文視窗:每個模型的硬性上限(模型可見的權杖)
- 工作階段儲存庫計數器:寫入
sessions.json的滾動統計(用於 /status 與儀表板)
- 上下文視窗來自模型目錄(並且可透過設定覆寫)。
- 儲存庫中的
contextTokens是執行時估計/回報值;不要把它當成嚴格保證。
壓縮:它是什麼
Compaction summarizes older conversation into a persistedcompaction entry in the transcript and keeps recent messages intact.
壓縮後,後續回合會看到:
- 壓縮摘要
firstKeptEntryId之後的訊息
When auto-compaction happens (Pi runtime)
In the embedded Pi agent, auto-compaction triggers in two cases:- 溢位復原:模型回傳上下文溢位錯誤 → 壓縮 → 重試。
- 閾值維護:成功完成一個回合後,當:
contextTokens > contextWindow - reserveTokens
Where:
contextWindow是模型的上下文視窗reserveTokens是為提示詞 + 下一次模型輸出保留的餘裕
壓縮設定(reserveTokens、keepRecentTokens)
Pi 的壓縮設定位於 Pi 設定中:
- 若
compaction.reserveTokens < reserveTokensFloor,OpenClaw 會提高它。 - Default floor is
20000tokens. - 設定
agents.defaults.compaction.reserveTokensFloor: 0可停用下限。 - 若原本已更高,OpenClaw 會維持不變。
src/agents/pi-settings.ts 中的 ensurePiCompactionReserveTokens()
(由 src/agents/pi-embedded-runner.ts 呼叫)。
使用者可見的介面
You can observe compaction and session state via:/status(任何聊天工作階段中)openclaw status(CLI)openclaw sessions/sessions --json- 詳細模式:
🧹 Auto-compaction complete+ 壓縮次數
Silent housekeeping (NO_REPLY)
OpenClaw 支援用於背景工作的「無聲」回合,使用者不應看到中間輸出。
慣例:
- 助理以
NO_REPLY開頭輸出,表示「不要將回覆傳遞給使用者」。 - OpenClaw strips/suppresses this in the delivery layer.
2026.1.10 起,當部分串流區塊以 NO_REPLY 開頭時,OpenClaw 也會抑制 草稿/輸入中串流,避免無聲操作在回合中途洩漏部分輸出。
Pre-compaction “memory flush” (implemented)
目標:在自動壓縮發生之前,執行一次無聲的代理程式回合,將可持久化的 狀態寫入磁碟(例如代理程式工作區中的memory/YYYY-MM-DD.md),以確保壓縮不會
抹除關鍵上下文。
OpenClaw 採用 壓縮前閾值寫入 的方式:
- 監控工作階段上下文使用量。
- 當超過「軟性閾值」(低於 Pi 的壓縮閾值)時,對代理程式執行一次無聲的 「立即寫入記憶體」指令。
- 使用
NO_REPLY,讓使用者看不到任何輸出。
agents.defaults.compaction.memoryFlush):
enabled(預設:true)softThresholdTokens(預設:4000)prompt(寫入回合的使用者訊息)systemPrompt(附加於寫入回合的額外系統提示)
- 預設的提示/系統提示包含
NO_REPLY提示以抑制傳遞。 - 清空操作在每個壓縮週期中只會執行一次(記錄於
sessions.json)。 - 僅對內嵌 Pi 工作階段執行(CLI 後端會略過)。
- The flush is skipped when the session workspace is read-only (
workspaceAccess: "ro"or"none"). - See Memory for the workspace file layout and write patterns.
session_before_compact 掛鉤,但 OpenClaw 的
寫入邏輯目前位於 Gateway 閘道器端。
疑難排解檢查清單
-
- 工作階段金鑰錯誤? 工作階段金鑰錯誤?先從 /concepts/session 開始,並確認
/status中的sessionKey。
- 工作階段金鑰錯誤? 工作階段金鑰錯誤?先從 /concepts/session 開始,並確認
- 儲存區與逐字稿不一致? 儲存區與逐字稿不一致? Confirm the Gateway host and the store path from
openclaw status. - Compaction spam? 檢查:
- 模型上下文視窗(是否過小)
- 壓縮設定(
reserveTokens對模型視窗而言過高,可能導致提早壓縮) - 工具結果膨脹:啟用/調整工作階段修剪
- Silent turns leaking? 確認回覆以
NO_REPLY(完全相同的權杖)開頭,且你正在使用包含串流抑制修復的版本。