import { type CSSProperties, memo, useState } from "react"; import { normalizeProviderAccentColor, providerAccentForegroundColor, providerInstanceInitials, } from "@t3tools/client-runtime/state/provider-instance-display"; import { normalizeProviderIconUrl, ProviderDriverKind } from "@t3tools/contracts"; import { AntigravityIcon, ClaudeAI, Icon, OpenAI } from "../Icons"; import { cn } from "~/lib/utils"; import { providerClients } from "../settings/providerDriverMeta"; import { ProviderPackageIcon } from "./ProviderPackageIcon"; import { AcpRegistryAgentIcon, officialAcpRegistryIconUrlForAgentId, resolveOfficialAcpRegistryIconUrl, } from "../settings/AcpRegistryIcon"; const PROVIDER_ICON_BY_PROVIDER: Partial> = { [ProviderDriverKind.make("codex")]: OpenAI, [ProviderDriverKind.make("claudeAgent")]: ClaudeAI, [ProviderDriverKind.make("antigravity")]: AntigravityIcon, }; const PROVIDER_TEXT_COLOR_BY_PROVIDER: Partial> = { [ProviderDriverKind.make("codex")]: "text-black dark:text-white", [ProviderDriverKind.make("claudeAgent")]: "text-[#d97757]", [ProviderDriverKind.make("antigravity")]: "text-[#5b87bf]", }; export function providerTextColor(driverKind: ProviderDriverKind): { readonly className?: string; readonly style?: CSSProperties; } { const icon = providerClients.get(driverKind)?.icon; if (icon) { return { className: "text-(--icon-light) dark:text-(--icon-dark)", style: { "--icon-light": icon.fill.light, "--icon-dark": icon.fill.dark } as CSSProperties, }; } const className = PROVIDER_TEXT_COLOR_BY_PROVIDER[driverKind]; return className ? { className } : {}; } export function resolveProviderInstanceAcpRegistryIconUrl(input: { readonly driverKind: ProviderDriverKind; readonly agentId?: string | undefined; readonly iconUrl?: string | undefined; }): string | null { if (input.driverKind !== "acpRegistry") return null; return ( resolveOfficialAcpRegistryIconUrl(input.iconUrl ?? null) ?? officialAcpRegistryIconUrlForAgentId(input.agentId?.trim() || null) ); } export const ProviderInstanceIcon = memo(function ProviderInstanceIcon(props: { driverKind: ProviderDriverKind; displayName: string; accentColor?: string | undefined; acpRegistryAgentId?: string | undefined; iconUrl?: string | undefined; showBadge?: boolean; badgeContent?: "initials" | "none"; size?: "default" | "compact"; className?: string; iconClassName?: string; badgeClassName?: string; indicatorBackground?: string; }) { const Icon = PROVIDER_ICON_BY_PROVIDER[props.driverKind] ?? null; const packageIcon = providerClients.get(props.driverKind)?.icon; const indicatorBackground = props.indicatorBackground ?? "var(--card)"; const accentColor = normalizeProviderAccentColor(props.accentColor); const accentStyle = accentColor ? ({ "--provider-accent": accentColor, "--provider-accent-foreground": providerAccentForegroundColor(accentColor), } as CSSProperties) : undefined; const badgeContent = props.badgeContent ?? "initials"; const iconClassName = cn(props.size === "compact" && "size-3.5", props.iconClassName); const isAcpRegistry = props.driverKind === "acpRegistry"; const registryIconUrl = resolveProviderInstanceAcpRegistryIconUrl({ driverKind: props.driverKind, agentId: props.acpRegistryAgentId, iconUrl: props.iconUrl, }); const customIconUrl = isAcpRegistry && resolveOfficialAcpRegistryIconUrl(props.iconUrl ?? null) ? null : normalizeProviderIconUrl(props.iconUrl); const [image, setImage] = useState<{ url: string; loaded: boolean } | null>(null); const currentImage = image?.url === customIconUrl ? image : null; const showCustomIcon = customIconUrl !== null && currentImage?.loaded === true; return ( {customIconUrl && currentImage?.loaded !== false ? ( setImage({ url: customIconUrl, loaded: true })} onError={() => setImage({ url: customIconUrl, loaded: false })} /> ) : null} {showCustomIcon ? null : isAcpRegistry ? ( ) : packageIcon ? ( ) : Icon ? ( ) : ( {providerInstanceInitials(props.displayName)} )} {props.showBadge ? ( {badgeContent === "initials" ? providerInstanceInitials(props.displayName) : null} ) : null} ); });