DeepSeek Harness 持久化 seam 瘦身:从「实现必须为无人提供什么」回到「恰好是消费方使用的东西」
【免费下载链接】deepseek-harnessDeepSeek Harness: Everything is a Plugin.项目地址: https://gitcode.com/gh_mirrors/de/deepseek-harness
本篇技术指南以 DeepSeek Harness 仓库中已归档的 Agent Note(
2026-06-20-prune-dead-seam-methods.zh.md)为核心骨架,完整还原一次真实的 seam 精简决策:仅移除SessionPersistence.has()与.delete(),并同步清掉协调器、PersistenceBackend.deleteStored钩子以及只为覆盖它们而存在的契约测试。文中会结合仓库内能力 seam 的三角色模型、双后端持久化设计与共享写入协调器的源码实现,讲解「没有消费方的方法不算 seam,而是每个实现都必须维护的推测性表面」这一核心判断,并给出可操作的验收清单与同类决策判断方法。
背景:什么是能力 seam,为什么它承载方法需要谨慎
在 DeepSeek Harness(Everything is a Plugin)中,可替换的能力(shell 执行、模型提供方、会话持久化等)被组织为「能力 seam」。依据 capability seams Agent Note,一个完整的 seam 由三个角色构成:
- Service Definition(服务定义)——Cordis
Service与词汇表类型,拥有ctx.<key>,只依赖契约所需的词汇(例如dsh-session-persistence的SessionPersistence抽象服务); - Service Provider(服务提供方)——注册/提供实现的插件(例如
dsh-session-persistence-jsonl与dsh-session-persistence-sqlite两个后端); - Consumer(消费方)——模型与插件编程所面向的对象(例如恢复会话的 agent 循环、会话查询接口)。
seam 的存在目的是让实现与消费方独立演进:一个沙箱执行器可以替换本地执行器,而不触碰模型看到的工具 schema。但这里有一个容易忽略的推论——一个没有任何消费方以之编程的方法,不是 seam 的一部分,而是每个实现仍必须实现和测试的「推测性表面」(speculative surface)。本 Agent Note 记录的正是对会话持久化 seam 的一次此类清理。
问题:SessionPersistence.has()与.delete()是无人消费的死方法
会话持久化抽象服务在 create/append 之外,最初声明了更多的操作:load、list、has、delete。逐一核对生产消费方的调用情况后发现问题集中在两个方法上:
- 生产消费方实际使用
load()(恢复)与list()(会话发现),而没有任何生产调用方使用持久化的has()或delete(); - 协议与 UI 代码中名称相似的内存集合调用(
Map.has/Map.delete)与持久化无关; - 持久化
has/delete的唯一调用者,是契约测试套件和各后端的 spec——即「测试覆盖了它们,但已发布代码从不会询问『这个会话是否已持久化?』,也不会删除某个会话」。
has()的问题还不止于「未使用」:在loadStored(id)已负责持久化存在性检查的情况下,它仍然给协调器增加了一个「已跟踪 / 未跟踪」探测和一个契约分支。delete()则拖入了一个deleteStored后端钩子,每个后端都必须为实现它而实现deleteStored。
这与同期的另一项精简——移除可变会话 summary——是同一类模式:契约测试覆盖了两者,但发布代码从不使用。可参考的既有先例是:SessionPersistence.update()曾有零生产调用者、firstPrompt从未被任何生产代码读取,最终被整体删除,JSONL 失去 sidecar 机制、SQLite 的SCHEMA_VERSION从 1 升到 2。
决策:从抽象 seam、实现与测试套件中同步移除
本 Agent Note 的决策非常克制——不是重新设计后端,只是删除没有消费方的东西:
SessionPersistence.has()/.delete()被移除:抽象声明、协调器的has/delete/deleteCore,以及PersistenceBackend.deleteStored钩子全部消失;- jsonl 与 sqlite 两个后端都只是为满足该钩子才实现
deleteStored,这些实现一并移除; - 所有文档与源码注释引用都更新为存留的四方法、仅含
list()的契约——不仅包括字面的has(/delete(/deleteStored拼写,还包括{@link has}/{@link delete}JSDoc 链接和「六个公共方法」的计数——涉及 seam 与后端 README、docs/architecture.md、会话持久化 Agent Note、共享持久化写入协调器 Agent Note 以及协调器/后端 JSDoc。
值得强调的是「双后端」设计本身不在本次范围之内:两个后端属于会话持久化双后端架构,删除它们为没有消费方的钩子所做的实现,是删除钩子的一部分,而非重新设计后端。
删除后的存留契约:四方法、list()-only
从当前仓库的 Service Definition 源码可以确认,存活的抽象SessionPersistence契约如下(均在存档笔记记载的create/append/load/list语义上演进):
| 方法 | 职责 | 关键语义 |
|---|---|---|
create(meta) | 注册新会话的元数据 | 后端可延迟物理写入(lazy materialization),从未 append 的会话不出现在list(),被放弃的会话不留痕迹 |
append(id, events) | 持久化一批事件 | 遵循 append-only 与 contiguous-seq 契约:首个事件的seq必须等于存储的 next-seq;append在持久化完成后才 resolve |
load(id) | 加载不可变平衡逻辑视图并提交冷恢复 | 完整的被中断末尾轮次被保留并持久化闭合,仅丢弃撕裂的末尾记录;未知版本与已提交前缀中的损坏会拒绝加载 |
list() | 从元数据轻量列举 | 无需解析完整日志,返回每个已物化会话的 header 一个 |
除此之外,Service Definition 还包含locate、readRaw、ensureMaterialized、prepare、inspect、borrowSession、readFrom、listSnapshots等围绕恢复、只读观察与后缀读取的方法——但它们不属于本次精简所讨论的「create/append 之外的多余操作」,而是恢复与查询链路的真实消费方所必需的。本决策验证的核心断言正是:剩余的create/append/load/list未受影响,基于持久化的会话查询和崩溃恢复行为完全一致。
实现细节:deleteStored钩子的移除如何落进协调器
为了理解移除的边界,需要看共享持久化写入协调器的设计。dsh-session-persistence-jsonl与dsh-session-persistence-sqlite故意用不同存储介质证明同一契约,但它们此前重复实现了整套写入路径编排。因此协调器被抽取进dsh-session-persistence,每个后端通过组合(composition,而非继承)持有它,并实现一个很小的PersistenceBackend钩子接口。
从当前 coordinator.ts 源码 可以看到,协调器与存储之间的唯一边界是这些钩子:
name——后端标签,用于 dispose 失败的AggregateError;loadStored(id)——按 id 跨所有存储范围读取一个已存储前缀;准备、逻辑加载/检查、物理后缀读取、活跃收养与 create-碰撞探测都复用这一查找;appendBatch(meta, events, isMaterialized)——持久化追加连续批次,在未物化时原子地惰性物化会话;materializeHeader?(meta)——可选的显式物化钩子;commitRepair(meta, tornMarker, closers)——使崩溃修复持久化:截断撕裂尾部(当tornMarker !== undefined)并追加 closers;不要求原子;list()——列出所有已存储元数据;close?()——可选的销毁钩子。
而deleteStored钩子之所以会出现在历史版本中,正是为了支撑SessionPersistence.delete()。一旦删除操作本身被认定无消费方,该钩子及其在两个后端中的实现就失去了存在理由。这印证了本 Agent Note 的一个方法论要点:钩子接口的宽度应随真实消费方收敛,而不是为了想象中的 API 完整性预置——正如协调器设计中那些被拒绝的候选钩子(无 scope 专属实时查找、无存储定位泛型、无单独 materialize 钩子、无独立 create-碰撞探测)一样,deleteStored也在「没有消费方」这一条件下被折叠掉了。
曾考虑的替代方案:为什么「seam 应当完整」不成立
本 Agent Note 明确记录了对直觉的反驳:「持久化 seam 理应提供 delete」这种直觉是真实的——但它恰恰是预发布阶段所警惕的投机性完整。仓库根 AGENTS.md 的立场是:为正确的基础优化,而非为你并不拥有的假想调用者优化(pre-release stance: foundation over blast radius)。
delete()只是一个方法,等消费方真正需要时再加回来即可:一个删除旧会话的会话管理 UI 会需要它——到那时再基于该 UI 的真实需求来设计(软删除?级联?确认?),而非现在猜测。两个关键论证:
- 有活跃消费方时重新添加一个 seam 方法,成本低且设计更优——因为消费方锚定了契约,而不是让实现方猜测契约;
- 在无人使用的情况下保留它,意味着每个实现(以及未来的每个后端)都必须实现和测试一个无实际作用的方法。
同样的判断逻辑也体现在品牌化 id Agent Note 的「not every string needs a brand」策略中:BashTaskId与OwnerToken被加入,是因为它们是模型可见或用于访问控制的 id;而ModelId、ToolName等候选被明确推迟。本 Agent Note 的实现说明也记录了同一思路下的另一处边界:BashExecutor.get()与.list()之所以保留,是因为删除它们的单行查找表面会要求消费方增加显著更多的完成跟踪机制——是否删一个方法,取决于「维护成本 vs. 移除成本 + 未来重建成本」的权衡,而不是一刀切的规则。
验证与后果:规模不大,但完成了 seam 的定义性修复
本 Agent Note 记录了完整的验证与后果评估:
验证结果:
has/delete/deleteStored已从持久化 seam、实现和契约测试套件中移除,没有新增无用导出;- 剩余操作(
create/append/load/list)未受影响,基于持久化的会话查询和崩溃恢复行为完全一致; - seam README 和
docs/architecture.md仅列出存留的方法。
后果评估:
delete()是产品最终会需要的操作——确实如此,但「最终」正是关键:现在删除、将来基于真实消费方重新添加,严格优于发布一份猜测的契约;两个后端各自减少了一个deleteStored实现,这是在本次范围之外的包中的有限改动;- 低耦合——移除局限于持久化 seam + 实现 + 测试;没有跨包消费方引用被移除的方法,因此除文档外没有涟漪效应。
沉淀的方法论:这类 seam 精简决策如何做、如何验收
结合本 Agent Note 及其引用的 drop-mutable-session-summary 先例,可总结出一套可复用的判断与验收清单:
- 枚举抽象 seam 上的全部方法,逐一核对生产消费方——区分「协议/UI 中同名的内存集合调用」与「持久化 API 的真实调用者」,契约测试与 per-backend spec 的调用不算生产调用;
- 检查该方法是否只是给协调器/后端增加探测分支或钩子——如果存在性检查已由
loadStored(id) !== undefined承担、可写操作只是为支撑该方法而引入后端钩子,那么该方法就是多余表面的典型信号; - 评估「现在删除」与「将来重建」的成本对比——重加一个 seam 方法在有活跃消费方时成本低且设计更优;而保留一个无人使用的方法则让每个实现与每个未来后端持续付费;
- 同步清理文档与 JSDoc——不仅是字面拼写,还包括
{@link has}这类链接和「六个公共方法」这类计数,避免文档与代码继续描述已删除的表面; - 验证剩余契约不变——
create/append/load/list行为完全一致,持久化会话查询与崩溃恢复无回归,且无新增无用导出。
本 Agent Note 自评「规模不大」,但它将 seam 从「实现必须为无人提供什么」恢复为「恰好是消费方使用的东西」——这正是 DeepSeek Harness 在预发布阶段反复实践的契约纪律:接口宽度由真实消费方决定,而非由「完整性」的直觉决定。对任何以可替换能力为核心的插件化系统而言,这份决策记录都是一份可直接引用的设计审慎范例。
延伸阅读(仓库内相关证据)
- 本决策的完整英文原文:
2026-06-20-prune-dead-seam-methods.md - 能力 seam 三角色模型:capability seams Agent Note
- 会话持久化双后端设计:session persistence Agent Note
- 写入协调器与
PersistenceBackend钩子:shared persistence write coordinator Agent Note - 同类先例(删除无消费方的
update()与可变 summary):drop-mutable-session-summary - 存留契约的源码实现:
SessionPersistenceService Definition、coordinator.ts
【免费下载链接】deepseek-harnessDeepSeek Harness: Everything is a Plugin.项目地址: https://gitcode.com/gh_mirrors/de/deepseek-harness
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考