@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
@@ -6,9 +6,34 @@ export function extractJson(text) {
6
6
  if (codeBlockMatch) {
7
7
  cleaned = codeBlockMatch[1].trim();
8
8
  }
9
- const start = cleaned.indexOf('{');
10
- if (start === -1)
9
+ const objectStart = cleaned.indexOf('{');
10
+ const arrayStart = cleaned.indexOf('[');
11
+ let start;
12
+ let open;
13
+ let close;
14
+ if (objectStart === -1 && arrayStart === -1) {
11
15
  return null;
16
+ }
17
+ else if (objectStart === -1) {
18
+ start = arrayStart;
19
+ open = '[';
20
+ close = ']';
21
+ }
22
+ else if (arrayStart === -1) {
23
+ start = objectStart;
24
+ open = '{';
25
+ close = '}';
26
+ }
27
+ else if (objectStart < arrayStart) {
28
+ start = objectStart;
29
+ open = '{';
30
+ close = '}';
31
+ }
32
+ else {
33
+ start = arrayStart;
34
+ open = '[';
35
+ close = ']';
36
+ }
12
37
  let depth = 0;
13
38
  let inString = false;
14
39
  let escape = false;
@@ -28,9 +53,9 @@ export function extractJson(text) {
28
53
  }
29
54
  if (inString)
30
55
  continue;
31
- if (ch === '{')
56
+ if (ch === open)
32
57
  depth++;
33
- else if (ch === '}') {
58
+ else if (ch === close) {
34
59
  depth--;
35
60
  if (depth === 0) {
36
61
  return cleaned.slice(start, i + 1);
@@ -40,7 +65,7 @@ export function extractJson(text) {
40
65
  if (depth > 0) {
41
66
  let repaired = cleaned.slice(start);
42
67
  repaired = repaired.replace(/,\s*$/, '');
43
- repaired += '}'.repeat(depth);
68
+ repaired += close.repeat(depth);
44
69
  try {
45
70
  JSON.parse(repaired);
46
71
  return repaired;
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAEvC,MAAM,UAAU,WAAW,CAAC,IAAY;IACtC,IAAI,OAAO,GAAG,IAAI,CAAC;IAEnB,MAAM,cAAc,GAAG,iCAAiC,CAAC;IACzD,MAAM,cAAc,GAAG,cAAc,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IACpD,IAAI,cAAc,EAAE,CAAC;QACnB,OAAO,GAAG,cAAc,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;IACrC,CAAC;IAED,MAAM,KAAK,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IACnC,IAAI,KAAK,KAAK,CAAC,CAAC;QAAE,OAAO,IAAI,CAAC;IAE9B,IAAI,KAAK,GAAG,CAAC,CAAC;IACd,IAAI,QAAQ,GAAG,KAAK,CAAC;IACrB,IAAI,MAAM,GAAG,KAAK,CAAC;IAEnB,KAAK,IAAI,CAAC,GAAG,KAAK,EAAE,CAAC,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QAC5C,MAAM,EAAE,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;QAEtB,IAAI,MAAM,EAAE,CAAC;YACX,MAAM,GAAG,KAAK,CAAC;YACf,SAAS;QACX,CAAC;QAED,IAAI,EAAE,KAAK,IAAI,IAAI,QAAQ,EAAE,CAAC;YAC5B,MAAM,GAAG,IAAI,CAAC;YACd,SAAS;QACX,CAAC;QAED,IAAI,EAAE,KAAK,GAAG,EAAE,CAAC;YACf,QAAQ,GAAG,CAAC,QAAQ,CAAC;YACrB,SAAS;QACX,CAAC;QAED,IAAI,QAAQ;YAAE,SAAS;QAEvB,IAAI,EAAE,KAAK,GAAG;YAAE,KAAK,EAAE,CAAC;aACnB,IAAI,EAAE,KAAK,GAAG,EAAE,CAAC;YACpB,KAAK,EAAE,CAAC;YACR,IAAI,KAAK,KAAK,CAAC,EAAE,CAAC;gBAChB,OAAO,OAAO,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;YACrC,CAAC;QACH,CAAC;IACH,CAAC;IAED,IAAI,KAAK,GAAG,CAAC,EAAE,CAAC;QACd,IAAI,QAAQ,GAAG,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;QACpC,QAAQ,GAAG,QAAQ,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;QACzC,QAAQ,IAAI,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QAC9B,IAAI,CAAC;YACH,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;YACrB,OAAO,QAAQ,CAAC;QAClB,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,IAAI,CAAC;QACd,CAAC;IACH,CAAC;IAED,OAAO,IAAI,CAAC;AACd,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cogitator-ai/self-modifying",
3
- "version": "17.0.16",
3
+ "version": "17.0.18",
4
4
  "description": "Self-modifying agent capabilities for Cogitator - tool generation, meta-reasoning, architecture evolution",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -16,22 +16,14 @@
16
16
  "dist",
17
17
  "src"
18
18
  ],
19
- "scripts": {
20
- "build": "tsc",
21
- "dev": "tsc --watch",
22
- "test": "vitest run",
23
- "test:watch": "vitest",
24
- "lint": "eslint src --ext .ts",
25
- "typecheck": "tsc --noEmit"
26
- },
27
19
  "dependencies": {
28
- "@cogitator-ai/types": "workspace:*",
29
20
  "nanoid": "^5.0.4",
30
- "zod": "^4.3.6"
21
+ "zod": "^4.3.6",
22
+ "@cogitator-ai/types": "0.22.3"
31
23
  },
32
24
  "peerDependencies": {
33
- "@cogitator-ai/core": "workspace:*",
34
- "@cogitator-ai/neuro-symbolic": "workspace:*"
25
+ "@cogitator-ai/core": "0.19.4",
26
+ "@cogitator-ai/neuro-symbolic": "15.1.16"
35
27
  },
36
28
  "peerDependenciesMeta": {
37
29
  "@cogitator-ai/neuro-symbolic": {
@@ -61,5 +53,13 @@
61
53
  "publishConfig": {
62
54
  "registry": "https://npm.pkg.github.com",
63
55
  "access": "public"
56
+ },
57
+ "scripts": {
58
+ "build": "tsc",
59
+ "dev": "tsc --watch",
60
+ "test": "vitest run",
61
+ "test:watch": "vitest",
62
+ "lint": "eslint src --ext .ts",
63
+ "typecheck": "tsc --noEmit"
64
64
  }
65
- }
65
+ }
@@ -46,7 +46,11 @@ describe('SelfModifyingAgent tool execution', () => {
46
46
  .mockResolvedValueOnce(
47
47
  chatResponse('', [{ id: 'call_1', name: 'calculator', arguments: { input: '6*7' } }])
48
48
  )
49
- .mockResolvedValueOnce(chatResponse('The answer is 42.')),
49
+ .mockResolvedValueOnce(
50
+ chatResponse(
51
+ 'The answer to your calculation is 42. I used the calculator tool to compute 6 times 7.'
52
+ )
53
+ ),
50
54
  };
51
55
 
52
56
  const agent = createMockAgent([calculator]);
@@ -63,7 +67,9 @@ describe('SelfModifyingAgent tool execution', () => {
63
67
 
64
68
  const result = await selfMod.run('What is 6 times 7?');
65
69
 
66
- expect(result.output).toBe('The answer is 42.');
70
+ expect(result.output).toBe(
71
+ 'The answer to your calculation is 42. I used the calculator tool to compute 6 times 7.'
72
+ );
67
73
  expect(calculator.execute).toHaveBeenCalledOnce();
68
74
  expect(calculator.execute).toHaveBeenCalledWith(
69
75
  { input: '6*7' },
@@ -89,7 +95,11 @@ describe('SelfModifyingAgent tool execution', () => {
89
95
  .mockResolvedValueOnce(
90
96
  chatResponse('', [{ id: 'call_2', name: 'format', arguments: { input: 'found it' } }])
91
97
  )
92
- .mockResolvedValueOnce(chatResponse('Here is your formatted result.')),
98
+ .mockResolvedValueOnce(
99
+ chatResponse(
100
+ 'Here is your formatted result. I searched for the information and then formatted it for you.'
101
+ )
102
+ ),
93
103
  };
94
104
 
95
105
  const agent = createMockAgent([search, format]);
@@ -106,7 +116,9 @@ describe('SelfModifyingAgent tool execution', () => {
106
116
 
107
117
  const result = await selfMod.run('Search and format');
108
118
 
109
- expect(result.output).toBe('Here is your formatted result.');
119
+ expect(result.output).toBe(
120
+ 'Here is your formatted result. I searched for the information and then formatted it for you.'
121
+ );
110
122
  expect(search.execute).toHaveBeenCalledOnce();
111
123
  expect(format.execute).toHaveBeenCalledOnce();
112
124
  expect(vi.mocked(mockLLM.chat!)).toHaveBeenCalledTimes(3);
@@ -122,7 +134,11 @@ describe('SelfModifyingAgent tool execution', () => {
122
134
  .mockResolvedValueOnce(
123
135
  chatResponse('', [{ id: 'call_1', name: 'broken', arguments: { input: 'test' } }])
124
136
  )
125
- .mockResolvedValueOnce(chatResponse('The tool failed but I can help anyway.')),
137
+ .mockResolvedValueOnce(
138
+ chatResponse(
139
+ 'The tool failed but I can still help you with your request. Let me try a different approach.'
140
+ )
141
+ ),
126
142
  };
127
143
 
128
144
  const agent = createMockAgent([failTool]);
@@ -139,7 +155,9 @@ describe('SelfModifyingAgent tool execution', () => {
139
155
 
140
156
  const result = await selfMod.run('Use the broken tool');
141
157
 
142
- expect(result.output).toBe('The tool failed but I can help anyway.');
158
+ expect(result.output).toBe(
159
+ 'The tool failed but I can still help you with your request. Let me try a different approach.'
160
+ );
143
161
  const secondCall = vi.mocked(mockLLM.chat!).mock.calls[1][0];
144
162
  const toolMsg = secondCall.messages.find((m: { role: string }) => m.role === 'tool');
145
163
  expect(toolMsg?.content).toContain('tool crashed');
@@ -152,7 +170,11 @@ describe('SelfModifyingAgent tool execution', () => {
152
170
  .mockResolvedValueOnce(
153
171
  chatResponse('', [{ id: 'call_1', name: 'nonexistent', arguments: { input: 'x' } }])
154
172
  )
155
- .mockResolvedValueOnce(chatResponse('I could not find that tool.')),
173
+ .mockResolvedValueOnce(
174
+ chatResponse(
175
+ 'I could not find that tool in my available tools. Let me try to help you without it.'
176
+ )
177
+ ),
156
178
  };
157
179
 
158
180
  const agent = createMockAgent([]);
@@ -169,7 +191,9 @@ describe('SelfModifyingAgent tool execution', () => {
169
191
 
170
192
  const result = await selfMod.run('Call a tool');
171
193
 
172
- expect(result.output).toBe('I could not find that tool.');
194
+ expect(result.output).toBe(
195
+ 'I could not find that tool in my available tools. Let me try to help you without it.'
196
+ );
173
197
  const secondCall = vi.mocked(mockLLM.chat!).mock.calls[1][0];
174
198
  const toolMsg = secondCall.messages.find((m: { role: string }) => m.role === 'tool');
175
199
  expect(toolMsg?.content).toContain('not found');
@@ -177,7 +201,13 @@ describe('SelfModifyingAgent tool execution', () => {
177
201
 
178
202
  it('works without any tools (no tools passed to LLM)', async () => {
179
203
  const mockLLM: Partial<LLMBackend> = {
180
- chat: vi.fn().mockResolvedValueOnce(chatResponse('Hello world')),
204
+ chat: vi
205
+ .fn()
206
+ .mockResolvedValueOnce(
207
+ chatResponse(
208
+ 'Hello world! I am a test assistant and I am here to help you with your questions.'
209
+ )
210
+ ),
181
211
  };
182
212
 
183
213
  const agent = createMockAgent([]);
@@ -194,7 +224,9 @@ describe('SelfModifyingAgent tool execution', () => {
194
224
 
195
225
  const result = await selfMod.run('Just say hi');
196
226
 
197
- expect(result.output).toBe('Hello world');
227
+ expect(result.output).toBe(
228
+ 'Hello world! I am a test assistant and I am here to help you with your questions.'
229
+ );
198
230
  const chatCall = vi.mocked(mockLLM.chat!).mock.calls[0][0];
199
231
  expect(chatCall.tools).toBeUndefined();
200
232
  });
@@ -121,6 +121,7 @@ const COMPLEXITY_INDICATORS = {
121
121
  simple: ['explain', 'define', 'list', 'describe', 'show'],
122
122
  moderate: ['compare', 'analyze', 'summarize', 'evaluate', 'implement'],
123
123
  complex: ['design', 'architect', 'optimize', 'comprehensive', 'detailed'],
124
+ expert: ['expert', 'advanced', 'specialized', 'intricate', 'sophisticated'],
124
125
  extreme: ['novel', 'research', 'breakthrough', 'state-of-the-art', 'cutting-edge'],
125
126
  };
126
127
 
@@ -237,6 +238,8 @@ export class CapabilityAnalyzer {
237
238
  domain,
238
239
  estimatedTokens: this.estimateTokens(wordCount, complexity),
239
240
  requiresTools: toolAnalysis.requiresTools,
241
+ requiresReasoning: domain === 'reasoning' || domain === 'coding',
242
+ requiresCreativity: domain === 'creative',
240
243
  toolIntensity: toolAnalysis.intensity,
241
244
  reasoningDepth: this.estimateReasoningDepth(complexity, domain),
242
245
  creativityLevel:
@@ -375,10 +378,6 @@ export class CapabilityAnalyzer {
375
378
  domain: TaskProfile['domain'],
376
379
  task: string
377
380
  ): TaskProfile['accuracyRequirement'] {
378
- if (domain === 'coding' || domain === 'factual') {
379
- return 'high';
380
- }
381
-
382
381
  const criticalIndicators = ['critical', 'exact', 'precise', 'must be correct', 'no errors'];
383
382
  for (const indicator of criticalIndicators) {
384
383
  if (task.includes(indicator)) {
@@ -386,6 +385,10 @@ export class CapabilityAnalyzer {
386
385
  }
387
386
  }
388
387
 
388
+ if (domain === 'coding' || domain === 'factual') {
389
+ return 'high';
390
+ }
391
+
389
392
  const approximateIndicators = ['rough', 'approximate', 'estimate', 'about', 'roughly'];
390
393
  for (const indicator of approximateIndicators) {
391
394
  if (task.includes(indicator)) {
@@ -152,8 +152,9 @@ export class EvolutionStrategy {
152
152
 
153
153
  const d = shape - 1 / 3;
154
154
  const c = 1 / Math.sqrt(9 * d);
155
+ const maxIterations = 1000;
155
156
 
156
- while (true) {
157
+ for (let i = 0; i < maxIterations; i++) {
157
158
  let x: number;
158
159
  let v: number;
159
160
 
@@ -173,6 +174,8 @@ export class EvolutionStrategy {
173
174
  return d * v;
174
175
  }
175
176
  }
177
+
178
+ return d;
176
179
  }
177
180
 
178
181
  private sampleNormal(): number {
@@ -202,7 +205,7 @@ export class EvolutionStrategy {
202
205
  (this.strategy.explorationConstant ?? 2) / Math.sqrt(this.totalSelections)
203
206
  );
204
207
  case 'thompson_sampling':
205
- return 0.5;
208
+ return Math.max(0.05, 1 / Math.sqrt(this.totalSelections + 1));
206
209
  default:
207
210
  return 0.1;
208
211
  }
@@ -82,11 +82,20 @@ export class ParameterOptimizer {
82
82
 
83
83
  const mergedConfig = this.mergeConfigs(this.baseConfig, selection.candidate.config);
84
84
 
85
+ const bestEvaluated = this.candidates
86
+ .filter((c) => c.evaluationCount > 0)
87
+ .sort((a, b) => b.score - a.score)[0];
88
+
89
+ const shouldAdopt =
90
+ !bestEvaluated ||
91
+ selection.candidate.id === bestEvaluated.id ||
92
+ selection.score >= bestEvaluated.score * 0.9;
93
+
85
94
  return {
86
95
  recommendedConfig: mergedConfig,
87
96
  candidate: selection.candidate,
88
97
  metrics: this.calculateMetrics(),
89
- shouldAdopt: true,
98
+ shouldAdopt,
90
99
  confidence: selection.score,
91
100
  reasoning: selection.reasoning,
92
101
  };
@@ -247,23 +256,20 @@ export class ParameterOptimizer {
247
256
  const mutated = { ...config };
248
257
  const mutationRate = 0.3;
249
258
 
250
- if (Math.random() < mutationRate && mutated.temperature !== undefined) {
251
- mutated.temperature = Math.max(
252
- 0,
253
- Math.min(2, mutated.temperature + (Math.random() - 0.5) * 0.3)
254
- );
259
+ if (Math.random() < mutationRate) {
260
+ const base = mutated.temperature ?? this.baseConfig.temperature;
261
+ mutated.temperature = Math.max(0, Math.min(2, base + (Math.random() - 0.5) * 0.3));
255
262
  }
256
263
 
257
- if (Math.random() < mutationRate && mutated.maxTokens !== undefined) {
264
+ if (Math.random() < mutationRate) {
265
+ const base = mutated.maxTokens ?? this.baseConfig.maxTokens;
258
266
  const delta = Math.floor((Math.random() - 0.5) * 1000);
259
- mutated.maxTokens = Math.max(100, Math.min(32000, mutated.maxTokens + delta));
267
+ mutated.maxTokens = Math.max(100, Math.min(32000, base + delta));
260
268
  }
261
269
 
262
- if (Math.random() < mutationRate && mutated.reflectionDepth !== undefined) {
263
- mutated.reflectionDepth = Math.max(
264
- 0,
265
- Math.min(5, mutated.reflectionDepth + Math.round(Math.random() * 2 - 1))
266
- );
270
+ if (Math.random() < mutationRate) {
271
+ const base = mutated.reflectionDepth ?? this.baseConfig.reflectionDepth;
272
+ mutated.reflectionDepth = Math.max(0, Math.min(5, base + Math.round(Math.random() * 2 - 1)));
267
273
  }
268
274
 
269
275
  return mutated;
@@ -316,12 +322,16 @@ export class ParameterOptimizer {
316
322
  }
317
323
 
318
324
  private shouldEvolve(): boolean {
319
- const minEvaluations = this.candidates.reduce(
325
+ const evaluatedCandidates = this.candidates.filter((c) => c.evaluationCount > 0);
326
+ if (evaluatedCandidates.length === 0) return false;
327
+
328
+ const minEvaluations = evaluatedCandidates.reduce(
320
329
  (min, c) => Math.min(min, c.evaluationCount),
321
330
  Infinity
322
331
  );
323
332
 
324
- if (minEvaluations < 3) return false;
333
+ const minRequired = this.config.minEvaluationsBeforeEvolution ?? 3;
334
+ if (minEvaluations < minRequired) return false;
325
335
 
326
336
  const evaluationsSinceEvolution = this.history.filter(
327
337
  (h) => h.timestamp > this.getLastEvolutionTime()
@@ -418,6 +428,20 @@ export class ParameterOptimizer {
418
428
  fields++;
419
429
  }
420
430
 
431
+ if (
432
+ a.toolStrategy !== undefined &&
433
+ b.toolStrategy !== undefined &&
434
+ a.toolStrategy !== b.toolStrategy
435
+ ) {
436
+ distance += 1;
437
+ fields++;
438
+ }
439
+
440
+ if (a.reflectionDepth !== undefined && b.reflectionDepth !== undefined) {
441
+ distance += Math.abs(a.reflectionDepth - b.reflectionDepth) / 5;
442
+ fields++;
443
+ }
444
+
421
445
  return fields > 0 ? distance / fields : 0;
422
446
  }
423
447
 
@@ -37,10 +37,12 @@ ${contextSection}
37
37
 
38
38
  Respond with a JSON object:
39
39
  {
40
- "complexity": "trivial" | "simple" | "moderate" | "complex" | "extreme",
40
+ "complexity": "trivial" | "simple" | "moderate" | "complex" | "expert" | "extreme",
41
41
  "domain": "general" | "coding" | "reasoning" | "creative" | "factual" | "conversational",
42
42
  "estimatedTokens": number,
43
43
  "requiresTools": boolean,
44
+ "requiresReasoning": boolean,
45
+ "requiresCreativity": boolean,
44
46
  "toolIntensity": "none" | "light" | "moderate" | "heavy",
45
47
  "reasoningDepth": "shallow" | "moderate" | "deep" | "exhaustive",
46
48
  "creativityLevel": "low" | "moderate" | "high",
@@ -152,6 +154,8 @@ export function parseTaskProfileResponse(response: string): TaskProfile | null {
152
154
  domain: parsed.domain || 'general',
153
155
  estimatedTokens: parsed.estimatedTokens || 1000,
154
156
  requiresTools: Boolean(parsed.requiresTools),
157
+ requiresReasoning: Boolean(parsed.requiresReasoning),
158
+ requiresCreativity: Boolean(parsed.requiresCreativity),
155
159
  toolIntensity: parsed.toolIntensity || 'none',
156
160
  reasoningDepth: parsed.reasoningDepth || 'moderate',
157
161
  creativityLevel: parsed.creativityLevel || 'moderate',
@@ -164,11 +168,11 @@ export function parseTaskProfileResponse(response: string): TaskProfile | null {
164
168
  }
165
169
 
166
170
  export function parseCandidateGenerationResponse(response: string): EvolutionCandidate[] {
167
- const jsonMatch = /\[[\s\S]*\]/.exec(response);
168
- if (!jsonMatch) return [];
171
+ const json = extractJsonArray(response);
172
+ if (!json) return [];
169
173
 
170
174
  try {
171
- const parsed = JSON.parse(jsonMatch[0]);
175
+ const parsed = JSON.parse(json);
172
176
  if (!Array.isArray(parsed)) return [];
173
177
 
174
178
  return parsed
@@ -214,3 +218,43 @@ export function parsePerformanceAnalysisResponse(response: string): {
214
218
  return null;
215
219
  }
216
220
  }
221
+
222
+ function extractJsonArray(text: string): string | null {
223
+ const start = text.indexOf('[');
224
+ if (start === -1) return null;
225
+
226
+ let depth = 0;
227
+ let inString = false;
228
+ let escape = false;
229
+
230
+ for (let i = start; i < text.length; i++) {
231
+ const ch = text[i];
232
+
233
+ if (escape) {
234
+ escape = false;
235
+ continue;
236
+ }
237
+
238
+ if (ch === '\\' && inString) {
239
+ escape = true;
240
+ continue;
241
+ }
242
+
243
+ if (ch === '"') {
244
+ inString = !inString;
245
+ continue;
246
+ }
247
+
248
+ if (inString) continue;
249
+
250
+ if (ch === '[' || ch === '{') depth++;
251
+ else if (ch === ']' || ch === '}') {
252
+ depth--;
253
+ if (depth === 0) {
254
+ return text.slice(start, i + 1);
255
+ }
256
+ }
257
+ }
258
+
259
+ return null;
260
+ }
@@ -92,10 +92,21 @@ export class ModificationValidator {
92
92
  return this.evaluateExpression(rule, request.payload as Record<string, unknown>);
93
93
  }
94
94
 
95
- return this.evaluateExpression(
96
- rule.expression ?? '',
97
- request.payload as Record<string, unknown>
98
- );
95
+ const context = request.payload as Record<string, unknown>;
96
+ const checks: boolean[] = [];
97
+
98
+ if (rule.expression) {
99
+ checks.push(this.evaluateExpression(rule.expression, context));
100
+ }
101
+
102
+ if (rule.pattern) {
103
+ const subject = JSON.stringify(request.changes ?? request.payload ?? '');
104
+ checks.push(rule.pattern.test(subject));
105
+ }
106
+
107
+ if (checks.length === 0) return false;
108
+
109
+ return checks.every(Boolean);
99
110
  }
100
111
 
101
112
  private evaluateExpression(expression: string, context: Record<string, unknown>): boolean {
@@ -181,7 +192,7 @@ export class ModificationValidator {
181
192
  ): Promise<ConstraintCheckResult[]> {
182
193
  const results: ConstraintCheckResult[] = [];
183
194
 
184
- if (request.type !== 'tool_generation') {
195
+ if (request.type !== 'tool_generation' && request.type !== 'tool_creation') {
185
196
  return results;
186
197
  }
187
198
 
@@ -239,7 +250,7 @@ export class ModificationValidator {
239
250
 
240
251
  if (
241
252
  constraint.maxTokensPerRun &&
242
- payload.tokensUsed &&
253
+ payload.tokensUsed != null &&
243
254
  payload.tokensUsed > constraint.maxTokensPerRun
244
255
  ) {
245
256
  satisfied = false;
@@ -249,7 +260,7 @@ export class ModificationValidator {
249
260
  if (
250
261
  satisfied &&
251
262
  constraint.maxCostPerRun &&
252
- payload.cost &&
263
+ payload.cost != null &&
253
264
  payload.cost > constraint.maxCostPerRun
254
265
  ) {
255
266
  satisfied = false;
@@ -259,7 +270,7 @@ export class ModificationValidator {
259
270
  if (
260
271
  satisfied &&
261
272
  constraint.maxToolsActive &&
262
- payload.activeTools &&
273
+ payload.activeTools != null &&
263
274
  payload.activeTools > constraint.maxToolsActive
264
275
  ) {
265
276
  satisfied = false;
@@ -119,11 +119,30 @@ export class RollbackManager {
119
119
  if (!checkpoint) return null;
120
120
 
121
121
  return {
122
- agentConfig: checkpoint.agentConfig as unknown as AgentConfig,
122
+ agentConfig: this.toAgentConfig(checkpoint.agentConfig),
123
123
  tools: checkpoint.tools.map((t) => ({ ...t })),
124
124
  };
125
125
  }
126
126
 
127
+ private toAgentConfig(record: Record<string, unknown>): AgentConfig {
128
+ const config: AgentConfig = {
129
+ name: typeof record.name === 'string' ? record.name : 'agent',
130
+ model: typeof record.model === 'string' ? record.model : 'default',
131
+ instructions: typeof record.instructions === 'string' ? record.instructions : '',
132
+ };
133
+
134
+ if (typeof record.id === 'string') config.id = record.id;
135
+ if (typeof record.description === 'string') config.description = record.description;
136
+ if (typeof record.provider === 'string') config.provider = record.provider;
137
+ if (typeof record.temperature === 'number') config.temperature = record.temperature;
138
+ if (typeof record.topP === 'number') config.topP = record.topP;
139
+ if (typeof record.maxTokens === 'number') config.maxTokens = record.maxTokens;
140
+ if (typeof record.maxIterations === 'number') config.maxIterations = record.maxIterations;
141
+ if (typeof record.timeout === 'number') config.timeout = record.timeout;
142
+
143
+ return config;
144
+ }
145
+
127
146
  async rollbackToLatest(
128
147
  agentId: string
129
148
  ): Promise<{ agentConfig: AgentConfig; tools: Tool[] } | null> {
@@ -30,7 +30,7 @@ export class SelfModifyingEventEmitter {
30
30
  ...(wildcardHandlers ? [...wildcardHandlers] : []),
31
31
  ];
32
32
 
33
- await Promise.allSettled(
33
+ const results = await Promise.allSettled(
34
34
  allHandlers.map((h) => {
35
35
  try {
36
36
  return Promise.resolve(h(event));
@@ -39,21 +39,12 @@ export class SelfModifyingEventEmitter {
39
39
  }
40
40
  })
41
41
  );
42
- }
43
42
 
44
- createEvent(
45
- type: SelfModifyingEventType,
46
- runId: string,
47
- agentId: string,
48
- data: unknown
49
- ): SelfModifyingEvent {
50
- return {
51
- type,
52
- runId,
53
- agentId,
54
- timestamp: new Date(),
55
- data,
56
- };
43
+ for (const result of results) {
44
+ if (result.status === 'rejected') {
45
+ console.error(`[self-modifying] event handler for "${event.type}" failed:`, result.reason);
46
+ }
47
+ }
57
48
  }
58
49
 
59
50
  removeAllListeners(event?: SelfModifyingEventType | '*'): void {