({
id,
model,
inputModality,
outputModality,
maxTokens,
supportedParameters,
}: {
id: string
model: OpenRouterBaseModel
inputModality: string[] | null | undefined
outputModality: string[] | null | undefined
maxTokens: number | null | undefined
supportedParameters?: string[]
})
| 185 | */ |
| 186 | |
| 187 | export const parseOpenRouterModel = ({ |
| 188 | id, |
| 189 | model, |
| 190 | inputModality, |
| 191 | outputModality, |
| 192 | maxTokens, |
| 193 | supportedParameters, |
| 194 | }: { |
| 195 | id: string |
| 196 | model: OpenRouterBaseModel |
| 197 | inputModality: string[] | null | undefined |
| 198 | outputModality: string[] | null | undefined |
| 199 | maxTokens: number | null | undefined |
| 200 | supportedParameters?: string[] |
| 201 | }): ModelInfo => { |
| 202 | const cacheWritesPrice = model.pricing?.input_cache_write |
| 203 | ? parseApiPrice(model.pricing?.input_cache_write) |
| 204 | : undefined |
| 205 | |
| 206 | const cacheReadsPrice = model.pricing?.input_cache_read ? parseApiPrice(model.pricing?.input_cache_read) : undefined |
| 207 | |
| 208 | const supportsPromptCache = typeof cacheReadsPrice !== "undefined" // some models support caching but don't charge a cacheWritesPrice, e.g. GPT-5 |
| 209 | |
| 210 | const modelInfo: ModelInfo = { |
| 211 | maxTokens: maxTokens || Math.ceil(model.context_length * 0.2), |
| 212 | contextWindow: model.context_length, |
| 213 | supportsImages: inputModality?.includes("image") ?? false, |
| 214 | supportsPromptCache, |
| 215 | inputPrice: parseApiPrice(model.pricing?.prompt), |
| 216 | outputPrice: parseApiPrice(model.pricing?.completion), |
| 217 | cacheWritesPrice, |
| 218 | cacheReadsPrice, |
| 219 | description: model.description, |
| 220 | supportsReasoningEffort: supportedParameters ? supportedParameters.includes("reasoning") : undefined, |
| 221 | supportedParameters: supportedParameters ? supportedParameters.filter(isModelParameter) : undefined, |
| 222 | } |
| 223 | |
| 224 | if (OPEN_ROUTER_REASONING_BUDGET_MODELS.has(id)) { |
| 225 | modelInfo.supportsReasoningBudget = true |
| 226 | } |
| 227 | |
| 228 | if (OPEN_ROUTER_REQUIRED_REASONING_BUDGET_MODELS.has(id)) { |
| 229 | modelInfo.requiredReasoningBudget = true |
| 230 | } |
| 231 | |
| 232 | // For backwards compatibility with the old model definitions we will |
| 233 | // continue to disable extending thinking for anthropic/claude-3.7-sonnet |
| 234 | // and force it for anthropic/claude-3.7-sonnet:thinking. |
| 235 | |
| 236 | if (id === "anthropic/claude-3.7-sonnet") { |
| 237 | modelInfo.maxTokens = anthropicModels["claude-3-7-sonnet-20250219"].maxTokens |
| 238 | modelInfo.supportsReasoningBudget = false |
| 239 | modelInfo.supportsReasoningEffort = false |
| 240 | } |
| 241 | |
| 242 | if (id === "anthropic/claude-3.7-sonnet:thinking") { |
| 243 | modelInfo.maxTokens = anthropicModels["claude-3-7-sonnet-20250219:thinking"].maxTokens |
| 244 | } |
no test coverage detected