dsh-layered-memory 0.8.3 → 0.8.5
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.en.md +38 -17
- package/README.md +34 -17
- package/assets/img/ui-dark.jpg +0 -0
- package/assets/img/ui-light.jpg +0 -0
- package/assets/readme/bench-dialog.svg +53 -70
- package/assets/readme/bench-workflow.svg +29 -29
- package/dist/bench-control.d.ts +35 -0
- package/dist/bench-control.js +16 -0
- package/dist/client.js +205 -29
- package/dist/config.d.ts +12 -0
- package/dist/config.js +9 -1
- package/dist/hooks/recall.d.ts +23 -0
- package/dist/hooks/recall.js +36 -9
- package/dist/index.d.ts +2 -0
- package/dist/index.js +16 -1
- package/dist/llm-usage.d.ts +27 -0
- package/dist/llm-usage.js +39 -0
- package/dist/llm.d.ts +11 -2
- package/dist/llm.js +20 -6
- package/dist/pipeline/l1.js +4 -2
- package/dist/pipeline/l2.js +1 -0
- package/dist/pipeline/l3.js +1 -0
- package/dist/pipeline/runner.d.ts +16 -0
- package/dist/pipeline/runner.js +60 -0
- package/dist/prompts/l1-extraction.d.ts +7 -1
- package/dist/prompts/l1-extraction.js +12 -3
- package/dist/settings.d.ts +3 -3
- package/dist/settings.js +3 -3
- package/dist/stats.d.ts +27 -1
- package/dist/stats.js +42 -5
- package/dist/store/l0.d.ts +2 -0
- package/dist/store/l0.js +4 -0
- package/dist/store/sqlite.d.ts +2 -0
- package/dist/store/sqlite.js +14 -0
- package/dist/types.d.ts +8 -0
- package/dist/types.js +8 -0
- package/package.json +17 -17
package/dist/stats.js
CHANGED
|
@@ -9,14 +9,15 @@
|
|
|
9
9
|
import { createRequire } from 'node:module';
|
|
10
10
|
import { closeSync, openSync, readSync, statSync } from 'node:fs';
|
|
11
11
|
import { join } from 'node:path';
|
|
12
|
-
import { resolveDataDir } from './config.js';
|
|
12
|
+
import { EFFORT_CHOICES, resolveDataDir } from './config.js';
|
|
13
13
|
import { effectiveCfg } from './pipeline/runner.js';
|
|
14
|
+
import { emptyRecallStats } from './hooks/recall.js';
|
|
14
15
|
import { decideSendableEffort, LAYER_DEFAULT_BUDGETS, resolveModelEfforts, resolveModelRoute } from './llm.js';
|
|
15
16
|
import { errDetail } from './util/filelog.js';
|
|
16
17
|
const require = createRequire(import.meta.url);
|
|
17
18
|
export const PLUGIN_VERSION = require('../package.json').version;
|
|
18
19
|
/** 注册状态 RPC(web 侧 connection 服务可选,缺失时跳过,不影响插件主体)。 */
|
|
19
|
-
export function registerMemoryRpc(ctx, cfg, stores, logger, status, live, modes, dataDir, rebuild, embedManager) {
|
|
20
|
+
export function registerMemoryRpc(ctx, cfg, stores, logger, status, live, modes, dataDir, rebuild, embedManager, sessionInfo) {
|
|
20
21
|
/** 当前是否持有一段有效注册(dispose 完成后清空,允许服务重上线时重注册)。 */
|
|
21
22
|
let holding = false;
|
|
22
23
|
/** 当前 handle 绑定的 connection 实例(internal/service 第二参;用于识别实例替换)。 */
|
|
@@ -43,6 +44,7 @@ export function registerMemoryRpc(ctx, cfg, stores, logger, status, live, modes,
|
|
|
43
44
|
logger,
|
|
44
45
|
rebuild,
|
|
45
46
|
embedManager,
|
|
47
|
+
sessionInfo,
|
|
46
48
|
});
|
|
47
49
|
return { ok: true, value };
|
|
48
50
|
}
|
|
@@ -142,7 +144,7 @@ function expectSessionId(v) {
|
|
|
142
144
|
return v;
|
|
143
145
|
}
|
|
144
146
|
async function handleEndpoint(endpoint, payload, deps) {
|
|
145
|
-
const { cfg, stores, status, live, modes, dataDir, rebuild, embedManager } = deps;
|
|
147
|
+
const { cfg, stores, status, live, modes, dataDir, rebuild, embedManager, sessionInfo } = deps;
|
|
146
148
|
switch (endpoint) {
|
|
147
149
|
case 'dsh-memory/stats':
|
|
148
150
|
return buildStats(cfg, stores, status);
|
|
@@ -166,6 +168,39 @@ async function handleEndpoint(endpoint, payload, deps) {
|
|
|
166
168
|
deps.logger.info(`[memory] 会话档位设置 session=${sessionId} mode=${p.mode}`);
|
|
167
169
|
return { sessionId, mode: p.mode };
|
|
168
170
|
}
|
|
171
|
+
// ── 会话级统计(悬浮卡信息区;热路径端点,见 SessionInfoSource 的零 I/O 硬规则) ──
|
|
172
|
+
case 'dsh-memory/session-stats': {
|
|
173
|
+
if (!sessionInfo)
|
|
174
|
+
return { supported: false };
|
|
175
|
+
const p = (payload ?? {});
|
|
176
|
+
const sessionId = expectSessionId(p.sessionId);
|
|
177
|
+
const mode = modes ? modes.get(sessionId) : 'auto';
|
|
178
|
+
const caps = sessionInfo.capabilities();
|
|
179
|
+
const l0Count = await sessionInfo.l0Count(sessionId);
|
|
180
|
+
const s = live?.get();
|
|
181
|
+
const recallOn = cfg.recall.enabled && (s?.recall ?? true) && mode !== 'off';
|
|
182
|
+
const view = sessionInfo.runnerView(sessionId, mode);
|
|
183
|
+
// lastDistillAt 统一转 ISO(与 global.lastExtractAt 口径一致,client 直接 fmtAgo)
|
|
184
|
+
const distillView = { ...view, lastDistillAt: view.lastDistillAt ? new Date(view.lastDistillAt).toISOString() : null };
|
|
185
|
+
const chat = stores.state.forFamily('chat');
|
|
186
|
+
const work = stores.state.forFamily('work');
|
|
187
|
+
const lastAt = Math.max(chat.lastExtractAt, work.lastExtractAt);
|
|
188
|
+
return {
|
|
189
|
+
supported: true,
|
|
190
|
+
sessionId,
|
|
191
|
+
mode,
|
|
192
|
+
defaultMode: modes?.default ?? cfg.family,
|
|
193
|
+
recall: { enabled: recallOn, ...(sessionInfo.recallStats(sessionId) ?? emptyRecallStats()) },
|
|
194
|
+
distill: distillView,
|
|
195
|
+
l0Count,
|
|
196
|
+
retrieval: caps.vectorSearch ? (caps.ftsSearch ? 'hybrid' : 'vector') : caps.ftsSearch ? 'keyword' : 'none',
|
|
197
|
+
global: {
|
|
198
|
+
degraded: status?.degraded() ?? false,
|
|
199
|
+
pendingTotal: status?.pending() ?? 0,
|
|
200
|
+
lastExtractAt: lastAt ? new Date(lastAt).toISOString() : null,
|
|
201
|
+
},
|
|
202
|
+
};
|
|
203
|
+
}
|
|
169
204
|
case 'dsh-memory/settings-get': {
|
|
170
205
|
const s = live?.get();
|
|
171
206
|
const budgets = s?.distillBudgets ?? { extract: 0, dedup: 0, l2: 0, l3: 0 };
|
|
@@ -234,8 +269,10 @@ async function handleEndpoint(endpoint, payload, deps) {
|
|
|
234
269
|
}
|
|
235
270
|
if (patch.reasoningEffort !== undefined) {
|
|
236
271
|
const v = String(patch.reasoningEffort);
|
|
237
|
-
|
|
238
|
-
|
|
272
|
+
// 白名单与 schema/settings 同源(config.ts EFFORT_CHOICES)——此前此处漏扩词表,
|
|
273
|
+
// 设置页新词汇(none/minimal/low/medium/xhigh)被拒并回滚
|
|
274
|
+
if (!EFFORT_CHOICES.includes(v)) {
|
|
275
|
+
throw new Error(`非法思考档位: ${v}(允许 '' 或 ${EFFORT_CHOICES.filter((x) => x !== '').join('/')})`);
|
|
239
276
|
}
|
|
240
277
|
clean.reasoningEffort = v;
|
|
241
278
|
}
|
package/dist/store/l0.d.ts
CHANGED
|
@@ -15,6 +15,8 @@ export declare class L0Store {
|
|
|
15
15
|
append(sessionId: string, messages: ConversationMessage[]): Promise<void>;
|
|
16
16
|
/** 今日已捕获消息数(SQL 计数,不再读整文件)。 */
|
|
17
17
|
countToday(): Promise<number>;
|
|
18
|
+
/** 该会话累计已捕获消息数(session-stats 数据源;索引 COUNT)。 */
|
|
19
|
+
countBySession(sessionId: string): Promise<number>;
|
|
18
20
|
/** 该会话最近 n 条消息(时间升序;蒸馏背景参考用,按会话现查——ADR-0003)。 */
|
|
19
21
|
recentBySession(sessionId: string, limit: number): Promise<ConversationMessage[]>;
|
|
20
22
|
/** 检索:FTS + 向量 hybrid(RRF 融合),返回按相关性排序的消息。 */
|
package/dist/store/l0.js
CHANGED
|
@@ -104,6 +104,10 @@ export class L0Store {
|
|
|
104
104
|
const d = new Date();
|
|
105
105
|
return this.db.countL0Since(new Date(d.getFullYear(), d.getMonth(), d.getDate()).toISOString());
|
|
106
106
|
}
|
|
107
|
+
/** 该会话累计已捕获消息数(session-stats 数据源;索引 COUNT)。 */
|
|
108
|
+
async countBySession(sessionId) {
|
|
109
|
+
return this.db.countL0BySession(sessionId);
|
|
110
|
+
}
|
|
107
111
|
/** 该会话最近 n 条消息(时间升序;蒸馏背景参考用,按会话现查——ADR-0003)。 */
|
|
108
112
|
async recentBySession(sessionId, limit) {
|
|
109
113
|
return this.db.recentL0BySession(sessionId, limit);
|
package/dist/store/sqlite.d.ts
CHANGED
|
@@ -148,6 +148,8 @@ export declare class MemoryDb {
|
|
|
148
148
|
countL0(): number;
|
|
149
149
|
/** 统计 recorded_at >= iso 的消息数(状态面板"今日捕获"用)。 */
|
|
150
150
|
countL0Since(iso: string): number;
|
|
151
|
+
/** 统计某会话已捕获消息数(session-stats 数据源;idx_l0_session_id 索引点查)。 */
|
|
152
|
+
countL0BySession(sessionId: string): number;
|
|
151
153
|
/** 按会话取最近消息(时间升序返回;走 idx_l0_session_id 索引)。
|
|
152
154
|
* 蒸馏背景参考专用——按会话现查替代全局内存数组(ADR-0003)。 */
|
|
153
155
|
recentL0BySession(sessionId: string, limit: number): L0MessageRecord[];
|
package/dist/store/sqlite.js
CHANGED
|
@@ -989,6 +989,20 @@ export class MemoryDb {
|
|
|
989
989
|
return 0;
|
|
990
990
|
}
|
|
991
991
|
}
|
|
992
|
+
/** 统计某会话已捕获消息数(session-stats 数据源;idx_l0_session_id 索引点查)。 */
|
|
993
|
+
countL0BySession(sessionId) {
|
|
994
|
+
if (this.degraded)
|
|
995
|
+
return 0;
|
|
996
|
+
try {
|
|
997
|
+
const row = this.db
|
|
998
|
+
.prepare('SELECT COUNT(*) AS n FROM l0_conversations WHERE session_id = ?')
|
|
999
|
+
.get(sessionId);
|
|
1000
|
+
return row?.n ?? 0;
|
|
1001
|
+
}
|
|
1002
|
+
catch {
|
|
1003
|
+
return 0;
|
|
1004
|
+
}
|
|
1005
|
+
}
|
|
992
1006
|
/** 按会话取最近消息(时间升序返回;走 idx_l0_session_id 索引)。
|
|
993
1007
|
* 蒸馏背景参考专用——按会话现查替代全局内存数组(ADR-0003)。 */
|
|
994
1008
|
recentL0BySession(sessionId, limit) {
|
package/dist/types.d.ts
CHANGED
|
@@ -43,7 +43,15 @@ export interface ExtractedMemory {
|
|
|
43
43
|
metadata: Record<string, unknown>;
|
|
44
44
|
/** 所属情境名(L1 抽取的情境切分结果)。 */
|
|
45
45
|
scene_name: string;
|
|
46
|
+
/** auto 档抽取输出的显式族判定(chat|work;纯档 Prompt 无此字段)。
|
|
47
|
+
* 语境归族、形状不归族——修复"个人计划性事实被 work_* 形状吸走"的族错标
|
|
48
|
+
* (2026-08-23 lifecycle 赛道实测发现)。 */
|
|
49
|
+
family?: string;
|
|
46
50
|
}
|
|
51
|
+
/** 抽取输出的 family 字段归一:只认 chat|work,其余(缺省/非法值)交由调用方回落。 */
|
|
52
|
+
export declare function normExtractedFamily(raw: unknown): MemoryFamily | undefined;
|
|
53
|
+
/** 记录族三级兜底链:会话档位强制(纯档)→ 抽取显式判定(auto)→ type 前缀推导(旧输出兜底)。 */
|
|
54
|
+
export declare function resolveRecordFamily(forced: MemoryFamily | undefined, extracted: unknown, type: string): MemoryFamily;
|
|
47
55
|
/** L1 持久化记录(字段对齐 MemoryCore;version/source_message_ids/metadata 由写入侧补默认)。 */
|
|
48
56
|
export interface MemoryRecord {
|
|
49
57
|
id: string;
|
package/dist/types.js
CHANGED
|
@@ -5,3 +5,11 @@
|
|
|
5
5
|
export function familyForType(type) {
|
|
6
6
|
return type.startsWith('work') ? 'work' : 'chat';
|
|
7
7
|
}
|
|
8
|
+
/** 抽取输出的 family 字段归一:只认 chat|work,其余(缺省/非法值)交由调用方回落。 */
|
|
9
|
+
export function normExtractedFamily(raw) {
|
|
10
|
+
return raw === 'chat' || raw === 'work' ? raw : undefined;
|
|
11
|
+
}
|
|
12
|
+
/** 记录族三级兜底链:会话档位强制(纯档)→ 抽取显式判定(auto)→ type 前缀推导(旧输出兜底)。 */
|
|
13
|
+
export function resolveRecordFamily(forced, extracted, type) {
|
|
14
|
+
return forced ?? normExtractedFamily(extracted) ?? familyForType(type);
|
|
15
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-layered-memory",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.5",
|
|
4
4
|
"description": "L0~L3 分层蒸馏记忆插件 for DeepSeek Harness:自动捕获对话(L0)、抽取原子记忆(L1)、整合场景块(L2)、蒸馏核心画像/团队方法论(L3),并在模型步骤前自动召回注入。移植自 MemoryCore (TencentDB Agent Memory) 的管线设计。",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -58,25 +58,25 @@
|
|
|
58
58
|
},
|
|
59
59
|
"peerDependencies": {
|
|
60
60
|
"@deepseek-ai/cordis": "^4.0.1",
|
|
61
|
-
"@deepseek-ai/dsh-agent": "^0.1.
|
|
62
|
-
"@deepseek-ai/dsh-home-paths": "^0.1.
|
|
63
|
-
"@deepseek-ai/dsh-llm": "^0.1.
|
|
64
|
-
"@deepseek-ai/dsh-session": "^0.1.
|
|
65
|
-
"@deepseek-ai/dsh-settings": "^0.1.
|
|
66
|
-
"@deepseek-ai/dsh-system-prompt": "^0.1.
|
|
67
|
-
"@deepseek-ai/dsh-tools": "^0.1.
|
|
61
|
+
"@deepseek-ai/dsh-agent": "^0.1.1-rc.2",
|
|
62
|
+
"@deepseek-ai/dsh-home-paths": "^0.1.1-rc.2",
|
|
63
|
+
"@deepseek-ai/dsh-llm": "^0.1.1-rc.2",
|
|
64
|
+
"@deepseek-ai/dsh-session": "^0.1.1-rc.2",
|
|
65
|
+
"@deepseek-ai/dsh-settings": "^0.1.1-rc.2",
|
|
66
|
+
"@deepseek-ai/dsh-system-prompt": "^0.1.1-rc.2",
|
|
67
|
+
"@deepseek-ai/dsh-tools": "^0.1.1-rc.2"
|
|
68
68
|
},
|
|
69
69
|
"devDependencies": {
|
|
70
70
|
"@deepseek-ai/cordis": "4.0.1",
|
|
71
|
-
"@deepseek-ai/dsh-agent": "0.1.
|
|
72
|
-
"@deepseek-ai/dsh-agent-default-model": "0.1.
|
|
73
|
-
"@deepseek-ai/dsh-client-connection": "0.1.
|
|
74
|
-
"@deepseek-ai/dsh-home-paths": "0.1.
|
|
75
|
-
"@deepseek-ai/dsh-llm": "0.1.
|
|
76
|
-
"@deepseek-ai/dsh-session": "0.1.
|
|
77
|
-
"@deepseek-ai/dsh-settings": "0.1.
|
|
78
|
-
"@deepseek-ai/dsh-system-prompt": "0.1.
|
|
79
|
-
"@deepseek-ai/dsh-tools": "0.1.
|
|
71
|
+
"@deepseek-ai/dsh-agent": "0.1.1-rc.2",
|
|
72
|
+
"@deepseek-ai/dsh-agent-default-model": "0.1.1-rc.2",
|
|
73
|
+
"@deepseek-ai/dsh-client-connection": "0.1.1-rc.2",
|
|
74
|
+
"@deepseek-ai/dsh-home-paths": "0.1.1-rc.2",
|
|
75
|
+
"@deepseek-ai/dsh-llm": "0.1.1-rc.2",
|
|
76
|
+
"@deepseek-ai/dsh-session": "0.1.1-rc.2",
|
|
77
|
+
"@deepseek-ai/dsh-settings": "0.1.1-rc.2",
|
|
78
|
+
"@deepseek-ai/dsh-system-prompt": "0.1.1-rc.2",
|
|
79
|
+
"@deepseek-ai/dsh-tools": "0.1.1-rc.2",
|
|
80
80
|
"@types/node": "^22.0.0",
|
|
81
81
|
"typescript": "^5.6.0"
|
|
82
82
|
}
|