feat: add Sonnet 5 to Claude provider catalog

This commit is contained in:
Tam Nhu Tran committed 2026-07-02 10:31:42 -04:00
1 parent 631a515986
commit c8a4b42990
6 files changed
+84 -16

No files matched your search

+16 -4
View File
@@ -854,8 +854,20 @@ export const MODEL_CATALOGS: Record<string, ProviderCatalog> = {
claude: {
provider: 'claude',
displayName: 'Claude (Anthropic)',
defaultModel: 'claude-sonnet-4-6',
defaultModel: 'claude-sonnet-5',
models: [
{
id: 'claude-sonnet-5',
name: 'Claude Sonnet 5',
description: 'Latest Sonnet model',
extendedContext: true,
presetMapping: {
default: 'claude-sonnet-5',
opus: 'claude-opus-4-8',
sonnet: 'claude-sonnet-5',
haiku: 'claude-haiku-4-5-20251001',
},
},
{
id: 'claude-fable-5',
name: 'Claude Fable 5',
@@ -864,7 +876,7 @@ export const MODEL_CATALOGS: Record<string, ProviderCatalog> = {
presetMapping: {
default: 'claude-fable-5',
opus: 'claude-fable-5',
sonnet: 'claude-sonnet-4-6',
sonnet: 'claude-sonnet-5',
haiku: 'claude-haiku-4-5-20251001',
},
},
@@ -876,7 +888,7 @@ export const MODEL_CATALOGS: Record<string, ProviderCatalog> = {
presetMapping: {
default: 'claude-opus-4-8',
opus: 'claude-opus-4-8',
sonnet: 'claude-sonnet-4-6',
sonnet: 'claude-sonnet-5',
haiku: 'claude-haiku-4-5-20251001',
},
},
@@ -888,7 +900,7 @@ export const MODEL_CATALOGS: Record<string, ProviderCatalog> = {
presetMapping: {
default: 'claude-opus-4-7',
opus: 'claude-opus-4-7',
sonnet: 'claude-sonnet-4-6',
sonnet: 'claude-sonnet-5',
haiku: 'claude-haiku-4-5-20251001',
},
},
@@ -70,7 +70,7 @@ describe('FlexibleModelSelector', () => {
expect(screen.queryByText(/All Models \(/i)).not.toBeInTheDocument();
});
it('surfaces Claude Opus 4.7 in the curated Claude picker', async () => {
it('surfaces Claude Sonnet 5 in the curated Claude picker', async () => {
render(
<FlexibleModelSelector
label="Primary model"
@@ -83,8 +83,8 @@ describe('FlexibleModelSelector', () => {
await userEvent.click(screen.getByRole('button', { name: /select model/i }));
expect(screen.getByRole('option', { name: /claude-opus-4-7/i })).toBeInTheDocument();
expect(screen.getByRole('option', { name: /claude-opus-4-6/i })).toBeInTheDocument();
expect(screen.getByRole('option', { name: /claude-sonnet-5/i })).toBeInTheDocument();
expect(screen.getByRole('option', { name: /claude-opus-4-8/i })).toBeInTheDocument();
expect(screen.getByRole('option', { name: /claude-sonnet-4-6/i })).toBeInTheDocument();
});
@@ -129,6 +129,28 @@ describe('FlexibleModelSelector', () => {
expect(onChange).toHaveBeenCalledWith('claude-sonnet-6');
});
it('lets users enter a future direct Claude model ID from the CLIProxy picker', async () => {
const onChange = vi.fn();
render(
<FlexibleModelSelector
label="Primary model"
value={undefined}
onChange={onChange}
catalog={MODEL_CATALOGS.claude}
allModels={[]}
/>
);
await userEvent.click(screen.getByRole('button', { name: /select model/i }));
await userEvent.type(await screen.findByPlaceholderText('Search models...'), 'claude-sonnet-6');
expect(screen.getAllByText('Custom model').length).toBeGreaterThan(0);
await userEvent.click(screen.getByRole('option', { name: /claude-sonnet-6/i }));
expect(onChange).toHaveBeenCalledWith('claude-sonnet-6');
});
it('preserves a filtered legacy value under the current-value fallback group', async () => {
render(
<FlexibleModelSelector
+8 -7
View File
@@ -16,11 +16,12 @@ describe('claude preset utils', () => {
vi.restoreAllMocks();
});
it('keeps the claude catalog default on Sonnet 4.6 while exposing Opus 4.7/4.8 and Fable 5', () => {
it('keeps the claude catalog default on Sonnet 5 while exposing recent Claude models', () => {
const claudeCatalog = MODEL_CATALOGS.claude;
const ids = claudeCatalog.models.map((model) => model.id);
expect(claudeCatalog.defaultModel).toBe('claude-sonnet-4-6');
expect(claudeCatalog.defaultModel).toBe('claude-sonnet-5');
expect(ids).toContain('claude-sonnet-5');
expect(ids).toContain('claude-fable-5');
expect(ids).toContain('claude-opus-4-8');
expect(ids).toContain('claude-opus-4-7');
@@ -50,15 +51,15 @@ describe('claude preset utils', () => {
const result = await applyDefaultPreset('claude');
expect(result).toEqual({ success: true, presetName: 'Claude Sonnet 4.6' });
expect(result).toEqual({ success: true, presetName: 'Claude Sonnet 5' });
const [, requestInit] = fetchMock.mock.calls[2] ?? [];
const body = JSON.parse(String(requestInit?.body));
expect(body.settings.env).toMatchObject({
ANTHROPIC_MODEL: 'claude-sonnet-4-6',
ANTHROPIC_DEFAULT_OPUS_MODEL: 'claude-opus-4-6',
ANTHROPIC_DEFAULT_SONNET_MODEL: 'claude-sonnet-4-6',
ANTHROPIC_MODEL: 'claude-sonnet-5',
ANTHROPIC_DEFAULT_OPUS_MODEL: 'claude-opus-4-8',
ANTHROPIC_DEFAULT_SONNET_MODEL: 'claude-sonnet-5',
ANTHROPIC_DEFAULT_HAIKU_MODEL: 'claude-haiku-4-5-20251001',
});
});
@@ -76,7 +77,7 @@ describe('claude preset utils', () => {
const result = await applyDefaultPreset('claude', undefined, MODEL_CATALOGS.claude);
expect(result).toEqual({ success: true, presetName: 'Claude Sonnet 4.6' });
expect(result).toEqual({ success: true, presetName: 'Claude Sonnet 5' });
expect(fetchMock).toHaveBeenCalledTimes(2);
expect(fetchMock).toHaveBeenNthCalledWith(1, '/api/settings/auth/tokens/raw');
expect(fetchMock).toHaveBeenNthCalledWith(