Agent
- 内存里的运行控制器。
- 持有
messages/tools/model。 - 管理 active run、abort、steering/followUp。
- 把 snapshot 交给
runAgentLoop()。
05 · Session
这一章看 Agent、SessionManager、AgentSession:多轮历史如何保存成 JSONL tree,如何用 /tree 回到旧节点继续,以及 compaction 如何缩短发给模型的上下文。
05 的主线是分清运行时状态、持久化历史和产品层会话控制。
messages/tools/model。runAgentLoop()。id/parentId/leafId。buildSessionContext() 构造上下文。session 不是只保存聊天文本,还要保存模型调用工具后的观察结果。
user: 看一下 a.ts
assistant: toolCall read(a.ts)
toolResult: a.ts 内容...
assistant: 根据文件内容回答
user 是用户意图,assistant 是模型行为,toolResult 是外部世界返回给模型的信息。
分支不是靠删除旧消息实现,而是靠 parentId 和 leafId 选择当前路径。
A -> B -> C -> D
\
E这些命令的差异主要是:在当前文件内导航,还是创建新的 session 文件。
同一个 JSONL 文件里切分支,移动 leaf,并重建当前 context。
从某个 user message 复制当前路径,创建新 session 文件。
从当前 leaf 复制当前路径,创建新 session 文件。
创建新的空 session,重新开始。
压缩不会删除旧 entries,而是追加一个 compaction entry,让 buildSessionContext 改变发给模型的 messages。
compact()
-> getBranch()
-> prepareCompaction()
-> generate summary
-> appendCompaction(summary, firstKeptEntryId)
-> buildSessionContext()
-> agent.state.messages = context.messages
fileEntries 仍然保留原始 JSONL 历史;改变的是 buildSessionContext() 生成的模型视图。
学 session tree 最快的方法是自己画一次 leaf 怎么移动。
起点:
A -> B -> C -> D
leafId = D
操作:
/tree 选中 B
输入 E
A -> B -> C -> D
\
E
leafId = E
fileEntries = A/B/C/D/E 全部保留
parentId 决定树边。leafId 决定当前路径。fileEntries 是完整历史,不是当前上下文。toolResult?为什么 /tree 选中 user message 时要回到它的 parent?为什么 compaction 不删除旧 entries?
session 主干已经看完,下一节进入扩展系统。