TokenMeter

AG-UI React Live token usage and running cost with optional budget cap. Green → amber → red warning states, locked state at 100%, smooth count-up animation. Zero deps beyond React.

idle
① Compact mode — idle (all models)
② Expanded mode — mid-conversation (light + dark)
Light
Dark
③ Approaching budget — amber warning (75%)
Light
Dark
④ Over budget — red locked (streaming increments budget)
Light
Dark

Copy-paste snippet

// Controlled mode — pass usage directly
import { TokenMeter } from './TokenMeter.jsx';

// Compact pill (default)
return <TokenMeter
  model="claude-sonnet-4"
  usage={{ inputTokens: 12_450, outputTokens: 3_872 }}
  budgetUsd={1.00}
  mode="compact"
  theme="light"
  onBudgetExceeded={() => console.log('budget hit!')}
/>;

// Expanded card
return <TokenMeter
  model="gpt-4o"
  usage={{ inputTokens: 24_200, outputTokens: 7_150 }}
  budgetUsd={5.00}
  mode="expanded"
  theme="dark"
/>;

// AG-UI stream mode — auto-updates from event bus
import { TokenMeterContainer } from './TokenMeter.jsx';

const bus = new EventTarget();

// Your agent runtime dispatches usage updates on each chunk:
bus.dispatchEvent(new CustomEvent('TEXT_MESSAGE_CHUNK', {
  detail: { delta: '...', usage: { inputTokens: 12450, outputTokens: 3872 } }
}));

return <TokenMeterContainer
  eventSource={bus}
  model="claude-sonnet-4"
  budgetUsd={1.00}
  mode="expanded"
  theme="light"
  onBudgetExceeded={() => pauseAgent()}
/>;

// Override or extend the pricing table:
import { MODEL_PRICING } from './TokenMeter.jsx';
MODEL_PRICING['my-fine-tune'] = {
  inputPer1M: 1.00, outputPer1M: 2.00,
  label: 'My Fine-tune', provider: 'custom', color: '#6366f1'
};