import { useState, useCallback, useEffect, useRef } from 'react'; import { Box, Typography, Button, CircularProgress, Alert, } from '@mui/material'; import OpenInNewIcon from '@mui/icons-material/OpenInNew'; import GroupAddIcon from '@mui/icons-material/GroupAdd'; import { useSessionStore } from '@/store/sessionStore'; import { useAgentStore } from '@/store/agentStore'; import { apiFetch } from '@/utils/api'; import { isInIframe, triggerLogin } from '@/hooks/useAuth'; /** HF brand orange */ const HF_ORANGE = '#FF9D00'; const ORG_JOIN_URL = 'https://huggingface.co/organizations/ml-agent-explorers/share/GzPMJUivoFPlfkvFtIqEouZKSytatKQSZT'; const ORG_JOINED_KEY = 'hf-agent-org-joined'; function hasJoinedOrg(): boolean { try { return localStorage.getItem(ORG_JOINED_KEY) === '1'; } catch { return false; } } function markOrgJoined(): void { try { localStorage.setItem(ORG_JOINED_KEY, '1'); } catch { /* ignore */ } } export default function WelcomeScreen() { const { createSession } = useSessionStore(); const { setPlan, clearPanel, user } = useAgentStore(); const [isCreating, setIsCreating] = useState(false); const [error, setError] = useState(null); const [orgJoined, setOrgJoined] = useState(hasJoinedOrg); const joinLinkOpened = useRef(false); const inIframe = isInIframe(); const isAuthenticated = user?.authenticated; const isDevUser = user?.username === 'dev'; // Auto-advance when user returns from the join link useEffect(() => { const handleVisibility = () => { if (document.visibilityState !== 'visible' || !joinLinkOpened.current) return; joinLinkOpened.current = false; markOrgJoined(); setOrgJoined(true); }; document.addEventListener('visibilitychange', handleVisibility); return () => document.removeEventListener('visibilitychange', handleVisibility); }, []); const tryCreateSession = useCallback(async () => { setIsCreating(true); setError(null); try { const response = await apiFetch('/api/session', { method: 'POST' }); if (response.status === 503) { const data = await response.json(); setError(data.detail || 'Server is at capacity. Please try again later.'); return; } if (response.status === 401) { triggerLogin(); return; } if (!response.ok) { setError('Failed to create session. Please try again.'); return; } const data = await response.json(); createSession(data.session_id); setPlan([]); clearPanel(); } catch { // Redirect may throw — ignore } finally { setIsCreating(false); } }, [createSession, setPlan, clearPanel]); const handleStart = useCallback(async () => { if (isCreating) return; if (!isAuthenticated && !isDevUser) { if (inIframe) return; triggerLogin(); return; } await tryCreateSession(); }, [isCreating, isAuthenticated, isDevUser, inIframe, tryCreateSession]); // Build the direct Space URL for the "open in new tab" link const spaceHost = typeof window !== 'undefined' ? window.location.hostname.includes('.hf.space') ? window.location.origin : `https://smolagents-ml-agent.hf.space` : ''; // Shared button style const primaryBtnSx = { px: 5, py: 1.5, fontSize: '1rem', fontWeight: 700, textTransform: 'none' as const, borderRadius: '12px', bgcolor: HF_ORANGE, color: '#000', boxShadow: '0 4px 24px rgba(255, 157, 0, 0.3)', textDecoration: 'none', '&:hover': { bgcolor: '#FFB340', boxShadow: '0 6px 32px rgba(255, 157, 0, 0.45)', }, }; // Description block (reused across screens) const description = ( A general-purpose AI agent for machine learning engineering. It browses Hugging Face documentation, manages{' '} repositories, launches training jobs, and explores datasets — all through natural conversation. ); // Which screen to show const needsJoin = inIframe && !orgJoined; const showOpenAgent = inIframe && orgJoined; const showSignin = !inIframe && !isAuthenticated && !isDevUser; const showReady = !inIframe && (isAuthenticated || isDevUser); return ( {/* HF Logo */} {/* Title */} HF Agent {/* ── Iframe: join org (first visit only) ──────────────────── */} {needsJoin && ( <> Under the hood, this agent uses GPUs, inference APIs, and other paid Hub goodies — but we made them all free for you. Just join ML Agent Explorers to get started! )} {/* ── Iframe: already joined → open Space ──────────────────── */} {showOpenAgent && ( <> {description} )} {/* ── Direct: not logged in → sign in ──────────────────────── */} {showSignin && ( <> {description} Make sure to enable access to the ml-agent-explorers org when prompted. )} {/* ── Direct: authenticated → start session ────────────────── */} {showReady && ( <> {description} )} {/* Error */} {error && ( setError(null)} sx={{ mt: 3, maxWidth: 400, fontSize: '0.8rem', borderColor: HF_ORANGE, color: 'var(--text)', }} > {error} )} {/* Footnote */} Conversations are stored locally in your browser. ); }