import { AGENT_STEPS, AGENT_STEP_LABELS, STEP_PHASE } from '@/lib/types/run' import type { AgentStep } from '@/lib/types/run' import type { StepStatus } from '@/lib/types/agents' function formatTokens(n: number): string { return n >= 1000 ? `${(n / 1000).toFixed(1)}k` : String(n) } type Phase = 'analysts' | 'researchers' | 'trader' | 'risk' const MULTI_TURN_STEPS = new Set([ 'bull_researcher', 'bear_researcher', 'aggressive_analyst', 'conservative_analyst', 'neutral_analyst', ]) const STEP_ACCENT: Record = { market_analyst: '#00C4E8', news_analyst: '#A78BFA', fundamentals_analyst: '#00E078', social_analyst: '#FFB400', bull_researcher: '#00E078', bear_researcher: '#FF1F4C', research_manager: '#00C4E8', trader: '#FFB400', aggressive_analyst: '#FF1F4C', conservative_analyst: '#00C4E8', neutral_analyst: '#A78BFA', risk_judge: '#FFB400', chief_analyst: '#adc6ff', } const STEP_ROLE_DESC: Partial> = { market_analyst: 'Technical & price action', news_analyst: 'Sentiment & headlines', fundamentals_analyst: 'Earnings & financials', social_analyst: 'Social signals', bull_researcher: 'Bullish thesis', bear_researcher: 'Bearish thesis', research_manager: 'Research synthesis', trader: 'Trade plan', aggressive_analyst: 'High-risk perspective', conservative_analyst: 'Risk-averse perspective', neutral_analyst: 'Balanced view', risk_judge: 'Final risk decision', } type Props = { phase: Phase steps: Record reports: Record tokensByStep: Record } export default function AnalystReports({ phase, steps, reports, tokensByStep }: Props) { const phaseSteps = AGENT_STEPS.filter((s) => STEP_PHASE[s] === phase) return (
{phaseSteps.map((step, stepIdx) => { const stepStatus = steps[step] ?? 'pending' const turns = reports[step] ?? [] const isRunning = stepStatus === 'running' const isDone = stepStatus === 'done' const isMulti = MULTI_TURN_STEPS.has(step) const accent = STEP_ACCENT[step] const roleDesc = STEP_ROLE_DESC[step] return (
{/* Completed turns */} {turns.map((report, i) => (
{/* Colored header bar */}
{AGENT_STEP_LABELS[step]} {roleDesc && ( · {roleDesc} )} {isMulti && ( T{i + 1} )} {(() => { const tok = tokensByStep[step] return tok && (tok.in > 0 || tok.out > 0) ? ( {formatTokens(tok.in)}↑{' '} {formatTokens(tok.out)}↓ ) : null })()}
DONE
{/* Report body */}

{report}

))} {/* Running state */} {isRunning && (
{AGENT_STEP_LABELS[step]} {isMulti && turns.length > 0 && ( T{turns.length + 1} )}
ANALYZING
{[85, 62, 44, 30].map((w, i) => (
))}
)} {/* Pending state */} {turns.length === 0 && !isRunning && (
{AGENT_STEP_LABELS[step]}
QUEUED
)}
) })}
) }