@alisio/plugin-semantic 0.0.0-stage → 0.1.0

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 (114) hide show
  1. package/LICENSE +21 -0
  2. package/README.es.md +152 -0
  3. package/README.md +144 -2
  4. package/THIRD_PARTY_NOTICES.md +42 -0
  5. package/assets/architecture.svg +1 -0
  6. package/assets/ask-flow.svg +1 -0
  7. package/cover.svg +53 -0
  8. package/dist/apps.d.ts +26 -0
  9. package/dist/apps.d.ts.map +1 -0
  10. package/dist/apps.js +135 -0
  11. package/dist/apps.js.map +1 -0
  12. package/dist/embedded.html +2194 -0
  13. package/dist/engine/download.d.ts +77 -0
  14. package/dist/engine/download.d.ts.map +1 -0
  15. package/dist/engine/download.js +213 -0
  16. package/dist/engine/download.js.map +1 -0
  17. package/dist/engine/embedder.d.ts +55 -0
  18. package/dist/engine/embedder.d.ts.map +1 -0
  19. package/dist/engine/embedder.js +182 -0
  20. package/dist/engine/embedder.js.map +1 -0
  21. package/dist/engine/infer.d.ts +22 -0
  22. package/dist/engine/infer.d.ts.map +1 -0
  23. package/dist/engine/infer.js +53 -0
  24. package/dist/engine/infer.js.map +1 -0
  25. package/dist/engine/models.d.ts +45 -0
  26. package/dist/engine/models.d.ts.map +1 -0
  27. package/dist/engine/models.js +132 -0
  28. package/dist/engine/models.js.map +1 -0
  29. package/dist/engine/runtime.d.ts +46 -0
  30. package/dist/engine/runtime.d.ts.map +1 -0
  31. package/dist/engine/runtime.js +172 -0
  32. package/dist/engine/runtime.js.map +1 -0
  33. package/dist/engine/setup.d.ts +82 -0
  34. package/dist/engine/setup.d.ts.map +1 -0
  35. package/dist/engine/setup.js +183 -0
  36. package/dist/engine/setup.js.map +1 -0
  37. package/dist/engine/store.d.ts +46 -0
  38. package/dist/engine/store.d.ts.map +1 -0
  39. package/dist/engine/store.js +280 -0
  40. package/dist/engine/store.js.map +1 -0
  41. package/dist/engine/tar.d.ts +18 -0
  42. package/dist/engine/tar.d.ts.map +1 -0
  43. package/dist/engine/tar.js +198 -0
  44. package/dist/engine/tar.js.map +1 -0
  45. package/dist/engine/worker.d.ts +2 -0
  46. package/dist/engine/worker.d.ts.map +1 -0
  47. package/dist/engine/worker.js +64 -0
  48. package/dist/engine/worker.js.map +1 -0
  49. package/dist/errors.d.ts +15 -0
  50. package/dist/errors.d.ts.map +1 -0
  51. package/dist/errors.js +58 -0
  52. package/dist/errors.js.map +1 -0
  53. package/dist/index.d.ts +14 -0
  54. package/dist/index.d.ts.map +1 -0
  55. package/dist/index.js +258 -0
  56. package/dist/index.js.map +1 -0
  57. package/dist/messages.d.ts +53 -0
  58. package/dist/messages.d.ts.map +1 -0
  59. package/dist/messages.js +118 -0
  60. package/dist/messages.js.map +1 -0
  61. package/dist/notebook/answer.d.ts +33 -0
  62. package/dist/notebook/answer.d.ts.map +1 -0
  63. package/dist/notebook/answer.js +77 -0
  64. package/dist/notebook/answer.js.map +1 -0
  65. package/dist/notebook/chunk.d.ts +23 -0
  66. package/dist/notebook/chunk.d.ts.map +1 -0
  67. package/dist/notebook/chunk.js +124 -0
  68. package/dist/notebook/chunk.js.map +1 -0
  69. package/dist/notebook/db.d.ts +98 -0
  70. package/dist/notebook/db.d.ts.map +1 -0
  71. package/dist/notebook/db.js +328 -0
  72. package/dist/notebook/db.js.map +1 -0
  73. package/dist/notebook/docx.d.ts +3 -0
  74. package/dist/notebook/docx.d.ts.map +1 -0
  75. package/dist/notebook/docx.js +16 -0
  76. package/dist/notebook/docx.js.map +1 -0
  77. package/dist/notebook/extract.d.ts +11 -0
  78. package/dist/notebook/extract.d.ts.map +1 -0
  79. package/dist/notebook/extract.js +99 -0
  80. package/dist/notebook/extract.js.map +1 -0
  81. package/dist/notebook/jobs.d.ts +31 -0
  82. package/dist/notebook/jobs.d.ts.map +1 -0
  83. package/dist/notebook/jobs.js +84 -0
  84. package/dist/notebook/jobs.js.map +1 -0
  85. package/dist/notebook/ooxml.d.ts +6 -0
  86. package/dist/notebook/ooxml.d.ts.map +1 -0
  87. package/dist/notebook/ooxml.js +131 -0
  88. package/dist/notebook/ooxml.js.map +1 -0
  89. package/dist/notebook/retrieve.d.ts +14 -0
  90. package/dist/notebook/retrieve.d.ts.map +1 -0
  91. package/dist/notebook/retrieve.js +37 -0
  92. package/dist/notebook/retrieve.js.map +1 -0
  93. package/dist/notebook/service.d.ts +72 -0
  94. package/dist/notebook/service.d.ts.map +1 -0
  95. package/dist/notebook/service.js +620 -0
  96. package/dist/notebook/service.js.map +1 -0
  97. package/dist/notebook/workspace.d.ts +17 -0
  98. package/dist/notebook/workspace.d.ts.map +1 -0
  99. package/dist/notebook/workspace.js +75 -0
  100. package/dist/notebook/workspace.js.map +1 -0
  101. package/dist/notebook/zip.d.ts +33 -0
  102. package/dist/notebook/zip.d.ts.map +1 -0
  103. package/dist/notebook/zip.js +154 -0
  104. package/dist/notebook/zip.js.map +1 -0
  105. package/dist/paths.d.ts +17 -0
  106. package/dist/paths.d.ts.map +1 -0
  107. package/dist/paths.js +28 -0
  108. package/dist/paths.js.map +1 -0
  109. package/dist/version.d.ts +2 -0
  110. package/dist/version.d.ts.map +1 -0
  111. package/dist/version.js +3 -0
  112. package/dist/version.js.map +1 -0
  113. package/icon.svg +16 -0
  114. package/package.json +62 -3
@@ -0,0 +1,77 @@
1
+ import { type ModelSpec } from "./models.js";
2
+ /** Progress of a model download: per file and overall, in bytes; `fraction` is 0..1. */
3
+ export interface DownloadProgress {
4
+ file: string;
5
+ /** 1-based position of `file` in the snapshot. */
6
+ fileIndex: number;
7
+ fileCount: number;
8
+ fileBytes: number;
9
+ fileTotal: number;
10
+ bytes: number;
11
+ total: number;
12
+ fraction: number;
13
+ }
14
+ /** The subset of `fetch` the downloader needs; injectable so tests stay offline. */
15
+ export type Fetcher = (url: string, init: {
16
+ headers: Record<string, string>;
17
+ signal: AbortSignal;
18
+ }) => Promise<{
19
+ ok: boolean;
20
+ status: number;
21
+ url?: string;
22
+ body: AsyncIterable<Uint8Array> | ReadableStream<Uint8Array> | null;
23
+ }>;
24
+ export interface DownloadOptions {
25
+ fetcher?: Fetcher;
26
+ onProgress?: (progress: DownloadProgress) => void;
27
+ signal: AbortSignal;
28
+ }
29
+ /** Directory holding a verified snapshot. */
30
+ export declare const modelPath: (cacheRoot: string, spec: ModelSpec) => string;
31
+ /** Where an in-progress file lives: outside the snapshot, so it is never mistaken for a model file. */
32
+ export declare const partialPath: (cacheRoot: string, spec: ModelSpec, file: string) => string;
33
+ /** Pinned, HTTPS-only URL of one file of the snapshot. */
34
+ export declare const fileUrl: (spec: ModelSpec, file: string) => string;
35
+ /**
36
+ * Cheap readiness check (no rehash): the verification marker names this exact snapshot and every
37
+ * file still has its pinned size. Every digest was checked before the marker was written.
38
+ */
39
+ export declare function isModelReady(cacheRoot: string, spec: ModelSpec): Promise<boolean>;
40
+ /**
41
+ * Overall and per-file progress across several downloads (runtime tarballs, then model files), so
42
+ * one progress bar covers the whole first-time download. Overall bytes never go backwards.
43
+ */
44
+ export declare class ProgressTracker {
45
+ readonly total: number;
46
+ readonly fileCount: number;
47
+ private readonly onProgress?;
48
+ private done;
49
+ private reported;
50
+ private index;
51
+ private current;
52
+ constructor(total: number, fileCount: number, onProgress?: ((progress: DownloadProgress) => void) | undefined);
53
+ begin(file: string, fileTotal: number): void;
54
+ update(fileBytes: number): void;
55
+ end(): void;
56
+ }
57
+ export type DigestSpec = {
58
+ algorithm: "sha256" | "sha512";
59
+ value: string;
60
+ encoding: "hex" | "base64";
61
+ };
62
+ /** Streams `url` into `partial` (resuming a leftover with `Range`), then checks size and digest. */
63
+ export declare function fetchVerified(fetcher: Fetcher, url: string, partial: string, expected: number, digest: DigestSpec, signal: AbortSignal, progress: (bytes: number) => void): Promise<void>;
64
+ /** Maps a download failure to a plugin code after removing the partial file. */
65
+ export declare function failDownload(partial: string, error: unknown, signal: AbortSignal): Promise<never>;
66
+ /**
67
+ * Downloads and verifies a pinned snapshot into `cacheRoot` (D3). Only called after an explicit
68
+ * user action. Each file streams into `.partial/`, is checked against its pinned size and SHA-256,
69
+ * and only then moves into the snapshot directory. A partial file left by a crash is resumed with a
70
+ * `Range` request; a cancelled, failed or tampered download removes its partial file.
71
+ */
72
+ export declare function downloadModel(cacheRoot: string, spec: ModelSpec, options: DownloadOptions & {
73
+ tracker?: ProgressTracker;
74
+ }): Promise<{
75
+ downloaded: boolean;
76
+ }>;
77
+ //# sourceMappingURL=download.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"download.d.ts","sourceRoot":"","sources":["../../src/engine/download.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,213 @@
1
+ import { createHash } from "node:crypto";
2
+ import { createReadStream } from "node:fs";
3
+ import { mkdir, open, readFile, rename, rm, rmdir, stat, writeFile } from "node:fs/promises";
4
+ import { dirname, join } from "node:path";
5
+ import { isAbort, SemanticPluginError } from "../errors.js";
6
+ import { modelDirName, modelId, totalBytes } from "./models.js";
7
+ const MARKER = ".verified.json";
8
+ const HOST = "https://huggingface.co";
9
+ /** Directory holding a verified snapshot. */
10
+ export const modelPath = (cacheRoot, spec) => join(cacheRoot, modelDirName(spec));
11
+ /** Where an in-progress file lives: outside the snapshot, so it is never mistaken for a model file. */
12
+ export const partialPath = (cacheRoot, spec, file) => join(cacheRoot, ".partial", modelDirName(spec), file.replaceAll("/", "__"));
13
+ /** Pinned, HTTPS-only URL of one file of the snapshot. */
14
+ export const fileUrl = (spec, file) => `${HOST}/${spec.repo}/resolve/${spec.revision}/${file}`;
15
+ /**
16
+ * Cheap readiness check (no rehash): the verification marker names this exact snapshot and every
17
+ * file still has its pinned size. Every digest was checked before the marker was written.
18
+ */
19
+ export async function isModelReady(cacheRoot, spec) {
20
+ const dir = modelPath(cacheRoot, spec);
21
+ let marker;
22
+ try {
23
+ marker = JSON.parse(await readFile(join(dir, MARKER), "utf8"));
24
+ }
25
+ catch {
26
+ return false;
27
+ }
28
+ if (marker?.modelId !== modelId(spec))
29
+ return false;
30
+ for (const file of spec.files) {
31
+ const recorded = marker.files?.[file.path];
32
+ if (!recorded || recorded.sha256 !== file.sha256)
33
+ return false;
34
+ const info = await stat(join(dir, file.path)).catch(() => undefined);
35
+ if (!info?.isFile() || info.size !== file.bytes)
36
+ return false;
37
+ }
38
+ return true;
39
+ }
40
+ async function hashFile(path, hash) {
41
+ for await (const chunk of createReadStream(path))
42
+ hash.update(chunk);
43
+ }
44
+ async function* chunks(body) {
45
+ if (Symbol.asyncIterator in body) {
46
+ yield* body;
47
+ return;
48
+ }
49
+ const reader = body.getReader();
50
+ try {
51
+ for (;;) {
52
+ const { done, value } = await reader.read();
53
+ if (done)
54
+ return;
55
+ yield value;
56
+ }
57
+ }
58
+ finally {
59
+ reader.releaseLock();
60
+ }
61
+ }
62
+ /**
63
+ * Overall and per-file progress across several downloads (runtime tarballs, then model files), so
64
+ * one progress bar covers the whole first-time download. Overall bytes never go backwards.
65
+ */
66
+ export class ProgressTracker {
67
+ total;
68
+ fileCount;
69
+ onProgress;
70
+ done = 0;
71
+ reported = 0;
72
+ index = 0;
73
+ current = { file: "", total: 0 };
74
+ constructor(total, fileCount, onProgress) {
75
+ this.total = total;
76
+ this.fileCount = fileCount;
77
+ this.onProgress = onProgress;
78
+ }
79
+ begin(file, fileTotal) {
80
+ this.index++;
81
+ this.current = { file, total: fileTotal };
82
+ this.update(0);
83
+ }
84
+ update(fileBytes) {
85
+ this.reported = Math.min(this.total, Math.max(this.reported, this.done + fileBytes));
86
+ this.onProgress?.({
87
+ file: this.current.file,
88
+ fileIndex: this.index,
89
+ fileCount: this.fileCount,
90
+ fileBytes,
91
+ fileTotal: this.current.total,
92
+ bytes: this.reported,
93
+ total: this.total,
94
+ fraction: this.total > 0 ? this.reported / this.total : 1,
95
+ });
96
+ }
97
+ end() {
98
+ this.update(this.current.total);
99
+ this.done += this.current.total;
100
+ }
101
+ }
102
+ /** Streams `url` into `partial` (resuming a leftover with `Range`), then checks size and digest. */
103
+ export async function fetchVerified(fetcher, url, partial, expected, digest, signal, progress) {
104
+ if (!url.startsWith("https://"))
105
+ throw new SemanticPluginError("download_failed");
106
+ let offset = (await stat(partial).catch(() => undefined))?.size ?? 0;
107
+ if (offset >= expected) {
108
+ await rm(partial, { force: true });
109
+ offset = 0;
110
+ }
111
+ const response = await fetcher(url, {
112
+ headers: offset > 0 ? { Range: `bytes=${offset}-` } : {},
113
+ signal,
114
+ });
115
+ if (!response.ok || !response.body)
116
+ throw new SemanticPluginError("download_failed");
117
+ // Redirects (to a CDN) must stay on HTTPS.
118
+ if (response.url && !response.url.startsWith("https://"))
119
+ throw new SemanticPluginError("download_failed");
120
+ const hash = createHash(digest.algorithm);
121
+ if (response.status === 206 && offset > 0)
122
+ await hashFile(partial, hash);
123
+ else
124
+ offset = 0;
125
+ const handle = await open(partial, offset > 0 ? "a" : "w", 0o600);
126
+ let bytes = offset;
127
+ try {
128
+ progress(bytes);
129
+ for await (const chunk of chunks(response.body)) {
130
+ signal.throwIfAborted?.();
131
+ bytes += chunk.byteLength;
132
+ if (bytes > expected)
133
+ throw new SemanticPluginError("model_corrupt");
134
+ hash.update(chunk);
135
+ await handle.write(chunk);
136
+ progress(bytes);
137
+ }
138
+ await handle.sync();
139
+ }
140
+ finally {
141
+ await handle.close();
142
+ }
143
+ if (bytes !== expected || hash.digest(digest.encoding) !== digest.value)
144
+ throw new SemanticPluginError("model_corrupt");
145
+ }
146
+ /** Maps a download failure to a plugin code after removing the partial file. */
147
+ export async function failDownload(partial, error, signal) {
148
+ await rm(partial, { force: true });
149
+ if (isAbort(error) || signal.aborted)
150
+ throw new SemanticPluginError("cancelled");
151
+ if (error instanceof SemanticPluginError)
152
+ throw error;
153
+ throw new SemanticPluginError("download_failed");
154
+ }
155
+ /**
156
+ * Downloads and verifies a pinned snapshot into `cacheRoot` (D3). Only called after an explicit
157
+ * user action. Each file streams into `.partial/`, is checked against its pinned size and SHA-256,
158
+ * and only then moves into the snapshot directory. A partial file left by a crash is resumed with a
159
+ * `Range` request; a cancelled, failed or tampered download removes its partial file.
160
+ */
161
+ export async function downloadModel(cacheRoot, spec, options) {
162
+ const { signal } = options;
163
+ const fetcher = options.fetcher ?? globalThis.fetch;
164
+ const own = !options.tracker;
165
+ const tracker = options.tracker ?? new ProgressTracker(totalBytes(spec), spec.files.length, options.onProgress);
166
+ if (await isModelReady(cacheRoot, spec)) {
167
+ if (own)
168
+ for (const file of spec.files) {
169
+ tracker.begin(file.path, file.bytes);
170
+ tracker.end();
171
+ }
172
+ return { downloaded: false };
173
+ }
174
+ const dir = modelPath(cacheRoot, spec);
175
+ await mkdir(dir, { recursive: true, mode: 0o700 });
176
+ for (const file of spec.files) {
177
+ signal.throwIfAborted?.();
178
+ tracker.begin(file.path, file.bytes);
179
+ const finalPath = join(dir, file.path);
180
+ const existing = await stat(finalPath).catch(() => undefined);
181
+ if (existing?.isFile() && existing.size === file.bytes) {
182
+ const hash = createHash("sha256");
183
+ await hashFile(finalPath, hash);
184
+ if (hash.digest("hex") === file.sha256) {
185
+ tracker.end();
186
+ continue;
187
+ }
188
+ }
189
+ await rm(finalPath, { force: true });
190
+ const partial = partialPath(cacheRoot, spec, file.path);
191
+ await mkdir(dirname(partial), { recursive: true, mode: 0o700 });
192
+ try {
193
+ await fetchVerified(fetcher, fileUrl(spec, file.path), partial, file.bytes, { algorithm: "sha256", value: file.sha256, encoding: "hex" }, signal, (n) => tracker.update(n));
194
+ }
195
+ catch (error) {
196
+ await failDownload(partial, error, signal);
197
+ }
198
+ await mkdir(dirname(finalPath), { recursive: true, mode: 0o700 });
199
+ await rename(partial, finalPath);
200
+ tracker.end();
201
+ }
202
+ await rm(join(cacheRoot, ".partial", modelDirName(spec)), { recursive: true, force: true });
203
+ await rmdir(join(cacheRoot, ".partial")).catch(() => { });
204
+ const marker = {
205
+ modelId: modelId(spec),
206
+ files: Object.fromEntries(spec.files.map((f) => [f.path, { bytes: f.bytes, sha256: f.sha256 }])),
207
+ };
208
+ const temp = join(dir, `${MARKER}.${process.pid}.tmp`);
209
+ await writeFile(temp, JSON.stringify(marker), { mode: 0o600 });
210
+ await rename(temp, join(dir, MARKER));
211
+ return { downloaded: true };
212
+ }
213
+ //# sourceMappingURL=download.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"download.js","sourceRoot":"","sources":["../../src/engine/download.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,55 @@
1
+ import type { EmbeddingKind, EmbeddingProvider, SemanticHealth } from "@alisio/sdk";
2
+ import { type ModelSpec } from "./models.js";
3
+ /** What the embedder needs from an inference backend (the worker, or a fake in tests). */
4
+ export interface EmbedBackend {
5
+ /** Texts already prefixed; one unit vector per text, same order. */
6
+ embed(texts: string[]): Promise<Float32Array[]>;
7
+ close(): Promise<void>;
8
+ }
9
+ export type BackendFactory = (modelDir: string, spec: ModelSpec, runtimeDir: string) => Promise<EmbedBackend>;
10
+ export interface EmbedderOptions {
11
+ spec: ModelSpec;
12
+ cacheRoot: string;
13
+ factory?: BackendFactory;
14
+ /** Defaults to: the cached ONNX Runtime and the model snapshot are both verified. */
15
+ ready?: () => Promise<boolean>;
16
+ idleMs?: number;
17
+ batchSize?: number;
18
+ }
19
+ /**
20
+ * Local `EmbeddingProvider` (`semantic.e5`). Inference runs in a worker thread started lazily and
21
+ * stopped after 5 minutes idle (D5); inputs get the model family's prefixes (D7).
22
+ */
23
+ export declare class E5Embedder implements EmbeddingProvider {
24
+ readonly id = "semantic.e5";
25
+ readonly name: string;
26
+ private readonly spec;
27
+ private readonly cacheRoot;
28
+ private readonly factory;
29
+ private readonly ready;
30
+ private readonly idleMs;
31
+ private readonly batchSize;
32
+ private backend;
33
+ private idleTimer;
34
+ private downloading;
35
+ private loading;
36
+ private configDimensions;
37
+ constructor(options: EmbedderOptions);
38
+ modelId(): string;
39
+ /** `hidden_size` of the downloaded `config.json`, else the size the table declares. */
40
+ dimensions(): number;
41
+ /** Set by the setup job so `health()` reports `starting` while the model downloads. */
42
+ setDownloading(value: boolean): void;
43
+ embed(texts: string[], options: {
44
+ kind: EmbeddingKind;
45
+ signal: AbortSignal;
46
+ }): Promise<Float32Array<ArrayBufferLike>[]>;
47
+ health(): Promise<SemanticHealth>;
48
+ /** Stops the worker (plugin dispose); the next `embed` starts it again. */
49
+ close(): void;
50
+ private load;
51
+ private armIdle;
52
+ }
53
+ /** Starts `worker.js` (a `node:worker_threads` worker) and talks to it by request id. */
54
+ export declare function workerBackend(modelDir: string, spec: ModelSpec, runtimeDir: string): Promise<EmbedBackend>;
55
+ //# sourceMappingURL=embedder.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"embedder.d.ts","sourceRoot":"","sources":["../../src/engine/embedder.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,aAAa,EAAE,iBAAiB,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAGpF,OAAO,EAAe,KAAK,SAAS,EAAW,MAAM,aAAa,CAAC;AAGnE,0FAA0F;AAC1F,MAAM,WAAW,YAAY;IAC3B,oEAAoE;IACpE,KAAK,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC,CAAC;IAChD,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACxB;AACD,MAAM,MAAM,cAAc,GAAG,CAC3B,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,SAAS,EACf,UAAU,EAAE,MAAM,KACf,OAAO,CAAC,YAAY,CAAC,CAAC;AAE3B,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,SAAS,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,cAAc,CAAC;IACzB,qFAAqF;IACrF,KAAK,CAAC,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,CAAC;IAC/B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAuBD;;;GAGG;AACH,qBAAa,UAAW,YAAW,iBAAiB;IAClD,QAAQ,CAAC,EAAE,iBAAiB;IAC5B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAY;IACjC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;IACnC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAiB;IACzC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAyB;IAC/C,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;IAChC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;IACnC,OAAO,CAAC,OAAO,CAAoC;IACnD,OAAO,CAAC,SAAS,CAA4C;IAC7D,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,gBAAgB,CAAqB;IAE7C,YAAY,OAAO,EAAE,eAAe,EAWnC;IAED,OAAO,WAEN;IAED,uFAAuF;IACvF,UAAU,WAaT;IAED,uFAAuF;IACvF,cAAc,CAAC,KAAK,EAAE,OAAO,QAE5B;IAEK,KAAK,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,OAAO,EAAE;QAAE,IAAI,EAAE,aAAa,CAAC;QAAC,MAAM,EAAE,WAAW,CAAA;KAAE,4CAqBjF;IAEK,MAAM,IAAI,OAAO,CAAC,cAAc,CAAC,CAItC;IAED,2EAA2E;IAC3E,KAAK,SAKJ;IAED,OAAO,CAAC,IAAI;IAkBZ,OAAO,CAAC,OAAO;CAKhB;AAOD,yFAAyF;AACzF,wBAAsB,aAAa,CACjC,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,SAAS,EACf,UAAU,EAAE,MAAM,GACjB,OAAO,CAAC,YAAY,CAAC,CAqDvB"}
@@ -0,0 +1,182 @@
1
+ import { readFileSync } from "node:fs";
2
+ import { join } from "node:path";
3
+ import { Worker } from "node:worker_threads";
4
+ import { SemanticPluginError } from "../errors.js";
5
+ import { isModelReady, modelPath } from "./download.js";
6
+ import { applyPrefix, modelId } from "./models.js";
7
+ import { isRuntimeReady, runtimePath } from "./runtime.js";
8
+ const IDLE_MS = 5 * 60 * 1000;
9
+ const BATCH = 32;
10
+ function abortable(promise, signal) {
11
+ if (signal.aborted)
12
+ return Promise.reject(signal.reason);
13
+ return new Promise((resolve, reject) => {
14
+ const onAbort = () => reject(signal.reason);
15
+ signal.addEventListener("abort", onAbort, { once: true });
16
+ promise.then((value) => {
17
+ signal.removeEventListener("abort", onAbort);
18
+ resolve(value);
19
+ }, (error) => {
20
+ signal.removeEventListener("abort", onAbort);
21
+ reject(error);
22
+ });
23
+ });
24
+ }
25
+ /**
26
+ * Local `EmbeddingProvider` (`semantic.e5`). Inference runs in a worker thread started lazily and
27
+ * stopped after 5 minutes idle (D5); inputs get the model family's prefixes (D7).
28
+ */
29
+ export class E5Embedder {
30
+ id = "semantic.e5";
31
+ name;
32
+ spec;
33
+ cacheRoot;
34
+ factory;
35
+ ready;
36
+ idleMs;
37
+ batchSize;
38
+ backend;
39
+ idleTimer;
40
+ downloading = false;
41
+ loading = false;
42
+ configDimensions;
43
+ constructor(options) {
44
+ this.spec = options.spec;
45
+ this.cacheRoot = options.cacheRoot;
46
+ this.factory = options.factory ?? workerBackend;
47
+ this.ready =
48
+ options.ready ??
49
+ (async () => (await isRuntimeReady(this.cacheRoot)) && (await isModelReady(this.cacheRoot, this.spec)));
50
+ this.idleMs = options.idleMs ?? IDLE_MS;
51
+ this.batchSize = options.batchSize ?? BATCH;
52
+ this.name = `Local ${options.spec.label}`;
53
+ }
54
+ modelId() {
55
+ return modelId(this.spec);
56
+ }
57
+ /** `hidden_size` of the downloaded `config.json`, else the size the table declares. */
58
+ dimensions() {
59
+ if (this.configDimensions === undefined) {
60
+ try {
61
+ const config = JSON.parse(readFileSync(join(modelPath(this.cacheRoot, this.spec), "config.json"), "utf8"));
62
+ if (Number.isInteger(config.hidden_size))
63
+ this.configDimensions = config.hidden_size;
64
+ }
65
+ catch {
66
+ return this.spec.dimensions;
67
+ }
68
+ }
69
+ return this.configDimensions ?? this.spec.dimensions;
70
+ }
71
+ /** Set by the setup job so `health()` reports `starting` while the model downloads. */
72
+ setDownloading(value) {
73
+ this.downloading = value;
74
+ }
75
+ async embed(texts, options) {
76
+ options.signal.throwIfAborted();
77
+ if (!(await this.ready()))
78
+ throw new SemanticPluginError("model_missing");
79
+ const prefixed = texts.map((text) => applyPrefix(this.spec, options.kind, text));
80
+ const vectors = [];
81
+ clearTimeout(this.idleTimer);
82
+ try {
83
+ const backend = await abortable(this.load(), options.signal);
84
+ for (let i = 0; i < prefixed.length; i += this.batchSize) {
85
+ options.signal.throwIfAborted();
86
+ vectors.push(...(await abortable(backend.embed(prefixed.slice(i, i + this.batchSize)), options.signal)));
87
+ }
88
+ }
89
+ finally {
90
+ this.armIdle();
91
+ }
92
+ return vectors;
93
+ }
94
+ async health() {
95
+ if (this.downloading || this.loading)
96
+ return { status: "starting" };
97
+ if (!(await this.ready()))
98
+ return { status: "unavailable", detail: "run /semantic:setup" };
99
+ return { status: "ready" };
100
+ }
101
+ /** Stops the worker (plugin dispose); the next `embed` starts it again. */
102
+ close() {
103
+ clearTimeout(this.idleTimer);
104
+ const backend = this.backend;
105
+ this.backend = undefined;
106
+ void backend?.then((b) => b.close()).catch(() => { });
107
+ }
108
+ load() {
109
+ if (!this.backend) {
110
+ this.loading = true;
111
+ const started = this.factory(modelPath(this.cacheRoot, this.spec), this.spec, runtimePath(this.cacheRoot)).finally(() => {
112
+ this.loading = false;
113
+ });
114
+ started.catch(() => {
115
+ if (this.backend === started)
116
+ this.backend = undefined;
117
+ });
118
+ this.backend = started;
119
+ }
120
+ return this.backend;
121
+ }
122
+ armIdle() {
123
+ clearTimeout(this.idleTimer);
124
+ this.idleTimer = setTimeout(() => this.close(), this.idleMs);
125
+ this.idleTimer.unref?.();
126
+ }
127
+ }
128
+ /** Starts `worker.js` (a `node:worker_threads` worker) and talks to it by request id. */
129
+ export async function workerBackend(modelDir, spec, runtimeDir) {
130
+ const worker = new Worker(new URL("./worker.js", import.meta.url), {
131
+ workerData: { modelDir, runtimeDir, maxTokens: spec.maxTokens },
132
+ });
133
+ worker.unref();
134
+ const pending = new Map();
135
+ let next = 0;
136
+ const failAll = (code) => {
137
+ for (const p of pending.values())
138
+ p.reject(new SemanticPluginError("engine_unavailable", code));
139
+ pending.clear();
140
+ };
141
+ await new Promise((resolve, reject) => {
142
+ worker.once("error", () => reject(new SemanticPluginError("engine_unavailable")));
143
+ worker.on("message", (message) => {
144
+ if (message.type === "ready") {
145
+ if (message.dimensions !== spec.dimensions) {
146
+ reject(new SemanticPluginError("model_corrupt"));
147
+ void worker.terminate();
148
+ }
149
+ else
150
+ resolve();
151
+ return;
152
+ }
153
+ if (message.type === "error" && message.id === undefined) {
154
+ reject(new SemanticPluginError(message.code === "model_corrupt" ? "model_corrupt" : "engine_unavailable"));
155
+ return;
156
+ }
157
+ const request = message.id === undefined ? undefined : pending.get(message.id);
158
+ if (!request || message.id === undefined)
159
+ return;
160
+ pending.delete(message.id);
161
+ if (message.type === "vectors")
162
+ request.resolve(message.vectors);
163
+ else
164
+ request.reject(new SemanticPluginError("engine_unavailable", message.code));
165
+ });
166
+ });
167
+ worker.on("error", () => failAll("worker_error"));
168
+ worker.on("exit", () => failAll("worker_exit"));
169
+ return {
170
+ embed(texts) {
171
+ const id = next++;
172
+ return new Promise((resolve, reject) => {
173
+ pending.set(id, { resolve, reject });
174
+ worker.postMessage({ type: "embed", id, texts });
175
+ });
176
+ },
177
+ async close() {
178
+ await worker.terminate();
179
+ },
180
+ };
181
+ }
182
+ //# sourceMappingURL=embedder.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"embedder.js","sourceRoot":"","sources":["../../src/engine/embedder.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,22 @@
1
+ export interface TokenizerLike {
2
+ encode(text: string): {
3
+ ids: number[];
4
+ };
5
+ }
6
+ /** Token ids per text, cut to `maxTokens` while keeping the closing special token. */
7
+ export declare function encodeBatch(tokenizer: TokenizerLike, texts: string[], maxTokens: number): number[][];
8
+ /**
9
+ * Row-major padded `int64` inputs. Padding uses the tokenizer's pad id: the q8 graph quantizes
10
+ * activations per tensor, so the pad value affects the numbers of the other rows.
11
+ */
12
+ export declare function batchInputs(encoded: number[][], padId: number): {
13
+ batch: number;
14
+ length: number;
15
+ inputIds: BigInt64Array<ArrayBuffer>;
16
+ attention: BigInt64Array<ArrayBuffer>;
17
+ tokenTypes: BigInt64Array<ArrayBuffer>;
18
+ lengths: number[];
19
+ };
20
+ /** Mean of the first `lengths[i]` token vectors of each row, scaled to unit length. */
21
+ export declare function meanPoolNormalize(hidden: Float32Array, dims: readonly number[], lengths: number[]): Float32Array[];
22
+ //# sourceMappingURL=infer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"infer.d.ts","sourceRoot":"","sources":["../../src/engine/infer.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,aAAa;IAC5B,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG;QAAE,GAAG,EAAE,MAAM,EAAE,CAAA;KAAE,CAAC;CACzC;AAED,sFAAsF;AACtF,wBAAgB,WAAW,CAAC,SAAS,EAAE,aAAa,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE,SAAS,EAAE,MAAM,cAMvF;AAED;;;GAGG;AACH,wBAAgB,WAAW,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM;;;;;;;EAa7D;AAED,uFAAuF;AACvF,wBAAgB,iBAAiB,CAC/B,MAAM,EAAE,YAAY,EACpB,IAAI,EAAE,SAAS,MAAM,EAAE,EACvB,OAAO,EAAE,MAAM,EAAE,GAChB,YAAY,EAAE,CAmBhB"}
@@ -0,0 +1,53 @@
1
+ // Pure inference helpers shared by the worker: tokenization limits, input tensors, mean pooling and
2
+ // L2 normalization. Verified against transformers.js `feature-extraction` (`pooling: "mean"`,
3
+ // `normalize: true`, `dtype: "q8"`): cosine 1.000000 on the pinned e5-small (spec §16).
4
+ /** Token ids per text, cut to `maxTokens` while keeping the closing special token. */
5
+ export function encodeBatch(tokenizer, texts, maxTokens) {
6
+ return texts.map((text) => {
7
+ const ids = tokenizer.encode(text).ids;
8
+ if (ids.length <= maxTokens)
9
+ return ids;
10
+ return [...ids.slice(0, maxTokens - 1), ids[ids.length - 1]];
11
+ });
12
+ }
13
+ /**
14
+ * Row-major padded `int64` inputs. Padding uses the tokenizer's pad id: the q8 graph quantizes
15
+ * activations per tensor, so the pad value affects the numbers of the other rows.
16
+ */
17
+ export function batchInputs(encoded, padId) {
18
+ const batch = encoded.length;
19
+ const length = Math.max(1, ...encoded.map((ids) => ids.length));
20
+ const inputIds = new BigInt64Array(batch * length).fill(BigInt(padId));
21
+ const attention = new BigInt64Array(batch * length);
22
+ const tokenTypes = new BigInt64Array(batch * length);
23
+ encoded.forEach((ids, row) => {
24
+ ids.forEach((id, col) => {
25
+ inputIds[row * length + col] = BigInt(id);
26
+ attention[row * length + col] = 1n;
27
+ });
28
+ });
29
+ return { batch, length, inputIds, attention, tokenTypes, lengths: encoded.map((e) => e.length) };
30
+ }
31
+ /** Mean of the first `lengths[i]` token vectors of each row, scaled to unit length. */
32
+ export function meanPoolNormalize(hidden, dims, lengths) {
33
+ const length = dims[1];
34
+ const size = dims[2];
35
+ return lengths.map((count, row) => {
36
+ const vector = new Float32Array(size);
37
+ for (let t = 0; t < count; t++) {
38
+ const offset = (row * length + t) * size;
39
+ for (let d = 0; d < size; d++)
40
+ vector[d] = vector[d] + hidden[offset + d];
41
+ }
42
+ let norm = 0;
43
+ for (let d = 0; d < size; d++) {
44
+ vector[d] = vector[d] / Math.max(1, count);
45
+ norm += vector[d] ** 2;
46
+ }
47
+ norm = Math.sqrt(norm) || 1;
48
+ for (let d = 0; d < size; d++)
49
+ vector[d] = vector[d] / norm;
50
+ return vector;
51
+ });
52
+ }
53
+ //# sourceMappingURL=infer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"infer.js","sourceRoot":"","sources":["../../src/engine/infer.ts"],"names":[],"mappings":"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"}