| 28 | |
| 29 | /** Format duration between two ISO timestamps into a human-readable string */ |
| 30 | const formatDuration = (startedAt?: string, completedAt?: string): string | null => { |
| 31 | if (!startedAt || !completedAt) return null; |
| 32 | const ms = new Date(completedAt).getTime() - new Date(startedAt).getTime(); |
| 33 | if (ms < 0) return null; |
| 34 | if (ms < 1000) return `${ms}ms`; |
| 35 | const secs = ms / 1000; |
| 36 | if (secs < 60) return `${secs.toFixed(1)}s`; |
| 37 | const mins = Math.floor(secs / 60); |
| 38 | const remainSecs = Math.round(secs % 60); |
| 39 | return `${mins}m ${remainSecs}s`; |
| 40 | }; |
| 41 | |
| 42 | export function AgentRunCard({ run }: AgentRunCardProps) { |
| 43 | const normalizedBlocks = run.thinkingBlocks |