(usage: Record<string, unknown> | undefined | null, model: string)
| 127 | } |
| 128 | |
| 129 | function extractUsageAndCost(usage: Record<string, unknown> | undefined | null, model: string): UsageData { |
| 130 | if (!usage) return { inputTokens: 0, outputTokens: 0, cacheReadInputTokens: 0, reasoningTokens: 0, cost: 0 } |
| 131 | const promptDetails = usage.prompt_tokens_details as Record<string, unknown> | undefined | null |
| 132 | const completionDetails = usage.completion_tokens_details as Record<string, unknown> | undefined | null |
| 133 | |
| 134 | const inputTokens = typeof usage.prompt_tokens === 'number' ? usage.prompt_tokens : 0 |
| 135 | const outputTokens = typeof usage.completion_tokens === 'number' ? usage.completion_tokens : 0 |
| 136 | const cacheReadInputTokens = typeof promptDetails?.cached_tokens === 'number' ? promptDetails.cached_tokens : 0 |
| 137 | const reasoningTokens = typeof completionDetails?.reasoning_tokens === 'number' ? completionDetails.reasoning_tokens : 0 |
| 138 | |
| 139 | const pricing = getCanopyWavePricing(model) |
| 140 | const nonCachedInputTokens = Math.max(0, inputTokens - cacheReadInputTokens) |
| 141 | const cost = |
| 142 | nonCachedInputTokens * pricing.inputCostPerToken + |
| 143 | cacheReadInputTokens * pricing.cachedInputCostPerToken + |
| 144 | outputTokens * pricing.outputCostPerToken |
| 145 | |
| 146 | return { inputTokens, outputTokens, cacheReadInputTokens, reasoningTokens, cost } |
| 147 | } |
| 148 | |
| 149 | export async function handleCanopyWaveNonStream({ |
| 150 | body, |
no test coverage detected