{"_id":"@buddhilive/dsh-compaction","name":"@buddhilive/dsh-compaction","dist-tags":{"alpha":"0.1.2-alpha.3","latest":"0.1.2-alpha.3"},"versions":{"0.1.2-alpha.3":{"name":"@buddhilive/dsh-compaction","description":"Abstract compaction service seam (ctx.compaction) 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/compaction/compaction"},"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"},"./types":{"types":"./lib/types/types.d.ts","default":"./lib/types/types.js"},"./checkpoint":{"types":"./lib/types/checkpoint.d.ts","default":"./lib/types/checkpoint.js"},"./src/*":"./src/*","./package.json":"./package.json"},"license":"MIT","peerDependencies":{"@buddhilive/dsh-brand":"^0.1.2-alpha.3","@buddhilive/dsh-commands":"^0.1.2-alpha.3","@buddhilive/dsh-llm":"^0.1.2-alpha.3","@buddhilive/dsh-session":"^0.1.2-alpha.3","@deepseek-ai/cordis":"^4.0.2","@buddhilive/dsh-invariants":"^0.1.2-alpha.3"},"devDependencies":{"@buddhilive/dsh-brand":"^0.1.2-alpha.3","@buddhilive/dsh-invariants":"^0.1.2-alpha.3","@buddhilive/dsh-commands":"^0.1.2-alpha.3","@deepseek-ai/cordis":"^4.0.2","@buddhilive/dsh-llm":"^0.1.2-alpha.3","@buddhilive/dsh-session":"^0.1.2-alpha.3"},"_id":"@buddhilive/dsh-compaction@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-JERpeqDNXcQJSSfQkjbqyDMP84D7McoehZfIc9zdQpdxSQ1ZatDhKvxbTJkfjYJEh6FaZctg+AlNdQwhE2UW1g==","_resolved":"C:\\DevDojo\\Buddhi\\buddhi-ai-harness\\dist\\npm\\buddhilive-dsh-compaction-0.1.2-alpha.3.tgz","_from":"file:C:/DevDojo/Buddhi/buddhi-ai-harness/dist/npm/buddhilive-dsh-compaction-0.1.2-alpha.3.tgz","_nodeVersion":"24.13.0","_npmVersion":"11.6.2","dist":{"integrity":"sha512-JERpeqDNXcQJSSfQkjbqyDMP84D7McoehZfIc9zdQpdxSQ1ZatDhKvxbTJkfjYJEh6FaZctg+AlNdQwhE2UW1g==","shasum":"6e99cfa73e38def048502f973592ca12457a8403","tarball":"https://registry.npmjs.org/@buddhilive/dsh-compaction/-/dsh-compaction-0.1.2-alpha.3.tgz","fileCount":19,"unpackedSize":87061,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEQCIA4HZ32q+NX7GHLh1N4EX5bwbx5HL3gssjJQdMDG+Mc4AiA+m5e6da864OgIfbqcMRL8eHEsjqGUc33ON00PWHT2oQ=="}]},"_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-compaction_0.1.2-alpha.3_1788165086373_0.41168972456140795"},"_hasShrinkwrap":false}},"time":{"created":"2026-08-31T08:31:26.114Z","0.1.2-alpha.3":"2026-08-31T08:31:26.502Z","modified":"2026-08-31T08:31:26.769Z"},"maintainers":[{"name":"buddhilive","email":"visitbudkavin@gmail.com"}],"description":"Abstract compaction service seam (ctx.compaction) 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/compaction/compaction"},"bugs":{"url":"https://github.com/Buddhilive/buddhi-ai-harness/issues"},"license":"MIT","readme":"---\ndescription: \"面向后端实现者与部署方的共享压缩约定：会话压缩做什么、何时使用，以及如何实现后端。\"\nkind: \"package-reference\"\n---\n\n# @buddhilive/dsh-compaction\n\n[English](README.md) | 中文\n\n## 概述\n\n`dsh-compaction` 让长时会话把较早历史压缩（compaction）成一条摘要消息、保持近期对话不变，并像摘要一直存在那样继续下去——配合 `dsh-compaction-basic` 之类的后端与可选的 `/compact` 命令即可实现。被压缩的内容仍保留在会话日志中，因此回放会话可以还原出完全相同的对话。当你实现压缩后端、构建触发压缩的组件，或需要识别压缩后的消息时，才需要本包——它本身不执行任何压缩。只想开箱即用地获得该功能时，请选择随附后端。\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先确定你需要什么。随附后端加 `/compact` 命令即可零代码获得自动与按需压缩；只有在你扩展或重实现该功能时才需要本包。以下各节说明压缩做什么、如何启用，以及如何编写后端。\n\n### 何时选择\n\n当模型撰写的摘要符合需求时，选择 `dsh-compaction-basic`：会话增长时自动压缩，并可通过 `dsh-command-compact` 按需压缩。当你需要不同的摘要方式——固定模板或远程服务——或构建以编程方式触发压缩的组件时，选择本包。不要单独挂载它：没有后端就什么都不会压缩。\n\n### 压缩后会发生什么\n\n压缩运行时，所选较早范围的对话会被替换为一条摘要消息；近期历史不受影响，对话从摘要继续。压缩可以由 token 压力自动触发、按需触发，或针对显式范围触发；结果会报告压缩了哪些历史以及估算释放的 token 数。\n\n### 启用压缩\n\n挂载随附后端以注册压缩服务，并添加 `dsh-command-compact` 获得按需命令：\n\n```yaml\n- name: '@buddhilive/dsh-compaction-basic'\n- name: '@buddhilive/dsh-command-compact'\n```\n\n有了这两行配置，功能即已开启：会话增长时自动压缩，`/compact` 收到请求后立即压缩并报告替换了多少历史项。如果未挂载后端，什么都不会压缩，`/compact` 也会失败；随附后端的完整依赖链见其自身 README。\n\n### 实现后端\n\n继承提供的基类并实现三个操作：一个针对自动触发决定并执行压缩，一个按需压缩，一个压缩对话的显式范围。把你的类作为插件加载，它就会成为该组合的压缩服务。精确签名、失败规则以及每个后端必须生成的检查点标记，见下方实现章节与[压缩子系统参考](../../../docs/subsystems/compaction.zh.md)。\n\n### 识别压缩后的历史\n\n后端写入的摘要消息带有稳定标记，因此任何消费方都能在持久化或克隆后识别压缩历史，而无需知道是哪个后端生成的。该标记从包根导出，也从一个无 cordis 依赖的子路径导出，客户端与 wire 程序均可导入。\n\n-----\n\n<a id=\"understand-the-implementation\"></a>\n## 理解实现\n\n<details>\n<summary>实现细节——点击展开</summary>\n\n本节以 API 术语解释约定及其背后的设计决策；功能层面行为见[使用本包](#use-this-package)。\n\n### 设计理念\n\n该 seam 建立在一个拆分与三项承诺之上：\n\n- **抽象约定，具体后端。** 接口规定压缩做什么；提供方拥有策略、保留与摘要，因此各角色可独立演进、独立替换。\n- **会话与 LLM 词汇是约定的一部分。** 操作作用于 `Session`，摘要使用 `ContentBlock`，因此尽管有通用的 cordis-only 指引，Service Definition 仍依赖 `dsh-session` 与 `dsh-llm`——这是一项有意的偏离，记录在[压缩能力 seam Agent Note](../../../.agents/notes/implemented/feature/2026-06-18-compaction-capability-seam.zh.md) 中。\n- **日志记录的标记对就是锁。** `compaction/start` 在摘要让出控制权之前追加，`compaction/end` 释放；每次失败都恰好进行一次闭合尝试，闭合失败会留下未匹配 start 作为有意的 busy 信号。\n- **表层只变更一次。** 摘要承载在标记对内的一条 `user/message` 替换上；所有 `compaction/*` 事件仅写入日志。\n\n### 服务 API\n\n该约定是后端实现的三个抽象操作：`compactIfNeeded` 针对自动 `pressure` 或 `context-overflow` 触发，`compactNow` 进行一次显式按需缩减，`compactRegion` 针对调用方选择的表层范围。可复用的请求测量是独立服务 `ctx.tokenMeter`。穷尽式逐操作语义见[压缩子系统参考](../../../docs/subsystems/compaction.zh.md)；精确签名见 [`src/index.ts`](src/index.ts)。\n\n通过 `ctx.llm.stream()` 摘要的后端必须将 signal 转发到调用的 `GenerateOptions.signal`，因此 abort 或 fiber dispose（资源释放）会停止进行中的摘要。自动和显式范围标记对会从打开的轮次恢复其数字形式归属；手动标记对不要求存在打开的轮次，并标记 `turn: null`。\n\n### 手动失败分类\n\n预期手动失败会抛出 `ManualCompactionError`，携带来自小型封闭集合的稳定 `code`；只有 `compaction/start` 标记之后发生的失败才会被记录——以携带错误的 `compaction/end` 形式——而 `busy` 拒绝或 start 之前的取消不会留下记录。每个错误码的语义见[压缩子系统参考](../../../docs/subsystems/compaction.zh.md)。\n\n<a id=\"tool-pairing-boundaries\"></a>\n### 工具配对边界\n\n该 Service Definition 导出 `toolPairingBalancedBefore(session, seq)` 与 `toolPairingBalancedAfter(session, seq)`，用于对齐和验证压缩边界。安全边界不会被尚未回答的 assistant 工具调用跨越。每个 helper 都会验证给定事件 seq 位于当前表层，并根据按表层顺序缓存的各切分点配对状态返回结果，因此重复检查不读取事件；replace generation 会重建缓存，缺失 seq 或孤立的 `tool/result` 会被视为表层状态损坏并遭拒绝。\n\n### 表层约定\n\n`SurfaceEventType` 是封闭联合——只有 `user/message`、`assistant/message` 与 `tool/result` 可以携带 `surfaceOp`，因此 `compaction/*` 事件不能出现在表层上。成功的后端运行改为在日志中包围整个操作：先追加 `compaction/start`（仅日志）获取锁，摘要该范围，追加仅日志的 `compaction/summary` 记录，用一条承载摘要的 `user/message` 替换所选范围——这是唯一的表层变更——最后追加 `compaction/end`（仅日志）释放锁。\n\n替换位于锁的起止范围**内**，因此 `compaction/start` 与 `compaction/end` 之间崩溃会留下可检测的遗留锁，而不是虚假声称成功的 `compaction/end`。`deriveMessages()` 将摘要渲染为 user 角色消息，后面跟随已保留节点；已遮蔽事件仍保留在原始日志中，因此回放具有确定性。每个事件的具体 payload 见[压缩子系统参考](../../../docs/subsystems/compaction.zh.md)。\n\n### 源码地图\n\n| 文件 | 职责 |\n|---|---|\n| [`src/index.ts`](src/index.ts) | 插件入口：抽象 `CompactionEngine`、`CompactionTrigger`、`ManualCompactionError`、`ctx.compaction` 合并 |\n| [`src/types.ts`](src/types.ts) | `CompactionResult` 与声明合并的 `compaction/*` 会话事件 |\n| [`src/tool-pairing.ts`](src/tool-pairing.ts) | 两个边界 helper 背后的每会话切分点平衡缓存 |\n| [`src/checkpoint.ts`](src/checkpoint.ts) | 无 cordis 依赖的检查点来源构造函数与谓词（`./checkpoint` 叶子） |\n| [`src/brand.ts`](src/brand.ts) | `CompactionId` 品牌化标识 |\n| [`src/invariant.ts`](src/invariant.ts) | 不变式伴生插件：校验 `compaction/start`→`summary`→`end` 标记对、其属主轮次包裹与检查点关联 |\n\n### 锁与串行化\n\n所有入口点共享一个日志记录的锁。尾部检查会分别查找最新的未匹配 `compaction/start` 与最新的 `session/end-seed`；位于该边界之后的未匹配 start 是活动锁并报告 `busy`，更早的则是先前进程生命周期留下的陈旧证据。活动标记对不能跨越 `turn/start` 或 `turn/end`。标记是锁的时间点，而非排他容器：空闲的 `inject()` 可以在手动 start 与 end 之间追加不相关的上下文，因此手动路径重新验证其选中范围，而不要求整个表层相等。\n\n### 事件\n\n`compaction/*` 事件通过 declaration merging 扩展 `SessionEventMap`（可合并扩展）——它们是会话事件，不是 cordis `Events`，且都仅写入日志。生成的[持久化日志事件目录](../../../docs/persistence-catalog.zh.md)拥有每个事件的 payload；`compaction/prune` 记录了与工具结果修剪器共享的影子价格协议。\n\n</details>\n\n-----\n\n<a id=\"further-exploration\"></a>\n## 进一步探索\n\n当包级约定不够用时阅读以下页面；它们从共享词汇逐步进入随附后端与决策证据。\n\n- [压缩子系统参考](../../../docs/subsystems/compaction.zh.md)——压缩词汇、结果与生成的 API。\n- [压缩基础后端](../compaction-basic/README.zh.md)——自动与按需压缩的随附后端。\n- [工具结果修剪器](../compaction-tool-result-pruner/README.zh.md)——先修剪超大工具输出的可选配套工具。\n- [人类 /compact 命令](../command-compact/README.zh.md)——按需触发压缩的入口。\n- [Token meter](../../llm/token-meter/README.zh.md)——决定何时压缩的测量服务。\n- [压缩能力 seam Agent Note](../../../.agents/notes/implemented/feature/2026-06-18-compaction-capability-seam.zh.md)——拆分及 session/llm 依赖的依据。\n\n-----\n\n<a id=\"model-experience\"></a>\n## 模型体验\n\n### 调用后端时的会话历史\n\n#### 模型看到的内容\n\n成功的后端会用一条 user 角色摘要检查点替换较早表层范围——一条携带 `surfaceOp: { op: 'replace', start, end }` 的 `user/message`。原始事件仍会记录，但不再出现在派生模型消息中；seam 本身不执行改写。\n\n#### Token 影响\n\n该 Service Definition 不会直接产生 token。后端用一份摘要换取多个原本保留的历史 token，并保持近期尾部不变。\n\n#### KV Cache 影响\n\n成功的后端替换会使从第一个被遮蔽历史 token 起的复用失效；seam 本身不会改变请求。\n\n## 已知限制与延期工作\n\n<a id=\"known-limitations-and-deferred-work\"></a>\n\n\n这些限制说明无论加载哪个后端，压缩都无法做到的事；它们是当前包约束。\n\n- **面向用户的命令，而非模型工具**——压缩由 `/compact` 命令与自动压力触发；不会注册面向模型的压缩工具。\n- **部分单元溢出不在约定内**——平衡摘要压缩无法拆分一个不可分单元。当闭合工具对中可移除的主要部分是承载文本的工具结果时，可选剪枝配套服务仍可修复该工具对；无法压缩大型非工具节点，或不可剪枝剩余部分过大的工具单元。\n- **单独接近窗口大小的 envelope 不属于表层压缩工作**——压缩缩减派生历史，绝不缩减系统提示词、工具或会话前缀。\n\n<a id=\"dev-note\"></a>\n### 开发备注\n\n<details>\n<summary>维护者的工作上下文——点击展开</summary>\n\n本开发备注是维护者的工作上下文，明确不具权威性；已交付行为以上文、包代码与所链接的 Agent Note 为准。\n\n- **面向模型的工具，尚未决定**——压缩目前仅限用户命令。面向模型的压缩工具仍是开放问题；它需要自己的 schema，并与现有命令路径协调。\n- **模板与远程后端，尚未决定**——`SummaryResult` 约定已带有未标记的 `rawOutput` 变体，供不通过 `ctx.llm.stream()` 识别调用的摘要器使用，但此类后端尚未随附。\n- **`/compact` 的范围参数，尚未决定**——无参数形式使各命令适配器的行为保持稳定；显式范围仍由编程接口 `compactRegion()` 处理。\n\n</details>\n","readmeFilename":"README.zh.md","_rev":"1-911e9ec43bd548c072b8c312a11f3d14"}