| 26 | |
| 27 | // Helper function to validate file parts in messages |
| 28 | function validateFileParts(messages: any[]): { |
| 29 | valid: boolean |
| 30 | error?: string |
| 31 | } { |
| 32 | const lastMessage = messages[messages.length - 1] |
| 33 | const fileParts = |
| 34 | lastMessage?.parts?.filter((p: any) => p.type === "file") || [] |
| 35 | |
| 36 | if (fileParts.length > MAX_FILES) { |
| 37 | return { |
| 38 | valid: false, |
| 39 | error: `Too many files. Maximum ${MAX_FILES} allowed.`, |
| 40 | } |
| 41 | } |
| 42 | |
| 43 | for (const filePart of fileParts) { |
| 44 | // Data URLs format: data:image/png;base64,<data> |
| 45 | // Base64 increases size by ~33%, so we check the decoded size |
| 46 | if (filePart.url?.startsWith("data:")) { |
| 47 | const base64Data = filePart.url.split(",")[1] |
| 48 | if (base64Data) { |
| 49 | const sizeInBytes = Math.ceil((base64Data.length * 3) / 4) |
| 50 | if (sizeInBytes > MAX_FILE_SIZE) { |
| 51 | return { |
| 52 | valid: false, |
| 53 | error: `File exceeds ${MAX_FILE_SIZE / 1024 / 1024}MB limit.`, |
| 54 | } |
| 55 | } |
| 56 | } |
| 57 | } |
| 58 | } |
| 59 | |
| 60 | return { valid: true } |
| 61 | } |
| 62 | |
| 63 | // Helper function to check if diagram is minimal/empty |
| 64 | function isMinimalDiagram(xml: string): boolean { |