← Back to home@kkwings

dsh-super-memory

No description

Stars
1
Language
JavaScript
Created
Oct 2, 2026
Updated
Oct 7, 2026
GitHub repo

Introduction

dsh-super-memory(超级记忆)

跨压缩记忆插件:在同一个超长会话里聊到被上下文压缩过几次之后,你提到更早(已被压掉)问过 / 定过的事时,模型先看到它,并作为参考结合这次的新条件综合分析——不会当新问题从零重来。

它只做「跨压缩」,不做跨会话;自包含,不依赖任何其他记忆插件。

三件事

#时机做什么成本
①压缩时把这次被压掉的内容本地入库:L1 摘要块(用 DSH 已生成好的摘要)+ L2 对话原文块(只留用户问题与助手回答的文字)0 模型调用
②压缩后注入一份目录级「本会话此前脉络」(话题 — 结论),让新窗口一开场就知道过去聊过哪几大块≤ 300 token,自适应,可为 0
③提问时每次提问先在本地词法检索这个库,命中才注入参考命中 ≤ 500 token(≤2 条、每条 ≤300 字符);未命中 0 token

原文只在用户明确要求时才由 history_read 工具读取(例如「把当时那段原文调出来」),日常不会自动展开。

数据落在哪里

记忆本体一律放在会话所属工作区内(Windows 上就是 <工作区>\.dsh-compaction-memory\), 不同项目天然隔离,不占用系统盘:

<workspace>/.dsh-compaction-memory/
  <sessionId>.jsonl        该会话的压缩记忆(一行一条块)
  _trash/<时间>_<会话>/    回收站(blocks.jsonl + manifest.json)
  _audit.jsonl             删除 / 还原 / 清空的审计

只有两个全局文件放在"全局数据目录"里,默认是 $DSH_HOME(默认 ~/.dsh)。 不想让它落在系统盘?设一个环境变量指到任意目录即可(例:setx DSH_SUPER_MEMORY_HOME "E:\DSH-data\dsh-super-memory",然后重启 DSH):

文件大小为什么是全局的
dsh-super-memory.settings.json<1 KB设置跨工作区生效,还存着面板登记的已知工作区列表
dsh-super-memory.diag.jsonl上限 4000 行(超了自动压缩)打分日志横跨所有会话,排障要看全局

装载回执等调试输出都写进上面这个诊断日志,不再另开文件。面板 ⑥ 里会显示当前解析到的 全局数据目录及其来源(环境变量 / 默认),一眼能看出有没有落在系统盘。 记忆目录可以在面板 ⑥「记忆目录」里直接改:填相对路径 = 每个工作区各自一份(默认), 填绝对路径 = 所有工作区集中存到一个目录(例如 D:\dsh-memory)。改完对新写入生效, 已有记忆不会自己搬家(想搬就手动剪切那个目录)。

(建议把 .dsh-compaction-memory 加进项目的 .gitignore,可选。)

隐私

  • 默认全本地、零外发:不联网、不调用任何模型、没有遥测或统计上报。代码里没有任何 HTTP 客户端 (lib/ 不引入 node:http(s)/net/dns/tls);唯一的"网络"行为是你在设置面板里点按钮时 访问本机 127.0.0.1 上的插件接口。 唯一例外:你在 ⑦ 里主动打开「模型辅助」之后,插件才会通过 DSH 的 ctx.llm 调用你自己配置的 模型服务(入库扩写、以及你点击「✕ 未命中诊断」时的查询改写)。关着它就是纯本地插件。
  • 存什么:对话文字(你的提问 + 助手的回答正文)+ 读类工具的结果原文 (read/grep/glob/web_fetch/history_read,即模型读过的文件内容与检索结果; 可用 includeToolResults 关闭,或用 toolResultNames 改白名单)。 不含深度思考(reasoning)、不含 shell 等其它工具的输出、不含系统注入内容。
  • 存哪里:<工作区>/.dsh-compaction-memory/(按工作区隔离)+ 两个全局小文件(设置、诊断日志, 路径见上一节)。除此之外不写任何地方,绝不触碰 DSH 的原始会话日志。
  • 原文什么时候会被读出来:只有你明确要求("把当时那段原文调出来")时,history_read 才会去读; 日常问答不会读取原文。
  • 误提交风险:记忆目录位于你的项目文件夹里。如果那个工作区本身是 git 仓库,设置面板 ④ 会检测到 并给出「帮我加忽略规则」按钮(把忽略规则写进该项目的 .gitignore)——插件自己仓库里的 .gitignore 管不到你的项目,这条要你点一下。
  • 彻底删除:删掉 <工作区>/.dsh-compaction-memory/ 即完全清除该项目的记忆;面板 ④/⑤ 也支持按会话 删除(默认 7 天保护期,可关)与清空回收站。

安全边界:本插件只操作自己 storeDir 内的文件(路径规范化 + 穿越校验),绝不触碰 DSH 原始会话日志 ~/.dsh/sessions/**——删除记忆不会动到会话本体。

可选:模型辅助(默认关闭)

成本口径(2026-10 起):本插件的目标从"尽量不花钱地延长记忆"演进为 "让你自己选档位,并在你选的档位内严格控制成本": ① 不打开模型辅助 = 纯本地、0 token、0 模型调用,与早期版本完全一致; ② 打开模型辅助 = 只在你指定的时机(压缩入库、你点击「✕ 未命中诊断」)调用模型,并受 每日调用上限 + 按路径自动退避 + 相同输入不重复调用 + 单次输出上限 + 辅助调用思考强度可控 五重约束。 成本始终是硬目标,只是不再是一条"死"的红线 —— 你愿意为命中率多付一点点,那"一点点"是多少由你定。

问了"换个说法"的问题时,纯词法检索可能一个字都对不上。⑦ 里可以打开可选的模型辅助,它只用在两个不在热路径的地方:

用途时机成本
① 入库扩写压缩发生时(你本来就在等),给每块生成 3–6 个"用户可能怎么问这块内容"的短词,写进检索关键词每批一次调用;同一块永不重复扩写
③ 查询改写你点了「✕ 未命中诊断」之后,把口语长句换成关键词再检索一遍一次点击一次调用(按提问哈希缓存)

铁律:提问时的本地检索永远是纯本地、零延迟、零 token。模型只在你打开开关后、且只在上面两个时机被调用;任何失败(提供方没注册、凭据缺失、限流、超时、输出不是合法 JSON)都静默降级,插件表现与"没这个功能"完全一致。

  • 不用配置任何提供方:provider / model 留空 = 跟随当前会话的主模型。想用自己的免费渠道或本地模型(Ollama / LM Studio 的 OpenAI 兼容地址),在 DSH 侧登记一次即可 —— 插件不自己连网、不自己存密钥。
  • 会话内「✕」按钮只在会话压缩过之后出现:没压缩过的会话记忆库是空的,按钮既不显示也不打扰;而只要你不点它,插件的行为就是"没有模型辅助"的版本。
  • 成本闸门:每日调用上限(默认 200 次,0 = 不限)、按路径自动退避(限流/额度问题暂停 10 分钟,凭据/提供方问题暂停 30 分钟)、相同提问不重复调用。

设置面板「超级记忆」

面板按插件实际做的三件事分板块,每块只放跟它有关的开关与参数,块标题旁直接标出这块花不花 token; 最上面是一张「30 秒读懂」卡(做什么、成本、边界),最下面是两个辅助板块。

板块做什么成本
① 压缩时:把被压掉的内容存到本地摘要入库(L1)+ 原文入库(L2,只留对话文字);显示本工作区最近一次入库0 token(只占磁盘)
② 压缩后:注入一份脉络总览压缩后注入目录级「本会话此前脉络」;可调总览上限、是否在窗口内保持稳定;带「预览它会注入什么」≤N token / 次压缩,可为 0
③ 提问时:检索历史,命中才参考提问时本地检索:命中阈值、单轮上限、条数、每条字符、参考块保持显示、指纹去重;带「试检索」自检未命中 0;命中 ≤N token / 轮
④ 被保存的压缩内容编号列表:会话标题(与 DSH 左栏一致) + 相对时间 + 已压缩几轮 + 存了 L1/L2 各几块 + 占用;每行有「浏览 / 明细 / 删除」,另有删除保护期只占磁盘
⑤ 回收站编号列表:标题 + 删除于多久前 + 条数;每行「还原」(还原后回到 ④);卡片底部是回收站设置(先进回收站 / 自动清空 / 保留天数)只占磁盘
⑥ 诊断与高级(默认折叠)命中/未命中计数、打分日志、回填开关、查询轮数、L1/L2 优先级、会话累计上限、路径与「恢复默认设置」—

会话标题从哪来:$DSH_HOME/storages/session_projcache/sessions/<会话id>.json 的 record.rows.title.val ——就是 DSH 侧栏显示的那一个(由 session-title-first-prompt-llm 生成);取不到时退回该会话的首条提问截断, 再取不到才用记忆块标题。同名会话会在标题后补 8 位短码(如 #1a2b3c4d)以便区分。

「浏览」怎么实现:宿主半边新增 POST /api/dsh-super-memory/reveal,在系统文件管理器里定位该会话的 记忆文件(Windows explorer /select,、macOS open -R、Linux xdg-open)。路径必须落在插件自己的 storeDir 内,越界工作区一律 403。

要点:

  • 顶部有一个总开关;关掉后 ①②③ 会整块变灰并标注「总开关已关:本块不生效」。
  • 每个被注入的历史块抬头都写着「历史只作参考,不作结论;若与当前结论不同,请说明此前是 X、这次因为 Y 改为 Z」—— 所以在后续对话里把方案 A 改成方案 B 时,回答以 B 为准并解释变化,该推理推理、该联网联网,不会被旧内容绑住。
  • 所有参数改完即时生效,不需要重启(面板 ↔ 宿主走 /api/dsh-super-memory/*)。

默认配置

键默认说明
enabledtrue总开关
injectRecap / injectRecalltrue / true两个注入开关,都关 = 零注入
ingestSummary / ingestRawTexttrue / true两层入库开关,都关 = 不写盘
compactionRecapMaxTokens300压缩后总览 token 上限(0 = 不注入)
maxTokensPerTurn500单轮注入上限(0 = 不注入)
maxItems2单轮最多条数(0–5)
maxCharsPerItem300每条最大字符
sessionBudgetRatio0.02会话累计注入上限(窗口比例;0 = 关闭全部自动注入)
recapPersisttrue总览在本次压缩窗口内保持稳定(省一次上下文快照,且整段窗口都看得到);关 = 压缩后只注入一轮
minScore0.28命中阈值(见下面的标定)
observationTurns3查询拼接最近几条用户消息
preferSummaryChunkstrue先 L1 摘要块,分数不够再 L2 原文块兜底
dedupetrue同块永不重复注入;连续两轮同话题不重复
cooldownTurns1同话题连续轮次的最小间隔
storeDir.dsh-compaction-memory相对工作区;也可填绝对路径集中存放
includeToolResultstrue是否收读类工具的结果原文(模型读过的文件内容/检索结果)。默认只收 read/grep/glob/web_fetch/history_read,单条 ≤4000 字符、每次压缩合计 ≤120000 字符;shell 等其它工具输出不收。深度思考永不入库,没有开关
toolResultNamesread, grep, glob, web_fetch, history_read读类工具白名单(逗号分隔;* = 全部工具结果,慎用)
toolResultMaxChars / toolResultBudgetChars4000 / 120000单条上限 / 每次压缩合计上限(字符)
includePrunefalse是否也记录 compaction/prune
maxRawCharsPerCompaction400000单次压缩 L2 入库字符上限(超出均匀抽样)
backfillOnStarttrue插件中途装上时,把本会话已有压缩补进库(0 token)
trashEnabledtrue删除先进回收站
protectRecentDays7删除保护期天数(0 = 不保护,需警告确认)
trashAutoPurgeEnabled / trashAutoPurgeDaystrue / 7回收站自动清空开关与天数(≥1)
logScorestrue写打分日志

minScore 的标定

用真实会话(3.8 MB / 5388 事件 / 2 次压缩 / 404K+308K token 被压掉)实测:

查询类型L1 摘要块 top 分L2 原文块 top 分
与已压缩内容相关的历史问题(12 条抽样)0.02 – 0.480.72 – 1.50
完全不相关的问题(3 条)0.00 – 0.070.07 – 0.14

两者分得很开,默认 0.28 落在中间偏保守的一侧。跑几天后可以看「诊断 → 打分日志」里 hit:false reason=below-threshold/... 的 topScore 分布,漏召多就往下调。

安装 / 卸载

支持 DSH 0.1.7-rc.2 与 0.2.0-rc.1 及以上(见 package.json 的 peerDependencies;已在 0.2.0-rc.2 客户端实测)。

方式一:插件市场——在 DSH 里打开插件市场搜 dsh-super-memory 直接装(若你的版本带市场)。

方式二:让 DSH 自己装(把 <本机插件目录> 换成你 clone / 解压出来的路径):

plugin_manager  action: install_bundle  target: <本机插件目录>

方式三:从 npm 装(已发布时):

plugin_manager  action: install_bundle  target: dsh-super-memory

装完重启 DSH 客户端:宿主插件代码在进程里缓存,不重启不会生效。重启后在 「设置 → 超级记忆」能看到分节、工具列表里出现 history_read 即为成功。

方式四:桌面端 CLI(路径按你自己的安装位置改;$DSH_HOME 默认是 ~/.dsh):

$exe = '<DSH 安装目录>\DeepSeek Harness.exe'
$cli = '<DSH 安装目录>\resources\app.asar\dsh\node_modules\@deepseek-ai\dsh-desktop-host\lib\cli.js'
$env:ELECTRON_RUN_AS_NODE = '1'
& $exe $cli plugin --profile desktop add '<本机插件目录>' 2>&1 | Out-String -Width 200
Remove-Item Env:ELECTRON_RUN_AS_NODE

Windows 上有个坑:必须把输出接给 cmdlet(2>&1 | Out-String),否则 PowerShell 不等这个 GUI 子系统的 exe,命令看着"秒退"。

卸载:& $exe $cli plugin --profile desktop remove 'dsh-super-memory'。 卸载不会自动删除工作区里的 .dsh-compaction-memory 与全局目录下的两个文件,需要手动清理 (数据位置见上一节)。

自检脚本

需要 Node ≥ 22.15(原始会话日志是多帧 zstd,用到 zstdDecompressSync;低版本跑自检脚本会直接报"不支持 zstd")。 DSH 自带的 node 在 <DSH 安装目录>/resources/runtime/primary-runtime/dependencies/node/bin/node.exe, 系统里装了新版 node 也可以直接 node。

npm test 会真的报错(退出码非 0),不是"打印给人看":它跑 ① 单元测试(纯函数,含历次真实 bug 的回归检查)与 ② 面板静态自检(设置键 / CSS 类名 / API 路径 / 功能板块 / 数字框精度)。 其余脚本用真实会话日志做端到端验证:

# 0) 单元测试 + 面板自检 + 面板渲染冒烟(不需要会话日志;
pm test 就是这三条)
node scripts/unit.mjs
node scripts/panel-check.mjs
node scripts/panel-render.mjs

# 1) 纯离线:用真实会话日志跑通「压缩入库 → 检索 → 总览 → 注入样例」+ minScore 标定表
node scripts/selftest.mjs <session.v4.jsonl.zstd>

# 2) 宿主半边联调:假 cordis ctx + 真实日志,跑通入库/总览/命中/未命中/开关/面板 API/history_read
#    含 ③b 回归(inbox 事件一到即召回、同一提问落库后文本逐字不变、未命中不回退)
#    与 ④b 安全断言(写操作来源校验:无来源标记/非 JSON → 403)
node scripts/harness.mjs <session.v4.jsonl.zstd> [临时工作区]

# 3) 验收证据导出:库条目统计、总览预览、试检索命中、最近打分日志
node scripts/inspect.mjs "<工作区>" "<一个旧话题>"

# 4) 时序排障:压缩事件、投影里还剩哪些用户消息、每份运行上下文快照的字符/token
node scripts/compactions.mjs <sessionId> [fromSeq toSeq | --snap | --raw <seq>]

# 5) L2 抽取完整度审核:日志里"应当收进来的文字"vs 插件实际入库字符数
node scripts/shadow-audit.mjs <sessionId> <fromSeq> <toSeq> [插件记账的rawChars]

会话日志位置:$DSH_HOME/sessions/**/session.v4.jsonl.zstd(多帧 zstd,脚本里按帧解码; Windows 上路径形如 C:\Users\<你>\.dsh\sessions\...)。

已知行为与限制

  • 成本机制:DSH 的运行时上下文按「快照有变化才追加一条消息」处理,所以注入块变了就会追加快照(内容 = 全部运行时上下文分节,通常几百字符)。本插件因此:总览在窗口内保持稳定(不churn)、命中块指纹去重、同一轮内结果稳定、未命中返回空串。这是 DSH 的既有机制,不是本插件引入的开销。
  • 压缩时 0 模型调用:入库只用 compaction/summary 里现成的摘要文本 + 本地字符 bigram 规则提词,不做任何模型提炼。
  • L2 兜底依赖 shadowedRange:取自当前会话的事件流(session.snapshotEvents()),不依赖读取压缩日志文件;取不到就不入库(不会退化成"把整个会话当原文")。
  • 会话累计额度不会自动重置:sessionBudgetRatio(默认窗口 2%)是整个会话的成本红线,只累加、不重置,用尽后"提问时注入"会停(压缩后总览不受此限)。面板 ⑥ 会显示「已用 X / 上限 Y」并在用尽时给出明确提示——想恢复就重启 DSH 或调大上限。
  • 记忆目录在用户项目里:如果工作区本身是 git 仓库,记忆文件(对话原文)有被提交的风险。面板 ④ 会检测到并给一个「帮我加忽略规则」按钮,把它写进该项目的 .gitignore。
  • 总览是"目录"不是"全文":同一个标题只保留一条(标题在同一会话里会反复出现),新一轮的内容优先;被挤掉的早期内容仍可通过提问时的检索找回。
  • 失败静默:检索不到、插件内部出错都不影响正常回答(全部路径都包了 try/catch,只写诊断日志)。
  • 检索只用纯本地词法(BM25 + 中文字符 bigram),不引入任何模型依赖;查询改写 / 本地向量检索属于未实现的路线图,没有对应的配置项,免得留下"改了没用"的空旋钮。

权限与边界声明(给市场审查与用户)

本节逐条列出本插件实际用到的主机能力与数据边界,全部可在仓库源码中核对。没有列在这里的能力,插件不会使用。

依赖

  • 没有任何第三方 npm 运行时依赖:package.json 里只有 peerDependencies,没有 dependencies / devDependencies / optionalDependencies。
  • peerDependencies 声明的 @deepseek-ai/* 全部是 DSH 宿主自身提供的包,由宿主在运行时注入,插件不自行安装、不打包它们。
  • 插件通过 ctx.inject 拿到的服务:必需 tools、systemPrompt、webServer;可选 llm(见 lib/host.js 的 export const inject = ['tools', 'systemPrompt', 'webServer'] 与单独的 ctx.inject(['llm'], …) 作用域)。拿不到可选服务时对应功能自动降级,插件照常工作。

读什么

  • 只读会话日志 $DSH_HOME/sessions/**(默认 ~/.dsh/sessions/**,多帧 zstd 逐帧解码):绝不写入、绝不修改、绝不删除该目录下的任何文件。
  • 只读会话标题投影缓存 $DSH_HOME/storages/session_projcache/sessions/<会话id>.json(用于面板显示会话标题)。
  • 状态查询对会话日志只做 stat 取大小,不读内容。

写什么

  • 记忆本体只写会话所属工作区内的记忆目录:默认 <工作区>\.dsh-compaction-memory\(会话记录 <sessionId>.jsonl、回收站 _trash/、审计 _audit.jsonl)。storeDir 可配置,但含 .. 的配置会被拒绝并回落默认值。
  • 全局数据目录只放两个跨工作区文件:设置 dsh-super-memory.settings.json 与诊断日志 dsh-super-memory.diag.jsonl。该目录默认是 $DSH_HOME(默认 ~/.dsh),可用环境变量 DSH_SUPER_MEMORY_HOME 指向任意目录。
  • 删除操作只作用于记忆目录内部:所有删除路径先经 assertInside() 校验——目标必须严格位于记忆目录之内(等于根目录也拒绝,..、绝对路径、符号链接逃逸一律拒绝)。
  • 删除走回收站语义(trashEnabled 默认 true):条目移入 _trash/ 可还原,并写审计日志。注意:把 trashEnabled 显式设为 false 时删除是直接删记录、不进回收站;面板「清空回收站」是永久删除回收站条目,两者都写审计。这是回收站之外仅有的两条永久删除路径。

网络

  • 不访问互联网。代码中没有任何对公网地址的请求(无硬编码外部域名/URL)。
  • 面板(浏览器半边)里的 fetch 全部指向本机 DSH 的插件 API 路径 /api/dsh-super-memory/*,即同源、同进程的本机 HTTP 服务,不产生对外流量。

命令执行

  • 全仓库只有一处 spawn(lib/routes.js 的 revealInFileManager()),唯一用途是"在系统文件管理器里定位 / 显示文件",服务于面板的「浏览」按钮:Windows 用 explorer.exe(/select,),macOS 用 open -R,其它的用 xdg-open。
  • 该 spawn 不经过 shell,不接受任何来自请求的字符串作为可执行文件名或参数;路径由服务端自己用记忆目录根 + 会话 id 拼出,越界或未知工作区直接返回 403(另有 404「文件不存在」、500「无法自动打开文件夹」)。目标路径必须落在记忆目录内。

凭据

  • 不读取、不存储、不转发任何密钥或凭据。仓库内没有 .env 读取、没有 keyring / 凭据存储访问,也没有对任何密钥字段的读写。
  • 模型调用一律经由 DSH 的 llm 服务,插件侧只填 provider + model 两个字符串名字;真正的鉴权与密钥由 DSH 掌握,插件拿不到也不需要。

外部服务与失败边界

  • 模型辅助默认关闭(llmAssistEnabled 默认 false):关闭时插件纯本地运行、0 模型调用、0 网络请求,核心功能(压缩入库、检索、注入)完全可用。
  • 开启后,每次模型调用都有超时(入库默认 8000ms、检索默认 4000ms)、失败冷却(限流/额度/鉴权类错误会暂停一段时间)、每日调用上限(默认 200 次)、相同输入缓存(默认开启)。超时用 AbortSignal.timeout 主动放弃。
  • 任何失败都只写诊断日志,不抛出到宿主、不阻塞宿主对话:检索未命中、模型不可用、格式不合要求等全部在内部消化,最坏情况就是不注入参考,回答照常进行。
  • 未观察到本插件使用除 tools / systemPrompt / webServer / llm 之外的宿主服务,也未观察到文件系统之外的系统资源访问(除上述唯一一处 spawn)。

关于 locale/*.json 与"是否需要构建"

  • locale/zh.json、locale/en.json 是手写源文件,不是构建产物;它们是面板文案,随包分发并被 exports 的 ./locale/*.json 导出。市场检查把它们当成"运行时产物模式"属于识别偏差。
  • 本仓库没有构建步骤:不存在 build / prepare / prepublish 之类会产出运行产物的脚本。npm test 只是自检(单元测试 + 面板静态检查 + 面板渲染冒烟),不产出任何运行产物,也不被运行时依赖。分发的 lib/ 与 locale/ 就是仓库里提交的那份源码,逐字节一致。

本节写法说明:以上只写能从本仓库代码与 package.json 核实的事实。"未观察到"表示在源码中检索不到相应用法;若将来新增了本节未列出的能力,请同步更新本节。