- Migration 015: extends agents with trigger config, adds reactive_runs table - Reactor engine: decision chain (mode, depth, budget, cooldown, sequential) - Reactor store: SQLite persistence for runs with RFC3339 timestamps - Reactor poller: K8s Job status polling (15s interval) - Failure notifier: system DM to owner on job failure - REST API: /api/runs, /api/runs/:id, /api/runs/:id/retry, /api/agents/reactive - Agent model: trigger_mode, cooldown, budget, depth, k8s_image, pending_work - K8s runner: GetClientset() for poller - All 28 test packages pass (8 new reactor tests) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
53 lines
1.4 KiB
Go
53 lines
1.4 KiB
Go
package reactor
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
|
|
"github.com/synapbus/synapbus/internal/messaging"
|
|
)
|
|
|
|
// DMFailureNotifier sends system DMs to agent owners on job failure.
|
|
type DMFailureNotifier struct {
|
|
msgService *messaging.MessagingService
|
|
}
|
|
|
|
// NewDMFailureNotifier creates a new failure notifier.
|
|
func NewDMFailureNotifier(msgService *messaging.MessagingService) *DMFailureNotifier {
|
|
return &DMFailureNotifier{msgService: msgService}
|
|
}
|
|
|
|
// NotifyFailure sends a system DM to the agent's owner with error details.
|
|
func (n *DMFailureNotifier) NotifyFailure(ctx context.Context, ownerAgentName, agentName, triggerFrom, triggerEvent string, durationMs int64, errorSummary string) error {
|
|
durationStr := "< 1s"
|
|
if durationMs > 0 {
|
|
secs := durationMs / 1000
|
|
if secs >= 60 {
|
|
durationStr = fmt.Sprintf("%dm%ds", secs/60, secs%60)
|
|
} else {
|
|
durationStr = fmt.Sprintf("%ds", secs)
|
|
}
|
|
}
|
|
|
|
body := fmt.Sprintf(
|
|
"⚠️ **Reactive run failed** for **%s**\n\n"+
|
|
"**Trigger**: %s from %s\n"+
|
|
"**Duration**: %s\n"+
|
|
"**Error**: %s\n\n"+
|
|
"View details in Agent Runs page.",
|
|
agentName, triggerEvent, triggerFrom, durationStr, truncateError(errorSummary, 500),
|
|
)
|
|
|
|
_, err := n.msgService.SendMessage(ctx, "system", ownerAgentName, body, messaging.SendOptions{
|
|
Priority: 7,
|
|
})
|
|
return err
|
|
}
|
|
|
|
func truncateError(s string, maxLen int) string {
|
|
if len(s) <= maxLen {
|
|
return s
|
|
}
|
|
return s[:maxLen] + "..."
|
|
}
|