diff --git a/apps/ui/src/components/views/settings-view/providers/opencode-dynamic-providers.tsx b/apps/ui/src/components/views/settings-view/providers/opencode-dynamic-providers.tsx deleted file mode 100644 index 723fb052..00000000 --- a/apps/ui/src/components/views/settings-view/providers/opencode-dynamic-providers.tsx +++ /dev/null @@ -1,294 +0,0 @@ -/** - * OpenCode Dynamic Providers Component - * - * Shows authenticated providers from OpenCode CLI and allows - * refreshing the model list from the CLI. - */ - -import { useState, useCallback, useEffect } from 'react'; -import { Button } from '@/components/ui/button'; -import { Badge } from '@/components/ui/badge'; -import { RefreshCw, CheckCircle2, XCircle, Cloud, Terminal, Loader2 } from 'lucide-react'; -import { toast } from 'sonner'; -import { cn } from '@/lib/utils'; -import { getElectronAPI } from '@/lib/electron'; -import { useAppStore } from '@/store/app-store'; -import { createLogger } from '@automaker/utils/logger'; - -const logger = createLogger('OpenCodeDynamicProviders'); - -interface OpenCodeProviderInfo { - id: string; - name: string; - authenticated: boolean; - authMethod?: 'oauth' | 'api_key'; -} - -interface OpenCodeDynamicProvidersProps { - isCliInstalled: boolean; -} - -/** - * Provider display configuration - */ -const PROVIDER_CONFIG: Record = { - copilot: { icon: '', displayName: 'GitHub Copilot' }, - anthropic: { icon: '', displayName: 'Anthropic' }, - openai: { icon: '', displayName: 'OpenAI' }, - google: { icon: '', displayName: 'Google' }, - 'amazon-bedrock': { icon: '', displayName: 'AWS Bedrock' }, - azure: { icon: '', displayName: 'Azure OpenAI' }, - ollama: { icon: '', displayName: 'Ollama' }, - lmstudio: { icon: '', displayName: 'LM Studio' }, - opencode: { icon: '', displayName: 'OpenCode' }, -}; - -function getProviderDisplay(provider: OpenCodeProviderInfo) { - const config = PROVIDER_CONFIG[provider.id] || { - displayName: provider.name || provider.id, - }; - return config.displayName; -} - -export function OpenCodeDynamicProviders({ isCliInstalled }: OpenCodeDynamicProvidersProps) { - const [providers, setProviders] = useState([]); - const [isLoadingProviders, setIsLoadingProviders] = useState(false); - const [isRefreshingModels, setIsRefreshingModels] = useState(false); - const { dynamicOpencodeModels, setDynamicOpencodeModels } = useAppStore(); - - // Model count derived from store - const modelCount = dynamicOpencodeModels.length; - - // Fetch models from API and store them (only if not already loaded) - const fetchModels = useCallback( - async (force = false) => { - // Skip if already have models and not forcing refresh - if (!force && dynamicOpencodeModels.length > 0) { - logger.debug('Dynamic models already loaded, skipping fetch'); - return; - } - - try { - const api = getElectronAPI(); - if (api?.setup?.getOpencodeModels) { - const data = await api.setup.getOpencodeModels(); - if (data.success && data.models) { - setDynamicOpencodeModels(data.models); - logger.info(`Loaded ${data.models.length} dynamic OpenCode models`); - } - } - } catch (error) { - logger.error('Failed to fetch OpenCode models:', error); - } - }, - [dynamicOpencodeModels.length, setDynamicOpencodeModels] - ); - - // Fetch providers on mount, but only fetch models if not already loaded - useEffect(() => { - if (isCliInstalled) { - fetchProviders(); - // Only fetch models if store is empty - if (dynamicOpencodeModels.length === 0) { - fetchModels(false); - } - } - }, [isCliInstalled]); // Intentionally not including fetchModels to avoid re-fetching - - const fetchProviders = useCallback(async () => { - setIsLoadingProviders(true); - try { - const api = getElectronAPI(); - if (api?.setup?.getOpencodeProviders) { - const data = await api.setup.getOpencodeProviders(); - if (data.success && data.providers) { - setProviders(data.providers); - } - } else { - logger.warn('OpenCode providers API not available'); - } - } catch (error) { - logger.error('Failed to fetch OpenCode providers:', error); - } finally { - setIsLoadingProviders(false); - } - }, []); - - const handleRefreshModels = useCallback(async () => { - setIsRefreshingModels(true); - try { - const api = getElectronAPI(); - if (api?.setup?.refreshOpencodeModels) { - const data = await api.setup.refreshOpencodeModels(); - if (data.success) { - // Store the refreshed models in the app store - if (data.models) { - setDynamicOpencodeModels(data.models); - toast.success(`Refreshed ${data.models.length} models from OpenCode CLI`); - } - // Also refresh providers - await fetchProviders(); - } else { - toast.error(data.error || 'Failed to refresh models'); - } - } else { - logger.warn('OpenCode refresh models API not available'); - toast.error('OpenCode API not available'); - } - } catch (error) { - logger.error('Failed to refresh OpenCode models:', error); - toast.error('Failed to refresh models from OpenCode CLI'); - } finally { - setIsRefreshingModels(false); - } - }, [fetchProviders, setDynamicOpencodeModels]); - - if (!isCliInstalled) { - return null; - } - - const authenticatedProviders = providers.filter((p) => p.authenticated); - const unauthenticatedProviders = providers.filter((p) => !p.authenticated); - - return ( -
-
-
-
-
- -
-
-

- Dynamic Providers -

- {modelCount !== null && ( -

{modelCount} models available

- )} -
-
- -
-

- OpenCode discovers models from your authenticated providers (GitHub Copilot, Google, etc.) -

-
- -
- {isLoadingProviders ? ( -
- -
- ) : providers.length === 0 ? ( -
- -

No providers detected yet

-

- Run opencode and use{' '} - /connect to authenticate - with providers -

-
- ) : ( -
- {/* Authenticated Providers */} - {authenticatedProviders.length > 0 && ( -
-

- - Authenticated -

-
- {authenticatedProviders.map((provider) => ( -
-
-
- -
- - {getProviderDisplay(provider)} - -
- {provider.authMethod && ( - - {provider.authMethod === 'oauth' ? 'OAuth' : 'API Key'} - - )} -
- ))} -
-
- )} - - {/* Available but Not Authenticated */} - {unauthenticatedProviders.length > 0 && ( -
-

- - Available -

-
- {unauthenticatedProviders.slice(0, 5).map((provider) => ( -
-
-
- -
- - {getProviderDisplay(provider)} - -
- Not authenticated -
- ))} - {unauthenticatedProviders.length > 5 && ( -

- +{unauthenticatedProviders.length - 5} more providers available -

- )} -
-
- )} - - {/* Help text */} -
-

- Use opencode /connect{' '} - to add new providers like GitHub Copilot, Google AI, or local models. -

-
-
- )} -
-
- ); -}