"use client"; import * as React from "react"; import Link from "next/link"; import { AlertCircle, Info, KeyRound, RefreshCw, Shuffle } from "lucide-react"; import { humanizeChatError, secondsLeft, type ChatErrorLike } from "@/lib/chat/humanize-error"; import { ResponsiveDialog } from "@/components/ui/sheet"; import { Button } from "@/components/ui/button"; import { CopyButton } from "@/components/ui/misc"; import { PROVIDERS } from "@/lib/client/providers"; interface Props { error: ChatErrorLike; /** Provider id (message.provider) for the copy. */ provider?: string | null; requestId?: string | null; /** When the error happened (ms) — drives the retry countdown. */ since?: number; onRetry?: () => void; onSwitchModel?: () => void; compact?: boolean; } /** * Humanized provider error with Retry (live countdown from `retryAfterMs`), Switch model and * View details (code, provider code, HTTP status, request id). */ export function MessageError({ error, provider, requestId, since, onRetry, onSwitchModel, compact }: Props) { const providerName = provider ? PROVIDERS[provider as keyof typeof PROVIDERS]?.name ?? provider : undefined; const h = React.useMemo(() => humanizeChatError(error, { providerName, requestId }), [error, providerName, requestId]); const [detailsOpen, setDetailsOpen] = React.useState(false); const [now, setNow] = React.useState(() => since ?? 0); const start = since ?? 0; const wait = h.retryAfterMs && since ? secondsLeft(h.retryAfterMs, start, now) : null; React.useEffect(() => { if (!h.retryAfterMs || !since) return; const t = setInterval(() => setNow(Date.now()), 500); return () => clearInterval(t); }, [h.retryAfterMs, since]); return (

{h.title}

{h.description}

{onRetry && h.canRetry ? ( ) : null} {onSwitchModel && h.suggestSwitch ? ( ) : null} {h.suggestProviders ? ( ) : null}
{h.retryAfterMs ? : null} {h.details.raw ? : null}
); } function Row({ k, v, mono }: { k: string; v: string; mono?: boolean }) { return ( <>
{k}
{v}
); }