@devflow-tools/memory-engine 0.16.10 → 0.16.12

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.
Files changed (55) hide show
  1. package/dist/embedding-model-store.d.ts +67 -0
  2. package/dist/embedding-model-store.d.ts.map +1 -0
  3. package/dist/embedding-model-store.js +350 -0
  4. package/dist/embedding-model-store.js.map +1 -0
  5. package/dist/embedding-provider.d.ts +8 -0
  6. package/dist/embedding-provider.d.ts.map +1 -1
  7. package/dist/embedding-provider.js +68 -11
  8. package/dist/embedding-provider.js.map +1 -1
  9. package/dist/hybrid-search.d.ts +8 -0
  10. package/dist/hybrid-search.d.ts.map +1 -1
  11. package/dist/hybrid-search.js +37 -10
  12. package/dist/hybrid-search.js.map +1 -1
  13. package/dist/index.d.ts +5 -3
  14. package/dist/index.d.ts.map +1 -1
  15. package/dist/index.js +3 -2
  16. package/dist/index.js.map +1 -1
  17. package/dist/memory-engine.d.ts +4 -0
  18. package/dist/memory-engine.d.ts.map +1 -1
  19. package/dist/memory-engine.js +62 -39
  20. package/dist/memory-engine.js.map +1 -1
  21. package/dist/memory-gate.d.ts +3 -1
  22. package/dist/memory-gate.d.ts.map +1 -1
  23. package/dist/memory-gate.js +22 -40
  24. package/dist/memory-gate.js.map +1 -1
  25. package/dist/memory-maintenance.d.ts.map +1 -1
  26. package/dist/memory-maintenance.js +4 -2
  27. package/dist/memory-maintenance.js.map +1 -1
  28. package/dist/memory-store.d.ts +38 -1
  29. package/dist/memory-store.d.ts.map +1 -1
  30. package/dist/memory-store.js +488 -5
  31. package/dist/memory-store.js.map +1 -1
  32. package/dist/migrations/v3-to-v4.d.ts.map +1 -1
  33. package/dist/migrations/v3-to-v4.js +4 -0
  34. package/dist/migrations/v3-to-v4.js.map +1 -1
  35. package/dist/migrations/v6-to-v7.d.ts +3 -0
  36. package/dist/migrations/v6-to-v7.d.ts.map +1 -0
  37. package/dist/migrations/v6-to-v7.js +18 -0
  38. package/dist/migrations/v6-to-v7.js.map +1 -0
  39. package/dist/migrations/v6-to-v7.test.d.ts +2 -0
  40. package/dist/migrations/v6-to-v7.test.d.ts.map +1 -0
  41. package/dist/migrations/v6-to-v7.test.js +33 -0
  42. package/dist/migrations/v6-to-v7.test.js.map +1 -0
  43. package/dist/observation-types.d.ts +2 -0
  44. package/dist/observation-types.d.ts.map +1 -1
  45. package/dist/observation-types.js +13 -0
  46. package/dist/observation-types.js.map +1 -1
  47. package/dist/preference-conflicts.d.ts +19 -0
  48. package/dist/preference-conflicts.d.ts.map +1 -0
  49. package/dist/preference-conflicts.js +293 -0
  50. package/dist/preference-conflicts.js.map +1 -0
  51. package/dist/preference-conflicts.test.d.ts +2 -0
  52. package/dist/preference-conflicts.test.d.ts.map +1 -0
  53. package/dist/preference-conflicts.test.js +72 -0
  54. package/dist/preference-conflicts.test.js.map +1 -0
  55. package/package.json +4 -4
@@ -0,0 +1,67 @@
1
+ export declare const EMBEDDING_MODEL_ID = "Xenova/all-MiniLM-L6-v2";
2
+ export declare const EMBEDDING_MODEL_REVISION = "751bff37182d3f1213fa05d7196b954e230abad9";
3
+ export interface EmbeddingModelFileManifest {
4
+ path: string;
5
+ size: number;
6
+ sha256: string;
7
+ }
8
+ export declare const EMBEDDING_MODEL_FILES: readonly EmbeddingModelFileManifest[];
9
+ export type EmbeddingModelFileState = "ready" | "missing" | "corrupt";
10
+ export type EmbeddingModelState = "ready" | "missing" | "corrupt";
11
+ export interface EmbeddingModelFileStatus extends EmbeddingModelFileManifest {
12
+ absolutePath: string;
13
+ state: EmbeddingModelFileState;
14
+ actualSize?: number;
15
+ actualSha256?: string;
16
+ }
17
+ export interface EmbeddingModelStatus {
18
+ ready: boolean;
19
+ state: EmbeddingModelState;
20
+ modelId: string;
21
+ revision: string;
22
+ cacheRoot: string;
23
+ modelPath: string;
24
+ files: EmbeddingModelFileStatus[];
25
+ missingFiles: string[];
26
+ corruptFiles: string[];
27
+ }
28
+ export type EmbeddingModelPrepareSource = "existing" | "legacy_cache" | "download";
29
+ export interface EmbeddingModelPrepareResult extends EmbeddingModelStatus {
30
+ source: EmbeddingModelPrepareSource;
31
+ attemptedEndpoints: string[];
32
+ migratedFrom?: string;
33
+ }
34
+ export interface EmbeddingModelStoreOptions {
35
+ env?: NodeJS.ProcessEnv;
36
+ homeDir?: string;
37
+ cacheRoot?: string;
38
+ cwd?: string;
39
+ endpoints?: string[];
40
+ legacyCacheRoots?: string[];
41
+ allowDownload?: boolean;
42
+ timeoutMs?: number;
43
+ fetchImpl?: typeof fetch;
44
+ }
45
+ export declare class EmbeddingModelUnavailableError extends Error {
46
+ readonly details: {
47
+ cacheRoot: string;
48
+ attemptedEndpoints: string[];
49
+ retryAt?: number;
50
+ causes?: string[];
51
+ };
52
+ readonly category = "embedding_model_unavailable";
53
+ readonly retryWithoutAttempt = true;
54
+ constructor(message: string, details: {
55
+ cacheRoot: string;
56
+ attemptedEndpoints: string[];
57
+ retryAt?: number;
58
+ causes?: string[];
59
+ });
60
+ get retryAfterMs(): number | undefined;
61
+ }
62
+ export declare function getEmbeddingModelCacheRoot(options?: Pick<EmbeddingModelStoreOptions, "cacheRoot" | "env" | "homeDir">): string;
63
+ export declare function getEmbeddingModelPath(options?: Pick<EmbeddingModelStoreOptions, "cacheRoot" | "env" | "homeDir">): string;
64
+ export declare function resolveEmbeddingModelEndpoints(options?: Pick<EmbeddingModelStoreOptions, "endpoints" | "env">): string[];
65
+ export declare function inspectEmbeddingModel(options?: Pick<EmbeddingModelStoreOptions, "cacheRoot" | "env" | "homeDir">): Promise<EmbeddingModelStatus>;
66
+ export declare function prepareEmbeddingModel(options?: EmbeddingModelStoreOptions): Promise<EmbeddingModelPrepareResult>;
67
+ //# sourceMappingURL=embedding-model-store.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"embedding-model-store.d.ts","sourceRoot":"","sources":["../src/embedding-model-store.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,350 @@
1
+ import { createHash, randomUUID } from "node:crypto";
2
+ import { chmod, copyFile, mkdir, open, rename, rm, stat, } from "node:fs/promises";
3
+ import { createReadStream } from "node:fs";
4
+ import { homedir } from "node:os";
5
+ import { dirname, join, resolve } from "node:path";
6
+ import { fileURLToPath } from "node:url";
7
+ export const EMBEDDING_MODEL_ID = "Xenova/all-MiniLM-L6-v2";
8
+ export const EMBEDDING_MODEL_REVISION = "751bff37182d3f1213fa05d7196b954e230abad9";
9
+ const DEFAULT_ENDPOINTS = [
10
+ "https://huggingface.co",
11
+ "https://hf-mirror.com",
12
+ ];
13
+ const DEFAULT_DOWNLOAD_TIMEOUT_MS = 60_000;
14
+ const ENDPOINT_PROBE_TIMEOUT_MS = 8_000;
15
+ const ongoingPreparations = new Map();
16
+ export const EMBEDDING_MODEL_FILES = [
17
+ {
18
+ path: "config.json",
19
+ size: 650,
20
+ sha256: "7135149f7cffa1a573466c6e4d8423ed73b62fd2332c575bf738a0d033f70df7",
21
+ },
22
+ {
23
+ path: "tokenizer.json",
24
+ size: 711_661,
25
+ sha256: "da0e79933b9ed51798a3ae27893d3c5fa4a201126cef75586296df9b4d2c62a0",
26
+ },
27
+ {
28
+ path: "tokenizer_config.json",
29
+ size: 366,
30
+ sha256: "9261e7d79b44c8195c1cada2b453e55b00aeb81e907a6664974b4d7776172ab3",
31
+ },
32
+ {
33
+ path: "onnx/model_quantized.onnx",
34
+ size: 22_972_370,
35
+ sha256: "afdb6f1a0e45b715d0bb9b11772f032c399babd23bfc31fed1c170afc848bdb1",
36
+ },
37
+ ];
38
+ export class EmbeddingModelUnavailableError extends Error {
39
+ details;
40
+ category = "embedding_model_unavailable";
41
+ retryWithoutAttempt = true;
42
+ constructor(message, details) {
43
+ super(message);
44
+ this.details = details;
45
+ this.name = "EmbeddingModelUnavailableError";
46
+ }
47
+ get retryAfterMs() {
48
+ return this.details.retryAt === undefined
49
+ ? undefined
50
+ : Math.max(0, this.details.retryAt - Date.now());
51
+ }
52
+ }
53
+ export function getEmbeddingModelCacheRoot(options = {}) {
54
+ const env = options.env ?? process.env;
55
+ return resolve(options.cacheRoot
56
+ ?? env.DEVFLOW_EMBEDDING_MODEL_DIR
57
+ ?? join(options.homeDir ?? homedir(), ".devflow", "models", "transformers-cache"));
58
+ }
59
+ export function getEmbeddingModelPath(options = {}) {
60
+ return join(getEmbeddingModelCacheRoot(options), ...EMBEDDING_MODEL_ID.split("/"), EMBEDDING_MODEL_REVISION);
61
+ }
62
+ export function resolveEmbeddingModelEndpoints(options = {}) {
63
+ const env = options.env ?? process.env;
64
+ const configured = [
65
+ ...(options.endpoints ?? []),
66
+ ...splitEndpoints(env.DEVFLOW_HF_ENDPOINTS),
67
+ env.DEVFLOW_HF_ENDPOINT,
68
+ env.HF_ENDPOINT,
69
+ ];
70
+ const endpoints = [...configured, ...DEFAULT_ENDPOINTS];
71
+ return [...new Set(endpoints
72
+ .filter((value) => typeof value === "string" && value.trim().length > 0)
73
+ .map(normalizeEndpoint))];
74
+ }
75
+ export async function inspectEmbeddingModel(options = {}) {
76
+ const cacheRoot = getEmbeddingModelCacheRoot(options);
77
+ const modelPath = getEmbeddingModelPath(options);
78
+ const files = [];
79
+ for (const manifest of EMBEDDING_MODEL_FILES) {
80
+ files.push(await inspectModelFile(modelPath, manifest));
81
+ }
82
+ const missingFiles = files.filter(file => file.state === "missing").map(file => file.path);
83
+ const corruptFiles = files.filter(file => file.state === "corrupt").map(file => file.path);
84
+ const state = corruptFiles.length > 0
85
+ ? "corrupt"
86
+ : missingFiles.length > 0
87
+ ? "missing"
88
+ : "ready";
89
+ return {
90
+ ready: state === "ready",
91
+ state,
92
+ modelId: EMBEDDING_MODEL_ID,
93
+ revision: EMBEDDING_MODEL_REVISION,
94
+ cacheRoot,
95
+ modelPath,
96
+ files,
97
+ missingFiles,
98
+ corruptFiles,
99
+ };
100
+ }
101
+ export function prepareEmbeddingModel(options = {}) {
102
+ const cacheRoot = getEmbeddingModelCacheRoot(options);
103
+ const existing = ongoingPreparations.get(cacheRoot);
104
+ if (existing)
105
+ return existing;
106
+ const preparation = prepareEmbeddingModelOnce({ ...options, cacheRoot })
107
+ .finally(() => {
108
+ if (ongoingPreparations.get(cacheRoot) === preparation) {
109
+ ongoingPreparations.delete(cacheRoot);
110
+ }
111
+ });
112
+ ongoingPreparations.set(cacheRoot, preparation);
113
+ return preparation;
114
+ }
115
+ async function prepareEmbeddingModelOnce(options) {
116
+ const existing = await inspectEmbeddingModel(options);
117
+ if (existing.ready) {
118
+ return { ...existing, source: "existing", attemptedEndpoints: [] };
119
+ }
120
+ const legacyModelPaths = resolveLegacyModelPaths(options, existing.cacheRoot);
121
+ for (const legacyModelPath of legacyModelPaths) {
122
+ if (legacyModelPath === existing.modelPath)
123
+ continue;
124
+ if (!await modelDirectoryIsValid(legacyModelPath))
125
+ continue;
126
+ await copyVerifiedModel(legacyModelPath, existing.modelPath);
127
+ const migrated = await inspectEmbeddingModel(options);
128
+ if (migrated.ready) {
129
+ return {
130
+ ...migrated,
131
+ source: "legacy_cache",
132
+ attemptedEndpoints: [],
133
+ migratedFrom: legacyModelPath,
134
+ };
135
+ }
136
+ }
137
+ if (options.allowDownload === false) {
138
+ throw unavailableError(existing, [], ["No verified local embedding model was found"]);
139
+ }
140
+ const endpoints = resolveEmbeddingModelEndpoints(options);
141
+ const attemptedEndpoints = [];
142
+ const causes = [];
143
+ for (const endpoint of endpoints) {
144
+ attemptedEndpoints.push(endpoint);
145
+ try {
146
+ await downloadModelFromEndpoint(endpoint, existing.modelPath, options);
147
+ const downloaded = await inspectEmbeddingModel(options);
148
+ if (downloaded.ready) {
149
+ return { ...downloaded, source: "download", attemptedEndpoints };
150
+ }
151
+ causes.push(`${endpoint}: downloaded model failed integrity validation`);
152
+ }
153
+ catch (error) {
154
+ causes.push(`${endpoint}: ${formatError(error)}`);
155
+ }
156
+ }
157
+ throw unavailableError(await inspectEmbeddingModel(options), attemptedEndpoints, causes);
158
+ }
159
+ async function inspectModelFile(modelPath, manifest) {
160
+ const absolutePath = join(modelPath, manifest.path);
161
+ return inspectFileAtPath(absolutePath, manifest);
162
+ }
163
+ async function inspectFileAtPath(absolutePath, manifest) {
164
+ let fileStat;
165
+ try {
166
+ fileStat = await stat(absolutePath);
167
+ }
168
+ catch (error) {
169
+ if (isNodeError(error, "ENOENT")) {
170
+ return { ...manifest, absolutePath, state: "missing" };
171
+ }
172
+ throw error;
173
+ }
174
+ if (!fileStat.isFile() || fileStat.size !== manifest.size) {
175
+ return {
176
+ ...manifest,
177
+ absolutePath,
178
+ state: "corrupt",
179
+ actualSize: fileStat.size,
180
+ };
181
+ }
182
+ const actualSha256 = await hashFile(absolutePath);
183
+ return {
184
+ ...manifest,
185
+ absolutePath,
186
+ state: actualSha256 === manifest.sha256 ? "ready" : "corrupt",
187
+ actualSize: fileStat.size,
188
+ actualSha256,
189
+ };
190
+ }
191
+ async function modelDirectoryIsValid(modelPath) {
192
+ for (const manifest of EMBEDDING_MODEL_FILES) {
193
+ const status = await inspectModelFile(modelPath, manifest);
194
+ if (status.state !== "ready")
195
+ return false;
196
+ }
197
+ return true;
198
+ }
199
+ async function hashFile(path) {
200
+ const hash = createHash("sha256");
201
+ for await (const chunk of createReadStream(path))
202
+ hash.update(chunk);
203
+ return hash.digest("hex");
204
+ }
205
+ async function copyVerifiedModel(source, target) {
206
+ for (const manifest of EMBEDDING_MODEL_FILES) {
207
+ await atomicCopy(join(source, manifest.path), join(target, manifest.path), manifest);
208
+ }
209
+ }
210
+ async function atomicCopy(source, target, manifest) {
211
+ await mkdir(dirname(target), { recursive: true, mode: 0o700 });
212
+ const temporary = `${target}.part-${process.pid}-${randomUUID()}`;
213
+ try {
214
+ await copyFile(source, temporary);
215
+ await chmod(temporary, 0o600);
216
+ const status = await inspectFileAtPath(temporary, manifest);
217
+ if (status.state !== "ready")
218
+ throw new Error(`Legacy cache file failed validation: ${manifest.path}`);
219
+ await rename(temporary, target);
220
+ }
221
+ finally {
222
+ await rm(temporary, { force: true }).catch(() => undefined);
223
+ }
224
+ }
225
+ async function downloadModelFromEndpoint(endpoint, targetModelPath, options) {
226
+ const fetchImpl = options.fetchImpl ?? fetch;
227
+ const timeoutMs = positiveTimeout(options.timeoutMs, options.env ?? process.env);
228
+ await probeEndpoint(endpoint, fetchImpl, Math.min(timeoutMs, ENDPOINT_PROBE_TIMEOUT_MS));
229
+ for (const manifest of EMBEDDING_MODEL_FILES) {
230
+ const current = await inspectModelFile(targetModelPath, manifest);
231
+ if (current.state === "ready")
232
+ continue;
233
+ const url = modelFileUrl(endpoint, manifest.path);
234
+ const data = await downloadBufferWithTimeout(fetchImpl, url, timeoutMs);
235
+ if (data.byteLength !== manifest.size) {
236
+ throw new Error(`Size mismatch for ${manifest.path}: expected ${manifest.size}, received ${data.byteLength}`);
237
+ }
238
+ const sha256 = createHash("sha256").update(data).digest("hex");
239
+ if (sha256 !== manifest.sha256) {
240
+ throw new Error(`SHA-256 mismatch for ${manifest.path}`);
241
+ }
242
+ await atomicWrite(join(targetModelPath, manifest.path), data);
243
+ }
244
+ }
245
+ async function downloadBufferWithTimeout(fetchImpl, url, timeoutMs) {
246
+ const controller = new AbortController();
247
+ const timer = setTimeout(() => controller.abort(), timeoutMs);
248
+ timer.unref?.();
249
+ try {
250
+ const response = await fetchImpl(url, { redirect: "follow", signal: controller.signal });
251
+ if (!response.ok)
252
+ throw new Error(`HTTP ${response.status} for ${url}`);
253
+ return Buffer.from(await response.arrayBuffer());
254
+ }
255
+ finally {
256
+ clearTimeout(timer);
257
+ }
258
+ }
259
+ async function probeEndpoint(endpoint, fetchImpl, timeoutMs) {
260
+ const response = await fetchWithTimeout(fetchImpl, modelFileUrl(endpoint, "config.json"), timeoutMs);
261
+ if (!response.ok)
262
+ throw new Error(`HTTP ${response.status} while probing ${endpoint}`);
263
+ await response.body?.cancel().catch(() => undefined);
264
+ }
265
+ async function fetchWithTimeout(fetchImpl, url, timeoutMs) {
266
+ const controller = new AbortController();
267
+ const timer = setTimeout(() => controller.abort(), timeoutMs);
268
+ timer.unref?.();
269
+ try {
270
+ return await fetchImpl(url, { redirect: "follow", signal: controller.signal });
271
+ }
272
+ finally {
273
+ clearTimeout(timer);
274
+ }
275
+ }
276
+ async function atomicWrite(target, data) {
277
+ await mkdir(dirname(target), { recursive: true, mode: 0o700 });
278
+ const temporary = `${target}.part-${process.pid}-${randomUUID()}`;
279
+ try {
280
+ const handle = await open(temporary, "wx", 0o600);
281
+ try {
282
+ await handle.writeFile(data);
283
+ await handle.sync();
284
+ }
285
+ finally {
286
+ await handle.close();
287
+ }
288
+ await rename(temporary, target);
289
+ }
290
+ finally {
291
+ await rm(temporary, { force: true }).catch(() => undefined);
292
+ }
293
+ }
294
+ function resolveLegacyModelPaths(options, cacheRoot) {
295
+ const env = options.env ?? process.env;
296
+ const cwd = resolve(options.cwd ?? process.cwd());
297
+ const moduleDir = dirname(fileURLToPath(import.meta.url));
298
+ const projectRoots = [cwd, env.DEVFLOW_PROJECT_ROOT, env.CLAUDE_PROJECT_DIR]
299
+ .filter((value) => typeof value === "string" && value.trim().length > 0)
300
+ .map(value => resolve(value));
301
+ const cacheRoots = [
302
+ ...(options.legacyCacheRoots ?? []),
303
+ ...splitLegacyRoots(env.DEVFLOW_EMBEDDING_LEGACY_CACHE_DIRS),
304
+ ...projectRoots.map(root => join(root, "node_modules", "@xenova", "transformers", ".cache")),
305
+ resolve(moduleDir, "../../../node_modules/@xenova/transformers/.cache"),
306
+ resolve(moduleDir, "../../../@xenova/transformers/.cache"),
307
+ cacheRoot,
308
+ ];
309
+ const paths = cacheRoots.flatMap(root => {
310
+ const modelRoot = join(resolve(root), ...EMBEDDING_MODEL_ID.split("/"));
311
+ return [join(modelRoot, EMBEDDING_MODEL_REVISION), modelRoot];
312
+ });
313
+ return [...new Set(paths)];
314
+ }
315
+ function modelFileUrl(endpoint, path) {
316
+ return `${normalizeEndpoint(endpoint)}/${EMBEDDING_MODEL_ID}/resolve/${EMBEDDING_MODEL_REVISION}/${path}`;
317
+ }
318
+ function unavailableError(status, attemptedEndpoints, causes) {
319
+ return new EmbeddingModelUnavailableError([
320
+ `Verified embedding model is unavailable in ${status.cacheRoot}`,
321
+ causes.length > 0 ? causes.join(" | ") : null,
322
+ ].filter(Boolean).join(": "), { cacheRoot: status.cacheRoot, attemptedEndpoints, causes });
323
+ }
324
+ function normalizeEndpoint(endpoint) {
325
+ return endpoint.trim().replace(/\/+$/, "");
326
+ }
327
+ function splitEndpoints(value) {
328
+ return value?.split(/[;,\n]/).map(endpoint => endpoint.trim()).filter(Boolean) ?? [];
329
+ }
330
+ function splitLegacyRoots(value) {
331
+ return value?.split(/[\n,;]/).map(path => path.trim()).filter(Boolean) ?? [];
332
+ }
333
+ function positiveTimeout(value, env) {
334
+ const configured = value ?? Number(env.DEVFLOW_EMBEDDING_DOWNLOAD_TIMEOUT_MS);
335
+ return Number.isSafeInteger(configured) && configured > 0
336
+ ? configured
337
+ : DEFAULT_DOWNLOAD_TIMEOUT_MS;
338
+ }
339
+ function formatError(error) {
340
+ if (error instanceof AggregateError) {
341
+ return [error.message, ...error.errors.map(formatError)].filter(Boolean).join(": ");
342
+ }
343
+ if (!(error instanceof Error))
344
+ return String(error);
345
+ return error.cause ? `${error.message}: ${formatError(error.cause)}` : error.message;
346
+ }
347
+ function isNodeError(error, code) {
348
+ return error instanceof Error && "code" in error && error.code === code;
349
+ }
350
+ //# sourceMappingURL=embedding-model-store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"embedding-model-store.js","sourceRoot":"","sources":["../src/embedding-model-store.ts"],"names":[],"mappings":"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"}
@@ -1,5 +1,11 @@
1
1
  export type EmbeddingStatus = "idle" | "warming" | "ready" | "failed";
2
2
  export declare const EMBEDDING_DIMENSIONS = 384;
3
+ export declare class EmbeddingWarmupTimeoutError extends Error {
4
+ readonly category = "embedding_warmup_timeout";
5
+ readonly retryWithoutAttempt = true;
6
+ readonly retryAfterMs = 30000;
7
+ constructor(timeoutMs: number);
8
+ }
3
9
  export declare function assertEmbeddingBatch(embeddings: Float32Array[], expectedCount: number, dimensions?: number): void;
4
10
  type EmbeddingPipeline = (texts: string[]) => Promise<Array<{
5
11
  data: Float32Array;
@@ -8,6 +14,7 @@ export declare class EmbeddingProvider {
8
14
  private readonly pipelineLoader;
9
15
  private status;
10
16
  private lastError;
17
+ private lastFailure;
11
18
  private initializationPromise;
12
19
  private pipeline;
13
20
  private errorLogPath;
@@ -15,6 +22,7 @@ export declare class EmbeddingProvider {
15
22
  isReady(): boolean;
16
23
  getStatus(): EmbeddingStatus;
17
24
  getLastError(): string | null;
25
+ getLastFailure(): Error | null;
18
26
  initialize(): Promise<void>;
19
27
  warmup(options?: {
20
28
  timeoutMs?: number;
@@ -1 +1 @@
1
- {"version":3,"file":"embedding-provider.d.ts","sourceRoot":"","sources":["../src/embedding-provider.ts"],"names":[],"mappings":"AAIA,MAAM,MAAM,eAAe,GAAG,MAAM,GAAG,SAAS,GAAG,OAAO,GAAG,QAAQ,CAAC;AACtE,eAAO,MAAM,oBAAoB,MAAM,CAAC;AAExC,wBAAgB,oBAAoB,CAClC,UAAU,EAAE,YAAY,EAAE,EAC1B,aAAa,EAAE,MAAM,EACrB,UAAU,SAAuB,GAChC,IAAI,CAiBN;AAED,KAAK,iBAAiB,GAAG,CACvB,KAAK,EAAE,MAAM,EAAE,KACZ,OAAO,CAAC,KAAK,CAAC;IAAE,IAAI,EAAE,YAAY,CAAA;CAAE,CAAC,CAAC,CAAC;AA0E5C,qBAAa,iBAAiB;IAa1B,OAAO,CAAC,QAAQ,CAAC,cAAc;IAZjC,OAAO,CAAC,MAAM,CAA2B;IACzC,OAAO,CAAC,SAAS,CAAuB;IACxC,OAAO,CAAC,qBAAqB,CAA8B;IAC3D,OAAO,CAAC,QAAQ,CAAkC;IAClD,OAAO,CAAC,YAAY,CAKlB;gBAGiB,cAAc,GAAE,MAAM,OAAO,CAAC,iBAAiB,CAC5C;IAGtB,OAAO,IAAI,OAAO;IAIlB,SAAS,IAAI,eAAe;IAI5B,YAAY,IAAI,MAAM,GAAG,IAAI;IAI7B,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IA0BrB,MAAM,CAAC,OAAO,GAAE;QACpB,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,YAAY,CAAC,EAAE,MAAM,CAAC;KAClB,GAAG,OAAO,CAAC,OAAO,CAAC;IA2BnB,KAAK,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC;IAY1C,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC;IAY1D,OAAO,CAAC,SAAS;YAKH,aAAa;YAOb,UAAU;CAazB"}
1
+ {"version":3,"file":"embedding-provider.d.ts","sourceRoot":"","sources":["../src/embedding-provider.ts"],"names":[],"mappings":"AAUA,MAAM,MAAM,eAAe,GAAG,MAAM,GAAG,SAAS,GAAG,OAAO,GAAG,QAAQ,CAAC;AACtE,eAAO,MAAM,oBAAoB,MAAM,CAAC;AAExC,qBAAa,2BAA4B,SAAQ,KAAK;IACpD,QAAQ,CAAC,QAAQ,8BAA8B;IAC/C,QAAQ,CAAC,mBAAmB,QAAQ;IACpC,QAAQ,CAAC,YAAY,SAAU;gBAEnB,SAAS,EAAE,MAAM;CAI9B;AAED,wBAAgB,oBAAoB,CAClC,UAAU,EAAE,YAAY,EAAE,EAC1B,aAAa,EAAE,MAAM,EACrB,UAAU,SAAuB,GAChC,IAAI,CAiBN;AAED,KAAK,iBAAiB,GAAG,CACvB,KAAK,EAAE,MAAM,EAAE,KACZ,OAAO,CAAC,KAAK,CAAC;IAAE,IAAI,EAAE,YAAY,CAAA;CAAE,CAAC,CAAC,CAAC;AAqH5C,qBAAa,iBAAiB;IAc1B,OAAO,CAAC,QAAQ,CAAC,cAAc;IAbjC,OAAO,CAAC,MAAM,CAA2B;IACzC,OAAO,CAAC,SAAS,CAAuB;IACxC,OAAO,CAAC,WAAW,CAAsB;IACzC,OAAO,CAAC,qBAAqB,CAA8B;IAC3D,OAAO,CAAC,QAAQ,CAAkC;IAClD,OAAO,CAAC,YAAY,CAKlB;gBAGiB,cAAc,GAAE,MAAM,OAAO,CAAC,iBAAiB,CAC5C;IAGtB,OAAO,IAAI,OAAO;IAIlB,SAAS,IAAI,eAAe;IAI5B,YAAY,IAAI,MAAM,GAAG,IAAI;IAI7B,cAAc,IAAI,KAAK,GAAG,IAAI;IAI9B,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IA0BrB,MAAM,CAAC,OAAO,GAAE;QACpB,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,YAAY,CAAC,EAAE,MAAM,CAAC;KAClB,GAAG,OAAO,CAAC,OAAO,CAAC;IA2BnB,KAAK,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC;IAY1C,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC;IAa1D,OAAO,CAAC,SAAS;YAMH,aAAa;YASb,UAAU;CAazB"}
@@ -1,7 +1,17 @@
1
1
  import { appendFile, chmod, mkdir } from "node:fs/promises";
2
2
  import { homedir } from "node:os";
3
3
  import { dirname, join } from "node:path";
4
+ import { EMBEDDING_MODEL_ID, EMBEDDING_MODEL_REVISION, EmbeddingModelUnavailableError, prepareEmbeddingModel, } from "./embedding-model-store.js";
4
5
  export const EMBEDDING_DIMENSIONS = 384;
6
+ export class EmbeddingWarmupTimeoutError extends Error {
7
+ category = "embedding_warmup_timeout";
8
+ retryWithoutAttempt = true;
9
+ retryAfterMs = 30_000;
10
+ constructor(timeoutMs) {
11
+ super(`Embedding model warmup timed out after ${timeoutMs}ms`);
12
+ this.name = "EmbeddingWarmupTimeoutError";
13
+ }
14
+ }
5
15
  export function assertEmbeddingBatch(embeddings, expectedCount, dimensions = EMBEDDING_DIMENSIONS) {
6
16
  if (embeddings.length !== expectedCount) {
7
17
  throw new Error(`Observation vector count mismatch: ${expectedCount} observations, ${embeddings.length} vectors`);
@@ -30,20 +40,28 @@ function splitBatchTensor(result, expectedCount) {
30
40
  }
31
41
  let sharedPipeline = null;
32
42
  let sharedPipelinePromise = null;
43
+ let sharedModelPreparePromise = null;
44
+ let sharedCircuit = null;
45
+ const DEFAULT_CIRCUIT_OPEN_MS = 5 * 60_000;
33
46
  function loadSharedPipeline() {
34
47
  if (sharedPipeline)
35
48
  return Promise.resolve(sharedPipeline);
36
49
  if (sharedPipelinePromise)
37
50
  return sharedPipelinePromise;
51
+ if (sharedCircuit && sharedCircuit.retryAt > Date.now()) {
52
+ return Promise.reject(withCircuitRetry(sharedCircuit.error, sharedCircuit.retryAt));
53
+ }
54
+ sharedCircuit = null;
38
55
  sharedPipelinePromise = (async () => {
56
+ sharedModelPreparePromise ??= prepareEmbeddingModel();
57
+ const prepared = await sharedModelPreparePromise;
39
58
  const { pipeline: transformersPipeline, env: transformersEnv, } = await import("@xenova/transformers");
40
- const remoteHost = process.env.DEVFLOW_HF_ENDPOINT ?? process.env.HF_ENDPOINT;
41
- if (remoteHost) {
42
- transformersEnv.remoteHost = remoteHost.endsWith("/")
43
- ? remoteHost
44
- : `${remoteHost}/`;
45
- }
46
- const raw = await transformersPipeline("feature-extraction", "Xenova/all-MiniLM-L6-v2");
59
+ transformersEnv.cacheDir = prepared.cacheRoot;
60
+ const raw = await transformersPipeline("feature-extraction", EMBEDDING_MODEL_ID, {
61
+ revision: EMBEDDING_MODEL_REVISION,
62
+ cache_dir: prepared.cacheRoot,
63
+ local_files_only: true,
64
+ });
47
65
  const loaded = async (texts) => {
48
66
  const result = await raw(texts, { pooling: "mean", normalize: true });
49
67
  return Array.isArray(result)
@@ -51,25 +69,56 @@ function loadSharedPipeline() {
51
69
  : splitBatchTensor(result, texts.length);
52
70
  };
53
71
  sharedPipeline = loaded;
72
+ sharedCircuit = null;
54
73
  return loaded;
55
74
  })().catch((error) => {
56
75
  sharedPipelinePromise = null;
57
- throw error;
76
+ sharedModelPreparePromise = null;
77
+ const normalized = normalizeError(error);
78
+ if (normalized instanceof EmbeddingModelUnavailableError) {
79
+ const retryAt = Date.now() + circuitOpenMs();
80
+ sharedCircuit = { error: normalized, retryAt };
81
+ throw withCircuitRetry(normalized, retryAt);
82
+ }
83
+ sharedCircuit = null;
84
+ throw normalized;
58
85
  });
59
86
  return sharedPipelinePromise;
60
87
  }
61
88
  function errorMessage(error) {
89
+ if (error instanceof AggregateError) {
90
+ return [error.message, ...error.errors.map(errorMessage)].filter(Boolean).join(": ");
91
+ }
62
92
  if (!(error instanceof Error))
63
93
  return String(error);
64
- const cause = error.cause instanceof Error ? error.cause.message : null;
94
+ const cause = error.cause ? errorMessage(error.cause) : null;
65
95
  return cause && cause !== error.message
66
96
  ? `${error.message}: ${cause}`
67
97
  : error.message;
68
98
  }
99
+ function normalizeError(error) {
100
+ return error instanceof Error ? error : new Error(String(error));
101
+ }
102
+ function withCircuitRetry(error, retryAt) {
103
+ if (error instanceof EmbeddingModelUnavailableError) {
104
+ return new EmbeddingModelUnavailableError(error.message, {
105
+ ...error.details,
106
+ retryAt,
107
+ });
108
+ }
109
+ return error;
110
+ }
111
+ function circuitOpenMs() {
112
+ const configured = Number(process.env.DEVFLOW_EMBEDDING_CIRCUIT_OPEN_MS);
113
+ return Number.isSafeInteger(configured) && configured > 0
114
+ ? configured
115
+ : DEFAULT_CIRCUIT_OPEN_MS;
116
+ }
69
117
  export class EmbeddingProvider {
70
118
  pipelineLoader;
71
119
  status = "idle";
72
120
  lastError = null;
121
+ lastFailure = null;
73
122
  initializationPromise = null;
74
123
  pipeline = null;
75
124
  errorLogPath = join(homedir(), ".devflow", "errors", "embedder.log");
@@ -85,6 +134,9 @@ export class EmbeddingProvider {
85
134
  getLastError() {
86
135
  return this.lastError;
87
136
  }
137
+ getLastFailure() {
138
+ return this.lastFailure;
139
+ }
88
140
  initialize() {
89
141
  if (this.pipeline) {
90
142
  this.markReady();
@@ -118,7 +170,7 @@ export class EmbeddingProvider {
118
170
  await Promise.race([
119
171
  this.initialize(),
120
172
  new Promise((_, reject) => {
121
- timeout = setTimeout(() => reject(new Error(`Embedding model warmup timed out after ${timeoutMs}ms`)), timeoutMs);
173
+ timeout = setTimeout(() => reject(new EmbeddingWarmupTimeoutError(timeoutMs)), timeoutMs);
122
174
  }),
123
175
  ]);
124
176
  return this.status === "ready";
@@ -148,6 +200,8 @@ export class EmbeddingProvider {
148
200
  }
149
201
  }
150
202
  async embedBatch(texts) {
203
+ if (texts.length === 0)
204
+ return [];
151
205
  await this.initialize();
152
206
  try {
153
207
  const results = await this.pipeline(texts);
@@ -162,11 +216,14 @@ export class EmbeddingProvider {
162
216
  markReady() {
163
217
  this.status = "ready";
164
218
  this.lastError = null;
219
+ this.lastFailure = null;
165
220
  }
166
221
  async recordFailure(error) {
167
- const message = errorMessage(error);
222
+ const failure = normalizeError(error);
223
+ const message = errorMessage(failure);
168
224
  this.status = "failed";
169
225
  this.lastError = message;
226
+ this.lastFailure = failure;
170
227
  await this.logFailure(message);
171
228
  }
172
229
  async logFailure(message) {