mirror of
https://github.com/simstudioai/sim.git
synced 2026-01-06 21:54:01 -05:00
feat(execution): base execution charge of 0.001/execution (#817)
This commit is contained in:
committed by
GitHub
parent
08720d926c
commit
13608a8bbc
@@ -6,6 +6,7 @@ import { Button } from '@/components/ui/button'
|
||||
import { CopyButton } from '@/components/ui/copy-button'
|
||||
import { ScrollArea } from '@/components/ui/scroll-area'
|
||||
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '@/components/ui/tooltip'
|
||||
import { BASE_EXECUTION_CHARGE } from '@/lib/billing/constants'
|
||||
import { redactApiKeys } from '@/lib/utils'
|
||||
import { FrozenCanvasModal } from '@/app/workspace/[workspaceId]/logs/components/frozen-canvas/frozen-canvas-modal'
|
||||
import LogMarkdownRenderer from '@/app/workspace/[workspaceId]/logs/components/sidebar/components/markdown-renderer'
|
||||
@@ -254,14 +255,10 @@ export function Sidebar({
|
||||
}, [log])
|
||||
|
||||
// Helper to determine if we have cost information to display
|
||||
// All workflow executions now have cost info (base charge + any model costs)
|
||||
const hasCostInfo = useMemo(() => {
|
||||
return !!(
|
||||
log?.metadata?.cost &&
|
||||
((log.metadata.cost.input && log.metadata.cost.input > 0) ||
|
||||
(log.metadata.cost.output && log.metadata.cost.output > 0) ||
|
||||
(log.metadata.cost.total && log.metadata.cost.total > 0))
|
||||
)
|
||||
}, [log])
|
||||
return isWorkflowExecutionLog && log?.metadata?.cost
|
||||
}, [log, isWorkflowExecutionLog])
|
||||
|
||||
const isWorkflowWithCost = useMemo(() => {
|
||||
return isWorkflowExecutionLog && hasCostInfo
|
||||
@@ -492,49 +489,6 @@ export function Sidebar({
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Enhanced Cost - only show for enhanced logs with actual cost data */}
|
||||
{log.metadata?.enhanced && hasCostInfo && (
|
||||
<div>
|
||||
<h3 className='mb-1 font-medium text-muted-foreground text-xs'>
|
||||
Cost Breakdown
|
||||
</h3>
|
||||
<div className='space-y-1 text-sm'>
|
||||
{(log.metadata?.cost?.total ?? 0) > 0 && (
|
||||
<div className='flex justify-between'>
|
||||
<span>Total Cost:</span>
|
||||
<span className='font-medium'>
|
||||
${log.metadata?.cost?.total?.toFixed(4)}
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
{(log.metadata?.cost?.input ?? 0) > 0 && (
|
||||
<div className='flex justify-between'>
|
||||
<span>Input Cost:</span>
|
||||
<span className='text-muted-foreground'>
|
||||
${log.metadata?.cost?.input?.toFixed(4)}
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
{(log.metadata?.cost?.output ?? 0) > 0 && (
|
||||
<div className='flex justify-between'>
|
||||
<span>Output Cost:</span>
|
||||
<span className='text-muted-foreground'>
|
||||
${log.metadata?.cost?.output?.toFixed(4)}
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
{(log.metadata?.cost?.tokens?.total ?? 0) > 0 && (
|
||||
<div className='flex justify-between'>
|
||||
<span>Total Tokens:</span>
|
||||
<span className='text-muted-foreground'>
|
||||
{log.metadata?.cost?.tokens?.total?.toLocaleString()}
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Frozen Canvas Button - only show for workflow execution logs with execution ID */}
|
||||
{isWorkflowExecutionLog && log.executionId && (
|
||||
<div>
|
||||
@@ -588,17 +542,23 @@ export function Sidebar({
|
||||
{/* Cost Information (moved to bottom) */}
|
||||
{hasCostInfo && (
|
||||
<div>
|
||||
<h3 className='mb-1 font-medium text-muted-foreground text-xs'>Models</h3>
|
||||
<h3 className='mb-1 font-medium text-muted-foreground text-xs'>
|
||||
Cost Breakdown
|
||||
</h3>
|
||||
<div className='overflow-hidden rounded-md border'>
|
||||
<div className='space-y-2 p-3'>
|
||||
<div className='flex items-center justify-between'>
|
||||
<span className='text-muted-foreground text-sm'>Input:</span>
|
||||
<span className='text-muted-foreground text-sm'>Base Execution:</span>
|
||||
<span className='text-sm'>{formatCost(BASE_EXECUTION_CHARGE)}</span>
|
||||
</div>
|
||||
<div className='flex items-center justify-between'>
|
||||
<span className='text-muted-foreground text-sm'>Model Input:</span>
|
||||
<span className='text-sm'>
|
||||
{formatCost(log.metadata?.cost?.input || 0)}
|
||||
</span>
|
||||
</div>
|
||||
<div className='flex items-center justify-between'>
|
||||
<span className='text-muted-foreground text-sm'>Output:</span>
|
||||
<span className='text-muted-foreground text-sm'>Model Output:</span>
|
||||
<span className='text-sm'>
|
||||
{formatCost(log.metadata?.cost?.output || 0)}
|
||||
</span>
|
||||
@@ -677,8 +637,8 @@ export function Sidebar({
|
||||
{isWorkflowWithCost && (
|
||||
<div className='border-t bg-muted p-3 text-muted-foreground text-xs'>
|
||||
<p>
|
||||
This is the total cost for all LLM-based blocks in this workflow
|
||||
execution.
|
||||
Total cost includes a base execution charge of{' '}
|
||||
{formatCost(BASE_EXECUTION_CHARGE)} plus any model usage costs.
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
|
||||
9
apps/sim/lib/billing/constants.ts
Normal file
9
apps/sim/lib/billing/constants.ts
Normal file
@@ -0,0 +1,9 @@
|
||||
/**
|
||||
* Billing and cost constants shared between client and server code
|
||||
*/
|
||||
|
||||
/**
|
||||
* Base charge applied to every workflow execution
|
||||
* This charge is applied regardless of whether the workflow uses AI models
|
||||
*/
|
||||
export const BASE_EXECUTION_CHARGE = 0.001
|
||||
@@ -119,6 +119,8 @@ export class ExecutionLogger implements IExecutionLoggerService {
|
||||
totalTokens: number
|
||||
totalPromptTokens: number
|
||||
totalCompletionTokens: number
|
||||
baseExecutionCharge: number
|
||||
modelCost: number
|
||||
models: Record<
|
||||
string,
|
||||
{
|
||||
@@ -263,6 +265,8 @@ export class ExecutionLogger implements IExecutionLoggerService {
|
||||
totalTokens: number
|
||||
totalPromptTokens: number
|
||||
totalCompletionTokens: number
|
||||
baseExecutionCharge: number
|
||||
modelCost: number
|
||||
},
|
||||
trigger: ExecutionTrigger['type']
|
||||
): Promise<void> {
|
||||
@@ -286,7 +290,8 @@ export class ExecutionLogger implements IExecutionLoggerService {
|
||||
|
||||
const userId = workflowRecord.userId
|
||||
const costMultiplier = getCostMultiplier()
|
||||
const costToStore = costSummary.totalCost * costMultiplier
|
||||
// Apply cost multiplier only to model costs, not base execution charge
|
||||
const costToStore = costSummary.baseExecutionCharge + costSummary.modelCost * costMultiplier
|
||||
|
||||
// Check if user stats record exists
|
||||
const userStatsRecords = await db.select().from(userStats).where(eq(userStats.userId, userId))
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { BASE_EXECUTION_CHARGE } from '@/lib/billing/constants'
|
||||
import type { ExecutionEnvironment, ExecutionTrigger, WorkflowState } from '@/lib/logs/types'
|
||||
import { loadWorkflowFromNormalizedTables } from '@/lib/workflows/db-helpers'
|
||||
|
||||
@@ -53,6 +54,8 @@ export function calculateCostSummary(traceSpans: any[]): {
|
||||
totalTokens: number
|
||||
totalPromptTokens: number
|
||||
totalCompletionTokens: number
|
||||
baseExecutionCharge: number
|
||||
modelCost: number
|
||||
models: Record<
|
||||
string,
|
||||
{
|
||||
@@ -65,12 +68,14 @@ export function calculateCostSummary(traceSpans: any[]): {
|
||||
} {
|
||||
if (!traceSpans || traceSpans.length === 0) {
|
||||
return {
|
||||
totalCost: 0,
|
||||
totalCost: BASE_EXECUTION_CHARGE,
|
||||
totalInputCost: 0,
|
||||
totalOutputCost: 0,
|
||||
totalTokens: 0,
|
||||
totalPromptTokens: 0,
|
||||
totalCompletionTokens: 0,
|
||||
baseExecutionCharge: BASE_EXECUTION_CHARGE,
|
||||
modelCost: 0,
|
||||
models: {},
|
||||
}
|
||||
}
|
||||
@@ -139,6 +144,9 @@ export function calculateCostSummary(traceSpans: any[]): {
|
||||
}
|
||||
}
|
||||
|
||||
const modelCost = totalCost
|
||||
totalCost += BASE_EXECUTION_CHARGE
|
||||
|
||||
return {
|
||||
totalCost,
|
||||
totalInputCost,
|
||||
@@ -146,6 +154,8 @@ export function calculateCostSummary(traceSpans: any[]): {
|
||||
totalTokens,
|
||||
totalPromptTokens,
|
||||
totalCompletionTokens,
|
||||
baseExecutionCharge: BASE_EXECUTION_CHARGE,
|
||||
modelCost,
|
||||
models,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { BASE_EXECUTION_CHARGE } from '@/lib/billing/constants'
|
||||
import { createLogger } from '@/lib/logs/console/logger'
|
||||
import { executionLogger } from '@/lib/logs/execution/logger'
|
||||
import {
|
||||
@@ -117,12 +118,14 @@ export class LoggingSession {
|
||||
async completeWithError(error?: any): Promise<void> {
|
||||
try {
|
||||
const costSummary = {
|
||||
totalCost: 0,
|
||||
totalCost: BASE_EXECUTION_CHARGE,
|
||||
totalInputCost: 0,
|
||||
totalOutputCost: 0,
|
||||
totalTokens: 0,
|
||||
totalPromptTokens: 0,
|
||||
totalCompletionTokens: 0,
|
||||
baseExecutionCharge: BASE_EXECUTION_CHARGE,
|
||||
modelCost: 0,
|
||||
models: {},
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user