fix: detect attachment mime from file contents (#23291)

This commit is contained in:
Kit Langton
2026-04-18 11:59:08 -04:00
committed by GitHub
parent dd8c424806
commit 9918f389e7
6 changed files with 198 additions and 77 deletions

View File

@@ -1,6 +1,7 @@
import { describe, expect, test } from "bun:test"
import { APICallError } from "ai"
import { MessageV2 } from "../../src/session/message-v2"
import { ProviderTransform } from "../../src/provider"
import type { Provider } from "../../src/provider"
import { ModelID, ProviderID } from "../../src/provider/schema"
import { SessionID, MessageID, PartID } from "../../src/session/schema"
@@ -359,6 +360,89 @@ describe("session.message-v2.toModelMessage", () => {
])
})
test("preserves jpeg tool-result media for anthropic models", async () => {
const anthropicModel: Provider.Model = {
...model,
id: ModelID.make("anthropic/claude-opus-4-7"),
providerID: ProviderID.make("anthropic"),
api: {
id: "claude-opus-4-7-20250805",
url: "https://api.anthropic.com",
npm: "@ai-sdk/anthropic",
},
capabilities: {
...model.capabilities,
attachment: true,
input: {
...model.capabilities.input,
image: true,
pdf: true,
},
},
}
const jpeg = Buffer.from([0xff, 0xd8, 0xff, 0xe0, 0x00, 0x10, 0x4a, 0x46, 0x49, 0x46, 0x00, 0x01]).toString(
"base64",
)
const userID = "m-user-anthropic"
const assistantID = "m-assistant-anthropic"
const input: MessageV2.WithParts[] = [
{
info: userInfo(userID),
parts: [
{
...basePart(userID, "u1-anthropic"),
type: "text",
text: "run tool",
},
] as MessageV2.Part[],
},
{
info: assistantInfo(assistantID, userID),
parts: [
{
...basePart(assistantID, "a1-anthropic"),
type: "tool",
callID: "call-anthropic-1",
tool: "read",
state: {
status: "completed",
input: { filePath: "/tmp/rails-demo.png" },
output: "Image read successfully",
title: "Read",
metadata: {},
time: { start: 0, end: 1 },
attachments: [
{
...basePart(assistantID, "file-anthropic-1"),
type: "file",
mime: "image/jpeg",
filename: "rails-demo.png",
url: `data:image/jpeg;base64,${jpeg}`,
},
],
},
},
] as MessageV2.Part[],
},
]
const result = ProviderTransform.message(await MessageV2.toModelMessages(input, anthropicModel), anthropicModel, {})
expect(result).toHaveLength(3)
expect(result[2].role).toBe("tool")
expect(result[2].content[0]).toMatchObject({
type: "tool-result",
toolCallId: "call-anthropic-1",
toolName: "read",
output: {
type: "content",
value: [
{ type: "text", text: "Image read successfully" },
{ type: "media", mediaType: "image/jpeg", data: jpeg },
],
},
})
})
test("omits provider metadata when assistant model differs", async () => {
const userID = "m-user"
const assistantID = "m-assistant"