summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorRenĂ© <[email protected]>2025-12-15 06:56:47 +0100
committerGitHub <[email protected]>2025-12-14 23:56:47 -0600
commit9eefcd1b41db29e5142bce800790f559f01f2877 (patch)
tree1655e3cc72f5e4323b3eb399a7b34b951219fa23
parent7c1124199ecba33750c9b536c907359f40ed91de (diff)
downloadopencode-9eefcd1b41db29e5142bce800790f559f01f2877.tar.gz
opencode-9eefcd1b41db29e5142bce800790f559f01f2877.zip
Provider fix, anthropic Errorhandling if empty image file is read (#5521)
-rw-r--r--packages/opencode/src/provider/transform.ts14
-rw-r--r--packages/opencode/test/provider/transform.test.ts103
2 files changed, 117 insertions, 0 deletions
diff --git a/packages/opencode/src/provider/transform.ts b/packages/opencode/src/provider/transform.ts
index 728c26a27..9af5589e8 100644
--- a/packages/opencode/src/provider/transform.ts
+++ b/packages/opencode/src/provider/transform.ts
@@ -171,6 +171,20 @@ export namespace ProviderTransform {
const filtered = msg.content.map((part) => {
if (part.type !== "file" && part.type !== "image") return part
+ // Check for empty base64 image data
+ if (part.type === "image") {
+ const imageStr = part.image.toString()
+ if (imageStr.startsWith("data:")) {
+ const match = imageStr.match(/^data:([^;]+);base64,(.*)$/)
+ if (match && (!match[2] || match[2].length === 0)) {
+ return {
+ type: "text" as const,
+ text: "ERROR: Image file is empty or corrupted. Please provide a valid image.",
+ }
+ }
+ }
+ }
+
const mime = part.type === "image" ? part.image.toString().split(";")[0].replace("data:", "") : part.mediaType
const filename = part.type === "file" ? part.filename : undefined
const modality = mimeToModality(mime)
diff --git a/packages/opencode/test/provider/transform.test.ts b/packages/opencode/test/provider/transform.test.ts
index eecf43783..b040f24f4 100644
--- a/packages/opencode/test/provider/transform.test.ts
+++ b/packages/opencode/test/provider/transform.test.ts
@@ -262,3 +262,106 @@ describe("ProviderTransform.message - DeepSeek reasoning content", () => {
expect(result[0].providerOptions?.openaiCompatible?.reasoning_content).toBeUndefined()
})
})
+
+describe("ProviderTransform.message - empty image handling", () => {
+ const mockModel = {
+ id: "anthropic/claude-3-5-sonnet",
+ providerID: "anthropic",
+ api: {
+ id: "claude-3-5-sonnet-20241022",
+ url: "https://api.anthropic.com",
+ npm: "@ai-sdk/anthropic",
+ },
+ name: "Claude 3.5 Sonnet",
+ capabilities: {
+ temperature: true,
+ reasoning: false,
+ attachment: true,
+ toolcall: true,
+ input: { text: true, audio: false, image: true, video: false, pdf: true },
+ output: { text: true, audio: false, image: false, video: false, pdf: false },
+ interleaved: false,
+ },
+ cost: {
+ input: 0.003,
+ output: 0.015,
+ cache: { read: 0.0003, write: 0.00375 },
+ },
+ limit: {
+ context: 200000,
+ output: 8192,
+ },
+ status: "active",
+ options: {},
+ headers: {},
+ } as any
+
+ test("should replace empty base64 image with error text", () => {
+ const msgs = [
+ {
+ role: "user",
+ content: [
+ { type: "text", text: "What is in this image?" },
+ { type: "image", image: "data:image/png;base64," },
+ ],
+ },
+ ] as any[]
+
+ const result = ProviderTransform.message(msgs, mockModel)
+
+ expect(result).toHaveLength(1)
+ expect(result[0].content).toHaveLength(2)
+ expect(result[0].content[0]).toEqual({ type: "text", text: "What is in this image?" })
+ expect(result[0].content[1]).toEqual({
+ type: "text",
+ text: "ERROR: Image file is empty or corrupted. Please provide a valid image.",
+ })
+ })
+
+ test("should keep valid base64 images unchanged", () => {
+ const validBase64 =
+ "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg=="
+ const msgs = [
+ {
+ role: "user",
+ content: [
+ { type: "text", text: "What is in this image?" },
+ { type: "image", image: `data:image/png;base64,${validBase64}` },
+ ],
+ },
+ ] as any[]
+
+ const result = ProviderTransform.message(msgs, mockModel)
+
+ expect(result).toHaveLength(1)
+ expect(result[0].content).toHaveLength(2)
+ expect(result[0].content[0]).toEqual({ type: "text", text: "What is in this image?" })
+ expect(result[0].content[1]).toEqual({ type: "image", image: `data:image/png;base64,${validBase64}` })
+ })
+
+ test("should handle mixed valid and empty images", () => {
+ const validBase64 =
+ "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg=="
+ const msgs = [
+ {
+ role: "user",
+ content: [
+ { type: "text", text: "Compare these images" },
+ { type: "image", image: `data:image/png;base64,${validBase64}` },
+ { type: "image", image: "data:image/jpeg;base64," },
+ ],
+ },
+ ] as any[]
+
+ const result = ProviderTransform.message(msgs, mockModel)
+
+ expect(result).toHaveLength(1)
+ expect(result[0].content).toHaveLength(3)
+ expect(result[0].content[0]).toEqual({ type: "text", text: "Compare these images" })
+ expect(result[0].content[1]).toEqual({ type: "image", image: `data:image/png;base64,${validBase64}` })
+ expect(result[0].content[2]).toEqual({
+ type: "text",
+ text: "ERROR: Image file is empty or corrupted. Please provide a valid image.",
+ })
+ })
+})