ProgressTracker

AG-UI React Multi-step agent progress with live duration timers, ETA estimates, failure states, and skip support. Compact pill row or expanded vertical timeline. Progress bars that don't lie.

idle
① Live simulated agent run
② Side-by-side themes (mid-run state)
Light
Dark
③ Failure + skip states
With failure
With skips + ETA

Copy-paste snippet

// Controlled mode — pass steps array directly
import { ProgressTracker } from './ProgressTracker.jsx';

const steps = [
  { id: 'fetch',    label: 'Fetch data',       status: 'done',    startedAt: t0, completedAt: t0+1200 },
  { id: 'parse',    label: 'Parse results',    status: 'running',  startedAt: Date.now() },
  { id: 'validate', label: 'Validate schema', status: 'pending' },
  { id: 'save',     label: 'Save to DB',       status: 'pending' },
];

// Expanded vertical timeline (default)
return <ProgressTracker
  steps={steps}
  variant="expanded"
  theme="light"
  showETA={true}
/>;

// Compact horizontal pill row
return <ProgressTracker
  steps={steps}
  variant="compact"
  theme="dark"
/>;

// AG-UI stream mode — auto-wired to event bus
import { ProgressTrackerContainer } from './ProgressTracker.jsx';

const bus = new EventTarget();

// Your agent runtime dispatches these events:
bus.dispatchEvent(new CustomEvent('STEP_STARTED',   { detail: { stepId: 'fetch', label: 'Fetch data' } }));
bus.dispatchEvent(new CustomEvent('PROGRESS_UPDATE', { detail: { stepId: 'fetch', description: 'Retrieved 240 records' } }));
bus.dispatchEvent(new CustomEvent('STEP_COMPLETED',  { detail: { stepId: 'fetch' } }));
bus.dispatchEvent(new CustomEvent('STEP_FAILED',    { detail: { stepId: 'save',  error: 'Connection timeout' } }));
bus.dispatchEvent(new CustomEvent('STEP_SKIPPED',   { detail: { stepId: 'cache' } }));

return <ProgressTrackerContainer
  eventSource={bus}
  initialSteps={[
    { id: 'fetch',  label: 'Fetch data',    status: 'pending' },
    { id: 'parse',  label: 'Parse results', status: 'pending' },
    { id: 'save',   label: 'Save to DB',    status: 'pending' },
    { id: 'cache',  label: 'Warm cache',    status: 'pending' },
  ]}
  variant="expanded"
  theme="light"
  showETA={true}
/>;

// Step status values:
// 'pending'  → gray dot (not started)
// 'running'  → animated spinner + live elapsed timer
// 'done'     → green check + completion duration
// 'failed'   → red × + inline error message
// 'skipped'  → dashed circle + strikethrough label