@modusensus/dsh-mneme 0.4.0 → 0.4.2

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/README.md CHANGED
@@ -131,6 +131,7 @@ v0.3.0 起新增**记忆基因**层:从记忆里抽取**命名实体**、**带
131
131
 
132
132
  | 版本 | 亮点 |
133
133
  |------|------|
134
+ | **v0.4.2** | autoSummarize 自定义模型:`summarizeProvider`/`summarizeModel` 配置项,可独立指定轻量模型(如 qwen3.6-plus)用于会话摘要,节省主模型 token;473 测试全绿 |
134
135
  | **v0.4.0** | 系统级睡眠 Sleep Mode:空闲触发的四阶段深度维护(冲突消解 / 归档降级 / 模式发现 / 关系补全),可中断、串行安全、fail-safe,分层压缩释放冷记忆;471 测试全绿 |
135
136
  | **v0.3.9** | 修复第三方审计 4 项 FAIL:CAS 同事务原子化、Mirror 降级回执透传、逐 type 物理终态收敛、Generation 强整数校验与并发初始化稳定化 |
136
137
  | **v0.3.8** | audit peer 复验 6 项运行时阻断全部修复:desired generation 同事务原子递增(崩溃窗口不再静默跳过)、同步失败不静默、原子 generation 增量(多进程零丢失)、逐 type committed/failed/pending 回执、读取失败显式 unknown、generation 上界/负数 CHECK |
@@ -146,8 +147,8 @@ v0.3.0 起新增**记忆基因**层:从记忆里抽取**命名实体**、**带
146
147
  | v0.3.0 | ✅ 完成 | 记忆基因 | entities/attrs/relations 三表 + 时间轴 + 实体搜索 |
147
148
  | v0.3.6–0.3.8 | ✅ 完成 | 镜像一致性 + 审计加固 | generation 同步状态机、audit peer 6 项运行时阻断修复、450 测试全绿 |
148
149
  | v0.3.9 | ✅ 完成 | 审计加固 A/B/D/F | compareAndUpdate 同事务原子性、degraded 回执、逐 type 物理终态、整数 fail-closed、并发初始化稳定 |
149
- | **v0.4.0** | 🚧 开发中 | 系统级睡眠 Sleep Mode | 空闲触发的四阶段深度维护(冲突消解 / 归档降级 / 模式发现 / 关系补全)、分层压缩、可中断串行 fail-safe;471 测试全绿 |
150
- | **v0.4.1** | 📋 规划 | 反思性成长 | 纠错双向回流(改记忆同时反思"为什么记错/召回错")+ 规则演进(从 failure 提炼规律注入系统提示)+ 自适应参数 |
150
+ | **v0.4.0** | 完成 | 系统级睡眠 Sleep Mode | 空闲触发的四阶段深度维护(冲突消解 / 归档降级 / 模式发现 / 关系补全)、分层压缩、可中断串行 fail-safe;471 测试全绿 |
151
+ | **v0.4.2** | 完成 | autoSummarize 自定义模型 | `summarizeProvider`/`summarizeModel` 配置项支持,可独立指定轻量模型(如 qwen3.6-plus)用于会话摘要,节省主模型 token;473 测试全绿 |
151
152
  | **v0.5.0+** | 🚀 远期 | 自进化记忆 | 兴趣漂移跟踪 + 跨 workspace 记忆共享(等 DSH 支持) |
152
153
 
153
154
  > 新能力一律做成**可开关的功能**(配置启用/关闭),默认保守开启、不破坏现有行为。`failure_memories` 表与 autoDream 决策引擎已为后续反思性成长铺好路。
@@ -210,6 +211,7 @@ dsh web
210
211
  | `memoryDir` | `~/.dsh/memory` | 记忆存储目录(SQLite + Markdown) |
211
212
  | `autoInject` | `true` | 会话启动自动注入记忆 |
212
213
  | `autoSummarize` | `true` | 会话结束自动提炼摘要 |
214
+ | `summarizeProvider` / `summarizeModel` | 空 | 摘要的 LLM 路由覆盖(空=使用当前会话模型);推荐轻量模型节省主模型 token |
213
215
  | `maxInjectedItems` | `5` | 最多注入几条记忆 |
214
216
  | `importanceThreshold` | `3` | 注入的最低重要性(1-5) |
215
217
  | `autoDream` | `true` | 自动记忆整理开关 |
package/lib/config.js CHANGED
@@ -4,6 +4,11 @@ export const Config = z.object({
4
4
  memoryDir: z.string().default("~/.dsh/memory"),
5
5
  autoInject: z.boolean().default(true),
6
6
  autoSummarize: z.boolean().default(true),
7
+ // Optional model override for summarization. When both are non-empty, they
8
+ // take priority over the session's current model. Empty = use the session's
9
+ // active provider/model (same as before).
10
+ summarizeProvider: z.string().default(""),
11
+ summarizeModel: z.string().default(""),
7
12
  maxInjectedItems: z.natural().min(1).max(20).default(5),
8
13
  importanceThreshold: z.natural().min(1).max(5).default(3),
9
14
  autoDream: z.boolean().default(true),
package/lib/summarize.js CHANGED
@@ -100,9 +100,12 @@ export function createSummarizer(ctx, service, config) {
100
100
  inFlight.set(session.id, controller);
101
101
  try {
102
102
  const header = session.requestHeader?.()?.config;
103
- const route = header?.provider && header?.model
104
- ? { provider: header.provider, model: header.model }
105
- : undefined;
103
+ // Config override takes priority, then session header, then nothing.
104
+ const route = (config.summarizeProvider && config.summarizeModel)
105
+ ? { provider: config.summarizeProvider, model: config.summarizeModel }
106
+ : (header?.provider && header?.model)
107
+ ? { provider: header.provider, model: header.model }
108
+ : undefined;
106
109
  if (!route) return;
107
110
  const messages = collectMessages(session);
108
111
  if (!messages.length) return;
package/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.4.0",
4
+ "version": "0.4.2",
5
5
  "license": "MIT",
6
6
  "type": "module",
7
7
  "main": "lib/index.js",
@@ -64,4 +64,4 @@
64
64
  "overrides": {
65
65
  "adm-zip": "0.6.0"
66
66
  }
67
- }
67
+ }
package/src/config.js CHANGED
@@ -4,6 +4,11 @@ export const Config = z.object({
4
4
  memoryDir: z.string().default("~/.dsh/memory"),
5
5
  autoInject: z.boolean().default(true),
6
6
  autoSummarize: z.boolean().default(true),
7
+ // Optional model override for summarization. When both are non-empty, they
8
+ // take priority over the session's current model. Empty = use the session's
9
+ // active provider/model (same as before).
10
+ summarizeProvider: z.string().default(""),
11
+ summarizeModel: z.string().default(""),
7
12
  maxInjectedItems: z.natural().min(1).max(20).default(5),
8
13
  importanceThreshold: z.natural().min(1).max(5).default(3),
9
14
  autoDream: z.boolean().default(true),
package/src/summarize.js CHANGED
@@ -100,9 +100,12 @@ export function createSummarizer(ctx, service, config) {
100
100
  inFlight.set(session.id, controller);
101
101
  try {
102
102
  const header = session.requestHeader?.()?.config;
103
- const route = header?.provider && header?.model
104
- ? { provider: header.provider, model: header.model }
105
- : undefined;
103
+ // Config override takes priority, then session header, then nothing.
104
+ const route = (config.summarizeProvider && config.summarizeModel)
105
+ ? { provider: config.summarizeProvider, model: config.summarizeModel }
106
+ : (header?.provider && header?.model)
107
+ ? { provider: header.provider, model: header.model }
108
+ : undefined;
106
109
  if (!route) return;
107
110
  const messages = collectMessages(session);
108
111
  if (!messages.length) return;
@@ -154,3 +154,38 @@ test("aborted finish does not store entries", async () => {
154
154
  assert.equal(calls.length, 1); // the stream was actually reached
155
155
  assert.equal(store.count(), 0);
156
156
  });
157
+
158
+ test("uses summarizeProvider/summarizeModel config override when set", async () => {
159
+ const { events, calls } = setup({
160
+ summarizeProvider: "aliyun",
161
+ summarizeModel: "qwen3.6-plus"
162
+ });
163
+ const handler = events.find((e) => e.name === "session/event").fn;
164
+ const session = {
165
+ id: "s4",
166
+ // Session header has a different model — config override should win.
167
+ requestHeader: () => ({ config: { provider: "deepseek", model: "deepseek-v4-pro" } }),
168
+ events: [userMessage("测试覆盖"), { seq: 2, type: "turn/end" }]
169
+ };
170
+ await handler(session, { seq: 2, type: "turn/end" });
171
+ assert.equal(calls.length, 1);
172
+ assert.equal(calls[0].provider, "aliyun");
173
+ assert.equal(calls[0].model, "qwen3.6-plus");
174
+ });
175
+
176
+ test("falls back to session header when summarize config is empty", async () => {
177
+ const { events, calls } = setup({
178
+ summarizeProvider: "",
179
+ summarizeModel: ""
180
+ });
181
+ const handler = events.find((e) => e.name === "session/event").fn;
182
+ const session = {
183
+ id: "s5",
184
+ requestHeader: () => ({ config: { provider: "deepseek", model: "deepseek-chat" } }),
185
+ events: [userMessage("回退测试"), { seq: 2, type: "turn/end" }]
186
+ };
187
+ await handler(session, { seq: 2, type: "turn/end" });
188
+ assert.equal(calls.length, 1);
189
+ assert.equal(calls[0].provider, "deepseek");
190
+ assert.equal(calls[0].model, "deepseek-chat");
191
+ });