import { useState, useRef, useCallback } from 'react'; import { useTranslation } from 'react-i18next'; import { PaperAirplaneIcon, StopCircleIcon, CurrencyDollarIcon } from '@heroicons/react/24/outline'; interface AgentStep { step_number: number; thought: string; action: string | null; action_input: Record | null; observation: string | null; cost_usd: number; } interface AgentChatProps { agentId: string; agentName: string; } export function AgentChat({ agentId, agentName }: AgentChatProps) { const { t } = useTranslation(); const [messages, setMessages] = useState([]); const [input, setInput] = useState(''); const [steps, setSteps] = useState([]); const [isRunning, setIsRunning] = useState(false); const [totalCost, setTotalCost] = useState(0); const [extendedTrace, setExtendedTrace] = useState(false); const [dryRun, setDryRun] = useState(false); const eventSourceRef = useRef(null); const handleSend = useCallback(() => { if (!input.trim() || isRunning) return; const userMsg = input.trim(); setMessages((prev) => [...prev, `User: ${userMsg}`]); setInput(''); setIsRunning(true); setSteps([]); setTotalCost(0); const url = `/api/v1/agents/${agentId}/stream?message=${encodeURIComponent(userMsg)}&trace_mode=${extendedTrace ? 'extended' : 'standard'}&dry_run=${dryRun}`; const eventSource = new EventSource(url); eventSourceRef.current = eventSource; eventSource.addEventListener('step', (e) => { const step = JSON.parse(e.data) as AgentStep; setSteps((prev) => [...prev, step]); setTotalCost((prev) => prev + (step.cost_usd || 0)); }); eventSource.addEventListener('status', (e) => { const data = JSON.parse(e.data); if (data.status === 'running') { setMessages((prev) => [...prev, `Step ${data.step}: ${data.action || 'Thinking...'}`]); } }); eventSource.addEventListener('done', (e) => { const data = JSON.parse(e.data); setMessages((prev) => [...prev, `Agent: ${data.final_content}`]); setIsRunning(false); eventSource.close(); }); eventSource.addEventListener('error', (e) => { try { const data = JSON.parse(e.data); setMessages((prev) => [...prev, `Error: ${data.error}`]); } catch { setMessages((prev) => [...prev, 'Error: Connection lost']); } setIsRunning(false); eventSource.close(); }); }, [input, isRunning, agentId, extendedTrace, dryRun]); const handleStop = useCallback(() => { eventSourceRef.current?.close(); setIsRunning(false); setMessages((prev) => [...prev, 'Agent run stopped by user']); }, []); return (

{agentName}

{totalCost > 0 && ( {totalCost.toFixed(6)} )}
{messages.map((msg, i) => (

{msg}

))} {extendedTrace && steps.map((step) => (
Step {step.step_number} ${step.cost_usd.toFixed(6)}
{step.thought &&

Thought: {step.thought}

} {step.action &&

Action: {step.action}

} {step.observation &&

Observation: {step.observation}

}
))}
setInput(e.target.value)} onKeyDown={(e) => e.key === 'Enter' && handleSend()} placeholder={t('agents.typeMessage')} disabled={isRunning} className="flex-1 px-4 py-2 rounded-lg border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-800 text-gray-900 dark:text-white focus:ring-2 focus:ring-primary-500" aria-label={t('agents.messageInput')} /> {isRunning ? ( ) : ( )}
); }