chore: auto-commit uncommitted changes
This commit is contained in:
parent
6d48e6a826
commit
78bf7bd68b
|
|
@ -56,4 +56,4 @@ triage:
|
||||||
base_url: https://api.fireworks.ai/inference/v1
|
base_url: https://api.fireworks.ai/inference/v1
|
||||||
api_key: ${FIREWORKS_API_KEY}
|
api_key: ${FIREWORKS_API_KEY}
|
||||||
model: accounts/fireworks/models/kimi-k2p5
|
model: accounts/fireworks/models/kimi-k2p5
|
||||||
dashboard_url: http://localhost:9200/api/news
|
# dashboard_url removed — routing handled by OpenClaw via webhook
|
||||||
|
|
|
||||||
69
triage.go
69
triage.go
|
|
@ -28,7 +28,17 @@ type ProviderConfig struct {
|
||||||
|
|
||||||
// TriageResult is the expected LLM response
|
// TriageResult is the expected LLM response
|
||||||
type TriageResult struct {
|
type TriageResult struct {
|
||||||
Action string `json:"action"` // trash, archive, keep, escalate
|
Action string `json:"action"` // junk, pass
|
||||||
|
Reason string `json:"reason"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// triageLogEntry is a structured log entry for triage decisions
|
||||||
|
type triageLogEntry struct {
|
||||||
|
Ts string `json:"ts"`
|
||||||
|
ID string `json:"id"`
|
||||||
|
From string `json:"from"`
|
||||||
|
Subject string `json:"subject"`
|
||||||
|
Action string `json:"action"`
|
||||||
Reason string `json:"reason"`
|
Reason string `json:"reason"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -154,7 +164,7 @@ func callLLM(provider ProviderConfig, systemPrompt, userMessage string) (*Triage
|
||||||
|
|
||||||
// Validate action
|
// Validate action
|
||||||
switch result.Action {
|
switch result.Action {
|
||||||
case "trash", "archive", "keep", "escalate":
|
case "junk", "pass":
|
||||||
// valid
|
// valid
|
||||||
default:
|
default:
|
||||||
return nil, fmt.Errorf("unknown triage action: %q", result.Action)
|
return nil, fmt.Errorf("unknown triage action: %q", result.Action)
|
||||||
|
|
@ -166,23 +176,13 @@ func callLLM(provider ProviderConfig, systemPrompt, userMessage string) (*Triage
|
||||||
// executeTriageAction performs the action decided by the LLM
|
// executeTriageAction performs the action decided by the LLM
|
||||||
func executeTriageAction(msg UnifiedMessage, result TriageResult) error {
|
func executeTriageAction(msg UnifiedMessage, result TriageResult) error {
|
||||||
switch result.Action {
|
switch result.Action {
|
||||||
case "trash":
|
case "junk":
|
||||||
if err := store.Delete(msg.ID); err != nil {
|
if err := store.Delete(msg.ID); err != nil {
|
||||||
return fmt.Errorf("trash: %w", err)
|
return fmt.Errorf("junk delete: %w", err)
|
||||||
}
|
}
|
||||||
orch.RecordAction(msg.ID, "delete")
|
orch.RecordAction(msg.ID, "delete")
|
||||||
case "archive":
|
case "pass":
|
||||||
if err := store.Archive(msg.ID); err != nil {
|
// Leave for webhook — record as seen so it shows in /messages/new for the agent
|
||||||
return fmt.Errorf("archive: %w", err)
|
|
||||||
}
|
|
||||||
orch.RecordAction(msg.ID, "archive")
|
|
||||||
case "keep":
|
|
||||||
if err := store.MarkSeen(msg.ID); err != nil {
|
|
||||||
return fmt.Errorf("mark seen: %w", err)
|
|
||||||
}
|
|
||||||
orch.RecordAction(msg.ID, "seen")
|
|
||||||
case "escalate":
|
|
||||||
// Record as seen but don't action — webhook will fire
|
|
||||||
source, sourceID, _ := parseMessageID(msg.ID)
|
source, sourceID, _ := parseMessageID(msg.ID)
|
||||||
orch.RecordSeen(msg.ID, source, sourceID, "INBOX")
|
orch.RecordSeen(msg.ID, source, sourceID, "INBOX")
|
||||||
}
|
}
|
||||||
|
|
@ -190,6 +190,40 @@ func executeTriageAction(msg UnifiedMessage, result TriageResult) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// logTriageDecision appends a structured log entry to the triage log file
|
||||||
|
func logTriageDecision(msg UnifiedMessage, result TriageResult) {
|
||||||
|
logPath := os.ExpandEnv("$HOME") + "/.message-center/triage-log.jsonl"
|
||||||
|
|
||||||
|
sender := msg.From
|
||||||
|
if msg.FromName != "" {
|
||||||
|
sender = msg.FromName + " <" + msg.From + ">"
|
||||||
|
}
|
||||||
|
|
||||||
|
entry := triageLogEntry{
|
||||||
|
Ts: time.Now().UTC().Format(time.RFC3339),
|
||||||
|
ID: msg.ID,
|
||||||
|
From: sender,
|
||||||
|
Subject: msg.Subject,
|
||||||
|
Action: result.Action,
|
||||||
|
Reason: result.Reason,
|
||||||
|
}
|
||||||
|
|
||||||
|
data, err := json.Marshal(entry)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("[triage] Failed to marshal log entry: %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
f, err := os.OpenFile(logPath, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("[triage] Failed to open triage log %s: %v", logPath, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer f.Close()
|
||||||
|
|
||||||
|
f.Write(append(data, '\n'))
|
||||||
|
}
|
||||||
|
|
||||||
// logTriageToDashboard posts a log entry to the alert dashboard
|
// logTriageToDashboard posts a log entry to the alert dashboard
|
||||||
func logTriageToDashboard(dashboardURL string, msg UnifiedMessage, result TriageResult) {
|
func logTriageToDashboard(dashboardURL string, msg UnifiedMessage, result TriageResult) {
|
||||||
if dashboardURL == "" {
|
if dashboardURL == "" {
|
||||||
|
|
@ -270,9 +304,10 @@ func triageNewEmails(accountName string, cfg TriageConfig) bool {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
logTriageDecision(msg, *result)
|
||||||
logTriageToDashboard(cfg.DashboardURL, msg, *result)
|
logTriageToDashboard(cfg.DashboardURL, msg, *result)
|
||||||
|
|
||||||
if result.Action == "escalate" {
|
if result.Action == "pass" {
|
||||||
shouldEscalate = true
|
shouldEscalate = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue