DSH / Atlas
2026-09-05implementedbug-fixarchived 2026-09-30

Reuse spill storage for truncated session references

为截断的会话引用复用 spill 存储

A bounded cross-session preview can omit whole messages or most of a retained message. A model that sees only the preview needs an accurate account of the omission and a way to inspect the captured text, without treating another session's instructions as current authority. Rereading the source later would not recover the same observation when the source advances or compacts.

English

Problem

A bounded cross-session preview can omit whole messages or most of a retained message. A model that sees only the preview needs an accurate account of the omission and a way to inspect the captured text, without treating another session's instructions as current authority. Rereading the source later would not recover the same observation when the source advances or compacts.

Decision

Session-reference preparation retains its existing preview policy and per-reference JSON byte budget. Each truncated reference attempts saveText through optional ctx.get("spillStore"); an untruncated reference writes no artifact. The full transcript and bounded preview derive from the same captured user/assistant text projection, including compaction checkpoints but excluding tools, reasoning, and other injected context. No second source read occurs.

The artifact belongs to the target session receiving the context. Its descriptive source is { kind: "session-reference", sessionId, label }, where sessionId identifies the referenced session. Spill storage accepts this minimal alternative alongside the existing tool source; it requires no fabricated tool name or call id. Storage ownership does not authorize retrieval.

A separate omission notice outside the bounded preview JSON records exact omittedMessages and omittedBytes. It carries the saved locator and backend retrievalHint, or an unavailable outcome distinguishing missing storage from a failed save. This notice is model-visible content in the same durable reference message, not metadata-only UI decoration. A tiny preview budget cannot remove it. The saved transcript carries capture metadata, including capturedFormatVersion, and the same untrusted-background warning as the preview. Per-message JSON string fragments contain at most 64 Unicode code points per line; decoding and concatenating them restores exact text, including original newlines. This fixed artifact format keeps long single-line middles retrievable with ordinary paged file reads without changing preview retention.

Cancellation after an asynchronous save prevents context publication, even if storage already created the artifact. The consumer does not add rollback or deletion APIs; the existing backend expiry policy governs that artifact. Replay uses the logged preview and notice and never repeats the save or source read.

Alternatives considered

Write a separate session-reference file store. Rejected because private naming, session-scoped ownership, locator guidance, and artifact lifetime already belong to spill storage. A second store would duplicate those policies.

Reread the source when saving or retrieving. Rejected because source mutation could make the artifact disagree with the preview and its captured sequence. Saving the original projection preserves the observation.

Put omission and retrieval data inside the bounded preview JSON. Rejected because that spends the conversation budget on metadata and can hide the notice precisely when the budget is smallest. Separate durable model-visible text preserves both obligations.

Use a tool source for every spill. Rejected because a session reference has no model-issued tool call. Invented tool ids would misattribute the artifact rather than describe its producer.

Consequences

The model can inspect text omitted from a preview without increasing the preview budget. Notices add request tokens outside that budget, and retrieval adds the requested transcript text later. Storage is best-effort: an unavailable notice is honest about loss of retrieval while the bounded preview remains usable. A saved locator can expire even while its notice remains in durable history; this feature does not promise permanent archival or recover content already removed by source compaction.

Verification

The unit suite pins omission counts, full Unicode and control-character recovery, whole-message drops, three-reference isolation, missing and failed storage, source exclusions and mutation isolation, and cancellation before publication. The Loader composition test exercises the real local store and paged read tool against the middle of a giant single-line message, with target-session storage ownership. The keyless recorded-session scenario pins the durable model-visible reference context. Nested Windows-locator regressions cover both serialized extraction and normalization without rewriting unrelated backslashes. Replay normalizes known quoted spill locators while preserving saved byte lengths and omission counts.

Related decisions

The tool-output spill decision remains active: its storage/policy separation, failure degradation, provider caps, and retrieval alternatives still constrain tool consumers. This note extends its producer vocabulary without replacing that rationale. Separate context injection from turn execution remains the authority for durable message admission, and producer-declared context forms remains the authority for recall presentation.

中文

问题

有界的跨会话预览可能省略整条消息,也可能省略保留消息中的大部分文本。只看到预览的模型需要准确了解省略情况,并能检查已捕获的文本,同时不能把其他会话的指令视为当前授权。源会话继续推进或发生压缩后,再次读取无法恢复同一次观察。

决策

会话引用准备保留既有预览策略和逐引用 JSON 字节预算。每个被截断的引用通过可选的 ctx.get("spillStore") 尝试 saveText;未截断的引用不写入产物。完整转录与有界预览来自同一份已捕获的 user/assistant 文本投影,包含压缩检查点,但排除工具、推理与其他注入上下文。不发生第二次源读取。

产物归接收上下文的目标会话所有。其描述性来源是 { kind: "session-reference", sessionId, label },其中 sessionId 标识被引用的会话。spill 存储在工具来源之外接受这一最小分支;不需要伪造工具名称或调用 id。存储归属不授权取回。

有界预览 JSON 之外的独立省略通知记录精确的 omittedMessages 与 omittedBytes。通知携带保存后的定位信息和后端 retrievalHint,或区分未配置存储与保存失败的不可用结果。该通知是同一条持久引用消息中的模型可见内容,而不是只供 UI 使用的元数据装饰。极小的预览预算无法移除它。保存的转录携带包括 capturedFormatVersion 在内的捕获元数据,以及与预览相同的不受信任背景警告。每条消息的 JSON 字符串片段每行至多包含 64 个 Unicode 码点;解码并拼接后可恢复精确文本,包括原始换行。这种固定产物格式让普通分页文件读取可以取回很长的单行文本中部,而不改变预览保留策略。

异步保存后的取消会阻止上下文发布,即使存储已经创建了产物。消费方不增加回滚或删除 API;该产物遵循后端既有过期策略。回放使用已记录的预览与通知,不会重复保存或源读取。

考虑过的替代方案

另写一个会话引用文件存储。 不予采纳,因为私有命名、会话级归属、定位指引与产物生命周期已经由 spill 存储负责。第二套存储会重复这些策略。

保存或取回时重新读取源。 不予采纳,因为源变更可能使产物与预览及其捕获序列不一致。保存原始投影可以保留该次观察。

把省略与取回数据放入有界预览 JSON。 不予采纳,因为这会让元数据占用对话预算,并可能在预算最小时恰好隐藏通知。独立的持久模型可见文本同时保留两项保证。

所有 spill 都使用工具来源。 不予采纳,因为会话引用没有模型发出的工具调用。虚构工具 id 会错误归属产物,而不是描述其生产者。

后果

模型可以检查预览省略的文本,而无需增加预览预算。通知在该预算之外增加请求 token,之后的取回再添加所请求的转录文本。存储采用尽力而为策略:不可用通知如实说明无法取回,而有界预览仍可使用。即使通知仍在持久历史中,保存的定位信息也可能过期;此功能不承诺永久归档,也无法恢复源压缩已经移除的内容。

验证

单元测试锁定省略计数、完整 Unicode 与控制字符恢复、整条消息丢弃、三个引用的隔离、无存储与保存失败、来源排除与变更隔离,以及发布前取消。Loader 组合测试使用真实本地存储和分页 read 工具,读取巨型单行消息的中部,并检查存储归目标会话所有。无密钥录制会话场景锁定持久的模型可见引用上下文。嵌套 Windows 定位信息回归覆盖序列化提取与规范化,且不改写无关反斜杠。回放会规范化已知的带引号 spill 定位信息,同时保留保存字节数与省略计数。

相关决策

工具输出 spill 决策保持活跃:其存储/策略分离、失败降级、提供方上限与取回替代方案仍约束工具消费方。本说明扩展其生产者词汇,而不替代这些理由。分离上下文注入与轮次执行仍负责持久消息准入,生产者声明的上下文形式仍负责 recall 展示。