Files

88 lines
2.8 KiB
C#

using MarketAlly.GitCommitEditor.Models;
using MarketAlly.GitCommitEditor.Options;
using MarketAlly.GitCommitEditor.Resources;
using MarketAlly.GitCommitEditor.Services;
namespace MarketAlly.GitCommitEditor.Rewriters;
/// <summary>
/// Exception thrown when AI features are used without an API key configured.
/// </summary>
public class ApiKeyNotConfiguredException : InvalidOperationException
{
public ApiKeyNotConfiguredException()
: base(Str.Service_ApiKeyNotConfigured)
{
}
}
/// <summary>
/// Dynamic commit rewriter that uses AI when configured, or throws if not.
/// </summary>
public sealed class DynamicCommitRewriter : ICommitMessageRewriter, IDisposable
{
private readonly AiOptions _options;
private readonly ICostTrackingService? _costTracker;
private AICommitRewriter? _aiRewriter;
private string? _lastApiKey;
private string? _lastProvider;
private string? _lastModel;
public DynamicCommitRewriter(AiOptions options, ICostTrackingService? costTracker = null)
{
_options = options ?? throw new ArgumentNullException(nameof(options));
_costTracker = costTracker;
}
/// <summary>
/// Returns true if an API key is configured and AI features are available.
/// </summary>
public bool IsConfigured => !string.IsNullOrEmpty(_options.ApiKey);
private AICommitRewriter GetRewriter()
{
// If no API key, throw exception
if (string.IsNullOrEmpty(_options.ApiKey))
{
throw new ApiKeyNotConfiguredException();
}
// Check if we need to create/recreate the AI rewriter
// (API key, provider, or model changed)
if (_aiRewriter == null ||
_lastApiKey != _options.ApiKey ||
_lastProvider != _options.Provider ||
_lastModel != _options.Model)
{
// Dispose old rewriter if exists
_aiRewriter?.Dispose();
// Create new rewriter with current settings
_aiRewriter = new AICommitRewriter(_options, _costTracker);
_lastApiKey = _options.ApiKey;
_lastProvider = _options.Provider;
_lastModel = _options.Model;
}
return _aiRewriter;
}
public Task<SuggestionResult> SuggestImprovedMessageAsync(CommitAnalysis analysis, CancellationToken ct = default)
{
return GetRewriter().SuggestImprovedMessageAsync(analysis, ct);
}
public Task<IReadOnlyList<(CommitAnalysis Analysis, SuggestionResult Result)>> SuggestBatchAsync(
IEnumerable<CommitAnalysis> analyses,
IProgress<int>? progress = null,
CancellationToken ct = default)
{
return GetRewriter().SuggestBatchAsync(analyses, progress, ct);
}
public void Dispose()
{
_aiRewriter?.Dispose();
}
}