Spaces:
Running
Running
File size: 4,398 Bytes
5012205 264f96c 5012205 d8c725b 5012205 d8c725b 5012205 d8c725b 5012205 d8c725b 5012205 d8c725b 264f96c d8c725b 264f96c d8c725b 5012205 264f96c d8c725b 264f96c d8c725b 5012205 d8c725b 5012205 d8c725b 5012205 0c91a71 5012205 0c91a71 5012205 0c91a71 5012205 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 |
"use client";
import { useState } from "react";
import {
ChevronDownIcon,
ChevronUpIcon,
Loader2,
CheckCircle2,
TerminalSquare,
Code,
ArrowRight,
Circle,
} from "lucide-react";
import { cn } from "@/lib/utils";
interface ToolInvocationProps {
toolName: string;
state: string;
args: any;
result: any;
isLatestMessage: boolean;
status: string;
}
export function ToolInvocation({
toolName,
state,
args,
result,
isLatestMessage,
status,
}: ToolInvocationProps) {
const [isExpanded, setIsExpanded] = useState(false);
const getStatusIcon = () => {
if (state === "call") {
if (isLatestMessage && status !== "ready") {
return <Loader2 className="animate-spin h-3.5 w-3.5 text-primary/70" />;
}
return <Circle className="h-3.5 w-3.5 fill-muted-foreground/10 text-muted-foreground/70" />;
}
return <CheckCircle2 size={14} className="text-primary/90" />;
};
const getStatusClass = () => {
if (state === "call") {
if (isLatestMessage && status !== "ready") {
return "text-primary";
}
return "text-muted-foreground";
}
return "text-primary";
};
const formatContent = (content: any): string => {
try {
if (typeof content === "string") {
try {
const parsed = JSON.parse(content);
return JSON.stringify(parsed, null, 2);
} catch {
return content;
}
}
return JSON.stringify(content, null, 2);
} catch {
return String(content);
}
};
return (
<div className={cn(
"flex flex-col mb-2 rounded-md border border-border/50 overflow-hidden",
"bg-gradient-to-b from-background to-muted/30 backdrop-blur-sm",
"transition-all duration-200 hover:border-border/80 group"
)}>
<div
className={cn(
"flex items-center gap-2.5 px-3 py-2 cursor-pointer transition-colors",
"hover:bg-muted/20"
)}
onClick={() => setIsExpanded(!isExpanded)}
>
<div className="flex items-center justify-center rounded-full w-5 h-5 bg-primary/5 text-primary">
<TerminalSquare className="h-3.5 w-3.5" />
</div>
<div className="flex items-center gap-1.5 text-xs font-medium text-muted-foreground flex-1">
<span className="text-foreground font-semibold tracking-tight">{toolName}</span>
<ArrowRight className="h-3 w-3 text-muted-foreground/50" />
<span className={cn("font-medium", getStatusClass())}>
{state === "call" ? (isLatestMessage && status !== "ready" ? "Running" : "Waiting") : "Completed"}
</span>
</div>
<div className="flex items-center gap-2 opacity-70 group-hover:opacity-100 transition-opacity">
{getStatusIcon()}
<div className="bg-muted/30 rounded-full p-0.5 border border-border/30">
{isExpanded ? (
<ChevronUpIcon className="h-3 w-3 text-foreground/70" />
) : (
<ChevronDownIcon className="h-3 w-3 text-foreground/70" />
)}
</div>
</div>
</div>
{isExpanded && (
<div className="space-y-2 px-3 pb-3">
{!!args && (
<div className="space-y-1.5">
<div className="flex items-center gap-1.5 text-xs text-muted-foreground/70 pt-1.5">
<Code className="h-3 w-3" />
<span className="font-medium">Arguments</span>
</div>
<pre className={cn(
"text-xs font-mono p-2.5 rounded-md overflow-x-auto",
"border border-border/40 bg-muted/10"
)}>
{formatContent(args)}
</pre>
</div>
)}
{!!result && (
<div className="space-y-1.5">
<div className="flex items-center gap-1.5 text-xs text-muted-foreground/70">
<ArrowRight className="h-3 w-3" />
<span className="font-medium">Result</span>
</div>
<pre className={cn(
"text-xs font-mono p-2.5 rounded-md overflow-x-auto max-h-[300px] overflow-y-auto",
"border border-border/40 bg-muted/10"
)}>
{formatContent(result)}
</pre>
</div>
)}
</div>
)}
</div>
);
} |