Skip to content

feat(usage): Cost & token analytics dashboard - #560

Open
juanludataanalyst wants to merge 1 commit into
gethouston:mainfrom
juanludataanalyst:feat/cost-analytics
Open

feat(usage): Cost & token analytics dashboard#560
juanludataanalyst wants to merge 1 commit into
gethouston:mainfrom
juanludataanalyst:feat/cost-analytics

Conversation

@juanludataanalyst

@juanludataanalyst juanludataanalyst commented Jun 21, 2026

Copy link
Copy Markdown

Summary

Adds a Usage tab to the sidebar that shows cost and token consumption across all agents: KPI cards, a filter by agent or model, per-agent and per-model breakdowns with cache hit rate, a daily trend chart, and an activity-by-hour chart.

Cost is shown as the exact amount when Claude's CLI reports it (API-key billing), and as an estimate from each provider's official published pricing when it does not (Claude on a subscription, and Codex, which never report a cost). For subscription users this is an API-equivalent estimate of value rather than a literal charge, and the view states this clearly.

Closes #558

How cost is determined

Source Behaviour
Claude with cost reported by the CLI (API billing) Exact
Claude without a reported cost (subscription) Estimated from official Anthropic pricing
Codex Estimated from official OpenAI pricing
Gemini Tokens only (no pricing row)

Pricing was taken from the official sources, verified June 2026:

  • Anthropic: platform.claude.com/docs/en/docs/about-claude/pricing
  • OpenAI: developers.openai.com/api/docs/pricing

What's included

Frontend

File Purpose
use-cost-analytics.ts Loads conversations via TanStack Query, batches history reads (concurrency 6), folds each into one session record.
cost-aggregate.ts Pure aggregation (by agent, model, day, hour) plus the cache-hit helper. Unit tested and reused for filter re-aggregation.
usage-format.ts Pure formatting helpers (cost, tokens, model label).
token-pricing.ts Pricing table and the cost estimator. Only models the picker can select are priced.
date-utils.ts Converts UTC timestamps to the user's local calendar date.
usage-view.tsx The view: KPI cards, filter dropdown, breakdowns, charts.
usage-chart.tsx SVG bar chart with hover tooltips. Guards against DOM mutation after unmount.

Engine (Rust)

session_runner.rs: the model is now recorded on each final-result row, so cost can be estimated for sessions whose CLI does not report one. Backwards compatible: rows written before this change deserialize with a null model and fall back to a token-only view.

Data loading

Loading goes through TanStack Query (the project standard), so results are cached, de-duplicated, and refetched on window focus, keyed by the set of agent paths. The top-level conversation list uses the toast-on-error wrapper; individual history reads are resilient so one unreadable conversation cannot blank the dashboard.

Correctness notes

  • Cache hit rate is computed over input (context) tokens, not over input plus output, so output volume does not dilute the figure.
  • The persisted token usage does not separate cache-write tokens, so the estimate prices them at the base input rate. This is a small under-count on cache-heavy turns; exact figures come from the CLI cost when available.

Tests

  • Frontend: pricing, date utilities, aggregation, cache-hit, and model formatting. Run with node --experimental-strip-types --test tests/*.test.ts.
  • Engine: model-persistence cases in cargo test -p houston-agents-conversations.
  • pnpm tsc --noEmit and pnpm check-locales pass. Strings are localized in en, es, and pt.

Test plan

  • Open the Usage tab; KPI cards load with real data
  • Filter by an individual agent; metrics update
  • Filter by model when more than one is present
  • Hover chart bars; tooltips appear without errors
  • Navigate away and back; no console crash
  • Run a new session; its cost appears after returning to the tab

UI

  • Built entirely on Houston's existing design tokens (bg-card, border-border, text-foreground, text-muted-foreground, and friends), with no hardcoded colors, so it matches the rest of the app.
  • Works in both light and dark themes. The HTML surfaces inherit the themed tokens automatically; the SVG chart reads its colors from the live computed styles and re-resolves them when the theme changes, so it stays correct on a light/dark switch.

Design notes

  • Subscription sessions show an API-equivalent cost estimate, labeled as such in the view, so the dashboard is useful for the common case where the CLI reports no cost. Exact figures are used whenever the CLI provides them.
  • Data loads through TanStack Query and refreshes on tab open, on window focus, and on session-completion events (the dashboard updates live when an agent finishes a run).

Screenshots

Captura5 Captura4 Captura3 Captura2 Captura1 Captura8 Captura7

@juanludataanalyst
juanludataanalyst force-pushed the feat/cost-analytics branch 5 times, most recently from bba568f to 5e6b7ac Compare June 22, 2026 05:24
Adds a Usage tab to the Houston sidebar with real-time cost and token
analytics across all agents. Closes gethouston#558.

### Frontend

- `use-cost-analytics.ts` — loads all conversations via listAllConversations,
  batches loadChatHistory (concurrency 6), aggregates per session. Errors
  surface as toasts, never silently swallowed.
- `cost-aggregate.ts` — pure aggregation logic (byAgent, byModel, byDay,
  byHour) extracted for testability and filter re-aggregation.
- `usage-format.ts` — pure formatting utils (fmtCost, fmtTokens, shortModel)
  in a .ts file so unit tests can import without JSX overhead.
- `token-pricing.ts` — OpenAI/Codex pricing table verified June 2026 at
  developers.openai.com/api/docs/pricing. Claude uses cost_usd from the CLI
  directly; Codex cost is computed from tokens + this table.
- `date-utils.ts` — isoToLocalDate (UTC ISO to local YYYY-MM-DD) and streak
  helpers; fixes day-boundary skew for users in non-UTC timezones.
- `usage-view.tsx` — KPI cards, filter dropdown (All / Agent / Model),
  by-model breakdown, by-agent with per-agent cache hit %, daily trend chart,
  activity-by-hour chart. All strings go through t().
- `usage-chart.tsx` — SVG bar chart with hover tooltips. Guards
  svg.isConnected before imperative DOM mutation to prevent the removeChild
  crash on unmount (React fiber tree conflict with imperative SVG children).
- `usage-parts.tsx` — JSX helper components (KpiCard, Section, DataBar).
- Locales en / es / pt — all keys added, check-locales passes.
- Sidebar: Usage nav item. workspace-shell: renders UsageView on usage mode.

### Engine (Rust)

- `session_runner.ts` — serialize_for_persist now accepts model: Option<&str>
  and injects it into the final_result JSON row so the frontend can compute
  cost for Codex sessions that do not report cost_usd themselves. Fully
  backwards-compatible: rows written before this change deserialize with
  model: null and fall back to token-only display.

### Tests

- 39 frontend unit tests: token-pricing, date-utils, cost-aggregate, shortModel
- 35 Rust tests: session_runner including 3 new model-persistence tests
- Verified visually: data loads correctly, filter works, charts render in dark
  mode without crashes on mount/unmount
@cravenceiling cravenceiling added the enhancement New feature or request label Jun 22, 2026
@cravenceiling cravenceiling self-assigned this Jun 22, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat(usage): Cost & token analytics dashboard

2 participants