History

fix(models): compute "latest" badge from release_date, not a stale name tag

The model picker flagged "latest" whenever a model's catalog name contained "(latest)". That string goes stale the moment a newer model ships — e.g. Opus 4.8 and Sonnet 5 are out, but "Claude Opus 4.5 (latest)" / "Claude Sonnet 4.5 (latest)" kept the tag, so superseded models read as latest. The same staleness hit every provider whose catalog aliases lagged (openai, mistral, openrouter, …). Compute "latest" as the newest model per (provider, family) by release_date instead. Provider-agnostic, driven by real dates: within each family the model with the max release_date wins; models missing family/release_date are never flagged (no false positives). Deprecated models are already filtered upstream. Result for anthropic: Opus 4.8, Sonnet 5, Haiku 4.5, Fable 5 — not the old 4.5s. The "(latest)" suffix is still stripped from display names.

KB committed 4 months ago

Commit 421f5f41 parent 4301ed41 file · +26 −7Browse files

Unified · Split

frontend/workspace/src/context/models.tsx+26−7
@@ -44,13 +44,32 @@ export const { use: useModels, provider: ModelsProvider } = createSimpleContext( · 43 unmodified lines
44 return map44 return map
45 })45 })
46 46
47 const list = createMemo(() =>47 // "latest" = the newest model per (provider, family), decided by release_date
48 available().map((m) => ({48 // rather than a catalog "(latest)" name string. That string goes stale the
49 ...m,49 // moment a newer model ships — e.g. Opus 4.8 lands but 4.5 keeps the tag — so
50 name: m.name.replace("(latest)", "").trim(),50 // it mislabelled superseded models as latest across every provider.
51 latest: m.name.includes("(latest)"),51 const list = createMemo(() => {
52 })),52 const items = available()
53 )53 const newestByFamily = new Map<string, string>()
54 for (const m of items) {
55 const family = m.family?.trim()
56 const released = m.release_date?.trim()
57 if (!family || !released) continue
58 const key = `${m.provider.id}:${family}`
59 const current = newestByFamily.get(key)
60 if (!current || released > current) newestByFamily.set(key, released)
61 }
62 return items.map((m) => {
63 const family = m.family?.trim()
64 const released = m.release_date?.trim()
65 const latest = !!family && !!released && newestByFamily.get(`${m.provider.id}:${family}`) === released
66 return {
67 ...m,
68 name: m.name.replace("(latest)", "").trim(),
69 latest,
70 }
71 })
72 })
54 73
55 const find = (key: ModelKey) => list().find((m) => m.id === key.modelID && m.provider.id === key.providerID)74 const find = (key: ModelKey) => list().find((m) => m.id === key.modelID && m.provider.id === key.providerID)
56 75