DSH HUB
HomePlugin StorePlugin PacksCommunityRankingsResourcesPublish Guide
Plugin source
Back to catalog

masquerator-coder /

masquerator-coder/dsh-memory

Verified

Deepseek Harness memory plugin

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

dsh-memory

DeepSeek Harness 的三层凝练记忆插件(Cordis 插件,bundle-declarative,零 npm 运行时依赖)。它以工作 / 情景 / 语义三层存储组织记忆,用双信号热度(指数衰减 + 召回频率)衡量"这条还活跃吗",以三级阶梯主动遗忘做磁盘与上下文的熵管理——核心存、查、写、热度、遗忘全程零 LLM,纯函数 + 规则,稳定可靠。


一、设计思路

1.1 为什么做三层(演进动机)

早期方案只有"语义事实"一张表,存在四个缺口:

  1. 缺情景层——只记录"事实",不记录"发生过什么"。会话级摘要缺失,无法回答"当时是怎么讨论的"。
  2. 库只增不减——归档是软删,无物理删除,磁盘无限增长。
  3. 热度只看 recency——1/(1+λ·Δt)^α 只依赖最后访问时间,区分不出"过去 30 天召回 50 次"与"昨天召回 1 次"。
  4. 凝练未显式化——记忆应沿时间熵减(对话 → 事实 → 规则),早期只有去重/合并,缺"情景 → 语义"的抽取管道。

v3 对应补齐:情景层、主动遗忘、双信号热度、显式凝练管道(L0 记录落地,L1/L2 周期性运行 + 即时触发)。

1.2 三层记忆架构

层 存储 载体 注入策略 遗忘
工作记忆 不落盘 dsh 上下文窗口(宿主能力) 实时 —
情景记忆 episodes 表 会话级摘要(第一级压缩) 显式召回,不常驻 时间驱动归档
语义记忆 memories 表 稳定事实 / 偏好 / 教训 Tier0 注入 + Tier1 召回 三级阶梯
工作记忆(宿主) ──会话结束──▶ 情景记忆(episodes) ──L1抽取(周期/即时)──▶ 语义记忆(memories) ──L2去重/合并──▶ 技能(扩展预留)

三个关键决策:

  • 情景层存"会话摘要"而非原始全文——原文由 dsh 宿主 session 管理,插件不重复存。既解决"存什么",又天然完成第一级压缩,还控制磁盘增长。
  • 上限只约束"注入",不约束"存储"——海量记忆照存,进上下文必须过预算闸门。
  • 注入现算而非冻结——systemPrompt.section() 每次装配重算,天然实时 + 抗 compaction;工作记忆由宿主上下文窗口实时承担,插件不引入冻结。

1.3 双信号热度(为什么这个模型)

heat = recency_weight × frequency_boost
recency_weight  = e^(-λ·Δt)               # 指数衰减,Δt = 距 last_accessed 的天数
frequency_boost = 1 + ln(1 + window_freq) # 近 windowDays 天召回次数的对数加成

λ 由期望遗忘时间反推(λ = ln20 / forgetDays,即降到 heat≈0.05 所需天数):

kind forgetDays(默认) 半衰期 降到 heat<0.01
env(环境) 365 天 84.5 天 561 天
lesson(教训) 180 天 41.6 天 277 天
decision(决策) 90 天 20.8 天 138 天
general(一般) 60 天 13.9 天 92 天
user(用户层) ∞(免疫) 0 永不

要点:

  • 双信号分离是防误删核心:热度回答"这条现在还活跃吗"(负责排序、降级、进入遗忘候选),重要性回答"这条删得起吗"(负责遗忘的最终闸门)。
  • 召回频率 ≠ 价值:用户房贷还款日在每月 15 日 这类低频高价值事实,绝不因冷而被删。
  • 诚实标注:window_freq 是"召回命中"的代理信号,不是"被模型真正采用";固定窗口有边界效应,后续可换 EWMA 平滑。

1.4 主动遗忘(三级阶梯 + 双遗忘面)

遗忘是降级 → 软归档 → 真删,每步可回滚,双向都可审计。两个遗忘面:memories(语义层,按热度 + 重要性)+ episodes(情景层,按时间)。

语义事实真删门槛(缺一不可):

  • heat < 0.05(冷,约一个 forgetDays 未访问)且 archived = 1 且超过观察期(默认 30 天)
  • importance < 3、quality < 60(低价值、低质量)
  • layer != 'user' 且无未决纠错痕迹

免疫规则:layer=user 与 importance=5 永远免疫真删(importance=5 最多降级)。真删前落快照(forget_deleted 表),内容 + 原因可查、可回滚。

1.5 零 LLM 主循环 & Live 设置

  • 存、查、写、热度、遗忘全零 LLM(纯函数 + 规则)。核心存查循环绝不因 LLM 挂掉而退化。
  • LLM 只在凝练增强使用:L0 会话摘要(默认纯规则,可切 LLM)、L1/L2 决策式整理(周期性 + 即时触发)、情景召回摘要增强。
  • 宿主通过 ctx.settings 注册 memory 命名空间,设置面板的开关改动经 scope.watch live 热生效,无需重启。

二、功能特性

2.1 记忆工具(Agent 可调用)

memory —— 写入全局语义库(跨会话即刻可见):

{ action: list|add|replace|remove, layer, kind, tier, topic, id,
  content, importance, force }

memory_recall —— 三种范围召回:

{ query, topK?, scope? }   # scope: semantic | episodic | all(默认 all)
  • 语义层:FTS5 + CJK 子串 + epistemic × heat 加权
  • 情景层:FTS5 + 时间近因

memory_drafts(2026-09-08,事件驱动沉淀兜底)——处理 turn-end 纯规则(零 LLM)捕获的"待沉淀技术经验草稿":

{ action: list|promote|discard, id?, content?, kind?, layer?, topic?, importance?, epistemic? }
  • 背景:记忆写入触发依赖主会话(LLM)临场想起 memory add,LLM 忙(构建/调试/查证)时会忽略阶段收尾而丢失稳定技术事实。插件在每次完成的回合用纯规则探测"用户明确确认/查证根因/确定技术决策"等强信号,命中即自动留存为 memory_drafts 草稿(零 LLM、零旁路,不占模型);memory:drafts system-prompt 节在有待沉淀草稿时提示主会话。
  • list 查看待沉淀草稿;promote 对认可的草稿先查重(memory_recall)再 memory add(写入语义层,kind/layer/importance 由本调用把关)并标记 promoted;discard 丢弃草稿。
  • 草稿本身不直接入语义层——promote 是唯一转成 memory 的通道,守"写入必须闸门"。开关:设置面板「事件驱动沉淀兜底」(draftCaptureEnabled,默认开)。

2.2 设置面板(dsh 设置页「记忆」项)

设置面板注册在官方 settings.section slot,左侧导航自带神经元图标(插件自声明,无需侵入 harness shell)。可实时切换(经 scope.watch live 生效,免重启,写入 dsh 设置文档持久化):

开关 / 控件 字段 作用
记忆总开关 enabled 关 → 清洁会话(不注入任何记忆),后台整理/遗忘全停
系统提示注入当前日期 timeInjection 关 → 系统提示不注入真实世界日期节
自定义系统提示词 customPromptEnabled / customSystemPrompt 开关置于该段之前(见 §2.4b):开 → customSystemPrompt 用户自编指令逐字注入系统提示词、每个会话生效;关 → 整段不注入(即使有内容);留空亦不注入
主动遗忘 forgetEnabled 关 → 暂停降级/归档/硬删,不清理已有记忆
事件驱动沉淀兜底 draftCaptureEnabled 关 → 回合结束不再纯规则捕获待沉淀草稿(memory_drafts 工具仍可显式用)
忙闲时段抑制扫描 peakHourSuppress 关 → 任何时段都跑后台 LLM 凝练(费 API 钱)
凝练整理时间间隔(小时) refineIntervalMs 自定义 L1/L2 抽取与去重的周期扫描间隔(默认 1h,0.1h 起);改小更及时更费 API、改大更省。新会话后 10 秒内仍会即时凝练一次(不受此间隔影响)
凝练模型(R10) refineModelMode / refineModelProvider / refineModel 记忆整理(L1 抽取/L2 合并/教训升格/会话收口)所用 LLM 的路由策略。自动 = 跟随会话所用模型 → dsh 默认模型(含 cordis 显式 l1/l2/l0 路由);手动 = 固定用一个模型——下拉从 dsh 已配置模型(GET /memory/models,与 dsh 模型选择器同源的 LLM registry)里选,或选「自定义…」手填 provider/model。手动值填完整则最高优先于其余路由来源;未填完整自动回落,绝不硬降级
soul.md / user.md 编辑器 — 行内 textarea 编辑 + 保存;旁有 打开编辑 按钮——经 /memory/identity/open 用系统默认编辑器打开磁盘上的真实文件(文件仍为真相源)
教训沉淀开关 lessonDraftEnabled 关 → 纠错仍记审计、草案滞留表内,但不做升格沉淀
纠正即时判定 lessonInstantJudge 关 → 仅周期升格(默认 1h + 会话后 10s 触发),不做 replace 现场即时判定
教训用 LLM lessonUseLlm 关 → 纯规则模板升格(降级兜底,不调 LLM)

面板另有两个操作按钮:

  • 立即整理记忆 —— 点按即触发 POST /memory/trigger,不等定时扫描,立即执行 L1/L2 凝练 + 主动遗忘(绕过忙闲时段抑制,因为是你主动要求),并回显本次结果(凝练是否执行、遗忘降级/归档/删除各多少)。
  • 查看记忆 —— 打开一个弹窗(GET /memory/view),展示当前有效记忆摘要:有效记忆/会话摘要/主题计数 + 表格(层级、类型、主题、内容、重要性)。弹窗顶部可切换视图 tab(2026-09-08):全部 与 常驻区 T0——常驻区 T0 专看常驻核心(tier-0)记忆;后端保证常驻区记忆在 digest 中完整返回(此前统一 slice(0,400) 按 updated 排序可能把常驻区挤出首 400 行导致"看不到常驻区")。每行带「编辑 / 删除」按钮(人工记忆编辑,2026-09-06):编辑经 POST /memory/memories/edit 就地改内容/主题/重要度/类型(按 id 精确定位,不触发模型去重/合并启发式,只改该行);删除经 POST /memory/memories/delete,memory 层硬删并快照留痕(可回滚),user 层不可摧毁、退化为归档。

面板底部的备份区(/memory/backup/*,同受 loopback 信任模型约束):

  • 导出备份 —— 下载一个「整库」一致快照 .db(VACUUM INTO,含记忆、会话摘要、FTS 与全部审计轨,WAL 无关),可离线保存/迁移。
  • 导入备份 —— 选择一个 .db 快照替换全部现有数据;导入前先读-only 校验(非 SQLite 或缺 memories/episodes 表直接拒绝、不清空现有数据),成功后热切换连接——既有路由/工具/后台 pass 无需重启即针对恢复后数据继续工作,同时把导入前状态 VACUUM INTO 到 memory.db.pre-import.bak 供回滚。
  • 重置记忆(2026-09-06)—— POST /memory/reset,清空全部语义记忆与会话摘要(含归档/低质量)与整理/遗忘/纠错审计轨,把库回到空白态;保留 soul.md / user.md(身份文件是绑定在磁盘的独立文件,重置记忆不碰它们,语义即「重置记忆、保留我的画像」)。破坏性操作走两步确认弹窗;执行前自动把当前状态 VACUUM INTO 到 memory.db.pre-reset.bak 供误操作回滚(备份失败会在回显里显式警告「无法回滚」)。

面板另有 导出 Markdown(/memory/export/markdown,MD-EXPORT,2026-09-06,同受 loopback 信任模型约束)——分层导出全部记忆为 3 个 Markdown 档案:01-memories.md(全部语义记忆,按 状态→layer→kind→importance 分节,含已归档与低质量)、02-episodes.md(全部会话摘要,含已归档,时间倒序)、03-identity.md(soul.md / user.md 原文)。只读、零 LLM:任何时点导出一致,不触发凝练/遗忘、不改库;数据源与「查看记忆」弹窗同口径,UI 所见即所得。注册为前端 fetch 后逐个浏览器下载(不打 zip、零新增依赖)。

2.3 身份文件(soul.md / user.md)

  • soul.md:AI 人格 / 行为准则,只由人写,插件永不自动改写。
  • user.md:用户长期画像,由人手动维护(2026-08-31 权威化 → 2026-09-02 彻底取消自动维护)——与 soul.md 完全相同的人写机制。layer=user 稳定记忆继续在库中积累、供 memory_recall 召回,但不注入 Tier0(画像只经 user.md 呈现,避免双份 + KV-prefix 抖动)。

两者通过设置面板的 保存 / 打开编辑 或直接手改文件维护(<memoryHome>/memory/*.md),作为恒定 section 注入(mtime 变化才重读,KV 缓存友好),不与 memories 表混管(不该被热度/遗忘管)。Windows 写入无 BOM UTF-8。

2.4 当前日期注入(time-injection)

解决"大模型不知道自己处于真实世界哪一天"(训练截止 ≠ 现在)。会话开始时在系统提示词里预置一条当前真实世界日期 section(name: memory:time,order 5,置于大多 section 之前):

  • 日期来自互联网:后台刷新循环(默认每 15 分钟一次,timeRefreshIntervalMs)从公开授时 API 取权威 UTC 时刻(worldtimeapi.org → timeapi.io 依次尝试,单次超时 5s),再套用当前系统时区渲染成本地日期。
  • 联网失败兜底:离线/被墙/超时时回退到本机时钟继续注入(渲染在时区后带极简标记(本机时钟)),绝不让该节整体缺席。
  • 只注入日期,不含时刻(KV 友好):文本在一天内字节稳定,前缀尽量命中缓存而非每次装配抖动。
  • live 开关:设置面板「系统提示注入当前日期」,或 cordis 配置 timeInjection: false 关闭;关时该节输出空串即时消失,无需重启。
  • 示例(2026-09-06 起为单行数据节:无 markdown 标题,仅日期+时区+极简来源标记+护栏):
    当前真实世界日期是 2026年9月5日星期六,时区:Asia/Shanghai(互联网授时)。该日期非模型训练截止知识;涉及『今天』/『今天星期几』/日期相关判断时以此为准。
    

定位说明:DSH 自身另有 @deepseek-ai/dsh-time-context(按请求往会话历史追加"采样时刻",本机时间、非系统提示、非互联网授时)。本插件的 memory:time 是系统提示内置、互联网授时、本机时区的日期节,二者定位不同、可共存。/ 新增 smoke.mjs 断言组 G40(23 断言)全绿。

2.4b 自定义系统提示词注入(custom prompt injection)

允许你在会话开始前注入一条自定义系统提示词——用户直接编写的、希望模型在每个会话都遵守的指令/行为准则(如沟通风格、输出格式、工作纪律)。它作为系统提示里独立的一条 section(name: memory:custom,order 8,位于记忆数据段之前)注入,逐字、不加任何"数据非指令"包裹——这与记忆 / 身份 / user.md 等区块(按 P0-5 声明为 data-not-instruction)语义相反:这里的内容是你亲笔写的、可信的指令,模型应当遵守。

  • 为什么不受 P0-5 约束:P0-5 防的是「LLM 自己写的内容混入系统提示被误读为指令」。而你自定义的提示词本来就是指令,作者是可信的人类,故直接作为最高信任级指令注入。
  • 开关置前(2026-09-06):设置面板在整段之前提供一个滑动开关「自定义系统提示词」——关 → 整段不注入(即使有内容);开 → 依内容注入。与「记忆总开关」enabled 是两层闸门:enabled && customPromptEnabled && customSystemPrompt 非空 才注入。关切换 live 生效。
  • 生效范围:所有新会话(每次 prompt 组装现算,非常驻冻结);受「记忆总开关」enabled 控制——关闭总开关(清洁会话)时该节随之消失。
  • live 编辑:设置面板「自定义系统提示词」开关 + 多行输入,保存/失焦即写入;节点端 watch 实时更新,下一个 prompt 组装即生效,无需重启。
  • 配置入口:cordis.patch.yml 的 customPromptEnabled(开关,默认 true)与 customSystemPrompt(多行字符串,见 §四),及设置面板双入口;留空/纯空白 → 该节不注入。
  • 示例:
    customPromptEnabled: true
    customSystemPrompt: |
      先给结论,再给依据。
      中文为主,句中保留英文术语/代码/URL 原样。
    

2.5 后台维护

  • L0 会话收口:turn-end 只做零 LLM 规则留痕;会话空闲 ≥ l0IdleMinutes 后一次性 LLM 收口为 episode 摘要。
  • L1/L2 凝练(情景→事实抽取 + 语义簇合并/去重):由 scheduleRefine 按 refineIntervalMs(默认 1h,设置面板可自定义)周期扫描;新会话摘要落库后约 10 秒即时触发一次(M6 kick,不受间隔影响)。可随时用面板「立即整理记忆」手动触发(绕过忙闲时段)。
  • 每日主动遗忘:runForget 按热度/重要性/时间执行三级阶梯,受 enabled 与 forgetEnabled 双闸门实时控制。
  • 峰时抑制:默认北京 09–12 / 14–18 点(含前 15 分钟)跳过后台 LLM 凝练,省 API 费用。

2.6 关于 KV Cache(配置注意事项)

Tier0 section 每次装配现算。写入路径会按"从第一个变动的 token 起复用失效"影响前缀缓存命中:append-only 代价最小;replace/remove 位置之后的 token 全量重算。因此建议:跨会话稳定的记忆尽量在会话早期写入;频繁检索走 memory_recall(不落盘、不动 section);不要在会话中途反复改预算/开关。

2026-08-31 去重改造对 KV 的影响(正向):layer=user 记忆已移出 Tier0 注入(画像只经 user.md 恒定 section 呈现),Tier0 段落在会话间趋于稳定;新增"写时近重复合并"(findCanonical,严格门 SIM_DUP=0.85)与"跨 topic 分组"(L2 周期用 LLM 判断歧义),重复事实被合并/收敛而不是反复 INSERT——两者都让 Tier0 内容更少变动,前缀命中更稳。


三、安装方法

运行时要求:Node ≥ 22.5(依赖 node:sqlite;Node 24 才稳定)。lib/ 已提交,消费者无需任何工具链。

3.1 从远端安装(推荐)

dsh plugin --profile web add https://gitcode.com/foqiang/dsh-memory.git
# 或 GitHub 源:
dsh plugin --profile web add git@github.com:masquerator-coder/dsh-memory.git

3.2 本地开发安装

dsh plugin --profile web add file:C:/abs/path/to/dsh-memory

3.3 验证

重启 dsh 后:

# 1. 存储库初始化:
ls ~/.dsh/memory/memory.db
# 2. 新会话 system prompt 出现记忆 section
# 3. 设置 → 「记忆」面板出现(含神经元图标、记忆总开关、主动遗忘等)

bundle 安装时 cordis.patch.yml 自动作为 loader patch 应用,注入 id: memory 的实例(enableInjection: true 默认开启 Tier0 注入)。

/memory/* 路由的信任模型(安全,2026-09-02):设置面板依赖的路由——/memory/identity(GET/POST 读写 soul/user)、/memory/identity/open(打开本地编辑器)、/memory/trigger(立即整理)、/memory/view(查看记忆)、/memory/memories/edit(人工编辑单条记忆,2026-09-06)、/memory/memories/delete(人工删除单条记忆,2026-09-06)、/memory/reset(重置全部记忆,2026-09-06)、/memory/models(R10:读取 dsh 已配置模型清单)、/memory/backup/export(导出整库快照)、/memory/backup/import(导入替换全部数据)、/memory/export/markdown(MD-EXPORT:分层导出 Markdown 档案)——全部仅接受 loopback 来源,校验基于 socket.remoteAddress(传输层事实,不可被 Host/Origin 头伪造),可挡局域网客户端与 DNS-rebinding 页面,即使 webServer 绑到非 loopback 地址。面板的 soul/user 编辑器或按钮在跨源时将得到 403。请保持绑定 loopback,或在宿主侧为该组路由前置你自己的鉴权。


四、配置说明

dsh-memory 开箱即用(全默认即可)。按需在 dsh 配置中覆盖:

# --- 存储 & 注入 ---
memoryHome: <path>           # 存储目录(默认 ~/.dsh)——注意:库文件在 <memoryHome>/memory/memory.db,
                             # store 会再拼一层 memory/。想让库落在 ~/.dsh/memory/memory.db 就设 ~/.dsh,
                             # 不要设 ~/.dsh/memory(否则得到 ~/.dsh/memory/memory/memory.db)
enableInjection: true        # Tier0 常驻 section
budgetTier0: 900             # 常驻核心字符预算
budgetUser: 400
budgetMemory: 500
importanceThreshold: 3
epistemicWeighting: true

# --- 主动遗忘 ---
forgetEnabled: true          # false → 暂停降级/归档/硬删(不清理已有记忆)
forgetDays:                  # 期望遗忘时间(天);0 = 立即过冷,仍受重要性/观察期门槛保护
  env: 365
  lesson: 180
  decision: 90
  general: 60
windowDays: 30               # frequency 滑动窗口(天)
episodeRetentionDays: 180    # episodes 归档时间(天)
forgetObserveDays: 30        # 归档 → 真删观察期(天)

# --- 后台凝练 L0 / L1 / L2 ---
# 路由跟随 dsh 模型选择,勿写死:L0 缺省用会话 request-header;L1/L2 缺省按
# 会话路由 → 宿主导航模型 回退。写死而缺凭证会导致 refine 全程 degraded。留空=跟随。
l0Summarize: 'llm'           # 'llm' | 'rules'(L0 会话 → 情景摘要)
l0Provider: ''               # 显式路由(建议留空跟随)
l0Model: ''
l0MaxTokens: 400
l0TimeoutMs: 8000
l1Enabled: true              # L1 情景→稳定事实抽取(LLM 决策)
l2Enabled: true              # L2 语义簇合并/仲裁(LLM 决策)
refineIntervalMs: 3600000    # 后台整理扫描间隔(面板可自定义,live 生效)
l2MinCluster: 2
# L1 遇非 JSON/空输出先做一次纠错重试(R8)再降级;手动"立即整理"始终复活
# degraded 的 episode(R9),不受本开关影响。true=后台周期也重试 degraded。
l1RetryDegraded: false

# --- M5 会话收口 ---
l0IdleMinutes: 30            # 会话空闲 ≥ 此分钟数才一次性 LLM 收口
checkMinutes: 5              # idle 收口判定周期(分钟)

# --- M8 峰时抑制(省 API 钱)---
suppressWindows:             # 这些时段 L1/L2 后台 LLM 不跑(按 timeZone 计算)
  - start: '09:00'
    end: '12:00'
  - start: '14:00'
    end: '18:00'
suppressLeadMinutes: 15
timeZone: 'Asia/Shanghai'
peakHourSuppress: true       # false → 任何时段都跑后台 LLM

# --- M9 身份块 ---
enableIdentity: true         # 注入恒定 soul.md / user.md 身份 section

# --- time-injection:系统提示注入当前日期 ---
timeInjection: true                  # 注入真实世界日期(互联网授时 / 本机时区)
timeRefreshIntervalMs: 900000        # 互联网日期重校间隔 ms(默认 15 分钟)

# --- 自定义系统提示词注入 ---
customPromptEnabled: true              # 总开关(默认 true);false → 整段不注入
customSystemPrompt: |                # 用户自编指令,逐字注入每个会话的系统提示(§2.4b)
  先给结论,再给依据。
  中文为主,句中保留英文术语/代码/URL 原样。
  # 留空/不写 → 不注入

# --- R3-total:记忆总开关 ---
enabled: true                # false → 清洁会话,后台全部停;memory 工具保留

哪些可在设置面板实时切换(免重启):enabled / forgetEnabled / refineIntervalMs / peakHourSuppress / lessonDraftEnabled / lessonInstantJudge / lessonUseLlm / timeInjection / customPromptEnabled / customSystemPrompt / refineModelMode + refineModelProvider + refineModel(R10 凝练模型)——这些经 dsh 设置页「记忆」面板读写,settings 用户层覆盖 cordis config,改动 live 生效、写入设置文档持久化。


五、存储布局

~/.dsh/memory/
└── memory.db              # SQLite (node:sqlite), WAL
    ├── memories           # 语义事实(含 window_freq/window_start/archived_at)
    ├── mem_fts            # FTS5 语义索引
    ├── episodes           # 情景会话摘要
    ├── ep_fts             # FTS5 情景索引
    ├── failure_memories   # 纠错留痕
    ├── forget_runs        # 遗忘审计
    └── forget_deleted     # 真删快照(内容+原因,可回滚/可查)

身份文件(不进 memories 表):<memoryHome>/memory/soul.md、<memoryHome>/memory/user.md。


六、使用示例

# Agent 记入一条用户偏好(layer=user → 永生;不自动写 user.md,user.md 由人维护)
memory  action=add  layer=user  topic="用户偏好"  importance=5  content="用户偏爱简洁、结构化的中文回答"

# 记一条一般教训
memory  action=add  layer=memory  topic="部署教训"  importance=4  content="harness 推送 master:main 到 gitcode"

# 跨层召回
memory_recall  query="用户的回答风格偏好"  scope=semantic
memory_recall  query="上周关于部署的讨论"    scope=episodic

七、开发

# 一键构建:自动定位 deepseek-harness(DSH_HARNESS_ROOT 优先),从其 pnpm store
# 自动探测 esbuild / @types/react / typescript 最高语义版本(不硬编码),
# 随后 tsc 类型检查(Node + client)+ esbuild 打包 client。
node build.mjs
# 冒烟(无 dsh 也可跑,全量断言组 G1–G35)
npm run smoke   # 等价于 node smoke.mjs

提交的 tsconfig.json / tsconfig.client.json 仅为开发机 IDE 默认;构建不用其中的硬编码路径。前端 client 入口为 exports["./client"](dsh.client.platform: "web"),esbuild 打包成 window.__ModuleLoader__.load 格式(react 走 shell 单例,不打进 bundle)。


八、状态与兼容性

  • 事件驱动沉淀兜底(2026-09-08,MEMORY-TRIGGER):插件补上"写入前触发"这一记忆盲区——turn-end 用纯规则(零 LLM、零旁路)从当前回合的 user/agent 文本 + 工具集探测稳定技术事实强信号(用户明确确认/查证根因/确定技术决策),命中即自动留存为 memory_drafts 草稿(新表),即使主会话 LLM 忙到忘了 memory add 也不丢。memory:drafts system-prompt 节(仅有待草稿时非空、KV 友好)提示主会话;新工具 memory_drafts(list / promote / discard)让主会话闲时查重(memory_recall)后沉淀(promote→memory add,守写入闸门)或丢弃。草稿不直接入语义层。新开关 draftCaptureEnabled(settings 面板「事件驱动沉淀兜底」,默认开,live-toggle)。不改 memories/episodes 存储检索热度遗忘语义(与设计文档正交);不每轮 spawn LLM 旁路、无常驻进程。新增 smoke.mjs 断言组 G44(23 断言)全绿。设计定稿见 Obsidian dsh-memory/MEMORY-TRIGGER-DESIGN.md。

  • 核心闭环完成:三层存储、全局直写、跨会话召回、双信号热度、主动遗忘(三级阶梯 + 双遗忘面 + 审计 + 免疫 + 真删快照)、教训沉淀管道、整库备份导出/导入——smoke.mjs 全部断言组(219 项,G1–G35)全绿、稳定连跑,tsc 零错误。

  • 真机联调通过(2026-08-31):「记忆」设置项出现、面板控件渲染正常;curl /memory/identity 路由通;设置页关「记忆总开关」→ 新会话 agent 不再记得(live 生效铁证)。

  • 后台凝练 L1/L2:周期性运行(默认 1h,面板可自定义间隔),情景→事实抽取 + 语义簇合并/去重,受忙闲时段抑制;新会话落库 10 秒内即时触发一次;亦可面板「立即整理记忆」手动触发。LLM 降级时不退化为纯规则硬抽(标记 degraded)。

  • KV Cache:Tier0 现算,写路径会按变动位置影响前缀缓存命中(见 §2.6)。

  • 去重 + 身份权威化(2026-08-31):① 写时近重复合并 findCanonical(严格门)+ L1 同通道受益;② isNearDupCandidate token 宽松门支撑跨 topic 分组;③ crossTopicNearDupGroups 接入 L2 周期,破除按 topic 聚类边界;④ layer=user 移出 Tier0 注入 —— user.md 转人写权威(画像只经 user.md 呈现)。

  • user.md 按需加载(2026-09-02):完整画像不再内联注入系统提示(省上下文、稳 KV 前缀),系统提示仅留一条指引;模型确需了解用户画像时调用 memory_read_user 工具读取 user.md。

  • 设置面板控制面(2026-09-02):soul/user 编辑器新增「打开编辑」(/memory/identity/open 默认编辑器打开磁盘文件);新增「立即整理记忆」(/memory/trigger,绕过忙闲时段立即执行凝练+遗忘并回显结果)与「查看记忆」(/memory/view 只读弹窗);「凝练整理时间间隔」可在面板自定义(refineIntervalMs),改动 live 生效。新增路由全部 loopback 校验。

  • 教训沉淀管道(2026-09-02,DESIGN docs/lesson-pipeline.md):replace/合并冲突 触发 recordFailure 时,零 LLM 即时双写 lesson_drafts 草案(同 memory 纠正聚合 draft_count);后台周期(默认 1h)+ replace 现场即时(lessonInstantJudge)两条通道经 LLM 判定(wrong-original / stale → 升格 kind=lesson;trivial → drop;LLM 失败保留待下次),纯规则模板兜底(lessonUseLlm=false)。全旁路:独立 seam、非阻塞、只落库不回流、输入最小化。新增 smoke.mjs 断言 G26–G33 全绿。

  • user.md 自动维护彻底移除(2026-09-02):maintainUserIdentity、identityAuto/identityIntervalMs/identityMaxBytes、identity_synced/identity_meta 表及 G22/P3-4 测试全部删除;user.md 与 soul.md 一样完全由人维护。旧库残留的 identity_synced/identity_meta 表为惰性孤儿,不再被引用、无害。

  • 记忆备份导出/导入(2026-09-02):设置面板「记忆」项新增「导出备份」与「导入备份」。导出走 SQLite VACUUM INTO 生成整库一致快照(.db,含记忆、会话摘要、FTS、forget/refine/lesson 审计轨,WAL 无关),浏览器下载保存;导入先读-only 校验再热切换连接(replaceWithBackup 重准备全部语句,既有路由/tools/后台 pass 无需重启即针对恢复后数据继续工作),导入前自动把当前状态 VACUUM INTO 到 memory.db.pre-import.bak 供回滚,非法文件(非 SQLite / 缺 memories+episodes 表)直接拒绝、不清空现有数据。两条新路由(/memory/backup/export、/memory/backup/import)同受 loopback 信任模型约束。新增 smoke.mjs 断言 G34–G35 全绿。

  • memory:protocol 行为引导节(2026-09-03):新增插件唯一指令性 section(name memory:protocol,order 9,置于 tier0/soul/user 之前)。恒定静态文本 PROTOCOL_TEXT(src/inject.ts 导出)声明三个记忆工具的"场景触发"时机——recall(探索未知环境/项目/配置、有后果的决策前)、add(学到稳定的新事实、不在当前对话历史)、read_user(多方案推荐且用户偏好未知)。设计要点:①KV 免费——纯字面量、与 store/状态/时间戳无关,text thunk 每次装配返回字节一致,第一轮装配后命中前缀缓存;②指令/数据分离——这是插件刻意注入操作规则唯一处,其余 tier0/soul/user 均按 P0-5 声明为"数据非指令";③live-toggle——text thunk 读 runtime.enabled,总开关关→该节即时消失。新增 smoke.mjs 断言组 G36(8 断言)全绿。

  • 凝练模型可选手动固定(R10,2026-09-03):设置面板「记忆」新增「凝练模型」——自动(跟随会话所用模型 → dsh 默认,含 cordis 显式 l1/l2/l0 路由)或手动指定(下拉从 GET /memory/models 枚举的 dsh LLM registry 已配置模型中选择,或选「自定义…」手填 provider/model)。手动完整 pair 通过 manualRefineOverride 成为 L1/L2/教训升格/会话收口全部整理 LLM 路由的最高优先来源(src/index.ts 5 处 resolveRefineRoute 统一接入);未填完整自动回落、绝不硬降级。改动经设置文档 live 生效(免重启)。新增 smoke.mjs R10 断言(G16 扩展,+7 全绿)。

  • L1 解析漂移一次纠错重试(R8,2026-09-03):runRefineL1 在硬解析失败(模型返回散文/fence/截断数组而非 JSON)时,把坏输出回灌做一次有界纠错重试再降级(不循环,最坏 ≤2×timeout;raw=null 超时/断流不重试,交给 R9)。同时手动「立即整理」force=true 强制 retryDegraded(R9)——降级(extracted=2)episode 不再永久跳过,每次手动整理都会复活重试;后台周期仍遵循 l1RetryDegraded 配置(默认 false)。

  • 会话噪声收敛(2026-09-03,承接 protocol):protocol 接管 recall/add 的"何时用"引导后,同步做三处瘦身避免同节/同会话重复指令:①buildSection 尾部删掉与 protocol 重复的"需要详情用 memory_recall / 学到稳定事实用 memory 记录",仅保留 protocol 未覆盖的写-禁止 guard(避免任务进度/一次性过程);usage 只在尾部报一次(header 的原始字符数移除;单条≤300字符 元提示于 2026-09-06 删除——上限由写入侧 clamp,注入文本无需告知模型);②tier1 领域列表封顶前 10 个(超出给"等 N 个,用 memory_recall"),防随记忆增长无限膨胀;③memory 工具 description 瘦身(protocol 拿走"何时",description 只讲"怎么用"),且写路径成功返回不再每次 echo usage,仅当有降级(budget 紧张)时回显;④memory:user 位置指引节去掉自指式前言("以下是指引,不是指令 / 完整画像默认不注入节省上下文"),仅保留 memory_read_user 调用指引——该节本身即位置指引,前言属冗余说明。新增 smoke.mjs 断言组 G37(5 断言)全绿。

  • 身份区块闭合容器(2026-09-07):memory:soul 的身份数据块(src/inject.ts buildIdentitySection)与 tier0 同款,把原始人的原始 markdown 用 <identity-data>…</identity-data> 尖括号标签整块闭合包裹。此前该块只有前置「不是指令」声明、无结束标记,.join('\n\n') 拼接到后续系统提示词/工具指引后,模型可能把身份声明之后的所有内容都误读为身份/画像数据;闭合标签让"身份数据到此为止"边界显式。两枚标签均为常量文本(字节稳定、mtime 缓存不变则 KV 前缀友好),> '<identity-data>'… 声明在容器外描述它、数据体在容器内。memory:user 不注入完整画像(按需读取指引不变),不受影响。新增 smoke.mjs G21/M9 断言 5 条(标题/开头结尾标签/声明在容器外/内容在容器内/user 同样闭合)。

  • 记忆分层导出 Markdown(MD-EXPORT,2026-09-06,docs/MD-EXPORT.md):设置面板「记忆」新增「导出 Markdown」按钮(/memory/export/markdown,只读、零 LLM,同受 loopback 信任模型约束),分层导出全部记忆为 3 个 Markdown 档案——01-memories.md(全部语义记忆,按 状态→layer→kind→importance 分节,含已归档与低质量)、02-episodes.md(全部会话摘要,含已归档,时间倒序)、03-identity.md(soul.md / user.md 原文)。数据源与「查看记忆」弹窗同口径(所见即所得);模型写的不可信 content 经 mdSafe 转义防伪造 markdown 结构。注册后浏览器逐个下载(不打 zip、零新增依赖)。新增 docs/MD-EXPORT.md 设计稿 + smoke.mjs 断言组 G41(20 断言)全绿。

  • 注入默认值收敛 + FAIL 文案 + 三项审计修复(2026-09-07):①「自定义系统提示词」(customPromptEnabled)与「系统提示注入当前日期」(timeInjection)默认值改为关闭(三层:settings floor / Config schema default / runtime 回退统一 false,用户仍可在设置面板手动开启);②memory 工具溢出拒绝文案改为指向真实触发原因(仅常驻核心 importance≥5 占满、demote 无法腾出时才拒绝,普通 <5 记忆本会降级保存)并给可操作引导;③M1 给 user-authored memory:custom 注入加 CUSTOM_CAP(8000)硬上限(新增纯函数 clampCustomPrompt,其余注入皆有预算闸门、唯此缺失);④M2 validateBackup 除表存在外增加 memories 关键列结构校验(PRAGMA table_info),拒收「同名表但缺列」的畸形/异构备份,防热切换后 rowToEntry 强转读到垃圾值;⑤L1 抽出单点 sqlPathLiteral 复用三处 VACUUM INTO 路径转义(SQLite 不支持参数绑定,转义必须内联)。新增 smoke.mjs G43 断言 9 条全绿。

  • 审计三项真缺陷修复(2026-09-07):对一份 13 项问题清单逐条核对代码后,落地其中 3 个确凿缺陷—— ①过期 window_freq 不再抬高热度(src/heat.ts heatOf):此前频率信号只看存储的 window_freq,而 touchAccess 只在下一次召回命中时重置窗口,窗口过期本身不归零——窗口内高频、此后长期冷的条目 freq 卡高位,抬高 heat、挡住降级(general 60d:100 次召回后 90d 安静 → heat 0.063,本应 0.0112)。修复:heatOf 增可选 windowMs 参数,当 window_start>0 且窗口已过时按 freq=0 计;shouldDemote/shouldArchive 同步透传,store 各处经 windowMs()(= windowDays*DAY_MS)显式启用。无 window_start/未传 windowMs 时保持旧行为(现有 3 参调用不受影响)。 ②预算闸门与注入闸门口径对齐「方向 A」(src/store.ts enforceBudget + src/inject.ts buildSection + src/types.ts):此前 enforceBudget 把所有 kind 计入 memory 预算桶,而 buildSection 只注入 kind∈{preference,env}——不受注入的受保护 lesson/decision/general(importance≥5)占预算、甚至能把本该注入的 preference/env 挤出导致溢出拒绝。修复:抽共享谓词 isInjectableKind(types.ts 单一来源),buildSection 与 enforceBudget 同用;memory 预算桶改核算 injectable(isInjectableKind && importance>=injectThreshold,阈值经构造器从 index.ts 传入),其 squeeze 只降级可注入冷条目。不受注入的 tier0 仍计入总 tier0 存储上限、由 forgetRun 按热度处理,但不再挤占注入配额、不再触发注入溢出。 ③identity 注入无上限无转义(src/inject.ts buildIdentitySection):tier0 有 sanitize+escHtml+SECTION_CAP,而 soul.md/user.md 原文直接包进 <identity-data>——大 user.md 撑爆 KV 前缀、字面量 </identity-data> 可破坏容器(memory-entry 同类问题在 identity 路径漏修)。修复:新增保留换行的 sanitizeIdentity(只清控制符+归一化 LF+截断到 IDENTITY_CAP,不复用 tier0 sanitizeText 以免折叠 markdown 行结构)+ escHtml 转义 &<>"。新增 smoke 断言 7 条(热函数窗口归零/保留、identity 闭合标签转义/截断、② 预算口径)全绿,累计 350 断言 / 0 失败。

  • 人工记忆编辑 / 删除 / 重置(2026-09-06):设置面板「查看记忆」弹窗每行新增「编辑 / 删除」按钮——编辑经 POST /memory/memories/edit(store 新增 updateMemory)就地改 内容/主题/重要度/类型,按 id 精确定位、不触发模型去重/合并启发式,只改该行且保留档案身份(id/创建时间/热度);删除经 POST /memory/memories/delete(deleteMemory),memory 层硬删并快照进 forget_deleted 留痕(可回滚),user 层不可摧毁自动退化为归档。备份区新增「重置记忆」按钮(POST /memory/reset,resetStore)——两步确认弹窗后清空全部记忆/会话摘要/审计轨、保留 soul.md / user.md,执行前 VACUUM INTO 到 memory.db.pre-reset.bak 供回滚(备份失败显式警告)。三条新路由同受 loopback 信任模型约束。新增 smoke.mjs 断言组 G42(23 断言)全绿。

  • 记忆数据块闭合容器(2026-09-06):memory:tier0 的 Persistent memory 记忆数据块再用 <memory-data>…</memory-data> 尖括号标签整块闭合包裹(src/inject.ts buildSection)。此前该块只有前置「数据非指令」声明、无结束标记,.join('\n\n') 拼接到后续 soul.md / user.md / 系统提示词后,模型可能把记忆声明之后的所有内容都误读为记忆记录数据;闭合标签让"记忆数据到此为止"边界显式。两枚标签均为常量文本(字节稳定,KV 前缀友好),结束标签恒定置于 SECTION_CAP 截断文本之后保证容器闭环。新增 smoke.mjs G37 断言 3 条(开头/结尾标签 + 声明在容器内)全绿。


设计文档

  • docs/DESIGN.md —— v3 设计稿(设计哲学、双信号热度推导、主动遗忘门槛、凝练管道)。
  • docs/REFINE-REDESIGN.md —— 凝练管道重构方案(L0/L1/L2 触发与降级)。
  • docs/MD-EXPORT.md —— 记忆分层导出为 Markdown 的设计方案(分层文件布局、格式、路由、测试)。
—/ 5

No ratings yet

Verified DSH bundle

Commit 552feeec38d6

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