@entro314labs/ai-changelog-generator 3.0.5 → 3.2.0

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 (51) hide show
  1. package/CHANGELOG.md +383 -785
  2. package/README.md +30 -3
  3. package/ai-changelog-mcp.sh +0 -0
  4. package/ai-changelog.sh +0 -0
  5. package/bin/ai-changelog-dxt.js +9 -9
  6. package/bin/ai-changelog-mcp.js +19 -17
  7. package/bin/ai-changelog.js +6 -6
  8. package/package.json +84 -52
  9. package/src/ai-changelog-generator.js +83 -81
  10. package/src/application/orchestrators/changelog.orchestrator.js +1040 -296
  11. package/src/application/services/application.service.js +145 -123
  12. package/src/cli.js +76 -57
  13. package/src/domains/ai/ai-analysis.service.js +289 -209
  14. package/src/domains/analysis/analysis.engine.js +253 -193
  15. package/src/domains/changelog/changelog.service.js +1062 -784
  16. package/src/domains/changelog/workspace-changelog.service.js +420 -249
  17. package/src/domains/git/git-repository.analyzer.js +348 -258
  18. package/src/domains/git/git.service.js +132 -112
  19. package/src/infrastructure/cli/cli.controller.js +415 -247
  20. package/src/infrastructure/config/configuration.manager.js +220 -190
  21. package/src/infrastructure/interactive/interactive-staging.service.js +332 -0
  22. package/src/infrastructure/interactive/interactive-workflow.service.js +200 -159
  23. package/src/infrastructure/mcp/mcp-server.service.js +208 -207
  24. package/src/infrastructure/metrics/metrics.collector.js +140 -123
  25. package/src/infrastructure/providers/core/base-provider.js +87 -40
  26. package/src/infrastructure/providers/implementations/anthropic.js +101 -99
  27. package/src/infrastructure/providers/implementations/azure.js +124 -101
  28. package/src/infrastructure/providers/implementations/bedrock.js +136 -126
  29. package/src/infrastructure/providers/implementations/dummy.js +23 -23
  30. package/src/infrastructure/providers/implementations/google.js +123 -114
  31. package/src/infrastructure/providers/implementations/huggingface.js +94 -87
  32. package/src/infrastructure/providers/implementations/lmstudio.js +75 -60
  33. package/src/infrastructure/providers/implementations/mock.js +69 -73
  34. package/src/infrastructure/providers/implementations/ollama.js +89 -66
  35. package/src/infrastructure/providers/implementations/openai.js +88 -89
  36. package/src/infrastructure/providers/implementations/vertex.js +227 -197
  37. package/src/infrastructure/providers/provider-management.service.js +245 -207
  38. package/src/infrastructure/providers/provider-manager.service.js +145 -125
  39. package/src/infrastructure/providers/utils/base-provider-helpers.js +308 -302
  40. package/src/infrastructure/providers/utils/model-config.js +220 -195
  41. package/src/infrastructure/providers/utils/provider-utils.js +105 -100
  42. package/src/infrastructure/validation/commit-message-validation.service.js +556 -0
  43. package/src/shared/constants/colors.js +467 -172
  44. package/src/shared/utils/cli-demo.js +285 -0
  45. package/src/shared/utils/cli-entry-utils.js +257 -249
  46. package/src/shared/utils/cli-ui.js +447 -0
  47. package/src/shared/utils/diff-processor.js +513 -0
  48. package/src/shared/utils/error-classes.js +125 -156
  49. package/src/shared/utils/json-utils.js +93 -89
  50. package/src/shared/utils/utils.js +1299 -775
  51. package/types/index.d.ts +353 -344
@@ -3,64 +3,65 @@
3
3
  * Reduces code duplication by providing common implementations
4
4
  */
5
5
 
6
- import {
7
- selectModelByComplexity,
8
- standardConnectionTest,
9
- createProviderErrorResponse,
10
- createProviderSuccessResponse,
11
- validateModelWithFallbacks,
12
- extractProviderConfig,
13
- buildClientOptions
14
- } from './provider-utils.js';
15
-
16
- import {
17
- MODEL_CONFIGS,
18
- getProviderModelConfig,
19
- getModelCapabilities,
20
- getSuggestedModels,
21
- normalizeModelName,
6
+ import {
22
7
  analyzeCommitComplexity,
23
8
  getBestModelForCapabilities,
24
- getAllHubProviders
25
- } from './model-config.js';
9
+ getModelCapabilities,
10
+ getProviderModelConfig,
11
+ getSuggestedModels,
12
+ MODEL_CONFIGS,
13
+ normalizeModelName,
14
+ } from './model-config.js'
15
+ import {
16
+ buildClientOptions,
17
+ createProviderErrorResponse,
18
+ createProviderSuccessResponse,
19
+ extractProviderConfig,
20
+ selectModelByComplexity,
21
+ standardConnectionTest,
22
+ validateModelWithFallbacks,
23
+ } from './provider-utils.js'
26
24
 
27
25
  // Provider utility functions
28
26
  function isHubProvider(providerName) {
29
- const config = MODEL_CONFIGS[providerName];
30
- return config && config.isHub === true;
27
+ const config = MODEL_CONFIGS[providerName]
28
+ return config && config.isHub === true
31
29
  }
32
30
 
33
31
  function selectHubModel(providerName, complexity = 'standard', availableModels = []) {
34
- const modelConfig = getProviderModelConfig(providerName);
35
- if (!modelConfig) return null;
36
-
37
- const modelKey = {
38
- simple: 'smallModel',
39
- standard: 'standardModel',
40
- medium: 'mediumModel',
41
- complex: 'complexModel'
42
- }[complexity] || 'standardModel';
43
-
44
- const preferredModel = modelConfig[modelKey];
45
-
32
+ const modelConfig = getProviderModelConfig(providerName)
33
+ if (!modelConfig) {
34
+ return null
35
+ }
36
+
37
+ const modelKey =
38
+ {
39
+ simple: 'smallModel',
40
+ standard: 'standardModel',
41
+ medium: 'mediumModel',
42
+ complex: 'complexModel',
43
+ }[complexity] || 'standardModel'
44
+
45
+ const preferredModel = modelConfig[modelKey]
46
+
46
47
  // If we have available models list, check if preferred model exists
47
48
  if (Array.isArray(availableModels) && availableModels.length > 0) {
48
49
  if (availableModels.includes(preferredModel)) {
49
- return preferredModel;
50
+ return preferredModel
50
51
  }
51
-
52
+
52
53
  // Try fallbacks
53
54
  for (const fallback of modelConfig.fallbacks || []) {
54
55
  if (availableModels.includes(fallback)) {
55
- return fallback;
56
+ return fallback
56
57
  }
57
58
  }
58
-
59
+
59
60
  // Return first available model if nothing else matches
60
- return availableModels[0];
61
+ return availableModels[0]
61
62
  }
62
-
63
- return preferredModel;
63
+
64
+ return preferredModel
64
65
  }
65
66
 
66
67
  /**
@@ -72,50 +73,59 @@ export function ModelRecommendationMixin(providerName) {
72
73
  return {
73
74
  getModelRecommendation(commitDetails) {
74
75
  // Get available models for hub providers
75
- const availableModels = this.getAvailableModels ? this.getAvailableModels() : [];
76
- const modelConfig = getProviderModelConfig(providerName, this.config, availableModels);
77
-
76
+ const availableModels = this.getAvailableModels ? this.getAvailableModels() : []
77
+ const modelConfig = getProviderModelConfig(providerName, this.config, availableModels)
78
+
78
79
  // Use enhanced complexity analysis
79
- const complexityAnalysis = analyzeCommitComplexity(commitDetails, providerName);
80
-
80
+ const complexityAnalysis = analyzeCommitComplexity(commitDetails, providerName)
81
+
81
82
  // For hub providers, use specialized selection logic
82
83
  if (isHubProvider(providerName)) {
83
- const selectedModel = selectHubModel(providerName, complexityAnalysis.complexity, availableModels);
84
+ const selectedModel = selectHubModel(
85
+ providerName,
86
+ complexityAnalysis.complexity,
87
+ availableModels
88
+ )
84
89
  return {
85
90
  model: selectedModel,
86
91
  complexity: complexityAnalysis.complexity,
87
92
  reasoning: complexityAnalysis.reasoning,
88
93
  isHubProvider: true,
89
- availableModels: availableModels.length
90
- };
94
+ availableModels: availableModels.length,
95
+ }
91
96
  }
92
-
97
+
93
98
  // Standard provider logic
94
- return selectModelByComplexity(commitDetails, modelConfig);
99
+ return selectModelByComplexity(commitDetails, modelConfig)
95
100
  },
96
-
101
+
97
102
  async selectOptimalModel(commitDetails) {
98
103
  // Enhanced async version with hub awareness
99
104
  if (isHubProvider(providerName)) {
100
105
  // Try to refresh available models for hub providers
101
106
  if (this.refreshAvailableModels) {
102
107
  try {
103
- await this.refreshAvailableModels();
108
+ await this.refreshAvailableModels()
104
109
  } catch (error) {
105
110
  // Continue with cached models if refresh fails
106
- console.warn(`Failed to refresh models for ${providerName}:`, error.message);
111
+ console.warn(`Failed to refresh models for ${providerName}:`, error.message)
107
112
  }
108
113
  }
109
114
  }
110
-
111
- return this.getModelRecommendation(commitDetails);
115
+
116
+ return this.getModelRecommendation(commitDetails)
112
117
  },
113
-
118
+
114
119
  async selectModelForCapabilities(requiredCapabilities = []) {
115
- const availableModels = this.getAvailableModels ? this.getAvailableModels() : [];
116
- return getBestModelForCapabilities(providerName, requiredCapabilities, this.config, availableModels);
117
- }
118
- };
120
+ const availableModels = this.getAvailableModels ? this.getAvailableModels() : []
121
+ return getBestModelForCapabilities(
122
+ providerName,
123
+ requiredCapabilities,
124
+ this.config,
125
+ availableModels
126
+ )
127
+ },
128
+ }
119
129
  }
120
130
 
121
131
  /**
@@ -128,37 +138,33 @@ export function ConnectionTestMixin(providerName) {
128
138
  async testConnection() {
129
139
  if (!this.isAvailable()) {
130
140
  return createProviderErrorResponse(
131
- providerName,
132
- 'connection_test',
141
+ providerName,
142
+ 'connection_test',
133
143
  `${providerName} provider is not configured`,
134
144
  [`Configure ${providerName.toUpperCase()}_API_KEY`]
135
- );
145
+ )
136
146
  }
137
-
138
- const modelConfig = getProviderModelConfig(providerName, this.config);
139
- const defaultModel = normalizeModelName(providerName, modelConfig.standardModel);
140
-
141
- const result = await standardConnectionTest(
142
- this.generateCompletion.bind(this),
143
- defaultModel
144
- );
145
-
147
+
148
+ const modelConfig = getProviderModelConfig(providerName, this.config)
149
+ const defaultModel = normalizeModelName(providerName, modelConfig.standardModel)
150
+
151
+ const result = await standardConnectionTest(this.generateCompletion.bind(this), defaultModel)
152
+
146
153
  if (result.success) {
147
154
  return createProviderSuccessResponse(providerName, {
148
155
  response: result.response,
149
156
  model: result.model,
150
- provider_info: this.getProviderInfo ? this.getProviderInfo() : {}
151
- });
152
- } else {
153
- return createProviderErrorResponse(
154
- providerName,
155
- 'connection_test',
156
- result.error,
157
- modelConfig.fallbacks
158
- );
157
+ provider_info: this.getProviderInfo ? this.getProviderInfo() : {},
158
+ })
159
159
  }
160
- }
161
- };
160
+ return createProviderErrorResponse(
161
+ providerName,
162
+ 'connection_test',
163
+ result.error,
164
+ modelConfig.fallbacks
165
+ )
166
+ },
167
+ }
162
168
  }
163
169
 
164
170
  /**
@@ -175,94 +181,96 @@ export function ModelValidationMixin(providerName) {
175
181
  'model_validation',
176
182
  `${providerName} provider is not configured`,
177
183
  [`Configure ${providerName.toUpperCase()}_API_KEY`]
178
- );
184
+ )
179
185
  }
180
-
181
- const normalizedModel = normalizeModelName(providerName, modelName);
182
- const availableModels = this.getAvailableModels ? this.getAvailableModels() : [];
183
- const fallbacks = getSuggestedModels(providerName, normalizedModel, availableModels);
184
-
186
+
187
+ const normalizedModel = normalizeModelName(providerName, modelName)
188
+ const availableModels = this.getAvailableModels ? this.getAvailableModels() : []
189
+ const fallbacks = getSuggestedModels(providerName, normalizedModel, availableModels)
190
+
185
191
  // For hub providers, check if model is in available list first
186
- if (isHubProvider(providerName) && Array.isArray(availableModels) && availableModels.length > 0) {
187
- if (!availableModels.includes(normalizedModel)) {
188
- return createProviderErrorResponse(
189
- providerName,
190
- 'model_validation',
191
- `Model '${normalizedModel}' not found in available deployments`,
192
- fallbacks
193
- );
194
- }
192
+ if (
193
+ isHubProvider(providerName) &&
194
+ Array.isArray(availableModels) &&
195
+ availableModels.length > 0 &&
196
+ !availableModels.includes(normalizedModel)
197
+ ) {
198
+ return createProviderErrorResponse(
199
+ providerName,
200
+ 'model_validation',
201
+ `Model '${normalizedModel}' not found in available deployments`,
202
+ fallbacks
203
+ )
195
204
  }
196
-
205
+
197
206
  // Use provider-specific model testing if available
198
207
  if (this.testModel) {
199
- return validateModelWithFallbacks(
200
- this.testModel.bind(this),
201
- normalizedModel,
202
- fallbacks
203
- );
208
+ return validateModelWithFallbacks(this.testModel.bind(this), normalizedModel, fallbacks)
204
209
  }
205
-
210
+
206
211
  // Fallback to basic connection test with the model
207
212
  try {
208
213
  const result = await standardConnectionTest(
209
214
  this.generateCompletion.bind(this),
210
215
  normalizedModel
211
- );
212
-
216
+ )
217
+
213
218
  if (result.success) {
214
219
  return createProviderSuccessResponse(providerName, {
215
220
  model: normalizedModel,
216
221
  capabilities: this.getCapabilities(normalizedModel),
217
222
  isHubProvider: isHubProvider(providerName),
218
- availableModels: availableModels.length
219
- });
220
- } else {
221
- return createProviderErrorResponse(
222
- providerName,
223
- 'model_validation',
224
- result.error,
225
- fallbacks
226
- );
223
+ availableModels: availableModels.length,
224
+ })
227
225
  }
226
+ return createProviderErrorResponse(
227
+ providerName,
228
+ 'model_validation',
229
+ result.error,
230
+ fallbacks
231
+ )
228
232
  } catch (error) {
229
233
  return createProviderErrorResponse(
230
234
  providerName,
231
235
  'model_validation',
232
236
  error.message,
233
237
  fallbacks
234
- );
238
+ )
235
239
  }
236
- }
237
- };
240
+ },
241
+ }
238
242
  }
239
243
 
240
244
  /**
241
245
  * Mixin that provides standard capabilities lookup
242
- * @param {string} providerName - Name of the provider
246
+ * @param {string} providerName - Name of the provider
243
247
  * @returns {Object} Mixin methods
244
248
  */
245
249
  export function CapabilitiesMixin(providerName) {
246
250
  return {
247
251
  getCapabilities(modelName) {
248
- const availableModels = this.getAvailableModels ? this.getAvailableModels() : [];
249
- const modelConfig = getProviderModelConfig(providerName, this.config, availableModels);
250
-
251
- const model = modelName ||
252
- this.config.AI_MODEL ||
252
+ const availableModels = this.getAvailableModels ? this.getAvailableModels() : []
253
+ const modelConfig = getProviderModelConfig(providerName, this.config, availableModels)
254
+
255
+ const model =
256
+ modelName ||
257
+ this.config.AI_MODEL ||
253
258
  this.config[`${providerName.toUpperCase()}_MODEL`] ||
254
- modelConfig.standardModel;
255
-
256
- const normalizedModel = normalizeModelName(providerName, model);
257
- const capabilities = getModelCapabilities(normalizedModel);
258
-
259
+ modelConfig.standardModel
260
+
261
+ const normalizedModel = normalizeModelName(providerName, model)
262
+ const capabilities = getModelCapabilities(normalizedModel)
263
+
259
264
  // Add provider-specific metadata
260
265
  if (isHubProvider(providerName)) {
261
- capabilities.isHubProvider = true;
262
- capabilities.availableInHub = !Array.isArray(availableModels) || availableModels.length === 0 || availableModels.includes(normalizedModel);
266
+ capabilities.isHubProvider = true
267
+ capabilities.availableInHub =
268
+ !Array.isArray(availableModels) ||
269
+ availableModels.length === 0 ||
270
+ availableModels.includes(normalizedModel)
263
271
  }
264
-
265
- return capabilities;
272
+
273
+ return capabilities
266
274
  },
267
275
 
268
276
  /**
@@ -278,67 +286,67 @@ export function CapabilitiesMixin(providerName) {
278
286
  capabilities: {},
279
287
  errors: [],
280
288
  performance: {},
281
- tested_at: new Date().toISOString()
282
- };
289
+ tested_at: new Date().toISOString(),
290
+ }
283
291
 
284
292
  try {
285
293
  // Test 1: Basic availability
286
- results.available = this.isAvailable();
294
+ results.available = this.isAvailable()
287
295
  if (!results.available) {
288
- results.errors.push('Provider not available - check configuration');
289
- return results;
296
+ results.errors.push('Provider not available - check configuration')
297
+ return results
290
298
  }
291
299
 
292
300
  // Test 2: Connection test
293
301
  if (this.testConnection) {
294
- const startTime = Date.now();
302
+ const startTime = Date.now()
295
303
  try {
296
- await this.testConnection();
297
- results.connection = true;
298
- results.performance.connectionTime = Date.now() - startTime;
304
+ await this.testConnection()
305
+ results.connection = true
306
+ results.performance.connectionTime = Date.now() - startTime
299
307
  } catch (error) {
300
- results.errors.push(`Connection test failed: ${error.message}`);
308
+ results.errors.push(`Connection test failed: ${error.message}`)
301
309
  }
302
310
  }
303
311
 
304
312
  // Test 3: Model access test
305
313
  if (options.testModel !== false) {
306
314
  try {
307
- const testStartTime = Date.now();
315
+ const testStartTime = Date.now()
308
316
  const testResponse = await ProviderResponseHandler.executeWithErrorHandling(
309
317
  this,
310
318
  'test_model_access',
311
319
  async () => {
312
- return await this.generateCompletion([
313
- { role: 'user', content: 'Test message - respond with "OK"' }
314
- ], { max_tokens: 10 });
320
+ return await this.generateCompletion(
321
+ [{ role: 'user', content: 'Test message - respond with "OK"' }],
322
+ { max_tokens: 10 }
323
+ )
315
324
  }
316
- );
325
+ )
317
326
 
318
327
  if (testResponse && !testResponse.error) {
319
- results.modelAccess = true;
320
- results.performance.modelResponseTime = Date.now() - testStartTime;
321
- results.performance.tokensGenerated = testResponse.tokens || 0;
328
+ results.modelAccess = true
329
+ results.performance.modelResponseTime = Date.now() - testStartTime
330
+ results.performance.tokensGenerated = testResponse.tokens || 0
322
331
  } else {
323
- results.errors.push(`Model test failed: ${testResponse.error || 'Unknown error'}`);
332
+ results.errors.push(`Model test failed: ${testResponse.error || 'Unknown error'}`)
324
333
  }
325
334
  } catch (error) {
326
- results.errors.push(`Model access test failed: ${error.message}`);
335
+ results.errors.push(`Model access test failed: ${error.message}`)
327
336
  }
328
337
  }
329
338
 
330
339
  // Test 4: Get detailed capabilities
331
340
  try {
332
- results.capabilities = this.getCapabilities(options.model);
341
+ results.capabilities = this.getCapabilities(options.model)
333
342
  } catch (error) {
334
- results.errors.push(`Capabilities detection failed: ${error.message}`);
343
+ results.errors.push(`Capabilities detection failed: ${error.message}`)
335
344
  }
336
-
337
345
  } catch (error) {
338
- results.errors.push(`Capability testing failed: ${error.message}`);
346
+ results.errors.push(`Capability testing failed: ${error.message}`)
339
347
  }
340
348
 
341
- return results;
349
+ return results
342
350
  },
343
351
 
344
352
  /**
@@ -350,61 +358,70 @@ export function CapabilitiesMixin(providerName) {
350
358
  status: 'unknown',
351
359
  available: false,
352
360
  configured: false,
353
- timestamp: new Date().toISOString()
354
- };
361
+ timestamp: new Date().toISOString(),
362
+ }
355
363
 
356
364
  try {
357
- health.available = this.isAvailable();
358
- health.configured = this.getName && this.config;
359
-
365
+ health.available = this.isAvailable()
366
+ health.configured = this.getName && this.config
367
+
360
368
  if (health.available && health.configured) {
361
- health.status = 'healthy';
369
+ health.status = 'healthy'
362
370
  } else if (health.configured) {
363
- health.status = 'configured_but_unavailable';
371
+ health.status = 'configured_but_unavailable'
364
372
  } else {
365
- health.status = 'not_configured';
373
+ health.status = 'not_configured'
366
374
  }
367
375
  } catch (error) {
368
- health.status = 'error';
369
- health.error = error.message;
376
+ health.status = 'error'
377
+ health.error = error.message
370
378
  }
371
379
 
372
- return health;
380
+ return health
373
381
  },
374
-
382
+
375
383
  getSimilarModels(modelName, providedAvailableModels = []) {
376
384
  // Use provider's available models if not provided
377
- const availableModels = providedAvailableModels.length > 0 ?
378
- providedAvailableModels :
379
- (this.getAvailableModels ? this.getAvailableModels() : []);
380
-
385
+ const availableModels =
386
+ providedAvailableModels.length > 0
387
+ ? providedAvailableModels
388
+ : this.getAvailableModels
389
+ ? this.getAvailableModels()
390
+ : []
391
+
381
392
  // Enhanced similarity matching for hub providers
382
- if (isHubProvider(providerName) && Array.isArray(availableModels) && availableModels.length > 0) {
383
- const modelFamily = modelName.split('-')[0] || modelName.split('.')[0]; // e.g., 'gpt', 'claude', 'gemini', 'anthropic'
393
+ if (
394
+ isHubProvider(providerName) &&
395
+ Array.isArray(availableModels) &&
396
+ availableModels.length > 0
397
+ ) {
398
+ const modelFamily = modelName.split('-')[0] || modelName.split('.')[0] // e.g., 'gpt', 'claude', 'gemini', 'anthropic'
384
399
  const familyModels = availableModels
385
- .filter(m => m.includes(modelFamily) && m !== modelName)
386
- .slice(0, 3);
387
-
400
+ .filter((m) => m.includes(modelFamily) && m !== modelName)
401
+ .slice(0, 3)
402
+
388
403
  // If no family matches, get models from the same capability tier
389
404
  if (familyModels.length === 0) {
390
- const modelCapabilities = getModelCapabilities(modelName);
405
+ const modelCapabilities = getModelCapabilities(modelName)
391
406
  const similarCapabilityModels = availableModels
392
- .filter(m => {
393
- const caps = getModelCapabilities(m);
394
- return caps.reasoning === modelCapabilities.reasoning &&
395
- caps.large_context === modelCapabilities.large_context;
407
+ .filter((m) => {
408
+ const caps = getModelCapabilities(m)
409
+ return (
410
+ caps.reasoning === modelCapabilities.reasoning &&
411
+ caps.large_context === modelCapabilities.large_context
412
+ )
396
413
  })
397
- .slice(0, 3);
398
- return similarCapabilityModels;
414
+ .slice(0, 3)
415
+ return similarCapabilityModels
399
416
  }
400
-
401
- return familyModels;
417
+
418
+ return familyModels
402
419
  }
403
-
420
+
404
421
  // Standard provider logic with enhanced suggestions
405
- return getSuggestedModels(providerName, modelName, availableModels);
406
- }
407
- };
422
+ return getSuggestedModels(providerName, modelName, availableModels)
423
+ },
424
+ }
408
425
  }
409
426
 
410
427
  /**
@@ -416,53 +433,49 @@ export function CapabilitiesMixin(providerName) {
416
433
  export function ConfigurationMixin(providerName, defaults = {}) {
417
434
  return {
418
435
  getProviderConfig() {
419
- return extractProviderConfig(
420
- this.config,
421
- providerName.toUpperCase(),
422
- defaults
423
- );
436
+ return extractProviderConfig(this.config, providerName.toUpperCase(), defaults)
424
437
  },
425
-
438
+
426
439
  getProviderModelConfig() {
427
- const availableModels = this.getAvailableModels ? this.getAvailableModels() : [];
428
- return getProviderModelConfig(providerName, this.config, availableModels);
440
+ const availableModels = this.getAvailableModels ? this.getAvailableModels() : []
441
+ return getProviderModelConfig(providerName, this.config, availableModels)
429
442
  },
430
-
443
+
431
444
  buildClientOptions(extraDefaults = {}) {
432
- const providerConfig = this.getProviderConfig();
433
- return buildClientOptions(providerConfig, { ...defaults, ...extraDefaults });
445
+ const providerConfig = this.getProviderConfig()
446
+ return buildClientOptions(providerConfig, { ...defaults, ...extraDefaults })
434
447
  },
435
-
448
+
436
449
  getProviderInfo() {
437
- const providerConfig = this.getProviderConfig();
438
- const availableModels = this.getAvailableModels ? this.getAvailableModels() : [];
439
- const modelConfig = getProviderModelConfig(providerName, this.config, availableModels);
440
-
450
+ const providerConfig = this.getProviderConfig()
451
+ const availableModels = this.getAvailableModels ? this.getAvailableModels() : []
452
+ const modelConfig = getProviderModelConfig(providerName, this.config, availableModels)
453
+
441
454
  const info = {
442
455
  name: providerName,
443
456
  configured: this.isAvailable(),
444
- config_keys: Object.keys(providerConfig).filter(k => providerConfig[k]),
457
+ config_keys: Object.keys(providerConfig).filter((k) => providerConfig[k]),
445
458
  default_model: modelConfig.standardModel || 'unknown',
446
- isHub: isHubProvider(providerName)
447
- };
448
-
459
+ isHub: isHubProvider(providerName),
460
+ }
461
+
449
462
  // Add hub-specific information
450
463
  if (isHubProvider(providerName)) {
451
464
  info.hubInfo = {
452
465
  availableModels: availableModels.length,
453
466
  supportedProviders: modelConfig.hubInfo?.supportedProviders || [],
454
467
  defaultProvider: modelConfig.hubInfo?.defaultProvider,
455
- canDetectDeployments: !!(this.getAvailableModels || this.refreshAvailableModels)
456
- };
457
-
468
+ canDetectDeployments: !!(this.getAvailableModels || this.refreshAvailableModels),
469
+ }
470
+
458
471
  if (availableModels.length > 0) {
459
- info.hubInfo.sampleModels = availableModels.slice(0, 3);
472
+ info.hubInfo.sampleModels = availableModels.slice(0, 3)
460
473
  }
461
474
  }
462
-
463
- return info;
464
- }
465
- };
475
+
476
+ return info
477
+ },
478
+ }
466
479
  }
467
480
 
468
481
  /**
@@ -481,13 +494,13 @@ export class ProviderResponseHandler {
481
494
  static async executeWithErrorHandling(provider, operation, operationFn, context = {}) {
482
495
  // Check availability first
483
496
  if (!provider.isAvailable()) {
484
- return this.createUnavailableResponse(provider.getName(), operation);
497
+ return ProviderResponseHandler.createUnavailableResponse(provider.getName(), operation)
485
498
  }
486
499
 
487
500
  try {
488
- return await operationFn();
501
+ return await operationFn()
489
502
  } catch (error) {
490
- return provider.handleProviderError(error, operation, context);
503
+ return provider.handleProviderError(error, operation, context)
491
504
  }
492
505
  }
493
506
 
@@ -503,7 +516,7 @@ export class ProviderResponseHandler {
503
516
  operation,
504
517
  `${providerName} provider is not configured`,
505
518
  [`Configure ${providerName.toUpperCase()}_API_KEY and other required settings`]
506
- );
519
+ )
507
520
  }
508
521
 
509
522
  /**
@@ -513,16 +526,21 @@ export class ProviderResponseHandler {
513
526
  * @returns {Promise<Array>} Array of results
514
527
  */
515
528
  static async executeMultiple(provider, operations) {
516
- const results = [];
529
+ const results = []
517
530
  for (const op of operations) {
518
- const result = await this.executeWithErrorHandling(provider, op.name, op.fn, op.context);
519
- results.push(result);
531
+ const result = await ProviderResponseHandler.executeWithErrorHandling(
532
+ provider,
533
+ op.name,
534
+ op.fn,
535
+ op.context
536
+ )
537
+ results.push(result)
520
538
  // Stop on first error if any operation fails
521
539
  if (result.error) {
522
- break;
540
+ break
523
541
  }
524
542
  }
525
- return results;
543
+ return results
526
544
  }
527
545
  }
528
546
 
@@ -536,59 +554,49 @@ export function ErrorHandlingMixin(providerName) {
536
554
  handleProviderError(error, operation, context = {}) {
537
555
  // Common error patterns and their standardized responses
538
556
  if (error.message.includes('API key') || error.message.includes('401')) {
539
- return createProviderErrorResponse(
540
- providerName,
541
- operation,
542
- 'Invalid or missing API key',
543
- [`Check ${providerName.toUpperCase()}_API_KEY configuration`]
544
- );
557
+ return createProviderErrorResponse(providerName, operation, 'Invalid or missing API key', [
558
+ `Check ${providerName.toUpperCase()}_API_KEY configuration`,
559
+ ])
545
560
  }
546
-
561
+
547
562
  if (error.message.includes('model') && error.message.includes('not found')) {
548
- const availableModels = this.getAvailableModels ? this.getAvailableModels() : [];
549
- const modelConfig = getProviderModelConfig(providerName, this.config, availableModels);
550
- const fallbacks = getSuggestedModels(providerName, context.model, availableModels);
551
-
552
- let errorMessage = `Model not available: ${context.model}`;
553
- if (isHubProvider(providerName) && Array.isArray(availableModels) && availableModels.length > 0) {
554
- errorMessage += ` (Available models: ${availableModels.length})`;
563
+ const availableModels = this.getAvailableModels ? this.getAvailableModels() : []
564
+ const _modelConfig = getProviderModelConfig(providerName, this.config, availableModels)
565
+ const fallbacks = getSuggestedModels(providerName, context.model, availableModels)
566
+
567
+ let errorMessage = `Model not available: ${context.model}`
568
+ if (
569
+ isHubProvider(providerName) &&
570
+ Array.isArray(availableModels) &&
571
+ availableModels.length > 0
572
+ ) {
573
+ errorMessage += ` (Available models: ${availableModels.length})`
555
574
  }
556
-
557
- return createProviderErrorResponse(
558
- providerName,
559
- operation,
560
- errorMessage,
561
- fallbacks
562
- );
575
+
576
+ return createProviderErrorResponse(providerName, operation, errorMessage, fallbacks)
563
577
  }
564
-
578
+
565
579
  if (error.message.includes('rate limit') || error.message.includes('429')) {
566
- return createProviderErrorResponse(
567
- providerName,
568
- operation,
569
- 'Rate limit exceeded',
570
- ['Wait before retrying', 'Consider upgrading API plan']
571
- );
580
+ return createProviderErrorResponse(providerName, operation, 'Rate limit exceeded', [
581
+ 'Wait before retrying',
582
+ 'Consider upgrading API plan',
583
+ ])
572
584
  }
573
-
585
+
574
586
  if (error.message.includes('timeout')) {
575
- return createProviderErrorResponse(
576
- providerName,
577
- operation,
578
- 'Request timeout',
579
- ['Increase timeout setting', 'Try again later']
580
- );
587
+ return createProviderErrorResponse(providerName, operation, 'Request timeout', [
588
+ 'Increase timeout setting',
589
+ 'Try again later',
590
+ ])
581
591
  }
582
-
592
+
583
593
  // Generic error response
584
- return createProviderErrorResponse(
585
- providerName,
586
- operation,
587
- error.message,
588
- ['Check provider configuration', 'Verify network connectivity']
589
- );
590
- }
591
- };
594
+ return createProviderErrorResponse(providerName, operation, error.message, [
595
+ 'Check provider configuration',
596
+ 'Verify network connectivity',
597
+ ])
598
+ },
599
+ }
592
600
  }
593
601
 
594
602
  /**
@@ -605,18 +613,18 @@ export function applyMixins(ProviderClass, providerName, mixins = []) {
605
613
  ConnectionTestMixin,
606
614
  ModelValidationMixin,
607
615
  CapabilitiesMixin,
608
- ErrorHandlingMixin
609
- ];
610
-
611
- const allMixins = [...defaultMixins, ...mixins];
612
-
616
+ ErrorHandlingMixin,
617
+ ]
618
+
619
+ const allMixins = [...defaultMixins, ...mixins]
620
+
613
621
  // Apply each mixin to the prototype
614
- allMixins.forEach(mixinFn => {
615
- const methods = mixinFn(providerName);
616
- Object.assign(ProviderClass.prototype, methods);
617
- });
618
-
619
- return ProviderClass;
622
+ allMixins.forEach((mixinFn) => {
623
+ const methods = mixinFn(providerName)
624
+ Object.assign(ProviderClass.prototype, methods)
625
+ })
626
+
627
+ return ProviderClass
620
628
  }
621
629
 
622
630
  /**
@@ -626,35 +634,33 @@ export function applyMixins(ProviderClass, providerName, mixins = []) {
626
634
  * @returns {Function} Base provider class with mixins applied
627
635
  */
628
636
  export function createEnhancedProvider(providerName, options = {}) {
629
- const { mixins = [] } = options;
630
-
637
+ const { mixins = [] } = options
638
+
631
639
  class EnhancedProvider {
632
640
  constructor(config) {
633
- this.config = config;
634
- this.providerName = providerName;
635
-
641
+ this.config = config
642
+ this.providerName = providerName
643
+
636
644
  // Initialize provider-specific client if available method exists
637
- if (this.initializeClient) {
638
- if (this.isAvailable()) {
639
- this.initializeClient();
640
- }
645
+ if (this.initializeClient && this.isAvailable()) {
646
+ this.initializeClient()
641
647
  }
642
648
  }
643
-
649
+
644
650
  getName() {
645
- return providerName;
651
+ return providerName
646
652
  }
647
-
653
+
648
654
  // These methods should be implemented by the specific provider
649
655
  isAvailable() {
650
- throw new Error('isAvailable() must be implemented by the provider');
656
+ throw new Error('isAvailable() must be implemented by the provider')
651
657
  }
652
-
658
+
653
659
  async generateCompletion() {
654
- throw new Error('generateCompletion() must be implemented by the provider');
660
+ throw new Error('generateCompletion() must be implemented by the provider')
655
661
  }
656
662
  }
657
-
663
+
658
664
  // Apply all mixins
659
- return applyMixins(EnhancedProvider, providerName, mixins);
660
- }
665
+ return applyMixins(EnhancedProvider, providerName, mixins)
666
+ }