AI tech developments, April 14-15, 2026: the two-commit day a Mac app discovered ACP's image block is flat, and PDFs have no content type at all
Every April 14-15, 2026 roundup lists GPT-Rosalind, Gemini 3.1 Flash-Lite, GTC's agentic stack, and the 97 million MCP installs. None of them talks about the protocol-shape problem a desktop client app hits the moment a user drags a PDF onto its chat window. Fazm hit that problem on exactly those two days, shipped 33 commits around it, and its fix, at line 1408 of one TypeScript file, is a ten-line diff that tells you something about the Agent Client Protocol you will not find in any news roundup.
The anchor fact in ten lines
At 14:30:00 PDT on 2026-04-15, commit 865249d9 landed in /Users/matthewdi/fazm/acp-bridge/src/index.ts, lines 1408 to 1425. The before side is the shape every Anthropic API tutorial uses. The after side is what the Agent Client Protocol actually accepts. The difference is not in a release note. The difference is right here.
ACP schema fix, Apr 15 2026 14:30 PDT
// acp-bridge/src/index.ts (before commit 865249d9)
// Fazm shipped the Anthropic Messages API shape, because that is
// the shape every Anthropic tutorial and every LLM-generated
// example uses. It is the obvious default.
if (mime.startsWith("image/")) {
promptBlocks.push({
type: "image",
source: {
type: "base64",
media_type: mime,
data: fileData.toString("base64"),
},
});
} else if (mime === "application/pdf") {
promptBlocks.push({
type: "document",
source: {
type: "base64",
media_type: mime,
data: fileData.toString("base64"),
},
});
}
// Result: the ACP agent silently drops both blocks.
// No error. No warning. The model just never "sees" the file.What the rest of the internet covered on April 14-15, 2026
The top ten results for this keyword all talk about roughly the same ten things. That is the definition of a SERP gap: not the absence of coverage, but the absence of a specific, verifiable, client-side artifact that shows what the news cycle meant in practice for an app someone actually has to build. Here is the news cycle on one side, and the Fazm plumbing on the other.
What shipped in the cloud vs what shipped on the Mac
Step one, April 14 at 17:23 PDT: a single string becomes an array
Seven lines added, one removed. That is the surface area of commit b8f0d01d in acp-bridge/src/protocol.ts, and it is the moment every downstream piece of this page becomes possible. You cannot drag three files onto a chat bar if your wire protocol has one optional imagePath string.
Two minutes later: the Swift side gets its model
At 17:25:31 PDT, commit 063a12b2 adds a ChatAttachment struct to Desktop/Sources/Providers/ChatProvider.swift and extends ChatMessage with an attachments: [ChatAttachment] field. Thirty-seven lines added, two changed. Note the bridgeDict property at the bottom. That is the exact shape that will cross into the TypeScript bridge as a QueryAttachment.
The rest of the evening, to the minute
Ten checkpoints between 10:36 PDT on April 14 and 17:18 PDT on April 15. Each one has a commit hash and a real file path. All verifiable with git show <hash> inside /Users/matthewdi/fazm.
April 14, 10:36 PDT — Sparkle critical-update floor
Commit 6df1c4e3 flips the appcast sparkle:criticalUpdate gate to minimum version 2.1.0. Anyone below that number is force-upgraded before the attachments work lands, because a v1.x client would send imagePath to a bridge that no longer understands it.
April 14, 12:54 PDT — Per-window model selection
Commits 96b7bfab, 542ea6ff, 0e16d45b, and 238e86f2 give each detached chat window its own selectedModel. You can run Opus in one pop-out and Sonnet in another, which matters when the April 14-15 news cycle is about cost-sensitive fast models (Gemini 3.1 Flash-Lite at $0.25 per M input) alongside heavy reasoning models (GPT-5.4, Opus 4.7).
April 14, 17:22 PDT — Conversation history in Settings
Commits fa5244bb, 4966a950, b5f5332a add a Conversation History section to Settings, plus the settings search index. Without it, session resume (added minutes later in ba58c841 and fef37fb5) has no user-visible surface.
April 14, 17:23 PDT — imagePath → attachments[]
Commit b8f0d01d in /Users/matthewdi/fazm/acp-bridge/src/protocol.ts replaces a single optional string field with a QueryAttachment[] array. Seven lines added, one removed. This is the protocol-level moment that unlocks everything else in this list.
April 14, 17:25 PDT — ChatAttachment Swift model
Commit 063a12b2 in Desktop/Sources/Providers/ChatProvider.swift adds a ChatAttachment struct (id, path, name, mimeType, optional thumbnailData) and extends ChatMessage with an attachments: [ChatAttachment] field. +37 lines, -2 lines, one file.
April 14, 17:26–18:02 PDT — Floating bar attachment UI
Commits a85f660b, 063a12b2, 25ffa48f, 578712bc, e468ef82 wire the floating control bar's AskAIInputView to ChatAttachmentHelper for drag, drop, paste, and follow-up send. The same sequence (caceb915, 00610a9d at 17:29) adds file and image paste to FazmTextEditor.
April 14, 18:46 PDT — ChatAttachmentHelper shared utility
Commit 09546b7b creates Desktop/Sources/FloatingControlBar/ChatAttachmentViews.swift with 254 new lines: addFiles(from:to:), handleDrop(_:to:), addPastedImage(_:to:), generateThumbnail(from:maxSize:), and mimeTypeForExtension(_:). Every chat input surface in the app now drops files through the same function.
April 14, 20:09–20:14 PDT — Binary and large-file hardening
Commits 21ce1fb3, 66634116, f3a59ea8, 181db6c7, bdd59d7f add size limits and a path-fallback for large or binary drops, prevent reading binary file attachments into memory, and teach the dropped-item parser to handle URL and Data types. NSLog replaces AppLog for drop failures so Console.app shows them.
April 15, 14:30 PDT — The ACP schema fix
Commit 865249d9 in /Users/matthewdi/fazm/acp-bridge/src/index.ts lines 1408-1425 discovers, documents, and patches the two protocol gotchas this whole page is about. The diff is small. The discovery is the point.
April 15, 17:12–17:18 PDT — Per-message streaming buffers
Commits 21875930, 4c615476, 2e9ed681, c894bbff, db469333, 28f82d64 refactor the streaming buffer to key on message ID and the tool-executor callbacks to key on sessionKey. Fixes the v2.3.2 CHANGELOG line 'Fixed AI responses leaking between pop-out chat windows when streaming simultaneously.'
The two shapes, drawn
Images cross the protocol boundary as bytes. PDFs cross as a sentence. Each sequence below is what happens inside one query turn, from the moment the user lets go of the mouse to the first token in the response stream.
Dragged image (April 15 2026 path)
Dragged PDF (April 15 2026 path)
What actually prints in the log
Both flows produce log output that pins the exact file path and the exact line number in acp-bridge/src/index.ts where the block was constructed. The image path hits line 1412. The PDF path hits line 1421. Everything after that is model-side.
ACP vs Anthropic Messages API, one row at a time
This is not a marketing comparison. It is a schema reference. Both are valid protocols. The point is that if you write client code against one and send to the other, neither side tells you. The blocks just get silently discarded.
| Feature | Anthropic Messages API | ACP (what Fazm speaks) |
|---|---|---|
| Image block shape | nested: {type, source: {type, media_type, data}} | flat: {type, data, mimeType} |
| PDF block type | document block with source.type=base64 | no document type; text reference + Read tool |
| Base64 bloat for PDFs | ~33% encoding overhead on the wire | zero (path handed to Read tool on disk) |
| Tool-surface integration | model extracts PDF text server-side | model's own Read tool opens file on disk |
| Where this is verifiable | Anthropic Messages API documentation | Fazm acp-bridge/src/index.ts L1408 (Apr 15) |
What you get on top of the schema fix
The April 14-15 window is not just the ACP schema patch. It is also the day per-window model selection, per-message streaming buffers, and session-ID-based conversation resume landed. Together they make a Mac app that can treat a news cycle full of new models, new modalities, and new agent frameworks as something routable instead of something to wait on.
Flat ACP image block
ACP wants {type:'image', data, mimeType}. Not the Anthropic Messages API's nested source object. Commit 865249d9 is where Fazm figured that out in production.
No document type in ACP
PDFs ride across the bridge as a text block with a path reference. The model uses its Read tool on the on-disk file. Zero base64 bloat.
33 commits in 3 hours
April 14, 17:20 to 20:30 PDT. One protocol change, one Swift model, one shared helper, every input surface wired up, large-file hardening. No open PR, no design doc, no ticket.
Per-window models
Each detached chat window remembers its own selectedModel. Run Opus in one window, Sonnet in another. Shipped April 14 at 12:54 PDT.
Per-message buffers
Each streaming message has its own buffer, keyed by message ID. No more token bleed between pop-out windows streaming at the same time.
“Fixed AI responses leaking between pop-out chat windows when streaming simultaneously.”
/Users/matthewdi/fazm/CHANGELOG.json, v2.3.2, 2026-04-16
Verify every claim on this page in under five minutes
The evidence is not in a blog screenshot or a tweet. It is in specific commits, specific files, and specific line numbers you can open and inspect. If any row fails, this page is wrong and should be corrected.
Reader verification checklist
- Drag an image onto the floating bar, a detached chat window, or a follow-up input
- Drag a PDF from Finder onto any of the same surfaces
- Paste a screenshot from the clipboard into a chat input
- Attach a text file, Markdown, or source file by drag or paste
- Run Opus in one pop-out window and Sonnet in another, same prompt
- Stream two answers at once across two pop-out windows without token bleed
- Verify the bridge shape: git show 865249d9 inside /Users/matthewdi/fazm
- Verify the protocol migration: git show b8f0d01d for the imagePath -> attachments[] diff
Curious about the ACP layer underneath Fazm?
Book a 20-minute walkthrough of how Fazm bridges Swift to the Claude Agent SDK on a Mac, including the attachment and streaming fixes that shipped April 14-15, 2026.
Book a call →More on the April 2026 model-release cycle and Mac plumbing
AI News April 14-15, 2026: The Ten-Day Ship Log of the Mac Router That Had to Be Ready First
The Smart/Fast toggle, ACP v0.25.0 error frames, the Custom API Endpoint setting, and the 600ms typing-indicator debounce: ten days of routing plumbing that landed right before the April 14-15 model wave.
AI Model Releases, April 2026: How a Three-Function LLM Router Absorbed Seven Frontier Drops
Gemma 4, Llama 4 Scout and Maverick, Mythos, GPT-5.4, Gemini 3.1, Opus 4.7, Grok 4.20, DeepSeek V3.2: all seven land in Fazm with zero binary rebuilds.
Anthropic Claude Opus 4.7 News, April 2026
The +13 / -18 single-file cleanup that shipped Opus 4.7 GA in a Claude-powered Mac app with no Sparkle release and no notarization round trip.
Frequently asked questions
What actually shipped on April 14-15, 2026 in the wider AI news cycle?
The SERP-visible headlines for those two days were: OpenAI's 'Trusted access for the next era of cyber defense' program on April 14, OpenAI's evolution of the Agents SDK on April 15, Google's Gemini 3.1 Flash-Lite with 2.5x faster response times at $0.25 per million input tokens, NVIDIA GTC 2026's agentic-AI stack (NeMoCLAW, OpenCLAW), and Anthropic's Model Context Protocol crossing 97 million installs in March. Llama 4 Maverick and Codestral 2 (Apache 2.0) were also tracking strongly in the open-weights ledger. Every one of those is covered in five competing roundups. The one thing those roundups do not cover is the protocol plumbing a desktop client app has to write to actually feed one of those new multimodal models a user's dragged-in image or PDF.
What is the 'flat image block' thing this page talks about?
The Agent Client Protocol (ACP) content block for an image is flat: {type: 'image', data: <base64>, mimeType: <mime>}. The Anthropic Messages API content block for the same image is nested: {type: 'image', source: {type: 'base64', media_type: <mime>, data: <base64>}}. Both are valid in their own universe, and every reasonable engineer writes the Anthropic shape first because that is the one documented everywhere. On April 15, 2026 at 14:30:00 PDT, commit 865249d9 in /Users/matthewdi/fazm/acp-bridge/src/index.ts (lines 1408 to 1425) swaps the second for the first. Before that commit, a dragged image would silently arrive as an opaque content block the ACP agent would not decode. After it, the bytes land as a proper image in the model's context.
What does 'ACP has no document content type' mean for PDFs?
The Anthropic Messages API accepts {type: 'document', source: {type: 'base64', media_type: 'application/pdf', data: <base64>}} and the model will extract the PDF text on its side. The Agent Client Protocol, as of the version Fazm uses on April 15, 2026, has no 'document' content type at all. So the commit 865249d9 fix for PDFs is not a schema adjustment, it is a workaround: inline a text block that describes the attachment as '[Attached PDF: <name> (<size>MB) at path: <path>] Please use the Read tool to read this PDF file.' and let the model's own Read tool open the file from disk. A 1.4 MB PDF does not cross the protocol boundary as bytes; it crosses as a reference and a tool call. Readers can verify by running git show 865249d9 inside /Users/matthewdi/fazm and looking at the diff at acp-bridge/src/index.ts lines 1408-1425.
Why did the attachments refactor itself happen on April 14?
Because on April 14, 2026 the news cycle was already heavy with multimodal capability expansion (GPT-Rosalind for life sciences, Gemini 3.1 Flash-Lite, open-source Llama 4 Maverick), and a field named imagePath?: string is not a shape that survives models that take multi-file, multi-mime input. At 17:23:30 PDT on April 14, commit b8f0d01d replaced a single optional imagePath string on QueryMessage in /Users/matthewdi/fazm/acp-bridge/src/protocol.ts with an optional attachments: QueryAttachment[] where QueryAttachment is {path: string; name: string; mimeType: string}. In the next 85 minutes, the Swift side followed: commit 063a12b2 at 17:25:31 added a ChatAttachment struct to ChatProvider.swift (39 lines added, 2 changed), a101320a at 17:24 added the attachments parameter to sendMessage in ChatProvider, and 09546b7b at 18:46:20 created ChatAttachmentHelper in /Users/matthewdi/fazm/Desktop/Sources/FloatingControlBar/ChatAttachmentViews.swift (254 new lines) to centralize drag-and-drop, paste, thumbnail generation, and temp-file writes for every input surface in the app.
How many commits were in the April 14 evening attachment push?
Thirty-three commits between 17:20 and 20:30 PDT on April 14, 2026, ending with an evening cluster that hardened the drop code (size limits and path fallback for large or binary files in commit 21ce1fb3, a fix for URL and Data drop types in 181db6c7, binary-attachment memory protection in 66634116). The night also shipped auto-resume for the main chat session after an ACP restart (commit fef37fb5), session-ID-based conversation history (ba58c841), and conversation-history list UI in Settings (b5f5332a, fa5244bb). Readers can verify by running git log --pretty=format:'%h %ad %s' --date=format:'%Y-%m-%d %H:%M' --since='2026-04-14 17:00' --until='2026-04-14 21:00' in /Users/matthewdi/fazm.
What is the streaming-buffer-per-message fix on April 15 and why is it on this page?
At 17:12 to 17:18 PDT on April 15, 2026, commits 21875930 (Refactor streaming buffers to be per-message), 4c615476 (Refactor streaming buffer logic to use per-message state), 2e9ed681 (Add per-session callbacks for quick replies and follow-ups), and 28f82d64 (Unregister ChatToolExecutor callbacks on detached window close) landed. Together they fixed the v2.3.2 CHANGELOG line 'Fixed AI responses leaking between pop-out chat windows when streaming simultaneously.' It matters for a news page because the April 14-15 window is also when users started running multiple pop-out chat windows in parallel, one per detached task, each on its own model (Opus in one, Sonnet in another), and the shared-buffer bug would splice tokens across windows. The fix makes each message its own streaming buffer keyed by message ID, and each session its own callback target keyed by sessionKey. That is the concurrency primitive a multi-model, multi-window agent surface needs before you can take a news cycle full of new models seriously.
Does Fazm actually use ACP in production, or is it just a name?
Production. The bridge binary at /Users/matthewdi/fazm/acp-bridge/src/index.ts is a long-running Node process the Swift app launches at startup. It speaks ACP (Agent Client Protocol) to the Claude Agent SDK on one side and a custom line-delimited JSON protocol to the Swift side on the other. QueryMessage, the message type this whole page is about, is the Swift-to-bridge shape; promptBlocks inside handleQuery (the function containing the April 15 fix at lines 1408-1425) is the bridge-to-ACP shape. If you want to read the bridge in one file, it is 2000+ lines of TypeScript at that single index.ts path.
Does this page have anything to do with MCP crossing 97 million installs in March?
Indirectly. The ACP shape for images and the ACP lack-of-document-type for PDFs is a live reminder that 'everyone speaks the same protocol now' is not true yet, even in April 2026. MCP solved the tool-calling surface: which tools does this model have, what do their signatures look like. ACP solves the agent-runtime surface: how does a desktop app stream tokens from a long-lived agent session, attach files to a prompt, interrupt a turn, and resume a session. They are adjacent, not the same, and the fact that a 1.4 MB PDF has to travel from your Finder to your Mac's Claude session as 'please use the Read tool on this path' rather than as a binary content block is the most concrete piece of evidence you will see this month.
How do I reproduce the schema mismatch on my own?
Clone the Fazm bridge (or study the public @zed-industries/agent-client-protocol types) and write a minimal ACP agent that accepts promptBlocks. Send it a block shaped {type: 'image', source: {type: 'base64', media_type: 'image/png', data: '<base64>'}} (the Anthropic Messages API shape) and watch it silently drop the block. Then send {type: 'image', data: '<base64>', mimeType: 'image/png'} (the ACP shape) and watch the image arrive. Now try {type: 'document', source: {type: 'base64', media_type: 'application/pdf', data: '<base64>'}} and watch it get dropped too, because 'document' is not a valid ACP block type at all.
Why does the fix inline the PDF file path instead of uploading the bytes?
Two reasons. One, the model on the other end of the ACP session already has a Read tool (Fazm exposes the full Claude Agent SDK filesystem toolset), so pointing it at /absolute/path/to/doc.pdf is cheaper than sending the whole file as base64 across the protocol boundary. Two, base64-encoded PDFs balloon by about 33 percent, and the app was already getting drops for large attachments (commit 21ce1fb3 on April 14 at 20:09 PDT added explicit size limits and a path-fallback path). A text reference plus a tool call sidesteps both problems and keeps the round trip consistent whether the PDF is 40 KB or 40 MB.
Is there a changelog entry users can see that maps to this work?
The user-visible release notes for v2.3.2 on 2026-04-16 in /Users/matthewdi/fazm/CHANGELOG.json say: 'Tightened privacy language in onboarding and system prompts to accurately say local-first instead of nothing leaves your device,' 'Fixed AI responses leaking between pop-out chat windows when streaming simultaneously,' and 'Fixed onboarding chat splitting AI messages into multiple bubbles.' The second line is the streaming-buffer-per-message fix on April 15. The attachment refactor on April 14 went out in that same v2.3.2 build but is not individually called out, which is the normal pattern for plumbing-layer changes: users never see imagePath become attachments, they just see that drag-and-drop now works across the floating bar, detached chat windows, and follow-up inputs.
Comments (••)
Leave a comment to see what others are saying.Public and anonymous. No signup.