dsh-memory-projection
Hot-pluggable memory-projection scheduling framework for DeepSeek Harness (dsh): pure-function projection strategies + a runtime invariant guard, built on the cordis plugin kernel.
- Stars
- 0
- Language
- TypeScript
- Created
- Aug 20, 2026
- Updated
- Aug 28, 2026
Introduction
dsh-memory-projection
DeepSeek Harness 可热插拔的「记忆投影」框架 —— 在运行时动态切换 Agent 的认知模式(模型可见上下文的切片方式),而非对历史做有损压缩。
项目介绍:关于「记忆投影」的定位
很多上下文管理方案做的是 context-compression(上下文压缩):把历史对话塞进一个摘要,用摘要替换原始记录,从而「缩小」喂给模型的 token 数。这种做法的代价是不可逆地丢弃了原始日志——一旦压缩,模型就再也看不到被压缩掉的真实事件。
本插件做的是 memory-projection(记忆投影),二者有本质区别:
| 维度 | Context Compression | Memory Projection(本插件) |
|---|---|---|
| 对原始日志 | 压缩 / 覆盖 / 丢弃 | 只读、永不直接修改 |
| 历史的可恢复性 | 不可恢复(摘要即真值) | 始终可从 append-only 日志精确重建 |
| 模型看到的内容 | 一段「总结」 | 原始事件的某个切片 / 重排(真实事件) |
| 运行时行为 | 通常静态 | 热插拔、可切换、可回归默认 |
| 与 DSH 不变量关系 | 容易破坏 Model-Visible ⇔ Logged | 由 invariant guard 强制守住该不变量 |
核心心智模型:
append-only 会话事件日志是唯一的真相源(single source of truth)。 投影(projection)只是这个日志的一个纯函数视图——同一个日志,配合不同策略,得到不同的「模型可见切片」。模型当下看到什么,永远可以追溯回某几条原始事件(
sourceSeqs)。
因此本插件不是一个「压缩器」,而是一个调度框架 + 内置策略集:它让你在运行时按场景切换 Agent 关注历史的哪一部分,而历史本身一分不少地留在日志里。
核心特性
- 🔌 可热插拔的调度框架:
ctx.memoryProjection提供registerStrategy/setActiveStrategy/getActiveStrategy/listStrategies,运行时动态切换 Agent 认知模式,下一次投影即生效。 - 🧩 内置三种纯函数策略 + 默认
passthrough(等价于原生推导):precision-window—— 保留最近 N 轮 + 关键事件(聚焦执行)。associative-divergence—— 从全史召回与当前上下文语义相关的事件,前置拼接(创造联想)。critical-focus—— 只保留错误 / 边界 / 未解决事件(调试 / 复盘)。
- 🛡️ 运行时不变式守卫(invariant guard):对激活策略做「双跑可复现性 + 日志溯源(provenance)」校验。凡违反
Model-Visible ⇔ Logged不变量的投影,自动回退到默认投影,绝不让 Agent 循环中断。可开关。 - ♻️ 零残留热插拔:所有副作用(service、事件监听、第三方注册)均通过 Cordis 原生生命周期(fiber 作用域)注册,卸载时 LIFO 自动回滚。不手写事件总线、不手写服务管理器、不手写 cleanup。
- 📐 Cordis 原生合规:仅使用
definePlugin/ctx.plugin(Service)/ctx.on(...)等官方扩展点,不修改内核。 - 🧪 严格工程:TypeScript
strict+ ESM、Vitest 测试、ESLint + Prettier、tsup打包,npm publish就绪,一键 GitHub CI。
快速开始
安装
npm install dsh-memory-projection
运行依赖为
@deepseek-ai/cordis@^4(即 DSH 运行时所用的 Cordis 内核,已发布于公共 npm,可直接npm install)。@deepseek/harness以 可选 peerDependency 声明——本插件只依赖 Cordis 契约,不强制依赖 Harness 内核。
在你的 DSH / Cordis 应用中加载
import { Context } from '@deepseek-ai/cordis';
import { dshMemoryProjection } from 'dsh-memory-projection';
const root = new Context();
root.plugin(dshMemoryProjection);
const svc = root.memoryProjection;
// 切换策略(下一次投影即生效)
svc.setActiveStrategy('precision-window', { windowSize: 6 });
// 投影:输入 append-only 事件日志,输出模型可见消息
const messages = svc.project(sessionEvents);
接入原生推导(拦截 session/derive-messages)
插件在加载时注册了一个 waterfall 事件监听 session/derive-messages:
- 监听存在时 → 用当前激活策略替换原生推导(veto
next)。 - 监听移除时(插件卸载)→ 原生
next()原样执行,默认投影完全恢复。
在 DSH 侧,只需把原生 Session.deriveMessages() 作为 next 续体传入该 waterfall 即可;本插件不要求修改内核。
内置策略详解
所有策略都是纯函数:相同输入(日志 + 选项)→ 相同输出,只读日志、无 I/O、无时钟读取、不修改入参。
passthrough(默认)
恒等投影,等价于 DSH 原生推导。即「不投影」,把完整日志逐事件映射为模型可见消息。作为守卫回退的安全兜底。
precision-window
选项(均可选):
windowSize number 保留最近 N 个会话轮次(以 user 消息为轮次边界),默认 6
keepSystemEvents boolean 轮次外仍保留 system/boundary 事件,默认 true
keepErrors boolean 轮次外仍保留 error 事件,默认 true
适用:高频工具调用 Agent、聚焦执行场景。模型只需「最近上下文 + 持久系统约束」,丢弃窗口外的冗余工具步骤。
associative-divergence
选项(均可选):
threshold number 历史事件的语义相似度下限,默认 0.08
topK number 最多召回的历史事件数(0 = 不限),默认 0
keepRecentRound boolean 始终保留最近一轮(当前线程),默认 true
从全史中,按「当前上下文(最新 user prompt / recentContent)」的局部词重叠余弦相似度,召回语义相关事件并前置拼接。不强制截断——最近上下文始终保留,相关历史是「追加」而非「替换」。
相似度用确定性、零依赖的局部词重叠余弦作为「语义相关」的代理,保证策略仍是纯函数。 生产环境可通过
registerStrategy注册基于 embedding 的策略实现真正的语义召回。
适用:创造联想、跨会话回溯——模型拿到相关先验上下文,同时不丢失当前线程。
critical-focus
选项(均可选):
keepErrors boolean 保留 error/failure 事件,默认 true
keepBoundary boolean 保留 boundary(约束)事件,默认 true
keepUnresolved boolean 保留 unresolved 事件,默认 true
keepLastUser boolean 保留最后一条 user 消息作为上下文锚点,默认 true
只保留 error / boundary / unresolved 事件,丢弃所有「顺利执行」的步骤。适用:调试、质量审查、风险复盘——模型只看「什么出错了 + 约束是什么」。
自定义策略开发指南
一个策略 = 一个满足 ProjectionStrategy 契约的纯函数对象:
import type { ProjectionStrategy, ProjectedMessage, SessionEvent } from 'dsh-memory-projection';
const myStrategy: ProjectionStrategy = {
name: 'my-strategy',
project(events: readonly SessionEvent[], options?: Record<string, unknown>): ProjectedMessage[] {
// 1) 只读 events + options,不读外部状态 / 不读时钟 / 不修改入参
// 2) 每条产出的消息必须带 sourceSeqs(溯源到日志中的真实事件)
const out: ProjectedMessage[] = [];
for (const e of events) {
if (/* 你关心的条件 */ e.data.role === 'user') {
out.push({
role: 'user',
content: e.data.content ?? '',
sourceSeqs: [e.seq], // 溯源:必须落在 events 的 seq 集合内
});
}
}
return out;
},
};
注册并启用:
const svc = root.memoryProjection;
svc.registerStrategy('my-strategy', myStrategy);
svc.setActiveStrategy('my-strategy', {/* 运行时选项 */});
不变式要求(由 guard 强制):
- 可复现性:同一日志跑两次必须
deepEqual一致。读外部状态 / 随机 / 时钟 → 守卫判定为「非纯函数」并回退。 - 日志溯源:每条输出消息的
sourceSeqs必须是日志中真实存在的seq。凭空捏造内容 → 守卫回退。
若你想关闭守卫(例如你信任自己的策略且需要跑非确定性逻辑),可:
svc.setGuardEnabled(false);
架构设计
1. 与 DSH 不变式的关系(Model-Visible ⇔ Logged)
DSH 的核心不变量是:模型可见的内容,必须能从已落库(logged)的会话日志中重建。本插件把这条不变量变成可机检的工程约束:
- 日志(
SessionEvent[])是唯一的真相源,投影只读它。 - 每条投影消息携带
sourceSeqs,显式声明「我来自哪几条原始事件」。 invariant-guard.ts在每次投影后做两层校验:- 可复现性:纯函数双跑一致。
- 溯源:
sourceSeqs ⊆ 日志.seq。
- 任一校验失败 → 回退到
passthrough(默认投影),并告警。Agent 循环永不因投影失败而中断。
这把「不变量」从一句哲学宣言,落地为每次投影都会跑的自动化测试。
2. 可逆副作用原则(零残留热插拔)
插件不手写事件总线、不手写服务管理器、不手写 cleanup 函数。所有副作用都委托给 Cordis 原生生命周期:
| 副作用 | 实现方式 | 卸载时如何回滚 |
|---|---|---|
ctx.memoryProjection 服务 | 继承 Service 基类,super(ctx, 'memoryProjection') | Cordis 自动从所属 fiber 移除该服务 |
session/derive-messages 监听 | ctx.on('session/derive-messages', handler) | 返回的 fiber 作用域处置器自动注销 |
| 第三方策略注册 | ctx.plugin(...) / ctx.on(...) | 同样随 fiber 作用域 LIFO 回滚 |
加载流程(apply(ctx) → ctx.plugin(MemoryProjectionService))→ 注册 4 个内置策略 + 1 个 waterfall 监听;卸载(ctx.dispose())→ 服务、监听、第三方注册全部自动撤销,原生推导恢复如初。不留下任何全局状态或孤儿监听。
3. 为什么把 session/derive-messages 建模为 waterfall
DSH 原生的「消息推导」是一个方法(Session.deriveMessages()),并不存在字面意义上的 session/derive-messages 事件。本插件把它建模为 Cordis 的 waterfall 接缝:
- 插件监听在该接缝上,包裹原生
next(即原生推导)。监听存在时,返回策略结果(veto 原生next)。 - 监听消失(卸载)时,
next()原样执行 → 默认投影完全恢复。
这是对「官方扩展点」的正确使用方式:既实现了「拦截推导」的诉求,又保证卸载可逆、零残留。
目录结构
dsh-memory-projection/
├── src/
│ ├── index.ts # definePlugin 包装 + 公共导出
│ ├── types.ts # 类型 + 纯辅助(classifyEvent/isKeyEvent/eventToMessage/deepEqual)+ 模块增强
│ ├── core/
│ │ ├── projection-service.ts # MemoryProjectionService(ctx.memoryProjection)
│ │ └── invariant-guard.ts # checkInvariant(可复现 + 溯源)
│ └── strategies/
│ ├── precision-window.ts
│ ├── associative-divergence.ts
│ └── critical-focus.ts
├── tests/ # Vitest 单测(策略正确性 + 纯函数性 + 生命周期零残留)
├── examples/
│ └── basic-usage.ts # 可运行最小示例
├── .github/workflows/ci.yml # 推送自动 类型检查→单测→构建
├── package.json
├── tsconfig.json
├── tsup.config.ts
├── vitest.config.ts
├── .eslintrc.json
├── .prettierrc.json
├── .gitignore
├── README.md
└── LICENSE
验证清单(自测通过项)
本仓库已覆盖以下 7 项自检:
- Cordis 原生合规:仅使用
definePlugin/Service/ctx.on/ 模块增强,未修改内核。 - 不变式守卫:
checkInvariant对非确定性 / 无溯源的策略自动回退。 - 零残留热插拔:
load → setActiveStrategy → dispose后,session/derive-messages恢复原生推导。 - 纯函数性:内置策略满足确定性、不可变性、同源同输出(测试覆盖)。
- 策略可扩展:
registerStrategy注册自定义策略并即时生效;未知策略名安全忽略。 - 工程就绪:
tsc --noEmit/vitest run/tsup全绿;ESLint + Prettier 配齐。 - 发布就绪:
files字段、exports映射、MIT LICENSE、CI 工作流齐备,npm publish可直接发。
许可证
本项目基于 MIT 许可证 开源。