diff --git a/packages/tools/src/vercel/middleware.ts b/packages/tools/src/vercel/middleware.ts index 6064f286..c211f207 100644 --- a/packages/tools/src/vercel/middleware.ts +++ b/packages/tools/src/vercel/middleware.ts @@ -104,11 +104,41 @@ export const convertToConversationMessages = ( type: "text", text: content.text, }) - } else if ( - content.type === "file" && - content.mediaType.startsWith("image/") - ) { - const url = toConversationImageUrl(content.data, content.mediaType) + } else if (content.type === "file") { + const fileContent = content as { + mediaType?: unknown + mimeType?: unknown + data?: unknown + } + const mediaType = + typeof fileContent.mediaType === "string" + ? fileContent.mediaType + : typeof fileContent.mimeType === "string" + ? fileContent.mimeType + : "" + if (mediaType.startsWith("image/")) { + const url = toConversationImageUrl(fileContent.data, mediaType) + if (url) { + contentParts.push({ type: "image_url", imageUrl: { url } }) + } + } + } else if (content.type === "image") { + const imageContent = content as { + image?: unknown + data?: unknown + mimeType?: unknown + mediaType?: unknown + } + const mediaType = + typeof imageContent.mimeType === "string" + ? imageContent.mimeType + : typeof imageContent.mediaType === "string" + ? imageContent.mediaType + : "image/jpeg" + const url = toConversationImageUrl( + imageContent.image ?? imageContent.data, + mediaType, + ) if (url) { contentParts.push({ type: "image_url", imageUrl: { url } }) } diff --git a/packages/tools/src/vercel/util.ts b/packages/tools/src/vercel/util.ts index 97b2c3e8..4d562232 100644 --- a/packages/tools/src/vercel/util.ts +++ b/packages/tools/src/vercel/util.ts @@ -10,7 +10,7 @@ import { toConversationImageUrl } from "../conversations-client" export type { ProfileStructure, ProfileMarkdownData, -} from "../shared" +} from "../shared/types" // Provider v2 does not export V3 names, so keep the public declaration on the // common V2 surface and structurally accept V3 models at the wrapper boundary. @@ -98,12 +98,30 @@ export const hasPersistableUserContent = ( if (part.type === "text" && typeof part.text === "string") { return Boolean(part.text.trim()) } - return ( - part.type === "file" && - typeof part.mediaType === "string" && - part.mediaType.startsWith("image/") && - toConversationImageUrl(part.data, part.mediaType) !== null - ) + if (part.type === "file") { + const mediaType = + typeof part.mediaType === "string" + ? part.mediaType + : typeof part.mimeType === "string" + ? part.mimeType + : "" + return ( + mediaType.startsWith("image/") && + toConversationImageUrl(part.data, mediaType) !== null + ) + } + if (part.type === "image") { + const mediaType = + typeof part.mimeType === "string" + ? part.mimeType + : typeof part.mediaType === "string" + ? part.mediaType + : "image/jpeg" + return ( + toConversationImageUrl(part.image ?? part.data, mediaType) !== null + ) + } + return false }) }) } diff --git a/packages/tools/test/with-supermemory/conversation-conversion.test.ts b/packages/tools/test/with-supermemory/conversation-conversion.test.ts index 8497e334..19b20e68 100644 --- a/packages/tools/test/with-supermemory/conversation-conversion.test.ts +++ b/packages/tools/test/with-supermemory/conversation-conversion.test.ts @@ -355,4 +355,36 @@ describe("convertToConversationMessages", () => { { role: "assistant", content: "Found it" }, ]) }) + + it("converts standard Vercel AI SDK type: 'image' parts to conversation image_url", async () => { + const params: LanguageModelV2CallOptions = { + prompt: [ + { + role: "user", + content: [ + { type: "text", text: "Look at this screenshot" }, + { + type: "image", + image: "https://example.com/screenshot.png", + mimeType: "image/png", + }, + ], + } as unknown as LanguageModelV2Message, + ], + } + + expect(await persistMessages(params, "I see it")).toEqual([ + { + role: "user", + content: [ + { type: "text", text: "Look at this screenshot" }, + { + type: "image_url", + imageUrl: { url: "https://example.com/screenshot.png" }, + }, + ], + }, + { role: "assistant", content: "I see it" }, + ]) + }) })