agentic-flow 1.4.6 → 1.4.8
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/CHANGELOG.md +96 -0
- package/dist/cli-proxy.js +8 -1
- package/dist/reasoningbank/core/database.js +250 -0
- package/dist/reasoningbank/core/memory-engine.js +335 -0
- package/dist/reasoningbank/types/index.js +5 -0
- package/dist/utils/reasoningbankCommands.js +167 -100
- package/docs/releases/GITHUB-ISSUE-ADDENDUM-v1.4.6.md +1529 -0
- package/docs/releases/GITHUB-ISSUE-v1.4.6.md +1453 -0
- package/docs/releases/v1.4.6-reasoningbank-release.md +541 -0
- package/docs/releases/v1.4.7-bugfix.md +212 -0
- package/package.json +1 -1
|
@@ -0,0 +1,335 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ReasoningBank Memory Engine
|
|
3
|
+
* Implements the 4-phase learning loop: RETRIEVE → JUDGE → DISTILL → CONSOLIDATE
|
|
4
|
+
*/
|
|
5
|
+
import { ReasoningBankDB } from './database.js';
|
|
6
|
+
import { createEmbeddingProvider, cosineSimilarity } from '../utils/embeddings.js';
|
|
7
|
+
import { piiScrubber } from '../utils/pii-scrubber.js';
|
|
8
|
+
export class ReasoningBankEngine {
|
|
9
|
+
db;
|
|
10
|
+
embeddings;
|
|
11
|
+
piiEnabled;
|
|
12
|
+
weights;
|
|
13
|
+
defaultK;
|
|
14
|
+
minConfidence;
|
|
15
|
+
consolidationThreshold;
|
|
16
|
+
memoriesSinceConsolidation = 0;
|
|
17
|
+
constructor(config) {
|
|
18
|
+
this.db = new ReasoningBankDB(config.dbPath);
|
|
19
|
+
this.embeddings = createEmbeddingProvider(config.embeddings?.provider || 'hash', {
|
|
20
|
+
apiKey: process.env.OPENAI_API_KEY || process.env.ANTHROPIC_API_KEY,
|
|
21
|
+
model: config.embeddings?.model
|
|
22
|
+
});
|
|
23
|
+
this.piiEnabled = config.piiScrub?.enabled !== false;
|
|
24
|
+
this.weights = {
|
|
25
|
+
alpha: config.retrieval?.weights?.alpha || 0.65, // Similarity
|
|
26
|
+
beta: config.retrieval?.weights?.beta || 0.15, // Recency
|
|
27
|
+
gamma: config.retrieval?.weights?.gamma || 0.20, // Reliability
|
|
28
|
+
delta: config.retrieval?.weights?.delta || 0.10 // Diversity penalty
|
|
29
|
+
};
|
|
30
|
+
this.defaultK = config.retrieval?.k || 3;
|
|
31
|
+
this.minConfidence = config.retrieval?.minConfidence || 0.3;
|
|
32
|
+
this.consolidationThreshold = config.consolidation?.scheduleEvery || 20;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Phase 1: RETRIEVE - Get relevant memories using 4-factor scoring
|
|
36
|
+
*/
|
|
37
|
+
async retrieve(options) {
|
|
38
|
+
const k = options.k || this.defaultK;
|
|
39
|
+
const lambda = options.lambda || 0.9;
|
|
40
|
+
// Generate query embedding
|
|
41
|
+
const queryEmbedding = await this.embeddings.generate(options.query);
|
|
42
|
+
// Get all memories
|
|
43
|
+
const allMemories = this.db.getAllMemories();
|
|
44
|
+
const embeddings = this.db.getAllEmbeddings();
|
|
45
|
+
// Filter by domain if specified
|
|
46
|
+
let candidates = allMemories;
|
|
47
|
+
if (options.domain) {
|
|
48
|
+
candidates = candidates.filter(m => m.pattern_data.domain === options.domain ||
|
|
49
|
+
m.pattern_data.domain?.startsWith(options.domain + '.'));
|
|
50
|
+
}
|
|
51
|
+
// Calculate scores for each candidate
|
|
52
|
+
const scoredCandidates = [];
|
|
53
|
+
for (const memory of candidates) {
|
|
54
|
+
const embedding = embeddings.get(memory.id);
|
|
55
|
+
if (!embedding)
|
|
56
|
+
continue;
|
|
57
|
+
// 1. Similarity score (cosine similarity)
|
|
58
|
+
const similarity = cosineSimilarity(queryEmbedding, embedding);
|
|
59
|
+
// 2. Recency score (exponential decay, 30-day half-life)
|
|
60
|
+
const ageDays = (Date.now() - new Date(memory.created_at).getTime()) / (1000 * 60 * 60 * 24);
|
|
61
|
+
const recency = Math.exp(-ageDays / 30);
|
|
62
|
+
// 3. Reliability score (confidence × sqrt(usage/10))
|
|
63
|
+
const reliability = Math.min(memory.confidence * Math.sqrt(memory.usage_count / 10), 1.0);
|
|
64
|
+
// Combined score (before diversity penalty)
|
|
65
|
+
const score = this.weights.alpha * similarity +
|
|
66
|
+
this.weights.beta * recency +
|
|
67
|
+
this.weights.gamma * reliability;
|
|
68
|
+
scoredCandidates.push({
|
|
69
|
+
...memory,
|
|
70
|
+
score,
|
|
71
|
+
similarity,
|
|
72
|
+
recency,
|
|
73
|
+
reliability,
|
|
74
|
+
diversityPenalty: 0 // Will be calculated in MMR
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
// Sort by score
|
|
78
|
+
scoredCandidates.sort((a, b) => b.score - a.score);
|
|
79
|
+
// Apply MMR for diversity
|
|
80
|
+
const selected = this.selectWithMMR(scoredCandidates, queryEmbedding, k, lambda);
|
|
81
|
+
// Update usage counts
|
|
82
|
+
for (const memory of selected) {
|
|
83
|
+
this.db.updateMemoryUsage(memory.id);
|
|
84
|
+
}
|
|
85
|
+
// Filter by minimum confidence
|
|
86
|
+
return selected.filter(m => m.confidence >= this.minConfidence);
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* MMR (Maximal Marginal Relevance) Selection
|
|
90
|
+
* Balances relevance and diversity
|
|
91
|
+
*/
|
|
92
|
+
selectWithMMR(candidates, queryEmbedding, k, lambda) {
|
|
93
|
+
const selected = [];
|
|
94
|
+
const remaining = [...candidates];
|
|
95
|
+
const embeddings = this.db.getAllEmbeddings();
|
|
96
|
+
while (selected.length < k && remaining.length > 0) {
|
|
97
|
+
let bestScore = -Infinity;
|
|
98
|
+
let bestIndex = -1;
|
|
99
|
+
for (let i = 0; i < remaining.length; i++) {
|
|
100
|
+
const candidate = remaining[i];
|
|
101
|
+
const candidateEmbedding = embeddings.get(candidate.id);
|
|
102
|
+
if (!candidateEmbedding)
|
|
103
|
+
continue;
|
|
104
|
+
// Relevance to query
|
|
105
|
+
const relevance = candidate.score;
|
|
106
|
+
// Maximum similarity to already selected
|
|
107
|
+
let maxSimilarity = 0;
|
|
108
|
+
if (selected.length > 0) {
|
|
109
|
+
for (const selectedMemory of selected) {
|
|
110
|
+
const selectedEmbedding = embeddings.get(selectedMemory.id);
|
|
111
|
+
if (selectedEmbedding) {
|
|
112
|
+
const sim = cosineSimilarity(candidateEmbedding, selectedEmbedding);
|
|
113
|
+
maxSimilarity = Math.max(maxSimilarity, sim);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
// MMR score
|
|
118
|
+
const mmrScore = lambda * relevance - (1 - lambda) * maxSimilarity;
|
|
119
|
+
if (mmrScore > bestScore) {
|
|
120
|
+
bestScore = mmrScore;
|
|
121
|
+
bestIndex = i;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
if (bestIndex >= 0) {
|
|
125
|
+
selected.push(remaining[bestIndex]);
|
|
126
|
+
remaining.splice(bestIndex, 1);
|
|
127
|
+
}
|
|
128
|
+
else {
|
|
129
|
+
break;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
return selected;
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* Phase 2: JUDGE - Evaluate task outcome
|
|
136
|
+
*/
|
|
137
|
+
async judge(trajectory) {
|
|
138
|
+
// Simple heuristic judge (can be upgraded to LLM)
|
|
139
|
+
const scrubbed = this.piiEnabled ? piiScrubber.scrub(trajectory) : trajectory;
|
|
140
|
+
// Heuristics for success/failure
|
|
141
|
+
const errorKeywords = ['error', 'failed', 'exception', 'timeout', 'unauthorized', 'forbidden'];
|
|
142
|
+
const successKeywords = ['success', 'completed', 'ok', '200', 'done'];
|
|
143
|
+
const lowerTrajectory = scrubbed.toLowerCase();
|
|
144
|
+
const hasError = errorKeywords.some(kw => lowerTrajectory.includes(kw));
|
|
145
|
+
const hasSuccess = successKeywords.some(kw => lowerTrajectory.includes(kw));
|
|
146
|
+
if (hasSuccess && !hasError) {
|
|
147
|
+
return { label: 'Success', confidence: 0.8, rationale: 'Success keywords found' };
|
|
148
|
+
}
|
|
149
|
+
else if (hasError && !hasSuccess) {
|
|
150
|
+
return { label: 'Failure', confidence: 0.8, rationale: 'Error keywords found' };
|
|
151
|
+
}
|
|
152
|
+
else if (hasSuccess && hasError) {
|
|
153
|
+
return { label: 'Success', confidence: 0.5, rationale: 'Mixed signals' };
|
|
154
|
+
}
|
|
155
|
+
else {
|
|
156
|
+
return { label: 'Failure', confidence: 0.5, rationale: 'No clear indicators' };
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* Phase 3: DISTILL - Extract patterns from trajectory
|
|
161
|
+
*/
|
|
162
|
+
async distill(taskId, trajectory, verdict, domain) {
|
|
163
|
+
const scrubbed = this.piiEnabled ? piiScrubber.scrub(trajectory) : trajectory;
|
|
164
|
+
// Store trajectory
|
|
165
|
+
this.db.insertTrajectory({
|
|
166
|
+
task_id: taskId,
|
|
167
|
+
trajectory: scrubbed,
|
|
168
|
+
verdict: verdict.label,
|
|
169
|
+
confidence: verdict.confidence
|
|
170
|
+
});
|
|
171
|
+
// Extract pattern based on verdict
|
|
172
|
+
const pattern = verdict.label === 'Success'
|
|
173
|
+
? this.extractSuccessPattern(scrubbed, domain)
|
|
174
|
+
: this.extractFailureGuardrail(scrubbed, domain);
|
|
175
|
+
// Store as memory
|
|
176
|
+
const memoryId = this.db.insertMemory({
|
|
177
|
+
title: pattern.title,
|
|
178
|
+
description: pattern.description,
|
|
179
|
+
content: pattern.content,
|
|
180
|
+
confidence: verdict.confidence,
|
|
181
|
+
usage_count: 0,
|
|
182
|
+
pattern_data: {
|
|
183
|
+
domain,
|
|
184
|
+
success_pattern: verdict.label === 'Success',
|
|
185
|
+
failure_guardrail: verdict.label === 'Failure'
|
|
186
|
+
}
|
|
187
|
+
});
|
|
188
|
+
// Generate and store embedding
|
|
189
|
+
const embedding = await this.embeddings.generate(pattern.content);
|
|
190
|
+
this.db.insertEmbedding(memoryId, embedding);
|
|
191
|
+
this.memoriesSinceConsolidation++;
|
|
192
|
+
return memoryId;
|
|
193
|
+
}
|
|
194
|
+
extractSuccessPattern(trajectory, domain) {
|
|
195
|
+
// Extract key steps from successful execution
|
|
196
|
+
const lines = trajectory.split('\n').filter(l => l.trim());
|
|
197
|
+
const keySteps = lines.slice(0, 5).join('\n');
|
|
198
|
+
return {
|
|
199
|
+
title: `Success pattern for ${domain}`,
|
|
200
|
+
description: `Successful execution strategy`,
|
|
201
|
+
content: `Successful approach:\n${keySteps}`
|
|
202
|
+
};
|
|
203
|
+
}
|
|
204
|
+
extractFailureGuardrail(trajectory, domain) {
|
|
205
|
+
// Extract error information
|
|
206
|
+
const lines = trajectory.split('\n').filter(l => l.trim());
|
|
207
|
+
const errorInfo = lines.find(l => l.toLowerCase().includes('error') ||
|
|
208
|
+
l.toLowerCase().includes('failed')) || 'Unknown error';
|
|
209
|
+
return {
|
|
210
|
+
title: `Failure guardrail for ${domain}`,
|
|
211
|
+
description: `Prevention strategy for common failures`,
|
|
212
|
+
content: `Avoid: ${errorInfo}\nRecommend: Check prerequisites and retry with backoff`
|
|
213
|
+
};
|
|
214
|
+
}
|
|
215
|
+
/**
|
|
216
|
+
* Phase 4: CONSOLIDATE - Deduplicate and prune
|
|
217
|
+
*/
|
|
218
|
+
async consolidate(options) {
|
|
219
|
+
const startTime = Date.now();
|
|
220
|
+
const dedupeThreshold = options?.dedupeThreshold || 0.95;
|
|
221
|
+
const maxAgeDays = options?.prune?.maxAgeDays || 90;
|
|
222
|
+
const minConfidence = options?.prune?.minConfidence || 0.3;
|
|
223
|
+
const unusedDays = options?.prune?.unusedDays || 30;
|
|
224
|
+
// Find and merge duplicates
|
|
225
|
+
const duplicates = this.db.findDuplicates(dedupeThreshold);
|
|
226
|
+
for (const [id1, id2] of duplicates) {
|
|
227
|
+
const mem1 = this.db.getMemory(id1);
|
|
228
|
+
const mem2 = this.db.getMemory(id2);
|
|
229
|
+
if (mem1 && mem2) {
|
|
230
|
+
// Keep the one with higher confidence and usage
|
|
231
|
+
const keepId = mem1.confidence > mem2.confidence ||
|
|
232
|
+
(mem1.confidence === mem2.confidence && mem1.usage_count > mem2.usage_count)
|
|
233
|
+
? id1 : id2;
|
|
234
|
+
const deleteId = keepId === id1 ? id2 : id1;
|
|
235
|
+
this.db.deleteMemory(deleteId);
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
// Prune old or low-quality memories
|
|
239
|
+
const allMemories = this.db.getAllMemories();
|
|
240
|
+
let pruned = 0;
|
|
241
|
+
for (const memory of allMemories) {
|
|
242
|
+
const ageDays = (Date.now() - new Date(memory.created_at).getTime()) / (1000 * 60 * 60 * 24);
|
|
243
|
+
const lastUsedDays = ageDays; // Simplified: assume last used = created
|
|
244
|
+
const shouldPrune = ageDays > maxAgeDays ||
|
|
245
|
+
memory.confidence < minConfidence ||
|
|
246
|
+
(memory.usage_count === 0 && lastUsedDays > unusedDays);
|
|
247
|
+
if (shouldPrune) {
|
|
248
|
+
this.db.deleteMemory(memory.id);
|
|
249
|
+
pruned++;
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
// Detect contradictions (simplified)
|
|
253
|
+
const contradictions = 0; // TODO: Implement semantic contradiction detection
|
|
254
|
+
this.memoriesSinceConsolidation = 0;
|
|
255
|
+
return {
|
|
256
|
+
processed: allMemories.length,
|
|
257
|
+
duplicates: duplicates.length,
|
|
258
|
+
contradictions,
|
|
259
|
+
pruned,
|
|
260
|
+
durationMs: Date.now() - startTime
|
|
261
|
+
};
|
|
262
|
+
}
|
|
263
|
+
/**
|
|
264
|
+
* High-level task execution with full learning loop
|
|
265
|
+
*/
|
|
266
|
+
async runTask(options) {
|
|
267
|
+
// Phase 1: RETRIEVE
|
|
268
|
+
const memories = await this.retrieve({
|
|
269
|
+
query: options.query,
|
|
270
|
+
domain: options.domain
|
|
271
|
+
});
|
|
272
|
+
// EXECUTE
|
|
273
|
+
const result = await options.executeFn(memories);
|
|
274
|
+
// Phase 2: JUDGE
|
|
275
|
+
const verdict = await this.judge(result.log);
|
|
276
|
+
// Phase 3: DISTILL
|
|
277
|
+
await this.distill(options.taskId, result.log, verdict, options.domain);
|
|
278
|
+
// Phase 4: CONSOLIDATE (if threshold reached)
|
|
279
|
+
if (this.memoriesSinceConsolidation >= this.consolidationThreshold) {
|
|
280
|
+
await this.consolidate();
|
|
281
|
+
}
|
|
282
|
+
return {
|
|
283
|
+
success: result.success,
|
|
284
|
+
summary: `Task ${options.taskId}: ${verdict.label} (confidence: ${verdict.confidence})`,
|
|
285
|
+
memories,
|
|
286
|
+
verdict
|
|
287
|
+
};
|
|
288
|
+
}
|
|
289
|
+
/**
|
|
290
|
+
* MaTTS: Memory-aware Test-Time Scaling (Parallel)
|
|
291
|
+
*/
|
|
292
|
+
async mattsParallel(options) {
|
|
293
|
+
const runs = await Promise.all(Array.from({ length: options.k }, async (_, i) => {
|
|
294
|
+
const memories = await this.retrieve({
|
|
295
|
+
query: options.query,
|
|
296
|
+
domain: options.domain
|
|
297
|
+
});
|
|
298
|
+
const result = await options.executeFn(memories);
|
|
299
|
+
const verdict = await this.judge(result.log);
|
|
300
|
+
this.db.insertMattsRun({
|
|
301
|
+
task_id: options.taskId,
|
|
302
|
+
run_index: i,
|
|
303
|
+
result: result.log,
|
|
304
|
+
verdict: verdict.label,
|
|
305
|
+
confidence: verdict.confidence
|
|
306
|
+
});
|
|
307
|
+
return { result, verdict };
|
|
308
|
+
}));
|
|
309
|
+
// Calculate consensus
|
|
310
|
+
const successes = runs.filter(r => r.verdict.label === 'Success').length;
|
|
311
|
+
const avgConfidence = runs.reduce((sum, r) => sum + r.verdict.confidence, 0) / runs.length;
|
|
312
|
+
const consensusVerdict = {
|
|
313
|
+
label: successes > runs.length / 2 ? 'Success' : 'Failure',
|
|
314
|
+
confidence: avgConfidence
|
|
315
|
+
};
|
|
316
|
+
return {
|
|
317
|
+
success: consensusVerdict.label === 'Success',
|
|
318
|
+
summary: `MaTTS Parallel: ${successes}/${runs.length} successes, consensus: ${consensusVerdict.label}`,
|
|
319
|
+
memories: [],
|
|
320
|
+
verdict: consensusVerdict
|
|
321
|
+
};
|
|
322
|
+
}
|
|
323
|
+
/**
|
|
324
|
+
* Get statistics
|
|
325
|
+
*/
|
|
326
|
+
getStats() {
|
|
327
|
+
return this.db.getStats();
|
|
328
|
+
}
|
|
329
|
+
/**
|
|
330
|
+
* Close database connection
|
|
331
|
+
*/
|
|
332
|
+
close() {
|
|
333
|
+
this.db.close();
|
|
334
|
+
}
|
|
335
|
+
}
|
|
@@ -1,58 +1,57 @@
|
|
|
1
|
-
|
|
1
|
+
/**
|
|
2
|
+
* ReasoningBank CLI Commands
|
|
3
|
+
* Handles demo, test, init, benchmark, status, consolidate, list
|
|
4
|
+
*/
|
|
2
5
|
import { spawn } from 'child_process';
|
|
3
|
-
import {
|
|
6
|
+
import { join } from 'path';
|
|
7
|
+
import { fileURLToPath } from 'url';
|
|
8
|
+
import { dirname } from 'path';
|
|
9
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
10
|
+
const __dirname = dirname(__filename);
|
|
4
11
|
export async function handleReasoningBankCommand(subcommand) {
|
|
5
|
-
const
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
(
|
|
38
|
-
(SELECT COUNT(*) FROM reasoning_memory WHERE confidence > 0.7) as high_confidence,
|
|
39
|
-
(SELECT COUNT(*) FROM task_trajectory) as total_tasks,
|
|
40
|
-
(SELECT AVG(confidence) FROM reasoning_memory) as avg_confidence;"`);
|
|
41
|
-
console.log('\n');
|
|
42
|
-
break;
|
|
43
|
-
case 'help':
|
|
44
|
-
default:
|
|
45
|
-
printReasoningBankHelp();
|
|
46
|
-
break;
|
|
12
|
+
const args = process.argv.slice(4); // Get args after 'reasoningbank <subcommand>'
|
|
13
|
+
try {
|
|
14
|
+
switch (subcommand) {
|
|
15
|
+
case 'demo':
|
|
16
|
+
await runExternalScript('../reasoningbank/demo-comparison.js');
|
|
17
|
+
break;
|
|
18
|
+
case 'test':
|
|
19
|
+
await runExternalScript('../reasoningbank/test-validation.js');
|
|
20
|
+
break;
|
|
21
|
+
case 'init':
|
|
22
|
+
await initDatabase();
|
|
23
|
+
break;
|
|
24
|
+
case 'benchmark':
|
|
25
|
+
await runExternalScript('../reasoningbank/benchmark.js');
|
|
26
|
+
break;
|
|
27
|
+
case 'status':
|
|
28
|
+
await showStatus();
|
|
29
|
+
break;
|
|
30
|
+
case 'consolidate':
|
|
31
|
+
await runConsolidation();
|
|
32
|
+
break;
|
|
33
|
+
case 'list':
|
|
34
|
+
await listMemories(args);
|
|
35
|
+
break;
|
|
36
|
+
case 'help':
|
|
37
|
+
default:
|
|
38
|
+
printHelp();
|
|
39
|
+
break;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
catch (error) {
|
|
43
|
+
console.error(`\n❌ Error: ${error instanceof Error ? error.message : String(error)}\n`);
|
|
44
|
+
process.exit(1);
|
|
47
45
|
}
|
|
48
46
|
}
|
|
49
|
-
async function
|
|
47
|
+
async function runExternalScript(relativePath) {
|
|
48
|
+
const scriptPath = join(__dirname, relativePath);
|
|
50
49
|
return new Promise((resolve, reject) => {
|
|
51
|
-
const
|
|
50
|
+
const child = spawn('node', [scriptPath], {
|
|
52
51
|
stdio: 'inherit',
|
|
53
|
-
|
|
52
|
+
cwd: process.cwd()
|
|
54
53
|
});
|
|
55
|
-
|
|
54
|
+
child.on('exit', (code) => {
|
|
56
55
|
if (code === 0) {
|
|
57
56
|
resolve();
|
|
58
57
|
}
|
|
@@ -60,77 +59,145 @@ async function runScript(scriptPath) {
|
|
|
60
59
|
reject(new Error(`Script exited with code ${code}`));
|
|
61
60
|
}
|
|
62
61
|
});
|
|
63
|
-
|
|
64
|
-
reject(
|
|
62
|
+
child.on('error', (error) => {
|
|
63
|
+
reject(error);
|
|
65
64
|
});
|
|
66
65
|
});
|
|
67
66
|
}
|
|
68
|
-
async function
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
67
|
+
async function initDatabase() {
|
|
68
|
+
console.log('\n🔧 Initializing ReasoningBank Database');
|
|
69
|
+
console.log('═'.repeat(50));
|
|
70
|
+
const { initialize } = await import('../reasoningbank/index.js');
|
|
71
|
+
console.log('\nInitializing database with migrations...\n');
|
|
72
|
+
await initialize();
|
|
73
|
+
console.log('\n✅ Database initialized successfully!');
|
|
74
|
+
console.log('\nSchema created:');
|
|
75
|
+
console.log(' • patterns (reasoning memories)');
|
|
76
|
+
console.log(' • pattern_embeddings');
|
|
77
|
+
console.log(' • pattern_links');
|
|
78
|
+
console.log(' • task_trajectories');
|
|
79
|
+
console.log(' • matts_runs');
|
|
80
|
+
console.log(' • consolidation_runs');
|
|
81
|
+
console.log(' • metrics_log\n');
|
|
82
|
+
}
|
|
83
|
+
async function showStatus() {
|
|
84
|
+
console.log('\n📊 ReasoningBank Status');
|
|
85
|
+
console.log('═'.repeat(50));
|
|
86
|
+
const { db } = await import('../reasoningbank/index.js');
|
|
87
|
+
const dbInstance = db.getDb();
|
|
88
|
+
const stats = {
|
|
89
|
+
totalMemories: dbInstance.prepare("SELECT COUNT(*) as count FROM patterns WHERE type = 'reasoning_memory'").get(),
|
|
90
|
+
avgConfidence: dbInstance.prepare("SELECT AVG(confidence) as avg FROM patterns WHERE type = 'reasoning_memory'").get(),
|
|
91
|
+
totalEmbeddings: dbInstance.prepare('SELECT COUNT(*) as count FROM pattern_embeddings').get(),
|
|
92
|
+
totalTrajectories: dbInstance.prepare('SELECT COUNT(*) as count FROM task_trajectories').get()
|
|
93
|
+
};
|
|
94
|
+
console.log(`\n📈 Statistics:`);
|
|
95
|
+
console.log(` • Total memories: ${stats.totalMemories.count}`);
|
|
96
|
+
console.log(` • Average confidence: ${stats.avgConfidence.avg?.toFixed(2) || 'N/A'}`);
|
|
97
|
+
console.log(` • Total embeddings: ${stats.totalEmbeddings.count}`);
|
|
98
|
+
console.log(` • Total trajectories: ${stats.totalTrajectories.count}\n`);
|
|
86
99
|
}
|
|
87
|
-
function
|
|
100
|
+
async function runConsolidation() {
|
|
101
|
+
console.log('\n🔄 Running Memory Consolidation');
|
|
102
|
+
console.log('═'.repeat(50));
|
|
103
|
+
console.log('\nDeduplicating and pruning memories...\n');
|
|
104
|
+
const { consolidate } = await import('../reasoningbank/index.js');
|
|
105
|
+
const startTime = Date.now();
|
|
106
|
+
const result = await consolidate();
|
|
107
|
+
const duration = Date.now() - startTime;
|
|
108
|
+
console.log('✅ Consolidation complete!\n');
|
|
109
|
+
console.log(`📊 Results:`);
|
|
110
|
+
console.log(` • Memories processed: ${result.itemsProcessed}`);
|
|
111
|
+
console.log(` • Duplicates found: ${result.duplicatesFound}`);
|
|
112
|
+
console.log(` • Contradictions found: ${result.contradictionsFound}`);
|
|
113
|
+
console.log(` • Pruned: ${result.itemsPruned}`);
|
|
114
|
+
console.log(` • Duration: ${result.durationMs}ms\n`);
|
|
115
|
+
}
|
|
116
|
+
async function listMemories(args) {
|
|
117
|
+
const { db } = await import('../reasoningbank/index.js');
|
|
118
|
+
const dbInstance = db.getDb();
|
|
119
|
+
// Parse arguments
|
|
120
|
+
const sortBy = args.includes('--sort') ? args[args.indexOf('--sort') + 1] : 'created_at';
|
|
121
|
+
const limit = args.includes('--limit') ? parseInt(args[args.indexOf('--limit') + 1], 10) : 10;
|
|
122
|
+
console.log('\n📚 Memory Bank Contents');
|
|
123
|
+
console.log('═'.repeat(50));
|
|
124
|
+
console.log(`\nShowing top ${limit} memories (sorted by ${sortBy})\n`);
|
|
125
|
+
let orderBy = 'created_at DESC';
|
|
126
|
+
if (sortBy === 'confidence') {
|
|
127
|
+
orderBy = 'confidence DESC';
|
|
128
|
+
}
|
|
129
|
+
else if (sortBy === 'usage') {
|
|
130
|
+
orderBy = 'usage_count DESC';
|
|
131
|
+
}
|
|
132
|
+
const memories = dbInstance.prepare(`
|
|
133
|
+
SELECT
|
|
134
|
+
id,
|
|
135
|
+
json_extract(pattern_data, '$.title') as title,
|
|
136
|
+
json_extract(pattern_data, '$.description') as description,
|
|
137
|
+
json_extract(pattern_data, '$.domain') as domain,
|
|
138
|
+
confidence,
|
|
139
|
+
usage_count,
|
|
140
|
+
created_at
|
|
141
|
+
FROM patterns
|
|
142
|
+
WHERE type = 'reasoning_memory'
|
|
143
|
+
ORDER BY ${orderBy}
|
|
144
|
+
LIMIT ?
|
|
145
|
+
`).all(limit);
|
|
146
|
+
if (memories.length === 0) {
|
|
147
|
+
console.log('No memories found. Run `npx agentic-flow reasoningbank demo` to create some!\n');
|
|
148
|
+
return;
|
|
149
|
+
}
|
|
150
|
+
for (let i = 0; i < memories.length; i++) {
|
|
151
|
+
const mem = memories[i];
|
|
152
|
+
console.log(`${i + 1}. ${mem.title}`);
|
|
153
|
+
console.log(` Confidence: ${parseFloat(mem.confidence).toFixed(2)} | Usage: ${mem.usage_count} | Created: ${mem.created_at}`);
|
|
154
|
+
console.log(` Domain: ${mem.domain}`);
|
|
155
|
+
console.log(` ${mem.description}`);
|
|
156
|
+
console.log('');
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
function printHelp() {
|
|
88
160
|
console.log(`
|
|
89
|
-
🧠 ReasoningBank -
|
|
161
|
+
🧠 ReasoningBank - Closed-loop memory system for AI agents
|
|
90
162
|
|
|
91
163
|
USAGE:
|
|
92
|
-
npx agentic-flow reasoningbank <
|
|
164
|
+
npx agentic-flow reasoningbank <COMMAND>
|
|
93
165
|
|
|
94
166
|
COMMANDS:
|
|
95
|
-
demo
|
|
96
|
-
test
|
|
97
|
-
init
|
|
98
|
-
benchmark
|
|
99
|
-
status
|
|
100
|
-
|
|
167
|
+
demo Run interactive demo showing learning progression
|
|
168
|
+
test Run validation test suite
|
|
169
|
+
init Initialize database schema
|
|
170
|
+
benchmark Run performance benchmarks
|
|
171
|
+
status Show memory statistics
|
|
172
|
+
consolidate Run memory consolidation now
|
|
173
|
+
list List memories with options
|
|
174
|
+
help Show this help message
|
|
175
|
+
|
|
176
|
+
LIST OPTIONS:
|
|
177
|
+
--sort <field> Sort by: confidence, usage, created_at (default)
|
|
178
|
+
--limit <n> Show top N memories (default: 10)
|
|
101
179
|
|
|
102
180
|
EXAMPLES:
|
|
103
|
-
#
|
|
181
|
+
# Run demo to see 0% → 100% success transformation
|
|
104
182
|
npx agentic-flow reasoningbank demo
|
|
105
183
|
|
|
106
|
-
#
|
|
107
|
-
npx agentic-flow reasoningbank test
|
|
108
|
-
|
|
109
|
-
# Setup database for first-time use
|
|
184
|
+
# Initialize database
|
|
110
185
|
npx agentic-flow reasoningbank init
|
|
111
186
|
|
|
112
|
-
#
|
|
113
|
-
npx agentic-flow reasoningbank
|
|
187
|
+
# Run validation tests
|
|
188
|
+
npx agentic-flow reasoningbank test
|
|
114
189
|
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
✅ 100% success rate after learning (vs 0% for traditional)
|
|
118
|
-
✅ 46% faster execution over time
|
|
119
|
-
✅ Knowledge transfers across similar tasks
|
|
120
|
-
✅ Zero manual intervention needed
|
|
190
|
+
# Show current statistics
|
|
191
|
+
npx agentic-flow reasoningbank status
|
|
121
192
|
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
• ANTHROPIC_API_KEY (optional, for LLM-based learning)
|
|
193
|
+
# Consolidate memories (dedupe + prune)
|
|
194
|
+
npx agentic-flow reasoningbank consolidate
|
|
125
195
|
|
|
126
|
-
|
|
127
|
-
|
|
196
|
+
# List top 10 memories by confidence
|
|
197
|
+
npx agentic-flow reasoningbank list --sort confidence --limit 10
|
|
128
198
|
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
• Demo Report: docs/REASONINGBANK-DEMO.md
|
|
132
|
-
• Integration: docs/REASONINGBANK-CLI-INTEGRATION.md
|
|
133
|
-
• Paper: https://arxiv.org/html/2509.25140v1
|
|
199
|
+
# List top 5 most used memories
|
|
200
|
+
npx agentic-flow reasoningbank list --sort usage --limit 5
|
|
134
201
|
|
|
135
202
|
For more information: https://github.com/ruvnet/agentic-flow
|
|
136
203
|
`);
|