Newer
Older
cortex-hub / frontend / src / features / agents / components / drilldown / MetricsPanel.js
import React from 'react';

const MetricsPanel = ({ agent, tokenUsage, tokenError, flippedCards, setFlippedCards, handleResetMetrics, clearing }) => {
    return (
        <div className="p-6 flex flex-col gap-6 font-sans">
             <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 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="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="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>
            </div>
        </div>
    );
};

export default MetricsPanel;