import { useCallback, useEffect, useMemo, useState } from "react"; import { Alert, Text, View } from "react-native"; import { useTranslation } from "react-i18next"; import { StyleSheet } from "react-native-unistyles"; import type { AgentProvider } from "@getpaseo/protocol/agent-types"; import { CombinedModelSelector } from "@/components/combined-model-selector"; import { ExternalLink } from "@/components/ui/external-link"; import { LoadingSpinner } from "@/components/ui/loading-spinner"; import { SegmentedControl } from "@/components/ui/segmented-control"; import { useDaemonConfig } from "@/hooks/use-daemon-config"; import { useProvidersSnapshot } from "@/hooks/use-providers-snapshot"; import { buildSelectableProviderSelectorProviders } from "@/provider-selection/provider-selection"; import { SettingsSection } from "@/screens/settings/settings-section"; import { settingsStyles } from "@/styles/settings"; const METADATA_GENERATION_DOCS_URL = "https://paseo.sh/docs/metadata-generation"; type SelectionMode = "automatic" | "preferred"; export function MetadataGenerationPage({ serverId }: { serverId: string }) { const { t } = useTranslation(); const { config, isLoading: isConfigLoading, patchConfig } = useDaemonConfig(serverId); const snapshot = useProvidersSnapshot(serverId); const providers = useMemo( () => buildSelectableProviderSelectorProviders(snapshot.entries), [snapshot.entries], ); const configuredProviders = config?.metadataGeneration.providers; const configuredProvider = configuredProviders?.[0] ?? null; const savedMode: SelectionMode = configuredProvider ? "preferred" : "automatic"; const [draftMode, setDraftMode] = useState(null); const [isSaving, setIsSaving] = useState(false); const mode = draftMode ?? savedMode; useEffect(() => { setDraftMode(null); }, [configuredProvider?.model, configuredProvider?.provider]); const modeOptions = useMemo( () => [ { value: "automatic" as const, label: t("settings.metadataGeneration.automatic") }, { value: "preferred" as const, label: t("settings.metadataGeneration.preferred") }, ], [t], ); const saveProviders = useCallback( async (providersPatch: { provider: string; model?: string }[]) => { setIsSaving(true); try { await patchConfig({ metadataGeneration: { providers: providersPatch } }); } catch (error) { setDraftMode(null); Alert.alert( t("settings.metadataGeneration.saveError"), error instanceof Error ? error.message : String(error), ); } finally { setIsSaving(false); } }, [patchConfig, t], ); const handleModeChange = useCallback( (next: SelectionMode) => { setDraftMode(next); if (next === "automatic") { void saveProviders([]); } }, [saveProviders], ); const handleModelSelect = useCallback( (provider: AgentProvider, model: string) => { setDraftMode("preferred"); void saveProviders([ { provider, ...(model ? { model } : {}) }, ...(configuredProviders?.slice(1) ?? []), ]); }, [configuredProviders, saveProviders], ); const handleSelectorOpen = useCallback(() => { snapshot.refetchIfStale(configuredProvider?.provider); }, [configuredProvider?.provider, snapshot]); const handleRetryProvider = useCallback( (provider: AgentProvider) => snapshot.refresh([provider]), [snapshot], ); const docsLink = useMemo( () => ( ), [t], ); if (isConfigLoading || !config) { return ( ); } return ( {t("settings.metadataGeneration.description")} {t("settings.metadataGeneration.selection")} {mode === "automatic" ? t("settings.metadataGeneration.automaticHint") : t("settings.metadataGeneration.preferredHint")} {mode === "preferred" ? ( {t("settings.metadataGeneration.model")} {t("settings.metadataGeneration.fallbackHint")} ) : null} ); } const styles = StyleSheet.create((theme) => ({ description: { color: theme.colors.foregroundMuted, fontSize: theme.fontSize.sm, lineHeight: theme.fontSize.sm * 1.45, marginHorizontal: theme.spacing[1], }, loading: { alignItems: "center", justifyContent: "center", minHeight: 180, }, spinnerColor: { color: theme.colors.foregroundMuted, }, }));