Pulse/internal/ai/cost_persistence.go
rcourtman 88d419dd5b feat(ai): Add enriched context with historical trends and predictions
Phase 1 of Pulse AI differentiation:

- Create internal/ai/context package with types, trends, builder, formatter
- Implement linear regression for trend computation (growing/declining/stable/volatile)
- Add storage capacity predictions (predicts days until 90% and 100%)
- Wire MetricsHistory from monitor to patrol service
- Update patrol to use buildEnrichedContext instead of basic summary
- Update patrol prompt to reference trend indicators and predictions

This gives the AI awareness of historical patterns, enabling it to:
- Identify resources with concerning growth rates
- Predict capacity exhaustion before it happens
- Distinguish between stable high usage vs growing problems
- Provide more actionable, time-aware insights

All tests passing. Falls back to basic summary if metrics history unavailable.
2025-12-12 09:45:57 +00:00

61 lines
1.8 KiB
Go

package ai
import (
"github.com/rcourtman/pulse-go-rewrite/internal/ai/cost"
"github.com/rcourtman/pulse-go-rewrite/internal/config"
)
// CostPersistenceAdapter bridges ConfigPersistence to cost.Persistence.
type CostPersistenceAdapter struct {
config *config.ConfigPersistence
}
// NewCostPersistenceAdapter creates a new adapter.
func NewCostPersistenceAdapter(cfg *config.ConfigPersistence) *CostPersistenceAdapter {
return &CostPersistenceAdapter{config: cfg}
}
// SaveUsageHistory saves usage events to disk via ConfigPersistence.
func (a *CostPersistenceAdapter) SaveUsageHistory(events []cost.UsageEvent) error {
records := make([]config.AIUsageEventRecord, len(events))
for i, e := range events {
records[i] = config.AIUsageEventRecord{
Timestamp: e.Timestamp,
Provider: e.Provider,
RequestModel: e.RequestModel,
ResponseModel: e.ResponseModel,
UseCase: e.UseCase,
InputTokens: e.InputTokens,
OutputTokens: e.OutputTokens,
TargetType: e.TargetType,
TargetID: e.TargetID,
FindingID: e.FindingID,
}
}
return a.config.SaveAIUsageHistory(records)
}
// LoadUsageHistory loads usage events from disk via ConfigPersistence.
func (a *CostPersistenceAdapter) LoadUsageHistory() ([]cost.UsageEvent, error) {
data, err := a.config.LoadAIUsageHistory()
if err != nil {
return nil, err
}
events := make([]cost.UsageEvent, len(data.Events))
for i, r := range data.Events {
events[i] = cost.UsageEvent{
Timestamp: r.Timestamp,
Provider: r.Provider,
RequestModel: r.RequestModel,
ResponseModel: r.ResponseModel,
UseCase: r.UseCase,
InputTokens: r.InputTokens,
OutputTokens: r.OutputTokens,
TargetType: r.TargetType,
TargetID: r.TargetID,
FindingID: r.FindingID,
}
}
return events, nil
}