From 058b21570419c7654aad3b39575ed8d8cf673039 Mon Sep 17 00:00:00 2001 From: DBT Date: Sat, 28 Feb 2026 06:01:29 +0000 Subject: [PATCH] autonomy M1 phase2: expose idle-run source and block reasons in task queue; add whitelist policy plumbing --- pkg/agent/loop.go | 6 ++++++ pkg/nodes/registry_server.go | 37 +++++++++++++++++++++++++++++++++++ webui/src/pages/TaskAudit.tsx | 11 ++++++++++- 3 files changed, 53 insertions(+), 1 deletion(-) diff --git a/pkg/agent/loop.go b/pkg/agent/loop.go index 0322ae1..9f2db01 100644 --- a/pkg/agent/loop.go +++ b/pkg/agent/loop.go @@ -361,6 +361,10 @@ func (al *AgentLoop) appendTaskAuditEvent(taskID string, msg bus.InboundMessage, } path := filepath.Join(al.workspace, "memory", "task-audit.jsonl") _ = os.MkdirAll(filepath.Dir(path), 0755) + source := "direct" + if msg.Metadata != nil && msg.Metadata["trigger"] != "" { + source = msg.Metadata["trigger"] + } row := map[string]interface{}{ "task_id": taskID, "time": time.Now().UTC().Format(time.RFC3339), @@ -369,6 +373,8 @@ func (al *AgentLoop) appendTaskAuditEvent(taskID string, msg bus.InboundMessage, "chat_id": msg.ChatID, "sender_id": msg.SenderID, "status": status, + "source": source, + "idle_run": source == "autonomy", "duration_ms": durationMs, "suppressed": suppressed, "retry_count": 0, diff --git a/pkg/nodes/registry_server.go b/pkg/nodes/registry_server.go index ac5b32f..dcd8280 100644 --- a/pkg/nodes/registry_server.go +++ b/pkg/nodes/registry_server.go @@ -1436,6 +1436,43 @@ func (s *RegistryServer) handleWebUITaskQueue(w http.ResponseWriter, r *http.Req running = append(running, row) } } + + // Merge autonomy queue states (including waiting/blocked-by-user) for full audit visibility. + tasksPath := filepath.Join(strings.TrimSpace(s.workspacePath), "memory", "tasks.json") + if tb, err := os.ReadFile(tasksPath); err == nil { + var tasks []map[string]interface{} + if json.Unmarshal(tb, &tasks) == nil { + seen := map[string]struct{}{} + for _, it := range items { + seen[fmt.Sprintf("%v", it["task_id"])] = struct{}{} + } + for _, t := range tasks { + id := fmt.Sprintf("%v", t["id"]) + if id == "" { + continue + } + if _, ok := seen[id]; ok { + continue + } + row := map[string]interface{}{ + "task_id": id, + "time": t["updated_at"], + "status": t["status"], + "source": t["source"], + "idle_run": true, + "input_preview": t["content"], + "block_reason": t["block_reason"], + "logs": []string{fmt.Sprintf("autonomy state: %v", t["status"])}, + "retry_count": 0, + } + items = append(items, row) + if fmt.Sprintf("%v", row["status"]) == "running" { + running = append(running, row) + } + } + } + } + _ = json.NewEncoder(w).Encode(map[string]interface{}{"ok": true, "running": running, "items": items}) } diff --git a/webui/src/pages/TaskAudit.tsx b/webui/src/pages/TaskAudit.tsx index 5d6d9f7..8bb1980 100644 --- a/webui/src/pages/TaskAudit.tsx +++ b/webui/src/pages/TaskAudit.tsx @@ -10,6 +10,9 @@ type TaskAuditItem = { chat_id?: string; sender_id?: string; status?: string; + source?: string; + idle_run?: boolean; + block_reason?: string; duration_ms?: number; retry_count?: number; error?: string; @@ -72,7 +75,7 @@ const TaskAudit: React.FC = () => { className={`w-full text-left px-3 py-2 border-b border-zinc-800/60 hover:bg-zinc-800/40 ${active ? 'bg-indigo-500/15' : ''}`} >
{it.task_id || `task-${idx + 1}`}
-
{it.channel} · {it.status} · {it.duration_ms || 0}ms · retry:{it.retry_count || 0}
+
{it.channel || '-'} · {it.status} · {it.duration_ms || 0}ms · retry:{it.retry_count || 0} · {it.source || '-'}
{it.time}
); @@ -90,6 +93,7 @@ const TaskAudit: React.FC = () => {
Task ID
{selected.task_id}
Status
{selected.status}
+
Source
{selected.source || '-'}
Duration
{selected.duration_ms || 0}ms
Channel
{selected.channel}
Session
{selected.session}
@@ -106,6 +110,11 @@ const TaskAudit: React.FC = () => {
{selected.error || '-'}
+
+
Block Reason
+
{selected.block_reason || '-'}
+
+
{t('taskLogs')}
{Array.isArray(selected.logs) && selected.logs.length ? selected.logs.join('\n') : '-'}