{ "name": "tool", "type": "registry:ui", "registryDependencies": [ "collapsible", "button" ], "dependencies": [ "lucide-react" ], "devDependencies": [], "tailwind": {}, "cssVars": { "light": {}, "dark": {} }, "description": "Displays tool call details including input, output, status, and errors. Ideal for visualizing AI tool usage in chat UIs.", "files": [ { "path": "tool.tsx", "content": "\"use client\"\n\nimport { Button } from \"@/components/ui/button\"\nimport {\n Collapsible,\n CollapsibleContent,\n CollapsibleTrigger,\n} from \"@/components/ui/collapsible\"\nimport { cn } from \"@/lib/utils\"\nimport {\n CheckCircle,\n ChevronDown,\n Loader2,\n Settings,\n XCircle,\n} from \"lucide-react\"\nimport { useState } from \"react\"\n\nexport type ToolPart = {\n type: string\n state:\n | \"input-streaming\"\n | \"input-available\"\n | \"output-available\"\n | \"output-error\"\n input?: Record\n output?: Record\n toolCallId?: string\n errorText?: string\n}\n\nexport type ToolProps = {\n toolPart: ToolPart\n defaultOpen?: boolean\n className?: string\n}\n\nconst Tool = ({ toolPart, defaultOpen = false, className }: ToolProps) => {\n const [isOpen, setIsOpen] = useState(defaultOpen)\n\n const { state, input, output, toolCallId } = toolPart\n\n const getStateIcon = () => {\n switch (state) {\n case \"input-streaming\":\n return \n case \"input-available\":\n return \n case \"output-available\":\n return \n case \"output-error\":\n return \n default:\n return \n }\n }\n\n const getStateBadge = () => {\n const baseClasses = \"px-2 py-1 rounded-full text-xs font-medium\"\n switch (state) {\n case \"input-streaming\":\n return (\n \n Processing\n \n )\n case \"input-available\":\n return (\n \n Ready\n \n )\n case \"output-available\":\n return (\n \n Completed\n \n )\n case \"output-error\":\n return (\n \n Error\n \n )\n default:\n return (\n \n Pending\n \n )\n }\n }\n\n const formatValue = (value: unknown): string => {\n if (value === null) return \"null\"\n if (value === undefined) return \"undefined\"\n if (typeof value === \"string\") return value\n if (typeof value === \"object\") {\n return JSON.stringify(value, null, 2)\n }\n return String(value)\n }\n\n return (\n \n \n \n \n
\n {getStateIcon()}\n \n {toolPart.type}\n \n {getStateBadge()}\n
\n \n \n
\n \n
\n {input && Object.keys(input).length > 0 && (\n
\n

\n Input\n

\n
\n {Object.entries(input).map(([key, value]) => (\n
\n {key}:{\" \"}\n {formatValue(value)}\n
\n ))}\n
\n
\n )}\n\n {output && (\n
\n

\n Output\n

\n
\n
\n                    {formatValue(output)}\n                  
\n
\n
\n )}\n\n {state === \"output-error\" && toolPart.errorText && (\n
\n

Error

\n
\n {toolPart.errorText}\n
\n
\n )}\n\n {state === \"input-streaming\" && (\n
\n Processing tool call...\n
\n )}\n\n {toolCallId && (\n
\n Call ID: {toolCallId}\n
\n )}\n
\n \n
\n \n )\n}\n\nexport { Tool }\n", "type": "registry:ui" } ] }