mirror of
https://github.com/YspCoder/clawgo.git
synced 2026-05-20 02:07:29 +08:00
pause autonomy during active user chats and expose waiting/retry telemetry
This commit is contained in:
@@ -205,7 +205,8 @@ func gatewayCmd() {
|
|||||||
reflect.DeepEqual(cfg.Tools, newCfg.Tools) &&
|
reflect.DeepEqual(cfg.Tools, newCfg.Tools) &&
|
||||||
reflect.DeepEqual(cfg.Channels, newCfg.Channels)
|
reflect.DeepEqual(cfg.Channels, newCfg.Channels)
|
||||||
|
|
||||||
changes := summarizeDialogTemplateChanges(cfg, newCfg)
|
templateChanges := summarizeDialogTemplateChanges(cfg, newCfg)
|
||||||
|
autonomyChanges := summarizeAutonomyChanges(cfg, newCfg)
|
||||||
|
|
||||||
if runtimeSame {
|
if runtimeSame {
|
||||||
configureLogging(newCfg)
|
configureLogging(newCfg)
|
||||||
@@ -230,8 +231,11 @@ func gatewayCmd() {
|
|||||||
sentinelService.Start()
|
sentinelService.Start()
|
||||||
}
|
}
|
||||||
cfg = newCfg
|
cfg = newCfg
|
||||||
if len(changes) > 0 {
|
if len(templateChanges) > 0 {
|
||||||
fmt.Printf("↻ Dialog template changes: %s\n", strings.Join(changes, ", "))
|
fmt.Printf("↻ Dialog template changes: %s\n", strings.Join(templateChanges, ", "))
|
||||||
|
}
|
||||||
|
if len(autonomyChanges) > 0 {
|
||||||
|
fmt.Printf("↻ Autonomy changes: %s\n", strings.Join(autonomyChanges, ", "))
|
||||||
}
|
}
|
||||||
fmt.Println("✓ Config hot-reload applied (logging/metadata only)")
|
fmt.Println("✓ Config hot-reload applied (logging/metadata only)")
|
||||||
continue
|
continue
|
||||||
@@ -275,8 +279,11 @@ func gatewayCmd() {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
go agentLoop.Run(ctx)
|
go agentLoop.Run(ctx)
|
||||||
if len(changes) > 0 {
|
if len(templateChanges) > 0 {
|
||||||
fmt.Printf("↻ Dialog template changes: %s\n", strings.Join(changes, ", "))
|
fmt.Printf("↻ Dialog template changes: %s\n", strings.Join(templateChanges, ", "))
|
||||||
|
}
|
||||||
|
if len(autonomyChanges) > 0 {
|
||||||
|
fmt.Printf("↻ Autonomy changes: %s\n", strings.Join(autonomyChanges, ", "))
|
||||||
}
|
}
|
||||||
fmt.Println("✓ Config hot-reload applied")
|
fmt.Println("✓ Config hot-reload applied")
|
||||||
default:
|
default:
|
||||||
@@ -294,6 +301,34 @@ func gatewayCmd() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func summarizeAutonomyChanges(oldCfg, newCfg *config.Config) []string {
|
||||||
|
if oldCfg == nil || newCfg == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
o := oldCfg.Agents.Defaults.Autonomy
|
||||||
|
n := newCfg.Agents.Defaults.Autonomy
|
||||||
|
changes := make([]string, 0)
|
||||||
|
if o.Enabled != n.Enabled {
|
||||||
|
changes = append(changes, "enabled")
|
||||||
|
}
|
||||||
|
if o.TickIntervalSec != n.TickIntervalSec {
|
||||||
|
changes = append(changes, "tick_interval_sec")
|
||||||
|
}
|
||||||
|
if o.MinRunIntervalSec != n.MinRunIntervalSec {
|
||||||
|
changes = append(changes, "min_run_interval_sec")
|
||||||
|
}
|
||||||
|
if o.UserIdleResumeSec != n.UserIdleResumeSec {
|
||||||
|
changes = append(changes, "user_idle_resume_sec")
|
||||||
|
}
|
||||||
|
if strings.TrimSpace(o.QuietHours) != strings.TrimSpace(n.QuietHours) {
|
||||||
|
changes = append(changes, "quiet_hours")
|
||||||
|
}
|
||||||
|
if o.NotifyCooldownSec != n.NotifyCooldownSec {
|
||||||
|
changes = append(changes, "notify_cooldown_sec")
|
||||||
|
}
|
||||||
|
return changes
|
||||||
|
}
|
||||||
|
|
||||||
func summarizeDialogTemplateChanges(oldCfg, newCfg *config.Config) []string {
|
func summarizeDialogTemplateChanges(oldCfg, newCfg *config.Config) []string {
|
||||||
if oldCfg == nil || newCfg == nil {
|
if oldCfg == nil || newCfg == nil {
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
@@ -130,7 +130,7 @@ func statusCmd() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if summary, nextRetry, dedupeHits, err := collectAutonomyTaskSummary(filepath.Join(workspace, "memory", "tasks.json")); err == nil {
|
if summary, nextRetry, dedupeHits, err := collectAutonomyTaskSummary(filepath.Join(workspace, "memory", "tasks.json")); err == nil {
|
||||||
fmt.Printf("Autonomy Tasks: todo=%d doing=%d blocked=%d done=%d dedupe_hits=%d\n", summary["todo"], summary["doing"], 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)
|
||||||
if nextRetry != "" {
|
if nextRetry != "" {
|
||||||
fmt.Printf("Autonomy Next Retry: %s\n", nextRetry)
|
fmt.Printf("Autonomy Next Retry: %s\n", nextRetry)
|
||||||
}
|
}
|
||||||
@@ -252,7 +252,7 @@ func collectAutonomyTaskSummary(path string) (map[string]int, string, int, error
|
|||||||
data, err := os.ReadFile(path)
|
data, err := os.ReadFile(path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if os.IsNotExist(err) {
|
if os.IsNotExist(err) {
|
||||||
return map[string]int{"todo": 0, "doing": 0, "blocked": 0, "done": 0}, "", 0, nil
|
return map[string]int{"todo": 0, "doing": 0, "waiting": 0, "blocked": 0, "done": 0}, "", 0, nil
|
||||||
}
|
}
|
||||||
return nil, "", 0, err
|
return nil, "", 0, err
|
||||||
}
|
}
|
||||||
@@ -264,7 +264,7 @@ func collectAutonomyTaskSummary(path string) (map[string]int, string, int, error
|
|||||||
if err := json.Unmarshal(data, &items); err != nil {
|
if err := json.Unmarshal(data, &items); err != nil {
|
||||||
return nil, "", 0, err
|
return nil, "", 0, err
|
||||||
}
|
}
|
||||||
summary := map[string]int{"todo": 0, "doing": 0, "blocked": 0, "done": 0}
|
summary := map[string]int{"todo": 0, "doing": 0, "waiting": 0, "blocked": 0, "done": 0}
|
||||||
nextRetry := ""
|
nextRetry := ""
|
||||||
nextRetryAt := time.Time{}
|
nextRetryAt := time.Time{}
|
||||||
totalDedupe := 0
|
totalDedupe := 0
|
||||||
|
|||||||
@@ -123,6 +123,7 @@ func (e *Engine) tick() {
|
|||||||
for _, st := range e.state {
|
for _, st := range e.state {
|
||||||
if st.Status == "running" {
|
if st.Status == "running" {
|
||||||
st.Status = "waiting"
|
st.Status = "waiting"
|
||||||
|
e.writeReflectLog("waiting", st, "paused due to active user conversation")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
e.persistStateLocked()
|
e.persistStateLocked()
|
||||||
@@ -204,6 +205,10 @@ func (e *Engine) tick() {
|
|||||||
if st.Status == "completed" {
|
if st.Status == "completed" {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
if st.Status == "waiting" {
|
||||||
|
st.Status = "idle"
|
||||||
|
e.writeReflectLog("resume", st, "user conversation idle, autonomy resumed")
|
||||||
|
}
|
||||||
if st.Status == "blocked" {
|
if st.Status == "blocked" {
|
||||||
if !st.RetryAfter.IsZero() && now.Before(st.RetryAfter) {
|
if !st.RetryAfter.IsZero() && now.Before(st.RetryAfter) {
|
||||||
continue
|
continue
|
||||||
@@ -437,6 +442,8 @@ func (e *Engine) persistStateLocked() {
|
|||||||
switch st.Status {
|
switch st.Status {
|
||||||
case "running":
|
case "running":
|
||||||
status = "doing"
|
status = "doing"
|
||||||
|
case "waiting":
|
||||||
|
status = "waiting"
|
||||||
case "blocked":
|
case "blocked":
|
||||||
status = "blocked"
|
status = "blocked"
|
||||||
case "completed":
|
case "completed":
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ type TaskItem struct {
|
|||||||
Content string `json:"content"`
|
Content string `json:"content"`
|
||||||
Priority string `json:"priority"`
|
Priority string `json:"priority"`
|
||||||
DueAt string `json:"due_at,omitempty"`
|
DueAt string `json:"due_at,omitempty"`
|
||||||
Status string `json:"status"` // todo|doing|blocked|done
|
Status string `json:"status"` // todo|doing|waiting|blocked|done
|
||||||
RetryAfter string `json:"retry_after,omitempty"`
|
RetryAfter string `json:"retry_after,omitempty"`
|
||||||
Source string `json:"source"`
|
Source string `json:"source"`
|
||||||
DedupeHits int `json:"dedupe_hits,omitempty"`
|
DedupeHits int `json:"dedupe_hits,omitempty"`
|
||||||
|
|||||||
Reference in New Issue
Block a user