Context meter A budget split between the document, the standing instructions and the conversation, with a threshold at which the meter appears at all. The line in the transcript marks where earlier turns stopped being visible to the model. npx shadcn@latest add button Tokens this needs: --card, --muted, --muted-foreground, --border, --chart-1, --scale-seq-1, --scale-seq-2, --scale-seq-3 The status, chart, scale, state and direction names are an extension, not a rename. shadcn has --destructive and five --chart-* and nothing else in this territory. ──────────────────────────────────────────────────────────────────────── // ContextMeter.tsx ──────────────────────────────────────────────────────────────────────── import { Button } from "@/components/ui/button"; /** * What the product does when the window is full. The set is closed because * each one is a different experience for the viewer, and the boundary marker * has to say which happened. */ export type Overflow = "truncate" | "summarise" | "refuse"; /** Everything that draws on the window. Order is display order. */ export type Segment = { key: string; /** What the viewer sees under the bar: a file name, "rules", "turns". */ label: string; tokens: number; }; const SEGMENT_COLOR = ["bg-scale-seq-3", "bg-scale-seq-2", "bg-scale-seq-1", "bg-scale-seq-4"]; /** * A stacked budget bar. It stays out of the way until `showAt` of the window is * spent, because a meter that never moves off empty teaches people to ignore * it, and once visible it offers the one action that still helps. */ export function ContextMeter({ budget, segments, showAt = 2 / 3, onStartFresh, }: { /** The window, in tokens, for the model in use. */ budget: number; segments: Segment[]; /** Fraction of the window spent before the meter appears at all. */ showAt?: number; /** Continue in a new conversation carrying a summary. */ onStartFresh: () => void; }) { const used = segments.reduce((sum, s) => sum + s.tokens, 0); const pct = (n: number) => `${(100 * n) / budget}%`; if (used / budget < showAt) return null; // Percent, never tokens: a token count is precise and meaningless to almost everyone. const usedPct = Math.round((100 * used) / budget); return (
{BOUNDARY[overflow]}
{t.who}: {t.text}