Context Meter

How much of the model's context window a conversation has used. A 16px ring and a percentage on the toolbar; hover or click it and it opens onto what the total is made of and what it has cost.

Installation#

# One-time setup (tokens + lib helpers)npx koalaui-cli@latest init# Add this component (its dependencies come along)npx koalaui-cli@latest add context-meter

Usage#

usage.tsxTSX
import {  ContextMeter,  ContextMeterTrigger,  ContextMeterContent,  ContextMeterRows,  ContextMeterRow,  ContextMeterFooter,} from "@/components/ui/context-meter"export function Usage({ usage, model }) {  return (    <ContextMeter used={usage.totalTokens} max={model.contextWindow}>      <ContextMeterTrigger />      <ContextMeterContent>        <ContextMeterRows>          <ContextMeterRow label="Input" tokens={usage.inputTokens} />          <ContextMeterRow label="Output" tokens={usage.outputTokens} />        </ContextMeterRows>      </ContextMeterContent>    </ContextMeter>  )}

Anatomy#

import {  ContextMeter,  ContextMeterTrigger,  ContextMeterContent,  ContextMeterRows,  ContextMeterRow,  ContextMeterFooter,} from "@/components/ui/context-meter"<ContextMeter>  <ContextMeterTrigger />  <ContextMeterContent>    <ContextMeterRows>      <ContextMeterRow />    </ContextMeterRows>    <ContextMeterFooter />  </ContextMeterContent></ContextMeter>

Levels#

Three levels by the fraction of the window used: normal, then warning from warnAt (70%), then critical from criticalAt (90%). The level tints the ring and the bar and nothing else: a window filling up is information, not an error, until it is nearly full. Drag the slider to watch the ring sweep.

Ring only#

showValue={false} drops the percentage for a crowded toolbar. The trigger keeps the whole reading as its accessible name, and the number is one hover away.

The footer is a muted well, so it can carry the way out of a full window as well as the cost: a ghost button to compact or summarise the conversation.

In a composer#

On PromptInput's toolbar it sits beside the send button, with the Model Selector at the other end. Pass the selected model's window as max and the reading re-scales when you switch: the same chat is 42% of a 200K window and 8% of a 1M one.

API reference#

ContextMeter

The root: the reading every part shares, and a Popover that opens on hover and on click.

PropTypeDefaultDescription
used*number-Tokens the conversation uses now.
max*number-The model's context window, in tokens.
warnAtnumber0.7Fraction from which the reading turns warning.
criticalAtnumber0.9Fraction from which the reading turns critical.
format(tokens: number) => stringcompact, en-USHow a token count is written (84.2K). Fixed locale by default, so server and client agree.
openboolean-The panel's open state, controlled.
defaultOpenboolean-The panel's initial open state.
onOpenChange(open: boolean) => void-Called when the panel opens or closes.

ContextMeterTrigger

A ghost Button with the ring and the percentage. Its accessible name is the whole reading. Forwards Button props.

PropTypeDefaultDescription
showValuebooleantrueShow the percentage beside the ring.
sizeButtonProps["size"]"sm"Match the bar it sits on.
Data attributeDescription
data-levelnormal, warning or critical.

ContextMeterContent

The breakdown panel: the total over a Meter bar in the level's tone, then your rows. Forwards PopoverContent props.

PropTypeDefaultDescription
titleReact.ReactNode"Context window"The panel's heading.

ContextMeterRows

The rows under the bar, a <dl>.

ContextMeterRow

One part of the total, a <dt>/<dd> pair.

PropTypeDefaultDescription
label*React.ReactNode-What the part is: Input, Cached.
tokensnumber-Formatted the way the root formats.
valueReact.ReactNode-Anything else in the value column (a price).
swatchstring-A text colour class for a leading dot, to key the row to a chart.

ContextMeterFooter

The muted well that closes the panel: the cost, or an action. Forwards native <div> props.

FAQ#

The reading matters on a phone too, and a HoverCard never opens on touch. The Popover opens on hover for a pointer and on a tap or Enter for everyone else, so the breakdown is reachable however you get there.