npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

dsh-persist

v0.2.5

Published

Persistent memory for DeepSeek Harness: per-conversation notes, selective injection, project memory, semantic Vault search (bge-m3, free optional key) and automatic retrieval — agents stop forgetting.

Readme

dsh-persist

English | 简体中文

给 DeepSeek Harness 的 agent 装上"不会失忆"的长期记忆。 Persistent memory for DeepSeek Harness agents.

它解决什么问题

默认情况下 DSH 的 agent 换对话就失忆——上下文一关,什么都不记得。dsh-persist 把记忆做成 文件系统上的分层结构,每个对话按需注入:

| 层 | 存储 | 对标 | 怎么被读取 | |---|---|---|---| | 用户画像 + 长期记忆 | USER.md / MEMORY.md | 长期记忆(LTM) | 每对话可选注入 | | 关键记忆 | memory.json | 速查卡片 | 每对话可选注入;工具读写 | | 对话记忆 | sessions/<id>/memory.md | 工作记忆 | 只注入本对话 | | 项目记忆 | projects/<key>/memory.md | PARA 的 Project 层 | 按项目勾选注入 | | Vault 语义记忆 | vault.md + vault.db | Zettelkasten 卡片盒 | 按需语义召回(工具或「自动检索」开关,不静态注入) |

特性

  • 对话独有记忆——每个对话一本"不会丢的笔记本",其他对话看不到、不注入
  • 选择性注入——勾选什么才注入什么;新对话默认零注入,不占上下文
  • 项目记忆互通——同一工作目录共享项目经验;命名项目可把同目录的多项目分开
  • Vault 语义检索——配一个免费 key 就能"按意思"找记忆;不配自动降级为关键词搜索
  • 自动召回(三态模式)——记忆 tab 里选择自动检索模式:关闭(默认)/ 智能(纯本地规则过滤闲聊,提到历史/项目/主题才查,零外发)/ LLM 判断(调用模型判断是否需要检索,更准但会把消息发给模型提供商,超时/失败自动降级为智能)
  • 记忆 tab——对话顶部可视化编辑 + 注入配置 + 实时预览(所见即所得);tab 右上角的「打开记忆管理页」在新标签打开完整管理页(全部会话/项目/Vault/全局文件)
  • 全部纯文本——~/.dsh-memory/ 下每个文件人类可读可改,随时备份、迁移、导出

快速上手

dsh plugin --profile web add dsh-persist   # 1. 安装
# 2. 重启 DSH(dsh --profile web)
# 3. 打开对话 → 顶部「记忆」tab → 勾选要注入的块

想让 agent 记住什么,直接对它说"记住这个",它会自动写入本对话记忆。 要开语义搜索:在 硅基流动免费申请 key,设置环境变量 SILICONFLOW_API_KEY=... 后重启即可(不配也能用,自动降级为关键词搜索)。

怎么装?

曾用名 dsh-memory(npm 名已被占用,故改名 dsh-persist)。存储路径 ~/.dsh-memory/、路由 /dsh-memory/ 不变,旧数据无需迁移。

环境要求:Node.js >= 22.6(推荐 24+;测试用 --experimental-strip-types 自 22.6 起可用)。Vault 层用内置 node:sqlite:23.4+ 默认可用,22.6–23.3 需 --experimental-sqlite 标志;更低版本插件照常加载,仅 Vault 工具自动降级禁用(记忆/注入/UI 不受影响)。宿主为 DeepSeek Harness(需提供 tools / systemPrompt / webServer / sessions / agents 服务与 conversation.view UI 槽位)。

dsh-persist 是一个标准 DSH 组合包(bundle):声明了 dsh.bundle,通过 dsh plugin 装进任意 profile。@deepseek-ai/* 是 optional peer 依赖,由 DSH 宿主在运行时提供,npm 不会、也不需要安装它们。

从 npm 安装(自带构建好的 lib/,无需构建):

# 装进你的 web profile(首选)
dsh plugin --profile web add dsh-persist
# 或装进别的 profile
dsh plugin --profile demo add dsh-persist

安装后重启(dsh --profile web),插件即生效。

从 GitHub 安装(会拉源码并跑 prepare 构建,见下文):

dsh plugin --profile web add github:tluoluo/dsh-persist

从 git 安装时 pnpm 在首次 add 后可能需要你授权运行 prepare 构建脚本:把 dsh 打印的包键复制进 profile 的 pnpm-workspace.yaml 的 allowBuilds,再重跑 add(详见 DSH 官方文档 publish.md)。

可选环境变量(全部非必需,装完就能用):

  • SILICONFLOW_API_KEY=... → 可选,开启"语义搜索"。bge-m3 会把记忆转成向量、按意思找(比纯关键词更懂你)。不配也能用:Vault 记忆自动降级成关键词搜索,功能不受影响。在硅基流动免费拿 key,然后设这个环境变量即可。它是本插件唯一可选的"外挂大脑",用来让搜索更聪明,但不是必需。
  • DSH_MEMORY_INJECT=0 → 关闭自动注入(默认开启)
  • DSH_MEMORY_ALLOW_REMOTE=1 → 允许非本机(非 loopback)访问记忆 API(默认一律 403;仅当 DSH web server 绑定 0.0.0.0 时需要,请自行评估隐私风险)
  • DSH_MEMORY_AUTO_VAULT=0 → 强制关闭所有对话的自动语义检索;=1 → 强制开启(不设置则按每个对话记忆 tab 里的「自动检索」模式,默认关。注意:=1 且未显式设置 GATE 时一律按智能门控,会话 tab 里选的 LLM 档不生效)
  • DSH_MEMORY_AUTO_VAULT_GATE=heuristic|llm|off → 全局覆盖每个对话的自动检索模式(heuristic 智能门控:纯本地规则过滤闲聊,零成本、零外发、零延迟;llm 调用模型判断(模型见 DSH_MEMORY_JUDGE_MODEL),任何失败自动降级为 heuristic;off 关闭门控——每回合都检索)。不设置则按各对话记忆 tab 的选择——注意 tab 的「关闭」= 不检索,与这里的 off 含义不同:off 只在显式设置该变量时生效。词表是启发式的,存在已知边界(如无触发词的短消息不查、长闲聊可能漏网),属设计取舍
  • DSH_MEMORY_JUDGE_MODEL=provider/model → LLM 判断模式用的模型(默认 deepseek-official/deepseek-chat,便宜快速;格式 provider/model)
  • DSH_MEMORY_JUDGE_TIMEOUT_MS=5000 → LLM 判断超时(默认 5000ms,超时降级为智能模式)
  • DSH_MEMORY_AUTO_VAULT_NAMESPACES=user,dsh-persist → 限制自动检索只查这些 namespace(默认查全部 namespace,含项目归档)

隐私提示:开启语义搜索(SILICONFLOW_API_KEY)后,每条用户消息和记忆内容都会发送给硅基流动(SiliconFlow)做向量化;自动检索同样如此。LLM 判断模式还会把当前消息发送给 DSH_MEMORY_JUDGE_MODEL 指定的模型提供商做"是否需要检索"的判断。介意请勿配置 key,或设 DSH_MEMORY_AUTO_VAULT=0 关闭自动检索(手动 vault search 仍可用)。

一句话:装完 dsh plugin add 重启就有记忆功能;想要更聪明的语义搜索,再去硅基流动拿个免费 key 配上。

装完怎么用(新手三步)

  1. 重启 DSH(dsh --profile web,别用还在跑的旧进程),插件即生效。
  2. 打开 Web 界面,进入任一对话,会话顶部(轨迹 tab 右边)会出现一个 「记忆」tab——这里就是你本对话的记忆和注入开关。
  3. 想让 agent 记住什么,就在对话里直接说,agent 会自动通过 memory 工具写入本对话记忆;或你在记忆 tab 里手动编辑。默认不注入任何记忆(不占上下文),你在记忆 tab 勾选后才把对应记忆每轮放进上下文。

可选:想用语义搜索,先在硅基流动拿到免费 key,设置环境变量 SILICONFLOW_API_KEY=... 再重启,Vault 层就从关键词搜索升级为语义搜索(README 不替你存 key,请放在 DSH 宿主能读到的环境里)。

安全提示:/dsh-memory/api/* 只允许 loopback 访问(非本机请求返回 403,除非显式设置 DSH_MEMORY_ALLOW_REMOTE=1)。记忆内容包含个人身份信息,请勿在共享网络中开放。

开发构建

使用者不需要构建——发布包自带 lib/,dsh plugin add 直接装。

外部开发者在自己环境 clone 后,npm install 会自动运行 prepare(tsdown 纯转译,不依赖 @deepseek-ai 类型即可产出 lib/),因此能自包含地构建出可用的产物:

npm install        # 自动跑 prepare → lib/index.js + lib/client.js
npm run prepare    # 显式重建自包含产物(host 用 tsdown.host.config.ts,client 用 tsdown.config.ts)
npm test           # smoke 测试(node --experimental-strip-types src/smoke.ts)

prepare 只做转译(不 type-check):它把源码里对 @deepseek-ai/* 的 import type 全部擦除,产物运行时只保留对宿主提供的两个 import(@deepseek-ai/dsh-tools.defineTool 与 @deepseek-ai/dsh-llm.createUserMessage)——所以无宿主类型也能构建,产物由 DSH 宿主持有并加载。

维护者(在 DSH 宿主树内、junction 到宿主依赖以获得 @deepseek-ai 类型的场景)可跑全量构建,额外产出 .d.ts 并做完整类型检查:

npm run build      # typecheck + typecheck:client + build:host + bundle + dts

语义检索的端到端测试在 src/smoke-semantic.ts(需要真实 SILICONFLOW_API_KEY),不包含在 npm test 里——需要时手动运行:

  • PowerShell:$env:SILICONFLOW_API_KEY=...; node --experimental-strip-types src/smoke-semantic.ts
  • bash:SILICONFLOW_API_KEY=... node --experimental-strip-types src/smoke-semantic.ts

注意:lib/ 已 gitignore;运行中的 DSH 需重启才加载新 host 代码(client bundle 刷新页面即可)。

怎么用?

工具动作(model 调用)

memory 工具的 scope 参数决定写/读到哪:

  • scope=conversation(默认)→ 本对话记忆:add 追加一条笔记,list/search 读全文
  • scope=project → 当前工作目录的项目记忆(同目录对话互通)
  • scope=global → 全局 keyed 记忆:add/get/search/delete(按 key)

| 动作 | 参数 | 作用 | |---|---|---| | add | scope, content(global 还需 key) | 存一条记忆 | | get / search / delete | scope, key | global 的 keyed 操作 | | list | scope | 读对话/项目记忆全文 | | profile | profileKind, profileOp, content | 读写全局用户画像(USER.md/MEMORY.md) | | vault | vaultOp, content/query, namespace | 语义存取:add 存、search 查、list 列、export 导出、import 导回(带 namespace 隔离) |

记忆文件(全部人类可读可改)

| 文件 | 内容 | 怎么改 | |---|---|---| | ~/.dsh-memory/sessions/<id>/memory.md | 本对话记忆 | 记忆 tab 里编辑,或 memory add | | ~/.dsh-memory/sessions/<id>/inject.json | 本对话注入配置 | 记忆 tab 里勾选 | | 所有历史会话 | 各对话记忆 + 注入配置 | /dsh-memory/ 管理页「会话记忆」tab:浏览 / 编辑 / 删除(记忆 tab 只能编辑当前对话) | | ~/.dsh-memory/projects/<key>/memory.md | 项目经验 | memory add(scope=project),或直接编辑 | | ~/.dsh-memory/USER.md / MEMORY.md | 全局池 | /dsh-memory/ 页面或直接编辑 | | ~/.dsh-memory/memory.json | 全局 keyed | 直接编辑 JSON | | ~/.dsh-memory/vault.md | Vault 语义记忆 | 工具增删(memory(vaultOp="add"/"delete"))自动同步此文件;手改文件后 memory(vaultOp="import")(或管理页「Vault 同步」)写回数据库 |

例子

对话 A(工作目录 /work/projA):
- 记忆 tab 勾选:用户画像 + 本对话记忆 + 项目记忆(projA)
- agent 每轮自动注入这三块;对话 B 看不到对话 A 的记忆

agent: 用户说他喜欢用空格缩进
agent: memory(action="add", content="用户偏好空格缩进")   # 写入对话 A 的记忆

agent: 用户问"你记得我喜欢怎么缩进吗"(同一对话)
agent: memory(action="list") → 读回对话 A 的记忆

agent: 记录项目经验
agent: memory(action="add", scope="project", content="构建脚本在 build.ps1")
       # 写入 /work/projA 的项目记忆,同目录其他对话也能勾选注入

agent: 全局 keyed 记忆(跨对话共享)
agent: memory(action="add", scope="global", key="user-name", content="小明")

技术设计(对应 DSH 课程)

| 部分 | 实现 | 课程模块 | |---|---|---| | 存储层 | MemoryStore / ProfileStore / SessionMemoryStore,文件 + 原子写入 | 模块 ⑤ 方案 A | | Vault 层 | VaultStore + embedder(SQLite + bge-m3) | 模块 ⑤ 方案 C | | 工具层 | ctx.tools.register(defineTool({...})),scope 三态 | 模块 ③④ | | 选择性注入 | ctx.systemPrompt.context() 按会话读 inject.json 渲染(子 agent 沿 parentSession 继承所属对话) | 模块 ⑥ | | 多 agent 隔离 | namespace + 对话/项目两级隔离 | 模块 ⑦ | | Client UI | conversation.view 槽位 id memory order 20(轨迹右边),tsdown 自包含 bundle | 模块 ⑧ | | 混合检索 | 有向量走语义、无向量走关键词,合并排序 | 模块 ⑤ | | 插件结构 | name / inject / apply 三件套 | 模块 ② |

注意:改代码后需要重启 DSH 才会加载新 host 代码(lib/ 更新了,但运行中的进程持有旧模块;client bundle 刷新页面即可)。

故障排查

| 现象 | 处理 | |---|---| | 记忆文件损坏(memory.json / inject.json 无法解析) | 插件会自动把损坏文件备份为同目录下 *.corrupt-<时间戳> 并重置为空,控制台会打印备份路径——从备份找回内容即可 | | 记忆 API 返回 403 | loopback 守卫生效(默认只允许本机)。确认 DSH 绑定 127.0.0.1;确实需要远程时设置 DSH_MEMORY_ALLOW_REMOTE=1(自行评估隐私风险) | | 想完全关闭自动注入 | DSH_MEMORY_INJECT=0 后重启 DSH | | 改 host 代码不生效 | DSH 进程持有旧模块,需要重启 DSH(client bundle 刷新页面即可) | | 注入内容过长 | 静态记忆块(USER/MEMORY/对话/项目)有 100 行截断,超出的部分不会注入——请在 /dsh-memory/ 页面精简对应文件。Vault 无静态注入:只经「自动检索」topK=3 或工具按需召回,不受行数限制 | | 对话/项目记忆文件越来越大 | 注入有 100 行截断,但磁盘上的 memory.md 会持续增长——建议定期(如每个里程碑)用 memory 工具或直接编辑精简,过时条目移入 Vault 归档 | | 手改 vault.md 后内容丢失 | 工具增删(memory(vaultOp="add"/"delete"))会全量重写 vault.md(自动同步镜像)。手改请在无工具操作的间隙进行,改完立即 memory(vaultOp="import") 或管理页「Vault 同步」写回数据库 |

贡献

  • 代码结构:src/ 顶层 = 宿主逻辑 + 公共纯函数,src/client/ = 浏览器侧;两套产物独立构建(host 用 tsdown.host.config.ts,client 用 tsdown.config.ts),类型声明(.d.ts)由 tsc 生成
  • 开发流程:改代码 → npm run build(typecheck + host + client + d.ts 全量)→ npm test 全绿;只改 client 时可单独 npm run bundle 快速迭代
  • 测试永远用临时目录(src/smoke.ts 已如此),绝不直接读写 ~/.dsh-memory/ 真数据
  • 提交前跑 npm pack --dry-run 确认发布内容(prepack 钩子会自动构建)

路线图

  • [x] v1 基础:memory 工具 + 文件存储
  • [x] Builtin 层:用户画像 + 自动注入(context())
  • [x] Vault 层:向量语义检索(bge-m3,含关键词降级)
  • [x] 对话层:每对话独有记忆 + 注入配置 + 项目(cwd)记忆
  • [x] Client UI:记忆 tab(轨迹右边)+ 编辑/注入配置面板
  • [x] 真正的自动向量注入:agent/pre-step 按当前消息检索 Vault topK=3 注入(记忆 tab 勾选「自动检索」,默认关;DSH_MEMORY_AUTO_VAULT=0/1 可全局强制)

License

MIT