Saltar al contenido principal
K

dsh-biomemory

klrsl/dsh-biomemory

Sistema de memoria biomimético para DeepSeek Harness: un único almacén SQLite (node:sqlite, WAL) cuyo árbol Markdown se mantiene como espejo de solo lectura; herramientas de memoria, inyección de instantánea congelada al inicio de la sesión, puertas de aprobación escalonada, extracción bajo demanda de la sesión actual, fusión de casi duplicados, un ciclo de vida de archivo y reemplazo, metabolismo de memoria (dream), anclajes de memoria, recuperación semántica sobre incrustaciones locales, y el comando /memory.

Instalar

dsh plugin --profile web add github:klrsl/dsh-biomemory

README

dsh-biomemory

生物仿生记忆系统:跨会话记忆插件,像人脑一样分层记、分级审、会代谢、透明可改。

简体中文 · English

v0.9.2 · MIT License · DSH ≥ 0.1.1-rc.2(已在 0.1.5-rc.1 / 0.1.5-rc.2 / 0.2.0-rc.2(桌面版) 实测)· Node ≥ 22.19.0

⚠️ Node 版本提示:本插件用 node:sqlite。已在 Node 24.19 实测通过;Node 22.x 上该模块可能仍需 --experimental-sqlite(本机无 22.x,未能实测)。若启动报 node:sqlite 不可用,请升级到 24.x 或加上该 flag。

给 DeepSeek Harness(DSH)的跨会话记忆插件:像人脑一样分层记、分级审、会代谢、透明可改。数据层为 SQLite(node:sqlite 内置、WAL 模式、零外部依赖),旧 Markdown 记忆首次启动自动迁移并保留只读备份。

功能特性

能力说明
分层记忆Memory / Retrieved / Applied 三层分离——存储层、查询候选、已注入快照;检索到 ≠ 已采用,执行与否由 AI 结合上下文判断
分级审批重要记忆(用户偏好/项目决策/踩坑教训)人工审批,普通事实自动写入;审批通道不可用时按 approvalFallback 降级(auto/deny)
自动沉淀会话结束自动注入「沉淀本轮」指令;启动自动注入冻结记忆快照(锁定与偏好最高优先级,冲突行为记忆置顶 [冲突] 标注)
记忆代谢半衰期衰减 + 引用巩固(用进废退)+ 冲突豁免 + 低权重归档;执行前自动备份、支持断点续跑与 dry-run 预览
深度反思主题聚类 / 趋势统计 / 冲突提醒 / 遗忘建议,纯本地无 LLM,报告写入 longterm/reflections/
记忆类别memory_class 自动推断:user_decision / user_preference / fact / model_suggestion / model_inference(建议 ≠ 决定)
来源可溯source_ref 记录来源,add 缺省记 session:<id>;结构化审计五元组(时间/操作者/事件/条目/详情)全程可查
确定性检索单一检索路径:命中字段权重(text 1.0 / summary 0.5 / entities 0.25)+ 命中次数有界加成 + weight 有界加成(≤50%)。v0.9.0 起移除嵌入模型与 semantic/hybrid 模式
透明可改每条记忆可编辑/删除/回滚(删除前自动备份);SQLite 单文件即所有数据,.db 直接用标准工具查看
零原生依赖node:sqlite 内置 + 纯 JS 实现,无原生模块冲突;纯 host 插件(无 UI 半边),只用 memory 工具与 /memory 命令

安装

从 GitHub 安装(推荐)

# 需要已安装 git;--profile web 换成你的 profile 名
dsh plugin --profile web add github:KLRSL/dsh-biomemory
# 在项目目录下执行
dsh plugin --profile web add link:./dsh-biomemory

dsh plugin 会自动把安装的包登记到 profile 的 dsh.profile.bundles 并挂载补丁;安装完成后重启 DSH。

安装后验证:

# 1. 工具已注册 —— 在会话中直接调用(对话内模型可见)
memory action=query text="测试"

# 2. 数据层就绪 —— 首次启动后应出现
ls ~/.dsh/biomemory/
# biomemory.db  biomemory.db-wal  biomemory.db-shm

# 3. 旧 Markdown 记忆自动迁移(保留只读备份,不删除)
#    迁移状态可通过 Web API 查看:
#    GET /biomemory/api/status → migration 字段

# 4. 使用 —— 无需任何 UI:直接用 memory 工具或 /memory 命令
#    memory action=query text="关键词"        # 查(自动召回也在后台生效)
#    memory action=add track=agent text="…"   # 写(重要记忆会弹审批)

快速开始

# ① 保存一条用户偏好(重要记忆 → 触发人工审批;审批通过后入库)
memory action=add track=user text="用户偏好:网络下载一律用国内镜像源" source="用户原话"

# ② 查询(确定性相关度排序)
memory action=query text="镜像源" topK=5

# ③ 修复一条记忆(内容说错了,直接改文本,元数据不动)
memory action=update fp="a1b2c3" text="用户偏好:网络下载一律用国内镜像源(pip 清华 / npm npmmirror)"

# ④ 锁定重要条目(不参与衰减,永远进会话快照)
memory action=pin fp="a1b2c3"

# ⑤ 代谢 + 反思(建议跑一次看看效果;--dry-run 可以只预览)
memory action=dream dryRun=true
memory action=reflect dryRun=true

# ⑥ 审计(看看这段时间记忆系统发生了什么)
memory action=audit sinceDays=7
memory action=audit aggregate=true groupBy=action

# ⑦ 运行时也可以在对话里用 /memory 命令
/memory list
/memory query 偏好

使用指南

memory 工具(action 清单)

action参数说明
addtext(必填), track=user|agent, source保存记忆;重要条目自动请求审批,审批不可用时按 approvalFallback 降级
querytext, topK, minWeight, projectId, fragmentTypes, includeArchived(mode 自 v0.9.0 起废弃并忽略)查询;命中自动巩固(用进废退)
updatefp, text编辑一条记忆(保留锁定/权重等元数据;文本变了向量置空重算;审计 UPDATE)
removefp删除一条(删除前自动备份数据库,可回滚)
restorefp从最近备份回滚被删除的一条
listtopK列出全部条目;与偏好冲突的行为记忆置顶并标注
pin / unpinfp锁定/解锁。锁定 = 不遗忘(防衰减/归档),不代表每轮必须执行
dreamdryRun, resume(默认 true)记忆代谢:衰减/巩固/冲突/归档;支持断点续跑
reflectdryRun深度反思:主题聚类/趋势统计/冲突提醒/遗忘建议
audittype, sinceDays, aggregate, groupBy(action|day|entry)结构化审计查询/聚合统计

示例:

memory action=add track=user text="正式名「大肥鱼」,不用旧名" source="用户原话"
memory action=query text="UI 渲染宽度规则" topK=10 minWeight=0.1 fragmentTypes=decision,preference
memory action=audit type="DECAY" sinceDays=7
memory action=audit aggregate=true groupBy=day

记忆类别(自动推断,写入时记录):user_decision(用户明确决定)· user_preference(用户偏好)· fact(普通事实)· model_suggestion(模型建议)· model_inference(模型推测)。建议 ≠ 决定,模型建议永不冒充用户拍板。

memory_recall 工具

跨会话召回(「你还记得…吗」场景),与 memory query 同底,语义上专用于回忆:

memory_recall text="去年定下的版本规则"

/memory 命令族

命令说明
/memory list列出全部条目(冲突条目置顶)
/memory query <词>关键词检索
/memory add <内容>直接写入(人类发起,免审批)
/memory edit <fp> <新内容>编辑一条
/memory remove <fp>删除一条(可回滚)
/memory undo <fp>回滚被删除的一条
/memory pin <fp> / unpin <fp>锁定 / 解锁
/memory entries [词]列出条目(可带过滤词)
/memory dream [--dry-run]记忆代谢
/memory reflect [--dry-run]深度反思
/memory audit [--since 7d] [--type DECAY]审计查询

冻结快照注入

会话启动时,插件自动把高价值记忆冻结注入 system prompt(注册即冻结,快照标记「会话冻结」):

  • 头部明确三层概念:本快照 = Applied Context(已注入 prompt);Memory(存储层)与 Retrieved(查询候选)不在此列;检索到 ≠ 已采用。
  • 注入顺序:锁定记忆(最高优先级,不参与衰减)→ 用户偏好(最高优先级,写入须尊重)→ 近期知识 → 近期行为。
  • 与偏好冲突的行为记忆置顶并标注 [冲突],由你裁决修改。
  • 热区 token 预算 hotTokenLimit(默认 5000),超出时保留偏好与锁定段。

分级审批门

记忆类型审批方式
用户偏好 / 项目决策 / 踩坑教训(track=user 或命中重要词)人工审批(ask)
普通事实自动写入(auto)
审批通道不可用(策略 never / 服务缺失)按 approvalFallback:auto = 自动保存并审计降级标记 · deny = 拒绝写入(fail-closed)

记忆代谢(Dream)

相当于睡眠时大脑做的事——/memory dream 或 memory action=dream:

  1. 半衰期衰减(默认 7 天):w × 0.5^(年龄/半衰期),下限 1。
  2. 引用巩固:单条命中引用 ≥ consolidateThreshold(默认 3)次则 +1 权重,上限 weightCap(默认 20)。
  3. 冲突豁免:与偏好冲突的行为记忆不衰减不归档、保持活跃,在列表与快照中置顶浮出,由你人工裁决(编辑改掉冲突内容后恢复正常代谢),记 CONFLICT 事件。
  4. 低权重归档:权重低于 decayThreshold(默认 3)→ status=archived,移动不删除。

执行前自动备份数据库(保留最近 7 次,ROLLBACK 事件可溯);每 100 条写检查点,中断后 resume=true 断点续跑;--dry-run 只预览不落盘。

深度反思(Reflect)

纯本地、无 LLM 的周期总结:主题聚类(TF 向量余弦相似度 ≥ 0.25)· 趋势统计(近 7 天 vs 上一周写入量)· 冲突提醒(行为与偏好潜在冲突清单)· 遗忘建议(低权重候选)。报告写入 longterm/reflections/<时间戳>.md,支持 --dry-run 预览。

知识库(通过命令与工具)

v0.9.1 起管理 UI 已移除(用户决策):不再有设置页 tab。检索与维护全部走 memory 工具 / /memory 命令。

能力入口
关键词检索(相关度 + 权重限幅)memory action=query text="…" [fragmentTypes=…] [minWeight=…]
逐条查看 / 按层过滤/memory list
就地编辑 / 删除(先备份可回滚)/ 钉选memory action=update|remove|pin|unpin
记忆代谢(衰减/巩固/归档,含 dry-run)memory action=dream [dryRun=true]
深度反思(聚类/冲突/遗忘建议)memory action=reflect [dryRun=true]
结构化审计memory action=audit

审计

双通道:SQLite audit_log 表(结构化,五元组 t / actor / action / entry_id / detail,主通道)+ audit.log(人类可读一行摘要,向后兼容)。

事件类型:WRITE / DECAY / CONSOLIDATE / CONFLICT / ARCHIVE / RECALL / ROLLBACK / AUTO-DREAM / AUTO-REFLECT(其余辅助事件:PIN / UNPIN / UPDATE / REMOVE / RESTORE / MIGRATE / VECTORIZE / PREVIEW / REFLECT / CONFIG)。

/memory audit                      # 最近事件
/memory audit --since 7d           # 最近 7 天
/memory audit --type DECAY         # 只看 DECAY
memory action=audit type="DECAY" sinceDays=7
memory action=audit aggregate=true groupBy=action   # 聚合统计

检索

单模式确定性检索(v0.9.0 起):按相关度排序,score = relevance · (1 + 0.5 · min(weight, weightCap) / weightCap), 其中 relevance = Σ 命中字段权重(text 1.0 / summary 0.5 / entities 0.25)+ 0.1 · min(命中次数, 5)。 同分时依次按 weight 降序 → created_at 降序 → entry_id 升序,全序且确定性(同输入必得同输出)。

无关键词的查询(list 浏览)按 weight 降序,并把与偏好冲突的行为记忆置顶。

v0.9.0 变更:移除了本地嵌入模型(bge-small-zh-v1.5)与 semantic/hybrid 两种模式—— 它们需要额外下载约 90MB ONNX 权重并拖入 @huggingface/transformers + onnxruntime 依赖。 关键词检索完全离线、零依赖、可复现,已足够。tokenize 与词频余弦仍保留,服务于 dream 的主题聚类。

配置

key默认值说明
halfLifeDays7半衰期(天):权重每过半衰期衰减一半
decayThreshold3权重低于此值 → 归档(移动,不删除)
consolidateThreshold3引用 ≥ 此次数 → 巩固(+1 权重)
weightCap20巩固权重上限(防膨胀)
hotTokenLimit5000快照注入热区 token 上限
maxQueryResults20查询返回上限
approvalFallbackdeny审批不可用时:auto=自动保存并审计降级 / deny=拒绝写入
autoDreamDays7启动时距上次代谢(meta lastDreamAt)≥ 此天数自动执行(0=关闭)
autoReflectDays3启动时距上次反思(meta lastReflectAt)≥ 此天数自动执行(0=关闭)
nearDuplicateThreshold0.7写入去重(v0.8.0):与已有同类条目的中文 bigram 相似度(长度相近时取 Jaccard 与包含度的较大者)≥ 此值时按 nearDuplicateAction 处理(0=关闭。实测「换了说法的同一件事」约 0.7~0.8)
nearDuplicateActionmerge命中近重复时:merge=合并进已有条目(追加 | 【补充·日期】… 并提权 +1,借鉴 @zheexinn/dsh-memory 的 merge-on-write)/skip=只提示不写(返回相似条目 fp 供 update)
sinkWindowMinutes5轮次结束后「请沉淀值得长期记住的内容」提醒的有效窗口(分钟,可配)。窗口内注入一次催促;超时丢弃(下一轮重新判断),避免隔很久再发消息时被一条过期的「上一轮请沉淀」打扰
conflictOverlap3冲突检测:行为与单条偏好的专有双字重叠阈值

可通过 POST /biomemory/api/config 调整(纯 host,无 UI);持久化为 biomemory.config.json(透明可改)。

集成

Web API(DshWebServer 注册,prefix /biomemory/api)

方法 / 路径说明
GET /status存储统计 + 配置 + 模型/迁移状态
GET /config · POST /config读取 / 更新配置(白名单字段,reset:true 恢复默认)
POST /dream记忆代谢(body { "dryRun": true })
POST /reflect深度反思(body { "dryRun": true })
GET /entries条目列表(q 搜索词 / layer 分层 / mode 检索模式 / limit 上限)
POST /entries/pin · /unpin · /remove · /restore · /update条目管理(body 含 fp 等)
GET /audit审计查询(sinceDays / type)

环境变量

变量默认值说明
DSH_BIOMEMORY_DIR~/.dsh/biomemorySQLite 数据目录
DSH_MEMORY_ROOT~/.dsh/memory旧 Markdown 根目录(迁移源与只读备份)
DSH_MEMORY_DEBUG否1 时向 stderr 输出 [dsh-biomemory] 前缀的调试日志(镜像同步 / 迁移 / 自愈等)

兼容性

  • Node ≥ 22.19.0(node:sqlite 内置要求)。
  • 运行时:@deepseek-ai/dsh-* ≥ 0.1.1-rc.2(当前 latest 线;0.1.2-rc.1 与 0.1.5-rc.1 均已实测,按实际 lib 源码核对实现)。
  • peerDependencies:@deepseek-ai/cordis ^4.0.2、@deepseek-ai/dsh-session >= 0.1.1-rc.2、@deepseek-ai/dsh-tools >= 0.1.1-rc.2。
  • 预发布版本号不受 semver 范围约束:按 semver 预发布规则,范围 >=0.1.1-rc.2 的 node-semver satisfies 判定为 false(不接受 0.1.5-rc.1 这类预发布版本)。这两个包由宿主运行时必定提供,故范围仅作参考、已写入 peerDependenciesMeta 标注 optional: true(不因范围判定而阻断加载)。已实测 0.1.5-rc.1 正常加载运行。
  • 零原生 npm 依赖:数据层为 node:sqlite 内置 + 纯 JS,不会与其他插件的原生模块冲突;语义检索模型为可选离线组件,缺失自动降级。
  • v0.6.3 起 memory 工具返回值兼容 dsh-tools 新版 lossless JSON 校验(undefined/NaN 字段统一置 null,避免工具校验报错)。

版本历史

版本日期要点
v0.9.22026-09-29删死模块 extract(去臃肿):extract.mjs(按需抽取)自 v0.9.1 删除 POST /api/extract 端点后已零生产调用方,仅剩自己的单测引用,却仍被打进发布包——现整模块删除(含 tests/extract.test.mjs、files 白名单项、4 个读取数为 0 的 CFG.extract* 死配置键与 POST /config 的 extract 特判分支);package-lock.json 清理掉已无来源的 jsdom/react/react-dom 及其 68 个传递依赖(72 → 4 个包)。测试 88 → 81。
v0.9.12026-09-29移除管理 UI(用户决策):删除 lib/client.js 与 DSH 设置页「记忆工作台」(含页面测试与 no-harness-client-imports 守卫),插件退化为纯 host 能力——只用 memory 工具与 /memory 命令;dsh.client 声明、./client 导出、files 里的 lib 与 jsdom/react devDependencies 一并移除。同时清掉随页面下线的死文案键,以及 /extract、/archived、/entries/{unarchive,supersede,reactivate}、/superseded、/audit/aggregate 端点(HTTP 端点 19→12)。测试 88/88。
v0.9.02026-09-29移除嵌入模型与语义检索(用户决策):query 收敛为单一确定性相关度检索(score = relevance · (1 + 0.5·min(weight,weightCap)/weightCap),relevance = 命中字段权重 + 命中次数有界加成);删除 embed.mjs、@huggingface/transformers 依赖与 preloadEmbeddings 配置(node_modules 410.5MB → 20.1MB,不再需要 ~90MB 本地 ONNX 模型与 onnxruntime);db 的向量 API(setVector/setVectorsBatch/entriesWithVectors/vectorCount)与 /vectors 端点删除,entries.vector 列保留以兼容既有数据库;设置页移除模式分段按钮与模型状态卡;tokenize/词频余弦保留(dream 主题聚类仍用)。适配 DSH 0.2.0-rc.2:客户端半边不再 require 任何 Harness Client 包(官方 practices.md §UI 第 1 条)——Button/Input/9 个图标已本地化内联(0.2.0 起官方只导出 ...Regular/...Medium,裸名与 ...16 后缀名全部消失,直接解构会得到 undefined 组件并在渲染时清空槽位);dsh.client.inject 删除 0.2.0 中不存在的 @deepseek-ai/dsh-client-runtime;新增 tests/no-harness-client-imports.test.mjs 守卫。95 测试全绿
v0.8.22026-09-20配置项按类型落库(真机踩坑):设置页写入接口 POST /config 此前除 petEndpoint/approvalFallback 外一律走 Number(),于是字符串型的 extractProvider/extractModel 被存成 0(随后 String(0)="0" 被当作提供方名 → NO_ADAPTER,设置页也因 `0
v0.8.12026-09-20冲突裁决闭环 + 按需抽取 + UI 说真话:①superseded 从「永不写入的死值」变成真实语义——人工作废(被更新的结论取代),与 archived 分工是原因不同、效果相同(都退出注入与检索),allEntries/entriesWithVectors 只取 active;新增 setEntryStatus 统一「归档/作废/恢复」,审计 SUPERSEDE/ARCHIVE-MANUAL/REACTIVATE;新增 GET /superseded 与 UI 的「作废」「恢复」按钮(此前冲突只有红徽章、没有解决手段)。②按需抽取按钮:POST /api/extract 取 ctx.sessions.get(id).deriveMessages(),模型走 ctx.llm.stream(复用 DSH 现有提供方),候选经同一套指纹去重/近重复合并入库;「预览」零 token。③UI 说真话:模型卡改三态(待载入/512维/降级),审计卡注脚不再错配。④合规:客户端 bundle 迁入 lib/client.js、bundle 条目 id 统一为包名。98 测试全绿
v0.8.02026-09-20自动代谢修复(真缺陷,已造成数据损失):①自动 dream 的间隔判据用 store.latestBackup(),而它读的是单轨制前 Markdown 备份目录(MEMORY_ROOT/backups 下的 12 位数字目录),v0.6.4 之后永不产生 → 恒 null → 每次插件加载都全量跑一遍 dream(实测累计 109 次,单日最高 26 次);②runDream 的衰减写作 w × 0.5^(年龄/半衰期),拿「已经被衰减过的当前权重」再乘全龄因子 = 复合衰减,重复执行指数加速 → 19 条行为记忆(含多条合并后的综合条目)被压到 decayThreshold 以下误归档。修法:判据改读 meta 表 lastDreamAt / lastReflectAt(dream/reflect 结束时写入,不再依赖任何文件 mtime);衰减改为增量幂等——基准 = max(创建时间, 上次代谢时间),且只在入库精度(1 位小数)真的下降时才记一次 DECAY。新增 store.unarchiveEntry(fp, {weight})(归档行 → active + 权重校准,审计 UNARCHIVE)与维护脚本 bm-restore-archived.cjs(默认 dry-run),19 条误归档已全部恢复(权重校准为 10)。同批修复:setPinFp 钉住时把 weight 清零(一解锁就低于阈值被归档)→ 不动权重,「不衰减」由 runDream 跳过 pinned 保证;removeByFp 连带 DELETE audit_log(删条目即抹审计轨迹)→ 不再删;/status 的 auditCount 走 queryAudit({}) 默认 limit=50 → 恒 ≤50,改 limit: 100000;retrieve 把所有返回条目都计 hits(与注释「真实关键词召回才巩固」不符)→ 只计关键词命中;嵌入模型加载失败无负缓存、且 apply 后 100ms 强制 ensureVectors(等于每次启动都加载 24MB onnx 模型)→ 加负缓存 + 改真懒加载(preloadEmbeddings 默认 false,置 true 或 DSH_BIOMEMORY_PRELOAD=1 可预热);PRAGMA busy_timeout=5000(多实例同库);Markdown 迁移不再把同步镜像 条目镜像.md 与 reflections/ 误解析成条目。死代码清理:rewriteFile / findByText / backupNow / latestBackup(后者正是本次缺陷的引信)/ embedMany / isModelReady / embedTextOf / db.getById / db.listPinned / session-state.getSummarySid。新增回归测试 tests/dream-idempotent.test.mjs(幂等衰减 / 新条目基准 / 取消归档 / 快照不注入归档 / 触发判据 / 巩固与召回时间挂钩 / restore 保留 entry_id)。追加整理:自动代谢判据抽成纯函数 meta.shouldRunAuto()(可直接单测);巩固改为只认最近仍被真实召回的条目(要求 last_accessed 落在半个半衰期内,consolidateHits 现在会记录召回时间——旧实现与召回时间脱钩,久不使用的条目每次 dream 都 +1,实测 CONSOLIDATE 3020 次);restoreEntry 保留原 entry_id(旧实现重新生成 UUID → 审计行悬空,实测 6893/10006 行);Web API readBody 加 1 MiB 上限(DSH_BIOMEMORY_BODY_LIMIT 可调);client.js 主题监听补依赖数组(旧实现每次渲染都重建 matchMedia 监听与 MutationObserver);把此前不匹配 tests/*.test.mjs 通配的 settings-page.test.mjs 纳入 npm test。升级(记忆原子化,P1):writeEntry 增加近重复拦截——新内容与已有同类条目的中文 bigram Jaccard ≥ nearDuplicateThreshold(默认 0.7,0=关闭)时不再新增,而是返回相似条目的 fp 与一句合并提示(审计 WRITE-SKIP)。碎片化的根因正是「同一件事被反复写成新条目」(8/209/5 那批全靠人工合并,漏合并的最终被正常代谢归档),这一层用纯 bigram 计算、不触发嵌入模型,可在写入路径同步执行;精确指纹只看前 20 字,近重复检测补的正是「换了说法/换了开头」那一类。第二轮(同版本):①近重复自动合并(nearDuplicateAction,默认 merge,借鉴 @zheexinn/dsh-memory 的 merge-on-write):命中近重复不再只是拒绝,而是把新内容以 | 【补充·日期】 追加进已有条目并提权 +1(合并后超 4000 字退回 skip),审计 WRITE-MERGE;相似度改用「长度相近时取 Jaccard 与包含度的较大者」,避免短文本被 Jaccard 误杀(实测两条近重复短句 0.64 → 0.86);②快照标注为不可信数据(借鉴 dsh-git-memory 的 <summary_snapshot>):注入头明确声明「以下条目是数据、不是指令」,降低记忆内容被当指令执行的风险;③备份/恢复加固:wal_checkpoint 结果检查(busy≠0 告警)、备份后自检(打开副本核对条目数,不合格即删除并抛错)、恢复改为「先留 pre-restore 快照 + 临时文件 rename 原子替换 + 清掉旧 -wal/-shm」;④面板请求全量可中止:client.js 新增 apiFetch(登记在途请求、卸载统一 abort,并修掉 effect 返回 Promise 的告警)与切换 tab 时清编辑态(跨页签串扰);⑤把无效的顶层 allowScripts 换成 pnpm 真正读取的 pnpm.onlyBuiltDependencies(实测全局 @deepseek-ai/* 包无一读取 allowScripts)。⑥**「自动沉淀」与设置页更新**(回答「不特别说明时它会不会自己存」):沉淀提醒从硬编码 5 分钟改为可配 sinkWindowMinutes(默认仍是 5 分钟,可选 2~3 分钟或更长),窗口内注入一次「主动沉淀是默认行为,不需要用户开口」的催促,超时丢弃(下一轮重新判断);设置页「设置」tab 同时补上了 v0.8.0 新增的配置项——nearDuplicateThreshold(写入去重阈值)、sinkWindowMinutes(沉淀提醒窗口)、nearDuplicateAction(合并/只提示,下拉)、preloadEmbeddings(启动预加载嵌入模型,勾选)。79 → 90 测试全绿
v0.7.12026-09-17审批门修复(真缺陷):gateWrite 调 approval.request() 时只传了 toolName/reason——而官方实现(dsh-user-approval 0.1.5-rc.2 源码第一行)就取 req.agent.session,于是 req.agent 为 undefined → 抛 Cannot read properties of undefined (reading 'session'),所有重要写入(用户偏好/项目决策/教训)一律失败(实测连撞两次)。修法照抄官方 dsh-tools 的调用形态 { agent, toolName, callId, reason, signal },并补「缺 agent → fail-closed 兜底 + 审计 no-agent」而不是崩(官方对无 agent 同样是返回 deny,不是抛)。新增 2 例:载荷透传 agent/callId、缺 agent 不崩且记审计;79 测试全绿
v0.7.02026-09-17镜像同步挂载:新增 mirror.mjs——dream / reflect 结束后(工具 memory action=dream、/memory dream、启动自动代谢、设置页 POST /dream 四条路径)异步触发外部维护脚本(默认按「插件目录向上两级/tools/bm-sync-mirror.cjs」解析,可用 DSH_BIOMEMORY_MIRROR_SCRIPT 换成自己的脚本),把 SQLite 重新导出为人类可读镜像(<MEMORY_ROOT>/preferences.md + longterm\条目镜像.md)。为什么由外部脚本做:v0.6.4 单轨制的核心就是「SQLite 唯一事实源、插件不写 Markdown」,若在写入路径恢复 Markdown 写入等于退回双轨(正是 8/20~9/5 那 79 条从未注入的根因)——所以插件只负责触发,生成与备份全留在外部脚本。行为:--dry-run 不同步、DSH_BIOMEMORY_MIRROR_SYNC=0 可关闭、DSH_BIOMEMORY_MIRROR_SCRIPT 可换脚本;脚本缺失/失败/超时(15s)都不影响记忆本体,只留一行调试日志;脚本路径惰性求值(模块顶层固化会让「先 import 后设环境变量」的覆盖失效,与 db.mjs::biomemoryDir() 同一教训)。另:镜像脚本改为原子写(临时文件 + rename),避免中断留下半个镜像。★实现上踩掉两个坑:①脚本路径必须惰性求值(模块顶层固化会让「先 import 后设环境变量」的覆盖失效,与 db.mjs::biomemoryDir() 同一教训);②不能对子进程调 unref()——实测 detached + unref 会让父进程收不到 exit/close 事件,Promise 永不 settle、调用方 await 悬挂(改用 close 事件且不 unref)。新增用例覆盖触发/环境变量透传/关闭开关/脚本缺失;77 测试全绿(连跑 3 次稳定)
v0.6.82026-09-17审计双写修复:store.mjs 原先 8 处、retrieve.mjs 1 处直接调用 db.audit(只写 SQLite 的 audit_log 表),而人类可读镜像 <MEMORY_ROOT>/audit.log 的追加逻辑在 shared.mjs::audit 里——于是自 v0.5 起,经 memory 工具写入/编辑/删除/钉选的记忆全都不进镜像(实查镜像里 WRITE 行止于 2026-08-19,只剩 DECAY / CONSOLIDATE 等代谢事件),与文档「SQLite audit_log 表 + 人类可读镜像」的说法不符。现统一走 shared.audit,并把 fp / 文本摘要提到顶层载荷(对齐 meta.mjs 既有约定),镜像行恢复为 [时间] ACTION fp 摘要;新增回归用例锁死该行为;76 测试全绿
v0.6.72026-09-17备份文件唯一性兜底:backupDb() 的时间戳只有毫秒精度,同一毫秒内连续备份会撞名并静默覆盖上一份(「每次备份独立文件」用例偶发失败即此因)——现在撞名自动追加 -2 / -3 序号后缀,每次备份必定独立成文件;对应用例改为紧密循环连续备份(同毫秒内 3 次也必须互不撞名且文件都存在);75 测试全绿
v0.6.62026-09-17exact 排序语义修正:由「按 weight 排序」改为「按相关度排序 + weight 有界加成」——score = relevance × (1 + 0.5·min(weight, weightCap)/weightCap),relevance = Σ 命中字段权重(正文 1.0 / 摘要 0.5 / 实体 0.25)+ 0.1·min(命中次数, 5) ∈ [0, 2.25];weight 最多把分数抬高 50%(与 hybrid 的 γ 项同构、同用 weightCap 归一),因此低 weight 但更相关的条目不再被高 weight 擦边命中者压后,用户锁定的重要记忆在同分/近似分时仍有优势;同分时按 weight 降序 → created_at 降序 → entry_id 升序收敛(全序、确定性,同输入同输出);空查询(list/浏览)保持 weight 降序与冲突置顶不变;queryEntries 返回结构、命中自动巩固(hits+1)、search/queryEntries 参数与 hybrid 的 RRF 融合(只取 exact 的 rank)均不变;新增 6 个用例(75 测试全绿)
v0.6.52026-09-16缺陷修复与安全加固:审批门 fail-closed(默认审批缺失/异常/非授予 → 拒绝写入并记审计,原默认 auto 会静默免审批;接受运行时全部授予词);hybrid 融合 γ·(weight/weightCap) 归一到 RRF 同量级(原 γ·weight 淹没语义排名);快照预算修正(偏好/锁定逐条截断 + kb/bb 保底,注入不再超 hotTokenLimit);反思冲突判别改 kind==='行为'(新写入行为记忆此前永远进不了潜在冲突);/memory audit 与 GET /entries 字段对齐(audit 不再输出 undefined、entries 补 hits/pinned/mode/ts/kind 且 q 分支应用 layer);UI 主题跟随加 MutationObserver、副标题动态取数、操作失败不再静默;peerDependenciesMeta 适配预发布范围
v0.6.42026-09-06数据层单轨制:SQLite 为唯一运行时数据源——写入一律走 memory 工具(writeEntry 不再追加 preferences.md);偏好文本/冲突检测改从 SQLite 读(prefsText(),替代读 Markdown);Markdown(hot/projects/longterm/preferences)永久降级为只读备份+人工查看层,不再参与运行时读写(消除「双轨不同步」盲区);60 测试全绿
v0.6.32026-09-05适配 DSH 0.1.2-rc.1:memory 工具返回值兼容 dsh-tools 新版 lossless JSON 校验(undefined/NaN 字段置 null,修复工具报错);插件 UI 深色适配(DSH 主题跟随,双通道探测 + MutationObserver)
v0.6.22026-09-05管理 UI 按「骨架/血肉/呼吸」设计语言重构:现代极简——neutralSurface 底 + 白色圆角卡片分层、主色下划线 tabs、4/8px 栅格、150ms 动效;配色全部取自 dsh-fuse design 令牌,零硬编码;确立紫粉品牌色(记忆神经)
v0.6.12026-09-05Memory / Retrieved / Applied 三层分离(检索到 ≠ 已采用);记忆钉语义修正(锁定 = 不遗忘 + relevance admission);记忆类别 memory_class + 来源 source_ref;schema 演进(entries 表新增列,旧库启动自动 ALTER,幂等)
v0.6.02026-08-31index.mjs 拆为 shared / store / retrieve / meta / snapshot / gate / notify / session-state 模块(行为不变,57 测试全绿);会话结束自动沉淀(turn/end 后注入总结指令,写即清标记、5 分钟防呆、严格去重)
v0.5.32026-08-31设置页改用 dsh-fuse 设计令牌;peerDeps 升至 >=0.1.1-rc.1
v0.5.22026-08-20可编辑记忆(update 保留锁定/权重,审计 UPDATE,防重复)+ 冲突浮出置顶(行为与偏好冲突不再静默降权)+ 单条回滚(restore / /memory undo)
v0.5.02026-08-20SQLite 数据层(~/.dsh/biomemory/biomemory.db,node:sqlite 内置、WAL、零外部依赖)+ 本地嵌入语义检索(bge-small-zh-v1.5,512 维,离线);旧 Markdown 记忆自动迁移(保留只读备份)+ 审计聚合 + dream 断点续跑
v0.4.0—自动召回(命中巩固,用进废退)/ 自动保存(审批降级 + 自动代谢/反思周期)+ 深度反思 + 知识页(设置页 tab)
v0.3.x—记忆代谢(dream)+ 记忆钉(pin)+ 结构化审计(audit.jsonl)+ 语义检索(TF-IDF)+ 设置面板

常见问题

  • Node 版本:要求 Node ≥ 22.19.0(node:sqlite 内置);旧版本可能无法加载插件。
  • DSH 运行时兼容性:目标 @deepseek-ai/dsh-* ≥ 0.1.1-rc.2——请核对实际运行的运行时版本(0.1.2-rc.1 与 0.1.5-rc.1 均已实测)。注意 semver 预发布规则:>=0.1.1-rc.2 不会 satisfies 0.1.5-rc.1,但这两个包由宿主提供,加载不受影响(见「兼容性」)。
  • 工具报错(Invalid object / lossless JSON):升级到 v0.6.3+,返回值已兼容 dsh-tools 新版严格校验。
  • 重要记忆写不进/被拒:v0.6.5 起审批门默认 fail-closed——审批服务缺失、approval.request 抛错或返回非授予值(rejected/cancelled/unavailable)都会拒绝写入并记 APPROVAL-UNAVAILABLE 审计。若想沿用旧的自动保存行为,在设置页或 biomemory.config.json 显式设置 approvalFallback: "auto"。
  • 审计/知识库列表出现 undefined:已在 v0.6.5 修复(/memory audit 字段对齐 action/entry_id/detail;GET /entries 补 hits/pinned/mode/ts/kind,带 q 时也应用 layer 筛选)。
  • 记忆写入失败:检查 ~/.dsh/biomemory/(及 DSH_BIOMEMORY_DIR)读写权限;审批被拒时确认审批策略与 approvalFallback 设置。
  • 旧 Markdown 记忆去哪了:首次启动已自动迁移进 SQLite;$DSH_MEMORY_ROOT(默认 ~/.dsh/memory)保留为只读备份(v0.6.4 起为纯只读层,不再写入/读取,修改它不会影响运行时——写入一律走 memory 工具)。

数据层(单轨)

  • 唯一数据源:~/.dsh/biomemory/biomemory.db(SQLite,node:sqlite 内置、WAL)。
  • 只读镜像:$DSH_MEMORY_ROOT(默认 ~/.dsh/memory)(hot/ projects/ longterm/ preferences.md)仅备份与人工查看,v0.6.4 起不参与运行时——手工编辑不会生效。
  • 写入入口:memory 工具(add/edit/remove/pin)与 /memory 命令,全部落 SQLite 并审计。
  • 一次性迁移:新环境首次启动仍会从 Markdown 导入历史(meta.migrated_at 幂等,仅一次)。
  • 误删的条目还能找回吗:删除前自动备份数据库(保留最近 7 次),/memory undo <fp> 或 memory action=restore fp=... 即可恢复。
  • 原生模块冲突:本插件无任何原生依赖——纯 JS 实现,不会与其他插件冲突。

开发

# 运行测试(node:test,81 个用例全绿)
npm test

# 发布一致性自检(版本号 / README 版本露出 / files 白名单 / lock / git 状态)
node scripts/release-check.mjs

CI:.github/workflows/ci.yml 在 Node 24 上执行「安装依赖 → 发布自检 → 单元测试 → npm pack --dry-run」,推送与 PR 都会触发。

模块结构:index.mjs(接线层)+ shared(配置/审计/冲突/快照预算)+ store(写入/钉选/删除/恢复/迁移)+ retrieve(确定性检索)+ meta(代谢/反思聚类)+ snapshot(快照/会话注入)+ gate(审批门/自检)+ mirror(镜像同步)+ session-state(会话沉淀状态)+ extract(按需抽取,当前无入口)+ db(SQLite 数据层)

贡献:fork → 修改 → 补充/更新测试 → 提交前运行 npm test;报 issue 请附 DSH 运行时版本、Node 版本与复现步骤。

License

MIT — 完整文本见 LICENSE。

Plugins relacionados