@@ -257,27 +257,43 @@ function SpanBody({
257257 const isAiGeneration = span . entity ?. type === "ai-generation" ;
258258
259259 return (
260- < div className = "grid h-full max-h-full grid-rows-[2.5rem_1fr] overflow-hidden bg-background-bright" >
261- < div className = "flex items-center justify-between gap-2 overflow-x-hidden border-b border-grid-bright px-3 pr-2" >
262- < div className = "flex items-center gap-1 overflow-x-hidden" >
263- < RunIcon
264- name = { span . style ?. icon }
265- spanName = { span . message }
266- className = "size-5 min-h-5 min-w-5"
267- />
268- < Header2 className = { cn ( "overflow-x-hidden" ) } >
269- < SpanTitle { ...span } size = "large" hideAccessory />
270- </ Header2 >
260+ < div className = { cn (
261+ "grid h-full max-h-full overflow-hidden bg-background-bright" ,
262+ isAiGeneration ? "grid-rows-[auto_1fr]" : "grid-rows-[2.5rem_1fr]"
263+ ) } >
264+ < div className = "border-b border-grid-bright px-3 pr-2" >
265+ < div className = "flex h-10 items-center justify-between gap-2 overflow-x-hidden" >
266+ < div className = "flex items-center gap-1 overflow-x-hidden" >
267+ < RunIcon
268+ name = { span . style ?. icon }
269+ spanName = { span . message }
270+ className = "size-5 min-h-5 min-w-5"
271+ />
272+ < Header2 className = { cn ( "overflow-x-hidden" ) } >
273+ < SpanTitle { ...span } size = "large" hideAccessory />
274+ </ Header2 >
275+ </ div >
276+ { runParam && closePanel && (
277+ < Button
278+ onClick = { closePanel }
279+ variant = "minimal/small"
280+ TrailingIcon = { ExitIcon }
281+ shortcut = { { key : "esc" } }
282+ shortcutPosition = "before-trailing-icon"
283+ className = "pl-1"
284+ />
285+ ) }
271286 </ div >
272- { runParam && closePanel && (
273- < Button
274- onClick = { closePanel }
275- variant = "minimal/small"
276- TrailingIcon = { ExitIcon }
277- shortcut = { { key : "esc" } }
278- shortcutPosition = "before-trailing-icon"
279- className = "pl-1"
280- />
287+ { isAiGeneration && (
288+ < div className = "flex items-center gap-3 pb-1.5 pl-6 text-xs text-text-dimmed" >
289+ < DateTime date = { span . startTime } includeSeconds />
290+ { span . duration != null && (
291+ < >
292+ < span className = "text-charcoal-600" > /</ span >
293+ < span className = "text-text-bright" > { formatSpanDuration ( span . duration ) } </ span >
294+ </ >
295+ ) }
296+ </ div >
281297 ) }
282298 </ div >
283299 { isAiGeneration ? (
@@ -291,6 +307,15 @@ function SpanBody({
291307 ) ;
292308}
293309
310+ function formatSpanDuration ( nanoseconds : number ) : string {
311+ const ms = nanoseconds / 1_000_000 ;
312+ if ( ms < 1000 ) return `${ Math . round ( ms ) } ms` ;
313+ if ( ms < 60_000 ) return `${ ( ms / 1000 ) . toFixed ( 1 ) } s` ;
314+ const mins = Math . floor ( ms / 60_000 ) ;
315+ const secs = ( ( ms % 60_000 ) / 1000 ) . toFixed ( 0 ) ;
316+ return `${ mins } m ${ secs } s` ;
317+ }
318+
294319function applySpanOverrides ( span : Span , spanOverrides ?: SpanOverride ) : Span {
295320 if ( ! spanOverrides ) {
296321 return span ;
0 commit comments