{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "model-info",
  "title": "AI Model Info",
  "description": "Display AI model metadata including provider, context window, capabilities badges (vision, tools, streaming, JSON, functions), pricing info, and release date. Supports multiple providers with themed colors.",
  "dependencies": [
    "lucide-react"
  ],
  "registryDependencies": [],
  "files": [
    {
      "path": "registry/default/blocks/ai/ai-model-info/components/elements/ai-model-info.tsx",
      "content": "\"use client\";\n\nimport * as React from \"react\";\n\nimport {\n  Calendar,\n  Cpu,\n  DollarSign,\n  Eye,\n  FileJson,\n  FunctionSquare,\n  Wrench,\n  Zap,\n} from \"lucide-react\";\n\nimport { cn } from \"@/lib/utils\";\n\ntype ModelCapability = \"vision\" | \"tools\" | \"streaming\" | \"json\" | \"functions\";\n\ninterface ModelInfo {\n  id: string;\n  name: string;\n  provider: string;\n  contextWindow: number;\n  capabilities: ModelCapability[];\n  inputPrice?: number;\n  outputPrice?: number;\n  releaseDate?: Date;\n}\n\ninterface AiModelInfoContextValue {\n  model: ModelInfo;\n  showPricing: boolean;\n}\n\nconst AiModelInfoContext = React.createContext<AiModelInfoContextValue | null>(\n  null,\n);\n\nfunction useModelInfoContext() {\n  const context = React.useContext(AiModelInfoContext);\n  if (!context) {\n    throw new Error(\"AiModelInfo components must be used within <AiModelInfo>\");\n  }\n  return context;\n}\n\nconst PROVIDER_CONFIG: Record<\n  string,\n  { logo: string; color: string; bgClass: string }\n> = {\n  openai: {\n    logo: \"OpenAI\",\n    color: \"text-emerald-600 dark:text-emerald-400\",\n    bgClass: \"bg-emerald-100 dark:bg-emerald-950\",\n  },\n  anthropic: {\n    logo: \"Anthropic\",\n    color: \"text-orange-600 dark:text-orange-400\",\n    bgClass: \"bg-orange-100 dark:bg-orange-950\",\n  },\n  google: {\n    logo: \"Google\",\n    color: \"text-blue-600 dark:text-blue-400\",\n    bgClass: \"bg-blue-100 dark:bg-blue-950\",\n  },\n  mistral: {\n    logo: \"Mistral\",\n    color: \"text-indigo-600 dark:text-indigo-400\",\n    bgClass: \"bg-indigo-100 dark:bg-indigo-950\",\n  },\n  cohere: {\n    logo: \"Cohere\",\n    color: \"text-purple-600 dark:text-purple-400\",\n    bgClass: \"bg-purple-100 dark:bg-purple-950\",\n  },\n  meta: {\n    logo: \"Meta\",\n    color: \"text-sky-600 dark:text-sky-400\",\n    bgClass: \"bg-sky-100 dark:bg-sky-950\",\n  },\n};\n\nconst CAPABILITY_CONFIG: Record<\n  ModelCapability,\n  { icon: React.ReactNode; label: string; className: string }\n> = {\n  vision: {\n    icon: <Eye className=\"size-3\" />,\n    label: \"Vision\",\n    className: \"bg-pink-100 text-pink-700 dark:bg-pink-950 dark:text-pink-300\",\n  },\n  tools: {\n    icon: <Wrench className=\"size-3\" />,\n    label: \"Tools\",\n    className:\n      \"bg-amber-100 text-amber-700 dark:bg-amber-950 dark:text-amber-300\",\n  },\n  streaming: {\n    icon: <Zap className=\"size-3\" />,\n    label: \"Streaming\",\n    className: \"bg-cyan-100 text-cyan-700 dark:bg-cyan-950 dark:text-cyan-300\",\n  },\n  json: {\n    icon: <FileJson className=\"size-3\" />,\n    label: \"JSON Mode\",\n    className:\n      \"bg-violet-100 text-violet-700 dark:bg-violet-950 dark:text-violet-300\",\n  },\n  functions: {\n    icon: <FunctionSquare className=\"size-3\" />,\n    label: \"Functions\",\n    className: \"bg-lime-100 text-lime-700 dark:bg-lime-950 dark:text-lime-300\",\n  },\n};\n\nfunction formatContextWindow(tokens: number): string {\n  if (tokens >= 1000000) {\n    return `${(tokens / 1000000).toFixed(1)}M`;\n  }\n  if (tokens >= 1000) {\n    return `${(tokens / 1000).toFixed(0)}K`;\n  }\n  return tokens.toString();\n}\n\nfunction formatPrice(price: number): string {\n  if (price < 0.01) {\n    return `$${price.toFixed(4)}`;\n  }\n  return `$${price.toFixed(2)}`;\n}\n\ninterface AiModelInfoProps {\n  model: ModelInfo;\n  showPricing?: boolean;\n  className?: string;\n  children?: React.ReactNode;\n}\n\nfunction AiModelInfo({\n  model,\n  showPricing = true,\n  className,\n  children,\n}: AiModelInfoProps) {\n  const contextValue = React.useMemo(\n    () => ({ model, showPricing }),\n    [model, showPricing],\n  );\n\n  return (\n    <AiModelInfoContext.Provider value={contextValue}>\n      <div\n        data-slot=\"ai-model-info\"\n        className={cn(\n          \"rounded-lg border border-border bg-card text-card-foreground\",\n          className,\n        )}\n      >\n        {children}\n      </div>\n    </AiModelInfoContext.Provider>\n  );\n}\n\ninterface AiModelInfoHeaderProps {\n  className?: string;\n}\n\nfunction AiModelInfoHeader({ className }: AiModelInfoHeaderProps) {\n  const { model } = useModelInfoContext();\n\n  const providerConfig = PROVIDER_CONFIG[model.provider.toLowerCase()] || {\n    logo: model.provider,\n    color: \"text-gray-600 dark:text-gray-400\",\n    bgClass: \"bg-gray-100 dark:bg-gray-800\",\n  };\n\n  return (\n    <div\n      data-slot=\"ai-model-info-header\"\n      className={cn(\n        \"flex items-center gap-3 px-4 py-3 border-b border-border\",\n        className,\n      )}\n    >\n      <div\n        className={cn(\n          \"flex size-10 shrink-0 items-center justify-center rounded-lg\",\n          providerConfig.bgClass,\n        )}\n      >\n        <Cpu className={cn(\"size-5\", providerConfig.color)} />\n      </div>\n      <div className=\"flex-1 min-w-0\">\n        <h3 className=\"font-semibold text-sm truncate\">{model.name}</h3>\n        <p className={cn(\"text-xs\", providerConfig.color)}>\n          {providerConfig.logo}\n        </p>\n      </div>\n      <div className=\"text-right shrink-0\">\n        <p className=\"text-sm font-mono font-medium\">\n          {formatContextWindow(model.contextWindow)}\n        </p>\n        <p className=\"text-xs text-muted-foreground\">context</p>\n      </div>\n    </div>\n  );\n}\n\ninterface AiModelInfoCapabilitiesProps {\n  className?: string;\n}\n\nfunction AiModelInfoCapabilities({ className }: AiModelInfoCapabilitiesProps) {\n  const { model } = useModelInfoContext();\n\n  if (model.capabilities.length === 0) {\n    return null;\n  }\n\n  return (\n    <div\n      data-slot=\"ai-model-info-capabilities\"\n      className={cn(\"px-4 py-3 border-b border-border\", className)}\n    >\n      <p className=\"text-xs font-medium text-muted-foreground uppercase tracking-wider mb-2\">\n        Capabilities\n      </p>\n      <div className=\"flex flex-wrap gap-1.5\">\n        {model.capabilities.map((capability) => {\n          const config = CAPABILITY_CONFIG[capability];\n          return (\n            <span\n              key={capability}\n              className={cn(\n                \"inline-flex items-center gap-1 rounded-full px-2 py-0.5 text-xs font-medium\",\n                config.className,\n              )}\n            >\n              {config.icon}\n              {config.label}\n            </span>\n          );\n        })}\n      </div>\n    </div>\n  );\n}\n\ninterface AiModelInfoPricingProps {\n  className?: string;\n}\n\nfunction AiModelInfoPricing({ className }: AiModelInfoPricingProps) {\n  const { model, showPricing } = useModelInfoContext();\n\n  if (\n    !showPricing ||\n    (model.inputPrice === undefined && model.outputPrice === undefined)\n  ) {\n    return null;\n  }\n\n  return (\n    <div\n      data-slot=\"ai-model-info-pricing\"\n      className={cn(\"px-4 py-3 border-b border-border\", className)}\n    >\n      <p className=\"text-xs font-medium text-muted-foreground uppercase tracking-wider mb-2\">\n        Pricing (per 1M tokens)\n      </p>\n      <div className=\"grid grid-cols-2 gap-3\">\n        {model.inputPrice !== undefined && (\n          <div className=\"flex items-center gap-2\">\n            <div className=\"flex size-7 shrink-0 items-center justify-center rounded bg-green-100 dark:bg-green-950\">\n              <DollarSign className=\"size-3.5 text-green-600 dark:text-green-400\" />\n            </div>\n            <div>\n              <p className=\"text-sm font-mono font-medium\">\n                {formatPrice(model.inputPrice)}\n              </p>\n              <p className=\"text-xs text-muted-foreground\">Input</p>\n            </div>\n          </div>\n        )}\n        {model.outputPrice !== undefined && (\n          <div className=\"flex items-center gap-2\">\n            <div className=\"flex size-7 shrink-0 items-center justify-center rounded bg-blue-100 dark:bg-blue-950\">\n              <DollarSign className=\"size-3.5 text-blue-600 dark:text-blue-400\" />\n            </div>\n            <div>\n              <p className=\"text-sm font-mono font-medium\">\n                {formatPrice(model.outputPrice)}\n              </p>\n              <p className=\"text-xs text-muted-foreground\">Output</p>\n            </div>\n          </div>\n        )}\n      </div>\n    </div>\n  );\n}\n\ninterface AiModelInfoMetaProps {\n  className?: string;\n}\n\nfunction AiModelInfoMeta({ className }: AiModelInfoMetaProps) {\n  const { model } = useModelInfoContext();\n\n  return (\n    <div data-slot=\"ai-model-info-meta\" className={cn(\"px-4 py-3\", className)}>\n      <div className=\"flex items-center justify-between text-xs\">\n        <div className=\"flex items-center gap-1.5 text-muted-foreground\">\n          <span className=\"font-mono\">{model.id}</span>\n        </div>\n        {model.releaseDate && (\n          <div className=\"flex items-center gap-1 text-muted-foreground\">\n            <Calendar className=\"size-3\" />\n            <span>\n              {model.releaseDate.toLocaleDateString(\"en-US\", {\n                month: \"short\",\n                year: \"numeric\",\n              })}\n            </span>\n          </div>\n        )}\n      </div>\n    </div>\n  );\n}\n\ninterface AiModelInfoBadgeProps {\n  className?: string;\n}\n\nfunction AiModelInfoBadge({ className }: AiModelInfoBadgeProps) {\n  const { model } = useModelInfoContext();\n\n  const providerConfig = PROVIDER_CONFIG[model.provider.toLowerCase()] || {\n    logo: model.provider,\n    color: \"text-gray-600 dark:text-gray-400\",\n    bgClass: \"bg-gray-100 dark:bg-gray-800\",\n  };\n\n  return (\n    <div\n      data-slot=\"ai-model-info-badge\"\n      className={cn(\n        \"inline-flex items-center gap-2 rounded-full border border-border bg-card px-3 py-1.5\",\n        className,\n      )}\n    >\n      <div\n        className={cn(\n          \"flex size-5 shrink-0 items-center justify-center rounded-full\",\n          providerConfig.bgClass,\n        )}\n      >\n        <Cpu className={cn(\"size-3\", providerConfig.color)} />\n      </div>\n      <span className=\"text-xs font-medium\">{model.name}</span>\n      <span className=\"text-xs text-muted-foreground font-mono\">\n        {formatContextWindow(model.contextWindow)}\n      </span>\n    </div>\n  );\n}\n\nexport {\n  AiModelInfo,\n  AiModelInfoHeader,\n  AiModelInfoCapabilities,\n  AiModelInfoPricing,\n  AiModelInfoMeta,\n  AiModelInfoBadge,\n};\nexport type { AiModelInfoProps, ModelInfo, ModelCapability };\n",
      "type": "registry:component"
    }
  ],
  "docs": "A compound component for displaying model information. Use AiModelInfo as root with AiModelInfoHeader, AiModelInfoCapabilities, AiModelInfoPricing, AiModelInfoMeta, and AiModelInfoBadge sub-components. Supports OpenAI, Anthropic, Google, Mistral, Cohere, and Meta providers with automatic theming.",
  "categories": [
    "ai"
  ],
  "type": "registry:ui"
}