dsh-super-memory
No description
- Stars
- 1
- Language
- JavaScript
- Created
- Oct 2, 2026
- Updated
- Oct 7, 2026
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/*)。
默认配置
| 键 | 默认 | 说明 |
|---|---|---|
enabled | true | 总开关 |
injectRecap / injectRecall | true / true | 两个注入开关,都关 = 零注入 |
ingestSummary / ingestRawText | true / true | 两层入库开关,都关 = 不写盘 |
compactionRecapMaxTokens | 300 | 压缩后总览 token 上限(0 = 不注入) |
maxTokensPerTurn | 500 | 单轮注入上限(0 = 不注入) |
maxItems | 2 | 单轮最多条数(0–5) |
maxCharsPerItem | 300 | 每条最大字符 |
sessionBudgetRatio | 0.02 | 会话累计注入上限(窗口比例;0 = 关闭全部自动注入) |
recapPersist | true | 总览在本次压缩窗口内保持稳定(省一次上下文快照,且整段窗口都看得到);关 = 压缩后只注入一轮 |
minScore | 0.28 | 命中阈值(见下面的标定) |
observationTurns | 3 | 查询拼接最近几条用户消息 |
preferSummaryChunks | true | 先 L1 摘要块,分数不够再 L2 原文块兜底 |
dedupe | true | 同块永不重复注入;连续两轮同话题不重复 |
cooldownTurns | 1 | 同话题连续轮次的最小间隔 |
storeDir | .dsh-compaction-memory | 相对工作区;也可填绝对路径集中存放 |
includeToolResults | true | 是否收读类工具的结果原文(模型读过的文件内容/检索结果)。默认只收 read/grep/glob/web_fetch/history_read,单条 ≤4000 字符、每次压缩合计 ≤120000 字符;shell 等其它工具输出不收。深度思考永不入库,没有开关 |
toolResultNames | read, grep, glob, web_fetch, history_read | 读类工具白名单(逗号分隔;* = 全部工具结果,慎用) |
toolResultMaxChars / toolResultBudgetChars | 4000 / 120000 | 单条上限 / 每次压缩合计上限(字符) |
includePrune | false | 是否也记录 compaction/prune |
maxRawCharsPerCompaction | 400000 | 单次压缩 L2 入库字符上限(超出均匀抽样) |
backfillOnStart | true | 插件中途装上时,把本会话已有压缩补进库(0 token) |
trashEnabled | true | 删除先进回收站 |
protectRecentDays | 7 | 删除保护期天数(0 = 不保护,需警告确认) |
trashAutoPurgeEnabled / trashAutoPurgeDays | true / 7 | 回收站自动清空开关与天数(≥1) |
logScores | true | 写打分日志 |
minScore 的标定
用真实会话(3.8 MB / 5388 事件 / 2 次压缩 / 404K+308K token 被压掉)实测:
| 查询类型 | L1 摘要块 top 分 | L2 原文块 top 分 |
|---|---|---|
| 与已压缩内容相关的历史问题(12 条抽样) | 0.02 – 0.48 | 0.72 – 1.50 |
| 完全不相关的问题(3 条) | 0.00 – 0.07 | 0.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核实的事实。"未观察到"表示在源码中检索不到相应用法;若将来新增了本节未列出的能力,请同步更新本节。