Stream Inspector

A model’s token stream event by event, with the timing between them. An average tokens-per-second hides both numbers that matter — time to first token, and the stalls after it.

src/components/ui/stream-inspector.tsx

About

From the component's own source, where it was written.

A model's token stream, event by event, with the timing between them.

The devtool for the two numbers that decide whether a stream feels fast: **time to first token**, and the gaps after it. An average tokens-per-second hides both — a stream that stalls for two seconds mid-sentence and then catches up scores identically to one that never stalled, and only one of them is unpleasant to read.

So gaps above stallMs are marked inline, in the sequence, where they can be traced to the event that caused them — usually a tool call the stream paused for.

Text deltas collapse into runs. A stream is thousands of two-character events; rendering each as a row makes the tool-call boundaries impossible to find, which is the only reason to open a stream inspector at all.

Install

npx astralyx-ui add stream-inspector

Usage

import { StreamInspector } from '@/components/ui/stream-inspector'

<StreamInspector events={events} stallMs={400} />

Composer

Change the props and the source below follows.

Stream

412ms to first token
  • 0msstartrequest sent
  • stalled 412ms
  • 412msthinkingThe customer is asking about a refund…
  • stalled 478ms
  • 890msYour refund of £340 is (6 deltas)
  • 1.04stoolget_invoice({ id: "inv_881" })
  • stalled 2.08s
  • 3.12s pending approval. (3 deltas)
  • 3.24sstopend_turn
Props
tsx
<StreamInspector events={events} stallMs={400} />

Examples

A stream that paused for a tool call

API

Generated from the source, so it cannot fall behind the code. One table per exported component, then hooks, functions and types.

StreamInspector

Extends Omit<ComponentProps<'div'>, 'children'>.

PropTypeDefaultDescription
eventsStreamEvent[]required{ id, at, kind, content? } where kind is 'start' | 'text' | 'tool' | 'thinking' | 'stop' | 'error'. at is ms from the start of the request.
stallMsnumber400A gap longer than this is marked inline, in the sequence, where it can be traced to the event that caused it — usually a tool call the stream paused for.
collapseTextbooleantrueA stream is thousands of two-character deltas; a row each makes the tool-call boundaries impossible to find, which is the only reason to open this.
formatDuration(ms: number) => stringdefaultDuration—
emptyLabelstring'No events captured.'—
ttftLabelstring'to first token'—
stallLabelstring'stalled'—
labelstring'Stream'—
tocomputed—From the first text or thinking event, shown in the header.

Types

StreamEvent

A model's token stream, event by event, with the timing between them.

FieldTypeDescription
idstring—
atnumberMilliseconds from the start of the request.
kind'start' | 'text' | 'tool' | 'thinking' | 'stop' | 'error'—
content?stringText delta, tool name, or an error message.