import React, { useState, useRef, useEffect } from 'react'; import { Search, Bot, Loader2, FileText, ExternalLink, Sparkles, RefreshCw, BookOpen, ChevronRight, ArrowRight, Globe, Database, Brain, CheckCircle, AlertCircle } from 'lucide-react'; import { Button } from '@/components/ui/button'; import { Input } from '@/components/ui/input'; import { ScrollArea } from '@/components/ui/scroll-area'; import { Badge } from '@/components/ui/badge'; import { cn } from '@/lib/utils'; import { API_URL } from '@/config/api'; import ReactMarkdown from 'react-markdown'; interface ResearchStep { id: string; description: string; status: 'pending' | 'active' | 'completed' | 'failed'; timestamp: Date; details?: string; } export default function ResearchAgentWidget() { const [query, setQuery] = useState(''); const [isResearching, setIsResearching] = useState(false); const [steps, setSteps] = useState([]); const [streamedContent, setStreamedContent] = useState(''); const scrollRef = useRef(null); // Auto-scroll output useEffect(() => { if (scrollRef.current) { // scrollRef.current.scrollTop = scrollRef.current.scrollHeight; } }, [streamedContent]); const addStep = (desc: string, status: ResearchStep['status'] = 'active', details?: string) => { setSteps(prev => { // Mark previous active step as completed if exists const newSteps = prev.map(s => s.status === 'active' ? { ...s, status: 'completed' } : s ); return [...newSteps, { id: Date.now().toString() + Math.random(), description: desc, status, timestamp: new Date(), details } as ResearchStep]; }); }; const completeLastStep = () => { setSteps(prev => prev.map(s => s.status === 'active' ? { ...s, status: 'completed' } : s )); }; const failLastStep = () => { setSteps(prev => prev.map(s => s.status === 'active' ? { ...s, status: 'failed' } : s )); }; const startResearch = async () => { if (!query.trim()) return; setIsResearching(true); setSteps([]); setStreamedContent(''); try { addStep('Initializing research agent...', 'completed'); addStep(`Analyzing topic: "${query}"`); // Use the autonomous hybrid search endpoint // We frame it as a 'research' request which the backend should handle intelligently // or we use the generic query endpoint and let the agent decide const response = await fetch(`${API_URL}/api/mcp/autonomous/query`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ type: 'research', // Hint to the router params: { query: query, // Common param topic: query, // Specific param depth: 'deep', includeSources: true } }) }); if (!response.ok) throw new Error(`API Error: ${response.status}`); // Simulate progression if not streaming (since our current API is request/response) // In a real websocket setup, these would be events setTimeout(() => { if (isResearching) addStep('Querying internal knowledge base...', 'active', 'Vector Search + Graph Traversal'); }, 1000); setTimeout(() => { if (isResearching) addStep('Synthesizing intelligence...', 'active', 'GPU-accelerated context fusion'); }, 2500); const data = await response.json(); if (data.success && data.data) { completeLastStep(); addStep('Research completed', 'completed'); // Format output let content = ''; if (typeof data.data === 'string') { content = data.data; } else { // Try to format object nicely if (data.data.answer) content += `### Answer\n${data.data.answer}\n\n`; if (data.data.summary) content += `### Summary\n${data.data.summary}\n\n`; if (data.data.results && Array.isArray(data.data.results)) { content += `### Key Findings\n`; data.data.results.forEach((r: any) => { content += `- **${r.score?.toFixed(2) || '?'}**: ${r.content?.substring(0, 150)}...\n`; }); } if (!content) content = JSON.stringify(data.data, null, 2); } setStreamedContent(content); } else { throw new Error(data.error || 'No data returned'); } } catch (error: any) { console.error('Research failed:', error); failLastStep(); addStep('Error: ' + error.message, 'failed'); setStreamedContent(`### Research Failed\n\n${error.message}\n\nPlease ensure the backend is running and the GPU bridge is active.`); } finally { setIsResearching(false); } }; return (
{/* Header */}

Deep Research Agent

{isResearching ? "PROCESSING" : "IDLE"} • GPU ENABLED
{/* Main Content */}
{/* Left Panel: Input & Process */}
setQuery(e.target.value)} onKeyDown={e => e.key === 'Enter' && startResearch()} placeholder="E.g. Advanced Persistent Threats in 2025..." disabled={isResearching} className="bg-background/50 border-border/50 focus:ring-purple-500/50" />
{/* Agent Thought Process */}
AGENT PROCESS
{steps.map((step, i) => (
{step.status === 'completed' ? : step.status === 'failed' ? : i + 1}
{i < steps.length - 1 &&
}

{step.description}

{step.details && (

{step.details}

)} {step.timestamp.toLocaleTimeString()}
))} {steps.length === 0 && (
Waiting for mission...
)}
{/* Right Panel: Results */}
INTELLIGENCE REPORT {streamedContent && ( GENERATED )}
{streamedContent ? (
{streamedContent}
) : (

No intelligence generated yet

Enter a topic to begin deep research

)}
); }