diff --git a/src/app/api/profile/usage/route.ts b/src/app/api/profile/usage/route.ts index 10ec01d1b..c76272d89 100644 --- a/src/app/api/profile/usage/route.ts +++ b/src/app/api/profile/usage/route.ts @@ -27,7 +27,11 @@ export async function GET(request: NextRequest) { // Build the select object conditionally const selectFields = { date: sql`DATE(${microdollar_usage.created_at})`, - ...(groupByModel && { model: microdollar_usage.model }), + ...(groupByModel && { + model: sql< + string | null + >`COALESCE(${microdollar_usage.requested_model}, ${microdollar_usage.model})`, + }), total_cost: sql`SUM(${microdollar_usage.cost})::float`, request_count: sql`COUNT(*)::float`, total_input_tokens: sql`SUM(${microdollar_usage.input_tokens})::float`, @@ -39,11 +43,15 @@ export async function GET(request: NextRequest) { // Build the group by and order by clauses conditionally const groupByClause = [ sql`DATE(${microdollar_usage.created_at})`, - ...(groupByModel ? [microdollar_usage.model] : []), + ...(groupByModel + ? [sql`COALESCE(${microdollar_usage.requested_model}, ${microdollar_usage.model})`] + : []), ]; const orderByClause = [ desc(sql`DATE(${microdollar_usage.created_at})`), - ...(groupByModel ? [microdollar_usage.model] : []), + ...(groupByModel + ? [sql`COALESCE(${microdollar_usage.requested_model}, ${microdollar_usage.model})`] + : []), ]; // Build where conditions based on view type diff --git a/src/routers/organizations/organization-usage-details-router.test.ts b/src/routers/organizations/organization-usage-details-router.test.ts index 20afc01b2..a7b7c9e97 100644 --- a/src/routers/organizations/organization-usage-details-router.test.ts +++ b/src/routers/organizations/organization-usage-details-router.test.ts @@ -219,6 +219,7 @@ describe('organizations usage details trpc router', () => { output_tokens: 200, created_at: now, model: 'gpt-4', + requested_model: 'gpt-4', }); await insertUsageWithOverrides({ @@ -229,6 +230,7 @@ describe('organizations usage details trpc router', () => { output_tokens: 100, created_at: now, model: 'gpt-3.5-turbo', + requested_model: 'gpt-3.5-turbo', }); const caller = await createCallerForUser(memberUser.id); @@ -250,6 +252,30 @@ describe('organizations usage details trpc router', () => { expect(gpt35Result?.microdollarCost).toBe('500'); }); + it('should fall back to model when requested_model is null (legacy rows)', async () => { + const now = await getDateFromDb(); + + await insertUsageWithOverrides({ + kilo_user_id: memberUser.id, + organization_id: testOrganization.id, + cost: 750, + created_at: now, + model: 'legacy-model', + requested_model: null, + }); + + const caller = await createCallerForUser(memberUser.id); + + const result = await caller.organizations.usageDetails.get({ + organizationId: testOrganization.id, + groupByModel: true, + }); + + const legacyRow = result.daily.find(d => d.model === 'legacy-model'); + expect(legacyRow).toBeDefined(); + expect(legacyRow?.microdollarCost).toBe('750'); + }); + it('should handle empty usage data', async () => { const caller = await createCallerForUser(memberUser.id); diff --git a/src/routers/organizations/organization-usage-details-router.ts b/src/routers/organizations/organization-usage-details-router.ts index 817c6b6d7..6ba7bb800 100644 --- a/src/routers/organizations/organization-usage-details-router.ts +++ b/src/routers/organizations/organization-usage-details-router.ts @@ -170,7 +170,7 @@ export const organizationsUsageDetailsRouter = createTRPCRouter({ datetime: timeBucket.as('datetime'), userName: kilocode_users.google_user_name, userEmail: kilocode_users.google_user_email, - model: microdollar_usage.model, + model: sql`COALESCE(${microdollar_usage.requested_model}, ${microdollar_usage.model})`, provider: microdollar_usage.provider, projectId: microdollar_usage.project_id, costMicrodollars: sum(microdollar_usage.cost), @@ -191,7 +191,7 @@ export const organizationsUsageDetailsRouter = createTRPCRouter({ timeBucket, kilocode_users.google_user_name, kilocode_users.google_user_email, - microdollar_usage.model, + sql`COALESCE(${microdollar_usage.requested_model}, ${microdollar_usage.model})`, microdollar_usage.provider, microdollar_usage.project_id ) @@ -318,7 +318,11 @@ export const organizationsUsageDetailsRouter = createTRPCRouter({ date: sql`DATE(${microdollar_usage.created_at})`.as('date'), userName: kilocode_users.google_user_name, userEmail: kilocode_users.google_user_email, - ...(groupByModel && { model: microdollar_usage.model }), + ...(groupByModel && { + model: sql< + string | null + >`COALESCE(${microdollar_usage.requested_model}, ${microdollar_usage.model})`, + }), microdollarCost: sum(microdollar_usage.cost), tokenCount: sum( sql`${microdollar_usage.input_tokens} + ${microdollar_usage.output_tokens} + ${microdollar_usage.cache_write_tokens} + ${microdollar_usage.cache_hit_tokens}` @@ -334,7 +338,9 @@ export const organizationsUsageDetailsRouter = createTRPCRouter({ sql`DATE(${microdollar_usage.created_at})`, kilocode_users.google_user_name, kilocode_users.google_user_email, - ...(groupByModel ? [microdollar_usage.model] : []) + ...(groupByModel + ? [sql`COALESCE(${microdollar_usage.requested_model}, ${microdollar_usage.model})`] + : []) ) .orderBy(sql`DATE(${microdollar_usage.created_at}) DESC`) );