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; } } }