import StepTimeline from './StepTimeline'
import ScoreCard from './ScoreCard'
import { generateReasoning, getRegionalComparison } from '../utils'
const DECISION_STYLE = {
remove: { color: '#f87171', glow: 'glow-red', border: 'rgba(248,113,113,0.25)', bg: 'rgba(248,113,113,0.05)' },
allow: { color: '#4ade80', glow: 'glow-green', border: 'rgba(74,222,128,0.25)', bg: 'rgba(74,222,128,0.05)' },
flag: { color: '#fb923c', glow: 'glow-orange', border: 'rgba(251,146,60,0.25)', bg: 'rgba(251,146,60,0.05)' },
escalate: { color: '#c084fc', glow: 'glow-purple', border: 'rgba(192,132,252,0.25)', bg: 'rgba(192,132,252,0.05)' },
}
const SEVERITY_COLOR = {
critical: '#f87171', high: '#fb923c', medium: '#fbbf24', low: '#60a5fa',
}
const VIOLATION_COLOR = {
harassment: '#f87171', misinformation: '#fb923c', restricted: '#fbbf24', safe: '#4ade80',
}
const REGION_LABELS = { US: '🇺🇸 US', EU: '🇪🇺 EU', IN: '🇮🇳 IN', UK: '🇬🇧 UK' }
const REGION_ORDER = ['US', 'EU', 'IN', 'UK']
function SectionLabel({ children }) {
return (
)
}
function Chip({ label, color }) {
return (
{label}
)
}
function ActionPill({ action }) {
const ds = DECISION_STYLE[action] || { color: '#5a5f7a', border: 'rgba(90,95,122,0.3)', bg: 'transparent' }
return (
{action}
)
}
function LoadingSkeleton({ llmProvider }) {
const modelName = llmProvider === 'gemini' ? 'Gemini 2.5 Flash' : (llmProvider === 'openai' ? 'OpenAI GPT-4o mini' : 'Agent')
return (
{[1, 0.85, 0.7, 0.55, 0.4].map((op, i) => (
))}
â—Ž {modelName} reasoning...
)
}
export default function AgentPanel({ result, observation, loading, error, animKey, llmProvider }) {
const breakdown = result?.score?.breakdown
if (loading) return (
)
if (error) return (
)
if (!result) return (
◌
Select a scenario and run the AI agent to see its reasoning and decision
)
const action = breakdown?.agent_action
const expected = breakdown?.expected_action
const isCorrect = action === expected
const ds = DECISION_STYLE[action] || { color: '#5a5f7a', glow: '', border: 'rgba(90,95,122,0.2)', bg: 'transparent' }
const sevColor = SEVERITY_COLOR[breakdown?.final_severity] || '#5a5f7a'
const vioColor = VIOLATION_COLOR[breakdown?.violation_type] || '#5a5f7a'
const reasoning = generateReasoning(breakdown, result.trajectory)
const regional = getRegionalComparison(breakdown?.violation_type, breakdown?.final_severity)
const currentGeo = observation?.geo || null
return (
{/* Header */}
{result.trajectory?.length} step{result.trajectory?.length !== 1 ? 's' : ''}
{/* ── 1. DECISION CARD ──────────────────────────── */}
{/* Giant decision word */}
Final Decision
{action?.toUpperCase() ?? 'NO DECISION'}
{/* Expected vs actual */}
Agent:
{isCorrect ? '✓' : '✗'}
{!isCorrect && (
)}
{/* Chips */}
{breakdown?.violation_type && }
{breakdown?.final_severity && }
{/* Reasoning explanation */}
{/* ── 2. REGION COMPARISON ─────────────────────── */}
Policy Comparison by Region
{REGION_ORDER.map(geo => {
const decision = regional[geo] || 'allow'
const dStyle = DECISION_STYLE[decision] || { color: '#5a5f7a', border: 'rgba(90,95,122,0.2)', bg: 'transparent' }
const isCurrent = geo === currentGeo
return (
{REGION_LABELS[geo]}
{decision}
{isCurrent && (
current
)}
)
})}
{/* ── 3. TRAJECTORY ────────────────────────────── */}
Agent Trajectory
{/* ── 4. SCORE BREAKDOWN ───────────────────────── */}
Performance Breakdown
)
}