From 0ce6bda33bda3b99e3ac83aa2b81d515d0762e5c Mon Sep 17 00:00:00 2001 From: rcourtman Date: Sun, 21 Dec 2025 21:48:09 +0000 Subject: [PATCH] fix: AI settings persistence and UI improvements Bug Fixes: - Fix boolean fields with 'omitempty' not persisting false values - AlertTriggeredAnalysis, PatrolAnalyzeNodes/Guests/Docker/Storage - omitempty causes Go to skip false (zero value) when marshaling JSON - On reload, NewDefaultAIConfig() sets true, and missing field stays true - Fix model dropdown losing selection after save (SolidJS reactivity issue) - Added explicit 'selected' attribute to option elements - Ensures browser maintains selection with optgroups during re-renders Improvements: - Change patrol type label from 'Quick' to 'Patrol' in history table - Add chat_model and patrol_model to AI settings update log - Add alert_triggered_analysis to AI config load log for debugging --- frontend-modern/src/components/Settings/AISettings.tsx | 4 ++-- frontend-modern/src/pages/Alerts.tsx | 2 +- internal/api/ai_handlers.go | 2 ++ internal/config/ai.go | 10 +++++----- internal/config/persistence.go | 2 +- 5 files changed, 11 insertions(+), 9 deletions(-) diff --git a/frontend-modern/src/components/Settings/AISettings.tsx b/frontend-modern/src/components/Settings/AISettings.tsx index 2f79fe7..6be11b4 100644 --- a/frontend-modern/src/components/Settings/AISettings.tsx +++ b/frontend-modern/src/components/Settings/AISettings.tsx @@ -653,7 +653,7 @@ export const AISettings: Component = () => { {(model) => ( - )} @@ -667,7 +667,7 @@ export const AISettings: Component = () => { {(model) => ( - )} diff --git a/frontend-modern/src/pages/Alerts.tsx b/frontend-modern/src/pages/Alerts.tsx index d668e89..5717600 100644 --- a/frontend-modern/src/pages/Alerts.tsx +++ b/frontend-modern/src/pages/Alerts.tsx @@ -3490,7 +3490,7 @@ function OverviewTab(props: { ? 'bg-violet-100 dark:bg-violet-900/50 text-violet-700 dark:text-violet-300' : 'bg-sky-100 dark:bg-sky-900/50 text-sky-700 dark:text-sky-300' }`}> - {run.type === 'deep' ? 'Deep' : 'Quick'} + {run.type === 'deep' ? 'Deep' : 'Patrol'} diff --git a/internal/api/ai_handlers.go b/internal/api/ai_handlers.go index b2709d0..0ae0f32 100644 --- a/internal/api/ai_handlers.go +++ b/internal/api/ai_handlers.go @@ -489,6 +489,8 @@ func (h *AISettingsHandler) HandleUpdateAISettings(w http.ResponseWriter, r *htt Bool("enabled", settings.Enabled). Str("provider", settings.Provider). Str("model", settings.GetModel()). + Str("chatModel", settings.ChatModel). + Str("patrolModel", settings.PatrolModel). Str("patrolPreset", settings.PatrolSchedulePreset). Bool("alertTriggeredAnalysis", settings.AlertTriggeredAnalysis). Msg("AI settings updated") diff --git a/internal/config/ai.go b/internal/config/ai.go index 3a62082..2210c6b 100644 --- a/internal/config/ai.go +++ b/internal/config/ai.go @@ -43,15 +43,15 @@ type AIConfig struct { PatrolEnabled bool `json:"patrol_enabled"` // Enable background AI health patrol PatrolIntervalMinutes int `json:"patrol_interval_minutes,omitempty"` // How often to run quick patrols (default: 360 = 6 hours) PatrolSchedulePreset string `json:"patrol_schedule_preset,omitempty"` // User-friendly preset: "15min", "1hr", "6hr", "12hr", "daily", "disabled" - PatrolAnalyzeNodes bool `json:"patrol_analyze_nodes,omitempty"` // Include Proxmox nodes in patrol - PatrolAnalyzeGuests bool `json:"patrol_analyze_guests,omitempty"` // Include VMs/containers in patrol - PatrolAnalyzeDocker bool `json:"patrol_analyze_docker,omitempty"` // Include Docker hosts in patrol - PatrolAnalyzeStorage bool `json:"patrol_analyze_storage,omitempty"` // Include storage in patrol + PatrolAnalyzeNodes bool `json:"patrol_analyze_nodes"` // Include Proxmox nodes in patrol + PatrolAnalyzeGuests bool `json:"patrol_analyze_guests"` // Include VMs/containers in patrol + PatrolAnalyzeDocker bool `json:"patrol_analyze_docker"` // Include Docker hosts in patrol + PatrolAnalyzeStorage bool `json:"patrol_analyze_storage"` // Include storage in patrol PatrolAutoFix bool `json:"patrol_auto_fix,omitempty"` // When true, patrol can attempt automatic remediation (default: false, observe only) AutoFixModel string `json:"auto_fix_model,omitempty"` // Model for automatic remediation (defaults to PatrolModel, may want more capable model) // Alert-triggered AI analysis - analyze specific resources when alerts fire - AlertTriggeredAnalysis bool `json:"alert_triggered_analysis,omitempty"` // Enable AI analysis when alerts fire (token-efficient) + AlertTriggeredAnalysis bool `json:"alert_triggered_analysis"` // Enable AI analysis when alerts fire (token-efficient) // AI cost controls // Budget is expressed as an estimated USD amount over a 30-day window (pro-rated in UI for other ranges). diff --git a/internal/config/persistence.go b/internal/config/persistence.go index 05f1714..6d6938a 100644 --- a/internal/config/persistence.go +++ b/internal/config/persistence.go @@ -1452,7 +1452,7 @@ func (c *ConfigPersistence) LoadAIConfig() (*AIConfig, error) { settings.PatrolIntervalMinutes = 15 } - log.Info().Str("file", c.aiFile).Bool("enabled", settings.Enabled).Bool("patrol_enabled", settings.PatrolEnabled).Msg("AI configuration loaded") + log.Info().Str("file", c.aiFile).Bool("enabled", settings.Enabled).Bool("patrol_enabled", settings.PatrolEnabled).Bool("alert_triggered_analysis", settings.AlertTriggeredAnalysis).Msg("AI configuration loaded") return settings, nil }