import { useModelProvider } from '@/hooks/useModelProvider' import { useAppUpdater } from '@/hooks/useAppUpdater' import { useServiceHub } from '@/hooks/useServiceHub' import { useEffect } from 'react' import { useMCPServers } from '@/hooks/useMCPServers' import { useAssistant } from '@/hooks/useAssistant' import { useNavigate } from '@tanstack/react-router' import { route } from '@/constants/routes' import { useThreads } from '@/hooks/useThreads' import { useLocalApiServer } from '@/hooks/useLocalApiServer' import { useAppState } from '@/hooks/useAppState' import { AppEvent, events } from '@janhq/core' import { SystemEvent } from '@/types/events' import { getModelToStart } from '@/utils/getModelToStart' export function DataProvider() { const { setProviders, selectedModel, selectedProvider, getProviderByName } = useModelProvider() const { checkForUpdate } = useAppUpdater() const { setServers } = useMCPServers() const { setAssistants, initializeWithLastUsed } = useAssistant() const { setThreads } = useThreads() const navigate = useNavigate() const serviceHub = useServiceHub() // Local API Server hooks const { enableOnStartup, serverHost, serverPort, apiPrefix, apiKey, trustedHosts, corsEnabled, verboseLogs, proxyTimeout, } = useLocalApiServer() const setServerStatus = useAppState((state) => state.setServerStatus) useEffect(() => { console.log('Initializing DataProvider...') serviceHub.providers().getProviders().then(setProviders) serviceHub .mcp() .getMCPConfig() .then((data) => setServers(data.mcpServers ?? {})) serviceHub .assistants() .getAssistants() .then((data) => { // Only update assistants if we have valid data if (data && Array.isArray(data) && data.length > 0) { setAssistants(data as unknown as Assistant[]) initializeWithLastUsed() } }) .catch((error) => { console.warn('Failed to load assistants, keeping default:', error) }) serviceHub.deeplink().getCurrent().then(handleDeepLink) serviceHub.deeplink().onOpenUrl(handleDeepLink) // Listen for deep link events let unsubscribe = () => {} serviceHub .events() .listen(SystemEvent.DEEP_LINK, (event) => { const deep_link = event.payload as string handleDeepLink([deep_link]) }) .then((unsub) => { unsubscribe = unsub }) return () => { unsubscribe() } // eslint-disable-next-line react-hooks/exhaustive-deps }, [serviceHub]) useEffect(() => { serviceHub .threads() .fetchThreads() .then((threads) => { setThreads(threads) }) }, [serviceHub, setThreads]) // Check for app updates useEffect(() => { // Only check for updates if the auto updater is not disabled // App might be distributed via other package managers // or methods that handle updates differently if (!AUTO_UPDATER_DISABLED) { checkForUpdate() } }, [checkForUpdate]) useEffect(() => { events.on(AppEvent.onModelImported, () => { serviceHub.providers().getProviders().then(setProviders) }) }, [serviceHub, setProviders]) // Auto-start Local API Server on app startup if enabled useEffect(() => { if (enableOnStartup) { // Validate API key before starting if (!apiKey || apiKey.toString().trim().length === 0) { console.warn('Cannot start Local API Server: API key is required') return } const modelToStart = getModelToStart({ selectedModel, selectedProvider, getProviderByName, }) // Only start server if we have a model to load if (!modelToStart) { console.warn( 'Cannot start Local API Server: No model available to load' ) return } setServerStatus('pending') // Start the model first serviceHub .models() .startModel(modelToStart.provider, modelToStart.model) .then(() => { console.log(`Model ${modelToStart.model} started successfully`) // Then start the server return window.core?.api?.startServer({ host: serverHost, port: serverPort, prefix: apiPrefix, apiKey, trustedHosts, isCorsEnabled: corsEnabled, isVerboseEnabled: verboseLogs, proxyTimeout: proxyTimeout, }) }) .then(() => { setServerStatus('running') }) .catch((error: unknown) => { console.error('Failed to start Local API Server on startup:', error) setServerStatus('stopped') }) } // eslint-disable-next-line react-hooks/exhaustive-deps }, [serviceHub]) const handleDeepLink = (urls: string[] | null) => { if (!urls) return console.log('Received deeplink:', urls) const deeplink = urls[0] if (deeplink) { const url = new URL(deeplink) const params = url.pathname.split('/').filter((str) => str.length > 0) if (params.length < 3) return undefined // const action = params[0] // const provider = params[1] const resource = params.slice(1).join('/') // return { action, provider, resource } navigate({ to: route.hub.model, search: { repo: resource, }, }) } } return null }