@sparkleideas/neural 3.5.2-patch.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.
- package/README.md +260 -0
- package/__tests__/README.md +235 -0
- package/__tests__/algorithms.test.ts +582 -0
- package/__tests__/patterns.test.ts +549 -0
- package/__tests__/sona.test.ts +445 -0
- package/docs/SONA_INTEGRATION.md +460 -0
- package/docs/SONA_QUICKSTART.md +168 -0
- package/examples/sona-usage.ts +318 -0
- package/package.json +23 -0
- package/src/algorithms/a2c.d.ts +86 -0
- package/src/algorithms/a2c.d.ts.map +1 -0
- package/src/algorithms/a2c.js +361 -0
- package/src/algorithms/a2c.js.map +1 -0
- package/src/algorithms/a2c.ts +478 -0
- package/src/algorithms/curiosity.d.ts +82 -0
- package/src/algorithms/curiosity.d.ts.map +1 -0
- package/src/algorithms/curiosity.js +392 -0
- package/src/algorithms/curiosity.js.map +1 -0
- package/src/algorithms/curiosity.ts +509 -0
- package/src/algorithms/decision-transformer.d.ts +82 -0
- package/src/algorithms/decision-transformer.d.ts.map +1 -0
- package/src/algorithms/decision-transformer.js +415 -0
- package/src/algorithms/decision-transformer.js.map +1 -0
- package/src/algorithms/decision-transformer.ts +521 -0
- package/src/algorithms/dqn.d.ts +72 -0
- package/src/algorithms/dqn.d.ts.map +1 -0
- package/src/algorithms/dqn.js +303 -0
- package/src/algorithms/dqn.js.map +1 -0
- package/src/algorithms/dqn.ts +382 -0
- package/src/algorithms/index.d.ts +32 -0
- package/src/algorithms/index.d.ts.map +1 -0
- package/src/algorithms/index.js +74 -0
- package/src/algorithms/index.js.map +1 -0
- package/src/algorithms/index.ts +122 -0
- package/src/algorithms/ppo.d.ts +72 -0
- package/src/algorithms/ppo.d.ts.map +1 -0
- package/src/algorithms/ppo.js +331 -0
- package/src/algorithms/ppo.js.map +1 -0
- package/src/algorithms/ppo.ts +429 -0
- package/src/algorithms/q-learning.d.ts +77 -0
- package/src/algorithms/q-learning.d.ts.map +1 -0
- package/src/algorithms/q-learning.js +259 -0
- package/src/algorithms/q-learning.js.map +1 -0
- package/src/algorithms/q-learning.ts +333 -0
- package/src/algorithms/sarsa.d.ts +82 -0
- package/src/algorithms/sarsa.d.ts.map +1 -0
- package/src/algorithms/sarsa.js +297 -0
- package/src/algorithms/sarsa.js.map +1 -0
- package/src/algorithms/sarsa.ts +383 -0
- package/src/algorithms/tmp.json +0 -0
- package/src/application/index.ts +11 -0
- package/src/application/services/neural-application-service.ts +217 -0
- package/src/domain/entities/pattern.ts +169 -0
- package/src/domain/index.ts +18 -0
- package/src/domain/services/learning-service.ts +256 -0
- package/src/index.d.ts +118 -0
- package/src/index.d.ts.map +1 -0
- package/src/index.js +201 -0
- package/src/index.js.map +1 -0
- package/src/index.ts +363 -0
- package/src/modes/balanced.d.ts +60 -0
- package/src/modes/balanced.d.ts.map +1 -0
- package/src/modes/balanced.js +234 -0
- package/src/modes/balanced.js.map +1 -0
- package/src/modes/balanced.ts +299 -0
- package/src/modes/base.ts +163 -0
- package/src/modes/batch.d.ts +82 -0
- package/src/modes/batch.d.ts.map +1 -0
- package/src/modes/batch.js +316 -0
- package/src/modes/batch.js.map +1 -0
- package/src/modes/batch.ts +434 -0
- package/src/modes/edge.d.ts +85 -0
- package/src/modes/edge.d.ts.map +1 -0
- package/src/modes/edge.js +310 -0
- package/src/modes/edge.js.map +1 -0
- package/src/modes/edge.ts +409 -0
- package/src/modes/index.d.ts +55 -0
- package/src/modes/index.d.ts.map +1 -0
- package/src/modes/index.js +83 -0
- package/src/modes/index.js.map +1 -0
- package/src/modes/index.ts +16 -0
- package/src/modes/real-time.d.ts +58 -0
- package/src/modes/real-time.d.ts.map +1 -0
- package/src/modes/real-time.js +196 -0
- package/src/modes/real-time.js.map +1 -0
- package/src/modes/real-time.ts +257 -0
- package/src/modes/research.d.ts +79 -0
- package/src/modes/research.d.ts.map +1 -0
- package/src/modes/research.js +389 -0
- package/src/modes/research.js.map +1 -0
- package/src/modes/research.ts +486 -0
- package/src/modes/tmp.json +0 -0
- package/src/pattern-learner.d.ts +117 -0
- package/src/pattern-learner.d.ts.map +1 -0
- package/src/pattern-learner.js +603 -0
- package/src/pattern-learner.js.map +1 -0
- package/src/pattern-learner.ts +757 -0
- package/src/reasoning-bank.d.ts +259 -0
- package/src/reasoning-bank.d.ts.map +1 -0
- package/src/reasoning-bank.js +993 -0
- package/src/reasoning-bank.js.map +1 -0
- package/src/reasoning-bank.ts +1279 -0
- package/src/reasoningbank-adapter.ts +697 -0
- package/src/sona-integration.d.ts +168 -0
- package/src/sona-integration.d.ts.map +1 -0
- package/src/sona-integration.js +316 -0
- package/src/sona-integration.js.map +1 -0
- package/src/sona-integration.ts +432 -0
- package/src/sona-manager.d.ts +147 -0
- package/src/sona-manager.d.ts.map +1 -0
- package/src/sona-manager.js +695 -0
- package/src/sona-manager.js.map +1 -0
- package/src/sona-manager.ts +835 -0
- package/src/tmp.json +0 -0
- package/src/types.d.ts +431 -0
- package/src/types.d.ts.map +1 -0
- package/src/types.js +11 -0
- package/src/types.js.map +1 -0
- package/src/types.ts +590 -0
- package/tmp.json +0 -0
- package/tsconfig.json +9 -0
- package/vitest.config.ts +19 -0
|
@@ -0,0 +1,697 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* V3 ReasoningBank Adapter
|
|
3
|
+
*
|
|
4
|
+
* Provides @sparkleideas/agentic-flow@alpha compatible ReasoningBank interface:
|
|
5
|
+
* - 4-step pipeline: RETRIEVE, JUDGE, DISTILL, CONSOLIDATE
|
|
6
|
+
* - Trajectory tracking and verdict judgment
|
|
7
|
+
* - Memory distillation from successful trajectories
|
|
8
|
+
* - Pattern consolidation with deduplication and pruning
|
|
9
|
+
*
|
|
10
|
+
* Based on Algorithm 3 & 4 from ReasoningBank paper.
|
|
11
|
+
*
|
|
12
|
+
* Performance Targets:
|
|
13
|
+
* - Pattern retrieval: <5ms
|
|
14
|
+
* - Verdict judgment: <10ms
|
|
15
|
+
* - Memory distillation: <50ms
|
|
16
|
+
* - Consolidation: <100ms
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
import type {
|
|
20
|
+
Trajectory,
|
|
21
|
+
TrajectoryVerdict,
|
|
22
|
+
DistilledMemory,
|
|
23
|
+
Pattern,
|
|
24
|
+
SONAMode,
|
|
25
|
+
} from './types.js';
|
|
26
|
+
import { createSONAManager, SONAManager } from './sona-manager.js';
|
|
27
|
+
import { createPatternLearner, PatternLearner } from './pattern-learner.js';
|
|
28
|
+
|
|
29
|
+
// ============================================================================
|
|
30
|
+
// ReasoningBank Types (@sparkleideas/agentic-flow compatible)
|
|
31
|
+
// ============================================================================
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* ReasoningBank pattern record
|
|
35
|
+
*/
|
|
36
|
+
export interface ReasoningBankPattern {
|
|
37
|
+
id: string;
|
|
38
|
+
type: 'reasoning_memory' | 'strategy' | 'pattern';
|
|
39
|
+
domain: string;
|
|
40
|
+
patternData: {
|
|
41
|
+
title: string;
|
|
42
|
+
description: string;
|
|
43
|
+
content: string;
|
|
44
|
+
source: {
|
|
45
|
+
taskId: string;
|
|
46
|
+
agentId: string;
|
|
47
|
+
outcome: 'Success' | 'Failure' | 'Partial';
|
|
48
|
+
evidence: string[];
|
|
49
|
+
};
|
|
50
|
+
tags: string[];
|
|
51
|
+
domain: string;
|
|
52
|
+
createdAt: string;
|
|
53
|
+
confidence: number;
|
|
54
|
+
nUses: number;
|
|
55
|
+
};
|
|
56
|
+
confidence: number;
|
|
57
|
+
usageCount: number;
|
|
58
|
+
embedding: Float32Array;
|
|
59
|
+
createdAt: number;
|
|
60
|
+
lastUsed: number;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Verdict from trajectory judgment
|
|
65
|
+
*/
|
|
66
|
+
export interface ReasoningBankVerdict {
|
|
67
|
+
label: 'Success' | 'Failure' | 'Partial';
|
|
68
|
+
score: number;
|
|
69
|
+
evidence: string[];
|
|
70
|
+
reasoning: string;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Consolidation result
|
|
75
|
+
*/
|
|
76
|
+
export interface ConsolidationResult {
|
|
77
|
+
itemsProcessed: number;
|
|
78
|
+
duplicatesFound: number;
|
|
79
|
+
contradictionsFound: number;
|
|
80
|
+
itemsPruned: number;
|
|
81
|
+
durationMs: number;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* ReasoningBank configuration
|
|
86
|
+
*/
|
|
87
|
+
export interface ReasoningBankConfig {
|
|
88
|
+
/** Database path */
|
|
89
|
+
dbPath?: string;
|
|
90
|
+
|
|
91
|
+
/** Enable learning */
|
|
92
|
+
enableLearning?: boolean;
|
|
93
|
+
|
|
94
|
+
/** Enable reasoning agents */
|
|
95
|
+
enableReasoning?: boolean;
|
|
96
|
+
|
|
97
|
+
/** SONA mode */
|
|
98
|
+
sonaMode?: SONAMode;
|
|
99
|
+
|
|
100
|
+
/** Duplicate similarity threshold */
|
|
101
|
+
duplicateThreshold?: number;
|
|
102
|
+
|
|
103
|
+
/** Contradiction similarity threshold */
|
|
104
|
+
contradictionThreshold?: number;
|
|
105
|
+
|
|
106
|
+
/** Maximum age for pruning (days) */
|
|
107
|
+
pruneAgeDays?: number;
|
|
108
|
+
|
|
109
|
+
/** Minimum confidence to keep */
|
|
110
|
+
minConfidenceKeep?: number;
|
|
111
|
+
|
|
112
|
+
/** Consolidation trigger threshold */
|
|
113
|
+
consolidateTriggerThreshold?: number;
|
|
114
|
+
|
|
115
|
+
/** Maximum items for success distillation */
|
|
116
|
+
maxItemsSuccess?: number;
|
|
117
|
+
|
|
118
|
+
/** Maximum items for failure distillation */
|
|
119
|
+
maxItemsFailure?: number;
|
|
120
|
+
|
|
121
|
+
/** Confidence prior for success */
|
|
122
|
+
confidencePriorSuccess?: number;
|
|
123
|
+
|
|
124
|
+
/** Confidence prior for failure */
|
|
125
|
+
confidencePriorFailure?: number;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// ============================================================================
|
|
129
|
+
// ReasoningBank Adapter Implementation
|
|
130
|
+
// ============================================================================
|
|
131
|
+
|
|
132
|
+
export class ReasoningBankAdapter {
|
|
133
|
+
private readonly config: Required<ReasoningBankConfig>;
|
|
134
|
+
private readonly sonaManager: SONAManager;
|
|
135
|
+
private readonly patternLearner: PatternLearner;
|
|
136
|
+
private patterns: Map<string, ReasoningBankPattern> = new Map();
|
|
137
|
+
private newPatternsSinceConsolidation = 0;
|
|
138
|
+
private initialized = false;
|
|
139
|
+
|
|
140
|
+
constructor(config?: ReasoningBankConfig) {
|
|
141
|
+
this.config = {
|
|
142
|
+
dbPath: config?.dbPath || '.@sparkleideas/agentdb/reasoningbank.db',
|
|
143
|
+
enableLearning: config?.enableLearning ?? true,
|
|
144
|
+
enableReasoning: config?.enableReasoning ?? true,
|
|
145
|
+
sonaMode: config?.sonaMode || 'balanced',
|
|
146
|
+
duplicateThreshold: config?.duplicateThreshold ?? 0.95,
|
|
147
|
+
contradictionThreshold: config?.contradictionThreshold ?? 0.85,
|
|
148
|
+
pruneAgeDays: config?.pruneAgeDays ?? 30,
|
|
149
|
+
minConfidenceKeep: config?.minConfidenceKeep ?? 0.3,
|
|
150
|
+
consolidateTriggerThreshold: config?.consolidateTriggerThreshold ?? 100,
|
|
151
|
+
maxItemsSuccess: config?.maxItemsSuccess ?? 5,
|
|
152
|
+
maxItemsFailure: config?.maxItemsFailure ?? 3,
|
|
153
|
+
confidencePriorSuccess: config?.confidencePriorSuccess ?? 0.8,
|
|
154
|
+
confidencePriorFailure: config?.confidencePriorFailure ?? 0.5,
|
|
155
|
+
};
|
|
156
|
+
|
|
157
|
+
this.sonaManager = createSONAManager(this.config.sonaMode);
|
|
158
|
+
this.patternLearner = createPatternLearner({
|
|
159
|
+
maxPatterns: 5000,
|
|
160
|
+
matchThreshold: 0.7,
|
|
161
|
+
qualityThreshold: 0.5,
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
async initialize(): Promise<void> {
|
|
166
|
+
if (this.initialized) return;
|
|
167
|
+
|
|
168
|
+
await this.sonaManager.initialize();
|
|
169
|
+
this.initialized = true;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
// ==========================================================================
|
|
173
|
+
// Step 1: RETRIEVE - Top-k memory injection with MMR diversity
|
|
174
|
+
// ==========================================================================
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
* Retrieve relevant patterns for a query
|
|
178
|
+
*/
|
|
179
|
+
async retrieve(
|
|
180
|
+
queryEmbedding: Float32Array,
|
|
181
|
+
options?: {
|
|
182
|
+
k?: number;
|
|
183
|
+
domain?: string;
|
|
184
|
+
minConfidence?: number;
|
|
185
|
+
useMmr?: boolean;
|
|
186
|
+
mmrLambda?: number;
|
|
187
|
+
}
|
|
188
|
+
): Promise<ReasoningBankPattern[]> {
|
|
189
|
+
const k = options?.k ?? 5;
|
|
190
|
+
const domain = options?.domain;
|
|
191
|
+
const minConfidence = options?.minConfidence ?? 0;
|
|
192
|
+
const useMmr = options?.useMmr ?? true;
|
|
193
|
+
const mmrLambda = options?.mmrLambda ?? 0.7;
|
|
194
|
+
|
|
195
|
+
// Get all patterns, filter by domain and confidence
|
|
196
|
+
let candidates = Array.from(this.patterns.values());
|
|
197
|
+
|
|
198
|
+
if (domain) {
|
|
199
|
+
candidates = candidates.filter(p => p.domain === domain);
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
if (minConfidence > 0) {
|
|
203
|
+
candidates = candidates.filter(p => p.confidence >= minConfidence);
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
if (candidates.length === 0) {
|
|
207
|
+
return [];
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
// Compute similarities
|
|
211
|
+
const similarities = candidates.map(pattern => ({
|
|
212
|
+
pattern,
|
|
213
|
+
similarity: this.cosineSimilarity(queryEmbedding, pattern.embedding),
|
|
214
|
+
}));
|
|
215
|
+
|
|
216
|
+
if (!useMmr) {
|
|
217
|
+
// Simple top-k
|
|
218
|
+
return similarities
|
|
219
|
+
.sort((a, b) => b.similarity - a.similarity)
|
|
220
|
+
.slice(0, k)
|
|
221
|
+
.map(s => s.pattern);
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
// Maximal Marginal Relevance (MMR) for diversity
|
|
225
|
+
return this.mmrSelect(queryEmbedding, similarities, k, mmrLambda);
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
// ==========================================================================
|
|
229
|
+
// Step 2: JUDGE - LLM-as-judge trajectory evaluation
|
|
230
|
+
// ==========================================================================
|
|
231
|
+
|
|
232
|
+
/**
|
|
233
|
+
* Judge a trajectory's success
|
|
234
|
+
*/
|
|
235
|
+
async judge(trajectory: Trajectory): Promise<ReasoningBankVerdict> {
|
|
236
|
+
// Compute quality metrics
|
|
237
|
+
const qualityScore = trajectory.qualityScore;
|
|
238
|
+
const stepCount = trajectory.steps.length;
|
|
239
|
+
const avgReward = stepCount > 0
|
|
240
|
+
? trajectory.steps.reduce((sum, s) => sum + s.reward, 0) / stepCount
|
|
241
|
+
: 0;
|
|
242
|
+
|
|
243
|
+
// Determine verdict label
|
|
244
|
+
let label: 'Success' | 'Failure' | 'Partial';
|
|
245
|
+
if (qualityScore >= 0.8 && avgReward >= 0.7) {
|
|
246
|
+
label = 'Success';
|
|
247
|
+
} else if (qualityScore < 0.4 || avgReward < 0.3) {
|
|
248
|
+
label = 'Failure';
|
|
249
|
+
} else {
|
|
250
|
+
label = 'Partial';
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
// Collect evidence
|
|
254
|
+
const evidence: string[] = [];
|
|
255
|
+
evidence.push(`Quality score: ${qualityScore.toFixed(2)}`);
|
|
256
|
+
evidence.push(`Average reward: ${avgReward.toFixed(2)}`);
|
|
257
|
+
evidence.push(`Step count: ${stepCount}`);
|
|
258
|
+
|
|
259
|
+
if (trajectory.steps.length > 0) {
|
|
260
|
+
const lastStep = trajectory.steps[trajectory.steps.length - 1];
|
|
261
|
+
evidence.push(`Final action: ${lastStep.action}`);
|
|
262
|
+
evidence.push(`Final reward: ${lastStep.reward.toFixed(2)}`);
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
// Generate reasoning
|
|
266
|
+
const reasoning = this.generateJudgmentReasoning(trajectory, label, evidence);
|
|
267
|
+
|
|
268
|
+
return {
|
|
269
|
+
label,
|
|
270
|
+
score: qualityScore,
|
|
271
|
+
evidence,
|
|
272
|
+
reasoning,
|
|
273
|
+
};
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
// ==========================================================================
|
|
277
|
+
// Step 3: DISTILL - Extract strategy memories from trajectories
|
|
278
|
+
// ==========================================================================
|
|
279
|
+
|
|
280
|
+
/**
|
|
281
|
+
* Distill memories from a judged trajectory
|
|
282
|
+
*/
|
|
283
|
+
async distill(
|
|
284
|
+
trajectory: Trajectory,
|
|
285
|
+
verdict: ReasoningBankVerdict,
|
|
286
|
+
options?: {
|
|
287
|
+
taskId?: string;
|
|
288
|
+
agentId?: string;
|
|
289
|
+
}
|
|
290
|
+
): Promise<string[]> {
|
|
291
|
+
const maxItems = verdict.label === 'Success'
|
|
292
|
+
? this.config.maxItemsSuccess
|
|
293
|
+
: this.config.maxItemsFailure;
|
|
294
|
+
|
|
295
|
+
const confidencePrior = verdict.label === 'Success'
|
|
296
|
+
? this.config.confidencePriorSuccess
|
|
297
|
+
: this.config.confidencePriorFailure;
|
|
298
|
+
|
|
299
|
+
const memoryIds: string[] = [];
|
|
300
|
+
|
|
301
|
+
// Extract key patterns from trajectory
|
|
302
|
+
const patterns = this.extractPatternsFromTrajectory(trajectory, verdict);
|
|
303
|
+
|
|
304
|
+
for (let i = 0; i < Math.min(patterns.length, maxItems); i++) {
|
|
305
|
+
const pattern = patterns[i];
|
|
306
|
+
|
|
307
|
+
const id = `mem_${Date.now()}_${Math.random().toString(36).slice(2, 9)}`;
|
|
308
|
+
|
|
309
|
+
const rbPattern: ReasoningBankPattern = {
|
|
310
|
+
id,
|
|
311
|
+
type: 'reasoning_memory',
|
|
312
|
+
domain: trajectory.domain,
|
|
313
|
+
patternData: {
|
|
314
|
+
title: pattern.title,
|
|
315
|
+
description: pattern.description,
|
|
316
|
+
content: pattern.content,
|
|
317
|
+
source: {
|
|
318
|
+
taskId: options?.taskId || trajectory.trajectoryId,
|
|
319
|
+
agentId: options?.agentId || 'unknown',
|
|
320
|
+
outcome: verdict.label,
|
|
321
|
+
evidence: verdict.evidence,
|
|
322
|
+
},
|
|
323
|
+
tags: pattern.tags,
|
|
324
|
+
domain: trajectory.domain,
|
|
325
|
+
createdAt: new Date().toISOString(),
|
|
326
|
+
confidence: confidencePrior,
|
|
327
|
+
nUses: 0,
|
|
328
|
+
},
|
|
329
|
+
confidence: confidencePrior,
|
|
330
|
+
usageCount: 0,
|
|
331
|
+
embedding: this.computePatternEmbedding(trajectory, i),
|
|
332
|
+
createdAt: Date.now(),
|
|
333
|
+
lastUsed: Date.now(),
|
|
334
|
+
};
|
|
335
|
+
|
|
336
|
+
this.patterns.set(id, rbPattern);
|
|
337
|
+
this.newPatternsSinceConsolidation++;
|
|
338
|
+
memoryIds.push(id);
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
// Check if consolidation should run
|
|
342
|
+
if (this.shouldConsolidate()) {
|
|
343
|
+
await this.consolidate();
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
return memoryIds;
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
// ==========================================================================
|
|
350
|
+
// Step 4: CONSOLIDATE - Dedup, detect contradictions, prune old patterns
|
|
351
|
+
// ==========================================================================
|
|
352
|
+
|
|
353
|
+
/**
|
|
354
|
+
* Run consolidation: deduplicate, detect contradictions, prune
|
|
355
|
+
*/
|
|
356
|
+
async consolidate(): Promise<ConsolidationResult> {
|
|
357
|
+
const startTime = Date.now();
|
|
358
|
+
|
|
359
|
+
const patterns = Array.from(this.patterns.values());
|
|
360
|
+
let duplicatesFound = 0;
|
|
361
|
+
let contradictionsFound = 0;
|
|
362
|
+
let itemsPruned = 0;
|
|
363
|
+
|
|
364
|
+
// Step 1: Deduplicate similar patterns
|
|
365
|
+
const toRemove = new Set<string>();
|
|
366
|
+
|
|
367
|
+
for (let i = 0; i < patterns.length; i++) {
|
|
368
|
+
if (toRemove.has(patterns[i].id)) continue;
|
|
369
|
+
|
|
370
|
+
for (let j = i + 1; j < patterns.length; j++) {
|
|
371
|
+
if (toRemove.has(patterns[j].id)) continue;
|
|
372
|
+
|
|
373
|
+
const similarity = this.cosineSimilarity(
|
|
374
|
+
patterns[i].embedding,
|
|
375
|
+
patterns[j].embedding
|
|
376
|
+
);
|
|
377
|
+
|
|
378
|
+
if (similarity >= this.config.duplicateThreshold) {
|
|
379
|
+
duplicatesFound++;
|
|
380
|
+
|
|
381
|
+
// Keep the one with higher usage/confidence
|
|
382
|
+
const score1 = patterns[i].usageCount * patterns[i].confidence;
|
|
383
|
+
const score2 = patterns[j].usageCount * patterns[j].confidence;
|
|
384
|
+
|
|
385
|
+
if (score1 >= score2) {
|
|
386
|
+
toRemove.add(patterns[j].id);
|
|
387
|
+
} else {
|
|
388
|
+
toRemove.add(patterns[i].id);
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
// Step 2: Detect contradictions (similar embeddings, different outcomes)
|
|
395
|
+
for (let i = 0; i < patterns.length; i++) {
|
|
396
|
+
if (toRemove.has(patterns[i].id)) continue;
|
|
397
|
+
|
|
398
|
+
for (let j = i + 1; j < patterns.length; j++) {
|
|
399
|
+
if (toRemove.has(patterns[j].id)) continue;
|
|
400
|
+
|
|
401
|
+
const similarity = this.cosineSimilarity(
|
|
402
|
+
patterns[i].embedding,
|
|
403
|
+
patterns[j].embedding
|
|
404
|
+
);
|
|
405
|
+
|
|
406
|
+
const outcome1 = patterns[i].patternData.source.outcome;
|
|
407
|
+
const outcome2 = patterns[j].patternData.source.outcome;
|
|
408
|
+
|
|
409
|
+
if (
|
|
410
|
+
similarity >= this.config.contradictionThreshold &&
|
|
411
|
+
outcome1 !== outcome2
|
|
412
|
+
) {
|
|
413
|
+
contradictionsFound++;
|
|
414
|
+
// Log contradiction for analysis (don't auto-remove)
|
|
415
|
+
console.warn(`Contradiction detected: ${patterns[i].id} vs ${patterns[j].id}`);
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
// Step 3: Prune old, low-confidence patterns
|
|
421
|
+
const now = Date.now();
|
|
422
|
+
const maxAge = this.config.pruneAgeDays * 24 * 60 * 60 * 1000;
|
|
423
|
+
|
|
424
|
+
for (const pattern of patterns) {
|
|
425
|
+
if (toRemove.has(pattern.id)) continue;
|
|
426
|
+
|
|
427
|
+
const age = now - pattern.createdAt;
|
|
428
|
+
if (
|
|
429
|
+
age > maxAge &&
|
|
430
|
+
pattern.confidence < this.config.minConfidenceKeep &&
|
|
431
|
+
pattern.usageCount < 3
|
|
432
|
+
) {
|
|
433
|
+
toRemove.add(pattern.id);
|
|
434
|
+
itemsPruned++;
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
// Remove marked patterns
|
|
439
|
+
for (const id of toRemove) {
|
|
440
|
+
this.patterns.delete(id);
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
this.newPatternsSinceConsolidation = 0;
|
|
444
|
+
const durationMs = Date.now() - startTime;
|
|
445
|
+
|
|
446
|
+
return {
|
|
447
|
+
itemsProcessed: patterns.length,
|
|
448
|
+
duplicatesFound,
|
|
449
|
+
contradictionsFound,
|
|
450
|
+
itemsPruned,
|
|
451
|
+
durationMs,
|
|
452
|
+
};
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
// ==========================================================================
|
|
456
|
+
// Pattern Management
|
|
457
|
+
// ==========================================================================
|
|
458
|
+
|
|
459
|
+
/**
|
|
460
|
+
* Insert a pattern directly
|
|
461
|
+
*/
|
|
462
|
+
insertPattern(pattern: Omit<ReasoningBankPattern, 'createdAt' | 'lastUsed'>): string {
|
|
463
|
+
const fullPattern: ReasoningBankPattern = {
|
|
464
|
+
...pattern,
|
|
465
|
+
createdAt: Date.now(),
|
|
466
|
+
lastUsed: Date.now(),
|
|
467
|
+
};
|
|
468
|
+
|
|
469
|
+
this.patterns.set(pattern.id, fullPattern);
|
|
470
|
+
this.newPatternsSinceConsolidation++;
|
|
471
|
+
|
|
472
|
+
return pattern.id;
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
/**
|
|
476
|
+
* Get a pattern by ID
|
|
477
|
+
*/
|
|
478
|
+
getPattern(id: string): ReasoningBankPattern | undefined {
|
|
479
|
+
const pattern = this.patterns.get(id);
|
|
480
|
+
if (pattern) {
|
|
481
|
+
pattern.lastUsed = Date.now();
|
|
482
|
+
pattern.usageCount++;
|
|
483
|
+
}
|
|
484
|
+
return pattern;
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
/**
|
|
488
|
+
* Update pattern confidence
|
|
489
|
+
*/
|
|
490
|
+
updateConfidence(id: string, delta: number): void {
|
|
491
|
+
const pattern = this.patterns.get(id);
|
|
492
|
+
if (pattern) {
|
|
493
|
+
pattern.confidence = Math.max(0, Math.min(1, pattern.confidence + delta));
|
|
494
|
+
pattern.patternData.confidence = pattern.confidence;
|
|
495
|
+
}
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
/**
|
|
499
|
+
* Get statistics
|
|
500
|
+
*/
|
|
501
|
+
getStats(): {
|
|
502
|
+
totalPatterns: number;
|
|
503
|
+
byDomain: Record<string, number>;
|
|
504
|
+
byOutcome: Record<string, number>;
|
|
505
|
+
avgConfidence: number;
|
|
506
|
+
} {
|
|
507
|
+
const patterns = Array.from(this.patterns.values());
|
|
508
|
+
const byDomain: Record<string, number> = {};
|
|
509
|
+
const byOutcome: Record<string, number> = {};
|
|
510
|
+
|
|
511
|
+
for (const pattern of patterns) {
|
|
512
|
+
byDomain[pattern.domain] = (byDomain[pattern.domain] || 0) + 1;
|
|
513
|
+
byOutcome[pattern.patternData.source.outcome] =
|
|
514
|
+
(byOutcome[pattern.patternData.source.outcome] || 0) + 1;
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
const avgConfidence = patterns.length > 0
|
|
518
|
+
? patterns.reduce((sum, p) => sum + p.confidence, 0) / patterns.length
|
|
519
|
+
: 0;
|
|
520
|
+
|
|
521
|
+
return {
|
|
522
|
+
totalPatterns: patterns.length,
|
|
523
|
+
byDomain,
|
|
524
|
+
byOutcome,
|
|
525
|
+
avgConfidence,
|
|
526
|
+
};
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
// ==========================================================================
|
|
530
|
+
// Private Helper Methods
|
|
531
|
+
// ==========================================================================
|
|
532
|
+
|
|
533
|
+
private cosineSimilarity(a: Float32Array, b: Float32Array): number {
|
|
534
|
+
if (a.length !== b.length) return 0;
|
|
535
|
+
|
|
536
|
+
let dot = 0;
|
|
537
|
+
let normA = 0;
|
|
538
|
+
let normB = 0;
|
|
539
|
+
|
|
540
|
+
for (let i = 0; i < a.length; i++) {
|
|
541
|
+
dot += a[i] * b[i];
|
|
542
|
+
normA += a[i] * a[i];
|
|
543
|
+
normB += b[i] * b[i];
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
const denom = Math.sqrt(normA) * Math.sqrt(normB);
|
|
547
|
+
return denom > 0 ? dot / denom : 0;
|
|
548
|
+
}
|
|
549
|
+
|
|
550
|
+
private mmrSelect(
|
|
551
|
+
query: Float32Array,
|
|
552
|
+
candidates: Array<{ pattern: ReasoningBankPattern; similarity: number }>,
|
|
553
|
+
k: number,
|
|
554
|
+
lambda: number
|
|
555
|
+
): ReasoningBankPattern[] {
|
|
556
|
+
const selected: ReasoningBankPattern[] = [];
|
|
557
|
+
const remaining = [...candidates];
|
|
558
|
+
|
|
559
|
+
while (selected.length < k && remaining.length > 0) {
|
|
560
|
+
let bestScore = -Infinity;
|
|
561
|
+
let bestIdx = 0;
|
|
562
|
+
|
|
563
|
+
for (let i = 0; i < remaining.length; i++) {
|
|
564
|
+
const candidate = remaining[i];
|
|
565
|
+
const relevance = candidate.similarity;
|
|
566
|
+
|
|
567
|
+
// Calculate max similarity to already selected patterns
|
|
568
|
+
let maxSimilarity = 0;
|
|
569
|
+
for (const sel of selected) {
|
|
570
|
+
const sim = this.cosineSimilarity(candidate.pattern.embedding, sel.embedding);
|
|
571
|
+
maxSimilarity = Math.max(maxSimilarity, sim);
|
|
572
|
+
}
|
|
573
|
+
|
|
574
|
+
// MMR score: lambda * relevance - (1 - lambda) * redundancy
|
|
575
|
+
const score = lambda * relevance - (1 - lambda) * maxSimilarity;
|
|
576
|
+
|
|
577
|
+
if (score > bestScore) {
|
|
578
|
+
bestScore = score;
|
|
579
|
+
bestIdx = i;
|
|
580
|
+
}
|
|
581
|
+
}
|
|
582
|
+
|
|
583
|
+
selected.push(remaining[bestIdx].pattern);
|
|
584
|
+
remaining.splice(bestIdx, 1);
|
|
585
|
+
}
|
|
586
|
+
|
|
587
|
+
return selected;
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
private shouldConsolidate(): boolean {
|
|
591
|
+
return this.newPatternsSinceConsolidation >= this.config.consolidateTriggerThreshold;
|
|
592
|
+
}
|
|
593
|
+
|
|
594
|
+
private generateJudgmentReasoning(
|
|
595
|
+
trajectory: Trajectory,
|
|
596
|
+
label: string,
|
|
597
|
+
evidence: string[]
|
|
598
|
+
): string {
|
|
599
|
+
const parts: string[] = [];
|
|
600
|
+
|
|
601
|
+
parts.push(`Trajectory ${trajectory.trajectoryId} judged as ${label}.`);
|
|
602
|
+
parts.push(`Domain: ${trajectory.domain}, Steps: ${trajectory.steps.length}.`);
|
|
603
|
+
|
|
604
|
+
if (label === 'Success') {
|
|
605
|
+
parts.push('The trajectory achieved high quality scores with positive rewards.');
|
|
606
|
+
} else if (label === 'Failure') {
|
|
607
|
+
parts.push('The trajectory had low quality scores or negative rewards.');
|
|
608
|
+
} else {
|
|
609
|
+
parts.push('The trajectory showed mixed results with room for improvement.');
|
|
610
|
+
}
|
|
611
|
+
|
|
612
|
+
return parts.join(' ');
|
|
613
|
+
}
|
|
614
|
+
|
|
615
|
+
private extractPatternsFromTrajectory(
|
|
616
|
+
trajectory: Trajectory,
|
|
617
|
+
verdict: ReasoningBankVerdict
|
|
618
|
+
): Array<{ title: string; description: string; content: string; tags: string[] }> {
|
|
619
|
+
const patterns: Array<{ title: string; description: string; content: string; tags: string[] }> = [];
|
|
620
|
+
|
|
621
|
+
// Extract overall strategy pattern
|
|
622
|
+
const actions = trajectory.steps.map(s => s.action);
|
|
623
|
+
patterns.push({
|
|
624
|
+
title: `${verdict.label}: ${trajectory.context.slice(0, 50)}`,
|
|
625
|
+
description: `Strategy for ${trajectory.domain} task with ${verdict.label.toLowerCase()} outcome`,
|
|
626
|
+
content: `Actions: ${actions.slice(0, 5).join(' -> ')}${actions.length > 5 ? '...' : ''}`,
|
|
627
|
+
tags: [verdict.label.toLowerCase(), trajectory.domain, 'strategy'],
|
|
628
|
+
});
|
|
629
|
+
|
|
630
|
+
// Extract key step patterns for successful trajectories
|
|
631
|
+
if (verdict.label === 'Success' && trajectory.steps.length > 0) {
|
|
632
|
+
const highRewardSteps = trajectory.steps
|
|
633
|
+
.filter(s => s.reward > 0.7)
|
|
634
|
+
.slice(0, 3);
|
|
635
|
+
|
|
636
|
+
for (const step of highRewardSteps) {
|
|
637
|
+
patterns.push({
|
|
638
|
+
title: `High-reward action: ${step.action.slice(0, 30)}`,
|
|
639
|
+
description: `Effective action in ${trajectory.domain} context`,
|
|
640
|
+
content: `Action: ${step.action}, Reward: ${step.reward.toFixed(2)}`,
|
|
641
|
+
tags: ['high-reward', trajectory.domain, 'action'],
|
|
642
|
+
});
|
|
643
|
+
}
|
|
644
|
+
}
|
|
645
|
+
|
|
646
|
+
return patterns;
|
|
647
|
+
}
|
|
648
|
+
|
|
649
|
+
private computePatternEmbedding(trajectory: Trajectory, index: number): Float32Array {
|
|
650
|
+
if (trajectory.steps.length === 0) {
|
|
651
|
+
return new Float32Array(768);
|
|
652
|
+
}
|
|
653
|
+
|
|
654
|
+
// Use weighted average of step embeddings
|
|
655
|
+
const dim = trajectory.steps[0].stateAfter.length;
|
|
656
|
+
const embedding = new Float32Array(dim);
|
|
657
|
+
|
|
658
|
+
let totalWeight = 0;
|
|
659
|
+
for (let i = 0; i < trajectory.steps.length; i++) {
|
|
660
|
+
const weight = (i + 1 + index) / (trajectory.steps.length + index);
|
|
661
|
+
totalWeight += weight;
|
|
662
|
+
for (let j = 0; j < dim; j++) {
|
|
663
|
+
embedding[j] += trajectory.steps[i].stateAfter[j] * weight;
|
|
664
|
+
}
|
|
665
|
+
}
|
|
666
|
+
|
|
667
|
+
for (let j = 0; j < dim; j++) {
|
|
668
|
+
embedding[j] /= totalWeight;
|
|
669
|
+
}
|
|
670
|
+
|
|
671
|
+
return embedding;
|
|
672
|
+
}
|
|
673
|
+
}
|
|
674
|
+
|
|
675
|
+
// ============================================================================
|
|
676
|
+
// Factory Functions
|
|
677
|
+
// ============================================================================
|
|
678
|
+
|
|
679
|
+
/**
|
|
680
|
+
* Create ReasoningBank adapter
|
|
681
|
+
*/
|
|
682
|
+
export function createReasoningBankAdapter(
|
|
683
|
+
config?: ReasoningBankConfig
|
|
684
|
+
): ReasoningBankAdapter {
|
|
685
|
+
return new ReasoningBankAdapter(config);
|
|
686
|
+
}
|
|
687
|
+
|
|
688
|
+
/**
|
|
689
|
+
* Create default ReasoningBank adapter
|
|
690
|
+
*/
|
|
691
|
+
export function createDefaultReasoningBankAdapter(): ReasoningBankAdapter {
|
|
692
|
+
return new ReasoningBankAdapter({
|
|
693
|
+
enableLearning: true,
|
|
694
|
+
enableReasoning: true,
|
|
695
|
+
sonaMode: 'balanced',
|
|
696
|
+
});
|
|
697
|
+
}
|