mirror of
https://github.com/Significant-Gravitas/AutoGPT.git
synced 2026-04-30 03:00:41 -04:00
fix(platform): Added updated graph meta to include runs (#8088)
This commit is contained in:
@@ -3,7 +3,8 @@
|
||||
"version": "0.1.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "next dev",
|
||||
"dev": "export NODE_ENV=development && next dev",
|
||||
"dev:test": "export NODE_ENV=test && next dev",
|
||||
"build": "next build",
|
||||
"start": "next start",
|
||||
"lint": "next lint",
|
||||
|
||||
@@ -7,6 +7,8 @@ import * as Sentry from "@sentry/nextjs";
|
||||
Sentry.init({
|
||||
dsn: "https://fe4e4aa4a283391808a5da396da20159@o4505260022104064.ingest.us.sentry.io/4507946746380288",
|
||||
|
||||
enabled: process.env.NODE_ENV !== "development",
|
||||
|
||||
// Add optional integrations for additional features
|
||||
integrations: [
|
||||
Sentry.replayIntegration(),
|
||||
|
||||
@@ -8,6 +8,8 @@ import * as Sentry from "@sentry/nextjs";
|
||||
Sentry.init({
|
||||
dsn: "https://fe4e4aa4a283391808a5da396da20159@o4505260022104064.ingest.us.sentry.io/4507946746380288",
|
||||
|
||||
enabled: process.env.NODE_ENV !== "development",
|
||||
|
||||
// Define how likely traces are sampled. Adjust this value in production, or use tracesSampler for greater control.
|
||||
tracesSampleRate: 1,
|
||||
|
||||
|
||||
@@ -8,6 +8,8 @@ import * as Sentry from "@sentry/nextjs";
|
||||
Sentry.init({
|
||||
dsn: "https://fe4e4aa4a283391808a5da396da20159@o4505260022104064.ingest.us.sentry.io/4507946746380288",
|
||||
|
||||
enabled: process.env.NODE_ENV !== "development",
|
||||
|
||||
// Define how likely traces are sampled. Adjust this value in production, or use tracesSampler for greater control.
|
||||
tracesSampleRate: 1,
|
||||
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
import React, { useCallback, useEffect, useMemo, useState } from "react";
|
||||
|
||||
import AutoGPTServerAPI, {
|
||||
GraphMeta,
|
||||
NodeExecutionResult,
|
||||
GraphMetaWithRuns,
|
||||
ExecutionMeta,
|
||||
} from "@/lib/autogpt-server-api";
|
||||
|
||||
import { Card } from "@/components/ui/card";
|
||||
@@ -17,62 +17,37 @@ import {
|
||||
} from "@/components/monitor";
|
||||
|
||||
const Monitor = () => {
|
||||
const [flows, setFlows] = useState<GraphMeta[]>([]);
|
||||
const [flows, setFlows] = useState<GraphMetaWithRuns[]>([]);
|
||||
const [flowRuns, setFlowRuns] = useState<FlowRun[]>([]);
|
||||
const [selectedFlow, setSelectedFlow] = useState<GraphMeta | null>(null);
|
||||
const [selectedFlow, setSelectedFlow] = useState<GraphMetaWithRuns | null>(
|
||||
null,
|
||||
);
|
||||
const [selectedRun, setSelectedRun] = useState<FlowRun | null>(null);
|
||||
|
||||
const api = useMemo(() => new AutoGPTServerAPI(), []);
|
||||
|
||||
const refreshFlowRuns = useCallback(
|
||||
(flowID: string) => {
|
||||
// Fetch flow run IDs
|
||||
api.listGraphRunIDs(flowID).then((runIDs) =>
|
||||
runIDs.map((runID) => {
|
||||
let run;
|
||||
if (
|
||||
(run = flowRuns.find((fr) => fr.id == runID)) &&
|
||||
!["waiting", "running"].includes(run.status)
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Fetch flow run
|
||||
api.getGraphExecutionInfo(flowID, runID).then((execInfo) =>
|
||||
setFlowRuns((flowRuns) => {
|
||||
if (execInfo.length == 0) return flowRuns;
|
||||
|
||||
const flowRunIndex = flowRuns.findIndex((fr) => fr.id == runID);
|
||||
const flowRun = flowRunFromNodeExecutionResults(execInfo);
|
||||
if (flowRunIndex > -1) {
|
||||
flowRuns.splice(flowRunIndex, 1, flowRun);
|
||||
} else {
|
||||
flowRuns.push(flowRun);
|
||||
}
|
||||
return [...flowRuns];
|
||||
}),
|
||||
);
|
||||
}),
|
||||
const fetchAgents = useCallback(() => {
|
||||
api.listGraphsWithRuns().then((agent) => {
|
||||
setFlows(agent);
|
||||
const flowRuns = agent.flatMap((graph) =>
|
||||
graph.executions != null
|
||||
? graph.executions.map((execution) =>
|
||||
flowRunFromExecutionMeta(graph, execution),
|
||||
)
|
||||
: [],
|
||||
);
|
||||
},
|
||||
[api, flowRuns],
|
||||
);
|
||||
|
||||
const fetchFlowsAndRuns = useCallback(() => {
|
||||
api.listGraphs().then((flows) => {
|
||||
setFlows(flows);
|
||||
flows.map((flow) => refreshFlowRuns(flow.id));
|
||||
setFlowRuns(flowRuns);
|
||||
});
|
||||
}, [api, refreshFlowRuns]);
|
||||
}, [api]);
|
||||
|
||||
useEffect(() => fetchFlowsAndRuns(), [fetchFlowsAndRuns]);
|
||||
useEffect(() => {
|
||||
const intervalId = setInterval(
|
||||
() => flows.map((f) => refreshFlowRuns(f.id)),
|
||||
5000,
|
||||
);
|
||||
fetchAgents();
|
||||
}, [api, fetchAgents]);
|
||||
|
||||
useEffect(() => {
|
||||
const intervalId = setInterval(() => fetchAgents(), 5000);
|
||||
return () => clearInterval(intervalId);
|
||||
}, [flows, refreshFlowRuns]);
|
||||
}, [fetchAgents, flows]);
|
||||
|
||||
const column1 = "md:col-span-2 xl:col-span-3 xxl:col-span-2";
|
||||
const column2 = "md:col-span-3 lg:col-span-2 xl:col-span-3 space-y-4";
|
||||
@@ -87,7 +62,9 @@ const Monitor = () => {
|
||||
selectedFlow={selectedFlow}
|
||||
onSelectFlow={(f) => {
|
||||
setSelectedRun(null);
|
||||
setSelectedFlow(f.id == selectedFlow?.id ? null : f);
|
||||
setSelectedFlow(
|
||||
f.id == selectedFlow?.id ? null : (f as GraphMetaWithRuns),
|
||||
);
|
||||
}}
|
||||
/>
|
||||
<FlowRunsList
|
||||
@@ -123,56 +100,20 @@ const Monitor = () => {
|
||||
);
|
||||
};
|
||||
|
||||
function flowRunFromNodeExecutionResults(
|
||||
nodeExecutionResults: NodeExecutionResult[],
|
||||
function flowRunFromExecutionMeta(
|
||||
graphMeta: GraphMetaWithRuns,
|
||||
executionMeta: ExecutionMeta,
|
||||
): FlowRun {
|
||||
// Determine overall status
|
||||
let status: "running" | "waiting" | "success" | "failed" = "success";
|
||||
for (const execution of nodeExecutionResults) {
|
||||
if (execution.status === "FAILED") {
|
||||
status = "failed";
|
||||
break;
|
||||
} else if (["QUEUED", "RUNNING"].includes(execution.status)) {
|
||||
status = "running";
|
||||
break;
|
||||
} else if (execution.status === "INCOMPLETE") {
|
||||
status = "waiting";
|
||||
}
|
||||
}
|
||||
|
||||
// Determine aggregate startTime, endTime, and totalRunTime
|
||||
const now = Date.now();
|
||||
const startTime = Math.min(
|
||||
...nodeExecutionResults.map((ner) => ner.add_time.getTime()),
|
||||
now,
|
||||
);
|
||||
const endTime = ["success", "failed"].includes(status)
|
||||
? Math.max(
|
||||
...nodeExecutionResults.map((ner) => ner.end_time?.getTime() || 0),
|
||||
startTime,
|
||||
)
|
||||
: now;
|
||||
const duration = (endTime - startTime) / 1000; // Convert to seconds
|
||||
const totalRunTime =
|
||||
nodeExecutionResults.reduce(
|
||||
(cum, node) =>
|
||||
cum +
|
||||
((node.end_time?.getTime() ?? now) -
|
||||
(node.start_time?.getTime() ?? now)),
|
||||
0,
|
||||
) / 1000;
|
||||
|
||||
return {
|
||||
id: nodeExecutionResults[0].graph_exec_id,
|
||||
graphID: nodeExecutionResults[0].graph_id,
|
||||
graphVersion: nodeExecutionResults[0].graph_version,
|
||||
status,
|
||||
startTime,
|
||||
endTime,
|
||||
duration,
|
||||
totalRunTime,
|
||||
nodeExecutionResults: nodeExecutionResults,
|
||||
};
|
||||
id: executionMeta.execution_id,
|
||||
graphID: graphMeta.id,
|
||||
graphVersion: graphMeta.version,
|
||||
status: executionMeta.status,
|
||||
startTime: executionMeta.started_at,
|
||||
endTime: executionMeta.ended_at,
|
||||
duration: executionMeta.duration,
|
||||
totalRunTime: executionMeta.total_run_time,
|
||||
} as FlowRun;
|
||||
}
|
||||
|
||||
export default Monitor;
|
||||
|
||||
@@ -5,7 +5,9 @@ import {
|
||||
GraphCreatable,
|
||||
GraphUpdateable,
|
||||
GraphMeta,
|
||||
GraphMetaWithRuns,
|
||||
GraphExecuteResponse,
|
||||
ExecutionMeta,
|
||||
NodeExecutionResult,
|
||||
User,
|
||||
AnalyticsMetrics,
|
||||
@@ -45,7 +47,12 @@ export default class BaseAutoGPTServerAPI {
|
||||
}
|
||||
|
||||
async listGraphs(): Promise<GraphMeta[]> {
|
||||
return this._get("/graphs");
|
||||
return this._get(`/graphs`);
|
||||
}
|
||||
|
||||
async listGraphsWithRuns(): Promise<GraphMetaWithRuns[]> {
|
||||
let graphs = await this._get(`/graphs?with_runs=true`);
|
||||
return graphs.map(parseGraphMetaWithRuns);
|
||||
}
|
||||
|
||||
async listTemplates(): Promise<GraphMeta[]> {
|
||||
@@ -328,3 +335,28 @@ function parseNodeExecutionResultTimestamps(result: any): NodeExecutionResult {
|
||||
end_time: result.end_time ? new Date(result.end_time) : undefined,
|
||||
};
|
||||
}
|
||||
|
||||
function parseGraphMetaWithRuns(result: any): GraphMetaWithRuns {
|
||||
return {
|
||||
...result,
|
||||
executions: result.executions.map(parseExecutionMetaTimestamps),
|
||||
};
|
||||
}
|
||||
|
||||
function parseExecutionMetaTimestamps(result: any): ExecutionMeta {
|
||||
let status: "running" | "waiting" | "success" | "failed" = "success";
|
||||
if (result.status === "FAILED") {
|
||||
status = "failed";
|
||||
} else if (["QUEUED", "RUNNING"].includes(result.status)) {
|
||||
status = "running";
|
||||
} else if (result.status === "INCOMPLETE") {
|
||||
status = "waiting";
|
||||
}
|
||||
|
||||
return {
|
||||
...result,
|
||||
status,
|
||||
started_at: new Date(result.started_at).getTime(),
|
||||
ended_at: result.ended_at ? new Date(result.ended_at).getTime() : undefined,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -139,6 +139,16 @@ export type LinkCreatable = Omit<Link, "id" | "is_static"> & {
|
||||
id?: string;
|
||||
};
|
||||
|
||||
/* Mirror of autogpt_server/data/graph.py:ExecutionMeta */
|
||||
export type ExecutionMeta = {
|
||||
execution_id: string;
|
||||
started_at: number;
|
||||
ended_at: number;
|
||||
duration: number;
|
||||
total_run_time: number;
|
||||
status: "running" | "waiting" | "success" | "failed";
|
||||
};
|
||||
|
||||
/* Mirror of backend/data/graph.py:GraphMeta */
|
||||
export type GraphMeta = {
|
||||
id: string;
|
||||
@@ -149,6 +159,10 @@ export type GraphMeta = {
|
||||
description: string;
|
||||
};
|
||||
|
||||
export type GraphMetaWithRuns = GraphMeta & {
|
||||
executions: ExecutionMeta[];
|
||||
};
|
||||
|
||||
/* Mirror of backend/data/graph.py:Graph */
|
||||
export type Graph = GraphMeta & {
|
||||
nodes: Array<Node>;
|
||||
|
||||
Reference in New Issue
Block a user