April 2026 Open Source LLMs

New Open Source LLM Release April 2026: What Gemma 4, GLM-5.1, Qwen 3.6-Plus and DeepSeek V3.2 Actually Look Like Inside a Shipping Consumer Mac AI App

Every April 2026 open-source LLM roundup lists params, license, and benchmark scores. None of them show what those releases look like from inside a real consumer Mac AI agent. Fazm’s answer is two small pieces of code: acp-bridge/src/index.ts line 1274 (the entire bridge allowlist is one !== condition) and ShortcutSettings.swift lines 159 to 163 (a three-row substring table). Together they decide whether your Gemma 4 or GLM-5.1 lands as a first-class “Smart” button or at sort order 99 with its raw modelId.

F
Fazm
5.0from Fazm source tree
Bridge allowlist: 1 condition (index.ts:1274)
Swift substring table: 3 rows (ShortcutSettings.swift:159-163)
Unknown-family fallback: order 99 (ShortcutSettings.swift:189)

What open-source actually shipped in April 2026

Six major releases across labs. Each one reaches Fazm through the same pipe and lives or dies by the same two pieces of code.

Gemma 4 (Apache 2.0, Apr 2)GLM-5.1 (MIT, 754B MoE, 37B active)Qwen 3.6-Plus (1M-ctx)DeepSeek V3.2 (Apr 11)Mistral Small 3.2 (Apache 2.0)PrismML Bonsai 8BLlama 4 Maverick fine-tunesvLLM 0.8.xllama.cpp Gemma 4 arch supportLiteLLM 1.67.xCloudflare AI GatewayAnthropic-compatible /messages shimACP session/set_modelmodelId !== 'default'order = 99gemma-4-27bglm-5.1-chatqwen-3.6-plusdeepseek-chat-v3.2availableModels

The substring table: seven lines that decide Gemma 4’s label

This is the literal source from Desktop/Sources/FloatingControlBar/ShortcutSettings.swift, lines 157 to 163. It recognizes exactly three substrings. Anything else lands in the fallback branch.

ShortcutSettings.swift:157-163
0Substrings recognized by Swift
0Filter conditions on the bridge
0Sort order for unknown families
0+Open-source LLMs April shipped
0Fazm app rebuilds required
0GitHub lines for modelFamilyMap
1 condition

Filter out the 'default' pseudo-model - it's not a real selectable model

acp-bridge/src/index.ts, comment above line 1274

The bridge allowlist: one condition, end of list

This is the complete model-filtering logic on the Node side. Eleven lines total, one condition that matters. Every April 2026 open-source LLM rides through this unchanged.

acp-bridge/src/index.ts:1271-1281

The Swift side: substring match or fallback to order 99

This is where the label on a “Gemma 4 27B” or “GLM-5.1 Chat” button is decided. Every non-Claude modelId falls through to line 187-189.

ShortcutSettings.swift:178-192

How four April 2026 open-source LLMs route through the pipe

Four sources on the left: the big April 2026 open-source releases. Four destinations on the right: the picker positions they can land in. The hub is the substring-match gate. Only the fourth destination (order 99) ever fires for a non-Claude modelId.

April 2026 open-source LLM → substring-match gate → picker bucket

Gemma 4
GLM-5.1
Qwen 3.6-Plus
DeepSeek V3.2
substring match
Scary
Fast
Smart
Raw modelId

Each April 2026 release, mapped to its Fazm-side fate

Six cards. Each one is a specific open-source release plus the exact line in Fazm that decides what it looks like in the Settings picker.

Google Gemma 4 (Apache 2.0, April 2)

Multimodal open weights in 2B/9B/27B sizes. Through a LiteLLM proxy exposing an Anthropic /messages shape for Gemma 4, the modelId 'gemma-4-27b' reaches emitModelsIfChanged at index.ts:1279. ShortcutSettings.swift:183 runs 'gemma-4-27b'.contains('haiku'/'sonnet'/'opus') → all three false. Falls to line 189. Button: 'Gemma 4 27B'. Position: 99.

Zhipu GLM-5.1 (MIT, 754B MoE)

37B active params, MIT license. Served through vLLM 0.8.x plus an OpenAI-to-Anthropic shim, the modelId 'glm-5.1-chat' hits the unknown-family branch. Button renders as 'GLM-5.1 Chat' at order 99. The 754B total weights are irrelevant to Fazm; only the modelId string and the proxy's /messages response shape matter at this boundary.

Alibaba Qwen 3.6-Plus (1M-ctx)

1M-token context survives the Fazm session hop because ACP stores conversation memory in the SDK's ~/.claude/projects/ file, not in the bridge process. The modelId 'qwen-3.6-plus' sorts to 99; the context capacity rides through session/prompt unchanged.

DeepSeek V3.2 (April 11)

Chinese-lab flagship, DeepSeek license. Via OpenRouter or a self-hosted shim, surfaces as 'deepseek-chat-v3.2'. No substring match. Fallback branch. The user can flip floating onto DeepSeek for one question, observer stays on Sonnet, main stays on Sonnet, because the three sessions are role-keyed at ChatProvider.swift:1047-1051.

Mistral Small 3.2 + PrismML Bonsai 8B + Llama 4 fine-tunes

Three smaller Apache 2.0 releases. Each arrives as a raw modelId; each sorts to 99. Bonsai 8B's practical pitch (runs on 16GB MacBook via llama.cpp Q4) is visible only as the label string — the runtime cost is hidden from Fazm behind the proxy. The bridge has no 'local vs hosted' awareness at this layer.

The one that does NOT surface

modelId = 'default'. Line 1274 strips it. This is an ACP SDK pseudo-model that represents whatever the subprocess is running. If a misconfigured proxy reports 'default' for a real model, that model disappears. Everything else — every actual Claude, every April 2026 open-source LLM — flows through.

Same input shape, two fates: Claude-native vs April 2026 open-source

Identical flow, identical data structure, different outcome. The substring match at line 183 is the single branch that decides which bucket a new open-source LLM lands in.

The same updateModels call, two branches, two picker positions

// Input: Claude-native modelId
// acpModels = [{ modelId: "claude-opus-4-7", name: "Claude Opus 4.7" }]

// ShortcutSettings.swift:183
if let match = modelFamilyMap.first(where: {
  modelId.contains($0.substring)   // "claude-opus-4-7".contains("opus") == true
}) {
  // match = (substring: "opus", short: "Smart", family: "Opus", order: 2)
  let label = "Smart (Opus, latest)"
  return (ModelOption(
    id: "claude-opus-4-7",
    label: "Smart (Opus, latest)",
    shortLabel: "Smart"
  ), 2)
}

// Renders at position 2 in the picker with a tier alias.
-12% fewer lines

What a new open-source LLM needs to surface in Fazm’s picker

Eight requirements. None of them live inside Fazm. All of them live in the proxy that fronts the model.

Requirements on the proxy side

  • Proxy exposes Anthropic-compatible /v1/messages endpoint
  • Proxy implements ACP session/new returning { sessionId, models: { availableModels: [...] } }
  • Proxy implements ACP session/prompt streaming text deltas
  • Proxy implements ACP session/set_model for mid-chat swaps
  • Claude Agent SDK pointed at the proxy's base URL
  • Model's modelId is not literally the string 'default' (would hit the index.ts:1274 filter)
  • Model's modelId string can contain anything else (the substring table only recognizes haiku/sonnet/opus)
  • Model's returned name field becomes the picker label; empty name falls back to modelId

Watching Gemma 4 land in the bridge log

This is a clipped log from a Fazm dev build (/tmp/fazm-dev.log) on a boot where the Claude Agent SDK is pointed at a LiteLLM proxy that fronts Claude plus four April 2026 open-source LLMs. The raw-list and emit log lines come from index.ts lines 1272 and 1280.

acp-bridge stderr

Timeline: open-source weights → Fazm picker button

Seven steps. Five of them happen outside Fazm. The two inside Fazm (steps 4 and 6) are the ones with the exact file:line anchors.

1

1. Open-source lab publishes weights

April 2: Google ships Gemma 4 under Apache 2.0. April 11: DeepSeek ships V3.2. Each release is on Hugging Face within hours. Serving stack (vLLM 0.8.x, llama.cpp) lights up architecture support within days. Nothing inside Fazm knows yet.

2

2. User points ACP SDK at an Anthropic-compatible proxy

LiteLLM, Cloudflare AI Gateway, or a hand-rolled shim that translates Anthropic /v1/messages into whatever Gemma 4 or GLM-5.1 speaks. The proxy also has to implement the ACP session methods that the Claude Agent SDK uses: session/new, session/prompt, session/set_model. Without the last one, Fazm's mid-chat model swap breaks.

3

3. Proxy enumerates available models to the SDK

On session/new, the proxy returns result.models.availableModels = [claude family, gemma-4-27b, glm-5.1-chat, qwen-3.6-plus, deepseek-chat-v3.2]. The Claude Agent SDK hands this list back through its stdio RPC to acp-bridge. No transformation happens in the SDK; it is a pass-through.

4

4. acp-bridge logs the raw list and filters

index.ts:1272 writes 'Raw models from ACP SDK: [...]' to stderr. Line 1274 removes any entry with modelId === 'default'. Line 1276 stringifies and diffs against lastEmittedModelsJson. If different, line 1279 sends the models_available event to the Swift side. The JSON diff cache means a list that repeats across multiple session warm-ups emits once.

5

5. ACPBridge.swift decodes and forwards to ShortcutSettings

The Swift side receives the JSON line, decodes the models array, and calls ShortcutSettings.updateModels. updateModels (line 178) iterates acpModels, applies the substring match, builds a new [ModelOption, Int] tuple per entry, sorts by the Int, and strips the Int to produce the final [ModelOption] array.

6

6. Substring match decides each model's fate

'claude-haiku-4-5' → 'haiku' match → ('Scary (Haiku, latest)', 0). 'claude-sonnet-4-6' → 'sonnet' → ('Fast (Sonnet, latest)', 1). 'claude-opus-4-7' → 'opus' → ('Smart (Opus, latest)', 2). 'gemma-4-27b' → no match → ('Gemma 4 27B', 99). Same fallback for GLM-5.1, Qwen 3.6-Plus, DeepSeek V3.2.

7

7. Sort and publish

Line 191 sorts by the Int. Line 192 strips the Int. Line 196 assigns to availableModels (a @Published var). SwiftUI re-renders SettingsPage.swift:2025 where ForEach(availableModels) draws the picker. The user sees: Scary, Fast, Smart, Gemma 4 27B, GLM-5.1 Chat, Qwen 3.6-Plus, DeepSeek V3.2. Click any one; next message routes through it via session/set_model.

Full trace: from Hugging Face to a picker click to a session/set_model call

Fifteen messages across seven actors. The proxy implements Anthropic’s /messages plus ACP; the Claude Agent SDK does not know it is talking to anything other than its usual endpoint; acp-bridge applies the one-condition filter; ShortcutSettings applies the three-substring match and the order-99 fallback.

Gemma 4 arrives via LiteLLM, becomes a picker button, gets clicked

HuggingFaceGemma 4 serverLiteLLM proxyClaude Agent SDKacp-bridge (Node)ShortcutSettings.swiftUser (picker)pull google/gemma-4-27b weightsconfigure route: model 'gemma-4-27b' → Gemma 4 serversession/new { cwd, mcpServers }{ sessionId, models.availableModels: [..., {modelId: 'gemma-4-27b', ...}] }availableModels = [...] (ACP SDK stdio)filter(m => m.modelId !== 'default') (index.ts:1274)send { type: 'models_available', models: [...] } (index.ts:1279)substring: 'gemma-4-27b'.contains('haiku'/'sonnet'/'opus') → all false (line 183)fallback branch: (ModelOption('gemma-4-27b', 'Gemma 4 27B', 'Gemma 4 27B'), 99) (line 189)@Published availableModels re-render: 'Gemma 4 27B' appears at position 99user clicks 'Gemma 4 27B'selectedModel = 'gemma-4-27b' (ShortcutSettings.swift:140)next message: query(model: 'gemma-4-27b', sessionKey: 'floating')session/set_model { sessionId, modelId: 'gemma-4-27b' }session/prompt routed to Gemma 4 via the proxy

The path most desktop AI agents take vs the path Fazm took

The split is at whether the model roster lives in app code or in an external proxy. If it lives in app code, every new open-source LLM release is an app-release event. If it lives in a proxy (via a permissive substring table), releases decouple entirely.

New open-source LLM ships: 'Gemma 4, April 2, 2026'

Naive desktop-agent architecture: A hardcoded enum of supported modelIds. New open-source LLM ships. User has to wait for a new app build that adds 'gemma-4-27b' to the enum, re-signs the binary, goes through code signing and notarization, and ships a point release. Meanwhile the model has been on Hugging Face for a week.

  • Hardcoded modelId enum
  • New release blocked on app-update
  • Notarization gates every vendor adapter
  • Users stuck on last-shipped models

Fazm’s path vs the hardcoded-roster path

Eight rows. Each row is a concrete behavioral difference, each tied to a file:line anchor that a reader can verify inside the shipping open-source repo at github.com/mediar-ai/fazm.

FeatureHardcoded-roster pathFazm (permissive table path)
Bridge-side filterHardcoded vendor allowlist or a model manifest fileOne condition: modelId !== 'default' (index.ts:1274)
Claude-family detectionEnum of exact modelIds that requires an update per releaseSubstring match against 3 rows (ShortcutSettings.swift:159-163)
Unknown-family fallbackRejected, hidden from picker, or thrown as an errorRaw modelId as label, order 99, renders at end (line 189)
App update needed when Gemma 4 shipsNew app build with the new modelId wired into an enumNone; arrives via proxy, surfaces automatically next launch
Observer session target when user flips to Gemma 4Follows the foreground pick or has no separate observerStill claude-sonnet-4-6 (hardcoded at ChatProvider.swift:1050)
Where to verify the open-source-model UI fateScattered across vendor adapters and UI codeTwo files, seven lines total (ShortcutSettings.swift:159-163,189 + index.ts:1274)
What appears when two April 2026 open-source LLMs arrive togetherOne absorbs the other or both get a generic 'Other' labelTwo buttons, both order 99, stable order preserved
Source visibilityClosed source or selectively published adapters onlygithub.com/mediar-ai/fazm (ChatPrompts.swift:172, OnboardingView.swift:456)

See a Gemma 4 or GLM-5.1 button appear in a live Fazm picker

Book a 20-minute demo. We will point the Claude Agent SDK at a LiteLLM proxy in front of an April 2026 open-source LLM and watch the new button show up in Settings at order 99 with its raw modelId.

Book a call

FAQ

Frequently asked questions

What new open source LLMs shipped in April 2026?

The most significant April 2026 open-source releases: Google Gemma 4 (Apache 2.0, April 2), Zhipu GLM-5.1 (MIT, 754B MoE with 37B active), Alibaba Qwen 3.6-Plus (1M-token context, Tongyi license), DeepSeek V3.2 (DeepSeek license, April 11), Mistral Small 3.2 (Apache 2.0, early April), and PrismML Bonsai 8B (Apache 2.0). On the tooling layer, vLLM 0.8.x and llama.cpp both shipped architecture support within days. Fazm's bridge does not care which of these a user routes through; the allowlist at acp-bridge/src/index.ts line 1274 filters only modelId !== 'default'.

Can Fazm use a new open source LLM from April 2026 without a Fazm update?

Yes, via an Anthropic-compatible proxy. The Claude Agent SDK that acp-bridge spawns accepts a custom base URL. Point that at a proxy like LiteLLM, Cloudflare AI Gateway, or a self-hosted OpenAI-to-Anthropic shim, configure the proxy to route to Gemma 4 or GLM-5.1, and the bridge will emit the model as-is through emitModelsIfChanged at index.ts line 1271. The Swift side at ShortcutSettings.swift line 178 accepts any modelId without validation and renders a button for it. No Fazm rebuild required.

Why does Fazm ship with only Claude support in the model picker today?

The default path uses Anthropic's Claude Agent SDK over ACP (Agent Client Protocol), and that SDK's availableModels response returns the three Claude families. Fazm does not maintain its own model adapter layer; it forwards whatever the ACP SDK hands back. This is a deliberate choice: every model that Fazm surfaces has already passed the ACP SDK's tool-calling and session-state contracts. For an April 2026 open-source LLM to appear, it has to be fronted by a proxy that speaks Anthropic's /messages shape and respects the ACP session/prompt and session/set_model methods.

What happens to a new open source LLM's name in Fazm's picker?

ShortcutSettings.swift line 183 runs modelId.contains(substring) against the three-entry modelFamilyMap at lines 159 to 163. The substrings are exactly 'haiku', 'sonnet', 'opus'. 'gemma-4-27b' contains none of those, so line 187 to 189 kicks in: the label becomes the API 'name' field (or the raw modelId if name is empty), shortLabel becomes the same string, sort order becomes 99. Visually, Gemma 4 renders at the bottom of the picker as a full-width button with 'gemma-4-27b' as its label, no tier alias. GLM-5.1 would be 'glm-5.1-chat'. Qwen 3.6-Plus would be 'qwen-3.6-plus'. DeepSeek V3.2 would be 'deepseek-chat-v3.2'.

What is the exact allowlist on the bridge side?

One line: acp-bridge/src/index.ts line 1274 reads const filtered = availableModels.filter(m => m.modelId !== 'default'). That is the entire model filter. There is no family check, no Claude check, no vendor check, no version check. Anything the ACP SDK hands back (minus the 'default' pseudo-model) gets forwarded to the Swift picker via send({ type: 'models_available', models: filtered }) at line 1279. For a new open-source LLM to be rejected, the proxy fronting it would have to report its modelId as literally the string 'default'.

How many substrings does the Swift side actually recognize?

Three. ShortcutSettings.swift lines 159 to 163 define private static let modelFamilyMap with exactly three rows: ('haiku', 'Scary', 'Haiku', 0), ('sonnet', 'Fast', 'Sonnet', 1), ('opus', 'Smart', 'Opus', 2). Any modelId that does not contain one of those three substrings falls to the line 187-189 branch: (ModelOption(id: modelId, label: displayName, shortLabel: displayName), 99). A contributor who wanted to add 'Gemma' as a first-class family ('Fast-OSS', order 3) would add exactly one row to this table.

What does the log line look like when a new open source LLM arrives via proxy?

Two lines at index.ts line 1272 and line 1280, both going to stderr which becomes /tmp/fazm-dev.log. Line 1272: 'Raw models from ACP SDK: [{modelId:"gemma-4-27b",name:"Gemma 4 27B",description:"..."},{modelId:"claude-sonnet-4-6",name:"..."},...]'. Line 1280: 'Emitted models_available: gemma-4-27b=Gemma 4 27B, claude-sonnet-4-6=Claude Sonnet 4.6, ...'. Then on the Swift side ShortcutSettings.swift line 198 logs: 'ShortcutSettings: updated availableModels to [claude-haiku-4-5 = Scary (Haiku, latest), claude-sonnet-4-6 = Fast (Sonnet, latest), claude-opus-4-7 = Smart (Opus, latest), gemma-4-27b = Gemma 4 27B]'.

Why does the unknown-family branch return order 99?

Lines 159 to 163 assign orders 0, 1, 2 to Haiku, Sonnet, Opus respectively. Line 191 sorts availableModels by the numeric order field. Anything with a higher order sorts later. The line 189 fallback uses 99 as a deliberately large bucket so every non-Claude model lands after every Claude model, without needing per-vendor ordering. An open-source LLM like Gemma 4 arriving through a proxy renders after 'Smart (Opus, latest)' even if it was handed back first in the API response. If two non-Claude models arrive together, they both get order 99 and their relative order is the stable order Swift's sort preserves.

Is Fazm itself open source?

Yes, 100%. Source at github.com/mediar-ai/fazm, referenced from three places inside the Desktop app: ChatPrompts.swift line 172 ('Fazm is 100% open source (github.com/mediar-ai/fazm) and local-first'), OnboardingView.swift line 450 ('Fazm is fully open source. You can inspect exactly what data is collected and how it is processed by reviewing our source code on GitHub'), and OnboardingView.swift line 456 which opens the GitHub URL from a button. The bridge (acp-bridge/src/index.ts) and the Swift Desktop sources are both in the same public repo. Every file:line anchor on this page is grep-able from there.

What does 'a model passes the ACP contract' mean in practice for a new open source LLM?

Two methods need to work. session/new has to accept mcpServers and return a sessionId plus availableModels. session/prompt has to stream text deltas and respect tool-call structure. session/set_model has to mutate the model bound to an existing sessionId. A proxy like LiteLLM implements all three on top of any OpenAI-compatible backend. A raw llama.cpp server does not; it speaks an OpenAI-compatible /v1/chat/completions and stops there. The bridge only knows about ACP, so getting Gemma 4 in front of Fazm means either an ACP-native adapter or a shim that turns the model's native API into ACP RPC. The bridge forwards identically either way.

Why does the observer session never see the new open source LLM button?

ChatProvider.swift line 1050 hardcodes the observer's model to 'claude-sonnet-4-6'. The observer runs silently in the background summarizing chat. It is warmed once at app launch, it registers with sessionKey 'observer', and it never reads ShortcutSettings.selectedModel. The open-source LLM button appearing in the picker changes the user's UserDefaults and the foreground 'floating' session binding; it cannot reach the observer. This is by design: a user flipping to Qwen 3.6-Plus for one question should not retarget the cost-gated background summarization loop.

What are the grep commands to verify everything on this page?

grep -n 'modelFamilyMap' /Users/matthewdi/fazm/Desktop/Sources/FloatingControlBar/ShortcutSettings.swift returns line 159. grep -n 'm.modelId !== "default"' /Users/matthewdi/fazm/acp-bridge/src/index.ts returns line 1274. grep -n 'shortLabel: displayName' ShortcutSettings.swift returns line 189 (the order 99 fallback). grep -n 'github.com/mediar-ai/fazm' Desktop/Sources/ returns ChatPrompts.swift:172 and OnboardingView.swift:456. grep -n 'emitModelsIfChanged' acp-bridge/src/index.ts returns the function definition at line 1271 and every callsite. Every number on this page is a direct file:line reference in the shipping codebase.

fazm.AI Computer Agent for macOS
© 2026 fazm. All rights reserved.

How did this page land for you?

React to reveal totals

Comments ()

Leave a comment to see what others are saying.

Public and anonymous. No signup.