genesis-ai-cli 8.1.0 → 8.3.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.
@@ -61,6 +61,9 @@ const child_process_1 = require("child_process");
61
61
  const util_1 = require("util");
62
62
  const fs = __importStar(require("fs"));
63
63
  const path = __importStar(require("path"));
64
+ // v8.3: Self-modification imports
65
+ const darwin_godel_js_1 = require("../self-modification/darwin-godel.js");
66
+ const self_improvement_js_1 = require("../self-modification/self-improvement.js");
64
67
  const execAsync = (0, util_1.promisify)(child_process_1.exec);
65
68
  // ============================================================================
66
69
  // Lazy Singleton Instances
@@ -1410,6 +1413,215 @@ registerAction('code.diff', async (context) => {
1410
1413
  }
1411
1414
  });
1412
1415
  // ============================================================================
1416
+ // SELF-MODIFICATION EXECUTOR (v8.3)
1417
+ // ============================================================================
1418
+ /**
1419
+ * self.modify: Radical self-modification via Darwin-Gödel Engine
1420
+ *
1421
+ * This is the core action that allows Genesis to modify its own code.
1422
+ * Requires:
1423
+ * - φ ≥ 0.3 (consciousness threshold)
1424
+ * - Valid modification plan
1425
+ * - All invariants must pass after modification
1426
+ *
1427
+ * Flow:
1428
+ * 1. Check consciousness level
1429
+ * 2. Generate or use provided modification plan
1430
+ * 3. Validate plan (syntax, safety)
1431
+ * 4. Apply in sandbox
1432
+ * 5. Verify (build, test, invariants)
1433
+ * 6. Atomic apply on success
1434
+ * 7. Store outcome in memory
1435
+ */
1436
+ registerAction('self.modify', async (context) => {
1437
+ const start = Date.now();
1438
+ try {
1439
+ // 1. Check consciousness level
1440
+ const phiMonitor = getPhiMonitor();
1441
+ const level = phiMonitor.getCurrentLevel();
1442
+ const phi = level.phi;
1443
+ if (phi < 0.3) {
1444
+ return {
1445
+ success: false,
1446
+ action: 'self.modify',
1447
+ error: `Insufficient consciousness level: φ=${phi.toFixed(3)} (need ≥0.3)`,
1448
+ data: { phi, threshold: 0.3 },
1449
+ duration: Date.now() - start,
1450
+ };
1451
+ }
1452
+ // 2. Get or create modification plan
1453
+ let plan;
1454
+ if (context.parameters?.plan) {
1455
+ // Use provided plan
1456
+ plan = context.parameters.plan;
1457
+ }
1458
+ else if (context.parameters?.targetMetric) {
1459
+ // Use SelfImprovementEngine to find opportunity
1460
+ const engine = (0, self_improvement_js_1.getSelfImprovementEngine)();
1461
+ const cycleResult = await engine.runCycle();
1462
+ // Find opportunity matching target metric
1463
+ const targetMetric = context.parameters.targetMetric;
1464
+ const opportunity = cycleResult.opportunities.find((o) => o.metric === targetMetric);
1465
+ if (!opportunity || !opportunity.suggestedFix) {
1466
+ return {
1467
+ success: false,
1468
+ action: 'self.modify',
1469
+ error: `No improvement opportunity found for metric: ${targetMetric}`,
1470
+ data: {
1471
+ metrics: cycleResult.metrics,
1472
+ availableOpportunities: cycleResult.opportunities.map((o) => o.metric),
1473
+ },
1474
+ duration: Date.now() - start,
1475
+ };
1476
+ }
1477
+ plan = opportunity.suggestedFix;
1478
+ }
1479
+ else {
1480
+ // Auto-detect: run full improvement cycle
1481
+ const engine = (0, self_improvement_js_1.getSelfImprovementEngine)();
1482
+ const result = await engine.runCycle();
1483
+ if (result.results.length === 0) {
1484
+ return {
1485
+ success: true,
1486
+ action: 'self.modify',
1487
+ data: {
1488
+ message: 'No improvements needed - all metrics within targets',
1489
+ metrics: result.metrics,
1490
+ opportunities: result.opportunities.length,
1491
+ },
1492
+ duration: Date.now() - start,
1493
+ };
1494
+ }
1495
+ // Return first improvement result
1496
+ const improvement = result.results[0];
1497
+ return {
1498
+ success: improvement.success,
1499
+ action: 'self.modify',
1500
+ data: {
1501
+ opportunityId: improvement.opportunityId,
1502
+ applied: improvement.applied,
1503
+ beforeMetrics: improvement.beforeMetrics,
1504
+ afterMetrics: improvement.afterMetrics,
1505
+ commitHash: improvement.commitHash,
1506
+ },
1507
+ duration: Date.now() - start,
1508
+ };
1509
+ }
1510
+ // 3. Apply via Darwin-Gödel Engine
1511
+ const darwinGodel = (0, darwin_godel_js_1.getDarwinGodelEngine)();
1512
+ const applyResult = await darwinGodel.apply(plan);
1513
+ // 4. Log outcome (memory storage removed - use event system instead)
1514
+ console.log(`[self.modify] ${applyResult.success ? 'SUCCESS' : 'FAILED'}: ${plan.name}`);
1515
+ return {
1516
+ success: applyResult.success,
1517
+ action: 'self.modify',
1518
+ data: {
1519
+ planId: plan.id,
1520
+ planName: plan.name,
1521
+ modificationsCount: plan.modifications.length,
1522
+ verification: {
1523
+ buildSuccess: applyResult.verificaton.buildSuccess,
1524
+ testsSuccess: applyResult.verificaton.testsSuccess,
1525
+ invariantsPass: applyResult.verificaton.invariantsPass,
1526
+ },
1527
+ commitHash: applyResult.commitHash,
1528
+ rollbackHash: applyResult.rollbackHash,
1529
+ canRollback: !!applyResult.rollbackHash,
1530
+ },
1531
+ duration: Date.now() - start,
1532
+ };
1533
+ }
1534
+ catch (error) {
1535
+ return {
1536
+ success: false,
1537
+ action: 'self.modify',
1538
+ error: error instanceof Error ? error.message : String(error),
1539
+ duration: Date.now() - start,
1540
+ };
1541
+ }
1542
+ });
1543
+ /**
1544
+ * improve.self: High-level self-improvement action
1545
+ *
1546
+ * Observes metrics, identifies bottlenecks, and triggers self.modify.
1547
+ * This is the "autonomous improvement" entry point.
1548
+ */
1549
+ registerAction('improve.self', async (context) => {
1550
+ const start = Date.now();
1551
+ try {
1552
+ const engine = (0, self_improvement_js_1.getSelfImprovementEngine)();
1553
+ // 1. Run improvement cycle (observe + reflect + optionally apply)
1554
+ const cycleResult = await engine.runCycle();
1555
+ const { metrics, opportunities, results } = cycleResult;
1556
+ if (opportunities.length === 0) {
1557
+ return {
1558
+ success: true,
1559
+ action: 'improve.self',
1560
+ data: {
1561
+ message: 'System is operating within optimal parameters',
1562
+ metrics: {
1563
+ phi: metrics.phi,
1564
+ memoryReuse: metrics.memoryReuse,
1565
+ errorRate: metrics.errorRate,
1566
+ taskSuccessRate: metrics.taskSuccessRate,
1567
+ },
1568
+ },
1569
+ duration: Date.now() - start,
1570
+ };
1571
+ }
1572
+ // 2. Sort by priority and pick top
1573
+ const sorted = [...opportunities].sort((a, b) => b.priority - a.priority);
1574
+ const topOpportunity = sorted[0];
1575
+ // 3. If autoApply and we have results, report them
1576
+ if (context.parameters?.autoApply && results.length > 0) {
1577
+ return {
1578
+ success: true,
1579
+ action: 'improve.self',
1580
+ data: {
1581
+ applied: results.length > 0,
1582
+ improvements: results.map((i) => ({
1583
+ id: i.opportunityId,
1584
+ success: i.success,
1585
+ })),
1586
+ metrics: metrics,
1587
+ },
1588
+ duration: Date.now() - start,
1589
+ };
1590
+ }
1591
+ // 4. Otherwise, just report opportunities
1592
+ return {
1593
+ success: true,
1594
+ action: 'improve.self',
1595
+ data: {
1596
+ opportunities: sorted.map((o) => ({
1597
+ id: o.id,
1598
+ category: o.category,
1599
+ metric: o.metric,
1600
+ current: o.currentValue,
1601
+ target: o.targetValue,
1602
+ priority: o.priority,
1603
+ description: o.description,
1604
+ })),
1605
+ topRecommendation: {
1606
+ metric: topOpportunity.metric,
1607
+ description: topOpportunity.description,
1608
+ priority: topOpportunity.priority,
1609
+ },
1610
+ hint: 'Use self.modify with targetMetric parameter to apply improvement',
1611
+ },
1612
+ duration: Date.now() - start,
1613
+ };
1614
+ }
1615
+ catch (error) {
1616
+ return {
1617
+ success: false,
1618
+ action: 'improve.self',
1619
+ error: error instanceof Error ? error.message : String(error),
1620
+ duration: Date.now() - start,
1621
+ };
1622
+ }
1623
+ });
1624
+ // ============================================================================
1413
1625
  // Action Executor Manager
1414
1626
  // ============================================================================
1415
1627
  class ActionExecutorManager {
@@ -54,6 +54,9 @@ export declare class Brain {
54
54
  private worldModel;
55
55
  private darwinGodel;
56
56
  private persistence;
57
+ private toolCache;
58
+ private readonly TOOL_CACHE_TTL;
59
+ private readonly TOOL_CACHE_MAX_SIZE;
57
60
  private running;
58
61
  private currentState;
59
62
  private systemPrompt;
@@ -118,8 +121,17 @@ export declare class Brain {
118
121
  private stepGrounding;
119
122
  /**
120
123
  * Tools module: execute tool calls
124
+ * v8.2: Added caching for repeated tool calls
121
125
  */
122
126
  private stepTools;
127
+ /**
128
+ * v8.2: Clean expired entries from tool cache
129
+ */
130
+ private cleanToolCache;
131
+ /**
132
+ * v8.2: Generate cache key from tool call
133
+ */
134
+ private getToolCacheKey;
123
135
  /**
124
136
  * Healing module: recover from errors
125
137
  */
@@ -99,6 +99,10 @@ class Brain {
99
99
  darwinGodel = null;
100
100
  // v8.1: State Persistence
101
101
  persistence;
102
+ // v8.2: Tool Results Cache (approved self-modification)
103
+ toolCache = new Map();
104
+ TOOL_CACHE_TTL = 60000; // 1 minute TTL
105
+ TOOL_CACHE_MAX_SIZE = 100;
102
106
  // State
103
107
  running = false;
104
108
  currentState = null;
@@ -563,6 +567,7 @@ class Brain {
563
567
  }
564
568
  /**
565
569
  * Tools module: execute tool calls
570
+ * v8.2: Added caching for repeated tool calls
566
571
  */
567
572
  async stepTools(state) {
568
573
  if (state.toolCalls.length === 0) {
@@ -574,21 +579,44 @@ class Brain {
574
579
  // Parse tool calls for dispatcher
575
580
  const dispatcherCalls = this.dispatcher.parseToolCalls(state.response);
576
581
  const results = [];
582
+ // v8.2: Check cache and clean expired entries
583
+ this.cleanToolCache();
577
584
  if (dispatcherCalls.length > 0) {
578
- const dispatchResult = await this.dispatcher.dispatch(dispatcherCalls);
579
- for (const r of dispatchResult.results) {
580
- results.push({
581
- name: r.name,
582
- success: r.success,
583
- data: r.data,
584
- error: r.error,
585
- duration: r.duration,
586
- });
587
- if (r.success) {
585
+ const uncachedCalls = [];
586
+ // v8.2: Check cache for each call
587
+ for (const call of dispatcherCalls) {
588
+ const cacheKey = this.getToolCacheKey(call);
589
+ const cached = this.toolCache.get(cacheKey);
590
+ if (cached && (Date.now() - cached.timestamp) < this.TOOL_CACHE_TTL) {
591
+ // Cache hit
592
+ results.push({ ...cached.result, cached: true });
588
593
  this.metrics.toolSuccesses++;
589
594
  }
590
595
  else {
591
- this.metrics.toolFailures++;
596
+ uncachedCalls.push(call);
597
+ }
598
+ }
599
+ // Execute uncached calls
600
+ if (uncachedCalls.length > 0) {
601
+ const dispatchResult = await this.dispatcher.dispatch(uncachedCalls);
602
+ for (const r of dispatchResult.results) {
603
+ const result = {
604
+ name: r.name,
605
+ success: r.success,
606
+ data: r.data,
607
+ error: r.error,
608
+ duration: r.duration,
609
+ };
610
+ results.push(result);
611
+ // v8.2: Cache successful results
612
+ if (r.success) {
613
+ const cacheKey = this.getToolCacheKey({ name: r.name, arguments: {} });
614
+ this.toolCache.set(cacheKey, { result, timestamp: Date.now() });
615
+ this.metrics.toolSuccesses++;
616
+ }
617
+ else {
618
+ this.metrics.toolFailures++;
619
+ }
592
620
  }
593
621
  }
594
622
  }
@@ -610,6 +638,34 @@ class Brain {
610
638
  reason: 'tool_results',
611
639
  };
612
640
  }
641
+ /**
642
+ * v8.2: Clean expired entries from tool cache
643
+ */
644
+ cleanToolCache() {
645
+ const now = Date.now();
646
+ // Remove expired entries
647
+ for (const [key, entry] of this.toolCache.entries()) {
648
+ if (now - entry.timestamp > this.TOOL_CACHE_TTL) {
649
+ this.toolCache.delete(key);
650
+ }
651
+ }
652
+ // Enforce max size (LRU-style: remove oldest entries)
653
+ if (this.toolCache.size > this.TOOL_CACHE_MAX_SIZE) {
654
+ const entries = Array.from(this.toolCache.entries())
655
+ .sort((a, b) => a[1].timestamp - b[1].timestamp);
656
+ const toRemove = entries.slice(0, this.toolCache.size - this.TOOL_CACHE_MAX_SIZE);
657
+ for (const [key] of toRemove) {
658
+ this.toolCache.delete(key);
659
+ }
660
+ }
661
+ }
662
+ /**
663
+ * v8.2: Generate cache key from tool call
664
+ */
665
+ getToolCacheKey(call) {
666
+ const argsStr = call.arguments ? JSON.stringify(call.arguments) : '';
667
+ return `${call.name}:${argsStr}`;
668
+ }
613
669
  /**
614
670
  * Healing module: recover from errors
615
671
  */
@@ -123,18 +123,24 @@ const node_assert_1 = __importDefault(require("node:assert"));
123
123
  });
124
124
  });
125
125
  (0, node_test_1.describe)('Brain Metrics', () => {
126
- (0, node_test_1.test)('initial metrics are zeroed', async () => {
126
+ (0, node_test_1.test)('metrics have correct structure and types', async () => {
127
127
  const { createBrain } = await import('../src/brain/index.js');
128
128
  const brain = createBrain();
129
129
  const metrics = brain.getMetrics();
130
- node_assert_1.default.strictEqual(metrics.totalCycles, 0);
131
- node_assert_1.default.strictEqual(metrics.successfulCycles, 0);
132
- node_assert_1.default.strictEqual(metrics.failedCycles, 0);
133
- node_assert_1.default.strictEqual(metrics.memoryRecalls, 0);
134
- node_assert_1.default.strictEqual(metrics.groundingChecks, 0);
135
- node_assert_1.default.strictEqual(metrics.toolExecutions, 0);
136
- node_assert_1.default.strictEqual(metrics.healingAttempts, 0);
137
- node_assert_1.default.strictEqual(metrics.broadcasts, 0);
130
+ // Note: Due to v8.1 state persistence, metrics may carry over from previous runs
131
+ // We verify the metrics structure and types rather than exact values
132
+ node_assert_1.default.ok(typeof metrics.totalCycles === 'number', 'totalCycles should be a number');
133
+ node_assert_1.default.ok(typeof metrics.successfulCycles === 'number', 'successfulCycles should be a number');
134
+ node_assert_1.default.ok(typeof metrics.failedCycles === 'number', 'failedCycles should be a number');
135
+ node_assert_1.default.ok(typeof metrics.memoryRecalls === 'number', 'memoryRecalls should be a number');
136
+ node_assert_1.default.ok(typeof metrics.groundingChecks === 'number', 'groundingChecks should be a number');
137
+ node_assert_1.default.ok(typeof metrics.toolExecutions === 'number', 'toolExecutions should be a number');
138
+ node_assert_1.default.ok(typeof metrics.healingAttempts === 'number', 'healingAttempts should be a number');
139
+ node_assert_1.default.ok(typeof metrics.broadcasts === 'number', 'broadcasts should be a number');
140
+ // Verify metrics are non-negative
141
+ node_assert_1.default.ok(metrics.totalCycles >= 0, 'totalCycles should be >= 0');
142
+ node_assert_1.default.ok(metrics.successfulCycles >= 0, 'successfulCycles should be >= 0');
143
+ node_assert_1.default.ok(metrics.failedCycles >= 0, 'failedCycles should be >= 0');
138
144
  });
139
145
  (0, node_test_1.test)('metrics track avgPhi', async () => {
140
146
  const { createBrain } = await import('../src/brain/index.js');
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "genesis-ai-cli",
3
- "version": "8.1.0",
3
+ "version": "8.3.0",
4
4
  "description": "Fully Autonomous AI System - Self-funding, Self-deploying, Production Memory, A2A Protocol & Governance",
5
5
  "main": "dist/src/index.js",
6
6
  "types": "dist/src/index.d.ts",