@stackmemoryai/stackmemory 1.6.0 → 1.6.1

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 (34) hide show
  1. package/dist/src/cli/commands/orchestrate.js +249 -2
  2. package/dist/src/cli/commands/orchestrator.js +206 -23
  3. package/package.json +1 -2
  4. package/scripts/gepa/.before-optimize.md +0 -112
  5. package/scripts/gepa/README.md +0 -275
  6. package/scripts/gepa/config.json +0 -59
  7. package/scripts/gepa/evals/coding-tasks.jsonl +0 -5
  8. package/scripts/gepa/evals/fixtures/api-endpoint.ts +0 -31
  9. package/scripts/gepa/evals/fixtures/brittle-integration.ts +0 -38
  10. package/scripts/gepa/evals/fixtures/buggy-loop.js +0 -18
  11. package/scripts/gepa/evals/fixtures/callback-hell.js +0 -53
  12. package/scripts/gepa/evals/fixtures/fts5-triggers.sql +0 -23
  13. package/scripts/gepa/evals/fixtures/leaky-service.ts +0 -70
  14. package/scripts/gepa/evals/fixtures/mcp-dispatch-stub.ts +0 -39
  15. package/scripts/gepa/evals/fixtures/pr-diff.txt +0 -24
  16. package/scripts/gepa/evals/fixtures/unsafe-webhook.ts +0 -34
  17. package/scripts/gepa/evals/fixtures/unwrapped-db-op.ts +0 -42
  18. package/scripts/gepa/evals/stackmemory-tasks.jsonl +0 -8
  19. package/scripts/gepa/generations/gen-000/baseline.md +0 -112
  20. package/scripts/gepa/generations/gen-001/baseline.md +0 -112
  21. package/scripts/gepa/generations/gen-001/variant-a.md +0 -107
  22. package/scripts/gepa/generations/gen-001/variant-b.md +0 -216
  23. package/scripts/gepa/generations/gen-001/variant-c.md +0 -83
  24. package/scripts/gepa/generations/gen-001/variant-d.md +0 -90
  25. package/scripts/gepa/hooks/auto-optimize.js +0 -494
  26. package/scripts/gepa/hooks/eval-tracker.js +0 -203
  27. package/scripts/gepa/hooks/reflect.js +0 -350
  28. package/scripts/gepa/optimize.js +0 -853
  29. package/scripts/gepa/results/eval-1-baseline.json +0 -218
  30. package/scripts/gepa/results/eval-1-variant-a.json +0 -218
  31. package/scripts/gepa/results/eval-1-variant-b.json +0 -218
  32. package/scripts/gepa/results/eval-1-variant-c.json +0 -218
  33. package/scripts/gepa/results/eval-1-variant-d.json +0 -218
  34. package/scripts/gepa/state.json +0 -49
@@ -1,350 +0,0 @@
1
- #!/usr/bin/env node
2
- /**
3
- * GEPA Reflection Engine
4
- *
5
- * Analyzes evaluation results to generate insights for next mutation cycle.
6
- * This is the key differentiator from random mutations.
7
- */
8
-
9
- import fs from 'fs';
10
- import path from 'path';
11
- import { fileURLToPath } from 'url';
12
- import { spawn } from 'child_process';
13
-
14
- const __dirname = path.dirname(fileURLToPath(import.meta.url));
15
- const PROJECT_ROOT = path.resolve(__dirname, '../../..');
16
-
17
- // Load .env from project root
18
- const envPath = path.join(PROJECT_ROOT, '.env');
19
- if (fs.existsSync(envPath)) {
20
- for (const line of fs.readFileSync(envPath, 'utf8').split('\n')) {
21
- const match = line.match(/^([A-Z_][A-Z0-9_]*)=(.*)$/);
22
- if (match && !process.env[match[1]]) {
23
- process.env[match[1]] = match[2].replace(/^["']|["']$/g, '');
24
- }
25
- }
26
- }
27
-
28
- /**
29
- * Call Claude CLI via spawn (stdin pipe, no shell interpolation)
30
- */
31
- function spawnClaude(prompt) {
32
- return new Promise((resolve, reject) => {
33
- const child = spawn('claude', ['--print'], {
34
- stdio: ['pipe', 'pipe', 'pipe'],
35
- env: { ...process.env },
36
- });
37
-
38
- let stdout = '';
39
- let stderr = '';
40
-
41
- child.stdout.on('data', (d) => (stdout += d));
42
- child.stderr.on('data', (d) => (stderr += d));
43
-
44
- child.on('close', (code) => {
45
- if (code !== 0 && !stdout)
46
- return reject(new Error(stderr || `claude exited ${code}`));
47
- resolve(stdout);
48
- });
49
-
50
- child.on('error', reject);
51
-
52
- child.stdin.write(prompt);
53
- child.stdin.end();
54
- });
55
- }
56
-
57
- const GEPA_DIR = path.join(__dirname, '..');
58
- const RESULTS_DIR = path.join(GEPA_DIR, 'results');
59
- const GENERATIONS_DIR = path.join(GEPA_DIR, 'generations');
60
-
61
- /**
62
- * Analyze session data for patterns
63
- */
64
- function analyzeSessionPatterns() {
65
- const sessionsDir = path.join(RESULTS_DIR, 'sessions');
66
- if (!fs.existsSync(sessionsDir)) return { patterns: [], insights: [] };
67
-
68
- const sessions = fs
69
- .readdirSync(sessionsDir)
70
- .filter((f) => f.endsWith('.json'))
71
- .map((f) => JSON.parse(fs.readFileSync(path.join(sessionsDir, f), 'utf8')));
72
-
73
- const patterns = {
74
- // Error patterns
75
- commonErrors: extractCommonErrors(sessions),
76
-
77
- // Tool usage patterns
78
- toolUsage: extractToolPatterns(sessions),
79
-
80
- // Feedback patterns
81
- feedbackPatterns: extractFeedbackPatterns(sessions),
82
-
83
- // Performance patterns
84
- performanceByVariant: extractPerformanceByVariant(sessions),
85
- };
86
-
87
- return patterns;
88
- }
89
-
90
- function extractCommonErrors(sessions) {
91
- const errorCounts = {};
92
-
93
- sessions.forEach((s) => {
94
- s.errors?.forEach((e) => {
95
- const normalized = normalizeError(e.error);
96
- errorCounts[normalized] = (errorCounts[normalized] || 0) + 1;
97
- });
98
- });
99
-
100
- return Object.entries(errorCounts)
101
- .sort((a, b) => b[1] - a[1])
102
- .slice(0, 10)
103
- .map(([error, count]) => ({ error, count }));
104
- }
105
-
106
- function normalizeError(error) {
107
- // Normalize error messages for grouping
108
- return error
109
- .replace(/\d+/g, 'N')
110
- .replace(/['"`][^'"`]+['"`]/g, '"..."')
111
- .replace(/\/[^\s]+/g, '/path')
112
- .slice(0, 100);
113
- }
114
-
115
- function extractToolPatterns(sessions) {
116
- const toolStats = {};
117
-
118
- sessions.forEach((s) => {
119
- s.toolCalls?.forEach((t) => {
120
- if (!toolStats[t.tool]) {
121
- toolStats[t.tool] = { count: 0, success: 0, avgDuration: 0 };
122
- }
123
- toolStats[t.tool].count++;
124
- if (t.success) toolStats[t.tool].success++;
125
- toolStats[t.tool].avgDuration += t.duration || 0;
126
- });
127
- });
128
-
129
- // Calculate averages
130
- Object.values(toolStats).forEach((s) => {
131
- s.avgDuration = s.count > 0 ? s.avgDuration / s.count : 0;
132
- s.successRate = s.count > 0 ? s.success / s.count : 0;
133
- });
134
-
135
- return toolStats;
136
- }
137
-
138
- function extractFeedbackPatterns(sessions) {
139
- const feedback = { positive: 0, negative: 0, corrections: 0, retries: 0 };
140
-
141
- sessions.forEach((s) => {
142
- s.userFeedback?.forEach((f) => {
143
- if (f.type === 'thumbs_up') feedback.positive++;
144
- if (f.type === 'thumbs_down') feedback.negative++;
145
- if (f.type === 'correction') feedback.corrections++;
146
- if (f.type === 'retry') feedback.retries++;
147
- });
148
- });
149
-
150
- return feedback;
151
- }
152
-
153
- function extractPerformanceByVariant(sessions) {
154
- const variants = {};
155
-
156
- sessions.forEach((s) => {
157
- if (!variants[s.variant]) {
158
- variants[s.variant] = {
159
- sessions: 0,
160
- totalErrors: 0,
161
- totalSuccess: 0,
162
- avgDuration: 0,
163
- };
164
- }
165
-
166
- variants[s.variant].sessions++;
167
- variants[s.variant].totalErrors += s.metrics?.errorCount || 0;
168
- variants[s.variant].totalSuccess += s.metrics?.successfulToolCalls || 0;
169
- variants[s.variant].avgDuration += s.duration || 0;
170
- });
171
-
172
- // Normalize
173
- Object.values(variants).forEach((v) => {
174
- v.avgDuration = v.sessions > 0 ? v.avgDuration / v.sessions : 0;
175
- v.errorRate = v.sessions > 0 ? v.totalErrors / v.sessions : 0;
176
- v.successRate = v.totalSuccess / (v.totalSuccess + v.totalErrors) || 0;
177
- });
178
-
179
- return variants;
180
- }
181
-
182
- /**
183
- * Generate reflection insights
184
- */
185
- async function generateReflection() {
186
- const patterns = analyzeSessionPatterns();
187
- const state = JSON.parse(
188
- fs.readFileSync(path.join(GEPA_DIR, 'state.json'), 'utf8')
189
- );
190
-
191
- // Load current best prompt for context
192
- const currentPrompt = fs.readFileSync(
193
- path.join(
194
- GENERATIONS_DIR,
195
- `gen-${String(state.currentGeneration).padStart(3, '0')}`,
196
- `${state.bestVariant}.md`
197
- ),
198
- 'utf8'
199
- );
200
-
201
- const reflectionPrompt = `Analyze these AI agent performance patterns and generate specific improvement recommendations.
202
-
203
- CURRENT SYSTEM PROMPT (excerpt):
204
- \`\`\`markdown
205
- ${currentPrompt.slice(0, 3000)}...
206
- \`\`\`
207
-
208
- PERFORMANCE PATTERNS:
209
-
210
- 1. COMMON ERRORS (${patterns.commonErrors.length} types):
211
- ${patterns.commonErrors.map((e) => ` - "${e.error}" (${e.count}x)`).join('\n')}
212
-
213
- 2. TOOL USAGE:
214
- ${Object.entries(patterns.toolUsage)
215
- .map(
216
- ([tool, s]) =>
217
- ` - ${tool}: ${s.count} calls, ${(s.successRate * 100).toFixed(0)}% success, ${s.avgDuration.toFixed(0)}ms avg`
218
- )
219
- .join('\n')}
220
-
221
- 3. USER FEEDBACK:
222
- - Positive: ${patterns.feedbackPatterns.positive}
223
- - Negative: ${patterns.feedbackPatterns.negative}
224
- - Corrections needed: ${patterns.feedbackPatterns.corrections}
225
- - Retries: ${patterns.feedbackPatterns.retries}
226
-
227
- 4. VARIANT PERFORMANCE:
228
- ${Object.entries(patterns.performanceByVariant)
229
- .map(
230
- ([v, s]) =>
231
- ` - ${v}: ${s.sessions} sessions, ${s.errorRate.toFixed(1)} errors/session, ${(s.successRate * 100).toFixed(0)}% success`
232
- )
233
- .join('\n')}
234
-
235
- Based on this data, provide:
236
-
237
- 1. TOP 3 FAILURE MODES - What's causing the most errors?
238
-
239
- 2. MISSING INSTRUCTIONS - What rules should be added to prevent errors?
240
-
241
- 3. UNCLEAR INSTRUCTIONS - What existing rules are being misinterpreted?
242
-
243
- 4. PRIORITY MUTATIONS - What specific changes would have highest impact?
244
-
245
- Format as JSON:
246
- {
247
- "failureModes": ["...", "...", "..."],
248
- "missingInstructions": ["...", "...", "..."],
249
- "unclearInstructions": ["...", "...", "..."],
250
- "priorityMutations": [
251
- {"type": "add|modify|remove", "section": "...", "change": "...", "rationale": "..."},
252
- ...
253
- ]
254
- }`;
255
-
256
- try {
257
- const result = await spawnClaude(reflectionPrompt);
258
-
259
- // Parse JSON from response
260
- const jsonMatch = result.match(/\{[\s\S]*\}/);
261
- if (jsonMatch) {
262
- const insights = JSON.parse(jsonMatch[0]);
263
-
264
- // Save reflection
265
- const reflectionPath = path.join(
266
- RESULTS_DIR,
267
- `reflection-${Date.now()}.json`
268
- );
269
- fs.writeFileSync(
270
- reflectionPath,
271
- JSON.stringify(
272
- {
273
- timestamp: new Date().toISOString(),
274
- generation: state.currentGeneration,
275
- patterns,
276
- insights,
277
- },
278
- null,
279
- 2
280
- )
281
- );
282
-
283
- return insights;
284
- }
285
- } catch (e) {
286
- console.error('Reflection failed:', e.message);
287
- }
288
-
289
- return null;
290
- }
291
-
292
- /**
293
- * Generate focused mutation prompts based on reflection
294
- */
295
- function generateMutationGuide(insights) {
296
- if (!insights) return null;
297
-
298
- return `
299
- REFLECTION-GUIDED MUTATIONS:
300
-
301
- Based on ${insights.failureModes.length} identified failure modes:
302
- ${insights.failureModes.map((f, i) => `${i + 1}. ${f}`).join('\n')}
303
-
304
- PRIORITY CHANGES:
305
- ${insights.priorityMutations
306
- .map(
307
- (m) =>
308
- `- [${m.type.toUpperCase()}] ${m.section}: ${m.change}\n Rationale: ${m.rationale}`
309
- )
310
- .join('\n\n')}
311
-
312
- MISSING INSTRUCTIONS TO ADD:
313
- ${insights.missingInstructions.map((i) => `- ${i}`).join('\n')}
314
-
315
- UNCLEAR INSTRUCTIONS TO CLARIFY:
316
- ${insights.unclearInstructions.map((i) => `- ${i}`).join('\n')}
317
- `;
318
- }
319
-
320
- // CLI
321
- const command = process.argv[2];
322
-
323
- switch (command) {
324
- case 'analyze':
325
- const patterns = analyzeSessionPatterns();
326
- console.log(JSON.stringify(patterns, null, 2));
327
- break;
328
-
329
- case 'reflect':
330
- generateReflection().then((insights) => {
331
- if (insights) {
332
- console.log('\nReflection Insights:');
333
- console.log(JSON.stringify(insights, null, 2));
334
- console.log('\nMutation Guide:');
335
- console.log(generateMutationGuide(insights));
336
- }
337
- });
338
- break;
339
-
340
- default:
341
- console.log(`
342
- GEPA Reflection Engine
343
-
344
- Usage:
345
- node reflect.js analyze Analyze session patterns
346
- node reflect.js reflect Generate reflection insights
347
- `);
348
- }
349
-
350
- export { analyzeSessionPatterns, generateReflection, generateMutationGuide };