@devflow-tools/memory-engine 0.16.11 → 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.
- package/dist/embedding-model-store.d.ts +67 -0
- package/dist/embedding-model-store.d.ts.map +1 -0
- package/dist/embedding-model-store.js +350 -0
- package/dist/embedding-model-store.js.map +1 -0
- package/dist/embedding-provider.d.ts +8 -0
- package/dist/embedding-provider.d.ts.map +1 -1
- package/dist/embedding-provider.js +68 -11
- package/dist/embedding-provider.js.map +1 -1
- package/dist/hybrid-search.d.ts +8 -0
- package/dist/hybrid-search.d.ts.map +1 -1
- package/dist/hybrid-search.js +37 -10
- package/dist/hybrid-search.js.map +1 -1
- package/dist/index.d.ts +4 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -1
- package/dist/index.js.map +1 -1
- package/dist/memory-engine.d.ts +4 -0
- package/dist/memory-engine.d.ts.map +1 -1
- package/dist/memory-engine.js +61 -37
- package/dist/memory-engine.js.map +1 -1
- package/dist/memory-gate.d.ts +3 -1
- package/dist/memory-gate.d.ts.map +1 -1
- package/dist/memory-gate.js +17 -28
- package/dist/memory-gate.js.map +1 -1
- package/dist/memory-maintenance.d.ts.map +1 -1
- package/dist/memory-maintenance.js +4 -2
- package/dist/memory-maintenance.js.map +1 -1
- package/dist/memory-store.d.ts +38 -1
- package/dist/memory-store.d.ts.map +1 -1
- package/dist/memory-store.js +488 -5
- package/dist/memory-store.js.map +1 -1
- package/dist/migrations/v3-to-v4.d.ts.map +1 -1
- package/dist/migrations/v3-to-v4.js +4 -0
- package/dist/migrations/v3-to-v4.js.map +1 -1
- package/dist/migrations/v6-to-v7.d.ts +3 -0
- package/dist/migrations/v6-to-v7.d.ts.map +1 -0
- package/dist/migrations/v6-to-v7.js +18 -0
- package/dist/migrations/v6-to-v7.js.map +1 -0
- package/dist/migrations/v6-to-v7.test.d.ts +2 -0
- package/dist/migrations/v6-to-v7.test.d.ts.map +1 -0
- package/dist/migrations/v6-to-v7.test.js +33 -0
- package/dist/migrations/v6-to-v7.test.js.map +1 -0
- package/dist/preference-conflicts.d.ts +19 -0
- package/dist/preference-conflicts.d.ts.map +1 -0
- package/dist/preference-conflicts.js +293 -0
- package/dist/preference-conflicts.js.map +1 -0
- package/dist/preference-conflicts.test.d.ts +2 -0
- package/dist/preference-conflicts.test.d.ts.map +1 -0
- package/dist/preference-conflicts.test.js +72 -0
- package/dist/preference-conflicts.test.js.map +1 -0
- 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":"AAeA,eAAO,MAAM,kBAAkB,4BAA4B,CAAC;AAC5D,eAAO,MAAM,wBAAwB,6CAA6C,CAAC;AAUnF,MAAM,WAAW,0BAA0B;IACzC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,eAAO,MAAM,qBAAqB,EAAE,SAAS,0BAA0B,EAqB7D,CAAC;AAEX,MAAM,MAAM,uBAAuB,GAAG,OAAO,GAAG,SAAS,GAAG,SAAS,CAAC;AACtE,MAAM,MAAM,mBAAmB,GAAG,OAAO,GAAG,SAAS,GAAG,SAAS,CAAC;AAElE,MAAM,WAAW,wBAAyB,SAAQ,0BAA0B;IAC1E,YAAY,EAAE,MAAM,CAAC;IACrB,KAAK,EAAE,uBAAuB,CAAC;IAC/B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,oBAAoB;IACnC,KAAK,EAAE,OAAO,CAAC;IACf,KAAK,EAAE,mBAAmB,CAAC;IAC3B,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,wBAAwB,EAAE,CAAC;IAClC,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,YAAY,EAAE,MAAM,EAAE,CAAC;CACxB;AAED,MAAM,MAAM,2BAA2B,GAAG,UAAU,GAAG,cAAc,GAAG,UAAU,CAAC;AAEnF,MAAM,WAAW,2BAA4B,SAAQ,oBAAoB;IACvE,MAAM,EAAE,2BAA2B,CAAC;IACpC,kBAAkB,EAAE,MAAM,EAAE,CAAC;IAC7B,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,0BAA0B;IACzC,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;IACxB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;IACrB,gBAAgB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC5B,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,OAAO,KAAK,CAAC;CAC1B;AAED,qBAAa,8BAA+B,SAAQ,KAAK;IAMrD,QAAQ,CAAC,OAAO,EAAE;QAChB,SAAS,EAAE,MAAM,CAAC;QAClB,kBAAkB,EAAE,MAAM,EAAE,CAAC;QAC7B,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;KACnB;IAVH,QAAQ,CAAC,QAAQ,iCAAiC;IAClD,QAAQ,CAAC,mBAAmB,QAAQ;gBAGlC,OAAO,EAAE,MAAM,EACN,OAAO,EAAE;QAChB,SAAS,EAAE,MAAM,CAAC;QAClB,kBAAkB,EAAE,MAAM,EAAE,CAAC;QAC7B,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;KACnB;IAMH,IAAI,YAAY,IAAI,MAAM,GAAG,SAAS,CAIrC;CACF;AAED,wBAAgB,0BAA0B,CACxC,OAAO,GAAE,IAAI,CAAC,0BAA0B,EAAE,WAAW,GAAG,KAAK,GAAG,SAAS,CAAM,GAC9E,MAAM,CAOR;AAED,wBAAgB,qBAAqB,CACnC,OAAO,GAAE,IAAI,CAAC,0BAA0B,EAAE,WAAW,GAAG,KAAK,GAAG,SAAS,CAAM,GAC9E,MAAM,CAMR;AAED,wBAAgB,8BAA8B,CAC5C,OAAO,GAAE,IAAI,CAAC,0BAA0B,EAAE,WAAW,GAAG,KAAK,CAAM,GAClE,MAAM,EAAE,CAYV;AAED,wBAAsB,qBAAqB,CACzC,OAAO,GAAE,IAAI,CAAC,0BAA0B,EAAE,WAAW,GAAG,KAAK,GAAG,SAAS,CAAM,GAC9E,OAAO,CAAC,oBAAoB,CAAC,CAyB/B;AAED,wBAAgB,qBAAqB,CACnC,OAAO,GAAE,0BAA+B,GACvC,OAAO,CAAC,2BAA2B,CAAC,CAYtC"}
|
|
@@ -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":"
|
|
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
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
|
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) {
|