( usageMetadata: GenerateContentResponseUsageMetadata | undefined | null, )
| 119 | * fabricating zeroed totals. |
| 120 | */ |
| 121 | export function buildGeminiUsage( |
| 122 | usageMetadata: GenerateContentResponseUsageMetadata | undefined | null, |
| 123 | ): TokenUsage<GeminiProviderUsageDetails> | undefined { |
| 124 | if (!usageMetadata) return undefined |
| 125 | |
| 126 | const promptTokens = usageMetadata.promptTokenCount ?? 0 |
| 127 | const completionTokens = usageMetadata.candidatesTokenCount ?? 0 |
| 128 | |
| 129 | const result = buildBaseUsage<GeminiProviderUsageDetails>({ |
| 130 | promptTokens: promptTokens, |
| 131 | completionTokens: completionTokens, |
| 132 | totalTokens: |
| 133 | usageMetadata.totalTokenCount ?? promptTokens + completionTokens, |
| 134 | }) |
| 135 | |
| 136 | // Add prompt token details |
| 137 | // Flatten modality breakdown for prompt |
| 138 | const promptModalities = flattenModalityTokenCounts( |
| 139 | usageMetadata.promptTokensDetails, |
| 140 | ) |
| 141 | const cachedTokens = usageMetadata.cachedContentTokenCount |
| 142 | |
| 143 | const promptTokensDetails = { |
| 144 | ...(hasModalityTokens(promptModalities) ? promptModalities : {}), |
| 145 | ...(cachedTokens !== undefined && cachedTokens > 0 ? { cachedTokens } : {}), |
| 146 | } |
| 147 | |
| 148 | // Add completion token details |
| 149 | // Flatten modality breakdown for candidates (output) |
| 150 | const completionModalities = flattenModalityTokenCounts( |
| 151 | usageMetadata.candidatesTokensDetails, |
| 152 | ) |
| 153 | const thoughtsTokens = usageMetadata.thoughtsTokenCount |
| 154 | |
| 155 | const completionTokensDetails = { |
| 156 | ...(hasModalityTokens(completionModalities) ? completionModalities : {}), |
| 157 | // Map thoughtsTokenCount to reasoningTokens for consistency with OpenAI |
| 158 | ...(thoughtsTokens !== undefined && thoughtsTokens > 0 |
| 159 | ? { reasoningTokens: thoughtsTokens } |
| 160 | : {}), |
| 161 | } |
| 162 | |
| 163 | // Add provider-specific details |
| 164 | const providerDetails: GeminiProviderUsageDetails = { |
| 165 | ...(usageMetadata.trafficType |
| 166 | ? { trafficType: usageMetadata.trafficType } |
| 167 | : {}), |
| 168 | ...(usageMetadata.toolUsePromptTokenCount !== undefined && |
| 169 | usageMetadata.toolUsePromptTokenCount > 0 |
| 170 | ? { toolUsePromptTokenCount: usageMetadata.toolUsePromptTokenCount } |
| 171 | : {}), |
| 172 | ...(usageMetadata.toolUsePromptTokensDetails && |
| 173 | usageMetadata.toolUsePromptTokensDetails.length > 0 |
| 174 | ? { |
| 175 | toolUsePromptTokensDetails: |
| 176 | usageMetadata.toolUsePromptTokensDetails.map((item) => ({ |
| 177 | modality: item.modality || 'UNKNOWN', |
| 178 | tokenCount: item.tokenCount ?? 0, |
no test coverage detected