@cogitator-ai/self-modifying 17.0.5 → 17.0.10

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 (85) hide show
  1. package/README.md +42 -1
  2. package/dist/architecture-evolution/capability-analyzer.d.ts +1 -1
  3. package/dist/architecture-evolution/capability-analyzer.d.ts.map +1 -1
  4. package/dist/architecture-evolution/capability-analyzer.js +4 -3
  5. package/dist/architecture-evolution/capability-analyzer.js.map +1 -1
  6. package/dist/architecture-evolution/evolution-strategy.d.ts.map +1 -1
  7. package/dist/architecture-evolution/evolution-strategy.js +3 -2
  8. package/dist/architecture-evolution/evolution-strategy.js.map +1 -1
  9. package/dist/architecture-evolution/parameter-optimizer.d.ts +1 -0
  10. package/dist/architecture-evolution/parameter-optimizer.d.ts.map +1 -1
  11. package/dist/architecture-evolution/parameter-optimizer.js +7 -4
  12. package/dist/architecture-evolution/parameter-optimizer.js.map +1 -1
  13. package/dist/architecture-evolution/prompts.d.ts.map +1 -1
  14. package/dist/architecture-evolution/prompts.js +7 -6
  15. package/dist/architecture-evolution/prompts.js.map +1 -1
  16. package/dist/constraints/index.d.ts +1 -1
  17. package/dist/constraints/index.d.ts.map +1 -1
  18. package/dist/constraints/index.js +1 -1
  19. package/dist/constraints/index.js.map +1 -1
  20. package/dist/constraints/modification-validator.d.ts.map +1 -1
  21. package/dist/constraints/modification-validator.js +13 -22
  22. package/dist/constraints/modification-validator.js.map +1 -1
  23. package/dist/constraints/safety-constraints.d.ts +2 -1
  24. package/dist/constraints/safety-constraints.d.ts.map +1 -1
  25. package/dist/constraints/safety-constraints.js +11 -1
  26. package/dist/constraints/safety-constraints.js.map +1 -1
  27. package/dist/events/event-emitter.d.ts.map +1 -1
  28. package/dist/events/event-emitter.js +8 -1
  29. package/dist/events/event-emitter.js.map +1 -1
  30. package/dist/index.d.ts +2 -1
  31. package/dist/index.d.ts.map +1 -1
  32. package/dist/index.js +2 -1
  33. package/dist/index.js.map +1 -1
  34. package/dist/meta-reasoning/meta-reasoner.d.ts.map +1 -1
  35. package/dist/meta-reasoning/meta-reasoner.js +6 -0
  36. package/dist/meta-reasoning/meta-reasoner.js.map +1 -1
  37. package/dist/meta-reasoning/prompts.d.ts.map +1 -1
  38. package/dist/meta-reasoning/prompts.js +37 -3
  39. package/dist/meta-reasoning/prompts.js.map +1 -1
  40. package/dist/self-modifying-agent.d.ts +1 -1
  41. package/dist/self-modifying-agent.d.ts.map +1 -1
  42. package/dist/self-modifying-agent.js +57 -10
  43. package/dist/self-modifying-agent.js.map +1 -1
  44. package/dist/tool-generation/generated-tool-store.d.ts.map +1 -1
  45. package/dist/tool-generation/generated-tool-store.js +2 -4
  46. package/dist/tool-generation/generated-tool-store.js.map +1 -1
  47. package/dist/tool-generation/prompts.d.ts.map +1 -1
  48. package/dist/tool-generation/prompts.js +10 -9
  49. package/dist/tool-generation/prompts.js.map +1 -1
  50. package/dist/tool-generation/tool-generator.d.ts +1 -1
  51. package/dist/tool-generation/tool-generator.d.ts.map +1 -1
  52. package/dist/tool-generation/tool-generator.js +12 -13
  53. package/dist/tool-generation/tool-generator.js.map +1 -1
  54. package/dist/tool-generation/tool-sandbox.d.ts.map +1 -1
  55. package/dist/tool-generation/tool-sandbox.js +6 -2
  56. package/dist/tool-generation/tool-sandbox.js.map +1 -1
  57. package/dist/utils/index.d.ts +1 -0
  58. package/dist/utils/index.d.ts.map +1 -1
  59. package/dist/utils/index.js +34 -0
  60. package/dist/utils/index.js.map +1 -1
  61. package/dist/utils/llm-helper.d.ts +1 -0
  62. package/dist/utils/llm-helper.d.ts.map +1 -1
  63. package/dist/utils/llm-helper.js +1 -1
  64. package/dist/utils/llm-helper.js.map +1 -1
  65. package/package.json +1 -1
  66. package/src/__tests__/events.test.ts +112 -0
  67. package/src/__tests__/utils.test.ts +100 -0
  68. package/src/architecture-evolution/capability-analyzer.ts +5 -3
  69. package/src/architecture-evolution/evolution-strategy.ts +3 -2
  70. package/src/architecture-evolution/parameter-optimizer.ts +8 -7
  71. package/src/architecture-evolution/prompts.ts +7 -6
  72. package/src/constraints/index.ts +1 -0
  73. package/src/constraints/modification-validator.ts +14 -23
  74. package/src/constraints/safety-constraints.ts +16 -1
  75. package/src/events/event-emitter.ts +9 -1
  76. package/src/index.ts +3 -0
  77. package/src/meta-reasoning/meta-reasoner.ts +9 -0
  78. package/src/meta-reasoning/prompts.ts +43 -3
  79. package/src/self-modifying-agent.ts +58 -10
  80. package/src/tool-generation/generated-tool-store.ts +2 -4
  81. package/src/tool-generation/prompts.ts +10 -9
  82. package/src/tool-generation/tool-generator.ts +13 -15
  83. package/src/tool-generation/tool-sandbox.ts +12 -2
  84. package/src/utils/index.ts +40 -0
  85. package/src/utils/llm-helper.ts +2 -2
@@ -7,7 +7,7 @@ import type {
7
7
  EvolutionMetrics,
8
8
  } from '@cogitator-ai/types';
9
9
  import { CapabilityAnalyzer } from './capability-analyzer';
10
- import { EvolutionStrategy, type SelectionResult as _SelectionResult } from './evolution-strategy';
10
+ import { EvolutionStrategy } from './evolution-strategy';
11
11
  import {
12
12
  buildCandidateGenerationPrompt,
13
13
  buildPerformanceAnalysisPrompt,
@@ -48,6 +48,7 @@ export class ParameterOptimizer {
48
48
  private candidates: EvolutionCandidate[] = [];
49
49
  private history: HistoricalRecord[] = [];
50
50
  private currentGeneration = 0;
51
+ private lastEvolutionTimestamp = 0;
51
52
  private readonly maxHistorySize = 100;
52
53
 
53
54
  constructor(options: ParameterOptimizerOptions) {
@@ -173,6 +174,7 @@ export class ParameterOptimizer {
173
174
 
174
175
  private async evolve(currentProfile: TaskProfile): Promise<void> {
175
176
  this.currentGeneration++;
177
+ this.lastEvolutionTimestamp = Date.now();
176
178
 
177
179
  const topCandidates = [...this.candidates]
178
180
  .filter((c) => c.evaluationCount > 0)
@@ -325,10 +327,7 @@ export class ParameterOptimizer {
325
327
  }
326
328
 
327
329
  private getLastEvolutionTime(): number {
328
- const latestGenCandidate = this.candidates.find(
329
- (c) => c.generation === this.currentGeneration && c.evaluationCount === 0
330
- );
331
- return latestGenCandidate ? Date.now() - 300000 : 0;
330
+ return this.lastEvolutionTimestamp;
332
331
  }
333
332
 
334
333
  private getRelevantHistory(profile: TaskProfile): HistoricalRecord[] {
@@ -410,7 +409,7 @@ export class ParameterOptimizer {
410
409
  fields++;
411
410
  }
412
411
 
413
- if (a.model !== b.model) {
412
+ if (a.model !== undefined && b.model !== undefined && a.model !== b.model) {
414
413
  distance += 1;
415
414
  fields++;
416
415
  }
@@ -447,8 +446,9 @@ export class ParameterOptimizer {
447
446
  if (evaluatedCandidates.length === 0) return null;
448
447
 
449
448
  const results = evaluatedCandidates.map((c) => {
449
+ const configKey = JSON.stringify(c.config, Object.keys(c.config).sort());
450
450
  const records = this.history.filter(
451
- (h) => JSON.stringify(h.config) === JSON.stringify(c.config)
451
+ (h) => JSON.stringify(h.config, Object.keys(h.config).sort()) === configKey
452
452
  );
453
453
  const avgMetrics =
454
454
  records.length > 0
@@ -503,6 +503,7 @@ export class ParameterOptimizer {
503
503
  this.candidates = [];
504
504
  this.history = [];
505
505
  this.currentGeneration = 0;
506
+ this.lastEvolutionTimestamp = 0;
506
507
  this.evolutionStrategy.reset();
507
508
  }
508
509
  }
@@ -1,4 +1,5 @@
1
1
  import type { TaskProfile, ArchitectureConfig, EvolutionCandidate } from '@cogitator-ai/types';
2
+ import { extractJson } from '../utils';
2
3
 
3
4
  export const ARCHITECTURE_ANALYSIS_SYSTEM_PROMPT = `You are an expert in AI agent architecture optimization.
4
5
  Your task is to analyze tasks and recommend optimal configurations.
@@ -140,11 +141,11 @@ Respond with:
140
141
  }
141
142
 
142
143
  export function parseTaskProfileResponse(response: string): TaskProfile | null {
143
- const jsonMatch = /\{[\s\S]*\}/.exec(response);
144
- if (!jsonMatch) return null;
144
+ const json = extractJson(response);
145
+ if (!json) return null;
145
146
 
146
147
  try {
147
- const parsed = JSON.parse(jsonMatch[0]);
148
+ const parsed = JSON.parse(json);
148
149
 
149
150
  return {
150
151
  complexity: parsed.complexity || 'moderate',
@@ -197,11 +198,11 @@ export function parsePerformanceAnalysisResponse(response: string): {
197
198
  shouldAdopt: boolean;
198
199
  analysis: string;
199
200
  } | null {
200
- const jsonMatch = /\{[\s\S]*\}/.exec(response);
201
- if (!jsonMatch) return null;
201
+ const json = extractJson(response);
202
+ if (!json) return null;
202
203
 
203
204
  try {
204
- const parsed = JSON.parse(jsonMatch[0]);
205
+ const parsed = JSON.parse(json);
205
206
 
206
207
  return {
207
208
  recommendation: String(parsed.recommendation || ''),
@@ -6,6 +6,7 @@ export {
6
6
  mergeSafetyConstraints,
7
7
  mergeCapabilityConstraints,
8
8
  mergeResourceConstraints,
9
+ mergeCustomConstraints,
9
10
  mergeConstraints,
10
11
  } from './safety-constraints';
11
12
 
@@ -92,23 +92,7 @@ export class ModificationValidator {
92
92
  return this.evaluateExpression(rule, request.payload as Record<string, unknown>);
93
93
  }
94
94
 
95
- const payload = request.payload as Record<string, unknown>;
96
-
97
- switch (rule.type) {
98
- case 'invariant':
99
- return this.evaluateExpression(rule.expression ?? '', payload);
100
- case 'precondition':
101
- return this.evaluateExpression(rule.expression ?? '', payload);
102
- case 'postcondition':
103
- return true;
104
- case 'temporal':
105
- if (rule.pattern?.source === 'never') {
106
- return !this.evaluateExpression(rule.expression ?? '', payload);
107
- }
108
- return true;
109
- default:
110
- return true;
111
- }
95
+ return this.evaluateExpression(rule.expression ?? '', request.payload as Record<string, unknown>);
112
96
  }
113
97
 
114
98
  private evaluateExpression(expression: string, context: Record<string, unknown>): boolean {
@@ -127,16 +111,18 @@ export class ModificationValidator {
127
111
 
128
112
  if (conditions.length === 0) return true;
129
113
 
130
- let result = conditions[0];
114
+ const orGroups: boolean[][] = [[]];
115
+ orGroups[0].push(conditions[0]);
116
+
131
117
  for (let i = 0; i < operators.length; i++) {
132
118
  if (operators[i] === 'AND') {
133
- result = result && conditions[i + 1];
119
+ orGroups[orGroups.length - 1].push(conditions[i + 1]);
134
120
  } else {
135
- result = result || conditions[i + 1];
121
+ orGroups.push([conditions[i + 1]]);
136
122
  }
137
123
  }
138
124
 
139
- return result;
125
+ return orGroups.some((group) => group.every(Boolean));
140
126
  }
141
127
 
142
128
  private evaluateSimpleCondition(condition: string, context: Record<string, unknown>): boolean {
@@ -238,7 +224,7 @@ export class ModificationValidator {
238
224
  request: ModificationRequest
239
225
  ): Promise<ConstraintCheckResult[]> {
240
226
  const results: ConstraintCheckResult[] = [];
241
- const payload = request.payload as {
227
+ const payload = (request.payload ?? {}) as {
242
228
  tokensUsed?: number;
243
229
  cost?: number;
244
230
  activeTools?: number;
@@ -384,6 +370,11 @@ export class ModificationValidator {
384
370
  }
385
371
 
386
372
  getConstraints(): ModificationConstraints {
387
- return { ...this.constraints };
373
+ return {
374
+ safety: [...this.constraints.safety],
375
+ capability: [...this.constraints.capability],
376
+ resource: [...this.constraints.resource],
377
+ custom: this.constraints.custom ? [...this.constraints.custom] : [],
378
+ };
388
379
  }
389
380
  }
@@ -2,6 +2,7 @@ import type {
2
2
  SafetyConstraint,
3
3
  CapabilityConstraint,
4
4
  ResourceConstraint,
5
+ CustomConstraint,
5
6
  ModificationConstraints,
6
7
  } from '@cogitator-ai/types';
7
8
  import { DEFAULT_SAFETY_CONSTRAINTS } from '@cogitator-ai/types';
@@ -84,6 +85,20 @@ export function mergeResourceConstraints(
84
85
  return [...result.values()];
85
86
  }
86
87
 
88
+ export function mergeCustomConstraints(
89
+ base: CustomConstraint[],
90
+ additions: CustomConstraint[]
91
+ ): CustomConstraint[] {
92
+ const result = new Map<string, CustomConstraint>();
93
+ for (const c of base) {
94
+ result.set(c.id, c);
95
+ }
96
+ for (const c of additions) {
97
+ result.set(c.id, c);
98
+ }
99
+ return [...result.values()];
100
+ }
101
+
87
102
  export function mergeConstraints(
88
103
  base: ModificationConstraints,
89
104
  additions: Partial<ModificationConstraints>
@@ -96,6 +111,6 @@ export function mergeConstraints(
96
111
  resource: additions.resource
97
112
  ? mergeResourceConstraints(base.resource, additions.resource)
98
113
  : base.resource,
99
- custom: [...(base.custom ?? []), ...(additions.custom ?? [])],
114
+ custom: mergeCustomConstraints(base.custom ?? [], additions.custom ?? []),
100
115
  };
101
116
  }
@@ -30,7 +30,15 @@ export class SelfModifyingEventEmitter {
30
30
  ...(wildcardHandlers ? [...wildcardHandlers] : []),
31
31
  ];
32
32
 
33
- await Promise.all(allHandlers.map((h) => Promise.resolve(h(event))));
33
+ await Promise.allSettled(
34
+ allHandlers.map((h) => {
35
+ try {
36
+ return Promise.resolve(h(event));
37
+ } catch (e) {
38
+ return Promise.reject(e instanceof Error ? e : new Error(String(e)));
39
+ }
40
+ })
41
+ );
34
42
  }
35
43
 
36
44
  createEvent(
package/src/index.ts CHANGED
@@ -67,6 +67,7 @@ export {
67
67
  mergeSafetyConstraints,
68
68
  mergeCapabilityConstraints,
69
69
  mergeResourceConstraints,
70
+ mergeCustomConstraints,
70
71
  type ModificationValidatorOptions,
71
72
  type RollbackManagerOptions,
72
73
  type CheckpointStore,
@@ -75,6 +76,8 @@ export {
75
76
 
76
77
  export { SelfModifyingEventEmitter, type SelfModifyingEventHandler } from './events';
77
78
 
79
+ export { llmChat, extractJson } from './utils';
80
+
78
81
  export type {
79
82
  SelfModifyingConfig,
80
83
  ToolSelfGenerationConfig,
@@ -111,6 +111,9 @@ export class MetaReasoner {
111
111
  case 'progress_stall':
112
112
  return context.stagnationCount >= this.config.triggerOnProgressStall;
113
113
 
114
+ case 'periodic':
115
+ return context.iteration > 0 && context.iteration % this.config.triggerAfterIterations === 0;
116
+
114
117
  case 'tool_call_failed':
115
118
  return true;
116
119
 
@@ -165,12 +168,17 @@ export class MetaReasoner {
165
168
 
166
169
  recommendation: this.buildRecommendation(parsed, observation),
167
170
 
171
+ requiresAdaptation:
172
+ parsed?.recommendation?.action !== undefined &&
173
+ parsed?.recommendation?.action !== 'continue',
174
+
168
175
  assessmentDuration: Date.now() - startTime,
169
176
  assessmentCost: (response.usage?.outputTokens ?? 0) * 0.00001,
170
177
  };
171
178
 
172
179
  const runAssessments = this.assessments.get(observation.runId) ?? [];
173
180
  runAssessments.push(assessment);
181
+ this.assessments.set(observation.runId, runAssessments);
174
182
  this.lastAssessmentTime.set(observation.runId, Date.now());
175
183
 
176
184
  return assessment;
@@ -277,6 +285,7 @@ export class MetaReasoner {
277
285
 
278
286
  const runAdaptations = this.adaptations.get(runId) ?? [];
279
287
  runAdaptations.push(adaptation);
288
+ this.adaptations.set(runId, runAdaptations);
280
289
  this.lastAdaptationTime.set(runId, Date.now());
281
290
 
282
291
  return adaptation;
@@ -111,14 +111,54 @@ export interface ParsedAssessment {
111
111
 
112
112
  export function parseMetaAssessmentResponse(content: string): ParsedAssessment | null {
113
113
  try {
114
- const jsonMatch = /\{[\s\S]*\}/.exec(content);
115
- if (!jsonMatch) return null;
116
- return JSON.parse(jsonMatch[0]) as ParsedAssessment;
114
+ const json = extractJson(content);
115
+ if (!json) return null;
116
+ return JSON.parse(json) as ParsedAssessment;
117
117
  } catch {
118
118
  return null;
119
119
  }
120
120
  }
121
121
 
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
+
122
162
  export const META_REASONING_SYSTEM_PROMPT = `You are a meta-reasoning system analyzing an AI agent's reasoning process.
123
163
  Your job is to assess whether the agent is on track and recommend strategic adjustments.
124
164
 
@@ -54,7 +54,7 @@ export class SelfModifyingAgent {
54
54
  private readonly toolStore: InMemoryGeneratedToolStore;
55
55
  private readonly metaReasoner: MetaReasoner;
56
56
  private readonly parameterOptimizer: ParameterOptimizer;
57
- private readonly _capabilityAnalyzer: CapabilityAnalyzer;
57
+ private readonly capabilityAnalyzer: CapabilityAnalyzer;
58
58
  private readonly modificationValidator: ModificationValidator;
59
59
  private readonly rollbackManager: RollbackManager;
60
60
 
@@ -91,7 +91,7 @@ export class SelfModifyingAgent {
91
91
  baseConfig: baseArchConfig,
92
92
  });
93
93
 
94
- this._capabilityAnalyzer = new CapabilityAnalyzer({
94
+ this.capabilityAnalyzer = new CapabilityAnalyzer({
95
95
  llm: this.llm,
96
96
  enableLLMAnalysis: true,
97
97
  });
@@ -217,6 +217,7 @@ export class SelfModifyingAgent {
217
217
 
218
218
  throw error;
219
219
  } finally {
220
+ this.metaReasoner.cleanupRun(runId);
220
221
  this.currentContext = null;
221
222
  }
222
223
  }
@@ -409,18 +410,34 @@ export class SelfModifyingAgent {
409
410
 
410
411
  return {
411
412
  enabled: partial.enabled ?? defaults.enabled,
412
- toolGeneration: { ...defaults.toolGeneration, ...partial.toolGeneration },
413
- metaReasoning: { ...defaults.metaReasoning, ...partial.metaReasoning },
413
+ toolGeneration: {
414
+ ...defaults.toolGeneration,
415
+ ...partial.toolGeneration,
416
+ sandboxConfig: partial.toolGeneration?.sandboxConfig
417
+ ? { ...defaults.toolGeneration.sandboxConfig, ...partial.toolGeneration.sandboxConfig }
418
+ : defaults.toolGeneration.sandboxConfig,
419
+ },
420
+ metaReasoning: {
421
+ ...defaults.metaReasoning,
422
+ ...partial.metaReasoning,
423
+ modeProfiles: {
424
+ ...defaults.metaReasoning.modeProfiles,
425
+ ...partial.metaReasoning?.modeProfiles,
426
+ },
427
+ },
414
428
  architectureEvolution: {
415
429
  ...defaults.architectureEvolution,
416
430
  ...partial.architectureEvolution,
431
+ strategy: partial.architectureEvolution?.strategy
432
+ ? { ...defaults.architectureEvolution.strategy, ...partial.architectureEvolution.strategy }
433
+ : defaults.architectureEvolution.strategy,
417
434
  },
418
435
  constraints: { ...defaults.constraints, ...partial.constraints },
419
436
  };
420
437
  }
421
438
 
422
439
  private getAvailableTools(): Tool[] {
423
- return [];
440
+ return this.agent.tools ?? [];
424
441
  }
425
442
 
426
443
  private async optimizeArchitecture(input: string): Promise<void> {
@@ -452,7 +469,14 @@ export class SelfModifyingAgent {
452
469
  });
453
470
  }
454
471
  }
455
- } catch {}
472
+ } catch (error) {
473
+ void this.emitter.emit({
474
+ type: 'architecture_evolved',
475
+ runId: this.currentContext.runId,
476
+ timestamp: new Date(),
477
+ data: { error: error instanceof Error ? error.message : String(error) },
478
+ });
479
+ }
456
480
  }
457
481
 
458
482
  private async analyzeAndGenerateTools(input: string): Promise<void> {
@@ -479,7 +503,19 @@ export class SelfModifyingAgent {
479
503
  }
480
504
  }
481
505
  }
482
- } catch {}
506
+ } catch (error) {
507
+ void this.emitter.emit({
508
+ type: 'tool_generation_completed',
509
+ runId: this.currentContext.runId,
510
+ timestamp: new Date(),
511
+ data: {
512
+ toolId: '',
513
+ name: '',
514
+ success: false,
515
+ error: error instanceof Error ? error.message : String(error),
516
+ },
517
+ });
518
+ }
483
519
  }
484
520
 
485
521
  private async executeWithMetaReasoning(input: string, runId: string): Promise<string> {
@@ -562,7 +598,19 @@ export class SelfModifyingAgent {
562
598
  }
563
599
 
564
600
  private async executeAgentStep(input: string): Promise<string> {
565
- return `Processed: ${input}`;
601
+ const response = await this.llm.chat({
602
+ model: this.currentContext?.currentConfig.model ?? this.agent.model ?? 'default',
603
+ messages: [
604
+ ...(this.agent.instructions
605
+ ? [{ role: 'system' as const, content: this.agent.instructions }]
606
+ : []),
607
+ { role: 'user' as const, content: input },
608
+ ],
609
+ temperature: this.currentContext?.currentConfig.temperature,
610
+ maxTokens: this.currentContext?.currentConfig.maxTokens,
611
+ });
612
+
613
+ return response.content;
566
614
  }
567
615
 
568
616
  private estimateConfidence(output: string): number {
@@ -572,7 +620,7 @@ export class SelfModifyingAgent {
572
620
  return 0.8;
573
621
  }
574
622
 
575
- private isTaskComplete(output: string): boolean {
576
- return output.length > 0;
623
+ private isTaskComplete(_output: string): boolean {
624
+ return true;
577
625
  }
578
626
  }
@@ -25,10 +25,8 @@ export class InMemoryGeneratedToolStore implements IGeneratedToolStore {
25
25
 
26
26
  async save(tool: GeneratedTool): Promise<void> {
27
27
  const existing = this.tools.get(tool.id);
28
- if (existing) {
29
- tool.version = existing.version + 1;
30
- }
31
- this.tools.set(tool.id, { ...tool, updatedAt: new Date() });
28
+ const version = existing ? existing.version + 1 : tool.version;
29
+ this.tools.set(tool.id, { ...tool, version, updatedAt: new Date() });
32
30
  }
33
31
 
34
32
  async get(id: string): Promise<GeneratedTool | null> {
@@ -1,4 +1,5 @@
1
1
  import type { CapabilityGap, GeneratedTool, ToolValidationResult } from '@cogitator-ai/types';
2
+ import { extractJson } from '../utils';
2
3
 
3
4
  export const TOOL_GENERATION_SYSTEM_PROMPT = `You are an expert TypeScript developer specializing in creating tools for AI agents.
4
5
  Your task is to generate safe, efficient, and well-typed tool implementations.
@@ -205,13 +206,13 @@ export function parseGapAnalysisResponse(response: string): {
205
206
  canProceed: boolean;
206
207
  alternativeApproach?: string;
207
208
  } {
208
- const jsonMatch = /\{[\s\S]*\}/.exec(response);
209
- if (!jsonMatch) {
209
+ const json = extractJson(response);
210
+ if (!json) {
210
211
  return { hasGap: false, gaps: [], canProceed: true };
211
212
  }
212
213
 
213
214
  try {
214
- const parsed = JSON.parse(jsonMatch[0]);
215
+ const parsed = JSON.parse(json);
215
216
  return {
216
217
  hasGap: Boolean(parsed.hasGap),
217
218
  gaps: Array.isArray(parsed.gaps)
@@ -238,13 +239,13 @@ export function parseGapAnalysisResponse(response: string): {
238
239
  }
239
240
 
240
241
  export function parseToolGenerationResponse(response: string): GeneratedTool | null {
241
- const jsonMatch = /\{[\s\S]*\}/.exec(response);
242
- if (!jsonMatch) {
242
+ const json = extractJson(response);
243
+ if (!json) {
243
244
  return null;
244
245
  }
245
246
 
246
247
  try {
247
- const parsed = JSON.parse(jsonMatch[0]);
248
+ const parsed = JSON.parse(json);
248
249
  if (!parsed.name || !parsed.implementation) {
249
250
  return null;
250
251
  }
@@ -268,13 +269,13 @@ export function parseToolGenerationResponse(response: string): GeneratedTool | n
268
269
  }
269
270
 
270
271
  export function parseValidationResponse(response: string): ToolValidationResult | null {
271
- const jsonMatch = /\{[\s\S]*\}/.exec(response);
272
- if (!jsonMatch) {
272
+ const json = extractJson(response);
273
+ if (!json) {
273
274
  return null;
274
275
  }
275
276
 
276
277
  try {
277
- const parsed = JSON.parse(jsonMatch[0]);
278
+ const parsed = JSON.parse(json);
278
279
 
279
280
  return {
280
281
  isValid: Boolean(parsed.isValid),
@@ -8,6 +8,7 @@ import type {
8
8
  } from '@cogitator-ai/types';
9
9
  import { z, type ZodType } from 'zod';
10
10
  import { ToolValidator } from './tool-validator';
11
+ import { ToolSandbox } from './tool-sandbox';
11
12
  import {
12
13
  TOOL_GENERATION_SYSTEM_PROMPT,
13
14
  buildToolGenerationPrompt,
@@ -32,6 +33,7 @@ export class ToolGenerator {
32
33
  private readonly llm: LLMBackend;
33
34
  private readonly config: ToolSelfGenerationConfig;
34
35
  private readonly validator: ToolValidator;
36
+ private readonly sandbox: ToolSandbox;
35
37
 
36
38
  constructor(options: ToolGeneratorOptions) {
37
39
  this.llm = options.llm;
@@ -40,6 +42,7 @@ export class ToolGenerator {
40
42
  llm: options.llm,
41
43
  config: options.config,
42
44
  });
45
+ this.sandbox = new ToolSandbox(options.config.sandboxConfig);
43
46
  }
44
47
 
45
48
  async generate(
@@ -203,7 +206,16 @@ export class ToolGenerator {
203
206
  }
204
207
 
205
208
  createExecutableTool(generated: GeneratedTool): Tool {
206
- const execute = this.compileImplementation(generated.implementation);
209
+ const sandbox = this.sandbox;
210
+ const tool = generated;
211
+
212
+ const execute = async (params: unknown): Promise<unknown> => {
213
+ const result = await sandbox.execute(tool, params);
214
+ if (!result.success) {
215
+ throw new Error(result.error ?? 'Tool execution failed');
216
+ }
217
+ return result.result;
218
+ };
207
219
 
208
220
  return {
209
221
  name: generated.name,
@@ -221,20 +233,6 @@ export class ToolGenerator {
221
233
  };
222
234
  }
223
235
 
224
- private compileImplementation(implementation: string): (params: unknown) => Promise<unknown> {
225
- return async (params: unknown): Promise<unknown> => {
226
- // eslint-disable-next-line @typescript-eslint/no-implied-eval
227
- const factory = new Function(`
228
- "use strict";
229
- ${implementation}
230
- return execute;
231
- `);
232
-
233
- const execute = factory();
234
- return execute(params);
235
- };
236
- }
237
-
238
236
  private async callLLM(
239
237
  messages: Array<{ role: 'system' | 'user' | 'assistant'; content: string }>,
240
238
  temperature: number
@@ -150,7 +150,8 @@ export class ToolSandbox {
150
150
  /\bexec\s*\(/,
151
151
  /\bspawn\s*\(/,
152
152
  /__proto__/,
153
- /\bconstructor\s*\[/,
153
+ /\bconstructor\b/,
154
+ /\bgetPrototypeOf\b/,
154
155
  ];
155
156
 
156
157
  if (this.config.isolationLevel === 'strict') {
@@ -267,7 +268,16 @@ export class ToolSandbox {
267
268
  return execute;
268
269
  `);
269
270
  const execute = factory();
270
- const result = await execute(params);
271
+
272
+ const result = await Promise.race([
273
+ execute(params),
274
+ new Promise((_, reject) =>
275
+ setTimeout(
276
+ () => reject(new Error(`Execution timeout: exceeded ${this.config.maxExecutionTime}ms`)),
277
+ this.config.maxExecutionTime
278
+ )
279
+ ),
280
+ ]);
271
281
 
272
282
  return {
273
283
  success: true,
@@ -1 +1,41 @@
1
1
  export { llmChat } from './llm-helper';
2
+
3
+ export function extractJson(text: string): string | null {
4
+ const start = text.indexOf('{');
5
+ if (start === -1) return null;
6
+
7
+ let depth = 0;
8
+ let inString = false;
9
+ let escape = false;
10
+
11
+ for (let i = start; i < text.length; i++) {
12
+ const ch = text[i];
13
+
14
+ if (escape) {
15
+ escape = false;
16
+ continue;
17
+ }
18
+
19
+ if (ch === '\\' && inString) {
20
+ escape = true;
21
+ continue;
22
+ }
23
+
24
+ if (ch === '"') {
25
+ inString = !inString;
26
+ continue;
27
+ }
28
+
29
+ if (inString) continue;
30
+
31
+ if (ch === '{') depth++;
32
+ else if (ch === '}') {
33
+ depth--;
34
+ if (depth === 0) {
35
+ return text.slice(start, i + 1);
36
+ }
37
+ }
38
+ }
39
+
40
+ return null;
41
+ }