import { useState } from 'react'; import { Plus, Save, Trash2, RefreshCw, Loader2, X } from 'lucide-react'; import { useQuery, useQueryClient } from '@tanstack/react-query'; import { toast } from 'sonner'; import { Button } from '@/components/ui/button'; import { Input } from '@/components/ui/input'; import { CommandDialog, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList, } from '@/components/ui/command'; import { useClient } from 'hooks/useClient'; type VersionInfo = { version: string | null; path: string | null; globalPath: string | null }; type StoredApiKeys = { keys: { provider: string; value: string }[] }; type LocalProviderEntry = { id: string; name: string; url: string; apiType: 'ollama' | 'openai-compatible' | 'lmstudio'; auth?: { type: 'api-key' | 'basic' }; }; type ProbeResult = { success: boolean; apiType?: LocalProviderEntry['apiType']; name?: string; needsAuth?: boolean; authType?: 'api-key' | 'basic' | 'unknown'; models?: string[]; error?: string; }; const PI_PROVIDERS: { key: string; piId: string }[] = [ { key: 'Anthropic', piId: 'anthropic' }, { key: 'OpenAI', piId: 'openai' }, { key: 'Google', piId: 'google' }, { key: 'Groq', piId: 'groq' }, { key: 'Mistral', piId: 'mistral' }, { key: 'xAI', piId: 'xai' }, { key: 'OpenRouter', piId: 'openrouter' }, { key: 'MiniMax', piId: 'minimax' }, { key: 'Hugging Face', piId: 'huggingface' }, { key: 'Azure OpenAI', piId: 'azure-openai-responses' }, { key: 'OpenCode Zen', piId: 'zai' }, { key: 'Cerebras', piId: 'cerebras' }, ]; type ProbeState = | { step: 'url' } | { step: 'probing' } | { step: 'auth'; probe: ProbeResult } | { step: 'saving' }; export const AIHarnessesSection = () => { const client = useClient(); const queryClient = useQueryClient(); const [installing, setInstalling] = useState(false); const { data: piMonoVersion, isLoading: piMonoLoading } = useQuery({ queryKey: ['PI_MONO_VERSION'], queryFn: () => client.get('/server-settings/pi-mono/version'), }); const { data: piMonoKeys } = useQuery({ queryKey: ['PI_MONO_API_KEYS'], queryFn: () => client.get('/server-settings/pi-mono/api-keys'), enabled: !!piMonoVersion?.version, }); const { data: localProviders = [] as LocalProviderEntry[] } = useQuery({ queryKey: ['PI_MONO_LOCAL_PROVIDERS'], queryFn: () => client.get('/server-settings/pi-mono/local-providers'), enabled: !!piMonoVersion?.version, }); const { data: localHealth = {} as Record } = useQuery({ queryKey: ['PI_MONO_LOCAL_HEALTH'], queryFn: () => client.get>('/server-settings/pi-mono/local-providers/health'), enabled: localProviders.length > 0, refetchInterval: 15_000, }); const [keyInputs, setKeyInputs] = useState>({}); const [savingKey, setSavingKey] = useState(null); const [commandOpen, setCommandOpen] = useState(false); const [editingProvider, setEditingProvider] = useState(null); // Local provider connection flow const [addingLocal, setAddingLocal] = useState(false); const [localName, setLocalName] = useState(''); const [localUrl, setLocalUrl] = useState(''); const [probeState, setProbeState] = useState({ step: 'url' }); const [authApiKey, setAuthApiKey] = useState(''); const [authUsername, setAuthUsername] = useState(''); const [authPassword, setAuthPassword] = useState(''); const resetLocalForm = () => { setAddingLocal(false); setLocalName(''); setLocalUrl(''); setProbeState({ step: 'url' }); setAuthApiKey(''); setAuthUsername(''); setAuthPassword(''); }; const storedKeys: StoredApiKeys['keys'] = piMonoKeys?.keys ?? []; const storedPiIds = new Set(storedKeys.map((k) => k.provider)); const connectedProviders = PI_PROVIDERS.filter((p) => storedPiIds.has(p.piId)); const unconnectedProviders = PI_PROVIDERS.filter((p) => !storedPiIds.has(p.piId)); const getStoredMasked = (piId: string) => storedKeys.find((k) => k.provider === piId)?.value ?? ''; const saveApiKey = async (piId: string) => { const value = keyInputs[piId]; if (value === undefined) return; setSavingKey(piId); try { await client.put('/server-settings/pi-mono/api-keys', { provider: piId, value }); queryClient.invalidateQueries({ queryKey: ['PI_MONO_API_KEYS'] }); queryClient.invalidateQueries({ queryKey: ['PI_MODELS'] }); setKeyInputs((prev) => { const next = { ...prev }; delete next[piId]; return next; }); } finally { setSavingKey(null); } }; const disconnectProvider = async (provider: typeof PI_PROVIDERS[number]) => { await client.put('/server-settings/pi-mono/api-keys', { provider: provider.piId, value: '' }); queryClient.invalidateQueries({ queryKey: ['PI_MONO_API_KEYS'] }); queryClient.invalidateQueries({ queryKey: ['PI_MODELS'] }); if (editingProvider === provider.key) setEditingProvider(null); }; const installPiMono = async () => { setInstalling(true); try { const result = await client.post('/server-settings/pi-mono/install'); queryClient.setQueryData(['PI_MONO_VERSION'], result); } finally { setInstalling(false); } }; const handleProbe = async (auth?: { type: 'api-key'; apiKey: string } | { type: 'basic'; username: string; password: string }) => { setProbeState({ step: 'probing' }); try { const result = await client.post('/server-settings/pi-mono/local-providers/probe', { url: localUrl.trim(), auth, }); if (!result.success) { toast.error(result.error ?? 'Could not detect API type'); setProbeState({ step: 'url' }); return; } if (result.needsAuth) { setProbeState({ step: 'auth', probe: result }); return; } // No auth needed — save directly await saveLocalProvider(result, auth); } catch { toast.error('Failed to connect'); setProbeState({ step: 'url' }); } }; const handleAuthSubmit = async (probe: ProbeResult) => { const auth = probe.authType === 'basic' ? { type: 'basic' as const, username: authUsername, password: authPassword } : { type: 'api-key' as const, apiKey: authApiKey }; // Re-probe with credentials to verify they work setProbeState({ step: 'probing' }); try { const result = await client.post('/server-settings/pi-mono/local-providers/probe', { url: localUrl.trim(), auth, }); if (!result.success) { toast.error(result.error ?? 'Could not connect with provided credentials'); setProbeState({ step: 'auth', probe }); return; } if (result.needsAuth) { toast.error('Authentication failed'); setProbeState({ step: 'auth', probe }); return; } await saveLocalProvider(result, auth); } catch { toast.error('Failed to connect'); setProbeState({ step: 'auth', probe }); } }; const saveLocalProvider = async ( probe: ProbeResult, auth?: { type: 'api-key'; apiKey: string } | { type: 'basic'; username: string; password: string }, ) => { setProbeState({ step: 'saving' }); try { await client.post('/server-settings/pi-mono/local-providers', { url: localUrl.trim(), name: localName.trim() || probe.name, apiType: probe.apiType, auth, }); queryClient.invalidateQueries({ queryKey: ['PI_MONO_LOCAL_PROVIDERS'] }); queryClient.invalidateQueries({ queryKey: ['PI_MONO_LOCAL_HEALTH'] }); queryClient.invalidateQueries({ queryKey: ['PI_MODELS'] }); toast.success(`Connected to ${probe.name}`); resetLocalForm(); } catch { toast.error('Failed to save provider'); setProbeState({ step: 'url' }); } }; const removeLocalProvider = async (id: string) => { await client.delete(`/server-settings/pi-mono/local-providers/${id}`); queryClient.invalidateQueries({ queryKey: ['PI_MONO_LOCAL_PROVIDERS'] }); queryClient.invalidateQueries({ queryKey: ['PI_MONO_LOCAL_HEALTH'] }); queryClient.invalidateQueries({ queryKey: ['PI_MODELS'] }); }; return (
Pi Mono {piMonoLoading ? ( Checking... ) : piMonoVersion?.version ? (
{piMonoVersion.version}
) : ( )}
{piMonoVersion?.version && ( <> {/* Local Providers */}
Local Providers
{localProviders.map((lp: LocalProviderEntry) => (
{lp.name} {lp.url}
))} {addingLocal ? (
{/* Step 1: Name + URL inputs stacked */} setLocalName(ev.target.value)} onKeyDown={(ev) => { if (ev.key === 'Escape') resetLocalForm(); }} disabled={probeState.step !== 'url'} autoFocus /> setLocalUrl(ev.target.value)} onKeyDown={(ev) => { if (ev.key === 'Escape') resetLocalForm(); if (ev.key === 'Enter' && localUrl.trim() && probeState.step === 'url') handleProbe(); }} disabled={probeState.step !== 'url'} />
{probeState.step === 'url' && ( )} {(probeState.step === 'probing' || probeState.step === 'saving') && ( )}
{/* Step 2: Auth form (if needed) */} {probeState.step === 'auth' && (
{probeState.probe.name} requires authentication {probeState.probe.authType === 'basic' ? ( <> setAuthUsername(ev.target.value)} autoFocus /> setAuthPassword(ev.target.value)} onKeyDown={(ev) => { if (ev.key === 'Enter' && authUsername && authPassword) handleAuthSubmit(probeState.probe); }} /> ) : ( <> setAuthApiKey(ev.target.value)} onKeyDown={(ev) => { if (ev.key === 'Enter' && authApiKey) handleAuthSubmit(probeState.probe); }} autoFocus /> )}
)}
) : ( )}
{/* Remote Providers */}
Remote Providers
{connectedProviders.map((provider) => (
setKeyInputs((prev) => ({ ...prev, [provider.piId]: ev.target.value }))} />
))} {editingProvider && (() => { const provider = PI_PROVIDERS.find((p) => p.key === editingProvider); if (!provider || connectedProviders.includes(provider)) return null; return (
setKeyInputs((prev) => ({ ...prev, [provider.piId]: ev.target.value }))} autoFocus />
); })()} {unconnectedProviders.length > 0 && ( )}
No providers found. {unconnectedProviders.map((provider) => ( { setEditingProvider(provider.key); setCommandOpen(false); }} > {provider.key} ))}
)}
); };