mirror of
https://github.com/sst/opencode.git
synced 2025-12-23 10:11:41 +00:00
Provider fix, anthropic Errorhandling if empty image file is read (#5521)
Some checks are pending
deploy / deploy (push) Waiting to run
generate / generate (push) Waiting to run
publish / publish (push) Waiting to run
publish / publish-tauri (map[host:blacksmith-4vcpu-ubuntu-2404 target:x86_64-unknown-linux-gnu]) (push) Blocked by required conditions
publish / publish-tauri (map[host:blacksmith-4vcpu-windows-2025 target:x86_64-pc-windows-msvc]) (push) Blocked by required conditions
publish / publish-tauri (map[host:macos-latest target:aarch64-apple-darwin]) (push) Blocked by required conditions
publish / publish-tauri (map[host:macos-latest target:x86_64-apple-darwin]) (push) Blocked by required conditions
test / test (push) Waiting to run
Some checks are pending
deploy / deploy (push) Waiting to run
generate / generate (push) Waiting to run
publish / publish (push) Waiting to run
publish / publish-tauri (map[host:blacksmith-4vcpu-ubuntu-2404 target:x86_64-unknown-linux-gnu]) (push) Blocked by required conditions
publish / publish-tauri (map[host:blacksmith-4vcpu-windows-2025 target:x86_64-pc-windows-msvc]) (push) Blocked by required conditions
publish / publish-tauri (map[host:macos-latest target:aarch64-apple-darwin]) (push) Blocked by required conditions
publish / publish-tauri (map[host:macos-latest target:x86_64-apple-darwin]) (push) Blocked by required conditions
test / test (push) Waiting to run
This commit is contained in:
parent
7c1124199e
commit
9eefcd1b41
2 changed files with 117 additions and 0 deletions
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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.",
|
||||
})
|
||||
})
|
||||
})
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue