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
This commit is contained in:
rcourtman 2025-12-21 21:48:09 +00:00
parent 4d7d2e42dc
commit 0ce6bda33b
5 changed files with 11 additions and 9 deletions

View file

@ -653,7 +653,7 @@ export const AISettings: Component = () => {
<optgroup label={PROVIDER_DISPLAY_NAMES[provider] || provider}>
<For each={models}>
{(model) => (
<option value={model.id}>
<option value={model.id} selected={model.id === form.model}>
{model.name || model.id.split(':').pop()}
</option>
)}
@ -667,7 +667,7 @@ export const AISettings: Component = () => {
<optgroup label={`⚠️ ${PROVIDER_DISPLAY_NAMES[provider] || provider} (not configured)`}>
<For each={models}>
{(model) => (
<option value={model.id} class="text-gray-400">
<option value={model.id} selected={model.id === form.model} class="text-gray-400">
{model.name || model.id.split(':').pop()}
</option>
)}

View file

@ -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'}
</span>
</td>
<td class="p-1.5 px-2 text-center">

View file

@ -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")

View file

@ -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).

View file

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