From a6cbbecf56e550c2e0691f44dbde879f13eb00e5 Mon Sep 17 00:00:00 2001
From: Davis <120677670+davisbuilds@users.noreply.github.com>
Date: Tue, 4 Aug 2026 08:41:33 -0400
Subject: [PATCH 1/4] feat(pricing): add Claude Opus 5 rates
---
src/pricing/data/claude.json | 10 +++++++++-
tests/pricing.test.ts | 20 ++++++++++++++++++++
2 files changed, 29 insertions(+), 1 deletion(-)
diff --git a/src/pricing/data/claude.json b/src/pricing/data/claude.json
index 10e61f3..dd83cf7 100644
--- a/src/pricing/data/claude.json
+++ b/src/pricing/data/claude.json
@@ -1,6 +1,6 @@
{
"provider": "anthropic",
- "lastUpdated": "2026-07-08T00:00:00Z",
+ "lastUpdated": "2026-08-04T00:00:00Z",
"models": {
"claude-fable-5": {
"aliases": [],
@@ -10,6 +10,14 @@
"cacheWriteCostPerMTok": 12.5,
"deprecated": false
},
+ "claude-opus-5": {
+ "aliases": [],
+ "inputCostPerMTok": 5,
+ "outputCostPerMTok": 25,
+ "cacheReadCostPerMTok": 0.5,
+ "cacheWriteCostPerMTok": 6.25,
+ "deprecated": false
+ },
"claude-opus-4-8": {
"aliases": [],
"inputCostPerMTok": 5,
diff --git a/tests/pricing.test.ts b/tests/pricing.test.ts
index ffd67cb..65c297f 100644
--- a/tests/pricing.test.ts
+++ b/tests/pricing.test.ts
@@ -54,6 +54,17 @@ describe('PricingRegistry', () => {
assert.equal(pricing.deprecated, false);
});
+ test('finds Claude Opus 5 and applies its published base and cache rates', () => {
+ const pricing = registry.lookup('claude-opus-5');
+ assert.ok(pricing);
+ assert.equal(pricing.provider, 'anthropic');
+ assert.equal(pricing.inputCostPerToken, 5 / 1_000_000);
+ assert.equal(pricing.outputCostPerToken, 25 / 1_000_000);
+ assert.equal(pricing.cacheReadCostPerToken, 0.5 / 1_000_000);
+ assert.equal(pricing.cacheWriteCostPerToken, 6.25 / 1_000_000);
+ assert.equal(pricing.deprecated, false);
+ });
+
test('finds Claude Fable 5 with the published per-MTok rates', () => {
const pricing = registry.lookup('claude-fable-5');
assert.ok(pricing);
@@ -224,6 +235,15 @@ describe('PricingRegistry', () => {
assert.equal(c.pricing_status, 'known');
});
+ test('classifies Claude Opus 5 as a known anthropic/opus tier', () => {
+ const c = classifyModel('claude-opus-5');
+ assert.equal(c.canonical_model, 'claude-opus-5');
+ assert.equal(c.provider, 'anthropic');
+ assert.equal(c.family, 'claude');
+ assert.equal(c.tier, 'opus');
+ assert.equal(c.pricing_status, 'known');
+ });
+
test('classifies the Antigravity flash id/display via gemini-3.5-flash', () => {
for (const id of ['gemini-3-flash-a', 'Gemini 3.5 Flash (Medium)']) {
const c = classifyModel(id);
From aa5cbb81c2cd30a853aa81f4a9557ee1379cbcf3 Mon Sep 17 00:00:00 2001
From: Davis <120677670+davisbuilds@users.noreply.github.com>
Date: Tue, 4 Aug 2026 09:09:02 -0400
Subject: [PATCH 2/4] docs(backlog): capture hidden unpriced cache usage
---
docs/project/BACKLOG.md | 16 ++++++++++++++++
1 file changed, 16 insertions(+)
diff --git a/docs/project/BACKLOG.md b/docs/project/BACKLOG.md
index 3af0f95..7eb6fea 100644
--- a/docs/project/BACKLOG.md
+++ b/docs/project/BACKLOG.md
@@ -145,6 +145,22 @@ These are the deferred follow-ups surfaced during and after the build.
### Pricing
+#### Top Models hides cache-heavy unknown-priced usage in its default view
+- **What**: Top Models defaults to Cost and renders only input + output tokens under
+ its Tokens toggle; cache-read and cache-write tokens are omitted. An unknown-priced
+ model with `cost_usd = 0` consequently appears in neither the Cost chart nor its
+ `Other` segment, even when its cache volume dominates model usage.
+- **Why it matters**: on the live database, `claude-opus-5` had 4,416 events across
+ 8 sessions from 2026-07-25 through 2026-08-04: 4,185,757 input + output tokens,
+ 1,033,353,152 cache tokens, and no stored cost because the runtime predated its
+ pricing record. It ranked second by the chart's current Tokens definition but was
+ entirely absent from the default Cost chart, masking both model adoption and
+ unpriced spend.
+- **Next**: decide whether the chart's Tokens metric should include cache traffic;
+ independently surface nonzero unknown-priced usage (for example, a visible
+ unpriced-cost state or chart annotation) so $0 does not mean no activity. Add a
+ live-data regression at the usage-overview/chart seam before changing the UI.
+
#### Processing-service tier is not captured with usage events
- **What**: cost estimation uses standard synchronous API rates. Event rows do not
record OpenAI Standard, Priority, Batch, or other processing-service tiers, so
From 5932e262a0a36b2eabe2a2b2c4a73dcef6400106 Mon Sep 17 00:00:00 2001
From: Davis <120677670+davisbuilds@users.noreply.github.com>
Date: Tue, 4 Aug 2026 09:43:25 -0400
Subject: [PATCH 3/4] feat(usage): surface unknown-priced model tokens
---
docs/project/BACKLOG.md | 16 -----
docs/project/ROADMAP.md | 6 ++
docs/system/FEATURES.md | 1 +
.../usage/UsageBreakdownTable.svelte | 7 +-
.../src/lib/components/usage/UsagePage.svelte | 6 +-
.../components/usage/UsageTopModels.svelte | 4 +-
.../usage/UsageUnpricedWarning.svelte | 25 +++++++
.../src/lib/components/usage/model-colors.ts | 8 ++-
.../lib/components/usage/unpriced-usage.ts | 35 ++++++++++
tests/unpriced-usage.test.ts | 66 +++++++++++++++++++
tests/usage-model-colors.test.ts | 16 +++++
11 files changed, 167 insertions(+), 23 deletions(-)
create mode 100644 frontend/src/lib/components/usage/UsageUnpricedWarning.svelte
create mode 100644 frontend/src/lib/components/usage/unpriced-usage.ts
create mode 100644 tests/unpriced-usage.test.ts
diff --git a/docs/project/BACKLOG.md b/docs/project/BACKLOG.md
index 7eb6fea..3af0f95 100644
--- a/docs/project/BACKLOG.md
+++ b/docs/project/BACKLOG.md
@@ -145,22 +145,6 @@ These are the deferred follow-ups surfaced during and after the build.
### Pricing
-#### Top Models hides cache-heavy unknown-priced usage in its default view
-- **What**: Top Models defaults to Cost and renders only input + output tokens under
- its Tokens toggle; cache-read and cache-write tokens are omitted. An unknown-priced
- model with `cost_usd = 0` consequently appears in neither the Cost chart nor its
- `Other` segment, even when its cache volume dominates model usage.
-- **Why it matters**: on the live database, `claude-opus-5` had 4,416 events across
- 8 sessions from 2026-07-25 through 2026-08-04: 4,185,757 input + output tokens,
- 1,033,353,152 cache tokens, and no stored cost because the runtime predated its
- pricing record. It ranked second by the chart's current Tokens definition but was
- entirely absent from the default Cost chart, masking both model adoption and
- unpriced spend.
-- **Next**: decide whether the chart's Tokens metric should include cache traffic;
- independently surface nonzero unknown-priced usage (for example, a visible
- unpriced-cost state or chart annotation) so $0 does not mean no activity. Add a
- live-data regression at the usage-overview/chart seam before changing the UI.
-
#### Processing-service tier is not captured with usage events
- **What**: cost estimation uses standard synchronous API rates. Event rows do not
record OpenAI Standard, Priority, Batch, or other processing-service tiers, so
diff --git a/docs/project/ROADMAP.md b/docs/project/ROADMAP.md
index 20256d2..c007a7b 100644
--- a/docs/project/ROADMAP.md
+++ b/docs/project/ROADMAP.md
@@ -6,6 +6,12 @@ Directional roadmap for AgentMonitor. This is a planning snapshot, not a release
Concise record of shipped work that has left `BACKLOG.md`. Newest first.
+- Cache-inclusive unknown-pricing visibility (2026-08-04) — *What:* Top Models now
+ offers an All tokens view that includes input, output, cache-read, and cache-write
+ traffic; model tables use the same total. The Usage page persistently identifies
+ unknown-priced models, their cache-inclusive observed tokens, and their event count
+ without fabricating a cost. *Why:* a cache-heavy new model can otherwise have $0
+ stored cost before its pricing record arrives and vanish from the default Cost view.
- Configurable Claude history root (2026-07-29) — *What:*
`AGENTMONITOR_CLAUDE_DIR` now supplies one Claude data root to startup sync,
live and periodic watcher discovery, automatic and historical event import,
diff --git a/docs/system/FEATURES.md b/docs/system/FEATURES.md
index f1eb773..eba9543 100644
--- a/docs/system/FEATURES.md
+++ b/docs/system/FEATURES.md
@@ -143,6 +143,7 @@ Product-surface reference for AgentMonitor.
- Summary totals, daily series, project/model/tier/agent attribution, and top-session views all use cost/token-bearing event rows as their source of truth.
- Codex aggregate usage reconciles overlapping telemetry sources: when a Codex session has imported JSONL usage and OTEL usage rows, imported usage is treated as authoritative and overlapping OTEL usage rows are ignored for rollups. Raw events remain queryable in monitor/session history.
- Usage models are classified at query time into canonical model, provider, family, tier, lifecycle, and pricing-status fields. Unknown and deprecated models remain visible in responses.
+- The Usage page’s Top Models **All tokens** view includes input, output, cache-read, and cache-write traffic. When a model’s pricing status is unknown, a persistent warning names the affected models and their observed token volume while keeping cost totals explicitly non-estimated.
- Usage endpoints accept optional `model`, `provider`, and `tier` filters in addition to date, project, and agent filters. Classification filters are applied consistently before summary, daily, attribution, tier, agent, and top-session panels aggregate.
- Usage summary includes `prior_total_cost_usd` and `cost_delta_pct` for the immediately preceding same-length date range when a valid current range is supplied.
- Usage budget reports live at `/api/v2/usage/budgets`. They read an optional local JSON config, reuse usage filters to compute current spend, and return alert states without blocking or enforcing agent activity.
diff --git a/frontend/src/lib/components/usage/UsageBreakdownTable.svelte b/frontend/src/lib/components/usage/UsageBreakdownTable.svelte
index b10c7a9..b75d3bc 100644
--- a/frontend/src/lib/components/usage/UsageBreakdownTable.svelte
+++ b/frontend/src/lib/components/usage/UsageBreakdownTable.svelte
@@ -36,6 +36,11 @@
return base;
}
+ function tokenTotal(row: UsageProjectBreakdown | UsageModelBreakdown | UsageTierBreakdown | UsageAgentBreakdown): number {
+ const base = row.input_tokens + row.output_tokens;
+ return kind === 'model' ? base + row.cache_read_tokens + row.cache_write_tokens : base;
+ }
+
function handleSelect(row: UsageProjectBreakdown | UsageModelBreakdown | UsageTierBreakdown | UsageAgentBreakdown): void {
if (kind === 'project' && 'project' in row) {
void usage.setProject(row.project === 'unknown' ? '' : row.project);
@@ -90,7 +95,7 @@
- Model mix by day. Click a day to drill the page into it.
+ Model mix by day. All tokens include cache reads and writes. Click a day to drill the page into it.