Newer
Older
cortex-hub / frontend / src / features / agents / components / AgentDrillDown.js
import React, { useState, useEffect } from 'react';
import ChatWindow from '../../chat/components/ChatWindow';
import FileSystemNavigator from '../../../shared/components/FileSystemNavigator';
import { getAgents, getSessionMessages, fetchWithAuth, updateAgentConfig, getUserConfig, clearSessionHistory, getSessionTokenStatus, getAgentTriggers, createAgentTrigger, deleteAgentTrigger, getUserAccessibleNodes, getSkills, resetAgentMetrics } from '../../../services/apiService';

export default function AgentDrillDown({ agentId, onNavigate }) {
    const [agent, setAgent] = useState(null);
    const [chatHistory, setChatHistory] = useState([]);
    const [loading, setLoading] = useState(true);
    const [error, setError] = useState(null);
    const [overrideText, setOverrideText] = useState("");
    
    // Day 2 Configurations
    const [activeTab, setActiveTab] = useState('config'); // workspace or config
    const [editConfig, setEditConfig] = useState(null);
    const [saving, setSaving] = useState(false);
    const [userConfig, setUserConfig] = useState(null);
    const [tokenUsage, setTokenUsage] = useState({ token_count: 0, token_limit: 0, percentage: 0 });
    const [clearing, setClearing] = useState(false);
    const [triggers, setTriggers] = useState([]);
    const [newTriggerType, setNewTriggerType] = useState('cron');
    const [newCronValue, setNewCronValue] = useState('0 * * * *');
    const [newIntervalValue, setNewIntervalValue] = useState(600);
    const [newDefaultPrompt, setNewDefaultPrompt] = useState('');
    const [creatingTrigger, setCreatingTrigger] = useState(false);
    const [modalConfig, setModalConfig] = useState(null);
    const [nodes, setNodes] = useState([]);
    const [allSkills, setAllSkills] = useState([]);
    const [flippedCards, setFlippedCards] = useState({ runtime: false, tokens: false });

    // Helper: Convert cron expression to human-readable text
    const describeCron = (expr) => {
        if (!expr) return '';
        if (/^\d+$/.test(expr)) {
            const secs = parseInt(expr);
            if (secs < 60) return `Every ${secs} seconds`;
            if (secs < 3600) return `Every ${Math.round(secs/60)} minute${secs >= 120 ? 's' : ''}`;
            return `Every ${Math.round(secs/3600)} hour${secs >= 7200 ? 's' : ''}`;
        }
        // Standard cron expressions
        const parts = expr.split(' ');
        if (parts.length >= 5) {
            if (expr === '* * * * *') return 'Every minute';
            if (expr === '0 * * * *') return 'Every hour';
            if (expr === '0 0 * * *') return 'Every day at midnight';
            if (parts[0].startsWith('*/')) return `Every ${parts[0].slice(2)} minute${parts[0].slice(2) !== '1' ? 's' : ''}`;
        }
        return expr;
    };

    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' 
        });
    };

    useEffect(() => {
        const loadConf = async () => {
            try {
                const conf = await getUserConfig();
                setUserConfig(conf);
            } catch (e) {}
            try {
                const nList = await getUserAccessibleNodes();
                setNodes(nList);
            } catch (e) {}
            try {
                const sList = await getSkills();
                setAllSkills(sList);
            } catch (e) {}
        };
        loadConf();
    }, []);

    const fetchData = async () => {
        try {
            // Find agent
            const allAgents = await getAgents();
            const found = allAgents.find(a => a.id === agentId);
            if (!found) throw new Error("Agent not found");
            setAgent(found);

            // Populate form only on first load using the agent context
            setEditConfig(prev => prev || {
                name: found.template?.name || "",
                system_prompt: found.template?.system_prompt_content || found.template?.system_prompt_path || "",
                max_loop_iterations: found.template?.max_loop_iterations || 20,
                mesh_node_id: found.mesh_node_id || "",
                provider_name: found.session?.provider_name || "",
                restrict_skills: found.session?.restrict_skills || false,
                allowed_skill_ids: found.session?.skills ? found.session.skills.map(s => s.id) : [],
                is_locked: found.session?.is_locked || false,
                auto_clear_history: found.session?.auto_clear_history || false
            });

            // Fetch chat history if session exists
            if (found.session_id) {
                const historyResp = await getSessionMessages(found.session_id);
                const formatted = (historyResp.messages || []).map(m => ({
                    text: m.content,
                    isUser: m.sender === 'user',
                    reasoning: m.reasoning_content,
                    status: null,
                    sender: m.sender,
                    timestamp: m.created_at,
                    id: m.id,
                    tool_calls: m.tool_calls
                }));
                setChatHistory(formatted);
                
                try {
                    const usage = await getSessionTokenStatus(found.session_id);
                    setTokenUsage(usage);
                } catch(e) {}
            }

            try {
                const tList = await getAgentTriggers(agentId);
                setTriggers(tList);
            } catch(e) {}
        } catch (err) {
            setError(err.message);
        } finally {
            setLoading(false);
        }
    };

    useEffect(() => {
        fetchData();
        const interval = setInterval(fetchData, 3000);
        return () => clearInterval(interval);
    }, [agentId]);

    const handleInjectOverride = async (e) => {
        e.preventDefault();
        if (!overrideText.trim() || !agent?.session_id) return;
        
        try {
            await fetchWithAuth(`/agents/${agentId}/webhook`, {
                method: "POST",
                body: { override_prompt: overrideText }
            });
            setOverrideText("");
            fetchData();
        } catch (err) {
            setModalConfig({ title: 'Injection Failed', message: err.message, type: 'error' });
        }
    };

    const handleClearHistory = () => {
        if (!agent?.session_id) return;
        setModalConfig({
            title: 'Confirm Memory Wipe',
            message: "Are you sure you want to clear the agent's memory? This cannot be undone.",
            type: 'error',
            confirmText: 'Clear Memory',
            confirmAction: async () => {
                try {
                    setClearing(true);
                    if (agent?.session?.is_locked && editConfig?.is_locked === false) {
                        await updateAgentConfig(agent.id, { 
                            is_locked: false,
                            mesh_node_id: agent.mesh_node_id || "hub" 
                        });
                    }
                    await clearSessionHistory(agent.session_id);
                    setChatHistory([]);
                    fetchData();
                } catch (err) {
                    setModalConfig({ title: 'Clear Failed', message: err.message, type: 'error' });
                } finally {
                    setClearing(false);
                }
            }
        });
    };

    const handleResetMetrics = () => {
        if (!agent?.id) return;
        setModalConfig({
            title: 'Confirm Reset Metrics',
            message: "Are you sure you want to reset all execution metrics for this agent? This cannot be undone.",
            type: 'error',
            confirmText: 'Reset Metrics',
            confirmAction: async () => {
                try {
                    setClearing(true); // Re-use the clearing state to block duplicate clicks
                    await resetAgentMetrics(agent.id);
                    fetchData();
                } catch (err) {
                    setModalConfig({ title: 'Reset Failed', message: err.message, type: 'error' });
                } finally {
                    setClearing(false);
                }
            }
        });
    };

    const handleSaveConfig = async () => {
        try {
            setSaving(true);
            const payload = {
                name: editConfig.name,
                system_prompt: editConfig.system_prompt,
                max_loop_iterations: parseInt(editConfig.max_loop_iterations, 10) || 20,
                mesh_node_id: editConfig.mesh_node_id
            };
            if (editConfig.provider_name) {
                payload.provider_name = editConfig.provider_name;
            }
            if (editConfig.restrict_skills !== undefined) {
                payload.restrict_skills = editConfig.restrict_skills;
            }
            if (editConfig.allowed_skill_ids !== undefined) {
                payload.allowed_skill_ids = editConfig.allowed_skill_ids;
            }
            if (editConfig.is_locked !== undefined) {
                payload.is_locked = editConfig.is_locked;
            }
            if (editConfig.auto_clear_history !== undefined) {
                payload.auto_clear_history = editConfig.auto_clear_history;
            }
            
            // Explicitly pause the agent loop during update as requested by the user
            try {
                await fetchWithAuth(`/agents/${agentId}/status`, { method: "PATCH", body: { status: "idle" } });
            } catch (e) {}
            
            await updateAgentConfig(agentId, payload);
            fetchData();
            setModalConfig({ title: 'Success', message: 'Configuration Saved Successfully!', type: 'success' });
        } catch (err) {
            setModalConfig({ title: 'Save Failed', message: err.message, type: 'error' });
        } finally {
            setSaving(false);
        }
    };

    const handleAddTrigger = async () => {
        try {
            setCreatingTrigger(true);
            const payload = { 
                trigger_type: newTriggerType,
                default_prompt: newDefaultPrompt
            };
            if (newTriggerType === 'cron') payload.cron_expression = newCronValue;
            if (newTriggerType === 'interval') payload.interval_seconds = parseInt(newIntervalValue) || 600;
            
            await createAgentTrigger(agentId, payload);
            setNewDefaultPrompt('');
            setNewCronValue('0 * * * *');
            setNewIntervalValue(600);
            fetchData();
        } catch (err) {
            setModalConfig({ title: 'Trigger Failed', message: err.message, type: 'error' });
        } finally {
            setCreatingTrigger(false);
        }
    };

    const handleDeleteTrigger = async (triggerId) => {
        try {
            await deleteAgentTrigger(triggerId);
            fetchData();
        } catch (err) {
            setModalConfig({ title: 'Delete Failed', message: err.message, type: 'error' });
        }
    };

    const handleFireTrigger = async (triggerPrompt) => {
        try {
            await fetchWithAuth(`/agents/${agentId}/run`, {
                method: 'POST',
                body: { prompt: triggerPrompt }
            });
            setModalConfig({ title: 'Success', message: 'Agent manual execution started successfully!', type: 'success' });
            fetchData();
        } catch (err) {
            setModalConfig({ title: 'Execution Failed', message: err.message, type: 'error' });
        }
    };

    if (loading && !agent) return (
        <div className="flex h-screen items-center justify-center bg-[#070b14] text-white">
            <div className="animate-spin w-8 h-8 border-4 border-indigo-500 border-t-transparent rounded-full font-mono text-sm ml-4"></div>
        </div>
    );

    if (error) return (
        <div className="flex h-screen items-center justify-center bg-gray-950 text-red-500">
            Error loading Agent Drilldown: {error}
        </div>
    );

    return (
        <div className="flex flex-col flex-grow h-full bg-gray-100 dark:bg-gray-900 text-gray-900 dark:text-gray-100 font-sans overflow-hidden">
            
            {/* Minimal Header */}
            <div className="border-b border-gray-200 dark:border-gray-800 bg-white dark:bg-gray-800 px-6 py-4 flex items-center justify-between z-10 shrink-0 shadow-sm">
                <div className="flex items-center space-x-4">
                    <button onClick={() => onNavigate('/agents')} className="text-gray-500 hover:text-gray-900 dark:hover:text-white transition-colors p-2 -ml-2 rounded-lg hover:bg-gray-100 dark:hover:bg-gray-700">
                        <svg className="w-5 h-5" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M10 19l-7-7m0 0l7-7m-7 7h18" /></svg>
                    </button>
                    <div>
                        <h2 className="text-xl font-bold tracking-tight">{agent?.id?.split('-')[0]} Dashboard</h2>
                        <div className="flex items-center space-x-2 mt-1">
                            <span className="flex h-2 w-2 relative">
                                {agent?.status === 'active' && <span className="animate-ping absolute inline-flex h-full w-full rounded-full bg-emerald-400 opacity-75"></span>}
                                <span className={`relative inline-flex rounded-full h-2 w-2 ${agent?.status === 'active' ? 'bg-emerald-500' : 'bg-amber-500'}`}></span>
                            </span>
                            <span className="text-[10px] text-gray-500 dark:text-gray-400 uppercase tracking-widest font-mono">Status: {agent?.status}</span>
                        </div>
                    </div>
                </div>
                <div className="flex items-center space-x-4 font-mono text-xs text-gray-500 dark:text-gray-400">
                    <span>Node: <span className="text-indigo-600 dark:text-indigo-400 font-bold">{nodes.find(n => n.id === agent?.mesh_node_id)?.name || agent?.mesh_node_id || 'unassigned'}</span></span>
                    <span>Jail Path: <span className="text-pink-600 dark:text-pink-400 font-bold">{agent?.current_workspace_jail || '/tmp'}</span></span>
                    <span>Synced Workspace: <span className="text-emerald-600 dark:text-emerald-400 font-bold">{agent?.session?.sync_workspace_id || agent?.session_id || 'not-bound'}</span></span>
                </div>
            </div>

            {/* Main Content Area - 50/50 Split */}
            <div className="flex-1 grid grid-cols-2 overflow-hidden gap-1 p-1 bg-gray-200 dark:bg-gray-950">
                
                {/* Left Pane: Chat Tracker */}
                <div className="flex flex-col bg-white dark:bg-gray-900 border border-gray-200 dark:border-gray-800/80 rounded-xl overflow-hidden relative shadow-lg">
                    <div className="px-4 py-2 border-b border-gray-200 dark:border-gray-800/80 bg-gray-50 dark:bg-gray-900/50 backdrop-blur-md flex justify-between items-center shrink-0">
                        <span className="text-[10px] uppercase tracking-[0.2em] font-black text-indigo-400 flex items-center gap-2">
                           <div className="w-1.5 h-1.5 bg-indigo-500 rounded-full animate-pulse shadow-[0_0_8px_rgba(99,102,241,0.5)]"></div>
                           Live Thought Process
                        </span>
                        {agent?.session_id && (
                            <button
                                onClick={handleClearHistory}
                                disabled={clearing || editConfig?.is_locked}
                                className="text-[10px] font-bold uppercase tracking-wider px-2 py-0.5 rounded border border-red-500/30 text-red-500 hover:bg-red-500/10 transition-colors disabled:opacity-50"
                            >
                                {clearing ? 'Clearing...' : editConfig?.is_locked ? "🔒 Locked" : "Clear History"}
                            </button>
                        )}
                    </div>

                    <div className="flex-1 overflow-hidden relative">
                         {agent?.session_id ? (
                            <ChatWindow 
                                chatHistory={chatHistory} 
                                maxHeight="100%" 
                                autoCollapse={true} 
                            />
                         ) : (
                             <div className="flex h-full items-center justify-center text-gray-500 italic text-sm">
                                 No session bounds established for this agent.
                             </div>
                         )}
                    </div>

                    {/* Inject Prompt Override */}
                    <div className="p-4 border-t border-gray-200 dark:border-gray-800 bg-gray-50 dark:bg-gray-900/90 shrink-0">
                        <form onSubmit={handleInjectOverride} className="relative flex items-center">
                            <input 
                                type="text" 
                                value={overrideText}
                                onChange={(e) => setOverrideText(e.target.value)}
                                placeholder="Steer agent execution loop..." 
                                className="w-full bg-white dark:bg-gray-950 border border-gray-300 dark:border-gray-700 text-sm rounded-xl py-3 pl-4 pr-12 focus:outline-none focus:border-indigo-500 focus:ring-1 focus:ring-indigo-500 text-gray-900 dark:text-gray-100 transition-all font-mono"
                            />
                            <button 
                                type="submit" 
                                disabled={!overrideText.trim()}
                                className="absolute right-2 px-3 py-1.5 bg-indigo-600/20 text-indigo-400 rounded-lg text-xs font-bold hover:bg-indigo-600 hover:text-white transition-colors disabled:opacity-30 disabled:hover:bg-transparent disabled:hover:text-indigo-400 uppercase tracking-wider"
                            >
                                Inject
                            </button>
                        </form>
                    </div>
                </div>

                {/* Right Pane: Multi-Tab Container */}
                <div className="flex flex-col bg-white dark:bg-gray-900 border border-gray-200 dark:border-gray-800/80 rounded-xl overflow-hidden shadow-lg">
                    {/* Tab Header */}
                    <div className="flex border-b border-gray-200 dark:border-gray-800/80 bg-gray-50 dark:bg-gray-900/50 px-2 pt-2 shrink-0">
                        <button 
                            onClick={() => setActiveTab('config')}
                            className={`px-4 py-2 text-xs font-bold uppercase tracking-widest rounded-t-lg transition-colors ${activeTab === 'config' ? 'bg-white dark:bg-gray-900 text-indigo-500 border-t border-l border-r border-gray-200 dark:border-gray-800/80 -mb-px' : 'text-gray-500 hover:text-gray-400'}`}
                        >
                            Metadata & System
                        </button>
                        <button 
                            onClick={() => setActiveTab('workspace')}
                            className={`px-4 py-2 text-xs font-bold uppercase tracking-widest rounded-t-lg transition-colors ${activeTab === 'workspace' ? 'bg-white dark:bg-gray-900 text-indigo-500 border-t border-l border-r border-gray-200 dark:border-gray-800/80 -mb-px' : 'text-gray-500 hover:text-gray-400'}`}
                        >
                            Mesh Workspace
                        </button>
                        <button 
                            onClick={() => setActiveTab('metrics')}
                            className={`px-4 py-2 text-xs font-bold uppercase tracking-widest rounded-t-lg transition-colors ${activeTab === 'metrics' ? 'bg-white dark:bg-gray-900 text-indigo-500 border-t border-l border-r border-gray-200 dark:border-gray-800/80 -mb-px' : 'text-gray-500 hover:text-gray-400'}`}
                        >
                            Metrics
                        </button>
                    </div>

                    {/* Tab Body */}
                    <div className="flex-1 overflow-auto relative">
                        {activeTab === 'workspace' && (
                            agent ? (
                                <FileSystemNavigator 
                                    nodeId={agent.mesh_node_id || "hub"} 
                                    initialPath="." 
                                    sessionId={agent.session?.sync_workspace_id || agent.session_id}
                                    showSyncStatus={true}
                                />
                            ) : (
                                <div className="flex h-full items-center justify-center text-gray-500">
                                    Initializing workspace bridge...
                                </div>
                            )
                        )}
                        
                        {activeTab === 'config' && (
                            <div className="p-6 flex flex-col gap-6">
                                {/* Token & History Utilities */}
                                <div className="p-4 rounded-xl border border-gray-200 dark:border-gray-700/50 bg-gray-50 dark:bg-gray-800/30 flex justify-between items-center">
                                    <div className="flex flex-col">
                                        <span className="uppercase text-[10px] tracking-widest text-gray-500 font-bold mb-1">Session Context Window</span>
                                        <div className="flex items-center gap-3 w-48">
                                            <div className="flex-1 h-2 bg-gray-200 dark:bg-gray-700 rounded-full overflow-hidden">
                                                <div 
                                                    className="h-full bg-gradient-to-r from-emerald-500 to-indigo-500" 
                                                    style={{ width: `${Math.min(tokenUsage.percentage, 100)}%` }}
                                                />
                                            </div>
                                            <span className="text-xs font-mono whitespace-nowrap text-gray-500">{Math.round(tokenUsage.percentage)}%</span>
                                        </div>
                                    </div>
                                </div>

                                <div className={`grid grid-cols-1 md:grid-cols-2 gap-6 ${editConfig?.is_locked ? 'opacity-50 pointer-events-none transition-opacity' : ''}`}>
                                    <div>
                                        <span className="uppercase text-[10px] tracking-widest text-gray-500 font-bold block mb-1">Agent Name</span>
                                        <input type="text" value={editConfig?.name || ""} onChange={(e) => setEditConfig({...editConfig, name: e.target.value})} className="w-full bg-white dark:bg-gray-950 border border-gray-300 dark:border-gray-700 text-sm rounded-md py-2.5 px-3 focus:outline-none focus:ring-1 focus:ring-indigo-500 text-gray-900 dark:text-gray-100 shadow-sm" placeholder="e.g. Documentation Assistant" disabled={editConfig?.is_locked} />
                                    </div>
                                    <div>
                                        <span className="uppercase text-[10px] tracking-widest text-gray-500 font-bold block mb-1">Active LLM Provider</span>
                                        <select
                                            value={editConfig?.provider_name || userConfig?.effective?.llm?.active_provider || ""}
                                            onChange={e => setEditConfig({...editConfig, provider_name: e.target.value})}
                                            className="w-full bg-white dark:bg-gray-950 border border-gray-300 dark:border-gray-700 text-sm rounded-md py-2.5 px-3 focus:outline-none focus:ring-1 focus:ring-indigo-500 text-gray-900 dark:text-gray-100 shadow-sm"
                                            disabled={editConfig?.is_locked}
                                        >
                                            {userConfig?.effective?.llm?.providers && Object.keys(userConfig.effective.llm.providers).map(pid => (
                                                <option key={pid} value={pid}>{pid} {userConfig.effective.llm.providers[pid].model ? `(${userConfig.effective.llm.providers[pid].model})` : ''}</option>
                                            ))}
                                        </select>
                                    </div>
                                    <div className="grid grid-cols-2 gap-4">
                                        <div>
                                            <span className="uppercase text-[10px] tracking-widest text-gray-500 font-bold block mb-1">Target Mesh Node</span>
                                            <select 
                                                value={editConfig?.mesh_node_id || ""} 
                                                onChange={(e) => setEditConfig({...editConfig, mesh_node_id: e.target.value})} 
                                                className="w-full bg-white dark:bg-gray-950 border border-gray-300 dark:border-gray-700 text-sm rounded-md py-2.5 px-3 focus:outline-none focus:ring-1 focus:ring-indigo-500 text-gray-900 dark:text-gray-100 shadow-sm"
                                                required
                                                disabled={editConfig?.is_locked}
                                            >
                                                {nodes.length === 0 && <option value="" disabled>No nodes available</option>}
                                                {nodes.map(n => <option key={n.node_id} value={n.node_id}>{n.display_name || n.node_id} ({n.last_status || 'unknown'})</option>)}
                                            </select>
                                        </div>
                                        <div>
                                            <span className="uppercase text-[10px] tracking-widest text-gray-500 font-bold block mb-1">Max Iterations</span>
                                            <input type="number" min="1" max="100" value={editConfig?.max_loop_iterations || 20} onChange={(e) => setEditConfig({...editConfig, max_loop_iterations: e.target.value})} className="w-full bg-white dark:bg-gray-950 border border-gray-300 dark:border-gray-700 text-sm rounded-md py-2.5 px-3 focus:outline-none focus:ring-1 focus:ring-indigo-500 text-gray-900 dark:text-gray-100 shadow-sm" disabled={editConfig?.is_locked} />
                                        </div>
                                    </div>
                                </div>
                                
                                {/* Skills and Lock Controls */}
                                <div className="grid grid-cols-1 md:grid-cols-2 gap-6 pb-2 border-b border-gray-200 dark:border-gray-800">
                                    <div className={editConfig?.is_locked ? 'opacity-50 pointer-events-none transition-opacity' : ''}>
                                        <span className="uppercase text-[10px] tracking-widest text-gray-500 font-bold block mb-2">Enabled Skills</span>
                                        <div className="bg-white dark:bg-gray-950 border border-gray-300 dark:border-gray-700 rounded-lg p-3 max-h-56 overflow-y-auto w-full shadow-sm">
                                            <label className="flex items-center gap-2 cursor-pointer pb-3 mb-3 border-b border-gray-100 dark:border-gray-800">
                                                <div className="relative inline-flex items-center cursor-pointer">
                                                    <input 
                                                        type="checkbox" 
                                                        className="sr-only peer"
                                                        checked={editConfig?.restrict_skills === false}
                                                        onChange={(e) => setEditConfig({...editConfig, restrict_skills: !e.target.checked})}
                                                    />
                                                    <div className="w-8 h-4.5 bg-gray-200 peer-focus:outline-none rounded-full peer dark:bg-gray-800 peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-3.5 after:w-3.5 after:transition-all dark:border-gray-600 peer-checked:bg-indigo-500"></div>
                                                </div>
                                                <span className="text-sm font-bold text-gray-900 dark:text-gray-100">All Skills (Unrestricted)</span>
                                            </label>

                                            <div className="mb-2">
                                                <span className="text-[10px] uppercase font-bold text-gray-400 block mb-1.5">System Core Skills</span>
                                                <div className="flex flex-wrap gap-1">
                                                    {allSkills.filter(s => s.is_system).map(skill => (
                                                        <span key={skill.id} className="text-[10px] font-bold bg-indigo-50 dark:bg-indigo-500/10 text-indigo-600 dark:text-indigo-400 border border-indigo-200 dark:border-indigo-500/20 px-2.5 py-0.5 rounded-full whitespace-nowrap">
                                                            ✓ {skill.name}
                                                        </span>
                                                    ))}
                                                </div>
                                            </div>

                                            {editConfig?.restrict_skills && (
                                                <div className="mt-3 pt-3 border-t border-gray-100 dark:border-gray-800">
                                                    <span className="text-[10px] uppercase font-bold text-gray-400 block mb-2">User Context Skills</span>
                                                    <div className="flex flex-col gap-2">
                                                        {allSkills.filter(s => !s.is_system).map(skill => (
                                                            <label key={skill.id} className="flex items-center gap-2.5 cursor-pointer hover:bg-gray-50 dark:hover:bg-gray-900 -mx-1 px-1 py-1 rounded">
                                                                <input 
                                                                    type="checkbox" 
                                                                    className="w-4 h-4 rounded text-indigo-500 focus:ring-indigo-500 bg-white dark:bg-gray-900 border-gray-300 dark:border-gray-700" 
                                                                    checked={editConfig?.allowed_skill_ids?.includes(skill.id) || false}
                                                                    onChange={(e) => {
                                                                        const ids = editConfig.allowed_skill_ids || [];
                                                                        const nextIds = e.target.checked ? [...ids, skill.id] : ids.filter(i => i !== skill.id);
                                                                        setEditConfig({...editConfig, allowed_skill_ids: nextIds});
                                                                    }}
                                                                />
                                                                <span className="text-xs font-mono font-medium text-gray-700 dark:text-gray-300 truncate">
                                                                    {skill.name}
                                                                </span>
                                                            </label>
                                                        ))}
                                                        {allSkills.filter(s => !s.is_system).length === 0 && (
                                                            <span className="text-xs text-gray-400 italic py-1">No user skills available</span>
                                                        )}
                                                    </div>
                                                </div>
                                            )}
                                        </div>
                                    </div>
                                    <div>
                                        <span className="uppercase text-[10px] tracking-widest text-gray-500 font-bold block mb-2">Memory Handling</span>
                                        <div className="bg-white dark:bg-gray-950 border border-gray-300 dark:border-gray-700 rounded-lg p-4 shadow-sm flex flex-col gap-4">
                                            <label className="flex items-center gap-3 cursor-pointer w-full">
                                                <div className="relative inline-flex items-center cursor-pointer">
                                                    <input 
                                                        type="checkbox" 
                                                        className="sr-only peer"
                                                        checked={editConfig?.is_locked || false}
                                                        onChange={(e) => setEditConfig({...editConfig, is_locked: e.target.checked})}
                                                    />
                                                    <div className="w-9 h-5 bg-gray-200 peer-focus:outline-none peer-focus:ring-2 peer-focus:ring-indigo-300 dark:peer-focus:ring-indigo-800 rounded-full peer dark:bg-gray-700 peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-4 after:w-4 after:transition-all dark:border-gray-600 peer-checked:bg-amber-500"></div>
                                                </div>
                                                <div className="flex flex-col flex-1">
                                                    <span className={`text-sm font-bold ${editConfig?.is_locked ? "text-amber-600 dark:text-amber-500" : "text-gray-900 dark:text-gray-100"}`}>
                                                        {editConfig?.is_locked ? 'Lock Session Memory' : 'Unlocked'}
                                                    </span>
                                                    <span className="text-xs text-gray-500 dark:text-gray-400">
                                                        When locked, the agent's memory (chat history) cannot be cleared or deleted. Unlock to clear history.
                                                    </span>
                                                </div>
                                            </label>

                                            <div className="w-full h-px bg-gray-200 dark:bg-gray-800 my-1"></div>

                                            <label className="flex items-center gap-3 cursor-pointer w-full">
                                                <div className="relative inline-flex items-center cursor-pointer">
                                                    <input 
                                                        type="checkbox" 
                                                        className="sr-only peer"
                                                        checked={editConfig?.auto_clear_history || false}
                                                        onChange={(e) => setEditConfig({...editConfig, auto_clear_history: e.target.checked})}
                                                    />
                                                    <div className="w-9 h-5 bg-gray-200 peer-focus:outline-none peer-focus:ring-2 peer-focus:ring-indigo-300 dark:peer-focus:ring-indigo-800 rounded-full peer dark:bg-gray-700 peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-4 after:w-4 after:transition-all dark:border-gray-600 peer-checked:bg-pink-500"></div>
                                                </div>
                                                <div className="flex flex-col flex-1">
                                                    <span className={`text-sm font-bold ${editConfig?.auto_clear_history ? "text-pink-600 dark:text-pink-500" : "text-gray-900 dark:text-gray-100"}`}>
                                                        {editConfig?.auto_clear_history ? 'Auto-Wipe Between Runs' : 'Preserve History Continuously'}
                                                    </span>
                                                    <span className="text-xs text-gray-500 dark:text-gray-400">
                                                        When enabled, the chat history will be completely wiped prior to every new background execution (e.g. cron/webhook).
                                                    </span>
                                                </div>
                                            </label>
                                        </div>
                                    </div>
                                </div>
                                
                                {/* Execution Triggers Box */}
                                <div>
                                    <span className="uppercase text-[10px] tracking-widest text-gray-500 font-bold block mb-2">Execution Triggers</span>
                                    <div className="bg-white dark:bg-gray-950 border border-gray-300 dark:border-gray-700 rounded-lg p-4 shadow-sm">
                                        
                                        {/* List existing triggers */}
                                        {triggers.length > 0 && (
                                            <div className="mb-4 space-y-2">
                                                {triggers.map(t => (
                                                    <div key={t.id} className="flex items-center justify-between bg-gray-50 dark:bg-gray-900 border border-gray-200 dark:border-gray-800 rounded px-3 py-2 text-sm">
                                                        <div className="flex flex-col">
                                                            <span className="font-bold text-gray-800 dark:text-gray-200 uppercase tracking-wider text-[10px]">
                                                                {({'manual': '🖐️ MANUAL', 'cron': '⏰ CRON', 'interval': '🔄 INTERVAL', 'webhook': '🔗 WEBHOOK'})[t.trigger_type] || t.trigger_type} &middot; {t.id.split('-')[0]}
                                                            </span>
                                                            <span className="font-mono text-gray-500 dark:text-gray-400 text-xs">
                                                                {t.trigger_type === 'cron' && `Schedule: ${t.cron_expression} (${describeCron(t.cron_expression)})`}
                                                                {t.trigger_type === 'interval' && `Every ${t.interval_seconds >= 3600 ? Math.round(t.interval_seconds/3600) + 'h' : t.interval_seconds >= 60 ? Math.round(t.interval_seconds/60) + 'min' : t.interval_seconds + 's'} after completion`}
                                                                {t.trigger_type === 'webhook' && `Secret: ${t.webhook_secret}`}
                                                                {t.trigger_type === 'manual' && `On-demand — Ready for requests`}
                                                            </span>
                                                            {t.default_prompt && (
                                                                <span className="text-[10px] text-gray-400 mt-1 italic">Prompt: "{t.default_prompt.substring(0, 40)}{t.default_prompt.length > 40 ? '...' : ''}"</span>
                                                            )}
                                                        </div>
                                                        <div className="flex items-center gap-2">
                                                            <button 
                                                                onClick={e => { e.preventDefault(); handleFireTrigger(t.default_prompt); }}
                                                                className="text-emerald-600 dark:text-emerald-400 hover:text-emerald-700 font-bold text-xs bg-emerald-50 dark:bg-emerald-500/10 hover:bg-emerald-100 dark:hover:bg-emerald-500/20 px-3 py-1.5 rounded transition-colors"
                                                            >
                                                                Fire
                                                            </button>
                                                            <button 
                                                                onClick={e => { e.preventDefault(); handleDeleteTrigger(t.id); }}
                                                                className="text-red-500 hover:text-red-700 font-bold text-xs bg-red-50 dark:bg-red-900/20 hover:bg-red-100 dark:hover:bg-red-900/40 px-3 py-1.5 rounded transition-colors"
                                                            >
                                                                Delete
                                                            </button>
                                                        </div>
                                                    </div>
                                                ))}
                                            </div>
                                        )}
                                        
                                        {/* Add new trigger form */}
                                        <div className="flex items-end gap-3 border-t border-gray-200 dark:border-gray-800 pt-4 mt-2">
                                            <div className="w-1/3">
                                                <span className="uppercase text-[10px] tracking-widest text-gray-500 font-bold block mb-1">Type</span>
                                                <select 
                                                    value={newTriggerType} 
                                                    onChange={e => setNewTriggerType(e.target.value)}
                                                    className="w-full bg-gray-50 dark:bg-gray-900 border border-gray-300 dark:border-gray-700 text-sm rounded-md py-2 px-3 focus:outline-none"
                                                >
                                                    <option value="manual">Manual Request</option>
                                                    <option value="cron">CRON Schedule</option>
                                                    <option value="interval">Recurrent Wait</option>
                                                    <option value="webhook">Webhook Link</option>
                                                </select>
                                            </div>
                                            
                                            {newTriggerType === 'cron' && (
                                                <div className="flex-1">
                                                    <span className="uppercase text-[10px] tracking-widest text-gray-500 font-bold block mb-1">CRON Expr</span>
                                                    <input 
                                                        type="text" 
                                                        value={newCronValue} 
                                                        onChange={e => setNewCronValue(e.target.value)}
                                                        className="w-full bg-gray-50 dark:bg-gray-900 border border-gray-300 dark:border-gray-700 text-sm rounded-md py-2 px-3 font-mono focus:outline-none" 
                                                    />
                                                </div>
                                            )}

                                            {newTriggerType === 'interval' && (
                                                <div className="flex-1">
                                                    <span className="uppercase text-[10px] tracking-widest text-gray-500 font-bold block mb-1">Wait Seconds</span>
                                                    <input 
                                                        type="number" 
                                                        value={newIntervalValue} 
                                                        onChange={e => setNewIntervalValue(e.target.value)}
                                                        className="w-full bg-gray-50 dark:bg-gray-900 border border-gray-300 dark:border-gray-700 text-sm rounded-md py-2 px-3 font-mono focus:outline-none" 
                                                    />
                                                </div>
                                            )}
                                        </div>

                                        <div className="mt-4 flex flex-col">
                                            <span className="uppercase text-[10px] tracking-widest text-gray-500 font-bold block mb-1">
                                                {newTriggerType === 'cron' || newTriggerType === 'interval' ? 'Fixed Automation Prompt' : 'Default/Overridable Prompt'}
                                            </span>
                                            <div className="flex gap-3 items-end">
                                                <input 
                                                    type="text" 
                                                    value={newDefaultPrompt} 
                                                    onChange={e => setNewDefaultPrompt(e.target.value)}
                                                    placeholder="Trigger instruction..."
                                                    className="flex-1 bg-gray-50 dark:bg-gray-900 border border-gray-300 dark:border-gray-700 text-sm rounded-md py-2 px-3 focus:outline-none" 
                                                />
                                                <button 
                                                    onClick={e => { e.preventDefault(); handleAddTrigger(); }}
                                                    disabled={creatingTrigger}
                                                    className="px-4 py-2 text-xs font-bold bg-indigo-100 dark:bg-indigo-900/30 text-indigo-700 dark:text-indigo-400 border border-indigo-200 dark:border-indigo-800 hover:bg-indigo-200 dark:hover:bg-indigo-800/50 rounded-md transition-colors whitespace-nowrap"
                                                >
                                                    + Add Trigger
                                                </button>
                                            </div>
                                        </div>
                                    </div>
                                </div>
                                
                                <div className={`flex-1 flex flex-col min-h-[300px] ${editConfig?.is_locked ? 'opacity-50 pointer-events-none transition-opacity' : ''}`}>
                                    <span className="uppercase text-[10px] tracking-widest text-gray-500 font-bold block mb-2">Core System Instruction Prompt (Modifiable Live)</span>
                                    <textarea value={editConfig?.system_prompt || ""} onChange={(e) => setEditConfig({...editConfig, system_prompt: e.target.value})} className="flex-1 resize-none w-full bg-gray-900 text-emerald-400 p-4 rounded-lg text-sm leading-relaxed font-mono shadow-inner border border-gray-700 focus:outline-none focus:border-indigo-500 focus:ring-1 focus:ring-indigo-500" placeholder="You are an expert AI agent..."></textarea>
                                    <p className="text-xs text-gray-500 mt-2 font-mono">Changes to the system prompt will be immediately picked up by the agent loop on its next invocation turn.</p>
                                </div>
                                <div className="flex justify-end pt-4">
                                    <button onClick={handleSaveConfig} disabled={saving} className="px-6 py-2.5 text-sm font-bold bg-indigo-600 hover:bg-indigo-700 text-white shadow-md rounded-lg transition-all active:scale-95 flex items-center gap-2">
                                        {saving ? "Saving Configuration..." : "Apply Live Configuration"}
                                    </button>
                                </div>
                            </div>
                        )}

                        {activeTab === 'metrics' && (
                            <div className="p-6 flex flex-col gap-6 font-mono text-sm">
                                <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-2 md:grid-cols-6 gap-4">
                                    <div className="bg-gray-50 dark:bg-gray-800/50 p-4 rounded-xl border border-gray-200 dark:border-gray-800">
                                        <span className="uppercase text-[10px] tracking-widest text-gray-500 font-bold block mb-1">Total Runs</span>
                                        <span className="text-2xl font-black text-indigo-500">{agent?.total_runs || 0}</span>
                                    </div>
                                    <div className="bg-gray-50 dark:bg-gray-800/50 p-4 rounded-xl border border-gray-200 dark:border-gray-800">
                                        <span className="uppercase text-[10px] tracking-widest text-gray-500 font-bold block mb-1">Last Run</span>
                                        <span className="text-sm font-black text-blue-500 mt-2 block">
                                            {formatTimeLocal(agent?.last_heartbeat)}
                                        </span>
                                    </div>
                                    <div 
                                        className="bg-gray-50 dark:bg-gray-800/50 p-4 rounded-xl border border-gray-200 dark:border-gray-800 cursor-help"
                                        title={`${agent?.successful_runs || 0} / ${agent?.total_runs || 0} (${(agent?.total_runs || 0) - (agent?.successful_runs || 0)})`}
                                    >
                                        <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>
                                    </div>
                                    <div 
                                        className="relative w-full min-h-[5.5rem] cursor-pointer group col-span-1"
                                        style={{ perspective: "1000px" }}
                                        onClick={() => setFlippedCards(prev => ({...prev, runtime: !prev.runtime}))}
                                    >
                                        <div 
                                            className="relative w-full h-full transition-transform duration-500" 
                                            style={{ transformStyle: "preserve-3d", transform: flippedCards.runtime ? "rotateX(180deg)" : "rotateX(0deg)" }}
                                        >
                                            <div 
                                                className="absolute inset-0 bg-gray-50 dark:bg-gray-800/50 p-4 rounded-xl border border-gray-200 dark:border-gray-800"
                                                style={{ backfaceVisibility: "hidden" }}
                                            >
                                                <span className="uppercase text-[10px] tracking-widest text-gray-500 font-bold block mb-1">Total AI Run Time <span className="opacity-0 group-hover:opacity-100 float-right text-indigo-400 transition-opacity">&#8635;</span></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 
                                                className="absolute inset-0 bg-gray-50 dark:bg-gray-800/50 p-4 rounded-xl border border-gray-200 dark:border-gray-800"
                                                style={{ backfaceVisibility: "hidden", transform: "rotateX(180deg)" }}
                                            >
                                                <span className="uppercase text-[10px] tracking-widest text-gray-500 font-bold block mb-1">Avg Request Time <span className="opacity-0 group-hover:opacity-100 float-right text-indigo-400 transition-opacity">&#8635;</span></span>
                                                <span className="text-2xl font-black text-pink-400">
                                                    {agent?.total_runs ? (agent.total_running_time_seconds / agent.total_runs).toFixed(1) : 0}s
                                                </span>
                                            </div>
                                        </div>
                                    </div>
                                    
                                    <div 
                                        className="relative w-full min-h-[5.5rem] cursor-pointer group col-span-2"
                                        style={{ perspective: "1000px" }}
                                        onClick={() => setFlippedCards(prev => ({...prev, tokens: !prev.tokens}))}
                                    >
                                        <div 
                                            className="relative w-full h-full transition-transform duration-500" 
                                            style={{ transformStyle: "preserve-3d", transform: flippedCards.tokens ? "rotateX(180deg)" : "rotateX(0deg)" }}
                                        >
                                            <div 
                                                className="absolute inset-0 bg-gray-50 dark:bg-gray-800/50 p-4 rounded-xl border border-gray-200 dark:border-gray-800"
                                                style={{ backfaceVisibility: "hidden" }}
                                            >
                                                <span className="uppercase text-[10px] tracking-widest text-gray-500 font-bold block mb-1">Total Tokens (In / Out) <span className="opacity-0 group-hover:opacity-100 float-right text-indigo-400 transition-opacity">&#8635;</span></span>
                                                <span className="text-2xl font-black text-blue-400 tabular-nums">
                                                    {agent?.total_input_tokens?.toLocaleString() || 0}
                                                    <span className="text-gray-400 text-sm mx-2 font-normal">/</span>
                                                    <span className="text-emerald-500">{agent?.total_output_tokens?.toLocaleString() || 0}</span>
                                                </span>
                                            </div>
                                            <div 
                                                className="absolute inset-0 bg-gray-50 dark:bg-gray-800/50 p-4 rounded-xl border border-gray-200 dark:border-gray-800"
                                                style={{ backfaceVisibility: "hidden", transform: "rotateX(180deg)" }}
                                            >
                                                <span className="uppercase text-[10px] tracking-widest text-gray-500 font-bold block mb-1">Avg Tokens (In / Out) <span className="opacity-0 group-hover:opacity-100 float-right text-indigo-400 transition-opacity">&#8635;</span></span>
                                                <span className="text-2xl font-black text-blue-400 tabular-nums">
                                                    {agent?.total_runs ? Math.round(agent.total_input_tokens / agent.total_runs).toLocaleString() : 0}
                                                    <span className="text-gray-400 text-sm mx-2 font-normal">/</span>
                                                    <span className="text-emerald-500">{agent?.total_runs ? Math.round(agent.total_output_tokens / agent.total_runs).toLocaleString() : 0}</span>
                                                </span>
                                            </div>
                                        </div>
                                    </div>
                                </div>

                                <div className="mt-4">
                                    <h4 className="text-sm font-bold tracking-widest text-gray-500 uppercase mb-3">Tool Usage breakdown</h4>
                                    <div className="bg-white dark:bg-gray-950 border border-gray-200 dark:border-gray-800 rounded-lg overflow-hidden">
                                        <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-4 py-3 font-bold">Tool Name</th>
                                                    <th className="px-4 py-3 font-bold text-right">Calls</th>
                                                    <th className="px-4 py-3 font-bold text-center">Success</th>
                                                    <th className="px-4 py-3 font-bold text-center">Failed</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;
                                                        return (
                                                        <tr key={tool} className="hover:bg-gray-50 dark:hover:bg-gray-900/50 transition-colors text-sm">
                                                            <td className="px-4 py-3 text-indigo-600 dark:text-indigo-400 font-bold">{tool}</td>
                                                            <td className="px-4 py-3 text-right tabular-nums">{calls}</td>
                                                            <td className="px-4 py-3 text-center text-emerald-500 font-medium">{successes}</td>
                                                            <td className="px-4 py-3 text-center text-red-500 font-medium">{failures > 0 ? failures : '-'}</td>
                                                        </tr>
                                                        );
                                                    })
                                                ) : (
                                                    <tr>
                                                        <td colSpan="4" className="px-4 py-6 text-center text-gray-500 italic text-xs">No tool calls recorded yet</td>
                                                    </tr>
                                                )}
                                            </tbody>
                                        </table>
                                    </div>
                                </div>
                            </div>
                        )}
                    </div>
                </div>

            </div>
            
            {/* Modal Overlay Component */}
            {modalConfig && (
                <div className="fixed inset-0 z-50 flex items-center justify-center bg-gray-900/40 backdrop-blur-sm p-4">
                    <div className="bg-white dark:bg-gray-800 shadow-2xl rounded-2xl w-full max-w-sm overflow-hidden border border-gray-100 dark:border-gray-700 transform transition-all p-6 relative">
                        <div className={`absolute top-0 right-0 w-64 h-64 ${modalConfig.type === 'error' ? 'bg-red-500/5' : 'bg-emerald-500/5'} blur-[80px] rounded-full pointer-events-none -z-10`} />
                        <h3 className={`text-xl font-bold mb-2 ${modalConfig.type === 'error' ? 'text-red-500' : 'text-emerald-500'}`}>{modalConfig.title}</h3>
                        <p className="text-gray-600 dark:text-gray-300 text-sm mb-6 font-mono">{modalConfig.message}</p>
                        <div className="flex gap-3 justify-end mt-2">
                            <button onClick={() => setModalConfig(null)} className="px-4 py-2 text-sm font-medium text-gray-700 dark:text-gray-300 hover:bg-gray-100 dark:hover:bg-gray-700 rounded-lg transition-colors">
                                {modalConfig.confirmAction ? 'Cancel' : 'Close'}
                            </button>
                            {modalConfig.confirmAction && (
                                <button 
                                    onClick={() => {
                                        modalConfig.confirmAction();
                                        setModalConfig(null);
                                    }}
                                    className={`px-4 py-2 text-sm font-bold text-white rounded-lg shadow transition-colors ${modalConfig.type === 'error' ? 'bg-red-600 hover:bg-red-500' : 'bg-indigo-600 hover:bg-indigo-500'}`}
                                >
                                    {modalConfig.confirmText || 'Confirm'}
                                </button>
                            )}
                        </div>
                    </div>
                </div>
            )}
        </div>
    );
}