Spaces:
Running
Running
| import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; | |
| import { Badge } from "@/components/ui/badge"; | |
| import { Separator } from "@/components/ui/separator"; | |
| import { ScrollArea } from "@/components/ui/scroll-area"; | |
| import { CheckCircle2, XCircle, Clock, Zap } from "lucide-react"; | |
| import type { StreamEvent } from "@/types/execution"; | |
| interface ResultViewerProps { | |
| status: string; | |
| finalAnswer: string | null; | |
| totalTokens: number; | |
| totalTime: number; | |
| events: StreamEvent[]; | |
| error: string | null; | |
| } | |
| export function ResultViewer({ | |
| status, | |
| finalAnswer, | |
| totalTokens, | |
| totalTime, | |
| events, | |
| error, | |
| }: ResultViewerProps) { | |
| const agentOutputs = events.filter((e) => e.event_type === "agent_output"); | |
| return ( | |
| <ScrollArea className="h-full"> | |
| <div className="space-y-3 p-3"> | |
| {/* Status summary */} | |
| <div className="flex items-center gap-2"> | |
| {status === "completed" && <CheckCircle2 className="h-4 w-4 text-green-500" />} | |
| {status === "error" && <XCircle className="h-4 w-4 text-red-500" />} | |
| {status === "running" && <Clock className="h-4 w-4 text-blue-500 animate-pulse" />} | |
| <span className="text-sm font-medium capitalize">{status}</span> | |
| {totalTokens > 0 && ( | |
| <Badge variant="secondary" className="text-xs gap-1"> | |
| <Zap className="h-3 w-3" /> | |
| {totalTokens} tokens | |
| </Badge> | |
| )} | |
| {totalTime > 0 && ( | |
| <Badge variant="secondary" className="text-xs gap-1"> | |
| <Clock className="h-3 w-3" /> | |
| {totalTime.toFixed(1)}s | |
| </Badge> | |
| )} | |
| </div> | |
| {error && ( | |
| <div className="rounded-md border border-red-200 bg-red-50 dark:bg-red-950 p-3"> | |
| <p className="text-sm text-red-700 dark:text-red-300">{error}</p> | |
| </div> | |
| )} | |
| {/* Final answer */} | |
| {finalAnswer && ( | |
| <Card> | |
| <CardHeader className="py-3 px-4"> | |
| <CardTitle className="text-sm">Final Answer</CardTitle> | |
| </CardHeader> | |
| <CardContent className="px-4 pb-4 pt-0"> | |
| <p className="text-sm whitespace-pre-wrap">{finalAnswer}</p> | |
| </CardContent> | |
| </Card> | |
| )} | |
| {/* Agent outputs */} | |
| {agentOutputs.length > 0 && ( | |
| <> | |
| <Separator /> | |
| <h4 className="text-sm font-medium">Agent Responses</h4> | |
| {agentOutputs.map((event, i) => ( | |
| <Card key={i}> | |
| <CardHeader className="py-2 px-4"> | |
| <div className="flex items-center justify-between"> | |
| <CardTitle className="text-xs font-medium"> | |
| {event.agent_name || event.agent_id} | |
| </CardTitle> | |
| {event.tokens_used && ( | |
| <span className="text-[10px] text-muted-foreground"> | |
| {event.tokens_used} tokens | |
| </span> | |
| )} | |
| </div> | |
| </CardHeader> | |
| <CardContent className="px-4 pb-3 pt-0"> | |
| <p className="text-xs whitespace-pre-wrap text-muted-foreground"> | |
| {event.content?.slice(0, 500)} | |
| {(event.content?.length ?? 0) > 500 ? "..." : ""} | |
| </p> | |
| </CardContent> | |
| </Card> | |
| ))} | |
| </> | |
| )} | |
| </div> | |
| </ScrollArea> | |
| ); | |
| } | |