@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.
Files changed (122) hide show
  1. package/README.md +260 -0
  2. package/__tests__/README.md +235 -0
  3. package/__tests__/algorithms.test.ts +582 -0
  4. package/__tests__/patterns.test.ts +549 -0
  5. package/__tests__/sona.test.ts +445 -0
  6. package/docs/SONA_INTEGRATION.md +460 -0
  7. package/docs/SONA_QUICKSTART.md +168 -0
  8. package/examples/sona-usage.ts +318 -0
  9. package/package.json +23 -0
  10. package/src/algorithms/a2c.d.ts +86 -0
  11. package/src/algorithms/a2c.d.ts.map +1 -0
  12. package/src/algorithms/a2c.js +361 -0
  13. package/src/algorithms/a2c.js.map +1 -0
  14. package/src/algorithms/a2c.ts +478 -0
  15. package/src/algorithms/curiosity.d.ts +82 -0
  16. package/src/algorithms/curiosity.d.ts.map +1 -0
  17. package/src/algorithms/curiosity.js +392 -0
  18. package/src/algorithms/curiosity.js.map +1 -0
  19. package/src/algorithms/curiosity.ts +509 -0
  20. package/src/algorithms/decision-transformer.d.ts +82 -0
  21. package/src/algorithms/decision-transformer.d.ts.map +1 -0
  22. package/src/algorithms/decision-transformer.js +415 -0
  23. package/src/algorithms/decision-transformer.js.map +1 -0
  24. package/src/algorithms/decision-transformer.ts +521 -0
  25. package/src/algorithms/dqn.d.ts +72 -0
  26. package/src/algorithms/dqn.d.ts.map +1 -0
  27. package/src/algorithms/dqn.js +303 -0
  28. package/src/algorithms/dqn.js.map +1 -0
  29. package/src/algorithms/dqn.ts +382 -0
  30. package/src/algorithms/index.d.ts +32 -0
  31. package/src/algorithms/index.d.ts.map +1 -0
  32. package/src/algorithms/index.js +74 -0
  33. package/src/algorithms/index.js.map +1 -0
  34. package/src/algorithms/index.ts +122 -0
  35. package/src/algorithms/ppo.d.ts +72 -0
  36. package/src/algorithms/ppo.d.ts.map +1 -0
  37. package/src/algorithms/ppo.js +331 -0
  38. package/src/algorithms/ppo.js.map +1 -0
  39. package/src/algorithms/ppo.ts +429 -0
  40. package/src/algorithms/q-learning.d.ts +77 -0
  41. package/src/algorithms/q-learning.d.ts.map +1 -0
  42. package/src/algorithms/q-learning.js +259 -0
  43. package/src/algorithms/q-learning.js.map +1 -0
  44. package/src/algorithms/q-learning.ts +333 -0
  45. package/src/algorithms/sarsa.d.ts +82 -0
  46. package/src/algorithms/sarsa.d.ts.map +1 -0
  47. package/src/algorithms/sarsa.js +297 -0
  48. package/src/algorithms/sarsa.js.map +1 -0
  49. package/src/algorithms/sarsa.ts +383 -0
  50. package/src/algorithms/tmp.json +0 -0
  51. package/src/application/index.ts +11 -0
  52. package/src/application/services/neural-application-service.ts +217 -0
  53. package/src/domain/entities/pattern.ts +169 -0
  54. package/src/domain/index.ts +18 -0
  55. package/src/domain/services/learning-service.ts +256 -0
  56. package/src/index.d.ts +118 -0
  57. package/src/index.d.ts.map +1 -0
  58. package/src/index.js +201 -0
  59. package/src/index.js.map +1 -0
  60. package/src/index.ts +363 -0
  61. package/src/modes/balanced.d.ts +60 -0
  62. package/src/modes/balanced.d.ts.map +1 -0
  63. package/src/modes/balanced.js +234 -0
  64. package/src/modes/balanced.js.map +1 -0
  65. package/src/modes/balanced.ts +299 -0
  66. package/src/modes/base.ts +163 -0
  67. package/src/modes/batch.d.ts +82 -0
  68. package/src/modes/batch.d.ts.map +1 -0
  69. package/src/modes/batch.js +316 -0
  70. package/src/modes/batch.js.map +1 -0
  71. package/src/modes/batch.ts +434 -0
  72. package/src/modes/edge.d.ts +85 -0
  73. package/src/modes/edge.d.ts.map +1 -0
  74. package/src/modes/edge.js +310 -0
  75. package/src/modes/edge.js.map +1 -0
  76. package/src/modes/edge.ts +409 -0
  77. package/src/modes/index.d.ts +55 -0
  78. package/src/modes/index.d.ts.map +1 -0
  79. package/src/modes/index.js +83 -0
  80. package/src/modes/index.js.map +1 -0
  81. package/src/modes/index.ts +16 -0
  82. package/src/modes/real-time.d.ts +58 -0
  83. package/src/modes/real-time.d.ts.map +1 -0
  84. package/src/modes/real-time.js +196 -0
  85. package/src/modes/real-time.js.map +1 -0
  86. package/src/modes/real-time.ts +257 -0
  87. package/src/modes/research.d.ts +79 -0
  88. package/src/modes/research.d.ts.map +1 -0
  89. package/src/modes/research.js +389 -0
  90. package/src/modes/research.js.map +1 -0
  91. package/src/modes/research.ts +486 -0
  92. package/src/modes/tmp.json +0 -0
  93. package/src/pattern-learner.d.ts +117 -0
  94. package/src/pattern-learner.d.ts.map +1 -0
  95. package/src/pattern-learner.js +603 -0
  96. package/src/pattern-learner.js.map +1 -0
  97. package/src/pattern-learner.ts +757 -0
  98. package/src/reasoning-bank.d.ts +259 -0
  99. package/src/reasoning-bank.d.ts.map +1 -0
  100. package/src/reasoning-bank.js +993 -0
  101. package/src/reasoning-bank.js.map +1 -0
  102. package/src/reasoning-bank.ts +1279 -0
  103. package/src/reasoningbank-adapter.ts +697 -0
  104. package/src/sona-integration.d.ts +168 -0
  105. package/src/sona-integration.d.ts.map +1 -0
  106. package/src/sona-integration.js +316 -0
  107. package/src/sona-integration.js.map +1 -0
  108. package/src/sona-integration.ts +432 -0
  109. package/src/sona-manager.d.ts +147 -0
  110. package/src/sona-manager.d.ts.map +1 -0
  111. package/src/sona-manager.js +695 -0
  112. package/src/sona-manager.js.map +1 -0
  113. package/src/sona-manager.ts +835 -0
  114. package/src/tmp.json +0 -0
  115. package/src/types.d.ts +431 -0
  116. package/src/types.d.ts.map +1 -0
  117. package/src/types.js +11 -0
  118. package/src/types.js.map +1 -0
  119. package/src/types.ts +590 -0
  120. package/tmp.json +0 -0
  121. package/tsconfig.json +9 -0
  122. 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
+ }