import { History, Send, Settings, Square } from 'lucide-react' import { useCallback, useEffect, useRef, useState } from 'react' import { Button } from '@/components/ui/button' import { InputGroup, InputGroupAddon, InputGroupButton, InputGroupTextarea, } from '@/components/ui/input-group' import { saveSession } from '@/lib/db' import { useAgent } from '../../agent/useAgent' import { ConfigPanel } from './components/ConfigPanel' import { HistoryDetail } from './components/HistoryDetail' import { HistoryList } from './components/HistoryList' import { ActivityCard, EventCard } from './components/cards' import { EmptyState, Logo, MotionOverlay, StatusDot } from './components/misc' type View = | { name: 'chat' } | { name: 'config' } | { name: 'history' } | { name: 'history-detail'; sessionId: string } export default function App() { const [view, setView] = useState({ name: 'chat' }) const [inputValue, setInputValue] = useState('') const historyRef = useRef(null) const textareaRef = useRef(null) const { status, history, activity, currentTask, config, execute, stop, configure } = useAgent() // Persist session when task finishes const prevStatusRef = useRef(status) useEffect(() => { const prev = prevStatusRef.current prevStatusRef.current = status if ( prev === 'running' && (status === 'completed' || status === 'error') && history.length > 0 && currentTask ) { saveSession({ task: currentTask, history, status }).catch((err) => console.error('[SidePanel] Failed to save session:', err) ) } }, [status, history, currentTask]) // Auto-scroll to bottom on new events useEffect(() => { if (historyRef.current) { historyRef.current.scrollTop = historyRef.current.scrollHeight } }, [history, activity]) const handleSubmit = useCallback( (e?: React.SyntheticEvent) => { e?.preventDefault() if (!inputValue.trim() || status === 'running') return const taskToExecute = inputValue.trim() setInputValue('') execute(taskToExecute).catch((error) => { console.error('[SidePanel] Failed to execute task:', error) }) }, [inputValue, status, execute] ) const handleStop = useCallback(() => { console.log('[SidePanel] Stopping task...') stop() }, [stop]) const handleKeyDown = (e: React.KeyboardEvent) => { if (e.key === 'Enter' && !e.shiftKey && !e.nativeEvent.isComposing) { e.preventDefault() handleSubmit() } } // --- View routing --- if (view.name === 'config') { return ( { await configure(newConfig) setView({ name: 'chat' }) }} onClose={() => setView({ name: 'chat' })} /> ) } if (view.name === 'history') { return ( setView({ name: 'history-detail', sessionId: id })} onBack={() => setView({ name: 'chat' })} /> ) } if (view.name === 'history-detail') { return setView({ name: 'history' })} /> } // --- Chat view --- const isRunning = status === 'running' const showEmptyState = !currentTask && history.length === 0 && !isRunning return (
{/* Header */}
Page Agent Ext
{/* Content */}
{/* Current task */} {currentTask && (
Task
{currentTask}
)} {/* History */}
{showEmptyState && } {history.map((event, index) => ( // eslint-disable-next-line react-x/no-array-index-key ))} {/* Activity indicator at bottom */} {activity && }
{/* Input */}
) }