@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.
- package/LICENSE +21 -0
- package/README.md +714 -0
- package/dist/architecture-evolution/capability-analyzer.d.ts +32 -0
- package/dist/architecture-evolution/capability-analyzer.d.ts.map +1 -0
- package/dist/architecture-evolution/capability-analyzer.js +264 -0
- package/dist/architecture-evolution/capability-analyzer.js.map +1 -0
- package/dist/architecture-evolution/evolution-strategy.d.ts +29 -0
- package/dist/architecture-evolution/evolution-strategy.d.ts.map +1 -0
- package/dist/architecture-evolution/evolution-strategy.js +176 -0
- package/dist/architecture-evolution/evolution-strategy.js.map +1 -0
- package/dist/architecture-evolution/index.d.ts +5 -0
- package/dist/architecture-evolution/index.d.ts.map +1 -0
- package/dist/architecture-evolution/index.js +5 -0
- package/dist/architecture-evolution/index.js.map +1 -0
- package/dist/architecture-evolution/parameter-optimizer.d.ts +67 -0
- package/dist/architecture-evolution/parameter-optimizer.d.ts.map +1 -0
- package/dist/architecture-evolution/parameter-optimizer.js +341 -0
- package/dist/architecture-evolution/parameter-optimizer.js.map +1 -0
- package/dist/architecture-evolution/prompts.d.ts +33 -0
- package/dist/architecture-evolution/prompts.d.ts.map +1 -0
- package/dist/architecture-evolution/prompts.js +169 -0
- package/dist/architecture-evolution/prompts.js.map +1 -0
- package/dist/constraints/index.d.ts +4 -0
- package/dist/constraints/index.d.ts.map +1 -0
- package/dist/constraints/index.js +4 -0
- package/dist/constraints/index.js.map +1 -0
- package/dist/constraints/modification-validator.d.ts +26 -0
- package/dist/constraints/modification-validator.d.ts.map +1 -0
- package/dist/constraints/modification-validator.js +313 -0
- package/dist/constraints/modification-validator.js.map +1 -0
- package/dist/constraints/rollback-manager.d.ts +52 -0
- package/dist/constraints/rollback-manager.d.ts.map +1 -0
- package/dist/constraints/rollback-manager.js +113 -0
- package/dist/constraints/rollback-manager.js.map +1 -0
- package/dist/constraints/safety-constraints.d.ts +11 -0
- package/dist/constraints/safety-constraints.d.ts.map +1 -0
- package/dist/constraints/safety-constraints.js +78 -0
- package/dist/constraints/safety-constraints.js.map +1 -0
- package/dist/events/event-emitter.d.ts +12 -0
- package/dist/events/event-emitter.d.ts.map +1 -0
- package/dist/events/event-emitter.js +43 -0
- package/dist/events/event-emitter.js.map +1 -0
- package/dist/events/index.d.ts +2 -0
- package/dist/events/index.d.ts.map +1 -0
- package/dist/events/index.js +2 -0
- package/dist/events/index.js.map +1 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +7 -0
- package/dist/index.js.map +1 -0
- package/dist/meta-reasoning/index.d.ts +5 -0
- package/dist/meta-reasoning/index.d.ts.map +1 -0
- package/dist/meta-reasoning/index.js +5 -0
- package/dist/meta-reasoning/index.js.map +1 -0
- package/dist/meta-reasoning/meta-reasoner.d.ts +53 -0
- package/dist/meta-reasoning/meta-reasoner.d.ts.map +1 -0
- package/dist/meta-reasoning/meta-reasoner.js +261 -0
- package/dist/meta-reasoning/meta-reasoner.js.map +1 -0
- package/dist/meta-reasoning/observation-collector.d.ts +37 -0
- package/dist/meta-reasoning/observation-collector.d.ts.map +1 -0
- package/dist/meta-reasoning/observation-collector.js +123 -0
- package/dist/meta-reasoning/observation-collector.js.map +1 -0
- package/dist/meta-reasoning/prompts.d.ts +31 -0
- package/dist/meta-reasoning/prompts.d.ts.map +1 -0
- package/dist/meta-reasoning/prompts.js +96 -0
- package/dist/meta-reasoning/prompts.js.map +1 -0
- package/dist/meta-reasoning/strategy-selector.d.ts +27 -0
- package/dist/meta-reasoning/strategy-selector.d.ts.map +1 -0
- package/dist/meta-reasoning/strategy-selector.js +138 -0
- package/dist/meta-reasoning/strategy-selector.js.map +1 -0
- package/dist/self-modifying-agent.d.ts +61 -0
- package/dist/self-modifying-agent.d.ts.map +1 -0
- package/dist/self-modifying-agent.js +449 -0
- package/dist/self-modifying-agent.js.map +1 -0
- package/dist/tool-generation/gap-analyzer.d.ts +25 -0
- package/dist/tool-generation/gap-analyzer.d.ts.map +1 -0
- package/dist/tool-generation/gap-analyzer.js +153 -0
- package/dist/tool-generation/gap-analyzer.js.map +1 -0
- package/dist/tool-generation/generated-tool-store.d.ts +51 -0
- package/dist/tool-generation/generated-tool-store.d.ts.map +1 -0
- package/dist/tool-generation/generated-tool-store.js +195 -0
- package/dist/tool-generation/generated-tool-store.js.map +1 -0
- package/dist/tool-generation/index.d.ts +7 -0
- package/dist/tool-generation/index.d.ts.map +1 -0
- package/dist/tool-generation/index.js +7 -0
- package/dist/tool-generation/index.js.map +1 -0
- package/dist/tool-generation/prompts.d.ts +28 -0
- package/dist/tool-generation/prompts.d.ts.map +1 -0
- package/dist/tool-generation/prompts.js +269 -0
- package/dist/tool-generation/prompts.js.map +1 -0
- package/dist/tool-generation/tool-generator.d.ts +29 -0
- package/dist/tool-generation/tool-generator.d.ts.map +1 -0
- package/dist/tool-generation/tool-generator.js +169 -0
- package/dist/tool-generation/tool-generator.js.map +1 -0
- package/dist/tool-generation/tool-sandbox.d.ts +31 -0
- package/dist/tool-generation/tool-sandbox.d.ts.map +1 -0
- package/dist/tool-generation/tool-sandbox.js +240 -0
- package/dist/tool-generation/tool-sandbox.js.map +1 -0
- package/dist/tool-generation/tool-validator.d.ts +32 -0
- package/dist/tool-generation/tool-validator.d.ts.map +1 -0
- package/dist/tool-generation/tool-validator.js +304 -0
- package/dist/tool-generation/tool-validator.js.map +1 -0
- package/dist/utils/index.d.ts +2 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/index.js +2 -0
- package/dist/utils/index.js.map +1 -0
- package/dist/utils/llm-helper.d.ts +6 -0
- package/dist/utils/llm-helper.d.ts.map +1 -0
- package/dist/utils/llm-helper.js +18 -0
- package/dist/utils/llm-helper.js.map +1 -0
- package/package.json +61 -0
- package/src/__tests__/architecture-evolution.test.ts +368 -0
- package/src/__tests__/constraints.test.ts +266 -0
- package/src/__tests__/index.test.ts +99 -0
- package/src/__tests__/meta-reasoning.test.ts +343 -0
- package/src/__tests__/tool-generation.test.ts +455 -0
- package/src/architecture-evolution/capability-analyzer.ts +337 -0
- package/src/architecture-evolution/evolution-strategy.ts +224 -0
- package/src/architecture-evolution/index.ts +26 -0
- package/src/architecture-evolution/parameter-optimizer.ts +489 -0
- package/src/architecture-evolution/prompts.ts +216 -0
- package/src/constraints/index.ts +23 -0
- package/src/constraints/modification-validator.ts +402 -0
- package/src/constraints/rollback-manager.ts +173 -0
- package/src/constraints/safety-constraints.ts +103 -0
- package/src/events/event-emitter.ts +62 -0
- package/src/events/index.ts +1 -0
- package/src/index.ts +112 -0
- package/src/meta-reasoning/index.ts +24 -0
- package/src/meta-reasoning/meta-reasoner.ts +381 -0
- package/src/meta-reasoning/observation-collector.ts +161 -0
- package/src/meta-reasoning/prompts.ts +131 -0
- package/src/meta-reasoning/strategy-selector.ts +179 -0
- package/src/self-modifying-agent.ts +585 -0
- package/src/tool-generation/gap-analyzer.ts +234 -0
- package/src/tool-generation/generated-tool-store.ts +268 -0
- package/src/tool-generation/index.ts +19 -0
- package/src/tool-generation/prompts.ts +308 -0
- package/src/tool-generation/tool-generator.ts +243 -0
- package/src/tool-generation/tool-sandbox.ts +332 -0
- package/src/tool-generation/tool-validator.ts +365 -0
- package/src/utils/index.ts +1 -0
- package/src/utils/llm-helper.ts +24 -0
|
@@ -0,0 +1,455 @@
|
|
|
1
|
+
import { describe, it, expect, beforeEach, vi } from 'vitest';
|
|
2
|
+
import {
|
|
3
|
+
GapAnalyzer,
|
|
4
|
+
ToolGenerator,
|
|
5
|
+
ToolValidator,
|
|
6
|
+
ToolSandbox,
|
|
7
|
+
InMemoryGeneratedToolStore,
|
|
8
|
+
parseGapAnalysisResponse,
|
|
9
|
+
parseToolGenerationResponse,
|
|
10
|
+
} from '../tool-generation';
|
|
11
|
+
import type { LLMBackend, GeneratedTool, ToolSelfGenerationConfig } from '@cogitator-ai/types';
|
|
12
|
+
|
|
13
|
+
const mockToolConfig: ToolSelfGenerationConfig = {
|
|
14
|
+
enabled: true,
|
|
15
|
+
autoGenerate: true,
|
|
16
|
+
maxToolsPerSession: 3,
|
|
17
|
+
minConfidenceForGeneration: 0.7,
|
|
18
|
+
maxIterationsPerTool: 3,
|
|
19
|
+
requireLLMValidation: false,
|
|
20
|
+
sandboxConfig: {
|
|
21
|
+
enabled: true,
|
|
22
|
+
maxExecutionTime: 5000,
|
|
23
|
+
maxMemory: 50 * 1024 * 1024,
|
|
24
|
+
allowedModules: [],
|
|
25
|
+
isolationLevel: 'strict',
|
|
26
|
+
},
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
const mockLLM: LLMBackend = {
|
|
30
|
+
complete: vi.fn(),
|
|
31
|
+
name: 'mock',
|
|
32
|
+
supportsTool: () => true,
|
|
33
|
+
supportsStreaming: () => false,
|
|
34
|
+
validateConfig: () => true,
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
describe('ToolSandbox', () => {
|
|
38
|
+
let sandbox: ToolSandbox;
|
|
39
|
+
|
|
40
|
+
beforeEach(() => {
|
|
41
|
+
sandbox = new ToolSandbox({ enabled: true, maxExecutionTime: 5000 });
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
it('executes safe code', async () => {
|
|
45
|
+
const tool: GeneratedTool = {
|
|
46
|
+
id: 'test-1',
|
|
47
|
+
name: 'add',
|
|
48
|
+
description: 'Add numbers',
|
|
49
|
+
implementation: `
|
|
50
|
+
async function execute(params) {
|
|
51
|
+
return params.a + params.b;
|
|
52
|
+
}
|
|
53
|
+
`,
|
|
54
|
+
parameters: { type: 'object', properties: { a: { type: 'number' }, b: { type: 'number' } } },
|
|
55
|
+
createdAt: new Date(),
|
|
56
|
+
version: 1,
|
|
57
|
+
status: 'validated',
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
const result = await sandbox.execute(tool, { a: 2, b: 3 });
|
|
61
|
+
|
|
62
|
+
expect(result.success).toBe(true);
|
|
63
|
+
expect(result.result).toBe(5);
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
it('rejects code with eval', async () => {
|
|
67
|
+
const tool: GeneratedTool = {
|
|
68
|
+
id: 'test-2',
|
|
69
|
+
name: 'evil',
|
|
70
|
+
description: 'Evil tool',
|
|
71
|
+
implementation: `
|
|
72
|
+
async function execute(params) {
|
|
73
|
+
return eval(params.code);
|
|
74
|
+
}
|
|
75
|
+
`,
|
|
76
|
+
parameters: { type: 'object', properties: { code: { type: 'string' } } },
|
|
77
|
+
createdAt: new Date(),
|
|
78
|
+
version: 1,
|
|
79
|
+
status: 'pending_validation',
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
const result = await sandbox.execute(tool, { code: '1+1' });
|
|
83
|
+
|
|
84
|
+
expect(result.success).toBe(false);
|
|
85
|
+
expect(result.error).toContain('Security violation');
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
it('blocks forbidden setTimeout', async () => {
|
|
89
|
+
const shortTimeoutSandbox = new ToolSandbox({ enabled: true, maxExecutionTime: 100 });
|
|
90
|
+
|
|
91
|
+
const tool: GeneratedTool = {
|
|
92
|
+
id: 'test-3',
|
|
93
|
+
name: 'slow',
|
|
94
|
+
description: 'Slow tool',
|
|
95
|
+
implementation: `
|
|
96
|
+
async function execute(params) {
|
|
97
|
+
await new Promise(r => setTimeout(r, 5000));
|
|
98
|
+
return 'done';
|
|
99
|
+
}
|
|
100
|
+
`,
|
|
101
|
+
parameters: { type: 'object', properties: {} },
|
|
102
|
+
createdAt: new Date(),
|
|
103
|
+
version: 1,
|
|
104
|
+
status: 'validated',
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
const result = await shortTimeoutSandbox.execute(tool, {});
|
|
108
|
+
|
|
109
|
+
expect(result.success).toBe(false);
|
|
110
|
+
expect(result.error).toContain('Security violation');
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
it('runs test cases', async () => {
|
|
114
|
+
const tool: GeneratedTool = {
|
|
115
|
+
id: 'test-4',
|
|
116
|
+
name: 'multiply',
|
|
117
|
+
description: 'Multiply numbers',
|
|
118
|
+
implementation: `
|
|
119
|
+
async function execute(params) {
|
|
120
|
+
return params.a * params.b;
|
|
121
|
+
}
|
|
122
|
+
`,
|
|
123
|
+
parameters: { type: 'object', properties: { a: { type: 'number' }, b: { type: 'number' } } },
|
|
124
|
+
createdAt: new Date(),
|
|
125
|
+
version: 1,
|
|
126
|
+
status: 'validated',
|
|
127
|
+
};
|
|
128
|
+
|
|
129
|
+
const result = await sandbox.testWithCases(tool, [
|
|
130
|
+
{ input: { a: 2, b: 3 }, expectedOutput: 6 },
|
|
131
|
+
{ input: { a: 0, b: 5 }, expectedOutput: 0 },
|
|
132
|
+
{ input: { a: -1, b: 3 }, expectedOutput: -3 },
|
|
133
|
+
]);
|
|
134
|
+
|
|
135
|
+
expect(result.passed).toBe(3);
|
|
136
|
+
expect(result.failed).toBe(0);
|
|
137
|
+
});
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
describe('ToolValidator', () => {
|
|
141
|
+
let validator: ToolValidator;
|
|
142
|
+
|
|
143
|
+
beforeEach(() => {
|
|
144
|
+
validator = new ToolValidator({ config: mockToolConfig });
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
it('validates safe tools', async () => {
|
|
148
|
+
const tool: GeneratedTool = {
|
|
149
|
+
id: 'test-1',
|
|
150
|
+
name: 'safe_tool',
|
|
151
|
+
description: 'Safe tool',
|
|
152
|
+
implementation: `
|
|
153
|
+
async function execute(params) {
|
|
154
|
+
return { result: params.value * 2 };
|
|
155
|
+
}
|
|
156
|
+
`,
|
|
157
|
+
parameters: { type: 'object', properties: { value: { type: 'number' } } },
|
|
158
|
+
createdAt: new Date(),
|
|
159
|
+
version: 1,
|
|
160
|
+
status: 'pending_validation',
|
|
161
|
+
};
|
|
162
|
+
|
|
163
|
+
const result = await validator.validate(tool, [
|
|
164
|
+
{ input: { value: 5 }, expectedOutput: { result: 10 } },
|
|
165
|
+
]);
|
|
166
|
+
|
|
167
|
+
expect(result.isValid).toBe(true);
|
|
168
|
+
expect(result.securityIssues).toHaveLength(0);
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
it('detects security issues', async () => {
|
|
172
|
+
const tool: GeneratedTool = {
|
|
173
|
+
id: 'test-2',
|
|
174
|
+
name: 'unsafe_tool',
|
|
175
|
+
description: 'Unsafe tool',
|
|
176
|
+
implementation: `
|
|
177
|
+
async function execute(params) {
|
|
178
|
+
const child_process = require('child_process');
|
|
179
|
+
return child_process.execSync(params.cmd);
|
|
180
|
+
}
|
|
181
|
+
`,
|
|
182
|
+
parameters: { type: 'object', properties: { cmd: { type: 'string' } } },
|
|
183
|
+
createdAt: new Date(),
|
|
184
|
+
version: 1,
|
|
185
|
+
status: 'pending_validation',
|
|
186
|
+
};
|
|
187
|
+
|
|
188
|
+
const result = await validator.validate(tool);
|
|
189
|
+
|
|
190
|
+
expect(result.isValid).toBe(false);
|
|
191
|
+
expect(result.securityIssues.length).toBeGreaterThan(0);
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
it('detects missing execute function', async () => {
|
|
195
|
+
const tool: GeneratedTool = {
|
|
196
|
+
id: 'test-3',
|
|
197
|
+
name: 'no_execute',
|
|
198
|
+
description: 'No execute',
|
|
199
|
+
implementation: `
|
|
200
|
+
function helper(x) { return x * 2; }
|
|
201
|
+
`,
|
|
202
|
+
parameters: { type: 'object', properties: {} },
|
|
203
|
+
createdAt: new Date(),
|
|
204
|
+
version: 1,
|
|
205
|
+
status: 'pending_validation',
|
|
206
|
+
};
|
|
207
|
+
|
|
208
|
+
const result = await validator.validate(tool);
|
|
209
|
+
|
|
210
|
+
expect(result.isValid).toBe(false);
|
|
211
|
+
expect(result.securityIssues.some((i) => i.includes('execute'))).toBe(true);
|
|
212
|
+
});
|
|
213
|
+
});
|
|
214
|
+
|
|
215
|
+
describe('GapAnalyzer', () => {
|
|
216
|
+
beforeEach(() => {
|
|
217
|
+
vi.clearAllMocks();
|
|
218
|
+
});
|
|
219
|
+
|
|
220
|
+
it('analyzes capability gaps', async () => {
|
|
221
|
+
(mockLLM.complete as ReturnType<typeof vi.fn>).mockResolvedValue({
|
|
222
|
+
content: JSON.stringify({
|
|
223
|
+
hasGap: true,
|
|
224
|
+
gaps: [
|
|
225
|
+
{
|
|
226
|
+
id: 'gap-1',
|
|
227
|
+
description: 'Missing CSV parsing capability',
|
|
228
|
+
requiredCapability: 'Parse CSV files',
|
|
229
|
+
suggestedToolName: 'csv_parser',
|
|
230
|
+
complexity: 'simple',
|
|
231
|
+
confidence: 0.9,
|
|
232
|
+
reasoning: 'User needs to analyze CSV data',
|
|
233
|
+
},
|
|
234
|
+
],
|
|
235
|
+
canProceed: false,
|
|
236
|
+
}),
|
|
237
|
+
});
|
|
238
|
+
|
|
239
|
+
const analyzer = new GapAnalyzer({ llm: mockLLM, config: mockToolConfig });
|
|
240
|
+
|
|
241
|
+
const result = await analyzer.analyze(
|
|
242
|
+
'Parse and analyze the sales.csv file',
|
|
243
|
+
[{ name: 'calculator', description: 'Perform calculations', parameters: {}, execute: async () => null }]
|
|
244
|
+
);
|
|
245
|
+
|
|
246
|
+
expect(result.gaps.length).toBe(1);
|
|
247
|
+
expect(result.gaps[0].suggestedToolName).toBe('csv_parser');
|
|
248
|
+
});
|
|
249
|
+
});
|
|
250
|
+
|
|
251
|
+
describe('ToolGenerator', () => {
|
|
252
|
+
beforeEach(() => {
|
|
253
|
+
vi.clearAllMocks();
|
|
254
|
+
});
|
|
255
|
+
|
|
256
|
+
it('generates tools from gaps', async () => {
|
|
257
|
+
(mockLLM.complete as ReturnType<typeof vi.fn>).mockResolvedValue({
|
|
258
|
+
content: JSON.stringify({
|
|
259
|
+
name: 'csv_parser',
|
|
260
|
+
description: 'Parse CSV data into JSON',
|
|
261
|
+
implementation: `
|
|
262
|
+
async function execute(params) {
|
|
263
|
+
const lines = params.data.split('\\n');
|
|
264
|
+
const headers = lines[0].split(',');
|
|
265
|
+
return lines.slice(1).map(line => {
|
|
266
|
+
const values = line.split(',');
|
|
267
|
+
const obj = {};
|
|
268
|
+
headers.forEach((h, i) => obj[h] = values[i]);
|
|
269
|
+
return obj;
|
|
270
|
+
});
|
|
271
|
+
}
|
|
272
|
+
`,
|
|
273
|
+
parameters: {
|
|
274
|
+
type: 'object',
|
|
275
|
+
properties: { data: { type: 'string' } },
|
|
276
|
+
required: ['data'],
|
|
277
|
+
},
|
|
278
|
+
reasoning: 'Simple CSV parsing without external dependencies',
|
|
279
|
+
}),
|
|
280
|
+
});
|
|
281
|
+
|
|
282
|
+
const generator = new ToolGenerator({ llm: mockLLM, config: mockToolConfig });
|
|
283
|
+
|
|
284
|
+
const result = await generator.generate(
|
|
285
|
+
{
|
|
286
|
+
id: 'gap-1',
|
|
287
|
+
description: 'CSV parsing',
|
|
288
|
+
requiredCapability: 'Parse CSV',
|
|
289
|
+
suggestedToolName: 'csv_parser',
|
|
290
|
+
complexity: 'simple',
|
|
291
|
+
confidence: 0.9,
|
|
292
|
+
reasoning: 'Needed for data analysis',
|
|
293
|
+
},
|
|
294
|
+
[]
|
|
295
|
+
);
|
|
296
|
+
|
|
297
|
+
expect(result.success).toBe(true);
|
|
298
|
+
expect(result.tool).not.toBeNull();
|
|
299
|
+
expect(result.tool?.name).toBe('csv_parser');
|
|
300
|
+
});
|
|
301
|
+
});
|
|
302
|
+
|
|
303
|
+
describe('InMemoryGeneratedToolStore', () => {
|
|
304
|
+
let store: InMemoryGeneratedToolStore;
|
|
305
|
+
|
|
306
|
+
beforeEach(() => {
|
|
307
|
+
store = new InMemoryGeneratedToolStore();
|
|
308
|
+
});
|
|
309
|
+
|
|
310
|
+
it('saves and retrieves tools', async () => {
|
|
311
|
+
const tool: GeneratedTool = {
|
|
312
|
+
id: 'tool-1',
|
|
313
|
+
name: 'test_tool',
|
|
314
|
+
description: 'Test',
|
|
315
|
+
implementation: 'async function execute() {}',
|
|
316
|
+
parameters: { type: 'object', properties: {} },
|
|
317
|
+
createdAt: new Date(),
|
|
318
|
+
version: 1,
|
|
319
|
+
status: 'active',
|
|
320
|
+
};
|
|
321
|
+
|
|
322
|
+
await store.save(tool);
|
|
323
|
+
const retrieved = await store.get('tool-1');
|
|
324
|
+
|
|
325
|
+
expect(retrieved).not.toBeNull();
|
|
326
|
+
expect(retrieved?.name).toBe('test_tool');
|
|
327
|
+
});
|
|
328
|
+
|
|
329
|
+
it('lists tools by status', async () => {
|
|
330
|
+
await store.save({
|
|
331
|
+
id: 'tool-1',
|
|
332
|
+
name: 'active_tool',
|
|
333
|
+
description: 'Active',
|
|
334
|
+
implementation: '',
|
|
335
|
+
parameters: { type: 'object', properties: {} },
|
|
336
|
+
createdAt: new Date(),
|
|
337
|
+
version: 1,
|
|
338
|
+
status: 'active',
|
|
339
|
+
});
|
|
340
|
+
|
|
341
|
+
await store.save({
|
|
342
|
+
id: 'tool-2',
|
|
343
|
+
name: 'pending_tool',
|
|
344
|
+
description: 'Pending',
|
|
345
|
+
implementation: '',
|
|
346
|
+
parameters: { type: 'object', properties: {} },
|
|
347
|
+
createdAt: new Date(),
|
|
348
|
+
version: 1,
|
|
349
|
+
status: 'pending_validation',
|
|
350
|
+
});
|
|
351
|
+
|
|
352
|
+
const activeTools = await store.list({ status: 'active' });
|
|
353
|
+
expect(activeTools).toHaveLength(1);
|
|
354
|
+
expect(activeTools[0].name).toBe('active_tool');
|
|
355
|
+
});
|
|
356
|
+
|
|
357
|
+
it('records usage and calculates metrics', async () => {
|
|
358
|
+
await store.save({
|
|
359
|
+
id: 'tool-1',
|
|
360
|
+
name: 'used_tool',
|
|
361
|
+
description: 'Used',
|
|
362
|
+
implementation: '',
|
|
363
|
+
parameters: { type: 'object', properties: {} },
|
|
364
|
+
createdAt: new Date(),
|
|
365
|
+
version: 1,
|
|
366
|
+
status: 'active',
|
|
367
|
+
});
|
|
368
|
+
|
|
369
|
+
await store.recordUsage({ toolId: 'tool-1', timestamp: new Date(), success: true, executionTime: 100 });
|
|
370
|
+
await store.recordUsage({ toolId: 'tool-1', timestamp: new Date(), success: true, executionTime: 150 });
|
|
371
|
+
await store.recordUsage({ toolId: 'tool-1', timestamp: new Date(), success: false, executionTime: 200 });
|
|
372
|
+
|
|
373
|
+
const metrics = await store.getMetrics('tool-1');
|
|
374
|
+
|
|
375
|
+
expect(metrics).not.toBeNull();
|
|
376
|
+
expect(metrics?.totalUsage).toBe(3);
|
|
377
|
+
expect(metrics?.successRate).toBeCloseTo(0.666, 2);
|
|
378
|
+
expect(metrics?.averageExecutionTime).toBe(150);
|
|
379
|
+
});
|
|
380
|
+
|
|
381
|
+
it('finds similar tools', async () => {
|
|
382
|
+
await store.save({
|
|
383
|
+
id: 'tool-1',
|
|
384
|
+
name: 'csv_parser',
|
|
385
|
+
description: 'Parse CSV files into JSON',
|
|
386
|
+
implementation: '',
|
|
387
|
+
parameters: { type: 'object', properties: {} },
|
|
388
|
+
createdAt: new Date(),
|
|
389
|
+
version: 1,
|
|
390
|
+
status: 'active',
|
|
391
|
+
});
|
|
392
|
+
|
|
393
|
+
await store.save({
|
|
394
|
+
id: 'tool-2',
|
|
395
|
+
name: 'json_formatter',
|
|
396
|
+
description: 'Format JSON data',
|
|
397
|
+
implementation: '',
|
|
398
|
+
parameters: { type: 'object', properties: {} },
|
|
399
|
+
createdAt: new Date(),
|
|
400
|
+
version: 1,
|
|
401
|
+
status: 'active',
|
|
402
|
+
});
|
|
403
|
+
|
|
404
|
+
const similar = await store.findSimilar('parse csv data');
|
|
405
|
+
expect(similar.length).toBeGreaterThan(0);
|
|
406
|
+
expect(similar[0].name).toBe('csv_parser');
|
|
407
|
+
});
|
|
408
|
+
});
|
|
409
|
+
|
|
410
|
+
describe('Parsing functions', () => {
|
|
411
|
+
it('parses gap analysis response', () => {
|
|
412
|
+
const response = `
|
|
413
|
+
Based on analysis:
|
|
414
|
+
{
|
|
415
|
+
"hasGap": true,
|
|
416
|
+
"gaps": [
|
|
417
|
+
{
|
|
418
|
+
"id": "gap-1",
|
|
419
|
+
"description": "Need image processing",
|
|
420
|
+
"requiredCapability": "Process images",
|
|
421
|
+
"suggestedToolName": "image_processor",
|
|
422
|
+
"complexity": "moderate",
|
|
423
|
+
"confidence": 0.85,
|
|
424
|
+
"reasoning": "No existing image tools"
|
|
425
|
+
}
|
|
426
|
+
],
|
|
427
|
+
"canProceed": false
|
|
428
|
+
}
|
|
429
|
+
`;
|
|
430
|
+
|
|
431
|
+
const parsed = parseGapAnalysisResponse(response);
|
|
432
|
+
|
|
433
|
+
expect(parsed.hasGap).toBe(true);
|
|
434
|
+
expect(parsed.gaps).toHaveLength(1);
|
|
435
|
+
expect(parsed.gaps[0].suggestedToolName).toBe('image_processor');
|
|
436
|
+
});
|
|
437
|
+
|
|
438
|
+
it('parses tool generation response', () => {
|
|
439
|
+
const response = `
|
|
440
|
+
Here's the tool:
|
|
441
|
+
{
|
|
442
|
+
"name": "calculator",
|
|
443
|
+
"description": "Perform arithmetic operations",
|
|
444
|
+
"implementation": "async function execute(p) { return p.a + p.b; }",
|
|
445
|
+
"parameters": { "type": "object", "properties": {} },
|
|
446
|
+
"reasoning": "Simple calculator implementation"
|
|
447
|
+
}
|
|
448
|
+
`;
|
|
449
|
+
|
|
450
|
+
const parsed = parseToolGenerationResponse(response);
|
|
451
|
+
|
|
452
|
+
expect(parsed).not.toBeNull();
|
|
453
|
+
expect(parsed?.name).toBe('calculator');
|
|
454
|
+
});
|
|
455
|
+
});
|