中文EN

@max-null/dsh-memory

memory已测通过npmMIT

跨会话明文记忆:确定性 BM25 关键词召回(无向量嵌入),memory_save/list/search/confirm/forget 五个工具 + 人工确认闸门,global/project 两层 JSON 存储(project 随 git 分享)。

下载量 / Downloads
4,807
依赖体积 / node_modules
8.58 MB
测试时间 / Tested
2026-11-06
DSH 版本 / Version
0.2.2-rc.1

安装

dsh plugin --profile web add @max-null/dsh-memory

沙箱测试结果

阶段结果
1 安装✓
2 列装✓
3 挂载✓
4 启动—

四阶段在隔离沙箱里跑:安装(有网)→ 列装 → 挂载 → 启动(后三步断网)。

README

dsh-memory

本插件属于 **@max-null/* 插件系列——这一系列共同构成 SSID(思灵 · Seek Soul in Darkness)** 桌面体验。SSID 是整合它们的盒:dsh-capture · dsh-chat-rail · dsh-chinese-thinking · dsh-draft-polish · dsh-guardian · dsh-habit · dsh-memory · dsh-node-appearance · dsh-plugin-center · dsh-quick-toolbar · dsh-skill-mcp-center · dsh-ssid-panels · dsh-ssid-zh-ui · dsh-achievements。

This plugin belongs to the **@max-null/* family — a set of plugins that together form the SSID (思灵 · Seek Soul in Darkness)** desktop experience.

一个面向 DeepSeek Harness 的跨会话明文记忆插件。遵循「一切皆插件」——它不修改 DSH 源码,声明 name/inject/apply,由 Loader 从 cordis.yml 加载。

设计原则

1. 写入即生效,人是例外干预者:模型写入的记忆直接生效(approved),不再逐条等人放行;人保留随时查看、改写、删除、钉住或回滚的能力——人不在场不等于失控。

2. 可观测先于精准:每条记忆是明文,memory_list 随时可见、memory_forget 随时删除——不存在"静默暗礁"。

3. 明文是人机共享的审计窗口:记忆是可读文本,模型可自检其是否过期(有效性锚点会在所绑环境值变化后标记 stale),人可随时查看与改写。

4. 确定性且缓存安全:BM25 关键词检索是存储的纯函数、无 LLM 调用;固定指引进 system-prompt section,approved + injected 记忆进 recall context(global 全量 + 当前会话工作区),逐条为单行摘要并按注入预算截断(超预算按最近更新优先取舍,省略数在面板可见)。

截图

装完后在设置里多出「记忆」一项,可查看与管理跨会话记忆:

入口: 设置 → 记忆

设置入口与面板

![设置 → 记忆](docs/shots/memory-settings-1.png)

用法

npm install @max-null/dsh-memory

在你的 cordis.yml 加一条(其余 storage / system-prompt / tools 由宿主已有;记忆的存储后端由插件自己注册):

- id: memory
  name: '@max-null/dsh-memory'

提供的服务与工具

  • 服务 ctx.memory:remember / list / search / forget / update / move / setStatus / setInjected / supersede / retract / sweep / demoteStale / verifyAnchors / reload 等
  • 工具(14 个):memory_save、memory_list、memory_search、memory_update、memory_confirm、memory_forget、memory_move、memory_sweep,提示词模板四件套 prompt_search、prompt_get、prompt_list、prompt_add,加日记两件套 diary_read、diary_write
  • 注入:tool:memory 指引 section(工具用法 + 常驻注入判据)+ memory:self 机制自述 + memory:recall 召回 context(global 的 approved + injected + 当前会话工作区的 approved + injected,带 [memory:<id>:<namespace>] 来源标记;摘要化 + 预算截断)+ memory:diary 指针(只有目录与最近日期,不含正文)
  • 检索:BM25(CJK 单字 + 2-gram,content 与 keywords 字段分离加权;中文多字查询精度显著优于单字切分);可选语义融合(见「可选配置」)

日记(第二套记忆,2026-10-24)

记忆与日记是两套东西,不是同一套的两个视图:

· 记忆 · 日记

写什么 · 从中得出了什么 · 今天发生了什么

准入判据 · 有用性 · 无——写就是了

怎么被读到 · 检索命中 / 常驻摘要 · 整篇读

存储 · ctx.storage 里的 JSON 块 · <DSH_HOME>/diary/YYYY-MM-DD.md

日记正文永远不经过 ctx.storage:那条路的写入模型是 writer per process and last-write-wins,而日记不该被另一个实例的「读—改—写」周期吃掉。日记也不进检索、不占常驻注入预算——注入里只有一行指针(目录 + 最近日期)。

  • 一天一个文件,按 ## HH:MM 分段;同日多场对话是追加,不覆盖。
  • 工具:diary_read(省略 date 读最近一篇)、diary_write(写一段)。
  • 写进日记的是经历:发生了什么(有细节)、我怎么想(可以有情绪、可以没结论)、关于他(他说了什么、我注意到了什么)。不写任务清单(那是 git log),不写结论(那是 memory_save)。
  • 提醒:指针行在距上次写日记超过 6 小时后附带一句提醒,同一次挂载只出现一次。
  • 开关:插件页的「日记」开关(diary.enabled,默认开)。关掉后两个工具都拒绝执行、指针不注入;已有 md 文件原样保留,不会被删。

设计依据、取舍与未决项见 [docs/设计/2026-10-24-日记机制-设计方案.md](docs/设计/2026-10-24-日记机制-设计方案.md)。

两层存储(global / project)

记忆按 namespace 分两层物理存储,各落在独立的明文 JSON:

namespace · 默认位置 · 用途

global · $DSH_HOME/storages/memory.json · 跨项目的个人偏好

project · <cwd>/.dsh/storages/memory_project_<hash>.json · 跟随仓库的项目共识,可 git 分享

两个根都可用 config 覆盖(globalRoot / projectRoot)。memory_list / memory_search 不带 namespace 过滤时会同时查两层。旧版双重前缀文件名(memory_project_memory_project_<hash>.json)在打开时自动迁移为规范名。

主题(topic,0.20.0)

namespace 管「在哪生效」,topic 管「这条讲什么」,两者正交:

字段 · 回答的问题 · 取值

namespace · 换个项目还成立吗 · global / project

kind · 是记忆还是提示词模板 · fact / prompt

topic · 这条记忆讲什么 · 自由字符串:见闻 / 约定 / 坑 / 偏好 / 事实 / 判据 …

memory_save 传 topic 落库,memory_list / memory_search 传 topic 切片。留空或省略即「未分类」。用它把「自己出去逛到的」(见闻)和「一起干活时记下的」分开翻,不必再往正文里手写前缀。

跨工作区可见性(0.10.0 / 0.11.0)

project 记忆按会话工作区分文件存放,所以「工作区」就是可见性的边界。0.10.0 起补了三个方向——针对的是同一个盲区:不知道存在(检索是有意图的动作,搜不出自己不知道存在的东西)。

方向 · 机制 · 效果

向上 · 祖先链 · 在子目录里开会话能检索到父目录的记忆(反向不行,链是单向向上的),结果带 .. / ../.. 来源标记

向下 · 子项目索引行 · 注入里多一行「本工作区下另有 N 个子项目带记忆:xxx(M 条)——用 memory_search 检索」

全局 · 记忆索引行 · 注入里多一行「索引:当前可见 N 条记忆,主题集中在 X(14)、Y(12)…——用 memory_search 检索」

三条边界:写入永远只落当前工作区(「我在这个项目里记的东西」不该被推理到别处);但检索得到的记录就改得动——memory_update / memory_forget 同样沿链定位;注入路径只读当前工作区(远处的记忆进检索、不进每轮成本)。

0.11.0 起,「放错了层」有了显式的修正通道:memory_move(id, to) 把一条记忆移到 global、self(当前工作区)或相对祖先(.. / ../..)。它是例外动作——默认写入仍然只落当前工作区,只有当你判定「这条其实属于上一层、或上一层的那一支」时才动它。移动保持 id、从源层删除(不是复制),并报告移动后源层是否仍看得见它:向上移动源层不失明(继承只向上,global 人人可见),向下移动则会让源层及其下层从此看不见它。典型用途是把放高了的记忆降回它真正属于的工作区——比如只属于某一个生态的规矩躺在 global 里、漏进了无关项目。判据与边界见设计文档 §3.2。

后两行不占注入预算、自消除(没有内容时整行不出现),且长度常数级——不随记忆增长。索引行里的主题取自各条的关键词词频,与检索用的是同一套词汇,所以索引里出现的词就是能搜到的词。

孤儿文件清点:node scripts/scan-orphans.mjs [根目录] 报出「哪些记忆文件当前代码已经打不开」(历史命名遗留:早期无哈希后缀、双重 memory_project_ 前缀)。只读,不做任何处置——旧文件可能含未过隔离检查的内容,处置需人工拍板。

祖先链诊断与探针:node scripts/ancestor-probe.mjs plan [--cwd <会话 cwd>] 只读地复算该 cwd 的祖先链(哪些层级带记忆文件、引擎会纳入几级),并回答「这个 cwd 上祖先链是否可观测」——若以上祖先层都没有记忆文件,祖先链生效与否行为逐字相同,那是个零差异的观测点。要实测检索侧跨链,用 seed / check / clean 在祖先层造一条临时探针再撤销。前提:探针只对没打开过该层的会话有效——引擎的表打开即缓存,而写路径的新鲜度门(refreshForWrite)只比对 global 与当前 cwd,不含祖先层,被缓存过的层会用陈旧内存态覆盖掉外部写入。

多实例共存(0.7.1)

两个 DSH 实例(例如 DSH web 与 SSiD 桌面壳)可以同时运行、共用同一个 DSH_HOME,记忆不再互相抹掉。

DSH 存储层的写入是「读—改—写全量覆盖」,且官方两个后端都声明不做跨进程协调(storage-json:writer per process and last-write-wins is correct;storage-sqlite:cross-process coordination is out of scope)。插件层的处置是写前重读(等价于 update 前先 select):每次写入在串行区里先比对存储文件指纹(mtime + size),发现磁盘被别的实例动过就先重载再写。代价是磁盘没变时的一次 statSync。

残余窗口只剩两个实例在同一瞬间写——此时后写者赢;同时写不同记忆已不再互相影响。

未覆盖:workspace.json(工作区登记)由 DSH 自己的 workspace 服务写,插件层够不着,仍会被双实例互相覆盖;根因处置在上游——[discussion #6882](https://github.com/deepseek-ai/deepseek-harness/discus

…(truncated)

以上内容来自 npm 上的 README,我们只做格式化,不改内容。

版本

npm 上共发布:36,最后更新 2026-10-30

链接

GitHub · Homepage · npm

同类插件