feat(operations): פאנל בריאות-הסוכנים + הסלמות אחרונות ב-/operations (#218+#222 UI)
הטמעת מוקאפ 02e (מאושר Claude-Design X17) — נראות שרת-הצד שנבנתה כ-backend: - backend: get_recent_escalations() ב-paperclip_client — משחזר הסלמות מהערות author_type='system' (severity+reason מנותחים מהגוף, identifier מ-join); Port pc_get_recent_escalations (read-only); endpoint GET /api/operations/agents/escalations. - frontend: useAgentHealth + useRecentEscalations (טיפוסים מקומיים כמו שאר operations.ts) + AgentHealthPanel ב-/operations תחת "בריאות-הסוכנים": 4 stat-tiles (זומבי/תקוע/עובד/רגוע), שורות-בעיה worst-first, וקארד הסלמות-אוטומטיות-אחרונות (severity+תיק+סיבה+מתי). דיוק מול המוקאפ: issue מוסלם עובר לבעלות-חיים→יוצא מרשימת-הבריאות, לכן שורות-הבריאות = זומבים טרם-הסלמה וקארד-ההסלמות = מטופלים (משלימים). Invariants: G12 (fetch מהמעטפת, המגע מהשער; UI צורך endpoint דומייני), G2 (מקור-בריאות/הסלמות יחיד). שער-עיצוב: מוקאפ 02e אושר לפני קוד (feedback_claude_design_gate). בדיקות: 13 pytest (2 חדשות ל-get_recent_escalations: parse severity/reason, fallback). frontend: tsc --noEmit + eslint נקיים (build מלא ב-CI/deploy — symlink node_modules שובר next build ב-worktree). api:types לא נדרש (operations.ts טיפוסים ידניים); ה-endpoint נפרס אטומית עם ה-UI. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -190,6 +190,61 @@ export function useAgentRuns() {
|
||||
});
|
||||
}
|
||||
|
||||
// ── Agent health taxonomy (#222) + recent escalations (#218) ───────────────
|
||||
export type AgentHealthState = "zombie" | "stalled" | "working" | "idle";
|
||||
|
||||
export type AgentHealthItem = {
|
||||
issue_id: string;
|
||||
identifier: string;
|
||||
status: string;
|
||||
agent_id: string;
|
||||
agent_name: string;
|
||||
health: AgentHealthState;
|
||||
wakeups: number;
|
||||
recovery_wakeups: number;
|
||||
};
|
||||
|
||||
export type AgentHealthResponse = {
|
||||
ok: boolean;
|
||||
items: AgentHealthItem[]; // worst-first (zombie → stalled → working → idle)
|
||||
counts: Record<AgentHealthState, number>;
|
||||
};
|
||||
|
||||
/** Per-issue agent health — surfaces recovery-loop zombies automatically. */
|
||||
export function useAgentHealth() {
|
||||
return useQuery({
|
||||
queryKey: ["operations", "agents", "health"],
|
||||
queryFn: ({ signal }) =>
|
||||
apiRequest<AgentHealthResponse>("/api/operations/agents/health", { signal }),
|
||||
refetchInterval: 5000, // live alongside the running-agents view
|
||||
staleTime: 3000,
|
||||
});
|
||||
}
|
||||
|
||||
export type EscalationItem = {
|
||||
issue_id: string;
|
||||
identifier: string;
|
||||
severity: "critical" | "high" | "medium";
|
||||
reason: string;
|
||||
created_at: string | null;
|
||||
};
|
||||
|
||||
export type RecentEscalationsResponse = {
|
||||
ok: boolean;
|
||||
items: EscalationItem[]; // newest-first
|
||||
};
|
||||
|
||||
/** Recent chair escalations (watchdog + manual) — the handled-loop history. */
|
||||
export function useRecentEscalations() {
|
||||
return useQuery({
|
||||
queryKey: ["operations", "agents", "escalations"],
|
||||
queryFn: ({ signal }) =>
|
||||
apiRequest<RecentEscalationsResponse>("/api/operations/agents/escalations", { signal }),
|
||||
refetchInterval: 15000, // escalations change slowly (watchdog runs every 15m)
|
||||
staleTime: 10000,
|
||||
});
|
||||
}
|
||||
|
||||
/** Full output log of one run — fetched on demand (drawer open). */
|
||||
export function useRunLog(runId: string | null) {
|
||||
return useQuery({
|
||||
|
||||
Reference in New Issue
Block a user