← All posts

v0.3.8 — Chat Attachments and Vision-Aware Image Uploads

The web chat composer now has a paperclip button for local file and image attachments. Images are routed to vision-capable models, text/code files are folded into the prompt as readable attachment blocks, and text-only models now fail clearly with a suggestion to switch models instead of silently dropping pictures.

0.3.8 makes the chat composer feel like a real working surface. The prompt bar now includes a standard Paperclip control, selected files appear as removable chips before send, and the agent receives the attachment content instead of a placeholder string.

Paperclip Composer

The chat panel now enables the @assistant-ui/react attachment adapter on the external-store runtime. ComposerPrimitive.AddAttachment opens the browser file picker, accepts multiple files, and renders a familiar paperclip icon beside the input. ComposerPrimitive.Attachments shows each pending attachment as a compact chip with a remove button.

Attachment Routing

Image files are read locally as data URLs and converted into Pi's image-content shape: { type: "image", mimeType, data }. Text-like files, including markdown, JSON, CSV, code, YAML, and plain text, are read in the browser and wrapped in named attachment blocks so the model can inspect them directly. Unsupported binary files are rejected before they reach the model.

Vision Model Guard

The send path now checks model.input.includes("image") before dispatching an image message. If the active model is text-only, Keating records the user's attempted message and immediately shows a chat error telling the user to switch to a vision-capable model such as Gemini Flash/Pro or GPT-4o, then send the image again.

Transcript Rendering

Sent images render inline in the user transcript. Text file attachments show a short [attached file: name] summary in the message bubble while the full file contents remain available in the actual model context. That keeps chat history readable without weakening the prompt.