@@ -3267,36 +3267,115 @@ export class UsageStatsDatabase {
32673267 }
32683268
32693269 /**
3270- * Queries per-(task_id, provider, model) input token sums from
3270+ * Queries per-(hour/day, provider, model) token sums from usage_events.
3271+ * Used for day-axis recomputation with custom pricing.
3272+ *
3273+ * @param fromEpochMs Start epoch ms (inclusive). 0 for no lower bound.
3274+ * @param toEpochMs End epoch ms (exclusive). MAX_SAFE_INTEGER for no upper bound.
3275+ * @param includeCancelled If true, includes cancelled events.
3276+ * @returns Array of { occurredAt, provider, model, endpoint, mode, inputTokens, outputTokens, cacheWriteTokens, cacheReadTokens } rows.
3277+ */
3278+ queryDailyTokensByProviderModel (
3279+ fromEpochMs : number ,
3280+ toEpochMs : number ,
3281+ includeCancelled : boolean = false ,
3282+ ) : Array < {
3283+ occurredAt : string
3284+ provider : string
3285+ model : string
3286+ endpoint : string | null
3287+ mode : string
3288+ inputTokens : number
3289+ outputTokens : number
3290+ cacheWriteTokens : number
3291+ cacheReadTokens : number
3292+ } > {
3293+ const db = this . getDb ( )
3294+
3295+ try {
3296+ let query = `SELECT occurred_at, provider, model, endpoint, mode,
3297+ SUM(COALESCE(json_extract(usage_json, '$.inputTokens.value'), 0)) as input_tokens,
3298+ SUM(COALESCE(json_extract(usage_json, '$.outputTokens.value'), 0)) as output_tokens,
3299+ SUM(COALESCE(json_extract(usage_json, '$.cacheWriteTokens.value'), 0)) as cache_write_tokens,
3300+ SUM(COALESCE(json_extract(usage_json, '$.cacheReadTokens.value'), 0)) as cache_read_tokens
3301+ FROM usage_events
3302+ WHERE occurred_epoch_ms >= ? AND occurred_epoch_ms < ?`
3303+ const params : Array < number | string > = [ fromEpochMs , toEpochMs ]
3304+
3305+ if ( ! includeCancelled ) {
3306+ query += ` AND status != 'cancelled'`
3307+ }
3308+
3309+ query += ` GROUP BY SUBSTR(occurred_at, 1, 13), provider, model, endpoint, mode`
3310+
3311+ const rows = db . prepare ( query ) . all ( ...params ) as Array < Record < string , unknown > >
3312+
3313+ return rows . map ( ( row ) => ( {
3314+ occurredAt : ( row . occurred_at as string ) ?? "" ,
3315+ provider : ( row . provider as string ) ?? "" ,
3316+ model : ( row . model as string ) ?? "" ,
3317+ endpoint : ( row . endpoint as string | null ) ?? null ,
3318+ mode : ( row . mode as string ) ?? "" ,
3319+ inputTokens : ( row . input_tokens as number ) ?? 0 ,
3320+ outputTokens : ( row . output_tokens as number ) ?? 0 ,
3321+ cacheWriteTokens : ( row . cache_write_tokens as number ) ?? 0 ,
3322+ cacheReadTokens : ( row . cache_read_tokens as number ) ?? 0 ,
3323+ } ) )
3324+ } catch ( err ) {
3325+ throw new StatsDbError ( "STATS_DB/read/001" , "Failed to query daily tokens by provider+model" , err )
3326+ }
3327+ }
3328+
3329+ /**
3330+ * Queries per-(task_id, provider, model) token sums from
32713331 * usage_events for a given set of task IDs. Used by the task projection
3272- * to recompute `cache_discount_base` at query time when `customPricing`
3273- * is available, overriding the stale stored value (which was 0 for custom
3274- * models because pricing wasn't available at write time).
3332+ * to recompute `totalCost` and ` cache_discount_base` at query time when
3333+ * `customPricing` is available, overriding the stale stored values (which
3334+ * were 0 for custom models because pricing wasn't available at write time).
32753335 *
32763336 * @param taskIds The task IDs to query.
32773337 * @param rangeMs Optional time range filter.
32783338 * @param includeCancelled If true, includes cancelled events.
3279- * @returns Array of { taskId, provider, model, inputTokens } rows.
3339+ * @returns Array of { taskId, provider, model, inputTokens, outputTokens, cacheWriteTokens, cacheReadTokens } rows.
32803340 */
32813341 queryInputTokensByTaskId (
32823342 taskIds : string [ ] ,
32833343 rangeMs ?: StatsQueryRangeMs ,
32843344 includeCancelled : boolean = false ,
3285- ) : Array < { taskId : string ; provider : string ; model : string ; inputTokens : number } > {
3345+ ) : Array < {
3346+ taskId : string
3347+ provider : string
3348+ model : string
3349+ inputTokens : number
3350+ outputTokens : number
3351+ cacheWriteTokens : number
3352+ cacheReadTokens : number
3353+ } > {
32863354 const db = this . getDb ( )
32873355 const uniqueTaskIds = [ ...new Set ( taskIds ) ]
32883356
32893357 if ( uniqueTaskIds . length === 0 ) return [ ]
32903358
32913359 try {
3292- const result : Array < { taskId : string ; provider : string ; model : string ; inputTokens : number } > = [ ]
3360+ const result : Array < {
3361+ taskId : string
3362+ provider : string
3363+ model : string
3364+ inputTokens : number
3365+ outputTokens : number
3366+ cacheWriteTokens : number
3367+ cacheReadTokens : number
3368+ } > = [ ]
32933369
32943370 for ( let start = 0 ; start < uniqueTaskIds . length ; start += TASK_ID_QUERY_CHUNK_SIZE ) {
32953371 const chunk = uniqueTaskIds . slice ( start , start + TASK_ID_QUERY_CHUNK_SIZE )
32963372 const placeholders = chunk . map ( ( ) => "?" ) . join ( ", " )
32973373
32983374 let query = `SELECT task_id, provider, model,
3299- SUM(COALESCE(json_extract(usage_json, '$.inputTokens.value'), 0)) as input_tokens
3375+ SUM(COALESCE(json_extract(usage_json, '$.inputTokens.value'), 0)) as input_tokens,
3376+ SUM(COALESCE(json_extract(usage_json, '$.outputTokens.value'), 0)) as output_tokens,
3377+ SUM(COALESCE(json_extract(usage_json, '$.cacheWriteTokens.value'), 0)) as cache_write_tokens,
3378+ SUM(COALESCE(json_extract(usage_json, '$.cacheReadTokens.value'), 0)) as cache_read_tokens
33003379 FROM usage_events
33013380 WHERE task_id IN (${ placeholders } )`
33023381 const params : Array < string | number > = [ ...chunk ]
@@ -3324,6 +3403,9 @@ export class UsageStatsDatabase {
33243403 provider : ( row . provider as string ) ?? "" ,
33253404 model : ( row . model as string ) ?? "" ,
33263405 inputTokens : ( row . input_tokens as number ) ?? 0 ,
3406+ outputTokens : ( row . output_tokens as number ) ?? 0 ,
3407+ cacheWriteTokens : ( row . cache_write_tokens as number ) ?? 0 ,
3408+ cacheReadTokens : ( row . cache_read_tokens as number ) ?? 0 ,
33273409 } )
33283410 }
33293411 }
0 commit comments