fix(core): Remove (latest) tags from models in agent models catalog (no-changelog) (#32023)

This commit is contained in:
Michael Drury
2026-06-12 08:54:28 +00:00
committed by GitHub
parent 6a904301be
commit 94cc6c8a5b
2 changed files with 85 additions and 0 deletions
@@ -70,4 +70,58 @@ describe('fetchProviderCatalog', () => {
expect(catalog.azure).toBeUndefined();
expect(catalog['azure-cognitive-services']).toBeUndefined();
});
it('strips the "(latest)" suffix from model names and drops duplicate pinned snapshots', async () => {
const fetchMock = vi.fn().mockResolvedValue({
ok: true,
json: async () =>
await Promise.resolve({
anthropic: {
id: 'anthropic',
name: 'Anthropic',
models: {
'claude-opus-4-5': {
id: 'claude-opus-4-5',
name: 'Claude Opus 4.5 (latest)',
},
'claude-opus-4-5-20251101': {
id: 'claude-opus-4-5-20251101',
name: 'Claude Opus 4.5',
},
'claude-opus-4-8': {
id: 'claude-opus-4-8',
name: 'Claude Opus 4.8',
},
'claude-3-5-haiku-latest': {
id: 'claude-3-5-haiku-latest',
name: 'Claude Haiku 3.5 (latest)',
},
},
},
google: {
id: 'google',
name: 'Google',
models: {
'gemini-flash-latest': {
id: 'gemini-flash-latest',
name: 'Gemini Flash Latest',
},
},
},
}),
});
global.fetch = fetchMock as typeof fetch;
const catalog = await fetchProviderCatalog();
// Alias keeps its id but loses the "(latest)" tag
expect(catalog.anthropic.models['claude-opus-4-5'].name).toBe('Claude Opus 4.5');
expect(catalog.anthropic.models['claude-3-5-haiku-latest'].name).toBe('Claude Haiku 3.5');
// Pinned snapshot with the same name as an alias is dropped
expect(catalog.anthropic.models['claude-opus-4-5-20251101']).toBeUndefined();
// Models without a same-named alias are untouched
expect(catalog.anthropic.models['claude-opus-4-8'].name).toBe('Claude Opus 4.8');
// Only the parenthesized suffix is stripped, not other "latest" naming
expect(catalog.google.models['gemini-flash-latest'].name).toBe('Gemini Flash Latest');
});
});
+31
View File
@@ -82,6 +82,33 @@ function toAgentProviderId(modelsDevProviderId: string): string {
return MODELS_DEV_PROVIDER_ALIASES[modelsDevProviderId] ?? modelsDevProviderId;
}
const LATEST_NAME_SUFFIX = /\s*\(latest\)$/i;
/**
* models.dev names versionless alias models with a " (latest)" suffix
* (e.g. `claude-opus-4-5` → "Claude Opus 4.5 (latest)"), which quickly goes
* stale as newer models ship. Strip the suffix from every model name, and when
* a pinned snapshot shares the resulting name with an alias (e.g.
* `claude-opus-4-5-20251101` "Claude Opus 4.5"), drop the snapshot so the
* alias is the single entry for that model.
*/
function normalizeLatestModelNames(models: Record<string, ModelInfo>): void {
const aliasNames = new Set<string>();
for (const model of Object.values(models)) {
if (LATEST_NAME_SUFFIX.test(model.name)) {
aliasNames.add(model.name.replace(LATEST_NAME_SUFFIX, ''));
}
}
for (const [modelId, model] of Object.entries(models)) {
if (LATEST_NAME_SUFFIX.test(model.name)) {
model.name = model.name.replace(LATEST_NAME_SUFFIX, '');
} else if (aliasNames.has(model.name)) {
delete models[modelId];
}
}
}
/**
* Fetch the provider/model catalog from models.dev.
*
@@ -146,6 +173,10 @@ export async function fetchProviderCatalog(): Promise<ProviderCatalog> {
};
}
for (const provider of Object.values(catalog)) {
normalizeLatestModelNames(provider.models);
}
return catalog;
}