Skip to content

fix(admin): use model history for cost data - #1816

Merged
smakosh merged 2 commits into
mainfrom
fix/admin-models-cost-tracking
Mar 11, 2026
Merged

smakosh merged 2 commits into
mainfrom
fix/admin-models-cost-tracking

Conversation

@smakosh

@smakosh smakosh commented Mar 11, 2026 •

Copy link
Copy Markdown
Member

Summary

  • Add totalCost column to modelHistory and modelProviderMappingHistory tables
  • Aggregate log.cost in the stats-calculator worker when computing minute-level history
  • Switch admin /models list endpoint to query modelHistory instead of projectHourlyModelStats for date-range stats
  • Switch admin /models/{modelId} detail endpoint to query modelProviderMappingHistory instead of projectHourlyModelStats for per-provider stats

The admin models page was broken because it relied on projectHourlyModelStats (a per-project hourly table) which doesn't properly aggregate costs at the model level. The modelHistory and modelProviderMappingHistory tables are the correct source for model-level stats but were missing cost tracking.

Test plan

  • Run pnpm build to verify compilation
  • Run pnpm run setup to push new schema columns
  • Verify admin models page loads with date range filter and shows cost data
  • Verify admin model detail page shows per-provider stats

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Added totalCost metrics to model and model-provider histories and exposed totals in stats and cost endpoints.
  • Refactor

    • API response fields renamed from usedModel/usedProvider to modelId/providerId.
    • Aggregations now include higher-resolution minute-level timestamps and updated history sources for more granular reporting.

Add totalCost column to modelHistory and
modelProviderMappingHistory tables, aggregate
log.cost in the stats-calculator worker, and
switch admin /models endpoints to query these
tables instead of projectHourlyModelStats.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Mar 11, 2026 •

Copy link
Copy Markdown
Contributor

Walkthrough

Replaces hourly aggregations with minute-level history sources and renames response keys from usedModel/usedProvider to modelId/providerId across admin routes; adds a new totalCost metric to minutely model and model-provider mapping histories and persists it via schema migration and worker upserts.

Changes

Cohort / File(s) Summary
Admin Routes
apps/api/src/routes/admin.ts
Switched aggregation queries from hourly to minute-level history tables; changed grouping keys from hourTimestamp → minuteTimestamp; renamed response and grouping keys from usedModel/usedProvider → modelId/providerId across getModelStats, getModelDetail, getProviderStats, history and cost-by-model endpoints.
Worker: stats calculation
apps/worker/src/services/stats-calculator.ts
Added totalCost to minutely aggregations for models and model-provider mappings; propagate totalCost through zero-stat fallbacks and upsertConflict updates to history tables.
Database schema & migrations
packages/db/src/schema.ts, packages/db/migrations/1773263792_boring_luminals.sql, packages/db/migrations/meta/_journal.json
Added totalCost/total_cost (real NOT NULL DEFAULT 0) columns to model_history and model_provider_mapping_history; migration journal updated.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely summarizes the main change: updating admin endpoints to use model history tables for cost data instead of the previous data source.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch fix/admin-models-cost-tracking

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@smakosh smakosh self-assigned this Mar 11, 2026
@smakosh
smakosh enabled auto-merge March 11, 2026 21:16

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@packages/db/migrations/1773263792_boring_luminals.sql`:
- Around line 1-2: The migration adds total_cost to model_history and
model_provider_mapping_history but leaves existing rows at 0; update the
migration to either backfill historical values from the log table or add
documentation noting the data gap. Specifically, add an UPDATE step after adding
the total_cost column that aggregates historical cost data from the log (or
whichever source the stats-calculator uses) and writes it into
model_history.total_cost and model_provider_mapping_history.total_cost for
matching records, or alternatively add a migration note in your docs describing
that pre-migration rows have zeroed total_cost and that admin queries should
exclude pre-migration time ranges; reference the table names model_history,
model_provider_mapping_history and the total_cost column when implementing the
fix.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 4e5a6508-ff5d-4e8f-a9c8-6ab053a2ca6c

📥 Commits

Reviewing files that changed from the base of the PR and between 688bb7f and e04567c.

📒 Files selected for processing (3)
  • packages/db/migrations/1773263792_boring_luminals.sql
  • packages/db/migrations/meta/1773263792_snapshot.json
  • packages/db/migrations/meta/_journal.json

Comment on lines +1 to +2
ALTER TABLE "model_history" ADD COLUMN "total_cost" real DEFAULT 0 NOT NULL;--> statement-breakpoint
ALTER TABLE "model_provider_mapping_history" ADD COLUMN "total_cost" real DEFAULT 0 NOT NULL; No newline at end of file

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "Looking for total_cost / totalCost writes in migrations and app code..."
rg -n -C3 'total_cost|totalCost' packages/db apps

echo
echo "Looking for backfill updates on existing history tables..."
rg -n -C3 'UPDATE\s+"?(model_history|model_provider_mapping_history)"?' packages/db

echo
echo "Looking for history upserts/inserts that only affect new rows..."
rg -n -C3 'modelHistory|modelProviderMappingHistory' packages/db apps

Repository: theopenco/llmgateway

Length of output: 50376


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "=== Checking how history tables are populated (INSERT/UPSERT logic) ==="
rg -A5 'insert.*modelHistory|insert.*modelProviderMappingHistory' packages/db apps --multiline

echo
echo "=== Checking if there are any backfill/migration scripts or scheduled jobs ==="
rg -l 'backfill|historical|aggregate' packages/db apps

echo
echo "=== Checking admin endpoint implementations for /models endpoints ==="
fd -e ts -e tsx 'admin|models' apps | head -20 | xargs rg -l 'model_history|modelHistory' 2>/dev/null || true

echo
echo "=== Looking for any references to migration or data sync scripts ==="
rg 'pnpm|npm|yarn' package.json | grep -i 'setup\|migrate\|sync' || true
fd -e ts -e js 'migrate\|sync\|seed' packages | head -10

Repository: theopenco/llmgateway

Length of output: 7955


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "=== Checking stats-calculator.ts INSERT logic for totalCost ==="
sed -n '1,100p' apps/worker/src/services/stats-calculator.ts
echo "..."
rg -A20 '\.insert\(modelHistory\)' apps/worker/src/services/stats-calculator.ts | head -35

echo
echo "=== Checking admin.ts /models endpoints query logic ==="
rg -B5 -A30 'models.*history|modelHistory.*history' apps/api/src/routes/admin.ts | head -80

Repository: theopenco/llmgateway

Length of output: 5553


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "=== Checking when modelHistory and modelProviderMappingHistory tables were created ==="
rg -A3 'createTable.*modelHistory|createTable.*modelProviderMappingHistory' packages/db/src/schema.ts | head -20

echo
echo "=== Looking at migration chronology to see table creation date ==="
ls -la packages/db/migrations/*.sql | tail -20

echo
echo "=== Checking if history tables existed before this migration ==="
git log --oneline packages/db/src/schema.ts | head -10 2>/dev/null || echo "Git not available; checking migration sequence instead"
</parameter>

Repository: theopenco/llmgateway

Length of output: 150


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "=== Listing migration files to understand when tables were added ==="
ls -1 packages/db/migrations/*.sql | sort

echo
echo "=== Searching for modelHistory table definition in schema ==="
rg -B2 -A8 'modelHistory.*=' packages/db/src/schema.ts | head -40

echo
echo "=== Checking the previous migration before this one ==="
ls -1 packages/db/migrations/*.sql | sort | tail -5

echo
echo "=== Reading the second-to-last migration to see what existed before ==="
SECOND_LAST=$(ls -1 packages/db/migrations/*.sql | sort | tail -2 | head -1)
echo "File: $SECOND_LAST"
cat "$SECOND_LAST"

Repository: theopenco/llmgateway

Length of output: 6517


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "=== Searching for creation of modelHistory table in migrations ==="
rg -l 'CREATE TABLE.*model_history' packages/db/migrations/*.sql

echo
echo "=== Reading the migration that created modelHistory table ==="
HIST_CREATION=$(rg -l 'CREATE TABLE.*model_history' packages/db/migrations/*.sql | head -1)
if [ -n "$HIST_CREATION" ]; then
  echo "File: $HIST_CREATION"
  cat "$HIST_CREATION"
fi

echo
echo "=== Checking if there's any backfill job or one-time script ==="
find packages apps -name '*.ts' -o -name '*.sql' | xargs rg -l 'backfill|UPDATE.*model_history|UPDATE.*model_provider_mapping_history' 2>/dev/null | head -10

echo
echo "=== Checking when history tables started being populated (git history of stats-calculator) ==="
git log --oneline packages/worker/src/services/stats-calculator.ts 2>/dev/null | head -5 || echo "Git history not available"

Repository: theopenco/llmgateway

Length of output: 5114


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "=== Checking the full stats-calculator totalCost calculation ==="
rg -B10 -A5 'totalCost:' apps/worker/src/services/stats-calculator.ts | head -80

echo
echo "=== Verifying if totalCost is calculated for every insert ==="
rg -B50 '\.insert\(modelHistory\)' apps/worker/src/services/stats-calculator.ts | grep -A50 'const modelStats'

Repository: theopenco/llmgateway

Length of output: 1136


Consider backfilling historical total_cost values or documenting the data gap.

The migration adds total_cost DEFAULT 0 to existing history rows without populating actual values. While new records will have correct costs (stats-calculator calculates and inserts them each minute), any pre-migration history rows will report zero cost. If admin endpoints query time windows that include pre-migration data, cost metrics will be underreported for those ranges. Either run an UPDATE to backfill from the log table, or add documentation confirming query windows won't span pre-migration records.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/db/migrations/1773263792_boring_luminals.sql` around lines 1 - 2,
The migration adds total_cost to model_history and
model_provider_mapping_history but leaves existing rows at 0; update the
migration to either backfill historical values from the log table or add
documentation noting the data gap. Specifically, add an UPDATE step after adding
the total_cost column that aggregates historical cost data from the log (or
whichever source the stats-calculator uses) and writes it into
model_history.total_cost and model_provider_mapping_history.total_cost for
matching records, or alternatively add a migration note in your docs describing
that pre-migration rows have zeroed total_cost and that admin queries should
exclude pre-migration time ranges; reference the table names model_history,
model_provider_mapping_history and the total_cost column when implementing the
fix.

@smakosh
smakosh added this pull request to the merge queue Mar 11, 2026
@smakosh
smakosh removed this pull request from the merge queue due to a manual request Mar 11, 2026
@smakosh
smakosh added this pull request to the merge queue Mar 11, 2026
Merged via the queue into main with commit a3032da Mar 11, 2026
8 checks passed
@smakosh
smakosh deleted the fix/admin-models-cost-tracking branch March 11, 2026 21:46
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants