AI Usage Dashboard
The AI Usage Dashboard (shipped in v0.8.0) is agent observability for your SaaS: it shows what the assistant costs, the tokens it burned, and the models and tools it used, broken down per user and per conversation. It is built for owners and admins watching the AI bill — without ever exposing message content.
What it does
The dashboard lives at /dashboard/ai-usage and renders, for a selected date range:
- KPI cards — total tokens, estimated cost, conversations, and tool calls.
- Usage-over-time chart — a stacked area chart split by call
kind:chat,embedding,summarization,title, andmemory. This is what older “usage tracking” missed: summarization, auto-titles, and memory extraction all spend credits, and now you can see them. - Model breakdown — cost and tokens grouped by model.
- Tool-usage breakdown — built by unnesting each row’s
tools_used, so you see which agent tools actually ran. - Per-user table and a per-conversation table — metadata only: titles, model, tokens, cost, and tool count. Message content is never read or shown.
A limit-warning banner appears as the org nears its monthly cap. The dashboard never invents a cost figure — see How to configure or enable.
How to use it
- Sign in as an owner or admin and open
/dashboard/ai-usagefrom the sidebar or command palette. (Members hitting the URL get a 404 — see below.) - Pick a range with the selector:
7d,30d,90d, ormtd(month-to-date). The choice is stored in the URL, so a view is shareable and bookmarkable. - Read the KPI cards, then drill into the model and tool breakdowns to find the expensive paths.
- Export the rows as CSV or JSON for the range. Exports are capped at 10,000 rows, are formula-injection-safe (leading
=,+,-,@are neutralized), and write an audit-log entry.
The tables are deliberately metadata-only: you see that a conversation cost $0.04 and ran the searchKnowledge tool — never what was said.
How to configure or enable
Access is gated by a new ai_usage:view permission, granted to owner and admin roles. Members are not granted it and receive a 404 — the route is hidden, not just disabled.
The migration: v0.8.0 ships one additive migration — an AIUsage.kind nullable column plus an index, with a deterministic backfill of existing rows. After pulling, run:
make db-migrate
# or: prisma migrate deploy
There are no new environment variables and no new infrastructure.
Cost precedence. A per-model price map in src/config/ai-models.ts drives cost display in this strict order:
| Precedence | Source | How it shows |
|---|---|---|
| 1. Recorded | Real provider cost stored on the row | Summed as-is |
| 2. Estimate | List price from the model’s config | Shown, labeled as an estimate |
| 3. Unpriced | No price available | Disclosed as “unpriced” — never guessed |
Real cost is captured for chat turns through OpenRouter’s usage accounting (usage: { include: true } → providerMetadata.openrouter.usage.cost), which is enabled automatically — no setup needed.
Key files
| File | Responsibility |
|---|---|
src/services/ai-usage-service.ts | Canonical AIUsageService.recordUsage — every LLM call routes through this one never-throws path, tagged with a kind |
src/config/ai-models.ts | Sourced per-model pricing map (recorded → estimate → unpriced) |
src/lib/ai-cost-utils | Cost math: summing recorded cost, applying list-price estimates |
| Dashboard service + page | Aggregation queries (KPIs, time-series, unnested tool breakdown) and the /dashboard/ai-usage UI |
Memory paths (extraction, consolidation, recall) record token counts only — never content — so the memory series reflects spend without leaking facts. See AI Memory.
How to extend
- Track a new call kind. Add the value to the
kindset and callAIUsageService.recordUsagewith it wherever the new LLM call happens. Because all recording flows through one path, the new kind appears in the chart and breakdowns automatically. - Price a new model. Add an entry to the price map in
src/config/ai-models.ts. Until then the model’s rows surface as “unpriced” rather than a fabricated number. See LLM Providers for adding the model itself. - Add a metric or column. Extend the dashboard service’s aggregation query. Keep the per-user and per-conversation tables metadata-only — titles and tool names are safe to surface; message content is not.
For how the assistant’s tools, RAG, and memory feed these numbers, see the Knowledge Base doc.
Ready to build with VibeReady?
Get the full AI-native SaaS foundation with production infrastructure, AI development framework, and all integrations.
Get VibeReady — From $149