DSH HUB
HomePlugin StorePlugin PacksCommunityRankingsResourcesPublish Guide
Plugin source
Back to catalog

wudaoyu65-collab /

wudaoyu65-collab/feiyu-memory

Verified

DSH 本地纯文件记忆插件:热层/事件层/事实层/摘要层,零运行时依赖,数据不出本机。

★ 0 Stars0 Forks0 IssuesN/A Community rating0 Confirmed installs
View on GitHub
READMESource: main@7611acfa

feiyu-memory

给 DSH 的本地纯文件长期记忆插件:热层 / 事件层 / 事实层 / 摘要层,每步按 token 预算注入相关记忆。 零运行时依赖:只用 Node 内置模块(fs / path / os),不装 npm 包、不连向量库、不调外部 embedding,连抽取都是本地规则——没有一行数据离开这台机器。

A local-first, zero-dependency memory plugin for DSH. Everything is plain files under your home directory; the recall/scoring code is ~500 lines of readable JS you can audit in ten minutes.

热层 hot.md      你手写/自动维护的「每次都得知道」的事
事件层 events.jsonl  一行一条经历,带时间、重要度、情绪、存活系数
事实层 facts.json    槽位表:key → value,可失效、可钉住(换人换说法不打架)
摘要层 summary/      按天压缩过去的事件,省 token

为什么是纯文件

  • 可读可改:想改记忆直接用编辑器打开 hot.md,下次注入立即生效;想全忘光就删目录。
  • 可审计:召回打分、衰减、去重全是明文规则,不藏在黑盒 embedding 里。
  • 零成本:没有 API 调用,没有后台模型,闲置时零 token。
  • 可迁移:一个目录拷走就是完整记忆,换机器、换版本都在。

安装

Host-only bundle,无构建步骤:

  1. 把本仓库放到任意目录(绝对路径,避免中文/空格更稳)。
  2. DSH → 设置 → 插件 → 安装 bundle,目标目录选本仓库根目录。
  3. 重启 DSH(插件代码变更需重启才会加载新模块)。

也可以在命令行登记进某个 profile:

node tools/install-profile.mjs
# 默认 ~/.dsh/profiles/desktop,可用 DSH_PROFILE_DIR / DSH_PROFILE 覆盖

脚本会做三件事(幂等、先备份 package.json):写 link: 依赖、把 feiyu-memory 加进 dsh.profile.bundles、在 node_modules 下建 junction。

注意:某些受限 profile / 会话预设不带 plugin_manager 权限,安装这一步要在桌面 UI 或权限完整的会话里做。

数据目录

默认 ~/.dsh/feiyu-memory/:

~/.dsh/feiyu-memory/
├── hot.md          # 热层:手改立即生效
├── facts.json      # 事实层:槽位表
├── events.jsonl    # 事件层:一行一条
├── summary/        # 按日摘要 YYYY-MM-DD.md
├── config.json     # 配置,缺省即默认
└── feiyu.log       # 出错日志(最多 200 行)

想放别的盘:cordis.patch.yml 里打开 dataDir,或在 config.json 里写 dataDir。 怎么全忘光:删掉整个目录即可,下次启动自动重建空库。

配置

优先级:行 config(cordis.patch.yml)> data/config.json > 默认值。

键 默认 含义
enabled true 关掉后不注入
injectTokenBudget 1200 每步注入预算(按字符 ×4 估算)
recallLimit 3 最多命中几条事件
minScore 0.35 证据分门槛
eventHalfLifeDays 30 普通事件半衰期
emotionalHalfLifeDays 7 情绪浓的事件半衰期
emotionalThreshold 0.6 多浓算「情绪浓」
hotMaxChars 800 热层截断上限
summaryEnabled true 是否做按日摘要
disableExtract false true 时只写不抽(隐私敏感场景)
extractModel heuristic 预留位,本插件不调远程模型
dataDir "" 覆盖数据目录
viewHttp true 是否起面板数据服务
viewPort 17654 数据服务起始端口

工具

工具 作用
feiyu_remember 写一条记忆(event 经历 / fact 长期事实)
feiyu_recall 按关键词检索,返回热层/事实/事件片段
feiyu_forget 标记遗忘(markSuperseded,不硬删,可追溯)
feiyu_stats 事件数 / 事实数 / 热层字数 / 数据目录

侧边栏面板

同一包里带客户端半边:client.js 注册一个全局面板(布局 root 作用域 main keyed slot,key = feiyu-memory), 并在 sidebar.panellist 里挂一个「记忆」图标。

面板用 Canvas 2D 手写(无 d3):

  • 力导向布局:斥力 + 弹簧 + 中心引力 + 碰撞 + 垂直漂移(decay 高上浮、衰减下沉),alpha 收敛到 0.02 停
  • 视觉编码:hot #FFD166 / fact #9B7BFF / event #4DD4E8 / summary #6B7A8F,半径 6+weight*10,透明度 0.25+0.75*decay,辉光 8+decay*16,贝塞尔边
  • 交互:悬停高亮 1 跳邻居、点击出详情卡、拖拽钉住 3 秒、滚轮缩放 0.3–3x、拖空白平移、搜索过滤、四层开关、时间轴双端滑块、重置视角
  • 召回脉冲:pre-step 命中时从 hot 沿边放白色光点
  • 降级:节点 > 600 或帧率连续低于 45fps → 关辉光/贝塞尔/标签

Host ↔ Client 通道(V1:回环 HTTP)

没有用 DSH 的 Typert Remote(那套要 TS 装饰器在编译期写原型上的描述符,纯 JS 手搓容易碎)。 V1 由 Host 起一个只绑 127.0.0.1 的小 HTTP 服务,端口从 viewPort 往后试 10 个:

路径 方法 作用
/graph GET 全量 nodes / edges
/stats GET 事件数 / 事实数 / 热层字数 / 数据目录
/hits?since= GET 上次之后的召回命中 id(脉冲用)
/forget POST 标 superseded
/pin POST 钉住 / 取消(事件与事实都支持)

安全边界:只绑回环、CORS 只放行 DSH 页面来源;但本机任何进程都能读这个端口,介意的话把 viewHttp 关掉。

面板数据每 2 秒轮询,没有推送;规模上万节点再换 SSE。

工作原理

环节 接口
每步注入 agent.ctx.systemPrompt.context({name, order, text}),宿主按步重算,内容不变自动不重复提交
取当前提问 agent.ctx.on('agent/pre-step', (payload, next) => next()) 只读捕获,不改消息
轮次收尾固化 agent.ctx.on('agent/turn-stopping') → 异步规则抽取 → 写 events / facts
挂到 agent ctx.on('agent/created', ({ agent }) => ...)
工具注册 ctx.tools.register(...) ×4
遗忘 markSuperseded 不硬删

召回打分(src/recall.js):

sim   = 提问 token 的 idf 加权覆盖率(不是 Jaccard)
decay = 0.5 ^ (天数 / 半衰期)        # 情绪浓的事件换更短半衰期
s     = sim × decay × importance
C     = 1 - e^(-3s)                  # 指数饱和,比 s/(s+2) 够得着门槛
命中条件:C ≥ minScore

设计取舍(实测后改的,写在这里免得后人再踩)

  1. C = s/(s+2) 数学上够不到 minScore = 0.35:s ∈ [0,1] 时 C 上限只有 1/3,已改为指数饱和 C = 1 - e^(-3s)。
  2. 相似度用加权覆盖度(intersection / 提问侧 idf 总量),不用 Jaccard:提问短、事件长时 Jaccard 天然偏低,会把真正相关的事件压死。
  3. 抽取默认不调模型:逐轮调 LLM 会持续花钱;默认本地规则抽取,extractModel 只留位。
  4. 注入走动态上下文,不往 decision.messages 里塞 user 消息:后者会把记忆写进会话日志,越长越贵。
  5. 用户文本先洗信封:聊天桥接常把「【当前时间】…(时区)【角色】」拼在消息前面,抽取前剥掉,事件库才不被时间戳污染。
  6. 24 小时内相同文本的事件自动去重,否则同一句话会被反复记。

隐私

  • 所有记忆都是你机器上的纯文本,插件不发起任何网络请求(面板服务只绑 127.0.0.1)。
  • 仓库里不含任何个人记忆数据:data/ 整个目录在 .gitignore 里,发布版从零开始建库。
  • 想彻底不留痕:删 ~/.dsh/feiyu-memory/;想只写不抽:disableExtract: true。

自检

npm test                          # 全部
node test/selftest.mjs            # 内核 28 项,生成 SELFTEST.md
node test/polish-test.mjs         # 精修 15 项:信封清洗、事实失效/钉住、去重、面板写接口
node test/view-selftest.mjs       # 图模型 + 面板数据服务 19 项
node test/apply-sim.mjs           # 假 ctx 演练钩子接线

测试全部用 os.tmpdir() 下的临时目录,不会碰你真实记忆库。

目录结构

index.js            Host 入口:钩子接线 + 4 个工具
client.js           面板(Canvas 2D 力导向图)
src/store.js        文件读写、原子写、日志
src/config.js       配置合并与默认值
src/event.js        事件层:写入、去重、衰减、命中
src/fact.js         事实层:槽位、失效、钉住
src/hot.js          热层
src/recall.js       检索打分
src/inject.js       注入文本渲染(按 token 预算截断)
src/extract.js      本地规则抽取(记不记 / 抽成什么)
src/summary.js      按日摘要压缩
src/graph.js        面板图模型
src/viewhost.js     127.0.0.1 数据服务
test/               自检脚本
tools/              安装与数据清洗小工具

License

MIT

—/ 5

No ratings yet

Verified DSH bundle

Commit 7611acfa2dd5

Community comments

No comments yet. Be the first to write one.

DSH HUB

A community index for DSH plugins. Not an official GitHub or DeepSeek AI product.

CommunityResourcesAPIAbout