mirror of
https://github.com/YspCoder/clawgo.git
synced 2026-05-20 23:57:30 +08:00
improve autonomy user-priority detection and add waiting/retry/priority telemetry
This commit is contained in:
@@ -129,8 +129,9 @@ func statusCmd() {
|
|||||||
fmt.Printf(" - %s\n", key)
|
fmt.Printf(" - %s\n", key)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if summary, nextRetry, dedupeHits, err := collectAutonomyTaskSummary(filepath.Join(workspace, "memory", "tasks.json")); err == nil {
|
if summary, prio, 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"])
|
||||||
if nextRetry != "" {
|
if nextRetry != "" {
|
||||||
fmt.Printf("Autonomy Next Retry: %s\n", nextRetry)
|
fmt.Printf("Autonomy Next Retry: %s\n", nextRetry)
|
||||||
}
|
}
|
||||||
@@ -248,23 +249,25 @@ func collectTriggerErrorCounts(path string) (map[string]int, error) {
|
|||||||
return counts, nil
|
return counts, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func collectAutonomyTaskSummary(path string) (map[string]int, string, int, error) {
|
func collectAutonomyTaskSummary(path string) (map[string]int, 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, "waiting": 0, "blocked": 0, "done": 0}, "", 0, nil
|
return map[string]int{"todo": 0, "doing": 0, "waiting": 0, "blocked": 0, "done": 0}, map[string]int{"high": 0, "normal": 0, "low": 0}, "", 0, nil
|
||||||
}
|
}
|
||||||
return nil, "", 0, err
|
return nil, nil, "", 0, err
|
||||||
}
|
}
|
||||||
var items []struct {
|
var items []struct {
|
||||||
Status string `json:"status"`
|
Status string `json:"status"`
|
||||||
|
Priority string `json:"priority"`
|
||||||
RetryAfter string `json:"retry_after"`
|
RetryAfter string `json:"retry_after"`
|
||||||
DedupeHits int `json:"dedupe_hits"`
|
DedupeHits int `json:"dedupe_hits"`
|
||||||
}
|
}
|
||||||
if err := json.Unmarshal(data, &items); err != nil {
|
if err := json.Unmarshal(data, &items); err != nil {
|
||||||
return nil, "", 0, err
|
return nil, nil, "", 0, err
|
||||||
}
|
}
|
||||||
summary := map[string]int{"todo": 0, "doing": 0, "waiting": 0, "blocked": 0, "done": 0}
|
summary := map[string]int{"todo": 0, "doing": 0, "waiting": 0, "blocked": 0, "done": 0}
|
||||||
|
priorities := map[string]int{"high": 0, "normal": 0, "low": 0}
|
||||||
nextRetry := ""
|
nextRetry := ""
|
||||||
nextRetryAt := time.Time{}
|
nextRetryAt := time.Time{}
|
||||||
totalDedupe := 0
|
totalDedupe := 0
|
||||||
@@ -274,6 +277,12 @@ func collectAutonomyTaskSummary(path string) (map[string]int, string, int, error
|
|||||||
summary[s]++
|
summary[s]++
|
||||||
}
|
}
|
||||||
totalDedupe += it.DedupeHits
|
totalDedupe += it.DedupeHits
|
||||||
|
p := strings.ToLower(strings.TrimSpace(it.Priority))
|
||||||
|
if _, ok := priorities[p]; ok {
|
||||||
|
priorities[p]++
|
||||||
|
} else {
|
||||||
|
priorities["normal"]++
|
||||||
|
}
|
||||||
if strings.TrimSpace(it.RetryAfter) != "" {
|
if strings.TrimSpace(it.RetryAfter) != "" {
|
||||||
if t, err := time.Parse(time.RFC3339, it.RetryAfter); err == nil {
|
if t, err := time.Parse(time.RFC3339, it.RetryAfter); err == nil {
|
||||||
if nextRetryAt.IsZero() || t.Before(nextRetryAt) {
|
if nextRetryAt.IsZero() || t.Before(nextRetryAt) {
|
||||||
@@ -283,7 +292,7 @@ func collectAutonomyTaskSummary(path string) (map[string]int, string, int, error
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return summary, nextRetry, totalDedupe, nil
|
return summary, priorities, nextRetry, totalDedupe, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func collectRecentSubagentSessions(sessionsDir string, limit int) ([]string, error) {
|
func collectRecentSubagentSessions(sessionsDir string, limit int) ([]string, error) {
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package autonomy
|
package autonomy
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bufio"
|
||||||
"context"
|
"context"
|
||||||
"crypto/sha1"
|
"crypto/sha1"
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
@@ -529,15 +530,14 @@ func (e *Engine) hasRecentUserActivity(now time.Time) bool {
|
|||||||
if e.opts.UserIdleResumeSec <= 0 || strings.TrimSpace(e.opts.Workspace) == "" {
|
if e.opts.UserIdleResumeSec <= 0 || strings.TrimSpace(e.opts.Workspace) == "" {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
// sessions are stored next to workspace directory in clawgo runtime
|
|
||||||
sessionsPath := filepath.Join(filepath.Dir(e.opts.Workspace), "sessions", "sessions.json")
|
sessionsPath := filepath.Join(filepath.Dir(e.opts.Workspace), "sessions", "sessions.json")
|
||||||
data, err := os.ReadFile(sessionsPath)
|
data, err := os.ReadFile(sessionsPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
var index map[string]struct {
|
var index map[string]struct {
|
||||||
Kind string `json:"kind"`
|
Kind string `json:"kind"`
|
||||||
UpdatedAt int64 `json:"updatedAt"`
|
SessionFile string `json:"sessionFile"`
|
||||||
}
|
}
|
||||||
if err := json.Unmarshal(data, &index); err != nil {
|
if err := json.Unmarshal(data, &index); err != nil {
|
||||||
return false
|
return false
|
||||||
@@ -547,16 +547,60 @@ func (e *Engine) hasRecentUserActivity(now time.Time) bool {
|
|||||||
if strings.ToLower(strings.TrimSpace(row.Kind)) != "main" {
|
if strings.ToLower(strings.TrimSpace(row.Kind)) != "main" {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if row.UpdatedAt <= 0 {
|
if strings.TrimSpace(row.SessionFile) == "" {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if time.UnixMilli(row.UpdatedAt).After(cutoff) {
|
if ts := latestUserMessageTime(row.SessionFile); !ts.IsZero() && ts.After(cutoff) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func latestUserMessageTime(path string) time.Time {
|
||||||
|
f, err := os.Open(path)
|
||||||
|
if err != nil {
|
||||||
|
return time.Time{}
|
||||||
|
}
|
||||||
|
defer f.Close()
|
||||||
|
|
||||||
|
var latest time.Time
|
||||||
|
s := bufio.NewScanner(f)
|
||||||
|
for s.Scan() {
|
||||||
|
line := s.Bytes()
|
||||||
|
|
||||||
|
// OpenClaw-like event line
|
||||||
|
var ev struct {
|
||||||
|
Type string `json:"type"`
|
||||||
|
Timestamp string `json:"timestamp"`
|
||||||
|
Message *struct {
|
||||||
|
Role string `json:"role"`
|
||||||
|
} `json:"message"`
|
||||||
|
}
|
||||||
|
if err := json.Unmarshal(line, &ev); err == nil && ev.Message != nil {
|
||||||
|
if strings.ToLower(strings.TrimSpace(ev.Message.Role)) == "user" {
|
||||||
|
if t, err := time.Parse(time.RFC3339Nano, strings.TrimSpace(ev.Timestamp)); err == nil && t.After(latest) {
|
||||||
|
latest = t
|
||||||
|
} else if t, err := time.Parse(time.RFC3339, strings.TrimSpace(ev.Timestamp)); err == nil && t.After(latest) {
|
||||||
|
latest = t
|
||||||
|
}
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// Legacy line
|
||||||
|
var msg struct {
|
||||||
|
Role string `json:"role"`
|
||||||
|
}
|
||||||
|
if err := json.Unmarshal(line, &msg); err == nil {
|
||||||
|
if strings.ToLower(strings.TrimSpace(msg.Role)) == "user" {
|
||||||
|
latest = time.Now().UTC()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return latest
|
||||||
|
}
|
||||||
|
|
||||||
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
|
||||||
|
|||||||
Reference in New Issue
Block a user