mirror of
https://github.com/YspCoder/clawgo.git
synced 2026-06-11 04:13:09 +08:00
prioritize user conversations by pausing autonomy and expose retry/dedupe telemetry
This commit is contained in:
@@ -650,6 +650,7 @@ func buildAutonomyEngine(cfg *config.Config, msgBus *bus.MessageBus) *autonomy.E
|
|||||||
MaxDispatchPerTick: a.MaxDispatchPerTick,
|
MaxDispatchPerTick: a.MaxDispatchPerTick,
|
||||||
NotifyCooldownSec: a.NotifyCooldownSec,
|
NotifyCooldownSec: a.NotifyCooldownSec,
|
||||||
QuietHours: a.QuietHours,
|
QuietHours: a.QuietHours,
|
||||||
|
UserIdleResumeSec: a.UserIdleResumeSec,
|
||||||
Workspace: cfg.WorkspacePath(),
|
Workspace: cfg.WorkspacePath(),
|
||||||
DefaultNotifyChannel: a.NotifyChannel,
|
DefaultNotifyChannel: a.NotifyChannel,
|
||||||
DefaultNotifyChatID: a.NotifyChatID,
|
DefaultNotifyChatID: a.NotifyChatID,
|
||||||
|
|||||||
@@ -22,6 +22,7 @@
|
|||||||
"max_dispatch_per_tick": 2,
|
"max_dispatch_per_tick": 2,
|
||||||
"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,
|
||||||
"notify_channel": "",
|
"notify_channel": "",
|
||||||
"notify_chat_id": ""
|
"notify_chat_id": ""
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"crypto/sha1"
|
"crypto/sha1"
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
@@ -29,6 +30,7 @@ type Options struct {
|
|||||||
DefaultNotifyChatID string
|
DefaultNotifyChatID string
|
||||||
NotifyCooldownSec int
|
NotifyCooldownSec int
|
||||||
QuietHours string
|
QuietHours string
|
||||||
|
UserIdleResumeSec int
|
||||||
}
|
}
|
||||||
|
|
||||||
type taskState struct {
|
type taskState struct {
|
||||||
@@ -74,6 +76,9 @@ func NewEngine(opts Options, msgBus *bus.MessageBus) *Engine {
|
|||||||
if opts.NotifyCooldownSec <= 0 {
|
if opts.NotifyCooldownSec <= 0 {
|
||||||
opts.NotifyCooldownSec = 300
|
opts.NotifyCooldownSec = 300
|
||||||
}
|
}
|
||||||
|
if opts.UserIdleResumeSec <= 0 {
|
||||||
|
opts.UserIdleResumeSec = 20
|
||||||
|
}
|
||||||
return &Engine{
|
return &Engine{
|
||||||
opts: opts,
|
opts: opts,
|
||||||
bus: msgBus,
|
bus: msgBus,
|
||||||
@@ -113,6 +118,19 @@ func (e *Engine) tick() {
|
|||||||
now := time.Now()
|
now := time.Now()
|
||||||
stored, _ := e.taskStore.Load()
|
stored, _ := e.taskStore.Load()
|
||||||
|
|
||||||
|
e.mu.Lock()
|
||||||
|
if e.hasRecentUserActivity(now) {
|
||||||
|
for _, st := range e.state {
|
||||||
|
if st.Status == "running" {
|
||||||
|
st.Status = "waiting"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
e.persistStateLocked()
|
||||||
|
e.mu.Unlock()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
e.mu.Unlock()
|
||||||
|
|
||||||
e.mu.Lock()
|
e.mu.Lock()
|
||||||
defer e.mu.Unlock()
|
defer e.mu.Unlock()
|
||||||
|
|
||||||
@@ -500,6 +518,38 @@ func dueWeight(dueAt string) int64 {
|
|||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (e *Engine) hasRecentUserActivity(now time.Time) bool {
|
||||||
|
if e.opts.UserIdleResumeSec <= 0 || strings.TrimSpace(e.opts.Workspace) == "" {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
// sessions are stored next to workspace directory in clawgo runtime
|
||||||
|
sessionsPath := filepath.Join(filepath.Dir(e.opts.Workspace), "sessions", "sessions.json")
|
||||||
|
data, err := os.ReadFile(sessionsPath)
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
var index map[string]struct {
|
||||||
|
Kind string `json:"kind"`
|
||||||
|
UpdatedAt int64 `json:"updatedAt"`
|
||||||
|
}
|
||||||
|
if err := json.Unmarshal(data, &index); err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
cutoff := now.Add(-time.Duration(e.opts.UserIdleResumeSec) * time.Second)
|
||||||
|
for _, row := range index {
|
||||||
|
if strings.ToLower(strings.TrimSpace(row.Kind)) != "main" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if row.UpdatedAt <= 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if time.UnixMilli(row.UpdatedAt).After(cutoff) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
func blockedRetryBackoff(stalls int, minRunIntervalSec int) time.Duration {
|
func blockedRetryBackoff(stalls int, minRunIntervalSec int) time.Duration {
|
||||||
if minRunIntervalSec <= 0 {
|
if minRunIntervalSec <= 0 {
|
||||||
minRunIntervalSec = 20
|
minRunIntervalSec = 20
|
||||||
|
|||||||
@@ -53,6 +53,7 @@ type AutonomyConfig struct {
|
|||||||
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"`
|
||||||
NotifyChannel string `json:"notify_channel" env:"CLAWGO_AGENTS_DEFAULTS_AUTONOMY_NOTIFY_CHANNEL"`
|
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"`
|
NotifyChatID string `json:"notify_chat_id" env:"CLAWGO_AGENTS_DEFAULTS_AUTONOMY_NOTIFY_CHAT_ID"`
|
||||||
}
|
}
|
||||||
@@ -307,6 +308,7 @@ func DefaultConfig() *Config {
|
|||||||
MaxDispatchPerTick: 2,
|
MaxDispatchPerTick: 2,
|
||||||
NotifyCooldownSec: 300,
|
NotifyCooldownSec: 300,
|
||||||
QuietHours: "23:00-08:00",
|
QuietHours: "23:00-08:00",
|
||||||
|
UserIdleResumeSec: 20,
|
||||||
NotifyChannel: "",
|
NotifyChannel: "",
|
||||||
NotifyChatID: "",
|
NotifyChatID: "",
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -108,6 +108,9 @@ func Validate(cfg *Config) []error {
|
|||||||
errs = append(errs, fmt.Errorf("agents.defaults.autonomy.quiet_hours must be HH:MM-HH:MM"))
|
errs = append(errs, fmt.Errorf("agents.defaults.autonomy.quiet_hours must be HH:MM-HH:MM"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if aut.UserIdleResumeSec <= 0 {
|
||||||
|
errs = append(errs, fmt.Errorf("agents.defaults.autonomy.user_idle_resume_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) == "" {
|
||||||
|
|||||||
Reference in New Issue
Block a user