@sparkleideas/providers 3.5.2-patch.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +574 -0
- package/package.json +70 -0
- package/src/__tests__/provider-integration.test.ts +446 -0
- package/src/__tests__/quick-test.ts +356 -0
- package/src/anthropic-provider.ts +435 -0
- package/src/base-provider.ts +596 -0
- package/src/cohere-provider.ts +423 -0
- package/src/google-provider.ts +429 -0
- package/src/index.ts +40 -0
- package/src/ollama-provider.ts +408 -0
- package/src/openai-provider.ts +490 -0
- package/src/provider-manager.ts +538 -0
- package/src/ruvector-provider.ts +721 -0
- package/src/types.ts +435 -0
|
@@ -0,0 +1,538 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* V3 Provider Manager
|
|
3
|
+
*
|
|
4
|
+
* Orchestrates multiple LLM providers with:
|
|
5
|
+
* - Load balancing (round-robin, latency-based, cost-based)
|
|
6
|
+
* - Automatic failover
|
|
7
|
+
* - Request caching
|
|
8
|
+
* - Cost optimization
|
|
9
|
+
*
|
|
10
|
+
* @module @sparkleideas/providers/provider-manager
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import { EventEmitter } from 'events';
|
|
14
|
+
import {
|
|
15
|
+
ILLMProvider,
|
|
16
|
+
LLMProvider,
|
|
17
|
+
LLMProviderConfig,
|
|
18
|
+
LLMRequest,
|
|
19
|
+
LLMResponse,
|
|
20
|
+
LLMStreamEvent,
|
|
21
|
+
LLMModel,
|
|
22
|
+
ProviderManagerConfig,
|
|
23
|
+
LoadBalancingStrategy,
|
|
24
|
+
HealthCheckResult,
|
|
25
|
+
CostEstimate,
|
|
26
|
+
UsageStats,
|
|
27
|
+
UsagePeriod,
|
|
28
|
+
LLMProviderError,
|
|
29
|
+
isLLMProviderError,
|
|
30
|
+
} from './types.js';
|
|
31
|
+
import { BaseProviderOptions, ILogger, consoleLogger } from './base-provider.js';
|
|
32
|
+
import { AnthropicProvider } from './anthropic-provider.js';
|
|
33
|
+
import { OpenAIProvider } from './openai-provider.js';
|
|
34
|
+
import { GoogleProvider } from './google-provider.js';
|
|
35
|
+
import { CohereProvider } from './cohere-provider.js';
|
|
36
|
+
import { OllamaProvider } from './ollama-provider.js';
|
|
37
|
+
import { RuVectorProvider } from './ruvector-provider.js';
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Cache entry for request caching
|
|
41
|
+
*/
|
|
42
|
+
interface CacheEntry {
|
|
43
|
+
response: LLMResponse;
|
|
44
|
+
timestamp: number;
|
|
45
|
+
hits: number;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Provider metrics for load balancing
|
|
50
|
+
*/
|
|
51
|
+
interface ProviderMetrics {
|
|
52
|
+
latency: number;
|
|
53
|
+
errorRate: number;
|
|
54
|
+
cost: number;
|
|
55
|
+
lastUsed: number;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Provider Manager - Orchestrates multiple LLM providers
|
|
60
|
+
*/
|
|
61
|
+
export class ProviderManager extends EventEmitter {
|
|
62
|
+
private providers: Map<LLMProvider, ILLMProvider> = new Map();
|
|
63
|
+
private cache: Map<string, CacheEntry> = new Map();
|
|
64
|
+
private metrics: Map<LLMProvider, ProviderMetrics> = new Map();
|
|
65
|
+
private roundRobinIndex = 0;
|
|
66
|
+
private logger: ILogger;
|
|
67
|
+
|
|
68
|
+
constructor(
|
|
69
|
+
private config: ProviderManagerConfig,
|
|
70
|
+
logger?: ILogger
|
|
71
|
+
) {
|
|
72
|
+
super();
|
|
73
|
+
this.logger = logger || consoleLogger;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Initialize all configured providers
|
|
78
|
+
*/
|
|
79
|
+
async initialize(): Promise<void> {
|
|
80
|
+
this.logger.info('Initializing provider manager', {
|
|
81
|
+
providerCount: this.config.providers.length,
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
const initPromises = this.config.providers.map(async (providerConfig) => {
|
|
85
|
+
try {
|
|
86
|
+
const provider = this.createProvider(providerConfig);
|
|
87
|
+
await provider.initialize();
|
|
88
|
+
this.providers.set(providerConfig.provider, provider);
|
|
89
|
+
this.metrics.set(providerConfig.provider, {
|
|
90
|
+
latency: 0,
|
|
91
|
+
errorRate: 0,
|
|
92
|
+
cost: 0,
|
|
93
|
+
lastUsed: 0,
|
|
94
|
+
});
|
|
95
|
+
this.logger.info(`Provider ${providerConfig.provider} initialized`);
|
|
96
|
+
} catch (error) {
|
|
97
|
+
this.logger.error(`Failed to initialize ${providerConfig.provider}`, error);
|
|
98
|
+
}
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
await Promise.all(initPromises);
|
|
102
|
+
|
|
103
|
+
this.logger.info('Provider manager initialized', {
|
|
104
|
+
activeProviders: Array.from(this.providers.keys()),
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Create a provider instance
|
|
110
|
+
*/
|
|
111
|
+
private createProvider(config: LLMProviderConfig): ILLMProvider {
|
|
112
|
+
const options: BaseProviderOptions = {
|
|
113
|
+
config,
|
|
114
|
+
logger: this.logger,
|
|
115
|
+
};
|
|
116
|
+
|
|
117
|
+
switch (config.provider) {
|
|
118
|
+
case 'anthropic':
|
|
119
|
+
return new AnthropicProvider(options);
|
|
120
|
+
case 'openai':
|
|
121
|
+
return new OpenAIProvider(options);
|
|
122
|
+
case 'google':
|
|
123
|
+
return new GoogleProvider(options);
|
|
124
|
+
case 'cohere':
|
|
125
|
+
return new CohereProvider(options);
|
|
126
|
+
case 'ollama':
|
|
127
|
+
return new OllamaProvider(options);
|
|
128
|
+
case 'ruvector':
|
|
129
|
+
return new RuVectorProvider(options);
|
|
130
|
+
default:
|
|
131
|
+
throw new Error(`Unknown provider: ${config.provider}`);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Complete a request with automatic provider selection
|
|
137
|
+
*/
|
|
138
|
+
async complete(request: LLMRequest, preferredProvider?: LLMProvider): Promise<LLMResponse> {
|
|
139
|
+
// Check cache first
|
|
140
|
+
if (this.config.cache?.enabled) {
|
|
141
|
+
const cached = this.getCached(request);
|
|
142
|
+
if (cached) {
|
|
143
|
+
this.logger.debug('Cache hit', { requestId: request.requestId });
|
|
144
|
+
return cached;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
// Select provider
|
|
149
|
+
const provider = preferredProvider
|
|
150
|
+
? this.providers.get(preferredProvider)
|
|
151
|
+
: await this.selectProvider(request);
|
|
152
|
+
|
|
153
|
+
if (!provider) {
|
|
154
|
+
throw new Error('No available providers');
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
const startTime = Date.now();
|
|
158
|
+
|
|
159
|
+
try {
|
|
160
|
+
const response = await provider.complete(request);
|
|
161
|
+
this.updateMetrics(provider.name, Date.now() - startTime, false, response.cost?.totalCost || 0);
|
|
162
|
+
|
|
163
|
+
// Cache response
|
|
164
|
+
if (this.config.cache?.enabled) {
|
|
165
|
+
this.setCached(request, response);
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
this.emit('complete', { provider: provider.name, response });
|
|
169
|
+
return response;
|
|
170
|
+
} catch (error) {
|
|
171
|
+
this.updateMetrics(provider.name, Date.now() - startTime, true, 0);
|
|
172
|
+
|
|
173
|
+
// Try fallback
|
|
174
|
+
if (this.config.fallback?.enabled && isLLMProviderError(error)) {
|
|
175
|
+
return this.completWithFallback(request, provider.name, error);
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
throw error;
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* Stream complete with automatic provider selection
|
|
184
|
+
*/
|
|
185
|
+
async *streamComplete(
|
|
186
|
+
request: LLMRequest,
|
|
187
|
+
preferredProvider?: LLMProvider
|
|
188
|
+
): AsyncIterable<LLMStreamEvent> {
|
|
189
|
+
const provider = preferredProvider
|
|
190
|
+
? this.providers.get(preferredProvider)
|
|
191
|
+
: await this.selectProvider(request);
|
|
192
|
+
|
|
193
|
+
if (!provider) {
|
|
194
|
+
throw new Error('No available providers');
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
const startTime = Date.now();
|
|
198
|
+
|
|
199
|
+
try {
|
|
200
|
+
for await (const event of provider.streamComplete(request)) {
|
|
201
|
+
yield event;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
this.updateMetrics(provider.name, Date.now() - startTime, false, 0);
|
|
205
|
+
} catch (error) {
|
|
206
|
+
this.updateMetrics(provider.name, Date.now() - startTime, true, 0);
|
|
207
|
+
throw error;
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
/**
|
|
212
|
+
* Select provider based on load balancing strategy
|
|
213
|
+
*/
|
|
214
|
+
private async selectProvider(request: LLMRequest): Promise<ILLMProvider | undefined> {
|
|
215
|
+
const availableProviders = Array.from(this.providers.values()).filter(
|
|
216
|
+
(p) => p.getStatus().available
|
|
217
|
+
);
|
|
218
|
+
|
|
219
|
+
if (availableProviders.length === 0) {
|
|
220
|
+
// Try to use any provider
|
|
221
|
+
return this.providers.values().next().value;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
const strategy = this.config.loadBalancing?.strategy || 'round-robin';
|
|
225
|
+
|
|
226
|
+
switch (strategy) {
|
|
227
|
+
case 'round-robin':
|
|
228
|
+
return this.selectRoundRobin(availableProviders);
|
|
229
|
+
case 'least-loaded':
|
|
230
|
+
return this.selectLeastLoaded(availableProviders);
|
|
231
|
+
case 'latency-based':
|
|
232
|
+
return this.selectByLatency(availableProviders);
|
|
233
|
+
case 'cost-based':
|
|
234
|
+
return this.selectByCost(availableProviders, request);
|
|
235
|
+
default:
|
|
236
|
+
return availableProviders[0];
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
private selectRoundRobin(providers: ILLMProvider[]): ILLMProvider {
|
|
241
|
+
const provider = providers[this.roundRobinIndex % providers.length];
|
|
242
|
+
this.roundRobinIndex++;
|
|
243
|
+
return provider;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
private selectLeastLoaded(providers: ILLMProvider[]): ILLMProvider {
|
|
247
|
+
return providers.reduce((best, current) =>
|
|
248
|
+
current.getStatus().currentLoad < best.getStatus().currentLoad ? current : best
|
|
249
|
+
);
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
private selectByLatency(providers: ILLMProvider[]): ILLMProvider {
|
|
253
|
+
return providers.reduce((best, current) => {
|
|
254
|
+
const bestMetrics = this.metrics.get(best.name);
|
|
255
|
+
const currentMetrics = this.metrics.get(current.name);
|
|
256
|
+
return (currentMetrics?.latency || Infinity) < (bestMetrics?.latency || Infinity)
|
|
257
|
+
? current
|
|
258
|
+
: best;
|
|
259
|
+
});
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
private async selectByCost(
|
|
263
|
+
providers: ILLMProvider[],
|
|
264
|
+
request: LLMRequest
|
|
265
|
+
): Promise<ILLMProvider> {
|
|
266
|
+
const estimates = await Promise.all(
|
|
267
|
+
providers.map(async (p) => ({
|
|
268
|
+
provider: p,
|
|
269
|
+
cost: (await p.estimateCost(request)).estimatedCost.total,
|
|
270
|
+
}))
|
|
271
|
+
);
|
|
272
|
+
|
|
273
|
+
return estimates.reduce((best, current) =>
|
|
274
|
+
current.cost < best.cost ? current : best
|
|
275
|
+
).provider;
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
/**
|
|
279
|
+
* Complete with fallback on failure
|
|
280
|
+
*/
|
|
281
|
+
private async completWithFallback(
|
|
282
|
+
request: LLMRequest,
|
|
283
|
+
failedProvider: LLMProvider,
|
|
284
|
+
originalError: LLMProviderError
|
|
285
|
+
): Promise<LLMResponse> {
|
|
286
|
+
const maxAttempts = this.config.fallback?.maxAttempts || 2;
|
|
287
|
+
let attempts = 0;
|
|
288
|
+
let lastError = originalError;
|
|
289
|
+
|
|
290
|
+
const remainingProviders = Array.from(this.providers.values()).filter(
|
|
291
|
+
(p) => p.name !== failedProvider
|
|
292
|
+
);
|
|
293
|
+
|
|
294
|
+
for (const provider of remainingProviders) {
|
|
295
|
+
if (attempts >= maxAttempts) break;
|
|
296
|
+
attempts++;
|
|
297
|
+
|
|
298
|
+
this.logger.info(`Attempting fallback to ${provider.name}`, {
|
|
299
|
+
attempt: attempts,
|
|
300
|
+
originalProvider: failedProvider,
|
|
301
|
+
});
|
|
302
|
+
|
|
303
|
+
try {
|
|
304
|
+
const response = await provider.complete(request);
|
|
305
|
+
this.emit('fallback_success', {
|
|
306
|
+
originalProvider: failedProvider,
|
|
307
|
+
fallbackProvider: provider.name,
|
|
308
|
+
attempts,
|
|
309
|
+
});
|
|
310
|
+
return response;
|
|
311
|
+
} catch (error) {
|
|
312
|
+
if (isLLMProviderError(error)) {
|
|
313
|
+
lastError = error;
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
this.emit('fallback_exhausted', {
|
|
319
|
+
originalProvider: failedProvider,
|
|
320
|
+
attempts,
|
|
321
|
+
});
|
|
322
|
+
|
|
323
|
+
throw lastError;
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
/**
|
|
327
|
+
* Update provider metrics
|
|
328
|
+
*/
|
|
329
|
+
private updateMetrics(
|
|
330
|
+
provider: LLMProvider,
|
|
331
|
+
latency: number,
|
|
332
|
+
error: boolean,
|
|
333
|
+
cost: number
|
|
334
|
+
): void {
|
|
335
|
+
const current = this.metrics.get(provider) || {
|
|
336
|
+
latency: 0,
|
|
337
|
+
errorRate: 0,
|
|
338
|
+
cost: 0,
|
|
339
|
+
lastUsed: 0,
|
|
340
|
+
};
|
|
341
|
+
|
|
342
|
+
// Exponential moving average for latency
|
|
343
|
+
const alpha = 0.3;
|
|
344
|
+
const newLatency = current.latency === 0 ? latency : alpha * latency + (1 - alpha) * current.latency;
|
|
345
|
+
|
|
346
|
+
// Update error rate
|
|
347
|
+
const errorWeight = error ? 1 : 0;
|
|
348
|
+
const newErrorRate = alpha * errorWeight + (1 - alpha) * current.errorRate;
|
|
349
|
+
|
|
350
|
+
this.metrics.set(provider, {
|
|
351
|
+
latency: newLatency,
|
|
352
|
+
errorRate: newErrorRate,
|
|
353
|
+
cost: current.cost + cost,
|
|
354
|
+
lastUsed: Date.now(),
|
|
355
|
+
});
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
/**
|
|
359
|
+
* Get cached response
|
|
360
|
+
*/
|
|
361
|
+
private getCached(request: LLMRequest): LLMResponse | undefined {
|
|
362
|
+
const key = this.getCacheKey(request);
|
|
363
|
+
const entry = this.cache.get(key);
|
|
364
|
+
|
|
365
|
+
if (!entry) return undefined;
|
|
366
|
+
|
|
367
|
+
const ttl = this.config.cache?.ttl || 300000;
|
|
368
|
+
if (Date.now() - entry.timestamp > ttl) {
|
|
369
|
+
this.cache.delete(key);
|
|
370
|
+
return undefined;
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
entry.hits++;
|
|
374
|
+
return entry.response;
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
/**
|
|
378
|
+
* Set cached response
|
|
379
|
+
*/
|
|
380
|
+
private setCached(request: LLMRequest, response: LLMResponse): void {
|
|
381
|
+
const key = this.getCacheKey(request);
|
|
382
|
+
|
|
383
|
+
// Enforce max size
|
|
384
|
+
const maxSize = this.config.cache?.maxSize || 1000;
|
|
385
|
+
if (this.cache.size >= maxSize) {
|
|
386
|
+
// Remove oldest entry
|
|
387
|
+
const oldest = Array.from(this.cache.entries()).sort(
|
|
388
|
+
(a, b) => a[1].timestamp - b[1].timestamp
|
|
389
|
+
)[0];
|
|
390
|
+
if (oldest) this.cache.delete(oldest[0]);
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
this.cache.set(key, {
|
|
394
|
+
response,
|
|
395
|
+
timestamp: Date.now(),
|
|
396
|
+
hits: 0,
|
|
397
|
+
});
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
/**
|
|
401
|
+
* Generate cache key
|
|
402
|
+
*/
|
|
403
|
+
private getCacheKey(request: LLMRequest): string {
|
|
404
|
+
return JSON.stringify({
|
|
405
|
+
messages: request.messages,
|
|
406
|
+
model: request.model,
|
|
407
|
+
temperature: request.temperature,
|
|
408
|
+
maxTokens: request.maxTokens,
|
|
409
|
+
});
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
/**
|
|
413
|
+
* Get a specific provider
|
|
414
|
+
*/
|
|
415
|
+
getProvider(name: LLMProvider): ILLMProvider | undefined {
|
|
416
|
+
return this.providers.get(name);
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
/**
|
|
420
|
+
* List all available providers
|
|
421
|
+
*/
|
|
422
|
+
listProviders(): LLMProvider[] {
|
|
423
|
+
return Array.from(this.providers.keys());
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
/**
|
|
427
|
+
* Health check all providers
|
|
428
|
+
*/
|
|
429
|
+
async healthCheck(): Promise<Map<LLMProvider, HealthCheckResult>> {
|
|
430
|
+
const results = new Map<LLMProvider, HealthCheckResult>();
|
|
431
|
+
|
|
432
|
+
await Promise.all(
|
|
433
|
+
Array.from(this.providers.entries()).map(async ([name, provider]) => {
|
|
434
|
+
const result = await provider.healthCheck();
|
|
435
|
+
results.set(name, result);
|
|
436
|
+
})
|
|
437
|
+
);
|
|
438
|
+
|
|
439
|
+
return results;
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
/**
|
|
443
|
+
* Estimate cost across providers
|
|
444
|
+
*/
|
|
445
|
+
async estimateCost(request: LLMRequest): Promise<Map<LLMProvider, CostEstimate>> {
|
|
446
|
+
const estimates = new Map<LLMProvider, CostEstimate>();
|
|
447
|
+
|
|
448
|
+
await Promise.all(
|
|
449
|
+
Array.from(this.providers.entries()).map(async ([name, provider]) => {
|
|
450
|
+
const estimate = await provider.estimateCost(request);
|
|
451
|
+
estimates.set(name, estimate);
|
|
452
|
+
})
|
|
453
|
+
);
|
|
454
|
+
|
|
455
|
+
return estimates;
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
/**
|
|
459
|
+
* Get aggregated usage statistics
|
|
460
|
+
*/
|
|
461
|
+
async getUsage(period: UsagePeriod = 'day'): Promise<UsageStats> {
|
|
462
|
+
let totalRequests = 0;
|
|
463
|
+
let totalTokens = { prompt: 0, completion: 0, total: 0 };
|
|
464
|
+
let totalCost = { prompt: 0, completion: 0, total: 0 };
|
|
465
|
+
let totalErrors = 0;
|
|
466
|
+
let totalLatency = 0;
|
|
467
|
+
let count = 0;
|
|
468
|
+
|
|
469
|
+
for (const provider of this.providers.values()) {
|
|
470
|
+
const usage = await provider.getUsage(period);
|
|
471
|
+
totalRequests += usage.requests;
|
|
472
|
+
totalTokens.prompt += usage.tokens.prompt;
|
|
473
|
+
totalTokens.completion += usage.tokens.completion;
|
|
474
|
+
totalTokens.total += usage.tokens.total;
|
|
475
|
+
totalCost.prompt += usage.cost.prompt;
|
|
476
|
+
totalCost.completion += usage.cost.completion;
|
|
477
|
+
totalCost.total += usage.cost.total;
|
|
478
|
+
totalErrors += usage.errors;
|
|
479
|
+
totalLatency += usage.averageLatency;
|
|
480
|
+
count++;
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
const now = new Date();
|
|
484
|
+
const start = new Date();
|
|
485
|
+
start.setDate(start.getDate() - 1);
|
|
486
|
+
|
|
487
|
+
return {
|
|
488
|
+
period: { start, end: now },
|
|
489
|
+
requests: totalRequests,
|
|
490
|
+
tokens: totalTokens,
|
|
491
|
+
cost: { ...totalCost, currency: 'USD' },
|
|
492
|
+
errors: totalErrors,
|
|
493
|
+
averageLatency: count > 0 ? totalLatency / count : 0,
|
|
494
|
+
modelBreakdown: {},
|
|
495
|
+
};
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
/**
|
|
499
|
+
* Get provider metrics
|
|
500
|
+
*/
|
|
501
|
+
getMetrics(): Map<LLMProvider, ProviderMetrics> {
|
|
502
|
+
return new Map(this.metrics);
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
/**
|
|
506
|
+
* Clear cache
|
|
507
|
+
*/
|
|
508
|
+
clearCache(): void {
|
|
509
|
+
this.cache.clear();
|
|
510
|
+
this.logger.info('Cache cleared');
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
/**
|
|
514
|
+
* Destroy all providers
|
|
515
|
+
*/
|
|
516
|
+
destroy(): void {
|
|
517
|
+
for (const provider of this.providers.values()) {
|
|
518
|
+
provider.destroy();
|
|
519
|
+
}
|
|
520
|
+
this.providers.clear();
|
|
521
|
+
this.cache.clear();
|
|
522
|
+
this.metrics.clear();
|
|
523
|
+
this.removeAllListeners();
|
|
524
|
+
this.logger.info('Provider manager destroyed');
|
|
525
|
+
}
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
/**
|
|
529
|
+
* Create and initialize a provider manager
|
|
530
|
+
*/
|
|
531
|
+
export async function createProviderManager(
|
|
532
|
+
config: ProviderManagerConfig,
|
|
533
|
+
logger?: ILogger
|
|
534
|
+
): Promise<ProviderManager> {
|
|
535
|
+
const manager = new ProviderManager(config, logger);
|
|
536
|
+
await manager.initialize();
|
|
537
|
+
return manager;
|
|
538
|
+
}
|