@cogitator-ai/self-modifying 17.0.18 → 19.0.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.
Files changed (84) hide show
  1. package/README.md +114 -50
  2. package/dist/architecture-evolution/capability-analyzer.d.ts.map +1 -1
  3. package/dist/architecture-evolution/capability-analyzer.js +38 -37
  4. package/dist/architecture-evolution/capability-analyzer.js.map +1 -1
  5. package/dist/architecture-evolution/index.d.ts +2 -2
  6. package/dist/architecture-evolution/index.d.ts.map +1 -1
  7. package/dist/architecture-evolution/index.js +1 -1
  8. package/dist/architecture-evolution/index.js.map +1 -1
  9. package/dist/architecture-evolution/parameter-optimizer.d.ts +5 -4
  10. package/dist/architecture-evolution/parameter-optimizer.d.ts.map +1 -1
  11. package/dist/architecture-evolution/parameter-optimizer.js +36 -31
  12. package/dist/architecture-evolution/parameter-optimizer.js.map +1 -1
  13. package/dist/architecture-evolution/prompts.d.ts +21 -2
  14. package/dist/architecture-evolution/prompts.d.ts.map +1 -1
  15. package/dist/architecture-evolution/prompts.js +150 -36
  16. package/dist/architecture-evolution/prompts.js.map +1 -1
  17. package/dist/constraints/modification-validator.d.ts +1 -0
  18. package/dist/constraints/modification-validator.d.ts.map +1 -1
  19. package/dist/constraints/modification-validator.js +30 -14
  20. package/dist/constraints/modification-validator.js.map +1 -1
  21. package/dist/index.d.ts +4 -4
  22. package/dist/index.d.ts.map +1 -1
  23. package/dist/index.js +3 -3
  24. package/dist/index.js.map +1 -1
  25. package/dist/meta-reasoning/meta-reasoner.d.ts +3 -0
  26. package/dist/meta-reasoning/meta-reasoner.d.ts.map +1 -1
  27. package/dist/meta-reasoning/meta-reasoner.js +101 -33
  28. package/dist/meta-reasoning/meta-reasoner.js.map +1 -1
  29. package/dist/meta-reasoning/prompts.d.ts +10 -14
  30. package/dist/meta-reasoning/prompts.d.ts.map +1 -1
  31. package/dist/meta-reasoning/prompts.js +109 -1
  32. package/dist/meta-reasoning/prompts.js.map +1 -1
  33. package/dist/self-modifying-agent.d.ts +83 -17
  34. package/dist/self-modifying-agent.d.ts.map +1 -1
  35. package/dist/self-modifying-agent.js +557 -444
  36. package/dist/self-modifying-agent.js.map +1 -1
  37. package/dist/tool-generation/gap-analyzer.d.ts +0 -1
  38. package/dist/tool-generation/gap-analyzer.d.ts.map +1 -1
  39. package/dist/tool-generation/gap-analyzer.js +14 -14
  40. package/dist/tool-generation/gap-analyzer.js.map +1 -1
  41. package/dist/tool-generation/index.d.ts +3 -3
  42. package/dist/tool-generation/index.d.ts.map +1 -1
  43. package/dist/tool-generation/index.js +2 -2
  44. package/dist/tool-generation/index.js.map +1 -1
  45. package/dist/tool-generation/prompts.d.ts +1 -0
  46. package/dist/tool-generation/prompts.d.ts.map +1 -1
  47. package/dist/tool-generation/prompts.js +33 -8
  48. package/dist/tool-generation/prompts.js.map +1 -1
  49. package/dist/tool-generation/tool-generator.d.ts +5 -5
  50. package/dist/tool-generation/tool-generator.d.ts.map +1 -1
  51. package/dist/tool-generation/tool-generator.js +41 -28
  52. package/dist/tool-generation/tool-generator.js.map +1 -1
  53. package/dist/tool-generation/tool-sandbox.d.ts +9 -6
  54. package/dist/tool-generation/tool-sandbox.d.ts.map +1 -1
  55. package/dist/tool-generation/tool-sandbox.js +257 -157
  56. package/dist/tool-generation/tool-sandbox.js.map +1 -1
  57. package/dist/tool-generation/tool-validator.d.ts +3 -8
  58. package/dist/tool-generation/tool-validator.d.ts.map +1 -1
  59. package/dist/tool-generation/tool-validator.js +53 -54
  60. package/dist/tool-generation/tool-validator.js.map +1 -1
  61. package/dist/utils/llm-helper.d.ts.map +1 -1
  62. package/dist/utils/llm-helper.js +1 -0
  63. package/dist/utils/llm-helper.js.map +1 -1
  64. package/package.json +11 -18
  65. package/src/__tests__/component-regressions.test.ts +599 -0
  66. package/src/__tests__/meta-reasoning.test.ts +5 -1
  67. package/src/__tests__/sandbox-security.test.ts +186 -0
  68. package/src/__tests__/self-modifying-agent.test.ts +363 -1
  69. package/src/architecture-evolution/capability-analyzer.ts +56 -40
  70. package/src/architecture-evolution/index.ts +2 -0
  71. package/src/architecture-evolution/parameter-optimizer.ts +52 -34
  72. package/src/architecture-evolution/prompts.ts +179 -41
  73. package/src/constraints/modification-validator.ts +30 -14
  74. package/src/index.ts +14 -0
  75. package/src/meta-reasoning/meta-reasoner.ts +105 -40
  76. package/src/meta-reasoning/prompts.ts +129 -15
  77. package/src/self-modifying-agent.ts +764 -489
  78. package/src/tool-generation/gap-analyzer.ts +19 -18
  79. package/src/tool-generation/index.ts +13 -3
  80. package/src/tool-generation/prompts.ts +41 -8
  81. package/src/tool-generation/tool-generator.ts +59 -33
  82. package/src/tool-generation/tool-sandbox.ts +306 -175
  83. package/src/tool-generation/tool-validator.ts +66 -63
  84. package/src/utils/llm-helper.ts +1 -0
@@ -74,6 +74,9 @@ export class ModificationValidator {
74
74
  const results: ConstraintCheckResult[] = [];
75
75
 
76
76
  for (const constraint of this.constraints.safety) {
77
+ if (constraint.appliesTo && !constraint.appliesTo.includes(request.type)) {
78
+ continue;
79
+ }
77
80
  const satisfied = this.evaluateSafetyRule(constraint.rule, request);
78
81
  results.push({
79
82
  constraintId: constraint.id,
@@ -88,11 +91,12 @@ export class ModificationValidator {
88
91
  }
89
92
 
90
93
  private evaluateSafetyRule(rule: ConstraintRule, request: ModificationRequest): boolean {
94
+ const context = this.payloadOf(request);
95
+
91
96
  if (typeof rule === 'string') {
92
- return this.evaluateExpression(rule, request.payload as Record<string, unknown>);
97
+ return this.evaluateExpression(rule, context);
93
98
  }
94
99
 
95
- const context = request.payload as Record<string, unknown>;
96
100
  const checks: boolean[] = [];
97
101
 
98
102
  if (rule.expression) {
@@ -170,10 +174,20 @@ export class ModificationValidator {
170
174
  return Boolean(value);
171
175
  }
172
176
 
177
+ private payloadOf(request: ModificationRequest): Record<string, unknown> {
178
+ const payload = request.payload;
179
+ return payload && typeof payload === 'object' && !Array.isArray(payload)
180
+ ? (payload as Record<string, unknown>)
181
+ : {};
182
+ }
183
+
173
184
  private resolveValue(expr: string, context: Record<string, unknown>): unknown {
174
185
  if (expr === 'true') return true;
175
186
  if (expr === 'false') return false;
176
- if (/^\d+(\.\d+)?$/.test(expr)) return parseFloat(expr);
187
+ if (expr === 'null') return null;
188
+ if (/^-?\d+(\.\d+)?$/.test(expr)) return parseFloat(expr);
189
+ const quoted = /^(['"])(.*)\1$/.exec(expr);
190
+ if (quoted) return quoted[2];
177
191
 
178
192
  const keys = expr.split('.');
179
193
  let current: unknown = context;
@@ -196,30 +210,32 @@ export class ModificationValidator {
196
210
  return results;
197
211
  }
198
212
 
199
- const payload = request.payload as { category?: string; complexity?: number };
213
+ const payload = this.payloadOf(request) as { category?: unknown; complexity?: unknown };
214
+ const category = typeof payload.category === 'string' ? payload.category : undefined;
215
+ const complexity = typeof payload.complexity === 'number' ? payload.complexity : undefined;
200
216
 
201
217
  for (const constraint of this.constraints.capability) {
202
218
  let satisfied = true;
203
219
  let message: string | undefined;
204
220
 
205
- if (payload.category) {
206
- if (constraint.forbidden?.includes(payload.category)) {
221
+ if (category) {
222
+ if (constraint.forbidden?.includes(category)) {
207
223
  satisfied = false;
208
- message = `Category '${payload.category}' is forbidden`;
209
- } else if (constraint.allowed?.length && !constraint.allowed.includes(payload.category)) {
224
+ message = `Category '${category}' is forbidden`;
225
+ } else if (constraint.allowed?.length && !constraint.allowed.includes(category)) {
210
226
  satisfied = false;
211
- message = `Category '${payload.category}' is not in allowed list`;
227
+ message = `Category '${category}' is not in allowed list`;
212
228
  }
213
229
  }
214
230
 
215
231
  if (
216
232
  satisfied &&
217
- constraint.maxComplexity &&
218
- payload.complexity &&
219
- payload.complexity > constraint.maxComplexity
233
+ constraint.maxComplexity !== undefined &&
234
+ complexity !== undefined &&
235
+ complexity > constraint.maxComplexity
220
236
  ) {
221
237
  satisfied = false;
222
- message = `Complexity ${payload.complexity} exceeds max ${constraint.maxComplexity}`;
238
+ message = `Complexity ${complexity} exceeds max ${constraint.maxComplexity}`;
223
239
  }
224
240
 
225
241
  results.push({
@@ -238,7 +254,7 @@ export class ModificationValidator {
238
254
  request: ModificationRequest
239
255
  ): Promise<ConstraintCheckResult[]> {
240
256
  const results: ConstraintCheckResult[] = [];
241
- const payload = (request.payload ?? {}) as {
257
+ const payload = this.payloadOf(request) as {
242
258
  tokensUsed?: number;
243
259
  cost?: number;
244
260
  activeTools?: number;
package/src/index.ts CHANGED
@@ -1,6 +1,9 @@
1
1
  export {
2
2
  SelfModifyingAgent,
3
3
  type SelfModifyingAgentOptions,
4
+ type SelfModifyingAgentConfig,
5
+ type SelfModifyingEventDataMap,
6
+ type TypedSelfModifyingEvent,
4
7
  type RunContext,
5
8
  } from './self-modifying-agent';
6
9
 
@@ -15,11 +18,16 @@ export {
15
18
  buildGapAnalysisPrompt,
16
19
  buildToolGenerationPrompt,
17
20
  buildToolValidationPrompt,
21
+ buildToolImprovementPrompt,
18
22
  parseGapAnalysisResponse,
19
23
  parseToolGenerationResponse,
24
+ parseValidationResponse,
20
25
  type GapAnalyzerOptions,
21
26
  type ToolGeneratorOptions,
22
27
  type ToolValidatorOptions,
28
+ type ValidationRule,
29
+ type SandboxTestCase,
30
+ type GenerateOptions,
23
31
  type GenerationResult,
24
32
  type ToolUsageRecord,
25
33
  type ToolMetrics,
@@ -48,13 +56,17 @@ export {
48
56
  ARCHITECTURE_ANALYSIS_SYSTEM_PROMPT,
49
57
  buildTaskProfilePrompt,
50
58
  buildCandidateGenerationPrompt,
59
+ buildPerformanceAnalysisPrompt,
51
60
  parseTaskProfileResponse,
52
61
  parseCandidateGenerationResponse,
62
+ parsePerformanceAnalysisResponse,
63
+ sanitizeCandidateConfig,
53
64
  type CapabilityAnalyzerOptions,
54
65
  type EvolutionStrategyOptions,
55
66
  type ParameterOptimizerOptions,
56
67
  type SelectionResult,
57
68
  type OptimizationResult,
69
+ type HistoricalRecord,
58
70
  } from './architecture-evolution';
59
71
 
60
72
  export {
@@ -64,6 +76,8 @@ export {
64
76
  DEFAULT_SAFETY_CONSTRAINTS,
65
77
  DEFAULT_CAPABILITY_CONSTRAINTS,
66
78
  DEFAULT_RESOURCE_CONSTRAINTS,
79
+ createDefaultConstraints,
80
+ mergeConstraints,
67
81
  mergeSafetyConstraints,
68
82
  mergeCapabilityConstraints,
69
83
  mergeResourceConstraints,
@@ -10,8 +10,6 @@ import type {
10
10
  ReasoningModeConfig,
11
11
  Insight,
12
12
  LLMBackend,
13
- MetaIssue,
14
- MetaOpportunity,
15
13
  } from '@cogitator-ai/types';
16
14
  import { DEFAULT_META_REASONING_CONFIG } from '@cogitator-ai/types';
17
15
  import {
@@ -28,6 +26,17 @@ import {
28
26
 
29
27
  export { DEFAULT_META_REASONING_CONFIG };
30
28
 
29
+ const TRIGGER_ALIASES: Partial<Record<MetaTrigger, MetaTrigger>> = {
30
+ confidence_drop: 'on_low_confidence',
31
+ progress_stall: 'on_stagnation',
32
+ tool_call_failed: 'on_failure',
33
+ explicit_request: 'on_request',
34
+ };
35
+
36
+ function canonicalTrigger(trigger: MetaTrigger): MetaTrigger {
37
+ return TRIGGER_ALIASES[trigger] ?? trigger;
38
+ }
39
+
31
40
  export interface MetaReasonerOptions {
32
41
  llm: LLMBackend;
33
42
  model: string;
@@ -44,6 +53,8 @@ export class MetaReasoner {
44
53
  private assessments = new Map<string, MetaAssessment[]>();
45
54
  private adaptations = new Map<string, MetaAdaptation[]>();
46
55
  private currentMode = new Map<string, ReasoningMode>();
56
+ private parameterOverrides = new Map<string, Partial<ReasoningModeConfig>>();
57
+ private overridesBefore = new Map<string, Partial<ReasoningModeConfig>>();
47
58
 
48
59
  private lastAssessmentTime = new Map<string, number>();
49
60
  private lastAdaptationTime = new Map<string, number>();
@@ -51,7 +62,14 @@ export class MetaReasoner {
51
62
  constructor(options: MetaReasonerOptions) {
52
63
  this.llm = options.llm;
53
64
  this.model = options.model;
54
- this.config = { ...DEFAULT_META_REASONING_CONFIG, ...options.config } as MetaReasoningConfig;
65
+ this.config = {
66
+ ...DEFAULT_META_REASONING_CONFIG,
67
+ ...options.config,
68
+ modeProfiles: {
69
+ ...DEFAULT_META_REASONING_CONFIG.modeProfiles,
70
+ ...options.config?.modeProfiles,
71
+ },
72
+ };
55
73
 
56
74
  this.collector = new ObservationCollector();
57
75
  this.selector = new StrategySelector({
@@ -65,10 +83,17 @@ export class MetaReasoner {
65
83
  this.assessments.set(runId, []);
66
84
  this.adaptations.set(runId, []);
67
85
  this.currentMode.set(runId, this.config.defaultMode);
86
+ this.parameterOverrides.delete(runId);
68
87
 
69
88
  return this.getModeConfig(this.config.defaultMode);
70
89
  }
71
90
 
91
+ isTriggerEnabled(trigger: MetaTrigger): boolean {
92
+ const canonical = canonicalTrigger(trigger);
93
+ if (canonical === 'on_request') return true;
94
+ return this.config.triggers.some((t) => canonicalTrigger(t) === canonical);
95
+ }
96
+
72
97
  recordAction(runId: string, action: ActionRecord): void {
73
98
  this.collector.recordAction(runId, action);
74
99
  }
@@ -88,6 +113,7 @@ export class MetaReasoner {
88
113
  }
89
114
  ): boolean {
90
115
  if (!this.config.enabled) return false;
116
+ if (!this.isTriggerEnabled(trigger)) return false;
91
117
 
92
118
  const lastAssessment = this.lastAssessmentTime.get(runId) ?? 0;
93
119
  if (Date.now() - lastAssessment < this.config.metaAssessmentCooldown) {
@@ -155,6 +181,7 @@ export class MetaReasoner {
155
181
  });
156
182
 
157
183
  const parsed = parseMetaAssessmentResponse(response.content);
184
+ const recommendation = this.buildRecommendation(parsed, observation);
158
185
 
159
186
  const assessment: MetaAssessment = {
160
187
  id: `meta_${nanoid(10)}`,
@@ -165,18 +192,16 @@ export class MetaReasoner {
165
192
  confidence: parsed?.confidence ?? 0.5,
166
193
  reasoning: parsed?.reasoning ?? 'Assessment unavailable',
167
194
 
168
- issues: (parsed?.issues ?? []) as MetaIssue[],
195
+ issues: parsed?.issues ?? [],
169
196
  opportunities: (parsed?.opportunities ?? []).map((o) => ({
170
- type: o.type as MetaOpportunity['type'],
171
- confidence: o.expectedImprovement ?? 0.5,
197
+ type: o.type,
198
+ confidence: o.expectedImprovement,
172
199
  description: o.description,
173
- })) as MetaOpportunity[],
200
+ })),
174
201
 
175
- recommendation: this.buildRecommendation(parsed, observation),
202
+ recommendation,
176
203
 
177
- requiresAdaptation:
178
- parsed?.recommendation?.action !== undefined &&
179
- parsed?.recommendation?.action !== 'continue',
204
+ requiresAdaptation: recommendation.action !== 'continue',
180
205
 
181
206
  assessmentDuration: Date.now() - startTime,
182
207
  assessmentCost: (response.usage?.outputTokens ?? 0) * 0.00001,
@@ -211,16 +236,7 @@ export class MetaReasoner {
211
236
  };
212
237
  }
213
238
 
214
- return {
215
- action: parsed.recommendation.action as MetaRecommendation['action'],
216
- newMode: parsed.recommendation.newMode as ReasoningMode | undefined,
217
- parameterChanges: parsed.recommendation.parameterChanges as
218
- | Partial<ReasoningModeConfig>
219
- | undefined,
220
- contextAddition: parsed.recommendation.contextAddition,
221
- confidence: parsed.recommendation.confidence,
222
- reasoning: parsed.recommendation.reasoning,
223
- };
239
+ return { ...parsed.recommendation };
224
240
  }
225
241
 
226
242
  async adapt(runId: string, assessment: MetaAssessment): Promise<MetaAdaptation | null> {
@@ -239,38 +255,62 @@ export class MetaReasoner {
239
255
  return null;
240
256
  }
241
257
 
242
- const adaptationCount = this.adaptations.get(runId)?.length ?? 0;
258
+ const adaptationCount = (this.adaptations.get(runId) ?? []).filter(
259
+ (a) => a.type !== 'rollback'
260
+ ).length;
243
261
  if (adaptationCount >= this.config.maxAdaptations) {
244
262
  return null;
245
263
  }
246
264
 
247
265
  const currentMode = this.currentMode.get(runId) ?? this.config.defaultMode;
248
- const currentConfig = this.getModeConfig(currentMode);
266
+ const currentConfig = this.getCurrentConfig(runId);
249
267
 
250
- let newConfig: Partial<ReasoningModeConfig> = {};
251
- let adaptationType: MetaAdaptation['type'] = 'parameter_change';
268
+ let newConfig: Partial<ReasoningModeConfig>;
269
+ let adaptationType: MetaAdaptation['type'];
270
+ let newMode = currentMode;
271
+ const previousOverrides = this.parameterOverrides.get(runId);
252
272
 
253
273
  switch (recommendation.action) {
254
- case 'switch_mode':
255
- if (recommendation.newMode && this.config.allowedModes.includes(recommendation.newMode)) {
256
- newConfig = this.getModeConfig(recommendation.newMode);
257
- adaptationType = 'mode_switch';
258
- this.currentMode.set(runId, recommendation.newMode);
274
+ case 'switch_mode': {
275
+ const target = recommendation.newMode;
276
+ if (!target || target === currentMode || !this.config.allowedModes.includes(target)) {
277
+ return null;
259
278
  }
279
+ newConfig = this.getModeConfig(target);
280
+ adaptationType = 'mode_switch';
281
+ newMode = target;
282
+ this.currentMode.set(runId, target);
283
+ this.parameterOverrides.delete(runId);
260
284
  break;
285
+ }
261
286
 
262
- case 'adjust_parameters':
263
- if (recommendation.parameterChanges) {
264
- newConfig = { ...currentConfig, ...recommendation.parameterChanges };
265
- adaptationType = 'parameter_change';
287
+ case 'adjust_parameters': {
288
+ const changes = recommendation.parameterChanges;
289
+ if (!changes) return null;
290
+ const effective: Partial<ReasoningModeConfig> = {};
291
+ if (
292
+ changes.temperature !== undefined &&
293
+ changes.temperature !== currentConfig.temperature
294
+ ) {
295
+ effective.temperature = changes.temperature;
296
+ }
297
+ if (changes.depth !== undefined && changes.depth !== currentConfig.depth) {
298
+ effective.depth = changes.depth;
266
299
  }
300
+ if (Object.keys(effective).length === 0) return null;
301
+ newConfig = { ...currentConfig, ...effective };
302
+ adaptationType = 'parameter_change';
303
+ this.parameterOverrides.set(runId, { ...previousOverrides, ...effective });
267
304
  break;
305
+ }
268
306
 
269
307
  case 'inject_context':
308
+ if (!recommendation.contextAddition) return null;
309
+ newConfig = { ...currentConfig };
270
310
  adaptationType = 'context_injection';
271
311
  break;
272
312
 
273
- case 'abort':
313
+ default:
274
314
  return null;
275
315
  }
276
316
 
@@ -282,6 +322,9 @@ export class MetaReasoner {
282
322
  type: adaptationType,
283
323
  before: currentConfig,
284
324
  after: newConfig,
325
+ previousMode: currentMode,
326
+ newMode,
327
+ reason: recommendation.reasoning || undefined,
285
328
 
286
329
  rollbackable: this.config.enableRollback,
287
330
  rollbackDeadline: this.config.enableRollback
@@ -289,6 +332,10 @@ export class MetaReasoner {
289
332
  : undefined,
290
333
  };
291
334
 
335
+ if (previousOverrides) {
336
+ this.overridesBefore.set(adaptation.id, previousOverrides);
337
+ }
338
+
292
339
  const runAdaptations = this.adaptations.get(runId) ?? [];
293
340
  runAdaptations.push(adaptation);
294
341
  this.adaptations.set(runId, runAdaptations);
@@ -301,7 +348,7 @@ export class MetaReasoner {
301
348
  const runAdaptations = this.adaptations.get(runId) ?? [];
302
349
  const target = adaptationId
303
350
  ? runAdaptations.find((a) => a.id === adaptationId)
304
- : runAdaptations[runAdaptations.length - 1];
351
+ : [...runAdaptations].reverse().find((a) => a.type !== 'rollback');
305
352
 
306
353
  if (!target?.rollbackable) {
307
354
  return null;
@@ -319,15 +366,29 @@ export class MetaReasoner {
319
366
  type: 'rollback',
320
367
  before: target.after,
321
368
  after: target.before,
369
+ previousMode: target.newMode,
370
+ newMode: target.previousMode,
371
+ reason: `Rollback of ${target.id}`,
372
+ isRollback: true,
322
373
 
323
374
  rollbackable: false,
324
375
  };
325
376
 
326
- if (target.type === 'mode_switch' && target.before.mode) {
327
- this.currentMode.set(runId, target.before.mode);
377
+ if (target.type === 'mode_switch' || target.type === 'parameter_change') {
378
+ const restoredMode = target.previousMode ?? target.before.mode;
379
+ if (restoredMode) {
380
+ this.currentMode.set(runId, restoredMode);
381
+ }
382
+ const restoredOverrides = this.overridesBefore.get(target.id);
383
+ if (restoredOverrides) {
384
+ this.parameterOverrides.set(runId, restoredOverrides);
385
+ } else {
386
+ this.parameterOverrides.delete(runId);
387
+ }
328
388
  }
329
389
 
330
390
  target.rollbackable = false;
391
+ this.overridesBefore.delete(target.id);
331
392
  runAdaptations.push(rollback);
332
393
  return rollback;
333
394
  }
@@ -351,7 +412,7 @@ export class MetaReasoner {
351
412
 
352
413
  getCurrentConfig(runId: string): ReasoningModeConfig {
353
414
  const mode = this.currentMode.get(runId) ?? this.config.defaultMode;
354
- return this.getModeConfig(mode);
415
+ return { ...this.getModeConfig(mode), ...this.parameterOverrides.get(runId) };
355
416
  }
356
417
 
357
418
  getCurrentMode(runId: string): ReasoningMode {
@@ -384,9 +445,13 @@ export class MetaReasoner {
384
445
  this.collector.cleanupRun(runId);
385
446
  this.selector.cleanupRun(runId);
386
447
  this.assessments.delete(runId);
387
- this.adaptations.delete(runId);
388
448
  this.currentMode.delete(runId);
449
+ this.parameterOverrides.delete(runId);
389
450
  this.lastAssessmentTime.delete(runId);
390
451
  this.lastAdaptationTime.delete(runId);
452
+ for (const adaptation of this.adaptations.get(runId) ?? []) {
453
+ this.overridesBefore.delete(adaptation.id);
454
+ }
455
+ this.adaptations.delete(runId);
391
456
  }
392
457
  }
@@ -1,4 +1,11 @@
1
- import type { MetaObservation, ReasoningMode, ReasoningModeConfig } from '@cogitator-ai/types';
1
+ import type {
2
+ MetaIssue,
3
+ MetaObservation,
4
+ MetaOpportunity,
5
+ MetaRecommendation,
6
+ ReasoningMode,
7
+ ReasoningModeConfig,
8
+ } from '@cogitator-ai/types';
2
9
  import { extractJson } from '../utils';
3
10
 
4
11
  export function buildMetaAssessmentPrompt(
@@ -86,38 +93,145 @@ Analyze the agent's reasoning process and respond with a JSON object:
86
93
  }`;
87
94
  }
88
95
 
96
+ const REASONING_MODES: readonly ReasoningMode[] = [
97
+ 'analytical',
98
+ 'creative',
99
+ 'systematic',
100
+ 'intuitive',
101
+ 'reflective',
102
+ 'exploratory',
103
+ ];
104
+ const ISSUE_TYPES: readonly MetaIssue['type'][] = [
105
+ 'stagnation',
106
+ 'low_confidence',
107
+ 'high_cost',
108
+ 'repetition',
109
+ 'tool_failure',
110
+ ];
111
+ const SEVERITIES: readonly MetaIssue['severity'][] = ['low', 'medium', 'high'];
112
+ const OPPORTUNITY_TYPES: readonly MetaOpportunity['type'][] = [
113
+ 'mode_switch',
114
+ 'parameter_tune',
115
+ 'context_add',
116
+ 'tool_compose',
117
+ ];
118
+ const ACTIONS: readonly MetaRecommendation['action'][] = [
119
+ 'continue',
120
+ 'switch_mode',
121
+ 'adjust_parameters',
122
+ 'inject_context',
123
+ 'abort',
124
+ ];
125
+
89
126
  export interface ParsedAssessment {
90
- onTrack: boolean;
91
- confidence: number;
92
- reasoning: string;
93
- issues: Array<{
94
- type: string;
95
- severity: string;
96
- description: string;
97
- }>;
127
+ onTrack?: boolean;
128
+ confidence?: number;
129
+ reasoning?: string;
130
+ issues: MetaIssue[];
98
131
  opportunities: Array<{
99
- type: string;
132
+ type: MetaOpportunity['type'];
100
133
  description: string;
101
134
  expectedImprovement: number;
102
135
  }>;
103
- recommendation: {
104
- action: string;
105
- newMode?: string;
106
- parameterChanges?: Record<string, unknown>;
136
+ recommendation?: {
137
+ action: MetaRecommendation['action'];
138
+ newMode?: ReasoningMode;
139
+ parameterChanges?: Partial<ReasoningModeConfig>;
107
140
  contextAddition?: string;
108
141
  confidence: number;
109
142
  reasoning: string;
110
143
  };
111
144
  }
112
145
 
146
+ function isRecord(value: unknown): value is Record<string, unknown> {
147
+ return typeof value === 'object' && value !== null && !Array.isArray(value);
148
+ }
149
+
150
+ function pick<T extends string>(value: unknown, allowed: readonly T[]): T | undefined {
151
+ return typeof value === 'string' && (allowed as readonly string[]).includes(value)
152
+ ? (value as T)
153
+ : undefined;
154
+ }
155
+
156
+ function probability(value: unknown): number | undefined {
157
+ return typeof value === 'number' && Number.isFinite(value)
158
+ ? Math.min(1, Math.max(0, value))
159
+ : undefined;
160
+ }
161
+
162
+ function parseParameterChanges(value: unknown): Partial<ReasoningModeConfig> | undefined {
163
+ if (!isRecord(value)) return undefined;
164
+ const changes: Partial<ReasoningModeConfig> = {};
165
+ if (typeof value.temperature === 'number' && Number.isFinite(value.temperature)) {
166
+ changes.temperature = Math.min(2, Math.max(0, value.temperature));
167
+ }
168
+ if (typeof value.depth === 'number' && Number.isFinite(value.depth)) {
169
+ changes.depth = Math.min(10, Math.max(1, Math.round(value.depth)));
170
+ }
171
+ return Object.keys(changes).length > 0 ? changes : undefined;
172
+ }
173
+
174
+ function parseRecommendation(value: unknown): ParsedAssessment['recommendation'] {
175
+ if (!isRecord(value)) return undefined;
176
+ const action = pick(value.action, ACTIONS);
177
+ if (!action) return undefined;
178
+
179
+ return {
180
+ action,
181
+ newMode: pick(value.newMode, REASONING_MODES),
182
+ parameterChanges: parseParameterChanges(value.parameterChanges),
183
+ contextAddition:
184
+ typeof value.contextAddition === 'string' && value.contextAddition.trim()
185
+ ? value.contextAddition.trim()
186
+ : undefined,
187
+ confidence: probability(value.confidence) ?? 0,
188
+ reasoning: typeof value.reasoning === 'string' ? value.reasoning : '',
189
+ };
190
+ }
191
+
113
192
  export function parseMetaAssessmentResponse(content: string): ParsedAssessment | null {
193
+ let parsed: unknown;
114
194
  try {
115
195
  const json = extractJson(content);
116
196
  if (!json) return null;
117
- return JSON.parse(json) as ParsedAssessment;
197
+ parsed = JSON.parse(json);
118
198
  } catch {
119
199
  return null;
120
200
  }
201
+ if (!isRecord(parsed)) return null;
202
+
203
+ const issues: MetaIssue[] = [];
204
+ for (const raw of Array.isArray(parsed.issues) ? parsed.issues : []) {
205
+ if (!isRecord(raw)) continue;
206
+ const type = pick(raw.type, ISSUE_TYPES);
207
+ if (!type) continue;
208
+ issues.push({
209
+ type,
210
+ severity: pick(raw.severity, SEVERITIES) ?? 'medium',
211
+ description: typeof raw.description === 'string' ? raw.description : '',
212
+ });
213
+ }
214
+
215
+ const opportunities: ParsedAssessment['opportunities'] = [];
216
+ for (const raw of Array.isArray(parsed.opportunities) ? parsed.opportunities : []) {
217
+ if (!isRecord(raw)) continue;
218
+ const type = pick(raw.type, OPPORTUNITY_TYPES);
219
+ if (!type) continue;
220
+ opportunities.push({
221
+ type,
222
+ description: typeof raw.description === 'string' ? raw.description : '',
223
+ expectedImprovement: probability(raw.expectedImprovement) ?? 0.5,
224
+ });
225
+ }
226
+
227
+ return {
228
+ onTrack: typeof parsed.onTrack === 'boolean' ? parsed.onTrack : undefined,
229
+ confidence: probability(parsed.confidence),
230
+ reasoning: typeof parsed.reasoning === 'string' ? parsed.reasoning : undefined,
231
+ issues,
232
+ opportunities,
233
+ recommendation: parseRecommendation(parsed.recommendation),
234
+ };
121
235
  }
122
236
 
123
237
  export const META_REASONING_SYSTEM_PROMPT = `You are a meta-reasoning system analyzing an AI agent's reasoning process.