import React from 'react';
const MetricsPanel = ({ agent, tokenUsage, tokenError, flippedCards, setFlippedCards, handleResetMetrics, clearing }) => {
const formatTimeLocal = (utcString) => {
if (!utcString) return 'Never';
const dateStr = utcString.endsWith('Z') || utcString.includes('+') ? utcString : utcString + 'Z';
return new Date(dateStr).toLocaleString(undefined, {
month: 'short', day: 'numeric',
hour: '2-digit', minute: '2-digit', second: '2-digit'
});
};
return (
<div className="p-6 flex flex-col gap-6 font-sans overflow-y-auto max-h-full scrollbar-hide">
<div className="flex justify-between items-center mb-2 border-b border-gray-200 dark:border-gray-800 pb-2">
<h3 className="text-xl font-bold tracking-tight text-gray-800 dark:text-gray-200">Execution Metrics</h3>
<button
onClick={handleResetMetrics}
disabled={clearing}
className="px-3 py-1.5 text-xs font-bold text-red-600 dark:text-red-400 hover:text-red-700 bg-red-50 dark:bg-red-900/20 hover:bg-red-100 dark:hover:bg-red-900/40 rounded border border-red-200 dark:border-red-800 transition-colors"
>
{clearing ? "Resetting..." : "Reset Metrics"}
</button>
</div>
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
{/* Runtime / Health Card */}
<div className="group min-h-[180px] bg-white dark:bg-gray-800 rounded-3xl p-6 shadow-sm border border-gray-200 dark:border-gray-700/50 hover:shadow-xl transition-all duration-300">
<div className="flex justify-between items-start mb-4">
<div className="p-3 bg-emerald-500/10 rounded-2xl">
<svg className="w-5 h-5 text-emerald-500" fill="none" viewBox="0 0 24 24" stroke="currentColor font-bold"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M13 10V3L4 14h7v7l9-11h-7z" /></svg>
</div>
<button
onClick={() => setFlippedCards(p => ({ ...p, runtime: !p.runtime }))}
className="text-[10px] font-black uppercase tracking-widest text-indigo-500"
>
{flippedCards.runtime ? 'Main View' : 'Drilldown'}
</button>
</div>
{!flippedCards.runtime ? (
<>
<h4 className="text-[10px] font-black uppercase tracking-widest text-gray-400 mb-1">Session Status</h4>
<div className="text-3xl font-black text-gray-900 dark:text-white mb-2">{agent?.status || 'idle'}</div>
<div className="flex items-center gap-2 text-xs font-bold text-gray-500">
<span className={`w-2 h-2 rounded-full ${agent?.status === 'active' ? 'bg-emerald-500 animate-pulse' : 'bg-amber-500'}`}></span>
Last seen {new Date(agent?.last_seen_at || Date.now()).toLocaleTimeString()}
</div>
</>
) : (
<div className="space-y-3 pt-2">
<div className="flex justify-between">
<span className="text-[10px] uppercase font-black text-gray-400">Mesh Node</span>
<span className="text-[10px] font-mono text-gray-900 dark:text-white">{agent?.mesh_node_id || 'hub'}</span>
</div>
<div className="flex justify-between">
<span className="text-[10px] uppercase font-black text-gray-400">Last Seen</span>
<span className="text-[10px] font-mono text-gray-900 dark:text-white italic">{new Date(agent?.last_seen_at || Date.now()).toLocaleString()}</span>
</div>
<div className="flex justify-between">
<span className="text-[10px] uppercase font-black text-gray-400">Jail Mount</span>
<span className="text-[10px] font-mono text-gray-900 dark:text-white truncate max-w-[120px]">{agent?.current_workspace_jail || '/tmp'}</span>
</div>
</div>
)}
</div>
{/* Precision / Score Card */}
<div className="min-h-[180px] bg-white dark:bg-gray-800 rounded-3xl p-6 shadow-sm border border-gray-200 dark:border-gray-700/50">
<div className="flex justify-between items-start mb-4">
<div className="p-3 bg-amber-500/10 rounded-2xl">
<svg className="w-5 h-5 text-amber-500" fill="none" viewBox="0 0 24 24" stroke="currentColor font-bold"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9 12l2 2 4-4m5.618-4.016A11.955 11.955 0 0112 2.944a11.955 11.955 0 01-8.618 3.04A12.02 12.02 0 003 9c0 5.591 3.824 10.29 9 11.622 5.176-1.332 9-6.03 9-11.622 0-1.042-.133-2.052-.382-3.016z" /></svg>
</div>
</div>
<h4 className="text-[10px] font-black uppercase tracking-widest text-gray-400 mb-1">Quality Score</h4>
<div className="text-3xl font-black text-gray-900 dark:text-white mb-2">{agent?.latest_quality_score || 0}%</div>
<div className="h-2 w-full bg-gray-100 dark:bg-gray-900 rounded-full overflow-hidden">
<div className={`h-full transition-all duration-1000 ${agent?.latest_quality_score >= 80 ? 'bg-emerald-500 shadow-[0_0_10px_rgba(16,185,129,0.5)]' : 'bg-amber-500'}`} style={{ width: `${agent?.latest_quality_score || 0}%` }}></div>
</div>
<div className="mt-3 text-[10px] text-gray-500 font-bold italic">Verification results for last assistant message</div>
</div>
{/* Resource / Tokens Card */}
<div className="min-h-[180px] bg-white dark:bg-gray-800 rounded-3xl p-6 shadow-sm border border-gray-200 dark:border-gray-700/50 hover:shadow-xl transition-all duration-300">
<div className="flex justify-between items-start mb-4">
<div className="p-3 bg-indigo-500/10 rounded-2xl">
<svg className="w-5 h-5 text-indigo-500" fill="none" viewBox="0 0 24 24" stroke="currentColor font-bold"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 8c-1.657 0-3 .895-3 2s1.343 2 3 2 3 .895 3 2-1.343 2-3 2m0-8c1.11 0 2.08.402 2.599 1M12 8V7m0 1v8m0 0v1m0-1c-1.11 0-2.08-.402-2.599-1M21 12a9 9 0 11-18 0 9 9 0 0118 0z" /></svg>
</div>
<button
onClick={() => setFlippedCards(p => ({ ...p, tokens: !p.tokens }))}
className="text-[10px] font-black uppercase tracking-widest text-indigo-500"
>
{flippedCards.tokens ? 'Main View' : 'Drilldown'}
</button>
</div>
{tokenError ? (
<div className="text-[10px] text-rose-500 font-bold bg-rose-50 dark:bg-rose-500/10 p-3 rounded-xl border border-rose-500/20 italic">Context state unavailable: {tokenError}</div>
) : !flippedCards.tokens ? (
<>
<h4 className="text-[10px] font-black uppercase tracking-widest text-gray-400 mb-1">Context Pressure</h4>
<div className="text-3xl font-black text-gray-900 dark:text-white mb-2">{tokenUsage.percentage || 0}%</div>
<div className="h-2 w-full bg-gray-100 dark:bg-gray-900 rounded-full overflow-hidden">
<div className={`h-full transition-all duration-1000 ${tokenUsage.percentage > 85 ? 'bg-rose-500 animate-pulse' : tokenUsage.percentage > 60 ? 'bg-amber-500' : 'bg-indigo-500 shadow-[0_0_10px_rgba(99,102,241,0.5)]'}`} style={{ width: `${tokenUsage.percentage || 0}%` }}></div>
</div>
<div className="flex justify-between mt-3 text-[10px] font-bold text-gray-500 tabular-nums">
<span>{tokenUsage.token_count || 0} used</span>
<span className="text-gray-400">limit {tokenUsage.token_limit || 0}</span>
</div>
</>
) : (
<div className="space-y-3 pt-2">
<div className="flex justify-between">
<span className="text-[10px] uppercase font-black text-gray-400">Total Consumption</span>
<span className="text-[10px] font-mono text-gray-900 dark:text-white font-bold">{tokenUsage.token_count || 0} tokens</span>
</div>
<div className="flex justify-between">
<span className="text-[10px] uppercase font-black text-gray-400">Context Window</span>
<span className="text-[10px] font-mono text-gray-900 dark:text-white">{tokenUsage.token_limit || 0} tokens</span>
</div>
<div className="flex justify-between">
<span className="text-[10px] uppercase font-black text-gray-400">Provider</span>
<span className="text-[10px] font-mono text-gray-900 dark:text-white italic">{agent?.session?.provider_name || 'default'}</span>
</div>
</div>
)}
</div>
{/* New Metrics Section (Restored from AgentDrillDown) */}
<div className="bg-gray-50 dark:bg-gray-800/50 p-6 rounded-3xl border border-gray-200 dark:border-gray-800">
<span className="uppercase text-[10px] tracking-widest text-gray-500 font-bold block mb-1">Total Task Executions</span>
<span className="text-3xl font-black text-indigo-500">{agent?.total_runs || 0}</span>
<div className="mt-4 flex flex-col">
<span className="uppercase text-[10px] tracking-widest text-gray-500 font-bold block mb-1">Success Rate</span>
<span className="text-2xl font-black text-emerald-500">
{agent?.total_runs ? Math.round(((agent?.successful_runs || 0) / agent.total_runs) * 100) : 0}%
</span>
<span className="text-[10px] text-gray-400 mt-1 font-mono italic">
{agent?.successful_runs || 0} passed / {agent?.total_runs || 0} total
</span>
</div>
</div>
<div className="bg-gray-50 dark:bg-gray-800/50 p-6 rounded-3xl border border-gray-200 dark:border-gray-800">
<span className="uppercase text-[10px] tracking-widest text-gray-500 font-bold block mb-1">Last Completion</span>
<span className="text-sm font-black text-blue-500 mt-2 block leading-relaxed">
{formatTimeLocal(agent?.last_heartbeat)}
</span>
<div className="mt-6 flex flex-col">
<span className="uppercase text-[10px] tracking-widest text-gray-500 font-bold block mb-1">Total Running Time</span>
<span className="text-2xl font-black text-pink-500">
{agent?.total_running_time_seconds ? agent.total_running_time_seconds.toLocaleString() + 's' : '0s'}
</span>
</div>
</div>
<div className="bg-gray-50 dark:bg-gray-800/50 p-6 rounded-3xl border border-gray-200 dark:border-gray-800">
<span className="uppercase text-[10px] tracking-widest text-gray-500 font-bold block mb-1">Cumulative Tokens</span>
<div className="flex flex-col gap-4 mt-2">
<div>
<span className="text-[9px] font-black text-blue-400 uppercase tracking-tight">Prompt (Input)</span>
<div className="text-2xl font-black text-blue-400 tabular-nums">{agent?.total_input_tokens?.toLocaleString() || 0}</div>
</div>
<div>
<span className="text-[9px] font-black text-emerald-500 uppercase tracking-tight">Completion (Output)</span>
<div className="text-2xl font-black text-emerald-500 tabular-nums">{agent?.total_output_tokens?.toLocaleString() || 0}</div>
</div>
</div>
</div>
</div>
<div className="mt-4">
<h4 className="text-sm font-bold tracking-widest text-gray-500 uppercase mb-4 px-1">Tool Usage Intelligence</h4>
<div className="bg-white dark:bg-gray-950 border border-gray-200 dark:border-gray-800 rounded-3xl overflow-hidden shadow-sm">
<table className="w-full text-left">
<thead className="bg-gray-50 dark:bg-gray-900 border-b border-gray-200 dark:border-gray-800 text-[10px] uppercase text-gray-500 tracking-wider">
<tr>
<th className="px-6 py-4 font-black">Tool Surface</th>
<th className="px-6 py-4 font-black text-right">Invocations</th>
<th className="px-6 py-4 font-black text-center">Success</th>
<th className="px-6 py-4 font-black text-center">Failure Rate</th>
</tr>
</thead>
<tbody className="divide-y divide-gray-200 dark:divide-gray-800">
{agent?.tool_call_counts && Object.keys(agent.tool_call_counts).length > 0 ? (
Object.entries(agent.tool_call_counts).sort((a,b) => {
const bVal = typeof b[1] === 'object' ? b[1].calls : b[1];
const aVal = typeof a[1] === 'object' ? a[1].calls : a[1];
return bVal - aVal;
}).map(([tool, data]) => {
const calls = typeof data === 'object' ? data.calls : data;
const successes = typeof data === 'object' ? data.successes : data;
const failures = typeof data === 'object' ? data.failures : 0;
const failRate = calls > 0 ? Math.round((failures / calls) * 100) : 0;
return (
<tr key={tool} className="hover:bg-gray-50 dark:hover:bg-gray-900/50 transition-colors text-sm group">
<td className="px-6 py-4 text-indigo-600 dark:text-indigo-400 font-bold font-mono">{tool}</td>
<td className="px-6 py-4 text-right tabular-nums font-bold text-gray-900 dark:text-white">{calls}</td>
<td className="px-6 py-4 text-center">
<span className="inline-flex items-center px-2 py-0.5 rounded-lg bg-emerald-500/10 text-emerald-500 font-black text-xs">
{successes}
</span>
</td>
<td className={`px-6 py-4 text-center font-bold ${failRate > 20 ? 'text-rose-500' : 'text-gray-400'}`}>
{failRate > 0 ? `${failRate}%` : <span className="text-gray-200 dark:text-gray-800">0%</span>}
</td>
</tr>
);
})
) : (
<tr>
<td colSpan="4" className="px-6 py-10 text-center text-gray-400 italic text-sm">
No autonomous tool transactions recorded in this session environment.
</td>
</tr>
)}
</tbody>
</table>
</div>
</div>
</div>
);
};
export default MetricsPanel;