Skip to content

Commit 0d86eaa

Browse files
authored
fix(usage): persist cost multiplier at provider level instead of also at the logger level (#1433)
* feat(changelog): added changelog * fix(usage): persist cost multiplier at provider level * Revert "feat(changelog): added changelog" This reverts commit 885d10c. --------- Co-authored-by: waleed <waleed>
1 parent aa0a33e commit 0d86eaa

File tree

4 files changed

+14
-16
lines changed

4 files changed

+14
-16
lines changed

apps/sim/app/api/billing/update-cost/route.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import { createLogger } from '@/lib/logs/console/logger'
99
import { generateRequestId } from '@/lib/utils'
1010
import { calculateCost } from '@/providers/utils'
1111

12-
const logger = createLogger('billing-update-cost')
12+
const logger = createLogger('BillingUpdateCostAPI')
1313

1414
const UpdateCostSchema = z.object({
1515
userId: z.string().min(1, 'User ID is required'),

apps/sim/lib/logs/execution/logger.ts

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import { eq, sql } from 'drizzle-orm'
1111
import { v4 as uuidv4 } from 'uuid'
1212
import { getHighestPrioritySubscription } from '@/lib/billing/core/subscription'
1313
import { checkUsageStatus, maybeSendUsageThresholdEmail } from '@/lib/billing/core/usage'
14-
import { getCostMultiplier, isBillingEnabled } from '@/lib/environment'
14+
import { isBillingEnabled } from '@/lib/environment'
1515
import { createLogger } from '@/lib/logs/console/logger'
1616
import { emitWorkflowExecutionCompleted } from '@/lib/logs/events'
1717
import { snapshotService } from '@/lib/logs/execution/snapshot/service'
@@ -195,9 +195,7 @@ export class ExecutionLogger implements IExecutionLoggerService {
195195
if (usr?.email) {
196196
const sub = await getHighestPrioritySubscription(usr.id)
197197

198-
const costMultiplier = getCostMultiplier()
199-
const costDelta =
200-
(costSummary.baseExecutionCharge || 0) + (costSummary.modelCost || 0) * costMultiplier
198+
const costDelta = costSummary.totalCost
201199

202200
const planName = sub?.plan || 'Free'
203201
const scope: 'user' | 'organization' =
@@ -399,9 +397,7 @@ export class ExecutionLogger implements IExecutionLoggerService {
399397
}
400398

401399
const userId = workflowRecord.userId
402-
const costMultiplier = getCostMultiplier()
403-
// Apply cost multiplier only to model costs, not base execution charge
404-
const costToStore = costSummary.baseExecutionCharge + costSummary.modelCost * costMultiplier
400+
const costToStore = costSummary.totalCost
405401

406402
const existing = await db.select().from(userStats).where(eq(userStats.userId, userId))
407403
if (existing.length === 0) {

apps/sim/providers/index.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { getCostMultiplier } from '@/lib/environment'
12
import { createLogger } from '@/lib/logs/console/logger'
23
import type { StreamingExecution } from '@/executor/types'
34
import type { ProviderRequest, ProviderResponse } from '@/providers/types'
@@ -87,7 +88,15 @@ export async function executeProviderRequest(
8788
const useCachedInput = !!request.context && request.context.length > 0
8889

8990
if (shouldBillModelUsage(response.model)) {
90-
response.cost = calculateCost(response.model, promptTokens, completionTokens, useCachedInput)
91+
const costMultiplier = getCostMultiplier()
92+
response.cost = calculateCost(
93+
response.model,
94+
promptTokens,
95+
completionTokens,
96+
useCachedInput,
97+
costMultiplier,
98+
costMultiplier
99+
)
91100
} else {
92101
response.cost = {
93102
input: 0,

apps/sim/providers/utils.ts

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -496,13 +496,11 @@ export function calculateCost(
496496
* Get pricing information for a specific model (including embedding models)
497497
*/
498498
export function getModelPricing(modelId: string): any {
499-
// First check if it's an embedding model
500499
const embeddingPricing = getEmbeddingModelPricing(modelId)
501500
if (embeddingPricing) {
502501
return embeddingPricing
503502
}
504503

505-
// Then check chat models
506504
return getModelPricingFromDefinitions(modelId)
507505
}
508506

@@ -516,20 +514,15 @@ export function formatCost(cost: number): string {
516514
if (cost === undefined || cost === null) return '—'
517515

518516
if (cost >= 1) {
519-
// For costs >= $1, show two decimal places
520517
return `$${cost.toFixed(2)}`
521518
}
522519
if (cost >= 0.01) {
523-
// For costs between 1¢ and $1, show three decimal places
524520
return `$${cost.toFixed(3)}`
525521
}
526522
if (cost >= 0.001) {
527-
// For costs between 0.1¢ and 1¢, show four decimal places
528523
return `$${cost.toFixed(4)}`
529524
}
530525
if (cost > 0) {
531-
// For very small costs, still show as fixed decimal instead of scientific notation
532-
// Find the first non-zero digit and show a few more places
533526
const places = Math.max(4, Math.abs(Math.floor(Math.log10(cost))) + 3)
534527
return `$${cost.toFixed(places)}`
535528
}

0 commit comments

Comments
 (0)