import { useCallback, useEffect, useState } from 'react'; import { useAtelierClient } from '../lib/api'; import type { ProviderStatus } from '../lib/api'; /** * The providers Officer curates, and which of them we hold a key for. * * One list, one call. There used to be two — the configured rows and the adapter catalogue — and they * were different shapes answering overlapping questions, which is most of why the old screen was * confusing. `/providers` now returns the curated list with each entry's key status and its models * attached, so "what can I use" and "what have I set up" are one answer. */ export const useProviders = () => { const client = useAtelierClient(); const [providers, setProviders] = useState([]); const [loading, setLoading] = useState(true); const [busy, setBusy] = useState(false); const [refreshing, setRefreshing] = useState(false); const [error, setError] = useState(null); const refresh = useCallback(async () => { try { setProviders(await client.listProviders()); setError(null); } catch (err) { setError(err instanceof Error ? err.message : String(err)); } finally { setLoading(false); } // eslint-disable-next-line react-hooks/exhaustive-deps }, []); useEffect(() => { void refresh(); }, [refresh]); const guard = async (action: () => Promise) => { setBusy(true); try { setProviders(await action()); setError(null); return true; } catch (err) { setError(err instanceof Error ? err.message : String(err)); return false; } finally { setBusy(false); } }; /** * Re-read a provider's models from the vendor, or every provider when omitted. * * Its own busy flag, separate from `busy`: this is a live fetch to a third party and takes seconds, * where setting a key is a local write. One flag would grey out the screen for a network round trip. */ const refreshCatalogue = async (name?: string) => { setRefreshing(true); try { const result = await client.refreshCatalogue(name); setProviders(result.providers); setError(null); return result; } catch (err) { setError(err instanceof Error ? err.message : String(err)); return null; } finally { setRefreshing(false); } }; return { providers, loading, busy, refreshing, error, refresh, refreshCatalogue, setKey: (name: string, apiKey: string) => guard(() => client.setProviderKey(name, apiKey)), clearKey: (name: string) => guard(() => client.clearProviderKey(name)), byName: (name: string) => providers.find((provider) => provider.name === name), /** The one a generation would use if you pressed Generate now: your choice, else the first with a key. */ firstUsable: () => providers.find((provider) => provider.configured && provider.usable), }; }; export type ProvidersManager = ReturnType;