diff --git a/apps/desktop/src/lib/model-status-label.test.ts b/apps/desktop/src/lib/model-status-label.test.ts index 58c03a3f122..78fe51492b1 100644 --- a/apps/desktop/src/lib/model-status-label.test.ts +++ b/apps/desktop/src/lib/model-status-label.test.ts @@ -10,6 +10,11 @@ describe('model-status-label', () => { expect(displayModelName('openai/gpt-5.5')).toBe('GPT-5.5') }) + it('strips trailing date-pin snapshots from the display name', () => { + expect(displayModelName('claude-opus-4-5-20251101')).toBe('Opus 4 5') + expect(displayModelName('anthropic/claude-haiku-4-5-20251001')).toBe('Haiku 4 5') + }) + it('maps reasoning effort to compact labels', () => { expect(reasoningEffortLabel('high')).toBe('High') expect(reasoningEffortLabel('xhigh')).toBe('Max') diff --git a/apps/desktop/src/lib/model-status-label.ts b/apps/desktop/src/lib/model-status-label.ts index 3a7d065cf17..60f0e81a959 100644 --- a/apps/desktop/src/lib/model-status-label.ts +++ b/apps/desktop/src/lib/model-status-label.ts @@ -68,6 +68,9 @@ export function modelDisplayParts(model: string): { name: string; tag: string } } } + // Drop a trailing date-pin (`…-20251101`) — snapshot noise, not a name. + base = base.replace(/-\d{8}$/, '') + return { name: prettifyBase(base) || model.trim() || 'No model', tag } } diff --git a/apps/desktop/src/store/model-visibility.test.ts b/apps/desktop/src/store/model-visibility.test.ts index ce78d1a6aa7..90eccdf457e 100644 --- a/apps/desktop/src/store/model-visibility.test.ts +++ b/apps/desktop/src/store/model-visibility.test.ts @@ -3,6 +3,7 @@ import { describe, expect, it } from 'vitest' import type { ModelOptionProvider } from '@/types/hermes' import { + collapseModelFamilies, effectiveVisibleKeys, emptyProviderSentinelKey, isProviderSentinel, @@ -78,6 +79,18 @@ describe('model visibility', () => { expect(visible.has(modelVisibilityKey('nous', 'hermes-3-llama-3.1-8b'))).toBe(false) }) + it('folds a date-pinned snapshot into its rolling alias when present', () => { + const families = collapseModelFamilies(['claude-opus-4-5', 'claude-opus-4-5-20251101']) + + expect(families.map(f => f.id)).toEqual(['claude-opus-4-5']) + }) + + it('keeps a date-pinned snapshot standing alone when it has no alias', () => { + const families = collapseModelFamilies(['claude-opus-4-5-20251101', 'claude-haiku-4-5-20251001']) + + expect(families.map(f => f.id)).toEqual(['claude-opus-4-5-20251101', 'claude-haiku-4-5-20251001']) + }) + it('sentinel key helper produces correct format', () => { expect(emptyProviderSentinelKey('openai')).toBe('openai::') expect(isProviderSentinel('openai::')).toBe(true) diff --git a/apps/desktop/src/store/model-visibility.ts b/apps/desktop/src/store/model-visibility.ts index de694fe3af5..5c2b568c596 100644 --- a/apps/desktop/src/store/model-visibility.ts +++ b/apps/desktop/src/store/model-visibility.ts @@ -51,6 +51,11 @@ export function collapseModelFamilies(models: readonly string[]): ModelFamily[] continue } + if (/-\d{8}$/.test(model) && present.has(model.replace(/-\d{8}$/, ''))) { + // A date-pinned snapshot superseded by its rolling alias — drop the dupe. + continue + } + const fastId = `${model}-fast` const hasFast = present.has(fastId) families.push({ fastId: hasFast ? fastId : null, id: model })