import { Cpu } from "lucide-react";
export interface ProviderIconProps {
provider: string;
size?: "sm" | "md" | "lg";
}
const sizeMap = {
sm: 16,
md: 20,
lg: 24,
};
// Anthropic "A" logo from SimpleIcons
function AnthropicIcon({ size, color, label = "Anthropic" }: { size: number; color: string; label?: string }) {
return (
);
}
// OpenAI flower logo from Iconify/SimpleIcons
function OpenAIIcon({ size, color, label = "OpenAI" }: { size: number; color: string; label?: string }) {
return (
);
}
// Google Gemini sparkle logo from SimpleIcons
function GeminiIcon({ size, color, label = "Google Gemini" }: { size: number; color: string; label?: string }) {
return (
);
}
// Ollama llama head logo from SimpleIcons
function OllamaIcon({ size, color, label = "Ollama" }: { size: number; color: string; label?: string }) {
return (
);
}
// MiniMax logo from SimpleIcons — stylized "M" grid mark
function MiniMaxIcon({ size, color, label = "MiniMax" }: { size: number; color: string; label?: string }) {
return (
);
}
// Z.ai / Zhipu AI logo — stylized "Z" mark from brand identity
function ZaiIcon({ size, color, label = "Z.ai" }: { size: number; color: string; label?: string }) {
return (
);
}
// Kimi / Moonshot AI logo — crescent moon mark from official Moonshot AI brand identity
// Source: https://raw.githubusercontent.com/gilbarbara/logos/master/logos/moonshot-ai.svg
// The moon crescent shape is derived from the official Moonshot AI logo
// For a 24x24 icon, we use a simplified crescent moon path
function KimiIcon({ size, color, label = "Kimi" }: { size: number; color: string; label?: string }) {
return (
);
}
function BedrockIcon({ size, color, label = "Amazon Bedrock" }: { size: number; color: string; label?: string }) {
return (
);
}
function XaiIcon({ size, color, label = "xAI" }: { size: number; color: string; label?: string }) {
return (
);
}
function OpencodeIcon({ size, color, label = "Opencode" }: { size: number; color: string; label?: string }) {
return (
);
}
// Qwen / Tongyi Qianwen monogram — stylized "Q" with the tail piercing
// the ring, a recognizable simplification of the official mark.
function QwenIcon({ size, color, label = "Qwen" }: { size: number; color: string; label?: string }) {
return (
);
}
// LM Studio — rounded square frame with a stylized "LM" wordmark inside,
// reminiscent of the desktop app's icon.
function LMStudioIcon({ size, color, label = "LM Studio" }: { size: number; color: string; label?: string }) {
return (
);
}
// Hugging Face — the iconic smiling-face emoji used as their official
// brand mark. Eyes and mouth are stamped using the surrounding contrast
// token so the face remains legible on any theme background.
function HuggingFaceIcon({ size, color, label = "Hugging Face" }: { size: number; color: string; label?: string }) {
return (
);
}
// Mistral — geometric "M" simplified from the official tricolor mark.
function MistralIcon({ size, color, label = "Mistral AI" }: { size: number; color: string; label?: string }) {
return (
);
}
// Azure — Microsoft Azure "A" sail mark.
function AzureIcon({ size, color, label = "Azure" }: { size: number; color: string; label?: string }) {
return (
);
}
// Cerebras — concentric arcs forming a stylized "C", echoing the
// official wafer-scale brand mark.
function CerebrasIcon({ size, color, label = "Cerebras" }: { size: number; color: string; label?: string }) {
return (
);
}
// Groq — stylized lightning-bolt pulse, evoking their fast-inference
// brand identity.
function GroqIcon({ size, color, label = "Groq" }: { size: number; color: string; label?: string }) {
return (
);
}
// Vercel — the iconic equilateral triangle wordmark.
function VercelIcon({ size, color, label = "Vercel" }: { size: number; color: string; label?: string }) {
return (
);
}
// Fireworks AI — burst of dots radiating from a central nucleus, a
// monochrome simplification of their identity mark.
function FireworksIcon({ size, color, label = "Fireworks AI" }: { size: number; color: string; label?: string }) {
return (
);
}
// OpenRouter ring mark — simplified geometric version of the OpenRouter brand symbol.
function OpenRouterIcon({ size, color, label = "OpenRouter" }: { size: number; color: string; label?: string }) {
return (
);
}
// GitHub logo (Octocat mark) from SimpleIcons.
function GitHubIcon({ size, color, label = "GitHub" }: { size: number; color: string; label?: string }) {
return (
);
}
// Hermes — caduceus (winged staff) mark, single-color so it adapts to theme.
function HermesIcon({ size, color, label = "Hermes" }: { size: number; color: string; label?: string }) {
return (
);
}
// OpenClaw — pixel-art lobster (verbatim 16×16 source SVG, recolor disabled
// so the iconic palette survives).
function OpenClawIcon({ size, label = "OpenClaw" }: { size: number; color: string; label?: string }) {
return (
);
}
// Paperclip — official paperclip outline, theme-color aware.
function PaperclipIcon({ size, color, label = "Paperclip" }: { size: number; color: string; label?: string }) {
return (
);
}
// Anthropic "A" mark composited with a small terminal "> _" badge in the
// bottom-right, visually signalling "Anthropic, but via the local CLI".
function ClaudeCliIcon({ size, color, label = "Anthropic — via Claude CLI" }: { size: number; color: string; label?: string }) {
return (
);
}
const providerConfig: Record<
string,
{ component: typeof AnthropicIcon; color: string; label?: string }
> = {
// Branded provider colors are tokenized in app/styles.css for theme-system consistency.
anthropic: { component: AnthropicIcon, color: "var(--provider-anthropic)" },
"claude-cli": { component: ClaudeCliIcon, color: "var(--provider-anthropic)", label: "Anthropic — via Claude CLI" },
"pi-claude-cli": { component: ClaudeCliIcon, color: "var(--provider-anthropic)", label: "Anthropic — via Claude CLI" },
openai: { component: OpenAIIcon, color: "var(--provider-openai)" },
"openai-codex": { component: OpenAIIcon, color: "var(--provider-openai)", label: "OpenAI Codex" }, // OpenAI alias
google: { component: GeminiIcon, color: "var(--provider-gemini)" },
gemini: { component: GeminiIcon, color: "var(--provider-gemini)" }, // Gemini alias family
"google-antigravity": { component: GeminiIcon, color: "var(--provider-gemini)", label: "Google Gemini" },
antigravity: { component: GeminiIcon, color: "var(--provider-gemini)", label: "Google Gemini" },
"google-vertex": { component: GeminiIcon, color: "var(--provider-gemini)", label: "Google Vertex AI" },
vertex: { component: GeminiIcon, color: "var(--provider-gemini)", label: "Google Vertex AI" },
"google-cloud-code": { component: GeminiIcon, color: "var(--provider-gemini)", label: "Google Cloud Code" },
"cloud-code": { component: GeminiIcon, color: "var(--provider-gemini)", label: "Google Cloud Code" },
"google-gemini-cli": { component: GeminiIcon, color: "var(--provider-gemini)", label: "Google Gemini CLI" },
"google-generative-ai": { component: GeminiIcon, color: "var(--provider-gemini)", label: "Google Generative AI" },
// Monochrome marks use theme-aware text color for dark/light safety.
ollama: { component: OllamaIcon, color: "var(--text)" },
github: { component: GitHubIcon, color: "var(--text)" },
"github-copilot": { component: GitHubIcon, color: "var(--text)", label: "GitHub Copilot" },
// OpenRouter appears in onboarding auth cards and should not fall back to CPU.
openrouter: { component: OpenRouterIcon, color: "var(--provider-openrouter)" },
minimax: { component: MiniMaxIcon, color: "var(--provider-minimax)" },
"minimax-cn": { component: MiniMaxIcon, color: "var(--provider-minimax)", label: "MiniMax (CN)" },
zai: { component: ZaiIcon, color: "var(--provider-zai)" },
kimi: { component: KimiIcon, color: "var(--provider-kimi)" },
moonshot: { component: KimiIcon, color: "var(--provider-kimi)" }, // Moonshot alias
"kimi-coding": { component: KimiIcon, color: "var(--provider-kimi)", label: "Kimi" }, // Kimi alias
bedrock: { component: BedrockIcon, color: "var(--provider-bedrock)" },
"amazon-bedrock": { component: BedrockIcon, color: "var(--provider-bedrock)", label: "Amazon Bedrock" },
xai: { component: XaiIcon, color: "var(--text)" },
grok: { component: XaiIcon, color: "var(--text)", label: "xAI" },
opencode: { component: OpencodeIcon, color: "var(--provider-opencode)" },
"opencode-go": { component: OpencodeIcon, color: "var(--provider-opencode)", label: "Opencode (Go)" },
qwen: { component: QwenIcon, color: "var(--provider-qwen)" },
"qwen-ai": { component: QwenIcon, color: "var(--provider-qwen)", label: "Qwen" },
"qwen-coder": { component: QwenIcon, color: "var(--provider-qwen)", label: "Qwen Coder" },
alibaba: { component: QwenIcon, color: "var(--provider-qwen)", label: "Qwen" },
tongyi: { component: QwenIcon, color: "var(--provider-qwen)", label: "Qwen" },
lmstudio: { component: LMStudioIcon, color: "var(--provider-lmstudio)", label: "LM Studio" },
"lm-studio": { component: LMStudioIcon, color: "var(--provider-lmstudio)", label: "LM Studio" },
huggingface: { component: HuggingFaceIcon, color: "var(--provider-huggingface)", label: "Hugging Face" },
"hugging-face": { component: HuggingFaceIcon, color: "var(--provider-huggingface)", label: "Hugging Face" },
hf: { component: HuggingFaceIcon, color: "var(--provider-huggingface)", label: "Hugging Face" },
mistral: { component: MistralIcon, color: "var(--provider-mistral)", label: "Mistral AI" },
"mistral-ai": { component: MistralIcon, color: "var(--provider-mistral)", label: "Mistral AI" },
azure: { component: AzureIcon, color: "var(--provider-azure)" },
"azure-openai": { component: AzureIcon, color: "var(--provider-azure)", label: "Azure OpenAI" },
"azure-openai-responses": { component: AzureIcon, color: "var(--provider-azure)", label: "Azure OpenAI" },
fireworks: { component: FireworksIcon, color: "var(--provider-fireworks)", label: "Fireworks AI" },
"fireworks-ai": { component: FireworksIcon, color: "var(--provider-fireworks)", label: "Fireworks AI" },
fireworksai: { component: FireworksIcon, color: "var(--provider-fireworks)", label: "Fireworks AI" },
cerebras: { component: CerebrasIcon, color: "var(--provider-cerebras)" },
groq: { component: GroqIcon, color: "var(--provider-groq)" },
vercel: { component: VercelIcon, color: "var(--provider-vercel)" },
"vercel-ai-gateway": { component: VercelIcon, color: "var(--provider-vercel)", label: "Vercel AI Gateway" },
// Runtime-plugin marks (Hermes / OpenClaw / Paperclip).
hermes: { component: HermesIcon, color: "var(--provider-hermes)", label: "Hermes" },
"hermes-agent": { component: HermesIcon, color: "var(--provider-hermes)", label: "Hermes" },
hermesagent: { component: HermesIcon, color: "var(--provider-hermes)", label: "Hermes" },
openclaw: { component: OpenClawIcon, color: "var(--provider-openclaw)", label: "OpenClaw" },
"open-claw": { component: OpenClawIcon, color: "var(--provider-openclaw)", label: "OpenClaw" },
paperclip: { component: PaperclipIcon, color: "var(--provider-paperclip)", label: "Paperclip" },
paperclipai: { component: PaperclipIcon, color: "var(--provider-paperclip)", label: "Paperclip" },
"paperclip-ai": { component: PaperclipIcon, color: "var(--provider-paperclip)", label: "Paperclip" },
};
export function ProviderIcon({ provider, size = "sm" }: ProviderIconProps) {
const normalizedProvider = provider.toLowerCase();
const config = providerConfig[normalizedProvider];
const IconComponent = config?.component;
const color = config?.color ?? "var(--text-muted)";
const label = config?.label;
const iconSize = sizeMap[size];
return (
{IconComponent ? (
) : (
)}
);
}