(model: string)
| 274 | * - "openai/gpt-4o" -> "openai/gpt-4o" (unchanged) |
| 275 | */ |
| 276 | export function resolveModelAlias(model: string): string { |
| 277 | const normalized = model.trim().toLowerCase(); |
| 278 | const resolved = MODEL_ALIASES[normalized]; |
| 279 | if (resolved) return resolved; |
| 280 | |
| 281 | // Check with "blockrun/" prefix stripped |
| 282 | if (normalized.startsWith("blockrun/")) { |
| 283 | const withoutPrefix = normalized.slice("blockrun/".length); |
| 284 | const resolvedWithoutPrefix = MODEL_ALIASES[withoutPrefix]; |
| 285 | if (resolvedWithoutPrefix) return resolvedWithoutPrefix; |
| 286 | |
| 287 | // Even if not an alias, strip the prefix for direct model paths |
| 288 | // e.g., "blockrun/anthropic/claude-sonnet-4-6" -> "anthropic/claude-sonnet-4-6" |
| 289 | return withoutPrefix; |
| 290 | } |
| 291 | |
| 292 | // Strip "openai/" prefix when it wraps a virtual routing profile or alias. |
| 293 | // OpenClaw sends virtual models as "openai/eco", "openai/auto", etc. because |
| 294 | // the provider uses the openai-completions API type. |
| 295 | if (normalized.startsWith("openai/")) { |
| 296 | const withoutPrefix = normalized.slice("openai/".length); |
| 297 | const resolvedWithoutPrefix = MODEL_ALIASES[withoutPrefix]; |
| 298 | if (resolvedWithoutPrefix) return resolvedWithoutPrefix; |
| 299 | |
| 300 | // If it's a known BlockRun virtual profile (eco, auto, premium), return bare id |
| 301 | const isVirtualProfile = BLOCKRUN_MODELS.some((m) => m.id === withoutPrefix); |
| 302 | if (isVirtualProfile) return withoutPrefix; |
| 303 | } |
| 304 | |
| 305 | // Strip "openai-codex/" prefix (OpenClaw v2026.4.5 model ID format). |
| 306 | // e.g. "openai-codex/gpt-5.4-mini" -> check alias, then strip prefix. |
| 307 | if (normalized.startsWith("openai-codex/")) { |
| 308 | const withoutPrefix = normalized.slice("openai-codex/".length); |
| 309 | const resolvedWithoutPrefix = MODEL_ALIASES[withoutPrefix]; |
| 310 | if (resolvedWithoutPrefix) return resolvedWithoutPrefix; |
| 311 | |
| 312 | // Fall back to checking if the bare name is a known model |
| 313 | const isKnownModel = BLOCKRUN_MODELS.some((m) => m.id === withoutPrefix); |
| 314 | if (isKnownModel) return withoutPrefix; |
| 315 | } |
| 316 | |
| 317 | return model; |
| 318 | } |
| 319 | |
| 320 | type BlockRunModel = { |
| 321 | id: string; |
no outgoing calls
no test coverage detected