mirror of
https://github.com/microsoft/agent-framework.git
synced 2026-06-16 21:04:09 +08:00
Python: Add DevUI to AgentFramework (#781)
* add initial backend service code for devui * add tests * add frontendcode * ui updates * update readme * ui updates and tweaks * update ui bundle * improve ui, add react flow base * add react flow ui, fix background * update ui, fix introspection bug * update readme * update ui build * add support for multimodal input - both backend and frontend * update ui build * refactor as main framework package * backend and tests refactor * ui build update * ui build update and refactor * update pyproject.toml, update uv.lock * update ui build * ui update to fit oai responses types * add backend updat and readme update * mypy and other fixes * add intial dev guide * update ui and fix workflow bug * update ui build, add thread support * type fixes * update workflow view * update uv.lock * fix workflow iport errors * lint and other fixes * mypy fixes * minor update * update ui build * refactor to use oai dependencies directly, update examples to samples, improve typing * readme update * update ui and ui build * fix workflow pyright error * update ui, fix issues with run workflow placement, miniamp menu, etc * make samples integrate serve --------- Co-authored-by: Chris <66376200+crickman@users.noreply.github.com> Co-authored-by: Eric Zhu <ekzhu@users.noreply.github.com>
This commit is contained in:
committed by
GitHub
Unverified
parent
adb6dcd2af
commit
1ef24d3e91
@@ -0,0 +1,126 @@
|
||||
import { useMemo, useState, useCallback } from "react";
|
||||
import type { ExtendedResponseStreamEvent } from "@/types";
|
||||
// import type { ExecutorNodeData } from "@/components/workflow/executor-node";
|
||||
|
||||
// Type for executor input/output data - can be various types based on workflow events
|
||||
export type ExecutorData =
|
||||
| string
|
||||
| number
|
||||
| boolean
|
||||
| Record<string, unknown>
|
||||
| null;
|
||||
|
||||
// State tracking for a specific executor
|
||||
interface ExecutorState {
|
||||
executorId: string;
|
||||
state: "pending" | "running" | "completed" | "failed" | "cancelled";
|
||||
inputData?: ExecutorData;
|
||||
outputData?: ExecutorData;
|
||||
error?: string;
|
||||
timestamp: string;
|
||||
}
|
||||
|
||||
|
||||
interface WorkflowEventCorrelationResult {
|
||||
// State access
|
||||
isWorkflowRunning: boolean;
|
||||
selectedExecutorId: string | null;
|
||||
recentlyActive: string[];
|
||||
|
||||
// Actions
|
||||
selectExecutor: (executorId: string) => void;
|
||||
getExecutorData: (executorId: string) => ExecutorState | null;
|
||||
getExecutorEvents: (executorId: string) => ExtendedResponseStreamEvent[];
|
||||
}
|
||||
|
||||
// Hook for correlating workflow events with executor states
|
||||
export function useWorkflowEventCorrelation(
|
||||
events: ExtendedResponseStreamEvent[],
|
||||
isStreaming: boolean
|
||||
): WorkflowEventCorrelationResult {
|
||||
const [selectedExecutorId, setSelectedExecutorId] = useState<string | null>(null);
|
||||
|
||||
// Process events into executor states
|
||||
const { executors, recentlyActive, isWorkflowRunning } = useMemo(() => {
|
||||
const executorMap: Record<string, ExecutorState> = {};
|
||||
const activeExecutors: string[] = [];
|
||||
let workflowActive = isStreaming;
|
||||
|
||||
// Process workflow events
|
||||
events.forEach((event) => {
|
||||
if (event.type === "response.workflow_event.complete" && "data" in event && event.data) {
|
||||
const data = event.data as any;
|
||||
const executorId = data.executor_id;
|
||||
|
||||
if (!executorId) return;
|
||||
|
||||
// Initialize executor if not exists
|
||||
if (!executorMap[executorId]) {
|
||||
executorMap[executorId] = {
|
||||
executorId,
|
||||
state: "pending",
|
||||
timestamp: new Date().toISOString(),
|
||||
};
|
||||
}
|
||||
|
||||
const executor = executorMap[executorId];
|
||||
const eventType = data.event_type;
|
||||
|
||||
// Update state based on event type
|
||||
if (eventType === "ExecutorInvokedEvent") {
|
||||
executor.state = "running";
|
||||
executor.inputData = data.data;
|
||||
if (!activeExecutors.includes(executorId)) {
|
||||
activeExecutors.push(executorId);
|
||||
}
|
||||
} else if (eventType === "ExecutorCompletedEvent") {
|
||||
executor.state = "completed";
|
||||
executor.outputData = data.data;
|
||||
} else if (eventType?.includes("Error") || eventType?.includes("Failed")) {
|
||||
executor.state = "failed";
|
||||
executor.error = typeof data.data === "string" ? data.data : "Execution failed";
|
||||
} else if (eventType?.includes("Cancel")) {
|
||||
executor.state = "cancelled";
|
||||
}
|
||||
|
||||
executor.timestamp = new Date().toISOString();
|
||||
}
|
||||
});
|
||||
|
||||
return {
|
||||
executors: executorMap,
|
||||
recentlyActive: activeExecutors.slice(-3), // Keep last 3 active executors
|
||||
isWorkflowRunning: workflowActive,
|
||||
};
|
||||
}, [events, isStreaming]);
|
||||
|
||||
const selectExecutor = useCallback((executorId: string) => {
|
||||
setSelectedExecutorId(executorId);
|
||||
}, []);
|
||||
|
||||
const getExecutorData = useCallback((executorId: string): ExecutorState | null => {
|
||||
return executors[executorId] || null;
|
||||
}, [executors]);
|
||||
|
||||
const getExecutorEvents = useCallback(
|
||||
(executorId: string): ExtendedResponseStreamEvent[] => {
|
||||
return events.filter((event) => {
|
||||
if (event.type === "response.workflow_event.complete" && "data" in event && event.data) {
|
||||
const data = event.data as any;
|
||||
return data.executor_id === executorId;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
},
|
||||
[events]
|
||||
);
|
||||
|
||||
return {
|
||||
isWorkflowRunning,
|
||||
selectedExecutorId,
|
||||
recentlyActive,
|
||||
selectExecutor,
|
||||
getExecutorData,
|
||||
getExecutorEvents,
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user