Skip to content
dsh.fish
Bundle

meow-memory

Cross-session project memory for DeepSeek Harness: seven-layer SQLite memory, first-turn snapshot injection, per-message keyword hits, memory_remember/search/project tools, automatic reflection with reflection-fold UI, and idle-triggered dream consolidati

Source
Phant0Meow
License
MIT
Updated
Updated 1 hour ago

Readme

# meow-memory 🐱📝

| [中文](README.md) | [English](README.en.md) | [MIT License](LICENSE) |
| :---: | :---: | :---: |

为 [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness)(DSH)打造的跨会话记忆插件。


**核心理念**:每个工作区维护一份结构化记忆数据库(`.dsh-meow/memory.db`,基于 `node:sqlite`)。
静态记忆手册(数据总览 + 工具用法 + 写作准则)以固定 section 的形式放在 **system prompt** 里——
文本恒定,因此不会破坏 LLM provider 的 KV/上下文缓存。动态内容(soul/user 全量、设计原则、
记忆导引)作为**第一条用户消息的前缀**注入,且首轮只注入长期记忆、不做关键词命中;
从第二轮起每条用户消息做关键词命中(top-2)。模型按需用 `memory_search` /
`memory_project` 深入检索。每个窗口由自己的主 agent 在空闲时("dream")整理记忆
(本窗口建立 + 提取过的记忆),以窗口最后一次对话时间戳冻结其知识。

## ✨ 功能特性

- **七层记忆**(`soul` = AI 自身 / `user` = 用户基本信息与偏好 / `project` = 项目信息,
  含 `subcategory`(overview/structure/decisions/quotes/ops/todo)/ `fact` = 原子事实 /
  `lesson` = 教训与纠正 / `topic` = 进行中的讨论话题,带目标句 / `rules` = 设计原则与行为准则)。
  每层一张 SQLite 表,UUID 带时间前缀,id 顺序即创建顺序。
- **首轮注入(长期记忆块)**:第一条用户消息前注入固定格式
  `===== 长期记忆 =====` → `【关于你】`(soul 全量)→ `【关于user】`(user 全量)→
  `【设计原则】`(全局 rules 且 importance≥2,少而精的命令式准则)→ `【记忆导引】`
  (用法说明 + 「用户的所有 project」动态列表,供 `memory_project` 选用)。
  记忆作为独立 plugin snapshot 消息放在真实 user 消息之前,不改写用户 prompt。
  **首轮不跑关键词命中**(命中从第二轮起)。即使首条用户消息与插件通知消息同批到达
  (如 approval policy 变更通知),快照仍会紧贴插入到真实用户消息之前、命中绝不提前。
- **每消息关键词命中**:从第二条用户消息起,每条真实用户消息都检索
  fact/lesson/rules/topic(范围 = 全局 + 当前 project 锚定),top-2 命中以
  「可能相关的记忆,仅供参考:」前缀注入。命中基于**条目关键词**(LLM 提取或自动
  bigram)而非全文——全文匹配噪音大。打分 = 交集分 × idf × 覆盖率 × 艾宾浩斯衰减
  (按记忆时间戳)× importance 权重 × title 加成。
- **当前 project 锚定**:`memory_remember/search/update/project` 带 project 参数即锚定
  该会话的当前项目;未锚定时命中只搜全局(用户闲聊不误伤)。
- **缓存友好设计**:静态 `meow-memory:guide` section(order 130,紧随各 `tool:*` 说明之后)
  在 system prompt 中注册一次——文本恒定,KV 缓存友好。已见记忆(`injected` + `searched`)
  按会话记录(`.dsh-meow/sessions/<id>.json`):注入绝不重复;`memory_search` 前 5 条按相关度
  无脑取(不排除已见/本 session 建立的记忆),其余从排名后续绕开已见补齐;收到会话压缩
  信号(`compaction/*`)时释放已见记录,允许压缩后被再次命中提取。
- **压缩后重注入**:会话被压缩(手动 `/compact` 或 token 压力自动触发)后,下一个用户
  消息轮自动重新注入长期记忆快照 + 本会话此前用 `memory_project` 查阅过的项目全景 +
  本会话自己写入/更新过的记忆原文(均按最新数据重新整理)——压缩甩掉的"记性"一个回合
  就补回来,AI 不会因为压缩突然失忆。
- **工具集**:`memory_remember`(写入,必填 content/project/keywords/importance 且缺失报错引导重填,
  自动去重合并,返回读回确认:关键词/项目归属)/
  `memory_search`(BM25 × 近期权重,支持 level/project/status/days 过滤,默认 top10 = 前 5 条
  最相关不排除已见 + 后 5 条绕开已见补齐,按记忆时间戳排序;返回检索元数据视图:
  归属 + 完整 id + 相对时间 + 关键词列表,不含原文)/
  `memory_project`(项目全景注入段落:**project 参数必填**——你要看哪个项目的信息?按子标签分组、未过时条目全给、每条带完整 id 与
  最后更新时间戳、todo 输出「已完成:」最近 5 条 +「To do list:」,末尾附记忆库与
  会话历史定位说明)/
  `memory_find_similar`(查重与冲突检测)/ `memory_read` / `memory_update`(含 status
  active/archived/stale、importance、goal、keywords 手动修正)/ `memory_dream`(手动触发;
  用户也可以直接在输入框敲 `/dream` 命令)。
- **记忆时间戳**(`updated_at` = 最后更新时间):dream 封存或 `memory_update` 刷新时更新。
  展示的时间戳一律是 `updated_at`;search(工作视图)带相对时间戳,命中注入/memory_project
  (原文视图)带相对 + 绝对时间戳(如「2026-08-15 10:58 [2 天前]」)。
- **project 归属**:全局适用的信息 project 填 `"全局"`(与留空=未标记区分);同时适用于
  多个项目时用英文逗号分隔(如 `"dsh, femwa"`)——检索/命中按"包含当前项目名 或 全局"判定。
- **按窗口 dream**:窗口空闲 ≥ `idleMinutes`(默认 **180 分钟 = 3 小时**)即进入允许
  触发状态(替代原夜间窗口),每个最后发言晚于上次 dream 的窗口由自己的主 agent
  整理——分轮处理(第 1 轮原子记忆 project/fact/lesson/rules/soul/user,第 2 轮 topic
  记忆,第 3 轮项目总结——本窗口涉及具体项目时追加:调 memory_project 复查并精简成
  新的项目长期记忆,被取代的旧条目归档),project 小标题分段,每条记忆附关键词行
  (AI 核查/重写关键词用),范围=本窗口
  建立 + 提取过(注入/检索/查阅 memory_read)的记忆,使用其完整会话上下文;
  长期稳定的 rules 不反复重审(`dream.rulesReviewDays` 默认 2 天内有更新才进清单,
  防"没话找话"式更新)。**峰时抑制**(按 `timeZone` 计算,默认
  北京时间):`suppressWindows`(默认 09:00–12:00、14:00–18:00,API 峰谷电价峰时)
  及各自开始前 `suppressLeadMinutes`(默认 15)分钟内不触发,峰时结束后下一个检查
  周期自动触发;进行中的 dream 不打断。无 live agent 且超过 24h 的旧窗口、以及已归档
  的会话,均不处理。
- **`/dream` 命令**:不想等空闲触发?在输入框敲 `/dream` 立即手动唤起本窗口的记忆整理
  (与 `memory_dream` 工具同语义,不受峰时抑制)。dsh 命令平面执行、不发给模型,输入 `/`
  的补全菜单里直接可见;已有整理在进行中会明确提示,不会重复启动。
- **跳过梦境整理(client 端)**:某个窗口的记忆不想被自动整理?左侧边栏该会话行的「…」
  菜单里点一下**「跳过梦境整理记忆」**即可,再点**「取消跳过梦境整理记忆」**恢复。被跳过
  的窗口不再被空闲定时器自动 dream(`/dream` 与 `memory_dream` 手动触发不受影响),
  会话列表里显示**静音灰「月牙+斜杠」**图标、一眼可辨。跳过状态持久保存、重启不丢;
  双实例共享同一记忆库,状态天然一致。
- **反思**:单次任务内连续 ≥7 个工具 step 后,插件询问模型自上次整理以来是否有值得记忆的内容。
  最后工具是 `memory_*` 视为已主动记忆、不重复反思;被取消的轮次绝不触发。
- **注入折叠 UI(client 端)**:首轮长期记忆 / 每消息关键词命中的注入文本在前端
  折叠成「▸ 已注入记忆(长期记忆/关键词命中)」横条(与用户气泡同宽),点开可查看
  注入全文;用户 prompt 以气泡形式直接显示,消息流干净不被注入刷屏。纯文本消息才折叠
  (带附件的保持原样)。
- **反思轮折叠 UI(client 端)**:记忆反思/dream 轮的 prompt 与后续 think/tool call/汇报
  折叠成一条横条(默认折叠,显示「新增记忆 N 条」/「记忆梦境任务」),点击向下展开成
  卡片查看完整记录——卡片内 Think / tool call / 上下文注入均可点开查看细节。
- **会话列表 dream 图标(client 端)**:左侧会话列表中,"dream 整理过记忆且之后无新对话
  新信息"的会话行显示**淡黄色小月牙 🌙**;dream 轮进行中显示**白→金呼吸灯月牙**(与 dsh
  状态点并存、月牙居左,不与正常工作混淆);被**跳过梦境整理**的会话显示**静音灰「月牙+斜杠」**
  (取消跳过自动回落;优先级:呼吸灯 > 跳过 > 月牙);有新活动即移除。图标放进 dsh 会话行的
  状态槽位、状态点左侧——只追加/只移除自有节点,不改写 React 拥有的子节点(整槽替换会令
  React 虚拟 DOM 失同步,commit 抛 removeChild NotFoundError 把侧边栏整树卸载)。
  数据走全页共享的 60s 轮询 diff(v0.23.0 连接池修复,替代原 SSE 长连接):
  `/meow-memory/dreamed-sessions` 与 `/meow-memory/skip-dreams` 各一次 GET,事件语义不变——
  dream 开始推 `state:'dreaming'`、完成推 `state:'dreamed'`、有新活动推 `state:'active'`、
  跳过翻转推 `state:'skip'/'unskip'`;client 挂载时全量对账一次。
  行定位零 dsh 改动:读 React 18 fiber(`__reactFiber$` 内部属性)拿会话行渲染 key =
  session id,不依赖标题匹配。
- **dream 防重复**:check 门(DB 原子 60s 检查节流)+ start 幂等抢占(`dream_pending`)+
  中断自愈(未收尾的 dream 自动补收尾)+ 孤儿收尾(跨实例/热重载后 turn 结束也能收尾);
  插件注入轮的事件不刷新窗口活跃度——已 dream 的窗口不会反复被 dream。
- **零运行时依赖**:`node:sqlite`(Node ≥22.13 默认可用;22.5–22.12 需 `--experimental-sqlite`)+ 自包含 esbuild 产物(`lib/index.js`)。
  无原生模块。

## 📦 安装

### 一键安装(推荐)

```sh
dsh plugin --profile web add github:Phant0Meow/dsh-meow-memory
```

一条命令装完即生效:安装时自动编译(包内含 `prepare` 脚本),自动挂载,重启 `dsh web` 后新会话自动加载插件。

> pnpm ≥10 默认会阻止安装期的构建脚本:首次 `add` 可能失败并提示 `allowBuilds`,按提示把输出的键加进 profile 的 `pnpm-workspace.yaml` 后重跑即可。

### 卸载

```sh
dsh plugin --profile web remove meow-memory
```

### 手动安装(开发者,任意 DSH 安装,无需 npm)

1. 把本包复制(或软链)到 profile 的 `node_modules`:
   ```sh
   mkdir -p ~/.dsh/profiles/web/node_modules
   ln -s /path/to/meow-memory ~/.dsh/profiles/web/node_modules/meow-memory
   ```
   (Windows:`New-Item -ItemType Junction ...` —— NTFS junction,无需管理员权限。)
2. 把 `meow-memory` 加进 profile `package.json` 的 `dsh.profile.bundles`(同上)。
3. 重启 `dsh web`。新会话自动加载插件。

## 🔌 兼容性

支持 **dsh 0.1.5**(含最新的 `0.1.5-rc.1`),同时向下兼容旧版本——升级 dsh 不需要改本插件,也不需要改任何配置。

插件不写死版本号,而是运行时探测宿主能力,因此新旧版走各自正确的分支。已实测两代:`0.1.5-rc.1` 上首次注入、记忆工具调用、客户端渲染全部正常;`0.1.1-rc.2` 上行为与历史版本完全一致。

## ⚙️ 配置

所有字段均可选(profile patch 或 `cordis.patch.yml`)。**也可以不手编文件**:DSH 设置页里有本插件的「喵记忆」标签页(与「通用」「模型」平级),下面这些项全部图形化可改、字段级保存、可单项恢复默认(恢复默认 = 回到插件出厂默认,不受 patch 基线影响);保存后热重载/重启 meow-memory 插件生效。

```yaml
- id: meow-memory
  name: 'meow-memory'
  config:
    enabled: true          # 总开关
    projectDir: '.dsh-meow' # 记忆目录(相对工作区)
    promptLang: 'zh'       # ⚠️ 首次使用建议显式配置(见下方说明)
    hitTopK: 2             # 每条用户消息关键词命中的条目数上限(fact/lesson/rules/topic)
    reflect: true          # 连续 ≥reflectTurns 轮工具调用后自动反思
    reflectTurns: 7        # 触发反思所需的连续工具轮数
    dream:
      enabled: true
      idleMinutes: 180      # 窗口空闲 ≥180 分钟(3 小时)允许 dream
      suppressWindows:      # 峰时抑制时段(按下方 timeZone 计算,"HH:MM" 起止)
        - start: '09:00'    #   API 峰谷电价峰时
          end: '12:00'
        - start: '14:00'
          end: '18:00'
      suppressLeadMinutes: 15  # 每个峰时开始前 15 分钟也不触发
      checkMinutes: 15
      timeZone: 'Asia/Shanghai'  # 用户机器时钟为美区时间;抑制时段必须
                                 # 按此固定时区计算
      rulesReviewDays: 2    # updated_at 距今超该天数的稳定准则不进 dream 第 1 轮
                            # 清单(防反复整理不变化的条目);0 = 不过滤
    delegate:
      model: ''            # 整理任务换模型(可选):填写后反思轮与梦境轮自动换用
                           # 该模型执行,轮次结束自动换回主模型;'provider/model'
                           # 指定 provider+model,'model' 只换模型(provider 继承
                           # 主会话);留空 = 全程主模型
```

### 整理任务换模型(可选)

反思轮和 dream 各组始终在主窗口执行(steer)——prompt、模型回应、工具调用落在主会话 log(折叠 UI 负责视觉收纳)。独立 fork 子代理执行方式已于 v0.24 移除,不再提供"独立执行"开关。

如果想让记忆整理换个(更便宜的)模型跑:配置 `delegate.model` 后,反思/梦境轮发起的每个 LLM 请求会经 dsh 的 `agent/request` waterfall 自动覆盖 provider/model,轮次结束自动换回主模型——正常对话、工具轮完全不受影响。实现是无状态的:按"当前 turn 是否携带反思/梦境指令标记"逐请求判定,用户中止、崩溃、热重载都不会留下"卡在换模型"的脏状态。

### promptLang:prompt 与检索语言(重要)

`promptLang` 决定两件事:①注入/反思/dream 文案的语言;②工具描述的语言。它同时影响模型写记忆条目用的语言——关键词按条目语言提取,**以你说话的语言为准**。

**因此首次使用时请显式配置它**:`promptLang: 'zh'`(默认)或 `'en'`(内置英文语言包)。如果你的对话语言和界面语言不一致(比如界面英文、说话中文),**以你说话的语言为准**。

检索侧说明:BM25 分词自 v0.20.0 起语言无关(类别路由),条目与查询语言不一致不再"杀检索";`en` 模式额外启用英语归一化(停用词过滤 + Porter 词干还原),屈折变化不影响命中(`tokenizers` 能命中存为 `tokenizer` 的条目)。

自定义 / 社区语言包:prompt 文案是数据文件(`src/prompts/`),一门语言一个子目录,改文件即生效、无需改代码——详见 [`src/prompts/README.md`](src/prompts/README.md)(含贡献指南与 `npm run check-lang` 自查)。实例级自定义:`<home>/.dsh-meow/prompts/<lang>/` 下放同名槽位文件即可覆盖(可只覆盖部分)。

## 🧠 工作原理

```
第一条用户消息(首轮)         第二条起的每条消息                空闲≥3h 且非峰时
┌────────────────────┐        ┌────────────────────┐        ┌──────────────────────┐
│ ===== 长期记忆 ===== │        │ 可能相关的记忆,仅供  │        │ 按窗口 dream:        │
│ 【关于你】(soul)     │        │ 参考:keywords 命中   │        │ 三轮(含项目总结)      │
│ 【关于user】         │        │ top-2(全局+当前     │        │ 七层+提取过的,       │
│ 【设计原则】(rules)   │        │ project 锚定)      │        │ updated_at 以 T 封存  │
│ 【记忆导引】          │        └────────────────────┘        └──────────────────────┘
└────────────────────┘        已见 id 按会话记录
独立 plugin snapshot        (sessions/<id>.json)
↓ 原样 user prompt          压缩信号 → 释放已见
 每会话只注入一次,
 首轮不做命中
```

## 🛠 开发

```sh
npm install
npm run build          # esbuild 打包 → lib/index.js(自包含)
npm run test           # 228 项逻辑测试:db / bm25 / migrate / inject / reflect / dream / tools / apply
```

`@deepseek-ai/*` 包位于 dsh-meow pnpm workspace 中,不在本包的 `node_modules` 里。
在 Windows 上,`npm run link-workspace`(或 `scripts/link-workspace.ps1`)创建 workspace
包的 junction 镜像,使 esbuild 能解析它们;`build.mjs` 通过 `nodePaths` 引用。
这些链接仅构建期需要。

## 🙏 致谢

感谢每一位贡献者让 meow-memory 越来越好:

- **[daveycodez](https://github.com/daveycodez)** — 英文语言包与英文分词([PR #6](https://github.com/Phant0Meow/dsh-meow-memory/pull/6),v0.22.0 发布)
- **[chenmzh](https://github.com/chenmzh)** — 记忆注入改为独立 plugin snapshot 消息,根治会话标题污染([PR #10](https://github.com/Phant0Meow/dsh-meow-memory/pull/10))
- **[cuddly-guacamole](https://github.com/cuddly-guacamole)** — dsh 0.1.2-alpha.4 双版本 Session events 兼容([PR #11](https://github.com/Phant0Meow/dsh-meow-memory/pull/11))

## 📄 License

MIT —— 见 [LICENSE](LICENSE)。

Install

dsh plugin --profile web add meow-memory@0.26.0

Profile: web

Source