mirror of
https://github.com/0xWheatyz/handler.git
synced 2026-08-30 04:36:24 +00:00
feat(control,api,ui): worker liveness + run event stream (phase 3)
- worker: heartbeat every loop pass (workers registry); reaper pass
every ~15s marks a silent worker's running runs crashed and flips
agents stuck in 'working' to crashed (paused/blocked keep their
still-accurate status). Idempotent via finish_run's running-guard;
any surviving worker can reap; no auto-requeue (half-done runs may
have pushed). Dead workers' registry rows are dropped once settled.
- api: GET /projects/{p}/agents/{name}/events - the persisted
stream-json event log, oldest-first, cursor-paged by row id;
AgentOut exposes session_id/worker_id
- frontend: Run events panel in the run detail (assistant text, tool
chips, result footer with cost/turns, runner notices, raw lines),
cursor-appended on the existing 5s poll; 'Crashed' filter + danger
badge; crashed agents show their frozen last frame ('last output
before crash'); static export regenerated
Suite 290 -> 296 green; next build clean.
This commit is contained in:
+20
-2
@@ -30,10 +30,28 @@ export interface Agent {
|
||||
working_dir: string;
|
||||
status: string;
|
||||
role?: string | null;
|
||||
/* Latest tmux pane-tail snapshot from the worker, so the UI can show what a running
|
||||
* agent is actually doing (and expose one wedged on an interactive prompt). */
|
||||
/* Latest output snapshot from the worker: the tmux pane tail for legacy agents, the
|
||||
* latest assistant text for headless runs. For a crashed agent this is the evidence
|
||||
* frame — the last thing the process said. */
|
||||
last_output?: string | null;
|
||||
output_at?: string | null;
|
||||
/* Headless runner: claude session UUID (null = legacy tmux agent) + supervising worker. */
|
||||
session_id?: string | null;
|
||||
worker_id?: string | null;
|
||||
created_at: string;
|
||||
}
|
||||
|
||||
/* One persisted stream-json event of a headless run (GET .../events, cursor-paged by id).
|
||||
* `type` mirrors the stream (system/assistant/user/result) plus `worker` (runner notices)
|
||||
* and `raw` (unparseable line kept verbatim). */
|
||||
export interface AgentEvent {
|
||||
id: number;
|
||||
agent_id: number;
|
||||
run_id: number;
|
||||
session_id?: string | null;
|
||||
seq: number;
|
||||
type: string;
|
||||
payload?: Record<string, unknown> | null;
|
||||
created_at: string;
|
||||
}
|
||||
|
||||
|
||||
@@ -21,6 +21,7 @@ export function statusTone(status: string | null | undefined): Tone {
|
||||
case "blocked":
|
||||
case "rejected":
|
||||
case "error":
|
||||
case "crashed":
|
||||
return "danger";
|
||||
case "pending":
|
||||
case "queued":
|
||||
|
||||
Reference in New Issue
Block a user