package domain import ( "math" "strings" ) const ( LLMProviderOpenAI = "openai" LLMProviderAnthropic = "anthropic" LLMProviderGoogle = "google" LLMProviderXAI = "xai" LLMProviderOllama = "ollama" defaultLLMTemperature = 0.2 minLLMTemperature = 0.0 maxLLMTemperature = 2.0 defaultLLMMaxTokens = 1200 minLLMMaxTokens = 64 maxLLMMaxTokens = 8192 ) type LLMModelOption struct { Value string Label string } type LLMProviderOption struct { Value string Label string Models []LLMModelOption } func DefaultLLMProvider() string { return LLMProviderOpenAI } func LLMProviderOptions() []LLMProviderOption { return []LLMProviderOption{ { Value: LLMProviderOpenAI, Label: "OpenAI", Models: []LLMModelOption{ {Value: "gpt-5.2", Label: "gpt-5.2"}, {Value: "gpt-5.4", Label: "gpt-5.4"}, {Value: "gpt-5.4-mini", Label: "gpt-5.4-mini"}, {Value: "gpt-5.4-nano", Label: "gpt-5.4-nano"}, }, }, { Value: LLMProviderAnthropic, Label: "Anthropic", Models: []LLMModelOption{ {Value: "claude-sonnet-4-5", Label: "claude-sonnet-4-5"}, {Value: "claude-opus-4-1", Label: "claude-opus-4-1"}, }, }, { Value: LLMProviderGoogle, Label: "Google", Models: []LLMModelOption{ {Value: "gemini-2.5-pro", Label: "gemini-2.5-pro"}, {Value: "gemini-2.5-flash", Label: "gemini-2.5-flash"}, }, }, { Value: LLMProviderXAI, Label: "xAI", Models: []LLMModelOption{ {Value: "grok-4", Label: "grok-4"}, {Value: "grok-3-mini", Label: "grok-3-mini"}, }, }, { Value: LLMProviderOllama, Label: "Ollama", Models: []LLMModelOption{ {Value: "llama3.2", Label: "llama3.2"}, {Value: "qwen2.5", Label: "qwen2.5"}, {Value: "mistral", Label: "mistral"}, }, }, } } func LLMModelsByProvider(provider string) []LLMModelOption { normalized := NormalizeLLMProvider(provider) for _, option := range LLMProviderOptions() { if option.Value == normalized { out := make([]LLMModelOption, len(option.Models)) copy(out, option.Models) return out } } return nil } func NormalizeLLMProvider(provider string) string { value := strings.ToLower(strings.TrimSpace(provider)) for _, option := range LLMProviderOptions() { if option.Value == value { return value } } return DefaultLLMProvider() } func NormalizeLLMModel(provider, model string) string { models := LLMModelsByProvider(provider) if len(models) == 0 { return "" } value := strings.TrimSpace(model) for _, option := range models { if option.Value == value { return value } } return models[0].Value } func DefaultLLMTemperature() float64 { return defaultLLMTemperature } func NormalizeLLMTemperature(value float64) float64 { if math.IsNaN(value) || math.IsInf(value, 0) { return defaultLLMTemperature } if value < minLLMTemperature { value = minLLMTemperature } if value > maxLLMTemperature { value = maxLLMTemperature } return math.Round(value*100) / 100 } func DefaultLLMMaxTokens() int { return defaultLLMMaxTokens } func NormalizeLLMMaxTokens(value int) int { if value <= 0 { return defaultLLMMaxTokens } if value < minLLMMaxTokens { return minLLMMaxTokens } if value > maxLLMMaxTokens { return maxLLMMaxTokens } return value } func LLMAPIKeyForProvider(provider string, settings AppSettings) string { switch NormalizeLLMProvider(provider) { case LLMProviderOpenAI: return strings.TrimSpace(settings.OpenAIAPIKeyEncrypted) case LLMProviderAnthropic: return strings.TrimSpace(settings.AnthropicAPIKeyEncrypted) case LLMProviderGoogle: return strings.TrimSpace(settings.GoogleAPIKeyEncrypted) case LLMProviderXAI: return strings.TrimSpace(settings.XAIAPIKeyEncrypted) case LLMProviderOllama: return strings.TrimSpace(settings.OllamaAPIKeyEncrypted) default: return "" } }