@cogitator-ai/self-modifying 17.0.16 → 17.0.18

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 (92) hide show
  1. package/LICENSE +21 -0
  2. package/dist/architecture-evolution/capability-analyzer.d.ts.map +1 -1
  3. package/dist/architecture-evolution/capability-analyzer.js +6 -3
  4. package/dist/architecture-evolution/capability-analyzer.js.map +1 -1
  5. package/dist/architecture-evolution/evolution-strategy.d.ts.map +1 -1
  6. package/dist/architecture-evolution/evolution-strategy.js +4 -2
  7. package/dist/architecture-evolution/evolution-strategy.js.map +1 -1
  8. package/dist/architecture-evolution/parameter-optimizer.d.ts.map +1 -1
  9. package/dist/architecture-evolution/parameter-optimizer.js +32 -9
  10. package/dist/architecture-evolution/parameter-optimizer.js.map +1 -1
  11. package/dist/architecture-evolution/prompts.d.ts.map +1 -1
  12. package/dist/architecture-evolution/prompts.js +42 -4
  13. package/dist/architecture-evolution/prompts.js.map +1 -1
  14. package/dist/constraints/modification-validator.d.ts.map +1 -1
  15. package/dist/constraints/modification-validator.js +16 -5
  16. package/dist/constraints/modification-validator.js.map +1 -1
  17. package/dist/constraints/rollback-manager.d.ts +1 -0
  18. package/dist/constraints/rollback-manager.d.ts.map +1 -1
  19. package/dist/constraints/rollback-manager.js +25 -1
  20. package/dist/constraints/rollback-manager.js.map +1 -1
  21. package/dist/events/event-emitter.d.ts +0 -1
  22. package/dist/events/event-emitter.d.ts.map +1 -1
  23. package/dist/events/event-emitter.js +6 -10
  24. package/dist/events/event-emitter.js.map +1 -1
  25. package/dist/meta-reasoning/meta-reasoner.d.ts +1 -1
  26. package/dist/meta-reasoning/meta-reasoner.d.ts.map +1 -1
  27. package/dist/meta-reasoning/meta-reasoner.js +22 -13
  28. package/dist/meta-reasoning/meta-reasoner.js.map +1 -1
  29. package/dist/meta-reasoning/observation-collector.d.ts.map +1 -1
  30. package/dist/meta-reasoning/observation-collector.js +6 -2
  31. package/dist/meta-reasoning/observation-collector.js.map +1 -1
  32. package/dist/meta-reasoning/prompts.d.ts.map +1 -1
  33. package/dist/meta-reasoning/prompts.js +5 -38
  34. package/dist/meta-reasoning/prompts.js.map +1 -1
  35. package/dist/meta-reasoning/strategy-selector.d.ts.map +1 -1
  36. package/dist/meta-reasoning/strategy-selector.js +6 -0
  37. package/dist/meta-reasoning/strategy-selector.js.map +1 -1
  38. package/dist/self-modifying-agent.d.ts +8 -1
  39. package/dist/self-modifying-agent.d.ts.map +1 -1
  40. package/dist/self-modifying-agent.js +108 -14
  41. package/dist/self-modifying-agent.js.map +1 -1
  42. package/dist/tool-generation/gap-analyzer.d.ts.map +1 -1
  43. package/dist/tool-generation/gap-analyzer.js +3 -2
  44. package/dist/tool-generation/gap-analyzer.js.map +1 -1
  45. package/dist/tool-generation/generated-tool-store.d.ts.map +1 -1
  46. package/dist/tool-generation/generated-tool-store.js +90 -10
  47. package/dist/tool-generation/generated-tool-store.js.map +1 -1
  48. package/dist/tool-generation/index.d.ts +1 -1
  49. package/dist/tool-generation/index.d.ts.map +1 -1
  50. package/dist/tool-generation/index.js +1 -1
  51. package/dist/tool-generation/index.js.map +1 -1
  52. package/dist/tool-generation/prompts.d.ts +3 -3
  53. package/dist/tool-generation/prompts.d.ts.map +1 -1
  54. package/dist/tool-generation/prompts.js +65 -12
  55. package/dist/tool-generation/prompts.js.map +1 -1
  56. package/dist/tool-generation/tool-generator.d.ts +1 -1
  57. package/dist/tool-generation/tool-generator.d.ts.map +1 -1
  58. package/dist/tool-generation/tool-generator.js +55 -3
  59. package/dist/tool-generation/tool-generator.js.map +1 -1
  60. package/dist/tool-generation/tool-sandbox.d.ts +2 -6
  61. package/dist/tool-generation/tool-sandbox.d.ts.map +1 -1
  62. package/dist/tool-generation/tool-sandbox.js +220 -130
  63. package/dist/tool-generation/tool-sandbox.js.map +1 -1
  64. package/dist/tool-generation/tool-validator.d.ts +1 -0
  65. package/dist/tool-generation/tool-validator.d.ts.map +1 -1
  66. package/dist/tool-generation/tool-validator.js +48 -1
  67. package/dist/tool-generation/tool-validator.js.map +1 -1
  68. package/dist/utils/index.d.ts.map +1 -1
  69. package/dist/utils/index.js +30 -5
  70. package/dist/utils/index.js.map +1 -1
  71. package/package.json +14 -14
  72. package/src/__tests__/self-modifying-agent.test.ts +42 -10
  73. package/src/architecture-evolution/capability-analyzer.ts +7 -4
  74. package/src/architecture-evolution/evolution-strategy.ts +5 -2
  75. package/src/architecture-evolution/parameter-optimizer.ts +39 -15
  76. package/src/architecture-evolution/prompts.ts +48 -4
  77. package/src/constraints/modification-validator.ts +19 -8
  78. package/src/constraints/rollback-manager.ts +20 -1
  79. package/src/events/event-emitter.ts +6 -15
  80. package/src/meta-reasoning/meta-reasoner.ts +22 -15
  81. package/src/meta-reasoning/observation-collector.ts +6 -2
  82. package/src/meta-reasoning/prompts.ts +5 -44
  83. package/src/meta-reasoning/strategy-selector.ts +6 -0
  84. package/src/self-modifying-agent.ts +123 -14
  85. package/src/tool-generation/gap-analyzer.ts +3 -2
  86. package/src/tool-generation/generated-tool-store.ts +97 -10
  87. package/src/tool-generation/index.ts +1 -1
  88. package/src/tool-generation/prompts.ts +81 -12
  89. package/src/tool-generation/tool-generator.ts +71 -3
  90. package/src/tool-generation/tool-sandbox.ts +241 -170
  91. package/src/tool-generation/tool-validator.ts +51 -1
  92. package/src/utils/index.ts +29 -5
@@ -106,19 +106,23 @@ export class MetaReasoner {
106
106
  );
107
107
 
108
108
  case 'confidence_drop':
109
+ case 'on_low_confidence':
109
110
  return context.confidence < this.config.triggerOnConfidenceDrop;
110
111
 
111
112
  case 'progress_stall':
113
+ case 'on_stagnation':
112
114
  return context.stagnationCount >= this.config.triggerOnProgressStall;
113
115
 
114
- case 'periodic':
115
- return (
116
- context.iteration > 0 && context.iteration % this.config.triggerAfterIterations === 0
117
- );
116
+ case 'periodic': {
117
+ const elapsed = Date.now() - lastAssessment;
118
+ return elapsed >= this.config.metaAssessmentCooldown * this.config.triggerAfterIterations;
119
+ }
118
120
 
121
+ case 'on_failure':
119
122
  case 'tool_call_failed':
120
123
  return true;
121
124
 
125
+ case 'on_request':
122
126
  case 'explicit_request':
123
127
  return true;
124
128
 
@@ -293,34 +297,37 @@ export class MetaReasoner {
293
297
  return adaptation;
294
298
  }
295
299
 
296
- rollback(runId: string): MetaAdaptation | null {
300
+ rollback(runId: string, adaptationId?: string): MetaAdaptation | null {
297
301
  const runAdaptations = this.adaptations.get(runId) ?? [];
298
- const lastAdaptation = runAdaptations[runAdaptations.length - 1];
302
+ const target = adaptationId
303
+ ? runAdaptations.find((a) => a.id === adaptationId)
304
+ : runAdaptations[runAdaptations.length - 1];
299
305
 
300
- if (!lastAdaptation?.rollbackable) {
306
+ if (!target?.rollbackable) {
301
307
  return null;
302
308
  }
303
309
 
304
- if (lastAdaptation.rollbackDeadline && Date.now() > lastAdaptation.rollbackDeadline) {
310
+ if (target.rollbackDeadline && Date.now() > target.rollbackDeadline) {
305
311
  return null;
306
312
  }
307
313
 
308
314
  const rollback: MetaAdaptation = {
309
315
  id: `rollback_${nanoid(10)}`,
310
- assessmentId: lastAdaptation.assessmentId,
316
+ assessmentId: target.assessmentId,
311
317
  timestamp: Date.now(),
312
318
 
313
319
  type: 'rollback',
314
- before: lastAdaptation.after,
315
- after: lastAdaptation.before,
320
+ before: target.after,
321
+ after: target.before,
316
322
 
317
323
  rollbackable: false,
318
324
  };
319
325
 
320
- if (lastAdaptation.type === 'mode_switch' && lastAdaptation.before.mode) {
321
- this.currentMode.set(runId, lastAdaptation.before.mode);
326
+ if (target.type === 'mode_switch' && target.before.mode) {
327
+ this.currentMode.set(runId, target.before.mode);
322
328
  }
323
329
 
330
+ target.rollbackable = false;
324
331
  runAdaptations.push(rollback);
325
332
  return rollback;
326
333
  }
@@ -337,7 +344,7 @@ export class MetaReasoner {
337
344
  adaptation.outcome = outcome;
338
345
 
339
346
  if (this.config.rollbackOnDecline && !outcome.improved && adaptation.rollbackable) {
340
- this.rollback(runId);
347
+ this.rollback(runId, adaptationId);
341
348
  }
342
349
  }
343
350
  }
@@ -352,7 +359,7 @@ export class MetaReasoner {
352
359
  }
353
360
 
354
361
  getModeConfig(mode: ReasoningMode): ReasoningModeConfig {
355
- return this.config.modeProfiles[mode];
362
+ return this.config.modeProfiles[mode] ?? this.config.modeProfiles[this.config.defaultMode];
356
363
  }
357
364
 
358
365
  getRunStats(runId: string): {
@@ -54,7 +54,11 @@ export class ObservationCollector {
54
54
 
55
55
  collect(context: ObservationContext, insights: Insight[]): MetaObservation {
56
56
  const { runId, iteration, goal, currentMode } = context;
57
- const prevObservations = this.observations.get(runId) ?? [];
57
+ let prevObservations = this.observations.get(runId);
58
+ if (!prevObservations) {
59
+ prevObservations = [];
60
+ this.observations.set(runId, prevObservations);
61
+ }
58
62
  const lastObs = prevObservations[prevObservations.length - 1];
59
63
  const actions = this.actionHistory.get(runId) ?? [];
60
64
  const confidenceHist = this.confidenceHistory.get(runId) ?? [];
@@ -62,7 +66,7 @@ export class ObservationCollector {
62
66
  const currentConfidence = confidenceHist[confidenceHist.length - 1] ?? 0.5;
63
67
  const progressScore = this.calculateProgress(actions);
64
68
  const progressDelta = lastObs ? progressScore - lastObs.progressScore : 0;
65
- const stagnationCount = progressDelta < 0.05 ? (lastObs?.stagnationCount ?? 0) + 1 : 0;
69
+ const stagnationCount = lastObs ? (progressDelta < 0.05 ? lastObs.stagnationCount + 1 : 0) : 0;
66
70
  const repetitionScore = this.calculateRepetition(actions);
67
71
  const toolSuccessRate = this.calculateToolSuccessRate(actions);
68
72
  const confidenceTrend = this.calculateTrend(confidenceHist);
@@ -1,4 +1,5 @@
1
1
  import type { MetaObservation, ReasoningMode, ReasoningModeConfig } from '@cogitator-ai/types';
2
+ import { extractJson } from '../utils';
2
3
 
3
4
  export function buildMetaAssessmentPrompt(
4
5
  observation: MetaObservation,
@@ -62,20 +63,20 @@ Analyze the agent's reasoning process and respond with a JSON object:
62
63
  "reasoning": "string",
63
64
  "issues": [
64
65
  {
65
- "type": "stagnation" | "repetition" | "resource_exhaustion" | "confidence_decline" | "strategy_mismatch" | "goal_drift",
66
- "severity": "low" | "medium" | "high" | "critical",
66
+ "type": "stagnation" | "low_confidence" | "high_cost" | "repetition" | "tool_failure",
67
+ "severity": "low" | "medium" | "high",
67
68
  "description": "string"
68
69
  }
69
70
  ],
70
71
  "opportunities": [
71
72
  {
72
- "type": "strategy_switch" | "temperature_adjust" | "tool_pivot" | "goal_refinement" | "context_injection",
73
+ "type": "mode_switch" | "parameter_tune" | "context_add" | "tool_compose",
73
74
  "description": "string",
74
75
  "expectedImprovement": number
75
76
  }
76
77
  ],
77
78
  "recommendation": {
78
- "action": "continue" | "switch_mode" | "adjust_parameters" | "inject_context" | "escalate" | "abort",
79
+ "action": "continue" | "switch_mode" | "adjust_parameters" | "inject_context" | "abort",
79
80
  "newMode": "string",
80
81
  "parameterChanges": {},
81
82
  "contextAddition": "string",
@@ -119,46 +120,6 @@ export function parseMetaAssessmentResponse(content: string): ParsedAssessment |
119
120
  }
120
121
  }
121
122
 
122
- function extractJson(text: string): string | null {
123
- const start = text.indexOf('{');
124
- if (start === -1) return null;
125
-
126
- let depth = 0;
127
- let inString = false;
128
- let escape = false;
129
-
130
- for (let i = start; i < text.length; i++) {
131
- const ch = text[i];
132
-
133
- if (escape) {
134
- escape = false;
135
- continue;
136
- }
137
-
138
- if (ch === '\\' && inString) {
139
- escape = true;
140
- continue;
141
- }
142
-
143
- if (ch === '"') {
144
- inString = !inString;
145
- continue;
146
- }
147
-
148
- if (inString) continue;
149
-
150
- if (ch === '{') depth++;
151
- else if (ch === '}') {
152
- depth--;
153
- if (depth === 0) {
154
- return text.slice(start, i + 1);
155
- }
156
- }
157
- }
158
-
159
- return null;
160
- }
161
-
162
123
  export const META_REASONING_SYSTEM_PROMPT = `You are a meta-reasoning system analyzing an AI agent's reasoning process.
163
124
  Your job is to assess whether the agent is on track and recommend strategic adjustments.
164
125
 
@@ -143,6 +143,12 @@ export class StrategySelector {
143
143
  if (currentMode === 'intuitive' && alternatives.includes('analytical')) {
144
144
  return 'analytical';
145
145
  }
146
+ if (currentMode === 'reflective' && alternatives.includes('intuitive')) {
147
+ return 'intuitive';
148
+ }
149
+ if (currentMode === 'exploratory' && alternatives.includes('analytical')) {
150
+ return 'analytical';
151
+ }
146
152
 
147
153
  return alternatives[0] ?? null;
148
154
  }
@@ -1,3 +1,4 @@
1
+ import { nanoid } from 'nanoid';
1
2
  import type {
2
3
  Agent,
3
4
  AgentConfig,
@@ -9,6 +10,8 @@ import type {
9
10
  MetaObservation,
10
11
  MetaAdaptation,
11
12
  ModificationCheckpoint,
13
+ AppliedModification,
14
+ ModificationRequest,
12
15
  SelfModifyingEvent,
13
16
  CapabilityGap,
14
17
  Message,
@@ -44,6 +47,8 @@ export interface RunContext {
44
47
  observations: MetaObservation[];
45
48
  adaptations: MetaAdaptation[];
46
49
  checkpoints: ModificationCheckpoint[];
50
+ modificationsCount: number;
51
+ appliedModifications: AppliedModification[];
47
52
  }
48
53
 
49
54
  export class SelfModifyingAgent {
@@ -63,6 +68,7 @@ export class SelfModifyingAgent {
63
68
 
64
69
  private currentContext: RunContext | null = null;
65
70
  private isInitialized = false;
71
+ private storedExecutableTools: Tool[] = [];
66
72
 
67
73
  constructor(options: SelfModifyingAgentOptions) {
68
74
  this.agent = options.agent;
@@ -145,7 +151,7 @@ export class SelfModifyingAgent {
145
151
  const tools = this.getAvailableTools();
146
152
 
147
153
  const baseConfig: ArchitectureConfig = {
148
- model: 'default',
154
+ model: this.agent.model ?? 'default',
149
155
  temperature: 0.7,
150
156
  maxTokens: 4096,
151
157
  toolStrategy: 'sequential',
@@ -162,6 +168,8 @@ export class SelfModifyingAgent {
162
168
  observations: [],
163
169
  adaptations: [],
164
170
  checkpoints: [],
171
+ modificationsCount: 0,
172
+ appliedModifications: [],
165
173
  };
166
174
 
167
175
  void this.emitter.emit({
@@ -172,6 +180,10 @@ export class SelfModifyingAgent {
172
180
  });
173
181
 
174
182
  try {
183
+ if (this.config.constraints.enabled && this.config.constraints.autoRollback) {
184
+ await this.createCheckpoint();
185
+ }
186
+
175
187
  if (this.config.architectureEvolution.enabled) {
176
188
  await this.optimizeArchitecture(input);
177
189
  }
@@ -215,6 +227,10 @@ export class SelfModifyingAgent {
215
227
 
216
228
  return result;
217
229
  } catch (error) {
230
+ if (this.config.constraints.enabled && this.config.constraints.autoRollback) {
231
+ await this.autoRollbackOnError();
232
+ }
233
+
218
234
  void this.emitter.emit({
219
235
  type: 'run_completed',
220
236
  runId,
@@ -301,7 +317,7 @@ export class SelfModifyingAgent {
301
317
  this.agent.name || 'agent',
302
318
  agentConfig,
303
319
  this.currentContext.tools,
304
- []
320
+ [...this.currentContext.appliedModifications]
305
321
  );
306
322
 
307
323
  this.currentContext.checkpoints.push(checkpoint);
@@ -322,6 +338,13 @@ export class SelfModifyingAgent {
322
338
 
323
339
  if (this.currentContext) {
324
340
  this.currentContext.tools = restored.tools;
341
+ this.currentContext.currentConfig = {
342
+ ...this.currentContext.currentConfig,
343
+ model: restored.agentConfig.model ?? this.currentContext.currentConfig.model,
344
+ temperature:
345
+ restored.agentConfig.temperature ?? this.currentContext.currentConfig.temperature,
346
+ maxTokens: restored.agentConfig.maxTokens ?? this.currentContext.currentConfig.maxTokens,
347
+ };
325
348
  }
326
349
 
327
350
  void this.emitter.emit({
@@ -340,7 +363,8 @@ export class SelfModifyingAgent {
340
363
  private async ensureInitialized(): Promise<void> {
341
364
  if (this.isInitialized) return;
342
365
 
343
- await this.toolStore.list({ status: 'active' });
366
+ const activeTools = await this.toolStore.list({ status: 'active' });
367
+ this.storedExecutableTools = activeTools.map((t) => this.toolGenerator.createExecutableTool(t));
344
368
 
345
369
  this.isInitialized = true;
346
370
  }
@@ -447,7 +471,7 @@ export class SelfModifyingAgent {
447
471
  }
448
472
 
449
473
  private getAvailableTools(): Tool[] {
450
- return this.agent.tools ?? [];
474
+ return [...(this.agent.tools ?? []), ...this.storedExecutableTools];
451
475
  }
452
476
 
453
477
  private async optimizeArchitecture(input: string): Promise<void> {
@@ -456,22 +480,24 @@ export class SelfModifyingAgent {
456
480
  try {
457
481
  const result = await this.parameterOptimizer.optimize(input);
458
482
 
459
- if (result.shouldAdopt && result.confidence > 0.6) {
460
- const validation = await this.modificationValidator.validate({
483
+ if (result.shouldAdopt && result.confidence > 0.6 && this.canApplyModification()) {
484
+ const validation = await this.validateModification({
461
485
  type: 'config_change',
462
486
  target: 'architecture',
463
487
  changes: result.recommendedConfig,
464
488
  reason: result.reasoning,
465
489
  });
466
490
 
467
- if (validation.valid) {
491
+ if (validation) {
468
492
  this.currentContext.currentConfig = result.recommendedConfig;
493
+ this.recordModification('config_change', result.recommendedConfig);
469
494
 
470
495
  void this.emitter.emit({
471
496
  type: 'architecture_evolved',
472
497
  runId: this.currentContext.runId,
473
498
  timestamp: new Date(),
474
499
  data: {
500
+ success: true,
475
501
  candidateId: result.candidate?.id,
476
502
  changes: result.recommendedConfig,
477
503
  metrics: result.metrics,
@@ -484,7 +510,10 @@ export class SelfModifyingAgent {
484
510
  type: 'architecture_evolved',
485
511
  runId: this.currentContext.runId,
486
512
  timestamp: new Date(),
487
- data: { error: error instanceof Error ? error.message : String(error) },
513
+ data: {
514
+ success: false,
515
+ error: error instanceof Error ? error.message : String(error),
516
+ },
488
517
  });
489
518
  }
490
519
  }
@@ -496,6 +525,12 @@ export class SelfModifyingAgent {
496
525
  const analysis = await this.gapAnalyzer.analyze(input, this.currentContext.tools);
497
526
 
498
527
  for (const gap of analysis.gaps) {
528
+ if (
529
+ this.currentContext.generatedTools.length >= this.config.toolGeneration.maxToolsPerSession
530
+ ) {
531
+ break;
532
+ }
533
+
499
534
  if (gap.confidence >= this.config.toolGeneration.minConfidenceForGeneration) {
500
535
  void this.emitter.emit({
501
536
  type: 'tool_generation_started',
@@ -506,11 +541,41 @@ export class SelfModifyingAgent {
506
541
 
507
542
  const tool = await this.generateTool(gap);
508
543
 
509
- if (tool) {
510
- this.currentContext.generatedTools.push(tool);
511
- const executableTool = this.toolGenerator.createExecutableTool(tool);
512
- this.currentContext.tools.push(executableTool);
544
+ if (!tool) continue;
545
+
546
+ const linesOfCode = tool.implementation.split('\n').length;
547
+ const validated = await this.validateModification({
548
+ type: 'tool_generation',
549
+ target: tool.name,
550
+ changes: { name: tool.name, implementation: tool.implementation },
551
+ reason: `Generated tool for gap: ${gap.suggestedToolName}`,
552
+ payload: {
553
+ sandboxExecution: this.config.toolGeneration.sandboxConfig?.enabled ?? false,
554
+ linesOfCode,
555
+ complexity: linesOfCode,
556
+ modificationDepth: 1,
557
+ },
558
+ });
559
+
560
+ if (!validated || !this.canApplyModification()) {
561
+ void this.emitter.emit({
562
+ type: 'tool_generation_completed',
563
+ runId: this.currentContext.runId,
564
+ timestamp: new Date(),
565
+ data: {
566
+ toolId: tool.id,
567
+ name: tool.name,
568
+ success: false,
569
+ error: 'Rejected by safety constraints or modification limit',
570
+ },
571
+ });
572
+ continue;
513
573
  }
574
+
575
+ this.currentContext.generatedTools.push(tool);
576
+ const executableTool = this.toolGenerator.createExecutableTool(tool);
577
+ this.currentContext.tools.push(executableTool);
578
+ this.recordModification('tool_generation', { toolId: tool.id, name: tool.name });
514
579
  }
515
580
  }
516
581
  } catch (error) {
@@ -693,6 +758,49 @@ export class SelfModifyingAgent {
693
758
  });
694
759
  }
695
760
 
761
+ private async validateModification(request: ModificationRequest): Promise<boolean> {
762
+ if (!this.config.constraints.enabled) return true;
763
+
764
+ const validation = await this.modificationValidator.validate(request);
765
+
766
+ if (validation.rollbackRequired && this.config.constraints.autoRollback) {
767
+ await this.autoRollbackOnError();
768
+ }
769
+
770
+ return validation.valid;
771
+ }
772
+
773
+ private canApplyModification(): boolean {
774
+ if (!this.config.constraints.enabled) return true;
775
+ if (!this.currentContext) return true;
776
+ return this.currentContext.modificationsCount < this.config.constraints.maxModificationsPerRun;
777
+ }
778
+
779
+ private recordModification(type: string, data: unknown): void {
780
+ if (!this.currentContext) return;
781
+ this.currentContext.modificationsCount++;
782
+ this.currentContext.appliedModifications.push({
783
+ id: `mod_${nanoid(8)}`,
784
+ type,
785
+ appliedAt: new Date(),
786
+ data,
787
+ });
788
+ }
789
+
790
+ private async autoRollbackOnError(): Promise<void> {
791
+ if (!this.currentContext) return;
792
+
793
+ const now = Date.now();
794
+ const window = this.config.constraints.rollbackWindow;
795
+ const target = this.currentContext.checkpoints
796
+ .filter((c) => now - c.timestamp.getTime() <= window)
797
+ .sort((a, b) => b.timestamp.getTime() - a.timestamp.getTime())[0];
798
+
799
+ if (target) {
800
+ await this.rollbackToCheckpoint(target.id);
801
+ }
802
+ }
803
+
696
804
  private estimateConfidence(output: string): number {
697
805
  if (!output) return 0.3;
698
806
  if (output.length < 50) return 0.4;
@@ -700,7 +808,8 @@ export class SelfModifyingAgent {
700
808
  return 0.8;
701
809
  }
702
810
 
703
- private isTaskComplete(_output: string): boolean {
704
- return true;
811
+ private isTaskComplete(output: string): boolean {
812
+ if (!output.trim()) return false;
813
+ return this.estimateConfidence(output) >= 0.6;
705
814
  }
706
815
  }
@@ -1,3 +1,4 @@
1
+ import { createHash } from 'node:crypto';
1
2
  import type {
2
3
  Tool,
3
4
  LLMBackend,
@@ -151,7 +152,6 @@ Consider tool composition before suggesting new tools.`,
151
152
  return 1.0;
152
153
  }
153
154
 
154
- const _intentWords = userIntent.toLowerCase().split(/\s+/).length;
155
155
  const toolDescriptionWords = availableTools
156
156
  .map((t) => t.description.toLowerCase().split(/\s+/))
157
157
  .flat();
@@ -222,7 +222,8 @@ Consider tool composition before suggesting new tools.`,
222
222
  .map((t) => t.name)
223
223
  .sort()
224
224
  .join(',');
225
- return `${userIntent.slice(0, 100)}|${toolSignature}`;
225
+ const raw = `${userIntent}|${toolSignature}`;
226
+ return createHash('sha256').update(raw).digest('hex');
226
227
  }
227
228
 
228
229
  clearCache(): void {
@@ -1,5 +1,78 @@
1
1
  import type { GeneratedTool, GeneratedToolStore as IGeneratedToolStore } from '@cogitator-ai/types';
2
2
 
3
+ const STOP_WORDS = new Set([
4
+ 'the',
5
+ 'and',
6
+ 'for',
7
+ 'not',
8
+ 'are',
9
+ 'was',
10
+ 'were',
11
+ 'been',
12
+ 'being',
13
+ 'have',
14
+ 'has',
15
+ 'had',
16
+ 'does',
17
+ 'did',
18
+ 'will',
19
+ 'would',
20
+ 'could',
21
+ 'should',
22
+ 'may',
23
+ 'might',
24
+ 'shall',
25
+ 'can',
26
+ 'this',
27
+ 'that',
28
+ 'these',
29
+ 'those',
30
+ 'with',
31
+ 'from',
32
+ 'into',
33
+ 'through',
34
+ 'during',
35
+ 'before',
36
+ 'after',
37
+ 'above',
38
+ 'below',
39
+ 'between',
40
+ 'under',
41
+ 'over',
42
+ 'again',
43
+ 'further',
44
+ 'then',
45
+ 'once',
46
+ 'here',
47
+ 'there',
48
+ 'when',
49
+ 'where',
50
+ 'why',
51
+ 'how',
52
+ 'all',
53
+ 'each',
54
+ 'every',
55
+ 'both',
56
+ 'few',
57
+ 'more',
58
+ 'most',
59
+ 'other',
60
+ 'some',
61
+ 'such',
62
+ 'only',
63
+ 'own',
64
+ 'same',
65
+ 'than',
66
+ 'too',
67
+ 'very',
68
+ 'just',
69
+ 'because',
70
+ 'but',
71
+ 'nor',
72
+ 'yet',
73
+ 'about',
74
+ ]);
75
+
3
76
  export interface ToolUsageRecord {
4
77
  toolId: string;
5
78
  timestamp: Date;
@@ -25,7 +98,7 @@ export class InMemoryGeneratedToolStore implements IGeneratedToolStore {
25
98
 
26
99
  async save(tool: GeneratedTool): Promise<void> {
27
100
  const existing = this.tools.get(tool.id);
28
- const version = existing ? existing.version + 1 : tool.version;
101
+ const version = existing ? existing.version + 1 : 1;
29
102
  this.tools.set(tool.id, { ...tool, version, updatedAt: new Date() });
30
103
  }
31
104
 
@@ -140,17 +213,27 @@ export class InMemoryGeneratedToolStore implements IGeneratedToolStore {
140
213
  }
141
214
 
142
215
  async findSimilar(description: string, limit: number = 5): Promise<GeneratedTool[]> {
143
- const descWords = new Set(description.toLowerCase().split(/\s+/));
216
+ const descWords = new Set(
217
+ description
218
+ .toLowerCase()
219
+ .split(/\s+/)
220
+ .filter((w) => w.length >= 3 && !STOP_WORDS.has(w))
221
+ );
144
222
  const scored: Array<{ tool: GeneratedTool; score: number }> = [];
145
223
 
146
224
  for (const tool of this.tools.values()) {
147
225
  if (tool.status === 'deprecated') continue;
148
226
 
149
- const toolWords = new Set(`${tool.name} ${tool.description}`.toLowerCase().split(/\s+/));
227
+ const toolWords = new Set(
228
+ `${tool.name} ${tool.description}`
229
+ .toLowerCase()
230
+ .split(/\s+/)
231
+ .filter((w) => w.length >= 3 && !STOP_WORDS.has(w))
232
+ );
150
233
 
151
234
  let matchCount = 0;
152
235
  for (const word of descWords) {
153
- if (word.length >= 3 && toolWords.has(word)) {
236
+ if (toolWords.has(word)) {
154
237
  matchCount++;
155
238
  }
156
239
  }
@@ -204,13 +287,13 @@ export class InMemoryGeneratedToolStore implements IGeneratedToolStore {
204
287
  let removed = 0;
205
288
  const now = Date.now();
206
289
 
290
+ const keysToRemove: string[] = [];
291
+
207
292
  for (const [id, tool] of this.tools) {
208
293
  if (options.maxAge && tool.createdAt) {
209
294
  const age = now - tool.createdAt.getTime();
210
295
  if (age > options.maxAge && tool.status !== 'active') {
211
- this.tools.delete(id);
212
- this.usageRecords.delete(id);
213
- removed++;
296
+ keysToRemove.push(id);
214
297
  continue;
215
298
  }
216
299
  }
@@ -218,13 +301,17 @@ export class InMemoryGeneratedToolStore implements IGeneratedToolStore {
218
301
  if (options.minUsage !== undefined) {
219
302
  const usage = tool.usageCount || 0;
220
303
  if (usage < options.minUsage && tool.status === 'deprecated') {
221
- this.tools.delete(id);
222
- this.usageRecords.delete(id);
223
- removed++;
304
+ keysToRemove.push(id);
224
305
  }
225
306
  }
226
307
  }
227
308
 
309
+ for (const id of keysToRemove) {
310
+ this.tools.delete(id);
311
+ this.usageRecords.delete(id);
312
+ removed++;
313
+ }
314
+
228
315
  if (options.maxDeprecated !== undefined) {
229
316
  const deprecated = Array.from(this.tools.values())
230
317
  .filter((t) => t.status === 'deprecated')
@@ -1,7 +1,7 @@
1
1
  export { GapAnalyzer, type GapAnalyzerOptions } from './gap-analyzer';
2
2
  export { ToolGenerator, type ToolGeneratorOptions, type GenerationResult } from './tool-generator';
3
3
  export { ToolValidator, type ToolValidatorOptions } from './tool-validator';
4
- export { ToolSandbox, DEFAULT_SANDBOX_CONFIG } from './tool-sandbox';
4
+ export { ToolSandbox, DEFAULT_SANDBOX_CONFIG, deepEqual } from './tool-sandbox';
5
5
  export {
6
6
  InMemoryGeneratedToolStore,
7
7
  type ToolUsageRecord,