Skip to content

Commit 13608a8

Browse files
feat(execution): base execution charge of 0.001/execution (#817)
1 parent 08720d9 commit 13608a8

File tree

5 files changed

+45
-58
lines changed

5 files changed

+45
-58
lines changed

apps/sim/app/workspace/[workspaceId]/logs/components/sidebar/sidebar.tsx

Lines changed: 15 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import { Button } from '@/components/ui/button'
66
import { CopyButton } from '@/components/ui/copy-button'
77
import { ScrollArea } from '@/components/ui/scroll-area'
88
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '@/components/ui/tooltip'
9+
import { BASE_EXECUTION_CHARGE } from '@/lib/billing/constants'
910
import { redactApiKeys } from '@/lib/utils'
1011
import { FrozenCanvasModal } from '@/app/workspace/[workspaceId]/logs/components/frozen-canvas/frozen-canvas-modal'
1112
import LogMarkdownRenderer from '@/app/workspace/[workspaceId]/logs/components/sidebar/components/markdown-renderer'
@@ -254,14 +255,10 @@ export function Sidebar({
254255
}, [log])
255256

256257
// Helper to determine if we have cost information to display
258+
// All workflow executions now have cost info (base charge + any model costs)
257259
const hasCostInfo = useMemo(() => {
258-
return !!(
259-
log?.metadata?.cost &&
260-
((log.metadata.cost.input && log.metadata.cost.input > 0) ||
261-
(log.metadata.cost.output && log.metadata.cost.output > 0) ||
262-
(log.metadata.cost.total && log.metadata.cost.total > 0))
263-
)
264-
}, [log])
260+
return isWorkflowExecutionLog && log?.metadata?.cost
261+
}, [log, isWorkflowExecutionLog])
265262

266263
const isWorkflowWithCost = useMemo(() => {
267264
return isWorkflowExecutionLog && hasCostInfo
@@ -492,49 +489,6 @@ export function Sidebar({
492489
</div>
493490
)}
494491

495-
{/* Enhanced Cost - only show for enhanced logs with actual cost data */}
496-
{log.metadata?.enhanced && hasCostInfo && (
497-
<div>
498-
<h3 className='mb-1 font-medium text-muted-foreground text-xs'>
499-
Cost Breakdown
500-
</h3>
501-
<div className='space-y-1 text-sm'>
502-
{(log.metadata?.cost?.total ?? 0) > 0 && (
503-
<div className='flex justify-between'>
504-
<span>Total Cost:</span>
505-
<span className='font-medium'>
506-
${log.metadata?.cost?.total?.toFixed(4)}
507-
</span>
508-
</div>
509-
)}
510-
{(log.metadata?.cost?.input ?? 0) > 0 && (
511-
<div className='flex justify-between'>
512-
<span>Input Cost:</span>
513-
<span className='text-muted-foreground'>
514-
${log.metadata?.cost?.input?.toFixed(4)}
515-
</span>
516-
</div>
517-
)}
518-
{(log.metadata?.cost?.output ?? 0) > 0 && (
519-
<div className='flex justify-between'>
520-
<span>Output Cost:</span>
521-
<span className='text-muted-foreground'>
522-
${log.metadata?.cost?.output?.toFixed(4)}
523-
</span>
524-
</div>
525-
)}
526-
{(log.metadata?.cost?.tokens?.total ?? 0) > 0 && (
527-
<div className='flex justify-between'>
528-
<span>Total Tokens:</span>
529-
<span className='text-muted-foreground'>
530-
{log.metadata?.cost?.tokens?.total?.toLocaleString()}
531-
</span>
532-
</div>
533-
)}
534-
</div>
535-
</div>
536-
)}
537-
538492
{/* Frozen Canvas Button - only show for workflow execution logs with execution ID */}
539493
{isWorkflowExecutionLog && log.executionId && (
540494
<div>
@@ -588,17 +542,23 @@ export function Sidebar({
588542
{/* Cost Information (moved to bottom) */}
589543
{hasCostInfo && (
590544
<div>
591-
<h3 className='mb-1 font-medium text-muted-foreground text-xs'>Models</h3>
545+
<h3 className='mb-1 font-medium text-muted-foreground text-xs'>
546+
Cost Breakdown
547+
</h3>
592548
<div className='overflow-hidden rounded-md border'>
593549
<div className='space-y-2 p-3'>
594550
<div className='flex items-center justify-between'>
595-
<span className='text-muted-foreground text-sm'>Input:</span>
551+
<span className='text-muted-foreground text-sm'>Base Execution:</span>
552+
<span className='text-sm'>{formatCost(BASE_EXECUTION_CHARGE)}</span>
553+
</div>
554+
<div className='flex items-center justify-between'>
555+
<span className='text-muted-foreground text-sm'>Model Input:</span>
596556
<span className='text-sm'>
597557
{formatCost(log.metadata?.cost?.input || 0)}
598558
</span>
599559
</div>
600560
<div className='flex items-center justify-between'>
601-
<span className='text-muted-foreground text-sm'>Output:</span>
561+
<span className='text-muted-foreground text-sm'>Model Output:</span>
602562
<span className='text-sm'>
603563
{formatCost(log.metadata?.cost?.output || 0)}
604564
</span>
@@ -677,8 +637,8 @@ export function Sidebar({
677637
{isWorkflowWithCost && (
678638
<div className='border-t bg-muted p-3 text-muted-foreground text-xs'>
679639
<p>
680-
This is the total cost for all LLM-based blocks in this workflow
681-
execution.
640+
Total cost includes a base execution charge of{' '}
641+
{formatCost(BASE_EXECUTION_CHARGE)} plus any model usage costs.
682642
</p>
683643
</div>
684644
)}

apps/sim/lib/billing/constants.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
/**
2+
* Billing and cost constants shared between client and server code
3+
*/
4+
5+
/**
6+
* Base charge applied to every workflow execution
7+
* This charge is applied regardless of whether the workflow uses AI models
8+
*/
9+
export const BASE_EXECUTION_CHARGE = 0.001

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

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,8 @@ export class ExecutionLogger implements IExecutionLoggerService {
119119
totalTokens: number
120120
totalPromptTokens: number
121121
totalCompletionTokens: number
122+
baseExecutionCharge: number
123+
modelCost: number
122124
models: Record<
123125
string,
124126
{
@@ -263,6 +265,8 @@ export class ExecutionLogger implements IExecutionLoggerService {
263265
totalTokens: number
264266
totalPromptTokens: number
265267
totalCompletionTokens: number
268+
baseExecutionCharge: number
269+
modelCost: number
266270
},
267271
trigger: ExecutionTrigger['type']
268272
): Promise<void> {
@@ -286,7 +290,8 @@ export class ExecutionLogger implements IExecutionLoggerService {
286290

287291
const userId = workflowRecord.userId
288292
const costMultiplier = getCostMultiplier()
289-
const costToStore = costSummary.totalCost * costMultiplier
293+
// Apply cost multiplier only to model costs, not base execution charge
294+
const costToStore = costSummary.baseExecutionCharge + costSummary.modelCost * costMultiplier
290295

291296
// Check if user stats record exists
292297
const userStatsRecords = await db.select().from(userStats).where(eq(userStats.userId, userId))

apps/sim/lib/logs/execution/logging-factory.ts

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { BASE_EXECUTION_CHARGE } from '@/lib/billing/constants'
12
import type { ExecutionEnvironment, ExecutionTrigger, WorkflowState } from '@/lib/logs/types'
23
import { loadWorkflowFromNormalizedTables } from '@/lib/workflows/db-helpers'
34

@@ -53,6 +54,8 @@ export function calculateCostSummary(traceSpans: any[]): {
5354
totalTokens: number
5455
totalPromptTokens: number
5556
totalCompletionTokens: number
57+
baseExecutionCharge: number
58+
modelCost: number
5659
models: Record<
5760
string,
5861
{
@@ -65,12 +68,14 @@ export function calculateCostSummary(traceSpans: any[]): {
6568
} {
6669
if (!traceSpans || traceSpans.length === 0) {
6770
return {
68-
totalCost: 0,
71+
totalCost: BASE_EXECUTION_CHARGE,
6972
totalInputCost: 0,
7073
totalOutputCost: 0,
7174
totalTokens: 0,
7275
totalPromptTokens: 0,
7376
totalCompletionTokens: 0,
77+
baseExecutionCharge: BASE_EXECUTION_CHARGE,
78+
modelCost: 0,
7479
models: {},
7580
}
7681
}
@@ -139,13 +144,18 @@ export function calculateCostSummary(traceSpans: any[]): {
139144
}
140145
}
141146

147+
const modelCost = totalCost
148+
totalCost += BASE_EXECUTION_CHARGE
149+
142150
return {
143151
totalCost,
144152
totalInputCost,
145153
totalOutputCost,
146154
totalTokens,
147155
totalPromptTokens,
148156
totalCompletionTokens,
157+
baseExecutionCharge: BASE_EXECUTION_CHARGE,
158+
modelCost,
149159
models,
150160
}
151161
}

apps/sim/lib/logs/execution/logging-session.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { BASE_EXECUTION_CHARGE } from '@/lib/billing/constants'
12
import { createLogger } from '@/lib/logs/console/logger'
23
import { executionLogger } from '@/lib/logs/execution/logger'
34
import {
@@ -117,12 +118,14 @@ export class LoggingSession {
117118
async completeWithError(error?: any): Promise<void> {
118119
try {
119120
const costSummary = {
120-
totalCost: 0,
121+
totalCost: BASE_EXECUTION_CHARGE,
121122
totalInputCost: 0,
122123
totalOutputCost: 0,
123124
totalTokens: 0,
124125
totalPromptTokens: 0,
125126
totalCompletionTokens: 0,
127+
baseExecutionCharge: BASE_EXECUTION_CHARGE,
128+
modelCost: 0,
126129
models: {},
127130
}
128131

0 commit comments

Comments
 (0)