April 2026 Model Releases

New LLM Model Release April 2026: What Actually Happens Inside a Running Mac Chat When You Swap to Opus 4.7 Mid-Conversation

Every roundup of April 2026 LLM releases ranks models by benchmark. None explain what “switch to the new model” means inside a live chat in a real consumer Mac app. Fazm’s answer is three role-keyed ACP sessions pre-warmed in parallel at app launch, and one call on line 1503 of acp-bridge/src/index.ts that mutates the model behind an existing sessionId without touching a single prior message.

F
Fazm
5.0from Fazm source tree
Three role-keyed sessions warmed in parallel at ChatProvider.swift:1047-1051
One session/set_model call per mid-chat swap at index.ts:1503
Zero messages lost across the swap; sessionId is reused

What actually shipped in April 2026

Nine significant model releases in the first two weeks. Every one of them flows through the same availableModels pipe into Fazm’s picker.

Claude Opus 4.7 GA (Apr 2)Claude Haiku 4.5.2 (Apr 2)Claude Mythos Preview (Apr 7)GPT-5 Turbo (Apr 7)Gemma 4 Apache 2.0 (Apr 2)GLM-5.1 754B MoEQwen 3.6-Plus 1M ctxDeepSeek V3.2Grok 4.1session/set_modelavailableModelsPromise.all warmuprole-keyed sessionssessionKey=floatingses_01J...~/.claude/projects/

The anchor: three role-keyed sessions at ChatProvider.swift:1047-1051

This is the exact literal from the Fazm Desktop source. It is the piece of code that decides what happens when a new April 2026 model arrives. Three sessions, three role strings, one hardcoded starting model. The observer at line 1050 is the one that does not switch when the user picks a new foreground model.

ChatProvider.swift:1047-1051
0Pre-warmed sessions at launch
0Models pinned per role
0set_model call per mid-chat swap
0Session/new calls per swap
0msSwap round-trip (dev build)
0%Messages preserved across swap

How a user’s model pick fans out to the three sessions

Role keying means the three sessions respond independently. When the user picks Opus 4.7 on the floating bar, only the floating session reaches line 1503. The observer stays on Sonnet at the model hardcoded on line 1050. MCP tool-server subprocesses stay bound to the sessionId and do not restart.

User pick → set_model → per-role session state

main picks Opus 4.7
floating picks Opus 4.7
observer stays on Sonnet
session/set_model
ses_01J9_MAIN
ses_01J9_FLOAT
ses_01J9_OBS
MCP subprocesses

The swap itself: one condition, one RPC, zero teardown

This is the full mid-chat swap path from the bridge. It sits inside handleQuery, in the else branch that runs when the session key is already registered. The condition on line 1502 is the “user changed model” detector; line 1503 is the swap call.

acp-bridge/src/index.ts:1498-1510
1 RPC

When the requested model differs from the session's current model, switch it.

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

What gets preserved vs what would reset

A naive implementation of “switch model” closes the existing session and opens a new one. Every piece of state tied to that sessionId goes away: conversation memory, bound MCP subprocesses, the abort controller scope. Fazm’s path routes through line 1503, which mutates the model binding without touching any of that.

Same UX goal, two completely different runtime costs

// Naive pattern: swap by tearing down the session
async function onUserPicksNewModel(modelId: string) {
  await sdk.request("session/close", { sessionId });
  const result = await sdk.request("session/new", {
    cwd,
    mcpServers: buildMcpServers(),
    systemPrompt,                  // rebuilt
  });
  sessionId = result.sessionId;
  await sdk.request("session/set_model", {
    sessionId,
    modelId,
  });
  // history LOST. MCP servers re-registered. ~2-4s first-token stall.
}
-7% fewer lines

The eight things that survive a mid-conversation model swap

This list is what the line 1503 approach preserves. Each item is directly verifiable in the source tree; none of it is “best effort” or gated on a flag.

Preserved across the swap

  • Same ACP sessionId (ses_01J9_FLOAT) before and after the swap
  • All 17 prior messages still in the transcript
  • MCP tool servers (playwright, macos-use, whatsapp) still bound to the session
  • Running query abort controller still scoped to the same sessionKey
  • Session memory file under ~/.claude/projects/ untouched
  • Observer session untouched; still on claude-sonnet-4-6
  • UserDefaults.selectedModel updated; picker re-renders to 'Smart (Opus 4.7, latest)'
  • Next query routes through the existing sessionId with new model bound server-side

Watching the swap happen in the bridge log

This is a clipped log from a Fazm dev build (/tmp/fazm-dev.log) on April 2, 2026, first launch after Opus 4.7 was published server-side. The “switched model” line is the exact log from index.ts line 1506.

acp-bridge stderr

Timeline: from Anthropic press release to a message on Opus 4.7

Seven steps. Nothing between “server-side rollout” and “user’s transcript continues on the new model” requires a Fazm app update.

1

1. A new Claude release lands server-side

Anthropic publishes 'claude-opus-4-7' in the Claude Agent SDK catalog on April 2. No Fazm process knows yet. The SDK's existing sessions still resolve to Opus 4.6 or Sonnet 4.6. Nothing visible in Fazm at this moment.

2

2. Fazm relaunches; pre-warm fires in parallel

ChatProvider.warmupBridge at ChatProvider.swift:879 invokes acpBridge.warmupSession with the three role configs at lines 1047 to 1051. Over inside acp-bridge, Promise.all at index.ts:1320 concurrently runs session/new (or session/resume) for main, floating, observer. Each response includes result.models.availableModels.

3

3. emitModelsIfChanged broadcasts the new list

index.ts:1271 stringifies the filtered availableModels and compares it to lastEmittedModelsJson. The list now contains 'claude-opus-4-7' where yesterday it did not. send() writes one JSON line: { type: 'models_available', models: [...] } at line 1279.

4

4. ShortcutSettings substring-maps the new ID

ACPBridge.swift:1202 forwards the list. ShortcutSettings.updateModels at ShortcutSettings.swift:178 runs 'claude-opus-4-7' through the modelFamilyMap substring table. The 'opus' substring matches; label becomes 'Smart (Opus, latest)'. availableModels @Published var publishes.

5

5. User opens a 17-message floating chat, picks the new Opus button

Click writes ShortcutSettings.selectedModel = 'claude-opus-4-7' to UserDefaults. The floating bar UI updates its selectedModelShortLabel immediately. No query fires yet; the conversation is still open, still on Sonnet under the hood.

6

6. User types message 18; handleQuery runs the swap

index.ts:1449 looks up sessions.get('floating'); finds ses_01J9_FLOAT. requestedModel = 'claude-opus-4-7', existingModel = 'claude-sonnet-4-6'. Line 1502 condition fires. Line 1503: acpRequest('session/set_model', { sessionId: 'ses_01J9_FLOAT', modelId: 'claude-opus-4-7' }). 58ms round trip. Message 18 runs on Opus 4.7; messages 1-17 stay in the transcript.

7

7. Observer keeps running on Sonnet underneath

None of steps 5-6 touched sessions.get('observer'). Its cached model is still claude-sonnet-4-6. When the next background chat-observer poll fires, it queries its session on Sonnet as before. Three foreground messages on Opus 4.7 produce three Sonnet summaries in the background; cost envelope matches the user's intent.

The full message trace: click to first token from Opus 4.7

Twelve messages, five actors, one sessionId reused throughout. This is the observable sequence from a click on the Opus 4.7 button to the first response token from Opus 4.7 streaming back into the floating bar.

Mid-conversation swap: click to first Opus 4.7 token

UserSettingsPage.swiftChatProvider.swiftacp-bridge (Node)Claude Agent SDKClick 'Smart (Opus 4.7, latest)' button (SettingsPage.swift:2025-2030)shortcutSettings.selectedModel = 'claude-opus-4-7' (ShortcutSettings.swift:139-141)Type message #18 and hit sendquery(model: 'claude-opus-4-7', sessionKey: 'floating', prompt: '...')sessions.get('floating') → ses_01J9_FLOAT; existingModel='claude-sonnet-4-6' (index.ts:1449,1501)requestedModel !== existingModel → true (index.ts:1502)session/set_model { sessionId: ses_01J9_FLOAT, modelId: claude-opus-4-7 } (index.ts:1503)ok (58ms)session/prompt { sessionId: ses_01J9_FLOAT, prompt: '...' } (same sessionId)stream: text deltas from Opus 4.7, memory = prior 17 msgs + newonTextDelta → AIResponseView rendersMessage 18 reply streams in; 1-17 still visible above

Before and after a single click

The same 17-turn floating-bar chat, with and without the line 1503 path. The visible difference from the user’s seat is the entire 17-turn investigation staying on screen.

17-turn floating chat picks Opus 4.7 mid-investigation

Turn 17. Floating chat has context on a tricky invoice reconciliation. Model: Fast (Sonnet 4.6). User wants to try Opus 4.7 on the next hop. Naive app: clicks model picker, session restarts, 17-turn context lost, MCP servers re-register (~2-4s of jank), tools reload, user starts over.

  • Session torn down on model change
  • 17-turn context lost
  • MCP servers re-register, 2-4s first-token stall
  • Observer restarts with foreground pick

The April 2026 releases that rode this path

Every one of these arrived in result.models.availableModels either from the Anthropic SDK directly or from a proxy fronting an open-source model. Each surfaced in the picker on next launch; each became swap-eligible via line 1503 on an existing floating or main session.

Claude Opus 4.7 (GA April 2)

Arrived inside result.models.availableModels with modelId 'claude-opus-4-7'. Substring-matched 'opus' at ShortcutSettings.swift line 168. Appeared as a second 'Smart' button next to existing Opus 4.6. A user with an active floating-bar conversation swapped to it mid-thread via line 1503. Messages 1-17 stayed in place; message 18 came back from Opus 4.7.

Haiku 4.5.2 (April 2)

Point-release update. Bridge has no special case; the new modelId flowed through emitModelsIfChanged and relabeled to 'Scary (Haiku, latest)'. Background observer could switch to it if the user wanted faster summaries, independent of what floating is running.

Claude Mythos Preview (April 7)

Partner-only. For the ~50 Project Glasswing organizations, Mythos IDs surfaced server-side through availableModels. Fazm's bridge has no UI gate: if the SDK hands back a modelId, the button appears. For a Mythos-eligible user, a live main-window chat could swap to Mythos at line 1503 mid-investigation without losing the existing context.

GPT-5 Turbo via LiteLLM (April 7)

OpenAI's multimodal flagship. Through a LiteLLM proxy exposing an Anthropic-compatible /messages shape, Fazm sees it as just another modelId in availableModels. Renders with raw 'gpt-5-turbo' name because no Haiku/Sonnet/Opus substring matches. Mid-chat swap path is identical: line 1503.

Gemma 4 Apache 2.0 + GLM-5.1 + Qwen 3.6-Plus + DeepSeek V3.2 + Grok 4.1

Custom-endpoint models. Bridge has zero model allowlist. Each appears in the picker with its raw modelId the moment the proxy reports it. Qwen's 1M-token context claim survives the swap because context lives in the SDK's session file under ~/.claude/projects/, not in the bridge process memory.

Observer stays on Sonnet

The background observer session at ChatProvider.swift line 1050 is the counter-example: it deliberately does NOT follow the user's foreground pick. Role keying means the cost-gated summarization loop stays on the cheaper model while a user can burn Opus 4.7 on a foreground question.

Why parallel pre-warming matters when a new release rolls out

On rollout days the SDK’s availableModels response is larger (new + old + deprecated IDs). Each session/new call has to receive and serialize that list. Fazm runs the three warm-ups in parallel via Promise.all at index.ts:1320, so cold-start is bounded by max(cfg time), not sum.

acp-bridge/src/index.ts:1320-1376 (abridged)

Fazm’s path vs the obvious path

The “session/new every time” path is the first thing most Claude Agent SDK tutorials show. It is also what makes model switching feel like a reset. Fazm chose the narrower path at line 1503 specifically so an April 2026 release becomes something a user can try inside an existing investigation.

FeatureRebuild-on-swap pathFazm (line 1503 path)
What mutates when you pick a new April 2026 model mid-chatThe entire session is torn down and recreatedThe sessionId's model binding server-side (via session/set_model at index.ts:1503)
Where the prior conversation livesLost on session teardown; you start overInside the ACP SDK's memory file at ~/.claude/projects/, unchanged
MCP tool-server subprocesses on swapRe-registered; 500-2000ms of tool-manifest rebuildStay bound to the sessionId; no restart
How many role sessions survive the swapOne global session swings together or is rebuiltThree (main, floating, observer); only the role you swap changes
Observer's cost-gated loop when you pick Opus 4.7Follows the global selection or is not a separate session at allStays on Sonnet at ChatProvider.swift:1050; cost envelope unchanged
Latency between click and first token of response~2-4s session/new rebuild + first-token latency40-80ms swap RTT + model-native first-token latency
What a 'new Claude model just launched' notification resolves toA changelog entry; wait for the next app updateA new button in the picker next launch, flowing from availableModels
How two April releases coexistTwo apps or two tabs, manual context copy between themfloating on Opus 4.7, main on Sonnet, observer on Sonnet; one process

See a live April 2026 model swap in a running Fazm session

Book a 20-minute demo. We will open a real floating-bar chat with tool calls mid-flight, switch models between Sonnet and Opus 4.7, and watch the transcript stay intact.

Book a call

FAQ

Frequently asked questions

What does 'switch to a new April 2026 model mid-conversation' actually do inside a Mac chat app?

In Fazm, clicking a new model button changes ShortcutSettings.selectedModel in UserDefaults. On the next handleQuery call, acp-bridge/src/index.ts line 1449 looks up the existing ACP session by its role key (main, floating, or observer). Because the session is found and the requested model differs from the session's cached model, line 1502 fires a single condition check (requestedModel !== existingModel) and line 1503 calls acpRequest('session/set_model', { sessionId, modelId: requestedModel }). No session/new. The sessionId is the same UUID that served every prior message. The ACP SDK swaps the model behind that ID server-side; Fazm's local conversation array in ChatProvider.swift keeps every message it had.

Why are Fazm's three ACP sessions keyed by role instead of by model?

ChatProvider.swift lines 1047 to 1051 warm three sessions at app startup: ('main', claude-sonnet-4-6, main system prompt, resume), ('floating', claude-sonnet-4-6, floating prefix + main prompt, resume), ('observer', claude-sonnet-4-6, chat observer prompt). Each key is a role string, not a model name. The observer is a background summarizer that watches chat activity and does not want to follow whatever shiny model the user picked in the floating bar. The main window and floating bar are two foreground surfaces with different system prompts. Role keying means the three can diverge on model independently: the user can push floating to Opus 4.7 for one hard question while main stays on Sonnet and observer continues its cost-gated Sonnet loop.

What is session/set_model and where is the exact line?

session/set_model is a JSON-RPC method on the Anthropic Claude Agent SDK's ACP protocol. It takes { sessionId, modelId } and mutates the model bound to that server-side session without tearing down the conversation. Inside the Fazm bridge it is called in six places: line 1341 (pre-warm after resume), line 1366 (pre-warm after new session), line 1475 (mid-flight resume), line 1495 (mid-flight new session), line 1503 (mid-flight model swap on an existing session), and line 1810 (cwd-change recovery). The mid-conversation swap case is the one at line 1503: it only fires when the session key already exists AND the requested model differs from the session's current cached model. Everything else on the line 1503 path is already bound, including the MCP tool servers and the running subprocess.

When Anthropic shipped Opus 4.7 on April 2, 2026, what did a Fazm user see?

On next launch, the pre-warm path at index.ts lines 1296 to 1379 called session/new for each of the three role keys. The SDK returned result.models.availableModels with the new 'claude-opus-4-7' modelId. emitModelsIfChanged at line 1271 noticed the JSON differed from lastEmittedModelsJson and broadcast { type: 'models_available', models: [...] } over stdout. ACPBridge.swift line 1202 decoded it and ShortcutSettings.updateModels ran 'claude-opus-4-7' through the three-row modelFamilyMap substring match: 'opus-4-7'.contains('opus') is true, so the label became 'Smart (Opus, latest)'. The user opens Settings, sees the Opus 4.7 button, clicks it, and the next message they send runs through session/set_model. Conversation history stays intact.

What is the difference between session/set_model and session/new for a model swap?

session/new tears down the SDK's in-memory conversation state, creates a new sessionId, re-applies the system prompt, and reinitializes the MCP tool servers. It's ~2-4 seconds on first token because the SDK has to rebuild the tool manifest. session/set_model reuses the sessionId, keeps the conversation memory file under ~/.claude/projects/, keeps the MCP tool servers bound, and is one RPC round trip. When a user picks a new April 2026 model mid-chat, the difference between 'conversation resets and Fazm feels broken' and 'next message just uses the new model' is whether line 1503 or line 1488 fires. Fazm routes through line 1503 whenever the session key is already registered.

Why does the observer session not follow the user's model pick?

The observer is a background ACP session whose job is to summarize chat messages silently. It runs whenever the foreground chat pauses. Cost and latency matter more than peak intelligence for that loop. ChatProvider.swift line 1050 hardcodes its model to claude-sonnet-4-6. When the user switches floating to Opus 4.7, the floating session gets session/set_model (line 1503); the observer session is untouched because its session key 'observer' is different from 'floating' and its model never changed. This is a real consequence of role keying: the roles behave independently on cost, model, and system prompt.

What happens to in-flight tool calls when session/set_model fires?

Nothing destructive. The tool call abort path at index.ts lines 1391 to 1396 only aborts the previous query if its sessionKey matches the incoming one. A click on a new model button does not fire a query on its own; it only updates UserDefaults. The next message the user sends picks up the new model via line 1503 before the query runs. If a query is already in flight for the same sessionKey when the new message arrives, line 1393 aborts the old one (standard behavior for typing before a response finishes), then line 1503 sets the new model, then the new query runs. Tool-server subprocesses (playwright MCP, macos-use MCP, etc.) are not restarted because they are bound to the sessionId, not the model.

Does pre-warming load all three sessions in parallel?

Yes. acp-bridge/src/index.ts line 1320 wraps the three warmup configs in Promise.all(toWarm.map(async cfg => {...})). Each cfg runs its own session/new (or session/resume) concurrently. The full cold-start cost is max(cfg time), not sum(cfg time). This matters on April-release day because the SDK's availableModels response is larger during active rollout periods (new + old + deprecated), and each session/new has to serialize it. Parallelism at line 1320 absorbs that cost.

How does the mid-session swap interact with the selected-model UI label?

ShortcutSettings.selectedModel at ShortcutSettings.swift line 139 is a @Published var, so the picker in SettingsPage.swift lines 2013 to 2031 and the floating bar's short label at FloatingControlBarWindow.swift line 1553 update on the same tick. The bridge gets the change only when the user's next message goes through handleQuery; the UI is already showing the new label by then. There is a brief window where the UI reflects the new model but the SDK is still running on the old one. For Fazm that window is bounded by the time between click and next send, typically under a second.

What April 2026 releases can ride this path without a Fazm update?

Any model that Anthropic's Claude Agent SDK or a user-configured custom endpoint reports back in result.models.availableModels. On April 2 that included Claude Opus 4.7 GA and Claude Haiku 4.5.2. On April 7 it included Claude Mythos Preview (for the ~50 Project Glasswing partners, gated server-side). For users pointing at custom Anthropic-compatible proxies (LiteLLM, Cloudflare AI Gateway), it also covered GPT-5 Turbo (April 7), Gemma 4 Apache 2.0 (April 2), GLM-5.1 (754B MoE), Qwen 3.6-Plus with 1M-token context, DeepSeek V3.2, and Grok 4.1. The bridge has no model allowlist; whatever comes through the pipe is forwarded to the Swift picker.

What is the exact user-visible latency of a mid-conversation model swap?

One RPC round trip between acp-bridge (Node) and the Claude Agent SDK subprocess, measured in Fazm dev builds at 40 to 80 ms locally when both are on the same machine. Plus the click-to-send delay. There is no UI blocking spinner for the swap itself; the user types, hits send, the bridge runs line 1503 before forwarding the prompt. Response latency on the first token after the swap is dominated by whichever model was selected, not by the swap mechanism.

Where can I verify all of this in the Fazm source tree?

Three warmup configs: /Users/matthewdi/fazm/Desktop/Sources/Providers/ChatProvider.swift lines 1047 to 1051. Parallel pre-warm: /Users/matthewdi/fazm/acp-bridge/src/index.ts lines 1296 to 1379, with the Promise.all at line 1320. Mid-conversation swap: index.ts lines 1498 to 1510, with the swap call at line 1503. Role-keyed lookup: index.ts lines 1449 to 1459. models_available broadcast: index.ts lines 1271 to 1281. Substring family map: /Users/matthewdi/fazm/Desktop/Sources/FloatingControlBar/ShortcutSettings.swift lines 159 to 163. Update pipe on the Swift side: ShortcutSettings.swift lines 178 to 212. Every one of these is a direct file:line anchor 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.