agentic-qe 2.5.7 → 2.5.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +133 -0
- package/README.md +1 -1
- package/dist/agents/BaseAgent.d.ts +231 -4
- package/dist/agents/BaseAgent.d.ts.map +1 -1
- package/dist/agents/BaseAgent.js +535 -5
- package/dist/agents/BaseAgent.js.map +1 -1
- package/dist/agents/CoverageAnalyzerAgent.d.ts +20 -23
- package/dist/agents/CoverageAnalyzerAgent.d.ts.map +1 -1
- package/dist/agents/CoverageAnalyzerAgent.js +95 -145
- package/dist/agents/CoverageAnalyzerAgent.js.map +1 -1
- package/dist/agents/QualityAnalyzerAgent.d.ts +2 -2
- package/dist/agents/QualityAnalyzerAgent.d.ts.map +1 -1
- package/dist/agents/QualityAnalyzerAgent.js.map +1 -1
- package/dist/agents/QualityGateAgent.d.ts +35 -18
- package/dist/agents/QualityGateAgent.d.ts.map +1 -1
- package/dist/agents/QualityGateAgent.js +72 -97
- package/dist/agents/QualityGateAgent.js.map +1 -1
- package/dist/agents/TestGeneratorAgent.d.ts +5 -0
- package/dist/agents/TestGeneratorAgent.d.ts.map +1 -1
- package/dist/agents/TestGeneratorAgent.js +38 -0
- package/dist/agents/TestGeneratorAgent.js.map +1 -1
- package/dist/agents/index.d.ts +1 -1
- package/dist/agents/index.d.ts.map +1 -1
- package/dist/agents/index.js +17 -4
- package/dist/agents/index.js.map +1 -1
- package/dist/core/memory/HNSWVectorMemory.js +1 -1
- package/dist/core/memory/RuVectorPatternStore.d.ts +90 -0
- package/dist/core/memory/RuVectorPatternStore.d.ts.map +1 -1
- package/dist/core/memory/RuVectorPatternStore.js +209 -0
- package/dist/core/memory/RuVectorPatternStore.js.map +1 -1
- package/dist/learning/FederatedManager.d.ts +232 -0
- package/dist/learning/FederatedManager.d.ts.map +1 -0
- package/dist/learning/FederatedManager.js +489 -0
- package/dist/learning/FederatedManager.js.map +1 -0
- package/dist/learning/HNSWPatternAdapter.d.ts +117 -0
- package/dist/learning/HNSWPatternAdapter.d.ts.map +1 -0
- package/dist/learning/HNSWPatternAdapter.js +262 -0
- package/dist/learning/HNSWPatternAdapter.js.map +1 -0
- package/dist/learning/LearningEngine.d.ts +27 -0
- package/dist/learning/LearningEngine.d.ts.map +1 -1
- package/dist/learning/LearningEngine.js +75 -1
- package/dist/learning/LearningEngine.js.map +1 -1
- package/dist/learning/PatternCurator.d.ts +217 -0
- package/dist/learning/PatternCurator.d.ts.map +1 -0
- package/dist/learning/PatternCurator.js +393 -0
- package/dist/learning/PatternCurator.js.map +1 -0
- package/dist/learning/index.d.ts +6 -0
- package/dist/learning/index.d.ts.map +1 -1
- package/dist/learning/index.js +16 -1
- package/dist/learning/index.js.map +1 -1
- package/dist/learning/types.d.ts +4 -0
- package/dist/learning/types.d.ts.map +1 -1
- package/dist/mcp/server-instructions.d.ts +1 -1
- package/dist/mcp/server-instructions.js +1 -1
- package/dist/mcp/tools.d.ts +6 -0
- package/dist/mcp/tools.d.ts.map +1 -1
- package/dist/mcp/tools.js +121 -0
- package/dist/mcp/tools.js.map +1 -1
- package/dist/memory/HNSWPatternStore.d.ts +176 -0
- package/dist/memory/HNSWPatternStore.d.ts.map +1 -0
- package/dist/memory/HNSWPatternStore.js +392 -0
- package/dist/memory/HNSWPatternStore.js.map +1 -0
- package/dist/memory/index.d.ts +8 -0
- package/dist/memory/index.d.ts.map +1 -0
- package/dist/memory/index.js +13 -0
- package/dist/memory/index.js.map +1 -0
- package/dist/providers/HybridRouter.d.ts +85 -4
- package/dist/providers/HybridRouter.d.ts.map +1 -1
- package/dist/providers/HybridRouter.js +332 -10
- package/dist/providers/HybridRouter.js.map +1 -1
- package/dist/providers/LLMBaselineTracker.d.ts +120 -0
- package/dist/providers/LLMBaselineTracker.d.ts.map +1 -0
- package/dist/providers/LLMBaselineTracker.js +305 -0
- package/dist/providers/LLMBaselineTracker.js.map +1 -0
- package/dist/providers/OpenRouterProvider.d.ts +26 -0
- package/dist/providers/OpenRouterProvider.d.ts.map +1 -1
- package/dist/providers/OpenRouterProvider.js +75 -6
- package/dist/providers/OpenRouterProvider.js.map +1 -1
- package/dist/providers/RuVectorClient.d.ts +259 -0
- package/dist/providers/RuVectorClient.d.ts.map +1 -0
- package/dist/providers/RuVectorClient.js +416 -0
- package/dist/providers/RuVectorClient.js.map +1 -0
- package/dist/providers/RuvllmPatternCurator.d.ts +116 -0
- package/dist/providers/RuvllmPatternCurator.d.ts.map +1 -0
- package/dist/providers/RuvllmPatternCurator.js +323 -0
- package/dist/providers/RuvllmPatternCurator.js.map +1 -0
- package/dist/providers/RuvllmProvider.d.ts +233 -1
- package/dist/providers/RuvllmProvider.d.ts.map +1 -1
- package/dist/providers/RuvllmProvider.js +781 -11
- package/dist/providers/RuvllmProvider.js.map +1 -1
- package/dist/providers/index.d.ts +5 -1
- package/dist/providers/index.d.ts.map +1 -1
- package/dist/providers/index.js +12 -2
- package/dist/providers/index.js.map +1 -1
- package/dist/utils/ruvllm-loader.d.ts +98 -1
- package/dist/utils/ruvllm-loader.d.ts.map +1 -1
- package/dist/utils/ruvllm-loader.js.map +1 -1
- package/package.json +1 -1
package/dist/agents/BaseAgent.js
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
/**
|
|
3
3
|
* BaseAgent - Abstract base class for all QE agents
|
|
4
4
|
* Phase 2 B1.2: Decomposed with strategy pattern (~500 LOC target)
|
|
5
|
+
* Phase 0: LLM Provider integration with RuvLLM support
|
|
5
6
|
*/
|
|
6
7
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
8
|
exports.BaseAgentFactory = exports.BaseAgent = exports.validateLearningConfig = exports.isSwarmMemoryManager = void 0;
|
|
@@ -12,9 +13,15 @@ const MemoryStoreAdapter_1 = require("../adapters/MemoryStoreAdapter");
|
|
|
12
13
|
const PerformanceTracker_1 = require("../learning/PerformanceTracker");
|
|
13
14
|
const SwarmMemoryManager_1 = require("../core/memory/SwarmMemoryManager");
|
|
14
15
|
const LearningEngine_1 = require("../learning/LearningEngine");
|
|
16
|
+
// Federated Learning (Phase 0 M0.5 - Team-wide pattern sharing)
|
|
17
|
+
const FederatedManager_1 = require("../learning/FederatedManager");
|
|
15
18
|
const AgentLifecycleManager_1 = require("./lifecycle/AgentLifecycleManager");
|
|
16
19
|
const AgentCoordinator_1 = require("./coordination/AgentCoordinator");
|
|
17
20
|
const AgentMemoryService_1 = require("./memory/AgentMemoryService");
|
|
21
|
+
const RuvllmProvider_1 = require("../providers/RuvllmProvider");
|
|
22
|
+
const LLMProviderFactory_1 = require("../providers/LLMProviderFactory");
|
|
23
|
+
// HybridRouter with RuVector cache (Phase 0.5 - GNN Self-Learning)
|
|
24
|
+
const HybridRouter_1 = require("../providers/HybridRouter");
|
|
18
25
|
const adapters_1 = require("./adapters");
|
|
19
26
|
// Extracted utilities (B1.2)
|
|
20
27
|
const utils_1 = require("./utils");
|
|
@@ -24,13 +31,16 @@ class BaseAgent extends events_1.EventEmitter {
|
|
|
24
31
|
constructor(config) {
|
|
25
32
|
super();
|
|
26
33
|
this.performanceMetrics = { tasksCompleted: 0, averageExecutionTime: 0, errorCount: 0, lastActivity: new Date() };
|
|
34
|
+
this.federatedInitialized = false;
|
|
27
35
|
this.agentId = { id: config.id || (0, utils_1.generateAgentId)(config.type), type: config.type, created: new Date() };
|
|
28
|
-
this.capabilities = new Map(config.capabilities.map(cap => [cap.name, cap]));
|
|
36
|
+
this.capabilities = new Map((config.capabilities || []).map(cap => [cap.name, cap]));
|
|
29
37
|
this.context = config.context;
|
|
30
38
|
this.memoryStore = config.memoryStore;
|
|
31
|
-
this.eventBus = config.eventBus;
|
|
39
|
+
this.eventBus = config.eventBus || new events_1.EventEmitter();
|
|
32
40
|
this.enableLearning = config.enableLearning ?? true;
|
|
33
41
|
this.learningConfig = config.learningConfig;
|
|
42
|
+
// LLM configuration (Phase 0 - default enabled with RuvLLM)
|
|
43
|
+
this.llmConfig = config.llm ?? { enabled: true, preferredProvider: 'ruvllm' };
|
|
34
44
|
// Early validation (Issue #137)
|
|
35
45
|
const validation = (0, utils_1.validateLearningConfig)(config);
|
|
36
46
|
if (!validation.valid && validation.warning) {
|
|
@@ -91,6 +101,10 @@ class BaseAgent extends events_1.EventEmitter {
|
|
|
91
101
|
else if (this.enableLearning) {
|
|
92
102
|
console.warn(`[${this.agentId.id}] Learning disabled: memoryStore is ${this.memoryStore.constructor.name}`);
|
|
93
103
|
}
|
|
104
|
+
// Initialize LLM Provider (Phase 0 - RuvLLM Integration)
|
|
105
|
+
await this.initializeLLMProvider();
|
|
106
|
+
// Initialize Federated Learning (Phase 0 M0.5)
|
|
107
|
+
await this.initializeFederatedLearning();
|
|
94
108
|
await this.initializeComponents();
|
|
95
109
|
await this.executeHook('post-initialization');
|
|
96
110
|
this.coordinator.emitEvent('agent.initialized', { agentId: this.agentId });
|
|
@@ -144,6 +158,8 @@ class BaseAgent extends events_1.EventEmitter {
|
|
|
144
158
|
await this.executeHook('pre-termination');
|
|
145
159
|
await this.saveState();
|
|
146
160
|
await this.cleanup();
|
|
161
|
+
await this.cleanupLLM(); // Phase 0: Cleanup LLM resources
|
|
162
|
+
await this.cleanupFederated(); // Phase 0 M0.5: Cleanup federated learning
|
|
147
163
|
this.coordinator.clearAllHandlers();
|
|
148
164
|
},
|
|
149
165
|
onPostTermination: async () => {
|
|
@@ -356,18 +372,34 @@ class BaseAgent extends events_1.EventEmitter {
|
|
|
356
372
|
duration: executionTime, metadata: { taskId: data.assignment.id, accuracy: result.accuracy, metrics: this.extractTaskMetrics(data.result) }
|
|
357
373
|
});
|
|
358
374
|
}
|
|
375
|
+
// Share successful patterns with team via federated learning (Phase 0 M0.5)
|
|
376
|
+
if (result.valid && this.federatedInitialized && this.llmProvider) {
|
|
377
|
+
try {
|
|
378
|
+
// Generate embedding for the task pattern
|
|
379
|
+
const taskDescription = `${data.assignment.task.type}: ${JSON.stringify(data.assignment.task.payload || {}).slice(0, 200)}`;
|
|
380
|
+
const embedding = await this.llmEmbed(taskDescription);
|
|
381
|
+
await this.shareLearnedPattern({
|
|
382
|
+
embedding,
|
|
383
|
+
quality: result.accuracy ?? 0.8,
|
|
384
|
+
category: data.assignment.task.type,
|
|
385
|
+
});
|
|
386
|
+
}
|
|
387
|
+
catch {
|
|
388
|
+
// Pattern sharing failed - non-critical, continue
|
|
389
|
+
}
|
|
390
|
+
}
|
|
359
391
|
this.emitEvent('hook.post-task.completed', { agentId: this.agentId, result });
|
|
360
392
|
}
|
|
361
393
|
async onTaskError(data) {
|
|
362
394
|
const executionTime = this.taskStartTime ? Date.now() - this.taskStartTime : 0;
|
|
363
395
|
await this.storeMemory(`error:${data.assignment.id}`, {
|
|
364
396
|
error: { message: data.error.message, name: data.error.name },
|
|
365
|
-
assignment: { id: data.assignment.id, taskType: data.assignment.task
|
|
397
|
+
assignment: { id: data.assignment.id, taskType: data.assignment.task?.type ?? 'unknown' },
|
|
366
398
|
timestamp: new Date(), agentId: this.agentId.id
|
|
367
399
|
});
|
|
368
400
|
if (this.strategies.lifecycle.onTaskError)
|
|
369
401
|
await this.strategies.lifecycle.onTaskError(data);
|
|
370
|
-
if (this.strategies.learning?.recordExecution) {
|
|
402
|
+
if (this.strategies.learning?.recordExecution && data.assignment.task) {
|
|
371
403
|
await this.strategies.learning.recordExecution({
|
|
372
404
|
task: data.assignment.task, error: data.error, success: false,
|
|
373
405
|
duration: executionTime, metadata: { taskId: data.assignment.id }
|
|
@@ -383,7 +415,8 @@ class BaseAgent extends events_1.EventEmitter {
|
|
|
383
415
|
await this[method](data);
|
|
384
416
|
}
|
|
385
417
|
catch (error) {
|
|
386
|
-
|
|
418
|
+
// Use warn - hooks are optional and failures shouldn't break agent operation
|
|
419
|
+
console.warn(`Hook ${hookName} failed:`, error);
|
|
387
420
|
}
|
|
388
421
|
}
|
|
389
422
|
setupEventHandlers() {
|
|
@@ -437,6 +470,503 @@ class BaseAgent extends events_1.EventEmitter {
|
|
|
437
470
|
async saveState() {
|
|
438
471
|
await this.memoryService.saveState({ performanceMetrics: this.performanceMetrics, timestamp: new Date() });
|
|
439
472
|
}
|
|
473
|
+
// ============================================
|
|
474
|
+
// LLM Provider Methods (Phase 0 - RuvLLM Integration)
|
|
475
|
+
// ============================================
|
|
476
|
+
/**
|
|
477
|
+
* Initialize LLM provider for agent use
|
|
478
|
+
* Supports RuvLLM (local), Claude, OpenRouter, and HybridRouter with RuVector cache
|
|
479
|
+
*/
|
|
480
|
+
async initializeLLMProvider() {
|
|
481
|
+
if (!this.llmConfig.enabled) {
|
|
482
|
+
console.log(`[${this.agentId.id}] LLM disabled by configuration`);
|
|
483
|
+
return;
|
|
484
|
+
}
|
|
485
|
+
try {
|
|
486
|
+
// If a provider was injected, use it directly
|
|
487
|
+
if (this.llmConfig.provider) {
|
|
488
|
+
this.llmProvider = this.llmConfig.provider;
|
|
489
|
+
console.log(`[${this.agentId.id}] Using injected LLM provider`);
|
|
490
|
+
return;
|
|
491
|
+
}
|
|
492
|
+
// Phase 0.5: Create HybridRouter with RuVector GNN cache for intelligent routing
|
|
493
|
+
if (this.llmConfig.enableHybridRouter || this.llmConfig.preferredProvider === 'hybrid') {
|
|
494
|
+
const hybridConfig = {
|
|
495
|
+
// RuVector cache configuration (GNN self-learning)
|
|
496
|
+
ruvector: {
|
|
497
|
+
enabled: true,
|
|
498
|
+
baseUrl: this.llmConfig.ruvectorCache?.baseUrl || 'http://localhost:8080',
|
|
499
|
+
cacheThreshold: this.llmConfig.ruvectorCache?.cacheThreshold ?? 0.85,
|
|
500
|
+
learningEnabled: this.llmConfig.ruvectorCache?.learningEnabled ?? true,
|
|
501
|
+
loraRank: this.llmConfig.ruvectorCache?.loraRank ?? 8,
|
|
502
|
+
ewcEnabled: this.llmConfig.ruvectorCache?.ewcEnabled ?? true,
|
|
503
|
+
...this.llmConfig.ruvectorCache,
|
|
504
|
+
},
|
|
505
|
+
// Local LLM via ruvllm
|
|
506
|
+
ruvllm: {
|
|
507
|
+
name: `${this.agentId.id}-ruvllm`,
|
|
508
|
+
enableSessions: this.llmConfig.enableSessions ?? true,
|
|
509
|
+
enableTRM: true,
|
|
510
|
+
enableSONA: true,
|
|
511
|
+
...this.llmConfig.ruvllm,
|
|
512
|
+
},
|
|
513
|
+
// Routing strategy
|
|
514
|
+
defaultStrategy: this.llmConfig.hybridRouterConfig?.defaultStrategy || HybridRouter_1.RoutingStrategy.BALANCED,
|
|
515
|
+
...this.llmConfig.hybridRouterConfig,
|
|
516
|
+
};
|
|
517
|
+
this.hybridRouter = new HybridRouter_1.HybridRouter(hybridConfig);
|
|
518
|
+
await this.hybridRouter.initialize();
|
|
519
|
+
this.llmProvider = this.hybridRouter;
|
|
520
|
+
console.log(`[${this.agentId.id}] HybridRouter initialized with RuVector GNN cache`);
|
|
521
|
+
return;
|
|
522
|
+
}
|
|
523
|
+
// Create RuvLLM provider directly (preferred for local inference)
|
|
524
|
+
if (this.llmConfig.preferredProvider === 'ruvllm' || !this.llmConfig.preferredProvider) {
|
|
525
|
+
const ruvllmConfig = {
|
|
526
|
+
name: `${this.agentId.id}-ruvllm`,
|
|
527
|
+
enableSessions: this.llmConfig.enableSessions ?? true,
|
|
528
|
+
enableTRM: true,
|
|
529
|
+
enableSONA: true,
|
|
530
|
+
debug: false,
|
|
531
|
+
...this.llmConfig.ruvllm
|
|
532
|
+
};
|
|
533
|
+
this.llmProvider = new RuvllmProvider_1.RuvllmProvider(ruvllmConfig);
|
|
534
|
+
await this.llmProvider.initialize();
|
|
535
|
+
// Create session for this agent if sessions enabled
|
|
536
|
+
if (this.llmConfig.enableSessions) {
|
|
537
|
+
const ruvllm = this.llmProvider;
|
|
538
|
+
const session = ruvllm.createSession();
|
|
539
|
+
this.llmSessionId = session.id;
|
|
540
|
+
console.log(`[${this.agentId.id}] LLM session created: ${this.llmSessionId}`);
|
|
541
|
+
}
|
|
542
|
+
console.log(`[${this.agentId.id}] RuvLLM provider initialized`);
|
|
543
|
+
return;
|
|
544
|
+
}
|
|
545
|
+
// Use factory for other providers (Claude, OpenRouter)
|
|
546
|
+
this.llmFactory = new LLMProviderFactory_1.LLMProviderFactory(this.llmConfig.factoryConfig || {});
|
|
547
|
+
await this.llmFactory.initialize();
|
|
548
|
+
this.llmProvider = this.llmFactory.getProvider(this.llmConfig.preferredProvider);
|
|
549
|
+
if (!this.llmProvider) {
|
|
550
|
+
console.warn(`[${this.agentId.id}] Preferred provider ${this.llmConfig.preferredProvider} not available, trying auto-select`);
|
|
551
|
+
this.llmProvider = this.llmFactory.selectBestProvider();
|
|
552
|
+
}
|
|
553
|
+
if (this.llmProvider) {
|
|
554
|
+
console.log(`[${this.agentId.id}] LLM provider initialized: ${this.llmConfig.preferredProvider}`);
|
|
555
|
+
}
|
|
556
|
+
else {
|
|
557
|
+
console.warn(`[${this.agentId.id}] No LLM provider available`);
|
|
558
|
+
}
|
|
559
|
+
}
|
|
560
|
+
catch (error) {
|
|
561
|
+
// Use warn instead of error - this is expected fallback behavior, not a failure
|
|
562
|
+
console.warn(`[${this.agentId.id}] LLM initialization failed:`, error.message);
|
|
563
|
+
// Don't throw - agent can still work without LLM (algorithmic fallback)
|
|
564
|
+
}
|
|
565
|
+
}
|
|
566
|
+
/**
|
|
567
|
+
* Initialize Federated Learning for team-wide pattern sharing
|
|
568
|
+
* Phase 0 M0.5 - Reduces Claude Code dependency through collective learning
|
|
569
|
+
*/
|
|
570
|
+
async initializeFederatedLearning() {
|
|
571
|
+
if (!this.llmConfig.enableFederated) {
|
|
572
|
+
return;
|
|
573
|
+
}
|
|
574
|
+
try {
|
|
575
|
+
// Use shared FederatedManager or create new one
|
|
576
|
+
if (this.llmConfig.federatedManager) {
|
|
577
|
+
this.federatedManager = this.llmConfig.federatedManager;
|
|
578
|
+
}
|
|
579
|
+
else {
|
|
580
|
+
this.federatedManager = new FederatedManager_1.FederatedManager(this.llmConfig.federatedConfig);
|
|
581
|
+
await this.federatedManager.initialize();
|
|
582
|
+
}
|
|
583
|
+
// Register this agent for federated learning
|
|
584
|
+
this.ephemeralAgent = this.federatedManager.registerAgent(this.agentId.id);
|
|
585
|
+
this.federatedInitialized = true;
|
|
586
|
+
console.log(`[${this.agentId.id}] Federated learning initialized`);
|
|
587
|
+
// Sync with existing team knowledge on startup
|
|
588
|
+
try {
|
|
589
|
+
await this.federatedManager.syncFromTeam(this.agentId.id);
|
|
590
|
+
console.log(`[${this.agentId.id}] Synced with team knowledge`);
|
|
591
|
+
}
|
|
592
|
+
catch {
|
|
593
|
+
// First agent or no prior knowledge - expected
|
|
594
|
+
}
|
|
595
|
+
}
|
|
596
|
+
catch (error) {
|
|
597
|
+
// Use warn instead of error - this is expected fallback behavior
|
|
598
|
+
console.warn(`[${this.agentId.id}] Federated learning initialization failed:`, error.message);
|
|
599
|
+
// Don't throw - agent can work without federated learning
|
|
600
|
+
}
|
|
601
|
+
}
|
|
602
|
+
/**
|
|
603
|
+
* Check if federated learning is available
|
|
604
|
+
*/
|
|
605
|
+
hasFederatedLearning() {
|
|
606
|
+
return this.federatedInitialized && this.federatedManager !== undefined;
|
|
607
|
+
}
|
|
608
|
+
/**
|
|
609
|
+
* Share a learned pattern with the team via federated learning
|
|
610
|
+
* Call this when the agent learns something useful (e.g., after successful task)
|
|
611
|
+
*
|
|
612
|
+
* @param pattern - The pattern to share (embedding, quality score, category)
|
|
613
|
+
*/
|
|
614
|
+
async shareLearnedPattern(pattern) {
|
|
615
|
+
if (!this.federatedManager || !this.federatedInitialized) {
|
|
616
|
+
return;
|
|
617
|
+
}
|
|
618
|
+
const fullPattern = {
|
|
619
|
+
...pattern,
|
|
620
|
+
id: `pattern-${this.agentId.id}-${Date.now()}`,
|
|
621
|
+
sourceAgent: this.agentId.id,
|
|
622
|
+
timestamp: Date.now(),
|
|
623
|
+
};
|
|
624
|
+
await this.federatedManager.sharePattern(this.agentId.id, fullPattern);
|
|
625
|
+
}
|
|
626
|
+
/**
|
|
627
|
+
* Sync this agent with team-wide learned knowledge
|
|
628
|
+
* Call this periodically or before complex tasks
|
|
629
|
+
*/
|
|
630
|
+
async syncWithTeam() {
|
|
631
|
+
if (!this.federatedManager || !this.federatedInitialized) {
|
|
632
|
+
return;
|
|
633
|
+
}
|
|
634
|
+
await this.federatedManager.syncFromTeam(this.agentId.id);
|
|
635
|
+
}
|
|
636
|
+
/**
|
|
637
|
+
* Submit this agent's learning updates to the team
|
|
638
|
+
* Call after completing a batch of tasks
|
|
639
|
+
*/
|
|
640
|
+
async submitLearningUpdate() {
|
|
641
|
+
if (!this.federatedManager || !this.federatedInitialized) {
|
|
642
|
+
return;
|
|
643
|
+
}
|
|
644
|
+
await this.federatedManager.submitAgentUpdate(this.agentId.id);
|
|
645
|
+
}
|
|
646
|
+
/**
|
|
647
|
+
* Get federated learning metrics
|
|
648
|
+
*/
|
|
649
|
+
getFederatedMetrics() {
|
|
650
|
+
if (!this.federatedManager) {
|
|
651
|
+
return null;
|
|
652
|
+
}
|
|
653
|
+
return this.federatedManager.getMetrics();
|
|
654
|
+
}
|
|
655
|
+
/**
|
|
656
|
+
* Check if LLM is available for this agent
|
|
657
|
+
*/
|
|
658
|
+
hasLLM() {
|
|
659
|
+
return this.llmProvider !== undefined;
|
|
660
|
+
}
|
|
661
|
+
/**
|
|
662
|
+
* Get LLM provider (for advanced usage)
|
|
663
|
+
*/
|
|
664
|
+
getLLMProvider() {
|
|
665
|
+
return this.llmProvider;
|
|
666
|
+
}
|
|
667
|
+
/**
|
|
668
|
+
* Make an LLM completion call
|
|
669
|
+
* Uses RuvLLM's session management for 50% latency reduction on multi-turn
|
|
670
|
+
*
|
|
671
|
+
* @param prompt - The prompt to send to the LLM
|
|
672
|
+
* @param options - Additional completion options
|
|
673
|
+
* @returns The LLM response text
|
|
674
|
+
* @throws Error if LLM is not available
|
|
675
|
+
*/
|
|
676
|
+
async llmComplete(prompt, options) {
|
|
677
|
+
if (!this.llmProvider) {
|
|
678
|
+
throw new Error(`[${this.agentId.id}] LLM not available - initialize agent first`);
|
|
679
|
+
}
|
|
680
|
+
const completionOptions = {
|
|
681
|
+
model: options?.model || this.llmConfig.ruvllm?.defaultModel || 'llama-3.2-3b-instruct',
|
|
682
|
+
messages: [{ role: 'user', content: prompt }],
|
|
683
|
+
maxTokens: options?.maxTokens,
|
|
684
|
+
temperature: options?.temperature,
|
|
685
|
+
stream: options?.stream,
|
|
686
|
+
metadata: {
|
|
687
|
+
...options?.metadata,
|
|
688
|
+
sessionId: this.llmSessionId, // Use session for faster multi-turn
|
|
689
|
+
agentId: this.agentId.id,
|
|
690
|
+
agentType: this.agentId.type
|
|
691
|
+
}
|
|
692
|
+
};
|
|
693
|
+
const response = await this.llmProvider.complete(completionOptions);
|
|
694
|
+
// Extract text from response
|
|
695
|
+
const text = response.content
|
|
696
|
+
.filter(block => block.type === 'text')
|
|
697
|
+
.map(block => block.text)
|
|
698
|
+
.join('\n');
|
|
699
|
+
return text;
|
|
700
|
+
}
|
|
701
|
+
/**
|
|
702
|
+
* Make a batch LLM completion call (4x throughput)
|
|
703
|
+
* Uses RuvLLM's native batch API for parallel processing
|
|
704
|
+
*
|
|
705
|
+
* @param prompts - Array of prompts to process in parallel
|
|
706
|
+
* @param options - Shared completion options
|
|
707
|
+
* @returns Array of response texts in same order as prompts
|
|
708
|
+
*/
|
|
709
|
+
async llmBatchComplete(prompts, options) {
|
|
710
|
+
if (!this.llmProvider) {
|
|
711
|
+
throw new Error(`[${this.agentId.id}] LLM not available - initialize agent first`);
|
|
712
|
+
}
|
|
713
|
+
// Check if provider supports batch (RuvLLM does)
|
|
714
|
+
const ruvllm = this.llmProvider;
|
|
715
|
+
if (typeof ruvllm.batchComplete === 'function') {
|
|
716
|
+
const defaultModel = options?.model || this.llmConfig.ruvllm?.defaultModel || 'llama-3.2-3b-instruct';
|
|
717
|
+
const requests = prompts.map(prompt => ({
|
|
718
|
+
model: defaultModel,
|
|
719
|
+
messages: [{ role: 'user', content: prompt }],
|
|
720
|
+
maxTokens: options?.maxTokens,
|
|
721
|
+
temperature: options?.temperature,
|
|
722
|
+
metadata: {
|
|
723
|
+
...options?.metadata,
|
|
724
|
+
agentId: this.agentId.id,
|
|
725
|
+
agentType: this.agentId.type
|
|
726
|
+
}
|
|
727
|
+
}));
|
|
728
|
+
const responses = await ruvllm.batchComplete(requests);
|
|
729
|
+
return responses.map(response => response.content
|
|
730
|
+
.filter(block => block.type === 'text')
|
|
731
|
+
.map(block => block.text)
|
|
732
|
+
.join('\n'));
|
|
733
|
+
}
|
|
734
|
+
// Fallback: sequential processing for non-batch providers
|
|
735
|
+
console.warn(`[${this.agentId.id}] Provider doesn't support batch, using sequential`);
|
|
736
|
+
const results = [];
|
|
737
|
+
for (const prompt of prompts) {
|
|
738
|
+
results.push(await this.llmComplete(prompt, options));
|
|
739
|
+
}
|
|
740
|
+
return results;
|
|
741
|
+
}
|
|
742
|
+
/**
|
|
743
|
+
* Generate embeddings for text
|
|
744
|
+
* Uses RuvLLM's SIMD-optimized embedding generation
|
|
745
|
+
*
|
|
746
|
+
* @param text - Text to embed
|
|
747
|
+
* @returns Embedding vector
|
|
748
|
+
*/
|
|
749
|
+
async llmEmbed(text) {
|
|
750
|
+
if (!this.llmProvider) {
|
|
751
|
+
throw new Error(`[${this.agentId.id}] LLM not available - initialize agent first`);
|
|
752
|
+
}
|
|
753
|
+
const response = await this.llmProvider.embed({ text });
|
|
754
|
+
return response.embedding || [];
|
|
755
|
+
}
|
|
756
|
+
/**
|
|
757
|
+
* Chat within agent's session (50% faster for multi-turn)
|
|
758
|
+
* Only works with RuvLLM provider with sessions enabled
|
|
759
|
+
*
|
|
760
|
+
* @param input - User input to chat
|
|
761
|
+
* @returns Assistant response
|
|
762
|
+
*/
|
|
763
|
+
async llmChat(input) {
|
|
764
|
+
if (!this.llmProvider) {
|
|
765
|
+
throw new Error(`[${this.agentId.id}] LLM not available`);
|
|
766
|
+
}
|
|
767
|
+
if (!this.llmSessionId) {
|
|
768
|
+
// Fallback to regular complete if no session
|
|
769
|
+
return this.llmComplete(input);
|
|
770
|
+
}
|
|
771
|
+
const ruvllm = this.llmProvider;
|
|
772
|
+
if (typeof ruvllm.sessionChat === 'function') {
|
|
773
|
+
return ruvllm.sessionChat(this.llmSessionId, input);
|
|
774
|
+
}
|
|
775
|
+
// Fallback
|
|
776
|
+
return this.llmComplete(input);
|
|
777
|
+
}
|
|
778
|
+
/**
|
|
779
|
+
* Get routing decision for observability
|
|
780
|
+
* Shows which model was selected and why
|
|
781
|
+
*/
|
|
782
|
+
getLLMRoutingDecision(input) {
|
|
783
|
+
if (!this.llmProvider) {
|
|
784
|
+
return null;
|
|
785
|
+
}
|
|
786
|
+
const ruvllm = this.llmProvider;
|
|
787
|
+
if (typeof ruvllm.getRoutingDecision === 'function') {
|
|
788
|
+
return ruvllm.getRoutingDecision(input);
|
|
789
|
+
}
|
|
790
|
+
return null;
|
|
791
|
+
}
|
|
792
|
+
/**
|
|
793
|
+
* Get LLM usage statistics for this agent
|
|
794
|
+
*/
|
|
795
|
+
getLLMStats() {
|
|
796
|
+
return {
|
|
797
|
+
available: this.hasLLM(),
|
|
798
|
+
sessionId: this.llmSessionId,
|
|
799
|
+
provider: this.hybridRouter ? 'hybrid' : (this.llmProvider ? 'ruvllm' : undefined),
|
|
800
|
+
hasRuVectorCache: this.hasRuVectorCache(),
|
|
801
|
+
};
|
|
802
|
+
}
|
|
803
|
+
// ============================================
|
|
804
|
+
// RuVector Cache Methods (Phase 0.5 - GNN Self-Learning)
|
|
805
|
+
// ============================================
|
|
806
|
+
/**
|
|
807
|
+
* Check if RuVector GNN cache is available
|
|
808
|
+
*/
|
|
809
|
+
hasRuVectorCache() {
|
|
810
|
+
return this.hybridRouter !== undefined;
|
|
811
|
+
}
|
|
812
|
+
/**
|
|
813
|
+
* Get RuVector cache metrics
|
|
814
|
+
* Returns cache hit rate, pattern count, and learning metrics
|
|
815
|
+
*/
|
|
816
|
+
async getRuVectorMetrics() {
|
|
817
|
+
if (!this.hybridRouter) {
|
|
818
|
+
return null;
|
|
819
|
+
}
|
|
820
|
+
try {
|
|
821
|
+
return await this.hybridRouter.getRuVectorMetrics();
|
|
822
|
+
}
|
|
823
|
+
catch {
|
|
824
|
+
return null;
|
|
825
|
+
}
|
|
826
|
+
}
|
|
827
|
+
/**
|
|
828
|
+
* Get cache hit rate for this agent's requests
|
|
829
|
+
*/
|
|
830
|
+
getCacheHitRate() {
|
|
831
|
+
if (!this.hybridRouter) {
|
|
832
|
+
return 0;
|
|
833
|
+
}
|
|
834
|
+
return this.hybridRouter.getCacheHitRate();
|
|
835
|
+
}
|
|
836
|
+
/**
|
|
837
|
+
* Get routing statistics including cache savings
|
|
838
|
+
*/
|
|
839
|
+
getRoutingStats() {
|
|
840
|
+
if (!this.hybridRouter) {
|
|
841
|
+
return {
|
|
842
|
+
totalDecisions: 0,
|
|
843
|
+
localDecisions: 0,
|
|
844
|
+
cloudDecisions: 0,
|
|
845
|
+
cacheHits: 0,
|
|
846
|
+
cacheMisses: 0,
|
|
847
|
+
cacheHitRate: 0,
|
|
848
|
+
averageLocalLatency: 0,
|
|
849
|
+
averageCloudLatency: 0,
|
|
850
|
+
successRate: 0,
|
|
851
|
+
};
|
|
852
|
+
}
|
|
853
|
+
return this.hybridRouter.getRoutingStats();
|
|
854
|
+
}
|
|
855
|
+
/**
|
|
856
|
+
* Force learning consolidation in the RuVector cache
|
|
857
|
+
* Triggers LoRA adaptation and EWC++ protection
|
|
858
|
+
*/
|
|
859
|
+
async forceRuVectorLearn() {
|
|
860
|
+
if (!this.hybridRouter) {
|
|
861
|
+
return { success: false, error: 'RuVector not enabled' };
|
|
862
|
+
}
|
|
863
|
+
return await this.hybridRouter.forceRuVectorLearn();
|
|
864
|
+
}
|
|
865
|
+
/**
|
|
866
|
+
* Get cost savings report from using RuVector cache
|
|
867
|
+
*/
|
|
868
|
+
getCostSavingsReport() {
|
|
869
|
+
if (!this.hybridRouter) {
|
|
870
|
+
return {
|
|
871
|
+
totalRequests: 0,
|
|
872
|
+
localRequests: 0,
|
|
873
|
+
cloudRequests: 0,
|
|
874
|
+
totalCost: 0,
|
|
875
|
+
estimatedCloudCost: 0,
|
|
876
|
+
savings: 0,
|
|
877
|
+
savingsPercentage: 0,
|
|
878
|
+
cacheHits: 0,
|
|
879
|
+
cacheSavings: 0,
|
|
880
|
+
};
|
|
881
|
+
}
|
|
882
|
+
return this.hybridRouter.getCostSavingsReport();
|
|
883
|
+
}
|
|
884
|
+
/**
|
|
885
|
+
* Make an LLM call with automatic caching and learning
|
|
886
|
+
* Uses RuVector GNN cache when available for sub-ms pattern matching
|
|
887
|
+
*
|
|
888
|
+
* @param prompt - The prompt to process
|
|
889
|
+
* @param options - Additional options
|
|
890
|
+
* @returns The response text
|
|
891
|
+
*/
|
|
892
|
+
async llmCompleteWithLearning(prompt, options) {
|
|
893
|
+
if (!this.llmProvider) {
|
|
894
|
+
throw new Error(`[${this.agentId.id}] LLM not available - initialize agent first`);
|
|
895
|
+
}
|
|
896
|
+
// If using HybridRouter, it automatically handles caching and learning
|
|
897
|
+
if (this.hybridRouter) {
|
|
898
|
+
const completionOptions = {
|
|
899
|
+
model: options?.model || 'auto',
|
|
900
|
+
messages: [{ role: 'user', content: prompt }],
|
|
901
|
+
maxTokens: options?.maxTokens,
|
|
902
|
+
temperature: options?.temperature,
|
|
903
|
+
metadata: {
|
|
904
|
+
...options?.metadata,
|
|
905
|
+
agentId: this.agentId.id,
|
|
906
|
+
agentType: this.agentId.type,
|
|
907
|
+
complexity: options?.complexity,
|
|
908
|
+
},
|
|
909
|
+
};
|
|
910
|
+
const response = await this.hybridRouter.complete(completionOptions);
|
|
911
|
+
// Extract text from response
|
|
912
|
+
const text = response.content
|
|
913
|
+
.filter(block => block.type === 'text')
|
|
914
|
+
.map(block => block.text)
|
|
915
|
+
.join('\n');
|
|
916
|
+
return {
|
|
917
|
+
response: text,
|
|
918
|
+
source: response.metadata?.source || 'local',
|
|
919
|
+
confidence: response.metadata?.confidence,
|
|
920
|
+
};
|
|
921
|
+
}
|
|
922
|
+
// Fallback to regular completion
|
|
923
|
+
const text = await this.llmComplete(prompt, options);
|
|
924
|
+
return { response: text, source: 'local' };
|
|
925
|
+
}
|
|
926
|
+
/**
|
|
927
|
+
* Cleanup LLM resources on agent termination
|
|
928
|
+
*/
|
|
929
|
+
async cleanupLLM() {
|
|
930
|
+
if (this.llmSessionId && this.llmProvider) {
|
|
931
|
+
const ruvllm = this.llmProvider;
|
|
932
|
+
if (typeof ruvllm.endSession === 'function') {
|
|
933
|
+
ruvllm.endSession(this.llmSessionId);
|
|
934
|
+
console.log(`[${this.agentId.id}] LLM session ended: ${this.llmSessionId}`);
|
|
935
|
+
}
|
|
936
|
+
}
|
|
937
|
+
if (this.llmProvider) {
|
|
938
|
+
await this.llmProvider.shutdown();
|
|
939
|
+
}
|
|
940
|
+
if (this.llmFactory) {
|
|
941
|
+
await this.llmFactory.shutdown();
|
|
942
|
+
}
|
|
943
|
+
}
|
|
944
|
+
/**
|
|
945
|
+
* Cleanup federated learning resources on agent termination
|
|
946
|
+
* Submits final learning updates and unregisters from the coordinator
|
|
947
|
+
*/
|
|
948
|
+
async cleanupFederated() {
|
|
949
|
+
if (!this.federatedManager || !this.federatedInitialized) {
|
|
950
|
+
return;
|
|
951
|
+
}
|
|
952
|
+
try {
|
|
953
|
+
// Submit final learning updates before terminating
|
|
954
|
+
await this.submitLearningUpdate();
|
|
955
|
+
// Unregister this agent from federated learning
|
|
956
|
+
this.federatedManager.unregisterAgent(this.agentId.id);
|
|
957
|
+
console.log(`[${this.agentId.id}] Federated learning cleanup complete`);
|
|
958
|
+
}
|
|
959
|
+
catch (error) {
|
|
960
|
+
console.warn(`[${this.agentId.id}] Federated cleanup error:`, error.message);
|
|
961
|
+
}
|
|
962
|
+
this.federatedInitialized = false;
|
|
963
|
+
this.ephemeralAgent = undefined;
|
|
964
|
+
// Only shutdown the manager if we created it (not if it was shared)
|
|
965
|
+
if (!this.llmConfig.federatedManager && this.federatedManager) {
|
|
966
|
+
await this.federatedManager.shutdown();
|
|
967
|
+
this.federatedManager = undefined;
|
|
968
|
+
}
|
|
969
|
+
}
|
|
440
970
|
}
|
|
441
971
|
exports.BaseAgent = BaseAgent;
|
|
442
972
|
class BaseAgentFactory {
|