Files
clawgo/pkg/agent/trigger_audit.go

87 lines
1.9 KiB
Go

package agent
import (
"encoding/json"
"os"
"path/filepath"
"sync"
"time"
)
type TriggerStats struct {
UpdatedAt string `json:"updated_at"`
Counts map[string]int `json:"counts"`
}
type triggerAudit struct {
workspace string
mu sync.Mutex
}
type triggerEvent struct {
Time string `json:"time"`
Trigger string `json:"trigger"`
Channel string `json:"channel"`
Session string `json:"session"`
Suppressed bool `json:"suppressed,omitempty"`
Error string `json:"error,omitempty"`
}
func newTriggerAudit(workspace string) *triggerAudit {
return &triggerAudit{workspace: workspace}
}
func (ta *triggerAudit) Record(trigger, channel, session string, suppressed bool, err error) {
if ta == nil {
return
}
trigger = normalizeTrigger(trigger)
e := triggerEvent{
Time: time.Now().UTC().Format(time.RFC3339),
Trigger: trigger,
Channel: channel,
Session: session,
Suppressed: suppressed,
}
if err != nil {
e.Error = err.Error()
}
ta.mu.Lock()
defer ta.mu.Unlock()
memDir := filepath.Join(ta.workspace, "memory")
_ = os.MkdirAll(memDir, 0755)
logPath := filepath.Join(memDir, "trigger-audit.jsonl")
if data, mErr := json.Marshal(e); mErr == nil {
f, oErr := os.OpenFile(logPath, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
if oErr == nil {
_, _ = f.Write(append(data, '\n'))
_ = f.Close()
}
}
statsPath := filepath.Join(memDir, "trigger-stats.json")
stats := TriggerStats{Counts: map[string]int{}}
if raw, rErr := os.ReadFile(statsPath); rErr == nil {
_ = json.Unmarshal(raw, &stats)
if stats.Counts == nil {
stats.Counts = map[string]int{}
}
}
stats.Counts[trigger]++
stats.UpdatedAt = e.Time
if raw, mErr := json.MarshalIndent(stats, "", " "); mErr == nil {
_ = os.WriteFile(statsPath, raw, 0644)
}
}
func normalizeTrigger(v string) string {
s := v
if s == "" {
return "user"
}
return s
}