@agentic-robotics/mcp 0.2.0 → 0.2.2

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.
@@ -1,475 +0,0 @@
1
- /**
2
- * Agentic Flow Orchestration Integration - SECURE VERSION
3
- *
4
- * Integrates agentic-flow's 66 agents and 213 MCP tools for
5
- * multi-robot coordination and complex task execution
6
- *
7
- * SECURITY: All command execution uses secure spawn() with argument arrays
8
- */
9
-
10
- import { spawn } from 'child_process';
11
-
12
- export interface AgentTask {
13
- id: string;
14
- type: string;
15
- priority: 'low' | 'medium' | 'high' | 'critical';
16
- params: Record<string, any>;
17
- timeout?: number;
18
- retries?: number;
19
- }
20
-
21
- export interface AgentResult {
22
- taskId: string;
23
- success: boolean;
24
- result: any;
25
- executionTime: number;
26
- agentsUsed: string[];
27
- toolsUsed: string[];
28
- reasoning?: string;
29
- }
30
-
31
- export interface SwarmConfig {
32
- numAgents?: number;
33
- strategy?: 'parallel' | 'sequential' | 'adaptive' | 'swarm';
34
- mcpTools?: string[];
35
- reasoningEnabled?: boolean;
36
- learningEnabled?: boolean;
37
- }
38
-
39
- export interface OrchestrationMetrics {
40
- totalTasks: number;
41
- successfulTasks: number;
42
- failedTasks: number;
43
- avgExecutionTime: number;
44
- agentUtilization: Record<string, number>;
45
- toolUsage: Record<string, number>;
46
- }
47
-
48
- /**
49
- * Secure helper to spawn commands with proper argument handling
50
- */
51
- function spawnAsync(
52
- command: string,
53
- args: string[],
54
- options: { timeout?: number } = {}
55
- ): Promise<{ stdout: string; stderr: string; code: number }> {
56
- return new Promise((resolve, reject) => {
57
- const child = spawn(command, args, {
58
- shell: false, // Critical: disable shell interpretation
59
- timeout: options.timeout,
60
- });
61
-
62
- let stdout = '';
63
- let stderr = '';
64
-
65
- child.stdout?.on('data', (data) => {
66
- stdout += data.toString();
67
- });
68
-
69
- child.stderr?.on('data', (data) => {
70
- stderr += data.toString();
71
- });
72
-
73
- child.on('close', (code) => {
74
- resolve({ stdout, stderr, code: code || 0 });
75
- });
76
-
77
- child.on('error', (error) => {
78
- reject(error);
79
- });
80
- });
81
- }
82
-
83
- /**
84
- * Validate and sanitize task parameters
85
- */
86
- function validateTaskParams(params: Record<string, any>): void {
87
- // Check for command injection attempts
88
- const paramStr = JSON.stringify(params);
89
- if (paramStr.includes(';') || paramStr.includes('|') || paramStr.includes('&')) {
90
- throw new Error('Invalid characters in task parameters');
91
- }
92
- }
93
-
94
- export class FlowOrchestrator {
95
- private config: SwarmConfig;
96
- private metrics: OrchestrationMetrics;
97
- private initialized: boolean = false;
98
-
99
- constructor(config: SwarmConfig = {}) {
100
- // Validate config
101
- if (config.numAgents && (config.numAgents < 1 || config.numAgents > 200)) {
102
- throw new Error('numAgents must be between 1 and 200');
103
- }
104
-
105
- this.config = {
106
- numAgents: config.numAgents || 66,
107
- strategy: config.strategy || 'adaptive',
108
- mcpTools: config.mcpTools || [],
109
- reasoningEnabled: config.reasoningEnabled ?? true,
110
- learningEnabled: config.learningEnabled ?? true,
111
- };
112
-
113
- this.metrics = {
114
- totalTasks: 0,
115
- successfulTasks: 0,
116
- failedTasks: 0,
117
- avgExecutionTime: 0,
118
- agentUtilization: {},
119
- toolUsage: {},
120
- };
121
- }
122
-
123
- async initialize(): Promise<void> {
124
- if (this.initialized) return;
125
-
126
- const startTime = Date.now();
127
-
128
- try {
129
- // Secure initialization with spawn
130
- const args = ['agentic-flow', 'init', '--agents', this.config.numAgents!.toString(), '--strategy', this.config.strategy!];
131
-
132
- if (this.config.reasoningEnabled) args.push('--enable-reasoning');
133
- if (this.config.learningEnabled) args.push('--enable-learning');
134
-
135
- await spawnAsync('npx', args);
136
-
137
- const initTime = Date.now() - startTime;
138
- console.error(`🌊 Agentic Flow initialized (${this.config.numAgents} agents, ${initTime}ms)`);
139
- this.initialized = true;
140
- } catch (error: any) {
141
- console.error('⚠️ Flow initialization warning:', error.message);
142
- this.initialized = true;
143
- }
144
- }
145
-
146
- async executeTask(task: AgentTask): Promise<AgentResult> {
147
- if (!this.initialized) {
148
- throw new Error('FlowOrchestrator not initialized. Call initialize() first.');
149
- }
150
-
151
- // Validate input
152
- validateTaskParams(task.params);
153
-
154
- const startTime = Date.now();
155
- this.metrics.totalTasks++;
156
-
157
- try {
158
- const args = [
159
- 'agentic-flow',
160
- 'execute',
161
- '--task-type',
162
- task.type,
163
- '--priority',
164
- task.priority,
165
- '--params',
166
- JSON.stringify(task.params),
167
- '--format',
168
- 'json',
169
- ];
170
-
171
- if (task.timeout) args.push('--timeout', task.timeout.toString());
172
- if (task.retries) args.push('--retries', task.retries.toString());
173
- if (this.config.reasoningEnabled) args.push('--enable-reasoning');
174
-
175
- const { stdout, code } = await spawnAsync('npx', args, {
176
- timeout: task.timeout || 30000,
177
- });
178
-
179
- if (code !== 0) {
180
- throw new Error(`Agentic-flow execution failed with code ${code}`);
181
- }
182
-
183
- const lines = stdout.trim().split('\n');
184
- const jsonLine = lines.find((line) => line.startsWith('{'));
185
-
186
- if (jsonLine) {
187
- const data = JSON.parse(jsonLine);
188
-
189
- const executionTime = Date.now() - startTime;
190
- this.metrics.successfulTasks++;
191
- this.updateMetrics(data, executionTime);
192
-
193
- console.error(`✅ Task ${task.id} completed in ${executionTime}ms`);
194
-
195
- return {
196
- taskId: task.id,
197
- success: true,
198
- result: data.result,
199
- executionTime,
200
- agentsUsed: data.agents_used || [],
201
- toolsUsed: data.tools_used || [],
202
- reasoning: data.reasoning,
203
- };
204
- }
205
-
206
- throw new Error('No valid JSON response from agentic-flow');
207
- } catch (error: any) {
208
- this.metrics.failedTasks++;
209
- const executionTime = Date.now() - startTime;
210
-
211
- console.error(`❌ Task ${task.id} failed: ${error.message}`);
212
-
213
- return {
214
- taskId: task.id,
215
- success: false,
216
- result: { error: error.message },
217
- executionTime,
218
- agentsUsed: [],
219
- toolsUsed: [],
220
- };
221
- }
222
- }
223
-
224
- async executeSwarm(tasks: AgentTask[]): Promise<AgentResult[]> {
225
- if (!this.initialized) {
226
- throw new Error('FlowOrchestrator not initialized. Call initialize() first.');
227
- }
228
-
229
- const startTime = Date.now();
230
- console.error(`🐝 Executing swarm with ${tasks.length} tasks`);
231
-
232
- try {
233
- // Validate all tasks
234
- tasks.forEach((task) => validateTaskParams(task.params));
235
-
236
- const args = [
237
- 'agentic-flow',
238
- 'swarm',
239
- '--tasks',
240
- JSON.stringify(tasks),
241
- '--strategy',
242
- this.config.strategy!,
243
- '--num-agents',
244
- this.config.numAgents!.toString(),
245
- '--format',
246
- 'json',
247
- ];
248
-
249
- if (this.config.reasoningEnabled) args.push('--enable-reasoning');
250
-
251
- const { stdout, code } = await spawnAsync('npx', args, { timeout: 60000 });
252
-
253
- if (code !== 0) {
254
- throw new Error(`Swarm execution failed with code ${code}`);
255
- }
256
-
257
- const lines = stdout.trim().split('\n');
258
- const jsonLine = lines.find((line) => line.startsWith('[') || line.startsWith('{'));
259
-
260
- if (jsonLine) {
261
- const data = JSON.parse(jsonLine);
262
- const results = Array.isArray(data) ? data : [data];
263
-
264
- const swarmTime = Date.now() - startTime;
265
- console.error(`🎯 Swarm completed ${results.length} tasks in ${swarmTime}ms`);
266
-
267
- return results.map((r, i) => ({
268
- taskId: tasks[i].id,
269
- success: r.success ?? true,
270
- result: r.result,
271
- executionTime: r.execution_time || swarmTime / results.length,
272
- agentsUsed: r.agents_used || [],
273
- toolsUsed: r.tools_used || [],
274
- reasoning: r.reasoning,
275
- }));
276
- }
277
-
278
- throw new Error('No valid JSON response from swarm execution');
279
- } catch (error: any) {
280
- console.error(`❌ Swarm execution failed: ${error.message}`);
281
-
282
- return tasks.map((task) => ({
283
- taskId: task.id,
284
- success: false,
285
- result: { error: error.message },
286
- executionTime: 0,
287
- agentsUsed: [],
288
- toolsUsed: [],
289
- }));
290
- }
291
- }
292
-
293
- async coordinateRobots(
294
- robots: string[],
295
- mission: {
296
- type: string;
297
- objectives: string[];
298
- constraints?: Record<string, any>;
299
- }
300
- ): Promise<{
301
- success: boolean;
302
- assignments: Record<string, string[]>;
303
- executionPlan: any;
304
- estimatedTime: number;
305
- }> {
306
- if (!this.initialized) {
307
- throw new Error('FlowOrchestrator not initialized. Call initialize() first.');
308
- }
309
-
310
- const startTime = Date.now();
311
-
312
- try {
313
- const args = [
314
- 'agentic-flow',
315
- 'coordinate',
316
- '--robots',
317
- JSON.stringify(robots),
318
- '--mission-type',
319
- mission.type,
320
- '--objectives',
321
- JSON.stringify(mission.objectives),
322
- '--format',
323
- 'json',
324
- ];
325
-
326
- if (mission.constraints) {
327
- args.push('--constraints', JSON.stringify(mission.constraints));
328
- }
329
-
330
- const { stdout, code } = await spawnAsync('npx', args, { timeout: 30000 });
331
-
332
- if (code !== 0) {
333
- throw new Error(`Coordination failed with code ${code}`);
334
- }
335
-
336
- const lines = stdout.trim().split('\n');
337
- const jsonLine = lines.find((line) => line.startsWith('{'));
338
-
339
- if (jsonLine) {
340
- const data = JSON.parse(jsonLine);
341
-
342
- const coordTime = Date.now() - startTime;
343
- console.error(`🤝 Robot coordination completed in ${coordTime}ms`);
344
-
345
- return {
346
- success: true,
347
- assignments: data.assignments || {},
348
- executionPlan: data.execution_plan || {},
349
- estimatedTime: data.estimated_time || 0,
350
- };
351
- }
352
-
353
- throw new Error('No valid JSON response from coordination');
354
- } catch (error: any) {
355
- throw new Error(`Robot coordination failed: ${error.message}`);
356
- }
357
- }
358
-
359
- async reasonAboutTask(
360
- context: string,
361
- options: {
362
- useMemory?: boolean;
363
- synthesizeStrategy?: boolean;
364
- explainReasoning?: boolean;
365
- } = {}
366
- ): Promise<{
367
- decision: string;
368
- reasoning: string;
369
- confidence: number;
370
- alternatives: string[];
371
- }> {
372
- if (!this.initialized) {
373
- throw new Error('FlowOrchestrator not initialized. Call initialize() first.');
374
- }
375
-
376
- try {
377
- const args = ['agentic-flow', 'reason', '--context', context, '--format', 'json'];
378
-
379
- if (options.useMemory) args.push('--use-memory');
380
- if (options.synthesizeStrategy) args.push('--synthesize-strategy');
381
- if (options.explainReasoning) args.push('--explain-reasoning');
382
-
383
- const { stdout, code } = await spawnAsync('npx', args, { timeout: 15000 });
384
-
385
- if (code !== 0) {
386
- throw new Error(`Reasoning failed with code ${code}`);
387
- }
388
-
389
- const lines = stdout.trim().split('\n');
390
- const jsonLine = lines.find((line) => line.startsWith('{'));
391
-
392
- if (jsonLine) {
393
- const data = JSON.parse(jsonLine);
394
-
395
- return {
396
- decision: data.decision || '',
397
- reasoning: data.reasoning || '',
398
- confidence: data.confidence || 0,
399
- alternatives: data.alternatives || [],
400
- };
401
- }
402
-
403
- throw new Error('No valid JSON response from reasoning');
404
- } catch (error: any) {
405
- throw new Error(`Reasoning failed: ${error.message}`);
406
- }
407
- }
408
-
409
- async getAvailableTools(): Promise<string[]> {
410
- try {
411
- const { stdout, code } = await spawnAsync('npx', [
412
- 'agentic-flow',
413
- 'list-tools',
414
- '--format',
415
- 'json',
416
- ]);
417
-
418
- if (code !== 0) {
419
- throw new Error('Failed to list tools');
420
- }
421
-
422
- const lines = stdout.trim().split('\n');
423
- const jsonLine = lines.find((line) => line.startsWith('['));
424
-
425
- if (jsonLine) {
426
- const tools = JSON.parse(jsonLine);
427
- console.error(`🔧 Found ${tools.length}/213 MCP tools available`);
428
- return tools;
429
- }
430
-
431
- return [];
432
- } catch (error: any) {
433
- throw new Error(`Failed to list tools: ${error.message}`);
434
- }
435
- }
436
-
437
- getMetrics(): OrchestrationMetrics {
438
- return {
439
- ...this.metrics,
440
- avgExecutionTime:
441
- this.metrics.totalTasks > 0 ? this.metrics.avgExecutionTime / this.metrics.totalTasks : 0,
442
- };
443
- }
444
-
445
- private updateMetrics(data: any, executionTime: number): void {
446
- this.metrics.avgExecutionTime += executionTime;
447
-
448
- if (data.agents_used) {
449
- for (const agent of data.agents_used) {
450
- this.metrics.agentUtilization[agent] = (this.metrics.agentUtilization[agent] || 0) + 1;
451
- }
452
- }
453
-
454
- if (data.tools_used) {
455
- for (const tool of data.tools_used) {
456
- this.metrics.toolUsage[tool] = (this.metrics.toolUsage[tool] || 0) + 1;
457
- }
458
- }
459
- }
460
-
461
- resetMetrics(): void {
462
- this.metrics = {
463
- totalTasks: 0,
464
- successfulTasks: 0,
465
- failedTasks: 0,
466
- avgExecutionTime: 0,
467
- agentUtilization: {},
468
- toolUsage: {},
469
- };
470
- }
471
-
472
- async close(): Promise<void> {
473
- this.initialized = false;
474
- }
475
- }