dsh-memory-engine
Manifest validFork of dsh-memory-engine with a redesigned memory graph (@wilshi 0.8.0)
DSH 记忆引擎(@wilshi 视觉分叉 0.8.0)
Fork notice:本仓库是 dsh-memory-engine 0.7.5 的分叉(MIT,作者 dsh-memory-engine contributors),包名改为
@wilshi/dsh-memory-engine、版本 0.8.0。0.8.0 只改图谱可视层与关联边算法:深空星云背景、语义星座布局、TF-IDF kNN 关联边、标签避让、图例筛选、可折叠复习清单、hover/脉冲动效。数据格式、工具、HTTP 路由与上游 0.7.5 完全兼容。
DSH 插件的本地记忆引擎,带神经网络可视化。它让 agent 保存、召回和管理跨会话记忆,也能把你已有的记忆文件导进来。
当前版本:0.7.5。Node ≥22,零新增依赖。自动记忆默认关闭,由用户在图谱头部或设置页手动打开;开启后每轮对话会额外调用一次模型,可能产生费用。自动导入默认只收聊天会话的用户消息,支持来源白名单、工作指令过滤、流程话过滤、规则分类、错误原因、一次性重扫和账本清理。
从 0.6.1 升级到 0.7.0 的变化
- 不再占用 18886 端口,改用 DSH 宿主的同源路由。
- 图谱从 iframe 改为直接绘制的 Canvas,保留旋转、缩放和节点详情。
- 新增中心角色卡、球体布局、记忆管理面板、自动记忆和自动导入。
- 记忆数据格式不变,可以直接升级,无需迁移命令。已有配置明确设置的启用状态会保留;未配置自动记忆时默认关闭。
已知限制
- 检索按字面匹配,不理解同义词,例如查“自行车”不能自动匹配只写“单车”的记忆。
- 单机使用,没有跨设备同步。
- 数据保存为明文 JSON,没有加密。
- 只支持 DSH 宿主。
- 自动记忆开启后会产生额外模型调用费用,实际金额取决于模型和计费方案。
0.7.0 功能
| 功能 | 内容 | 使用方式 |
|---|---|---|
| 原生图谱 | 同源路由、React Canvas,界面与离线 HTML 共用绘制源码 | 旋转、缩放、点击详情;离开页面停止动画 |
| 记忆管理 | 列表、搜索、编辑、删除、导出和清空 | 分页、筛选、确认与错误提示;写操作先备份 |
| 中心角色卡 | 固定角色核心、分层球壳、慢速自转 | 点击查看全文;拖拽暂停,松手 2 秒恢复 |
| 自动记忆开关 | 默认关闭,头部与设置页同步 | 首次开启提示成本;关闭即取消排队抽取并阻止迟到结果写库 |
| 使用引导 | 空库和手动回看共用三步卡片 | 复制提示词、刷新、知道了/Esc 关闭 |
- 引导回看:右上角「?」、中央卡片、复制提示词、知道了/Esc 关闭。
- 按钮开关:hideButton、showGuideOnEmpty;配置请求失败时保留按钮并警告。
界面使用应用内 canvas 渲染;/memory-engine/ 整页 HTML 保留给 CLI 与浏览器直接访问。七个 agent 工具继续可用,记忆管理在应用内的「记忆」「设置」页完成。
支持的 DSH 版本
实测可用范围:@deepseek-ai/dsh-tools 0.1.0-rc.8 ~ 0.2.2-alpha.2(本插件只用其中的 defineTool,这几个版本签名一致)。
插件对宿主做了三处兜底,所以版本不合适时也不会「装上了却什么都没有」:
| 宿主情况 | 插件行为 |
|---|---|
| 有 ctx.effect | 正常注册,随插件卸载一起清理 |
| 没有 ctx.effect | 直接注册工具,功能不减少,日志留一条提示 |
| 解析不到 @deepseek-ai/dsh-tools | 用内置直通 defineTool,工具照常可用 |
| 没有 header.actions 插槽 | 图谱按钮退到 views.actions(在「更多视图」菜单里) |
| 完全没有 slots 服务 | 跳过按钮,记忆工具不受影响 |
peerDependencies 已放宽为 >=0.1.0-rc.8 <0.3.0 并标为 optional——宿主自带这份 SDK,不该因为版本号不匹配而装不上。
0.7.0 的 GUI 还要求宿主提供 webServer.register({ kind, path, handler })。服务端声明 inject = ['tools', 'webServer'],插件生命周期结束时注销路由。原有 ctx.effect 和 defineTool 兼容逻辑保留;直接调用初始化时若路由注册失败,会记录提示,已注册的工具仍可用。
本机 0.2.1-rc.5 的 Cordis 把 inject 中的所有服务视为必需依赖,没有可选注入声明。因此 llm 和 sessionQuery 通过 ctx.get() 按需获取:缺少前者只停用自动抽取,缺少后者只跳过会话来源。把这两个名字加入必需注入数组会使整个插件在缺服务时无法启动。实际 session/event 回调签名为 (session, event)。
界面
安装并启用插件后,完全退出 DSH 再打开。进入任意会话,头部第一行会出现 🧠 记忆图谱 按钮。
点击后全屏显示图谱,顶部有 图谱 / 记忆 / 设置 三个 tab,? 左侧是 ○ 自动记忆 / ● 自动记忆 开关,右上角 关闭 × 退出。鼠标悬停可看当前状态和抽取上限。设置页也有同一个开关及成本说明,两处同步、刷新后保持状态。第一次开启会提示模型费用;保存失败恢复原状态,并显示红色原因。每次打开或从其他 tab 返回图谱都会读取当前记忆库,在内存中计算当前图谱,不写入离线 HTML。离开图谱 tab 时停止 Canvas 动画。
记忆 tab 按正文或标题搜索(250ms 防抖),可筛选知识、印象、对话、事件、日记,按最近、最老、快忘了或连接最多排序。每页 50 条,底部显示过滤后的总数和「加载更多」。点一条展开全文,再点「编辑」修改正文、分类、重要度或相关人;保存失败保留草稿并显示服务端错误,取消不发送写请求。删除必须再次确认。
设置 tab 显示数据目录、条数、文件大小,支持复制路径和下载全部记忆。导出文件结构为 { ok: true, data: { total, items } },保留原始条目的全部字段。清空必须输入大写 DELETE,输入错误不会发请求;成功后回到空库引导。界面不重复提供导入,仍使用 memory_import 工具。
点击神经元,右侧滑入约 350px 的只读详情卡片,显示分类、标题、重要度、留存、连接数、本地日期和正文;有情绪标签时才显示情绪行。空标题取正文前 20 字,长标题换行、长正文在卡片内滚动。点另一个节点只更新内容,不重复滑入。
卡片的 在图里高亮它 调用现有激活效果;复制正文 复制全文,成功后显示「已复制 ✓」,1.8 秒后恢复。点图上空白处或卡片 × 关闭详情,图谱继续显示。关闭整个浮层、切换 tab 或刷新图谱会清空选中状态;编辑和删除在「记忆」tab 完成。
记忆库为空时,默认自动弹出中央引导卡片;已经有记忆时,点右上角、关闭按钮左侧的 ? 随时回看。同一张卡片显示三步说明、提示词和数据目录;「复制这段提示词」成功后显示「已复制 ✓」,「刷新图谱」重新载入当前记忆。
点「知道了」关闭引导,图谱和已打开的详情仍在。Esc 按 引导卡片 → 详情卡片 → 整个图谱浮层 的顺序逐层关闭。引导通过结构化 JSON 和 React 组件显示,不注入 HTML、不跳转整页。
按钮与空库引导开关
在 {DSH_HOME}/memory-engine/config.json(默认 ~/.dsh/memory-engine/config.json)的现有对象中合并以下字段,然后完全退出 DSH 再打开:
{
"hideButton": false,
"showGuideOnEmpty": true
}
hideButton: true 隐藏会话头部的 🧠 按钮,七个记忆工具照常可用。showGuideOnEmpty: false 让空库不自动弹出引导,仍可点 ? 查看。未配置时分别默认 false/true,只有明确的布尔值才改变默认行为;现有 bridgeRoot/diaryDir 等字段请保留。
配置请求失败、返回无效内容或超过 5 秒时,客户端记录一条警告并按默认显示按钮,避免网络错误让入口消失。
拖拽旋转、滚轮缩放(0.3~4.5),点击神经元激活并查看详情。详情直接使用节点已有数据,不请求新接口,也不写入记忆。客户端使用相对路径 /memory-engine/api/map 获取数据,由 React 管理 Canvas;关闭浮层或卸载组件会停止动画、取消请求并清理监听。桌面端经 DSH 的原生协议转发,无需知道宿主端口。旧 config.json 中的 uiPort 不再使用,可保留或删除。还可以运行 node <插件目录>/scripts/render-map.mjs --open 生成并打开离线图谱,整页 HTML 仍可点击查看原文。
中心角色卡与自转
在现有 config.json 对象里合并以下字段(路径使用你自己的角色卡):
{
"personaFile": "C:/path/to/role.md",
"personaTitle": "小夏",
"spinSpeed": 0.35
}
也可使用 personaText 直接配置正文,最多 4000 个 Unicode 字符;非空 personaText 优先于文件。文件只读、取前 4000 字,读取失败记录警告并退回原布局。标题默认「角色卡」,速度范围 0.05~1.5,默认 0.35(正常帧率下约 90 秒一圈)。配置后重新打开图谱即可读取;升级插件本身需要重新加载或重启 DSH。
角色卡只作为图谱里的虚拟中心,不写入记忆库,也不参与评分、关联、复习、列表或导出。它固定在原点,点击显示 [人格] 标题、可滚动正文和「复制全文」。印象、知识、事件位于内层球壳,日记、对话和其他类别在外层;旧记忆更靠外。同一份数据的布局确定不变;没有角色卡时保留原来的脑状布局。
打开后自动慢速旋转,拖拽时暂停,松手或取消拖拽 2 秒后恢复。关闭图谱或切换 tab 停止动画。离线 HTML 使用同一份布局和 Canvas,支持中心角色卡与全文复制。
客户端构建
lib/render/canvas.js 是唯一绘制源码,导出 createRenderer(canvas, data, options),每个实例独立维护相机、节点缓存、脉冲和动画生命周期。它不导入模块,也不依赖 ModuleLoader。
lib/client.src.js 是 ModuleLoader 工厂模板;修改它或 Canvas 源码后运行 pnpm build(也可 npm run build),生成单文件 lib/client.js。产物头部标有「别直接改这个文件」。构建先写同目录临时文件,再原子替换;相同输入得到逐字节相同的产物,失败会非零退出。
lib/render/render.mjs 只保留 HTML、标题、图例、复习清单和原有详情外壳,读取同一份 Canvas 源码并内联。两个消费者共用 scripts/lib/strip-export.mjs 去掉导出声明,发布客户端和离线 HTML 都不需要运行时模块加载。离线 HTML 可直接双击打开。
pnpm test(或 npm test)包含 build-freshness 检查:改了源码却忘记构建会失败,并提示「跑 pnpm build」;测试不会自动修复产物。prepack 保证 pnpm pack / npm pack 发布前重新构建。
同源接口:
| 方法 | 路径 | 返回内容 |
|---|---|---|
| GET | /memory-engine/ | 独立浏览器可直接访问的整页 HTML 图谱;应用内界面不再加载此页面 |
| GET | /memory-engine/api/map | { nodes, links, review, stats, generatedAt, core, spinSpeed };配置角色卡时 nodes[0] 为 isCore,core 含 id/title/preview,否则为 null;stats 统计图谱节点 |
| GET | /memory-engine/api/stats | 记忆总数、分类、衰减状态及存储位置 |
| GET | /memory-engine/api/onboard | { empty, prompt, steps, dataDir },空库和手动帮助共用 |
| GET | /memory-engine/api/config | 保留既有字段,autoMemory 增加 dailyCap,另增加 showAutoMemoryCostHint;仍返回 autoImport: { enabled, sourceCount } 和 lastError: { at, stage, message },不返回 raw、来源路径或模型配置 |
| PUT | /memory-engine/api/config | 合并合法白名单字段,返回公开配置和 backup 文件名 |
| GET | /memory-engine/api/list?q=&kind=&sort=&limit=&offset= | { total, allTotal, limit, offset, items };包含留存、连接数和 60 字预览 |
| GET | /memory-engine/api/item/:id | 完整条目、留存和连接数;不存在返回 404 |
| PUT | /memory-engine/api/item/:id | 仅更新传入的 text/kind/heat/who;返回更新条目和 backup |
| DELETE | /memory-engine/api/item/:id | 删除一条,返回 { deleted, backup } |
| GET | /memory-engine/api/export | { total, items },条目原样导出 |
| POST | /memory-engine/api/clear | 请求 { confirm: "DELETE" },返回 { removed, backup } |
JSON 成功返回 { "ok": true, "data": ... },失败返回 { "ok": false, "error": "说明" }。既有接口返回结构保留;stats/list/export 仍只统计实际记忆。接口仅接受本机 Host,严格限制路径,拒绝路径穿越;不允许的方法返回 405。只读接口不接收请求体,PUT 和 POST 只接收 JSON 对象,声明大小和实际分块累计大小都限制在 1MB。
配置 PUT 使用嵌套对象,例如 { "autoMemory": { "enabled": false } }。只允许 autoMemory.enabled、autoImport.enabled、autoMemory.maxPerTurn(1~5 整数)、autoMemory.dailyCap(0~500 整数)、spinSpeed(0.05~1.5 数字)、showGuideOnEmpty 和 hideButton;所有启用/显示开关只接受布尔值。0.7.2 新增 autoImport.importAssistant(布尔值)、autoImport.workMarkers 和 autoImport.sessionFilter,校验规则见下节;sessionFilter 的局部更新保留未提供的旧字段。任何未知字段或类型错误会整次返回 400,不改任何字段。角色卡、来源路径、模型等不能通过此接口修改;GET 的公开字段保持原样。
配置写入前生成 config.json.bak-<时间戳>,同毫秒加序号,保留最近五份;先写临时文件再 rename。备份或写入失败保留原配置。首次成功启用时,服务端自行保存 showAutoMemoryCostHint: false,不向客户端额外开放这个字段的写权限。关闭会清空当前收集的对话、取消排队和进行中的抽取,重新开启时重置冷却和失败退避;自动导入独立运行,若要冻结所有自动入库,需同时关闭它。
列表默认最近优先、每页 50 条,limit 上限 200;搜索为不区分大小写的包含匹配,kind 精确匹配。留存复用 decay.retention(),连接数复用全库 scoreMemories(),筛选不会改变连接数。编辑只允许 text(1~2000 字符且非全空白)、kind(1~20 字符)、heat(整数 1/2/3)、who(0~40 字符);不会改动 id、时间、强化次数或触发相似合并。
管理写操作统一先调用 MemoryStore.backup(),再调用已有 write() 临时文件加 rename 原子落盘。memories.json.bak-<毫秒时间戳> 操作备份保留最新五份,同毫秒时自动加序号。备份失败不写入,原子替换失败保留原文件;同步任务的 bak-sync-* 备份保留原有策略。切回图谱重新取数即可看到编辑或删除的结果。
也可以让 agent 调用 memory_map(),生成可双击、离线打开的单文件 HTML:
memory_map()
memory_map(title="我的机器人的记忆", open=true)
memory_map(out="D:\\memory-map.html")
默认输出 {DSH_HOME}/memory-engine/starmap.html;未设置 DSH_HOME 时为 ~/.dsh/memory-engine/starmap.html。open 默认 false,显式 true 才启动系统默认浏览器。
自动记忆和自动导入
自动记忆默认关闭;在图谱头部「○ 自动记忆」或设置页可以一键打开,首次开启会显示成本提示。开启后每轮对话会多一次模型调用,异步抽取最多两条事实,不依赖 agent 调用工具。自动导入默认开启,在启动 8 秒后读取 DSH 已有会话,之后每小时续导;导入本身不调用模型。新装空库也会逐步获得历史记录。
在现有 config.json 中合并:
{
"autoMemory": {
"enabled": true,
"provider": "deepseek-account",
"model": "deepseek-flash",
"maxPerTurn": 2,
"minChars": 12,
"dailyCap": 40,
"cooldownSec": 30,
"excludePatterns": ["密码", "身份证", "银行卡", "手机号", "验证码"]
},
"autoImport": {
"enabled": true,
"importAssistant": false,
"noisePatterns": [],
"workMarkers": [],
"sessionFilter": { "mode": "include", "cwdContains": ["state/agents", "qq-bridge", "astrbot", "nonebot", "koishi"], "maxToolCalls": 0 },
"ledgerRetentionDays": { "skip": 30, "session": 120 },
"ledgerMaxEntries": 2000,
"sources": [{ "type": "dsh-sessions" }],
"intervalMinutes": 60,
"maxPerRun": 200
}
}
未显式配置 sources 时,默认先导入 dsh-sessions,再追加已有 bridgeRoot 和 diaryDir。显式配置的数组会替换这个来源列表。路径来源支持 bridge、diary、json、markdown、text,填写绝对 path。只接受真实根路径,拒绝逃出目录的软链接;所有源文件只读。两项 enabled 可独立关闭,下轮任务会读取新配置。
自动抽取只看本轮 user/assistant 的文本块,最近最多 4000 字;排除工具、推理、寒暄和敏感词。模型请求直接走宿主 llm.stream,15 秒超时,不写回会话。每天新增上限 40 条,同会话冷却 30 秒,连续失败三次暂停 10 分钟。自动去重阈值 0.85,重复只强化旧条目,超过每日上限仍允许强化。计数按本地日期写入 auto-log.json。自动任务的备份失败只警告并继续,既有管理接口的备份失败中止规则不变。
宿主支持 resolveModelInfo 时,按实际模型能力选择最低思考档,保留 400-token 输出上限;避免本机默认 high 思考占满预算。任务书抽取提示词原文保留,附加说明“助手说已记过不等于查重结果”,让重复事实交给程序强化;没有能力查询接口的宿主仍使用原来的请求参数。
会话导入仅通过 sessionQuery.listSessions/readSession,不直接读取或解压会话文件,不激活会话。默认 importAssistant=false,只收 user/message;改为 true 才额外收 assistant/message,两者都过滤流程话。此开关不影响自定义路径中的日记等正文。保留事件发生时间;连续重复、寒暄、纯代码块和敏感词仍被过滤,超过 2000 字的消息拆段保存。每会话每轮最多 200 条,全局默认最多 200 条,批间让出 20 毫秒。import-ledger.json 保存 seq、文件 size/mtime、JSONL 行数/字节位置及未完成批次,超限下轮继续。重复导入不强化旧记忆。
0.7.2 在读取消息和写入候选两个位置检查 importAssistant。运行中关闭后,尚未写入的 assistant 候选也会被拦住;运行中开启从下一轮生效。已有 assistant 存量不会自动删除。
autoImport.sessionFilter 只影响 dsh-sessions 来源,读取事件后先判断整段会话,再收集消息:
0.7.5 默认使用 include 来源白名单。常见聊天目录为 state/agents、qq-bridge、astrbot、nonebot 和 koishi;这些默认提示按完整目录段匹配,避免把 qq-bridge-probe 当成聊天目录。自定义 cwdContains 仍可填写路径片段。没有会话命中时,设置页会提示并提供「改用宽松模式」按钮;点击后保存 mode: auto,立即重新尝试此前跳过的会话。普通 DSH 聊天如不在这些目录,可在 config.json 设置 { "autoImport": { "sessionFilter": { "mode": "auto" } } };需要收全部会话则设 mode: all。聊天机器人可配置 { "mode": "include", "cwdContains": ["state/agents", "qq-bridge"] }。
0.7.4 在自动导入时直接丢弃桥接聊天记录、运行时快照、<message source_id=...>、会话令牌和 Runtime/Context 包装文本。dsh-sessions 消息默认至少 12 个 Unicode 字符,可在 config.json 的 autoImport.minChars 设为 4~200;手动 memory_import 和 QQ 文件来源不受此门槛影响。自动导入的长文本若前 50 个字符与已存条目相同,只保留先入库的一条。配置 personaFile 后,导入器还会跳过与角色卡正文高度重合的会话文本。在 auto 会话模式下,工作区中的无工具会话若用户消息命中至少两组工作词,也会整段跳过。这些规则只影响新导入,不删除已有记忆。
| mode | 行为 |
|---|---|
auto(默认) | 至少 2 条 user/message;工作工具调用次数不超过 maxToolCalls(默认 0) |
include | cwd 包含 cwdContains 中任一路径片段;忽略大小写并统一斜杠。空列表全部排除,不附加 auto 的工具条件 |
all | 不限制会话类型或消息条数,角色和内容过滤仍然生效 |
工作工具包括 pwsh/bash/read/write/edit/grep/glob/subagent/workflow/notebook,也识别带命名空间的名称;qq_* 和记忆工具不计入。maxToolCalls 只能为 0~10000 的整数;cwdContains 最多 50 个非空片段,每个最长 1000 字符,未知字段会被拒绝。QQ 会话如果也调用过工作工具,auto 同样跳过,可按实际需要选择 include。
跳过结果保存在 import-ledger.json 的 session:<id>.skip,含 sessionId、模式和原因:work-tools、cwd-excluded 或 too-few-user-messages。前两种在同一规则下直接复用账本,日志汇总跳过的工作会话及工具;不足两条消息的会话下轮再检查,以免永远漏掉后续聊天。修改过滤规则或使用 rescanFrom/rescanAll 会重新判断。跳过不会删除已经入库的记忆,也不把该会话的旧水位推进到结尾。
工作指令单独按六组特征计数:记忆工具名、插件配置名、任务/验收词、构建发布词、版本号、录屏演示词。通常命中至少两组才拦截,单独说“npm 这个包挺好用的”仍保留。0.7.3 收紧一个弱组合:只命中构建/软件词和版本号两组时保留,避免将“新版已发布,朋友可安装”误判为工作指令;再命中验收、工具调用等第三组时仍拦截。autoImport.workMarkers 可追加最多 20 个正则源码字符串(每个最长 300 字符,使用 iu 标志);无效正则拒绝保存,手工写入无效配置则停用自动导入并提示。会话消息在拆段前检查完整正文,路径来源在写入前也检查。旧流程话规则独立保留。
导入账本清理
每轮自动导入结束时检查一次 import-ledger.json,只有实际删除记录或过期 skip 缓存时才调用已有 automation-state 原子写;无变化时不写盘。默认无水位 skip 缓存按 skip.at 超过 30 天删除,会话水位按 importedAt 超过 120 天未更新才删除。重新判断 skip 不会延长旧水位的寿命;不认识对应时间的旧记录保留。
同一记录同时包含水位和 skip 时,水位按 120 天保留,过期 30 天的 skip 字段可以单独清除,下轮重新判断会话。文件来源的字节/行数进度、未完成分段、重扫任务均保留。导入中刚更新的水位不会因清理而丢失。
条目数超过 ledgerMaxEntries(默认 2000)时,按更新时间从旧到新淘汰没有水位的 skip 缓存,目标为上限的 75%(默认 1500)。容量压力下这种可重新判断的缓存可以提前淘汰;仍不动近期水位。如果全部都是受保护的水位或文件进度,允许暂时超过上限并告警,不能为凑数量造成重新导入。
在 config.json 的 autoImport 中设置 ledgerRetentionDays 和 ledgerMaxEntries;本版没有增加配置 PUT 白名单或界面入口。skip 天数范围为 30~36500,session 为 120~36500,条目上限为 1~100000,均为整数。非法配置会中止本轮导入并记录原因,不会按错误期限清库。日志分别报告过期删除、单独清除 skip 字段、容量淘汰及清理前后数量。近期账本即使有很多 skip,也不会为了显示“条数下降”提前按过期规则删除。
存量清理(逐步确认)
scripts/cleanup-imports.mjs 默认只预览。依次运行 assistant、work、dedupe,每一步先看完整 JSON 清单和终端前 10 条样本,获得用户确认后才执行。清单包含库指纹和确认 token,库或规则变化时必须重新预览。执行前关闭 DSH,避免另一个进程同时写库。
node scripts/cleanup-imports.mjs --home <DSH目录> --stage assistant --out <assistant-preview.json>
node scripts/cleanup-imports.mjs --home <DSH目录> --preview <assistant-preview.json> --confirm <该清单token>
第一步完成后对 work 重复预览和确认,再对 dedupe 重复;不能越过尚未完成的前一步。删除调用现成 store.backup()/write(),合并调用 store.dedupe({ dry_run: false }),默认阈值 0.7。每一步自动备份、写后核对数量;备份失败立即中止。QQ 来源匹配项保护保留并列在 protected 中。去重预览如果会减少 QQ 来源条数,blocked 为 true,执行会拒绝;先审阅冲突组,不自动更改来源或去重算法。无变更时不写库。
需要保留 QQ 冲突组、只合并其余组时,在 dedupe 预览命令增加 --protect-qq。清单的 protected 列出整个冲突组的所有条目,确认后这些条目原样保留;其余范围仍调用现成 store.dedupe,备份保存完整原库,最终写入仍走 store.write。必须审阅这份新清单后再确认,不能沿用未保护的合并清单。
流程话过滤采用固定词表,可在 autoImport.noisePatterns 追加字面短语。命中两个不同特征即拦截;只命中一个时,仅拦截不足 150 字的文本,长内容保留。开头 12 字内出现「已回:」「已回复:」「已发送:」「已处理:」「已确认:」「已读:」「已标记:」「回过了:」「发过了:」的工作汇报,无论长度都拦截;中间提到「他说已回复了」不算前缀。自动记忆的抽取结果也通过同一过滤器。规则只作用于后续入库,不追删旧条目。
新导入的会话按顺序粗分:日期命名的 Markdown 日记 → 日记;价格或解释 → 知识;过敏、忌口或偏好 → 印象;约定或计划 → 事件;有日期的 Markdown 标题 → 日记;其余 → 对话。印象默认 heat=1,其余为 2。自定义来源已有明确分类时保留原分类,日期日记优先。导入的分类是启发式猜测,可能分错,可以在管理面板手动编辑。 过滤和分类都不调用 LLM。
需要重新检查旧会话时,在现有 autoImport 中加 "rescanFrom": "session-实际ID",或 "rescanAll": true。下一轮导入先清除所选会话的 seq 水位并优先处理,随后自动移除配置中的一次性开关;超过限额时从未完成处续跑。要立即执行,可保存配置后正常重启 DSH,等待启动导入。enabled=false 时暂不消费重扫请求。重扫不清库,不重分类或强化已有记忆,重复内容由去重拦截;文件来源的增量水位不重置。
auto-log.json 保留每日 added/skipped/failed,额外记录 lastError 和最近最多五条 recentErrors。失败阶段是 llm(模型调用)、parse(解析输出)、dedupe(查重)或 store(读写存储);lastError.raw 最多 200 个 Unicode 字符,recentErrors 不含 raw。修复配置后后续轮次可恢复,历史错误保留供排查;连续三次失败仍按原规则暂停十分钟。公开 config 接口只给出最后错误的时间、阶段和原因,不含原始输出。
自定义来源复用 collectBridge 和 collectFile 解析器;JSONL 只读新字节范围,Markdown 变化时整篇重导并去重。历史很多时,每轮会继续补齐尚未处理的部分,因此“下一轮仍新增”并不表示重复导入。缺文件只警告一次,失败不推进该批次水位。
手动 memory_save、memory_import 和已有 QQ 夜间同步仍可用;七个工具的参数与文案保持原样。旧版工具空库提示和界面引导仍描述手动入库流程,自动行为以本节为准。
怎么让机器人自己记记忆
beta.6 默认自动抽取。下面是额外让 agent 主动调用 memory_save 的可选用法,不是自动记忆的前提。
需要 agent 主动保存时,可以在它的提示词/角色卡中加入:
聊天时遇到这些,用 memory_save 记下来:
· 对方的称呼、偏好、忌讳、习惯(kind="印象",who 填对方名字)
· 答应过的事、约定、承诺(kind="对话")
· 情绪特别重的瞬间(kind="事件",heat=1)
· 新学到的知识、名词、梗的解释(kind="知识")
· 每天结束时,用一两句写当天小结(kind="日记")
不用每条都记。一天三五条就够,宁可少存也别灌水。
存之前先 memory_recall 查一下,避免重复。
这段只影响 agent 主动使用工具;自动记忆通过独立后台调用完成,不需要修改角色卡。
这个插件的作者给自家机器人的做法是:除了上面的提示词,还额外跑一个夜间任务,从当天聊天记录里自动提炼印象(那部分不在本插件里,属于她的私有机器人适配器)。
保存和召回
让 agent 使用:
memory_save(text="他说把我当朋友", kind="对话", heat=1)
memory_recall(q="朋友", limit=5)
正文最多 2000 个 Unicode 字符。相似内容会合并,保留旧 id 和更早发生时间。省略 heat 时使用既有情绪推断;heat 的 1/2/3 分别表示热、温、冷。
召回结果区分直接命中和联想到的记忆。memory_stats() 查看总数和分类;memory_dedupe() 默认仅预览重复组。memory_forget 支持按 id 精确删除;关键词批量删除必须先预览,并经用户确认后传 confirm=true。
检索是按字面词匹配,不做语义理解。 库里只写“单车”,memory_recall(q="自行车") 就查不到。想覆盖不同说法,存记忆时可以同时写出常用名称,例如“小夏把自行车也叫作单车”。
联想到的记忆来自关键词共享:两条记忆提到同一个词,就会被连起来,查其中一条时另一条一起返回。它不是推理,是顺着关联往外摸。扩散默认一跳(hops=1),邻居要留存 > 0.4 才会被带出来。
导入自己机器人的旧记忆
三种格式都是你明确指定的本地文件或目录。如果旧格式均不匹配,可让有文件读取能力的 agent 理解文件,再通过 memory_save 逐条写入。导入先预览,用户确认后再传 dry_run=false。
memory_import 默认只预览,显式 dry_run=false 才备份并写入。每种格式都经过同一个相似去重流程;不会修改原文件。发生时间会保留,未提供时由原解析器补默认时间。成功新增后自动生成默认图谱,不自动打开浏览器;渲染失败只记录警告,不撤销已经成功的导入。
JSON 数组文件(UTF-8,支持 BOM):
[
{"text":"他说要一起养猫","ts":1793291223536,"kind":"对话","heat":1},
{"text":"手冲咖啡先按一比十五的粉水比试喝","kind":"知识"}
]
memory_import(source="json", path="D:\\memories.json")
memory_import(source="json", path="D:\\memories.json", dry_run=false)
Markdown 目录:每个 .md 文件一条记忆,递归读取子目录,支持以下 front-matter。省略 ts 时使用原文件修改时间,文件名作为默认标题。
---
heat: 1
kind: 对话
ts: 2026-10-19T12:00:00Z
---
他说要一起照顾楼下的流浪猫。
memory_import(source="markdown", path="D:\\memory-notes", dry_run=false)
纯文本文件:每个非空行一条,默认分类为“记忆”。
他说把我当朋友
手冲咖啡先按一比十五的粉水比试喝
memory_import(source="text", path="D:\\memories.txt", dry_run=false)
path 必须是本地绝对路径。单条正文超过 2000 字、日期无效等情况会在写入前报错,避免悄悄丢内容;请先拆分长文。JSON、Markdown 的解析直接复用原工具包,文本只做“逐行转 JSON”的外层适配,未重写解析器。
图怎么看
- 大小:重要度和连接数量。胞体周围有树突,关联线上有突触脉冲。
- 亮度:可视化评分中的留存。越暗表示越容易忘。
- 位置:重要知识、印象和重大情绪偏向中心;外围通常是更易淡忘的日常内容。
- 颜色:知识绿色、印象浅蓝、日记紫色、对话橙红,其他类型采用原工具包的默认配色。
- 红色虚环:提示快忘的记忆;左下角列出留存最低的复习清单。
拖动旋转、滚轮缩放、点击神经元查看正文并激活关联。图谱基于 neuron-memory-map 的脑状椭球和 Canvas 视觉;关联改为关键词倒排索引:从标题和正文提取 2~8 字片段,过滤纯数字和格式噪声,用关键词树匹配较长句子中的已提取片段;拉丁缩写只匹配完整片段。只为共享关键词的文档配对,每对最多 3 条关键词证据,boost 按这些证据累加。
关键词至少出现在 2 条记忆中;为避免泛词形成大团,DF 上限收紧为 min(总数×30%, max(2, 总数×2%)),实际 298 条时最高 DF 为 5。树突数量 min(9, 4+round(sqrt(degree)×1.2)),半径加成 min(1.4, sqrt(degree)×0.18),让连接多的节点保留大小差别。节点和边数随记忆库变化;图谱仍复用原渲染模块。
图中的评分是渲染器的视图值,留存公式没有改;关联和 boost 的输入变化会影响图中留存。agent 召回、衰减、排序和扩散仍使用记忆引擎原有公式,不会因浏览图谱改变。
数据存在哪
所有数据保存在 {DSH_HOME}/memory-engine/,默认 ~/.dsh/memory-engine/:
记忆库默认是 ~/.dsh/memory-engine/memories.json,图是 ~/.dsh/memory-engine/starmap.html,配置是 ~/.dsh/memory-engine/config.json。
记忆存储、导入和图谱生成在本机完成。自动记忆会将本轮最多 4000 字对话发送给配置的 DSH 模型服务,默认 deepseek-account / deepseek-flash;关闭 autoMemory.enabled 即停止这类调用。自动导入只读宿主会话服务和配置来源,GUI 访问本机同源路由。通用导入可能使用系统临时目录,完成后清理。
| 文件 | 内容 |
|---|---|
| memories.json | 记忆库 |
| starmap.html | 最新离线图谱 |
| config.json | 本机可选配置 |
| auto-log.json | 本地日期的自动新增、跳过、失败计数,以及最后错误和最近五条错误摘要 |
| import-ledger.json | 会话 seq 与文件增量水位 |
| sync.log | QQ 增量同步日志 |
| memories.json.bak-* | 导入/去重前的备份 |
记忆和图谱只写本机,生成过程不调用外部服务,也不需要联网。记忆正文中的网址按普通文本保留,不作为图谱资源加载。
普通用户无需配置图谱端口,也无需创建 config.json。可选的空配置为:
{}
路由不提供 memories.json/config.json 等任意文件下载,只暴露本版表格列出的页面和接口。所有响应禁用缓存;图谱页面限制为同源嵌入,不加载外部脚本或资源。原独立服务 lib/serve.js 已删除。
QQ 桥接适配器
source="qq-bridge" 是可选的私有格式适配器,普通用户导入 JSON/Markdown/text 时不需要配置它。插件不会改桥接文件,也不会代替桥接自身的存储。
适配器从 QQ_BRIDGE_DIR 环境变量取目录;未设置或无有效目录时再试本机 config.json 的 bridgeRoot,均不可用时给出配置提示。包内已去掉机器专属的桥接根路径。
{ "bridgeRoot": "D:/my-bot/qq-bridge-main" }
日记来源也需明确配置:QQ_DIARY_DIR 环境变量 → config.json 的 diaryDir → 跳过。例如在上面的配置对象中添加 "diaryDir": "D:/my-bot/diaries"。未配置时返回“未配置日记目录,跳过日记导入”,其他类别仍正常导入;包内不带任何用户日记路径。
memory_import(source="qq-bridge")
memory_import(source="qq-bridge", dry_run=false)
知识、印象、日记、重大情绪等来源保持既有规则。history 逐条按原始时间戳的本地日期分组:今天仅 self=false、至少 8 字,取最近 60 条;历史取情绪最强 6 条;跨文件先去重再导入。
已有桥接调度器可继续调用 scripts/sync-qq.mjs。脚本同样读取环境变量/config.json,无增量时不改库;--dry 完全不写盘。同步备份仅保留最近 5 份,sync.log 保留最近 500 行。图谱打开时按需重建,所以同步后的记忆会在下次打开时显示。
命令行和测试
在插件目录使用 Node ≥22:
node scripts/render-map.mjs
node scripts/render-map.mjs --out D:\map.html --title "我的记忆" --open
node scripts/sync-qq.mjs --dry
node --test test/*.test.mjs
通过包安装生成命令后也可运行 dsh-memory-map。测试使用隔离的临时记忆库。beta.6b 保留原有 153 项,新增 22 项导入质量回归。真实 87 条负样本默认读取本机 ~/.dsh/memory-engine/import-noise-review.json;其他机器可用 DSH_IMPORT_NOISE_REVIEW 指定该清单路径,文件不存在时仅跳过这一项私有样本测试。单独验证本次改动可运行 node --test test/import-quality.test.mjs。
本地开发安装:将本包作为目标 DSH profile 的 link 依赖,并启用同名 bundle;客户端入口已声明为 web/immediately。完全退出再打开 DSH。不要复制宿主 SDK 到包里。
文件写入仍继承原 MemoryStore 的单进程同步事务方式;多个独立宿主同时修改同一文件不提供跨进程锁。历史验收和本次截图、反向验证 HTML、文件变更清单位于相邻的 dsh-memory-engine-deliveries 目录。
许可
MIT。可以商用、可以修改、可以再发布,保留版权声明即可(见 LICENSE)。
Comments
Loading…
Similar plugins
by guyuefangyuanl
Cross-session persistent memory for the DeepSeek Harness: a model-facing memory tool, an always-on index section, and a bundled maintenance skill.
★ 3
↓ 1.5k/wk
MIT
JavaScript
Aug 21, 2026
dsh plugin --profile web add dsh-memoryby KKL08
Memory plugin with built-in curation and governance for DeepSeek Harness: 为你的 DSH 赋予可塑性记忆
★ 3
MIT
TypeScript
Oct 28, 2026
dsh plugin --profile web add dsh-plastic-memoryby ilaomianyang
Long-term associative memory for DeepSeek Harness: raw episodes, typed memory cards and entity pages in a plain-text vault you own. No auto-injection, no embeddings, no binary store.
★ 0
MIT
JavaScript
Nov 3, 2026
dsh plugin --profile web add @ilaomianyang/dsh-memory-graphby disc0nct
A persistent memory plugin for DeepSeek Harness that enables agents to store and recall information across sessions — DSH-native tools with atomic storage, validation, and concurrency-safe reads
★ 0
MIT
JavaScript
Aug 22, 2026
dsh plugin --profile web add @deepseek-ai/dsh-tool-memoryby DDDFXYqiming
Cross-session long-term memory plugin for DeepSeek Harness
★ 3
MIT
JavaScript
Oct 29, 2026
dsh plugin --profile web add dsh-layered-memoryby tianhao8687
Evidence-first long-term project memory for DeepSeek Harness (DSH), powered by MemoryOS.
★ 0
MIT
JavaScript
Aug 17, 2026
dsh plugin --profile web add dsh-memoryos