dsh-prime-memory 0.26.22 → 0.26.23
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/CHANGELOG.md +8 -0
- package/dist/clients/drsc-inproc.d.ts +1 -1
- package/dist/clients/drsc-inproc.js +49 -18
- package/dsh.plugin.json +1 -1
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
# 更新日志(Changelog)
|
|
2
2
|
|
|
3
|
+
## [0.26.23] — 2026-11-02
|
|
4
|
+
|
|
5
|
+
- **方案 B:DRSC 读面改走 collector 的正式门面(`drsReadFacade`)**。`0.26.21` 的进程内直调虽然绕开了宿主鉴权,但代价是**耦合 collector 的五个内部导出名**(`openProjectionStore`/`createQueryContext`/`search`/`sessionDetail`/`listSessions`),并且**自己另开一份投影库**——多占一份常驻 `summaries` 内存与一个读事务。现在 collector `0.2.5` 导出 `drsReadFacade()`,返回绑它**自己活 QueryContext** 的只读对象;本仓优先用这个门面,只认一个稳定符号,也不再开第二份库。
|
|
6
|
+
- **三条路径的优先级与降级**(`src/clients/drsc-inproc.ts`):① collector ≥0.2.5 且库已就绪 → 走门面;② collector 是新版本但库还在 `setImmediate` 初始化 → **本轮抛可重试错、且不缓存**,让下一次读重取门面。这一点是本轮自查出的真设计缺陷:若此时回退自开库,会把自开库结果**永久缓存**,把「优先用门面」变成只在首轮赌运气。降级走既有链路(背景窗当轮空窗、工具面显式报错),语义与旧 HTTP 遇 `503 initializing` 一致;③ collector 是旧版(无该导出)→ 回退自开只读库(保留 `0.26.21` 行为)。
|
|
7
|
+
- **参数映射不分叉**:门面对象被适配成与兼容路径同一个「模块形」,所以 `op`/`q`/`tail`/`limit`/`redact` 的解析口径、非法值整键缺席、`session` 缺 id 返回空行等语义只有一份实现,两条路径共用。
|
|
8
|
+
- **依赖下限抬到 `>=0.2.5 <0.3.0`**(`package.json` dependencies;`dsh.plugin.json` 的 `pluginDependencies` 只列包名不带区间,无需改)。低于该版仍可用,只是走兼容路径。
|
|
9
|
+
- **测试**:`tests/drsc-inproc.test.ts` 新增 3 例——门面可用时绝不调用 `openProjectionStore`;未就绪时报错且不缓存、对端就绪后下一次读拿到门面;旧版 collector 仍回退自开库。全量 **1904 例 / 190 文件**,typecheck/lint/build/build:smoke/smoke 全 0。
|
|
10
|
+
|
|
3
11
|
## [0.26.22] — 2026-11-02
|
|
4
12
|
|
|
5
13
|
- **#27 真机通过**:用户在 desktop 上 `register(work/dsh-host)` → `list` 显示「**现有 59 条**」,与注册前自生长清单里的 `work/dsh-host(59)` 逐位一致;`?? 0` 分支也未被误伤(有绑定即显示真数)。
|
|
@@ -38,7 +38,7 @@ export interface CollectorReadModule {
|
|
|
38
38
|
}
|
|
39
39
|
/** 注入面(单测);缺省按裸名动态 import。 */
|
|
40
40
|
export type CollectorLoader = () => Promise<CollectorReadModule>;
|
|
41
|
-
/** 清掉缓存(单测用;也供 collector
|
|
41
|
+
/** 清掉缓存(单测用;也供 collector 换装后强制重取)。 */
|
|
42
42
|
export declare function resetCollectorReadState(): void;
|
|
43
43
|
/**
|
|
44
44
|
* 执行一次读,返回与 HTTP 包络同形的对象(`ok:true` + 各 op 的字段)。
|
|
@@ -22,37 +22,67 @@
|
|
|
22
22
|
const COLLECTOR_PACKAGE = 'dsh-reference-session-collector';
|
|
23
23
|
const defaultLoader = async () => (await import(/* @vite-ignore */ COLLECTOR_PACKAGE));
|
|
24
24
|
let modulePromise;
|
|
25
|
-
let queryContext;
|
|
26
25
|
/**
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
* (句柄真为 undefined 时 createQueryContext 会在首读即报错,不会静默重开)。
|
|
26
|
+
* 兼容路径(旧 collector)的只读句柄(`openProjectionStore` 的返回值)。常驻 summaries
|
|
27
|
+
* 是内存 Map,每请求重开等于重扫全表,故只开一次;undefined 是合法的未开哨兵。
|
|
30
28
|
*/
|
|
31
29
|
let storeHandle;
|
|
32
|
-
/** 清掉缓存(单测用;也供 collector
|
|
30
|
+
/** 清掉缓存(单测用;也供 collector 换装后强制重取)。 */
|
|
33
31
|
export function resetCollectorReadState() {
|
|
34
32
|
modulePromise = undefined;
|
|
35
|
-
queryContext = undefined;
|
|
36
33
|
storeHandle = undefined;
|
|
37
34
|
}
|
|
38
|
-
/**
|
|
35
|
+
/** 把门面对象适配成本模块统一的「模块形」,以便与兼容路径共用同一套参数映射。
|
|
36
|
+
* 前三个成员在门面路径上永不会被调用:moduleOf 命中门面后直接返回,不走进兼容分支。
|
|
37
|
+
*/
|
|
38
|
+
function fromFacade(facade) {
|
|
39
|
+
const unused = () => {
|
|
40
|
+
throw new Error('门面路径不应自开投影库');
|
|
41
|
+
};
|
|
42
|
+
return {
|
|
43
|
+
resolveIndexDir: unused,
|
|
44
|
+
openProjectionStore: unused,
|
|
45
|
+
createQueryContext: unused,
|
|
46
|
+
listSessions: (ctx, offset, limit) => facade.listSessions(offset, limit),
|
|
47
|
+
sessionDetail: (ctx, sessionId, opts) => facade.sessionDetail(sessionId, opts),
|
|
48
|
+
search: (ctx, query, opts) => facade.search(query, opts),
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
/** 取一个可用的「模块形」:优先 collector 门面(>=0.2.5),否则回退自开只读库。 */
|
|
39
52
|
async function moduleOf(load) {
|
|
40
|
-
const pending = (modulePromise ??=
|
|
53
|
+
const pending = (modulePromise ??= (async () => {
|
|
54
|
+
const mod = (await load());
|
|
55
|
+
if (typeof mod.drsReadFacade === 'function') {
|
|
56
|
+
const facade = mod.drsReadFacade();
|
|
57
|
+
// 对端是新版本但库未就绪(collector 的重活推迟在 setImmediate 臂):本轮**不**回退
|
|
58
|
+
// 自开库,而是抛可重试错——否则会把自开库结果永久缓存,把“优先用门面”变成
|
|
59
|
+
// 只在首轮赌运气。抛错走既有降级链(背景窗当轮空窗、工具面显式报错),
|
|
60
|
+
// 且不缓存 rejection,下一次读会重取门面。
|
|
61
|
+
if (facade === undefined) {
|
|
62
|
+
throw new Error('collector 投影库尚未就绪(稍后自动重试)');
|
|
63
|
+
}
|
|
64
|
+
return fromFacade(facade);
|
|
65
|
+
}
|
|
66
|
+
return legacyStoreModule(mod);
|
|
67
|
+
})().catch((err) => {
|
|
41
68
|
if (modulePromise === pending)
|
|
42
69
|
modulePromise = undefined;
|
|
43
70
|
throw err;
|
|
44
71
|
}));
|
|
45
72
|
return pending;
|
|
46
73
|
}
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
return queryContext;
|
|
50
|
-
const mod = await moduleOf(load);
|
|
74
|
+
/** 旧 collector(无 drsReadFacade)的兼容路径:自己开一份只读库。 */
|
|
75
|
+
async function legacyStoreModule(mod) {
|
|
51
76
|
if (storeHandle === undefined) {
|
|
52
77
|
storeHandle = mod.openProjectionStore(mod.resolveIndexDir());
|
|
53
78
|
}
|
|
54
|
-
|
|
55
|
-
return
|
|
79
|
+
const ctx = mod.createQueryContext(storeHandle);
|
|
80
|
+
return {
|
|
81
|
+
...mod,
|
|
82
|
+
listSessions: (_c, offset, limit) => mod.listSessions(ctx, offset, limit),
|
|
83
|
+
sessionDetail: (_c, sessionId, opts) => mod.sessionDetail(ctx, sessionId, opts),
|
|
84
|
+
search: (_c, query, opts) => mod.search(ctx, query, opts),
|
|
85
|
+
};
|
|
56
86
|
}
|
|
57
87
|
/** 把 HTTP 查询串拆成参数表(与 collector 路由同源解析口径:它也只读 searchParams)。 */
|
|
58
88
|
function paramsOf(query) {
|
|
@@ -66,7 +96,6 @@ function paramsOf(query) {
|
|
|
66
96
|
* 把传输从 fetch 换成函数调用,不顺手改任何语义。
|
|
67
97
|
*/
|
|
68
98
|
export async function callCollectorRead(query, load = defaultLoader) {
|
|
69
|
-
const ctx = await contextFor(load);
|
|
70
99
|
const mod = await moduleOf(load);
|
|
71
100
|
const p = paramsOf(query);
|
|
72
101
|
const op = p.get('op') ?? '';
|
|
@@ -76,7 +105,7 @@ export async function callCollectorRead(query, load = defaultLoader) {
|
|
|
76
105
|
const limit = positiveInt(p.get('limit'));
|
|
77
106
|
return {
|
|
78
107
|
ok: true,
|
|
79
|
-
...mod.search(
|
|
108
|
+
...mod.search(READ_SURFACE, p.get('q') ?? '', {
|
|
80
109
|
// 非法/缺省时整个键缺席,而不是传 `limit: undefined` —— `'limit' in opts`
|
|
81
110
|
// 与 `opts.limit === undefined` 不是一回事,对端可能按前者走钳位分支。
|
|
82
111
|
...(limit === undefined ? {} : { limit }),
|
|
@@ -90,7 +119,7 @@ export async function callCollectorRead(query, load = defaultLoader) {
|
|
|
90
119
|
return { ok: true, session: null, rows: [] };
|
|
91
120
|
}
|
|
92
121
|
const tail = positiveInt(p.get('tail'));
|
|
93
|
-
const detail = mod.sessionDetail(
|
|
122
|
+
const detail = mod.sessionDetail(READ_SURFACE, sessionId, {
|
|
94
123
|
// collector 侧:tail 为正整数才切尾窗,键缺席即全量(#14-B 的整会话臂依赖这点)。
|
|
95
124
|
...(tail === undefined ? {} : { tail }),
|
|
96
125
|
redact,
|
|
@@ -101,7 +130,7 @@ export async function callCollectorRead(query, load = defaultLoader) {
|
|
|
101
130
|
// 这两个是位置参数,undefined 与“没传”在 JS 里同义,无需上面对象字面量那套处置。
|
|
102
131
|
const offset = positiveInt(p.get('offset')) ?? 0;
|
|
103
132
|
const limit = positiveInt(p.get('limit'));
|
|
104
|
-
return { ok: true, ...mod.listSessions(
|
|
133
|
+
return { ok: true, ...mod.listSessions(READ_SURFACE, offset, limit) };
|
|
105
134
|
}
|
|
106
135
|
throw new Error(`collector 未知 op: ${op === '' ? '(missing)' : op}`);
|
|
107
136
|
}
|
|
@@ -112,3 +141,5 @@ function positiveInt(raw) {
|
|
|
112
141
|
const n = Number(raw);
|
|
113
142
|
return Number.isFinite(n) && n > 0 ? Math.floor(n) : undefined;
|
|
114
143
|
}
|
|
144
|
+
/** 统一形后的模块不再需要真 QueryContext,这个占位只用来占位。 */
|
|
145
|
+
const READ_SURFACE = 'inproc-read-surface';
|
package/dsh.plugin.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"id": "dsh-prime-memory",
|
|
3
3
|
"name": "dsh-prime-memory",
|
|
4
|
-
"version": "0.26.
|
|
4
|
+
"version": "0.26.23",
|
|
5
5
|
"description": {
|
|
6
6
|
"en": "Layered distilled memory plugin (L0 capture → L1 atomic memory → L2 scenes → L3 persona) with automatic recall injection before each model step.",
|
|
7
7
|
"zh": "L0~L3 分层蒸馏记忆插件:自动捕获对话、抽取原子记忆、整合场景块、蒸馏核心画像,并在模型步骤前自动召回注入。"
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-prime-memory",
|
|
3
|
-
"version": "0.26.
|
|
3
|
+
"version": "0.26.23",
|
|
4
4
|
"publishConfig": {
|
|
5
5
|
"registry": "https://registry.npmjs.org",
|
|
6
6
|
"access": "public",
|
|
@@ -98,7 +98,7 @@
|
|
|
98
98
|
"dependencies": {
|
|
99
99
|
"@deepseek-ai/schemastery": "^3.18.4",
|
|
100
100
|
"@node-rs/jieba": "^2.0.2",
|
|
101
|
-
"dsh-reference-session-collector": ">=0.2.
|
|
101
|
+
"dsh-reference-session-collector": ">=0.2.5 <0.3.0",
|
|
102
102
|
"sqlite-vec": "^0.1.7-alpha.2",
|
|
103
103
|
"undici": "^7.29.0"
|
|
104
104
|
},
|