MCPcopy Index your code
hub / github.com/simstudioai/sim / calculateCostSummary

Function calculateCostSummary

apps/sim/lib/logs/execution/logging-factory.ts:135–267  ·  view source on GitHub ↗
(traceSpans: CostTraceSpan[] | undefined)

Source from the content-addressed store, hash-verified

133}
134
135export function calculateCostSummary(traceSpans: CostTraceSpan[] | undefined): CostSummary {
136 if (!traceSpans || traceSpans.length === 0) {
137 return {
138 totalCost: BASE_EXECUTION_CHARGE,
139 totalInputCost: 0,
140 totalOutputCost: 0,
141 totalTokens: 0,
142 totalPromptTokens: 0,
143 totalCompletionTokens: 0,
144 baseExecutionCharge: BASE_EXECUTION_CHARGE,
145 models: {},
146 charges: {},
147 }
148 }
149
150 /**
151 * Collects spans that contribute to the execution's billable cost.
152 *
153 * Rule: when a span has its own `cost` AND has child model segments, the
154 * parent's block-level cost is authoritative — skip the model children to
155 * avoid double-counting. The parent cost is set by the provider response
156 * (and is correctly zeroed by `executeProviderRequest` for BYOK calls);
157 * model children only carry per-segment cost from the trace enrichers,
158 * which is unaware of BYOK status. Non-model children are still visited
159 * so standalone nested costs remain billable.
160 *
161 * Spans without their own `cost` (e.g. parent workflow spans for
162 * subworkflow blocks) still recurse so nested billable spans are counted.
163 */
164 const collectCostSpans = (spans: CostTraceSpan[]): BillableTraceSpan[] => {
165 const costSpans: BillableTraceSpan[] = []
166
167 for (const span of spans) {
168 // `workflow`-typed spans are aggregate containers, not billable units: the
169 // synthetic "Workflow Execution" root (added to every run by
170 // buildTraceSpans) and any nested sub-workflow root carry a `cost.total`
171 // equal to the SUM of their descendants. Counting that aggregate in
172 // addition to the descendants double-charges the run, so treat these as
173 // pass-through: never count their own cost, always recurse into all
174 // children where the real billable leaves (agents, tools) live.
175 const isAggregateContainer = span.type === 'workflow'
176 const hasOwnCost = hasBillableCost(span)
177 const countOwnCost = hasOwnCost && !isAggregateContainer
178
179 if (countOwnCost) {
180 costSpans.push(span)
181 }
182
183 if (span.children && Array.isArray(span.children)) {
184 if (countOwnCost) {
185 // Authoritative leaf (e.g. an agent block whose block-level cost is set
186 // by the provider response and already accounts for its model
187 // segments): only recurse into non-model children to find further
188 // standalone billable units, skipping the model-breakdown duplicates.
189 const nonModelChildren = span.children.filter((child) => !isModelBreakdownSpan(child))
190 costSpans.push(...collectCostSpans(nonModelChildren))
191 } else {
192 // Container (workflow / sub-workflow root) or a no-cost parent: recurse

Callers 6

completeMethod · 0.90
completeWithErrorMethod · 0.90
completeWithPauseMethod · 0.90

Calls 1

collectCostSpansFunction · 0.85

Tested by

no test coverage detected