fix: GitHub Copilot fallback — remove stale API version header and fix model name mapping
Two issues prevented the GitHub Models fallback from working: 1. The X-GitHub-Api-Version: 2022-11-28 header caused '400 invalid apiVersion' errors. The Copilot chat completions endpoint does not use this header — removed from both constructor and rebuildClient. 2. The anthropicToGitHubModel mapping was incomplete: it only knew three models and the generic date-stripping fallback produced wrong names (e.g. 'claude-sonnet-4-5' instead of 'claude-sonnet-4.5'). GitHub Copilot uses dots for sub-versions, not hyphens. Updated with explicit mappings for all current models (sonnet 4, 4.5; opus 4, 4.5, 4.6; haiku 4.5) and a smarter generic fallback that converts digit-hyphen-digit to digit.digit at the end. 3. createClientFromConfig now auto-maps Anthropic-style model names when the provider is 'github', so users can copy model names from their Anthropic config into fallback blocks without manual renaming.
This commit is contained in:
+22
-5
@@ -115,7 +115,7 @@ export function createClientFromConfig(cfg: ModelConfig): ModelClient {
|
||||
});
|
||||
case 'github':
|
||||
return new GitHubModelsClient({
|
||||
model: cfg.model,
|
||||
model: anthropicToGitHubModel(cfg.model) ?? cfg.model,
|
||||
apiKey: cfg.api_key,
|
||||
endpoint: cfg.endpoint,
|
||||
onLoginRequired: async () => {
|
||||
@@ -134,20 +134,37 @@ export function createClientFromConfig(cfg: ModelConfig): ModelClient {
|
||||
/**
|
||||
* Map an Anthropic model identifier to its GitHub Models equivalent.
|
||||
* Returns undefined if no mapping is known.
|
||||
*
|
||||
* Anthropic uses hyphens and date suffixes: claude-sonnet-4-5-20250929
|
||||
* GitHub Copilot uses dots, no dates: claude-sonnet-4.5
|
||||
*/
|
||||
export function anthropicToGitHubModel(anthropicModel: string): string | undefined {
|
||||
// Mapping from Anthropic versioned names → GitHub Copilot short names
|
||||
// Explicit mappings for known models
|
||||
const MAPPINGS: Record<string, string> = {
|
||||
// Sonnet family
|
||||
'claude-sonnet-4-20250514': 'claude-sonnet-4',
|
||||
'claude-sonnet-4-5-20250929': 'claude-sonnet-4.5',
|
||||
// Opus family
|
||||
'claude-opus-4-20250514': 'claude-opus-4',
|
||||
'claude-3-5-haiku-20241022': 'claude-haiku-4',
|
||||
'claude-opus-4-5-20250918': 'claude-opus-4.5',
|
||||
'claude-opus-4-6-20250715': 'claude-opus-4.6',
|
||||
// Haiku family
|
||||
'claude-3-5-haiku-20241022': 'claude-haiku-4.5',
|
||||
'claude-haiku-4-5-20251001': 'claude-haiku-4.5',
|
||||
};
|
||||
|
||||
if (MAPPINGS[anthropicModel]) return MAPPINGS[anthropicModel];
|
||||
|
||||
// Try stripping date suffix (e.g. "claude-sonnet-4-20260101" → "claude-sonnet-4")
|
||||
// Generic fallback: strip date suffix, then convert trailing -N to .N
|
||||
// only when preceded by another digit (i.e. "4-5" → "4.5", not "sonnet-5" → "sonnet.5")
|
||||
// e.g. "claude-sonnet-4-7-20260301" → "claude-sonnet-4-7" → "claude-sonnet-4.7"
|
||||
const dateMatch = anthropicModel.match(/^(.+)-\d{8}$/);
|
||||
if (dateMatch) return dateMatch[1];
|
||||
if (dateMatch) {
|
||||
const base = dateMatch[1];
|
||||
// Convert "claude-sonnet-4-5" → "claude-sonnet-4.5" (digit-hyphen-digit at end)
|
||||
const dotted = base.replace(/(\d)-(\d+)$/, '$1.$2');
|
||||
return dotted;
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user