@arcanea/guardian-evolution 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/dist/algorithms/a2c.d.ts +86 -0
- package/dist/algorithms/a2c.d.ts.map +1 -0
- package/dist/algorithms/a2c.js +361 -0
- package/dist/algorithms/a2c.js.map +1 -0
- package/dist/algorithms/curiosity.d.ts +82 -0
- package/dist/algorithms/curiosity.d.ts.map +1 -0
- package/dist/algorithms/curiosity.js +392 -0
- package/dist/algorithms/curiosity.js.map +1 -0
- package/dist/algorithms/decision-transformer.d.ts +82 -0
- package/dist/algorithms/decision-transformer.d.ts.map +1 -0
- package/dist/algorithms/decision-transformer.js +415 -0
- package/dist/algorithms/decision-transformer.js.map +1 -0
- package/dist/algorithms/dqn.d.ts +72 -0
- package/dist/algorithms/dqn.d.ts.map +1 -0
- package/dist/algorithms/dqn.js +303 -0
- package/dist/algorithms/dqn.js.map +1 -0
- package/dist/algorithms/index.d.ts +32 -0
- package/dist/algorithms/index.d.ts.map +1 -0
- package/dist/algorithms/index.js +74 -0
- package/dist/algorithms/index.js.map +1 -0
- package/dist/algorithms/ppo.d.ts +72 -0
- package/dist/algorithms/ppo.d.ts.map +1 -0
- package/dist/algorithms/ppo.js +331 -0
- package/dist/algorithms/ppo.js.map +1 -0
- package/dist/algorithms/q-learning.d.ts +77 -0
- package/dist/algorithms/q-learning.d.ts.map +1 -0
- package/dist/algorithms/q-learning.js +259 -0
- package/dist/algorithms/q-learning.js.map +1 -0
- package/dist/algorithms/sarsa.d.ts +82 -0
- package/dist/algorithms/sarsa.d.ts.map +1 -0
- package/dist/algorithms/sarsa.js +297 -0
- package/dist/algorithms/sarsa.js.map +1 -0
- package/dist/index.d.ts +118 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +201 -0
- package/dist/index.js.map +1 -0
- package/dist/modes/balanced.d.ts +60 -0
- package/dist/modes/balanced.d.ts.map +1 -0
- package/dist/modes/balanced.js +234 -0
- package/dist/modes/balanced.js.map +1 -0
- package/dist/modes/batch.d.ts +82 -0
- package/dist/modes/batch.d.ts.map +1 -0
- package/dist/modes/batch.js +316 -0
- package/dist/modes/batch.js.map +1 -0
- package/dist/modes/edge.d.ts +85 -0
- package/dist/modes/edge.d.ts.map +1 -0
- package/dist/modes/edge.js +310 -0
- package/dist/modes/edge.js.map +1 -0
- package/dist/modes/index.d.ts +55 -0
- package/dist/modes/index.d.ts.map +1 -0
- package/dist/modes/index.js +83 -0
- package/dist/modes/index.js.map +1 -0
- package/dist/modes/real-time.d.ts +58 -0
- package/dist/modes/real-time.d.ts.map +1 -0
- package/dist/modes/real-time.js +196 -0
- package/dist/modes/real-time.js.map +1 -0
- package/dist/modes/research.d.ts +79 -0
- package/dist/modes/research.d.ts.map +1 -0
- package/dist/modes/research.js +389 -0
- package/dist/modes/research.js.map +1 -0
- package/dist/pattern-learner.d.ts +117 -0
- package/dist/pattern-learner.d.ts.map +1 -0
- package/dist/pattern-learner.js +603 -0
- package/dist/pattern-learner.js.map +1 -0
- package/dist/reasoning-bank.d.ts +259 -0
- package/dist/reasoning-bank.d.ts.map +1 -0
- package/dist/reasoning-bank.js +993 -0
- package/dist/reasoning-bank.js.map +1 -0
- package/dist/reasoningbank-adapter.d.ts +168 -0
- package/dist/reasoningbank-adapter.d.ts.map +1 -0
- package/dist/reasoningbank-adapter.js +463 -0
- package/dist/reasoningbank-adapter.js.map +1 -0
- package/dist/sona-integration.d.ts +168 -0
- package/dist/sona-integration.d.ts.map +1 -0
- package/dist/sona-integration.js +316 -0
- package/dist/sona-integration.js.map +1 -0
- package/dist/sona-manager.d.ts +147 -0
- package/dist/sona-manager.d.ts.map +1 -0
- package/dist/sona-manager.js +695 -0
- package/dist/sona-manager.js.map +1 -0
- package/dist/types.d.ts +431 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +11 -0
- package/dist/types.js.map +1 -0
- package/package.json +47 -0
|
@@ -0,0 +1,993 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ReasoningBank Integration with AgentDB
|
|
3
|
+
*
|
|
4
|
+
* Implements the 4-step learning pipeline with real vector storage:
|
|
5
|
+
* 1. RETRIEVE - Top-k memory injection with MMR diversity (using AgentDB HNSW)
|
|
6
|
+
* 2. JUDGE - LLM-as-judge trajectory evaluation
|
|
7
|
+
* 3. DISTILL - Extract strategy memories from trajectories
|
|
8
|
+
* 4. CONSOLIDATE - Dedup, detect contradictions, prune old patterns
|
|
9
|
+
*
|
|
10
|
+
* Performance Targets:
|
|
11
|
+
* - Retrieval: <10ms with AgentDB HNSW (150x faster than brute-force)
|
|
12
|
+
* - Learning step: <10ms
|
|
13
|
+
* - Consolidation: <100ms
|
|
14
|
+
*
|
|
15
|
+
* @module reasoning-bank
|
|
16
|
+
*/
|
|
17
|
+
// ============================================================================
|
|
18
|
+
// AgentDB Integration
|
|
19
|
+
// ============================================================================
|
|
20
|
+
let AgentDB;
|
|
21
|
+
let agentdbImportPromise;
|
|
22
|
+
async function ensureAgentDBImport() {
|
|
23
|
+
if (!agentdbImportPromise) {
|
|
24
|
+
agentdbImportPromise = (async () => {
|
|
25
|
+
try {
|
|
26
|
+
const agentdbModule = await import('agentdb');
|
|
27
|
+
AgentDB = agentdbModule.AgentDB || agentdbModule.default;
|
|
28
|
+
}
|
|
29
|
+
catch {
|
|
30
|
+
// AgentDB not available - will use fallback
|
|
31
|
+
AgentDB = undefined;
|
|
32
|
+
}
|
|
33
|
+
})();
|
|
34
|
+
}
|
|
35
|
+
return agentdbImportPromise;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Default ReasoningBank configuration
|
|
39
|
+
*/
|
|
40
|
+
const DEFAULT_CONFIG = {
|
|
41
|
+
maxTrajectories: 5000,
|
|
42
|
+
distillationThreshold: 0.6,
|
|
43
|
+
retrievalK: 3,
|
|
44
|
+
mmrLambda: 0.7,
|
|
45
|
+
maxPatternAgeDays: 30,
|
|
46
|
+
dedupThreshold: 0.95,
|
|
47
|
+
enableContradictionDetection: true,
|
|
48
|
+
dbPath: undefined,
|
|
49
|
+
vectorDimension: 768,
|
|
50
|
+
namespace: 'reasoning-bank',
|
|
51
|
+
enableAgentDB: true,
|
|
52
|
+
};
|
|
53
|
+
// ============================================================================
|
|
54
|
+
// ReasoningBank Class
|
|
55
|
+
// ============================================================================
|
|
56
|
+
/**
|
|
57
|
+
* ReasoningBank - Trajectory storage and learning pipeline with AgentDB
|
|
58
|
+
*
|
|
59
|
+
* This class implements a complete learning pipeline for AI agents:
|
|
60
|
+
* - Store and retrieve trajectories using vector similarity
|
|
61
|
+
* - Judge trajectory quality using rule-based evaluation
|
|
62
|
+
* - Distill successful trajectories into reusable patterns
|
|
63
|
+
* - Consolidate patterns to remove duplicates and contradictions
|
|
64
|
+
*/
|
|
65
|
+
export class ReasoningBank {
|
|
66
|
+
config;
|
|
67
|
+
trajectories = new Map();
|
|
68
|
+
memories = new Map();
|
|
69
|
+
patterns = new Map();
|
|
70
|
+
eventListeners = new Set();
|
|
71
|
+
// AgentDB instance for vector storage
|
|
72
|
+
agentdb = null;
|
|
73
|
+
agentdbAvailable = false;
|
|
74
|
+
initialized = false;
|
|
75
|
+
// Performance tracking
|
|
76
|
+
retrievalCount = 0;
|
|
77
|
+
totalRetrievalTime = 0;
|
|
78
|
+
distillationCount = 0;
|
|
79
|
+
totalDistillationTime = 0;
|
|
80
|
+
judgeCount = 0;
|
|
81
|
+
totalJudgeTime = 0;
|
|
82
|
+
consolidationCount = 0;
|
|
83
|
+
totalConsolidationTime = 0;
|
|
84
|
+
constructor(config = {}) {
|
|
85
|
+
this.config = { ...DEFAULT_CONFIG, ...config };
|
|
86
|
+
}
|
|
87
|
+
// ==========================================================================
|
|
88
|
+
// Initialization
|
|
89
|
+
// ==========================================================================
|
|
90
|
+
/**
|
|
91
|
+
* Initialize ReasoningBank with AgentDB
|
|
92
|
+
*/
|
|
93
|
+
async initialize() {
|
|
94
|
+
if (this.initialized)
|
|
95
|
+
return;
|
|
96
|
+
if (this.config.enableAgentDB) {
|
|
97
|
+
await ensureAgentDBImport();
|
|
98
|
+
this.agentdbAvailable = AgentDB !== undefined;
|
|
99
|
+
if (this.agentdbAvailable) {
|
|
100
|
+
try {
|
|
101
|
+
this.agentdb = new AgentDB({
|
|
102
|
+
dbPath: this.config.dbPath || ':memory:',
|
|
103
|
+
namespace: this.config.namespace,
|
|
104
|
+
vectorDimension: this.config.vectorDimension,
|
|
105
|
+
vectorBackend: 'auto',
|
|
106
|
+
});
|
|
107
|
+
await this.agentdb.initialize();
|
|
108
|
+
this.emitEvent({ type: 'memory_consolidated', memoriesCount: 0 });
|
|
109
|
+
}
|
|
110
|
+
catch (error) {
|
|
111
|
+
console.warn('AgentDB initialization failed, using fallback:', error);
|
|
112
|
+
this.agentdbAvailable = false;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
this.initialized = true;
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Shutdown and cleanup resources
|
|
120
|
+
*/
|
|
121
|
+
async shutdown() {
|
|
122
|
+
if (this.agentdb) {
|
|
123
|
+
await this.agentdb.close?.();
|
|
124
|
+
}
|
|
125
|
+
this.initialized = false;
|
|
126
|
+
}
|
|
127
|
+
// ==========================================================================
|
|
128
|
+
// STEP 1: RETRIEVE - Top-k memory injection with MMR diversity
|
|
129
|
+
// ==========================================================================
|
|
130
|
+
/**
|
|
131
|
+
* Retrieve relevant memories using Maximal Marginal Relevance (MMR)
|
|
132
|
+
*
|
|
133
|
+
* Uses AgentDB HNSW index for 150x faster retrieval when available.
|
|
134
|
+
*
|
|
135
|
+
* @param queryEmbedding - Query vector for similarity search
|
|
136
|
+
* @param k - Number of results to return (default: config.retrievalK)
|
|
137
|
+
* @returns Retrieval results with relevance and diversity scores
|
|
138
|
+
*/
|
|
139
|
+
async retrieve(queryEmbedding, k) {
|
|
140
|
+
const startTime = performance.now();
|
|
141
|
+
const retrieveK = k ?? this.config.retrievalK;
|
|
142
|
+
if (this.memories.size === 0) {
|
|
143
|
+
return [];
|
|
144
|
+
}
|
|
145
|
+
let candidates = [];
|
|
146
|
+
// Try AgentDB HNSW search first
|
|
147
|
+
if (this.agentdb && this.agentdbAvailable) {
|
|
148
|
+
try {
|
|
149
|
+
const results = await this.searchWithAgentDB(queryEmbedding, retrieveK * 3);
|
|
150
|
+
candidates = results
|
|
151
|
+
.map(r => {
|
|
152
|
+
const entry = this.memories.get(r.id);
|
|
153
|
+
return entry ? { entry, relevance: r.similarity } : null;
|
|
154
|
+
})
|
|
155
|
+
.filter((c) => c !== null);
|
|
156
|
+
}
|
|
157
|
+
catch {
|
|
158
|
+
// Fall through to brute-force
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
// Fallback: brute-force search
|
|
162
|
+
if (candidates.length === 0) {
|
|
163
|
+
for (const entry of this.memories.values()) {
|
|
164
|
+
const relevance = this.cosineSimilarity(queryEmbedding, entry.memory.embedding);
|
|
165
|
+
candidates.push({ entry, relevance });
|
|
166
|
+
}
|
|
167
|
+
candidates.sort((a, b) => b.relevance - a.relevance);
|
|
168
|
+
}
|
|
169
|
+
// Apply MMR for diversity
|
|
170
|
+
const results = [];
|
|
171
|
+
const selected = [];
|
|
172
|
+
while (results.length < retrieveK && candidates.length > 0) {
|
|
173
|
+
let bestIdx = 0;
|
|
174
|
+
let bestScore = -Infinity;
|
|
175
|
+
for (let i = 0; i < candidates.length; i++) {
|
|
176
|
+
const candidate = candidates[i];
|
|
177
|
+
// Compute MMR score: lambda * relevance - (1 - lambda) * max_similarity_to_selected
|
|
178
|
+
const relevance = candidate.relevance;
|
|
179
|
+
let maxSimilarity = 0;
|
|
180
|
+
for (const sel of selected) {
|
|
181
|
+
const sim = this.cosineSimilarity(candidate.entry.memory.embedding, sel.memory.embedding);
|
|
182
|
+
maxSimilarity = Math.max(maxSimilarity, sim);
|
|
183
|
+
}
|
|
184
|
+
const diversityScore = 1 - maxSimilarity;
|
|
185
|
+
const mmrScore = this.config.mmrLambda * relevance +
|
|
186
|
+
(1 - this.config.mmrLambda) * diversityScore;
|
|
187
|
+
if (mmrScore > bestScore) {
|
|
188
|
+
bestScore = mmrScore;
|
|
189
|
+
bestIdx = i;
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
// Add best candidate
|
|
193
|
+
const best = candidates[bestIdx];
|
|
194
|
+
selected.push(best.entry);
|
|
195
|
+
results.push({
|
|
196
|
+
memory: best.entry.memory,
|
|
197
|
+
relevanceScore: best.relevance,
|
|
198
|
+
diversityScore: 1 - this.computeMaxSimilarity(best.entry, selected.slice(0, -1)),
|
|
199
|
+
combinedScore: bestScore,
|
|
200
|
+
});
|
|
201
|
+
// Remove from candidates
|
|
202
|
+
candidates.splice(bestIdx, 1);
|
|
203
|
+
}
|
|
204
|
+
// Update stats
|
|
205
|
+
this.retrievalCount++;
|
|
206
|
+
this.totalRetrievalTime += performance.now() - startTime;
|
|
207
|
+
return results;
|
|
208
|
+
}
|
|
209
|
+
/**
|
|
210
|
+
* Search for similar memories by content string
|
|
211
|
+
*
|
|
212
|
+
* @param content - Text content to search for
|
|
213
|
+
* @param k - Number of results
|
|
214
|
+
* @returns Retrieval results
|
|
215
|
+
*/
|
|
216
|
+
async retrieveByContent(content, k) {
|
|
217
|
+
// Simple content-based retrieval using memory strategies
|
|
218
|
+
const retrieveK = k ?? this.config.retrievalK;
|
|
219
|
+
const results = [];
|
|
220
|
+
const contentLower = content.toLowerCase();
|
|
221
|
+
const entries = Array.from(this.memories.values());
|
|
222
|
+
// Score by content similarity
|
|
223
|
+
const scored = entries.map(entry => ({
|
|
224
|
+
entry,
|
|
225
|
+
score: this.computeContentSimilarity(contentLower, entry.memory.strategy),
|
|
226
|
+
}));
|
|
227
|
+
scored.sort((a, b) => b.score - a.score);
|
|
228
|
+
for (let i = 0; i < Math.min(retrieveK, scored.length); i++) {
|
|
229
|
+
const { entry, score } = scored[i];
|
|
230
|
+
if (score > 0) {
|
|
231
|
+
results.push({
|
|
232
|
+
memory: entry.memory,
|
|
233
|
+
relevanceScore: score,
|
|
234
|
+
diversityScore: 1,
|
|
235
|
+
combinedScore: score,
|
|
236
|
+
});
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
return results;
|
|
240
|
+
}
|
|
241
|
+
// ==========================================================================
|
|
242
|
+
// STEP 2: JUDGE - LLM-as-judge trajectory evaluation
|
|
243
|
+
// ==========================================================================
|
|
244
|
+
/**
|
|
245
|
+
* Judge a trajectory and produce a verdict
|
|
246
|
+
*
|
|
247
|
+
* Uses rule-based evaluation to assess trajectory quality.
|
|
248
|
+
* In production, this could be enhanced with LLM-as-judge.
|
|
249
|
+
*
|
|
250
|
+
* @param trajectory - Completed trajectory to judge
|
|
251
|
+
* @returns Verdict with success status and analysis
|
|
252
|
+
*/
|
|
253
|
+
async judge(trajectory) {
|
|
254
|
+
const startTime = performance.now();
|
|
255
|
+
if (!trajectory.isComplete) {
|
|
256
|
+
throw new Error('Cannot judge incomplete trajectory');
|
|
257
|
+
}
|
|
258
|
+
// Analyze trajectory steps
|
|
259
|
+
const stepAnalysis = this.analyzeSteps(trajectory.steps);
|
|
260
|
+
// Compute success based on quality and step analysis
|
|
261
|
+
const success = trajectory.qualityScore >= this.config.distillationThreshold &&
|
|
262
|
+
stepAnalysis.positiveRatio > 0.6;
|
|
263
|
+
// Identify strengths and weaknesses
|
|
264
|
+
const strengths = this.identifyStrengths(trajectory, stepAnalysis);
|
|
265
|
+
const weaknesses = this.identifyWeaknesses(trajectory, stepAnalysis);
|
|
266
|
+
// Generate improvement suggestions
|
|
267
|
+
const improvements = this.generateImprovements(weaknesses);
|
|
268
|
+
// Compute relevance for similar future tasks
|
|
269
|
+
const relevanceScore = this.computeRelevanceScore(trajectory);
|
|
270
|
+
const verdict = {
|
|
271
|
+
success,
|
|
272
|
+
confidence: this.computeConfidence(trajectory, stepAnalysis),
|
|
273
|
+
strengths,
|
|
274
|
+
weaknesses,
|
|
275
|
+
improvements,
|
|
276
|
+
relevanceScore,
|
|
277
|
+
};
|
|
278
|
+
// Store verdict with trajectory
|
|
279
|
+
trajectory.verdict = verdict;
|
|
280
|
+
// Update stats
|
|
281
|
+
this.judgeCount++;
|
|
282
|
+
this.totalJudgeTime += performance.now() - startTime;
|
|
283
|
+
return verdict;
|
|
284
|
+
}
|
|
285
|
+
// ==========================================================================
|
|
286
|
+
// STEP 3: DISTILL - Extract strategy memories from trajectories
|
|
287
|
+
// ==========================================================================
|
|
288
|
+
/**
|
|
289
|
+
* Distill a trajectory into a reusable memory
|
|
290
|
+
*
|
|
291
|
+
* @param trajectory - Trajectory to distill
|
|
292
|
+
* @returns Distilled memory or null if quality too low
|
|
293
|
+
*/
|
|
294
|
+
async distill(trajectory) {
|
|
295
|
+
const startTime = performance.now();
|
|
296
|
+
// Must be judged first
|
|
297
|
+
if (!trajectory.verdict) {
|
|
298
|
+
await this.judge(trajectory);
|
|
299
|
+
}
|
|
300
|
+
// Only distill successful trajectories
|
|
301
|
+
if (!trajectory.verdict.success ||
|
|
302
|
+
trajectory.qualityScore < this.config.distillationThreshold) {
|
|
303
|
+
return null;
|
|
304
|
+
}
|
|
305
|
+
// Extract strategy from trajectory
|
|
306
|
+
const strategy = this.extractStrategy(trajectory);
|
|
307
|
+
// Extract key learnings
|
|
308
|
+
const keyLearnings = this.extractKeyLearnings(trajectory);
|
|
309
|
+
// Compute aggregated embedding
|
|
310
|
+
const embedding = this.computeAggregateEmbedding(trajectory);
|
|
311
|
+
const memory = {
|
|
312
|
+
memoryId: `mem_${Date.now()}_${Math.random().toString(36).slice(2, 9)}`,
|
|
313
|
+
trajectoryId: trajectory.trajectoryId,
|
|
314
|
+
strategy,
|
|
315
|
+
keyLearnings,
|
|
316
|
+
embedding,
|
|
317
|
+
quality: trajectory.qualityScore,
|
|
318
|
+
usageCount: 0,
|
|
319
|
+
lastUsed: Date.now(),
|
|
320
|
+
};
|
|
321
|
+
// Store the memory
|
|
322
|
+
const entry = {
|
|
323
|
+
memory,
|
|
324
|
+
trajectory,
|
|
325
|
+
verdict: trajectory.verdict,
|
|
326
|
+
consolidated: false,
|
|
327
|
+
};
|
|
328
|
+
this.memories.set(memory.memoryId, entry);
|
|
329
|
+
// Store in AgentDB for vector search
|
|
330
|
+
if (this.agentdb && this.agentdbAvailable) {
|
|
331
|
+
await this.storeInAgentDB(memory);
|
|
332
|
+
}
|
|
333
|
+
// Also store trajectory reference
|
|
334
|
+
trajectory.distilledMemory = memory;
|
|
335
|
+
// Update stats
|
|
336
|
+
this.distillationCount++;
|
|
337
|
+
this.totalDistillationTime += performance.now() - startTime;
|
|
338
|
+
this.emitEvent({
|
|
339
|
+
type: 'trajectory_completed',
|
|
340
|
+
trajectoryId: trajectory.trajectoryId,
|
|
341
|
+
qualityScore: trajectory.qualityScore,
|
|
342
|
+
});
|
|
343
|
+
return memory;
|
|
344
|
+
}
|
|
345
|
+
/**
|
|
346
|
+
* Batch distill multiple trajectories
|
|
347
|
+
*
|
|
348
|
+
* @param trajectories - Array of trajectories to distill
|
|
349
|
+
* @returns Array of distilled memories (excludes nulls)
|
|
350
|
+
*/
|
|
351
|
+
async distillBatch(trajectories) {
|
|
352
|
+
const memories = [];
|
|
353
|
+
for (const trajectory of trajectories) {
|
|
354
|
+
const memory = await this.distill(trajectory);
|
|
355
|
+
if (memory) {
|
|
356
|
+
memories.push(memory);
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
return memories;
|
|
360
|
+
}
|
|
361
|
+
// ==========================================================================
|
|
362
|
+
// STEP 4: CONSOLIDATE - Dedup, detect contradictions, prune old patterns
|
|
363
|
+
// ==========================================================================
|
|
364
|
+
/**
|
|
365
|
+
* Consolidate memories: deduplicate, detect contradictions, prune old
|
|
366
|
+
*
|
|
367
|
+
* @returns Consolidation statistics
|
|
368
|
+
*/
|
|
369
|
+
async consolidate() {
|
|
370
|
+
const startTime = performance.now();
|
|
371
|
+
const result = {
|
|
372
|
+
removedDuplicates: 0,
|
|
373
|
+
contradictionsDetected: 0,
|
|
374
|
+
prunedPatterns: 0,
|
|
375
|
+
mergedPatterns: 0,
|
|
376
|
+
};
|
|
377
|
+
// 1. Deduplicate similar memories
|
|
378
|
+
result.removedDuplicates = await this.deduplicateMemories();
|
|
379
|
+
// 2. Detect contradictions
|
|
380
|
+
if (this.config.enableContradictionDetection) {
|
|
381
|
+
result.contradictionsDetected = await this.detectContradictions();
|
|
382
|
+
}
|
|
383
|
+
// 3. Prune old patterns
|
|
384
|
+
result.prunedPatterns = await this.pruneOldPatterns();
|
|
385
|
+
// 4. Merge similar patterns
|
|
386
|
+
result.mergedPatterns = await this.mergePatterns();
|
|
387
|
+
// Update stats
|
|
388
|
+
this.consolidationCount++;
|
|
389
|
+
this.totalConsolidationTime += performance.now() - startTime;
|
|
390
|
+
// Emit consolidation event
|
|
391
|
+
this.emitEvent({
|
|
392
|
+
type: 'memory_consolidated',
|
|
393
|
+
memoriesCount: this.memories.size,
|
|
394
|
+
});
|
|
395
|
+
return result;
|
|
396
|
+
}
|
|
397
|
+
// ==========================================================================
|
|
398
|
+
// Pattern Management
|
|
399
|
+
// ==========================================================================
|
|
400
|
+
/**
|
|
401
|
+
* Convert a distilled memory to a pattern
|
|
402
|
+
*/
|
|
403
|
+
memoryToPattern(memory) {
|
|
404
|
+
const pattern = {
|
|
405
|
+
patternId: `pat_${memory.memoryId}`,
|
|
406
|
+
name: this.generatePatternName(memory),
|
|
407
|
+
domain: this.inferDomain(memory),
|
|
408
|
+
embedding: memory.embedding,
|
|
409
|
+
strategy: memory.strategy,
|
|
410
|
+
successRate: memory.quality,
|
|
411
|
+
usageCount: memory.usageCount,
|
|
412
|
+
qualityHistory: [memory.quality],
|
|
413
|
+
evolutionHistory: [],
|
|
414
|
+
createdAt: Date.now(),
|
|
415
|
+
updatedAt: Date.now(),
|
|
416
|
+
};
|
|
417
|
+
this.patterns.set(pattern.patternId, pattern);
|
|
418
|
+
return pattern;
|
|
419
|
+
}
|
|
420
|
+
/**
|
|
421
|
+
* Evolve a pattern based on new experience
|
|
422
|
+
*/
|
|
423
|
+
evolvePattern(patternId, newExperience) {
|
|
424
|
+
const pattern = this.patterns.get(patternId);
|
|
425
|
+
if (!pattern)
|
|
426
|
+
return;
|
|
427
|
+
const previousQuality = pattern.successRate;
|
|
428
|
+
// Update quality history
|
|
429
|
+
pattern.qualityHistory.push(newExperience.qualityScore);
|
|
430
|
+
if (pattern.qualityHistory.length > 100) {
|
|
431
|
+
pattern.qualityHistory = pattern.qualityHistory.slice(-100);
|
|
432
|
+
}
|
|
433
|
+
// Update success rate
|
|
434
|
+
pattern.successRate = pattern.qualityHistory.reduce((a, b) => a + b, 0) /
|
|
435
|
+
pattern.qualityHistory.length;
|
|
436
|
+
pattern.usageCount++;
|
|
437
|
+
pattern.updatedAt = Date.now();
|
|
438
|
+
// Record evolution
|
|
439
|
+
const evolutionType = this.determineEvolutionType(previousQuality, pattern.successRate);
|
|
440
|
+
pattern.evolutionHistory.push({
|
|
441
|
+
timestamp: Date.now(),
|
|
442
|
+
type: evolutionType,
|
|
443
|
+
previousQuality,
|
|
444
|
+
newQuality: pattern.successRate,
|
|
445
|
+
description: `Updated based on trajectory ${newExperience.trajectoryId}`,
|
|
446
|
+
});
|
|
447
|
+
// Emit event
|
|
448
|
+
this.emitEvent({
|
|
449
|
+
type: 'pattern_evolved',
|
|
450
|
+
patternId,
|
|
451
|
+
evolutionType,
|
|
452
|
+
});
|
|
453
|
+
}
|
|
454
|
+
/**
|
|
455
|
+
* Get all patterns
|
|
456
|
+
*/
|
|
457
|
+
getPatterns() {
|
|
458
|
+
return Array.from(this.patterns.values());
|
|
459
|
+
}
|
|
460
|
+
/**
|
|
461
|
+
* Find patterns matching a query
|
|
462
|
+
*/
|
|
463
|
+
async findPatterns(queryEmbedding, k = 5) {
|
|
464
|
+
const results = [];
|
|
465
|
+
for (const pattern of this.patterns.values()) {
|
|
466
|
+
const score = this.cosineSimilarity(queryEmbedding, pattern.embedding);
|
|
467
|
+
results.push({ pattern, score });
|
|
468
|
+
}
|
|
469
|
+
results.sort((a, b) => b.score - a.score);
|
|
470
|
+
return results.slice(0, k).map(r => r.pattern);
|
|
471
|
+
}
|
|
472
|
+
// ==========================================================================
|
|
473
|
+
// Trajectory Management
|
|
474
|
+
// ==========================================================================
|
|
475
|
+
/**
|
|
476
|
+
* Store a trajectory
|
|
477
|
+
*/
|
|
478
|
+
storeTrajectory(trajectory) {
|
|
479
|
+
this.trajectories.set(trajectory.trajectoryId, trajectory);
|
|
480
|
+
// Prune if over capacity
|
|
481
|
+
if (this.trajectories.size > this.config.maxTrajectories) {
|
|
482
|
+
this.pruneTrajectories();
|
|
483
|
+
}
|
|
484
|
+
}
|
|
485
|
+
/**
|
|
486
|
+
* Get trajectory by ID
|
|
487
|
+
*/
|
|
488
|
+
getTrajectory(trajectoryId) {
|
|
489
|
+
return this.trajectories.get(trajectoryId);
|
|
490
|
+
}
|
|
491
|
+
/**
|
|
492
|
+
* Get all trajectories
|
|
493
|
+
*/
|
|
494
|
+
getTrajectories() {
|
|
495
|
+
return Array.from(this.trajectories.values());
|
|
496
|
+
}
|
|
497
|
+
/**
|
|
498
|
+
* Get successful trajectories
|
|
499
|
+
*/
|
|
500
|
+
getSuccessfulTrajectories() {
|
|
501
|
+
return Array.from(this.trajectories.values())
|
|
502
|
+
.filter(t => t.verdict?.success);
|
|
503
|
+
}
|
|
504
|
+
/**
|
|
505
|
+
* Get failed trajectories
|
|
506
|
+
*/
|
|
507
|
+
getFailedTrajectories() {
|
|
508
|
+
return Array.from(this.trajectories.values())
|
|
509
|
+
.filter(t => t.isComplete && !t.verdict?.success);
|
|
510
|
+
}
|
|
511
|
+
// ==========================================================================
|
|
512
|
+
// Statistics
|
|
513
|
+
// ==========================================================================
|
|
514
|
+
/**
|
|
515
|
+
* Get ReasoningBank statistics
|
|
516
|
+
*/
|
|
517
|
+
getStats() {
|
|
518
|
+
return {
|
|
519
|
+
trajectoryCount: this.trajectories.size,
|
|
520
|
+
memoryCount: this.memories.size,
|
|
521
|
+
patternCount: this.patterns.size,
|
|
522
|
+
avgRetrievalTimeMs: this.retrievalCount > 0
|
|
523
|
+
? this.totalRetrievalTime / this.retrievalCount
|
|
524
|
+
: 0,
|
|
525
|
+
avgDistillationTimeMs: this.distillationCount > 0
|
|
526
|
+
? this.totalDistillationTime / this.distillationCount
|
|
527
|
+
: 0,
|
|
528
|
+
avgJudgeTimeMs: this.judgeCount > 0
|
|
529
|
+
? this.totalJudgeTime / this.judgeCount
|
|
530
|
+
: 0,
|
|
531
|
+
avgConsolidationTimeMs: this.consolidationCount > 0
|
|
532
|
+
? this.totalConsolidationTime / this.consolidationCount
|
|
533
|
+
: 0,
|
|
534
|
+
consolidatedMemories: Array.from(this.memories.values())
|
|
535
|
+
.filter(e => e.consolidated).length,
|
|
536
|
+
successfulTrajectories: this.getSuccessfulTrajectories().length,
|
|
537
|
+
failedTrajectories: this.getFailedTrajectories().length,
|
|
538
|
+
agentdbEnabled: this.agentdbAvailable ? 1 : 0,
|
|
539
|
+
retrievalCount: this.retrievalCount,
|
|
540
|
+
distillationCount: this.distillationCount,
|
|
541
|
+
judgeCount: this.judgeCount,
|
|
542
|
+
consolidationCount: this.consolidationCount,
|
|
543
|
+
};
|
|
544
|
+
}
|
|
545
|
+
/**
|
|
546
|
+
* Get detailed metrics for hooks
|
|
547
|
+
*/
|
|
548
|
+
getDetailedMetrics() {
|
|
549
|
+
const successfulTrajectories = this.getSuccessfulTrajectories();
|
|
550
|
+
const allTrajectories = this.getTrajectories();
|
|
551
|
+
const successRate = allTrajectories.length > 0
|
|
552
|
+
? successfulTrajectories.length / allTrajectories.length
|
|
553
|
+
: 0;
|
|
554
|
+
// Extract domain-based routing stats
|
|
555
|
+
const domainStats = new Map();
|
|
556
|
+
for (const t of allTrajectories) {
|
|
557
|
+
const domain = t.domain || 'general';
|
|
558
|
+
const stats = domainStats.get(domain) || { count: 0, successes: 0 };
|
|
559
|
+
stats.count++;
|
|
560
|
+
if (t.verdict?.success)
|
|
561
|
+
stats.successes++;
|
|
562
|
+
domainStats.set(domain, stats);
|
|
563
|
+
}
|
|
564
|
+
const topAgents = Array.from(domainStats.entries())
|
|
565
|
+
.map(([agent, stats]) => ({
|
|
566
|
+
agent,
|
|
567
|
+
count: stats.count,
|
|
568
|
+
successRate: stats.count > 0 ? stats.successes / stats.count : 0,
|
|
569
|
+
}))
|
|
570
|
+
.sort((a, b) => b.count - a.count)
|
|
571
|
+
.slice(0, 5);
|
|
572
|
+
// Extract common patterns
|
|
573
|
+
const patternStrategies = Array.from(this.patterns.values())
|
|
574
|
+
.sort((a, b) => b.usageCount - a.usageCount)
|
|
575
|
+
.slice(0, 5)
|
|
576
|
+
.map(p => p.strategy);
|
|
577
|
+
return {
|
|
578
|
+
routing: {
|
|
579
|
+
totalRoutes: allTrajectories.length,
|
|
580
|
+
avgConfidence: successfulTrajectories.length > 0
|
|
581
|
+
? successfulTrajectories.reduce((sum, t) => sum + (t.verdict?.confidence || 0), 0) / successfulTrajectories.length
|
|
582
|
+
: 0,
|
|
583
|
+
topAgents,
|
|
584
|
+
},
|
|
585
|
+
edits: {
|
|
586
|
+
totalEdits: this.memories.size,
|
|
587
|
+
successRate,
|
|
588
|
+
commonPatterns: patternStrategies.slice(0, 4),
|
|
589
|
+
},
|
|
590
|
+
commands: {
|
|
591
|
+
totalCommands: this.distillationCount,
|
|
592
|
+
successRate,
|
|
593
|
+
avgExecutionTime: this.totalDistillationTime / Math.max(this.distillationCount, 1),
|
|
594
|
+
commonCommands: patternStrategies.slice(0, 4),
|
|
595
|
+
},
|
|
596
|
+
};
|
|
597
|
+
}
|
|
598
|
+
// ==========================================================================
|
|
599
|
+
// Event System
|
|
600
|
+
// ==========================================================================
|
|
601
|
+
addEventListener(listener) {
|
|
602
|
+
this.eventListeners.add(listener);
|
|
603
|
+
}
|
|
604
|
+
removeEventListener(listener) {
|
|
605
|
+
this.eventListeners.delete(listener);
|
|
606
|
+
}
|
|
607
|
+
emitEvent(event) {
|
|
608
|
+
for (const listener of this.eventListeners) {
|
|
609
|
+
try {
|
|
610
|
+
listener(event);
|
|
611
|
+
}
|
|
612
|
+
catch (error) {
|
|
613
|
+
console.error('Error in ReasoningBank event listener:', error);
|
|
614
|
+
}
|
|
615
|
+
}
|
|
616
|
+
}
|
|
617
|
+
// ==========================================================================
|
|
618
|
+
// AgentDB Integration Helpers
|
|
619
|
+
// ==========================================================================
|
|
620
|
+
/**
|
|
621
|
+
* Store memory in AgentDB for vector search
|
|
622
|
+
*/
|
|
623
|
+
async storeInAgentDB(memory) {
|
|
624
|
+
if (!this.agentdb)
|
|
625
|
+
return;
|
|
626
|
+
try {
|
|
627
|
+
if (typeof this.agentdb.store === 'function') {
|
|
628
|
+
await this.agentdb.store(memory.memoryId, {
|
|
629
|
+
content: memory.strategy,
|
|
630
|
+
embedding: memory.embedding,
|
|
631
|
+
metadata: {
|
|
632
|
+
trajectoryId: memory.trajectoryId,
|
|
633
|
+
quality: memory.quality,
|
|
634
|
+
keyLearnings: memory.keyLearnings,
|
|
635
|
+
usageCount: memory.usageCount,
|
|
636
|
+
lastUsed: memory.lastUsed,
|
|
637
|
+
},
|
|
638
|
+
});
|
|
639
|
+
}
|
|
640
|
+
}
|
|
641
|
+
catch (error) {
|
|
642
|
+
console.warn('Failed to store in AgentDB:', error);
|
|
643
|
+
}
|
|
644
|
+
}
|
|
645
|
+
/**
|
|
646
|
+
* Search using AgentDB HNSW index
|
|
647
|
+
*/
|
|
648
|
+
async searchWithAgentDB(queryEmbedding, k) {
|
|
649
|
+
if (!this.agentdb)
|
|
650
|
+
return [];
|
|
651
|
+
try {
|
|
652
|
+
if (typeof this.agentdb.search === 'function') {
|
|
653
|
+
return await this.agentdb.search(queryEmbedding, k);
|
|
654
|
+
}
|
|
655
|
+
// Try HNSW controller if available
|
|
656
|
+
const hnsw = this.agentdb.getController?.('hnsw');
|
|
657
|
+
if (hnsw) {
|
|
658
|
+
const results = await hnsw.search(queryEmbedding, k);
|
|
659
|
+
return results.map((r) => ({
|
|
660
|
+
id: String(r.id),
|
|
661
|
+
similarity: r.similarity || 1 - r.distance,
|
|
662
|
+
}));
|
|
663
|
+
}
|
|
664
|
+
}
|
|
665
|
+
catch {
|
|
666
|
+
// Fall through to return empty
|
|
667
|
+
}
|
|
668
|
+
return [];
|
|
669
|
+
}
|
|
670
|
+
/**
|
|
671
|
+
* Delete from AgentDB
|
|
672
|
+
*/
|
|
673
|
+
async deleteFromAgentDB(memoryId) {
|
|
674
|
+
if (!this.agentdb)
|
|
675
|
+
return;
|
|
676
|
+
try {
|
|
677
|
+
if (typeof this.agentdb.delete === 'function') {
|
|
678
|
+
await this.agentdb.delete(memoryId);
|
|
679
|
+
}
|
|
680
|
+
}
|
|
681
|
+
catch {
|
|
682
|
+
// Ignore deletion errors
|
|
683
|
+
}
|
|
684
|
+
}
|
|
685
|
+
// ==========================================================================
|
|
686
|
+
// Private Helper Methods
|
|
687
|
+
// ==========================================================================
|
|
688
|
+
cosineSimilarity(a, b) {
|
|
689
|
+
if (a.length !== b.length)
|
|
690
|
+
return 0;
|
|
691
|
+
let dot = 0, normA = 0, normB = 0;
|
|
692
|
+
for (let i = 0; i < a.length; i++) {
|
|
693
|
+
dot += a[i] * b[i];
|
|
694
|
+
normA += a[i] * a[i];
|
|
695
|
+
normB += b[i] * b[i];
|
|
696
|
+
}
|
|
697
|
+
const denom = Math.sqrt(normA) * Math.sqrt(normB);
|
|
698
|
+
// Clamp to [0, 1] to handle floating point precision issues
|
|
699
|
+
const similarity = denom > 0 ? dot / denom : 0;
|
|
700
|
+
return Math.max(0, Math.min(1, similarity));
|
|
701
|
+
}
|
|
702
|
+
computeContentSimilarity(query, content) {
|
|
703
|
+
const queryWords = new Set(query.toLowerCase().split(/\s+/));
|
|
704
|
+
const contentWords = content.toLowerCase().split(/\s+/);
|
|
705
|
+
let matches = 0;
|
|
706
|
+
for (const word of contentWords) {
|
|
707
|
+
if (queryWords.has(word))
|
|
708
|
+
matches++;
|
|
709
|
+
}
|
|
710
|
+
return contentWords.length > 0 ? matches / contentWords.length : 0;
|
|
711
|
+
}
|
|
712
|
+
computeMaxSimilarity(entry, selected) {
|
|
713
|
+
let maxSim = 0;
|
|
714
|
+
for (const sel of selected) {
|
|
715
|
+
const sim = this.cosineSimilarity(entry.memory.embedding, sel.memory.embedding);
|
|
716
|
+
maxSim = Math.max(maxSim, sim);
|
|
717
|
+
}
|
|
718
|
+
return maxSim;
|
|
719
|
+
}
|
|
720
|
+
analyzeSteps(steps) {
|
|
721
|
+
const rewardSum = steps.reduce((s, step) => s + step.reward, 0);
|
|
722
|
+
const positiveSteps = steps.filter(s => s.reward > 0.5).length;
|
|
723
|
+
return {
|
|
724
|
+
totalSteps: steps.length,
|
|
725
|
+
avgReward: steps.length > 0 ? rewardSum / steps.length : 0,
|
|
726
|
+
positiveRatio: steps.length > 0 ? positiveSteps / steps.length : 0,
|
|
727
|
+
trajectory: steps.length > 1
|
|
728
|
+
? (steps[steps.length - 1].reward - steps[0].reward)
|
|
729
|
+
: 0,
|
|
730
|
+
};
|
|
731
|
+
}
|
|
732
|
+
identifyStrengths(trajectory, analysis) {
|
|
733
|
+
const strengths = [];
|
|
734
|
+
if (analysis.avgReward > 0.7) {
|
|
735
|
+
strengths.push('High average reward across steps');
|
|
736
|
+
}
|
|
737
|
+
if (analysis.trajectory > 0.2) {
|
|
738
|
+
strengths.push('Positive reward trajectory');
|
|
739
|
+
}
|
|
740
|
+
if (trajectory.qualityScore > 0.8) {
|
|
741
|
+
strengths.push('High overall quality');
|
|
742
|
+
}
|
|
743
|
+
if (analysis.totalSteps < 5 && trajectory.qualityScore > 0.6) {
|
|
744
|
+
strengths.push('Efficient solution (few steps)');
|
|
745
|
+
}
|
|
746
|
+
return strengths;
|
|
747
|
+
}
|
|
748
|
+
identifyWeaknesses(trajectory, analysis) {
|
|
749
|
+
const weaknesses = [];
|
|
750
|
+
if (analysis.avgReward < 0.4) {
|
|
751
|
+
weaknesses.push('Low average reward');
|
|
752
|
+
}
|
|
753
|
+
if (analysis.trajectory < -0.1) {
|
|
754
|
+
weaknesses.push('Declining reward trajectory');
|
|
755
|
+
}
|
|
756
|
+
if (analysis.positiveRatio < 0.5) {
|
|
757
|
+
weaknesses.push('Many negative/neutral steps');
|
|
758
|
+
}
|
|
759
|
+
if (analysis.totalSteps > 10 && trajectory.qualityScore < 0.7) {
|
|
760
|
+
weaknesses.push('Long trajectory with mediocre outcome');
|
|
761
|
+
}
|
|
762
|
+
return weaknesses;
|
|
763
|
+
}
|
|
764
|
+
generateImprovements(weaknesses) {
|
|
765
|
+
const improvements = [];
|
|
766
|
+
for (const weakness of weaknesses) {
|
|
767
|
+
if (weakness.includes('Low average reward')) {
|
|
768
|
+
improvements.push('Consider alternative strategies for each step');
|
|
769
|
+
}
|
|
770
|
+
if (weakness.includes('Declining')) {
|
|
771
|
+
improvements.push('Re-evaluate approach when reward decreases');
|
|
772
|
+
}
|
|
773
|
+
if (weakness.includes('negative/neutral')) {
|
|
774
|
+
improvements.push('Focus on steps with clearer positive signals');
|
|
775
|
+
}
|
|
776
|
+
if (weakness.includes('Long trajectory')) {
|
|
777
|
+
improvements.push('Look for shortcuts or more direct approaches');
|
|
778
|
+
}
|
|
779
|
+
}
|
|
780
|
+
return improvements;
|
|
781
|
+
}
|
|
782
|
+
computeRelevanceScore(trajectory) {
|
|
783
|
+
// Base relevance on quality and recency
|
|
784
|
+
const qualityFactor = trajectory.qualityScore;
|
|
785
|
+
const ageDays = (Date.now() - trajectory.startTime) / (1000 * 60 * 60 * 24);
|
|
786
|
+
const recencyFactor = Math.exp(-ageDays / 30); // Decay over 30 days
|
|
787
|
+
return qualityFactor * 0.7 + recencyFactor * 0.3;
|
|
788
|
+
}
|
|
789
|
+
computeConfidence(trajectory, analysis) {
|
|
790
|
+
// More steps = more confidence
|
|
791
|
+
const stepFactor = Math.min(analysis.totalSteps / 10, 1);
|
|
792
|
+
// Consistent rewards = more confidence
|
|
793
|
+
const consistencyFactor = analysis.positiveRatio;
|
|
794
|
+
// Clear outcome = more confidence
|
|
795
|
+
const outcomeFactor = Math.abs(trajectory.qualityScore - 0.5) * 2;
|
|
796
|
+
return (stepFactor * 0.3 + consistencyFactor * 0.4 + outcomeFactor * 0.3);
|
|
797
|
+
}
|
|
798
|
+
extractStrategy(trajectory) {
|
|
799
|
+
const actions = trajectory.steps.map(s => s.action);
|
|
800
|
+
const uniqueActions = [...new Set(actions)];
|
|
801
|
+
if (uniqueActions.length <= 3) {
|
|
802
|
+
return `Apply ${uniqueActions.join(' -> ')}`;
|
|
803
|
+
}
|
|
804
|
+
return `Multi-step approach: ${uniqueActions.slice(0, 3).join(', ')}...`;
|
|
805
|
+
}
|
|
806
|
+
extractKeyLearnings(trajectory) {
|
|
807
|
+
const learnings = [];
|
|
808
|
+
const verdict = trajectory.verdict;
|
|
809
|
+
// Add key success factors
|
|
810
|
+
if (verdict.success) {
|
|
811
|
+
learnings.push(`Successful approach for ${trajectory.domain} domain`);
|
|
812
|
+
for (const strength of verdict.strengths.slice(0, 2)) {
|
|
813
|
+
learnings.push(`Strength: ${strength}`);
|
|
814
|
+
}
|
|
815
|
+
}
|
|
816
|
+
else {
|
|
817
|
+
learnings.push(`Approach needs refinement`);
|
|
818
|
+
for (const improvement of verdict.improvements.slice(0, 2)) {
|
|
819
|
+
learnings.push(`Improvement: ${improvement}`);
|
|
820
|
+
}
|
|
821
|
+
}
|
|
822
|
+
return learnings;
|
|
823
|
+
}
|
|
824
|
+
computeAggregateEmbedding(trajectory) {
|
|
825
|
+
if (trajectory.steps.length === 0) {
|
|
826
|
+
return new Float32Array(this.config.vectorDimension);
|
|
827
|
+
}
|
|
828
|
+
const dim = trajectory.steps[0].stateAfter.length;
|
|
829
|
+
const aggregate = new Float32Array(dim);
|
|
830
|
+
// Weighted average of step embeddings (higher weight for later steps)
|
|
831
|
+
let totalWeight = 0;
|
|
832
|
+
for (let i = 0; i < trajectory.steps.length; i++) {
|
|
833
|
+
const weight = (i + 1) / trajectory.steps.length;
|
|
834
|
+
totalWeight += weight;
|
|
835
|
+
const step = trajectory.steps[i];
|
|
836
|
+
for (let j = 0; j < dim; j++) {
|
|
837
|
+
aggregate[j] += step.stateAfter[j] * weight;
|
|
838
|
+
}
|
|
839
|
+
}
|
|
840
|
+
// Normalize
|
|
841
|
+
for (let j = 0; j < dim; j++) {
|
|
842
|
+
aggregate[j] /= totalWeight;
|
|
843
|
+
}
|
|
844
|
+
return aggregate;
|
|
845
|
+
}
|
|
846
|
+
async deduplicateMemories() {
|
|
847
|
+
let removed = 0;
|
|
848
|
+
const entries = Array.from(this.memories.entries());
|
|
849
|
+
for (let i = 0; i < entries.length; i++) {
|
|
850
|
+
for (let j = i + 1; j < entries.length; j++) {
|
|
851
|
+
const sim = this.cosineSimilarity(entries[i][1].memory.embedding, entries[j][1].memory.embedding);
|
|
852
|
+
if (sim > this.config.dedupThreshold) {
|
|
853
|
+
// Keep the higher quality one
|
|
854
|
+
if (entries[i][1].memory.quality >= entries[j][1].memory.quality) {
|
|
855
|
+
this.memories.delete(entries[j][0]);
|
|
856
|
+
await this.deleteFromAgentDB(entries[j][0]);
|
|
857
|
+
}
|
|
858
|
+
else {
|
|
859
|
+
this.memories.delete(entries[i][0]);
|
|
860
|
+
await this.deleteFromAgentDB(entries[i][0]);
|
|
861
|
+
}
|
|
862
|
+
removed++;
|
|
863
|
+
}
|
|
864
|
+
}
|
|
865
|
+
}
|
|
866
|
+
return removed;
|
|
867
|
+
}
|
|
868
|
+
async detectContradictions() {
|
|
869
|
+
let contradictions = 0;
|
|
870
|
+
const entries = Array.from(this.memories.values());
|
|
871
|
+
for (let i = 0; i < entries.length; i++) {
|
|
872
|
+
for (let j = i + 1; j < entries.length; j++) {
|
|
873
|
+
// Similar context but opposite outcomes
|
|
874
|
+
const sim = this.cosineSimilarity(entries[i].memory.embedding, entries[j].memory.embedding);
|
|
875
|
+
if (sim > 0.8) {
|
|
876
|
+
const qualityDiff = Math.abs(entries[i].memory.quality - entries[j].memory.quality);
|
|
877
|
+
if (qualityDiff > 0.4) {
|
|
878
|
+
contradictions++;
|
|
879
|
+
// Mark lower quality as consolidated (to exclude from retrieval)
|
|
880
|
+
if (entries[i].memory.quality < entries[j].memory.quality) {
|
|
881
|
+
entries[i].consolidated = true;
|
|
882
|
+
}
|
|
883
|
+
else {
|
|
884
|
+
entries[j].consolidated = true;
|
|
885
|
+
}
|
|
886
|
+
}
|
|
887
|
+
}
|
|
888
|
+
}
|
|
889
|
+
}
|
|
890
|
+
return contradictions;
|
|
891
|
+
}
|
|
892
|
+
async pruneOldPatterns() {
|
|
893
|
+
const now = Date.now();
|
|
894
|
+
const maxAge = this.config.maxPatternAgeDays * 24 * 60 * 60 * 1000;
|
|
895
|
+
let pruned = 0;
|
|
896
|
+
for (const [id, pattern] of this.patterns) {
|
|
897
|
+
const age = now - pattern.updatedAt;
|
|
898
|
+
if (age > maxAge && pattern.usageCount < 5) {
|
|
899
|
+
this.patterns.delete(id);
|
|
900
|
+
pruned++;
|
|
901
|
+
}
|
|
902
|
+
}
|
|
903
|
+
return pruned;
|
|
904
|
+
}
|
|
905
|
+
async mergePatterns() {
|
|
906
|
+
let merged = 0;
|
|
907
|
+
const patterns = Array.from(this.patterns.entries());
|
|
908
|
+
for (let i = 0; i < patterns.length; i++) {
|
|
909
|
+
for (let j = i + 1; j < patterns.length; j++) {
|
|
910
|
+
const sim = this.cosineSimilarity(patterns[i][1].embedding, patterns[j][1].embedding);
|
|
911
|
+
if (sim > 0.9 && patterns[i][1].domain === patterns[j][1].domain) {
|
|
912
|
+
// Merge into higher quality pattern
|
|
913
|
+
const [keepId, keep] = patterns[i][1].successRate >= patterns[j][1].successRate
|
|
914
|
+
? patterns[i]
|
|
915
|
+
: patterns[j];
|
|
916
|
+
const [removeId, remove] = patterns[i][1].successRate < patterns[j][1].successRate
|
|
917
|
+
? patterns[i]
|
|
918
|
+
: patterns[j];
|
|
919
|
+
// Combine statistics
|
|
920
|
+
keep.usageCount += remove.usageCount;
|
|
921
|
+
keep.qualityHistory.push(...remove.qualityHistory);
|
|
922
|
+
keep.evolutionHistory.push({
|
|
923
|
+
timestamp: Date.now(),
|
|
924
|
+
type: 'merge',
|
|
925
|
+
previousQuality: keep.successRate,
|
|
926
|
+
newQuality: (keep.successRate + remove.successRate) / 2,
|
|
927
|
+
description: `Merged with pattern ${removeId}`,
|
|
928
|
+
});
|
|
929
|
+
this.patterns.delete(removeId);
|
|
930
|
+
merged++;
|
|
931
|
+
}
|
|
932
|
+
}
|
|
933
|
+
}
|
|
934
|
+
return merged;
|
|
935
|
+
}
|
|
936
|
+
pruneTrajectories() {
|
|
937
|
+
const entries = Array.from(this.trajectories.entries())
|
|
938
|
+
.sort((a, b) => a[1].qualityScore - b[1].qualityScore);
|
|
939
|
+
const toRemove = entries.length - Math.floor(this.config.maxTrajectories * 0.8);
|
|
940
|
+
for (let i = 0; i < toRemove && i < entries.length; i++) {
|
|
941
|
+
this.trajectories.delete(entries[i][0]);
|
|
942
|
+
}
|
|
943
|
+
}
|
|
944
|
+
generatePatternName(memory) {
|
|
945
|
+
const words = memory.strategy.split(' ').slice(0, 4);
|
|
946
|
+
return words.join('_').toLowerCase().replace(/[^a-z0-9_]/g, '');
|
|
947
|
+
}
|
|
948
|
+
inferDomain(memory) {
|
|
949
|
+
// First check if we have the trajectory directly in our store
|
|
950
|
+
const trajectory = this.trajectories.get(memory.trajectoryId);
|
|
951
|
+
if (trajectory?.domain) {
|
|
952
|
+
return trajectory.domain;
|
|
953
|
+
}
|
|
954
|
+
// Check if the memory entry has the trajectory with domain info
|
|
955
|
+
const memoryEntry = this.memories.get(memory.memoryId);
|
|
956
|
+
if (memoryEntry?.trajectory?.domain) {
|
|
957
|
+
return memoryEntry.trajectory.domain;
|
|
958
|
+
}
|
|
959
|
+
return 'general';
|
|
960
|
+
}
|
|
961
|
+
determineEvolutionType(prev, curr) {
|
|
962
|
+
const delta = curr - prev;
|
|
963
|
+
if (delta > 0.05)
|
|
964
|
+
return 'improvement';
|
|
965
|
+
if (delta < -0.1)
|
|
966
|
+
return 'prune';
|
|
967
|
+
return 'improvement';
|
|
968
|
+
}
|
|
969
|
+
/**
|
|
970
|
+
* Check if AgentDB is available and initialized
|
|
971
|
+
*/
|
|
972
|
+
isAgentDBAvailable() {
|
|
973
|
+
return this.agentdbAvailable;
|
|
974
|
+
}
|
|
975
|
+
}
|
|
976
|
+
// ============================================================================
|
|
977
|
+
// Factory Function
|
|
978
|
+
// ============================================================================
|
|
979
|
+
/**
|
|
980
|
+
* Factory function for creating ReasoningBank
|
|
981
|
+
*/
|
|
982
|
+
export function createReasoningBank(config) {
|
|
983
|
+
return new ReasoningBank(config);
|
|
984
|
+
}
|
|
985
|
+
/**
|
|
986
|
+
* Create and initialize a ReasoningBank instance
|
|
987
|
+
*/
|
|
988
|
+
export async function createInitializedReasoningBank(config) {
|
|
989
|
+
const bank = new ReasoningBank(config);
|
|
990
|
+
await bank.initialize();
|
|
991
|
+
return bank;
|
|
992
|
+
}
|
|
993
|
+
//# sourceMappingURL=reasoning-bank.js.map
|