/** * ╔═══════════════════════════════════════════════════════════════════════════╗ * ║ AGENT PROCESS TRACKER ║ * ║═══════════════════════════════════════════════════════════════════════════║ * ║ Real-time visualization of agent task execution ║ * ║ Part of the Liquid UI Arsenal ║ * ╚═══════════════════════════════════════════════════════════════════════════╝ */ import { useState, useEffect } from 'react'; import { Badge } from '@/components/ui/badge'; import { Progress } from '@/components/ui/progress'; import { cn } from '@/lib/utils'; import { Bot, CheckCircle, Clock, AlertTriangle, Loader2, ChevronRight, Terminal, Sparkles, Cpu, Zap } from 'lucide-react'; export interface ProcessStep { id: string; name: string; status: 'pending' | 'running' | 'completed' | 'failed' | 'skipped'; duration_ms?: number; output?: string; error?: string; metadata?: Record; } export interface AgentProcess { id: string; agent: string; task: string; status: 'queued' | 'running' | 'completed' | 'failed'; progress: number; steps: ProcessStep[]; started_at?: string; completed_at?: string; result?: unknown; } export interface AgentProcessTrackerProps { process: AgentProcess; showSteps?: boolean; showOutput?: boolean; compact?: boolean; } const agentColors: Record = { claude: 'text-orange-400 bg-orange-500/20', gemini: 'text-blue-400 bg-blue-500/20', deepseek: 'text-purple-400 bg-purple-500/20', sentinel: 'text-cyan-400 bg-cyan-500/20', muse: 'text-pink-400 bg-pink-500/20', default: 'text-gray-400 bg-gray-500/20', }; const statusIcons = { pending: Clock, running: Loader2, completed: CheckCircle, failed: AlertTriangle, skipped: ChevronRight, queued: Clock, }; const statusColors = { pending: 'text-gray-400', queued: 'text-gray-400', running: 'text-yellow-400', completed: 'text-green-400', failed: 'text-red-400', skipped: 'text-gray-500', }; export function AgentProcessTracker({ process, showSteps = true, showOutput = true, compact = false, }: AgentProcessTrackerProps) { const [currentTime, setCurrentTime] = useState(Date.now()); // Update time for running processes useEffect(() => { if (process.status === 'running') { const interval = setInterval(() => setCurrentTime(Date.now()), 100); return () => clearInterval(interval); } }, [process.status]); const agentColor = agentColors[process.agent.toLowerCase()] || agentColors.default; const StatusIcon = statusIcons[process.status]; // Calculate elapsed time const getElapsed = () => { if (!process.started_at) return null; const start = new Date(process.started_at).getTime(); const end = process.completed_at ? new Date(process.completed_at).getTime() : currentTime; const ms = end - start; if (ms < 1000) return `${ms}ms`; if (ms < 60000) return `${(ms / 1000).toFixed(1)}s`; return `${(ms / 60000).toFixed(1)}m`; }; // Get current step const currentStep = process.steps.find(s => s.status === 'running'); const completedSteps = process.steps.filter(s => s.status === 'completed').length; if (compact) { return (
{process.task}
{getElapsed()}
); } return (
{/* Header */}
{process.agent} {process.id.slice(0, 8)}

{process.task}

{process.status.toUpperCase()}
{getElapsed() && ( {getElapsed()} )}
{/* Progress bar */}
Progress {process.progress}% ({completedSteps}/{process.steps.length} steps)
{/* Current step indicator */} {currentStep && (
{currentStep.name} {currentStep.duration_ms !== undefined && ( {currentStep.duration_ms}ms )}
)} {/* Steps list */} {showSteps && process.steps.length > 0 && (
Execution Steps
{process.steps.map((step, index) => { const StepIcon = statusIcons[step.status]; return (
{index + 1}. {step.name} {step.duration_ms !== undefined && step.status === 'completed' && ( {step.duration_ms}ms )}
); })}
)} {/* Output/Result */} {showOutput && (process.result || process.steps.some(s => s.output || s.error)) && (
Output
{process.result && (
                {typeof process.result === 'string' ? process.result : JSON.stringify(process.result, null, 2)}
              
)} {process.steps.filter(s => s.error).map(step => (
[{step.name}] ERROR: {step.error}
))}
)} {/* Footer */}
Started: {process.started_at || 'Queued'} {process.status === 'completed' && (
Task Complete
)}
); } export default AgentProcessTracker;