import { IpcClient } from "@/ipc/ipc_client"; import { AI_STREAMING_ERROR_MESSAGE_PREFIX } from "@/shared/texts"; import { X, ExternalLink as ExternalLinkIcon, CircleArrowUp, } from "lucide-react"; import ReactMarkdown from "react-markdown"; import remarkGfm from "remark-gfm"; export function ChatErrorBox({ onDismiss, error, isMoreMinimoreProEnabled, }: { onDismiss: () => void; error: string; isMoreMinimoreProEnabled: boolean; }) { if (error.includes("doesn't have a free quota tier")) { return ( {error} Access with MoreMinimore Pro {" "} or switch to another model. ); } // Important, this needs to come after the "free quota tier" check // because it also includes this URL in the error message // // Sometimes MoreMinimore Pro can return rate limit errors and we do not want to // show the upgrade to MoreMinimore Pro link in that case because they are // already on the MoreMinimore Pro plan. if ( !isMoreMinimoreProEnabled && (error.includes("Resource has been exhausted") || error.includes("https://ai.google.dev/gemini-api/docs/rate-limits") || error.includes("Provider returned error")) ) { return ( {error}
Upgrade to MoreMinimore Pro Troubleshooting guide
); } if (error.includes("LiteLLM Virtual Key expected")) { return ( Looks like you don't have a valid MoreMinimore Pro key.{" "} Upgrade to MoreMinimore Pro {" "} today. ); } if (isMoreMinimoreProEnabled && error.includes("ExceededBudget:")) { return ( You have used all of your MoreMinimore AI credits this month.{" "} Reload or upgrade your subscription {" "} and get more AI credits ); } // This is a very long list of model fallbacks that clutters the error message. // // We are matching "Fallbacks=[{" and not just "Fallbacks=" because the fallback // model itself can error and we want to include the fallback model error in the error message. // Example: https://github.com/kunthawat/moreminimore-vibe/issues/1849#issuecomment-3590685911 const fallbackPrefix = "Fallbacks=[{"; if (error.includes(fallbackPrefix)) { error = error.split(fallbackPrefix)[0]; } return ( {error}
{!isMoreMinimoreProEnabled && error.includes(AI_STREAMING_ERROR_MESSAGE_PREFIX) && !error.includes("TypeError: terminated") && ( Upgrade to MoreMinimore Pro )} Read docs
); } function ExternalLink({ href, children, variant = "secondary", icon, }: { href: string; children: React.ReactNode; variant?: "primary" | "secondary"; icon?: React.ReactNode; }) { const baseClasses = "cursor-pointer inline-flex items-center gap-1.5 rounded-md px-3 py-1.5 text-sm font-medium shadow-sm focus:outline-none focus:ring-2"; const primaryClasses = "bg-blue-600 text-white hover:bg-blue-700 focus:ring-blue-500"; const secondaryClasses = "bg-blue-50 text-blue-700 border border-blue-200 hover:bg-blue-100 hover:border-blue-300 focus:ring-blue-200"; const iconElement = icon ?? (variant === "primary" ? ( ) : ( )); return ( IpcClient.getInstance().openExternalUrl(href)} > {children} {iconElement} ); } function ChatErrorContainer({ onDismiss, children, }: { onDismiss: () => void; children: React.ReactNode | string; }) { return (
{typeof children === "string" ? ( ( { e.preventDefault(); if (props.href) { IpcClient.getInstance().openExternalUrl(props.href); } }} className="text-blue-500 hover:text-blue-700" > {linkChildren} ), }} > {children} ) : ( children )}
); } function ChatInfoContainer({ onDismiss, children, }: { onDismiss: () => void; children: React.ReactNode; }) { return (
{children}
); }