feat: auto same-model fallback via GitHub Models when primary Anthropic provider fails
When a tier uses the Anthropic provider and has no user-configured inline fallback, automatically insert a GitHub Models client for the equivalent model as a tier fallback. This ensures the same model is tried via an alternative provider before degrading to the global fallback chain (which may be a much weaker local model). Mapping: claude-sonnet-4-20250514 → claude-sonnet-4, etc.
This commit is contained in:
@@ -1,11 +1,12 @@
|
||||
import { describe, it, expect } from 'vitest';
|
||||
import { createClientFromConfig } from './index.js';
|
||||
import { createClientFromConfig, anthropicToGitHubModel, createAutoFallbackClient } from './index.js';
|
||||
import { AnthropicClient } from '../models/anthropic.js';
|
||||
import { OpenAIClient } from '../models/openai.js';
|
||||
import { OllamaClient } from '../models/local/ollama.js';
|
||||
import { LlamaCppClient } from '../models/local/llamacpp.js';
|
||||
import { GeminiClient } from '../models/gemini.js';
|
||||
import { BedrockClient } from '../models/bedrock.js';
|
||||
import { GitHubModelsClient } from '../models/github.js';
|
||||
|
||||
describe('createClientFromConfig', () => {
|
||||
it('creates AnthropicClient for anthropic provider', () => {
|
||||
@@ -94,3 +95,45 @@ describe('createClientFromConfig', () => {
|
||||
expect(client).toBeInstanceOf(BedrockClient);
|
||||
});
|
||||
});
|
||||
|
||||
describe('anthropicToGitHubModel', () => {
|
||||
it('maps claude-sonnet-4-20250514 to claude-sonnet-4', () => {
|
||||
expect(anthropicToGitHubModel('claude-sonnet-4-20250514')).toBe('claude-sonnet-4');
|
||||
});
|
||||
|
||||
it('maps claude-opus-4-20250514 to claude-opus-4', () => {
|
||||
expect(anthropicToGitHubModel('claude-opus-4-20250514')).toBe('claude-opus-4');
|
||||
});
|
||||
|
||||
it('maps claude-3-5-haiku-20241022 to claude-haiku-4', () => {
|
||||
expect(anthropicToGitHubModel('claude-3-5-haiku-20241022')).toBe('claude-haiku-4');
|
||||
});
|
||||
|
||||
it('strips date suffix for unknown versioned models', () => {
|
||||
expect(anthropicToGitHubModel('claude-sonnet-5-20260101')).toBe('claude-sonnet-5');
|
||||
});
|
||||
|
||||
it('returns undefined for models without date suffix', () => {
|
||||
expect(anthropicToGitHubModel('llama3.2:1b')).toBeUndefined();
|
||||
});
|
||||
});
|
||||
|
||||
describe('createAutoFallbackClient', () => {
|
||||
it('creates a GitHubModelsClient for anthropic provider', () => {
|
||||
const client = createAutoFallbackClient({
|
||||
provider: 'anthropic',
|
||||
model: 'claude-sonnet-4-20250514',
|
||||
});
|
||||
expect(client).toBeInstanceOf(GitHubModelsClient);
|
||||
});
|
||||
|
||||
it('returns undefined for non-anthropic providers', () => {
|
||||
expect(createAutoFallbackClient({ provider: 'openai', model: 'gpt-4o' })).toBeUndefined();
|
||||
expect(createAutoFallbackClient({ provider: 'ollama', model: 'llama3.2:1b' })).toBeUndefined();
|
||||
expect(createAutoFallbackClient({ provider: 'gemini', model: 'gemini-2.5-pro' })).toBeUndefined();
|
||||
});
|
||||
|
||||
it('returns undefined for unmappable anthropic models', () => {
|
||||
expect(createAutoFallbackClient({ provider: 'anthropic', model: 'custom-model' })).toBeUndefined();
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user