Skip to content

Commit eedf528

Browse files
jahoomaclaude
andcommitted
Address Greptile review: merge canopywave model + pricing maps
Combine CANOPYWAVE_MODEL_MAP and CANOPYWAVE_PRICING_MAP into a single CANOPYWAVE_MODELS map keyed by OpenRouter model ID. Removes the silent Kimi-pricing fallback in getCanopyWavePricing — it now throws on unknown models, since callers are expected to gate on isCanopyWaveModel first. Eliminates the drift risk if a future model is added to one map but not the other. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 150a5f8 commit eedf528

1 file changed

Lines changed: 40 additions & 30 deletions

File tree

web/src/llm-api/canopywave.ts

Lines changed: 40 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -26,18 +26,52 @@ const canopywaveAgent = new Agent({
2626
bodyTimeout: 0,
2727
})
2828

29-
/** Map from OpenRouter model IDs to CanopyWave model IDs */
30-
const CANOPYWAVE_MODEL_MAP: Record<string, string> = {
31-
'minimax/minimax-m2.5': 'minimax/minimax-m2.5',
32-
'moonshotai/kimi-k2.6': 'moonshotai/kimi-k2.6',
29+
// CanopyWave per-token pricing (dollars per token)
30+
interface CanopyWavePricing {
31+
inputCostPerToken: number
32+
cachedInputCostPerToken: number
33+
outputCostPerToken: number
34+
}
35+
36+
/** Single source of truth: which OpenRouter model IDs we route through
37+
* CanopyWave, the corresponding CanopyWave model ID, and per-model pricing.
38+
* Kept as one map so adding a model can't drift between routing and billing. */
39+
const CANOPYWAVE_MODELS: Record<
40+
string,
41+
{ canopywaveId: string; pricing: CanopyWavePricing }
42+
> = {
43+
'minimax/minimax-m2.5': {
44+
canopywaveId: 'minimax/minimax-m2.5',
45+
pricing: {
46+
inputCostPerToken: 0.27 / 1_000_000,
47+
cachedInputCostPerToken: 0.03 / 1_000_000,
48+
outputCostPerToken: 1.08 / 1_000_000,
49+
},
50+
},
51+
'moonshotai/kimi-k2.6': {
52+
canopywaveId: 'moonshotai/kimi-k2.6',
53+
pricing: {
54+
inputCostPerToken: 0.60 / 1_000_000,
55+
cachedInputCostPerToken: 0.15 / 1_000_000,
56+
outputCostPerToken: 2.50 / 1_000_000,
57+
},
58+
},
3359
}
3460

3561
export function isCanopyWaveModel(model: string): boolean {
36-
return model in CANOPYWAVE_MODEL_MAP
62+
return model in CANOPYWAVE_MODELS
3763
}
3864

3965
function getCanopyWaveModelId(openrouterModel: string): string {
40-
return CANOPYWAVE_MODEL_MAP[openrouterModel] ?? openrouterModel
66+
return CANOPYWAVE_MODELS[openrouterModel]?.canopywaveId ?? openrouterModel
67+
}
68+
69+
function getCanopyWavePricing(model: string): CanopyWavePricing {
70+
const entry = CANOPYWAVE_MODELS[model]
71+
if (!entry) {
72+
throw new Error(`No CanopyWave pricing found for model: ${model}`)
73+
}
74+
return entry.pricing
4175
}
4276

4377
type StreamState = { responseText: string; reasoningText: string; ttftMs: number | null; billedAlready: boolean }
@@ -86,30 +120,6 @@ function createCanopyWaveRequest(params: {
86120
})
87121
}
88122

89-
// CanopyWave per-token pricing (dollars per token), keyed by OpenRouter model ID
90-
interface CanopyWavePricing {
91-
inputCostPerToken: number
92-
cachedInputCostPerToken: number
93-
outputCostPerToken: number
94-
}
95-
96-
const CANOPYWAVE_PRICING_MAP: Record<string, CanopyWavePricing> = {
97-
'minimax/minimax-m2.5': {
98-
inputCostPerToken: 0.27 / 1_000_000,
99-
cachedInputCostPerToken: 0.03 / 1_000_000,
100-
outputCostPerToken: 1.08 / 1_000_000,
101-
},
102-
'moonshotai/kimi-k2.6': {
103-
inputCostPerToken: 0.60 / 1_000_000,
104-
cachedInputCostPerToken: 0.15 / 1_000_000,
105-
outputCostPerToken: 2.50 / 1_000_000,
106-
},
107-
}
108-
109-
function getCanopyWavePricing(model: string): CanopyWavePricing {
110-
return CANOPYWAVE_PRICING_MAP[model] ?? CANOPYWAVE_PRICING_MAP['moonshotai/kimi-k2.6']
111-
}
112-
113123
function extractUsageAndCost(usage: Record<string, unknown> | undefined | null, model: string): UsageData {
114124
if (!usage) return { inputTokens: 0, outputTokens: 0, cacheReadInputTokens: 0, reasoningTokens: 0, cost: 0 }
115125
const promptDetails = usage.prompt_tokens_details as Record<string, unknown> | undefined | null

0 commit comments

Comments
 (0)