( usage: ChatUsage | undefined | null, )
| 19 | * omit the field rather than fabricating zeroed totals. |
| 20 | */ |
| 21 | export function buildOpenRouterUsage( |
| 22 | usage: ChatUsage | undefined | null, |
| 23 | ): TokenUsage<OpenRouterProviderUsageDetails> | undefined { |
| 24 | if (!usage) return undefined |
| 25 | |
| 26 | const result = buildBaseUsage<OpenRouterProviderUsageDetails>({ |
| 27 | promptTokens: usage.promptTokens || 0, |
| 28 | completionTokens: usage.completionTokens || 0, |
| 29 | totalTokens: usage.totalTokens || 0, |
| 30 | }) |
| 31 | |
| 32 | // Add prompt token details (passthrough from SDK) |
| 33 | if (usage.promptTokensDetails) { |
| 34 | result.promptTokensDetails = usage.promptTokensDetails |
| 35 | } |
| 36 | |
| 37 | // Map completion tokens details (passthrough from SDK) |
| 38 | if (usage.completionTokensDetails) { |
| 39 | const details = usage.completionTokensDetails |
| 40 | result.completionTokensDetails = { |
| 41 | ...(details.reasoningTokens |
| 42 | ? { reasoningTokens: details.reasoningTokens } |
| 43 | : {}), |
| 44 | ...(details.audioTokens ? { audioTokens: details.audioTokens } : {}), |
| 45 | } |
| 46 | |
| 47 | // Add OpenRouter-specific prediction tokens to providerUsageDetails |
| 48 | const providerDetails = { |
| 49 | ...(details.acceptedPredictionTokens |
| 50 | ? { acceptedPredictionTokens: details.acceptedPredictionTokens } |
| 51 | : {}), |
| 52 | ...(details.rejectedPredictionTokens |
| 53 | ? { rejectedPredictionTokens: details.rejectedPredictionTokens } |
| 54 | : {}), |
| 55 | } satisfies OpenRouterProviderUsageDetails |
| 56 | |
| 57 | if (Object.keys(providerDetails).length > 0) { |
| 58 | result.providerUsageDetails = providerDetails |
| 59 | } |
| 60 | } |
| 61 | |
| 62 | return result |
| 63 | } |
no test coverage detected