@ruvector/edge-net 0.1.7 → 0.2.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.
- package/ledger.js +663 -0
- package/monitor.js +675 -0
- package/onnx-worker.js +482 -0
- package/package.json +40 -5
- package/qdag.js +582 -0
- package/scheduler.js +764 -0
- package/signaling.js +732 -0
package/onnx-worker.js
ADDED
|
@@ -0,0 +1,482 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @ruvector/edge-net ONNX Worker Module
|
|
3
|
+
*
|
|
4
|
+
* Real semantic embeddings and LLM inference for workers
|
|
5
|
+
* Uses @xenova/transformers for actual AI inference
|
|
6
|
+
*
|
|
7
|
+
* @module @ruvector/edge-net/onnx-worker
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { EventEmitter } from 'events';
|
|
11
|
+
import { randomBytes } from 'crypto';
|
|
12
|
+
|
|
13
|
+
// ============================================
|
|
14
|
+
// ONNX EMBEDDER (REAL SEMANTIC EMBEDDINGS)
|
|
15
|
+
// ============================================
|
|
16
|
+
|
|
17
|
+
let transformers = null;
|
|
18
|
+
let embeddingPipeline = null;
|
|
19
|
+
let textGenPipeline = null;
|
|
20
|
+
let loadedEmbedModel = null;
|
|
21
|
+
let loadedGenModel = null;
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Available embedding models (smallest first)
|
|
25
|
+
*/
|
|
26
|
+
export const EMBEDDING_MODELS = {
|
|
27
|
+
'minilm-l6': {
|
|
28
|
+
id: 'Xenova/all-MiniLM-L6-v2',
|
|
29
|
+
dimensions: 384,
|
|
30
|
+
size: '~22MB',
|
|
31
|
+
description: 'Fast, good quality embeddings',
|
|
32
|
+
},
|
|
33
|
+
'minilm-l12': {
|
|
34
|
+
id: 'Xenova/all-MiniLM-L12-v2',
|
|
35
|
+
dimensions: 384,
|
|
36
|
+
size: '~33MB',
|
|
37
|
+
description: 'Better quality, slightly slower',
|
|
38
|
+
},
|
|
39
|
+
'gte-small': {
|
|
40
|
+
id: 'Xenova/gte-small',
|
|
41
|
+
dimensions: 384,
|
|
42
|
+
size: '~67MB',
|
|
43
|
+
description: 'High quality embeddings',
|
|
44
|
+
},
|
|
45
|
+
'bge-small': {
|
|
46
|
+
id: 'Xenova/bge-small-en-v1.5',
|
|
47
|
+
dimensions: 384,
|
|
48
|
+
size: '~33MB',
|
|
49
|
+
description: 'Best for retrieval tasks',
|
|
50
|
+
},
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Available text generation models
|
|
55
|
+
*/
|
|
56
|
+
export const GENERATION_MODELS = {
|
|
57
|
+
'distilgpt2': {
|
|
58
|
+
id: 'Xenova/distilgpt2',
|
|
59
|
+
size: '~82MB',
|
|
60
|
+
description: 'Fast text generation',
|
|
61
|
+
},
|
|
62
|
+
'gpt2': {
|
|
63
|
+
id: 'Xenova/gpt2',
|
|
64
|
+
size: '~250MB',
|
|
65
|
+
description: 'Classic GPT-2',
|
|
66
|
+
},
|
|
67
|
+
'tinystories': {
|
|
68
|
+
id: 'Xenova/TinyStories-33M',
|
|
69
|
+
size: '~65MB',
|
|
70
|
+
description: 'Ultra-small for stories',
|
|
71
|
+
},
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Initialize transformers.js
|
|
76
|
+
*/
|
|
77
|
+
async function initTransformers() {
|
|
78
|
+
if (transformers) return transformers;
|
|
79
|
+
|
|
80
|
+
try {
|
|
81
|
+
transformers = await import('@xenova/transformers');
|
|
82
|
+
|
|
83
|
+
// Configure cache
|
|
84
|
+
const { env } = transformers;
|
|
85
|
+
env.cacheDir = process.env.ONNX_CACHE_DIR ||
|
|
86
|
+
(process.env.HOME ? `${process.env.HOME}/.ruvector/models/onnx` : '/tmp/.ruvector/models/onnx');
|
|
87
|
+
env.allowRemoteModels = true;
|
|
88
|
+
env.allowLocalModels = true;
|
|
89
|
+
|
|
90
|
+
return transformers;
|
|
91
|
+
} catch (error) {
|
|
92
|
+
console.error('[ONNX Worker] transformers.js not available:', error.message);
|
|
93
|
+
return null;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Initialize embedding model
|
|
99
|
+
*/
|
|
100
|
+
export async function initEmbedding(modelKey = 'minilm-l6') {
|
|
101
|
+
const tf = await initTransformers();
|
|
102
|
+
if (!tf) return false;
|
|
103
|
+
|
|
104
|
+
const model = EMBEDDING_MODELS[modelKey] || EMBEDDING_MODELS['minilm-l6'];
|
|
105
|
+
|
|
106
|
+
if (embeddingPipeline && loadedEmbedModel === model.id) {
|
|
107
|
+
return true;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
try {
|
|
111
|
+
console.error(`[ONNX] Loading embedding model: ${model.id}...`);
|
|
112
|
+
const { pipeline } = tf;
|
|
113
|
+
embeddingPipeline = await pipeline('feature-extraction', model.id, {
|
|
114
|
+
quantized: true,
|
|
115
|
+
});
|
|
116
|
+
loadedEmbedModel = model.id;
|
|
117
|
+
console.error(`[ONNX] Embedding model ready: ${model.id}`);
|
|
118
|
+
return true;
|
|
119
|
+
} catch (error) {
|
|
120
|
+
console.error('[ONNX] Failed to load embedding model:', error.message);
|
|
121
|
+
return false;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* Initialize text generation model
|
|
127
|
+
*/
|
|
128
|
+
export async function initGeneration(modelKey = 'distilgpt2') {
|
|
129
|
+
const tf = await initTransformers();
|
|
130
|
+
if (!tf) return false;
|
|
131
|
+
|
|
132
|
+
const model = GENERATION_MODELS[modelKey] || GENERATION_MODELS['distilgpt2'];
|
|
133
|
+
|
|
134
|
+
if (textGenPipeline && loadedGenModel === model.id) {
|
|
135
|
+
return true;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
try {
|
|
139
|
+
console.error(`[ONNX] Loading generation model: ${model.id}...`);
|
|
140
|
+
const { pipeline } = tf;
|
|
141
|
+
textGenPipeline = await pipeline('text-generation', model.id, {
|
|
142
|
+
quantized: true,
|
|
143
|
+
});
|
|
144
|
+
loadedGenModel = model.id;
|
|
145
|
+
console.error(`[ONNX] Generation model ready: ${model.id}`);
|
|
146
|
+
return true;
|
|
147
|
+
} catch (error) {
|
|
148
|
+
console.error('[ONNX] Failed to load generation model:', error.message);
|
|
149
|
+
return false;
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* Generate real semantic embeddings
|
|
155
|
+
*/
|
|
156
|
+
export async function embed(texts, options = {}) {
|
|
157
|
+
const initialized = await initEmbedding(options.model);
|
|
158
|
+
|
|
159
|
+
if (!initialized || !embeddingPipeline) {
|
|
160
|
+
// Fallback to hash-based embeddings
|
|
161
|
+
return fallbackEmbed(texts);
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
const inputTexts = Array.isArray(texts) ? texts : [texts];
|
|
165
|
+
const startTime = performance.now();
|
|
166
|
+
|
|
167
|
+
try {
|
|
168
|
+
const results = [];
|
|
169
|
+
|
|
170
|
+
for (const text of inputTexts) {
|
|
171
|
+
const output = await embeddingPipeline(text, {
|
|
172
|
+
pooling: 'mean',
|
|
173
|
+
normalize: true,
|
|
174
|
+
});
|
|
175
|
+
|
|
176
|
+
// Convert tensor to array
|
|
177
|
+
const embedding = Array.from(output.data);
|
|
178
|
+
|
|
179
|
+
results.push({
|
|
180
|
+
text: text.slice(0, 100),
|
|
181
|
+
embedding,
|
|
182
|
+
dimensions: embedding.length,
|
|
183
|
+
semantic: true,
|
|
184
|
+
});
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
const timeMs = performance.now() - startTime;
|
|
188
|
+
|
|
189
|
+
return {
|
|
190
|
+
embeddings: results,
|
|
191
|
+
model: loadedEmbedModel,
|
|
192
|
+
timeMs,
|
|
193
|
+
count: results.length,
|
|
194
|
+
semantic: true,
|
|
195
|
+
};
|
|
196
|
+
} catch (error) {
|
|
197
|
+
console.error('[ONNX] Embedding error:', error.message);
|
|
198
|
+
return fallbackEmbed(texts);
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
/**
|
|
203
|
+
* Fallback hash-based embeddings
|
|
204
|
+
*/
|
|
205
|
+
function fallbackEmbed(texts) {
|
|
206
|
+
const inputTexts = Array.isArray(texts) ? texts : [texts];
|
|
207
|
+
|
|
208
|
+
const results = inputTexts.map(text => {
|
|
209
|
+
const hash = createHash('sha256').update(String(text)).digest();
|
|
210
|
+
const embedding = new Float32Array(384);
|
|
211
|
+
for (let i = 0; i < 384; i++) {
|
|
212
|
+
embedding[i] = (hash[i % 32] - 128) / 128;
|
|
213
|
+
}
|
|
214
|
+
return {
|
|
215
|
+
text: String(text).slice(0, 100),
|
|
216
|
+
embedding: Array.from(embedding),
|
|
217
|
+
dimensions: 384,
|
|
218
|
+
semantic: false,
|
|
219
|
+
};
|
|
220
|
+
});
|
|
221
|
+
|
|
222
|
+
return {
|
|
223
|
+
embeddings: results,
|
|
224
|
+
model: 'hash-fallback',
|
|
225
|
+
count: results.length,
|
|
226
|
+
semantic: false,
|
|
227
|
+
};
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
/**
|
|
231
|
+
* Generate text using ONNX LLM
|
|
232
|
+
*/
|
|
233
|
+
export async function generate(prompt, options = {}) {
|
|
234
|
+
const initialized = await initGeneration(options.model);
|
|
235
|
+
|
|
236
|
+
if (!initialized || !textGenPipeline) {
|
|
237
|
+
return {
|
|
238
|
+
text: `[Fallback] Processing: ${prompt.slice(0, 50)}...`,
|
|
239
|
+
model: 'fallback',
|
|
240
|
+
semantic: false,
|
|
241
|
+
};
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
const startTime = performance.now();
|
|
245
|
+
|
|
246
|
+
try {
|
|
247
|
+
const outputs = await textGenPipeline(prompt, {
|
|
248
|
+
max_new_tokens: options.maxTokens || 64,
|
|
249
|
+
temperature: options.temperature || 0.7,
|
|
250
|
+
top_p: options.topP || 0.9,
|
|
251
|
+
do_sample: true,
|
|
252
|
+
return_full_text: false,
|
|
253
|
+
});
|
|
254
|
+
|
|
255
|
+
const timeMs = performance.now() - startTime;
|
|
256
|
+
const generatedText = outputs[0]?.generated_text || '';
|
|
257
|
+
|
|
258
|
+
return {
|
|
259
|
+
text: generatedText.trim(),
|
|
260
|
+
model: loadedGenModel,
|
|
261
|
+
timeMs,
|
|
262
|
+
tokensPerSecond: Math.round((generatedText.split(/\s+/).length * 1.3) / (timeMs / 1000)),
|
|
263
|
+
semantic: true,
|
|
264
|
+
};
|
|
265
|
+
} catch (error) {
|
|
266
|
+
console.error('[ONNX] Generation error:', error.message);
|
|
267
|
+
return {
|
|
268
|
+
text: `[Error] ${error.message}`,
|
|
269
|
+
model: 'error',
|
|
270
|
+
semantic: false,
|
|
271
|
+
};
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
/**
|
|
276
|
+
* Compute similarity between two texts
|
|
277
|
+
*/
|
|
278
|
+
export async function similarity(text1, text2, options = {}) {
|
|
279
|
+
const result = await embed([text1, text2], options);
|
|
280
|
+
|
|
281
|
+
if (result.embeddings.length < 2) {
|
|
282
|
+
return { similarity: 0, semantic: false };
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
const e1 = result.embeddings[0].embedding;
|
|
286
|
+
const e2 = result.embeddings[1].embedding;
|
|
287
|
+
|
|
288
|
+
// Cosine similarity
|
|
289
|
+
let dotProduct = 0;
|
|
290
|
+
let norm1 = 0;
|
|
291
|
+
let norm2 = 0;
|
|
292
|
+
|
|
293
|
+
for (let i = 0; i < e1.length; i++) {
|
|
294
|
+
dotProduct += e1[i] * e2[i];
|
|
295
|
+
norm1 += e1[i] * e1[i];
|
|
296
|
+
norm2 += e2[i] * e2[i];
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
const cosineSim = dotProduct / (Math.sqrt(norm1) * Math.sqrt(norm2));
|
|
300
|
+
|
|
301
|
+
return {
|
|
302
|
+
similarity: cosineSim,
|
|
303
|
+
text1: text1.slice(0, 50),
|
|
304
|
+
text2: text2.slice(0, 50),
|
|
305
|
+
model: result.model,
|
|
306
|
+
semantic: result.semantic,
|
|
307
|
+
};
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
/**
|
|
311
|
+
* Semantic search - find most similar texts
|
|
312
|
+
*/
|
|
313
|
+
export async function semanticSearch(query, documents, options = {}) {
|
|
314
|
+
const topK = options.topK || 5;
|
|
315
|
+
|
|
316
|
+
// Embed query and documents together
|
|
317
|
+
const allTexts = [query, ...documents];
|
|
318
|
+
const result = await embed(allTexts, options);
|
|
319
|
+
|
|
320
|
+
if (result.embeddings.length < 2) {
|
|
321
|
+
return { results: [], semantic: false };
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
const queryEmbed = result.embeddings[0].embedding;
|
|
325
|
+
const docEmbeds = result.embeddings.slice(1);
|
|
326
|
+
|
|
327
|
+
// Calculate similarities
|
|
328
|
+
const scores = docEmbeds.map((doc, index) => {
|
|
329
|
+
let dotProduct = 0;
|
|
330
|
+
let norm1 = 0;
|
|
331
|
+
let norm2 = 0;
|
|
332
|
+
|
|
333
|
+
for (let i = 0; i < queryEmbed.length; i++) {
|
|
334
|
+
dotProduct += queryEmbed[i] * doc.embedding[i];
|
|
335
|
+
norm1 += queryEmbed[i] * queryEmbed[i];
|
|
336
|
+
norm2 += doc.embedding[i] * doc.embedding[i];
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
return {
|
|
340
|
+
index,
|
|
341
|
+
text: documents[index],
|
|
342
|
+
score: dotProduct / (Math.sqrt(norm1) * Math.sqrt(norm2)),
|
|
343
|
+
};
|
|
344
|
+
});
|
|
345
|
+
|
|
346
|
+
// Sort by score and return top K
|
|
347
|
+
scores.sort((a, b) => b.score - a.score);
|
|
348
|
+
|
|
349
|
+
return {
|
|
350
|
+
query,
|
|
351
|
+
results: scores.slice(0, topK),
|
|
352
|
+
model: result.model,
|
|
353
|
+
semantic: result.semantic,
|
|
354
|
+
};
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
// ============================================
|
|
358
|
+
// ONNX WORKER POOL
|
|
359
|
+
// ============================================
|
|
360
|
+
|
|
361
|
+
/**
|
|
362
|
+
* Enhanced worker pool with ONNX capabilities
|
|
363
|
+
*/
|
|
364
|
+
export class OnnxWorkerPool extends EventEmitter {
|
|
365
|
+
constructor(options = {}) {
|
|
366
|
+
super();
|
|
367
|
+
this.id = `onnx-pool-${randomBytes(6).toString('hex')}`;
|
|
368
|
+
this.embedModel = options.embedModel || 'minilm-l6';
|
|
369
|
+
this.genModel = options.genModel || 'distilgpt2';
|
|
370
|
+
this.initialized = false;
|
|
371
|
+
|
|
372
|
+
this.stats = {
|
|
373
|
+
embeddings: 0,
|
|
374
|
+
generations: 0,
|
|
375
|
+
searches: 0,
|
|
376
|
+
totalTimeMs: 0,
|
|
377
|
+
};
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
/**
|
|
381
|
+
* Initialize ONNX models
|
|
382
|
+
*/
|
|
383
|
+
async initialize() {
|
|
384
|
+
this.emit('status', 'Initializing ONNX models...');
|
|
385
|
+
|
|
386
|
+
// Initialize embedding model
|
|
387
|
+
const embedReady = await initEmbedding(this.embedModel);
|
|
388
|
+
|
|
389
|
+
// Initialize generation model (optional)
|
|
390
|
+
const genReady = await initGeneration(this.genModel);
|
|
391
|
+
|
|
392
|
+
this.initialized = embedReady;
|
|
393
|
+
|
|
394
|
+
this.emit('ready', {
|
|
395
|
+
poolId: this.id,
|
|
396
|
+
embedding: embedReady,
|
|
397
|
+
generation: genReady,
|
|
398
|
+
});
|
|
399
|
+
|
|
400
|
+
return this;
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
/**
|
|
404
|
+
* Execute an ONNX task
|
|
405
|
+
*/
|
|
406
|
+
async execute(type, data, options = {}) {
|
|
407
|
+
const startTime = performance.now();
|
|
408
|
+
let result;
|
|
409
|
+
|
|
410
|
+
switch (type) {
|
|
411
|
+
case 'embed':
|
|
412
|
+
result = await embed(data, options);
|
|
413
|
+
this.stats.embeddings++;
|
|
414
|
+
break;
|
|
415
|
+
|
|
416
|
+
case 'generate':
|
|
417
|
+
result = await generate(data, options);
|
|
418
|
+
this.stats.generations++;
|
|
419
|
+
break;
|
|
420
|
+
|
|
421
|
+
case 'similarity':
|
|
422
|
+
result = await similarity(data.text1, data.text2, options);
|
|
423
|
+
break;
|
|
424
|
+
|
|
425
|
+
case 'search':
|
|
426
|
+
result = await semanticSearch(data.query, data.documents, options);
|
|
427
|
+
this.stats.searches++;
|
|
428
|
+
break;
|
|
429
|
+
|
|
430
|
+
default:
|
|
431
|
+
throw new Error(`Unknown task type: ${type}`);
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
this.stats.totalTimeMs += performance.now() - startTime;
|
|
435
|
+
|
|
436
|
+
return result;
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
/**
|
|
440
|
+
* Batch embed documents
|
|
441
|
+
*/
|
|
442
|
+
async embedBatch(texts, options = {}) {
|
|
443
|
+
return this.execute('embed', texts, options);
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
/**
|
|
447
|
+
* Semantic search
|
|
448
|
+
*/
|
|
449
|
+
async search(query, documents, options = {}) {
|
|
450
|
+
return this.execute('search', { query, documents }, options);
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
/**
|
|
454
|
+
* Get pool status
|
|
455
|
+
*/
|
|
456
|
+
getStatus() {
|
|
457
|
+
return {
|
|
458
|
+
poolId: this.id,
|
|
459
|
+
initialized: this.initialized,
|
|
460
|
+
embedModel: loadedEmbedModel,
|
|
461
|
+
genModel: loadedGenModel,
|
|
462
|
+
stats: this.stats,
|
|
463
|
+
};
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
/**
|
|
467
|
+
* Shutdown pool
|
|
468
|
+
*/
|
|
469
|
+
async shutdown() {
|
|
470
|
+
embeddingPipeline = null;
|
|
471
|
+
textGenPipeline = null;
|
|
472
|
+
loadedEmbedModel = null;
|
|
473
|
+
loadedGenModel = null;
|
|
474
|
+
this.initialized = false;
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
// ============================================
|
|
479
|
+
// EXPORTS
|
|
480
|
+
// ============================================
|
|
481
|
+
|
|
482
|
+
export default OnnxWorkerPool;
|
package/package.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ruvector/edge-net",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"type": "module",
|
|
5
|
-
"description": "Distributed compute intelligence network with AI agents and workers - contribute browser compute, spawn distributed AI agents, earn credits. Features Time Crystal coordination, Neural DAG attention, P2P swarm intelligence, and multi-agent workflows.",
|
|
5
|
+
"description": "Distributed compute intelligence network with AI agents and workers - contribute browser compute, spawn distributed AI agents, earn credits. Features Time Crystal coordination, Neural DAG attention, P2P swarm intelligence, ONNX inference, WebRTC signaling, CRDT ledger, and multi-agent workflows.",
|
|
6
6
|
"main": "ruvector_edge_net.js",
|
|
7
7
|
"module": "ruvector_edge_net.js",
|
|
8
8
|
"types": "ruvector_edge_net.d.ts",
|
|
@@ -35,7 +35,15 @@
|
|
|
35
35
|
"worker-pools",
|
|
36
36
|
"multi-agent",
|
|
37
37
|
"webrtc",
|
|
38
|
-
"task-orchestration"
|
|
38
|
+
"task-orchestration",
|
|
39
|
+
"onnx",
|
|
40
|
+
"semantic-search",
|
|
41
|
+
"crdt",
|
|
42
|
+
"ledger",
|
|
43
|
+
"signaling",
|
|
44
|
+
"scheduler",
|
|
45
|
+
"monitoring",
|
|
46
|
+
"qdag"
|
|
39
47
|
],
|
|
40
48
|
"author": "RuVector Team <team@ruvector.dev>",
|
|
41
49
|
"license": "MIT",
|
|
@@ -65,6 +73,12 @@
|
|
|
65
73
|
"real-workers.js",
|
|
66
74
|
"real-workflows.js",
|
|
67
75
|
"sync.js",
|
|
76
|
+
"onnx-worker.js",
|
|
77
|
+
"signaling.js",
|
|
78
|
+
"qdag.js",
|
|
79
|
+
"ledger.js",
|
|
80
|
+
"scheduler.js",
|
|
81
|
+
"monitor.js",
|
|
68
82
|
"README.md",
|
|
69
83
|
"LICENSE"
|
|
70
84
|
],
|
|
@@ -96,6 +110,24 @@
|
|
|
96
110
|
},
|
|
97
111
|
"./webrtc": {
|
|
98
112
|
"import": "./webrtc.js"
|
|
113
|
+
},
|
|
114
|
+
"./onnx-worker": {
|
|
115
|
+
"import": "./onnx-worker.js"
|
|
116
|
+
},
|
|
117
|
+
"./signaling": {
|
|
118
|
+
"import": "./signaling.js"
|
|
119
|
+
},
|
|
120
|
+
"./qdag": {
|
|
121
|
+
"import": "./qdag.js"
|
|
122
|
+
},
|
|
123
|
+
"./ledger": {
|
|
124
|
+
"import": "./ledger.js"
|
|
125
|
+
},
|
|
126
|
+
"./scheduler": {
|
|
127
|
+
"import": "./scheduler.js"
|
|
128
|
+
},
|
|
129
|
+
"./monitor": {
|
|
130
|
+
"import": "./monitor.js"
|
|
99
131
|
}
|
|
100
132
|
},
|
|
101
133
|
"sideEffects": [
|
|
@@ -113,10 +145,13 @@
|
|
|
113
145
|
"join:multi": "node join.js --generate",
|
|
114
146
|
"network": "node network.js stats",
|
|
115
147
|
"peers": "node join.js --peers",
|
|
116
|
-
"history": "node join.js --history"
|
|
148
|
+
"history": "node join.js --history",
|
|
149
|
+
"signaling": "node -e \"import('./signaling.js').then(m => new m.SignalingServer().start())\"",
|
|
150
|
+
"monitor": "node -e \"import('./monitor.js').then(m => { const mon = new m.Monitor(); mon.start(); setInterval(() => console.log(JSON.stringify(mon.generateReport(), null, 2)), 5000); })\""
|
|
117
151
|
},
|
|
118
152
|
"dependencies": {
|
|
119
153
|
"@ruvector/ruvllm": "^0.2.3",
|
|
120
|
-
"@xenova/transformers": "^2.17.2"
|
|
154
|
+
"@xenova/transformers": "^2.17.2",
|
|
155
|
+
"ws": "^8.18.3"
|
|
121
156
|
}
|
|
122
157
|
}
|