agentic-qe 2.5.8 → 2.5.10

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 (60) hide show
  1. package/CHANGELOG.md +122 -0
  2. package/README.md +2 -2
  3. package/dist/agents/BaseAgent.d.ts +211 -7
  4. package/dist/agents/BaseAgent.d.ts.map +1 -1
  5. package/dist/agents/BaseAgent.js +455 -7
  6. package/dist/agents/BaseAgent.js.map +1 -1
  7. package/dist/agents/CoverageAnalyzerAgent.d.ts +20 -23
  8. package/dist/agents/CoverageAnalyzerAgent.d.ts.map +1 -1
  9. package/dist/agents/CoverageAnalyzerAgent.js +95 -145
  10. package/dist/agents/CoverageAnalyzerAgent.js.map +1 -1
  11. package/dist/agents/FlakyTestHunterAgent.d.ts +15 -0
  12. package/dist/agents/FlakyTestHunterAgent.d.ts.map +1 -1
  13. package/dist/agents/FlakyTestHunterAgent.js +93 -0
  14. package/dist/agents/FlakyTestHunterAgent.js.map +1 -1
  15. package/dist/agents/QualityAnalyzerAgent.d.ts +2 -2
  16. package/dist/agents/QualityAnalyzerAgent.d.ts.map +1 -1
  17. package/dist/agents/QualityAnalyzerAgent.js.map +1 -1
  18. package/dist/agents/QualityGateAgent.d.ts +35 -18
  19. package/dist/agents/QualityGateAgent.d.ts.map +1 -1
  20. package/dist/agents/QualityGateAgent.js +72 -97
  21. package/dist/agents/QualityGateAgent.js.map +1 -1
  22. package/dist/agents/SecurityScannerAgent.d.ts +19 -0
  23. package/dist/agents/SecurityScannerAgent.d.ts.map +1 -1
  24. package/dist/agents/SecurityScannerAgent.js +137 -0
  25. package/dist/agents/SecurityScannerAgent.js.map +1 -1
  26. package/dist/agents/index.d.ts.map +1 -1
  27. package/dist/agents/index.js +17 -4
  28. package/dist/agents/index.js.map +1 -1
  29. package/dist/cli/commands/ruvector/index.d.ts +13 -0
  30. package/dist/cli/commands/ruvector/index.d.ts.map +1 -0
  31. package/dist/cli/commands/ruvector/index.js +308 -0
  32. package/dist/cli/commands/ruvector/index.js.map +1 -0
  33. package/dist/cli/index.js +5 -0
  34. package/dist/cli/index.js.map +1 -1
  35. package/dist/cli/init/index.d.ts.map +1 -1
  36. package/dist/cli/init/index.js +11 -0
  37. package/dist/cli/init/index.js.map +1 -1
  38. package/dist/core/memory/HNSWVectorMemory.js +1 -1
  39. package/dist/core/memory/HNSWVectorMemory.js.map +1 -1
  40. package/dist/mcp/server-instructions.d.ts +1 -1
  41. package/dist/mcp/server-instructions.d.ts.map +1 -1
  42. package/dist/mcp/server-instructions.js +1 -1
  43. package/dist/mcp/server-instructions.js.map +1 -1
  44. package/dist/mcp/tools.d.ts +6 -0
  45. package/dist/mcp/tools.d.ts.map +1 -1
  46. package/dist/mcp/tools.js +121 -0
  47. package/dist/mcp/tools.js.map +1 -1
  48. package/dist/memory/RuVectorPatternStore.d.ts +258 -0
  49. package/dist/memory/RuVectorPatternStore.d.ts.map +1 -0
  50. package/dist/memory/RuVectorPatternStore.js +525 -0
  51. package/dist/memory/RuVectorPatternStore.js.map +1 -0
  52. package/dist/providers/RuVectorPostgresAdapter.d.ts +134 -0
  53. package/dist/providers/RuVectorPostgresAdapter.d.ts.map +1 -0
  54. package/dist/providers/RuVectorPostgresAdapter.js +504 -0
  55. package/dist/providers/RuVectorPostgresAdapter.js.map +1 -0
  56. package/dist/providers/index.d.ts +2 -0
  57. package/dist/providers/index.d.ts.map +1 -1
  58. package/dist/providers/index.js +7 -1
  59. package/dist/providers/index.js.map +1 -1
  60. package/package.json +4 -2
@@ -20,6 +20,8 @@ const AgentCoordinator_1 = require("./coordination/AgentCoordinator");
20
20
  const AgentMemoryService_1 = require("./memory/AgentMemoryService");
21
21
  const RuvllmProvider_1 = require("../providers/RuvllmProvider");
22
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");
23
25
  const adapters_1 = require("./adapters");
24
26
  // Extracted utilities (B1.2)
25
27
  const utils_1 = require("./utils");
@@ -30,15 +32,32 @@ class BaseAgent extends events_1.EventEmitter {
30
32
  super();
31
33
  this.performanceMetrics = { tasksCompleted: 0, averageExecutionTime: 0, errorCount: 0, lastActivity: new Date() };
32
34
  this.federatedInitialized = false;
35
+ this.patternStoreInitialized = false;
33
36
  this.agentId = { id: config.id || (0, utils_1.generateAgentId)(config.type), type: config.type, created: new Date() };
34
- this.capabilities = new Map(config.capabilities.map(cap => [cap.name, cap]));
37
+ this.capabilities = new Map((config.capabilities || []).map(cap => [cap.name, cap]));
35
38
  this.context = config.context;
36
39
  this.memoryStore = config.memoryStore;
37
- this.eventBus = config.eventBus;
40
+ this.eventBus = config.eventBus || new events_1.EventEmitter();
38
41
  this.enableLearning = config.enableLearning ?? true;
39
42
  this.learningConfig = config.learningConfig;
40
43
  // LLM configuration (Phase 0 - default enabled with RuvLLM)
41
44
  this.llmConfig = config.llm ?? { enabled: true, preferredProvider: 'ruvllm' };
45
+ // QE Pattern Store configuration (Phase 0.5 - RuVector Integration)
46
+ // Environment variables take precedence, then config, then defaults
47
+ // RuVector is OPT-IN to maintain backward compatibility with existing users
48
+ const envRuVectorEnabled = process.env.AQE_RUVECTOR_ENABLED?.toLowerCase() === 'true';
49
+ const envRuVectorUrl = process.env.AQE_RUVECTOR_URL || process.env.RUVECTOR_URL;
50
+ const envPatternStoreEnabled = process.env.AQE_PATTERN_STORE_ENABLED?.toLowerCase() !== 'false';
51
+ this.qePatternConfig = {
52
+ enabled: config.patternStore?.enabled ?? envPatternStoreEnabled,
53
+ // RuVector defaults to FALSE - opt-in for advanced self-learning
54
+ useRuVector: config.patternStore?.useRuVector ?? envRuVectorEnabled,
55
+ useHNSW: config.patternStore?.useHNSW ?? true,
56
+ dualWrite: config.patternStore?.dualWrite ?? (process.env.AQE_PATTERN_DUAL_WRITE === 'true'),
57
+ ruvectorUrl: config.patternStore?.ruvectorUrl ?? envRuVectorUrl ?? 'postgresql://ruvector:ruvector@localhost:5432/ruvector_db',
58
+ storagePath: config.patternStore?.storagePath ?? process.env.AQE_PATTERN_STORE_PATH ?? './data/qe-patterns.ruvector',
59
+ autoSync: config.patternStore?.autoSync ?? (process.env.AQE_PATTERN_AUTO_SYNC === 'true'),
60
+ };
42
61
  // Early validation (Issue #137)
43
62
  const validation = (0, utils_1.validateLearningConfig)(config);
44
63
  if (!validation.valid && validation.warning) {
@@ -103,6 +122,8 @@ class BaseAgent extends events_1.EventEmitter {
103
122
  await this.initializeLLMProvider();
104
123
  // Initialize Federated Learning (Phase 0 M0.5)
105
124
  await this.initializeFederatedLearning();
125
+ // Initialize QE Pattern Store (Phase 0.5)
126
+ await this.initializePatternStore();
106
127
  await this.initializeComponents();
107
128
  await this.executeHook('post-initialization');
108
129
  this.coordinator.emitEvent('agent.initialized', { agentId: this.agentId });
@@ -158,6 +179,7 @@ class BaseAgent extends events_1.EventEmitter {
158
179
  await this.cleanup();
159
180
  await this.cleanupLLM(); // Phase 0: Cleanup LLM resources
160
181
  await this.cleanupFederated(); // Phase 0 M0.5: Cleanup federated learning
182
+ await this.cleanupPatternStore(); // Phase 0.5: Cleanup pattern store
161
183
  this.coordinator.clearAllHandlers();
162
184
  },
163
185
  onPostTermination: async () => {
@@ -413,7 +435,8 @@ class BaseAgent extends events_1.EventEmitter {
413
435
  await this[method](data);
414
436
  }
415
437
  catch (error) {
416
- console.error(`Hook ${hookName} failed:`, error);
438
+ // Use warn - hooks are optional and failures shouldn't break agent operation
439
+ console.warn(`Hook ${hookName} failed:`, error);
417
440
  }
418
441
  }
419
442
  setupEventHandlers() {
@@ -472,7 +495,7 @@ class BaseAgent extends events_1.EventEmitter {
472
495
  // ============================================
473
496
  /**
474
497
  * Initialize LLM provider for agent use
475
- * Supports RuvLLM (local), Claude, and OpenRouter providers
498
+ * Supports RuvLLM (local), Claude, OpenRouter, and HybridRouter with RuVector cache
476
499
  */
477
500
  async initializeLLMProvider() {
478
501
  if (!this.llmConfig.enabled) {
@@ -486,6 +509,37 @@ class BaseAgent extends events_1.EventEmitter {
486
509
  console.log(`[${this.agentId.id}] Using injected LLM provider`);
487
510
  return;
488
511
  }
512
+ // Phase 0.5: Create HybridRouter with RuVector GNN cache for intelligent routing
513
+ if (this.llmConfig.enableHybridRouter || this.llmConfig.preferredProvider === 'hybrid') {
514
+ const hybridConfig = {
515
+ // RuVector cache configuration (GNN self-learning)
516
+ ruvector: {
517
+ enabled: true,
518
+ baseUrl: this.llmConfig.ruvectorCache?.baseUrl || 'http://localhost:8080',
519
+ cacheThreshold: this.llmConfig.ruvectorCache?.cacheThreshold ?? 0.85,
520
+ learningEnabled: this.llmConfig.ruvectorCache?.learningEnabled ?? true,
521
+ loraRank: this.llmConfig.ruvectorCache?.loraRank ?? 8,
522
+ ewcEnabled: this.llmConfig.ruvectorCache?.ewcEnabled ?? true,
523
+ ...this.llmConfig.ruvectorCache,
524
+ },
525
+ // Local LLM via ruvllm
526
+ ruvllm: {
527
+ name: `${this.agentId.id}-ruvllm`,
528
+ enableSessions: this.llmConfig.enableSessions ?? true,
529
+ enableTRM: true,
530
+ enableSONA: true,
531
+ ...this.llmConfig.ruvllm,
532
+ },
533
+ // Routing strategy
534
+ defaultStrategy: this.llmConfig.hybridRouterConfig?.defaultStrategy || HybridRouter_1.RoutingStrategy.BALANCED,
535
+ ...this.llmConfig.hybridRouterConfig,
536
+ };
537
+ this.hybridRouter = new HybridRouter_1.HybridRouter(hybridConfig);
538
+ await this.hybridRouter.initialize();
539
+ this.llmProvider = this.hybridRouter;
540
+ console.log(`[${this.agentId.id}] HybridRouter initialized with RuVector GNN cache`);
541
+ return;
542
+ }
489
543
  // Create RuvLLM provider directly (preferred for local inference)
490
544
  if (this.llmConfig.preferredProvider === 'ruvllm' || !this.llmConfig.preferredProvider) {
491
545
  const ruvllmConfig = {
@@ -524,7 +578,8 @@ class BaseAgent extends events_1.EventEmitter {
524
578
  }
525
579
  }
526
580
  catch (error) {
527
- console.error(`[${this.agentId.id}] LLM initialization failed:`, error.message);
581
+ // Use warn instead of error - this is expected fallback behavior, not a failure
582
+ console.warn(`[${this.agentId.id}] LLM initialization failed:`, error.message);
528
583
  // Don't throw - agent can still work without LLM (algorithmic fallback)
529
584
  }
530
585
  }
@@ -559,7 +614,8 @@ class BaseAgent extends events_1.EventEmitter {
559
614
  }
560
615
  }
561
616
  catch (error) {
562
- console.error(`[${this.agentId.id}] Federated learning initialization failed:`, error.message);
617
+ // Use warn instead of error - this is expected fallback behavior
618
+ console.warn(`[${this.agentId.id}] Federated learning initialization failed:`, error.message);
563
619
  // Don't throw - agent can work without federated learning
564
620
  }
565
621
  }
@@ -760,9 +816,401 @@ class BaseAgent extends events_1.EventEmitter {
760
816
  return {
761
817
  available: this.hasLLM(),
762
818
  sessionId: this.llmSessionId,
763
- provider: this.llmProvider ? 'ruvllm' : undefined
819
+ provider: this.hybridRouter ? 'hybrid' : (this.llmProvider ? 'ruvllm' : undefined),
820
+ hasRuVectorCache: this.hasRuVectorCache(),
821
+ hasPatternStore: this.hasPatternStore(),
822
+ patternStoreType: this.hasPatternStore() ?
823
+ this.qePatternStore?.getImplementationInfo?.()?.type :
824
+ undefined,
764
825
  };
765
826
  }
827
+ // ============================================
828
+ // RuVector Cache Methods (Phase 0.5 - GNN Self-Learning)
829
+ // ============================================
830
+ /**
831
+ * Check if RuVector GNN cache is available
832
+ */
833
+ hasRuVectorCache() {
834
+ return this.hybridRouter !== undefined;
835
+ }
836
+ /**
837
+ * Get RuVector cache metrics
838
+ * Returns cache hit rate, pattern count, and learning metrics
839
+ */
840
+ async getRuVectorMetrics() {
841
+ if (!this.hybridRouter) {
842
+ return null;
843
+ }
844
+ try {
845
+ return await this.hybridRouter.getRuVectorMetrics();
846
+ }
847
+ catch {
848
+ return null;
849
+ }
850
+ }
851
+ /**
852
+ * Get cache hit rate for this agent's requests
853
+ */
854
+ getCacheHitRate() {
855
+ if (!this.hybridRouter) {
856
+ return 0;
857
+ }
858
+ return this.hybridRouter.getCacheHitRate();
859
+ }
860
+ /**
861
+ * Get routing statistics including cache savings
862
+ */
863
+ getRoutingStats() {
864
+ if (!this.hybridRouter) {
865
+ return {
866
+ totalDecisions: 0,
867
+ localDecisions: 0,
868
+ cloudDecisions: 0,
869
+ cacheHits: 0,
870
+ cacheMisses: 0,
871
+ cacheHitRate: 0,
872
+ averageLocalLatency: 0,
873
+ averageCloudLatency: 0,
874
+ successRate: 0,
875
+ };
876
+ }
877
+ return this.hybridRouter.getRoutingStats();
878
+ }
879
+ /**
880
+ * Force learning consolidation in the RuVector cache
881
+ * Triggers LoRA adaptation and EWC++ protection
882
+ */
883
+ async forceRuVectorLearn() {
884
+ if (!this.hybridRouter) {
885
+ return { success: false, error: 'RuVector not enabled' };
886
+ }
887
+ return await this.hybridRouter.forceRuVectorLearn();
888
+ }
889
+ /**
890
+ * Get cost savings report from using RuVector cache
891
+ */
892
+ getCostSavingsReport() {
893
+ if (!this.hybridRouter) {
894
+ return {
895
+ totalRequests: 0,
896
+ localRequests: 0,
897
+ cloudRequests: 0,
898
+ totalCost: 0,
899
+ estimatedCloudCost: 0,
900
+ savings: 0,
901
+ savingsPercentage: 0,
902
+ cacheHits: 0,
903
+ cacheSavings: 0,
904
+ };
905
+ }
906
+ return this.hybridRouter.getCostSavingsReport();
907
+ }
908
+ /**
909
+ * Make an LLM call with automatic caching and learning
910
+ * Uses RuVector GNN cache when available for sub-ms pattern matching
911
+ *
912
+ * @param prompt - The prompt to process
913
+ * @param options - Additional options
914
+ * @returns The response text
915
+ */
916
+ async llmCompleteWithLearning(prompt, options) {
917
+ if (!this.llmProvider) {
918
+ throw new Error(`[${this.agentId.id}] LLM not available - initialize agent first`);
919
+ }
920
+ // If using HybridRouter, it automatically handles caching and learning
921
+ if (this.hybridRouter) {
922
+ const completionOptions = {
923
+ model: options?.model || 'auto',
924
+ messages: [{ role: 'user', content: prompt }],
925
+ maxTokens: options?.maxTokens,
926
+ temperature: options?.temperature,
927
+ metadata: {
928
+ ...options?.metadata,
929
+ agentId: this.agentId.id,
930
+ agentType: this.agentId.type,
931
+ complexity: options?.complexity,
932
+ },
933
+ };
934
+ const response = await this.hybridRouter.complete(completionOptions);
935
+ // Extract text from response
936
+ const text = response.content
937
+ .filter(block => block.type === 'text')
938
+ .map(block => block.text)
939
+ .join('\n');
940
+ return {
941
+ response: text,
942
+ source: response.metadata?.source || 'local',
943
+ confidence: response.metadata?.confidence,
944
+ };
945
+ }
946
+ // Fallback to regular completion
947
+ const text = await this.llmComplete(prompt, options);
948
+ return { response: text, source: 'local' };
949
+ }
950
+ // ============================================
951
+ // QE Pattern Store Methods (Phase 0.5 - RuVector Integration)
952
+ // ============================================
953
+ /**
954
+ * Initialize QE Pattern Store for learned pattern storage
955
+ * Supports both RuVector Docker (150x faster) and local HNSW fallback
956
+ */
957
+ async initializePatternStore() {
958
+ if (!this.qePatternConfig.enabled) {
959
+ console.log(`[${this.agentId.id}] QE Pattern Store disabled by configuration`);
960
+ return;
961
+ }
962
+ try {
963
+ // Phase 0.5: Use PostgreSQL adapter when RuVector is enabled
964
+ if (this.qePatternConfig.useRuVector) {
965
+ try {
966
+ const { createDockerRuVectorAdapter } = require('../providers/RuVectorPostgresAdapter');
967
+ // Parse PostgreSQL connection URL or use defaults
968
+ const url = this.qePatternConfig.ruvectorUrl || '';
969
+ const isPostgres = url.startsWith('postgresql://') || url.startsWith('postgres://');
970
+ if (isPostgres) {
971
+ // Parse connection URL
972
+ const parsed = new URL(url);
973
+ this.qePatternStore = createDockerRuVectorAdapter({
974
+ host: parsed.hostname,
975
+ port: parseInt(parsed.port) || 5432,
976
+ database: parsed.pathname.slice(1) || 'ruvector_db',
977
+ user: parsed.username || 'ruvector',
978
+ password: parsed.password || 'ruvector',
979
+ learningEnabled: true,
980
+ cacheThreshold: 0.85,
981
+ });
982
+ }
983
+ else {
984
+ // Use default Docker configuration
985
+ this.qePatternStore = createDockerRuVectorAdapter({
986
+ host: process.env.RUVECTOR_HOST || 'localhost',
987
+ port: parseInt(process.env.RUVECTOR_PORT || '5432'),
988
+ database: process.env.RUVECTOR_DATABASE || 'ruvector_db',
989
+ user: process.env.RUVECTOR_USER || 'ruvector',
990
+ password: process.env.RUVECTOR_PASSWORD || 'ruvector',
991
+ learningEnabled: true,
992
+ cacheThreshold: 0.85,
993
+ });
994
+ }
995
+ await this.qePatternStore.initialize();
996
+ this.patternStoreInitialized = true;
997
+ console.log(`[${this.agentId.id}] QE Pattern Store initialized (RuVector PostgreSQL: enabled)`);
998
+ return;
999
+ }
1000
+ catch (postgresError) {
1001
+ console.warn(`[${this.agentId.id}] RuVector PostgreSQL unavailable, falling back to HNSW:`, postgresError.message);
1002
+ // Fall through to HNSW fallback
1003
+ }
1004
+ }
1005
+ // Fallback: Use local RuVectorPatternStore (HNSW-based)
1006
+ const { RuVectorPatternStore } = require('../memory/RuVectorPatternStore');
1007
+ // Configure pattern store with local HNSW
1008
+ const storeConfig = {
1009
+ dimension: 384,
1010
+ metric: 'cosine',
1011
+ storagePath: this.qePatternConfig.storagePath,
1012
+ autoPersist: true,
1013
+ enableMetrics: true,
1014
+ hnsw: {
1015
+ m: 32,
1016
+ efConstruction: 200,
1017
+ efSearch: 100,
1018
+ },
1019
+ };
1020
+ this.qePatternStore = new RuVectorPatternStore(storeConfig);
1021
+ await this.qePatternStore.initialize();
1022
+ this.patternStoreInitialized = true;
1023
+ console.log(`[${this.agentId.id}] QE Pattern Store initialized (HNSW fallback)`);
1024
+ }
1025
+ catch (error) {
1026
+ console.warn(`[${this.agentId.id}] Pattern Store initialization failed:`, error.message);
1027
+ // Don't throw - agent can work without pattern store
1028
+ }
1029
+ }
1030
+ /**
1031
+ * Check if QE pattern store is available
1032
+ */
1033
+ hasPatternStore() {
1034
+ return this.patternStoreInitialized && this.qePatternStore !== undefined;
1035
+ }
1036
+ /**
1037
+ * Store a QE learned pattern
1038
+ * Automatically uses RuVector when available, falls back to HNSW
1039
+ *
1040
+ * @param pattern - The QE pattern to store
1041
+ * @returns Success status
1042
+ */
1043
+ async storeQEPattern(pattern) {
1044
+ if (!this.hasPatternStore()) {
1045
+ return { success: false };
1046
+ }
1047
+ try {
1048
+ const testPattern = {
1049
+ id: pattern.id,
1050
+ type: pattern.type,
1051
+ domain: pattern.domain,
1052
+ content: pattern.content,
1053
+ embedding: pattern.embedding,
1054
+ framework: pattern.framework,
1055
+ coverage: pattern.coverage,
1056
+ createdAt: Date.now(),
1057
+ lastUsed: Date.now(),
1058
+ usageCount: 0,
1059
+ metadata: {
1060
+ agentId: this.agentId.id,
1061
+ agentType: this.agentId.type,
1062
+ ...pattern.metadata,
1063
+ },
1064
+ };
1065
+ // Use auto-sync variant if enabled
1066
+ if (this.qePatternConfig.autoSync && this.qePatternStore.storeWithSync) {
1067
+ const result = await this.qePatternStore.storeWithSync(testPattern);
1068
+ return { success: result.stored, synced: result.synced };
1069
+ }
1070
+ await this.qePatternStore.storePattern(testPattern);
1071
+ return { success: true };
1072
+ }
1073
+ catch (error) {
1074
+ console.warn(`[${this.agentId.id}] Failed to store QE pattern:`, error.message);
1075
+ return { success: false };
1076
+ }
1077
+ }
1078
+ /**
1079
+ * Search for similar QE patterns
1080
+ * Uses RuVector's 150x faster search when available
1081
+ *
1082
+ * @param embedding - Query embedding vector
1083
+ * @param k - Number of results to return (default: 10)
1084
+ * @param options - Additional search options
1085
+ * @returns Array of similar patterns with scores
1086
+ */
1087
+ async searchQEPatterns(embedding, k = 10, options) {
1088
+ if (!this.hasPatternStore()) {
1089
+ return [];
1090
+ }
1091
+ try {
1092
+ const results = await this.qePatternStore.searchSimilar(embedding, {
1093
+ k,
1094
+ domain: options?.domain,
1095
+ type: options?.type,
1096
+ framework: options?.framework,
1097
+ threshold: options?.threshold ?? 0.7,
1098
+ useMMR: options?.useMMR ?? false,
1099
+ });
1100
+ return results;
1101
+ }
1102
+ catch (error) {
1103
+ console.warn(`[${this.agentId.id}] Pattern search failed:`, error.message);
1104
+ return [];
1105
+ }
1106
+ }
1107
+ /**
1108
+ * Get QE pattern store metrics
1109
+ * Returns performance and usage statistics
1110
+ */
1111
+ getQEPatternMetrics() {
1112
+ if (!this.hasPatternStore()) {
1113
+ return null;
1114
+ }
1115
+ try {
1116
+ const stats = this.qePatternStore.getStats?.();
1117
+ const perfMetrics = this.qePatternStore.getPerformanceMetrics?.();
1118
+ const metrics = {
1119
+ enabled: true,
1120
+ patternCount: stats?.count ?? 0,
1121
+ implementation: stats?.implementation ?? 'fallback',
1122
+ };
1123
+ if (perfMetrics) {
1124
+ metrics.performance = {
1125
+ avgSearchTime: perfMetrics.avgSearchTime,
1126
+ p50SearchTime: perfMetrics.p50SearchTime,
1127
+ p99SearchTime: perfMetrics.p99SearchTime,
1128
+ estimatedQPS: perfMetrics.estimatedQPS,
1129
+ };
1130
+ }
1131
+ // GNN learning metrics if available
1132
+ if (this.qePatternStore.isGNNEnabled?.()) {
1133
+ const gnnMetrics = this.qePatternStore.getGNNMetrics?.();
1134
+ if (gnnMetrics) {
1135
+ metrics.gnnLearning = {
1136
+ enabled: gnnMetrics.enabled,
1137
+ cacheHitRate: gnnMetrics.cacheHitRate,
1138
+ patternsLearned: gnnMetrics.patternsLearned,
1139
+ };
1140
+ }
1141
+ }
1142
+ return metrics;
1143
+ }
1144
+ catch (error) {
1145
+ console.warn(`[${this.agentId.id}] Failed to get pattern metrics:`, error.message);
1146
+ return null;
1147
+ }
1148
+ }
1149
+ /**
1150
+ * Sync local patterns to remote RuVector service
1151
+ * Only applicable when RuVector Docker is enabled
1152
+ */
1153
+ async syncPatternsToRemote(options) {
1154
+ if (!this.hasPatternStore() || !this.qePatternStore.syncToRemote) {
1155
+ return { synced: 0, failed: 0, duration: 0 };
1156
+ }
1157
+ try {
1158
+ const result = await this.qePatternStore.syncToRemote(options);
1159
+ console.log(`[${this.agentId.id}] Synced ${result.synced} patterns to remote (${result.duration}ms)`);
1160
+ return result;
1161
+ }
1162
+ catch (error) {
1163
+ console.warn(`[${this.agentId.id}] Pattern sync failed:`, error.message);
1164
+ return { synced: 0, failed: 0, duration: 0 };
1165
+ }
1166
+ }
1167
+ /**
1168
+ * Force GNN learning consolidation on remote service
1169
+ * Triggers LoRA parameter updates with EWC protection
1170
+ */
1171
+ async forcePatternLearning() {
1172
+ if (!this.hasPatternStore() || !this.qePatternStore.forceGNNLearn) {
1173
+ return { success: false, patternsConsolidated: 0, duration: 0 };
1174
+ }
1175
+ try {
1176
+ const result = await this.qePatternStore.forceGNNLearn({
1177
+ domain: this.agentId.type,
1178
+ });
1179
+ return {
1180
+ success: result.success,
1181
+ patternsConsolidated: result.patternsConsolidated,
1182
+ duration: result.duration,
1183
+ };
1184
+ }
1185
+ catch (error) {
1186
+ console.warn(`[${this.agentId.id}] Force learning failed:`, error.message);
1187
+ return { success: false, patternsConsolidated: 0, duration: 0 };
1188
+ }
1189
+ }
1190
+ /**
1191
+ * Cleanup pattern store resources on agent termination
1192
+ */
1193
+ async cleanupPatternStore() {
1194
+ if (!this.patternStoreInitialized || !this.qePatternStore) {
1195
+ return;
1196
+ }
1197
+ try {
1198
+ // Sync pending patterns before shutdown
1199
+ if (this.qePatternConfig.autoSync && this.qePatternStore.syncToRemote) {
1200
+ await this.qePatternStore.syncToRemote({ force: true });
1201
+ }
1202
+ // Shutdown and release resources
1203
+ if (this.qePatternStore.shutdown) {
1204
+ await this.qePatternStore.shutdown();
1205
+ }
1206
+ console.log(`[${this.agentId.id}] Pattern Store cleanup complete`);
1207
+ }
1208
+ catch (error) {
1209
+ console.warn(`[${this.agentId.id}] Pattern Store cleanup error:`, error.message);
1210
+ }
1211
+ this.patternStoreInitialized = false;
1212
+ this.qePatternStore = undefined;
1213
+ }
766
1214
  /**
767
1215
  * Cleanup LLM resources on agent termination
768
1216
  */