{"_id":"@buddhilive/dsh-session-persistence","name":"@buddhilive/dsh-session-persistence","dist-tags":{"alpha":"0.1.2-alpha.3","latest":"0.1.2-alpha.3"},"versions":{"0.1.2-alpha.3":{"name":"@buddhilive/dsh-session-persistence","description":"Abstract durable session persistence seam (ctx.sessionPersistence) for the DeepSeek Harness","version":"0.1.2-alpha.3","publishConfig":{"access":"public"},"repository":{"type":"git","url":"git+https://github.com/Buddhilive/buddhi-ai-harness.git","directory":"packages/session/session-persistence"},"type":"module","main":"lib/index.js","types":"lib/types/index.d.ts","exports":{".":{"types":"./lib/types/index.d.ts","default":"./lib/index.js"},"./invariant":{"types":"./lib/types/invariant.d.ts","default":"./lib/invariant.js"},"./src/*":"./src/*","./package.json":"./package.json"},"license":"MIT","peerDependencies":{"@deepseek-ai/cordis":"^4.0.2","@buddhilive/dsh-invariants":"^0.1.2-alpha.3","@buddhilive/dsh-brand":"^0.1.2-alpha.3","@buddhilive/dsh-session":"^0.1.2-alpha.3","@buddhilive/dsh-timeout":"^0.1.2-alpha.3"},"devDependencies":{"@deepseek-ai/cordis":"^4.0.2","@buddhilive/dsh-brand":"^0.1.2-alpha.3","@buddhilive/dsh-invariants":"^0.1.2-alpha.3","@buddhilive/dsh-timeout":"^0.1.2-alpha.3","@buddhilive/dsh-session":"^0.1.2-alpha.3","@buddhilive/dsh-scope":"^0.1.2-alpha.3"},"dependencies":{"@buddhilive/dsh-util-values":"^0.1.2-alpha.3"},"_id":"@buddhilive/dsh-session-persistence@0.1.2-alpha.3","bugs":{"url":"https://github.com/Buddhilive/buddhi-ai-harness/issues"},"homepage":"https://github.com/Buddhilive/buddhi-ai-harness#readme","_integrity":"sha512-odyyfBMECsCv0tP76RH4lutdv4RM/SvzwrwX3mpnVnpv/t73yuMbUdGWab4w+uJRWqX98tC/LBn0mM/ac9DKaQ==","_resolved":"C:\\DevDojo\\Buddhi\\buddhi-ai-harness\\dist\\npm\\buddhilive-dsh-session-persistence-0.1.2-alpha.3.tgz","_from":"file:C:/DevDojo/Buddhi/buddhi-ai-harness/dist/npm/buddhilive-dsh-session-persistence-0.1.2-alpha.3.tgz","_nodeVersion":"24.13.0","_npmVersion":"11.6.2","dist":{"integrity":"sha512-odyyfBMECsCv0tP76RH4lutdv4RM/SvzwrwX3mpnVnpv/t73yuMbUdGWab4w+uJRWqX98tC/LBn0mM/ac9DKaQ==","shasum":"6402925c9458c1f0b61e89a5a38466397a0c9c28","tarball":"https://registry.npmjs.org/@buddhilive/dsh-session-persistence/-/dsh-session-persistence-0.1.2-alpha.3.tgz","fileCount":14,"unpackedSize":129626,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIAbc8B1tPWDn4YQZSIBD7YUQZcnC4YfpOgL+rP6BEvFkAiEAjojLDbMSQaypBAPaqZYKa6dCX8XXevTWGiyiUpAcdxg="}]},"_npmUser":{"name":"buddhilive","email":"visitbudkavin@gmail.com"},"directories":{},"maintainers":[{"name":"buddhilive","email":"visitbudkavin@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/dsh-session-persistence_0.1.2-alpha.3_1788165071475_0.5331841351306807"},"_hasShrinkwrap":false}},"time":{"created":"2026-08-31T08:31:11.210Z","0.1.2-alpha.3":"2026-08-31T08:31:11.608Z","modified":"2026-08-31T08:31:11.941Z"},"maintainers":[{"name":"buddhilive","email":"visitbudkavin@gmail.com"}],"description":"Abstract durable session persistence seam (ctx.sessionPersistence) for the DeepSeek Harness","homepage":"https://github.com/Buddhilive/buddhi-ai-harness#readme","repository":{"type":"git","url":"git+https://github.com/Buddhilive/buddhi-ai-harness.git","directory":"packages/session/session-persistence"},"bugs":{"url":"https://github.com/Buddhilive/buddhi-ai-harness/issues"},"license":"MIT","readme":"---\ndescription: \"面向用户与维护者的持久会话存储 seam 说明，用于选择持久化后端、恢复会话，或按共享服务约定构建后端。\"\nkind: \"package-reference\"\n---\n\n# @buddhilive/dsh-session-persistence\n\n[English](README.md) | 中文\n\n## 概述\n\n`dsh-session-persistence` 通过每个持久化后端都实现的一个后端无关服务（`ctx.sessionPersistence`）持久存储会话的事件日志、在恢复时重新加载并列出已存储会话。持久化单元就是现有 `SessionEvent` 日志——不存在另一套并行的存储消息类型——不可回放的元数据（格式版本、工作目录、血缘、种子边界）作为 `SessionHeader` 单独传输。后端拥有自己的存储，服务拥有语义：仅追加日志、连续序列号、保留中断轮次而非截断的崩溃恢复，以及只在批次安全后才返回的持久写入。选一个后端（按会话存储文件的 `session-persistence-jsonl`，或单库的 `session-persistence-sqlite`），挂载它，会话就会持久化并在恢复时还原，loop 与模型无需知道下面是哪个后端。\n\n## 目录\n\n- [使用本包](#use-this-package)\n- [理解实现](#understand-the-implementation)\n- [进一步探索](#further-exploration)\n- [模型体验](#model-experience)\n- [已知限制与延期工作](#known-limitations-and-deferred-work)\n- [开发备注](#dev-note)\n\n-----\n\n<a id=\"use-this-package\"></a>\n## 使用本包\n\n挂载一个持久化后端即可让会话持久化。后端把自己注册为 `ctx.sessionPersistence`；组合中的其他部分不变——loop、恢复与回放调用的是同一个服务。\n\n### 选择后端\n\nseam 随产品交付两个可互换后端。当每个会话应各占一份磁盘产物时选择 [JSONL](../session-persistence-jsonl/README.zh.md)：它把每个会话存为一份仅追加 `.jsonl.zstd` 日志，并由 `locate(meta)` 返回绝对产物路径。当单一可查询数据库适合部署时选择 [SQLite](../session-persistence-sqlite/README.zh.md)：它把每个会话的日志连同物理打包行一起存入单个数据库，不返回按会话的产物。第三方后端可以直接实现该服务；必须遵守的[后端约定](#understand-the-implementation)见下文。\n\n### 服务提供什么\n\n挂载后端后，你可以持久存储会话事件、重新加载已存储日志并列出已存储内容：\n\n```text\nawait ctx.sessionPersistence.create(meta)                  // register a session\nawait ctx.sessionPersistence.ensureMaterialized(session)   // persist an empty resumable session\nawait ctx.sessionPersistence.append(id, events)            // durably persist a batch\nconst { meta, events } = await ctx.sessionPersistence.load(id)   // reload on resume\nconst headers = await ctx.sessionPersistence.list()        // every stored session\n```\n\n`append` 只在批次持久后返回，因此成功返回的写入在操作系统崩溃或断电后依然存在。普通 `create` 保持惰性；只有当空会话本身必须出现在持久列表中时，生命周期前端才调用 `ensureMaterialized`，且不会虚构事件。`load` 返回不可变的平衡日志并提交任何需要的崩溃恢复；`inspect` 读取同一视图但不提交恢复。从水位恢复的消费方可以只读取该序列号及之后的已存储事件，会话的产物位置（`locate`）不经文件系统 I/O 即可解析。\n\n### 恢复与崩溃恢复\n\n恢复就是 `load` 加会话准备：存储日志连同其头部血缘一起返回，因此恢复后的 agent（智能体）看到相同的历史与组装。中途崩溃的会话重新加载时，其被中断的最终轮次会保留并保持平衡：`load` 为未获回答的调用追加合成 `tool/result` 与 `turn/end {interrupted}` closer，而不是丢弃事件——单个轮次可能很大，而这些事件在崩溃前已持久写入。只有从未完整写入的撕裂尾部碎片会被丢弃。\n\n### 失败与恢复\n\n当前构建无法忠实解读的存储日志会以方向感知的错误被拒绝，绝不错读。`SESSION_FORMAT_VERSION` 保持 v0，本构建不提供格式迁移路径；更高版本会要求操作者升级 harness。解码器只接受下文点名的有限同版本记录变体。本构建不认识的事件类型会被拒绝，除非其信封标记为 `ignorable`；已提交前缀中的损坏以 `SessionPersistenceCorruptionError` 拒绝。对仍绑定到活动会话的 id 执行 `load`，会先刷新其快照并在轮次开放时拒绝；冷 load 应用恢复。\n\n-----\n\n<a id=\"understand-the-implementation\"></a>\n## 理解实现\n\n<details>\n<summary>实现细节——点击展开</summary>\n\n本节说明 seam 如何实现持久存储以及后端如何接入；可观察约定见[使用本包](#use-this-package)与生成的 [Cordis API](../../../docs/subsystems/persistence.zh.md#cordis-surface)。\n\n### 设计理念\n\n本包是能力 seam 的 Service Definition，分两半。抽象的 `SessionPersistence` 服务是公开约定；`PersistenceCoordinator` 为缓冲、串行化、物化、修复、接管与完全停稳的 dispose 提供后端无关编排。后端实现存储读取、追加、修复与列出所需的小型持久原语，因此 JSONL 与 SQLite 共享生命周期正确性，同时保留不同的存储原语。\n\n### 每个后端必须遵守的不变量\n\n- **仅追加；崩溃轮次会被关闭，而非截断。** 已 flush 事件绝不重写；`load` 保留中断的最终轮次并持久追加合成 closer。\n- **连续 `seq`。** 日志中间的缺口会被拒绝；`append` 的第一个 `seq` 必须等于已存储 next-seq。\n- **无损 JSON 数据。** 批次经过共享单遍无损 JSON 边界；无法序列化的载荷在 append 处被拒绝。\n- **持久性。** `append` 只在批次持久后返回。\n\n### 源码地图\n\n| 文件 | 职责 |\n|---|---|\n| [`src/index.ts`](src/index.ts) | 插件入口：抽象 `SessionPersistence` 服务与重新导出的元数据类型 |\n| [`src/coordinator.ts`](src/coordinator.ts) | 共享写入编排：批处理、串行化、修复、接管、dispose、格式拒绝 |\n| [`src/write-behind.ts`](src/write-behind.ts) | 每会话有界写入控制器与 flush 屏障 |\n| [`src/preparations.ts`](src/preparations.ts) | 为恢复复用而有界保留的未发布 Session 准备结果 |\n| [`src/revision.ts`](src/revision.ts) | 带品牌类型的不透明修订值 token |\n| [`src/invariant.ts`](src/invariant.ts) | 不变式伴生插件（无运行时不变式；协调器断言存储/活动身份与 cwd） |\n\n### 写入路径概览\n\n每个 `session/event` 把事件复制到其会话的 controller。第一个待处理事件开启固定批处理窗口；后续事件加入但不重置截止时间。窗口到期后启动一次持久追加；该次写入期间接纳的事件形成另一个独立有界的后续批次。`session/flush` 取消等待并排空至完全停稳，因此 loop 在下一轮次前把它用作排序与错误观察检查点。被拒绝的后台写入保留其事件并暂停自动重试；新事件开启新窗口，而显式 flush 或后端拆卸会立即重试。\n\n### 存储记录兼容\n\n后端读取只会在校验当前记录之前，规范化明确支持的 v0 记录变体。协调器对 `load`、`inspect`、`readFrom`、无所有者状态认领与 HMR 接管使用同一份规范化视图。读取不会重写已存记录，后续追加使用当前 v0。[消息标识机制引入前的消息](../../../.agents/notes/implemented/bug-fix/2026-07-28-load-pre-identity-session-messages.zh.md)与 [react-loop 引入前会话](../../../.agents/notes/implemented/bug-fix/2026-08-04-load-pre-react-loop-sessions.zh.md)笔记规定这些有限例外；它们不构成通用格式迁移承诺。\n\n</details>\n-----\n\n<a id=\"further-exploration\"></a>\n## 进一步探索\n\n当包级约定不够用时阅读以下页面。它们从共享持久性模型逐步进入随产品交付的后端与决策证据。\n\n- [会话持久化子系统](../../../docs/subsystems/persistence.zh.md)——完整服务约定、flush 检查点、崩溃恢复与生成的 Cordis API。\n- [JSONL 持久化后端](../session-persistence-jsonl/README.zh.md)——随产品交付、按会话存储文件的后端。\n- [SQLite 持久化后端](../session-persistence-sqlite/README.zh.md)——可选启用的单数据库后端。\n- [会话检查点策略](../session-checkpoint-policy/README.zh.md)——在语义边界上经由本服务刷新的插件。\n- [会话包映射](../README.zh.md)——相邻的持久化、投影、标题与遥测包。\n\n-----\n\n<a id=\"model-experience\"></a>\n## 模型体验\n\n### 恢复的对话历史\n\n#### 模型看到什么\n\nseam 不添加提示词或 schema。恢复会将已存储的表层事件还原为消息历史；已存储请求 header 重建较早调用，新 loop 则为下一次请求组合当前系统提示词、工具与会话前缀。崩溃修复将没有持久调用的 assistant 请求标记为 `TOOL_NOT_STARTED`；有持久调用但无结果时变为 `TOOL_OUTCOME_UNKNOWN`，其文本允许模型重试只读或幂等工作，但要求验证副作用或询问用户，而不是盲目重试。\n\n#### Token 影响\n\n普通持久化期间为零 token。恢复后会重新计入保留历史的 token 用量，并照常计入当前请求 envelope 的 token 用量；每个已修复调用都会增加一段以引用形式保留的错误文本。\n\n#### KV Cache 影响\n\n持久化不修改实时请求前缀。只有当重建历史、当前 envelope 与模型路由匹配时，恢复 loop 才能重用提供方缓存；崩溃修复结果仅追加，不重写较早历史。\n\n## 已知限制与延期工作\n\n<a id=\"known-limitations-and-deferred-work\"></a>\n\n\n这些限制界定 seam 保证的终点。它们是当前包约束，不是任务积压。\n\n- **无删除或保留接口**——剪枝已存储会话属于带外后端维护。\n- **`list()` 无分页且无过滤**——它返回每个已存储会话的 header；适合本地存储，大规模时无索引。\n- **合成 closer 是唯一崩溃方案**——后端必须在 load 时合成 `tool/result`/`step/end`/`turn/end` closer；没有继续中断轮次而不先关闭它的部分轮次恢复。\n\n<a id=\"dev-note\"></a>\n### 开发备注\n\n<details>\n<summary>维护者的工作上下文——点击展开</summary>\n\n无。\n\n</details>\n","readmeFilename":"README.zh.md","_rev":"1-cd2ea1ac1e9f7a5857828a2d86f118cd"}