{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "tool-call",
  "title": "AI Tool Call",
  "description": "Display AI tool/function invocations with status indicators, input/output visualization, and collapsible interface for MCP and function calling workflows.",
  "dependencies": [
    "@radix-ui/react-collapsible",
    "lucide-react"
  ],
  "registryDependencies": [],
  "files": [
    {
      "path": "registry/default/blocks/ai/ai-tool-call/components/elements/ai-tool-call.tsx",
      "content": "\"use client\";\n\nimport * as React from \"react\";\n\nimport * as CollapsiblePrimitive from \"@radix-ui/react-collapsible\";\nimport {\n  AlertTriangle,\n  Check,\n  ChevronDown,\n  Clock,\n  Loader2,\n  ShieldQuestion,\n  Wrench,\n  X,\n} from \"lucide-react\";\n\nimport { cn } from \"@/lib/utils\";\n\ntype ToolCallState =\n  | \"pending\"\n  | \"running\"\n  | \"completed\"\n  | \"error\"\n  | \"awaiting-approval\"\n  | \"denied\";\n\ninterface AiToolCallContextValue {\n  name: string;\n  state: ToolCallState;\n  isOpen: boolean;\n}\n\nconst AiToolCallContext = React.createContext<AiToolCallContextValue | null>(\n  null,\n);\n\nfunction useToolCallContext() {\n  const context = React.useContext(AiToolCallContext);\n  if (!context) {\n    throw new Error(\"AiToolCall components must be used within <AiToolCall>\");\n  }\n  return context;\n}\n\ninterface AiToolCallProps {\n  name: string;\n  state: ToolCallState;\n  defaultOpen?: boolean;\n  open?: boolean;\n  onOpenChange?: (open: boolean) => void;\n  children?: React.ReactNode;\n  className?: string;\n}\n\nfunction AiToolCall({\n  name,\n  state,\n  defaultOpen = false,\n  open: controlledOpen,\n  onOpenChange,\n  children,\n  className,\n}: AiToolCallProps) {\n  const [uncontrolledOpen, setUncontrolledOpen] = React.useState(defaultOpen);\n\n  const isControlled = controlledOpen !== undefined;\n  const isOpen = isControlled ? controlledOpen : uncontrolledOpen;\n\n  const handleOpenChange = React.useCallback(\n    (open: boolean) => {\n      if (!isControlled) {\n        setUncontrolledOpen(open);\n      }\n      onOpenChange?.(open);\n    },\n    [isControlled, onOpenChange],\n  );\n\n  React.useEffect(() => {\n    if (state === \"completed\" || state === \"error\") {\n      handleOpenChange(true);\n    }\n  }, [state, handleOpenChange]);\n\n  const contextValue = React.useMemo(\n    () => ({ name, state, isOpen }),\n    [name, state, isOpen],\n  );\n\n  return (\n    <AiToolCallContext.Provider value={contextValue}>\n      <CollapsiblePrimitive.Root\n        data-slot=\"ai-tool-call\"\n        open={isOpen}\n        onOpenChange={handleOpenChange}\n        className={cn(\n          \"rounded-lg border border-border bg-card text-card-foreground overflow-hidden\",\n          className,\n        )}\n      >\n        {children}\n      </CollapsiblePrimitive.Root>\n    </AiToolCallContext.Provider>\n  );\n}\n\ninterface AiToolCallHeaderProps {\n  children?: React.ReactNode;\n  className?: string;\n}\n\nfunction AiToolCallHeader({ children, className }: AiToolCallHeaderProps) {\n  const { name, state, isOpen } = useToolCallContext();\n\n  const stateConfig = React.useMemo(() => {\n    const configs: Record<\n      ToolCallState,\n      { icon: React.ReactNode; label: string; className: string }\n    > = {\n      pending: {\n        icon: <Clock className=\"size-3.5\" />,\n        label: \"Pending\",\n        className: \"bg-muted text-muted-foreground\",\n      },\n      running: {\n        icon: <Loader2 className=\"size-3.5 animate-spin\" />,\n        label: \"Running\",\n        className:\n          \"bg-blue-100 text-blue-700 dark:bg-blue-950 dark:text-blue-300\",\n      },\n      completed: {\n        icon: <Check className=\"size-3.5\" />,\n        label: \"Completed\",\n        className:\n          \"bg-green-100 text-green-700 dark:bg-green-950 dark:text-green-300\",\n      },\n      error: {\n        icon: <X className=\"size-3.5\" />,\n        label: \"Error\",\n        className: \"bg-red-100 text-red-700 dark:bg-red-950 dark:text-red-300\",\n      },\n      \"awaiting-approval\": {\n        icon: <ShieldQuestion className=\"size-3.5\" />,\n        label: \"Awaiting Approval\",\n        className:\n          \"bg-amber-100 text-amber-700 dark:bg-amber-950 dark:text-amber-300\",\n      },\n      denied: {\n        icon: <AlertTriangle className=\"size-3.5\" />,\n        label: \"Denied\",\n        className:\n          \"bg-orange-100 text-orange-700 dark:bg-orange-950 dark:text-orange-300\",\n      },\n    };\n    return configs[state];\n  }, [state]);\n\n  return (\n    <CollapsiblePrimitive.Trigger\n      data-slot=\"ai-tool-call-header\"\n      className={cn(\n        \"flex w-full items-center gap-3 px-4 py-3 text-sm font-medium transition-colors hover:bg-muted/50 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring\",\n        className,\n      )}\n    >\n      <div className=\"flex size-8 shrink-0 items-center justify-center rounded-md bg-muted\">\n        <Wrench className=\"size-4 text-muted-foreground\" />\n      </div>\n      <div className=\"flex flex-1 items-center gap-2 text-left\">\n        <span className=\"font-mono text-sm\">{name}</span>\n        <span\n          className={cn(\n            \"inline-flex items-center gap-1 rounded-full px-2 py-0.5 text-xs font-medium\",\n            stateConfig.className,\n          )}\n        >\n          {stateConfig.icon}\n          {stateConfig.label}\n        </span>\n      </div>\n      {children}\n      <ChevronDown\n        className={cn(\n          \"size-4 shrink-0 text-muted-foreground transition-transform duration-200\",\n          isOpen && \"rotate-180\",\n        )}\n      />\n    </CollapsiblePrimitive.Trigger>\n  );\n}\n\ninterface AiToolCallContentProps {\n  children?: React.ReactNode;\n  className?: string;\n}\n\nfunction AiToolCallContent({ children, className }: AiToolCallContentProps) {\n  return (\n    <CollapsiblePrimitive.Content\n      data-slot=\"ai-tool-call-content\"\n      className={cn(\n        \"border-t border-border data-[state=closed]:animate-collapsible-up data-[state=open]:animate-collapsible-down\",\n        className,\n      )}\n    >\n      <div className=\"p-4 space-y-4\">{children}</div>\n    </CollapsiblePrimitive.Content>\n  );\n}\n\ninterface AiToolCallInputProps {\n  input: Record<string, unknown>;\n  className?: string;\n}\n\nfunction AiToolCallInput({ input, className }: AiToolCallInputProps) {\n  const formattedJson = React.useMemo(\n    () => JSON.stringify(input, null, 2),\n    [input],\n  );\n\n  return (\n    <div\n      data-slot=\"ai-tool-call-input\"\n      className={cn(\"space-y-1.5\", className)}\n    >\n      <span className=\"text-xs font-medium text-muted-foreground uppercase tracking-wider\">\n        Input\n      </span>\n      <pre className=\"rounded-md bg-muted/50 p-3 overflow-x-auto text-xs font-mono text-foreground\">\n        {formattedJson}\n      </pre>\n    </div>\n  );\n}\n\ninterface AiToolCallOutputProps {\n  children?: React.ReactNode;\n  className?: string;\n}\n\nfunction AiToolCallOutput({ children, className }: AiToolCallOutputProps) {\n  return (\n    <div\n      data-slot=\"ai-tool-call-output\"\n      className={cn(\"space-y-1.5\", className)}\n    >\n      <span className=\"text-xs font-medium text-muted-foreground uppercase tracking-wider\">\n        Output\n      </span>\n      <div className=\"rounded-md bg-muted/50 p-3 overflow-x-auto text-sm\">\n        {children}\n      </div>\n    </div>\n  );\n}\n\ninterface AiToolCallErrorProps {\n  error: string;\n  className?: string;\n}\n\nfunction AiToolCallError({ error, className }: AiToolCallErrorProps) {\n  return (\n    <div\n      data-slot=\"ai-tool-call-error\"\n      className={cn(\"space-y-1.5\", className)}\n    >\n      <span className=\"text-xs font-medium text-red-600 dark:text-red-400 uppercase tracking-wider\">\n        Error\n      </span>\n      <div className=\"rounded-md bg-red-50 dark:bg-red-950/30 border border-red-200 dark:border-red-900 p-3 text-sm text-red-700 dark:text-red-300\">\n        {error}\n      </div>\n    </div>\n  );\n}\n\nexport {\n  AiToolCall,\n  AiToolCallHeader,\n  AiToolCallContent,\n  AiToolCallInput,\n  AiToolCallOutput,\n  AiToolCallError,\n};\nexport type { AiToolCallProps, ToolCallState };\n",
      "type": "registry:component"
    }
  ],
  "docs": "Compound component for displaying tool calls. States: pending, running, completed, error, awaiting-approval, denied. Auto-opens on completion/error.",
  "categories": [
    "ai"
  ],
  "type": "registry:ui"
}