@sparkleideas/integration 3.0.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 +270 -0
- package/package.json +55 -0
- package/src/__tests__/agent-adapter.test.ts +271 -0
- package/src/__tests__/agentic-flow-agent.test.ts +176 -0
- package/src/__tests__/token-optimizer.test.ts +176 -0
- package/src/agent-adapter.ts +651 -0
- package/src/agentic-flow-agent.ts +802 -0
- package/src/agentic-flow-bridge.ts +803 -0
- package/src/attention-coordinator.ts +679 -0
- package/src/feature-flags.ts +485 -0
- package/src/index.ts +466 -0
- package/src/long-running-worker.ts +871 -0
- package/src/multi-model-router.ts +1079 -0
- package/src/provider-adapter.ts +1168 -0
- package/src/sdk-bridge.ts +435 -0
- package/src/sona-adapter.ts +824 -0
- package/src/specialized-worker.ts +864 -0
- package/src/swarm-adapter.ts +1112 -0
- package/src/token-optimizer.ts +306 -0
- package/src/types.ts +494 -0
- package/src/worker-base.ts +822 -0
- package/src/worker-pool.ts +933 -0
- package/tmp.json +0 -0
- package/tsconfig.json +9 -0
|
@@ -0,0 +1,824 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SONA (Self-Optimizing Neural Architecture) Adapter
|
|
3
|
+
*
|
|
4
|
+
* Provides integration with @sparkleideas/agentic-flow's SONA learning system,
|
|
5
|
+
* enabling real-time adaptation, pattern recognition, and
|
|
6
|
+
* continuous learning capabilities.
|
|
7
|
+
*
|
|
8
|
+
* Performance Targets:
|
|
9
|
+
* - Real-time mode: ~0.05ms adaptation
|
|
10
|
+
* - Balanced mode: General purpose learning
|
|
11
|
+
* - Research mode: Deep exploration with higher accuracy
|
|
12
|
+
*
|
|
13
|
+
* @module v3/integration/sona-adapter
|
|
14
|
+
* @version 3.0.0-alpha.1
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
import { EventEmitter } from 'events';
|
|
18
|
+
import type {
|
|
19
|
+
SONAConfiguration,
|
|
20
|
+
SONALearningMode,
|
|
21
|
+
SONATrajectory,
|
|
22
|
+
SONATrajectoryStep,
|
|
23
|
+
SONAPattern,
|
|
24
|
+
SONALearningStats,
|
|
25
|
+
DEFAULT_SONA_CONFIG,
|
|
26
|
+
} from './types.js';
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Interface for @sparkleideas/agentic-flow SONA reference (for delegation)
|
|
30
|
+
* This allows the adapter to delegate to @sparkleideas/agentic-flow when available
|
|
31
|
+
*/
|
|
32
|
+
interface AgenticFlowSONAReference {
|
|
33
|
+
setMode(mode: string): Promise<void>;
|
|
34
|
+
storePattern(params: {
|
|
35
|
+
pattern: string;
|
|
36
|
+
solution: string;
|
|
37
|
+
category: string;
|
|
38
|
+
confidence: number;
|
|
39
|
+
metadata?: Record<string, unknown>;
|
|
40
|
+
}): Promise<string>;
|
|
41
|
+
findPatterns(query: string, options?: {
|
|
42
|
+
category?: string;
|
|
43
|
+
topK?: number;
|
|
44
|
+
threshold?: number;
|
|
45
|
+
}): Promise<Array<{
|
|
46
|
+
id: string;
|
|
47
|
+
pattern: string;
|
|
48
|
+
solution: string;
|
|
49
|
+
category: string;
|
|
50
|
+
confidence: number;
|
|
51
|
+
usageCount: number;
|
|
52
|
+
createdAt: number;
|
|
53
|
+
lastUsedAt: number;
|
|
54
|
+
metadata: Record<string, unknown>;
|
|
55
|
+
}>>;
|
|
56
|
+
getStats(): Promise<unknown>;
|
|
57
|
+
beginTrajectory?(params: unknown): Promise<string>;
|
|
58
|
+
recordStep?(params: unknown): Promise<void>;
|
|
59
|
+
endTrajectory?(params: unknown): Promise<unknown>;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Mode-specific configurations for SONA learning
|
|
64
|
+
*/
|
|
65
|
+
const MODE_CONFIGS: Record<SONALearningMode, Partial<SONAConfiguration>> = {
|
|
66
|
+
'real-time': {
|
|
67
|
+
learningRate: 0.01,
|
|
68
|
+
similarityThreshold: 0.8,
|
|
69
|
+
maxPatterns: 5000,
|
|
70
|
+
consolidationInterval: 1800000, // 30 minutes
|
|
71
|
+
},
|
|
72
|
+
'balanced': {
|
|
73
|
+
learningRate: 0.001,
|
|
74
|
+
similarityThreshold: 0.7,
|
|
75
|
+
maxPatterns: 10000,
|
|
76
|
+
consolidationInterval: 3600000, // 1 hour
|
|
77
|
+
},
|
|
78
|
+
'research': {
|
|
79
|
+
learningRate: 0.0001,
|
|
80
|
+
similarityThreshold: 0.6,
|
|
81
|
+
maxPatterns: 50000,
|
|
82
|
+
consolidationInterval: 7200000, // 2 hours
|
|
83
|
+
},
|
|
84
|
+
'edge': {
|
|
85
|
+
learningRate: 0.005,
|
|
86
|
+
similarityThreshold: 0.85,
|
|
87
|
+
maxPatterns: 1000,
|
|
88
|
+
consolidationInterval: 900000, // 15 minutes
|
|
89
|
+
},
|
|
90
|
+
'batch': {
|
|
91
|
+
learningRate: 0.0005,
|
|
92
|
+
similarityThreshold: 0.65,
|
|
93
|
+
maxPatterns: 100000,
|
|
94
|
+
consolidationInterval: 14400000, // 4 hours
|
|
95
|
+
},
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* SONAAdapter - SONA Learning System Integration
|
|
100
|
+
*
|
|
101
|
+
* This adapter provides a clean interface to @sparkleideas/agentic-flow's SONA
|
|
102
|
+
* learning capabilities, including:
|
|
103
|
+
* - Learning mode selection and auto-switching
|
|
104
|
+
* - Trajectory tracking for experience replay
|
|
105
|
+
* - Pattern storage and retrieval
|
|
106
|
+
* - Memory distillation and consolidation
|
|
107
|
+
*/
|
|
108
|
+
export class SONAAdapter extends EventEmitter {
|
|
109
|
+
private config: SONAConfiguration;
|
|
110
|
+
private initialized: boolean = false;
|
|
111
|
+
private activeTrajectories: Map<string, SONATrajectory> = new Map();
|
|
112
|
+
private patterns: Map<string, SONAPattern> = new Map();
|
|
113
|
+
private stats: SONALearningStats;
|
|
114
|
+
private consolidationTimer: NodeJS.Timeout | null = null;
|
|
115
|
+
private learningCycleCount: number = 0;
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Reference to @sparkleideas/agentic-flow SONA for delegation (ADR-001)
|
|
119
|
+
* When set, methods delegate to @sparkleideas/agentic-flow instead of local implementation
|
|
120
|
+
*/
|
|
121
|
+
private agenticFlowSona: AgenticFlowSONAReference | null = null;
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Indicates if delegation to @sparkleideas/agentic-flow is active
|
|
125
|
+
*/
|
|
126
|
+
private delegationEnabled: boolean = false;
|
|
127
|
+
|
|
128
|
+
constructor(config: Partial<SONAConfiguration> = {}) {
|
|
129
|
+
super();
|
|
130
|
+
this.config = this.mergeConfig(config);
|
|
131
|
+
this.stats = this.initializeStats();
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Set reference to @sparkleideas/agentic-flow SONA for delegation
|
|
136
|
+
*
|
|
137
|
+
* This implements ADR-001: Adopt @sparkleideas/agentic-flow as Core Foundation
|
|
138
|
+
* When a reference is provided, pattern storage and retrieval
|
|
139
|
+
* delegate to @sparkleideas/agentic-flow's optimized implementations.
|
|
140
|
+
*
|
|
141
|
+
* @param sonaRef - The @sparkleideas/agentic-flow SONA interface reference
|
|
142
|
+
*/
|
|
143
|
+
setAgenticFlowReference(sonaRef: AgenticFlowSONAReference): void {
|
|
144
|
+
this.agenticFlowSona = sonaRef;
|
|
145
|
+
this.delegationEnabled = true;
|
|
146
|
+
this.emit('delegation-enabled', { target: '@sparkleideas/agentic-flow' });
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* Check if delegation to @sparkleideas/agentic-flow is enabled
|
|
151
|
+
*/
|
|
152
|
+
isDelegationEnabled(): boolean {
|
|
153
|
+
return this.delegationEnabled && this.agenticFlowSona !== null;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* Initialize the SONA adapter
|
|
158
|
+
*/
|
|
159
|
+
async initialize(): Promise<void> {
|
|
160
|
+
if (this.initialized) {
|
|
161
|
+
return;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
this.emit('initializing');
|
|
165
|
+
|
|
166
|
+
try {
|
|
167
|
+
// Apply mode-specific configuration
|
|
168
|
+
this.applyModeConfig(this.config.mode);
|
|
169
|
+
|
|
170
|
+
// Start consolidation timer if enabled
|
|
171
|
+
if (this.config.consolidationInterval > 0) {
|
|
172
|
+
this.startConsolidationTimer();
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
this.initialized = true;
|
|
176
|
+
this.emit('initialized', { mode: this.config.mode });
|
|
177
|
+
} catch (error) {
|
|
178
|
+
this.emit('initialization-failed', { error });
|
|
179
|
+
throw error;
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* Reconfigure the adapter
|
|
185
|
+
*/
|
|
186
|
+
async reconfigure(config: Partial<SONAConfiguration>): Promise<void> {
|
|
187
|
+
this.config = this.mergeConfig(config);
|
|
188
|
+
|
|
189
|
+
if (config.mode) {
|
|
190
|
+
this.applyModeConfig(config.mode);
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
// Restart consolidation timer with new interval
|
|
194
|
+
if (config.consolidationInterval !== undefined) {
|
|
195
|
+
this.stopConsolidationTimer();
|
|
196
|
+
if (config.consolidationInterval > 0) {
|
|
197
|
+
this.startConsolidationTimer();
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
this.emit('reconfigured', { config: this.config });
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
/**
|
|
205
|
+
* Get current learning mode
|
|
206
|
+
*/
|
|
207
|
+
getMode(): SONALearningMode {
|
|
208
|
+
return this.config.mode;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
/**
|
|
212
|
+
* Set learning mode
|
|
213
|
+
*/
|
|
214
|
+
async setMode(mode: SONALearningMode): Promise<void> {
|
|
215
|
+
const previousMode = this.config.mode;
|
|
216
|
+
this.config.mode = mode;
|
|
217
|
+
this.applyModeConfig(mode);
|
|
218
|
+
|
|
219
|
+
this.emit('mode-changed', {
|
|
220
|
+
previousMode,
|
|
221
|
+
newMode: mode,
|
|
222
|
+
config: MODE_CONFIGS[mode]
|
|
223
|
+
});
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
/**
|
|
227
|
+
* Begin a new trajectory for task tracking
|
|
228
|
+
*/
|
|
229
|
+
async beginTrajectory(params: {
|
|
230
|
+
taskId: string;
|
|
231
|
+
description?: string;
|
|
232
|
+
category?: string;
|
|
233
|
+
metadata?: Record<string, unknown>;
|
|
234
|
+
}): Promise<string> {
|
|
235
|
+
this.ensureInitialized();
|
|
236
|
+
|
|
237
|
+
const trajectoryId = this.generateId('traj');
|
|
238
|
+
const trajectory: SONATrajectory = {
|
|
239
|
+
id: trajectoryId,
|
|
240
|
+
taskId: params.taskId,
|
|
241
|
+
steps: [],
|
|
242
|
+
startTime: Date.now(),
|
|
243
|
+
totalReward: 0,
|
|
244
|
+
metadata: {
|
|
245
|
+
description: params.description,
|
|
246
|
+
category: params.category,
|
|
247
|
+
...params.metadata,
|
|
248
|
+
},
|
|
249
|
+
};
|
|
250
|
+
|
|
251
|
+
this.activeTrajectories.set(trajectoryId, trajectory);
|
|
252
|
+
this.stats.activeTrajectories++;
|
|
253
|
+
|
|
254
|
+
this.emit('trajectory-started', { trajectoryId, taskId: params.taskId });
|
|
255
|
+
return trajectoryId;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
/**
|
|
259
|
+
* Record a step in an active trajectory
|
|
260
|
+
*/
|
|
261
|
+
async recordTrajectoryStep(params: {
|
|
262
|
+
trajectoryId: string;
|
|
263
|
+
stepId?: string;
|
|
264
|
+
action: string;
|
|
265
|
+
observation: string;
|
|
266
|
+
reward: number;
|
|
267
|
+
embedding?: number[];
|
|
268
|
+
}): Promise<void> {
|
|
269
|
+
this.ensureInitialized();
|
|
270
|
+
|
|
271
|
+
const trajectory = this.activeTrajectories.get(params.trajectoryId);
|
|
272
|
+
if (!trajectory) {
|
|
273
|
+
throw new Error(`Trajectory ${params.trajectoryId} not found`);
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
const step: SONATrajectoryStep = {
|
|
277
|
+
stepId: params.stepId || this.generateId('step'),
|
|
278
|
+
action: params.action,
|
|
279
|
+
observation: params.observation,
|
|
280
|
+
reward: params.reward,
|
|
281
|
+
timestamp: Date.now(),
|
|
282
|
+
embedding: params.embedding,
|
|
283
|
+
};
|
|
284
|
+
|
|
285
|
+
trajectory.steps.push(step);
|
|
286
|
+
trajectory.totalReward += params.reward;
|
|
287
|
+
|
|
288
|
+
this.emit('trajectory-step-recorded', {
|
|
289
|
+
trajectoryId: params.trajectoryId,
|
|
290
|
+
step
|
|
291
|
+
});
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
/**
|
|
295
|
+
* End a trajectory with final verdict
|
|
296
|
+
*/
|
|
297
|
+
async endTrajectory(params: {
|
|
298
|
+
trajectoryId: string;
|
|
299
|
+
success: boolean;
|
|
300
|
+
verdict?: 'positive' | 'negative' | 'neutral';
|
|
301
|
+
reward?: number;
|
|
302
|
+
}): Promise<SONATrajectory> {
|
|
303
|
+
this.ensureInitialized();
|
|
304
|
+
|
|
305
|
+
const trajectory = this.activeTrajectories.get(params.trajectoryId);
|
|
306
|
+
if (!trajectory) {
|
|
307
|
+
throw new Error(`Trajectory ${params.trajectoryId} not found`);
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
// Finalize trajectory
|
|
311
|
+
trajectory.endTime = Date.now();
|
|
312
|
+
trajectory.verdict = params.verdict || (params.success ? 'positive' : 'negative');
|
|
313
|
+
|
|
314
|
+
if (params.reward !== undefined) {
|
|
315
|
+
trajectory.totalReward += params.reward;
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
// Remove from active and update stats
|
|
319
|
+
this.activeTrajectories.delete(params.trajectoryId);
|
|
320
|
+
this.stats.activeTrajectories--;
|
|
321
|
+
this.stats.completedTrajectories++;
|
|
322
|
+
|
|
323
|
+
// Learn from successful trajectories
|
|
324
|
+
if (params.success && trajectory.verdict === 'positive') {
|
|
325
|
+
await this.learnFromTrajectory(trajectory);
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
this.emit('trajectory-completed', {
|
|
329
|
+
trajectoryId: params.trajectoryId,
|
|
330
|
+
trajectory
|
|
331
|
+
});
|
|
332
|
+
|
|
333
|
+
return trajectory;
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
/**
|
|
337
|
+
* Store a learned pattern
|
|
338
|
+
*
|
|
339
|
+
* ADR-001: When @sparkleideas/agentic-flow is available, delegates to its optimized
|
|
340
|
+
* pattern storage which uses AgentDB with HNSW indexing for
|
|
341
|
+
* 150x-12,500x faster similarity search.
|
|
342
|
+
*/
|
|
343
|
+
async storePattern(params: {
|
|
344
|
+
pattern: string;
|
|
345
|
+
solution: string;
|
|
346
|
+
category: string;
|
|
347
|
+
confidence: number;
|
|
348
|
+
metadata?: Record<string, unknown>;
|
|
349
|
+
}): Promise<string> {
|
|
350
|
+
this.ensureInitialized();
|
|
351
|
+
|
|
352
|
+
// ADR-001: Delegate to @sparkleideas/agentic-flow when available
|
|
353
|
+
if (this.isDelegationEnabled() && this.agenticFlowSona) {
|
|
354
|
+
try {
|
|
355
|
+
const patternId = await this.agenticFlowSona.storePattern({
|
|
356
|
+
pattern: params.pattern,
|
|
357
|
+
solution: params.solution,
|
|
358
|
+
category: params.category,
|
|
359
|
+
confidence: Math.max(0, Math.min(1, params.confidence)),
|
|
360
|
+
metadata: params.metadata,
|
|
361
|
+
});
|
|
362
|
+
|
|
363
|
+
this.stats.totalPatterns++;
|
|
364
|
+
this.emit('pattern-stored', {
|
|
365
|
+
patternId,
|
|
366
|
+
delegated: true,
|
|
367
|
+
target: '@sparkleideas/agentic-flow',
|
|
368
|
+
});
|
|
369
|
+
|
|
370
|
+
return patternId;
|
|
371
|
+
} catch (error) {
|
|
372
|
+
// Log delegation failure and fall back to local implementation
|
|
373
|
+
this.emit('delegation-failed', {
|
|
374
|
+
method: 'storePattern',
|
|
375
|
+
error: (error as Error).message,
|
|
376
|
+
fallback: 'local',
|
|
377
|
+
});
|
|
378
|
+
// Continue with local implementation below
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
// Local implementation (fallback or when @sparkleideas/agentic-flow not available)
|
|
383
|
+
const patternId = this.generateId('pat');
|
|
384
|
+
const storedPattern: SONAPattern = {
|
|
385
|
+
id: patternId,
|
|
386
|
+
pattern: params.pattern,
|
|
387
|
+
solution: params.solution,
|
|
388
|
+
category: params.category,
|
|
389
|
+
confidence: Math.max(0, Math.min(1, params.confidence)),
|
|
390
|
+
usageCount: 0,
|
|
391
|
+
createdAt: Date.now(),
|
|
392
|
+
lastUsedAt: Date.now(),
|
|
393
|
+
metadata: params.metadata || {},
|
|
394
|
+
};
|
|
395
|
+
|
|
396
|
+
// Check if we need to prune patterns
|
|
397
|
+
if (this.patterns.size >= this.config.maxPatterns) {
|
|
398
|
+
await this.prunePatterns();
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
this.patterns.set(patternId, storedPattern);
|
|
402
|
+
this.stats.totalPatterns++;
|
|
403
|
+
this.updateAverageConfidence();
|
|
404
|
+
|
|
405
|
+
this.emit('pattern-stored', { patternId, pattern: storedPattern });
|
|
406
|
+
return patternId;
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
/**
|
|
410
|
+
* Find similar patterns to a query
|
|
411
|
+
*
|
|
412
|
+
* ADR-001: When @sparkleideas/agentic-flow is available, delegates to its optimized
|
|
413
|
+
* HNSW-indexed search for 150x-12,500x faster retrieval.
|
|
414
|
+
*/
|
|
415
|
+
async findSimilarPatterns(params: {
|
|
416
|
+
query: string;
|
|
417
|
+
category?: string;
|
|
418
|
+
topK?: number;
|
|
419
|
+
threshold?: number;
|
|
420
|
+
}): Promise<SONAPattern[]> {
|
|
421
|
+
this.ensureInitialized();
|
|
422
|
+
|
|
423
|
+
const topK = params.topK || 5;
|
|
424
|
+
const threshold = params.threshold ?? this.config.similarityThreshold;
|
|
425
|
+
|
|
426
|
+
// ADR-001: Delegate to @sparkleideas/agentic-flow when available for optimized search
|
|
427
|
+
if (this.isDelegationEnabled() && this.agenticFlowSona) {
|
|
428
|
+
try {
|
|
429
|
+
const results = await this.agenticFlowSona.findPatterns(params.query, {
|
|
430
|
+
category: params.category,
|
|
431
|
+
topK,
|
|
432
|
+
threshold,
|
|
433
|
+
});
|
|
434
|
+
|
|
435
|
+
// Map results to SONAPattern format
|
|
436
|
+
const patterns: SONAPattern[] = results.map(r => ({
|
|
437
|
+
id: r.id,
|
|
438
|
+
pattern: r.pattern,
|
|
439
|
+
solution: r.solution,
|
|
440
|
+
category: r.category,
|
|
441
|
+
confidence: r.confidence,
|
|
442
|
+
usageCount: r.usageCount,
|
|
443
|
+
createdAt: r.createdAt,
|
|
444
|
+
lastUsedAt: r.lastUsedAt,
|
|
445
|
+
metadata: r.metadata,
|
|
446
|
+
}));
|
|
447
|
+
|
|
448
|
+
this.emit('patterns-retrieved', {
|
|
449
|
+
query: params.query,
|
|
450
|
+
count: patterns.length,
|
|
451
|
+
delegated: true,
|
|
452
|
+
target: '@sparkleideas/agentic-flow',
|
|
453
|
+
});
|
|
454
|
+
|
|
455
|
+
return patterns;
|
|
456
|
+
} catch (error) {
|
|
457
|
+
// Log delegation failure and fall back to local implementation
|
|
458
|
+
this.emit('delegation-failed', {
|
|
459
|
+
method: 'findSimilarPatterns',
|
|
460
|
+
error: (error as Error).message,
|
|
461
|
+
fallback: 'local',
|
|
462
|
+
});
|
|
463
|
+
// Continue with local implementation below
|
|
464
|
+
}
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
// Local implementation (fallback or when @sparkleideas/agentic-flow not available)
|
|
468
|
+
const results: Array<{ pattern: SONAPattern; score: number }> = [];
|
|
469
|
+
|
|
470
|
+
for (const pattern of this.patterns.values()) {
|
|
471
|
+
// Filter by category if specified
|
|
472
|
+
if (params.category && pattern.category !== params.category) {
|
|
473
|
+
continue;
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
// Calculate text similarity (for vector embeddings, use HNSW index)
|
|
477
|
+
const score = this.calculateSimilarity(params.query, pattern.pattern);
|
|
478
|
+
|
|
479
|
+
if (score >= threshold) {
|
|
480
|
+
results.push({ pattern, score });
|
|
481
|
+
}
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
// Sort by score and return top K
|
|
485
|
+
results.sort((a, b) => b.score - a.score);
|
|
486
|
+
const topResults = results.slice(0, topK).map(r => {
|
|
487
|
+
// Update usage stats
|
|
488
|
+
r.pattern.usageCount++;
|
|
489
|
+
r.pattern.lastUsedAt = Date.now();
|
|
490
|
+
return r.pattern;
|
|
491
|
+
});
|
|
492
|
+
|
|
493
|
+
this.emit('patterns-retrieved', {
|
|
494
|
+
query: params.query,
|
|
495
|
+
count: topResults.length
|
|
496
|
+
});
|
|
497
|
+
|
|
498
|
+
return topResults;
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
/**
|
|
502
|
+
* Get a pattern by ID
|
|
503
|
+
*/
|
|
504
|
+
async getPattern(patternId: string): Promise<SONAPattern | null> {
|
|
505
|
+
this.ensureInitialized();
|
|
506
|
+
return this.patterns.get(patternId) || null;
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
/**
|
|
510
|
+
* Delete a pattern
|
|
511
|
+
*/
|
|
512
|
+
async deletePattern(patternId: string): Promise<boolean> {
|
|
513
|
+
this.ensureInitialized();
|
|
514
|
+
|
|
515
|
+
const deleted = this.patterns.delete(patternId);
|
|
516
|
+
if (deleted) {
|
|
517
|
+
this.stats.totalPatterns--;
|
|
518
|
+
this.updateAverageConfidence();
|
|
519
|
+
this.emit('pattern-deleted', { patternId });
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
return deleted;
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
/**
|
|
526
|
+
* Force a learning cycle
|
|
527
|
+
*/
|
|
528
|
+
async forceLearningCycle(): Promise<void> {
|
|
529
|
+
this.ensureInitialized();
|
|
530
|
+
|
|
531
|
+
this.emit('learning-cycle-starting');
|
|
532
|
+
|
|
533
|
+
try {
|
|
534
|
+
// Consolidate patterns
|
|
535
|
+
await this.consolidatePatterns();
|
|
536
|
+
|
|
537
|
+
// Prune low-confidence patterns
|
|
538
|
+
await this.prunePatterns();
|
|
539
|
+
|
|
540
|
+
// Update statistics
|
|
541
|
+
this.learningCycleCount++;
|
|
542
|
+
this.stats.learningCycles = this.learningCycleCount;
|
|
543
|
+
|
|
544
|
+
this.emit('learning-cycle-completed', {
|
|
545
|
+
cycleCount: this.learningCycleCount
|
|
546
|
+
});
|
|
547
|
+
} catch (error) {
|
|
548
|
+
this.emit('learning-cycle-failed', { error });
|
|
549
|
+
throw error;
|
|
550
|
+
}
|
|
551
|
+
}
|
|
552
|
+
|
|
553
|
+
/**
|
|
554
|
+
* Get learning statistics
|
|
555
|
+
*/
|
|
556
|
+
async getStats(): Promise<SONALearningStats> {
|
|
557
|
+
this.ensureInitialized();
|
|
558
|
+
|
|
559
|
+
return {
|
|
560
|
+
...this.stats,
|
|
561
|
+
totalPatterns: this.patterns.size,
|
|
562
|
+
activeTrajectories: this.activeTrajectories.size,
|
|
563
|
+
currentMode: this.config.mode,
|
|
564
|
+
memoryUsage: this.estimateMemoryUsage(),
|
|
565
|
+
};
|
|
566
|
+
}
|
|
567
|
+
|
|
568
|
+
/**
|
|
569
|
+
* Export patterns for persistence
|
|
570
|
+
*/
|
|
571
|
+
async exportPatterns(): Promise<SONAPattern[]> {
|
|
572
|
+
this.ensureInitialized();
|
|
573
|
+
return Array.from(this.patterns.values());
|
|
574
|
+
}
|
|
575
|
+
|
|
576
|
+
/**
|
|
577
|
+
* Import patterns from storage
|
|
578
|
+
*/
|
|
579
|
+
async importPatterns(patterns: SONAPattern[]): Promise<number> {
|
|
580
|
+
this.ensureInitialized();
|
|
581
|
+
|
|
582
|
+
let imported = 0;
|
|
583
|
+
for (const pattern of patterns) {
|
|
584
|
+
if (!this.patterns.has(pattern.id)) {
|
|
585
|
+
this.patterns.set(pattern.id, pattern);
|
|
586
|
+
imported++;
|
|
587
|
+
}
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
this.stats.totalPatterns = this.patterns.size;
|
|
591
|
+
this.updateAverageConfidence();
|
|
592
|
+
|
|
593
|
+
this.emit('patterns-imported', { count: imported });
|
|
594
|
+
return imported;
|
|
595
|
+
}
|
|
596
|
+
|
|
597
|
+
/**
|
|
598
|
+
* Shutdown the adapter
|
|
599
|
+
*/
|
|
600
|
+
async shutdown(): Promise<void> {
|
|
601
|
+
this.stopConsolidationTimer();
|
|
602
|
+
|
|
603
|
+
// Complete any active trajectories
|
|
604
|
+
for (const [id, trajectory] of this.activeTrajectories) {
|
|
605
|
+
trajectory.endTime = Date.now();
|
|
606
|
+
trajectory.verdict = 'neutral';
|
|
607
|
+
}
|
|
608
|
+
this.activeTrajectories.clear();
|
|
609
|
+
|
|
610
|
+
this.initialized = false;
|
|
611
|
+
this.emit('shutdown');
|
|
612
|
+
}
|
|
613
|
+
|
|
614
|
+
// ===== Private Methods =====
|
|
615
|
+
|
|
616
|
+
private mergeConfig(config: Partial<SONAConfiguration>): SONAConfiguration {
|
|
617
|
+
return {
|
|
618
|
+
mode: config.mode || 'balanced',
|
|
619
|
+
learningRate: config.learningRate ?? 0.001,
|
|
620
|
+
similarityThreshold: config.similarityThreshold ?? 0.7,
|
|
621
|
+
maxPatterns: config.maxPatterns ?? 10000,
|
|
622
|
+
enableTrajectoryTracking: config.enableTrajectoryTracking ?? true,
|
|
623
|
+
consolidationInterval: config.consolidationInterval ?? 3600000,
|
|
624
|
+
autoModeSelection: config.autoModeSelection ?? true,
|
|
625
|
+
};
|
|
626
|
+
}
|
|
627
|
+
|
|
628
|
+
private initializeStats(): SONALearningStats {
|
|
629
|
+
return {
|
|
630
|
+
totalPatterns: 0,
|
|
631
|
+
activeTrajectories: 0,
|
|
632
|
+
completedTrajectories: 0,
|
|
633
|
+
averageConfidence: 0,
|
|
634
|
+
learningCycles: 0,
|
|
635
|
+
lastConsolidation: Date.now(),
|
|
636
|
+
memoryUsage: 0,
|
|
637
|
+
currentMode: this.config.mode,
|
|
638
|
+
};
|
|
639
|
+
}
|
|
640
|
+
|
|
641
|
+
private applyModeConfig(mode: SONALearningMode): void {
|
|
642
|
+
const modeConfig = MODE_CONFIGS[mode];
|
|
643
|
+
if (modeConfig) {
|
|
644
|
+
Object.assign(this.config, modeConfig);
|
|
645
|
+
}
|
|
646
|
+
}
|
|
647
|
+
|
|
648
|
+
private startConsolidationTimer(): void {
|
|
649
|
+
this.consolidationTimer = setInterval(
|
|
650
|
+
() => this.consolidatePatterns(),
|
|
651
|
+
this.config.consolidationInterval
|
|
652
|
+
);
|
|
653
|
+
}
|
|
654
|
+
|
|
655
|
+
private stopConsolidationTimer(): void {
|
|
656
|
+
if (this.consolidationTimer) {
|
|
657
|
+
clearInterval(this.consolidationTimer);
|
|
658
|
+
this.consolidationTimer = null;
|
|
659
|
+
}
|
|
660
|
+
}
|
|
661
|
+
|
|
662
|
+
private async consolidatePatterns(): Promise<void> {
|
|
663
|
+
// Merge similar patterns
|
|
664
|
+
const patternsArray = Array.from(this.patterns.values());
|
|
665
|
+
const toRemove: Set<string> = new Set();
|
|
666
|
+
|
|
667
|
+
for (let i = 0; i < patternsArray.length; i++) {
|
|
668
|
+
if (toRemove.has(patternsArray[i].id)) continue;
|
|
669
|
+
|
|
670
|
+
for (let j = i + 1; j < patternsArray.length; j++) {
|
|
671
|
+
if (toRemove.has(patternsArray[j].id)) continue;
|
|
672
|
+
|
|
673
|
+
const similarity = this.calculateSimilarity(
|
|
674
|
+
patternsArray[i].pattern,
|
|
675
|
+
patternsArray[j].pattern
|
|
676
|
+
);
|
|
677
|
+
|
|
678
|
+
if (similarity > 0.95) {
|
|
679
|
+
// Merge into pattern with higher confidence
|
|
680
|
+
if (patternsArray[i].confidence >= patternsArray[j].confidence) {
|
|
681
|
+
patternsArray[i].usageCount += patternsArray[j].usageCount;
|
|
682
|
+
toRemove.add(patternsArray[j].id);
|
|
683
|
+
} else {
|
|
684
|
+
patternsArray[j].usageCount += patternsArray[i].usageCount;
|
|
685
|
+
toRemove.add(patternsArray[i].id);
|
|
686
|
+
}
|
|
687
|
+
}
|
|
688
|
+
}
|
|
689
|
+
}
|
|
690
|
+
|
|
691
|
+
// Remove merged patterns
|
|
692
|
+
for (const id of toRemove) {
|
|
693
|
+
this.patterns.delete(id);
|
|
694
|
+
}
|
|
695
|
+
|
|
696
|
+
this.stats.lastConsolidation = Date.now();
|
|
697
|
+
this.emit('consolidation-completed', {
|
|
698
|
+
removed: toRemove.size,
|
|
699
|
+
remaining: this.patterns.size
|
|
700
|
+
});
|
|
701
|
+
}
|
|
702
|
+
|
|
703
|
+
private async prunePatterns(): Promise<void> {
|
|
704
|
+
const maxPatterns = this.config.maxPatterns;
|
|
705
|
+
if (this.patterns.size <= maxPatterns) {
|
|
706
|
+
return;
|
|
707
|
+
}
|
|
708
|
+
|
|
709
|
+
// Sort patterns by score (combination of confidence, recency, and usage)
|
|
710
|
+
const scored = Array.from(this.patterns.entries()).map(([id, pattern]) => ({
|
|
711
|
+
id,
|
|
712
|
+
pattern,
|
|
713
|
+
score: this.calculatePatternScore(pattern),
|
|
714
|
+
}));
|
|
715
|
+
|
|
716
|
+
scored.sort((a, b) => b.score - a.score);
|
|
717
|
+
|
|
718
|
+
// Keep only top patterns
|
|
719
|
+
const toKeep = new Set(scored.slice(0, maxPatterns).map(s => s.id));
|
|
720
|
+
|
|
721
|
+
for (const id of this.patterns.keys()) {
|
|
722
|
+
if (!toKeep.has(id)) {
|
|
723
|
+
this.patterns.delete(id);
|
|
724
|
+
}
|
|
725
|
+
}
|
|
726
|
+
|
|
727
|
+
this.emit('patterns-pruned', {
|
|
728
|
+
removed: scored.length - maxPatterns,
|
|
729
|
+
remaining: this.patterns.size
|
|
730
|
+
});
|
|
731
|
+
}
|
|
732
|
+
|
|
733
|
+
private async learnFromTrajectory(trajectory: SONATrajectory): Promise<void> {
|
|
734
|
+
// Extract patterns from successful trajectory
|
|
735
|
+
if (trajectory.steps.length === 0) return;
|
|
736
|
+
|
|
737
|
+
const pattern = trajectory.steps.map(s => s.action).join(' -> ');
|
|
738
|
+
const solution = trajectory.steps[trajectory.steps.length - 1].observation;
|
|
739
|
+
|
|
740
|
+
await this.storePattern({
|
|
741
|
+
pattern,
|
|
742
|
+
solution,
|
|
743
|
+
category: (trajectory.metadata.category as string) || 'general',
|
|
744
|
+
confidence: Math.min(1, trajectory.totalReward / trajectory.steps.length),
|
|
745
|
+
metadata: {
|
|
746
|
+
trajectoryId: trajectory.id,
|
|
747
|
+
taskId: trajectory.taskId,
|
|
748
|
+
stepCount: trajectory.steps.length,
|
|
749
|
+
},
|
|
750
|
+
});
|
|
751
|
+
}
|
|
752
|
+
|
|
753
|
+
private calculateSimilarity(a: string, b: string): number {
|
|
754
|
+
// Jaccard similarity on words (simplified)
|
|
755
|
+
const wordsA = new Set(a.toLowerCase().split(/\s+/));
|
|
756
|
+
const wordsB = new Set(b.toLowerCase().split(/\s+/));
|
|
757
|
+
|
|
758
|
+
const intersection = new Set([...wordsA].filter(x => wordsB.has(x)));
|
|
759
|
+
const union = new Set([...wordsA, ...wordsB]);
|
|
760
|
+
|
|
761
|
+
return intersection.size / union.size;
|
|
762
|
+
}
|
|
763
|
+
|
|
764
|
+
private calculatePatternScore(pattern: SONAPattern): number {
|
|
765
|
+
const now = Date.now();
|
|
766
|
+
const ageMs = now - pattern.createdAt;
|
|
767
|
+
const recencyMs = now - pattern.lastUsedAt;
|
|
768
|
+
|
|
769
|
+
// Normalize age and recency (decay over 30 days)
|
|
770
|
+
const ageFactor = Math.exp(-ageMs / (30 * 24 * 60 * 60 * 1000));
|
|
771
|
+
const recencyFactor = Math.exp(-recencyMs / (7 * 24 * 60 * 60 * 1000));
|
|
772
|
+
const usageFactor = Math.min(1, pattern.usageCount / 100);
|
|
773
|
+
|
|
774
|
+
return (
|
|
775
|
+
pattern.confidence * 0.4 +
|
|
776
|
+
recencyFactor * 0.3 +
|
|
777
|
+
usageFactor * 0.2 +
|
|
778
|
+
ageFactor * 0.1
|
|
779
|
+
);
|
|
780
|
+
}
|
|
781
|
+
|
|
782
|
+
private updateAverageConfidence(): void {
|
|
783
|
+
if (this.patterns.size === 0) {
|
|
784
|
+
this.stats.averageConfidence = 0;
|
|
785
|
+
return;
|
|
786
|
+
}
|
|
787
|
+
|
|
788
|
+
let total = 0;
|
|
789
|
+
for (const pattern of this.patterns.values()) {
|
|
790
|
+
total += pattern.confidence;
|
|
791
|
+
}
|
|
792
|
+
this.stats.averageConfidence = total / this.patterns.size;
|
|
793
|
+
}
|
|
794
|
+
|
|
795
|
+
private estimateMemoryUsage(): number {
|
|
796
|
+
// Rough estimate: 500 bytes per pattern, 1KB per trajectory step
|
|
797
|
+
const patternBytes = this.patterns.size * 500;
|
|
798
|
+
const trajectoryBytes = Array.from(this.activeTrajectories.values())
|
|
799
|
+
.reduce((sum, t) => sum + t.steps.length * 1024, 0);
|
|
800
|
+
|
|
801
|
+
return patternBytes + trajectoryBytes;
|
|
802
|
+
}
|
|
803
|
+
|
|
804
|
+
private generateId(prefix: string): string {
|
|
805
|
+
return `${prefix}_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
|
|
806
|
+
}
|
|
807
|
+
|
|
808
|
+
private ensureInitialized(): void {
|
|
809
|
+
if (!this.initialized) {
|
|
810
|
+
throw new Error('SONAAdapter not initialized. Call initialize() first.');
|
|
811
|
+
}
|
|
812
|
+
}
|
|
813
|
+
}
|
|
814
|
+
|
|
815
|
+
/**
|
|
816
|
+
* Create and initialize a SONA adapter
|
|
817
|
+
*/
|
|
818
|
+
export async function createSONAAdapter(
|
|
819
|
+
config?: Partial<SONAConfiguration>
|
|
820
|
+
): Promise<SONAAdapter> {
|
|
821
|
+
const adapter = new SONAAdapter(config);
|
|
822
|
+
await adapter.initialize();
|
|
823
|
+
return adapter;
|
|
824
|
+
}
|