From 524ede52d23c2c2d400cde3a80aaf54ba669cd02 Mon Sep 17 00:00:00 2001 From: Pugazhendhi Date: Mon, 7 Jul 2025 11:21:32 +0530 Subject: [PATCH] feat: add .svg support (#3229) --- packages/core/src/utils/fileUtils.test.ts | 25 +++++++++++++++++++++++ packages/core/src/utils/fileUtils.ts | 20 +++++++++++++++++- 2 files changed, 44 insertions(+), 1 deletion(-) diff --git a/packages/core/src/utils/fileUtils.test.ts b/packages/core/src/utils/fileUtils.test.ts index c1381e85..78a5ab4c 100644 --- a/packages/core/src/utils/fileUtils.test.ts +++ b/packages/core/src/utils/fileUtils.test.ts @@ -211,6 +211,11 @@ describe('fileUtils', () => { expect(detectFileType('file.jpg')).toBe('image'); }); + it('should detect svg type by extension', () => { + expect(detectFileType('image.svg')).toBe('svg'); + expect(detectFileType('image.icon.svg')).toBe('svg'); + }); + it('should detect pdf type by extension', () => { mockMimeLookup.mockReturnValueOnce('application/pdf'); expect(detectFileType('file.pdf')).toBe('pdf'); @@ -355,6 +360,26 @@ describe('fileUtils', () => { expect(result.returnDisplay).toContain('Read pdf file: document.pdf'); }); + it('should read an SVG file as text when under 1MB', async () => { + const svgContent = ` + + + + `; + const testSvgFilePath = path.join(tempRootDir, 'test.svg'); + actualNodeFs.writeFileSync(testSvgFilePath, svgContent, 'utf-8'); + + mockMimeLookup.mockReturnValue('image/svg+xml'); + + const result = await processSingleFileContent( + testSvgFilePath, + tempRootDir, + ); + + expect(result.llmContent).toBe(svgContent); + expect(result.returnDisplay).toContain('Read SVG as text'); + }); + it('should skip binary files', async () => { actualNodeFs.writeFileSync( testBinaryFilePath, diff --git a/packages/core/src/utils/fileUtils.ts b/packages/core/src/utils/fileUtils.ts index 72f29436..a6b2e456 100644 --- a/packages/core/src/utils/fileUtils.ts +++ b/packages/core/src/utils/fileUtils.ts @@ -98,7 +98,7 @@ export function isBinaryFile(filePath: string): boolean { */ export function detectFileType( filePath: string, -): 'text' | 'image' | 'pdf' | 'audio' | 'video' | 'binary' { +): 'text' | 'image' | 'pdf' | 'audio' | 'video' | 'binary' | 'svg' { const ext = path.extname(filePath).toLowerCase(); // The mimetype for "ts" is MPEG transport stream (a video format) but we want @@ -107,6 +107,10 @@ export function detectFileType( return 'text'; } + if (ext === '.svg') { + return 'svg'; + } + const lookedUpMimeType = mime.lookup(filePath); // Returns false if not found, or the mime type string if (lookedUpMimeType) { if (lookedUpMimeType.startsWith('image/')) { @@ -235,6 +239,20 @@ export async function processSingleFileContent( returnDisplay: `Skipped binary file: ${relativePathForDisplay}`, }; } + case 'svg': { + const SVG_MAX_SIZE_BYTES = 1 * 1024 * 1024; + if (stats.size > SVG_MAX_SIZE_BYTES) { + return { + llmContent: `Cannot display content of SVG file larger than 1MB: ${relativePathForDisplay}`, + returnDisplay: `Skipped large SVG file (>1MB): ${relativePathForDisplay}`, + }; + } + const content = await fs.promises.readFile(filePath, 'utf8'); + return { + llmContent: content, + returnDisplay: `Read SVG as text: ${relativePathForDisplay}`, + }; + } case 'text': { const content = await fs.promises.readFile(filePath, 'utf8'); const lines = content.split('\n');