diff --git a/crates/tracevault-server/migrations/008_fix_double_counted_input_tokens.sql b/crates/tracevault-server/migrations/008_fix_double_counted_input_tokens.sql new file mode 100644 index 0000000..fe86f95 --- /dev/null +++ b/crates/tracevault-server/migrations/008_fix_double_counted_input_tokens.sql @@ -0,0 +1,14 @@ +-- Fix input_tokens that were double-counted (included cache_read + cache_write tokens). +-- Subtract cache tokens to get fresh (non-cached) input only. +UPDATE sessions_v2 +SET input_tokens = GREATEST(input_tokens - cache_read_tokens - cache_write_tokens, 0), + total_tokens = GREATEST(input_tokens - cache_read_tokens - cache_write_tokens, 0) + + output_tokens + cache_read_tokens + cache_write_tokens +WHERE input_tokens > 0 + AND (cache_read_tokens > 0 OR cache_write_tokens > 0); + +-- Reset estimated_cost_usd to 0 so it gets recalculated by the pricing sync. +-- The pricing sync runs on startup and will recalculate all affected sessions. +UPDATE sessions_v2 +SET estimated_cost_usd = 0 +WHERE estimated_cost_usd > 0; diff --git a/crates/tracevault-server/src/api/session_detail.rs b/crates/tracevault-server/src/api/session_detail.rs index 02b76f5..099d0bd 100644 --- a/crates/tracevault-server/src/api/session_detail.rs +++ b/crates/tracevault-server/src/api/session_detail.rs @@ -134,7 +134,7 @@ fn parse_record(record: &serde_json::Value, pricing: &ModelPricing) -> Option
{error}
{:else if data}No transcript data.
{:else} {@const turns = extractTurns(data.transcript_chunks)} + {@const roleCounts = turns.reduce((acc, t) => { acc[t.role] = (acc[t.role] || 0) + 1; return acc; }, {} as Record