1. Session 为什么是 append-only
如果 agent 的上下文只是一个不断被修改的 messages[],你很难可靠实现恢复、fork、回放、审计和 UI fidelity。DSH 选择把交互记录成不可变事件流,再从事件流投影出模型消息。
SessionEvent[] (source of truth)
├─ deriveMessages() → 下一次 LLM history
├─ projection → UI 当前状态
├─ persistence → JSONL / SQLite
├─ fork/resume → 新会话/恢复
└─ telemetry → 统计与追踪
2. “Model-visible means logged”
这是一个非常强的架构不变量:任何真正进入模型请求的上下文,都应该能从 session log 重建。这样恢复后的模型不会突然“忘掉”某段只存在内存里的隐式状态。
3. Turn 与 Step 也要成为持久边界
Turn 是一轮用户意图到系统空闲;Step 是一次模型请求及其工具调用。把这些边界记入日志,才能验证事件嵌套是否正确、工具 result 是否属于同一 step,并支持失败恢复。
4. 为什么 core/session 不直接做 persistence
因为“活跃会话语义”和“落到哪里”是两个变化速度不同的职责。core session 提供事件和 flush 检查点,JSONL/SQLite 等后端订阅它。这就是 seam 思想的另一处体现。