ruvector 0.2.28 → 0.2.29

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 (41) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +2270 -2270
  3. package/bin/cli.js +9570 -9479
  4. package/bin/mcp-server.js +3854 -3854
  5. package/dist/core/intelligence-engine.d.ts +13 -0
  6. package/dist/core/intelligence-engine.d.ts.map +1 -1
  7. package/dist/core/intelligence-engine.js +38 -0
  8. package/dist/core/onnx/bundled-parallel.mjs +164 -164
  9. package/dist/core/onnx/embed-worker.mjs +67 -67
  10. package/dist/core/onnx/loader.js +434 -434
  11. package/dist/core/onnx/package.json +3 -3
  12. package/dist/core/onnx/pkg/LICENSE +21 -21
  13. package/dist/core/onnx/pkg/loader.js +348 -348
  14. package/dist/core/onnx/pkg/package.json +3 -3
  15. package/dist/core/onnx/pkg/ruvector_onnx_embeddings_wasm.d.ts +112 -112
  16. package/dist/core/onnx/pkg/ruvector_onnx_embeddings_wasm.js +5 -5
  17. package/dist/core/onnx/pkg/ruvector_onnx_embeddings_wasm_bg.js +638 -638
  18. package/dist/core/onnx/pkg/ruvector_onnx_embeddings_wasm_bg.wasm.d.ts +29 -29
  19. package/dist/core/parallel-workers.js +439 -439
  20. package/dist/workers/benchmark.js +15 -15
  21. package/package.json +122 -122
  22. package/src/decompiler/api-prober.js +302 -302
  23. package/src/decompiler/index.js +463 -463
  24. package/src/decompiler/metrics.js +86 -86
  25. package/src/decompiler/model-decompiler.js +423 -423
  26. package/src/decompiler/module-splitter.js +498 -498
  27. package/src/decompiler/module-tree.js +142 -142
  28. package/src/decompiler/name-predictor.js +400 -400
  29. package/src/decompiler/npm-fetch.js +176 -176
  30. package/src/decompiler/reconstructor.js +499 -499
  31. package/src/decompiler/reference-tracker.js +285 -285
  32. package/src/decompiler/statement-parser.js +285 -285
  33. package/src/decompiler/style-improver.js +438 -438
  34. package/src/decompiler/subcategories.js +339 -339
  35. package/src/decompiler/validator.js +379 -379
  36. package/src/decompiler/witness.js +140 -140
  37. package/wasm/package.json +26 -26
  38. package/wasm/ruvector_decompiler_wasm.d.ts +27 -27
  39. package/wasm/ruvector_decompiler_wasm.js +220 -220
  40. package/wasm/ruvector_decompiler_wasm_bg.wasm.d.ts +16 -16
  41. package/dist/core/onnx/pkg/ruvector.db +0 -0
@@ -99,6 +99,9 @@ export declare class IntelligenceEngine {
99
99
  private agentMappings;
100
100
  private workerTriggerMappings;
101
101
  private currentTrajectoryId;
102
+ private currentTrajectoryContext;
103
+ private currentTrajectoryFile;
104
+ private currentTrajectoryAgent;
102
105
  private sessionStart;
103
106
  private learningEnabled;
104
107
  private episodeBatchQueue;
@@ -157,6 +160,16 @@ export declare class IntelligenceEngine {
157
160
  * Set the agent route for current trajectory
158
161
  */
159
162
  setTrajectoryRoute(agent: string): void;
163
+ /**
164
+ * Record the outcome of an agent routing decision.
165
+ *
166
+ * This is the write-side counterpart of route(): it derives the state key
167
+ * with the exact same getState()/getExtension() logic route() uses for
168
+ * lookups, so learned agent outcomes actually influence future routing
169
+ * (fixes #517 — previously only command/edit outcome episodes were stored,
170
+ * under state keys route() never queries).
171
+ */
172
+ recordRouteOutcome(task: string, file: string | undefined, agent: string, reward: number): void;
160
173
  /**
161
174
  * Record an episode for learning
162
175
  */
@@ -1 +1 @@
1
- {"version":3,"file":"intelligence-engine.d.ts","sourceRoot":"","sources":["../../src/core/intelligence-engine.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"intelligence-engine.d.ts","sourceRoot":"","sources":["../../src/core/intelligence-engine.ts"],"names":[],"mappings":"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"}
@@ -86,6 +86,9 @@ class IntelligenceEngine {
86
86
  this.workerTriggerMappings = new Map(); // trigger -> agents
87
87
  // Runtime state
88
88
  this.currentTrajectoryId = null;
89
+ this.currentTrajectoryContext = null;
90
+ this.currentTrajectoryFile = undefined;
91
+ this.currentTrajectoryAgent = null;
89
92
  this.sessionStart = Date.now();
90
93
  this.learningEnabled = true;
91
94
  this.episodeBatchQueue = [];
@@ -508,6 +511,11 @@ class IntelligenceEngine {
508
511
  */
509
512
  beginTrajectory(context, file) {
510
513
  const embed = this.embed(context + ' ' + (file || ''));
514
+ // Remember the task context so endTrajectory() can write the routing
515
+ // outcome into the same state namespace route() reads (issue #517).
516
+ this.currentTrajectoryContext = context;
517
+ this.currentTrajectoryFile = file;
518
+ this.currentTrajectoryAgent = null;
511
519
  if (this.sona) {
512
520
  try {
513
521
  this.currentTrajectoryId = this.sona.beginTrajectory(embed);
@@ -547,12 +555,21 @@ class IntelligenceEngine {
547
555
  // Ignore end errors
548
556
  }
549
557
  }
558
+ // Close the routing learning loop: if a route was chosen for this
559
+ // trajectory, record its outcome under the state key route() queries.
560
+ if (this.currentTrajectoryAgent && this.currentTrajectoryContext) {
561
+ this.recordRouteOutcome(this.currentTrajectoryContext, this.currentTrajectoryFile, this.currentTrajectoryAgent, q);
562
+ }
550
563
  this.currentTrajectoryId = null;
564
+ this.currentTrajectoryContext = null;
565
+ this.currentTrajectoryFile = undefined;
566
+ this.currentTrajectoryAgent = null;
551
567
  }
552
568
  /**
553
569
  * Set the agent route for current trajectory
554
570
  */
555
571
  setTrajectoryRoute(agent) {
572
+ this.currentTrajectoryAgent = agent;
556
573
  if (this.sona && this.currentTrajectoryId !== null) {
557
574
  try {
558
575
  this.sona.setRoute(this.currentTrajectoryId, agent);
@@ -562,6 +579,27 @@ class IntelligenceEngine {
562
579
  }
563
580
  }
564
581
  }
582
+ /**
583
+ * Record the outcome of an agent routing decision.
584
+ *
585
+ * This is the write-side counterpart of route(): it derives the state key
586
+ * with the exact same getState()/getExtension() logic route() uses for
587
+ * lookups, so learned agent outcomes actually influence future routing
588
+ * (fixes #517 — previously only command/edit outcome episodes were stored,
589
+ * under state keys route() never queries).
590
+ */
591
+ recordRouteOutcome(task, file, agent, reward) {
592
+ if (!agent || agent === 'unknown')
593
+ return;
594
+ const ext = file ? this.getExtension(file) : '';
595
+ const state = this.getState(task, ext);
596
+ if (!this.routingPatterns.has(state)) {
597
+ this.routingPatterns.set(state, new Map());
598
+ }
599
+ const patterns = this.routingPatterns.get(state);
600
+ const oldValue = patterns.get(agent) ?? 0.5;
601
+ patterns.set(agent, oldValue + this.config.learningRate * (reward - oldValue));
602
+ }
565
603
  // =========================================================================
566
604
  // Episode Learning (Q-learning compatible)
567
605
  // =========================================================================
@@ -1,164 +1,164 @@
1
- /**
2
- * Bundled-WASM parallel embedder (issue #523 SOTA).
3
- *
4
- * A self-contained worker_threads pool — NO external dependency — that shards
5
- * batches of text across CPU cores, each worker running the bundled ONNX WASM
6
- * embedder over the SAME model bytes (shared via SharedArrayBuffer) and config.
7
- * Output vectors are identical to the single-thread path (cosine-equivalent),
8
- * so this is a pure throughput optimization with no quality change.
9
- *
10
- * Drop-in shape compatible with the optional `ruvector-onnx-embeddings-wasm/parallel`
11
- * package: { numWorkers, dimension, init(), embedBatch(texts) -> number[][], shutdown() }.
12
- */
13
- import { Worker } from 'node:worker_threads';
14
- import * as os from 'node:os';
15
- import { fileURLToPath } from 'node:url';
16
- import * as path from 'node:path';
17
-
18
- const __dirname = path.dirname(fileURLToPath(import.meta.url));
19
-
20
- export class ParallelEmbedder {
21
- /**
22
- * @param {object} opts
23
- * @param {Uint8Array} opts.modelBytes raw ONNX model bytes (loaded once by caller)
24
- * @param {string} opts.tokenizerJson
25
- * @param {number} [opts.maxLength=256]
26
- * @param {number} [opts.dimension=384]
27
- * @param {number} [opts.numWorkers] defaults to min(cpus-2, 16), >=2
28
- */
29
- constructor(opts = {}) {
30
- this.numWorkers = opts.numWorkers || Math.max(2, Math.min((os.cpus().length || 4) - 2, 16));
31
- this.dimension = opts.dimension || 384;
32
- this._modelBytes = opts.modelBytes;
33
- this._tokenizerJson = opts.tokenizerJson;
34
- this._maxLength = opts.maxLength || 256;
35
- this._requestTimeoutMs = opts.requestTimeoutMs ?? 30000;
36
- this._workers = [];
37
- this._pending = new Map(); // id -> { resolve, reject, worker, timer }
38
- this._seq = 0;
39
- this._shuttingDown = false;
40
- }
41
-
42
- async init() {
43
- if (!this._modelBytes || !this._tokenizerJson) {
44
- throw new Error('ParallelEmbedder requires modelBytes and tokenizerJson');
45
- }
46
- // Share model bytes across all workers via a single SharedArrayBuffer.
47
- const sab = new SharedArrayBuffer(this._modelBytes.length);
48
- new Uint8Array(sab).set(this._modelBytes);
49
-
50
- const workerUrl = new URL('./embed-worker.mjs', import.meta.url);
51
- const readies = [];
52
-
53
- for (let i = 0; i < this.numWorkers; i++) {
54
- const w = new Worker(workerUrl, {
55
- workerData: { modelSab: sab, tokenizerJson: this._tokenizerJson, maxLength: this._maxLength },
56
- });
57
- w.on('message', (m) => this._onMessage(m));
58
- // If a worker dies (uncaught error or unexpected exit), fail every request
59
- // currently routed to it instead of letting those promises hang forever.
60
- w.on('error', (e) => this._failWorker(w, e instanceof Error ? e : new Error(String(e))));
61
- w.on('exit', (code) => {
62
- if (!this._shuttingDown && code !== 0) {
63
- this._failWorker(w, new Error(`embed worker exited unexpectedly (code ${code})`));
64
- }
65
- });
66
- this._workers.push(w);
67
- readies.push(new Promise((resolve, reject) => {
68
- const onReady = (m) => {
69
- if (m.type === 'ready') { cleanup(); resolve(); }
70
- else if (m.type === 'init-error') { cleanup(); reject(new Error('worker init failed: ' + m.error)); }
71
- };
72
- const onErr = (e) => { cleanup(); reject(e); };
73
- const cleanup = () => { w.off('message', onReady); w.off('error', onErr); };
74
- w.on('message', onReady);
75
- w.once('error', onErr);
76
- }));
77
- }
78
-
79
- await Promise.all(readies);
80
- // Drop the main-thread reference; the SAB keeps the shared copy alive.
81
- this._modelBytes = null;
82
- }
83
-
84
- _settle(id, fn) {
85
- const p = this._pending.get(id);
86
- if (!p) return;
87
- this._pending.delete(id);
88
- if (p.timer) clearTimeout(p.timer);
89
- fn(p);
90
- }
91
-
92
- _onMessage(m) {
93
- if (m.type !== 'result' && m.type !== 'error') return;
94
- this._settle(m.id, (p) => {
95
- if (m.type === 'error') p.reject(new Error(m.error));
96
- else p.resolve({ dim: m.dim, count: m.count, flat: new Float32Array(m.buffer) });
97
- });
98
- }
99
-
100
- /** Reject every in-flight request routed to a dead worker. */
101
- _failWorker(worker, err) {
102
- for (const [id, p] of this._pending) {
103
- if (p.worker === worker) this._settle(id, () => p.reject(err));
104
- }
105
- }
106
-
107
- _send(worker, texts) {
108
- const id = ++this._seq;
109
- return new Promise((resolve, reject) => {
110
- const entry = { resolve, reject, worker, timer: null };
111
- if (this._requestTimeoutMs > 0) {
112
- entry.timer = setTimeout(() => {
113
- this._settle(id, () =>
114
- reject(new Error(`embed request timed out after ${this._requestTimeoutMs}ms`)));
115
- }, this._requestTimeoutMs);
116
- // Don't keep the event loop alive solely for this timer.
117
- if (typeof entry.timer.unref === 'function') entry.timer.unref();
118
- }
119
- this._pending.set(id, entry);
120
- worker.postMessage({ type: 'embed', id, texts });
121
- });
122
- }
123
-
124
- /**
125
- * Embed many texts, sharded across workers. Returns number[][] in input order.
126
- */
127
- async embedBatch(texts) {
128
- if (!texts || texts.length === 0) return [];
129
- const n = this._workers.length;
130
- const shard = Math.ceil(texts.length / n);
131
- const tasks = [];
132
- const starts = [];
133
- for (let i = 0; i < n; i++) {
134
- const start = i * shard;
135
- if (start >= texts.length) break;
136
- const end = Math.min(texts.length, start + shard);
137
- starts.push(start);
138
- tasks.push(this._send(this._workers[i], texts.slice(start, end)));
139
- }
140
- const results = await Promise.all(tasks);
141
- const out = new Array(texts.length);
142
- for (let r = 0; r < results.length; r++) {
143
- const { dim, count, flat } = results[r];
144
- const start = starts[r];
145
- for (let j = 0; j < count; j++) {
146
- out[start + j] = Array.from(flat.subarray(j * dim, (j + 1) * dim));
147
- }
148
- }
149
- return out;
150
- }
151
-
152
- async shutdown() {
153
- this._shuttingDown = true;
154
- // Reject anything still in flight so callers don't hang on shutdown.
155
- for (const [id, p] of this._pending) {
156
- this._settle(id, () => p.reject(new Error('ParallelEmbedder shut down')));
157
- }
158
- const ws = this._workers;
159
- this._workers = [];
160
- await Promise.all(ws.map((w) => w.terminate()));
161
- }
162
- }
163
-
164
- export default ParallelEmbedder;
1
+ /**
2
+ * Bundled-WASM parallel embedder (issue #523 SOTA).
3
+ *
4
+ * A self-contained worker_threads pool — NO external dependency — that shards
5
+ * batches of text across CPU cores, each worker running the bundled ONNX WASM
6
+ * embedder over the SAME model bytes (shared via SharedArrayBuffer) and config.
7
+ * Output vectors are identical to the single-thread path (cosine-equivalent),
8
+ * so this is a pure throughput optimization with no quality change.
9
+ *
10
+ * Drop-in shape compatible with the optional `ruvector-onnx-embeddings-wasm/parallel`
11
+ * package: { numWorkers, dimension, init(), embedBatch(texts) -> number[][], shutdown() }.
12
+ */
13
+ import { Worker } from 'node:worker_threads';
14
+ import * as os from 'node:os';
15
+ import { fileURLToPath } from 'node:url';
16
+ import * as path from 'node:path';
17
+
18
+ const __dirname = path.dirname(fileURLToPath(import.meta.url));
19
+
20
+ export class ParallelEmbedder {
21
+ /**
22
+ * @param {object} opts
23
+ * @param {Uint8Array} opts.modelBytes raw ONNX model bytes (loaded once by caller)
24
+ * @param {string} opts.tokenizerJson
25
+ * @param {number} [opts.maxLength=256]
26
+ * @param {number} [opts.dimension=384]
27
+ * @param {number} [opts.numWorkers] defaults to min(cpus-2, 16), >=2
28
+ */
29
+ constructor(opts = {}) {
30
+ this.numWorkers = opts.numWorkers || Math.max(2, Math.min((os.cpus().length || 4) - 2, 16));
31
+ this.dimension = opts.dimension || 384;
32
+ this._modelBytes = opts.modelBytes;
33
+ this._tokenizerJson = opts.tokenizerJson;
34
+ this._maxLength = opts.maxLength || 256;
35
+ this._requestTimeoutMs = opts.requestTimeoutMs ?? 30000;
36
+ this._workers = [];
37
+ this._pending = new Map(); // id -> { resolve, reject, worker, timer }
38
+ this._seq = 0;
39
+ this._shuttingDown = false;
40
+ }
41
+
42
+ async init() {
43
+ if (!this._modelBytes || !this._tokenizerJson) {
44
+ throw new Error('ParallelEmbedder requires modelBytes and tokenizerJson');
45
+ }
46
+ // Share model bytes across all workers via a single SharedArrayBuffer.
47
+ const sab = new SharedArrayBuffer(this._modelBytes.length);
48
+ new Uint8Array(sab).set(this._modelBytes);
49
+
50
+ const workerUrl = new URL('./embed-worker.mjs', import.meta.url);
51
+ const readies = [];
52
+
53
+ for (let i = 0; i < this.numWorkers; i++) {
54
+ const w = new Worker(workerUrl, {
55
+ workerData: { modelSab: sab, tokenizerJson: this._tokenizerJson, maxLength: this._maxLength },
56
+ });
57
+ w.on('message', (m) => this._onMessage(m));
58
+ // If a worker dies (uncaught error or unexpected exit), fail every request
59
+ // currently routed to it instead of letting those promises hang forever.
60
+ w.on('error', (e) => this._failWorker(w, e instanceof Error ? e : new Error(String(e))));
61
+ w.on('exit', (code) => {
62
+ if (!this._shuttingDown && code !== 0) {
63
+ this._failWorker(w, new Error(`embed worker exited unexpectedly (code ${code})`));
64
+ }
65
+ });
66
+ this._workers.push(w);
67
+ readies.push(new Promise((resolve, reject) => {
68
+ const onReady = (m) => {
69
+ if (m.type === 'ready') { cleanup(); resolve(); }
70
+ else if (m.type === 'init-error') { cleanup(); reject(new Error('worker init failed: ' + m.error)); }
71
+ };
72
+ const onErr = (e) => { cleanup(); reject(e); };
73
+ const cleanup = () => { w.off('message', onReady); w.off('error', onErr); };
74
+ w.on('message', onReady);
75
+ w.once('error', onErr);
76
+ }));
77
+ }
78
+
79
+ await Promise.all(readies);
80
+ // Drop the main-thread reference; the SAB keeps the shared copy alive.
81
+ this._modelBytes = null;
82
+ }
83
+
84
+ _settle(id, fn) {
85
+ const p = this._pending.get(id);
86
+ if (!p) return;
87
+ this._pending.delete(id);
88
+ if (p.timer) clearTimeout(p.timer);
89
+ fn(p);
90
+ }
91
+
92
+ _onMessage(m) {
93
+ if (m.type !== 'result' && m.type !== 'error') return;
94
+ this._settle(m.id, (p) => {
95
+ if (m.type === 'error') p.reject(new Error(m.error));
96
+ else p.resolve({ dim: m.dim, count: m.count, flat: new Float32Array(m.buffer) });
97
+ });
98
+ }
99
+
100
+ /** Reject every in-flight request routed to a dead worker. */
101
+ _failWorker(worker, err) {
102
+ for (const [id, p] of this._pending) {
103
+ if (p.worker === worker) this._settle(id, () => p.reject(err));
104
+ }
105
+ }
106
+
107
+ _send(worker, texts) {
108
+ const id = ++this._seq;
109
+ return new Promise((resolve, reject) => {
110
+ const entry = { resolve, reject, worker, timer: null };
111
+ if (this._requestTimeoutMs > 0) {
112
+ entry.timer = setTimeout(() => {
113
+ this._settle(id, () =>
114
+ reject(new Error(`embed request timed out after ${this._requestTimeoutMs}ms`)));
115
+ }, this._requestTimeoutMs);
116
+ // Don't keep the event loop alive solely for this timer.
117
+ if (typeof entry.timer.unref === 'function') entry.timer.unref();
118
+ }
119
+ this._pending.set(id, entry);
120
+ worker.postMessage({ type: 'embed', id, texts });
121
+ });
122
+ }
123
+
124
+ /**
125
+ * Embed many texts, sharded across workers. Returns number[][] in input order.
126
+ */
127
+ async embedBatch(texts) {
128
+ if (!texts || texts.length === 0) return [];
129
+ const n = this._workers.length;
130
+ const shard = Math.ceil(texts.length / n);
131
+ const tasks = [];
132
+ const starts = [];
133
+ for (let i = 0; i < n; i++) {
134
+ const start = i * shard;
135
+ if (start >= texts.length) break;
136
+ const end = Math.min(texts.length, start + shard);
137
+ starts.push(start);
138
+ tasks.push(this._send(this._workers[i], texts.slice(start, end)));
139
+ }
140
+ const results = await Promise.all(tasks);
141
+ const out = new Array(texts.length);
142
+ for (let r = 0; r < results.length; r++) {
143
+ const { dim, count, flat } = results[r];
144
+ const start = starts[r];
145
+ for (let j = 0; j < count; j++) {
146
+ out[start + j] = Array.from(flat.subarray(j * dim, (j + 1) * dim));
147
+ }
148
+ }
149
+ return out;
150
+ }
151
+
152
+ async shutdown() {
153
+ this._shuttingDown = true;
154
+ // Reject anything still in flight so callers don't hang on shutdown.
155
+ for (const [id, p] of this._pending) {
156
+ this._settle(id, () => p.reject(new Error('ParallelEmbedder shut down')));
157
+ }
158
+ const ws = this._workers;
159
+ this._workers = [];
160
+ await Promise.all(ws.map((w) => w.terminate()));
161
+ }
162
+ }
163
+
164
+ export default ParallelEmbedder;
@@ -1,67 +1,67 @@
1
- /**
2
- * Worker-thread entry for the bundled-WASM parallel embedder (issue #523 SOTA).
3
- *
4
- * Each worker loads its own instance of the bundled ONNX WASM embedder from the
5
- * SAME model bytes (shared via SharedArrayBuffer — no per-worker download) and
6
- * the SAME config, so the vectors it produces are identical to the single-thread
7
- * path (cosine-equivalent by construction).
8
- *
9
- * Protocol:
10
- * workerData: { modelSab: SharedArrayBuffer, tokenizerJson: string, maxLength: number }
11
- * → posts { type: 'ready' } once the WASM embedder is constructed
12
- * message { type: 'embed', id, texts: string[] }
13
- * → posts { type: 'result', id, dim, count, buffer } (Float32Array buffer, transferred)
14
- * errors → { type: 'error', id, error }
15
- */
16
- import { parentPort, workerData } from 'node:worker_threads';
17
- import { pathToFileURL, fileURLToPath } from 'node:url';
18
- import * as path from 'node:path';
19
- import * as fs from 'node:fs';
20
-
21
- const __dirname = path.dirname(fileURLToPath(import.meta.url));
22
-
23
- let embedder = null;
24
-
25
- async function init() {
26
- const bgJsPath = path.join(__dirname, 'pkg', 'ruvector_onnx_embeddings_wasm_bg.js');
27
- const wasmPath = path.join(__dirname, 'pkg', 'ruvector_onnx_embeddings_wasm_bg.wasm');
28
-
29
- const wasmModule = await import(pathToFileURL(bgJsPath).href);
30
- const wasmBytes = fs.readFileSync(wasmPath);
31
- const wasmResult = await WebAssembly.instantiate(wasmBytes, {
32
- './ruvector_onnx_embeddings_wasm_bg.js': wasmModule,
33
- });
34
- const wasmExports = wasmResult.instance.exports;
35
- if (typeof wasmModule.__wbg_set_wasm === 'function') wasmModule.__wbg_set_wasm(wasmExports);
36
- if (typeof wasmExports.__wbindgen_start === 'function') wasmExports.__wbindgen_start();
37
-
38
- // Reconstruct model bytes from the shared buffer (zero-copy view, then handed
39
- // to wasm-bindgen which copies into WASM linear memory).
40
- const modelBytes = new Uint8Array(workerData.modelSab);
41
-
42
- const cfg = new wasmModule.WasmEmbedderConfig()
43
- .setMaxLength(workerData.maxLength || 256)
44
- .setNormalize(true)
45
- .setPooling(0); // Mean pooling — matches the single-thread path.
46
-
47
- embedder = wasmModule.WasmEmbedder.withConfig(modelBytes, workerData.tokenizerJson, cfg);
48
- }
49
-
50
- parentPort.on('message', (msg) => {
51
- if (msg.type !== 'embed') return;
52
- try {
53
- const dim = embedder.dimension();
54
- const flat = embedder.embedBatch(msg.texts); // length = texts.length * dim
55
- const arr = Float32Array.from(flat);
56
- parentPort.postMessage(
57
- { type: 'result', id: msg.id, dim, count: msg.texts.length, buffer: arr.buffer },
58
- [arr.buffer],
59
- );
60
- } catch (e) {
61
- parentPort.postMessage({ type: 'error', id: msg.id, error: e?.message || String(e) });
62
- }
63
- });
64
-
65
- init()
66
- .then(() => parentPort.postMessage({ type: 'ready' }))
67
- .catch((e) => parentPort.postMessage({ type: 'init-error', error: e?.message || String(e) }));
1
+ /**
2
+ * Worker-thread entry for the bundled-WASM parallel embedder (issue #523 SOTA).
3
+ *
4
+ * Each worker loads its own instance of the bundled ONNX WASM embedder from the
5
+ * SAME model bytes (shared via SharedArrayBuffer — no per-worker download) and
6
+ * the SAME config, so the vectors it produces are identical to the single-thread
7
+ * path (cosine-equivalent by construction).
8
+ *
9
+ * Protocol:
10
+ * workerData: { modelSab: SharedArrayBuffer, tokenizerJson: string, maxLength: number }
11
+ * → posts { type: 'ready' } once the WASM embedder is constructed
12
+ * message { type: 'embed', id, texts: string[] }
13
+ * → posts { type: 'result', id, dim, count, buffer } (Float32Array buffer, transferred)
14
+ * errors → { type: 'error', id, error }
15
+ */
16
+ import { parentPort, workerData } from 'node:worker_threads';
17
+ import { pathToFileURL, fileURLToPath } from 'node:url';
18
+ import * as path from 'node:path';
19
+ import * as fs from 'node:fs';
20
+
21
+ const __dirname = path.dirname(fileURLToPath(import.meta.url));
22
+
23
+ let embedder = null;
24
+
25
+ async function init() {
26
+ const bgJsPath = path.join(__dirname, 'pkg', 'ruvector_onnx_embeddings_wasm_bg.js');
27
+ const wasmPath = path.join(__dirname, 'pkg', 'ruvector_onnx_embeddings_wasm_bg.wasm');
28
+
29
+ const wasmModule = await import(pathToFileURL(bgJsPath).href);
30
+ const wasmBytes = fs.readFileSync(wasmPath);
31
+ const wasmResult = await WebAssembly.instantiate(wasmBytes, {
32
+ './ruvector_onnx_embeddings_wasm_bg.js': wasmModule,
33
+ });
34
+ const wasmExports = wasmResult.instance.exports;
35
+ if (typeof wasmModule.__wbg_set_wasm === 'function') wasmModule.__wbg_set_wasm(wasmExports);
36
+ if (typeof wasmExports.__wbindgen_start === 'function') wasmExports.__wbindgen_start();
37
+
38
+ // Reconstruct model bytes from the shared buffer (zero-copy view, then handed
39
+ // to wasm-bindgen which copies into WASM linear memory).
40
+ const modelBytes = new Uint8Array(workerData.modelSab);
41
+
42
+ const cfg = new wasmModule.WasmEmbedderConfig()
43
+ .setMaxLength(workerData.maxLength || 256)
44
+ .setNormalize(true)
45
+ .setPooling(0); // Mean pooling — matches the single-thread path.
46
+
47
+ embedder = wasmModule.WasmEmbedder.withConfig(modelBytes, workerData.tokenizerJson, cfg);
48
+ }
49
+
50
+ parentPort.on('message', (msg) => {
51
+ if (msg.type !== 'embed') return;
52
+ try {
53
+ const dim = embedder.dimension();
54
+ const flat = embedder.embedBatch(msg.texts); // length = texts.length * dim
55
+ const arr = Float32Array.from(flat);
56
+ parentPort.postMessage(
57
+ { type: 'result', id: msg.id, dim, count: msg.texts.length, buffer: arr.buffer },
58
+ [arr.buffer],
59
+ );
60
+ } catch (e) {
61
+ parentPort.postMessage({ type: 'error', id: msg.id, error: e?.message || String(e) });
62
+ }
63
+ });
64
+
65
+ init()
66
+ .then(() => parentPort.postMessage({ type: 'ready' }))
67
+ .catch((e) => parentPort.postMessage({ type: 'init-error', error: e?.message || String(e) }));