@gotza02/mathinking 2.9.4 → 2.9.5

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 (61) hide show
  1. package/dist/final-demo.js +0 -3
  2. package/dist/final-demo.js.map +1 -1
  3. package/dist/index.js +17 -16
  4. package/dist/index.js.map +1 -1
  5. package/dist/schemas/brain.schema.d.ts +70 -0
  6. package/dist/schemas/brain.schema.d.ts.map +1 -0
  7. package/dist/schemas/brain.schema.js +70 -0
  8. package/dist/schemas/brain.schema.js.map +1 -0
  9. package/dist/security.test.d.ts +2 -0
  10. package/dist/security.test.d.ts.map +1 -0
  11. package/dist/security.test.js +81 -0
  12. package/dist/security.test.js.map +1 -0
  13. package/dist/sse-server.js +39 -8
  14. package/dist/sse-server.js.map +1 -1
  15. package/dist/test-all.js +0 -20
  16. package/dist/test-all.js.map +1 -1
  17. package/dist/test-extended.js +0 -9
  18. package/dist/test-extended.js.map +1 -1
  19. package/dist/test-max-intelligence.js +0 -7
  20. package/dist/test-max-intelligence.js.map +1 -1
  21. package/dist/test-memory.js +0 -2
  22. package/dist/test-memory.js.map +1 -1
  23. package/dist/test-reflective.js +0 -6
  24. package/dist/test-reflective.js.map +1 -1
  25. package/dist/test-resilience.js +0 -8
  26. package/dist/test-resilience.js.map +1 -1
  27. package/dist/tools/orchestrator.d.ts +2 -47
  28. package/dist/tools/orchestrator.d.ts.map +1 -1
  29. package/dist/tools/orchestrator.js +139 -172
  30. package/dist/tools/orchestrator.js.map +1 -1
  31. package/dist/tools/sequential-thinking.d.ts +7 -6
  32. package/dist/tools/sequential-thinking.d.ts.map +1 -1
  33. package/dist/tools/sequential-thinking.js +210 -90
  34. package/dist/tools/sequential-thinking.js.map +1 -1
  35. package/dist/types/index.d.ts +2 -2
  36. package/dist/types/index.d.ts.map +1 -1
  37. package/dist/utils/dag.d.ts +0 -20
  38. package/dist/utils/dag.d.ts.map +1 -1
  39. package/dist/utils/dag.js +8 -48
  40. package/dist/utils/dag.js.map +1 -1
  41. package/dist/utils/memory.d.ts +5 -0
  42. package/dist/utils/memory.d.ts.map +1 -1
  43. package/dist/utils/memory.js +66 -60
  44. package/dist/utils/memory.js.map +1 -1
  45. package/dist/utils/mutex.d.ts +6 -0
  46. package/dist/utils/mutex.d.ts.map +1 -0
  47. package/dist/utils/mutex.js +22 -0
  48. package/dist/utils/mutex.js.map +1 -0
  49. package/dist/utils/resilience.d.ts +0 -4
  50. package/dist/utils/resilience.d.ts.map +1 -1
  51. package/dist/utils/resilience.js +1 -15
  52. package/dist/utils/resilience.js.map +1 -1
  53. package/dist/utils/tool-cache.d.ts +4 -12
  54. package/dist/utils/tool-cache.d.ts.map +1 -1
  55. package/dist/utils/tool-cache.js +12 -46
  56. package/dist/utils/tool-cache.js.map +1 -1
  57. package/dist/utils/vector-memory.d.ts +1 -22
  58. package/dist/utils/vector-memory.d.ts.map +1 -1
  59. package/dist/utils/vector-memory.js +31 -77
  60. package/dist/utils/vector-memory.js.map +1 -1
  61. package/package.json +22 -20
@@ -1,39 +1,45 @@
1
- import * as vm from 'vm';
1
+ import { getQuickJS } from 'quickjs-emscripten';
2
2
  import { resilienceManager } from '../utils/resilience.js';
3
3
  import { toolCache } from '../utils/tool-cache.js';
4
4
  import { topologicalSortWithLayers, validateDAG, visualizeDAG, getCriticalPath, getMaxParallelism } from '../utils/dag.js';
5
- /**
6
- * Orchestrator Manager (The Body)
7
- *
8
- * Provides DAG-based task execution with:
9
- * - Topological sorting for dependency resolution
10
- * - Parallel execution of independent tasks
11
- * - Tool orchestration via registry
12
- * - Graceful error handling
13
- * - Result aggregation
14
- */
15
5
  export class OrchestratorManager {
16
6
  toolRegistry = {};
17
7
  executionHistory = new Map();
18
8
  lastActionTimestamp = 0;
19
9
  MIN_DELAY_MS = 1000; // 1s delay for orchestrator actions
10
+ quickJS;
20
11
  constructor() {
21
12
  this.registerBuiltInTools();
22
13
  }
14
+ async safeEval(code) {
15
+ if (!this.quickJS) {
16
+ this.quickJS = await getQuickJS();
17
+ }
18
+ const vm = this.quickJS.newContext();
19
+ try {
20
+ const result = vm.evalCode(code);
21
+ if (result.error) {
22
+ const error = vm.dump(result.error);
23
+ result.error.dispose();
24
+ throw new Error(String(error));
25
+ }
26
+ const value = vm.dump(result.value);
27
+ result.value.dispose();
28
+ return value;
29
+ }
30
+ finally {
31
+ vm.dispose();
32
+ }
33
+ }
23
34
  sleep(ms) {
24
35
  return new Promise((resolve) => setTimeout(resolve, ms));
25
36
  }
26
- /**
27
- * Register built-in tools for testing and common operations
28
- */
29
37
  registerBuiltInTools() {
30
- // Echo tool - returns input as output (useful for testing)
31
38
  this.registerTool({
32
39
  name: 'echo',
33
40
  description: 'Returns the input as output',
34
41
  execute: async (input) => input
35
42
  });
36
- // Delay tool - waits for specified milliseconds
37
43
  this.registerTool({
38
44
  name: 'delay',
39
45
  description: 'Waits for specified milliseconds',
@@ -43,7 +49,6 @@ export class OrchestratorManager {
43
49
  return { delayed: ms, timestamp: new Date().toISOString() };
44
50
  }
45
51
  });
46
- // Transform tool - applies simple transformations
47
52
  this.registerTool({
48
53
  name: 'transform',
49
54
  description: 'Applies transformations to data',
@@ -66,7 +71,6 @@ export class OrchestratorManager {
66
71
  }
67
72
  }
68
73
  });
69
- // Aggregate tool - combines multiple inputs
70
74
  this.registerTool({
71
75
  name: 'aggregate',
72
76
  description: 'Aggregates multiple values',
@@ -90,7 +94,6 @@ export class OrchestratorManager {
90
94
  }
91
95
  }
92
96
  });
93
- // HTTP fetch tool - Real implementation using native fetch
94
97
  this.registerTool({
95
98
  name: 'fetch',
96
99
  description: 'Fetches data from a URL',
@@ -99,8 +102,15 @@ export class OrchestratorManager {
99
102
  const method = input.method || 'GET';
100
103
  const body = input.body ? JSON.stringify(input.body) : undefined;
101
104
  const headers = input.headers || {};
105
+ const controller = new AbortController();
106
+ const timeoutId = setTimeout(() => controller.abort(), 30000); // 30s timeout
102
107
  try {
103
- const response = await fetch(url, { method, body, headers });
108
+ const response = await fetch(url, {
109
+ method,
110
+ body,
111
+ headers,
112
+ signal: controller.signal
113
+ });
104
114
  const contentType = response.headers.get('content-type');
105
115
  let data;
106
116
  if (contentType && contentType.includes('application/json')) {
@@ -120,9 +130,11 @@ export class OrchestratorManager {
120
130
  catch (error) {
121
131
  throw new Error(`Fetch failed: ${error instanceof Error ? error.message : String(error)}`);
122
132
  }
133
+ finally {
134
+ clearTimeout(timeoutId);
135
+ }
123
136
  }
124
137
  });
125
- // File System: Read file
126
138
  this.registerTool({
127
139
  name: 'read_file',
128
140
  description: 'Reads content from a file',
@@ -139,7 +151,6 @@ export class OrchestratorManager {
139
151
  }
140
152
  }
141
153
  });
142
- // File System: Write file
143
154
  this.registerTool({
144
155
  name: 'write_file',
145
156
  description: 'Writes content to a file',
@@ -156,7 +167,6 @@ export class OrchestratorManager {
156
167
  }
157
168
  }
158
169
  });
159
- // File System: List directory
160
170
  this.registerTool({
161
171
  name: 'list_directory',
162
172
  description: 'Lists files in a directory',
@@ -172,12 +182,48 @@ export class OrchestratorManager {
172
182
  }
173
183
  }
174
184
  });
175
- // Shell execute
176
185
  this.registerTool({
177
186
  name: 'shell_execute',
178
187
  description: 'Executes a shell command',
179
188
  execute: async (input) => {
180
189
  const command = input.command;
190
+ const path = await import('path');
191
+ const ALLOWED_COMMANDS = [
192
+ 'ls',
193
+ 'echo',
194
+ 'cat',
195
+ 'mkdir',
196
+ 'rm',
197
+ 'touch',
198
+ 'git',
199
+ 'grep',
200
+ 'pwd',
201
+ 'find',
202
+ 'whoami'
203
+ ];
204
+ const tokenRegex = /[^\s"]+|"([^"]*)"/gi;
205
+ const tokens = [];
206
+ let match;
207
+ while ((match = tokenRegex.exec(command)) !== null) {
208
+ tokens.push(match[1] ? match[1] : match[0]); // match[1] is the content inside quotes
209
+ }
210
+ let binaryToken = tokens[0];
211
+ for (const token of tokens) {
212
+ if (!token.includes('=')) {
213
+ binaryToken = token;
214
+ break;
215
+ }
216
+ }
217
+ const binary = path.basename(binaryToken);
218
+ if (!ALLOWED_COMMANDS.includes(binary)) {
219
+ throw new Error(`Command "${binary}" is not allowed. Allowed: ${ALLOWED_COMMANDS.join(', ')}`);
220
+ }
221
+ if (/[\n\r;&|`>]|\$\(/.test(command)) {
222
+ throw new Error('Command contains disallowed characters (newlines, operators, redirection) to prevent injection.');
223
+ }
224
+ if (binary === 'git' && (command.includes('-c') || command.includes('--config'))) {
225
+ throw new Error('Git configuration flags are not allowed for security reasons.');
226
+ }
181
227
  const { exec } = await import('child_process');
182
228
  const { promisify } = await import('util');
183
229
  const execAsync = promisify(exec);
@@ -190,7 +236,6 @@ export class OrchestratorManager {
190
236
  }
191
237
  }
192
238
  });
193
- // Web Search tool - Enhanced with Google, Exa, and Brave API support
194
239
  this.registerTool({
195
240
  name: 'web_search',
196
241
  description: 'Searches the web for information (Prioritizes Tools like Brave/Exa, then MPC/Google, then Fallback)',
@@ -200,7 +245,6 @@ export class OrchestratorManager {
200
245
  const freshness = input.freshness || 'year'; // day, week, month, year
201
246
  const getFreshnessParams = (provider) => {
202
247
  if (provider === 'google') {
203
- // d[number], w[number], m[number], y[number]
204
248
  if (freshness === 'day')
205
249
  return 'd1';
206
250
  if (freshness === 'week')
@@ -210,7 +254,6 @@ export class OrchestratorManager {
210
254
  return 'y1'; // Default to past year for "latest" relevance
211
255
  }
212
256
  if (provider === 'brave') {
213
- // pd, pw, pm, py
214
257
  if (freshness === 'day')
215
258
  return 'pd';
216
259
  if (freshness === 'week')
@@ -220,7 +263,6 @@ export class OrchestratorManager {
220
263
  return 'py';
221
264
  }
222
265
  if (provider === 'scraper') {
223
- // qdr:d, qdr:w, qdr:m, qdr:y
224
266
  if (freshness === 'day')
225
267
  return '&tbs=qdr:d';
226
268
  if (freshness === 'week')
@@ -231,7 +273,6 @@ export class OrchestratorManager {
231
273
  }
232
274
  return '';
233
275
  };
234
- // 1. Brave Search (Tool) - Priority 1A
235
276
  const braveApiKey = process.env.BRAVE_SEARCH_API_KEY;
236
277
  if (braveApiKey) {
237
278
  try {
@@ -255,10 +296,8 @@ export class OrchestratorManager {
255
296
  console.error('Brave API failed, falling back:', e);
256
297
  }
257
298
  }
258
- // 2. Exa.ai Search (Tool) - Priority 1B
259
299
  if (process.env.EXA_API_KEY) {
260
300
  try {
261
- // Exa uses startPublishedDate for freshness
262
301
  let startPublishedDate;
263
302
  const now = new Date();
264
303
  if (freshness === 'day')
@@ -300,7 +339,6 @@ export class OrchestratorManager {
300
339
  console.error('Exa Search failed, falling back:', e);
301
340
  }
302
341
  }
303
- // 3. Google Custom Search (MPC/Gemini) - Priority 2
304
342
  if (process.env.GOOGLE_SEARCH_API_KEY && process.env.GOOGLE_SEARCH_CX) {
305
343
  try {
306
344
  const dateRestrict = getFreshnessParams('google');
@@ -324,50 +362,16 @@ export class OrchestratorManager {
324
362
  console.error('Google Search failed, falling back:', e);
325
363
  }
326
364
  }
327
- // 4. Fallback to basic scraper
328
365
  try {
329
- const freshParam = getFreshnessParams('scraper');
330
- const searchUrl = `https://www.google.com/search?q=${encodeURIComponent(query)}${freshParam}`;
331
- const response = await fetch(searchUrl, {
332
- headers: {
333
- 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36'
334
- }
335
- });
336
- const html = await response.text();
337
- const results = [];
338
- // Enhanced patterns for Google search results
339
- const patterns = [
340
- // Standard snippets
341
- /<div class="vvSyob">(.+?)<\/div>| <div class="BNeawe s3v9rd AP7Wnd">(.+?)<\/div>/g,
342
- // Mobile snippets
343
- /<div class="BNeawe vvSyob s3v9rd AP7Wnd">(.+?)<\/div>/g,
344
- // Alternative layout snippets
345
- /<span class="aCOpbd">(.+?)<\/span>/g
346
- ];
347
- for (const pattern of patterns) {
348
- let match;
349
- while ((match = pattern.exec(html)) !== null && results.length < numResults) {
350
- const text = (match[1] || match[2] || match[0]).replace(/<[^>]+>/g, '').trim();
351
- if (text.length > 20 && !results.some((r) => r.snippet === text)) {
352
- results.push({ snippet: text });
353
- }
354
- }
355
- }
356
- // Fallback: If no snippets found, try to extract anything that looks like a title/link description
357
- if (results.length === 0) {
358
- const linkDescRegex = /<h3[^>]*>(.+?)<\/h3>/g;
359
- let match;
360
- while ((match = linkDescRegex.exec(html)) !== null && results.length < numResults) {
361
- const text = match[1].replace(/<[^>]+>/g, '').trim();
362
- if (text.length > 10)
363
- results.push({ snippet: text });
364
- }
365
- }
366
+ console.warn('[Web Search] Scraper fallback is deprecated/unstable. Please set GOOGLE_SEARCH_API_KEY or BRAVE_SEARCH_API_KEY.');
366
367
  return {
367
368
  query,
368
- source: 'Scraper Fallback',
369
- results,
370
- searchUrl,
369
+ source: 'System',
370
+ results: [{
371
+ title: 'Configuration Required',
372
+ snippet: 'Web search scraping is disabled due to reliability issues. Please configure GOOGLE_SEARCH_API_KEY (and CX) or BRAVE_SEARCH_API_KEY in your environment to enable search functionality.',
373
+ url: 'https://console.cloud.google.com/apis/credentials'
374
+ }],
371
375
  timestamp: new Date().toISOString()
372
376
  };
373
377
  }
@@ -376,7 +380,6 @@ export class OrchestratorManager {
376
380
  }
377
381
  }
378
382
  });
379
- // Memory Save tool
380
383
  this.registerTool({
381
384
  name: 'memory_save',
382
385
  description: 'Saves a fact or information to long-term memory',
@@ -387,7 +390,6 @@ export class OrchestratorManager {
387
390
  return { success: true, message: `Saved to memory: ${key}`, entry };
388
391
  }
389
392
  });
390
- // Memory Query tool - Enhanced with filters
391
393
  this.registerTool({
392
394
  name: 'memory_query',
393
395
  description: 'Queries long-term memory with optional category and tag filters',
@@ -401,7 +403,6 @@ export class OrchestratorManager {
401
403
  return { query, results, count: results.length };
402
404
  }
403
405
  });
404
- // Memory Delete tool
405
406
  this.registerTool({
406
407
  name: 'memory_delete',
407
408
  description: 'Deletes an entry from long-term memory by its ID or Key',
@@ -412,7 +413,6 @@ export class OrchestratorManager {
412
413
  return { success: true, ...result };
413
414
  }
414
415
  });
415
- // Vector Memory Save
416
416
  this.registerTool({
417
417
  name: 'vector_save',
418
418
  description: 'Saves text to semantic vector memory (The Scholar)',
@@ -423,7 +423,6 @@ export class OrchestratorManager {
423
423
  return { success: true, id: entry.id, message: 'Saved to vector memory' };
424
424
  }
425
425
  });
426
- // Vector Memory Search
427
426
  this.registerTool({
428
427
  name: 'vector_search',
429
428
  description: 'Semantically searches vector memory',
@@ -434,49 +433,39 @@ export class OrchestratorManager {
434
433
  return { query, results };
435
434
  }
436
435
  });
437
- // Compute tool - performs calculations
438
436
  this.registerTool({
439
437
  name: 'compute',
440
438
  description: 'Performs mathematical computations',
441
439
  execute: async (input) => {
442
440
  const expression = input.expression;
443
441
  const variables = input.variables || {};
444
- // Simple expression evaluator (safe subset)
445
442
  let resultExpr = expression;
446
443
  for (const [key, value] of Object.entries(variables)) {
447
444
  resultExpr = resultExpr.replace(new RegExp(`\\b${key}\\b`, 'g'), String(value));
448
445
  }
449
- // Evaluate simple math expressions
450
446
  try {
451
- // Use vm for sandboxed execution
452
- if (/^[\d\s+\-*/().]+$/.test(resultExpr)) {
453
- return { result: vm.runInNewContext(resultExpr, {}) };
447
+ if (/^[\d\s+\-*/().,MathPIE_a-zA-Z]+$/.test(resultExpr) &&
448
+ !resultExpr.includes('process') &&
449
+ !resultExpr.includes('require') &&
450
+ !resultExpr.includes('import')) {
451
+ const result = await this.safeEval(resultExpr);
452
+ return { result };
454
453
  }
455
454
  return { error: 'Invalid expression', expression: resultExpr };
456
455
  }
457
- catch {
458
- return { error: 'Computation failed', expression: resultExpr };
456
+ catch (error) {
457
+ return { error: 'Computation failed', expression: resultExpr, details: String(error) };
459
458
  }
460
459
  }
461
460
  });
462
461
  }
463
- /**
464
- * Register a custom tool
465
- */
466
462
  registerTool(tool) {
467
463
  this.toolRegistry[tool.name] = tool;
468
464
  }
469
- /**
470
- * Get list of registered tools
471
- */
472
465
  getRegisteredTools() {
473
466
  return Object.keys(this.toolRegistry);
474
467
  }
475
- /**
476
- * Process an orchestrator action
477
- */
478
468
  async process(input) {
479
- // Rate limiting / Flood protection
480
469
  const now = Date.now();
481
470
  const elapsed = now - this.lastActionTimestamp;
482
471
  if (elapsed < this.MIN_DELAY_MS) {
@@ -501,9 +490,6 @@ export class OrchestratorManager {
501
490
  };
502
491
  }
503
492
  }
504
- /**
505
- * Delete an execution plan from history
506
- */
507
493
  deletePlan(input) {
508
494
  if (!input.planId) {
509
495
  return {
@@ -524,9 +510,6 @@ export class OrchestratorManager {
524
510
  message: `Successfully deleted execution history for plan: ${input.planId}`
525
511
  };
526
512
  }
527
- /**
528
- * Validate an execution plan
529
- */
530
513
  validatePlan(input) {
531
514
  if (!input.plan) {
532
515
  return {
@@ -537,7 +520,6 @@ export class OrchestratorManager {
537
520
  }
538
521
  const validation = validateDAG(input.plan);
539
522
  const errors = [...validation.errors];
540
- // Check for unregistered tools
541
523
  for (const task of input.plan.tasks) {
542
524
  if (!this.toolRegistry[task.toolName]) {
543
525
  errors.push(`Task "${task.id}" uses unregistered tool "${task.toolName}". Available tools: ${this.getRegisteredTools().join(', ')}`);
@@ -559,9 +541,6 @@ export class OrchestratorManager {
559
541
  executionOrder: topoResult.layers
560
542
  };
561
543
  }
562
- /**
563
- * Execute a plan with parallel processing
564
- */
565
544
  async executePlan(input) {
566
545
  if (!input.plan) {
567
546
  return {
@@ -569,14 +548,12 @@ export class OrchestratorManager {
569
548
  message: 'Execution plan is required'
570
549
  };
571
550
  }
572
- // Validate first
573
551
  const validation = this.validatePlan(input);
574
552
  if (!validation.success) {
575
553
  return validation;
576
554
  }
577
555
  const plan = input.plan;
578
556
  const startTime = new Date();
579
- // Get execution layers
580
557
  const topoResult = topologicalSortWithLayers(plan);
581
558
  const taskMap = new Map(plan.tasks.map((t) => [t.id, t]));
582
559
  const taskResults = [];
@@ -586,19 +563,44 @@ export class OrchestratorManager {
586
563
  console.log(`📊 Total tasks: ${plan.tasks.length}`);
587
564
  console.log(`📦 Execution layers: ${topoResult.layers.length}`);
588
565
  console.log(`⚡ Max parallelism: ${Math.max(...topoResult.layers.map((l) => l.length))}\n`);
589
- // Execute layer by layer
590
566
  for (let layerIndex = 0; layerIndex < topoResult.layers.length; layerIndex++) {
591
567
  const layer = topoResult.layers[layerIndex];
592
568
  console.log(`\n📍 Layer ${layerIndex + 1}: Executing ${layer.length} task(s) in parallel`);
593
569
  console.log(` Tasks: [${layer.join(', ')}]`);
594
- // Execute all tasks in this layer in parallel
595
570
  const layerPromises = layer.map(async (taskId) => {
596
571
  const task = taskMap.get(taskId);
572
+ const dependencies = task.dependencies.map(d => taskResults.find(r => r.taskId === d));
573
+ const failedDep = dependencies.find(d => d?.status === 'failed');
574
+ const skippedDep = dependencies.find(d => d?.status === 'skipped');
575
+ if (failedDep) {
576
+ console.log(` ○ Skipped: ${task.name} (Dependency "${failedDep.taskName}" failed)`);
577
+ return {
578
+ taskId: task.id,
579
+ taskName: task.name,
580
+ status: 'skipped',
581
+ error: `Dependency ${failedDep.taskName} failed`,
582
+ startTime: new Date().toISOString(),
583
+ endTime: new Date().toISOString(),
584
+ duration: 0,
585
+ retries: 0
586
+ };
587
+ }
588
+ if (skippedDep) {
589
+ console.log(` ○ Skipped: ${task.name} (Dependency "${skippedDep.taskName}" skipped)`);
590
+ return {
591
+ taskId: task.id,
592
+ taskName: task.name,
593
+ status: 'skipped',
594
+ error: `Dependency ${skippedDep.taskName} skipped`,
595
+ startTime: new Date().toISOString(),
596
+ endTime: new Date().toISOString(),
597
+ duration: 0,
598
+ retries: 0
599
+ };
600
+ }
597
601
  return this.executeTask(task, taskOutputs, errors);
598
602
  });
599
- // Wait for all tasks in this layer to complete
600
603
  const layerResults = await Promise.all(layerPromises);
601
- // Store results
602
604
  for (const result of layerResults) {
603
605
  taskResults.push(result);
604
606
  if (result.status === 'completed' && result.result !== undefined) {
@@ -608,7 +610,6 @@ export class OrchestratorManager {
608
610
  }
609
611
  const endTime = new Date();
610
612
  const totalDuration = endTime.getTime() - startTime.getTime();
611
- // Aggregate results
612
613
  const aggregatedResults = {};
613
614
  for (const [taskId, output] of taskOutputs) {
614
615
  aggregatedResults[taskId] = output;
@@ -647,9 +648,6 @@ export class OrchestratorManager {
647
648
  executionOrder: topoResult.layers
648
649
  };
649
650
  }
650
- /**
651
- * Execute a single task with error handling, retries, and resilience
652
- */
653
651
  async executeTask(task, taskOutputs, errors) {
654
652
  const startTime = new Date();
655
653
  const maxRetries = task.retryCount || 0;
@@ -658,9 +656,9 @@ export class OrchestratorManager {
658
656
  let repairAttempts = 0; // Guard against infinite repair loops
659
657
  let currentInput = task.toolInput; // Allow modification
660
658
  console.log(` ⚙️ Starting: ${task.name} (${task.id})`);
661
- // 1. Check Cache
659
+ let resolvedInput = this.resolveInput(currentInput, taskOutputs);
662
660
  if (['fetch', 'web_search'].includes(task.toolName)) {
663
- const cached = toolCache.get(task.toolName, currentInput);
661
+ const cached = toolCache.get(task.toolName, resolvedInput);
664
662
  if (cached) {
665
663
  console.log(` ⚡ Cached Hit: ${task.name}`);
666
664
  return {
@@ -675,20 +673,14 @@ export class OrchestratorManager {
675
673
  };
676
674
  }
677
675
  }
678
- // Get tool
679
676
  const tool = this.toolRegistry[task.toolName];
680
677
  if (!tool) {
681
- // ... error handling ...
682
678
  const error = `Tool "${task.toolName}" not found`;
683
679
  errors.push({ taskId: task.id, taskName: task.name, error, timestamp: new Date().toISOString() });
684
680
  return { taskId: task.id, taskName: task.name, status: 'failed', error, startTime: startTime.toISOString(), endTime: new Date().toISOString(), duration: 0, retries: 0 };
685
681
  }
686
- // Resolve input
687
- let resolvedInput = this.resolveInput(currentInput, taskOutputs);
688
- // Evaluate condition
689
682
  if (task.runIf) {
690
- // ... existing runIf logic ...
691
- const isConditionMet = this.evaluateCondition(task.runIf, taskOutputs);
683
+ const isConditionMet = await this.evaluateCondition(task.runIf, taskOutputs);
692
684
  if (!isConditionMet) {
693
685
  console.log(` ○ Skipped: ${task.name} (Condition "${task.runIf}" not met)`);
694
686
  return { taskId: task.id, taskName: task.name, status: 'skipped', startTime: startTime.toISOString(), endTime: new Date().toISOString(), duration: 0, retries: 0 };
@@ -701,7 +693,6 @@ export class OrchestratorManager {
701
693
  : await tool.execute(resolvedInput);
702
694
  const endTime = new Date();
703
695
  console.log(` ✓ Completed: ${task.name} (${endTime.getTime() - startTime.getTime()}ms)`);
704
- // Update Cache
705
696
  if (['fetch', 'web_search'].includes(task.toolName)) {
706
697
  toolCache.set(task.toolName, currentInput, result);
707
698
  }
@@ -718,33 +709,27 @@ export class OrchestratorManager {
718
709
  }
719
710
  catch (err) {
720
711
  const errorMessage = err instanceof Error ? err.message : String(err);
721
- // 🛡️ Resilience / Self-Healing
722
- // Only attempt repair if we haven't exceeded the limit (hardcoded to 3 for safety)
723
712
  if (repairAttempts < 3) {
724
- // Ask the Immune System what to do
725
713
  const recovery = await resilienceManager.diagnose(err, { ...task, toolInput: currentInput });
726
714
  if (recovery) {
727
715
  console.log(` 🚑 Self-Healing (${recovery.type}): ${recovery.description}`);
728
716
  repairAttempts++; // Increment guard
729
717
  if (recovery.type === 'run_command' && recovery.payload?.command) {
730
- // Execute the fix (e.g., mkdir)
731
718
  try {
732
719
  await this.toolRegistry['shell_execute'].execute({ command: recovery.payload.command });
733
- continue;
720
+ // continue; // Let it fall through to retry logic
734
721
  }
735
722
  catch (fixErr) {
736
723
  console.log(` ❌ Fix failed: ${fixErr}`);
737
724
  }
738
725
  }
739
726
  else if (recovery.type === 'modify_input' && recovery.payload) {
740
- // Modify input for next attempt
741
727
  currentInput = { ...currentInput, ...recovery.payload };
742
728
  resolvedInput = this.resolveInput(currentInput, taskOutputs);
743
- continue;
729
+ // continue; // Let it fall through to retry logic
744
730
  }
745
731
  }
746
732
  }
747
- // Standard Retry Logic
748
733
  retries++;
749
734
  if (retries <= maxRetries) {
750
735
  const backoff = Math.min(retryDelay * Math.pow(2, retries - 1), 30000);
@@ -752,14 +737,12 @@ export class OrchestratorManager {
752
737
  await new Promise((resolve) => setTimeout(resolve, backoff));
753
738
  }
754
739
  else {
755
- // 🚨 ACTIVE LEARNING: All retries failed. Ask Brain for a miracle.
756
740
  console.log(` 🚨 All retries failed for: ${task.name}. Requesting mid-execution re-plan...`);
757
741
  const replanResult = await resilienceManager.requestStrategicReplan(errorMessage, task);
758
742
  if (replanResult?.success && replanResult.executionPlan) {
759
743
  console.log(` ✨ MIRACLE! Brain provided a recovery plan: ${replanResult.executionPlan.name}`);
760
744
  const subResult = await this.executePlan({ action: 'execute_plan', plan: replanResult.executionPlan });
761
745
  if (subResult.success) {
762
- // If recovery plan succeeded, we can technically count the original task as "recovered"
763
746
  return {
764
747
  taskId: task.id,
765
748
  taskName: task.name,
@@ -780,28 +763,24 @@ export class OrchestratorManager {
780
763
  }
781
764
  return { taskId: task.id, taskName: task.name, status: 'failed', error: 'Unknown', startTime: startTime.toISOString(), endTime: new Date().toISOString(), duration: 0, retries };
782
765
  }
783
- evaluateCondition(condition, taskOutputs) {
784
- // 1. Resolve placeholders in the condition string
785
- const resolvedCondition = this.resolveValue(condition, taskOutputs);
786
- // 2. Simple evaluation for common cases
787
- // Handling literal booleans
788
- if (resolvedCondition === 'true')
789
- return true;
790
- if (resolvedCondition === 'false')
791
- return false;
792
- try {
793
- // 3. Safe evaluation using vm (sandboxed)
794
- // This prevents access to global objects like process, require, etc.
795
- return !!vm.runInNewContext(resolvedCondition, {});
796
- }
797
- catch {
798
- return false;
766
+ async evaluateCondition(condition, taskOutputs) {
767
+ const resolvedCondition = this.resolveValue(condition, taskOutputs, true);
768
+ if (typeof resolvedCondition === 'boolean')
769
+ return resolvedCondition;
770
+ if (typeof resolvedCondition === 'string') {
771
+ if (resolvedCondition === 'true')
772
+ return true;
773
+ if (resolvedCondition === 'false')
774
+ return false;
775
+ try {
776
+ return !!(await this.safeEval(resolvedCondition));
777
+ }
778
+ catch {
779
+ return false;
780
+ }
799
781
  }
782
+ return !!resolvedCondition;
800
783
  }
801
- /**
802
- * Resolve input placeholders with outputs from previous tasks
803
- * Supports syntax: "${taskId.property}" or "${taskId}"
804
- */
805
784
  resolveInput(input, taskOutputs) {
806
785
  const resolved = {};
807
786
  for (const [key, value] of Object.entries(input)) {
@@ -809,18 +788,18 @@ export class OrchestratorManager {
809
788
  }
810
789
  return resolved;
811
790
  }
812
- resolveValue(value, taskOutputs) {
791
+ resolveValue(value, taskOutputs, safeForEval = false) {
813
792
  if (typeof value === 'string') {
814
- // Check for placeholder pattern: ${taskId} or ${taskId.property}
815
793
  const placeholderRegex = /\$\{([^}]+)\}/g;
816
- // If entire string is a single placeholder, return the actual value (not stringified)
817
794
  const singleMatch = value.match(/^\$\{([^}]+)\}$/);
818
795
  if (singleMatch) {
819
796
  return this.resolvePlaceholder(singleMatch[1], taskOutputs);
820
797
  }
821
- // Otherwise, replace placeholders in string
822
798
  return value.replace(placeholderRegex, (_, placeholder) => {
823
799
  const resolved = this.resolvePlaceholder(placeholder, taskOutputs);
800
+ if (safeForEval && typeof resolved === 'string') {
801
+ return resolved.replace(/\\/g, '\\\\').replace(/"/g, '\\"');
802
+ }
824
803
  return String(resolved);
825
804
  });
826
805
  }
@@ -842,10 +821,8 @@ export class OrchestratorManager {
842
821
  if (parts.length === 1) {
843
822
  return output;
844
823
  }
845
- // Navigate nested properties
846
824
  let current = output;
847
825
  for (let i = 1; i < parts.length; i++) {
848
- // Allow traversal of objects and strings (for .length etc)
849
826
  if (current && (typeof current === 'object' || typeof current === 'string')) {
850
827
  current = current[parts[i]];
851
828
  }
@@ -855,18 +832,12 @@ export class OrchestratorManager {
855
832
  }
856
833
  return current;
857
834
  }
858
- /**
859
- * Execute a promise with timeout
860
- */
861
835
  async executeWithTimeout(promise, timeoutMs) {
862
836
  return Promise.race([
863
837
  promise,
864
838
  new Promise((_, reject) => setTimeout(() => reject(new Error(`Task timed out after ${timeoutMs}ms`)), timeoutMs))
865
839
  ]);
866
840
  }
867
- /**
868
- * Get execution status for a plan
869
- */
870
841
  getExecutionStatus(input) {
871
842
  if (!input.planId) {
872
843
  return {
@@ -887,9 +858,6 @@ export class OrchestratorManager {
887
858
  result
888
859
  };
889
860
  }
890
- /**
891
- * Format execution summary for display
892
- */
893
861
  formatExecutionSummary(result) {
894
862
  const lines = [
895
863
  '┌─────────────────────────────────────────────────┐',
@@ -914,6 +882,5 @@ export class OrchestratorManager {
914
882
  return lines.join('\n');
915
883
  }
916
884
  }
917
- // Export singleton instance
918
885
  export const orchestratorManager = new OrchestratorManager();
919
886
  //# sourceMappingURL=orchestrator.js.map