/** * Agent Timeline — visual execution timeline built from SSE events */ let containerEl; let steps = []; export function initTimeline() { // The timeline renders inside the inspector; this module manages the data containerEl = null; steps = []; } export function addTimelineStep({ step, totalSteps, agent, description, status }) { steps.push({ step, totalSteps, agent, description, status: status || 'executing', tools: [], }); renderTimeline(); } export function updateTimelineStep(agent, { tool, status }) { // Find the last step for this agent for (let i = steps.length - 1; i >= 0; i--) { if (steps[i].agent === agent) { if (tool) { steps[i].tools.push({ name: tool, status: status || 'completed' }); } break; } } renderTimeline(); } export function clearTimeline() { steps = []; renderTimeline(); } function renderTimeline() { // Find or create the timeline container in the inspector const inspector = document.getElementById('inspector'); if (!inspector) return; // Remove existing timeline section let existing = document.getElementById('live-timeline-section'); if (existing) existing.remove(); if (steps.length === 0) return; const section = document.createElement('div'); section.className = 'inspector-section'; section.id = 'live-timeline-section'; let html = '
Live Timeline
'; html += '
'; for (const s of steps) { const stepClass = s.status === 'executing' ? 'active' : s.status === 'completed' ? 'completed' : s.status === 'failed' ? 'failed' : ''; html += `
${s.agent} Step ${s.step}/${s.totalSteps}
${escapeHtml(s.description)}
`; if (s.tools.length > 0) { html += '
'; for (const t of s.tools) { html += `${escapeHtml(t.name)}`; } html += '
'; } html += '
'; } html += '
'; section.innerHTML = html; // Insert at the top of inspector (after session info if present) const firstSection = inspector.querySelector('.inspector-section'); if (firstSection && firstSection.nextSibling) { inspector.insertBefore(section, firstSection.nextSibling); } else { inspector.appendChild(section); } } function escapeHtml(str) { if (!str) return ''; return str.replace(/&/g, '&').replace(//g, '>'); }