MCPcopy
hub / github.com/coder/mux / createDisplayUsage

Function createDisplayUsage

src/common/utils/tokens/displayUsage.ts:102–198  ·  view source on GitHub ↗
(
  usage: LanguageModelV2Usage | undefined,
  model: string,
  providerMetadata?: Record<string, unknown>,
  metadataModelOverride?: string
)

Source from the content-addressed store, hash-verified

100 * for display in the UI. It does NOT require the tokenizer.
101 */
102export function createDisplayUsage(
103 usage: LanguageModelV2Usage | undefined,
104 model: string,
105 providerMetadata?: Record<string, unknown>,
106 metadataModelOverride?: string
107): ChatUsageDisplay | undefined {
108 if (!usage) return undefined;
109
110 // AI SDK v6 unified semantics: ALL providers now report inputTokens INCLUSIVE
111 // of cached tokens. Previously Anthropic excluded cached tokens from inputTokens
112 // but v6 changed this to match OpenAI/Google (inputTokens = total input including
113 // cache_read + cache_write). We always subtract both cachedInputTokens and
114 // cacheCreateTokens to get the true non-cached input count.
115 const cachedTokens = usage.cachedInputTokens ?? 0;
116 const rawInputTokens = usage.inputTokens ?? 0;
117
118 // Extract cache creation tokens from provider metadata (Anthropic-specific)
119 // Needed before computing inputTokens since we subtract it from the total.
120 const cacheCreateTokens =
121 (providerMetadata?.anthropic as { cacheCreationInputTokens?: number } | undefined)
122 ?.cacheCreationInputTokens ?? 0;
123
124 // Subtract both cache-read and cache-create tokens to isolate non-cached input.
125 // Math.max guards against pre-v6 historical data where inputTokens already excluded
126 // cache tokens (subtraction would go negative).
127 const inputTokens = Math.max(0, rawInputTokens - cachedTokens - cacheCreateTokens);
128
129 // Extract reasoning tokens with fallback to provider metadata (OpenAI-specific)
130 const reasoningTokens =
131 usage.reasoningTokens ??
132 (providerMetadata?.openai as { reasoningTokens?: number } | undefined)?.reasoningTokens ??
133 0;
134
135 // Calculate output tokens excluding reasoning
136 const outputWithoutReasoning = Math.max(0, (usage.outputTokens ?? 0) - reasoningTokens);
137
138 // Get model stats for cost calculation
139 const modelStats = getModelStats(metadataModelOverride ?? model);
140
141 const costsIncluded =
142 (providerMetadata?.mux as { costsIncluded?: boolean } | undefined)?.costsIncluded === true;
143
144 // Calculate costs based on model stats (undefined if model unknown)
145 let inputCost: number | undefined;
146 let cachedCost: number | undefined;
147 let cacheCreateCost: number | undefined;
148 let outputCost: number | undefined;
149 let reasoningCost: number | undefined;
150
151 if (modelStats) {
152 const costs = calculateUsageCosts(modelStats, {
153 inputTokens,
154 cachedTokens,
155 cacheCreateTokens,
156 outputTokens: outputWithoutReasoning,
157 reasoningTokens,
158 });
159 inputCost = costs.inputCost;

Callers 15

WorkspaceStoreClass · 0.90
getWorkspaceUsageMethod · 0.90
chatListenerFunction · 0.90
extractSyncMetadataFunction · 0.90
rebuildToolModelUsageMethod · 0.90
recordSessionUsageMethod · 0.90

Calls 2

getModelStatsFunction · 0.90
calculateUsageCostsFunction · 0.85

Tested by

no test coverage detected