dsh-hindsight-memory

DSH PLUGIN记忆与知识

仓库 meisijiya/dsh-hindsight-memory

记忆与知识 L5 · 运行验证通过 安全审查:低风险 可信度:金 可安装插件
安装这个插件

DSH 插件:把 Hindsight 记忆服务接到 DeepSeek Harness,与 omp 共用同一记忆库/同一套标签语义(单库 + 全局层/项目层双层标签),模型只看见封装后的语义化工具

一句话选型结论

按资料字段整理

dsh-hindsight-memory 是记忆与知识类的 DSH 可安装插件,验证等级 L5 · 运行验证通过,安全审查为低风险,有可直接复制的安装命令。验证通过不等于安全:插件会读写文件、执行命令或联网,装前先到仓库确认它做了什么;涉及密钥或系统权限的,建议先在隔离环境试装。

分类记忆与知识 收录类型可安装插件 验证等级L5 · 运行验证通过 安全审查低风险
验证等级 L5 L5 · 运行验证通过
GitHub 星标 0 复刻 0 · 未关闭 issue 0
最近更新 2026-10-27 创建于 2026-10-22
README 39.4 KB 正文体量,越大说明说明书写得越细

安装

可安装插件
在 DSH 里执行,装完用 dsh plugin list 确认已挂上;标了 L4 / L5 的命令已在沙盒里真实跑通
dsh plugin --profile web add github:meisijiya/dsh-hindsight-memory#v0.4.0
  1. 1
    确认版本与运行环境

    仓库没有标注兼容版本与 Node.js 要求,先确认你的 DSH 版本能装,再继续。

  2. 2
    执行安装命令

    在 DSH 里执行上面的命令;多包仓库要注意区分具体子包名,别装错包。

  3. 3
    确认已挂载

    用 dsh plugin list 查看列表里是否出现这个插件,出现即挂载成功。

  4. 4
    试跑并检查权限

    加载后跑一个最小用例,确认它能正常工作;同时看它申请了哪些文件、命令或网络权限。

兼容 DSH 版本未标注版本不匹配时安装会报错
Node.js 要求未标注来自仓库 package.json 的 engines 字段
前置依赖无需要同时安装的同级依赖
npm 包名未发布到 npm可用 npm view 查看包信息

能做什么

记忆与知识
字段来自项目仓库与公开索引,中文说明由本站标注

适用场景

记忆

上游标签

dsh-plugin

验证等级与安全审查

L5 · 运行验证通过
自动化流程结论,不是人工审核
验证等级L5 · 运行验证通过在 dsh 沙盒中完成安装与运行冒烟——装得上、跑得起来
安全审查低风险静态分析结论,未标注不代表已通过审查
仓库健康度活跃按仓库活跃度与最近更新时间给出
可信度金综合仓库活跃度与验证结果

选择建议

装之前先看这几条
按条目字段给出的判断,不替你决定用不用

值得选的地方

  • 验证等级 L5:安装和运行都在沙盒里跑通过,装完能直接用的概率高。
  • 静态安全审查为低风险,没有发现明显可疑行为。
  • 有可直接复制的安装命令,不用自己翻文档找入口。

先想清楚的地方

  • 没有声明 Node.js 版本要求,版本不匹配可能装不上。
  • 验证通过不等于安全:插件会读写文件、执行命令或联网,装前先到仓库确认它做了什么。

更适合

  • 需要在记忆与知识场景里给 DSH 补能力的人。
  • 想装完就能用、不想自己排依赖的人。
  • 能接受在本地装依赖、愿意自己确认权限的人。

不太适合

  • 只使用 DSH 官方内置能力、不接受第三方插件的人。

同类对比

6 个同类
同分类里挑最接近的几条,字段以各自详情页为准
插件验证等级安全审查星标兼容版本安装命令
dsh-hindsight-memory当前 L5 · 运行验证通过 低风险 0 未标注 有
ruflo L3 · 安装规范通过 低风险 7.4 万 未标注 无
OpenViking L3 · 安装规范通过 低风险 3.9 万 未标注 无
WeKnora L4 · 沙盒安装通过 低风险 3.3 万 未标注 有
distilly L4 · 沙盒安装通过 低风险 2.5 万 未标注 有
EverOS L4 · 沙盒安装通过 低风险 1.3 万 未标注 有

仓库档案

记忆与知识
字段来自项目仓库与公开索引,中文说明由本站标注
作者 / 维护方meisijiya仓库 dsh-hindsight-memory · 默认分支 main
分类记忆与知识memory
收录类型可安装插件声明了 dsh.bundle、可用 dsh plugin add 安装的条目
开发语言未标注仓库主语言
许可证MIT商用或二次分发前请确认条款原文
星标 / 复刻 / issue0 / 0 / 0收录时的数值,非实时
创建 / 更新2026-10-22 · 2026-10-27最后推送 2026-10-27
本站收录2026-10-30首次进入本站目录的时间

README 全文

39.4 KB
作者原文,中文版优先;只做安全转义,不改内容

dsh-hindsight-memory

DSH ⇄ omp 记忆行为对齐插件(中间层)

把「模型说的话」翻译成「omp 也会做的同一件事」:同一个 Hindsight 记忆库、同一套标签语义、同一套分层、同一套过滤规则。


它解决什么

现状 痛点
DSH 用 dsh-mnemon 的 Hindsight provider 写侧能打标签,读侧不能按项目过滤(search() 请求体里没有 tags)⇒ 读的是整库
omp 用官方原生 Hindsight 后端 读侧按 project: 过滤,读不到别的项目;但它产不出无标签的全局层
两边各写各的 同一个记忆库里标签规则不统一 ⇒ 写着写着就互相看不见

本插件把 DSH 侧换成受控的中间层:模型只看见 4 个语义化工具,标签与记忆库路由由插件自动处理,模型碰不到 tags、碰不到 bankId。

模型 ──▶ memory_recall / memory_retain / memory_reflect / memory_status
│  (插件盖章:project:<小写仓库名> 或 无标签)
▼
Hindsight 记忆库 `mem-<项目名小写>`
▲
│  (omp 原生后端:自动盖章 + 自动过滤)
omp

九个工具

工具 作用 与 omp 的对应
memory_recall(query, scope?) 召回长期记忆。scope=project(默认)= 本项目 + 全局;project_only = 只本项目;global = 只全局 omp 的 recall
memory_retain(content, tier?) 写入耐久事实。tier=project(默认)只有本项目可见;tier=global 所有项目可见 omp 的 retain
memory_reflect(query, scope?) 让记忆服务综合回答(不是返回原始条目) omp 的 reflect
memory_status() 连通性、当前记忆库(含 bank 体检告警)、项目标签、各层条数与类型分布、任务队列健康度 omp 无(诊断用)
memory_hygiene(action?, scope?) 整理共享记忆库:预览/清理近重复事实、触发 observation 合并、查看分层与口径命中;维护动作 audit/retract/restore/correct/supersede(见「记忆维护」一节);scope 可锁定某一层 omp 无(见「记忆卫生」一节)
memory_mental_models(action?) 维护精神模型(跨会话的经验总结):ensure 幂等建好三个模型(用户偏好 + 本项目约定/决策),list/content/refresh/patch,以及维护动作 delete/clear/dry-run(见「记忆维护」一节) omp 启动时自动建同样的三个(见「精神模型」一节)
memory_operations(action?) 运维观测:列出抽取/刷新/合并任务,可 retry 失败任务 omp 无(但 omp 也看不见失败任务)
memory_pages(action?, id?, query?, title?, sourceQuery?) 知识页层(服务端合成的长文):list 读知识库树、search 检索、read 读整页、create 建页(自动盖本项目标签),以及维护动作 update/delete(见「记忆维护」一节) omp 无(服务端同一套能力)
memory_initiative(action?, title?, question?) 把正在做的事登记成受跟踪的一页 + 一条标记事实(页与事实互链):capture 登记、list 查看 omp 无(服务端同一套能力)

> 知识页与 initiative 是 Hindsight 服务端原生能力(/knowledge-base),本插件只是把它包成与 omp 同语义的工具:产出盖 project:<小写项目名> 标签、不复用官方的 source:/harness: 标签、写入走 async:true + metadata.session_id。可用配置 knowledgePages: false 整体关掉这两个工具。

标签是插件的事,不是模型的事:模型不传 tags,插件按 basename(主 checkout 根).toLowerCase() 盖章——与 omp 的 projectLabel() 逐字同规则。


与 dsh-mnemon 的分工(重要)

两个插件不冲突,但只有一层能连 Hindsight。当前配置是:

层 归谁 连 Hindsight? 说明
① 运行时记忆 dsh-mnemon ❌ 本地 MEMORY.md / USER.md 投影,常驻注入上下文,omp 看不到
② 项目档案 dsh-mnemon ❌ 本地 markdown,按需检索,omp 看不到
③ 记忆空间 本插件接管 ✅ 与 omp 记忆系统同层:同一个记忆库、同一套标签、同一套过滤
④ 技能管理 dsh-mnemon ❌ 技能账本,不是记忆层

> 🔴 dsh-mnemon 的 Hindsight provider 必须保持「不启用」(enabled.hindsight=false,配置保留可一键回滚)。
> 它的写侧能打标签,但读侧不支持按项目过滤(provider 0.5.6 的 search() 请求体写死 {query,budget,max_tokens,types,prefer_observations}),
> 开着它就会出现「两边都在写、但过滤规则不一致」的分裂。记忆空间组件本身不要关——关掉会让 dsh-mnemon 的检索提醒整片清空。

记忆库布局:每项目一个 bank(2026-10-27 起)

当前这台机器上的实际布局是「每项目一个独立记忆库」,bank 基名 mem,bank 名为 mem-<项目目录名小写>(如 mem-随便问问、mem-blog、mem-毕设)。

  • Hindsight 服务里存的是「记忆库(bank)」,每个库是一块独立空间,可以有多个库,服务端有 /v1/default/banks 接口可列。
  • omp 与 DSH 仍然共享同一批 bank(两端 bankId 都设为 mem,靠 base 名对齐),但项目之间不再共享同一个库。
  • 项目隔离靠库名,不靠标签:每个项目一个库 ⇒ 删除某个项目的全部记忆只需一条命令
    DELETE /v1/default/banks/mem-<项目名小写>,不会误伤其它项目;在官方前端()切换 bank 即可查看对应项目的记忆。
  • 三种作用域模式(global / per-project / per-project-tagged)由 scoping 选择,插件已全部内置,parity.js 的 computeBankScope() 与 omp 同算法。当前取 per-project。
  • 代价:跨项目通用经验不再自动共享。迁移时把旧单库里的 96 条无标签全局事实复制进了每一个项目库,所以每个项目仍能召回这些经验,但它们不再有单一真源,后续修改需同步多份。
  • 旧的单库 shared(约 2426 条事实、35 个精神模型)完整保留作为回滚点,未删除;回滚只需把两端配置改回 bankId: shared + scoping: per-project-tagged。

一句话:bank 名里的 mem = 记忆库基名;mem-<项目名> = 这个项目自己的那块记忆空间。


面板:三个层次,各管一段

面板 位置 能看/能改什么
插件管理(配置) DSH → 插件 → dsh-hindsight-memory → 详情页 →「配置」(插件自带的 client 半体渲染) 逐项查看并修改插件配置(服务地址、记忆库、作用域、预算、只读/读写、自动召回/留存…)。配置写错不会炸 profile——非法输入一律回落到默认值
插件管理(记忆看板) DSH → 插件 → dsh-hindsight-memory → 详情页 →「记忆看板」(v0.7.0 新增) 只读快照:记忆库条数与告警、全局层/项目层/其它项目层分层、事实类型分布、近重复组、体检计数(陈旧/孤儿 observation/被取代/空知识页/卡住任务)、任务状态分布、精神模型与知识页清单。可手动刷新
终端状态面板 node scripts/panel.mjs 服务健康、记忆库清单、分层条数(全局层 / 本项目层 / 其它项目层)、最近事实与其标签;项目标签按 omp 同规则自动推导,也可用 --project <名字> 覆盖
官方前端(最详细) Hindsight Control Plane:知识页、实体、关系图、原始事实、库管理

> 插件里的「配置」按钮从哪来:DSH 的插件配置表单不会自动渲染。宿主只在某个 client 半体注册了 plugins.row.config(键 = <包名>#<行 id>)或 plugins.bundle.config(键 = <包名>)渲染槽位时才给出入口。本插件的 client 半体(src/ui-client.js,浏览器经典脚本)同时注册了这两个槽位,所以详情页会出现可编辑表单。
>
> 表单要拿到「可编辑配置项」还差一格(v0.3.0 修的就是这格):宿主只会把运行中且字段被标成 volatile 的插件行投影成可编辑配置项(dsh-settings 的 volatileForm() 会把非 volatile 字段整段裁掉)。少任何一样,详情页就只写「这个插件行还没有被宿主暴露为可编辑配置项 (settings namespace 未就绪)」——插件照常工作,只是没有表单。本插件的做法与 dsh-mnemon 一致:src/schema.js 导出 LiveConfig(把基础 schema 逐字段 .volatile()),并在 loader/volatile-update 里把改动写回运行中的配置引用(宿主改的是引用里的值,不是替换对象 ⇒ 插件必须每次读当前值,否则拿到的是包装对象)。
>
> ⚠️ 改完 client 半体必须重启 DSH Web:DSH 进程在启动时解析每个包的 package.json 并把结果缓存在进程内(不随磁盘变化失效),所以「装了带 client 半体的新版本 → 刷新页面看不到配置按钮」是预期行为,重启一次即可,别去反复点开关。

> 终端面板刻意不经过模型:跨 agent 记忆的验收只认服务端原始数据,模型自述不算证据。


安装

# 从 GitHub 装(推荐;仓库即源码)
dsh plugin --profile web add "git+https://github.com/meisijiya/dsh-hindsight-memory.git"

# 或本地开发(包名会被 DSH 用 import(name) 加载;Windows 不能用裸绝对路径)
dsh plugin --profile web add "file:D:/path/to/dsh-hindsight-memory"

> 需要重启 DSH Web 才会装载。回滚:dsh plugin --profile web remove dsh-hindsight-memory。

从插件市场发现页装:DSH → 插件 → 发现 → 索引源,填本仓库的索引地址:

https://raw.githubusercontent.com/meisijiya/dsh-hindsight-memory/main/index.json

索引里锁的是精确 commit(不是浮动 HEAD);改索引只要重新拉取,不用重启 DSH。索引格式与发布流程见 docs/market-index.md。

包声明了 dsh.bundle.patch,走 bundle 路线,profile 装载时自动组合插件自己的 cordis.patch.yml。

> 🔴 运行时真源是包内默认值,不是 profile 的行配置(2026-10-28 实测):
> DSH 启动后本插件拿到的配置是空对象 —— 改 ~/.dsh/profiles//cordis.patch.yml
> 里的 hindsight-memory 行、或改包里的 cordis.patch.yml,都不改变运行时行为;
> 只有改 src/config.js 的 DEFAULTS 才立刻生效(判定实验:把 DEFAULTS 的 bankId 改成
> probedefault 后,看板立刻报 Bank 'probedefault' not found)。
> 因此本仓库把 DEFAULTS / 包内 cordis.patch.yml / schema.js / ui-client.js 四层默认值钉成一致
> (test/defaults.test.js 门禁),并要求 profile 里的行配置与之一致
> (scripts/verify-dsh-runtime-e2e.mjs 有一项检查专门比对两者)。
> 宿主将来若开始投递行配置,两边一致 ⇒ 行为不变。

配置

- insert:
- id: hindsight-memory
name: 'dsh-hindsight-memory'
config:
enabled: true          # 总开关
inject: true           # 是否注入常驻系统提示词段
writeEnabled: true     # false = 只读(灰度第一步)
apiUrl: 'http://127.0.0.1:8888'
bankId: mem              # 必须与 omp 的 hindsight.bankId 一致(当前为 mem)
bankIdPrefix: ''
scoping: per-project   # global | per-project | per-project-tagged(当前为 per-project)
types: [world, experience]     # 与 omp 的 recallTypes 同值
budget: mid
reflectBudget: low
maxTokens: 1024
recallMaxQueryChars: 800
autoRecall: true        # 首回合自动召回(与 omp 的 autoRecall 默认值一致)
autoRetain: true        # 回合结束自动留存(与 omp 的 autoRetain 默认值一致)
retainEveryNTurns: 3
sectionOrder: 950
hygieneThreshold: 0.9        # 近重复判定阈值(越高越保守)
hygieneMaxFacts: 500          # 单次扫描的事实条数上限
hygieneProjectMission: '只保留该项目中长期有效的技术决策、约定、硬约束与踩过的坑;不保留一次性进度、临时状态与重复表述。'
hygieneProjectMaxObservations: 40   # 项目层每个 scope 的 observation 上限
hygieneGlobalMission: '只保留跨项目长期有效的约定、环境事实与用户偏好;不保留一次性进度、临时状态与重复表述。'
hygieneGlobalMaxObservations: 30   # 全局层 observation 上限

配置写错不会炸 profile:所有非法输入一律回落到默认值(normalizeConfig 不抛错)。

> autoRecall / autoRetain 与 omp 的默认值对齐(都开)。想改成只读或纯手动,在插件配置面板里把
> writeEnabled 或 autoRetain 关掉即可,不需要改代码。

缓存稳定性(为什么提示词段是常量)

DSH 把工具 schema 放进缓存前缀:工具集合一变 ⇒ 请求头变 ⇒ 重开请求序列 ⇒ 缓存作废。所以:

  1. 工具只在装载时注册一次,任何回合都不注册/注销。
  2. 系统提示词段是编译期常量(无时间戳、无项目名、无记忆内容);关闭时返回空串而不是换文本。
  3. 变化的内容(召回结果)走用户消息,落在缓存边界之后。
  4. 绝不改共享配置对象——请求配置在宿主侧是 deepFreeze(structuredClone(...))。

详见 docs/design.md §12。

隔离分层观测(怎么验证「隔离真的按预期分层」)

node scripts/isolation-check.mjs --a "D:/26code/随便问问" --b "D:/26code/测试hindsight"

脚本用两个项目目录写三条探针(项目A 事实 / 项目B 事实 / 全局层事实),然后打出可见性矩阵,
观测完自动作废探针(--keep 可保留)。2026-10-22 实测结果(DSH 插件侧,走插件自己的读写路径):

观察者 scope A 层 B 层 全局层
项目A(随便问问) project(项目层+全局层) ✅ 可见 ❌ 不可见 ✅ 可见
项目A project_only(仅项目层) ✅ 可见 ❌ 不可见 ❌ 不可见
项目A global(仅全局层) ❌ 不可见 ❌ 不可见 ✅ 可见
项目B(测试hindsight) project(项目层+全局层) ❌ 不可见 ✅ 可见 ✅ 可见
项目B project_only(仅项目层) ❌ 不可见 ✅ 可见 ❌ 不可见
项目B global(仅全局层) ❌ 不可见 ❌ 不可见 ✅ 可见

同一结论用真实 omp 客户端复核过(读 omp 会话文件里注入的 `` 块,不采信模型自述):

omp 运行的目录 注入条数 看到的探针 看不到的探针
D:\26code\测试hindsight 16 项目B 层 + 全局层 项目A 层
D:\26code\随便问问 17 项目A 层 + 全局层 项目B 层

整库分层(87 条活跃事实)按两个目录各看一次:

视角 全局层(无 tag) 本项目层 其它项目层
随便问问 29 58 0
测试hindsight 29 0 58

> 结论:项目隔离靠标签,不靠库名;同一块 shared 库里,靠 project:<仓库名小写> 区分项目层、
> 靠「无 tag」区分全局层。DSH 与 omp 读写同一批数据、各自只看自己该看的那一层。

记忆卫生(共享 bank 层,两端同时受益)

omp 自己没有清理能力(实测:omp 二进制里没有任何去重/整理逻辑,只有 retain/recall/reflect)。
所以「记忆越写越胖、召回里出现四五条近义重复」这件事,必须由中间层在共享 bank 上做——
只有这样 omp 与 DSH 才不会行为分裂(整理一处,两端同时受益;整理在某一侧做 ⇒ 立刻分裂)。

分两层,各管一段:

层 谁在做 管什么 状态
服务端自动 Hindsight 本体(bank 级配置) observation 归纳层的口径与上限:项目层 scope 用 consolidation_strategies(口径 + 上限 40),全局层用 bank 级 observations_mission + max_observations_per_scope=30;enable_auto_consolidation=true 已在本机 shared 库启用
客户端整理 本插件 memory_hygiene 工具 + scripts/hygiene.mjs world 原始事实的近重复清理(服务端不提供 world 去重) 工具与脚本已就绪,可预览/执行
# 只读预览(默认)
node scripts/hygiene.mjs --bank shared --threshold 0.8

# 真正作废近重复事实(服务端可逆:state 改回 valid 即恢复)
node scripts/hygiene.mjs --threshold 0.8 --apply

# 顺带触发服务端合并 observation
node scripts/hygiene.mjs --consolidate

工具版:memory_hygiene(action=preview|prune|consolidate|scopes|strategies-preview),prune 默认 dryRun=true。

去重规则(三条护栏,缺一条就会误伤)

  1. 只在同一层内找重复:项目层与全局层语义不同,同文也不同义 ⇒ 分组签名 = fact_type + 标签集。
  2. 不动 observation:服务端每次 retain 会同时产出 world 原始事实与 observation 归纳事实,两者文本高度相似但语义不同;把归纳层当重复删掉=删掉归纳成果(默认跳过,--include-observations 才纳入)。
  3. 每组保留最新的一条,其余作废;作废是可逆的(PATCH /memories/{id} {"state":"invalidated"} → {"state":"valid"} 即可恢复)。

2026-10-22 实测:93 条活跃事实 → 清理 6 条近重复 → 触发 consolidation(服务端返回 deduplicated: true)→ 88 条活跃;
召回命中 14 条、近重复组 0;node scripts/verify-live.mjs 8/8 通过(分层可见性、跨项目硬隔离负例 count=0 全部复验)。

> 阈值怎么选:0.9 只抓逐字重复;0.8 能抓「同一件事换个说法」(本机这轮的真实情况);0.7 起要人工看一眼再下手。

精神模型(mental models):跨会话的经验总结

精神模型是 Hindsight 的第三层记忆:服务端用 LLM 从事实层归纳出的一份长期画像文档,
客户端负责确保它存在、并把正文注入会话提示。omp 启动时幂等建三个,本插件对齐同样的三件套:

模型 标签 作用
user-preferences 无标签(全局层,所有项目可见) 用户的长期偏好
project-conventions 项目层 本项目的约定
project-decisions 项目层 本项目的决策

id 与 omp 完全相同 ⇒ 两端共用同一份模型(2026-10-27 起)。
id 规则随作用域变化,与 omp 逐字对齐:

作用域 id 形态 理由
per-project / global 裸 id(project-conventions) bank 已按项目隔离(或全局唯一),id 不需要再带项目名
per-project-tagged 裸 id + 项目 slug 后缀(project-conventions-blog) 单 bank 标签分栏,需要在 id 里区分项目

> 🔴 为什么必须两端同名:omp 注入精神模型时只按 scope 过滤、不按 id 过滤
> (loadMentalModelsBlock 传的是 recallTags;per-project 下为空 ⇒ bank 里每个模型都注入)。
> 两端各建一份同语义模型 ⇒ 上下文里出现两份「Project Conventions」,
> 并把渲染预算(hindsight.mentalModelMaxRenderChars,默认 16000 字符)吃光、
> 触发 [mental-model snapshot truncated at render budget]。
> 实测(切换前):同一 bank 里 7 个模型被注入,标题「Project Conventions」出现两次。
> 统一后:4 个模型、无重复。
>
> 本插件的注入过滤也改成与 omp 同规则(parity.js 的 mentalModelVisible():只按 scope 过滤,不按 id 白名单),
> 否则自定义模型(例如手写的架构文档)在一端可见、另一端不可见。

> ⚠️ 服务端 POST /mental-models 是仅创建:重复 id 返 409 且不改写已有 tags。
> 所以插件的做法是「缺就建、标签不对就 PATCH、对的就原样保留」——planEnsure() 干这件事。
> 两端同时启动时,第二个端拿到 409 就跳过(模型已存在且就是它要的那份)⇒ 不会互相覆盖。

# 插件工具:memory_mental_models(action=ensure|list|content|refresh|patch)

实测(2026-10-27,per-project 作用域):ensure 返回 created:0 patched:0 kept:3,
三个模型齐全且与 omp 侧同名;同一 bank 内不再有 dsh- 前缀的副本。

> mentalModelPrefix 配置项保留为可选隔离层:默认空 = 与 omp 完全同名;
> 填值(如 dsh)就在 omp 的 id 前再加一层,用于「同一 bank 内两端必须用不同模型」的特殊场景。

渲染预算:两端内容可能不等长

omp 把精神模型正文渲染成 ` 块,受hindsight.mentalModelMaxRenderChars约束 (默认 16000 字符,**在模型之间等分**,超了块尾出现…[mental-model snapshot truncated at render budget])。 本插件的renderMentalModelMessage()` 不设预算、渲染全量。

所以「共用同一份模型」不等于「两端看到的字符数一样」:模型正文够长时 omp 会被截断,DSH 不会。
模型正文越长的项目越明显(实测 mem-随便问问 无截断需 34000 字符,7 个 bank 里有 6 个在默认 16000 下被截断)。
需要两端内容对齐时,把 omp 侧的 hindsight.mentalModelMaxRenderChars 调到覆盖最长的一节
(代价:静态系统提示前缀变大)。

运维观测:失败任务不会自动重试

Hindsight 的抽取/刷新/合并任务都进 operations 队列,失败不会自动重试
(retry_count 不涨、next_retry_at 为空)。所以必须有观测手段,否则「记忆写不进去」会静默。

# 插件工具:memory_operations(action=list|retry|delete)

action=delete 是「先取消、再真删」两步:服务端的 DELETE /operations/{id} 只取消
(任务已是终态时返回 409),真删要走 DELETE /operations/{id}/delete。
所以 pending/processing 的行会先被推到终态再删掉,completed/failed 的行直接删。

memory_status 里已经带了队列体检:按状态/任务类型统计 + 最近任务的 error 与 retryCount。
实测:total 248 / processing 8 / completed 11 / failed 1,那条 failed 是探针 mental model 被删后
遗留的 refresh_mental_model(ValueError: Mental model probe-mm-测试 not found)。

> 排查「召回为空」的第一步:memory_status 里的 bank.factCount 与 bank.warnings
> ——同名空 legacy bank 会伪装成零结果,先核对 bank 名字再下结论。

知识页与 initiative(服务端原生能力,本插件只做对齐)

Hindsight 服务端自带 /knowledge-base(页 + 文件夹 + 全文检索)。本插件把它包成两个工具,
沿用与 omp 完全一致的写入纪律:

动作 落库形态 标签 写入方式
memory_pages action=create 一页(服务端按 source_query 异步合成正文) project:<小写项目名> POST /knowledge-base/pages,409 视作已存在
memory_initiative action=capture 一页 + 一条标记事实(context 里带 [[page:]] 互链) 页:project:<小写项目名> + knowledge:feature-work;事实:project:<小写项目名> 页同上;标记事实走 async:true + metadata.session_id

三条守则(与 omp 对齐的具体含义):

  1. 产出必须盖本项目标签 —— 这是 per-project-tagged 作用域下的硬要求:不盖标签的页 omp 召回看不见(它只认「无标签」或「带本项目标签」)。当前 scoping: per-project 时标签是冗余的(bank 本身已隔离),但盖上无害且便于跨模式回退时仍可判层。
  2. 不复用官方的 source:/harness: 标签 —— 那两个前缀是官方包的 provenance,混进来会让 DSH 侧按白名单过滤时把自家内容挡掉。
  3. 写操作异步 + 带 metadata.session_id —— 页正文要等服务端合成(实测几十秒到几分钟),刚建完立刻 search 可能只拿到 No content yet.。

实测(v0.5.0,bank shared):

memory_pages list      → ok, folders=[], pages=[]
memory_pages create   → ok, pageId=kp-…, operationId=41e2e487…(异步合成)
memory_pages search   → ok, count=1, snippet="No content yet."(合成未完成)
memory_initiative capture → ok, 自动建 Initiatives 文件夹 kf-…, 页 kp-…,标记事实 ok
memory_initiative list → ok, count=1, markers=[](标记事实异步落库,1~2 分钟后才有)

> ⚠️ 标记事实是异步的:capture 立刻返回 marker: {ok:true} 只代表入队成功,
> 事实真正落库要 1~2 分钟(服务端抽取 + 异步写)。刚 capture 就 list 看到 markers: [] 是正常的,不是失败。

knowledgePages: false 可整体关掉这一层(工具在 apply 时决定是否注册,见「缓存稳定性」)。

记忆维护(不只增)

Hindsight 的事实没有 DELETE 端点,只有软退役(state: "invalidated")与可回滚改写。所以「维护」不是额外功能,而是记忆系统的必需品:写错的事实如果只能靠再写一条去覆盖,旧错事实仍会参与召回,认知错位就是这么积累出来的。

维护并入既有工具的动作(不新增工具,工具总数仍是 9):

工具 新 action 作用 破坏性 需要 reason
memory_hygiene audit 只读体检:陈旧 / 被取代 / 孤儿 observation / 近重复 / 空知识页 / 卡住任务 否 否
memory_hygiene retract 软退役一条事实(state=invalidated + reason,可逆) 是 是
memory_hygiene restore 把已退役事实改回 valid 是 否
memory_hygiene correct 改写事实正文(服务端重新嵌入并丢弃派生 observation) 是 是
memory_hygiene supersede 先写入新事实,再软退役旧事实 是 是
memory_pages update 改一页的标题 / 取数问题 / 标签 / 上下文上限 否 否
memory_pages delete 删一页(不可逆) 是 否
memory_mental_models delete 删一个精神模型(不可逆) 是 否
memory_mental_models clear 清空一个精神模型的内容 是 否
memory_mental_models dry-run 预演刷新会产出什么,不落库 否 否

护栏(src/maintenance.js 的 guardAction):

  • 破坏性动作(retract / restore / correct / supersede / delete / clear)缺 confirm=true ⇒ 返回 {ok:false,error:"confirm_required"},一个服务端请求都不发。
  • 需要理由的动作(retract / correct / supersede)缺 reason ⇒ 返回 {ok:false,error:"reason_required"}。
  • 事实层的退役是可逆的:restore 能把 invalidated 改回 valid——「删错」有回头路。
  • 每条写路径都带 timestamp(本地时区)+ metadata.session_id,与 memory_retain 同口径。

配置:maintenanceStaleDays(默认 180,陈旧判定)、maintenanceStuckMinutes(默认 30,卡住任务判定)、maintenanceRequireConfirm(默认 true;不建议关)。

> 实测提醒:GET /memories/{id}/history 目前返回空数组(服务端还没记变更历史),所以「这条记忆什么时候被改的」只能看 edited_at;另外 correct 会让服务端重新嵌入该事实并丢弃它派生的 observation(宁可少一条观察,也不要留一条错的)。

三层模型:配方 / 事实 / 落后(维护能力的认知骨架)

层 是什么 谁能动 我们的工具
配方 生成快照的规则:source_query(回答什么问题)、tags(取材范围,不是标签)、trigger(何时重算)、max_tokens、name 人可改,改完下次重算才生效 memory_pages update / memory_mental_models patch
事实 bank 里的原子条目:fact_type(world / observation / experience)、tags(project:<小写名>=项目层,无 tag=全局层)、state(valid / invalidated) 只能经维护动作改 memory_retain 写;memory_hygiene 的 correct・retract・restore・supersede 改
落后 快照落后于素材的时间差:is_stale / last_refreshed_at / last_refresh_failed_at 不可直接改,只能观测 + 触发重算 memory_status / memory_hygiene action=audit / memory_operations / POST /consolidate

知识页 = 内部 mental model 的外壳(页与内部模型 last_refreshed_at 同秒、字段一致);正文永远由服务端 LLM 合成(UpdateNodeRequest 没有 body 字段)——所以「可维护」= 配方可改 + 落后可查 + 可删,不是「人能改正文」。手改正文会被下一次 consolidate 整个覆盖。

闭环:事实变 → is_stale=true → consolidate / refresh 按配方重算 → 新正文 → is_stale=false。删除知识页不可逆,且会让内部 mental model 变孤儿(后续刷新报 not found),慎用。

开发

node --test "test/*.test.js"     # 85 个单测(Windows 上不能写 node --test test/,会被当成模块解析)
node scripts/validate-market-index.mjs    # 市场索引闸门(格式 1 契约 + commit 与版本号对账)
node scripts/verify-live.mjs    # 活体自检(需要 Hindsight 服务在跑,8 项检查;per-project-tagged 口径)
node scripts/verify-live-per-project.mjs [apiUrl] [bankBase] [项目名]   # per-project 口径活体自检(9 项:写入落在独立 bank + 跨 bank 硬隔离负例)
node scripts/verify-dsh-runtime-e2e.mjs [apiUrl] [项目名]   # DSH 运行时端到端(从 dsh --dump-config 取真实配置喂插件,10 项)
node scripts/panel.mjs          # 状态面板(项目标签自动按 omp 同规则推导)
node scripts/hygiene.mjs        # 记忆卫生(默认只读预览;--apply 才作废,--consolidate 顺带合并)
node scripts/isolation-check.mjs --a <项目目录> --b <另一个项目目录>   # 两项目隔离可见性矩阵

已知差异(与 omp 的诚实账)

  • 召回注入载体是 DSH 的用户消息,omp 是 `` 背景块——形状已对齐,载体不同。
  • 自动召回结果未持久化进 session 文件,resume 会重查一次(omp 会重放缓存块)。
  • 自动留存是「本回合文本」简化版,未实现 omp 的 full-session 整段重发 + document_id=sessionId;
    节奏已对齐(每 retainEveryNTurns=3 回合一次)。
  • DSH 侧纯全局层读取需要「整库读 + 客户端过滤」(服务端没有「只取无标签」的表达)。
  • omp 自己产不出全局层(它的 retain 恒带 project: 标签);全局层目前只由 DSH 侧不传标签写入。
  • 精神模型:DSH 与 omp 各建各的(id 前缀不同、互不覆盖);DSH 侧不会去改 omp 建的模型。
  • mental model 刷新要能跑完,得同时放宽服务端三个超时(REFLECT_WALL_TIMEOUT / LLM_TIMEOUT / worker 存活),
    客户端改不了;本机已把服务端超时放宽(1800/600/600)。
  • 服务端版本:插件对齐 Hindsight 1.0 与 1.1(两版的 MCP 工具面与 REST 契约一致,recall 只多可选参数),
    所以升级服务端不需要改插件;反过来插件也不挑服务端小版本。

排障(踩过的坑,别重复踩)

症状 根因 处理
插件管理页里找不到「配置」按钮 client 半体没装载:DSH 启动时解析 package.json 的 dsh.client 并进程内缓存,之后改磁盘不会生效 重启 DSH Web(唯一可靠路径)
GET /plugins/dsh-hindsight-memory/client.js = 404 同上:该包在 client 图里没有记录 重启后应 200
插件被误关(卡片显示 disabled) 插件管理页的开关 = 增删 profile package.json 里 dsh.profile.bundles 数组里的包名 手动把包名加回 dsh.profile.bundles(依赖本身不需要重装)
升级后行为没变 git 依赖不会自动更新 在 profile 目录执行 pnpm update dsh-hindsight-memory --latest
终端面板「其它项目层」恒为 0 过滤条件把非本项目标签的事实也算成本项目 过滤应为「有标签 且 不含本项目标签」
node --test test/ 报 MODULE_NOT_FOUND Windows 上 test/ 被当成模块路径 写 node --test "test/*.test.js"
中文 bank id 报 400 / 建出乱码库 bash 内联 curl 传中文 body 会坏;URL 需 percent-encode body 写文件后 --data-binary @file;路径用 urllib.parse.quote
Hindsight 容器起不来(Unknown reranker provider: none) none 不是合法的 reranker provider 用 rrf(直通不重排)
启动日志出现 failed to import: ReferenceError: Config is not defined export { LiveConfig as Config } 只是再导出,模块作用域里没有 Config 绑定,默认导出里引用它就炸 v0.3.1 已修:默认导出写 Config: LiveConfig;并加了 test/entry.test.js 钉住"入口必须能被 import"
启动日志 dsh: warning: N entry did not activate 该插件行加载失败 ⇒ 整行静默不生效(功能全没了但没有报错弹窗) 看同一条日志里的 failed to import: 原文,它才是真线索
插件在「插件 → 发现」里整个不见了 索引里 source.commit 写了 7 位短 sha ⇒ 宿主要求 40 位小写 hex,整份索引被拒 node scripts/validate-market-index.mjs 按 FAIL 项修;详见 docs/market-index.md
想验证插件在宿主里的真实加载情况 不能重启正在服务当前会话的 DSH 实例 用 dsh headless --patch .yml "…" 旁路验证;注意 dsh --profile web 起的第二实例会和用户实例抢 3080/3081 端口

版本沿革

版本 内容
0.7.2 对齐 Hindsight 1.1 的服务端语义:memory_operations action=delete 改为「先取消再真删」(服务端 DELETE /operations/{id} 是取消、/operations/{id}/delete 才是真删,原来只打前者 ⇒ 僵尸行没被清掉);看板文档数改从 /stats 的 total_documents 取(bank 列表项本来就没有 document_count ⇒ 恒显示 0 份文档);事实新旧排序的回退链补上服务端真实字段(mentioned_at/date/occurred_start,服务端没有 created_at)。工具名与配置键未变
0.7.1 修看板通道注册失败:宿主 connection.rpc.handle() 内部要访问 owner.webServer,而 scope.get("connection") 拿到的是解析不到 webServer 的实例 ⇒ 注册抛 cannot get property "webServer" without inject(表现为通道 405)。改为 root 优先(与 dsh-rewind-plugin 一致),并补一条回归单测;另补进程 cwd 的兜底项目标签,避免无会话时分层全落到「其它项目层」
0.7.0 插件详情页记忆看板(只读):服务端在宿主 connection.rpc 通道上注册 /dsh-hindsight-memory(7 个只读端点:overview/layers/audit/operations/models/pages/config),client 半体注册 plugins.detail.section 席位渲染看板。取数走服务端代理(Hindsight 无 CORS,浏览器不能直连)。看板只读:写操作仍必须走记忆工具的 confirm+reason 护栏
0.1.0 首个可运行版本:四个封装工具 + omp 契约对齐(盖章/过滤/预算/异步语义)
0.2.0 记忆卫生层:memory_hygiene 工具 + src/hygiene.js + bank 级 consolidation 配置 + 终端面板卫生板块
0.3.0 把插件行投影成宿主可编辑配置项:LiveConfig(全部字段 .volatile())+ unwrapConfig + loader/volatile-update 热更新
0.3.1 修 v0.3.0 引入的入口 ReferenceError(默认导出引用了不存在的 Config 绑定)→ 补 test/entry.test.js 契约测试
0.4.0 对齐 omp 报告:新增精神模型层(memory_mental_models)+ 运维观测(memory_operations)+ memory_status 的 bank 体检与队列体检;memory_hygiene 支持按层 scope;写入补本地时区 timestamp + metadata.session_id;自动留存对齐 omp 的 retainEveryNTurns=3(原来每轮都写,项目层被灌到 137 条)
0.5.0 搬入知识页层(memory_pages)与 initiative 登记(memory_initiative):服务端 /knowledge-base 原生能力,产出盖项目标签、不复用 source:/harness:、写入 async + metadata.session_id;新增 src/pages.js + 13 条单测;配置 knowledgePages 可整体关掉
0.6.5 修 observation 提示在活体里失效:describeSources() 原按数组遍历,但 client.listFacts() 返回的是分页信封 {items:[...]} ⇒ 走到 observation 分支时抛 (facts ?? []) is not iterable,v0.6.4 的可操作提示在真实环境从未生效(单测用摊平数组,没暴露);现兼容数组 / {items} / {memories} 三种形状,并在同一条用例里补回归断言
0.6.4 observation 不可策展时给出可操作提示:服务端只允许策展 world/experience 事实,memory_hygiene correct 打派生 observation 时不再原样抛 400,而是返回 error="observation_not_curatable" + 中文说明 + sources[](源事实 id/tags/正文摘要),告诉你该改哪几条;新增 client.getFact(),纯函数落在 src/maintenance.js
0.6.3 MCP 会话自愈:服务端重建容器丢掉 MCP 会话后,插件旧代码会恒定 404 Session not found(整条工具链永久失效);现在识别会话失效就重置会话、重新握手并重试一次(withSessionRetry),对真实端点用过期 session id 实测 get_bank 成功;新增 test/mcp-session.test.js
0.6.2 把「超时到底是谁的」写进工具输出:memory_mental_models dry-run 失败时返回 hint(三层超时链:我们 120s→900s 的 deadline、Node 内置 fetch 的 300s 头超时、服务端 600s/1800s 预算),并指明长模型要走 refresh(异步 operation_id)+ memory_operations 轮询
0.6.1 维护层超时对齐服务端预算:新增 maintenanceTimeoutMs(默认 900000ms),服务端 LLM 长任务(精神模型 refresh/dry-run-refresh、dry-run-extract、知识页与精神模型增删改)统一用它 —— 此前客户端 deadline 只有 120s,而服务端 HINDSIGHT_API_LLM_TIMEOUT=600、reflect 墙钟 1800s,永远是我们先超时;新增 timeout() 解析器(小于下限回落默认值而非夹到下限)
0.6.0 记忆维护(不只增):记忆必须可维护,否则错事实堆积=认知错位。维护并入既有工具(工具总数仍 9):memory_hygiene 新增 audit/retract/restore/correct/supersede;memory_pages 新增 update/delete;memory_mental_models 新增 delete/clear/dry-run;破坏性动作必须 confirm=true,retract/correct/supersede 还必须带 reason(否则不碰服务端);事实层退役可逆(restore 改回 valid);新增 src/maintenance.js(纯函数、零 import)+ 15 条单测;配置 maintenanceStaleDays/maintenanceStuckMinutes/maintenanceRequireConfirm

常见问题

6 问
答案由本站依据条目字段整理,不引用上游原文
dsh-hindsight-memory 怎么安装?

在 DSH 里执行 `dsh plugin --profile web add github:meisijiya/dsh-hindsight-memory#v0.4.0` 即可。

dsh-hindsight-memory 的验证等级是什么意思?

L5 · 运行验证通过。在 dsh 沙盒中完成安装与运行冒烟——装得上、跑得起来

dsh-hindsight-memory 安全吗?

低风险。

dsh-hindsight-memory 装之前要先确认什么?

先看它会读写哪些文件、执行哪些命令、连接哪些网络地址;验证等级只说明装得上、跑得起来,不等于安全。涉及密钥或系统权限的,建议先在隔离环境试装。

dsh-hindsight-memory 用的是什么许可证?

上游标注为 MIT。商用或二次分发前请到仓库确认许可证原文。

这条记录的数据可靠吗?

本站按仓库名去重后合并整理,字段以作者仓库与 npm 元数据为准;安装命令、仓库地址与 README 保持原文,带 L4 / L5 标记的安装命令已在隔离沙盒里真实跑通。

同名或近似条目

2 条
不同作者的仓库分开列,请确认你要装的是哪一个
记忆与知识
按星标排序,可作替代方案

ruflo

ruflo

L3 · 安装规范通过 7.4 万 星

OpenViking

OpenViking

面向 DeepSeek Harness 的 OpenViking 记忆与上下文插件:pre-step 自动召回与画像注入、会话捕获、`vik

L3 · 安装规范通过 3.9 万 星

WeKnora

WeKnora

把 WeKnora 知识库接入 dsh 的四个只读工具:列出知识库、混合检索原文片段、按顺序还原单篇文档,以及直接取用 WeKnora 自己

L4 · 沙盒安装通过 3.3 万 星

distilly

distilly

Distilly — Distill how they think into reusable Skills for any Agent o

L4 · 沙盒安装通过 2.5 万 星

EverOS

EverOS

L4 · 沙盒安装通过 1.3 万 星

MemOS

MemOS

L4 · 沙盒安装通过 1.2 万 星

meisijiya 的其它插件

2 个

插件的元信息来自作者仓库;分类、验证等级与安全结论的中文说明为中文整理,最近核验 —。