dsh-layered-memory 0.6.1 → 0.7.1
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 +106 -81
- package/README.md +93 -80
- package/assets/img/Hero.png +0 -0
- package/assets/img/Layers.png +0 -0
- package/assets/img/Modes.png +0 -0
- package/assets/img/ui-dark.jpg +0 -0
- package/assets/img/ui-light.jpg +0 -0
- package/assets/readme/flow.svg +189 -0
- package/assets/readme/storage.svg +115 -0
- package/dist/client.js +1100 -402
- package/dist/config.d.ts +12 -0
- package/dist/config.js +20 -17
- package/dist/hooks/capture.d.ts +17 -1
- package/dist/hooks/capture.js +45 -11
- package/dist/hooks/recall.d.ts +7 -0
- package/dist/hooks/recall.js +20 -4
- package/dist/index.d.ts +8 -0
- package/dist/index.js +107 -44
- package/dist/pipeline/rebuild.d.ts +2 -0
- package/dist/pipeline/rebuild.js +7 -0
- package/dist/pipeline/runner.d.ts +7 -1
- package/dist/pipeline/runner.js +22 -7
- package/dist/runtime-package-lock.json +982 -0
- package/dist/settings.js +79 -20
- package/dist/stats.d.ts +7 -1
- package/dist/stats.js +131 -14
- package/dist/store/download-queue.d.ts +71 -0
- package/dist/store/download-queue.js +313 -0
- package/dist/store/embedding-source.d.ts +160 -0
- package/dist/store/embedding-source.js +421 -0
- package/dist/store/embedding.d.ts +3 -1
- package/dist/store/embedding.js +5 -0
- package/dist/store/l0.d.ts +13 -5
- package/dist/store/l0.js +40 -10
- package/dist/store/l1.d.ts +15 -5
- package/dist/store/l1.js +47 -19
- package/dist/store/local-embedding.d.ts +64 -0
- package/dist/store/local-embedding.js +120 -0
- package/dist/store/model-catalog.d.ts +45 -0
- package/dist/store/model-catalog.js +78 -0
- package/dist/store/runtime-installer.d.ts +65 -0
- package/dist/store/runtime-installer.js +220 -0
- package/dist/store/sqlite.d.ts +68 -7
- package/dist/store/sqlite.js +422 -73
- package/dist/tools/index.js +6 -4
- package/dist/util/filelog.d.ts +2 -0
- package/dist/util/filelog.js +20 -3
- package/package.json +1 -1
- package/assets/readme/hero.svg +0 -58
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 运行时安装器(D8 决策):本地嵌入的推理运行时(@huggingface/transformers,
|
|
3
|
+
* 纯库、二进制随 npm 包分发、零 postinstall)在用户首次开启本地嵌入时才安装——
|
|
4
|
+
* 插件 npm 包本体不带重依赖,不用本地嵌入的用户零成本。
|
|
5
|
+
*
|
|
6
|
+
* - 安装位置:数据目录 runtime/(自带 package.json 锚定,防 npm 向上层目录逃逸安装);
|
|
7
|
+
* - 子进程 npm ci --ignore-scripts --no-audit --no-fund,钉死精确版本 + 随包 lockfile
|
|
8
|
+
* (resources/runtime-package-lock.json,构建期拷入 dist/)锁定完整传递依赖树——
|
|
9
|
+
* 纯 install 只锁直接依赖的精确版本,传递依赖按 semver 浮动解析,registry 端
|
|
10
|
+
* 后续发布/投毒会随安装时间漂移;lockfile 把树冻结在作者侧。ci 失败(lock 与
|
|
11
|
+
* package.json 漂移等)自动回退 npm install 精确版本(可用性优先,树不再受锁);
|
|
12
|
+
* - 进度(用户硬性要求:不能傻等):npm 非交互模式无百分比 API,采用不确定进度——
|
|
13
|
+
* 已耗时 + 子进程 stdout/stderr 尾行实时流出 + 可 kill;
|
|
14
|
+
* - 幂等:已装版本 == 目标版本直接就绪;版本漂移(插件升级换了钉死版本)重装覆盖。
|
|
15
|
+
*/
|
|
16
|
+
import { spawn } from 'node:child_process';
|
|
17
|
+
import { createRequire } from 'node:module';
|
|
18
|
+
import { promises as fs } from 'node:fs';
|
|
19
|
+
import * as path from 'node:path';
|
|
20
|
+
import { fileURLToPath } from 'node:url';
|
|
21
|
+
/** 钉死的 transformers.js 版本(D8:精确版本,升级插件时在此变更并重装运行时)。 */
|
|
22
|
+
export const PINNED_TRANSFORMERS_VERSION = '4.2.0';
|
|
23
|
+
export class RuntimeInstaller {
|
|
24
|
+
runtimeDir;
|
|
25
|
+
target;
|
|
26
|
+
logger;
|
|
27
|
+
spawnImpl;
|
|
28
|
+
/** 随包 lockfile 路径(测试可注入;默认取 dist 根下构建期拷入的资产)。 */
|
|
29
|
+
lockfileSource;
|
|
30
|
+
progress;
|
|
31
|
+
child = null;
|
|
32
|
+
current = null;
|
|
33
|
+
/** 安装超时(npm 卡死不罕见:registry 停滞即永挂,applyBusy 会被锁死)。每次 spawn 独立计时。 */
|
|
34
|
+
static INSTALL_TIMEOUT_MS = 10 * 60_000;
|
|
35
|
+
constructor(dataDir, targetVersion, opts) {
|
|
36
|
+
this.runtimeDir = path.join(dataDir, 'runtime');
|
|
37
|
+
this.target = targetVersion;
|
|
38
|
+
this.logger = opts?.logger;
|
|
39
|
+
this.lockfileSource =
|
|
40
|
+
opts?.lockfileSource ?? path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..', 'runtime-package-lock.json');
|
|
41
|
+
this.spawnImpl =
|
|
42
|
+
opts?.spawnImpl ??
|
|
43
|
+
((command, args, cwd) => {
|
|
44
|
+
const child = spawn(command, args, {
|
|
45
|
+
cwd,
|
|
46
|
+
// Windows 上 .cmd 必须走 shell(Node 20+ 安全限制);参数全部来自插件常量,无注入面
|
|
47
|
+
shell: process.platform === 'win32',
|
|
48
|
+
windowsHide: true,
|
|
49
|
+
});
|
|
50
|
+
const spawned = {
|
|
51
|
+
onStdout(cb) {
|
|
52
|
+
child.stdout?.on('data', (d) => String(d).split(/\r?\n/).forEach((l) => l && cb(l)));
|
|
53
|
+
},
|
|
54
|
+
onStderr(cb) {
|
|
55
|
+
child.stderr?.on('data', (d) => String(d).split(/\r?\n/).forEach((l) => l && cb(l)));
|
|
56
|
+
},
|
|
57
|
+
kill: () => child.kill(),
|
|
58
|
+
// 'error'(如 ENOENT:PATH 无 npm)只发 error 不发 close——不监听会永挂
|
|
59
|
+
exited: new Promise((resolve) => {
|
|
60
|
+
child.on('close', (code) => resolve(code));
|
|
61
|
+
child.on('error', () => resolve(null));
|
|
62
|
+
}),
|
|
63
|
+
};
|
|
64
|
+
return spawned;
|
|
65
|
+
});
|
|
66
|
+
this.progress = {
|
|
67
|
+
phase: 'idle',
|
|
68
|
+
targetVersion: targetVersion,
|
|
69
|
+
installedVersion: null,
|
|
70
|
+
startedAt: 0,
|
|
71
|
+
elapsedMs: 0,
|
|
72
|
+
lastLines: [],
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
/** 包内模块名(与钉死版本一起构成安装目标)。 */
|
|
76
|
+
static packageName = '@huggingface/transformers';
|
|
77
|
+
/** 进度快照。 */
|
|
78
|
+
getProgress() {
|
|
79
|
+
const elapsed = this.progress.phase === 'installing' ? Date.now() - this.progress.startedAt : this.progress.elapsedMs;
|
|
80
|
+
return { ...this.progress, lastLines: [...this.progress.lastLines], elapsedMs: elapsed };
|
|
81
|
+
}
|
|
82
|
+
pkgJsonPath() {
|
|
83
|
+
return path.join(this.runtimeDir, 'node_modules', RuntimeInstaller.packageName, 'package.json');
|
|
84
|
+
}
|
|
85
|
+
/** 已就位版本(读 package.json;未安装返回 null)。 */
|
|
86
|
+
async installedVersion() {
|
|
87
|
+
try {
|
|
88
|
+
const raw = await fs.readFile(this.pkgJsonPath(), 'utf8');
|
|
89
|
+
const pkg = JSON.parse(raw);
|
|
90
|
+
return typeof pkg.version === 'string' ? pkg.version : null;
|
|
91
|
+
}
|
|
92
|
+
catch {
|
|
93
|
+
return null;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
/** 是否就绪(版本精确匹配目标)。 */
|
|
97
|
+
async isReady() {
|
|
98
|
+
return (await this.installedVersion()) === this.target;
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* 确保运行时就位:版本匹配直接就绪;否则安装(忙时并 await 同一次任务)。
|
|
102
|
+
* 返回是否就绪(失败/取消返回 false 并在 progress.error 说明原因)。
|
|
103
|
+
*/
|
|
104
|
+
async ensure() {
|
|
105
|
+
if (await this.isReady()) {
|
|
106
|
+
this.progress.phase = 'ready';
|
|
107
|
+
this.progress.installedVersion = this.target;
|
|
108
|
+
return true;
|
|
109
|
+
}
|
|
110
|
+
if (this.current)
|
|
111
|
+
return this.current;
|
|
112
|
+
this.current = this.installOnce();
|
|
113
|
+
try {
|
|
114
|
+
return await this.current;
|
|
115
|
+
}
|
|
116
|
+
finally {
|
|
117
|
+
this.current = null;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
/** 取消安装(kill 子进程;node_modules 残留无害,npm 幂等重装)。 */
|
|
121
|
+
cancel() {
|
|
122
|
+
if (this.progress.phase !== 'installing' || !this.child)
|
|
123
|
+
return false;
|
|
124
|
+
this.progress.phase = 'cancelled';
|
|
125
|
+
this.child.kill();
|
|
126
|
+
return true;
|
|
127
|
+
}
|
|
128
|
+
/** 从 runtime 目录解析已安装的 transformers 模块(LocalEmbeddingService 用)。 */
|
|
129
|
+
resolveModule() {
|
|
130
|
+
const req = createRequire(path.join(this.runtimeDir, 'package.json'));
|
|
131
|
+
return req(RuntimeInstaller.packageName);
|
|
132
|
+
}
|
|
133
|
+
pushLine(line) {
|
|
134
|
+
const lines = this.progress.lastLines;
|
|
135
|
+
lines.push(line.length > 300 ? line.slice(0, 300) + '…' : line);
|
|
136
|
+
if (lines.length > 5)
|
|
137
|
+
lines.splice(0, lines.length - 5);
|
|
138
|
+
}
|
|
139
|
+
/** 跑一次 npm 子进程(采集尾行 + 超时 kill),返回退出码(null = 被杀死/启动失败)。 */
|
|
140
|
+
async runNpm(args) {
|
|
141
|
+
const child = this.spawnImpl('npm', args, this.runtimeDir);
|
|
142
|
+
this.child = child;
|
|
143
|
+
child.onStdout((l) => this.pushLine(l));
|
|
144
|
+
child.onStderr((l) => this.pushLine(l));
|
|
145
|
+
const timeout = setTimeout(() => {
|
|
146
|
+
this.pushLine('安装超时(10 分钟),终止子进程');
|
|
147
|
+
child.kill();
|
|
148
|
+
}, RuntimeInstaller.INSTALL_TIMEOUT_MS);
|
|
149
|
+
const code = await child.exited;
|
|
150
|
+
clearTimeout(timeout);
|
|
151
|
+
this.child = null;
|
|
152
|
+
return code;
|
|
153
|
+
}
|
|
154
|
+
async installOnce() {
|
|
155
|
+
// 锚定 package.json(带精确依赖):没有它 npm 会向上层目录找最近的 package.json 安装(逃逸事故);
|
|
156
|
+
// npm ci 还要求它与 lockfile 根条目一致——每次安装都写规范化形状,覆盖历史遗留/被 npm 改写的副本。
|
|
157
|
+
await fs.mkdir(this.runtimeDir, { recursive: true });
|
|
158
|
+
const manifest = {
|
|
159
|
+
name: 'dsh-memory-runtime',
|
|
160
|
+
private: true,
|
|
161
|
+
dependencies: { [RuntimeInstaller.packageName]: this.target },
|
|
162
|
+
};
|
|
163
|
+
await fs.writeFile(path.join(this.runtimeDir, 'package.json'), JSON.stringify(manifest, null, 2));
|
|
164
|
+
this.progress = {
|
|
165
|
+
phase: 'installing',
|
|
166
|
+
targetVersion: this.target,
|
|
167
|
+
installedVersion: await this.installedVersion(),
|
|
168
|
+
startedAt: Date.now(),
|
|
169
|
+
elapsedMs: 0,
|
|
170
|
+
lastLines: [],
|
|
171
|
+
};
|
|
172
|
+
this.logger?.info(`[memory] 运行时安装开始: ${RuntimeInstaller.packageName}@${this.target} → ${this.runtimeDir}`);
|
|
173
|
+
// 首选 npm ci + 随包 lockfile(传递依赖树冻结在作者侧);lockfile 资产缺失(npm 包被裁剪等)
|
|
174
|
+
// 或 ci 失败(lock 与锚定版本漂移等)回退 npm install 精确版本——可用性优先。
|
|
175
|
+
let code = null;
|
|
176
|
+
let usedCi = false;
|
|
177
|
+
try {
|
|
178
|
+
const lock = await fs.readFile(this.lockfileSource, 'utf8');
|
|
179
|
+
await fs.writeFile(path.join(this.runtimeDir, 'package-lock.json'), lock);
|
|
180
|
+
this.pushLine(`npm ci(随包 lockfile 锁定依赖树,@${this.target},--ignore-scripts)`);
|
|
181
|
+
usedCi = true;
|
|
182
|
+
code = await this.runNpm(['ci', '--ignore-scripts', '--no-audit', '--no-fund', '--loglevel', 'notice']);
|
|
183
|
+
}
|
|
184
|
+
catch {
|
|
185
|
+
/* 无随包 lockfile,直接走 install 回退 */
|
|
186
|
+
}
|
|
187
|
+
if (!usedCi || code !== 0) {
|
|
188
|
+
if (usedCi) {
|
|
189
|
+
this.pushLine('npm ci 失败(lockfile 与钉死版本漂移?),回退 npm install');
|
|
190
|
+
this.logger?.warn('[memory] 运行时 npm ci 失败,回退 npm install(传递依赖不再受随包 lockfile 锁定)');
|
|
191
|
+
}
|
|
192
|
+
this.pushLine(`npm install ${RuntimeInstaller.packageName}@${this.target}(--ignore-scripts)`);
|
|
193
|
+
code = await this.runNpm([
|
|
194
|
+
'install',
|
|
195
|
+
'--ignore-scripts',
|
|
196
|
+
'--no-audit',
|
|
197
|
+
'--no-fund',
|
|
198
|
+
'--loglevel',
|
|
199
|
+
'notice',
|
|
200
|
+
`${RuntimeInstaller.packageName}@${this.target}`,
|
|
201
|
+
]);
|
|
202
|
+
}
|
|
203
|
+
this.progress.elapsedMs = Date.now() - this.progress.startedAt;
|
|
204
|
+
const version = await this.installedVersion();
|
|
205
|
+
this.progress.installedVersion = version;
|
|
206
|
+
if (this.progress.phase === 'cancelled') {
|
|
207
|
+
this.logger?.warn('[memory] 运行时安装已取消(残留无害,重装幂等)');
|
|
208
|
+
return false;
|
|
209
|
+
}
|
|
210
|
+
if (code === 0 && version === this.target) {
|
|
211
|
+
this.progress.phase = 'ready';
|
|
212
|
+
this.logger?.info(`[memory] 运行时安装完成: v${version}`);
|
|
213
|
+
return true;
|
|
214
|
+
}
|
|
215
|
+
this.progress.phase = 'error';
|
|
216
|
+
this.progress.error = `npm 退出码 ${code ?? '被杀死'}${version ? `(就位版本 ${version})` : '(模块未就位)'}`;
|
|
217
|
+
this.logger?.warn(`[memory] 运行时安装失败: ${this.progress.error}`);
|
|
218
|
+
return false;
|
|
219
|
+
}
|
|
220
|
+
}
|
package/dist/store/sqlite.d.ts
CHANGED
|
@@ -28,7 +28,9 @@ export declare class MemoryDb {
|
|
|
28
28
|
private degraded;
|
|
29
29
|
private ftsAvailable;
|
|
30
30
|
private vecLoaded;
|
|
31
|
-
private
|
|
31
|
+
private vecLoadWarned;
|
|
32
|
+
/** 向量维度:活切换嵌入源(D5)时会变——vec0 表随维度重建。 */
|
|
33
|
+
private dimensions;
|
|
32
34
|
private readonly logger?;
|
|
33
35
|
private stmtUpsertL1;
|
|
34
36
|
private stmtGetL1;
|
|
@@ -41,6 +43,7 @@ export declare class MemoryDb {
|
|
|
41
43
|
private stmtL1FtsSearch;
|
|
42
44
|
private stmtL1FtsSearchFamily;
|
|
43
45
|
private stmtUpsertL0;
|
|
46
|
+
private stmtGetL0;
|
|
44
47
|
private stmtDeleteL0Vec?;
|
|
45
48
|
private stmtInsertL0Vec?;
|
|
46
49
|
private stmtSearchL0Vec?;
|
|
@@ -55,6 +58,21 @@ export declare class MemoryDb {
|
|
|
55
58
|
* providerInfo 变化(provider/model/维度)时 drop 向量表并返回 needsReindex。
|
|
56
59
|
*/
|
|
57
60
|
init(providerInfo?: EmbeddingProviderInfo): StoreInitResult;
|
|
61
|
+
/** 惰性加载 sqlite-vec(纯 FTS 起步后切本地嵌入时补加载);失败只停用向量能力并告警一次。 */
|
|
62
|
+
private ensureVecLoaded;
|
|
63
|
+
/**
|
|
64
|
+
* 活切换嵌入源(D5):provider/model/维度任一变化 → drop 向量表按新维度重建,
|
|
65
|
+
* 返回 needsReindex=true(调用方后台重嵌,全部成功后 markEmbeddingSynced);
|
|
66
|
+
* 配置未变化 → false(切回同一模型不重嵌)。
|
|
67
|
+
* 新维度 > 0 但 sqlite-vec 不可用 → ok=false(调用方向用户说明,维持 FTS)。
|
|
68
|
+
*/
|
|
69
|
+
swapProvider(info: EmbeddingProviderInfo): {
|
|
70
|
+
ok: boolean;
|
|
71
|
+
needsReindex: boolean;
|
|
72
|
+
error?: string;
|
|
73
|
+
};
|
|
74
|
+
/** l1_vec 物理表的向量维度(建表 DDL 里的 float[N]);无表返回 null。 */
|
|
75
|
+
private physicalVecDims;
|
|
58
76
|
private initSchema;
|
|
59
77
|
private prepareL1VecStatements;
|
|
60
78
|
private prepareL0VecStatements;
|
|
@@ -66,15 +84,28 @@ export declare class MemoryDb {
|
|
|
66
84
|
private readEmbeddingMeta;
|
|
67
85
|
private writeEmbeddingMeta;
|
|
68
86
|
/**
|
|
69
|
-
*
|
|
70
|
-
*
|
|
71
|
-
*
|
|
87
|
+
* 持久化 embedding meta(语义:物理向量表当前对应的 provider/维度)。
|
|
88
|
+
* 活切换在 swapProvider 成功后即写(表已是新维度);启动/补齐链在
|
|
89
|
+
* 缺失向量补齐收敛(missing=0)后写——缺失行补齐判据是行数差,
|
|
90
|
+
* 不依赖 meta(review P7 语义在 backfill 计数判据下仍然收敛)。
|
|
72
91
|
*/
|
|
73
92
|
markEmbeddingSynced(info: EmbeddingProviderInfo): void;
|
|
74
93
|
/** upsert 一条 L1(元数据 + FTS 同步;embedding 非零时写向量)。失败返回 false 不抛。 */
|
|
75
94
|
upsertL1(record: MemoryRecord, embedding?: Float32Array): boolean;
|
|
76
|
-
/**
|
|
95
|
+
/**
|
|
96
|
+
* 批量 upsert L1(单事务;与单条同语义:FTS 失败整批回滚)。
|
|
97
|
+
* 追加/导入热路径用它——逐条开事务在 WAL FULL 下每条一次 fsync。
|
|
98
|
+
* 整批失败时回退逐条写入:好记录照常入库、坏记录只丢自身——否则
|
|
99
|
+
* JSONL 事实源已先行追加,检索库却整批缺失且无自动重导路径(批次空洞)。
|
|
100
|
+
*/
|
|
101
|
+
upsertL1Batch(records: MemoryRecord[], embeddings?: Array<Float32Array | undefined>): boolean;
|
|
102
|
+
/** 事务内的单条写入体(upsertL1 / upsertL1Batch 共用;调用方负责 BEGIN/COMMIT)。 */
|
|
103
|
+
private upsertL1InTx;
|
|
104
|
+
/** 批量删除 L1(元数据 + 向量 + FTS),返回删除条数。IN 按 ≤900 分块(避变量数上限)。 */
|
|
77
105
|
deleteL1Batch(ids: string[]): number;
|
|
106
|
+
/** 按块缓存的 IN 语句(表名/动作/尺寸 → 预编译语句):热路径不再每次动态 prepare。 */
|
|
107
|
+
private readonly inStmts;
|
|
108
|
+
private inStatement;
|
|
78
109
|
/**
|
|
79
110
|
* 清空 L1 检索库全部数据(重建用)。records/FTS 直接 DELETE;
|
|
80
111
|
* 向量表走 DROP + 重建(vec0 的全表 DELETE 语义不可靠,dropVectorTables
|
|
@@ -121,16 +152,46 @@ export declare class MemoryDb {
|
|
|
121
152
|
countL0Vec(): number;
|
|
122
153
|
searchL0Fts(query: string, limit: number): L0SearchHit[];
|
|
123
154
|
searchL0Vector(embedding: Float32Array, topK: number): L0SearchHit[];
|
|
124
|
-
|
|
155
|
+
/** L1 缺失向量的记录数(排除 skip 集后的补齐判据;向量能力不可用返回 -1)。 */
|
|
156
|
+
countL1VecMissing(exclude?: Set<string>): number;
|
|
157
|
+
/** L0 缺失向量的记录数(同上)。 */
|
|
158
|
+
countL0VecMissing(exclude?: Set<string>): number;
|
|
159
|
+
/**
|
|
160
|
+
* 待重嵌入的 L1:只取缺失向量的记录(增量),排除 skip 集里已判定
|
|
161
|
+
* "当前 provider 下不可嵌入(零向量)"的 id——缺 1 条不再全量重嵌,
|
|
162
|
+
* 零向量记录也不再反复喂给 embeddings API(H1 死循环双根因)。
|
|
163
|
+
*/
|
|
164
|
+
getL1ForReindex(exclude?: Set<string>): Array<{
|
|
125
165
|
id: string;
|
|
126
166
|
content: string;
|
|
127
167
|
}>;
|
|
128
|
-
|
|
168
|
+
/** 待重嵌入的 L0(增量 + 排除 skip 集,同 getL1ForReindex)。 */
|
|
169
|
+
getL0ForReindex(exclude?: Set<string>): Array<{
|
|
129
170
|
id: string;
|
|
130
171
|
text: string;
|
|
131
172
|
}>;
|
|
173
|
+
getVecSkipSet(kind: 'l1' | 'l0'): Set<string>;
|
|
174
|
+
addVecSkippedIds(kind: 'l1' | 'l0', ids: string[]): void;
|
|
175
|
+
clearVecSkipIds(kind: 'l1' | 'l0'): void;
|
|
132
176
|
/** 只更新向量行(重嵌入用)。 */
|
|
133
177
|
updateL1Vec(id: string, embedding: Float32Array): boolean;
|
|
134
178
|
updateL0Vec(id: string, embedding: Float32Array, recordedAt: string): boolean;
|
|
179
|
+
/**
|
|
180
|
+
* 批量更新 L1 向量行(重嵌入热路径):单事务写入整批,替代逐条裸写——
|
|
181
|
+
* 逐条每行一次隐式事务,批量场景(万级记录重嵌)开销集中在 fsync 上。
|
|
182
|
+
* 整批失败回退逐条:好行照常入库,坏行只丢自身(向量行 id 寻址,无顺序依赖)。
|
|
183
|
+
* 返回成功写入的行数(零向量行防御性跳过、不计入)。
|
|
184
|
+
*/
|
|
185
|
+
updateL1VecBatch(items: Array<{
|
|
186
|
+
id: string;
|
|
187
|
+
embedding: Float32Array;
|
|
188
|
+
}>): number;
|
|
189
|
+
/** L0 版 updateL1VecBatch(语义同:单事务 + 失败回退逐条)。recordedAt 整批统一。 */
|
|
190
|
+
updateL0VecBatch(items: Array<{
|
|
191
|
+
id: string;
|
|
192
|
+
embedding: Float32Array;
|
|
193
|
+
}>, recordedAt: string): number;
|
|
135
194
|
close(): void;
|
|
136
195
|
}
|
|
196
|
+
/** 全零向量(cosine 未定义,不可入向量表)。reindex 侧用它区分"不可嵌入"与"写入失败"。 */
|
|
197
|
+
export declare function isZeroVector(vec: Float32Array): boolean;
|