using System.ComponentModel;
using ClawdDotNet.Core.Api;
using ClawdDotNet.Core.Api.Models;
namespace ClawdDotNet.Models;
///
/// TypeConverter der im PropertyGrid eine Dropdown-Liste
/// mit verfügbaren OpenRouter-Modellen anzeigt.
/// Die Modelle werden einmalig per API abgerufen und gecached.
/// Freitext-Eingabe bleibt weiterhin möglich (CanConvertFrom = true).
///
public sealed class ModelTypeConverter : StringConverter
{
private static List? _cachedModels;
private static bool _fetchInProgress;
private static readonly Lock _lock = new();
///
/// Wird von außen gesetzt (beim Start der Anwendung), damit
/// der Converter Zugriff auf den OpenRouterClient hat.
///
public static OpenRouterClient? Client { get; set; }
public override bool GetStandardValuesSupported(ITypeDescriptorContext? context) => true;
/// false = Dropdown ist editierbar (Freitext erlaubt)
public override bool GetStandardValuesExclusive(ITypeDescriptorContext? context) => false;
public override StandardValuesCollection? GetStandardValues(ITypeDescriptorContext? context)
{
EnsureModelsLoaded();
if (_cachedModels is null || _cachedModels.Count == 0)
{
// Fallback: Einige gängige Modelle
return new StandardValuesCollection(new[]
{
"anthropic/claude-sonnet-4-5",
"anthropic/claude-haiku-4",
"openai/gpt-4.1",
"openai/gpt-4.1-mini",
"google/gemini-2.5-pro-preview",
"google/gemini-2.5-flash-preview",
"deepseek/deepseek-chat-v3-0324",
"meta-llama/llama-4-maverick"
});
}
var ids = _cachedModels.Select(m => m.Id).ToArray();
return new StandardValuesCollection(ids);
}
private static void EnsureModelsLoaded()
{
if (_cachedModels is not null || Client is null)
return;
lock (_lock)
{
if (_cachedModels is not null || _fetchInProgress)
return;
_fetchInProgress = true;
}
// Asynchronen Abruf im Hintergrund starten
_ = Task.Run(async () =>
{
try
{
var models = await Client.GetAvailableModelsAsync();
_cachedModels = models;
}
catch
{
_cachedModels = []; // Fehler → Fallback wird verwendet
}
finally
{
lock (_lock) { _fetchInProgress = false; }
}
});
}
///
/// Kann von außen aufgerufen werden um den Cache zu leeren
/// (z.B. wenn sich der API-Key ändert).
///
public static void InvalidateCache()
{
lock (_lock) { _cachedModels = null; }
}
}