claude-flow 2.0.0-alpha.66 → 2.0.0-alpha.68

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 (112) hide show
  1. package/.claude/cache/agent-pool.json +33 -0
  2. package/.claude/cache/memory-optimization.json +19 -0
  3. package/.claude/cache/neural-optimization.json +25 -0
  4. package/.claude/cache/optimized-hooks.json +19 -0
  5. package/.claude/cache/parallel-processing.json +26 -0
  6. package/.claude/optimized-settings.json +270 -0
  7. package/.claude/settings-backup.json +186 -0
  8. package/.claude/settings-enhanced.json +278 -0
  9. package/.claude/settings-fixed.json +186 -0
  10. package/.claude/settings.json +105 -8
  11. package/CHANGELOG.md +38 -0
  12. package/bin/claude-flow +1 -1
  13. package/dist/cli/simple-commands/hive-mind.js +1 -1
  14. package/dist/cli/simple-commands/hive-mind.js.map +1 -1
  15. package/dist/cli/simple-commands/hooks.js +6 -4
  16. package/dist/cli/simple-commands/hooks.js.map +1 -1
  17. package/dist/providers/anthropic-provider.d.ts +27 -0
  18. package/dist/providers/anthropic-provider.d.ts.map +1 -0
  19. package/dist/providers/anthropic-provider.js +247 -0
  20. package/dist/providers/anthropic-provider.js.map +1 -0
  21. package/dist/providers/base-provider.d.ts +134 -0
  22. package/dist/providers/base-provider.d.ts.map +1 -0
  23. package/dist/providers/base-provider.js +407 -0
  24. package/dist/providers/base-provider.js.map +1 -0
  25. package/dist/providers/cohere-provider.d.ts +28 -0
  26. package/dist/providers/cohere-provider.d.ts.map +1 -0
  27. package/dist/providers/cohere-provider.js +407 -0
  28. package/dist/providers/cohere-provider.js.map +1 -0
  29. package/dist/providers/google-provider.d.ts +23 -0
  30. package/dist/providers/google-provider.d.ts.map +1 -0
  31. package/dist/providers/google-provider.js +362 -0
  32. package/dist/providers/google-provider.js.map +1 -0
  33. package/dist/providers/index.d.ts +14 -0
  34. package/dist/providers/index.d.ts.map +1 -0
  35. package/dist/providers/index.js +18 -0
  36. package/dist/providers/index.js.map +1 -0
  37. package/dist/providers/ollama-provider.d.ts +23 -0
  38. package/dist/providers/ollama-provider.d.ts.map +1 -0
  39. package/dist/providers/ollama-provider.js +374 -0
  40. package/dist/providers/ollama-provider.js.map +1 -0
  41. package/dist/providers/openai-provider.d.ts +23 -0
  42. package/dist/providers/openai-provider.d.ts.map +1 -0
  43. package/dist/providers/openai-provider.js +349 -0
  44. package/dist/providers/openai-provider.js.map +1 -0
  45. package/dist/providers/provider-manager.d.ts +139 -0
  46. package/dist/providers/provider-manager.d.ts.map +1 -0
  47. package/dist/providers/provider-manager.js +513 -0
  48. package/dist/providers/provider-manager.js.map +1 -0
  49. package/dist/providers/types.d.ts +356 -0
  50. package/dist/providers/types.d.ts.map +1 -0
  51. package/dist/providers/types.js +61 -0
  52. package/dist/providers/types.js.map +1 -0
  53. package/dist/providers/utils.d.ts +37 -0
  54. package/dist/providers/utils.d.ts.map +1 -0
  55. package/dist/providers/utils.js +322 -0
  56. package/dist/providers/utils.js.map +1 -0
  57. package/dist/services/agentic-flow-hooks/hook-manager.d.ts +70 -0
  58. package/dist/services/agentic-flow-hooks/hook-manager.d.ts.map +1 -0
  59. package/dist/services/agentic-flow-hooks/hook-manager.js +512 -0
  60. package/dist/services/agentic-flow-hooks/hook-manager.js.map +1 -0
  61. package/dist/services/agentic-flow-hooks/index.d.ts +36 -0
  62. package/dist/services/agentic-flow-hooks/index.d.ts.map +1 -0
  63. package/dist/services/agentic-flow-hooks/index.js +325 -0
  64. package/dist/services/agentic-flow-hooks/index.js.map +1 -0
  65. package/dist/services/agentic-flow-hooks/llm-hooks.d.ts +33 -0
  66. package/dist/services/agentic-flow-hooks/llm-hooks.d.ts.map +1 -0
  67. package/dist/services/agentic-flow-hooks/llm-hooks.js +415 -0
  68. package/dist/services/agentic-flow-hooks/llm-hooks.js.map +1 -0
  69. package/dist/services/agentic-flow-hooks/memory-hooks.d.ts +45 -0
  70. package/dist/services/agentic-flow-hooks/memory-hooks.d.ts.map +1 -0
  71. package/dist/services/agentic-flow-hooks/memory-hooks.js +532 -0
  72. package/dist/services/agentic-flow-hooks/memory-hooks.js.map +1 -0
  73. package/dist/services/agentic-flow-hooks/neural-hooks.d.ts +39 -0
  74. package/dist/services/agentic-flow-hooks/neural-hooks.d.ts.map +1 -0
  75. package/dist/services/agentic-flow-hooks/neural-hooks.js +561 -0
  76. package/dist/services/agentic-flow-hooks/neural-hooks.js.map +1 -0
  77. package/dist/services/agentic-flow-hooks/performance-hooks.d.ts +33 -0
  78. package/dist/services/agentic-flow-hooks/performance-hooks.d.ts.map +1 -0
  79. package/dist/services/agentic-flow-hooks/performance-hooks.js +621 -0
  80. package/dist/services/agentic-flow-hooks/performance-hooks.js.map +1 -0
  81. package/dist/services/agentic-flow-hooks/types.d.ts +379 -0
  82. package/dist/services/agentic-flow-hooks/types.d.ts.map +1 -0
  83. package/dist/services/agentic-flow-hooks/types.js +8 -0
  84. package/dist/services/agentic-flow-hooks/types.js.map +1 -0
  85. package/dist/services/agentic-flow-hooks/workflow-hooks.d.ts +39 -0
  86. package/dist/services/agentic-flow-hooks/workflow-hooks.d.ts.map +1 -0
  87. package/dist/services/agentic-flow-hooks/workflow-hooks.js +742 -0
  88. package/dist/services/agentic-flow-hooks/workflow-hooks.js.map +1 -0
  89. package/package.json +1 -1
  90. package/scripts/optimize-performance.js +400 -0
  91. package/scripts/performance-monitor.js +263 -0
  92. package/src/cli/help-text.js +1 -1
  93. package/src/cli/simple-cli.js +1 -1
  94. package/src/cli/simple-commands/hive-mind.js +1 -1
  95. package/src/providers/anthropic-provider.ts +282 -0
  96. package/src/providers/base-provider.ts +560 -0
  97. package/src/providers/cohere-provider.ts +521 -0
  98. package/src/providers/google-provider.ts +477 -0
  99. package/src/providers/index.ts +21 -0
  100. package/src/providers/ollama-provider.ts +489 -0
  101. package/src/providers/openai-provider.ts +476 -0
  102. package/src/providers/provider-manager.ts +654 -0
  103. package/src/providers/types.ts +531 -0
  104. package/src/providers/utils.ts +376 -0
  105. package/src/services/agentic-flow-hooks/hook-manager.ts +701 -0
  106. package/src/services/agentic-flow-hooks/index.ts +386 -0
  107. package/src/services/agentic-flow-hooks/llm-hooks.ts +557 -0
  108. package/src/services/agentic-flow-hooks/memory-hooks.ts +710 -0
  109. package/src/services/agentic-flow-hooks/neural-hooks.ts +758 -0
  110. package/src/services/agentic-flow-hooks/performance-hooks.ts +827 -0
  111. package/src/services/agentic-flow-hooks/types.ts +503 -0
  112. package/src/services/agentic-flow-hooks/workflow-hooks.ts +1026 -0
@@ -0,0 +1,654 @@
1
+ /**
2
+ * Provider Manager - Central orchestration for multi-LLM providers
3
+ * Handles provider selection, fallback, load balancing, and cost optimization
4
+ */
5
+
6
+ import { EventEmitter } from 'events';
7
+ import { ILogger } from '../core/logger.js';
8
+ import { ConfigManager } from '../config/config-manager.js';
9
+ import {
10
+ ILLMProvider,
11
+ LLMProvider,
12
+ LLMProviderConfig,
13
+ LLMRequest,
14
+ LLMResponse,
15
+ LLMStreamEvent,
16
+ LLMModel,
17
+ FallbackStrategy,
18
+ FallbackRule,
19
+ LoadBalancer,
20
+ ProviderMetrics,
21
+ CostOptimizer,
22
+ CostConstraints,
23
+ OptimizationResult,
24
+ RateLimiter,
25
+ ProviderMonitor,
26
+ CacheConfig,
27
+ LLMProviderError,
28
+ RateLimitError,
29
+ isRateLimitError,
30
+ } from './types.js';
31
+
32
+ // Import providers
33
+ import { AnthropicProvider } from './anthropic-provider.js';
34
+ import { OpenAIProvider } from './openai-provider.js';
35
+ import { GoogleProvider } from './google-provider.js';
36
+ import { CohereProvider } from './cohere-provider.js';
37
+ import { OllamaProvider } from './ollama-provider.js';
38
+
39
+ export interface ProviderManagerConfig {
40
+ providers: Record<LLMProvider, LLMProviderConfig>;
41
+ defaultProvider: LLMProvider;
42
+ fallbackStrategy?: FallbackStrategy;
43
+ loadBalancing?: {
44
+ enabled: boolean;
45
+ strategy: 'round-robin' | 'least-loaded' | 'latency-based' | 'cost-based';
46
+ };
47
+ costOptimization?: {
48
+ enabled: boolean;
49
+ maxCostPerRequest?: number;
50
+ preferredProviders?: LLMProvider[];
51
+ };
52
+ caching?: CacheConfig;
53
+ monitoring?: {
54
+ enabled: boolean;
55
+ metricsInterval: number;
56
+ };
57
+ }
58
+
59
+ export class ProviderManager extends EventEmitter {
60
+ private providers: Map<LLMProvider, ILLMProvider> = new Map();
61
+ private logger: ILogger;
62
+ private config: ProviderManagerConfig;
63
+ private requestCount: Map<LLMProvider, number> = new Map();
64
+ private lastUsed: Map<LLMProvider, Date> = new Map();
65
+ private providerMetrics: Map<LLMProvider, ProviderMetrics[]> = new Map();
66
+ private cache: Map<string, { response: LLMResponse; timestamp: Date }> = new Map();
67
+ private currentProviderIndex = 0;
68
+
69
+ constructor(logger: ILogger, configManager: ConfigManager, config: ProviderManagerConfig) {
70
+ super();
71
+ this.logger = logger;
72
+ this.config = config;
73
+
74
+ // Initialize providers
75
+ this.initializeProviders();
76
+
77
+ // Start monitoring if enabled
78
+ if (config.monitoring?.enabled) {
79
+ this.startMonitoring();
80
+ }
81
+ }
82
+
83
+ /**
84
+ * Initialize all configured providers
85
+ */
86
+ private async initializeProviders(): Promise<void> {
87
+ for (const [providerName, providerConfig] of Object.entries(this.config.providers)) {
88
+ try {
89
+ const provider = await this.createProvider(providerName as LLMProvider, providerConfig);
90
+ if (provider) {
91
+ this.providers.set(providerName as LLMProvider, provider);
92
+ this.requestCount.set(providerName as LLMProvider, 0);
93
+ this.logger.info(`Initialized ${providerName} provider`);
94
+ }
95
+ } catch (error) {
96
+ this.logger.error(`Failed to initialize ${providerName} provider`, error);
97
+ }
98
+ }
99
+
100
+ if (this.providers.size === 0) {
101
+ throw new Error('No providers could be initialized');
102
+ }
103
+ }
104
+
105
+ /**
106
+ * Create a provider instance
107
+ */
108
+ private async createProvider(name: LLMProvider, config: LLMProviderConfig): Promise<ILLMProvider | null> {
109
+ const providerOptions = {
110
+ logger: this.logger,
111
+ config,
112
+ };
113
+
114
+ try {
115
+ let provider: ILLMProvider;
116
+
117
+ switch (name) {
118
+ case 'anthropic':
119
+ provider = new AnthropicProvider(providerOptions);
120
+ break;
121
+ case 'openai':
122
+ provider = new OpenAIProvider(providerOptions);
123
+ break;
124
+ case 'google':
125
+ provider = new GoogleProvider(providerOptions);
126
+ break;
127
+ case 'cohere':
128
+ provider = new CohereProvider(providerOptions);
129
+ break;
130
+ case 'ollama':
131
+ provider = new OllamaProvider(providerOptions);
132
+ break;
133
+ default:
134
+ this.logger.warn(`Unknown provider: ${name}`);
135
+ return null;
136
+ }
137
+
138
+ await provider.initialize();
139
+
140
+ // Set up event listeners
141
+ provider.on('response', (data) => this.handleProviderResponse(name, data));
142
+ provider.on('error', (error) => this.handleProviderError(name, error));
143
+ provider.on('health_check', (result) => this.handleHealthCheck(name, result));
144
+
145
+ return provider;
146
+ } catch (error) {
147
+ this.logger.error(`Failed to create ${name} provider`, error);
148
+ return null;
149
+ }
150
+ }
151
+
152
+ /**
153
+ * Complete a request using the appropriate provider
154
+ */
155
+ async complete(request: LLMRequest): Promise<LLMResponse> {
156
+ // Check cache first
157
+ if (this.config.caching?.enabled) {
158
+ const cached = this.checkCache(request);
159
+ if (cached) {
160
+ this.logger.debug('Returning cached response');
161
+ return cached;
162
+ }
163
+ }
164
+
165
+ // Select provider based on strategy
166
+ const provider = await this.selectProvider(request);
167
+
168
+ try {
169
+ const response = await provider.complete(request);
170
+
171
+ // Cache successful response
172
+ if (this.config.caching?.enabled) {
173
+ this.cacheResponse(request, response);
174
+ }
175
+
176
+ // Update metrics
177
+ this.updateProviderMetrics(provider.name, {
178
+ success: true,
179
+ latency: response.latency || 0,
180
+ cost: response.cost?.totalCost || 0,
181
+ });
182
+
183
+ return response;
184
+ } catch (error) {
185
+ // Handle error and potentially fallback
186
+ return this.handleRequestError(error, request, provider);
187
+ }
188
+ }
189
+
190
+ /**
191
+ * Stream complete a request
192
+ */
193
+ async *streamComplete(request: LLMRequest): AsyncIterable<LLMStreamEvent> {
194
+ const provider = await this.selectProvider(request);
195
+
196
+ try {
197
+ yield* provider.streamComplete(request);
198
+
199
+ // Update metrics
200
+ this.updateProviderMetrics(provider.name, {
201
+ success: true,
202
+ latency: 0, // Will be updated by stream events
203
+ cost: 0, // Will be updated by stream events
204
+ });
205
+ } catch (error) {
206
+ // Handle error and potentially fallback
207
+ const fallbackProvider = await this.getFallbackProvider(error, provider);
208
+ if (fallbackProvider) {
209
+ this.logger.info(`Falling back to ${fallbackProvider.name} provider`);
210
+ yield* fallbackProvider.streamComplete(request);
211
+ } else {
212
+ throw error;
213
+ }
214
+ }
215
+ }
216
+
217
+ /**
218
+ * Select the best provider for a request
219
+ */
220
+ private async selectProvider(request: LLMRequest): Promise<ILLMProvider> {
221
+ // If specific provider requested
222
+ if (request.providerOptions?.preferredProvider) {
223
+ const provider = this.providers.get(request.providerOptions.preferredProvider);
224
+ if (provider && this.isProviderAvailable(provider)) {
225
+ return provider;
226
+ }
227
+ }
228
+
229
+ // Cost optimization
230
+ if (this.config.costOptimization?.enabled && request.costConstraints) {
231
+ const optimized = await this.selectOptimalProvider(request);
232
+ if (optimized) {
233
+ return optimized;
234
+ }
235
+ }
236
+
237
+ // Load balancing
238
+ if (this.config.loadBalancing?.enabled) {
239
+ return this.selectLoadBalancedProvider();
240
+ }
241
+
242
+ // Default provider
243
+ const defaultProvider = this.providers.get(this.config.defaultProvider);
244
+ if (defaultProvider && this.isProviderAvailable(defaultProvider)) {
245
+ return defaultProvider;
246
+ }
247
+
248
+ // First available provider
249
+ for (const provider of this.providers.values()) {
250
+ if (this.isProviderAvailable(provider)) {
251
+ return provider;
252
+ }
253
+ }
254
+
255
+ throw new Error('No available providers');
256
+ }
257
+
258
+ /**
259
+ * Select provider based on cost optimization
260
+ */
261
+ private async selectOptimalProvider(request: LLMRequest): Promise<ILLMProvider | null> {
262
+ let bestProvider: ILLMProvider | null = null;
263
+ let bestCost = Infinity;
264
+
265
+ for (const provider of this.providers.values()) {
266
+ if (!this.isProviderAvailable(provider)) continue;
267
+
268
+ try {
269
+ const estimate = await provider.estimateCost(request);
270
+
271
+ if (estimate.estimatedCost.total < bestCost &&
272
+ (!request.costConstraints?.maxCostPerRequest ||
273
+ estimate.estimatedCost.total <= request.costConstraints.maxCostPerRequest)) {
274
+ bestCost = estimate.estimatedCost.total;
275
+ bestProvider = provider;
276
+ }
277
+ } catch (error) {
278
+ this.logger.warn(`Failed to estimate cost for ${provider.name}`, error);
279
+ }
280
+ }
281
+
282
+ return bestProvider;
283
+ }
284
+
285
+ /**
286
+ * Select provider using load balancing
287
+ */
288
+ private selectLoadBalancedProvider(): ILLMProvider {
289
+ const availableProviders = Array.from(this.providers.values()).filter(p =>
290
+ this.isProviderAvailable(p)
291
+ );
292
+
293
+ if (availableProviders.length === 0) {
294
+ throw new Error('No available providers');
295
+ }
296
+
297
+ switch (this.config.loadBalancing?.strategy) {
298
+ case 'round-robin':
299
+ return this.roundRobinSelect(availableProviders);
300
+
301
+ case 'least-loaded':
302
+ return this.leastLoadedSelect(availableProviders);
303
+
304
+ case 'latency-based':
305
+ return this.latencyBasedSelect(availableProviders);
306
+
307
+ case 'cost-based':
308
+ return this.costBasedSelect(availableProviders);
309
+
310
+ default:
311
+ return availableProviders[0];
312
+ }
313
+ }
314
+
315
+ /**
316
+ * Round-robin provider selection
317
+ */
318
+ private roundRobinSelect(providers: ILLMProvider[]): ILLMProvider {
319
+ const provider = providers[this.currentProviderIndex % providers.length];
320
+ this.currentProviderIndex++;
321
+ return provider;
322
+ }
323
+
324
+ /**
325
+ * Select least loaded provider
326
+ */
327
+ private leastLoadedSelect(providers: ILLMProvider[]): ILLMProvider {
328
+ let minLoad = Infinity;
329
+ let selectedProvider = providers[0];
330
+
331
+ for (const provider of providers) {
332
+ const status = provider.getStatus();
333
+ if (status.currentLoad < minLoad) {
334
+ minLoad = status.currentLoad;
335
+ selectedProvider = provider;
336
+ }
337
+ }
338
+
339
+ return selectedProvider;
340
+ }
341
+
342
+ /**
343
+ * Select provider with lowest latency
344
+ */
345
+ private latencyBasedSelect(providers: ILLMProvider[]): ILLMProvider {
346
+ let minLatency = Infinity;
347
+ let selectedProvider = providers[0];
348
+
349
+ for (const provider of providers) {
350
+ const metrics = this.providerMetrics.get(provider.name);
351
+ if (metrics && metrics.length > 0) {
352
+ const avgLatency = metrics.reduce((sum, m) => sum + m.latency, 0) / metrics.length;
353
+ if (avgLatency < minLatency) {
354
+ minLatency = avgLatency;
355
+ selectedProvider = provider;
356
+ }
357
+ }
358
+ }
359
+
360
+ return selectedProvider;
361
+ }
362
+
363
+ /**
364
+ * Select provider with lowest cost
365
+ */
366
+ private costBasedSelect(providers: ILLMProvider[]): ILLMProvider {
367
+ let minCost = Infinity;
368
+ let selectedProvider = providers[0];
369
+
370
+ for (const provider of providers) {
371
+ const metrics = this.providerMetrics.get(provider.name);
372
+ if (metrics && metrics.length > 0) {
373
+ const avgCost = metrics.reduce((sum, m) => sum + m.cost, 0) / metrics.length;
374
+ if (avgCost < minCost) {
375
+ minCost = avgCost;
376
+ selectedProvider = provider;
377
+ }
378
+ }
379
+ }
380
+
381
+ return selectedProvider;
382
+ }
383
+
384
+ /**
385
+ * Check if provider is available
386
+ */
387
+ private isProviderAvailable(provider: ILLMProvider): boolean {
388
+ const status = provider.getStatus();
389
+ return status.available;
390
+ }
391
+
392
+ /**
393
+ * Handle request error with fallback
394
+ */
395
+ private async handleRequestError(
396
+ error: unknown,
397
+ request: LLMRequest,
398
+ failedProvider: ILLMProvider
399
+ ): Promise<LLMResponse> {
400
+ this.logger.error(`Provider ${failedProvider.name} failed`, error);
401
+
402
+ // Update metrics
403
+ this.updateProviderMetrics(failedProvider.name, {
404
+ success: false,
405
+ latency: 0,
406
+ cost: 0,
407
+ });
408
+
409
+ // Try fallback
410
+ const fallbackProvider = await this.getFallbackProvider(error, failedProvider);
411
+ if (fallbackProvider) {
412
+ this.logger.info(`Falling back to ${fallbackProvider.name} provider`);
413
+ return fallbackProvider.complete(request);
414
+ }
415
+
416
+ throw error;
417
+ }
418
+
419
+ /**
420
+ * Get fallback provider based on error
421
+ */
422
+ private async getFallbackProvider(
423
+ error: unknown,
424
+ failedProvider: ILLMProvider
425
+ ): Promise<ILLMProvider | null> {
426
+ if (!this.config.fallbackStrategy?.enabled) {
427
+ return null;
428
+ }
429
+
430
+ const errorCondition = this.getErrorCondition(error);
431
+ const fallbackRule = this.config.fallbackStrategy.rules.find(rule =>
432
+ rule.condition === errorCondition
433
+ );
434
+
435
+ if (!fallbackRule) {
436
+ return null;
437
+ }
438
+
439
+ // Find first available fallback provider
440
+ for (const providerName of fallbackRule.fallbackProviders) {
441
+ const provider = this.providers.get(providerName);
442
+ if (provider && provider !== failedProvider && this.isProviderAvailable(provider)) {
443
+ return provider;
444
+ }
445
+ }
446
+
447
+ return null;
448
+ }
449
+
450
+ /**
451
+ * Determine error condition for fallback
452
+ */
453
+ private getErrorCondition(error: unknown): FallbackRule['condition'] {
454
+ if (isRateLimitError(error)) {
455
+ return 'rate_limit';
456
+ }
457
+
458
+ if (error instanceof LLMProviderError) {
459
+ if (error.statusCode === 503) {
460
+ return 'unavailable';
461
+ }
462
+ if (error.code === 'TIMEOUT') {
463
+ return 'timeout';
464
+ }
465
+ }
466
+
467
+ return 'error';
468
+ }
469
+
470
+ /**
471
+ * Cache management
472
+ */
473
+ private checkCache(request: LLMRequest): LLMResponse | null {
474
+ const cacheKey = this.generateCacheKey(request);
475
+ const cached = this.cache.get(cacheKey);
476
+
477
+ if (cached) {
478
+ const age = Date.now() - cached.timestamp.getTime();
479
+ if (age < (this.config.caching?.ttl || 3600) * 1000) {
480
+ return cached.response;
481
+ }
482
+ // Remove expired entry
483
+ this.cache.delete(cacheKey);
484
+ }
485
+
486
+ return null;
487
+ }
488
+
489
+ private cacheResponse(request: LLMRequest, response: LLMResponse): void {
490
+ const cacheKey = this.generateCacheKey(request);
491
+ this.cache.set(cacheKey, {
492
+ response,
493
+ timestamp: new Date(),
494
+ });
495
+
496
+ // Cleanup old cache entries
497
+ if (this.cache.size > 1000) {
498
+ const oldestKey = this.cache.keys().next().value;
499
+ this.cache.delete(oldestKey);
500
+ }
501
+ }
502
+
503
+ private generateCacheKey(request: LLMRequest): string {
504
+ return JSON.stringify({
505
+ model: request.model,
506
+ messages: request.messages,
507
+ temperature: request.temperature,
508
+ maxTokens: request.maxTokens,
509
+ });
510
+ }
511
+
512
+ /**
513
+ * Update provider metrics
514
+ */
515
+ private updateProviderMetrics(
516
+ provider: LLMProvider,
517
+ metrics: { success: boolean; latency: number; cost: number }
518
+ ): void {
519
+ const count = this.requestCount.get(provider) || 0;
520
+ this.requestCount.set(provider, count + 1);
521
+ this.lastUsed.set(provider, new Date());
522
+
523
+ const providerMetricsList = this.providerMetrics.get(provider) || [];
524
+ const errorRate = metrics.success ? 0 : 1;
525
+ const successRate = metrics.success ? 1 : 0;
526
+
527
+ providerMetricsList.push({
528
+ provider,
529
+ timestamp: new Date(),
530
+ latency: metrics.latency,
531
+ errorRate,
532
+ successRate,
533
+ load: this.providers.get(provider)?.getStatus().currentLoad || 0,
534
+ cost: metrics.cost,
535
+ availability: this.providers.get(provider)?.getStatus().available ? 1 : 0,
536
+ });
537
+
538
+ // Keep only recent metrics (last 100)
539
+ if (providerMetricsList.length > 100) {
540
+ providerMetricsList.shift();
541
+ }
542
+
543
+ this.providerMetrics.set(provider, providerMetricsList);
544
+ }
545
+
546
+ /**
547
+ * Event handlers
548
+ */
549
+ private handleProviderResponse(provider: LLMProvider, data: any): void {
550
+ this.emit('provider_response', { provider, ...data });
551
+ }
552
+
553
+ private handleProviderError(provider: LLMProvider, error: any): void {
554
+ this.emit('provider_error', { provider, error });
555
+ }
556
+
557
+ private handleHealthCheck(provider: LLMProvider, result: any): void {
558
+ this.emit('health_check', { provider, result });
559
+ }
560
+
561
+ /**
562
+ * Start monitoring
563
+ */
564
+ private startMonitoring(): void {
565
+ setInterval(() => {
566
+ this.emitMetrics();
567
+ }, this.config.monitoring?.metricsInterval || 60000);
568
+ }
569
+
570
+ /**
571
+ * Emit aggregated metrics
572
+ */
573
+ private emitMetrics(): void {
574
+ const metrics = {
575
+ providers: {} as Record<LLMProvider, any>,
576
+ totalRequests: 0,
577
+ totalCost: 0,
578
+ averageLatency: 0,
579
+ };
580
+
581
+ for (const [provider, count] of this.requestCount.entries()) {
582
+ const providerMetricsList = this.providerMetrics.get(provider) || [];
583
+ const avgLatency = providerMetricsList.length > 0
584
+ ? providerMetricsList.reduce((sum, m) => sum + m.latency, 0) / providerMetricsList.length
585
+ : 0;
586
+ const totalCost = providerMetricsList.reduce((sum, m) => sum + m.cost, 0);
587
+
588
+ metrics.providers[provider] = {
589
+ requests: count,
590
+ averageLatency: avgLatency,
591
+ totalCost,
592
+ lastUsed: this.lastUsed.get(provider),
593
+ available: this.providers.get(provider)?.getStatus().available,
594
+ };
595
+
596
+ metrics.totalRequests += count;
597
+ metrics.totalCost += totalCost;
598
+ }
599
+
600
+ if (metrics.totalRequests > 0) {
601
+ let totalLatency = 0;
602
+ let latencyCount = 0;
603
+
604
+ for (const providerMetricsList of this.providerMetrics.values()) {
605
+ for (const metric of providerMetricsList) {
606
+ totalLatency += metric.latency;
607
+ latencyCount++;
608
+ }
609
+ }
610
+
611
+ metrics.averageLatency = latencyCount > 0 ? totalLatency / latencyCount : 0;
612
+ }
613
+
614
+ this.emit('metrics', metrics);
615
+ }
616
+
617
+ /**
618
+ * Get available providers
619
+ */
620
+ getAvailableProviders(): LLMProvider[] {
621
+ return Array.from(this.providers.keys()).filter(name => {
622
+ const provider = this.providers.get(name);
623
+ return provider && this.isProviderAvailable(provider);
624
+ });
625
+ }
626
+
627
+ /**
628
+ * Get provider by name
629
+ */
630
+ getProvider(name: LLMProvider): ILLMProvider | undefined {
631
+ return this.providers.get(name);
632
+ }
633
+
634
+ /**
635
+ * Get all providers
636
+ */
637
+ getAllProviders(): Map<LLMProvider, ILLMProvider> {
638
+ return new Map(this.providers);
639
+ }
640
+
641
+ /**
642
+ * Clean up resources
643
+ */
644
+ destroy(): void {
645
+ for (const provider of this.providers.values()) {
646
+ provider.destroy();
647
+ }
648
+
649
+ this.providers.clear();
650
+ this.cache.clear();
651
+ this.providerMetrics.clear();
652
+ this.removeAllListeners();
653
+ }
654
+ }