From d754faa1e9f3f2af6c957a9b3b923006a3369e6e Mon Sep 17 00:00:00 2001 From: dominusbelial Date: Fri, 1 May 2026 12:48:14 -0500 Subject: [PATCH] fix: detect file MIME type from extension for -f attachments MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Previously all files attached with -f were hardcoded as text/plain, causing binary files (images, audio, video, PDFs) to be injected as text garbage instead of being base64-encoded and passed as proper media content to the LLM. This change adds a resolveMime() helper that maps known file extensions to MIME types. Unknown extensions still default to text/plain. The rest of the pipeline (prompt.ts line 1155) already handles non-text MIME types by reading the file as binary, base64-encoding it, and creating a data: URL — it was simply never reached because everything was labeled text/plain. Fixes image attachment with ollama providers that support OpenAI image_url format (gemma4, qwen3-vl). --- packages/opencode/src/cli/cmd/run.ts | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/packages/opencode/src/cli/cmd/run.ts b/packages/opencode/src/cli/cmd/run.ts index c94e9620386d..77198ce36018 100644 --- a/packages/opencode/src/cli/cmd/run.ts +++ b/packages/opencode/src/cli/cmd/run.ts @@ -19,6 +19,21 @@ import { ReadTool } from "../../tool/read" import { WebFetchTool } from "../../tool/webfetch" import { EditTool } from "../../tool/edit" import { WriteTool } from "../../tool/write" + +const MIME_MAP: Record = { + png: "image/png", jpg: "image/jpeg", jpeg: "image/jpeg", gif: "image/gif", + bmp: "image/bmp", webp: "image/webp", ico: "image/x-icon", tif: "image/tiff", + tiff: "image/tiff", svg: "image/svg+xml", svgz: "image/svg+xml", avif: "image/avif", + apng: "image/apng", jxl: "image/jxl", heic: "image/heic", heif: "image/heif", + mp4: "video/mp4", webm: "video/webm", mov: "video/quicktime", avi: "video/x-msvideo", + mp3: "audio/mpeg", wav: "audio/wav", ogg: "audio/ogg", flac: "audio/flac", + pdf: "application/pdf", +} + +function resolveMime(filePath: string): string { + const ext = path.extname(filePath).toLowerCase().slice(1) + return MIME_MAP[ext] ?? "text/plain" +} import { WebSearchTool } from "../../tool/websearch" import { TaskTool } from "../../tool/task" import { SkillTool } from "../../tool/skill" @@ -320,7 +335,7 @@ export const RunCommand = cmd({ process.exit(1) } - const mime = (await Filesystem.isDir(resolvedPath)) ? "application/x-directory" : "text/plain" + const mime = (await Filesystem.isDir(resolvedPath)) ? "application/x-directory" : resolveMime(resolvedPath) files.push({ type: "file",