mirror of
https://github.com/Significant-Gravitas/AutoGPT.git
synced 2026-04-30 03:00:41 -04:00
feat(frontend/library): wire Agent Briefing to real execution data with live WebSocket updates
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -292,4 +292,4 @@ function filterAgentsByStatus<T extends { id: string }>(
|
||||
if (statusFilter === "healthy") return info.health === "good";
|
||||
return info.status === statusFilter;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,25 +1,104 @@
|
||||
"use client";
|
||||
|
||||
import { useState } from "react";
|
||||
import {
|
||||
getGetV1ListAllExecutionsQueryKey,
|
||||
useGetV1ListAllExecutions,
|
||||
} from "@/app/api/__generated__/endpoints/graphs/graphs";
|
||||
import { AgentExecutionStatus } from "@/app/api/__generated__/models/agentExecutionStatus";
|
||||
import type { LibraryAgent } from "@/app/api/__generated__/models/libraryAgent";
|
||||
import { okData } from "@/app/api/helpers";
|
||||
import { useExecutionEvents } from "@/hooks/useExecutionEvents";
|
||||
import { useQueryClient } from "@tanstack/react-query";
|
||||
import { useCallback, useMemo } from "react";
|
||||
import type { FleetSummary } from "../types";
|
||||
|
||||
/**
|
||||
* Returns fleet-wide summary counts for the Agent Briefing Panel.
|
||||
*
|
||||
* TODO: Replace with a real `GET /agents/summary` API call once available.
|
||||
* For now, returns deterministic mock data so the UI renders correctly.
|
||||
*/
|
||||
export function useLibraryFleetSummary(): FleetSummary {
|
||||
// NOTE: useState initializer runs once on mount; the hardcoded mock values
|
||||
// will not update if the component re-renders. Replace with a real API call
|
||||
// once the backend endpoint is available.
|
||||
const [summary] = useState<FleetSummary>(() => ({
|
||||
running: 3,
|
||||
error: 2,
|
||||
listening: 4,
|
||||
scheduled: 5,
|
||||
idle: 8,
|
||||
monthlySpend: 127.45,
|
||||
}));
|
||||
return summary;
|
||||
const SEVENTY_TWO_HOURS_MS = 72 * 60 * 60 * 1000;
|
||||
|
||||
function isActiveExecution(status: string): boolean {
|
||||
return (
|
||||
status === AgentExecutionStatus.RUNNING ||
|
||||
status === AgentExecutionStatus.QUEUED ||
|
||||
status === AgentExecutionStatus.REVIEW
|
||||
);
|
||||
}
|
||||
|
||||
function isRecentFailure(
|
||||
status: string,
|
||||
endedAt?: string | Date | null,
|
||||
): boolean {
|
||||
if (
|
||||
status !== AgentExecutionStatus.FAILED &&
|
||||
status !== AgentExecutionStatus.TERMINATED
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
if (!endedAt) return false;
|
||||
const ts =
|
||||
endedAt instanceof Date ? endedAt.getTime() : new Date(endedAt).getTime();
|
||||
return Date.now() - ts < SEVENTY_TWO_HOURS_MS;
|
||||
}
|
||||
|
||||
export function useLibraryFleetSummary(
|
||||
agents: LibraryAgent[],
|
||||
): FleetSummary | undefined {
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
const { data: executions, isSuccess } = useGetV1ListAllExecutions({
|
||||
query: { select: okData },
|
||||
});
|
||||
|
||||
const graphIDs = useMemo(() => agents.map((a) => a.graph_id), [agents]);
|
||||
|
||||
const handleExecutionUpdate = useCallback(() => {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: getGetV1ListAllExecutionsQueryKey(),
|
||||
});
|
||||
}, [queryClient]);
|
||||
|
||||
useExecutionEvents({
|
||||
graphIds: graphIDs.length > 0 ? graphIDs : undefined,
|
||||
enabled: graphIDs.length > 0,
|
||||
onExecutionUpdate: handleExecutionUpdate,
|
||||
});
|
||||
|
||||
return useMemo(() => {
|
||||
if (!isSuccess || !executions) return undefined;
|
||||
|
||||
const agentsWithActiveExecution = new Set<string>();
|
||||
const agentsWithRecentFailure = new Set<string>();
|
||||
|
||||
for (const exec of executions) {
|
||||
if (isActiveExecution(exec.status)) {
|
||||
agentsWithActiveExecution.add(exec.graph_id);
|
||||
}
|
||||
if (isRecentFailure(exec.status, exec.ended_at)) {
|
||||
agentsWithRecentFailure.add(exec.graph_id);
|
||||
}
|
||||
}
|
||||
|
||||
const summary: FleetSummary = {
|
||||
running: 0,
|
||||
error: 0,
|
||||
listening: 0,
|
||||
scheduled: 0,
|
||||
idle: 0,
|
||||
monthlySpend: 0,
|
||||
};
|
||||
|
||||
for (const agent of agents) {
|
||||
if (agentsWithActiveExecution.has(agent.graph_id)) {
|
||||
summary.running += 1;
|
||||
} else if (agentsWithRecentFailure.has(agent.graph_id)) {
|
||||
summary.error += 1;
|
||||
} else if (agent.has_external_trigger) {
|
||||
summary.listening += 1;
|
||||
} else if (agent.recommended_schedule_cron) {
|
||||
summary.scheduled += 1;
|
||||
} else {
|
||||
summary.idle += 1;
|
||||
}
|
||||
}
|
||||
|
||||
return summary;
|
||||
}, [agents, executions, isSuccess]);
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ import { FavoriteAnimationProvider } from "./context/FavoriteAnimationContext";
|
||||
import type { LibraryTab, AgentStatusFilter } from "./types";
|
||||
import { useLibraryFleetSummary } from "./hooks/useLibraryFleetSummary";
|
||||
import { Flag, useGetFlag } from "@/services/feature-flags/use-get-flag";
|
||||
import { useLibraryAgents } from "@/hooks/useLibraryAgents/useLibraryAgents";
|
||||
|
||||
const LIBRARY_TABS: LibraryTab[] = [
|
||||
{ id: "all", title: "All", icon: ListIcon },
|
||||
@@ -22,7 +23,8 @@ export default function LibraryPage() {
|
||||
const [activeTab, setActiveTab] = useState(LIBRARY_TABS[0].id);
|
||||
const [statusFilter, setStatusFilter] = useState<AgentStatusFilter>("all");
|
||||
const isAgentBriefingEnabled = useGetFlag(Flag.AGENT_BRIEFING);
|
||||
const fleetSummary = useLibraryFleetSummary();
|
||||
const { agents } = useLibraryAgents();
|
||||
const fleetSummary = useLibraryFleetSummary(agents);
|
||||
|
||||
useEffect(() => {
|
||||
document.title = "Library – AutoGPT Platform";
|
||||
|
||||
Reference in New Issue
Block a user