* Resolves a model string to a ModelName, falling back to a similar model if unknown. * Optionally logs a warning when falling back.
(modelString: string)
| 76 | * Optionally logs a warning when falling back. |
| 77 | */ |
| 78 | function resolveModelName(modelString: string): ModelName { |
| 79 | const normalized = normalizeToCanonical(modelString); |
| 80 | let modelName = normalizeModelKey(normalized); |
| 81 | |
| 82 | if (!modelName) { |
| 83 | const provider = normalized.split(":")[0] || "anthropic"; |
| 84 | |
| 85 | // GitHub Copilot hosts models from multiple providers. |
| 86 | // Infer the tokenizer family from the model name prefix. |
| 87 | let effectiveProvider = provider; |
| 88 | if (provider === "github-copilot") { |
| 89 | const modelId = normalized.split(":")[1] || ""; |
| 90 | if (modelId.startsWith("claude-")) { |
| 91 | effectiveProvider = "anthropic"; |
| 92 | } else if (modelId.startsWith("gemini-")) { |
| 93 | effectiveProvider = "google"; |
| 94 | } else { |
| 95 | // gpt-*, grok-*, and unknown models use OpenAI tokenizer |
| 96 | effectiveProvider = "openai"; |
| 97 | } |
| 98 | } |
| 99 | |
| 100 | const fallbackModel = |
| 101 | effectiveProvider === "anthropic" |
| 102 | ? "anthropic/claude-sonnet-4.5" |
| 103 | : effectiveProvider === "google" |
| 104 | ? "google/gemini-2.5-pro" |
| 105 | : "openai/gpt-5"; |
| 106 | |
| 107 | // Only warn once per unknown model to avoid log spam |
| 108 | if (!warnedModels.has(modelString)) { |
| 109 | warnedModels.add(modelString); |
| 110 | log.warn( |
| 111 | `Unknown model '${modelString}', using ${fallbackModel} tokenizer for approximate token counting` |
| 112 | ); |
| 113 | } |
| 114 | |
| 115 | modelName = fallbackModel as ModelName; |
| 116 | } |
| 117 | |
| 118 | return modelName; |
| 119 | } |
| 120 | |
| 121 | function resolveEncoding(modelName: ModelName): Promise<string> { |
| 122 | let promise = encodingPromises.get(modelName); |
no test coverage detected