@cogitator-ai/self-modifying 0.1.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 (143) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +714 -0
  3. package/dist/architecture-evolution/capability-analyzer.d.ts +32 -0
  4. package/dist/architecture-evolution/capability-analyzer.d.ts.map +1 -0
  5. package/dist/architecture-evolution/capability-analyzer.js +264 -0
  6. package/dist/architecture-evolution/capability-analyzer.js.map +1 -0
  7. package/dist/architecture-evolution/evolution-strategy.d.ts +29 -0
  8. package/dist/architecture-evolution/evolution-strategy.d.ts.map +1 -0
  9. package/dist/architecture-evolution/evolution-strategy.js +176 -0
  10. package/dist/architecture-evolution/evolution-strategy.js.map +1 -0
  11. package/dist/architecture-evolution/index.d.ts +5 -0
  12. package/dist/architecture-evolution/index.d.ts.map +1 -0
  13. package/dist/architecture-evolution/index.js +5 -0
  14. package/dist/architecture-evolution/index.js.map +1 -0
  15. package/dist/architecture-evolution/parameter-optimizer.d.ts +67 -0
  16. package/dist/architecture-evolution/parameter-optimizer.d.ts.map +1 -0
  17. package/dist/architecture-evolution/parameter-optimizer.js +341 -0
  18. package/dist/architecture-evolution/parameter-optimizer.js.map +1 -0
  19. package/dist/architecture-evolution/prompts.d.ts +33 -0
  20. package/dist/architecture-evolution/prompts.d.ts.map +1 -0
  21. package/dist/architecture-evolution/prompts.js +169 -0
  22. package/dist/architecture-evolution/prompts.js.map +1 -0
  23. package/dist/constraints/index.d.ts +4 -0
  24. package/dist/constraints/index.d.ts.map +1 -0
  25. package/dist/constraints/index.js +4 -0
  26. package/dist/constraints/index.js.map +1 -0
  27. package/dist/constraints/modification-validator.d.ts +26 -0
  28. package/dist/constraints/modification-validator.d.ts.map +1 -0
  29. package/dist/constraints/modification-validator.js +313 -0
  30. package/dist/constraints/modification-validator.js.map +1 -0
  31. package/dist/constraints/rollback-manager.d.ts +52 -0
  32. package/dist/constraints/rollback-manager.d.ts.map +1 -0
  33. package/dist/constraints/rollback-manager.js +113 -0
  34. package/dist/constraints/rollback-manager.js.map +1 -0
  35. package/dist/constraints/safety-constraints.d.ts +11 -0
  36. package/dist/constraints/safety-constraints.d.ts.map +1 -0
  37. package/dist/constraints/safety-constraints.js +78 -0
  38. package/dist/constraints/safety-constraints.js.map +1 -0
  39. package/dist/events/event-emitter.d.ts +12 -0
  40. package/dist/events/event-emitter.d.ts.map +1 -0
  41. package/dist/events/event-emitter.js +43 -0
  42. package/dist/events/event-emitter.js.map +1 -0
  43. package/dist/events/index.d.ts +2 -0
  44. package/dist/events/index.d.ts.map +1 -0
  45. package/dist/events/index.js +2 -0
  46. package/dist/events/index.js.map +1 -0
  47. package/dist/index.d.ts +8 -0
  48. package/dist/index.d.ts.map +1 -0
  49. package/dist/index.js +7 -0
  50. package/dist/index.js.map +1 -0
  51. package/dist/meta-reasoning/index.d.ts +5 -0
  52. package/dist/meta-reasoning/index.d.ts.map +1 -0
  53. package/dist/meta-reasoning/index.js +5 -0
  54. package/dist/meta-reasoning/index.js.map +1 -0
  55. package/dist/meta-reasoning/meta-reasoner.d.ts +53 -0
  56. package/dist/meta-reasoning/meta-reasoner.d.ts.map +1 -0
  57. package/dist/meta-reasoning/meta-reasoner.js +261 -0
  58. package/dist/meta-reasoning/meta-reasoner.js.map +1 -0
  59. package/dist/meta-reasoning/observation-collector.d.ts +37 -0
  60. package/dist/meta-reasoning/observation-collector.d.ts.map +1 -0
  61. package/dist/meta-reasoning/observation-collector.js +123 -0
  62. package/dist/meta-reasoning/observation-collector.js.map +1 -0
  63. package/dist/meta-reasoning/prompts.d.ts +31 -0
  64. package/dist/meta-reasoning/prompts.d.ts.map +1 -0
  65. package/dist/meta-reasoning/prompts.js +96 -0
  66. package/dist/meta-reasoning/prompts.js.map +1 -0
  67. package/dist/meta-reasoning/strategy-selector.d.ts +27 -0
  68. package/dist/meta-reasoning/strategy-selector.d.ts.map +1 -0
  69. package/dist/meta-reasoning/strategy-selector.js +138 -0
  70. package/dist/meta-reasoning/strategy-selector.js.map +1 -0
  71. package/dist/self-modifying-agent.d.ts +61 -0
  72. package/dist/self-modifying-agent.d.ts.map +1 -0
  73. package/dist/self-modifying-agent.js +449 -0
  74. package/dist/self-modifying-agent.js.map +1 -0
  75. package/dist/tool-generation/gap-analyzer.d.ts +25 -0
  76. package/dist/tool-generation/gap-analyzer.d.ts.map +1 -0
  77. package/dist/tool-generation/gap-analyzer.js +153 -0
  78. package/dist/tool-generation/gap-analyzer.js.map +1 -0
  79. package/dist/tool-generation/generated-tool-store.d.ts +51 -0
  80. package/dist/tool-generation/generated-tool-store.d.ts.map +1 -0
  81. package/dist/tool-generation/generated-tool-store.js +195 -0
  82. package/dist/tool-generation/generated-tool-store.js.map +1 -0
  83. package/dist/tool-generation/index.d.ts +7 -0
  84. package/dist/tool-generation/index.d.ts.map +1 -0
  85. package/dist/tool-generation/index.js +7 -0
  86. package/dist/tool-generation/index.js.map +1 -0
  87. package/dist/tool-generation/prompts.d.ts +28 -0
  88. package/dist/tool-generation/prompts.d.ts.map +1 -0
  89. package/dist/tool-generation/prompts.js +269 -0
  90. package/dist/tool-generation/prompts.js.map +1 -0
  91. package/dist/tool-generation/tool-generator.d.ts +29 -0
  92. package/dist/tool-generation/tool-generator.d.ts.map +1 -0
  93. package/dist/tool-generation/tool-generator.js +169 -0
  94. package/dist/tool-generation/tool-generator.js.map +1 -0
  95. package/dist/tool-generation/tool-sandbox.d.ts +31 -0
  96. package/dist/tool-generation/tool-sandbox.d.ts.map +1 -0
  97. package/dist/tool-generation/tool-sandbox.js +240 -0
  98. package/dist/tool-generation/tool-sandbox.js.map +1 -0
  99. package/dist/tool-generation/tool-validator.d.ts +32 -0
  100. package/dist/tool-generation/tool-validator.d.ts.map +1 -0
  101. package/dist/tool-generation/tool-validator.js +304 -0
  102. package/dist/tool-generation/tool-validator.js.map +1 -0
  103. package/dist/utils/index.d.ts +2 -0
  104. package/dist/utils/index.d.ts.map +1 -0
  105. package/dist/utils/index.js +2 -0
  106. package/dist/utils/index.js.map +1 -0
  107. package/dist/utils/llm-helper.d.ts +6 -0
  108. package/dist/utils/llm-helper.d.ts.map +1 -0
  109. package/dist/utils/llm-helper.js +18 -0
  110. package/dist/utils/llm-helper.js.map +1 -0
  111. package/package.json +61 -0
  112. package/src/__tests__/architecture-evolution.test.ts +368 -0
  113. package/src/__tests__/constraints.test.ts +266 -0
  114. package/src/__tests__/index.test.ts +99 -0
  115. package/src/__tests__/meta-reasoning.test.ts +343 -0
  116. package/src/__tests__/tool-generation.test.ts +455 -0
  117. package/src/architecture-evolution/capability-analyzer.ts +337 -0
  118. package/src/architecture-evolution/evolution-strategy.ts +224 -0
  119. package/src/architecture-evolution/index.ts +26 -0
  120. package/src/architecture-evolution/parameter-optimizer.ts +489 -0
  121. package/src/architecture-evolution/prompts.ts +216 -0
  122. package/src/constraints/index.ts +23 -0
  123. package/src/constraints/modification-validator.ts +402 -0
  124. package/src/constraints/rollback-manager.ts +173 -0
  125. package/src/constraints/safety-constraints.ts +103 -0
  126. package/src/events/event-emitter.ts +62 -0
  127. package/src/events/index.ts +1 -0
  128. package/src/index.ts +112 -0
  129. package/src/meta-reasoning/index.ts +24 -0
  130. package/src/meta-reasoning/meta-reasoner.ts +381 -0
  131. package/src/meta-reasoning/observation-collector.ts +161 -0
  132. package/src/meta-reasoning/prompts.ts +131 -0
  133. package/src/meta-reasoning/strategy-selector.ts +179 -0
  134. package/src/self-modifying-agent.ts +585 -0
  135. package/src/tool-generation/gap-analyzer.ts +234 -0
  136. package/src/tool-generation/generated-tool-store.ts +268 -0
  137. package/src/tool-generation/index.ts +19 -0
  138. package/src/tool-generation/prompts.ts +308 -0
  139. package/src/tool-generation/tool-generator.ts +243 -0
  140. package/src/tool-generation/tool-sandbox.ts +332 -0
  141. package/src/tool-generation/tool-validator.ts +365 -0
  142. package/src/utils/index.ts +1 -0
  143. package/src/utils/llm-helper.ts +24 -0
@@ -0,0 +1,23 @@
1
+ export {
2
+ DEFAULT_SAFETY_CONSTRAINTS,
3
+ DEFAULT_CAPABILITY_CONSTRAINTS,
4
+ DEFAULT_RESOURCE_CONSTRAINTS,
5
+ createDefaultConstraints,
6
+ mergeSafetyConstraints,
7
+ mergeCapabilityConstraints,
8
+ mergeResourceConstraints,
9
+ mergeConstraints,
10
+ } from './safety-constraints';
11
+
12
+ export {
13
+ RollbackManager,
14
+ InMemoryCheckpointStore,
15
+ type CheckpointStore,
16
+ type RollbackManagerOptions,
17
+ type CheckpointDiff,
18
+ } from './rollback-manager';
19
+
20
+ export {
21
+ ModificationValidator,
22
+ type ModificationValidatorOptions,
23
+ } from './modification-validator';
@@ -0,0 +1,402 @@
1
+ import type {
2
+ ModificationRequest,
3
+ ModificationValidationResult,
4
+ ModificationConstraints,
5
+ ConstraintCheckResult,
6
+ SafetyConstraint,
7
+ CapabilityConstraint,
8
+ ResourceConstraint,
9
+ CustomConstraint,
10
+ ConstraintRule,
11
+ } from '@cogitator-ai/types';
12
+ import { createDefaultConstraints, mergeConstraints } from './safety-constraints';
13
+
14
+ export interface ModificationValidatorOptions {
15
+ constraints?: Partial<ModificationConstraints>;
16
+ strictMode?: boolean;
17
+ }
18
+
19
+ export class ModificationValidator {
20
+ private constraints: ModificationConstraints;
21
+ private strictMode: boolean;
22
+
23
+ constructor(options: ModificationValidatorOptions = {}) {
24
+ this.constraints = mergeConstraints(
25
+ createDefaultConstraints(),
26
+ options.constraints ?? {}
27
+ );
28
+ this.strictMode = options.strictMode ?? false;
29
+ }
30
+
31
+ async validate(request: ModificationRequest): Promise<ModificationValidationResult> {
32
+ const results: ConstraintCheckResult[] = [];
33
+ const errors: string[] = [];
34
+ const warnings: string[] = [];
35
+
36
+ const safetyResults = await this.checkSafetyConstraints(request);
37
+ results.push(...safetyResults);
38
+
39
+ const capabilityResults = await this.checkCapabilityConstraints(request);
40
+ results.push(...capabilityResults);
41
+
42
+ const resourceResults = await this.checkResourceConstraints(request);
43
+ results.push(...resourceResults);
44
+
45
+ const customResults = await this.checkCustomConstraints(request);
46
+ results.push(...customResults);
47
+
48
+ for (const result of results) {
49
+ if (!result.satisfied) {
50
+ if (result.severity === 'critical' || result.severity === 'error') {
51
+ errors.push(result.message ?? `Constraint ${result.constraintName} violated`);
52
+ } else {
53
+ warnings.push(result.message ?? `Constraint ${result.constraintName} warning`);
54
+ }
55
+ }
56
+ }
57
+
58
+ const hasCriticalViolation = results.some(
59
+ (r) => !r.satisfied && r.severity === 'critical'
60
+ );
61
+ const hasErrorViolation = results.some(
62
+ (r) => !r.satisfied && r.severity === 'error'
63
+ );
64
+
65
+ const valid = this.strictMode
66
+ ? results.every((r) => r.satisfied)
67
+ : !hasCriticalViolation && !hasErrorViolation;
68
+
69
+ return {
70
+ valid,
71
+ constraintResults: results,
72
+ errors,
73
+ warnings,
74
+ rollbackRequired: hasCriticalViolation,
75
+ };
76
+ }
77
+
78
+ private async checkSafetyConstraints(
79
+ request: ModificationRequest
80
+ ): Promise<ConstraintCheckResult[]> {
81
+ const results: ConstraintCheckResult[] = [];
82
+
83
+ for (const constraint of this.constraints.safety) {
84
+ const satisfied = this.evaluateSafetyRule(constraint.rule, request);
85
+ results.push({
86
+ constraintId: constraint.id,
87
+ constraintName: constraint.name,
88
+ satisfied,
89
+ severity: constraint.severity,
90
+ message: satisfied ? undefined : constraint.description,
91
+ });
92
+ }
93
+
94
+ return results;
95
+ }
96
+
97
+ private evaluateSafetyRule(rule: ConstraintRule, request: ModificationRequest): boolean {
98
+ if (typeof rule === 'string') {
99
+ return this.evaluateExpression(rule, request.payload as Record<string, unknown>);
100
+ }
101
+
102
+ const payload = request.payload as Record<string, unknown>;
103
+
104
+ switch (rule.type) {
105
+ case 'invariant':
106
+ return this.evaluateExpression(rule.expression ?? '', payload);
107
+ case 'precondition':
108
+ return this.evaluateExpression(rule.expression ?? '', payload);
109
+ case 'postcondition':
110
+ return true;
111
+ case 'temporal':
112
+ if (rule.pattern?.source === 'never') {
113
+ return !this.evaluateExpression(rule.expression ?? '', payload);
114
+ }
115
+ return true;
116
+ default:
117
+ return true;
118
+ }
119
+ }
120
+
121
+ private evaluateExpression(expression: string, context: Record<string, unknown>): boolean {
122
+ const parts = expression.split(/\s+(AND|OR)\s+/i);
123
+ const conditions: boolean[] = [];
124
+ const operators: string[] = [];
125
+
126
+ for (let i = 0; i < parts.length; i++) {
127
+ const part = parts[i].trim();
128
+ if (part.toUpperCase() === 'AND' || part.toUpperCase() === 'OR') {
129
+ operators.push(part.toUpperCase());
130
+ } else {
131
+ conditions.push(this.evaluateSimpleCondition(part, context));
132
+ }
133
+ }
134
+
135
+ if (conditions.length === 0) return true;
136
+
137
+ let result = conditions[0];
138
+ for (let i = 0; i < operators.length; i++) {
139
+ if (operators[i] === 'AND') {
140
+ result = result && conditions[i + 1];
141
+ } else {
142
+ result = result || conditions[i + 1];
143
+ }
144
+ }
145
+
146
+ return result;
147
+ }
148
+
149
+ private evaluateSimpleCondition(
150
+ condition: string,
151
+ context: Record<string, unknown>
152
+ ): boolean {
153
+ const operators = ['<=', '>=', '<', '>', '!=', '='];
154
+ for (const op of operators) {
155
+ const idx = condition.indexOf(op);
156
+ if (idx !== -1) {
157
+ const left = condition.substring(0, idx).trim();
158
+ const right = condition.substring(idx + op.length).trim();
159
+ const leftValue = this.resolveValue(left, context);
160
+ const rightValue = this.resolveValue(right, context);
161
+
162
+ switch (op) {
163
+ case '=':
164
+ return leftValue === rightValue;
165
+ case '!=':
166
+ return leftValue !== rightValue;
167
+ case '<':
168
+ return Number(leftValue) < Number(rightValue);
169
+ case '>':
170
+ return Number(leftValue) > Number(rightValue);
171
+ case '<=':
172
+ return Number(leftValue) <= Number(rightValue);
173
+ case '>=':
174
+ return Number(leftValue) >= Number(rightValue);
175
+ }
176
+ }
177
+ }
178
+
179
+ const value = this.resolveValue(condition, context);
180
+ return Boolean(value);
181
+ }
182
+
183
+ private resolveValue(expr: string, context: Record<string, unknown>): unknown {
184
+ if (expr === 'true') return true;
185
+ if (expr === 'false') return false;
186
+ if (/^\d+(\.\d+)?$/.test(expr)) return parseFloat(expr);
187
+
188
+ const keys = expr.split('.');
189
+ let current: unknown = context;
190
+ for (const key of keys) {
191
+ if (current && typeof current === 'object') {
192
+ current = (current as Record<string, unknown>)[key];
193
+ } else {
194
+ return undefined;
195
+ }
196
+ }
197
+ return current;
198
+ }
199
+
200
+ private async checkCapabilityConstraints(
201
+ request: ModificationRequest
202
+ ): Promise<ConstraintCheckResult[]> {
203
+ const results: ConstraintCheckResult[] = [];
204
+
205
+ if (request.type !== 'tool_generation') {
206
+ return results;
207
+ }
208
+
209
+ const payload = request.payload as { category?: string; complexity?: number };
210
+
211
+ for (const constraint of this.constraints.capability) {
212
+ let satisfied = true;
213
+ let message: string | undefined;
214
+
215
+ if (payload.category) {
216
+ if (constraint.forbidden?.includes(payload.category)) {
217
+ satisfied = false;
218
+ message = `Category '${payload.category}' is forbidden`;
219
+ } else if (
220
+ constraint.allowed?.length &&
221
+ !constraint.allowed.includes(payload.category)
222
+ ) {
223
+ satisfied = false;
224
+ message = `Category '${payload.category}' is not in allowed list`;
225
+ }
226
+ }
227
+
228
+ if (
229
+ satisfied &&
230
+ constraint.maxComplexity &&
231
+ payload.complexity &&
232
+ payload.complexity > constraint.maxComplexity
233
+ ) {
234
+ satisfied = false;
235
+ message = `Complexity ${payload.complexity} exceeds max ${constraint.maxComplexity}`;
236
+ }
237
+
238
+ results.push({
239
+ constraintId: constraint.id,
240
+ constraintName: constraint.name,
241
+ satisfied,
242
+ severity: 'error',
243
+ message,
244
+ });
245
+ }
246
+
247
+ return results;
248
+ }
249
+
250
+ private async checkResourceConstraints(
251
+ request: ModificationRequest
252
+ ): Promise<ConstraintCheckResult[]> {
253
+ const results: ConstraintCheckResult[] = [];
254
+ const payload = request.payload as {
255
+ tokensUsed?: number;
256
+ cost?: number;
257
+ activeTools?: number;
258
+ };
259
+
260
+ for (const constraint of this.constraints.resource) {
261
+ let satisfied = true;
262
+ let message: string | undefined;
263
+
264
+ if (
265
+ constraint.maxTokensPerRun &&
266
+ payload.tokensUsed &&
267
+ payload.tokensUsed > constraint.maxTokensPerRun
268
+ ) {
269
+ satisfied = false;
270
+ message = `Tokens ${payload.tokensUsed} exceeds max ${constraint.maxTokensPerRun}`;
271
+ }
272
+
273
+ if (
274
+ satisfied &&
275
+ constraint.maxCostPerRun &&
276
+ payload.cost &&
277
+ payload.cost > constraint.maxCostPerRun
278
+ ) {
279
+ satisfied = false;
280
+ message = `Cost ${payload.cost} exceeds max ${constraint.maxCostPerRun}`;
281
+ }
282
+
283
+ if (
284
+ satisfied &&
285
+ constraint.maxToolsActive &&
286
+ payload.activeTools &&
287
+ payload.activeTools > constraint.maxToolsActive
288
+ ) {
289
+ satisfied = false;
290
+ message = `Active tools ${payload.activeTools} exceeds max ${constraint.maxToolsActive}`;
291
+ }
292
+
293
+ results.push({
294
+ constraintId: constraint.id,
295
+ constraintName: constraint.name,
296
+ satisfied,
297
+ severity: 'error',
298
+ message,
299
+ });
300
+ }
301
+
302
+ return results;
303
+ }
304
+
305
+ private async checkCustomConstraints(
306
+ request: ModificationRequest
307
+ ): Promise<ConstraintCheckResult[]> {
308
+ const results: ConstraintCheckResult[] = [];
309
+
310
+ for (const constraint of this.constraints.custom ?? []) {
311
+ let satisfied: boolean;
312
+ try {
313
+ satisfied = await constraint.predicate(request);
314
+ } catch {
315
+ satisfied = false;
316
+ }
317
+
318
+ results.push({
319
+ constraintId: constraint.id,
320
+ constraintName: constraint.name,
321
+ satisfied,
322
+ severity: 'error',
323
+ message: satisfied ? undefined : constraint.description,
324
+ });
325
+ }
326
+
327
+ return results;
328
+ }
329
+
330
+ addSafetyConstraint(constraint: SafetyConstraint): void {
331
+ const idx = this.constraints.safety.findIndex((c) => c.id === constraint.id);
332
+ if (idx >= 0) {
333
+ this.constraints.safety[idx] = constraint;
334
+ } else {
335
+ this.constraints.safety.push(constraint);
336
+ }
337
+ }
338
+
339
+ addCapabilityConstraint(constraint: CapabilityConstraint): void {
340
+ const idx = this.constraints.capability.findIndex((c) => c.id === constraint.id);
341
+ if (idx >= 0) {
342
+ this.constraints.capability[idx] = constraint;
343
+ } else {
344
+ this.constraints.capability.push(constraint);
345
+ }
346
+ }
347
+
348
+ addResourceConstraint(constraint: ResourceConstraint): void {
349
+ const idx = this.constraints.resource.findIndex((c) => c.id === constraint.id);
350
+ if (idx >= 0) {
351
+ this.constraints.resource[idx] = constraint;
352
+ } else {
353
+ this.constraints.resource.push(constraint);
354
+ }
355
+ }
356
+
357
+ addCustomConstraint(constraint: CustomConstraint): void {
358
+ if (!this.constraints.custom) {
359
+ this.constraints.custom = [];
360
+ }
361
+ const idx = this.constraints.custom.findIndex((c) => c.id === constraint.id);
362
+ if (idx >= 0) {
363
+ this.constraints.custom[idx] = constraint;
364
+ } else {
365
+ this.constraints.custom.push(constraint);
366
+ }
367
+ }
368
+
369
+ removeConstraint(id: string): boolean {
370
+ const safetyIdx = this.constraints.safety.findIndex((c) => c.id === id);
371
+ if (safetyIdx >= 0) {
372
+ this.constraints.safety.splice(safetyIdx, 1);
373
+ return true;
374
+ }
375
+
376
+ const capIdx = this.constraints.capability.findIndex((c) => c.id === id);
377
+ if (capIdx >= 0) {
378
+ this.constraints.capability.splice(capIdx, 1);
379
+ return true;
380
+ }
381
+
382
+ const resIdx = this.constraints.resource.findIndex((c) => c.id === id);
383
+ if (resIdx >= 0) {
384
+ this.constraints.resource.splice(resIdx, 1);
385
+ return true;
386
+ }
387
+
388
+ if (this.constraints.custom) {
389
+ const customIdx = this.constraints.custom.findIndex((c) => c.id === id);
390
+ if (customIdx >= 0) {
391
+ this.constraints.custom.splice(customIdx, 1);
392
+ return true;
393
+ }
394
+ }
395
+
396
+ return false;
397
+ }
398
+
399
+ getConstraints(): ModificationConstraints {
400
+ return { ...this.constraints };
401
+ }
402
+ }
@@ -0,0 +1,173 @@
1
+ import { nanoid } from 'nanoid';
2
+ import type {
3
+ ModificationCheckpoint,
4
+ AppliedModification,
5
+ AgentConfig,
6
+ Tool,
7
+ } from '@cogitator-ai/types';
8
+
9
+ export interface CheckpointStore {
10
+ save(checkpoint: ModificationCheckpoint): Promise<void>;
11
+ get(id: string): Promise<ModificationCheckpoint | null>;
12
+ list(agentId: string): Promise<ModificationCheckpoint[]>;
13
+ delete(id: string): Promise<boolean>;
14
+ prune(agentId: string, keepCount: number): Promise<number>;
15
+ }
16
+
17
+ export class InMemoryCheckpointStore implements CheckpointStore {
18
+ private checkpoints = new Map<string, ModificationCheckpoint>();
19
+ private agentIndex = new Map<string, Set<string>>();
20
+
21
+ async save(checkpoint: ModificationCheckpoint): Promise<void> {
22
+ this.checkpoints.set(checkpoint.id, checkpoint);
23
+ if (!this.agentIndex.has(checkpoint.agentId)) {
24
+ this.agentIndex.set(checkpoint.agentId, new Set());
25
+ }
26
+ this.agentIndex.get(checkpoint.agentId)!.add(checkpoint.id);
27
+ }
28
+
29
+ async get(id: string): Promise<ModificationCheckpoint | null> {
30
+ return this.checkpoints.get(id) ?? null;
31
+ }
32
+
33
+ async list(agentId: string): Promise<ModificationCheckpoint[]> {
34
+ const ids = this.agentIndex.get(agentId);
35
+ if (!ids) return [];
36
+ return [...ids]
37
+ .map((id) => this.checkpoints.get(id)!)
38
+ .filter(Boolean)
39
+ .sort((a, b) => b.timestamp.getTime() - a.timestamp.getTime());
40
+ }
41
+
42
+ async delete(id: string): Promise<boolean> {
43
+ const checkpoint = this.checkpoints.get(id);
44
+ if (!checkpoint) return false;
45
+ this.checkpoints.delete(id);
46
+ this.agentIndex.get(checkpoint.agentId)?.delete(id);
47
+ return true;
48
+ }
49
+
50
+ async prune(agentId: string, keepCount: number): Promise<number> {
51
+ const checkpoints = await this.list(agentId);
52
+ const toDelete = checkpoints.slice(keepCount);
53
+ for (const cp of toDelete) {
54
+ await this.delete(cp.id);
55
+ }
56
+ return toDelete.length;
57
+ }
58
+ }
59
+
60
+ export interface RollbackManagerOptions {
61
+ maxCheckpoints: number;
62
+ checkpointStore?: CheckpointStore;
63
+ }
64
+
65
+ export interface CheckpointDiff {
66
+ configChanges: Array<{ key: string; before: unknown; after: unknown }>;
67
+ toolsAdded: string[];
68
+ toolsRemoved: string[];
69
+ modificationsApplied: AppliedModification[];
70
+ }
71
+
72
+ export class RollbackManager {
73
+ private maxCheckpoints: number;
74
+ private store: CheckpointStore;
75
+
76
+ constructor(options: RollbackManagerOptions) {
77
+ this.maxCheckpoints = options.maxCheckpoints;
78
+ this.store = options.checkpointStore ?? new InMemoryCheckpointStore();
79
+ }
80
+
81
+ async createCheckpoint(
82
+ agentId: string,
83
+ agentConfig: AgentConfig,
84
+ tools: Tool[],
85
+ modifications: AppliedModification[]
86
+ ): Promise<ModificationCheckpoint> {
87
+ const checkpoint: ModificationCheckpoint = {
88
+ id: `ckpt_${nanoid(12)}`,
89
+ agentId,
90
+ timestamp: new Date(),
91
+ agentConfig: { ...agentConfig },
92
+ tools: tools.map((t) => ({ ...t })),
93
+ modifications: [...modifications],
94
+ };
95
+
96
+ await this.store.save(checkpoint);
97
+ await this.store.prune(agentId, this.maxCheckpoints);
98
+
99
+ return checkpoint;
100
+ }
101
+
102
+ async getCheckpoint(id: string): Promise<ModificationCheckpoint | null> {
103
+ return this.store.get(id);
104
+ }
105
+
106
+ async listCheckpoints(agentId: string): Promise<ModificationCheckpoint[]> {
107
+ return this.store.list(agentId);
108
+ }
109
+
110
+ async getLatestCheckpoint(agentId: string): Promise<ModificationCheckpoint | null> {
111
+ const checkpoints = await this.store.list(agentId);
112
+ return checkpoints[0] ?? null;
113
+ }
114
+
115
+ async rollbackTo(
116
+ checkpointId: string
117
+ ): Promise<{ agentConfig: AgentConfig; tools: Tool[] } | null> {
118
+ const checkpoint = await this.store.get(checkpointId);
119
+ if (!checkpoint) return null;
120
+
121
+ return {
122
+ agentConfig: checkpoint.agentConfig as unknown as AgentConfig,
123
+ tools: checkpoint.tools.map((t) => ({ ...t })),
124
+ };
125
+ }
126
+
127
+ async rollbackToLatest(
128
+ agentId: string
129
+ ): Promise<{ agentConfig: AgentConfig; tools: Tool[] } | null> {
130
+ const latest = await this.getLatestCheckpoint(agentId);
131
+ if (!latest) return null;
132
+ return this.rollbackTo(latest.id);
133
+ }
134
+
135
+ compareCheckpoints(
136
+ checkpointA: ModificationCheckpoint,
137
+ checkpointB: ModificationCheckpoint
138
+ ): CheckpointDiff {
139
+ const configChanges: CheckpointDiff['configChanges'] = [];
140
+ const keysA = Object.keys(checkpointA.agentConfig) as (keyof AgentConfig)[];
141
+ const keysB = Object.keys(checkpointB.agentConfig) as (keyof AgentConfig)[];
142
+ const allKeys = new Set([...keysA, ...keysB]);
143
+
144
+ for (const key of allKeys) {
145
+ const valA = checkpointA.agentConfig[key];
146
+ const valB = checkpointB.agentConfig[key];
147
+ if (JSON.stringify(valA) !== JSON.stringify(valB)) {
148
+ configChanges.push({ key, before: valA, after: valB });
149
+ }
150
+ }
151
+
152
+ const toolsA = new Set(checkpointA.tools.map((t) => t.name));
153
+ const toolsB = new Set(checkpointB.tools.map((t) => t.name));
154
+
155
+ const toolsAdded = [...toolsB].filter((t) => !toolsA.has(t));
156
+ const toolsRemoved = [...toolsA].filter((t) => !toolsB.has(t));
157
+
158
+ const modsBefore = new Set(checkpointA.modifications.map((m) => m.id));
159
+ const modificationsApplied = checkpointB.modifications.filter(
160
+ (m) => !modsBefore.has(m.id)
161
+ );
162
+
163
+ return { configChanges, toolsAdded, toolsRemoved, modificationsApplied };
164
+ }
165
+
166
+ async pruneCheckpoints(agentId: string, keepCount?: number): Promise<number> {
167
+ return this.store.prune(agentId, keepCount ?? this.maxCheckpoints);
168
+ }
169
+
170
+ async deleteCheckpoint(id: string): Promise<boolean> {
171
+ return this.store.delete(id);
172
+ }
173
+ }
@@ -0,0 +1,103 @@
1
+ import type {
2
+ SafetyConstraint,
3
+ CapabilityConstraint,
4
+ ResourceConstraint,
5
+ ModificationConstraints,
6
+ } from '@cogitator-ai/types';
7
+ import { DEFAULT_SAFETY_CONSTRAINTS } from '@cogitator-ai/types';
8
+
9
+ export { DEFAULT_SAFETY_CONSTRAINTS };
10
+
11
+ export const DEFAULT_CAPABILITY_CONSTRAINTS: CapabilityConstraint[] = [
12
+ {
13
+ id: 'allowed_tool_categories',
14
+ name: 'Allowed Tool Categories',
15
+ type: 'tool_category',
16
+ description: 'Allowed and forbidden tool categories',
17
+ allowed: ['math', 'text', 'utility', 'data'],
18
+ forbidden: ['system', 'network', 'file'],
19
+ maxComplexity: 100,
20
+ },
21
+ ];
22
+
23
+ export const DEFAULT_RESOURCE_CONSTRAINTS: ResourceConstraint[] = [
24
+ {
25
+ id: 'default_resource_limits',
26
+ name: 'Default Resource Limits',
27
+ resource: 'runtime',
28
+ description: 'Default runtime resource limits',
29
+ maxMemory: 128,
30
+ maxTokensPerRun: 100000,
31
+ maxCostPerRun: 1.0,
32
+ maxToolsActive: 20,
33
+ },
34
+ ];
35
+
36
+ export function createDefaultConstraints(): ModificationConstraints {
37
+ return {
38
+ safety: [...DEFAULT_SAFETY_CONSTRAINTS],
39
+ capability: [...DEFAULT_CAPABILITY_CONSTRAINTS],
40
+ resource: [...DEFAULT_RESOURCE_CONSTRAINTS],
41
+ custom: [],
42
+ };
43
+ }
44
+
45
+ export function mergeSafetyConstraints(
46
+ base: SafetyConstraint[],
47
+ additions: SafetyConstraint[]
48
+ ): SafetyConstraint[] {
49
+ const result = new Map<string, SafetyConstraint>();
50
+ for (const c of base) {
51
+ result.set(c.id, c);
52
+ }
53
+ for (const c of additions) {
54
+ result.set(c.id, c);
55
+ }
56
+ return [...result.values()];
57
+ }
58
+
59
+ export function mergeCapabilityConstraints(
60
+ base: CapabilityConstraint[],
61
+ additions: CapabilityConstraint[]
62
+ ): CapabilityConstraint[] {
63
+ const result = new Map<string, CapabilityConstraint>();
64
+ for (const c of base) {
65
+ result.set(c.id, c);
66
+ }
67
+ for (const c of additions) {
68
+ result.set(c.id, c);
69
+ }
70
+ return [...result.values()];
71
+ }
72
+
73
+ export function mergeResourceConstraints(
74
+ base: ResourceConstraint[],
75
+ additions: ResourceConstraint[]
76
+ ): ResourceConstraint[] {
77
+ const result = new Map<string, ResourceConstraint>();
78
+ for (const c of base) {
79
+ result.set(c.id, c);
80
+ }
81
+ for (const c of additions) {
82
+ result.set(c.id, c);
83
+ }
84
+ return [...result.values()];
85
+ }
86
+
87
+ export function mergeConstraints(
88
+ base: ModificationConstraints,
89
+ additions: Partial<ModificationConstraints>
90
+ ): ModificationConstraints {
91
+ return {
92
+ safety: additions.safety
93
+ ? mergeSafetyConstraints(base.safety, additions.safety)
94
+ : base.safety,
95
+ capability: additions.capability
96
+ ? mergeCapabilityConstraints(base.capability, additions.capability)
97
+ : base.capability,
98
+ resource: additions.resource
99
+ ? mergeResourceConstraints(base.resource, additions.resource)
100
+ : base.resource,
101
+ custom: [...(base.custom ?? []), ...(additions.custom ?? [])],
102
+ };
103
+ }