import { ErrorBoundary } from "#/components/ErrorBoundary"; import { useState, useEffect, useMemo, useRef } from "react"; import { useNavigate } from "react-router"; import { Button } from "#/components/ui/Button"; import { Input } from "#/components/ui/Input"; import ApiKeysService, { PROVIDER_METADATA, type ProviderConfig, } from "#/api/api-keys-service/api-keys-service.api"; const PROVIDER_IDS = Object.keys(PROVIDER_METADATA); export default function ApiKeysPage() { return ( ); } function ApiKeysContent() { const navigate = useNavigate(); const [providers, setProviders] = useState(() => ApiKeysService.getAll(), ); const [selectedProvider, setSelectedProvider] = useState(null); const [selectedModel, setSelectedModel] = useState(""); const [apiKey, setApiKey] = useState(""); const [baseUrl, setBaseUrl] = useState(""); const [toast, setToast] = useState<{ message: string; type: "success" | "error"; } | null>(null); const [errors, setErrors] = useState>({}); const [providerDropdownOpen, setProviderDropdownOpen] = useState(false); const refreshProviders = () => setProviders(ApiKeysService.getAll()); // Toast effect useEffect(() => { if (!toast) return; const t = setTimeout(() => setToast(null), 2500); return () => clearTimeout(t); }, [toast]); const addFormRef = useRef(null); const providerBtnRef = useRef(null); // Close provider dropdown on outside click useEffect(() => { if (!providerDropdownOpen) return; const handleClick = (e: MouseEvent) => { // Don't close if clicking the toggle button itself if (providerBtnRef.current?.contains(e.target as Node)) return; setProviderDropdownOpen(false); }; document.addEventListener("click", handleClick); return () => document.removeEventListener("click", handleClick); }, [providerDropdownOpen]); // Reset form when provider changes useEffect(() => { if (!selectedProvider) return; const existing = ApiKeysService.get(selectedProvider); if (existing) { setSelectedModel(existing.model); setApiKey(existing.apiKey || ""); setBaseUrl(existing.baseUrl || ""); } else { const meta = PROVIDER_METADATA[selectedProvider]; setSelectedModel(meta?.models?.[0] || ""); setApiKey(""); setBaseUrl(""); } setErrors({}); }, [selectedProvider]); const selectedMeta = selectedProvider ? PROVIDER_METADATA[selectedProvider] : null; // ── Save ── const handleSave = () => { if (!selectedProvider) { setErrors({ provider: "Select a provider" }); return; } const meta = PROVIDER_METADATA[selectedProvider]; if (!meta?.local && apiKey.trim().length < 4) { setErrors({ apiKey: "Enter a valid API key" }); return; } ApiKeysService.save({ provider: selectedProvider, model: selectedModel, apiKey: meta?.local ? undefined : apiKey.trim(), baseUrl: baseUrl.trim() || undefined, }); refreshProviders(); setToast({ message: `${meta?.name || selectedProvider} configured successfully`, type: "success", }); // Reset form to add another setSelectedProvider(null); setSelectedModel(""); setApiKey(""); setBaseUrl(""); }; // ── Remove ── const handleRemove = (providerId: string) => { const meta = PROVIDER_METADATA[providerId]; ApiKeysService.remove(providerId); refreshProviders(); setToast({ message: `${meta?.name || providerId} removed`, type: "success", }); }; // Quick-edit: select a provider & scroll to form const handleEdit = (providerId: string) => { setSelectedProvider(providerId); // Scroll to the add form at top setTimeout(() => { addFormRef.current?.scrollIntoView({ behavior: "smooth", block: "center", }); }, 100); }; // ── Role availability ── const roleAvailability = useMemo( () => ApiKeysService.getRoleAvailability(), [providers], ); const rolesEnabled = Object.values(roleAvailability).filter( (r) => r.available, ).length; return (
{/* ── Toast ── */} {toast && (
{toast.message}
)}
{/* ── Header ── */}

API Keys

Add your LLM provider API keys. The Model Router automatically picks the best model for each task.

{/* ── Top: Quick Add Card ── */}

Add an API key

Select your provider, enter your key, and you're done.

{/* Row: Provider + Model */}
{/* Provider Select */}
{providerDropdownOpen && (
{PROVIDER_IDS.map((id) => { const meta = PROVIDER_METADATA[id]; const configured = providers.find( (p) => p.provider === id, ); return ( ); })}
)} {errors.provider && (

{errors.provider}

)}
{/* API Key */}
{selectedMeta?.local ? (
Running locally via Ollama
) : (
{ setApiKey(e.target.value); setErrors((prev) => ({ ...prev, apiKey: "" })); }} placeholder={ selectedProvider ? `Enter your ${selectedMeta?.name} key` : "Select a provider first" } disabled={!selectedProvider} className={`h-10 ${errors.apiKey ? "border-error" : ""}`} /> {errors.apiKey && (

{errors.apiKey}

)}
)}
{/* Row: Model + optional Base URL */} {selectedProvider && (
{/* Model quick-pick */} {selectedMeta?.models && (
{selectedMeta.models.map((m) => ( ))}
)} {/* Base URL (optional) */}
setBaseUrl(e.target.value)} placeholder="https://api.example.com/v1" className="h-10" />
)} {/* Save / Get Key */}
{selectedProvider && selectedMeta && !selectedMeta.local && ( Get key at {selectedMeta.name} → )} {!selectedProvider && ( )}
{/* ── Status Cards ── */}

{providers.length}/{PROVIDER_IDS.length}

Providers configured

{rolesEnabled}/4

Agent roles active

{providers.length > 0 ? "Ready" : "Not configured"}

Model Router status

{/* ── Configured Providers List ── */} {providers.length > 0 && (

Configured Providers

{providers.map((p) => { const meta = PROVIDER_METADATA[p.provider]; const rolesForProvider = Object.entries( ApiKeysService.getRoleAvailability(), ) .filter(([, info]) => info.providers.includes(p.provider)) .map(([role]) => role); return (
{(meta?.name || p.provider).charAt(0)}

{meta?.name || p.provider}

{p.model}

{/* Role tags */}
{rolesForProvider.map((role) => ( {role} ))}
); })}
)} {/* ── Empty State ── */} {providers.length === 0 && (

No API keys yet

Select a provider above and add your first key.

)} {/* ── Footer info ── */} {providers.length > 0 && (

Keys stored locally in your browser.

)}
); }