LLM new model release April 2026: the three-substring picker that absorbs every release without a new build.
April 2026 shipped Claude 4, Claude Mythos preview, GPT-5 Turbo, Gemma 4 across four variants, Llama 4 Scout with a 10M context, Qwen 3 under Apache 2.0, GLM-5.1 under MIT. Every recap renders the wave as a spec-sheet table. This page is not about the spec sheet. It is about the 60 lines of Swift and 10 lines of TypeScript that let a shipped consumer Mac agent absorb any of those model IDs the day they land, without a new release. The entire adaptation layer is three substring keys plus a one-line fallback plus an emit-if-changed forwarder. It is the thing you cannot see from a roundup, because it runs inside the binary on the user's Mac.
Models named in every April 2026 release recap
What the top results for this keyword all cover, and what every one of them misses.
I searched the exact phrase. The first page is consistent: llm-stats.com, aiflashreport.com, pricepertoken.com, whatllm.org, plus Fazm's own blog pages ranking on adjacent queries. Every one of them lists the April 2026 releases as a spec-sheet table, four or five columns: parameters, context window, license, provider stack, benchmark ELO. Claude Opus 4 for extended autonomous coding. Claude Mythos previewed to 50 partners through Project Glasswing. GPT-5 Turbo shipped April 7 with native image and audio in one model. Gemma 4 in four variants under Apache 2.0. Llama 4 Scout with a 10M context window. Qwen 3. GLM-5.1. DeepSeek V3.2. Every recap hits the same points.
None of them describes what a shipped consumer agent on a user's Mac literally does in code when a new model ID lands on its ACP SDK response. A desktop app does not get to redeploy the binary every time Anthropic bumps a snapshot. So it either hardcodes a model list (and breaks on every release), or it builds a dynamic detection path. Fazm does the second, and the entire path is about 70 lines spread across two files.
The 70 lines are the spine of this page.
The picker, lifted verbatim.
Read the lines yourself. This is ShortcutSettings.swift from 150 to 212, minus the lines that are not part of the new-model path (the UserDefaults persistence, the selectedModelShortLabel accessor). Every structural element of the adaptation layer fits in one screen.
“When a new Claude snapshot ships in April 2026, the entire Fazm-side adaptation is three substring keys, one fallback branch, and a JSON-diff. The picker survives because the model family is resolved at runtime from the ACP SDK, not hardcoded in the binary.”
ShortcutSettings.swift lines 159 to 189
Four family paths, each pinned to a line.
The modelFamilyMap at line 159 holds three entries. A fourth, implicit path exists at line 189 for everything else. These are the only four branches the picker ever takes.
haiku (order 0)
Substring keyword at modelFamilyMap[0], ShortcutSettings.swift line 160. Any modelId containing "haiku" renders as "Scary (Haiku, latest)" regardless of snapshot version.
sonnet (order 1)
Substring keyword at modelFamilyMap[1], line 161. claude-sonnet-4-6, claude-sonnet-4-7, any future Sonnet ID all collapse to "Fast (Sonnet, latest)".
opus (order 2)
Substring keyword at modelFamilyMap[2], line 162. claude-opus-4-6, the future claude-opus-5, all render as "Smart (Opus, latest)". No new release needed.
unknown family (order 99)
Fallback branch at line 187-189. Any modelId that does not match a keyword is displayed with its SDK-reported model.name. That is how Claude Mythos would show up without a code change.
empty-name guard (line 188)
'let displayName = model.name.isEmpty ? modelId : model.name'. If the SDK sends a model with no friendly name, the raw ID is the label. Never blank.
stable sort key (line 189 + sorted)
order 99 sits after known families. Every unknown-family model lands below Haiku / Sonnet / Opus in the picker, in the order the SDK reported them.
The bridge forwarder, lifted verbatim.
The Swift picker only works if it receives a fresh list. That job belongs to emitModelsIfChanged at acp-bridge/src/index.ts line 1271. Ten lines of TypeScript. Filter, diff, send. Called from every session/new response at lines 1347, 1361, and 1491.
How a new model ID flows from Anthropic's release notes to the picker on your Mac
April 2026 new-model wave arrives. What happens on the user's Mac?
The app ships a JSON or enum of supported model IDs at compile time. When Claude Mythos preview lands on April 7, the user sees a fixed list from the last release. Selecting an unsupported model surfaces a Model not found error. To support the new model, the team has to release a new binary, get it through notarization, push it through auto-update, and hope every user installs it within days of the release.
- Static model list in the binary
- New model needs a new release
- Auto-update bottleneck
- User sees Model not found until they update
- One binary per provider snapshot
- UI tied to a specific ID scheme
From Anthropic release note to a selectable button on the user's Mac
Anthropic ships a new model ID (hypothetical: claude-mythos-preview-20260407)
Announcement lands. User updates their ACP SDK package (pinned at acp-bridge/package.json to @agentclientprotocol/claude-agent-acp ^0.29.2 as of mid-April 2026). No Fazm binary update.
Fazm pre-warms a session on next app launch
acp-bridge/src/index.ts calls acpRequest("session/new", sessionParams) at line 1488. The SDK returns { sessionId, models: { availableModels: [...] } } with the new Mythos ID in the array.
emitModelsIfChanged fires at line 1491
Line 1274 filters out the "default" pseudo-model. Line 1277 JSON-diffs the new list against the last one. Line 1279 sends { type: "models_available", models: filtered } over stdout to the Swift side.
ACPBridge.swift line 1131 matches the case
case "models_available": parses the models array, logs "received models_available with N models" at line 1203, then calls the handler registered by ChatProvider.swift line 1016 via setModelsAvailableHandler.
ShortcutSettings.updateModels runs at line 178
For each incoming model, line 183 substring-matches against (haiku, sonnet, opus). "mythos" does not contain any of those, so the fallback at lines 187 to 189 fires. ModelOption is built from model.name (or the raw modelId if empty) with order 99.
@Published availableModels re-publishes at line 166
SwiftUI's ForEach at SettingsPage.swift line 2025 (ForEach(shortcutSettings.availableModels) { model in preferencesModelButton(model) }) receives the new array and renders a fourth button: Claude Mythos Preview, positioned after Scary, Fast, Smart.
User clicks the new button
ShortcutSettings.selectedModel is set to claude-mythos-preview-20260407 (the raw ID, persisted via UserDefaults at line 140). Next prompt sends msg.model=claude-mythos-preview-20260407 over the bridge. index.ts line 1426 picks it up ahead of DEFAULT_MODEL, calls session/set_model at line 1495.
Everything else keeps working.
The prompt stream, the rate-limit forwarder at patched-acp-entry.mjs line 132, the cost meter, the per-prompt usage accounting, the compaction banner, all ride on the ACP wire protocol and are model-agnostic. The picker was the only surface that had to adapt. It did, in zero lines of new code.
Eight messages, five actors, one new model
Grep it yourself.
Every claim on this page is two greps away from verification. Clone the Fazm source (the repo is public atgithub.com/mediar-ai/fazm) and run these.
Hardcoded model list vs the Fazm dynamic picker
| Feature | Typical hardcoded-list consumer agent | Fazm (ShortcutSettings.swift + index.ts) |
|---|---|---|
| Model list source | Hardcoded JSON or enum in the binary | session/new.models.availableModels, re-emitted at index.ts line 1279 |
| New-model support requires an app update? | Yes, each new ID means a release | No, substring match + fallback at ShortcutSettings.swift lines 183 to 189 |
| Label convention for known families | Provider's marketing name | (short) (family, latest) at line 184, e.g. "Smart (Opus, latest)" |
| Unknown-family model handling | Dropped or shown as unsupported | API name fallback at line 188, sort order 99, still selectable |
| De-dup of model list updates | Re-renders on every session event | JSON-string diff at line 1277 against lastEmittedModelsJson |
| Default when no model specified | Often undefined or provider default | const DEFAULT_MODEL = "claude-sonnet-4-6" at index.ts line 1245 |
| Legacy ID normalization | Manual mapping table per version | normalizeModelId at line 169, three contains() checks, fallback returns the raw ID |
| Persistence across launches | Tied to hardcoded list; breaks when list changes | UserDefaults at line 140 stores the raw modelId; picker re-finds it via the ACP-reported list |
Fourteen independently grep-verifiable claims
- ShortcutSettings.swift line 151: three ModelOptions as defaults (haiku, sonnet, opus)
- Line 159: modelFamilyMap tuple with (substring, short, family, order)
- Lines 160 to 162: exactly three substring keys (haiku / sonnet / opus)
- Line 166: @Published var availableModels, initialized from defaultModels
- Lines 169 to 175: normalizeModelId with three contains() checks
- Line 178: updateModels(_:) receives acpModels from the bridge
- Line 183: modelFamilyMap.first { modelId.contains($0.substring) } substring match
- Line 184: label template '(short) (family, latest)'
- Lines 187 to 189: unknown-family fallback with order 99 and model.name display
- index.ts line 1245: const DEFAULT_MODEL = "claude-sonnet-4-6"
- index.ts line 1271: emitModelsIfChanged signature
- index.ts line 1274: filter out the "default" pseudo-model
- index.ts line 1277: JSON-string diff against lastEmittedModelsJson
- index.ts line 1279: send({ type: "models_available", models })
Why three keys, not a full list.
Anthropic ships snapshot versions constantly. CHANGELOG.json at the Fazm repo root shows the churn: version 2.0.6 on 2026-04-04 added a Smart / Fast model toggle for Opus and Sonnet, version 2.0.7 on 2026-04-05 fixed a silent failure when a personal Claude account lacks access to the selected model. In between those two releases, the codebase already saw claude-sonnet-4-6 set as the default at index.ts line 1245 and claude-opus-4-6 referenced by users whose accounts hit access issues. A hardcoded list of full IDs would need updating on both days.
A substring keyword like "sonnet" at modelFamilyMap[1] matches claude-sonnet-4-6, claude-sonnet-4-7, and any future Sonnet snapshot, with no code change. The (latest) suffix at the label template on line 184 is a side effect of the family always resolving to whatever the ACP SDK reports today.
The unknown-family fallback at line 189 handles everything else. Claude Mythos, the next post-Opus codename, a hypothetical GPT-5 adapter, they all render with their SDK-reported model.name and land at sort-order 99 in the picker. The picker does not care what the spec sheet says. It cares what session/new returned.
See the three-substring picker absorb a new model in under a second, live.
15-minute demo: drop a new model ID into the ACP SDK surface, watch the Fazm picker re-render with the new button without a rebuild.
Book a call →Frequently asked questions
What LLMs shipped in April 2026?
The April 2026 release wave every roundup is tracking: Anthropic shipped the Claude 4 family on April 2 (Opus 4 as flagship for extended autonomous coding, Sonnet and Haiku tiers), previewed Claude Mythos on April 7 through Project Glasswing to roughly 50 partners, OpenAI shipped GPT-5 Turbo on April 7 with native image and audio inside one model, and Google released four Gemma 4 variants under Apache 2.0 on April 2. Open-source side: Meta Llama 4 Scout (10M context MoE), Alibaba Qwen 3 (Apache 2.0, 128K), Zhipu GLM-5.1 (MIT, 200K, 754B MoE), Mistral Medium 3 (open weights), DeepSeek V3.2 (128K), Arcee Trinity (400B, Apache 2.0). Every recap lists the same spec-sheet columns: parameters, context window, license, benchmark score.
What do the April 2026 LLM release roundups miss?
They miss the code a shipping consumer agent runs when a new model ID arrives on its ACP SDK response. A desktop app like Fazm does not get to redeploy the binary every time Anthropic ships a new snapshot. So it either hardcodes a model list (and breaks the day Claude Mythos lands) or it builds a dynamic detection path. Fazm does the second. The adaptation layer is about 60 lines of Swift plus a 10-line bridge forwarder, and it is the thing a reader cannot see from a spec-sheet table because it lives inside the shipping app, not in the Anthropic release notes.
Where in the Fazm source is the new-model adaptation layer?
Two files. First, /Users/matthewdi/fazm/Desktop/Sources/FloatingControlBar/ShortcutSettings.swift, lines 150 to 212. Line 151 is defaultModels (three fallback ModelOptions). Line 159 is the modelFamilyMap with three substring keys: haiku, sonnet, opus. Line 169 is normalizeModelId. Line 178 is updateModels(_:) which receives the ACP SDK's availableModels array. Line 184 is the matched-family label template: (short) (family, latest). Line 189 is the unknown-model fallback that shows the raw API name. Second, /Users/matthewdi/fazm/acp-bridge/src/index.ts, lines 1245 to 1281. Line 1245 pins the default to claude-sonnet-4-6. Line 1271 is emitModelsIfChanged which re-broadcasts session/new.models.availableModels to the Swift side every time the ACP SDK reports a new list.
What happens on the user's Mac the day Anthropic ships a new model ID?
Five concrete steps, each pinned to a file and line. 1. acp-bridge calls acpRequest("session/new", sessionParams) at index.ts line 1488. 2. The ACP SDK returns a models.availableModels array with the new model ID included. 3. emitModelsIfChanged at line 1271 filters out the "default" pseudo-model (line 1274), diffs against lastEmittedModelsJson, and sends a { type: "models_available", models } message to Swift. 4. ACPBridge.swift hits the "models_available" case at line 1131 and dispatches to the handler registered at line 233 via setModelsAvailableHandler. 5. ShortcutSettings.updateModels at line 178 substring-matches the new ID against (haiku, sonnet, opus), produces a ModelOption, and re-publishes @Published var availableModels at line 166. The Settings page at SettingsPage.swift line 2025 iterates shortcutSettings.availableModels and renders the button. No app update, no redeploy.
What does the unknown-model fallback look like in code?
Three lines at ShortcutSettings.swift 187 to 189: '// Unknown model family: use the API name directly' then 'let displayName = model.name.isEmpty ? modelId : model.name' then 'return (ModelOption(id: modelId, label: displayName, shortLabel: displayName), 99)'. The 99 is a deliberate sort order key so any unknown family sits after the three known ones. That branch is what turns claude-mythos-preview-20260407 (or whatever future ID Anthropic picks) into a selectable button labeled Claude Mythos Preview drawn from the SDK's model.name.
Why three substrings and not a full model ID list?
Because Anthropic ships snapshot versions constantly. In the April 2026 window alone, claude-sonnet-4-6 is the default at index.ts line 1245, claude-opus-4-6 shows up in user accounts (CHANGELOG.json v2.0.7 on 2026-04-05: "Fixed chat failing silently when personal Claude account lacks access to the selected model"), and claude-haiku-4-5 has been in the mix since late 2025. A full list grows and rots. A three-keyword substring match at line 183 (modelId.contains(match.substring)) absorbs every future Haiku, Sonnet, or Opus snapshot. The (latest) label at line 184 is not a marketing promise, it is a consequence of the model family always resolving to whatever the ACP SDK reports today.
What is the label template when a family match succeeds?
ShortcutSettings.swift line 184: 'let label = "\(match.short) (\(match.family), latest)"'. With the three hardcoded entries at lines 160-162, this renders as "Scary (Haiku, latest)", "Fast (Sonnet, latest)", "Smart (Opus, latest)". The short and family strings are pinned in the modelFamilyMap tuple. The order integer at position 3 of each tuple (0 for haiku, 1 for sonnet, 2 for opus) feeds the .sorted(by:) at line 191.
How is the default model pinned, and how does Fazm fall back when a user does not have access to the selected one?
The default lives at one line: acp-bridge/src/index.ts line 1245, 'const DEFAULT_MODEL = "claude-sonnet-4-6";'. Line 1426 picks it up as the fallback when a prompt arrives without a modelId: 'const requestedModel = msg.model || DEFAULT_MODEL;'. For the case where the user's personal Claude account does not have access to the requested model, the v2.0.7 changelog entry on 2026-04-05 describes the auto-fallback to the built-in account. That is a separate code path from the picker: the picker shows what the SDK reports; the account-fallback kicks in after a 402 or access-denied on the request itself.
Does the bridge de-duplicate model updates, and why does that matter?
Yes, at index.ts line 1277: 'if (json === lastEmittedModelsJson) return;'. Without that guard, every session/new call (main session, floating session, observer session, each is pre-warmed separately) would emit a duplicate models_available message to the Swift side, which would retrigger ShortcutSettings.updateModels, which would re-compute the ModelOption array and re-publish availableModels. The SwiftUI ForEach at SettingsPage.swift line 2025 would re-render the picker every few seconds. The JSON-string diff at line 1276 keeps the UI steady.
How do I verify all of this myself?
Two greps. First, 'grep -n modelFamilyMap /Users/matthewdi/fazm/Desktop/Sources/FloatingControlBar/ShortcutSettings.swift' shows line 159. Read lines 159 to 175 inline to see the three substrings and the normalize function. Second, 'grep -n emitModelsIfChanged /Users/matthewdi/fazm/acp-bridge/src/index.ts' shows lines 1271 and 1281. Read lines 1271 to 1281 to see the filter-out-default, diff-against-last, send-to-Swift pipeline. Every claim on this page resolves to those two passages.
Does Fazm work with models that are not Claude?
The bridge process wraps ClaudeAcpAgent, so the ACP SDK is the source of truth for what modelId strings are valid. The substring-family map (haiku, sonnet, opus) is Claude-specific by design; anything outside those three families hits the unknown-model fallback at line 189 and shows up in the picker with its API-reported name. The accessibility-tree capture, the floating bar UI, and the prompt-to-session plumbing are model-agnostic. The picker is not.
Why does this matter for the broader April 2026 new-model release story?
Because the difference between a consumer agent that survives a model release and one that breaks is a handful of lines. The April 2026 releases (Claude 4 family, Claude Mythos preview, GPT-5 Turbo, Gemma 4, Llama 4 Scout, Qwen 3, GLM-5.1) are all shipping behind evolving SDK surface areas. An agent that hardcodes a model list ships a new binary every time a provider bumps a version. An agent that dynamically discovers models (via session/new.models.availableModels in the ACP case) stays on the user's Mac through the whole release wave. The 60-line picker and the 10-line bridge forwarder are the entire delta between those two worlds.
Related guides on the same bridge process
Open source LLM releases 2026 news: the runtime layer every recap leaves out
Sibling guide. Same bridge process, different angle: the 267-line patched-acp-entry.mjs that re-forwards ten dropped ACP session events and augments every prompt return with nine fields.
How extra usage works with Claude
The eight-field RateLimitMessage shape the same bridge receives when the model (whichever April 2026 release) hits a weekly or five-hour ceiling.
Claude Sonnet 4 to 4.6 and Opus for agent work
What changed in the Claude family between snapshot bumps: tool-call reliability, planning depth, the 1M context window. The picker on this page renders those as (latest) automatically.
Comments (••)
Leave a comment to see what others are saying.Public and anonymous. No signup.