Spaces:
Running
Running
| import { useState, useEffect } from "react"; | |
| import { Play, Square, RotateCcw } from "lucide-react"; | |
| import { Button } from "@/components/ui/button"; | |
| import { Input } from "@/components/ui/input"; | |
| import { Label } from "@/components/ui/label"; | |
| import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"; | |
| import { Separator } from "@/components/ui/separator"; | |
| import { ExecutionTimeline } from "./ExecutionTimeline"; | |
| import { TokenUsageChart } from "./TokenUsageChart"; | |
| import { ResultViewer } from "./ResultViewer"; | |
| import { AgentStatusBadge } from "./AgentStatusBadge"; | |
| import { useExecutionStore } from "@/stores/executionStore"; | |
| import { useGraphStore } from "@/stores/graphStore"; | |
| import { useConfigStore } from "@/stores/configStore"; | |
| import type { AgentExecutionStatus } from "@/types/execution"; | |
| export function ExecutionPanel() { | |
| const { taskQuery, setTaskQuery, toGraphRequest, updateNodeExecutionStatus, resetExecutionStatus, nodes } = | |
| useGraphStore(); | |
| const { | |
| status, | |
| events, | |
| agentStatuses, | |
| tokenUsage, | |
| finalAnswer, | |
| totalTokens, | |
| totalTime, | |
| error, | |
| startExecution, | |
| cancelExecution, | |
| clearRun, | |
| } = useExecutionStore(); | |
| const { runnerConfig, llmProviders } = useConfigStore(); | |
| const isRunning = status === "running"; | |
| // Sync execution statuses to graph nodes for live visualization | |
| useEffect(() => { | |
| Object.entries(agentStatuses).forEach(([agentId, agentStatus]) => { | |
| updateNodeExecutionStatus(agentId, agentStatus as AgentExecutionStatus); | |
| }); | |
| }, [agentStatuses, updateNodeExecutionStatus]); | |
| // Update node token counts | |
| useEffect(() => { | |
| Object.entries(tokenUsage).forEach(([agentId, tokens]) => { | |
| updateNodeExecutionStatus(agentId, agentStatuses[agentId] as AgentExecutionStatus || "completed", undefined, tokens); | |
| }); | |
| }, [tokenUsage]); | |
| const handleRun = async () => { | |
| resetExecutionStatus(); | |
| const graphData = toGraphRequest(); | |
| const provider = llmProviders.length > 0 ? llmProviders[0] : null; | |
| await startExecution(null, graphData, taskQuery, runnerConfig, provider); | |
| }; | |
| const handleStop = () => { | |
| cancelExecution(); | |
| }; | |
| const handleClear = () => { | |
| clearRun(); | |
| resetExecutionStatus(); | |
| }; | |
| return ( | |
| <div className="flex h-full w-80 flex-col border-l bg-card"> | |
| <div className="p-3 border-b space-y-3"> | |
| <div className="space-y-2"> | |
| <Label className="text-xs">Task Query</Label> | |
| <Input | |
| placeholder="Describe the task for the agents..." | |
| value={taskQuery} | |
| onChange={(e) => setTaskQuery(e.target.value)} | |
| disabled={isRunning} | |
| /> | |
| </div> | |
| <div className="flex gap-2"> | |
| {!isRunning ? ( | |
| <Button | |
| onClick={handleRun} | |
| disabled={nodes.length === 0 || !taskQuery.trim()} | |
| className="flex-1 gap-1" | |
| size="sm" | |
| > | |
| <Play className="h-3.5 w-3.5" /> | |
| Execute | |
| </Button> | |
| ) : ( | |
| <Button onClick={handleStop} variant="destructive" className="flex-1 gap-1" size="sm"> | |
| <Square className="h-3.5 w-3.5" /> | |
| Stop | |
| </Button> | |
| )} | |
| <Button onClick={handleClear} variant="outline" size="sm" disabled={isRunning}> | |
| <RotateCcw className="h-3.5 w-3.5" /> | |
| </Button> | |
| </div> | |
| {/* Agent statuses */} | |
| {Object.keys(agentStatuses).length > 0 && ( | |
| <> | |
| <Separator /> | |
| <div className="space-y-1"> | |
| {Object.entries(agentStatuses).map(([id, agentStatus]) => ( | |
| <AgentStatusBadge | |
| key={id} | |
| status={agentStatus as AgentExecutionStatus} | |
| agentName={id} | |
| /> | |
| ))} | |
| </div> | |
| </> | |
| )} | |
| </div> | |
| <Tabs defaultValue="timeline" className="flex-1 flex flex-col"> | |
| <TabsList className="mx-3 mt-2"> | |
| <TabsTrigger value="timeline" className="text-xs"> | |
| Timeline | |
| </TabsTrigger> | |
| <TabsTrigger value="tokens" className="text-xs"> | |
| Tokens | |
| </TabsTrigger> | |
| <TabsTrigger value="result" className="text-xs"> | |
| Result | |
| </TabsTrigger> | |
| </TabsList> | |
| <TabsContent value="timeline" className="flex-1 overflow-hidden mt-0"> | |
| <ExecutionTimeline events={events} /> | |
| </TabsContent> | |
| <TabsContent value="tokens" className="flex-1 overflow-hidden mt-0 p-3"> | |
| <TokenUsageChart tokenUsage={tokenUsage} /> | |
| </TabsContent> | |
| <TabsContent value="result" className="flex-1 overflow-hidden mt-0"> | |
| <ResultViewer | |
| status={status} | |
| finalAnswer={finalAnswer} | |
| totalTokens={totalTokens} | |
| totalTime={totalTime} | |
| events={events} | |
| error={error} | |
| /> | |
| </TabsContent> | |
| </Tabs> | |
| </div> | |
| ); | |
| } | |