ruvector 0.2.27 → 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.
- package/LICENSE +21 -21
- package/README.md +2270 -2270
- package/bin/cli.js +9570 -9479
- package/bin/mcp-server.js +3854 -3854
- package/dist/core/intelligence-engine.d.ts +13 -0
- package/dist/core/intelligence-engine.d.ts.map +1 -1
- package/dist/core/intelligence-engine.js +38 -0
- package/dist/core/onnx/bundled-parallel.mjs +164 -164
- package/dist/core/onnx/embed-worker.mjs +67 -67
- package/dist/core/onnx/loader.js +434 -434
- package/dist/core/onnx/package.json +3 -3
- package/dist/core/onnx/pkg/LICENSE +21 -21
- package/dist/core/onnx/pkg/loader.js +348 -348
- package/dist/core/onnx/pkg/package.json +3 -3
- package/dist/core/onnx/pkg/ruvector_onnx_embeddings_wasm.d.ts +112 -112
- package/dist/core/onnx/pkg/ruvector_onnx_embeddings_wasm.js +5 -5
- package/dist/core/onnx/pkg/ruvector_onnx_embeddings_wasm_bg.js +638 -638
- package/dist/core/onnx/pkg/ruvector_onnx_embeddings_wasm_bg.wasm.d.ts +29 -29
- package/dist/core/onnx-embedder.d.ts.map +1 -1
- package/dist/core/onnx-embedder.js +24 -30
- package/dist/core/parallel-workers.js +439 -439
- package/dist/workers/benchmark.js +15 -15
- package/package.json +122 -122
- package/src/decompiler/api-prober.js +302 -302
- package/src/decompiler/index.js +463 -463
- package/src/decompiler/metrics.js +86 -86
- package/src/decompiler/model-decompiler.js +423 -423
- package/src/decompiler/module-splitter.js +498 -498
- package/src/decompiler/module-tree.js +142 -142
- package/src/decompiler/name-predictor.js +400 -400
- package/src/decompiler/npm-fetch.js +176 -176
- package/src/decompiler/reconstructor.js +499 -499
- package/src/decompiler/reference-tracker.js +285 -285
- package/src/decompiler/statement-parser.js +285 -285
- package/src/decompiler/style-improver.js +438 -438
- package/src/decompiler/subcategories.js +339 -339
- package/src/decompiler/validator.js +379 -379
- package/src/decompiler/witness.js +140 -140
- package/wasm/package.json +26 -26
- package/wasm/ruvector_decompiler_wasm.d.ts +27 -27
- package/wasm/ruvector_decompiler_wasm.js +220 -220
- package/wasm/ruvector_decompiler_wasm_bg.wasm.d.ts +16 -16
- 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) }));
|