@entro314labs/ai-changelog-generator 3.2.1 → 3.6.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.
- package/CHANGELOG.md +42 -2
- package/README.md +21 -1
- package/ai-changelog-mcp.sh +0 -0
- package/ai-changelog.sh +0 -0
- package/bin/ai-changelog-dxt.js +6 -3
- package/manifest.json +177 -0
- package/package.json +76 -81
- package/src/ai-changelog-generator.js +5 -4
- package/src/application/orchestrators/changelog.orchestrator.js +19 -203
- package/src/cli.js +16 -5
- package/src/domains/ai/ai-analysis.service.js +2 -0
- package/src/domains/analysis/analysis.engine.js +714 -37
- package/src/domains/changelog/changelog.service.js +623 -32
- package/src/domains/changelog/workspace-changelog.service.js +445 -622
- package/src/domains/git/commit-tagger.js +552 -0
- package/src/domains/git/git-manager.js +357 -0
- package/src/domains/git/git.service.js +865 -16
- package/src/infrastructure/cli/cli.controller.js +14 -9
- package/src/infrastructure/config/configuration.manager.js +25 -11
- package/src/infrastructure/interactive/interactive-workflow.service.js +8 -1
- package/src/infrastructure/mcp/mcp-server.service.js +105 -32
- package/src/infrastructure/providers/core/base-provider.js +1 -1
- package/src/infrastructure/providers/implementations/anthropic.js +16 -173
- package/src/infrastructure/providers/implementations/azure.js +16 -63
- package/src/infrastructure/providers/implementations/dummy.js +13 -16
- package/src/infrastructure/providers/implementations/mock.js +13 -26
- package/src/infrastructure/providers/implementations/ollama.js +12 -4
- package/src/infrastructure/providers/implementations/openai.js +13 -165
- package/src/infrastructure/providers/provider-management.service.js +126 -412
- package/src/infrastructure/providers/utils/base-provider-helpers.js +11 -0
- package/src/shared/utils/cli-ui.js +8 -10
- package/src/shared/utils/diff-processor.js +21 -19
- package/src/shared/utils/error-classes.js +33 -0
- package/src/shared/utils/utils.js +83 -63
- package/types/index.d.ts +61 -68
- package/src/domains/git/git-repository.analyzer.js +0 -678
|
@@ -83,6 +83,11 @@ export class CLIController {
|
|
|
83
83
|
}
|
|
84
84
|
|
|
85
85
|
async ensureConfig() {
|
|
86
|
+
// Skip config setup in test environments to prevent hanging
|
|
87
|
+
if (process.env.NODE_ENV === 'test' || process.env.CI) {
|
|
88
|
+
return
|
|
89
|
+
}
|
|
90
|
+
|
|
86
91
|
const configPath = path.join(process.cwd(), '.env.local')
|
|
87
92
|
try {
|
|
88
93
|
await access(configPath)
|
|
@@ -345,17 +350,17 @@ class ValidateCommand extends BaseCommand {
|
|
|
345
350
|
const validation = await appService.validateConfiguration()
|
|
346
351
|
|
|
347
352
|
if (validation.valid) {
|
|
348
|
-
|
|
353
|
+
EnhancedConsole.success('✅ Configuration is valid')
|
|
349
354
|
} else {
|
|
350
|
-
|
|
355
|
+
EnhancedConsole.error('❌ Configuration has issues:')
|
|
351
356
|
validation.issues.forEach((issue) => {
|
|
352
|
-
|
|
357
|
+
EnhancedConsole.log(` - ${issue}`)
|
|
353
358
|
})
|
|
354
359
|
|
|
355
360
|
if (validation.recommendations.length > 0) {
|
|
356
|
-
|
|
361
|
+
EnhancedConsole.info('\n💡 Recommendations:')
|
|
357
362
|
validation.recommendations.forEach((rec) => {
|
|
358
|
-
|
|
363
|
+
EnhancedConsole.log(` - ${rec}`)
|
|
359
364
|
})
|
|
360
365
|
}
|
|
361
366
|
}
|
|
@@ -554,7 +559,7 @@ class ProvidersCommand extends BaseCommand {
|
|
|
554
559
|
colors.dim('\nUse "ai-changelog providers configure <provider>" to set up a provider')
|
|
555
560
|
)
|
|
556
561
|
} catch (error) {
|
|
557
|
-
|
|
562
|
+
EnhancedConsole.error(`Error listing providers: ${error.message}`)
|
|
558
563
|
}
|
|
559
564
|
}
|
|
560
565
|
|
|
@@ -577,7 +582,7 @@ class ProvidersCommand extends BaseCommand {
|
|
|
577
582
|
)
|
|
578
583
|
}
|
|
579
584
|
} catch (error) {
|
|
580
|
-
|
|
585
|
+
EnhancedConsole.error(`Error switching provider: ${error.message}`)
|
|
581
586
|
}
|
|
582
587
|
}
|
|
583
588
|
|
|
@@ -637,7 +642,7 @@ class ProvidersCommand extends BaseCommand {
|
|
|
637
642
|
console.log(colors.infoMessage('\nAfter adding the configuration, run:'))
|
|
638
643
|
console.log(colors.highlight(`ai-changelog providers validate ${providerName}`))
|
|
639
644
|
} catch (error) {
|
|
640
|
-
|
|
645
|
+
EnhancedConsole.error(`Error configuring provider: ${error.message}`)
|
|
641
646
|
}
|
|
642
647
|
}
|
|
643
648
|
|
|
@@ -676,7 +681,7 @@ class ProvidersCommand extends BaseCommand {
|
|
|
676
681
|
}
|
|
677
682
|
}
|
|
678
683
|
} catch (error) {
|
|
679
|
-
|
|
684
|
+
EnhancedConsole.error(`Error validating provider: ${error.message}`)
|
|
680
685
|
}
|
|
681
686
|
}
|
|
682
687
|
}
|
|
@@ -5,15 +5,7 @@ import process from 'node:process'
|
|
|
5
5
|
import yaml from 'js-yaml'
|
|
6
6
|
|
|
7
7
|
import colors from '../../shared/constants/colors.js'
|
|
8
|
-
|
|
9
|
-
// Model configurations - moved from lib/utils/model-config.js
|
|
10
|
-
const MODEL_CONFIGS = {
|
|
11
|
-
'gpt-4': { maxTokens: 8192, cost: 0.03 },
|
|
12
|
-
'gpt-3.5-turbo': { maxTokens: 4096, cost: 0.002 },
|
|
13
|
-
'claude-3-opus': { maxTokens: 200000, cost: 0.015 },
|
|
14
|
-
'claude-3-sonnet': { maxTokens: 200000, cost: 0.003 },
|
|
15
|
-
'claude-3-haiku': { maxTokens: 200000, cost: 0.00025 },
|
|
16
|
-
}
|
|
8
|
+
import { MODEL_CONFIGS } from '../providers/utils/model-config.js'
|
|
17
9
|
|
|
18
10
|
/**
|
|
19
11
|
* Unified Configuration Manager
|
|
@@ -151,7 +143,7 @@ export class ConfigurationManager {
|
|
|
151
143
|
releaseTagGlobPattern: 'v[0-9]*.[0-9]*.[0-9]*',
|
|
152
144
|
},
|
|
153
145
|
changelog: {
|
|
154
|
-
commitTypes: ['feat', 'fix', 'perf', 'refactor', 'docs'],
|
|
146
|
+
commitTypes: ['feat', 'fix', 'perf', 'refactor', 'docs', 'merge'],
|
|
155
147
|
includeInvalidCommits: true,
|
|
156
148
|
commitIgnoreRegexPattern: '^WIP ',
|
|
157
149
|
headlines: {
|
|
@@ -529,7 +521,21 @@ export class ConfigurationManager {
|
|
|
529
521
|
}
|
|
530
522
|
|
|
531
523
|
getCommitTypes() {
|
|
532
|
-
return
|
|
524
|
+
return (
|
|
525
|
+
this.changelogConfig?.convention?.commitTypes || [
|
|
526
|
+
'feat',
|
|
527
|
+
'fix',
|
|
528
|
+
'docs',
|
|
529
|
+
'style',
|
|
530
|
+
'refactor',
|
|
531
|
+
'perf',
|
|
532
|
+
'test',
|
|
533
|
+
'build',
|
|
534
|
+
'ci',
|
|
535
|
+
'chore',
|
|
536
|
+
'revert',
|
|
537
|
+
]
|
|
538
|
+
)
|
|
533
539
|
}
|
|
534
540
|
|
|
535
541
|
getChangelogCommitTypes() {
|
|
@@ -565,4 +571,12 @@ export class ConfigurationManager {
|
|
|
565
571
|
const pattern = this.changelogConfig.changelog.commitIgnoreRegexPattern
|
|
566
572
|
return pattern ? new RegExp(pattern) : /^WIP /
|
|
567
573
|
}
|
|
574
|
+
|
|
575
|
+
/**
|
|
576
|
+
* Get the complete configuration object
|
|
577
|
+
* @returns {Object} Configuration object
|
|
578
|
+
*/
|
|
579
|
+
getConfig() {
|
|
580
|
+
return this.config || {}
|
|
581
|
+
}
|
|
568
582
|
}
|
|
@@ -198,6 +198,10 @@ Provide 3 suggestions.`
|
|
|
198
198
|
return summary
|
|
199
199
|
}
|
|
200
200
|
|
|
201
|
+
async generateChangelogForCommitHashes(commitHashes) {
|
|
202
|
+
return await this.generateChangelogForCommits(commitHashes)
|
|
203
|
+
}
|
|
204
|
+
|
|
201
205
|
async selectSpecificCommits() {
|
|
202
206
|
return await selectSpecificCommits()
|
|
203
207
|
}
|
|
@@ -207,7 +211,10 @@ Provide 3 suggestions.`
|
|
|
207
211
|
const spinner = new SimpleSpinner(`Generating changelog for recent ${count} commits...`)
|
|
208
212
|
spinner.start()
|
|
209
213
|
|
|
210
|
-
const commits =
|
|
214
|
+
const commits =
|
|
215
|
+
(await this.gitService.getCommitsSince?.(null)) ||
|
|
216
|
+
(await this.gitService.getCommitAnalysis?.()) ||
|
|
217
|
+
[]
|
|
211
218
|
const recentCommits = commits.slice(0, count)
|
|
212
219
|
|
|
213
220
|
if (recentCommits.length === 0) {
|
|
@@ -9,6 +9,7 @@ import fs from 'node:fs'
|
|
|
9
9
|
import path, { dirname } from 'node:path'
|
|
10
10
|
import process from 'node:process'
|
|
11
11
|
import { fileURLToPath } from 'node:url'
|
|
12
|
+
import { execSync } from 'node:child_process'
|
|
12
13
|
|
|
13
14
|
import { Server } from '@modelcontextprotocol/sdk/server/index.js'
|
|
14
15
|
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'
|
|
@@ -18,9 +19,9 @@ import { ChangelogOrchestrator } from '../../application/orchestrators/changelog
|
|
|
18
19
|
// Import application services
|
|
19
20
|
import { ApplicationService } from '../../application/services/application.service.js'
|
|
20
21
|
import { AnalysisEngine } from '../../domains/analysis/analysis.engine.js'
|
|
21
|
-
import {
|
|
22
|
+
import { GitService } from '../../domains/git/git.service.js'
|
|
22
23
|
import { ConfigurationManager } from '../config/configuration.manager.js'
|
|
23
|
-
import {
|
|
24
|
+
import { ProviderManagerService } from '../providers/provider-manager.service.js'
|
|
24
25
|
|
|
25
26
|
const __filename = fileURLToPath(import.meta.url)
|
|
26
27
|
const __dirname = dirname(__filename)
|
|
@@ -61,12 +62,17 @@ class AIChangelogMCPServer {
|
|
|
61
62
|
// Set MCP server mode to suppress verbose logging
|
|
62
63
|
process.env.MCP_SERVER_MODE = 'true'
|
|
63
64
|
|
|
65
|
+
// Initialize configuration
|
|
64
66
|
this.configManager = new ConfigurationManager()
|
|
67
|
+
|
|
68
|
+
// Initialize application service
|
|
65
69
|
this.applicationService = new ApplicationService()
|
|
70
|
+
|
|
71
|
+
// Initialize orchestrator with proper dependencies (it will create its own services)
|
|
66
72
|
this.changelogOrchestrator = new ChangelogOrchestrator(this.configManager)
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
this.providerService = new
|
|
73
|
+
|
|
74
|
+
// Initialize provider service
|
|
75
|
+
this.providerService = new ProviderManagerService(this.configManager.getAll())
|
|
70
76
|
|
|
71
77
|
// Log available configuration
|
|
72
78
|
const hasProvider = process.env.AI_PROVIDER
|
|
@@ -80,6 +86,9 @@ class AIChangelogMCPServer {
|
|
|
80
86
|
} else {
|
|
81
87
|
console.error(`[MCP] Configured with provider: ${process.env.AI_PROVIDER}`)
|
|
82
88
|
}
|
|
89
|
+
|
|
90
|
+
// Wait for orchestrator to initialize its services
|
|
91
|
+
this.initPromise = this.changelogOrchestrator.ensureInitialized()
|
|
83
92
|
} catch (error) {
|
|
84
93
|
console.error('[MCP] Failed to initialize services:', error.message)
|
|
85
94
|
console.error('[MCP] Server will start but tools may require configuration')
|
|
@@ -296,27 +305,55 @@ class AIChangelogMCPServer {
|
|
|
296
305
|
} = args
|
|
297
306
|
|
|
298
307
|
try {
|
|
308
|
+
// Ensure services are initialized
|
|
309
|
+
if (this.initPromise) {
|
|
310
|
+
await this.initPromise
|
|
311
|
+
}
|
|
312
|
+
|
|
299
313
|
let result
|
|
300
314
|
|
|
301
315
|
if (source === 'working-dir' || (source === 'auto' && this.hasWorkingDirectoryChanges())) {
|
|
302
|
-
// Generate from working directory changes
|
|
303
|
-
|
|
304
|
-
|
|
316
|
+
// Generate from working directory changes using ChangelogService
|
|
317
|
+
// Access the changelogService through the orchestrator
|
|
318
|
+
await this.changelogOrchestrator.ensureInitialized()
|
|
319
|
+
const changelogService = this.changelogOrchestrator.changelogService
|
|
320
|
+
|
|
321
|
+
result = await changelogService.generateWorkspaceChangelog(version, {
|
|
305
322
|
analysisMode,
|
|
306
323
|
includeAttribution,
|
|
307
324
|
})
|
|
325
|
+
|
|
326
|
+
// Format result to match expected structure
|
|
327
|
+
if (result && result.changelog) {
|
|
328
|
+
result = {
|
|
329
|
+
content: result.changelog,
|
|
330
|
+
metadata: {
|
|
331
|
+
version,
|
|
332
|
+
source: 'working-directory',
|
|
333
|
+
filesProcessed: result.filesProcessed,
|
|
334
|
+
filesSkipped: result.filesSkipped,
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
}
|
|
308
338
|
} else {
|
|
309
|
-
// Generate from commits
|
|
310
|
-
result = await this.changelogOrchestrator.generateChangelog(
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
339
|
+
// Generate from commits - use orchestrator's generateChangelog(version, since)
|
|
340
|
+
result = await this.changelogOrchestrator.generateChangelog(version, since)
|
|
341
|
+
|
|
342
|
+
// Wrap result if needed
|
|
343
|
+
if (result && typeof result === 'string') {
|
|
344
|
+
result = {
|
|
345
|
+
content: result,
|
|
346
|
+
metadata: {
|
|
347
|
+
version,
|
|
348
|
+
since,
|
|
349
|
+
source: 'commits'
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
}
|
|
316
353
|
}
|
|
317
354
|
|
|
318
355
|
// Write file if requested
|
|
319
|
-
if (writeFile && result.content) {
|
|
356
|
+
if (writeFile && result && result.content) {
|
|
320
357
|
const changelogPath = path.join(process.cwd(), 'AI_CHANGELOG.md')
|
|
321
358
|
try {
|
|
322
359
|
fs.writeFileSync(changelogPath, result.content, 'utf8')
|
|
@@ -330,10 +367,10 @@ class AIChangelogMCPServer {
|
|
|
330
367
|
content: [
|
|
331
368
|
{
|
|
332
369
|
type: 'text',
|
|
333
|
-
text: result
|
|
370
|
+
text: result?.content || 'No changelog content generated',
|
|
334
371
|
},
|
|
335
372
|
],
|
|
336
|
-
metadata: result
|
|
373
|
+
metadata: result?.metadata,
|
|
337
374
|
}
|
|
338
375
|
} catch (error) {
|
|
339
376
|
throw new Error(`Changelog generation failed: ${error.message}`)
|
|
@@ -344,23 +381,30 @@ class AIChangelogMCPServer {
|
|
|
344
381
|
const { analysisType = 'comprehensive', includeRecommendations = true, commitLimit = 50 } = args
|
|
345
382
|
|
|
346
383
|
try {
|
|
384
|
+
// Ensure services are initialized
|
|
385
|
+
if (this.initPromise) {
|
|
386
|
+
await this.initPromise
|
|
387
|
+
}
|
|
388
|
+
await this.changelogOrchestrator.ensureInitialized()
|
|
389
|
+
|
|
347
390
|
let result
|
|
348
391
|
|
|
349
392
|
switch (analysisType) {
|
|
350
393
|
case 'health':
|
|
351
|
-
result = await this.
|
|
394
|
+
result = await this.changelogOrchestrator.gitService.assessRepositoryHealth(includeRecommendations)
|
|
352
395
|
break
|
|
353
396
|
case 'commits':
|
|
354
|
-
result = await this.analysisEngine.analyzeRecentCommits(commitLimit)
|
|
397
|
+
result = await this.changelogOrchestrator.analysisEngine.analyzeRecentCommits(commitLimit)
|
|
355
398
|
break
|
|
356
399
|
case 'branches':
|
|
357
|
-
result = await this.
|
|
400
|
+
result = await this.changelogOrchestrator.gitService.analyzeBranches()
|
|
358
401
|
break
|
|
359
402
|
case 'working-dir':
|
|
360
|
-
result = await this.analysisEngine.analyzeCurrentChanges()
|
|
403
|
+
result = await this.changelogOrchestrator.analysisEngine.analyzeCurrentChanges()
|
|
361
404
|
break
|
|
362
405
|
default:
|
|
363
|
-
|
|
406
|
+
// Comprehensive analysis
|
|
407
|
+
result = await this.changelogOrchestrator.analyzeRepository({ type: analysisType })
|
|
364
408
|
break
|
|
365
409
|
}
|
|
366
410
|
|
|
@@ -381,7 +425,13 @@ class AIChangelogMCPServer {
|
|
|
381
425
|
const { includeAIAnalysis = true, includeAttribution = true } = args
|
|
382
426
|
|
|
383
427
|
try {
|
|
384
|
-
|
|
428
|
+
// Ensure services are initialized
|
|
429
|
+
if (this.initPromise) {
|
|
430
|
+
await this.initPromise
|
|
431
|
+
}
|
|
432
|
+
await this.changelogOrchestrator.ensureInitialized()
|
|
433
|
+
|
|
434
|
+
const result = await this.changelogOrchestrator.analysisEngine.analyzeCurrentChanges({
|
|
385
435
|
includeAIAnalysis,
|
|
386
436
|
includeAttribution,
|
|
387
437
|
})
|
|
@@ -419,15 +469,39 @@ class AIChangelogMCPServer {
|
|
|
419
469
|
result += `\n${testResult}`
|
|
420
470
|
}
|
|
421
471
|
break
|
|
422
|
-
case 'test':
|
|
423
|
-
|
|
472
|
+
case 'test': {
|
|
473
|
+
const activeProvider = this.providerService.getActiveProvider()
|
|
474
|
+
if (!activeProvider) {
|
|
475
|
+
throw new Error('No active provider found')
|
|
476
|
+
}
|
|
477
|
+
result = await this.providerService.testProvider(activeProvider.getName())
|
|
424
478
|
break
|
|
425
|
-
|
|
426
|
-
|
|
479
|
+
}
|
|
480
|
+
case 'configure': {
|
|
481
|
+
if (!provider) {
|
|
482
|
+
throw new Error('Provider required for configure action')
|
|
483
|
+
}
|
|
484
|
+
const providerData = this.providerService.findProviderByName(provider)
|
|
485
|
+
if (!providerData) {
|
|
486
|
+
throw new Error(`Provider '${provider}' not found`)
|
|
487
|
+
}
|
|
488
|
+
result = {
|
|
489
|
+
name: provider,
|
|
490
|
+
available: providerData.available,
|
|
491
|
+
configuration: providerData.instance.getConfiguration
|
|
492
|
+
? providerData.instance.getConfiguration()
|
|
493
|
+
: {},
|
|
494
|
+
requiredVars: providerData.instance.getRequiredEnvVars
|
|
495
|
+
? providerData.instance.getRequiredEnvVars()
|
|
496
|
+
: [],
|
|
497
|
+
}
|
|
427
498
|
break
|
|
428
|
-
|
|
429
|
-
|
|
499
|
+
}
|
|
500
|
+
case 'validate': {
|
|
501
|
+
const validationResults = await this.providerService.validateAll()
|
|
502
|
+
result = validationResults
|
|
430
503
|
break
|
|
504
|
+
}
|
|
431
505
|
default:
|
|
432
506
|
throw new Error(`Unknown action: ${action}`)
|
|
433
507
|
}
|
|
@@ -436,7 +510,7 @@ class AIChangelogMCPServer {
|
|
|
436
510
|
content: [
|
|
437
511
|
{
|
|
438
512
|
type: 'text',
|
|
439
|
-
text: result,
|
|
513
|
+
text: typeof result === 'string' ? result : JSON.stringify(result, null, 2),
|
|
440
514
|
},
|
|
441
515
|
],
|
|
442
516
|
}
|
|
@@ -448,7 +522,6 @@ class AIChangelogMCPServer {
|
|
|
448
522
|
hasWorkingDirectoryChanges() {
|
|
449
523
|
try {
|
|
450
524
|
// Simple check for working directory changes
|
|
451
|
-
const { execSync } = require('node:child_process')
|
|
452
525
|
const result = execSync('git status --porcelain', { encoding: 'utf8' })
|
|
453
526
|
return result.trim().length > 0
|
|
454
527
|
} catch (_error) {
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Abstract Base Provider for AI models.
|
|
3
3
|
* Defines the interface that all provider plugins must implement.
|
|
4
4
|
*/
|
|
5
|
-
import { AbstractMethodError } from '../../../shared/utils/
|
|
5
|
+
import { AbstractMethodError } from '../../../shared/utils/error-classes.js'
|
|
6
6
|
|
|
7
7
|
export class BaseProvider {
|
|
8
8
|
constructor(config) {
|
|
@@ -2,7 +2,6 @@ import Anthropic from '@anthropic-ai/sdk'
|
|
|
2
2
|
|
|
3
3
|
import { BaseProvider } from '../core/base-provider.js'
|
|
4
4
|
import { applyMixins, ProviderResponseHandler } from '../utils/base-provider-helpers.js'
|
|
5
|
-
import { buildClientOptions } from '../utils/provider-utils.js'
|
|
6
5
|
|
|
7
6
|
export class AnthropicProvider extends BaseProvider {
|
|
8
7
|
constructor(config) {
|
|
@@ -14,7 +13,7 @@ export class AnthropicProvider extends BaseProvider {
|
|
|
14
13
|
}
|
|
15
14
|
|
|
16
15
|
initializeClient() {
|
|
17
|
-
const clientOptions =
|
|
16
|
+
const clientOptions = this.buildClientOptions({
|
|
18
17
|
timeout: 60000,
|
|
19
18
|
maxRetries: 2,
|
|
20
19
|
defaultHeaders: {
|
|
@@ -24,7 +23,7 @@ export class AnthropicProvider extends BaseProvider {
|
|
|
24
23
|
})
|
|
25
24
|
|
|
26
25
|
this.anthropic = new Anthropic({
|
|
27
|
-
apiKey: clientOptions.
|
|
26
|
+
apiKey: clientOptions.ANTHROPIC_API_KEY,
|
|
28
27
|
baseURL: clientOptions.baseURL,
|
|
29
28
|
timeout: clientOptions.timeout,
|
|
30
29
|
maxRetries: clientOptions.maxRetries,
|
|
@@ -45,7 +44,8 @@ export class AnthropicProvider extends BaseProvider {
|
|
|
45
44
|
}
|
|
46
45
|
|
|
47
46
|
getDefaultModel() {
|
|
48
|
-
|
|
47
|
+
const modelConfig = this.getProviderModelConfig()
|
|
48
|
+
return modelConfig.standardModel
|
|
49
49
|
}
|
|
50
50
|
|
|
51
51
|
async generateCompletion(messages, options = {}) {
|
|
@@ -115,127 +115,32 @@ export class AnthropicProvider extends BaseProvider {
|
|
|
115
115
|
|
|
116
116
|
async getAvailableModels() {
|
|
117
117
|
// Anthropic doesn't provide a models endpoint, return known models
|
|
118
|
+
// Use direct model names to avoid circular dependency with mixins
|
|
118
119
|
return [
|
|
119
|
-
{
|
|
120
|
-
name: 'claude-sonnet-4-20250514',
|
|
121
|
-
id: 'claude-sonnet-4-20250514',
|
|
122
|
-
description: 'Claude Sonnet 4 - Latest balanced model (2025)',
|
|
123
|
-
contextWindow: 200000,
|
|
124
|
-
capabilities: {
|
|
125
|
-
reasoning: true,
|
|
126
|
-
function_calling: true,
|
|
127
|
-
json_mode: true,
|
|
128
|
-
multimodal: true,
|
|
129
|
-
largeContext: true,
|
|
130
|
-
toolUse: true,
|
|
131
|
-
},
|
|
132
|
-
},
|
|
133
120
|
{
|
|
134
121
|
name: 'claude-opus-4-20250514',
|
|
135
122
|
id: 'claude-opus-4-20250514',
|
|
136
123
|
description: 'Claude Opus 4 - Most capable model for complex tasks (2025)',
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
multimodal: true,
|
|
143
|
-
largeContext: true,
|
|
144
|
-
toolUse: true,
|
|
145
|
-
advancedReasoning: true,
|
|
146
|
-
},
|
|
124
|
+
},
|
|
125
|
+
{
|
|
126
|
+
name: 'claude-sonnet-4-20250514',
|
|
127
|
+
id: 'claude-sonnet-4-20250514',
|
|
128
|
+
description: 'Claude Sonnet 4 - Latest balanced model (2025)',
|
|
147
129
|
},
|
|
148
130
|
{
|
|
149
131
|
name: 'claude-3.7-sonnet-20250219',
|
|
150
132
|
id: 'claude-3.7-sonnet-20250219',
|
|
151
133
|
description: 'Claude 3.7 Sonnet - Enhanced reasoning capabilities',
|
|
152
|
-
contextWindow: 200000,
|
|
153
|
-
capabilities: {
|
|
154
|
-
reasoning: true,
|
|
155
|
-
function_calling: true,
|
|
156
|
-
json_mode: true,
|
|
157
|
-
multimodal: true,
|
|
158
|
-
largeContext: true,
|
|
159
|
-
toolUse: true,
|
|
160
|
-
},
|
|
161
|
-
},
|
|
162
|
-
{
|
|
163
|
-
name: 'claude-3-5-sonnet-20241022',
|
|
164
|
-
id: 'claude-3-5-sonnet-20241022',
|
|
165
|
-
description: 'Claude 3.5 Sonnet - Previous generation',
|
|
166
|
-
contextWindow: 200000,
|
|
167
|
-
capabilities: {
|
|
168
|
-
reasoning: true,
|
|
169
|
-
function_calling: true,
|
|
170
|
-
json_mode: true,
|
|
171
|
-
multimodal: true,
|
|
172
|
-
},
|
|
173
134
|
},
|
|
174
135
|
{
|
|
175
136
|
name: 'claude-3-5-haiku-20241022',
|
|
176
137
|
id: 'claude-3-5-haiku-20241022',
|
|
177
138
|
description: 'Claude 3.5 Haiku - Fast and efficient',
|
|
178
|
-
contextWindow: 200000,
|
|
179
|
-
capabilities: {
|
|
180
|
-
reasoning: true,
|
|
181
|
-
function_calling: true,
|
|
182
|
-
json_mode: true,
|
|
183
|
-
multimodal: true,
|
|
184
|
-
},
|
|
185
139
|
},
|
|
186
140
|
]
|
|
187
141
|
}
|
|
188
142
|
|
|
189
|
-
|
|
190
|
-
try {
|
|
191
|
-
const models = await this.getAvailableModels()
|
|
192
|
-
const model = models.find((m) => m.name === modelName)
|
|
193
|
-
|
|
194
|
-
if (model) {
|
|
195
|
-
return {
|
|
196
|
-
available: true,
|
|
197
|
-
model: modelName,
|
|
198
|
-
capabilities: model.capabilities,
|
|
199
|
-
contextWindow: model.contextWindow,
|
|
200
|
-
}
|
|
201
|
-
}
|
|
202
|
-
const availableModels = models.map((m) => m.name)
|
|
203
|
-
return {
|
|
204
|
-
available: false,
|
|
205
|
-
error: `Model '${modelName}' not available`,
|
|
206
|
-
alternatives: availableModels.slice(0, 5),
|
|
207
|
-
}
|
|
208
|
-
} catch (error) {
|
|
209
|
-
return {
|
|
210
|
-
available: false,
|
|
211
|
-
error: error.message,
|
|
212
|
-
alternatives: [
|
|
213
|
-
'claude-sonnet-4-20250514',
|
|
214
|
-
'claude-opus-4-20250514',
|
|
215
|
-
'claude-3.7-sonnet-20250219',
|
|
216
|
-
],
|
|
217
|
-
}
|
|
218
|
-
}
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
async testConnection() {
|
|
222
|
-
try {
|
|
223
|
-
const response = await this.generateCompletion([{ role: 'user', content: 'Hello' }], {
|
|
224
|
-
max_tokens: 5,
|
|
225
|
-
})
|
|
226
|
-
|
|
227
|
-
return {
|
|
228
|
-
success: true,
|
|
229
|
-
model: response.model,
|
|
230
|
-
message: 'Connection successful',
|
|
231
|
-
}
|
|
232
|
-
} catch (error) {
|
|
233
|
-
return {
|
|
234
|
-
success: false,
|
|
235
|
-
error: error.message,
|
|
236
|
-
}
|
|
237
|
-
}
|
|
238
|
-
}
|
|
143
|
+
// testConnection() and validateModelAvailability() now provided by mixins
|
|
239
144
|
|
|
240
145
|
async testModel(modelName) {
|
|
241
146
|
try {
|
|
@@ -258,73 +163,11 @@ export class AnthropicProvider extends BaseProvider {
|
|
|
258
163
|
}
|
|
259
164
|
}
|
|
260
165
|
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
json_mode: true,
|
|
267
|
-
reasoning: true,
|
|
268
|
-
multimodal: true,
|
|
269
|
-
large_context: true,
|
|
270
|
-
}
|
|
271
|
-
}
|
|
272
|
-
|
|
273
|
-
getModelRecommendation(commitDetails) {
|
|
274
|
-
const { files = 0, lines = 0, breaking = false, complex = false } = commitDetails
|
|
275
|
-
|
|
276
|
-
// Use the most capable model for complex or breaking changes
|
|
277
|
-
if (breaking || complex || files > 20 || lines > 1000) {
|
|
278
|
-
return {
|
|
279
|
-
model: 'claude-3-5-sonnet-20241022',
|
|
280
|
-
reason: 'Complex or breaking change requiring advanced reasoning',
|
|
281
|
-
}
|
|
282
|
-
}
|
|
283
|
-
|
|
284
|
-
// Use standard model for medium changes
|
|
285
|
-
if (files > 5 || lines > 200) {
|
|
286
|
-
return {
|
|
287
|
-
model: 'claude-3-sonnet-20240229',
|
|
288
|
-
reason: 'Medium-sized change requiring good analysis',
|
|
289
|
-
}
|
|
290
|
-
}
|
|
291
|
-
|
|
292
|
-
// Use efficient model for small changes
|
|
293
|
-
return {
|
|
294
|
-
model: 'claude-3-haiku-20240307',
|
|
295
|
-
reason: 'Small change, optimized for efficiency',
|
|
296
|
-
}
|
|
297
|
-
}
|
|
298
|
-
|
|
299
|
-
async selectOptimalModel(commitInfo) {
|
|
300
|
-
const recommendation = this.getModelRecommendation(commitInfo)
|
|
301
|
-
const validation = await this.validateModelAvailability(recommendation.model)
|
|
302
|
-
|
|
303
|
-
if (validation.available) {
|
|
304
|
-
return {
|
|
305
|
-
model: recommendation.model,
|
|
306
|
-
reason: recommendation.reason,
|
|
307
|
-
capabilities: validation.capabilities,
|
|
308
|
-
}
|
|
309
|
-
}
|
|
310
|
-
return {
|
|
311
|
-
model: this.getDefaultModel(),
|
|
312
|
-
reason: 'Fallback to default model',
|
|
313
|
-
capabilities: this.getCapabilities(this.getDefaultModel()),
|
|
314
|
-
}
|
|
315
|
-
}
|
|
316
|
-
|
|
317
|
-
getProviderModelConfig() {
|
|
318
|
-
return {
|
|
319
|
-
smallModel: 'claude-3-5-haiku-20241022',
|
|
320
|
-
mediumModel: 'claude-3.7-sonnet-20250219',
|
|
321
|
-
standardModel: 'claude-sonnet-4-20250514',
|
|
322
|
-
complexModel: 'claude-opus-4-20250514',
|
|
323
|
-
default: 'claude-sonnet-4-20250514',
|
|
324
|
-
temperature: 0.3,
|
|
325
|
-
maxTokens: 4096,
|
|
326
|
-
}
|
|
327
|
-
}
|
|
166
|
+
// All common methods now provided by mixins:
|
|
167
|
+
// - getCapabilities() from CapabilitiesMixin
|
|
168
|
+
// - getModelRecommendation() from ModelRecommendationMixin
|
|
169
|
+
// - selectOptimalModel() from ModelRecommendationMixin
|
|
170
|
+
// - getProviderModelConfig() from ConfigurationMixin
|
|
328
171
|
}
|
|
329
172
|
|
|
330
173
|
// Apply mixins to add standard provider functionality
|