@ruvector/edge-net 0.1.2 → 0.1.3

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 (3) hide show
  1. package/README.md +160 -0
  2. package/agents.js +965 -0
  3. package/package.json +19 -3
package/README.md CHANGED
@@ -44,6 +44,7 @@ A distributed computing platform that enables collective resource sharing for AI
44
44
  - [Exotic AI Capabilities](#exotic-ai-capabilities)
45
45
  - [Core Architecture & Capabilities](#core-architecture--capabilities)
46
46
  - [Self-Learning Hooks & MCP Integration](#self-learning-hooks--mcp-integration)
47
+ - [Distributed AI Agents & Workers](#distributed-ai-agents--workers)
47
48
 
48
49
  ---
49
50
 
@@ -1238,6 +1239,165 @@ ruvector hooks remember <content> -t <type> # Store memory
1238
1239
  ruvector hooks recall <query> # Semantic search
1239
1240
  ```
1240
1241
 
1242
+ ---
1243
+
1244
+ ## Distributed AI Agents & Workers
1245
+
1246
+ Edge-net enables spawning AI agents and distributed worker pools across the collective compute network. This transforms passive compute contribution into active distributed AI execution.
1247
+
1248
+ ### Architecture
1249
+
1250
+ ```
1251
+ ┌─────────────────────────────────────────────────────────────────────────────┐
1252
+ │ DISTRIBUTED AI AGENT SYSTEM │
1253
+ ├─────────────────────────────────────────────────────────────────────────────┤
1254
+ │ │
1255
+ │ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ │
1256
+ │ │ AgentSpawner │ │ WorkerPool │ │ TaskOrchestrator│ │
1257
+ │ │ │ │ │ │ │ │
1258
+ │ │ • Type routing │ │ • Load balance │ │ • Workflows │ │
1259
+ │ │ • rUv costing │ │ • Auto-scaling │ │ • Dependencies │ │
1260
+ │ │ • Priority mgmt │ │ • Fault tolerant│ │ • Parallel exec │ │
1261
+ │ └────────┬────────┘ └────────┬────────┘ └────────┬────────┘ │
1262
+ │ │ │ │ │
1263
+ │ └───────────────────────┼───────────────────────┘ │
1264
+ │ │ │
1265
+ │ ┌────────────┴────────────┐ │
1266
+ │ │ Edge-Net P2P Network │ │
1267
+ │ │ (WebRTC Data Channels) │ │
1268
+ │ └──────────────────────────┘ │
1269
+ │ │
1270
+ │ Agent Types: researcher | coder | reviewer | tester | analyst | │
1271
+ │ optimizer | coordinator | embedder │
1272
+ │ │
1273
+ └─────────────────────────────────────────────────────────────────────────────┘
1274
+ ```
1275
+
1276
+ ### Agent Types
1277
+
1278
+ | Type | Capabilities | Base rUv | Use Cases |
1279
+ |------|-------------|----------|-----------|
1280
+ | **researcher** | search, analyze, summarize, extract | 10 | Codebase analysis, documentation research |
1281
+ | **coder** | code, refactor, debug, test | 15 | Feature implementation, bug fixes |
1282
+ | **reviewer** | review, audit, validate, suggest | 12 | Code review, security audit |
1283
+ | **tester** | test, benchmark, validate, report | 10 | Test creation, coverage analysis |
1284
+ | **analyst** | analyze, metrics, report, visualize | 8 | Performance analysis, data insights |
1285
+ | **optimizer** | optimize, profile, benchmark, improve | 15 | Performance tuning, efficiency |
1286
+ | **coordinator** | orchestrate, route, schedule, monitor | 20 | Multi-agent workflows |
1287
+ | **embedder** | embed, vectorize, similarity, search | 5 | Vector operations, semantic search |
1288
+
1289
+ ### CLI Commands
1290
+
1291
+ ```bash
1292
+ # Show Edge-Net information
1293
+ ruvector edge-net info
1294
+
1295
+ # Spawn a distributed AI agent
1296
+ ruvector edge-net spawn researcher "Analyze the authentication system"
1297
+ ruvector edge-net spawn coder "Implement user profile feature" --max-ruv 50 --priority high
1298
+
1299
+ # Create and use worker pools
1300
+ ruvector edge-net pool create --size 10 --capabilities compute,embed
1301
+ ruvector edge-net pool execute "Process batch embeddings"
1302
+
1303
+ # Run multi-agent workflows
1304
+ ruvector edge-net workflow code-review
1305
+ ruvector edge-net workflow feature-dev
1306
+ ruvector edge-net workflow optimization
1307
+
1308
+ # Check network status
1309
+ ruvector edge-net status
1310
+ ```
1311
+
1312
+ ### MCP Tools
1313
+
1314
+ The following MCP tools are available when `ruvector` is configured as an MCP server:
1315
+
1316
+ | Tool | Description | Parameters |
1317
+ |------|-------------|------------|
1318
+ | `edge_net_info` | Get Edge-Net information | - |
1319
+ | `edge_net_spawn` | Spawn distributed agent | type, task, max_ruv, priority |
1320
+ | `edge_net_pool_create` | Create worker pool | min_workers, max_workers |
1321
+ | `edge_net_pool_execute` | Execute on pool | task, pool_id |
1322
+ | `edge_net_workflow` | Run workflow | name (code-review, feature-dev, etc.) |
1323
+ | `edge_net_status` | Network status | - |
1324
+
1325
+ ### Workflows
1326
+
1327
+ Pre-built multi-agent workflows:
1328
+
1329
+ | Workflow | Steps | Est. rUv | Description |
1330
+ |----------|-------|----------|-------------|
1331
+ | **code-review** | analyst → reviewer → tester → optimizer | 45 | Comprehensive code analysis |
1332
+ | **feature-dev** | researcher → coder → tester → reviewer | 60 | Full feature development cycle |
1333
+ | **bug-fix** | analyst → coder → tester | 35 | Bug diagnosis and fix |
1334
+ | **optimization** | analyst → optimizer → coder → tester | 50 | Performance improvement |
1335
+ | **research** | researcher → analyst → embedder | 30 | Deep research with embeddings |
1336
+
1337
+ ### JavaScript API
1338
+
1339
+ ```javascript
1340
+ import { AgentSpawner, WorkerPool, TaskOrchestrator, AGENT_TYPES } from '@ruvector/edge-net/agents';
1341
+
1342
+ // Spawn a distributed agent
1343
+ const spawner = new AgentSpawner(edgeNetNode);
1344
+ const agent = await spawner.spawn('coder', 'Implement authentication', {
1345
+ maxRuv: 30,
1346
+ priority: 'high'
1347
+ });
1348
+
1349
+ // Create a worker pool
1350
+ const pool = new WorkerPool(edgeNetNode, {
1351
+ minWorkers: 5,
1352
+ maxWorkers: 20,
1353
+ capabilities: ['compute', 'embed', 'analyze']
1354
+ });
1355
+ await pool.scale(10);
1356
+
1357
+ // Execute tasks on the pool
1358
+ const result = await pool.execute({
1359
+ type: 'parallel',
1360
+ task: 'Process batch data',
1361
+ data: largeDataset
1362
+ });
1363
+
1364
+ // Run multi-agent workflow
1365
+ const orchestrator = new TaskOrchestrator(edgeNetNode, spawner);
1366
+ await orchestrator.runWorkflow('feature-dev', 'Add user authentication');
1367
+ ```
1368
+
1369
+ ### Event System
1370
+
1371
+ Agents and workers emit events for monitoring:
1372
+
1373
+ ```javascript
1374
+ agent.on('started', ({ id, type }) => console.log(`Agent ${id} started`));
1375
+ agent.on('progress', ({ progress }) => console.log(`Progress: ${progress}%`));
1376
+ agent.on('completed', ({ result }) => console.log('Done:', result));
1377
+ agent.on('error', ({ error }) => console.error('Error:', error));
1378
+
1379
+ pool.on('scaled', ({ workers }) => console.log(`Pool scaled to ${workers}`));
1380
+ pool.on('task_completed', ({ taskId }) => console.log(`Task ${taskId} done`));
1381
+ ```
1382
+
1383
+ ### rUv Economics for Agents
1384
+
1385
+ | Factor | Impact |
1386
+ |--------|--------|
1387
+ | **Base Cost** | Agent type determines base rUv per task |
1388
+ | **Task Complexity** | Longer/complex tasks cost more |
1389
+ | **Priority** | High priority = 1.5x cost, Critical = 2x |
1390
+ | **Network Load** | Dynamic pricing based on availability |
1391
+ | **Early Adopter** | 10x multiplier during genesis phase |
1392
+
1393
+ ### Security Considerations
1394
+
1395
+ - All agent communications are encrypted via DTLS
1396
+ - Task execution sandboxed in WebWorkers
1397
+ - rUv spending limits prevent runaway costs
1398
+ - Input validation on all MCP tools
1399
+ - Rate limiting on agent spawning
1400
+
1241
1401
  ### Claude Code Hook Events
1242
1402
 
1243
1403
  | Event | Trigger | Action |
package/agents.js ADDED
@@ -0,0 +1,965 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Edge-Net Agent System
4
+ *
5
+ * Distributed AI agent execution across the Edge-Net collective.
6
+ * Spawn agents, create worker pools, and orchestrate multi-agent workflows.
7
+ */
8
+
9
+ import { EventEmitter } from 'events';
10
+ import { randomBytes, createHash } from 'crypto';
11
+
12
+ // Agent types and their capabilities
13
+ export const AGENT_TYPES = {
14
+ researcher: {
15
+ name: 'Researcher',
16
+ capabilities: ['search', 'analyze', 'summarize', 'extract'],
17
+ baseRuv: 10,
18
+ description: 'Analyzes and researches information',
19
+ },
20
+ coder: {
21
+ name: 'Coder',
22
+ capabilities: ['code', 'refactor', 'debug', 'test'],
23
+ baseRuv: 15,
24
+ description: 'Writes and improves code',
25
+ },
26
+ reviewer: {
27
+ name: 'Reviewer',
28
+ capabilities: ['review', 'audit', 'validate', 'suggest'],
29
+ baseRuv: 12,
30
+ description: 'Reviews code and provides feedback',
31
+ },
32
+ tester: {
33
+ name: 'Tester',
34
+ capabilities: ['test', 'benchmark', 'validate', 'report'],
35
+ baseRuv: 10,
36
+ description: 'Tests and validates implementations',
37
+ },
38
+ analyst: {
39
+ name: 'Analyst',
40
+ capabilities: ['analyze', 'metrics', 'report', 'visualize'],
41
+ baseRuv: 8,
42
+ description: 'Analyzes data and generates reports',
43
+ },
44
+ optimizer: {
45
+ name: 'Optimizer',
46
+ capabilities: ['optimize', 'profile', 'benchmark', 'improve'],
47
+ baseRuv: 15,
48
+ description: 'Optimizes performance and efficiency',
49
+ },
50
+ coordinator: {
51
+ name: 'Coordinator',
52
+ capabilities: ['orchestrate', 'route', 'schedule', 'monitor'],
53
+ baseRuv: 20,
54
+ description: 'Coordinates multi-agent workflows',
55
+ },
56
+ embedder: {
57
+ name: 'Embedder',
58
+ capabilities: ['embed', 'vectorize', 'similarity', 'search'],
59
+ baseRuv: 5,
60
+ description: 'Generates embeddings and vector operations',
61
+ },
62
+ };
63
+
64
+ // Task status enum
65
+ export const TaskStatus = {
66
+ PENDING: 'pending',
67
+ QUEUED: 'queued',
68
+ ASSIGNED: 'assigned',
69
+ RUNNING: 'running',
70
+ COMPLETED: 'completed',
71
+ FAILED: 'failed',
72
+ CANCELLED: 'cancelled',
73
+ };
74
+
75
+ /**
76
+ * Distributed Agent
77
+ *
78
+ * Represents an AI agent running on the Edge-Net network.
79
+ */
80
+ export class DistributedAgent extends EventEmitter {
81
+ constructor(options) {
82
+ super();
83
+ this.id = `agent-${randomBytes(8).toString('hex')}`;
84
+ this.type = options.type || 'researcher';
85
+ this.task = options.task;
86
+ this.config = AGENT_TYPES[this.type] || AGENT_TYPES.researcher;
87
+ this.maxRuv = options.maxRuv || this.config.baseRuv;
88
+ this.priority = options.priority || 'medium';
89
+ this.timeout = options.timeout || 300000; // 5 min default
90
+
91
+ this.status = TaskStatus.PENDING;
92
+ this.assignedNode = null;
93
+ this.progress = 0;
94
+ this.result = null;
95
+ this.error = null;
96
+ this.startTime = null;
97
+ this.endTime = null;
98
+ this.ruvSpent = 0;
99
+
100
+ this.subtasks = [];
101
+ this.logs = [];
102
+ }
103
+
104
+ /**
105
+ * Get agent info
106
+ */
107
+ getInfo() {
108
+ return {
109
+ id: this.id,
110
+ type: this.type,
111
+ task: this.task,
112
+ status: this.status,
113
+ progress: this.progress,
114
+ assignedNode: this.assignedNode,
115
+ maxRuv: this.maxRuv,
116
+ ruvSpent: this.ruvSpent,
117
+ startTime: this.startTime,
118
+ endTime: this.endTime,
119
+ duration: this.endTime && this.startTime
120
+ ? this.endTime - this.startTime
121
+ : null,
122
+ };
123
+ }
124
+
125
+ /**
126
+ * Update agent progress
127
+ */
128
+ updateProgress(progress, message) {
129
+ this.progress = Math.min(100, Math.max(0, progress));
130
+ this.log(`Progress: ${this.progress}% - ${message}`);
131
+ this.emit('progress', { progress: this.progress, message });
132
+ }
133
+
134
+ /**
135
+ * Log message
136
+ */
137
+ log(message) {
138
+ const entry = {
139
+ timestamp: Date.now(),
140
+ message,
141
+ };
142
+ this.logs.push(entry);
143
+ this.emit('log', entry);
144
+ }
145
+
146
+ /**
147
+ * Mark as completed
148
+ */
149
+ complete(result) {
150
+ this.status = TaskStatus.COMPLETED;
151
+ this.result = result;
152
+ this.progress = 100;
153
+ this.endTime = Date.now();
154
+ this.log('Agent completed successfully');
155
+ this.emit('complete', result);
156
+ }
157
+
158
+ /**
159
+ * Mark as failed
160
+ */
161
+ fail(error) {
162
+ this.status = TaskStatus.FAILED;
163
+ this.error = error;
164
+ this.endTime = Date.now();
165
+ this.log(`Agent failed: ${error}`);
166
+ this.emit('error', error);
167
+ }
168
+
169
+ /**
170
+ * Cancel the agent
171
+ */
172
+ cancel() {
173
+ this.status = TaskStatus.CANCELLED;
174
+ this.endTime = Date.now();
175
+ this.log('Agent cancelled');
176
+ this.emit('cancelled');
177
+ }
178
+ }
179
+
180
+ /**
181
+ * Agent Spawner
182
+ *
183
+ * Spawns and manages distributed agents across the Edge-Net network.
184
+ */
185
+ export class AgentSpawner extends EventEmitter {
186
+ constructor(networkManager, options = {}) {
187
+ super();
188
+ this.network = networkManager;
189
+ this.agents = new Map();
190
+ this.pendingQueue = [];
191
+ this.maxConcurrent = options.maxConcurrent || 10;
192
+ this.defaultTimeout = options.defaultTimeout || 300000;
193
+
194
+ // Agent routing table (learned from outcomes)
195
+ this.routingTable = new Map();
196
+
197
+ // Stats
198
+ this.stats = {
199
+ totalSpawned: 0,
200
+ completed: 0,
201
+ failed: 0,
202
+ totalRuvSpent: 0,
203
+ };
204
+ }
205
+
206
+ /**
207
+ * Spawn a new agent on the network
208
+ */
209
+ async spawn(options) {
210
+ const agent = new DistributedAgent({
211
+ ...options,
212
+ timeout: options.timeout || this.defaultTimeout,
213
+ });
214
+
215
+ this.agents.set(agent.id, agent);
216
+ this.stats.totalSpawned++;
217
+
218
+ agent.log(`Agent spawned: ${agent.type} - ${agent.task}`);
219
+ agent.status = TaskStatus.QUEUED;
220
+
221
+ // Find best node for this agent type
222
+ const targetNode = await this.findBestNode(agent);
223
+
224
+ if (targetNode) {
225
+ await this.assignToNode(agent, targetNode);
226
+ } else {
227
+ // Queue for later assignment
228
+ this.pendingQueue.push(agent);
229
+ agent.log('Queued - waiting for available node');
230
+ }
231
+
232
+ this.emit('agent-spawned', agent);
233
+ return agent;
234
+ }
235
+
236
+ /**
237
+ * Find the best node for an agent based on capabilities and load
238
+ */
239
+ async findBestNode(agent) {
240
+ if (!this.network) return null;
241
+
242
+ const peers = this.network.getPeerList ?
243
+ this.network.getPeerList() :
244
+ Array.from(this.network.peers?.values() || []);
245
+
246
+ if (peers.length === 0) return null;
247
+
248
+ // Score each peer based on:
249
+ // 1. Capability match
250
+ // 2. Current load
251
+ // 3. Historical performance
252
+ // 4. Latency
253
+ const scoredPeers = peers.map(peer => {
254
+ let score = 50; // Base score
255
+
256
+ // Check capabilities
257
+ const peerCaps = peer.capabilities || [];
258
+ const requiredCaps = agent.config.capabilities;
259
+ const capMatch = requiredCaps.filter(c => peerCaps.includes(c)).length;
260
+ score += capMatch * 10;
261
+
262
+ // Check load (lower is better)
263
+ const load = peer.load || 0;
264
+ score -= load * 20;
265
+
266
+ // Check historical performance
267
+ const history = this.routingTable.get(`${peer.piKey || peer.id}-${agent.type}`);
268
+ if (history) {
269
+ score += history.successRate * 30;
270
+ score -= history.avgLatency / 1000; // Penalize high latency
271
+ }
272
+
273
+ return { peer, score };
274
+ });
275
+
276
+ // Sort by score (highest first)
277
+ scoredPeers.sort((a, b) => b.score - a.score);
278
+
279
+ return scoredPeers[0]?.peer || null;
280
+ }
281
+
282
+ /**
283
+ * Assign agent to a specific node
284
+ */
285
+ async assignToNode(agent, node) {
286
+ agent.status = TaskStatus.ASSIGNED;
287
+ agent.assignedNode = node.piKey || node.id;
288
+ agent.startTime = Date.now();
289
+ agent.log(`Assigned to node: ${agent.assignedNode.slice(0, 12)}...`);
290
+
291
+ // Send task to node via network
292
+ if (this.network?.sendToPeer) {
293
+ await this.network.sendToPeer(agent.assignedNode, {
294
+ type: 'agent_task',
295
+ agentId: agent.id,
296
+ agentType: agent.type,
297
+ task: agent.task,
298
+ maxRuv: agent.maxRuv,
299
+ timeout: agent.timeout,
300
+ });
301
+ }
302
+
303
+ agent.status = TaskStatus.RUNNING;
304
+ this.emit('agent-assigned', { agent, node });
305
+
306
+ // Set timeout
307
+ setTimeout(() => {
308
+ if (agent.status === TaskStatus.RUNNING) {
309
+ agent.fail('Timeout exceeded');
310
+ }
311
+ }, agent.timeout);
312
+ }
313
+
314
+ /**
315
+ * Handle task result from network
316
+ */
317
+ handleResult(agentId, result) {
318
+ const agent = this.agents.get(agentId);
319
+ if (!agent) return;
320
+
321
+ if (result.success) {
322
+ agent.complete(result.data);
323
+ this.stats.completed++;
324
+ this.updateRoutingTable(agent, true, result.latency);
325
+ } else {
326
+ agent.fail(result.error);
327
+ this.stats.failed++;
328
+ this.updateRoutingTable(agent, false, result.latency);
329
+ }
330
+
331
+ agent.ruvSpent = result.ruvSpent || agent.config.baseRuv;
332
+ this.stats.totalRuvSpent += agent.ruvSpent;
333
+ }
334
+
335
+ /**
336
+ * Update routing table with outcome
337
+ */
338
+ updateRoutingTable(agent, success, latency) {
339
+ const key = `${agent.assignedNode}-${agent.type}`;
340
+ const existing = this.routingTable.get(key) || {
341
+ attempts: 0,
342
+ successes: 0,
343
+ totalLatency: 0,
344
+ };
345
+
346
+ existing.attempts++;
347
+ if (success) existing.successes++;
348
+ existing.totalLatency += latency || 0;
349
+ existing.successRate = existing.successes / existing.attempts;
350
+ existing.avgLatency = existing.totalLatency / existing.attempts;
351
+
352
+ this.routingTable.set(key, existing);
353
+ }
354
+
355
+ /**
356
+ * Get agent by ID
357
+ */
358
+ getAgent(agentId) {
359
+ return this.agents.get(agentId);
360
+ }
361
+
362
+ /**
363
+ * List all agents
364
+ */
365
+ listAgents(filter = {}) {
366
+ let agents = Array.from(this.agents.values());
367
+
368
+ if (filter.status) {
369
+ agents = agents.filter(a => a.status === filter.status);
370
+ }
371
+ if (filter.type) {
372
+ agents = agents.filter(a => a.type === filter.type);
373
+ }
374
+
375
+ return agents.map(a => a.getInfo());
376
+ }
377
+
378
+ /**
379
+ * Get spawner stats
380
+ */
381
+ getStats() {
382
+ return {
383
+ ...this.stats,
384
+ activeAgents: Array.from(this.agents.values())
385
+ .filter(a => a.status === TaskStatus.RUNNING).length,
386
+ queuedAgents: this.pendingQueue.length,
387
+ successRate: this.stats.completed /
388
+ (this.stats.completed + this.stats.failed) || 0,
389
+ };
390
+ }
391
+ }
392
+
393
+ /**
394
+ * Worker Pool
395
+ *
396
+ * Manages a pool of distributed workers for parallel task execution.
397
+ */
398
+ export class WorkerPool extends EventEmitter {
399
+ constructor(networkManager, options = {}) {
400
+ super();
401
+ this.id = `pool-${randomBytes(6).toString('hex')}`;
402
+ this.network = networkManager;
403
+ this.size = options.size || 5;
404
+ this.capabilities = options.capabilities || ['compute', 'embed'];
405
+ this.maxTasksPerWorker = options.maxTasksPerWorker || 10;
406
+
407
+ this.workers = new Map();
408
+ this.taskQueue = [];
409
+ this.activeTasks = new Map();
410
+ this.results = new Map();
411
+
412
+ this.status = 'initializing';
413
+ this.stats = {
414
+ tasksCompleted: 0,
415
+ tasksFailed: 0,
416
+ totalProcessingTime: 0,
417
+ };
418
+ }
419
+
420
+ /**
421
+ * Initialize the worker pool
422
+ */
423
+ async initialize() {
424
+ this.status = 'recruiting';
425
+ this.emit('status', 'Recruiting workers...');
426
+
427
+ // Find available workers from network
428
+ const peers = this.network?.getPeerList?.() ||
429
+ Array.from(this.network?.peers?.values() || []);
430
+
431
+ // Filter peers by capabilities
432
+ const eligiblePeers = peers.filter(peer => {
433
+ const peerCaps = peer.capabilities || [];
434
+ return this.capabilities.some(c => peerCaps.includes(c));
435
+ });
436
+
437
+ // Recruit up to pool size
438
+ const recruited = eligiblePeers.slice(0, this.size);
439
+
440
+ for (const peer of recruited) {
441
+ this.workers.set(peer.piKey || peer.id, {
442
+ id: peer.piKey || peer.id,
443
+ peer,
444
+ status: 'idle',
445
+ currentTasks: 0,
446
+ completedTasks: 0,
447
+ lastSeen: Date.now(),
448
+ });
449
+ }
450
+
451
+ // If not enough real workers, create virtual workers for local execution
452
+ while (this.workers.size < this.size) {
453
+ const virtualId = `virtual-${randomBytes(4).toString('hex')}`;
454
+ this.workers.set(virtualId, {
455
+ id: virtualId,
456
+ peer: null,
457
+ status: 'idle',
458
+ currentTasks: 0,
459
+ completedTasks: 0,
460
+ isVirtual: true,
461
+ });
462
+ }
463
+
464
+ this.status = 'ready';
465
+ this.emit('ready', {
466
+ poolId: this.id,
467
+ workers: this.workers.size,
468
+ realWorkers: Array.from(this.workers.values())
469
+ .filter(w => !w.isVirtual).length,
470
+ });
471
+
472
+ return this;
473
+ }
474
+
475
+ /**
476
+ * Execute tasks in parallel across workers
477
+ */
478
+ async execute(options) {
479
+ const {
480
+ task,
481
+ data,
482
+ strategy = 'parallel',
483
+ chunkSize = null,
484
+ } = options;
485
+
486
+ const batchId = `batch-${randomBytes(6).toString('hex')}`;
487
+ const startTime = Date.now();
488
+
489
+ // Split data into chunks for workers
490
+ let chunks;
491
+ if (Array.isArray(data)) {
492
+ const size = chunkSize || Math.ceil(data.length / this.workers.size);
493
+ chunks = [];
494
+ for (let i = 0; i < data.length; i += size) {
495
+ chunks.push(data.slice(i, i + size));
496
+ }
497
+ } else {
498
+ chunks = [data];
499
+ }
500
+
501
+ this.emit('batch-start', { batchId, chunks: chunks.length });
502
+
503
+ // Assign chunks to workers
504
+ const promises = chunks.map((chunk, index) =>
505
+ this.assignTask({
506
+ batchId,
507
+ index,
508
+ task,
509
+ data: chunk,
510
+ })
511
+ );
512
+
513
+ // Wait for all or handle based on strategy
514
+ let results;
515
+ if (strategy === 'parallel') {
516
+ results = await Promise.all(promises);
517
+ } else if (strategy === 'race') {
518
+ results = [await Promise.race(promises)];
519
+ } else {
520
+ // Sequential
521
+ results = [];
522
+ for (const promise of promises) {
523
+ results.push(await promise);
524
+ }
525
+ }
526
+
527
+ const endTime = Date.now();
528
+ this.stats.totalProcessingTime += endTime - startTime;
529
+
530
+ this.emit('batch-complete', {
531
+ batchId,
532
+ duration: endTime - startTime,
533
+ results: results.length,
534
+ });
535
+
536
+ // Flatten results if array
537
+ return Array.isArray(data) ? results.flat() : results[0];
538
+ }
539
+
540
+ /**
541
+ * Assign a single task to an available worker
542
+ */
543
+ async assignTask(taskInfo) {
544
+ const taskId = `task-${randomBytes(6).toString('hex')}`;
545
+
546
+ // Find idle worker
547
+ const worker = this.findIdleWorker();
548
+ if (!worker) {
549
+ // Queue task
550
+ return new Promise((resolve, reject) => {
551
+ this.taskQueue.push({ taskInfo, resolve, reject });
552
+ });
553
+ }
554
+
555
+ worker.status = 'busy';
556
+ worker.currentTasks++;
557
+
558
+ this.activeTasks.set(taskId, {
559
+ ...taskInfo,
560
+ workerId: worker.id,
561
+ startTime: Date.now(),
562
+ });
563
+
564
+ try {
565
+ // Execute on worker
566
+ const result = await this.executeOnWorker(worker, taskInfo);
567
+
568
+ worker.completedTasks++;
569
+ this.stats.tasksCompleted++;
570
+ this.results.set(taskId, result);
571
+
572
+ return result;
573
+ } catch (error) {
574
+ this.stats.tasksFailed++;
575
+ throw error;
576
+ } finally {
577
+ worker.currentTasks--;
578
+ if (worker.currentTasks === 0) {
579
+ worker.status = 'idle';
580
+ }
581
+ this.activeTasks.delete(taskId);
582
+
583
+ // Process queued task if any
584
+ if (this.taskQueue.length > 0) {
585
+ const { taskInfo, resolve, reject } = this.taskQueue.shift();
586
+ this.assignTask(taskInfo).then(resolve).catch(reject);
587
+ }
588
+ }
589
+ }
590
+
591
+ /**
592
+ * Find an idle worker
593
+ */
594
+ findIdleWorker() {
595
+ for (const worker of this.workers.values()) {
596
+ if (worker.status === 'idle' ||
597
+ worker.currentTasks < this.maxTasksPerWorker) {
598
+ return worker;
599
+ }
600
+ }
601
+ return null;
602
+ }
603
+
604
+ /**
605
+ * Execute task on a specific worker
606
+ */
607
+ async executeOnWorker(worker, taskInfo) {
608
+ if (worker.isVirtual) {
609
+ // Local execution for virtual workers
610
+ return this.executeLocally(taskInfo);
611
+ }
612
+
613
+ // Send to remote worker via network
614
+ return new Promise((resolve, reject) => {
615
+ const timeout = setTimeout(() => {
616
+ reject(new Error('Worker timeout'));
617
+ }, 60000);
618
+
619
+ // Send task
620
+ if (this.network?.sendToPeer) {
621
+ this.network.sendToPeer(worker.id, {
622
+ type: 'worker_task',
623
+ poolId: this.id,
624
+ task: taskInfo.task,
625
+ data: taskInfo.data,
626
+ });
627
+ }
628
+
629
+ // Listen for result
630
+ const handler = (msg) => {
631
+ if (msg.poolId === this.id && msg.batchId === taskInfo.batchId) {
632
+ clearTimeout(timeout);
633
+ this.network?.off?.('worker_result', handler);
634
+ resolve(msg.result);
635
+ }
636
+ };
637
+
638
+ this.network?.on?.('worker_result', handler);
639
+
640
+ // Fallback to local if no response
641
+ setTimeout(() => {
642
+ clearTimeout(timeout);
643
+ this.executeLocally(taskInfo).then(resolve).catch(reject);
644
+ }, 5000);
645
+ });
646
+ }
647
+
648
+ /**
649
+ * Execute task locally (for virtual workers or fallback)
650
+ */
651
+ async executeLocally(taskInfo) {
652
+ const { task, data } = taskInfo;
653
+
654
+ // Simple local execution based on task type
655
+ switch (task) {
656
+ case 'embed':
657
+ // Simulate embedding
658
+ return Array.isArray(data)
659
+ ? data.map(() => new Array(384).fill(0).map(() => Math.random()))
660
+ : new Array(384).fill(0).map(() => Math.random());
661
+
662
+ case 'process':
663
+ return Array.isArray(data)
664
+ ? data.map(item => ({ processed: true, item }))
665
+ : { processed: true, data };
666
+
667
+ case 'analyze':
668
+ return {
669
+ analyzed: true,
670
+ itemCount: Array.isArray(data) ? data.length : 1,
671
+ timestamp: Date.now(),
672
+ };
673
+
674
+ default:
675
+ return { task, data, executed: true };
676
+ }
677
+ }
678
+
679
+ /**
680
+ * Get pool status
681
+ */
682
+ getStatus() {
683
+ const workers = Array.from(this.workers.values());
684
+ return {
685
+ poolId: this.id,
686
+ status: this.status,
687
+ totalWorkers: workers.length,
688
+ idleWorkers: workers.filter(w => w.status === 'idle').length,
689
+ busyWorkers: workers.filter(w => w.status === 'busy').length,
690
+ virtualWorkers: workers.filter(w => w.isVirtual).length,
691
+ queuedTasks: this.taskQueue.length,
692
+ activeTasks: this.activeTasks.size,
693
+ stats: this.stats,
694
+ };
695
+ }
696
+
697
+ /**
698
+ * Shutdown the pool
699
+ */
700
+ async shutdown() {
701
+ this.status = 'shutting_down';
702
+
703
+ // Wait for active tasks
704
+ while (this.activeTasks.size > 0) {
705
+ await new Promise(r => setTimeout(r, 100));
706
+ }
707
+
708
+ // Clear workers
709
+ this.workers.clear();
710
+ this.status = 'shutdown';
711
+ this.emit('shutdown');
712
+ }
713
+ }
714
+
715
+ /**
716
+ * Task Orchestrator
717
+ *
718
+ * Orchestrates multi-agent workflows and complex task pipelines.
719
+ */
720
+ export class TaskOrchestrator extends EventEmitter {
721
+ constructor(agentSpawner, workerPool, options = {}) {
722
+ super();
723
+ this.spawner = agentSpawner;
724
+ this.pool = workerPool;
725
+ this.workflows = new Map();
726
+ this.maxConcurrentWorkflows = options.maxConcurrentWorkflows || 5;
727
+ }
728
+
729
+ /**
730
+ * Create a workflow
731
+ */
732
+ createWorkflow(name, steps) {
733
+ const workflow = {
734
+ id: `wf-${randomBytes(6).toString('hex')}`,
735
+ name,
736
+ steps,
737
+ status: 'created',
738
+ currentStep: 0,
739
+ results: [],
740
+ startTime: null,
741
+ endTime: null,
742
+ };
743
+
744
+ this.workflows.set(workflow.id, workflow);
745
+ return workflow;
746
+ }
747
+
748
+ /**
749
+ * Execute a workflow
750
+ */
751
+ async executeWorkflow(workflowId, input = {}) {
752
+ const workflow = this.workflows.get(workflowId);
753
+ if (!workflow) throw new Error('Workflow not found');
754
+
755
+ workflow.status = 'running';
756
+ workflow.startTime = Date.now();
757
+ workflow.input = input;
758
+
759
+ this.emit('workflow-start', { workflowId, name: workflow.name });
760
+
761
+ try {
762
+ let context = { ...input };
763
+
764
+ for (let i = 0; i < workflow.steps.length; i++) {
765
+ workflow.currentStep = i;
766
+ const step = workflow.steps[i];
767
+
768
+ this.emit('step-start', {
769
+ workflowId,
770
+ step: i,
771
+ type: step.type,
772
+ name: step.name,
773
+ });
774
+
775
+ const result = await this.executeStep(step, context);
776
+ workflow.results.push(result);
777
+
778
+ // Pass result to next step
779
+ context = { ...context, [step.name || `step${i}`]: result };
780
+
781
+ this.emit('step-complete', {
782
+ workflowId,
783
+ step: i,
784
+ result,
785
+ });
786
+ }
787
+
788
+ workflow.status = 'completed';
789
+ workflow.endTime = Date.now();
790
+
791
+ this.emit('workflow-complete', {
792
+ workflowId,
793
+ duration: workflow.endTime - workflow.startTime,
794
+ results: workflow.results,
795
+ });
796
+
797
+ return {
798
+ success: true,
799
+ results: workflow.results,
800
+ context,
801
+ };
802
+
803
+ } catch (error) {
804
+ workflow.status = 'failed';
805
+ workflow.endTime = Date.now();
806
+ workflow.error = error.message;
807
+
808
+ this.emit('workflow-failed', { workflowId, error: error.message });
809
+
810
+ return {
811
+ success: false,
812
+ error: error.message,
813
+ failedStep: workflow.currentStep,
814
+ };
815
+ }
816
+ }
817
+
818
+ /**
819
+ * Execute a single workflow step
820
+ */
821
+ async executeStep(step, context) {
822
+ switch (step.type) {
823
+ case 'agent':
824
+ return this.executeAgentStep(step, context);
825
+
826
+ case 'parallel':
827
+ return this.executeParallelStep(step, context);
828
+
829
+ case 'pool':
830
+ return this.executePoolStep(step, context);
831
+
832
+ case 'condition':
833
+ return this.executeConditionStep(step, context);
834
+
835
+ case 'transform':
836
+ return this.executeTransformStep(step, context);
837
+
838
+ default:
839
+ throw new Error(`Unknown step type: ${step.type}`);
840
+ }
841
+ }
842
+
843
+ /**
844
+ * Execute an agent step
845
+ */
846
+ async executeAgentStep(step, context) {
847
+ const task = typeof step.task === 'function'
848
+ ? step.task(context)
849
+ : step.task;
850
+
851
+ const agent = await this.spawner.spawn({
852
+ type: step.agentType || 'researcher',
853
+ task,
854
+ maxRuv: step.maxRuv,
855
+ priority: step.priority,
856
+ });
857
+
858
+ return new Promise((resolve, reject) => {
859
+ agent.on('complete', resolve);
860
+ agent.on('error', reject);
861
+
862
+ // Simulate completion for now
863
+ setTimeout(() => {
864
+ agent.complete({
865
+ task,
866
+ result: `Completed: ${task}`,
867
+ context,
868
+ });
869
+ }, 1000);
870
+ });
871
+ }
872
+
873
+ /**
874
+ * Execute parallel agents
875
+ */
876
+ async executeParallelStep(step, context) {
877
+ const promises = step.agents.map(agentConfig =>
878
+ this.executeAgentStep(agentConfig, context)
879
+ );
880
+
881
+ return Promise.all(promises);
882
+ }
883
+
884
+ /**
885
+ * Execute worker pool step
886
+ */
887
+ async executePoolStep(step, context) {
888
+ const data = typeof step.data === 'function'
889
+ ? step.data(context)
890
+ : step.data || context.data;
891
+
892
+ return this.pool.execute({
893
+ task: step.task,
894
+ data,
895
+ strategy: step.strategy || 'parallel',
896
+ });
897
+ }
898
+
899
+ /**
900
+ * Execute conditional step
901
+ */
902
+ async executeConditionStep(step, context) {
903
+ const condition = typeof step.condition === 'function'
904
+ ? step.condition(context)
905
+ : step.condition;
906
+
907
+ if (condition) {
908
+ return this.executeStep(step.then, context);
909
+ } else if (step.else) {
910
+ return this.executeStep(step.else, context);
911
+ }
912
+ return null;
913
+ }
914
+
915
+ /**
916
+ * Execute transform step
917
+ */
918
+ async executeTransformStep(step, context) {
919
+ return step.transform(context);
920
+ }
921
+
922
+ /**
923
+ * Get workflow status
924
+ */
925
+ getWorkflowStatus(workflowId) {
926
+ const workflow = this.workflows.get(workflowId);
927
+ if (!workflow) return null;
928
+
929
+ return {
930
+ id: workflow.id,
931
+ name: workflow.name,
932
+ status: workflow.status,
933
+ currentStep: workflow.currentStep,
934
+ totalSteps: workflow.steps.length,
935
+ progress: (workflow.currentStep / workflow.steps.length) * 100,
936
+ startTime: workflow.startTime,
937
+ endTime: workflow.endTime,
938
+ duration: workflow.endTime && workflow.startTime
939
+ ? workflow.endTime - workflow.startTime
940
+ : null,
941
+ };
942
+ }
943
+
944
+ /**
945
+ * List all workflows
946
+ */
947
+ listWorkflows() {
948
+ return Array.from(this.workflows.values()).map(w => ({
949
+ id: w.id,
950
+ name: w.name,
951
+ status: w.status,
952
+ steps: w.steps.length,
953
+ }));
954
+ }
955
+ }
956
+
957
+ // Export default instances
958
+ export default {
959
+ AGENT_TYPES,
960
+ TaskStatus,
961
+ DistributedAgent,
962
+ AgentSpawner,
963
+ WorkerPool,
964
+ TaskOrchestrator,
965
+ };
package/package.json CHANGED
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "name": "@ruvector/edge-net",
3
- "version": "0.1.2",
3
+ "version": "0.1.3",
4
4
  "type": "module",
5
- "description": "Distributed compute intelligence network - contribute browser compute, earn credits. Features Time Crystal coordination, Neural DAG attention, and P2P swarm intelligence.",
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.",
6
6
  "main": "ruvector_edge_net.js",
7
7
  "module": "ruvector_edge_net.js",
8
8
  "types": "ruvector_edge_net.d.ts",
@@ -29,7 +29,13 @@
29
29
  "time-crystal",
30
30
  "dag-attention",
31
31
  "swarm-intelligence",
32
- "neural-network"
32
+ "neural-network",
33
+ "ai-agents",
34
+ "distributed-agents",
35
+ "worker-pools",
36
+ "multi-agent",
37
+ "webrtc",
38
+ "task-orchestration"
33
39
  ],
34
40
  "author": "RuVector Team <team@ruvector.dev>",
35
41
  "license": "MIT",
@@ -54,6 +60,7 @@
54
60
  "network.js",
55
61
  "networks.js",
56
62
  "webrtc.js",
63
+ "agents.js",
57
64
  "README.md",
58
65
  "LICENSE"
59
66
  ],
@@ -64,6 +71,15 @@
64
71
  },
65
72
  "./wasm": {
66
73
  "import": "./ruvector_edge_net_bg.wasm"
74
+ },
75
+ "./agents": {
76
+ "import": "./agents.js"
77
+ },
78
+ "./network": {
79
+ "import": "./network.js"
80
+ },
81
+ "./webrtc": {
82
+ "import": "./webrtc.js"
67
83
  }
68
84
  },
69
85
  "sideEffects": [