Appearance
1.5 会话日志:事件溯源与"模型可见即已记录"
本章概览:DSH 的会话模型是事件溯源(event sourcing)——一次对话的全部历史是一条只追加的事件日志。本章讲清会话日志的数据结构、模型历史如何派生、以及"模型可见即已记录"这一贯穿全项目的不变式。
会话 = 只追加的事件日志
Session 是 Agent 整个交互历史的只追加(append-only)事实源。模型消息历史(LLM message history)是从日志派生的,而不是独立保存的副本。
text
Session
├── session.events # 只追加的 SessionEvent[](深冻结的持久事实)
├── session.surface # 有序的"消息产生事件"投影层(用于高效派生与压缩)
└── deriveMessages() # 从 surface 增量投影出完整模型历史出处:
packages/core/session/README.md(deepseek-harness-src/packages/core/session/README.md)
关键数据形态
| 概念 | 说明 |
|---|---|
SessionEvent | 持久事件:user/message、assistant/message、assistant/chunk、tool/call、tool/result、turn/*、step/* 等(SessionEventMap 声明) |
SessionSurface | 消息产生事件的有序投影;压缩(compaction)会用它做"整段替换" |
session.header | 脱离(detached)的创建元数据:version、id、createdAt、可选 cwd / parentSession / seedLength / delegationDepth |
SessionStore(ctx.sessions) | 创建并持有 Session 实例;持久化不在本包实现——插件订阅 session/event,在 session/flush 时落盘 |
为什么 surface 与 raw log 分开
- 模型面向的消费者读
session.surface(已应用压缩替换后的投影); - 人类 transcript(文本记录)读追加来源事件而非 surface——因为"落地的替换会遮蔽读者已经看过的历史";
- 原始
assistant/chunk事件保证回放与 UI 保真。
不变式:模型可见即已记录
模型可见即已记录。 抵达模型请求的一切都必须能从日志重建,并由一项运行时不变量断言这一点。因此,新增一项模型可见输入就需要新增一个会话事件:扩展
SessionEventMap并从日志渲染。
出处:
docs/architecture.md(deepseek-harness-src/docs/architecture.md)
这条不变式的工程后果:
- 新增模型可见输入(如 plan 状态、preset 切换、目标状态)必须新增会话事件并在日志中渲染;
- 仓库级约定把其提升为强制项:"Model-visible ⟺ logged: anything that reaches a model request must be reconstructable from the session log"(AGENTS.md);
- 例证:plan 模式切换追加
plan/mode事件;agent preset 切换追加agent-preset/selected事件;goal 每次变更追加goal/change事件。
从日志派生的下游
事件日志是"一处写入、多处派生"的枢纽:
| 下游 | 派生方式 |
|---|---|
| 模型历史 | deriveMessages() 增量投影 |
| 恢复(resume) | 从持久化日志重建会话,轮次编号与派生历史延续 |
| fork | ctx.sessions.fork(source, boundary?, childSessionId?) 以 boundary 之前缀建子会话(要求边界外不在开着的轮次内),携带 lineage 元数据 |
| transcript / 遥测 | 订阅 session/event 消费 |
| 会话标题 | ctx.sessionTitle 从日志折叠 |
| 投影(projection) | dsh-session-projection 注册折叠单元(fold unit),如 plan、todo 状态 |
| 压缩(compaction) | 把一段 surface 节点总结为单个替换节点(见 3.9) |
出处:
packages/core/session/README.md、packages/session/session-projection/README.md
持久化:seam 而非内置
会话存储故意不实现持久化——它通过 session/event 发布事件,插件(持久化后端)在 session/flush 时落盘:
- 后端:
dsh-session-persistence-jsonl(JSONL)与dsh-session-persistence-sqlite(SQLite),共享同一SessionEvent词汇; - 应用在组合时选择后端;
- 恢复要求持久化后端存在(非硬注入——无持久化的演示仍可运行,
resume在无持久化时给出明确报错)。
出处:
packages/session/session-persistence/README.md(deepseek-harness-src/packages/session/session-persistence/README.md)
不变式伴侣:dsh-invariants
DSH 把关键关系断言注册到 ctx.invariants(runtime-diagnostics/invariants),由各包的 ./invariant 伴生子路径贡献:
dsh-session/invariant:单调序列号、轮次/步骤包裹、同步骤工具调用/结果配对;dsh-agent/invariant、dsh-agent-loop/invariant:agent 状态转换、请求重建检查;dsh-goal/invariant:goal 变更的 revision 连续、生命周期合法迁移、时间戳不倒退。
出处:
packages/runtime-diagnostics/invariants/README.md与docs/subsystems/invariants.md
小结
会话日志是 DSH 的"真相中枢":模型历史、持久化、fork、压缩、标题、投影全部从它派生;"模型可见即已记录"则保证日志的完整性。下一部分 2.5 会话持久化 将深入持久化、恢复与投影的机制。
参考资料
- packages/core/session/README.md — 会话日志与存储(
deepseek-harness-src/packages/core/session/README.md) - docs/architecture.md — Session log 一节(
deepseek-harness-src/docs/architecture.md) - docs/subsystems/session.md — 会话子系统参考(
deepseek-harness-src/docs/subsystems/session.md) - packages/session/session-persistence/README.md — 持久化 seam