作用
让 agent 能在跨请求、跨进程、多用户场景下恢复状态。一次call() 结束后自动落盘两路产出:
- StateModule 快照(
Memory、ToolExecutionContext等可序列化状态)——默认走WorkspaceSession - 对话 JSONL(LLM 上下文 + 完整历史)——走
SessionTree,由MemoryFlushManager.offloadMessages触发
触发
关键逻辑
双轨存储布局
context/:WorkspaceSession继承JsonSession,base 在agents/<agentId>/context/;sessionId 子目录里按SessionKey → {key}.json存每个StateModule。sessions/:SessionTree在一个 JSONL 里按id/parentId组成一棵树;另一份同名的<sessionId>.log.jsonl从不被压缩,供审计和session_search使用。
RuntimeContext 怎么让二者对齐
HarnessAgent.bindRuntimeContext 会做几件事:
- 补默认:
session为空时使用构建时的defaultSession(默认是WorkspaceSession(workspace, agentId));sessionKey为空时依次试SimpleSessionKey.of(sessionId)→SimpleSessionKey.of(agentName)。 - 传递到 hooks:
workspaceContextHook、memoryFlushHook、sessionPersistenceHook、compactionHook都会同步该 ctx,他们在 offload / saveTo 时都能读到sessionId。 - 联动
userIdRef:AtomicReference<String>被顶下userId,默认NamespaceFactory → List.of(userId)会以该 userId 作为路径前缀,从而多租户透明隔离。 - 预加载状态:若
session && sessionKey都有,调用delegate.loadIfExists覆盖当前 Memory。不存在则什么都不动。
默认与自定义 Session
多用户隔离的两个层面
- 会话层:
sessionId决定context/<sessionId>/与sessions/<sessionId>.jsonl独立。 - 文件层:
userId+NamespaceFactory决定文件操作路径前缀(默认LocalFilesystemWithShell会读userIdRef)。
会话索引
MemoryFlushManager.offloadMessages 调完后,WorkspaceManager.updateSessionIndex(agentId, sessionId, summary) 会合并写 sessions/sessions.json,agent 在另一轮可以走 session_list 工具查看“该 agent 历史上都跟谁聊过”。