"use client"; export const dynamic = "force-dynamic"; import { useCallback, useEffect, useState } from "react"; import { Bot, KeyRound, Loader2, Plus, RefreshCw, Server, Trash2, X } from "lucide-react"; import { useAuth } from "@/auth/clerk"; import { DashboardPageLayout } from "@/components/templates/DashboardPageLayout"; import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; import { ConfirmActionDialog } from "@/components/ui/confirm-action-dialog"; import { useOrganizationMembership } from "@/lib/use-organization-membership"; import type { ProviderCredentialRead, ProviderUsageLiveRead } from "@/api/generated/model"; import { customFetch } from "@/api/mutator"; import { listProviderCredentialsApiV1ProviderCredentialsGet, createProviderCredentialApiV1ProviderCredentialsPost, updateProviderCredentialApiV1ProviderCredentialsCredentialIdPatch, deleteProviderCredentialApiV1ProviderCredentialsCredentialIdDelete, getProviderUsageLiveApiV1ProviderCredentialsCredentialIdUsageGet, } from "@/api/generated/provider-credentials/provider-credentials"; // --------------------------------------------------------------------------- // Provider metadata // --------------------------------------------------------------------------- const PROVIDERS = [ { id: "anthropic", label: "Claude (Anthropic)", icon: Bot, description: "Anthropic Claude API key. Add multiple accounts to track separate keys or billing profiles.", keyLabel: "API Key", keyPlaceholder: "sk-ant-…", showBaseUrl: false, allowMultiple: true, accountKeyDefault: "default", }, { id: "openai", label: "Codex / OpenAI", icon: Bot, description: "OpenAI API key. Add multiple accounts to track usage separately.", keyLabel: "API Key", keyPlaceholder: "sk-…", showBaseUrl: false, allowMultiple: true, accountKeyDefault: "", }, { id: "ollama", label: "Ollama", icon: Server, description: "Ollama instance — local, on-prem, or cloud. Add the base URL; API key only needed for authenticated deployments.", keyLabel: "API Key (optional)", keyPlaceholder: "Leave blank for unauthenticated", showBaseUrl: true, allowMultiple: true, accountKeyDefault: "default", }, ] as const; type ProviderId = (typeof PROVIDERS)[number]["id"]; // --------------------------------------------------------------------------- // Add/Edit form // --------------------------------------------------------------------------- interface CredentialFormProps { providerId: ProviderId; allowMultiple: boolean; showBaseUrl: boolean; keyLabel: string; keyPlaceholder: string; accountKeyDefault: string; onSave: (data: { account_key: string; display_name: string; api_key: string; base_url: string; }) => Promise; onTest: (data: { account_key: string; api_key: string; base_url: string; }) => Promise; onCancel: () => void; isSaving: boolean; error: string | null; } function CredentialForm({ allowMultiple, showBaseUrl, keyLabel, keyPlaceholder, accountKeyDefault, onSave, onTest, onCancel, isSaving, error, }: CredentialFormProps) { const [accountKey, setAccountKey] = useState(accountKeyDefault); const [displayName, setDisplayName] = useState(""); const [apiKey, setApiKey] = useState(""); const [baseUrl, setBaseUrl] = useState(""); const [isTesting, setIsTesting] = useState(false); const [testResult, setTestResult] = useState(null); const [testError, setTestError] = useState(null); const canTest = showBaseUrl ? Boolean(baseUrl.trim()) : Boolean(apiKey.trim()); const runTest = async () => { setIsTesting(true); setTestResult(null); setTestError(null); try { const result = await onTest({ account_key: accountKey.trim() || accountKeyDefault || "test", api_key: apiKey.trim(), base_url: baseUrl.trim(), }); setTestResult(result); } catch (err) { setTestError(err instanceof Error ? err.message : "Test failed."); } finally { setIsTesting(false); } }; return (
{allowMultiple && (
setAccountKey(e.target.value)} placeholder="e.g. work, personal, gpu-box" disabled={isSaving} />

Used to tell accounts apart in cost reports.

)}
setDisplayName(e.target.value)} placeholder={accountKey || "My account"} disabled={isSaving} />
{showBaseUrl && (
setBaseUrl(e.target.value)} placeholder="http://localhost:11434" disabled={isSaving} />
)}
setApiKey(e.target.value)} placeholder={keyPlaceholder} disabled={isSaving} autoComplete="new-password" />
{error && (

{error}

)}
{testError && (

{testError}

)} {testResult && (

{testResult.reachable ? "Connection successful" : "Connection failed"}

{testResult.error ?? `${testResult.models?.length ?? 0} model${(testResult.models?.length ?? 0) === 1 ? "" : "s"} returned`}

)}
); } // --------------------------------------------------------------------------- // Usage strip — live token data fetched from the provider // --------------------------------------------------------------------------- function fmtTokens(n: number | null | undefined): string { if (n == null) return "—"; if (n >= 1_000_000) return `${(n / 1_000_000).toFixed(1)}M`; if (n >= 1_000) return `${(n / 1_000).toFixed(0)}k`; return n.toString(); } function fmtResetMs(ms: number | null | undefined): string { if (ms == null || ms <= 0) return "now"; const s = Math.floor(ms / 1000); if (s < 60) return `${s}s`; const m = Math.floor(s / 60); if (m < 60) return `${m}m ${s % 60}s`; const h = Math.floor(m / 60); return `${h}h ${m % 60}m`; } function UsageStrip({ credentialId, provider }: { credentialId: string; provider: string }) { const [usage, setUsage] = useState(null); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); const [lastFetched, setLastFetched] = useState(null); const fetch = useCallback(async (refresh = false) => { setLoading(true); setError(null); try { const res = await getProviderUsageLiveApiV1ProviderCredentialsCredentialIdUsageGet( credentialId, refresh ? { refresh: true } : undefined, ); if (res.status === 200) { setUsage(res.data); setLastFetched(new Date()); } } catch (err) { setError(err instanceof Error ? err.message : "Failed to fetch usage."); } finally { setLoading(false); } }, [credentialId]); useEffect(() => { void fetch(); }, [fetch]); if (loading && !usage) { return (
Fetching live usage…
); } if (!usage?.reachable) { return (
{usage?.error ?? error ?? "Provider unreachable."}
); } const tok = usage.tokens; const inputTok = usage.input_tokens; const req = usage.requests; const isOllama = provider === "ollama"; const modelCount = usage.models?.length ?? 0; return (
{isOllama ? (
Connected {(usage.models?.length ?? 0) > 0 && ( {usage.models!.length} model{usage.models!.length !== 1 ? "s" : ""} available )}
) : (
{modelCount > 0 && (
Models {modelCount} available
)} {/* Tokens */} {tok.limit != null ? (
Tokens {fmtTokens(tok.remaining)} / {fmtTokens(tok.limit)} remaining {tok.reset_in_ms != null && ( · resets in {fmtResetMs(tok.reset_in_ms)} )}
{tok.pct_used != null && (
90 ? "bg-[color:var(--danger)]" : tok.pct_used > 75 ? "bg-[color:var(--warning)]" : "bg-[color:var(--success)]" }`} style={{ width: `${Math.min(100, tok.pct_used)}%` }} />
)}
) : null} {/* Anthropic input tokens */} {inputTok.limit != null ? (
Input tokens {fmtTokens(inputTok.remaining)} / {fmtTokens(inputTok.limit)} remaining {inputTok.reset_in_ms != null && ( · resets in {fmtResetMs(inputTok.reset_in_ms)} )}
{inputTok.pct_used != null && (
90 ? "bg-[color:var(--danger)]" : inputTok.pct_used > 75 ? "bg-[color:var(--warning)]" : "bg-[color:var(--success)]" }`} style={{ width: `${Math.min(100, inputTok.pct_used)}%` }} />
)}
) : null} {/* Requests */} {req.limit != null ? (
Requests {req.remaining ?? "—"} / {req.limit} remaining {req.reset_in_ms != null && ( · resets in {fmtResetMs(req.reset_in_ms)} )}
) : null} {tok.limit == null && inputTok.limit == null && req.limit == null && (

Connected — provider did not return token/request limit headers for this key tier.

)}
{lastFetched && Updated {Math.round((Date.now() - lastFetched.getTime()) / 1000)}s ago}
)}
); } // --------------------------------------------------------------------------- // Credential row // --------------------------------------------------------------------------- interface CredentialRowProps { cred: ProviderCredentialRead; isAdmin: boolean; onDelete: (cred: ProviderCredentialRead) => void; onToggle: (cred: ProviderCredentialRead) => Promise; showUsage?: boolean; } function CredentialRow({ cred, isAdmin, onDelete, onToggle, showUsage = true }: CredentialRowProps) { const [toggling, setToggling] = useState(false); return (

{cred.display_name || cred.account_key}

key: {cred.account_key} {cred.has_api_key && cred.api_key_last_four ? ( ••••{cred.api_key_last_four} ) : cred.has_api_key ? ( set ) : ( no key )} {cred.base_url && {cred.base_url}}
{isAdmin && (
)}
{showUsage && cred.active && (cred.has_api_key || cred.base_url) && ( )}
); } // --------------------------------------------------------------------------- // Provider section // --------------------------------------------------------------------------- interface ProviderSectionProps { provider: (typeof PROVIDERS)[number]; credentials: ProviderCredentialRead[]; isAdmin: boolean; onAdd: (providerId: ProviderId, data: { account_key: string; display_name: string; api_key: string; base_url: string }) => Promise; onTest: (providerId: ProviderId, data: { account_key: string; api_key: string; base_url: string }) => Promise; onDelete: (cred: ProviderCredentialRead) => void; onToggle: (cred: ProviderCredentialRead) => Promise; } function ProviderSection({ provider, credentials, isAdmin, onAdd, onTest, onDelete, onToggle }: ProviderSectionProps) { const Icon = provider.icon; const [showForm, setShowForm] = useState(false); const [saving, setSaving] = useState(false); const [saveError, setSaveError] = useState(null); const canAdd = isAdmin && (provider.allowMultiple || credentials.length === 0); return (

{provider.label}

{provider.description}

{canAdd && !showForm && ( )}
{showForm && ( { setSaving(true); setSaveError(null); try { await onAdd(provider.id, data); setShowForm(false); } catch (err) { setSaveError(err instanceof Error ? err.message : "Save failed."); } finally { setSaving(false); } }} onTest={(data) => onTest(provider.id, data)} onCancel={() => setShowForm(false)} isSaving={saving} error={saveError} /> )} {credentials.length > 0 && (
{credentials.map((cred) => ( ))}
)} {credentials.length === 0 && !showForm && (

No {provider.label} accounts configured. {isAdmin ? " Click Add to set one up." : ""}

)}
); } // --------------------------------------------------------------------------- // Page // --------------------------------------------------------------------------- export default function AIProvidersSettingsPage() { const { isSignedIn } = useAuth(); const { isAdmin } = useOrganizationMembership(isSignedIn); const [credentials, setCredentials] = useState([]); const [isLoading, setIsLoading] = useState(true); const [error, setError] = useState(null); const [deleteTarget, setDeleteTarget] = useState(null); const [isDeleting, setIsDeleting] = useState(false); const [deleteError, setDeleteError] = useState(null); const load = useCallback(async () => { try { setIsLoading(true); const res = await listProviderCredentialsApiV1ProviderCredentialsGet(); if (res.status === 200) setCredentials(res.data); setError(null); } catch (err) { setError(err instanceof Error ? err.message : "Could not load provider settings."); } finally { setIsLoading(false); } }, []); useEffect(() => { if (isSignedIn) void load(); }, [isSignedIn, load]); const handleAdd = async ( providerId: ProviderId, data: { account_key: string; display_name: string; api_key: string; base_url: string }, ) => { const res = await createProviderCredentialApiV1ProviderCredentialsPost({ provider: providerId, account_key: data.account_key, display_name: data.display_name || data.account_key, api_key: data.api_key || undefined, base_url: data.base_url || undefined, }); if (res.status === 201) { setCredentials((prev) => [...prev, res.data]); } else { throw new Error("Failed to save credential."); } }; const handleTest = async ( providerId: ProviderId, data: { account_key: string; api_key: string; base_url: string }, ): Promise => { const response = await customFetch<{ data: ProviderUsageLiveRead; status: number; headers: Headers; }>("/api/v1/provider-credentials/test", { method: "POST", body: JSON.stringify({ provider: providerId, account_key: data.account_key || "test", api_key: data.api_key || undefined, base_url: data.base_url || undefined, }), }); return response.data; }; const handleToggle = async (cred: ProviderCredentialRead) => { const res = await updateProviderCredentialApiV1ProviderCredentialsCredentialIdPatch( cred.id, { active: !cred.active }, ); if (res.status === 200) { setCredentials((prev) => prev.map((c) => (c.id === cred.id ? res.data : c))); } }; const handleDelete = async () => { if (!deleteTarget) return; setIsDeleting(true); setDeleteError(null); try { await deleteProviderCredentialApiV1ProviderCredentialsCredentialIdDelete(deleteTarget.id); setCredentials((prev) => prev.filter((c) => c.id !== deleteTarget.id)); setDeleteTarget(null); } catch (err) { setDeleteError(err instanceof Error ? err.message : "Delete failed."); } finally { setIsDeleting(false); } }; return ( <> {isLoading ? (
Loading provider settings…
) : error ? (
{error}
) : (
{!isAdmin && (
You can view provider settings. Only org admins can add or change credentials.
)} {PROVIDERS.map((provider) => ( c.provider === provider.id)} isAdmin={isAdmin} onAdd={handleAdd} onTest={handleTest} onDelete={setDeleteTarget} onToggle={handleToggle} /> ))}
)}
{ if (!open) setDeleteTarget(null); }} title="Remove provider account" description={ deleteTarget ? `Remove "${deleteTarget.display_name || deleteTarget.account_key}" (${deleteTarget.provider})? The stored key will be deleted and cannot be recovered.` : "" } onConfirm={handleDelete} isConfirming={isDeleting} errorMessage={deleteError} confirmLabel="Remove account" confirmingLabel="Removing…" confirmClassName="bg-destructive text-destructive-foreground hover:bg-destructive/90" cancelLabel="Keep it" /> ); }