import React, { useState, useCallback } from 'react'; import { useApi } from '../hooks/useApi'; import { reflect, getAgents, type ReflectAnalysis, type ReflectResultData, } from '../api/client'; type Tab = 'error_patterns' | 'tool_sequences' | 'cost_analysis' | 'performance_trends'; const TABS: { key: Tab; label: string; icon: string }[] = [ { key: 'error_patterns', label: 'Error Patterns', icon: '🔴' }, { key: 'tool_sequences', label: 'Tool Sequences', icon: '🔗' }, { key: 'cost_analysis', label: 'Cost Analysis', icon: '💰' }, { key: 'performance_trends', label: 'Performance', icon: '📈' }, ]; function formatTimestamp(ts?: string): string { if (!ts) return '—'; try { return new Date(ts).toLocaleDateString(); } catch { return ts; } } // ─── Error Patterns ───────────────────────────────────── function ErrorPatternsView({ data }: { data: ReflectResultData }): React.ReactElement { const patterns = data.insights; if (patterns.length === 0) { return
No error patterns found.
; } return ( {patterns.map((insight, idx) => ( ))}
Pattern Count First Seen Last Seen Confidence
{insight.summary} {(insight.data.count as number) ?? '—'} {formatTimestamp(insight.data.firstSeen as string)} {formatTimestamp(insight.data.lastSeen as string)} {(insight.confidence * 100).toFixed(0)}%
); } // ─── Tool Sequences ───────────────────────────────────── function ToolSequencesView({ data }: { data: ReflectResultData }): React.ReactElement { const sequences = data.insights; if (sequences.length === 0) { return
No tool sequences found.
; } return ( {sequences.map((insight, idx) => ( ))}
Sequence Frequency Error Rate Confidence
{insight.summary} {(insight.data.frequency as number) ?? '—'} {insight.data.errorRate != null ? `${((insight.data.errorRate as number) * 100).toFixed(1)}%` : '—'} {(insight.confidence * 100).toFixed(0)}%
); } // ─── Cost Analysis ────────────────────────────────────── function CostAnalysisView({ data }: { data: ReflectResultData }): React.ReactElement { const insights = data.insights; // Find summary insight const summaryInsight = insights.find((i) => i.type === 'cost_summary' || i.type === 'summary'); const modelInsights = insights.filter((i) => i.type === 'cost_by_model' || i.type === 'model_breakdown'); return (
{/* Summary Cards */} {summaryInsight && (
Total Cost
${((summaryInsight.data.totalCost as number) ?? 0).toFixed(2)}
Avg / Session
${((summaryInsight.data.avgPerSession as number) ?? 0).toFixed(4)}
Sessions
{(summaryInsight.data.totalSessions as number) ?? 0}
)} {/* Model Breakdown or All Insights */} {insights.length > 0 && ( {insights.map((insight, idx) => ( ))}
Insight Type Confidence
{insight.summary} {insight.type} {(insight.confidence * 100).toFixed(0)}%
)} {insights.length === 0 && (
No cost analysis data available.
)}
); } // ─── Performance Trends ───────────────────────────────── function PerformanceView({ data }: { data: ReflectResultData }): React.ReactElement { const insights = data.insights; // Server emits these as `performance_current` (metrics) and `performance_assessment`. const summaryInsight = insights.find((i) => i.type === 'performance_current'); const assessmentInsight = insights.find((i) => i.type === 'performance_assessment'); return (
{/* Summary Cards */} {summaryInsight && (
Success Rate
{(((summaryInsight.data.successRate as number) ?? 0) * 100).toFixed(1)}%
Avg Duration
{((summaryInsight.data.avgDuration as number) ?? 0).toFixed(0)}ms
Avg Tool Calls
{((summaryInsight.data.avgToolCalls as number) ?? 0).toFixed(1)}
Assessment
{(assessmentInsight?.data.assessment as string) ?? '—'}
)} {/* All Insights */} {insights.length > 0 ? ( {insights.map((insight, idx) => ( ))}
Insight Type Confidence
{insight.summary} {insight.type} {(insight.confidence * 100).toFixed(0)}%
) : (
No performance data available.
)}
); } // ─── Main Component ───────────────────────────────────── export function Insights(): React.ReactElement { const [tab, setTab] = useState('error_patterns'); const [agentFilter, setAgentFilter] = useState(''); const [from, setFrom] = useState(''); const [to, setTo] = useState(''); const agents = useApi(() => getAgents(), []); const result = useApi( () => reflect({ analysis: tab as ReflectAnalysis, agentId: agentFilter || undefined, from: from || undefined, to: to || undefined, }), [tab, agentFilter, from, to], ); const renderContent = useCallback(() => { if (result.loading) { return
Analyzing...
; } if (result.error) { return
Error: {result.error}
; } if (!result.data) { return
No data
; } switch (tab) { case 'error_patterns': return ; case 'tool_sequences': return ; case 'cost_analysis': return ; case 'performance_trends': return ; } }, [tab, result]); return (

Insights

{/* Filters */}
setFrom(e.target.value)} /> setTo(e.target.value)} />
{/* Tabs */}
{/* Metadata */} {result.data?.metadata && (
Analyzed {result.data.metadata.sessionsAnalyzed} sessions,{' '} {result.data.metadata.eventsAnalyzed} events {result.data.metadata.timeRange && ( <> ({formatTimestamp(result.data.metadata.timeRange.from)} – {formatTimestamp(result.data.metadata.timeRange.to)}) )}
)} {/* Content */}
{renderContent()}
); }