From 107acc68a24ca6a68450365a87e793830ee05c73 Mon Sep 17 00:00:00 2001 From: Ryan Westfall Date: Tue, 20 Oct 2026 10:05:12 -0500 Subject: [PATCH] Accept a Blob when checking whether a chat attachment is an image. Beta deploy typechecks the composer file as Blob, so the File-only helper failed the production build after the vision merge. Closes #130. Co-authored-by: Cursor --- .../llm-fe/pages/AsyncDashboard2/AsyncDashboard2.tsx | 12 ++++++------ llm-fe/src/llm-fe/utils/visionAttachment.test.ts | 1 + llm-fe/src/llm-fe/utils/visionAttachment.ts | 2 +- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/llm-fe/src/llm-fe/pages/AsyncDashboard2/AsyncDashboard2.tsx b/llm-fe/src/llm-fe/pages/AsyncDashboard2/AsyncDashboard2.tsx index 7608a5b..29db94e 100644 --- a/llm-fe/src/llm-fe/pages/AsyncDashboard2/AsyncDashboard2.tsx +++ b/llm-fe/src/llm-fe/pages/AsyncDashboard2/AsyncDashboard2.tsx @@ -335,15 +335,15 @@ const AlwaysScrollToBottom = ({ trigger }: { trigger: string | number }): JSX.El return
; }; -const AttachmentPreview = ({ file }: { file: File | null }): JSX.Element | null => { +const AttachmentPreview = ({ file }: { file: Blob | null }): JSX.Element | null => { const theme = useContext(ThemeContext); const [url, setUrl] = useState(null); useEffect(() => { - if (!isImageFile(file)) { + if (!file || !isImageFile(file)) { setUrl(null); return; } - const next = URL.createObjectURL(file as File); + const next = URL.createObjectURL(file); setUrl(next); return () => URL.revokeObjectURL(next); }, [file]); @@ -370,7 +370,7 @@ const AttachmentPreview = ({ file }: { file: File | null }): JSX.Element | null color: theme?.darkMode ? "rgba(255,255,255,0.6)" : "rgba(0,0,0,0.6)", textAlign: "center", }}> - Attached: {file.name} + Attached: {file instanceof File ? file.name : "attachment"}
); }; @@ -473,7 +473,7 @@ const AsyncDashboardInner = (): JSX.Element => { } try { clearActivity(); - const attachedImage = isImageFile(file) ? URL.createObjectURL(file as File) : null; + const attachedImage = file && isImageFile(file) ? URL.createObjectURL(file) : null; const tempConversations: ConversationPrompt[] = [ ...conversationDetails, new ConversationPrompt({ @@ -753,7 +753,7 @@ const AsyncDashboardInner = (): JSX.Element => { - + )} diff --git a/llm-fe/src/llm-fe/utils/visionAttachment.test.ts b/llm-fe/src/llm-fe/utils/visionAttachment.test.ts index fb8ea27..3eaed26 100644 --- a/llm-fe/src/llm-fe/utils/visionAttachment.test.ts +++ b/llm-fe/src/llm-fe/utils/visionAttachment.test.ts @@ -16,6 +16,7 @@ describe('visionAttachment', () => { it('detects image files', () => { expect(isImageFile(new File(['x'], 'a.png', { type: 'image/png' }))).toBe(true); expect(isImageFile(new File(['x'], 'a.pdf', { type: 'application/pdf' }))).toBe(false); + expect(isImageFile(new Blob(['x'], { type: 'image/png' }))).toBe(true); expect(isImageFile(null)).toBe(false); }); }); diff --git a/llm-fe/src/llm-fe/utils/visionAttachment.ts b/llm-fe/src/llm-fe/utils/visionAttachment.ts index 380039c..65b0e9b 100644 --- a/llm-fe/src/llm-fe/utils/visionAttachment.ts +++ b/llm-fe/src/llm-fe/utils/visionAttachment.ts @@ -1,7 +1,7 @@ export const CHAT_FILE_ACCEPT = '.csv,.xlsx,.txt,.pdf,.PDF,image/png,image/jpeg,image/webp,image/gif'; -export function isImageFile(file: File | null | undefined): boolean { +export function isImageFile(file: Blob | null | undefined): boolean { return Boolean(file && file.type.startsWith('image/')); } -- 2.54.0