summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorZeke Sikelianos <[email protected]>2026-05-01 16:14:22 -0700
committerGitHub <[email protected]>2026-05-01 18:14:22 -0500
commit51e310c9ce3faa3dab382222000a001db678cfb3 (patch)
tree09e0aa864c8fc95cd4d7a5f36eee2edf481f4d03
parent478156456e92c3db04803953127b4a4af2db064c (diff)
downloadopencode-51e310c9ce3faa3dab382222000a001db678cfb3.tar.gz
opencode-51e310c9ce3faa3dab382222000a001db678cfb3.zip
fix(read): prevent unsupported image formats from being sending to provider (#21114)
Co-authored-by: Aiden Cline <[email protected]>
-rw-r--r--packages/opencode/src/tool/read.ts7
-rw-r--r--packages/opencode/test/tool/read.test.ts18
2 files changed, 23 insertions, 2 deletions
diff --git a/packages/opencode/src/tool/read.ts b/packages/opencode/src/tool/read.ts
index ef33a48de..78436489f 100644
--- a/packages/opencode/src/tool/read.ts
+++ b/packages/opencode/src/tool/read.ts
@@ -10,7 +10,7 @@ import DESCRIPTION from "./read.txt"
import { InstanceState } from "@/effect/instance-state"
import { assertExternalDirectoryEffect } from "./external-directory"
import { Instruction } from "../session/instruction"
-import { isImageAttachment, isPdfAttachment, sniffAttachmentMime } from "@/util/media"
+import { isPdfAttachment, sniffAttachmentMime } from "@/util/media"
const DEFAULT_READ_LIMIT = 2000
const MAX_LINE_LENGTH = 2000
@@ -18,6 +18,7 @@ const MAX_LINE_SUFFIX = `... (line truncated to ${MAX_LINE_LENGTH} chars)`
const MAX_BYTES = 50 * 1024
const MAX_BYTES_LABEL = `${MAX_BYTES / 1024} KB`
const SAMPLE_BYTES = 4096
+const SUPPORTED_IMAGE_MIMES = new Set(["image/jpeg", "image/png", "image/gif", "image/webp"])
// `offset` and `limit` were originally `z.coerce.number()` — the runtime
// coercion was useful when the tool was called from a shell but serves no
@@ -220,7 +221,9 @@ export const ReadTool = Tool.define(
const sample = yield* readSample(filepath, Number(stat.size), SAMPLE_BYTES)
const mime = sniffAttachmentMime(sample, AppFileSystem.mimeType(filepath))
- if (isImageAttachment(mime) || isPdfAttachment(mime)) {
+ const isImage = SUPPORTED_IMAGE_MIMES.has(mime)
+
+ if (isImage || isPdfAttachment(mime)) {
const bytes = yield* fs.readFile(filepath)
const msg = isPdfAttachment(mime) ? "PDF read successfully" : "Image read successfully"
return {
diff --git a/packages/opencode/test/tool/read.test.ts b/packages/opencode/test/tool/read.test.ts
index db6678754..c20b08437 100644
--- a/packages/opencode/test/tool/read.test.ts
+++ b/packages/opencode/test/tool/read.test.ts
@@ -440,6 +440,24 @@ root_type Monster;`
expect(result.output).toContain("table Monster")
}),
)
+
+ it.live("falls through unsupported image mime types to text", () =>
+ Effect.gen(function* () {
+ const dir = yield* tmpdirScoped()
+ const cases = [
+ ["image.bmp", "BM text content"],
+ ["photo.tiff", "II text content"],
+ ["photo.avif", "avif text content"],
+ ] as const
+
+ for (const item of cases) {
+ yield* put(path.join(dir, item[0]), item[1])
+ const result = yield* exec(dir, { filePath: path.join(dir, item[0]) })
+ expect(result.attachments).toBeUndefined()
+ expect(result.output).toContain(item[1])
+ }
+ }),
+ )
})
describe("tool.read loaded instructions", () => {