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,560 @@
1
+ /**
2
+ * Abstract Base Provider for LLM integrations
3
+ * Provides common functionality for all LLM providers
4
+ */
5
+
6
+ import { EventEmitter } from 'events';
7
+ import { ILogger } from '../core/logger.js';
8
+ import { circuitBreaker, CircuitBreaker } from '../utils/helpers.js';
9
+ import {
10
+ ILLMProvider,
11
+ LLMProvider,
12
+ LLMProviderConfig,
13
+ LLMRequest,
14
+ LLMResponse,
15
+ LLMStreamEvent,
16
+ LLMModel,
17
+ ModelInfo,
18
+ ProviderCapabilities,
19
+ HealthCheckResult,
20
+ ProviderStatus,
21
+ CostEstimate,
22
+ UsageStats,
23
+ UsagePeriod,
24
+ LLMProviderError,
25
+ RateLimitError,
26
+ ProviderUnavailableError,
27
+ } from './types.js';
28
+
29
+ export interface BaseProviderOptions {
30
+ logger: ILogger;
31
+ config: LLMProviderConfig;
32
+ cacheTTL?: number;
33
+ circuitBreakerOptions?: {
34
+ threshold?: number;
35
+ timeout?: number;
36
+ resetTimeout?: number;
37
+ };
38
+ }
39
+
40
+ export abstract class BaseProvider extends EventEmitter implements ILLMProvider {
41
+ abstract readonly name: LLMProvider;
42
+ abstract readonly capabilities: ProviderCapabilities;
43
+
44
+ protected logger: ILogger;
45
+ protected circuitBreaker: CircuitBreaker;
46
+ protected healthCheckInterval?: NodeJS.Timeout;
47
+ protected lastHealthCheck?: HealthCheckResult;
48
+ protected requestCount = 0;
49
+ protected errorCount = 0;
50
+ protected totalTokens = 0;
51
+ protected totalCost = 0;
52
+ protected requestMetrics: Map<string, any> = new Map();
53
+
54
+ public config: LLMProviderConfig;
55
+
56
+ constructor(options: BaseProviderOptions) {
57
+ super();
58
+ this.logger = options.logger;
59
+ this.config = options.config;
60
+
61
+ // Initialize circuit breaker
62
+ this.circuitBreaker = circuitBreaker(`llm-${this.name}`, {
63
+ threshold: options.circuitBreakerOptions?.threshold || 5,
64
+ timeout: options.circuitBreakerOptions?.timeout || 60000,
65
+ resetTimeout: options.circuitBreakerOptions?.resetTimeout || 300000,
66
+ });
67
+
68
+ // Start health checks if enabled
69
+ if (this.config.enableCaching) {
70
+ this.startHealthChecks();
71
+ }
72
+ }
73
+
74
+ /**
75
+ * Initialize the provider
76
+ */
77
+ async initialize(): Promise<void> {
78
+ this.logger.info(`Initializing ${this.name} provider`, {
79
+ model: this.config.model,
80
+ temperature: this.config.temperature,
81
+ maxTokens: this.config.maxTokens,
82
+ });
83
+
84
+ // Validate configuration
85
+ this.validateConfig();
86
+
87
+ // Provider-specific initialization
88
+ await this.doInitialize();
89
+
90
+ // Perform initial health check
91
+ await this.healthCheck();
92
+ }
93
+
94
+ /**
95
+ * Provider-specific initialization
96
+ */
97
+ protected abstract doInitialize(): Promise<void>;
98
+
99
+ /**
100
+ * Validate provider configuration
101
+ */
102
+ protected validateConfig(): void {
103
+ if (!this.config.model) {
104
+ throw new Error(`Model is required for ${this.name} provider`);
105
+ }
106
+
107
+ if (!this.validateModel(this.config.model)) {
108
+ throw new Error(`Model ${this.config.model} is not supported by ${this.name} provider`);
109
+ }
110
+
111
+ if (this.config.temperature !== undefined) {
112
+ if (this.config.temperature < 0 || this.config.temperature > 2) {
113
+ throw new Error('Temperature must be between 0 and 2');
114
+ }
115
+ }
116
+
117
+ if (this.config.maxTokens !== undefined) {
118
+ const maxAllowed = this.capabilities.maxOutputTokens[this.config.model] || 4096;
119
+ if (this.config.maxTokens > maxAllowed) {
120
+ throw new Error(`Max tokens exceeds limit of ${maxAllowed} for model ${this.config.model}`);
121
+ }
122
+ }
123
+ }
124
+
125
+ /**
126
+ * Complete a request
127
+ */
128
+ async complete(request: LLMRequest): Promise<LLMResponse> {
129
+ const startTime = Date.now();
130
+
131
+ try {
132
+ // Use circuit breaker
133
+ const response = await this.circuitBreaker.execute(async () => {
134
+ return await this.doComplete(request);
135
+ });
136
+
137
+ // Track metrics
138
+ const latency = Date.now() - startTime;
139
+ this.trackRequest(request, response, latency);
140
+
141
+ // Emit events
142
+ this.emit('response', {
143
+ provider: this.name,
144
+ model: response.model,
145
+ latency,
146
+ tokens: response.usage.totalTokens,
147
+ cost: response.cost?.totalCost,
148
+ });
149
+
150
+ return response;
151
+ } catch (error) {
152
+ this.errorCount++;
153
+
154
+ // Transform to provider error
155
+ const providerError = this.transformError(error);
156
+
157
+ // Track error
158
+ this.emit('error', {
159
+ provider: this.name,
160
+ error: providerError,
161
+ request,
162
+ });
163
+
164
+ throw providerError;
165
+ }
166
+ }
167
+
168
+ /**
169
+ * Provider-specific completion implementation
170
+ */
171
+ protected abstract doComplete(request: LLMRequest): Promise<LLMResponse>;
172
+
173
+ /**
174
+ * Stream complete a request
175
+ */
176
+ async *streamComplete(request: LLMRequest): AsyncIterable<LLMStreamEvent> {
177
+ const startTime = Date.now();
178
+ let totalTokens = 0;
179
+ let totalCost = 0;
180
+
181
+ try {
182
+ // Check if streaming is supported
183
+ if (!this.capabilities.supportsStreaming) {
184
+ throw new LLMProviderError(
185
+ 'Streaming not supported',
186
+ 'STREAMING_NOT_SUPPORTED',
187
+ this.name,
188
+ undefined,
189
+ false
190
+ );
191
+ }
192
+
193
+ // Use circuit breaker
194
+ const stream = await this.circuitBreaker.execute(async () => {
195
+ return this.doStreamComplete(request);
196
+ });
197
+
198
+ // Process stream
199
+ for await (const event of stream) {
200
+ if (event.usage) {
201
+ totalTokens = event.usage.totalTokens;
202
+ }
203
+ if (event.cost) {
204
+ totalCost = event.cost.totalCost;
205
+ }
206
+
207
+ yield event;
208
+ }
209
+
210
+ // Track metrics
211
+ const latency = Date.now() - startTime;
212
+ this.trackStreamRequest(request, totalTokens, totalCost, latency);
213
+
214
+ } catch (error) {
215
+ this.errorCount++;
216
+
217
+ // Transform to provider error
218
+ const providerError = this.transformError(error);
219
+
220
+ // Yield error event
221
+ yield {
222
+ type: 'error',
223
+ error: providerError,
224
+ };
225
+
226
+ throw providerError;
227
+ }
228
+ }
229
+
230
+ /**
231
+ * Provider-specific stream completion implementation
232
+ */
233
+ protected abstract doStreamComplete(request: LLMRequest): AsyncIterable<LLMStreamEvent>;
234
+
235
+ /**
236
+ * List available models
237
+ */
238
+ abstract listModels(): Promise<LLMModel[]>;
239
+
240
+ /**
241
+ * Get model information
242
+ */
243
+ abstract getModelInfo(model: LLMModel): Promise<ModelInfo>;
244
+
245
+ /**
246
+ * Validate if a model is supported
247
+ */
248
+ validateModel(model: LLMModel): boolean {
249
+ return this.capabilities.supportedModels.includes(model);
250
+ }
251
+
252
+ /**
253
+ * Perform health check
254
+ */
255
+ async healthCheck(): Promise<HealthCheckResult> {
256
+ const startTime = Date.now();
257
+
258
+ try {
259
+ // Provider-specific health check
260
+ const result = await this.doHealthCheck();
261
+
262
+ this.lastHealthCheck = {
263
+ ...result,
264
+ latency: Date.now() - startTime,
265
+ timestamp: new Date(),
266
+ };
267
+
268
+ this.emit('health_check', this.lastHealthCheck);
269
+ return this.lastHealthCheck;
270
+
271
+ } catch (error) {
272
+ this.lastHealthCheck = {
273
+ healthy: false,
274
+ error: error instanceof Error ? error.message : 'Unknown error',
275
+ latency: Date.now() - startTime,
276
+ timestamp: new Date(),
277
+ };
278
+
279
+ this.emit('health_check', this.lastHealthCheck);
280
+ return this.lastHealthCheck;
281
+ }
282
+ }
283
+
284
+ /**
285
+ * Provider-specific health check implementation
286
+ */
287
+ protected abstract doHealthCheck(): Promise<HealthCheckResult>;
288
+
289
+ /**
290
+ * Get provider status
291
+ */
292
+ getStatus(): ProviderStatus {
293
+ const queueLength = this.requestMetrics.size;
294
+ const errorRate = this.requestCount > 0 ? this.errorCount / this.requestCount : 0;
295
+
296
+ return {
297
+ available: this.lastHealthCheck?.healthy ?? false,
298
+ currentLoad: queueLength / 100, // Normalize to 0-1
299
+ queueLength,
300
+ activeRequests: queueLength,
301
+ rateLimitRemaining: this.getRateLimitRemaining(),
302
+ rateLimitReset: this.getRateLimitReset(),
303
+ };
304
+ }
305
+
306
+ /**
307
+ * Get remaining rate limit (override in provider)
308
+ */
309
+ protected getRateLimitRemaining(): number | undefined {
310
+ return undefined;
311
+ }
312
+
313
+ /**
314
+ * Get rate limit reset time (override in provider)
315
+ */
316
+ protected getRateLimitReset(): Date | undefined {
317
+ return undefined;
318
+ }
319
+
320
+ /**
321
+ * Estimate cost for a request
322
+ */
323
+ async estimateCost(request: LLMRequest): Promise<CostEstimate> {
324
+ const model = request.model || this.config.model;
325
+ const pricing = this.capabilities.pricing?.[model];
326
+
327
+ if (!pricing) {
328
+ return {
329
+ estimatedPromptTokens: 0,
330
+ estimatedCompletionTokens: 0,
331
+ estimatedTotalTokens: 0,
332
+ estimatedCost: {
333
+ prompt: 0,
334
+ completion: 0,
335
+ total: 0,
336
+ currency: 'USD',
337
+ },
338
+ confidence: 0,
339
+ };
340
+ }
341
+
342
+ // Estimate tokens (simple approximation, providers should override)
343
+ const promptTokens = this.estimateTokens(JSON.stringify(request.messages));
344
+ const completionTokens = request.maxTokens || this.config.maxTokens || 1000;
345
+
346
+ const promptCost = (promptTokens / 1000) * pricing.promptCostPer1k;
347
+ const completionCost = (completionTokens / 1000) * pricing.completionCostPer1k;
348
+
349
+ return {
350
+ estimatedPromptTokens: promptTokens,
351
+ estimatedCompletionTokens: completionTokens,
352
+ estimatedTotalTokens: promptTokens + completionTokens,
353
+ estimatedCost: {
354
+ prompt: promptCost,
355
+ completion: completionCost,
356
+ total: promptCost + completionCost,
357
+ currency: pricing.currency,
358
+ },
359
+ confidence: 0.7, // 70% confidence in estimation
360
+ };
361
+ }
362
+
363
+ /**
364
+ * Simple token estimation (4 chars = 1 token approximation)
365
+ */
366
+ protected estimateTokens(text: string): number {
367
+ return Math.ceil(text.length / 4);
368
+ }
369
+
370
+ /**
371
+ * Get usage statistics
372
+ */
373
+ async getUsage(period: UsagePeriod = 'day'): Promise<UsageStats> {
374
+ const now = new Date();
375
+ const start = this.getStartDate(now, period);
376
+
377
+ // In a real implementation, this would query a database
378
+ // For now, return current session stats
379
+ return {
380
+ period: { start, end: now },
381
+ requests: this.requestCount,
382
+ tokens: {
383
+ prompt: Math.floor(this.totalTokens * 0.7), // Estimate
384
+ completion: Math.floor(this.totalTokens * 0.3),
385
+ total: this.totalTokens,
386
+ },
387
+ cost: {
388
+ prompt: this.totalCost * 0.7,
389
+ completion: this.totalCost * 0.3,
390
+ total: this.totalCost,
391
+ currency: 'USD',
392
+ },
393
+ errors: this.errorCount,
394
+ averageLatency: this.calculateAverageLatency(),
395
+ modelBreakdown: {}, // Would need to track per model
396
+ };
397
+ }
398
+
399
+ /**
400
+ * Get start date for period
401
+ */
402
+ private getStartDate(end: Date, period: UsagePeriod): Date {
403
+ const start = new Date(end);
404
+ switch (period) {
405
+ case 'hour':
406
+ start.setHours(start.getHours() - 1);
407
+ break;
408
+ case 'day':
409
+ start.setDate(start.getDate() - 1);
410
+ break;
411
+ case 'week':
412
+ start.setDate(start.getDate() - 7);
413
+ break;
414
+ case 'month':
415
+ start.setMonth(start.getMonth() - 1);
416
+ break;
417
+ case 'all':
418
+ start.setFullYear(2020); // Arbitrary old date
419
+ break;
420
+ }
421
+ return start;
422
+ }
423
+
424
+ /**
425
+ * Calculate average latency
426
+ */
427
+ private calculateAverageLatency(): number {
428
+ if (this.requestMetrics.size === 0) return 0;
429
+
430
+ let totalLatency = 0;
431
+ let count = 0;
432
+
433
+ this.requestMetrics.forEach((metrics) => {
434
+ if (metrics.latency) {
435
+ totalLatency += metrics.latency;
436
+ count++;
437
+ }
438
+ });
439
+
440
+ return count > 0 ? totalLatency / count : 0;
441
+ }
442
+
443
+ /**
444
+ * Track successful request
445
+ */
446
+ protected trackRequest(request: LLMRequest, response: LLMResponse, latency: number): void {
447
+ this.requestCount++;
448
+ this.totalTokens += response.usage.totalTokens;
449
+
450
+ if (response.cost) {
451
+ this.totalCost += response.cost.totalCost;
452
+ }
453
+
454
+ // Store metrics (in memory for now)
455
+ const requestId = response.id;
456
+ this.requestMetrics.set(requestId, {
457
+ timestamp: new Date(),
458
+ model: response.model,
459
+ tokens: response.usage.totalTokens,
460
+ cost: response.cost?.totalCost,
461
+ latency,
462
+ });
463
+
464
+ // Clean up old metrics (keep last 1000)
465
+ if (this.requestMetrics.size > 1000) {
466
+ const oldestKey = this.requestMetrics.keys().next().value;
467
+ this.requestMetrics.delete(oldestKey);
468
+ }
469
+ }
470
+
471
+ /**
472
+ * Track streaming request
473
+ */
474
+ protected trackStreamRequest(
475
+ request: LLMRequest,
476
+ totalTokens: number,
477
+ totalCost: number,
478
+ latency: number
479
+ ): void {
480
+ this.requestCount++;
481
+ this.totalTokens += totalTokens;
482
+ this.totalCost += totalCost;
483
+
484
+ // Store metrics
485
+ const requestId = `stream-${Date.now()}`;
486
+ this.requestMetrics.set(requestId, {
487
+ timestamp: new Date(),
488
+ model: request.model || this.config.model,
489
+ tokens: totalTokens,
490
+ cost: totalCost,
491
+ latency,
492
+ stream: true,
493
+ });
494
+ }
495
+
496
+ /**
497
+ * Transform errors to provider errors
498
+ */
499
+ protected transformError(error: unknown): LLMProviderError {
500
+ if (error instanceof LLMProviderError) {
501
+ return error;
502
+ }
503
+
504
+ if (error instanceof Error) {
505
+ // Check for common error patterns
506
+ if (error.message.includes('rate limit')) {
507
+ return new RateLimitError(error.message, this.name);
508
+ }
509
+
510
+ if (error.message.includes('timeout') || error.message.includes('ETIMEDOUT')) {
511
+ return new LLMProviderError(
512
+ 'Request timed out',
513
+ 'TIMEOUT',
514
+ this.name,
515
+ undefined,
516
+ true
517
+ );
518
+ }
519
+
520
+ if (error.message.includes('ECONNREFUSED') || error.message.includes('fetch failed')) {
521
+ return new ProviderUnavailableError(this.name, { originalError: error.message });
522
+ }
523
+ }
524
+
525
+ return new LLMProviderError(
526
+ error instanceof Error ? error.message : String(error),
527
+ 'UNKNOWN',
528
+ this.name,
529
+ undefined,
530
+ true
531
+ );
532
+ }
533
+
534
+ /**
535
+ * Start periodic health checks
536
+ */
537
+ protected startHealthChecks(): void {
538
+ const interval = this.config.cacheTimeout || 300000; // 5 minutes default
539
+
540
+ this.healthCheckInterval = setInterval(() => {
541
+ this.healthCheck().catch((error) => {
542
+ this.logger.error(`Health check failed for ${this.name}`, error);
543
+ });
544
+ }, interval);
545
+ }
546
+
547
+ /**
548
+ * Clean up resources
549
+ */
550
+ destroy(): void {
551
+ if (this.healthCheckInterval) {
552
+ clearInterval(this.healthCheckInterval);
553
+ }
554
+
555
+ this.requestMetrics.clear();
556
+ this.removeAllListeners();
557
+
558
+ this.logger.info(`${this.name} provider destroyed`);
559
+ }
560
+ }