add autonomy waiting-resume debounce config and status visibility

This commit is contained in:
DBT
2026-02-24 03:51:14 +00:00
parent 357a826319
commit ee91d6e479
6 changed files with 39 additions and 24 deletions

View File

@@ -384,6 +384,9 @@ func summarizeAutonomyChanges(oldCfg, newCfg *config.Config) []string {
if o.UserIdleResumeSec != n.UserIdleResumeSec { if o.UserIdleResumeSec != n.UserIdleResumeSec {
changes = append(changes, "user_idle_resume_sec") changes = append(changes, "user_idle_resume_sec")
} }
if o.WaitingResumeDebounceSec != n.WaitingResumeDebounceSec {
changes = append(changes, "waiting_resume_debounce_sec")
}
if strings.TrimSpace(o.QuietHours) != strings.TrimSpace(n.QuietHours) { if strings.TrimSpace(o.QuietHours) != strings.TrimSpace(n.QuietHours) {
changes = append(changes, "quiet_hours") changes = append(changes, "quiet_hours")
} }
@@ -750,6 +753,7 @@ func buildAutonomyEngine(cfg *config.Config, msgBus *bus.MessageBus) *autonomy.E
NotifyCooldownSec: a.NotifyCooldownSec, NotifyCooldownSec: a.NotifyCooldownSec,
QuietHours: a.QuietHours, QuietHours: a.QuietHours,
UserIdleResumeSec: a.UserIdleResumeSec, UserIdleResumeSec: a.UserIdleResumeSec,
WaitingResumeDebounceSec: a.WaitingResumeDebounceSec,
Workspace: cfg.WorkspacePath(), Workspace: cfg.WorkspacePath(),
DefaultNotifyChannel: a.NotifyChannel, DefaultNotifyChannel: a.NotifyChannel,
DefaultNotifyChatID: a.NotifyChatID, DefaultNotifyChatID: a.NotifyChatID,

View File

@@ -132,6 +132,7 @@ func statusCmd() {
fmt.Printf(" - %s\n", key) fmt.Printf(" - %s\n", key)
} }
} }
fmt.Printf("Autonomy Config: idle_resume=%ds waiting_debounce=%ds\n", cfg.Agents.Defaults.Autonomy.UserIdleResumeSec, cfg.Agents.Defaults.Autonomy.WaitingResumeDebounceSec)
if summary, prio, reasons, nextRetry, dedupeHits, err := collectAutonomyTaskSummary(filepath.Join(workspace, "memory", "tasks.json")); err == nil { if summary, prio, reasons, nextRetry, dedupeHits, err := collectAutonomyTaskSummary(filepath.Join(workspace, "memory", "tasks.json")); err == nil {
fmt.Printf("Autonomy Tasks: todo=%d doing=%d waiting=%d blocked=%d done=%d dedupe_hits=%d\n", summary["todo"], summary["doing"], summary["waiting"], summary["blocked"], summary["done"], dedupeHits) fmt.Printf("Autonomy Tasks: todo=%d doing=%d waiting=%d blocked=%d done=%d dedupe_hits=%d\n", summary["todo"], summary["doing"], summary["waiting"], summary["blocked"], summary["done"], dedupeHits)
fmt.Printf("Autonomy Priority: high=%d normal=%d low=%d\n", prio["high"], prio["normal"], prio["low"]) fmt.Printf("Autonomy Priority: high=%d normal=%d low=%d\n", prio["high"], prio["normal"], prio["low"])

View File

@@ -23,6 +23,7 @@
"notify_cooldown_sec": 300, "notify_cooldown_sec": 300,
"quiet_hours": "23:00-08:00", "quiet_hours": "23:00-08:00",
"user_idle_resume_sec": 20, "user_idle_resume_sec": 20,
"waiting_resume_debounce_sec": 5,
"notify_channel": "", "notify_channel": "",
"notify_chat_id": "" "notify_chat_id": ""
}, },

View File

@@ -20,18 +20,19 @@ import (
) )
type Options struct { type Options struct {
Enabled bool Enabled bool
TickIntervalSec int TickIntervalSec int
MinRunIntervalSec int MinRunIntervalSec int
MaxPendingDurationSec int MaxPendingDurationSec int
MaxConsecutiveStalls int MaxConsecutiveStalls int
MaxDispatchPerTick int MaxDispatchPerTick int
Workspace string Workspace string
DefaultNotifyChannel string DefaultNotifyChannel string
DefaultNotifyChatID string DefaultNotifyChatID string
NotifyCooldownSec int NotifyCooldownSec int
QuietHours string QuietHours string
UserIdleResumeSec int UserIdleResumeSec int
WaitingResumeDebounceSec int
} }
type taskState struct { type taskState struct {
@@ -82,6 +83,9 @@ func NewEngine(opts Options, msgBus *bus.MessageBus) *Engine {
if opts.UserIdleResumeSec <= 0 { if opts.UserIdleResumeSec <= 0 {
opts.UserIdleResumeSec = 20 opts.UserIdleResumeSec = 20
} }
if opts.WaitingResumeDebounceSec <= 0 {
opts.WaitingResumeDebounceSec = 5
}
return &Engine{ return &Engine{
opts: opts, opts: opts,
bus: msgBus, bus: msgBus,
@@ -227,7 +231,7 @@ func (e *Engine) tick() {
} }
if st.Status == "waiting" { if st.Status == "waiting" {
// Debounce waiting/resume flapping // Debounce waiting/resume flapping
if !st.WaitingSince.IsZero() && now.Sub(st.WaitingSince) < 5*time.Second { if !st.WaitingSince.IsZero() && now.Sub(st.WaitingSince) < time.Duration(e.opts.WaitingResumeDebounceSec)*time.Second {
continue continue
} }
reason := st.BlockReason reason := st.BlockReason

View File

@@ -45,17 +45,18 @@ type AgentDefaults struct {
} }
type AutonomyConfig struct { type AutonomyConfig struct {
Enabled bool `json:"enabled" env:"CLAWGO_AGENTS_DEFAULTS_AUTONOMY_ENABLED"` Enabled bool `json:"enabled" env:"CLAWGO_AGENTS_DEFAULTS_AUTONOMY_ENABLED"`
TickIntervalSec int `json:"tick_interval_sec" env:"CLAWGO_AGENTS_DEFAULTS_AUTONOMY_TICK_INTERVAL_SEC"` TickIntervalSec int `json:"tick_interval_sec" env:"CLAWGO_AGENTS_DEFAULTS_AUTONOMY_TICK_INTERVAL_SEC"`
MinRunIntervalSec int `json:"min_run_interval_sec" env:"CLAWGO_AGENTS_DEFAULTS_AUTONOMY_MIN_RUN_INTERVAL_SEC"` MinRunIntervalSec int `json:"min_run_interval_sec" env:"CLAWGO_AGENTS_DEFAULTS_AUTONOMY_MIN_RUN_INTERVAL_SEC"`
MaxPendingDurationSec int `json:"max_pending_duration_sec" env:"CLAWGO_AGENTS_DEFAULTS_AUTONOMY_MAX_PENDING_DURATION_SEC"` MaxPendingDurationSec int `json:"max_pending_duration_sec" env:"CLAWGO_AGENTS_DEFAULTS_AUTONOMY_MAX_PENDING_DURATION_SEC"`
MaxConsecutiveStalls int `json:"max_consecutive_stalls" env:"CLAWGO_AGENTS_DEFAULTS_AUTONOMY_MAX_CONSECUTIVE_STALLS"` MaxConsecutiveStalls int `json:"max_consecutive_stalls" env:"CLAWGO_AGENTS_DEFAULTS_AUTONOMY_MAX_CONSECUTIVE_STALLS"`
MaxDispatchPerTick int `json:"max_dispatch_per_tick" env:"CLAWGO_AGENTS_DEFAULTS_AUTONOMY_MAX_DISPATCH_PER_TICK"` MaxDispatchPerTick int `json:"max_dispatch_per_tick" env:"CLAWGO_AGENTS_DEFAULTS_AUTONOMY_MAX_DISPATCH_PER_TICK"`
NotifyCooldownSec int `json:"notify_cooldown_sec" env:"CLAWGO_AGENTS_DEFAULTS_AUTONOMY_NOTIFY_COOLDOWN_SEC"` NotifyCooldownSec int `json:"notify_cooldown_sec" env:"CLAWGO_AGENTS_DEFAULTS_AUTONOMY_NOTIFY_COOLDOWN_SEC"`
QuietHours string `json:"quiet_hours" env:"CLAWGO_AGENTS_DEFAULTS_AUTONOMY_QUIET_HOURS"` QuietHours string `json:"quiet_hours" env:"CLAWGO_AGENTS_DEFAULTS_AUTONOMY_QUIET_HOURS"`
UserIdleResumeSec int `json:"user_idle_resume_sec" env:"CLAWGO_AGENTS_DEFAULTS_AUTONOMY_USER_IDLE_RESUME_SEC"` UserIdleResumeSec int `json:"user_idle_resume_sec" env:"CLAWGO_AGENTS_DEFAULTS_AUTONOMY_USER_IDLE_RESUME_SEC"`
NotifyChannel string `json:"notify_channel" env:"CLAWGO_AGENTS_DEFAULTS_AUTONOMY_NOTIFY_CHANNEL"` WaitingResumeDebounceSec int `json:"waiting_resume_debounce_sec" env:"CLAWGO_AGENTS_DEFAULTS_AUTONOMY_WAITING_RESUME_DEBOUNCE_SEC"`
NotifyChatID string `json:"notify_chat_id" env:"CLAWGO_AGENTS_DEFAULTS_AUTONOMY_NOTIFY_CHAT_ID"` NotifyChannel string `json:"notify_channel" env:"CLAWGO_AGENTS_DEFAULTS_AUTONOMY_NOTIFY_CHANNEL"`
NotifyChatID string `json:"notify_chat_id" env:"CLAWGO_AGENTS_DEFAULTS_AUTONOMY_NOTIFY_CHAT_ID"`
} }
type AgentTextConfig struct { type AgentTextConfig struct {
@@ -309,6 +310,7 @@ func DefaultConfig() *Config {
NotifyCooldownSec: 300, NotifyCooldownSec: 300,
QuietHours: "23:00-08:00", QuietHours: "23:00-08:00",
UserIdleResumeSec: 20, UserIdleResumeSec: 20,
WaitingResumeDebounceSec: 5,
NotifyChannel: "", NotifyChannel: "",
NotifyChatID: "", NotifyChatID: "",
}, },

View File

@@ -111,6 +111,9 @@ func Validate(cfg *Config) []error {
if aut.UserIdleResumeSec <= 0 { if aut.UserIdleResumeSec <= 0 {
errs = append(errs, fmt.Errorf("agents.defaults.autonomy.user_idle_resume_sec must be > 0 when enabled=true")) errs = append(errs, fmt.Errorf("agents.defaults.autonomy.user_idle_resume_sec must be > 0 when enabled=true"))
} }
if aut.WaitingResumeDebounceSec <= 0 {
errs = append(errs, fmt.Errorf("agents.defaults.autonomy.waiting_resume_debounce_sec must be > 0 when enabled=true"))
}
} }
texts := cfg.Agents.Defaults.Texts texts := cfg.Agents.Defaults.Texts
if strings.TrimSpace(texts.NoResponseFallback) == "" { if strings.TrimSpace(texts.NoResponseFallback) == "" {