From 97e049a373344c94092476f83e69806b1e93b9ff Mon Sep 17 00:00:00 2001 From: rcourtman Date: Fri, 12 Dec 2025 13:54:38 +0000 Subject: [PATCH] feat(ai): Wire operational memory into router startup Complete Phase 3 integration: - Initialize ChangeDetector and RemediationLog in StartPatrol - Add SetChangeDetector/SetRemediationLog to handler chain: Router -> AISettingsHandler -> Service -> PatrolService - Persist change history to ai_changes.json - Persist remediation log to ai_remediations.json - Both use the Pulse config directory for storage Operational memory is now fully integrated: - Change detector tracks infrastructure changes on each patrol - Recent changes (24h) are appended to AI context - Remediation log ready for command execution logging All tests passing. --- internal/ai/service.go | 22 ++++++++++++++++++++++ internal/api/ai_handlers.go | 10 ++++++++++ internal/api/router.go | 22 ++++++++++++++++++++++ 3 files changed, 54 insertions(+) diff --git a/internal/ai/service.go b/internal/ai/service.go index 8f2fde9..246c2c8 100644 --- a/internal/ai/service.go +++ b/internal/ai/service.go @@ -219,6 +219,28 @@ func (s *Service) SetBaselineStore(store *BaselineStore) { } } +// SetChangeDetector sets the change detector for operational memory +func (s *Service) SetChangeDetector(detector *ChangeDetector) { + s.mu.RLock() + patrol := s.patrolService + s.mu.RUnlock() + + if patrol != nil { + patrol.SetChangeDetector(detector) + } +} + +// SetRemediationLog sets the remediation log for tracking fix attempts +func (s *Service) SetRemediationLog(remLog *RemediationLog) { + s.mu.RLock() + patrol := s.patrolService + s.mu.RUnlock() + + if patrol != nil { + patrol.SetRemediationLog(remLog) + } +} + // StartPatrol starts the background patrol service func (s *Service) StartPatrol(ctx context.Context) { s.mu.RLock() diff --git a/internal/api/ai_handlers.go b/internal/api/ai_handlers.go index 93761dd..60cf3f1 100644 --- a/internal/api/ai_handlers.go +++ b/internal/api/ai_handlers.go @@ -105,6 +105,16 @@ func (h *AISettingsHandler) SetBaselineStore(store *ai.BaselineStore) { h.aiService.SetBaselineStore(store) } +// SetChangeDetector sets the change detector for operational memory +func (h *AISettingsHandler) SetChangeDetector(detector *ai.ChangeDetector) { + h.aiService.SetChangeDetector(detector) +} + +// SetRemediationLog sets the remediation log for tracking fix attempts +func (h *AISettingsHandler) SetRemediationLog(remLog *ai.RemediationLog) { + h.aiService.SetRemediationLog(remLog) +} + // StopPatrol stops the background AI patrol service func (h *AISettingsHandler) StopPatrol() { h.aiService.StopPatrol() diff --git a/internal/api/router.go b/internal/api/router.go index dd5182f..c035596 100644 --- a/internal/api/router.go +++ b/internal/api/router.go @@ -1436,6 +1436,28 @@ func (r *Router) StartPatrol(ctx context.Context) { } } } + + // Initialize operational memory (change detection and remediation logging) + dataDir := "" + if r.persistence != nil { + dataDir = r.persistence.DataDir() + } + + changeDetector := ai.NewChangeDetector(ai.ChangeDetectorConfig{ + MaxChanges: 1000, + DataDir: dataDir, + }) + if changeDetector != nil { + r.aiSettingsHandler.SetChangeDetector(changeDetector) + } + + remediationLog := ai.NewRemediationLog(ai.RemediationLogConfig{ + MaxRecords: 500, + DataDir: dataDir, + }) + if remediationLog != nil { + r.aiSettingsHandler.SetRemediationLog(remediationLog) + } r.aiSettingsHandler.StartPatrol(ctx) }