@modusensus/dsh-mneme 0.7.5 → 0.7.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/workflows/publish.yml +38 -0
- package/CHANGELOG.md +2 -0
- package/README.md +11 -7
- package/dsh-mneme/CHANGELOG.md +15 -0
- package/dsh-mneme/README.md +9 -8
- package/dsh-mneme/lib/service.js +38 -0
- package/dsh-mneme/lib/store.js +22 -0
- package/dsh-mneme/lib/tools.js +24 -18
- package/dsh-mneme/package-lock.json +2 -2
- package/dsh-mneme/package.json +1 -1
- package/dsh-mneme/scripts/sync-lib.js +3 -3
- package/dsh-mneme/src/client.js +2050 -0
- package/dsh-mneme/src/service.js +38 -0
- package/dsh-mneme/src/store.js +22 -0
- package/dsh-mneme/src/tools.js +24 -18
- package/dsh-mneme/test/client.test.js +10 -5
- package/dsh-mneme/test/tools.test.js +133 -0
- package/package.json +1 -1
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
name: Publish to npm
|
|
2
|
+
|
|
3
|
+
# 发布路径:registry.npmjs.org 在本机云服务器被出口 SNI 过滤 + 17897 隧道不稳定,
|
|
4
|
+
# 改由 GitHub runner 发布(不依赖本机出网)。打 v* tag 自动触发,或 workflow_dispatch 手动。
|
|
5
|
+
|
|
6
|
+
on:
|
|
7
|
+
push:
|
|
8
|
+
tags:
|
|
9
|
+
- 'v*'
|
|
10
|
+
workflow_dispatch:
|
|
11
|
+
|
|
12
|
+
permissions:
|
|
13
|
+
contents: read
|
|
14
|
+
|
|
15
|
+
jobs:
|
|
16
|
+
publish:
|
|
17
|
+
runs-on: ubuntu-latest
|
|
18
|
+
steps:
|
|
19
|
+
- uses: actions/checkout@v4
|
|
20
|
+
|
|
21
|
+
- uses: actions/setup-node@v4
|
|
22
|
+
with:
|
|
23
|
+
node-version: 24
|
|
24
|
+
registry-url: https://registry.npmjs.org/
|
|
25
|
+
|
|
26
|
+
# npm publish 必须从仓库根跑(根 package.json main → ./dsh-mneme/lib/index.js)。
|
|
27
|
+
# prepublishOnly 会把 dsh-mneme/package.json 的版本写回根 package.json,
|
|
28
|
+
# 所以发出的版本永远跟随 dsh-mneme/ 子目录版本号。
|
|
29
|
+
- name: Publish @modusensus/dsh-mneme
|
|
30
|
+
run: npm publish
|
|
31
|
+
env:
|
|
32
|
+
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
|
|
33
|
+
|
|
34
|
+
# 发布后自检:查 registry 上刚发的版本是否可读
|
|
35
|
+
- name: Verify published version
|
|
36
|
+
run: |
|
|
37
|
+
V="$(node -p "require('./dsh-mneme/package.json').version")"
|
|
38
|
+
echo "Published: $(npm view "@modusensus/dsh-mneme@${V}" version)"
|
package/CHANGELOG.md
CHANGED
package/README.md
CHANGED
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
<a href="https://github.com/awesome-dsh-plugin/awesome-dsh-plugin"><img src="https://awesome-dsh-plugin.com/badge.svg" alt="Awesome"></a>
|
|
11
11
|
<a href="https://github.com/modusensus/dsh-mneme/actions"><img src="https://img.shields.io/github/actions/workflow/status/modusensus/dsh-mneme/test.yml" alt="CI"></a>
|
|
12
12
|
<a href="https://nodejs.org"><img src="https://img.shields.io/badge/node-24%2B-blue" alt="node"></a>
|
|
13
|
-
<a href="https://github.com/modusensus/dsh-mneme"><img src="https://img.shields.io/badge/tests-
|
|
13
|
+
<a href="https://github.com/modusensus/dsh-mneme"><img src="https://img.shields.io/badge/tests-801%20passed-success" alt="tests"></a>
|
|
14
14
|
<a href="https://www.npmjs.com/package/@modusensus/dsh-mneme"><img src="https://img.shields.io/npm/dm/@modusensus/dsh-mneme?color=blue&label=downloads" alt="npm downloads"></a>
|
|
15
15
|
<a href="https://codecov.io/gh/modusensus/dsh-mneme"><img src="https://img.shields.io/codecov/c/github/modusensus/dsh-mneme/main" alt="coverage"></a>
|
|
16
16
|
</p>
|
|
@@ -87,7 +87,7 @@ dsh web
|
|
|
87
87
|
| 语义架构 | [dsh-mneme/docs/SEMANTIC.md](dsh-mneme/docs/SEMANTIC.md) |
|
|
88
88
|
| 本地模型部署指南 | [dsh-mneme/docs/LOCAL_MODEL.md](dsh-mneme/docs/LOCAL_MODEL.md) |
|
|
89
89
|
| v0.1 迁移说明 | [dsh-mneme/docs/MIGRATION.md](dsh-mneme/docs/MIGRATION.md) |
|
|
90
|
-
| 版本历史 | [CHANGELOG.md](CHANGELOG.md) |
|
|
90
|
+
| 版本历史 | [dsh-mneme/CHANGELOG.md](dsh-mneme/CHANGELOG.md) |
|
|
91
91
|
| 安全策略 | [SECURITY.md](SECURITY.md) |
|
|
92
92
|
|
|
93
93
|
## 🗺️ 路线图
|
|
@@ -107,14 +107,16 @@ dsh web
|
|
|
107
107
|
| **v0.7.2** | issue #35 删除按钮内联确认修复 + issue #34 对话开始注入当前时间(opt-in) | ✅ |
|
|
108
108
|
| **v0.7.3** | issue #38 左下角入口按钮可选开关 `showSidebarTrigger` | ✅ |
|
|
109
109
|
| **v0.7.4** | issue #40 记忆花括号转义 + issue #41 记忆窗口关闭按钮重叠修复 | ✅ |
|
|
110
|
-
| **v0.
|
|
110
|
+
| **v0.7.5** | 分层记忆类型 user/fact + Web 总览视图 + stats 端点 | ✅ |
|
|
111
|
+
| **v0.7.6** | issue #48 修复:截断/前缀 id 也能精确操作(统一 resolveMemoryId)+ client.js 改 src 正源 | ✅ |
|
|
112
|
+
| **v0.8.0** | 图谱增强:兴趣漂移可视化 + scope 隔离(issue #17)+ 跨 workspace 共享 | 🚧 计划中(9 月末) |
|
|
111
113
|
|
|
112
114
|
## 🧪 本地开发
|
|
113
115
|
|
|
114
116
|
```bash
|
|
115
117
|
cd dsh-mneme
|
|
116
118
|
npm install
|
|
117
|
-
npm test #
|
|
119
|
+
npm test # 801 个测试
|
|
118
120
|
npm run stress # 三轴线压测
|
|
119
121
|
npm run sync # src → lib 同步
|
|
120
122
|
```
|
|
@@ -192,7 +194,7 @@ Works out of the box. Enable these as needed:
|
|
|
192
194
|
| Semantic architecture | [dsh-mneme/docs/SEMANTIC.md](dsh-mneme/docs/SEMANTIC.md) |
|
|
193
195
|
| Local model guide | [dsh-mneme/docs/LOCAL_MODEL.md](dsh-mneme/docs/LOCAL_MODEL.md) |
|
|
194
196
|
| v0.1 migration | [dsh-mneme/docs/MIGRATION.md](dsh-mneme/docs/MIGRATION.md) |
|
|
195
|
-
| Changelog | [CHANGELOG.md](CHANGELOG.md) |
|
|
197
|
+
| Changelog | [dsh-mneme/CHANGELOG.md](dsh-mneme/CHANGELOG.md) |
|
|
196
198
|
| Security | [SECURITY.md](SECURITY.md) |
|
|
197
199
|
|
|
198
200
|
## 🗺️ Roadmap
|
|
@@ -212,14 +214,16 @@ Works out of the box. Enable these as needed:
|
|
|
212
214
|
| **v0.7.2** | Issue #35 delete button inline-confirm fix + Issue #34 inject current time at conversation start (opt-in) | ✅ |
|
|
213
215
|
| **v0.7.3** | Issue #38 optional sidebar trigger `showSidebarTrigger` | ✅ |
|
|
214
216
|
| **v0.7.4** | Issue #40 prompt-brace escaping + Issue #41 overlay close-button overlap fix | ✅ |
|
|
215
|
-
| **v0.
|
|
217
|
+
| **v0.7.5** | Layered memory types (user/fact) + Overview view + stats endpoint | ✅ |
|
|
218
|
+
| **v0.7.6** | Issue #48 fix: truncated/prefix ids resolve for exact ops (unified resolveMemoryId) + client.js now src-authored | ✅ |
|
|
219
|
+
| **v0.8.0** | Graph enhancement: interest-drift visualization + scope isolation (issue #17) + cross-workspace sharing | 🚧 Planned (late Sep) |
|
|
216
220
|
|
|
217
221
|
## 🧪 Local Development
|
|
218
222
|
|
|
219
223
|
```bash
|
|
220
224
|
cd dsh-mneme
|
|
221
225
|
npm install
|
|
222
|
-
npm test #
|
|
226
|
+
npm test # 801 tests
|
|
223
227
|
npm run stress # three-axis stress test
|
|
224
228
|
npm run sync # src → lib sync
|
|
225
229
|
```
|
package/dsh-mneme/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,20 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.7.6] - 2026-09-02
|
|
4
|
+
|
|
5
|
+
### 🐛 issue #48:截断的短 id 也能精确操作
|
|
6
|
+
|
|
7
|
+
- **现象**:`memory_update` / `memory_delete` / `memory_forget` / `memory_archive` 此前对 id 做**严格精确匹配**(`WHERE id = ?`,无任何前缀/模糊逻辑)。若宿主上下文压缩或手抄把 36 位 UUID 截断,`memory_delete` 会静默返回 `{deleted:false}`(无 warn、无日志),其余三个工具抛错——对用户都表现为"操作不进也不出"。
|
|
8
|
+
- **新增 `service.resolveMemoryId`**:精确命中优先,否则把传入值当 id 前缀解析(主键前缀走索引,无性能问题);命中多条 → 拒绝操作并列出候选完整 id,**绝不瞎猜**。
|
|
9
|
+
- **四工具统一接入**:`memory_update` / `memory_forget` / `memory_archive` 未命中抛错并提示"请传完整 id(`memory_list` / `memory_search` 输出均为完整 id)";`memory_delete` 保持幂等返回 `{deleted:false}`,未命中补 `logger.warn` 留痕,可被服务日志定位。
|
|
10
|
+
- 完整 id 直连不受影响(精确命中优先,不会因"恰好是另一条的前缀"被误判歧义)。
|
|
11
|
+
- 复验加固:纯通配符 id(`%`/`_`)剥空后按无匹配处理,杜绝退化成 `LIKE '%'` 全表误删单条记忆;id 首尾空白自动 trim。
|
|
12
|
+
- 补 11 个用例(前缀删除/更新/归档/遗忘、歧义拒绝、未命中兜底、精确优先、通配符兜底、空白 trim、warnMiss 日志),全套 **801 通过**。
|
|
13
|
+
|
|
14
|
+
### 🧹 工程:client.js 改为 src 正源
|
|
15
|
+
|
|
16
|
+
- Web 面板 bundle `client.js` 历史上是 lib/ 下**手写、无 src 副本**的唯一例外(重蹈过 v0.6.7 源码漏提交);现补 `src/client.js` 为唯一正源,`npm run sync` 统一同步出 `lib/client.js`,guard 测试改为断言两文件字节一致,杜绝 drift。
|
|
17
|
+
|
|
3
18
|
## [0.7.5] - 2026-09-02
|
|
4
19
|
|
|
5
20
|
### 🆕 新功能:分层记忆类型 user/fact
|
package/dsh-mneme/README.md
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
[](https://www.npmjs.com/package/@modusensus/dsh-mneme)
|
|
6
6
|
[](LICENSE)
|
|
7
7
|
[](https://github.com/awesome-dsh-plugin/awesome-dsh-plugin)
|
|
8
|
-
[](https://github.com/modusensus/dsh-mneme)
|
|
9
9
|
[](https://github.com/modusensus/dsh-mneme/actions)
|
|
10
10
|
[](https://nodejs.org)
|
|
11
11
|
[](https://www.npmjs.com/package/@modusensus/dsh-mneme)
|
|
@@ -241,6 +241,7 @@ v0.3.0 起新增**记忆基因**层:从记忆里抽取**命名实体**、**带
|
|
|
241
241
|
|
|
242
242
|
| 版本 | 亮点 |
|
|
243
243
|
|------|------|
|
|
244
|
+
| **v0.7.6** | issue #48 修复:`memory_update`/`memory_delete`/`memory_forget`/`memory_archive` 支持截断/前缀短 id(新增 `service.resolveMemoryId`:精确命中优先 + 唯一前缀解析 + 多命中拒绝列出候选 + `memory_delete` 未命中幂等补 `logger.warn`;纯通配符/空白兜底);Web bundle `client.js` 改 src 正源;801 测试全绿 |
|
|
244
245
|
| **v0.7.5** | 分层记忆类型:新增 `user`(用户画像)/`fact`(原子事实)轻量记忆类型(单表 `type` 扩展,不动 schema)+ Web 面板「总览」视图(记忆分层卡片 + 用户画像卡 + 类型分布 + 近 7 天趋势)+ `/api/dsh-mneme/stats` 统计端点;kimi-k2.7-code 复验(days 整数化等);790 测试全绿 |
|
|
245
246
|
| **v0.7.4** | issue #40 修复:记忆内容含 `{{...}}` 模板语法时整轮崩溃(注入边界 run-based 花括号转义 `{{a}}`→`{\{a\}\}`,奇数连续如 `{{{a}}}` 也不残留字面 `{{`;新增 `escapePromptVariables` 配置默认开);issue #41 修复:记忆窗口关闭按钮与宿主窗口控制按钮重叠无法点击(顶栏左对齐,关闭按钮离开右上角宿主控制区);782 测试全绿 |
|
|
246
247
|
| **v0.7.3** | issue #38 新功能:左下角入口按钮可选开关 `showSidebarTrigger`(默认开)——与 dsh-cost-meter 等抢占 footer slot 的插件冲突时可在 Web 面板「设置」一键关闭,仅隐藏按钮、记忆库标签不受影响;776 测试全绿 |
|
|
@@ -295,7 +296,8 @@ v0.3.0 起新增**记忆基因**层:从记忆里抽取**命名实体**、**带
|
|
|
295
296
|
| **v0.7.3** | ✅ 完成 | issue #38 新功能 | 左下角入口按钮可选开关 `showSidebarTrigger`(默认开,settings-over-config);Web 面板设置一键关闭,与 dsh-cost-meter 等 footer 插件冲突可隐藏按钮、记忆库标签不受影响;776 测试全绿 |
|
|
296
297
|
| **v0.7.4** | ✅ 完成 | issue #40 + #41 修复 | 注入边界 run-based 花括号转义(`{{a}}`→`{\{a\}\}`、奇数连续如 `{{{a}}}` 不残留字面,`escapePromptVariables` 默认开)+ 记忆窗口顶栏左对齐、关闭按钮避开宿主窗口控制按钮区;782 测试全绿 |
|
|
297
298
|
| **v0.7.5** | ✅ 完成 | 分层记忆类型 + 总览视图 | 借鉴 meow-memory 分层概念、贴合单表架构:新增 `user`(用户画像)/`fact`(原子事实)类型,注入/镜像/梦境/质量过滤全链路打通;Web 面板「总览」视图(分层卡片 + 用户画像卡 + 类型分布 + 近 7 天趋势);`/api/dsh-mneme/stats` 端点;kimi-k2.7-code 复验;790 测试全绿 |
|
|
298
|
-
| **v0.
|
|
299
|
+
| **v0.7.6** | ✅ 完成 | issue #48 修复 | 四工具统一 `service.resolveMemoryId`:截断/前缀短 id 也能精确操作(精确命中优先、唯一前缀解析、多命中拒绝并列出候选、`memory_delete` 未命中幂等返回 + `logger.warn` 留痕);Web bundle `client.js` 改 src 正源;801 测试全绿 |
|
|
300
|
+
| **v0.8.0** | 🚧 计划中(9 月末) | 图谱增强 | 兴趣漂移可视化 + scope 隔离(issue #17)+ 跨 workspace 记忆共享 + 更多 heat 信号 |
|
|
299
301
|
|
|
300
302
|
> 新能力一律做成**可开关的功能**(配置启用/关闭),默认保守开启、不破坏现有行为。`failure_memories` 表与 autoDream 决策引擎已为后续反思性成长铺好路。
|
|
301
303
|
|
|
@@ -457,11 +459,10 @@ src/
|
|
|
457
459
|
├── hot-memory.js # 会话级短期热记忆(v0.5.0:滚动轮次 + token 预算)
|
|
458
460
|
├── embedding.js # OpenAI 兼容 embeddings 客户端 + 向量检索
|
|
459
461
|
├── api.js # HTTP 路由(Web 面板数据通道)
|
|
462
|
+
├── client.js # Web 面板 bundle(ModuleLoader 自注册;v0.7.6 起 src 正源)
|
|
460
463
|
└── index.js # 插件接线
|
|
461
|
-
lib/
|
|
462
|
-
|
|
463
|
-
└── *.js # src 的同步分发产物
|
|
464
|
-
test/ # 757 个 node:test 测试(含审计与三轴线压测不变量)
|
|
464
|
+
lib/ # src 的同步分发产物(npm run sync,prepack 自动执行;无手写例外)
|
|
465
|
+
test/ # 801 个 node:test 测试(含审计与三轴线压测不变量)
|
|
465
466
|
scripts/ # e2e-dsh.js 端到端演示 · stress-dsh.js 三轴线压测 · sync-lib.js 同步 · benchmark-recall.js 召回基准
|
|
466
467
|
```
|
|
467
468
|
|
|
@@ -470,14 +471,14 @@ scripts/ # e2e-dsh.js 端到端演示 · stress-dsh.js 三轴线压
|
|
|
470
471
|
```bash
|
|
471
472
|
cd dsh-mneme
|
|
472
473
|
npm install # 安装 peer 依赖(以 devDependencies 形式,用于本地测试)
|
|
473
|
-
npm test # 运行
|
|
474
|
+
npm test # 运行 801 个测试
|
|
474
475
|
npm run stress # 三轴线压测:长会话检索 / 冲突仲裁 / 多 Agent 并发(离线 mock LLM)
|
|
475
476
|
npm run sync # 把 src/ 同步到 lib/(发布时由 prepack 钩子自动执行)
|
|
476
477
|
```
|
|
477
478
|
|
|
478
479
|
> 压测(`npm run stress`)三条轴线:**长会话检索**(Recall@k、陈旧残留率)、**冲突裁决**(可重放仲裁集:审计快照 hash + receipt + 幂等回放)、**多 Agent 并发**(丢更新、重复合并、事务/崩溃恢复)。每次 autoDream 运行都会写入审计表 `dream_runs`(输入快照 digest + 决策清单 + 逐 id 去向 + receipt),让高通过率下也能定位静默错误。
|
|
479
480
|
|
|
480
|
-
> `lib/` 是 `src/` 的同步分发产物(`npm run sync
|
|
481
|
+
> `lib/` 是 `src/` 的同步分发产物(`npm run sync`):v0.7.6 起全部由 src 复制而来,**不再有任何手写 lib 文件**——Web 面板 bundle 也以 `src/client.js` 为唯一正源。
|
|
481
482
|
|
|
482
483
|
## 📄 设计文档
|
|
483
484
|
|
package/dsh-mneme/lib/service.js
CHANGED
|
@@ -1611,6 +1611,44 @@ export function createService({ store, mirror, config, onWrite, logger, settings
|
|
|
1611
1611
|
count: (type, opts) => store.count(type, opts),
|
|
1612
1612
|
stats: (opts) => store.stats(opts),
|
|
1613
1613
|
getById: (id) => store.getById(id),
|
|
1614
|
+
// issue #48: resolve a possibly-truncated id to its canonical full id.
|
|
1615
|
+
// Exact hit wins; otherwise the input is treated as a prefix of the id
|
|
1616
|
+
// PRIMARY KEY. Never guesses on ambiguity — returns the candidates and the
|
|
1617
|
+
// caller must pass a full id. Outcome is {ok:true,id} or {ok:false,reason,
|
|
1618
|
+
// message} with reason ∈ invalid | not-found | ambiguous. warnMiss logs the
|
|
1619
|
+
// silent-miss case the delete tool previously swallowed (no return channel
|
|
1620
|
+
// for it, so observability has to live here in the service layer).
|
|
1621
|
+
resolveMemoryId: (input, { warnMiss = false } = {}) => {
|
|
1622
|
+
const bad = (reason, message) => ({ ok: false, reason, message });
|
|
1623
|
+
if (typeof input !== "string") return bad("invalid", "memory id is required");
|
|
1624
|
+
// 手抄/上下文压缩来的 id 可能带首尾空白,统一 trim 后再做精确与前缀解析。
|
|
1625
|
+
const id = input.trim();
|
|
1626
|
+
if (!id) return bad("invalid", "memory id is required");
|
|
1627
|
+
const exact = store.getById(id);
|
|
1628
|
+
if (exact) return { ok: true, id: exact.id };
|
|
1629
|
+
const matches = store.listByIdPrefix(id);
|
|
1630
|
+
if (matches.length === 0) {
|
|
1631
|
+
if (warnMiss) {
|
|
1632
|
+
logger?.warn?.(
|
|
1633
|
+
`[dsh-mneme] memory id "${id}" matched nothing (exact or prefix) — ` +
|
|
1634
|
+
"no entry was deleted; ids are full-length, pass one from memory_list/memory_search output or delete by query=…"
|
|
1635
|
+
);
|
|
1636
|
+
}
|
|
1637
|
+
return bad(
|
|
1638
|
+
"not-found",
|
|
1639
|
+
`memory not found: ${id} (checked exact id and prefix; use a full id from memory_list/memory_search output)`
|
|
1640
|
+
);
|
|
1641
|
+
}
|
|
1642
|
+
if (matches.length > 1) {
|
|
1643
|
+
const sample = matches.slice(0, 5).map((m) => m.id);
|
|
1644
|
+
const tail = matches.length > sample.length ? ` …(+${matches.length - sample.length})` : "";
|
|
1645
|
+
return bad(
|
|
1646
|
+
"ambiguous",
|
|
1647
|
+
`memory id prefix "${id}" matches ${matches.length} entries (${sample.join(", ")}${tail}); refusing to guess — pass a full id`
|
|
1648
|
+
);
|
|
1649
|
+
}
|
|
1650
|
+
return { ok: true, id: matches[0].id };
|
|
1651
|
+
},
|
|
1614
1652
|
remove: (id) => {
|
|
1615
1653
|
store.remove(id);
|
|
1616
1654
|
afterSync("write");
|
package/dsh-mneme/lib/store.js
CHANGED
|
@@ -697,6 +697,27 @@ export function createStore(path) {
|
|
|
697
697
|
return toRow(row);
|
|
698
698
|
}
|
|
699
699
|
|
|
700
|
+
/**
|
|
701
|
+
* issue #48: resolve a truncated id — as can leak through an agent's context
|
|
702
|
+
* window when list/search output is shortened — by matching it as a prefix of
|
|
703
|
+
* the id PRIMARY KEY. Exact lookups keep using getById; this only serves
|
|
704
|
+
* resolving a *candidate* id. Returns up to 51 rows so the caller can tell
|
|
705
|
+
* "unique" from "ambiguous" without a second query. LIKE wildcards are
|
|
706
|
+
* stripped from the input (a valid id fragment is hex/UUID text, never % or
|
|
707
|
+
* _). Prefix over a PK stays an index scan, so this is cheap even at scale.
|
|
708
|
+
*/
|
|
709
|
+
function listByIdPrefix(idPrefix) {
|
|
710
|
+
if (typeof idPrefix !== "string" || !idPrefix.trim()) return [];
|
|
711
|
+
// LIKE 通配符不参与 id 匹配,一律剥掉。若剥完为空(如 id="%"),
|
|
712
|
+
// 不能让 SQL 退化成 `LIKE '%'` 全表命中——那会让单条记忆被误删,
|
|
713
|
+
// 一律视为无匹配返回。
|
|
714
|
+
const safe = idPrefix.replace(/[\\%_]/g, "");
|
|
715
|
+
if (!safe) return [];
|
|
716
|
+
const rows = db.prepare("SELECT * FROM memories WHERE id LIKE ? LIMIT 51")
|
|
717
|
+
.all(`${safe}%`);
|
|
718
|
+
return rows.map(toRow);
|
|
719
|
+
}
|
|
720
|
+
|
|
700
721
|
/**
|
|
701
722
|
* Case-insensitive exact title lookup (v0.6.1 wiki-link). COLLATE NOCASE
|
|
702
723
|
* folds ASCII case (CJK titles are inherently case-free, so they match
|
|
@@ -2210,6 +2231,7 @@ export function createStore(path) {
|
|
|
2210
2231
|
count,
|
|
2211
2232
|
stats,
|
|
2212
2233
|
getById,
|
|
2234
|
+
listByIdPrefix,
|
|
2213
2235
|
save,
|
|
2214
2236
|
update,
|
|
2215
2237
|
compareAndUpdate,
|
package/dsh-mneme/lib/tools.js
CHANGED
|
@@ -302,7 +302,7 @@ export function createTools(ctx, service, config, embedder) {
|
|
|
302
302
|
name: "memory_update",
|
|
303
303
|
description: "Modify an existing memory entry (title, content, type, tags, importance).",
|
|
304
304
|
parameters: {
|
|
305
|
-
id: { type: "string", required: true, description: "Memory id" },
|
|
305
|
+
id: { type: "string", required: true, description: "Memory id (full id from memory_list/memory_search output, or a unique prefix of it)" },
|
|
306
306
|
title: { type: "string" },
|
|
307
307
|
content: { type: "string" },
|
|
308
308
|
type: { type: "string", enum: ["preference", "project", "decision", "history", "user", "fact"] },
|
|
@@ -329,7 +329,9 @@ export function createTools(ctx, service, config, embedder) {
|
|
|
329
329
|
render: (_args, value) => TEXT_OUTPUT(`Updated memory ${value.memory.id}: ${value.memory.title}`)
|
|
330
330
|
},
|
|
331
331
|
async execute(args) {
|
|
332
|
-
const
|
|
332
|
+
const resolved = service.resolveMemoryId(args.id);
|
|
333
|
+
if (!resolved.ok) throw new Error(resolved.message);
|
|
334
|
+
const memory = service.update(resolved.id, {
|
|
333
335
|
title: args.title,
|
|
334
336
|
content: args.content,
|
|
335
337
|
type: args.type,
|
|
@@ -342,9 +344,9 @@ export function createTools(ctx, service, config, embedder) {
|
|
|
342
344
|
|
|
343
345
|
defineTool({
|
|
344
346
|
name: "memory_delete",
|
|
345
|
-
description: "Permanently delete a memory entry. Pass id for exact delete, or query to delete the single best-matching entry by text — lets the agent honor 'delete the memory about X' without a prior list/search round trip.",
|
|
347
|
+
description: "Permanently delete a memory entry. Pass id for exact delete (full id, or a unique prefix of it — ambiguous prefixes are rejected), or query to delete the single best-matching entry by text — lets the agent honor 'delete the memory about X' without a prior list/search round trip. An id that matches nothing is logged as a warning instead of failing silently.",
|
|
346
348
|
parameters: {
|
|
347
|
-
id: { type: "string", description: "
|
|
349
|
+
id: { type: "string", description: "Memory id to delete: full id (from memory_list/memory_search output) or a unique prefix of it; a miss is logged (warn) and returns deleted:false" },
|
|
348
350
|
query: { type: "string", description: "Delete the best-matching entry for this text (searches title/content/tags; uses hybrid recall when an embedder is configured)" }
|
|
349
351
|
},
|
|
350
352
|
output: {
|
|
@@ -353,13 +355,19 @@ export function createTools(ctx, service, config, embedder) {
|
|
|
353
355
|
additionalProperties: false,
|
|
354
356
|
properties: { deleted: { type: "boolean", required: true } }
|
|
355
357
|
},
|
|
356
|
-
render: (_args, value) => TEXT_OUTPUT(value.deleted
|
|
358
|
+
render: (_args, value) => TEXT_OUTPUT(value.deleted
|
|
359
|
+
? "Memory deleted."
|
|
360
|
+
: "Memory not found — nothing was deleted. Pass a full id (or a unique prefix) from memory_list/memory_search output, or delete by query=… instead.")
|
|
357
361
|
},
|
|
358
362
|
async execute(args) {
|
|
359
363
|
if (args.id) {
|
|
360
|
-
const
|
|
361
|
-
if (
|
|
362
|
-
|
|
364
|
+
const resolved = service.resolveMemoryId(args.id, { warnMiss: true });
|
|
365
|
+
if (!resolved.ok) {
|
|
366
|
+
if (resolved.reason === "ambiguous") throw new Error(resolved.message);
|
|
367
|
+
return { deleted: false };
|
|
368
|
+
}
|
|
369
|
+
service.remove(resolved.id);
|
|
370
|
+
return { deleted: true };
|
|
363
371
|
}
|
|
364
372
|
if (args.query) {
|
|
365
373
|
const [best] = await service.searchMemories(args.query, { mode: "auto", topK: 1, useRerank: true });
|
|
@@ -378,7 +386,7 @@ export function createTools(ctx, service, config, embedder) {
|
|
|
378
386
|
"Stop a memory from being auto-injected and from appearing in searches and lists without deleting it. " +
|
|
379
387
|
"The entry stays in storage; pass forgotten: false to restore it.",
|
|
380
388
|
parameters: {
|
|
381
|
-
id: { type: "string", required: true },
|
|
389
|
+
id: { type: "string", required: true, description: "Memory id: full id (from memory_list/memory_search output) or a unique prefix of it; ambiguous prefixes are rejected" },
|
|
382
390
|
forgotten: { type: "boolean", description: "Suppress (true, default) or restore (false) the entry's visibility" }
|
|
383
391
|
},
|
|
384
392
|
output: {
|
|
@@ -399,10 +407,9 @@ export function createTools(ctx, service, config, embedder) {
|
|
|
399
407
|
render: (_args, value) => TEXT_OUTPUT(`Memory ${value.memory.id} injection ${value.memory.forgotten ? "suppressed" : "restored"}.`)
|
|
400
408
|
},
|
|
401
409
|
async execute(args) {
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
const memory = service.setForget(args.id, args.forgotten ?? true);
|
|
410
|
+
const resolved = service.resolveMemoryId(args.id);
|
|
411
|
+
if (!resolved.ok) throw new Error(resolved.message);
|
|
412
|
+
const memory = service.setForget(resolved.id, args.forgotten ?? true);
|
|
406
413
|
return { memory: { id: memory.id, forgotten: memory.forgotten } };
|
|
407
414
|
}
|
|
408
415
|
}),
|
|
@@ -414,7 +421,7 @@ export function createTools(ctx, service, config, embedder) {
|
|
|
414
421
|
"Archived entries stay in storage and are recoverable: pass archived=false to restore, and use memory_list with " +
|
|
415
422
|
"include_archived=true to find archived entries.",
|
|
416
423
|
parameters: {
|
|
417
|
-
id: { type: "string", required: true, description: "Memory id" },
|
|
424
|
+
id: { type: "string", required: true, description: "Memory id: full id (from memory_list/memory_search output) or a unique prefix of it; ambiguous prefixes are rejected" },
|
|
418
425
|
archived: { type: "boolean", description: "Archive (true, default) or restore (false) the entry" }
|
|
419
426
|
},
|
|
420
427
|
output: {
|
|
@@ -435,10 +442,9 @@ export function createTools(ctx, service, config, embedder) {
|
|
|
435
442
|
render: (_args, value) => TEXT_OUTPUT(`Memory ${value.memory.id} ${value.memory.archived ? "archived" : "restored"}.`)
|
|
436
443
|
},
|
|
437
444
|
async execute(args) {
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
const memory = service.setArchived(args.id, args.archived ?? true);
|
|
445
|
+
const resolved = service.resolveMemoryId(args.id);
|
|
446
|
+
if (!resolved.ok) throw new Error(resolved.message);
|
|
447
|
+
const memory = service.setArchived(resolved.id, args.archived ?? true);
|
|
442
448
|
return { memory: { id: memory.id, archived: memory.archived } };
|
|
443
449
|
}
|
|
444
450
|
})
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@modusensus/dsh-mneme",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.6",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "@modusensus/dsh-mneme",
|
|
9
|
-
"version": "0.7.
|
|
9
|
+
"version": "0.7.6",
|
|
10
10
|
"license": "MIT",
|
|
11
11
|
"dependencies": {
|
|
12
12
|
"@huggingface/transformers": "^4.2.0"
|
package/dsh-mneme/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@modusensus/dsh-mneme",
|
|
3
3
|
"description": "Cross-session memory plugin for DeepSeek Harness with autoDream consolidation: SQLite store, Markdown mirrors, 7 model tools, automatic injection, session summarization, user profile/rules, custom slash commands, vector (semantic) search, and a Web GUI panel",
|
|
4
|
-
"version": "0.7.
|
|
4
|
+
"version": "0.7.6",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
7
7
|
"type": "git",
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// Sync the src/ tree into lib/ — the distributable consumed by DSH (package
|
|
2
|
-
// main is lib/index.js).
|
|
3
|
-
//
|
|
4
|
-
// src -> lib
|
|
2
|
+
// main is lib/index.js). src/ is the single source of truth for every module,
|
|
3
|
+
// including client.js (the Web panel bundle); the sync only copies
|
|
4
|
+
// src -> lib and never prunes output files.
|
|
5
5
|
//
|
|
6
6
|
// Usage: npm run sync (also run automatically by `npm pack`/`npm publish`
|
|
7
7
|
// via the prepack hook, so a published tarball always ships a fresh lib/).
|