DSH / Atlas
2026-06-20rejectedsimplification

Persist assembled assistant messages, not stream chunks

仅持久化组装后的 assistant 消息,不存储流式分片

The canonical session log currently persists every `assistant/chunk` exactly as streamed by the model. The [session persistence Agent Note](../../implemented/architecture/2026-06-14-session-persistence.md) chose this for token-level replay fidelity and contiguous `seq`, but the cost has grown: JSONL fixtures are dominated by tiny delta records, snapshot scenarios replay the model by grouping chunk events, ACP load re

English

Problem

The canonical session log currently persists every assistant/chunk exactly as streamed by the model. The session persistence Agent Note chose this for token-level replay fidelity and contiguous seq, but the cost has grown: JSONL fixtures are dominated by tiny delta records, snapshot scenarios replay the model by grouping chunk events, ACP load reconstructs prior assistant output from chunks, and any future log reader must distinguish durable message history from token-level trace.

For successful steps that assemble completed content, the loop already appends an assistant/message. That is the event deriveMessages() uses for the next model request. In other words, the normal resumable conversation state is already present without the chunks; chunks are a live rendering and deterministic-test artifact, not required conversation history. Failed or aborted streams are different: partial assistant output may exist only as chunks, and empty max-token steps may produce no assistant/message at all.

Proposal

Stop storing assistant/chunk in the canonical session log. The durable log keeps assistant/message, tool/call, tool/result, usage if retained, and turn boundaries. Live UIs can still receive token deltas through a deliberately transient stream event. Snapshot replay should move its model script into an explicit fixture sidecar or derive it from a recorded adapter artifact, rather than treating the canonical user session as a token tape. Scenarios that need partial failed-stream output must record that output in the replay fixture.

ACP session/load can replay prior assistant messages as complete content blocks instead of simulating the original token stream. A loaded transcript need not reproduce every historical delta; it must show the same completed assistant content and resume with a valid provider history.

Acceptance criteria

  • SessionEventMap drops assistant/chunk, or marks it as non-persisted if a transitional live event is needed.
  • Session persistence docs no longer require every stream chunk to be stored verbatim.
  • llm-replay and ACP snapshots use an explicit replay fixture format or sidecar for model chunks.
  • session/load renders completed assistant messages from assistant/message.
  • Stored logs get much smaller and remain seq-contiguous without chunk holes.
  • The session format version and recorded fixtures are refreshed; non-current stored logs are rejected per the pre-release format policy.

What we give up

The canonical user session no longer reconstructs the exact token stream of an old turn. It also loses partial assistant output from failed or aborted streams unless another event or fixture records it. That is too much information loss for the current resume, load, and snapshot contracts. Tests that need exact deterministic streams should own that fixture directly only if the production session log keeps enough fidelity for user-visible recovery.

Related

This supersedes the chunk-persistence choice in session persistence and affects ACP snapshot tests, whose current replay plugin derives its script from assistant/chunk events.

<!-- agent-note-format: alternatives-not-recorded (pre-format Agent Note) -->

中文

问题

当前的规范会话日志会持久化模型流式输出的每一个 assistant/chunk会话持久化 Agent Note选择这一方案是为了 token 级回放保真度和连续的 seq,但其代价日益增长:JSONL fixture(测试前置数据)被大量微小的增量记录占据,快照场景通过对分片事件分组来回放模型,ACP(Agent Client Protocol)加载时从分片重建先前的 assistant 输出,而任何未来的日志读取方都必须区分持久的消息历史与 token 级追踪。

对于成功组装出完整内容的步骤,agent loop(智能体循环)已经追加了一条 assistant/message。这正是 deriveMessages() 用来构造下一次模型请求的事件。换言之,正常的可恢复会话状态无需分片即已具备;分片是实时渲染和确定性测试的产物,不是必需的会话历史。失败或中止的流则不同:部分 assistant 输出可能仅以分片形式存在,而空的 max-token 步骤可能根本不产生 assistant/message

提案

停止在规范会话日志中存储 assistant/chunk。持久日志保留 assistant/messagetool/calltool/resultusage(如保留)以及轮次边界。实时 UI 仍可通过一个明确设计为瞬态的流事件接收 token 增量。快照回放应将其模型脚本移入显式的 fixture 伴随文件,或从记录的适配器产物中派生,而非将规范的用户会话当作 token 磁带。需要失败流部分输出的场景必须在回放 fixture 中记录该输出。

ACP session/load 可以将先前的 assistant 消息作为完整内容块回放,而非模拟原始的 token 流。加载后的 transcript(文本记录)无需重现每一个历史 delta;它必须展示相同的已完成 assistant 内容,并基于有效的提供方历史继续运行。

验收标准

  • SessionEventMap 移除 assistant/chunk,或在需要过渡性实时事件时将其标记为非持久化。
  • 会话持久化文档不再要求逐字存储每个流式分片。
  • llm-replay 和 ACP 快照使用显式的回放 fixture 格式或伴随文件来存储模型分片。
  • session/loadassistant/message 渲染已完成的 assistant 消息。
  • 存储的日志大幅缩小,且删除分片后仍保持 seq 连续,不留下序号缺口。
  • 会话格式版本与已记录的 fixture 一并刷新;按预发布格式策略拒绝非当前版本的存储日志。

放弃了什么

规范的用户会话不再能重建旧轮次的精确 token 流。它也会丢失失败或中止流的部分 assistant 输出,除非另有事件或 fixture 记录。对于当前的恢复、加载和快照约定而言,这是过大的信息损失。需要精确确定性流的测试应当直接拥有该 fixture,前提是生产会话日志为用户可见的恢复保留了足够的保真度。

相关

本 Agent Note 取代 会话持久化 中关于分片持久化的决策,并影响 ACP 快照测试——其当前的回放插件从 assistant/chunk 事件派生脚本。

<!-- agent-note-format: alternatives-not-recorded (pre-format Agent Note) -->