| | import { Providers } from '@librechat/agents'; |
| | import { mbToBytes } from 'librechat-data-provider'; |
| | import { validatePdf, validateVideo, validateAudio } from './validation'; |
| |
|
| | describe('PDF Validation with fileConfig.endpoints.*.fileSizeLimit', () => { |
| | |
| | const createMockPdfBuffer = (sizeInMB: number): Buffer => { |
| | const bytes = Math.floor(sizeInMB * 1024 * 1024); |
| | const buffer = Buffer.alloc(bytes); |
| | buffer.write('%PDF-1.4\n', 0); |
| | return buffer; |
| | }; |
| |
|
| | describe('validatePdf - OpenAI provider', () => { |
| | const provider = Providers.OPENAI; |
| |
|
| | it('should accept PDF within provider limit when no config provided', async () => { |
| | const pdfBuffer = createMockPdfBuffer(8); |
| | const result = await validatePdf(pdfBuffer, pdfBuffer.length, provider); |
| |
|
| | expect(result.isValid).toBe(true); |
| | expect(result.error).toBeUndefined(); |
| | }); |
| |
|
| | it('should reject PDF exceeding provider limit when no config provided', async () => { |
| | const pdfBuffer = createMockPdfBuffer(12); |
| | const result = await validatePdf(pdfBuffer, pdfBuffer.length, provider); |
| |
|
| | expect(result.isValid).toBe(false); |
| | expect(result.error).toContain('12MB'); |
| | expect(result.error).toContain('10MB'); |
| | }); |
| |
|
| | it('should use configured limit when it is lower than provider limit', async () => { |
| | const configuredLimit = 5 * 1024 * 1024; |
| | const pdfBuffer = createMockPdfBuffer(7); |
| | const result = await validatePdf(pdfBuffer, pdfBuffer.length, provider, configuredLimit); |
| |
|
| | expect(result.isValid).toBe(false); |
| | expect(result.error).toContain('7MB'); |
| | expect(result.error).toContain('5MB'); |
| | }); |
| |
|
| | it('should allow configured limit higher than provider default', async () => { |
| | const configuredLimit = 50 * 1024 * 1024; |
| | const pdfBuffer = createMockPdfBuffer(12); |
| | const result = await validatePdf(pdfBuffer, pdfBuffer.length, provider, configuredLimit); |
| |
|
| | expect(result.isValid).toBe(true); |
| | expect(result.error).toBeUndefined(); |
| | }); |
| |
|
| | it('should accept PDF within both configured and provider limits', async () => { |
| | const configuredLimit = 50 * 1024 * 1024; |
| | const pdfBuffer = createMockPdfBuffer(8); |
| | const result = await validatePdf(pdfBuffer, pdfBuffer.length, provider, configuredLimit); |
| |
|
| | expect(result.isValid).toBe(true); |
| | expect(result.error).toBeUndefined(); |
| | }); |
| |
|
| | it('should accept PDF within lower configured limit', async () => { |
| | const configuredLimit = 5 * 1024 * 1024; |
| | const pdfBuffer = createMockPdfBuffer(4); |
| | const result = await validatePdf(pdfBuffer, pdfBuffer.length, provider, configuredLimit); |
| |
|
| | expect(result.isValid).toBe(true); |
| | expect(result.error).toBeUndefined(); |
| | }); |
| |
|
| | it('should handle exact limit size correctly', async () => { |
| | const configuredLimit = 10 * 1024 * 1024; |
| | const pdfBuffer = Buffer.alloc(10 * 1024 * 1024); |
| | pdfBuffer.write('%PDF-1.4\n', 0); |
| | const result = await validatePdf(pdfBuffer, pdfBuffer.length, provider, configuredLimit); |
| |
|
| | expect(result.isValid).toBe(true); |
| | }); |
| | }); |
| |
|
| | describe('validatePdf - Anthropic provider', () => { |
| | const provider = Providers.ANTHROPIC; |
| |
|
| | it('should accept PDF within provider limit when no config provided', async () => { |
| | const pdfBuffer = createMockPdfBuffer(20); |
| | const result = await validatePdf(pdfBuffer, pdfBuffer.length, provider); |
| |
|
| | expect(result.isValid).toBe(true); |
| | expect(result.error).toBeUndefined(); |
| | }); |
| |
|
| | it('should reject PDF exceeding provider limit when no config provided', async () => { |
| | const pdfBuffer = createMockPdfBuffer(35); |
| | const result = await validatePdf(pdfBuffer, pdfBuffer.length, provider); |
| |
|
| | expect(result.isValid).toBe(false); |
| | expect(result.error).toContain('35MB'); |
| | expect(result.error).toContain('32MB'); |
| | }); |
| |
|
| | it('should use configured limit when it is lower than provider limit', async () => { |
| | const configuredLimit = mbToBytes(15); |
| | const pdfBuffer = createMockPdfBuffer(20); |
| | const result = await validatePdf(pdfBuffer, pdfBuffer.length, provider, configuredLimit); |
| |
|
| | expect(result.isValid).toBe(false); |
| | expect(result.error).toContain('20MB'); |
| | expect(result.error).toContain('15MB'); |
| | }); |
| |
|
| | it('should allow configured limit higher than provider default', async () => { |
| | const configuredLimit = mbToBytes(50); |
| | const pdfBuffer = createMockPdfBuffer(35); |
| | const result = await validatePdf(pdfBuffer, pdfBuffer.length, provider, configuredLimit); |
| |
|
| | expect(result.isValid).toBe(true); |
| | expect(result.error).toBeUndefined(); |
| | }); |
| |
|
| | it('should reject encrypted PDFs regardless of size', async () => { |
| | const pdfBuffer = Buffer.alloc(1024); |
| | pdfBuffer.write('%PDF-1.4\n', 0); |
| | pdfBuffer.write('/Encrypt ', 100); |
| | const result = await validatePdf(pdfBuffer, pdfBuffer.length, provider); |
| |
|
| | expect(result.isValid).toBe(false); |
| | expect(result.error).toContain('encrypted'); |
| | }); |
| |
|
| | it('should reject PDFs with invalid header', async () => { |
| | const pdfBuffer = Buffer.alloc(1024); |
| | pdfBuffer.write('INVALID', 0); |
| | const result = await validatePdf(pdfBuffer, pdfBuffer.length, provider); |
| |
|
| | expect(result.isValid).toBe(false); |
| | expect(result.error).toContain('PDF header'); |
| | }); |
| |
|
| | it('should reject PDFs that are too small', async () => { |
| | const pdfBuffer = Buffer.alloc(3); |
| | const result = await validatePdf(pdfBuffer, pdfBuffer.length, provider); |
| |
|
| | expect(result.isValid).toBe(false); |
| | expect(result.error).toContain('too small'); |
| | }); |
| | }); |
| |
|
| | describe('validatePdf - Google provider', () => { |
| | const provider = Providers.GOOGLE; |
| |
|
| | it('should accept PDF within provider limit when no config provided', async () => { |
| | const pdfBuffer = createMockPdfBuffer(15); |
| | const result = await validatePdf(pdfBuffer, pdfBuffer.length, provider); |
| |
|
| | expect(result.isValid).toBe(true); |
| | expect(result.error).toBeUndefined(); |
| | }); |
| |
|
| | it('should reject PDF exceeding provider limit when no config provided', async () => { |
| | const pdfBuffer = createMockPdfBuffer(25); |
| | const result = await validatePdf(pdfBuffer, pdfBuffer.length, provider); |
| |
|
| | expect(result.isValid).toBe(false); |
| | expect(result.error).toContain('25MB'); |
| | expect(result.error).toContain('20MB'); |
| | }); |
| |
|
| | it('should use configured limit when it is lower than provider limit', async () => { |
| | const configuredLimit = 10 * 1024 * 1024; |
| | const pdfBuffer = createMockPdfBuffer(15); |
| | const result = await validatePdf(pdfBuffer, pdfBuffer.length, provider, configuredLimit); |
| |
|
| | expect(result.isValid).toBe(false); |
| | expect(result.error).toContain('15MB'); |
| | expect(result.error).toContain('10MB'); |
| | }); |
| |
|
| | it('should allow configured limit higher than provider default', async () => { |
| | const configuredLimit = 50 * 1024 * 1024; |
| | const pdfBuffer = createMockPdfBuffer(25); |
| | const result = await validatePdf(pdfBuffer, pdfBuffer.length, provider, configuredLimit); |
| |
|
| | expect(result.isValid).toBe(true); |
| | expect(result.error).toBeUndefined(); |
| | }); |
| | }); |
| |
|
| | describe('validatePdf - VertexAI provider', () => { |
| | const provider = Providers.VERTEXAI; |
| |
|
| | it('should accept PDF within provider limit', async () => { |
| | const pdfBuffer = createMockPdfBuffer(15); |
| | const result = await validatePdf(pdfBuffer, pdfBuffer.length, provider); |
| |
|
| | expect(result.isValid).toBe(true); |
| | }); |
| |
|
| | it('should respect configured limit', async () => { |
| | const configuredLimit = 10 * 1024 * 1024; |
| | const pdfBuffer = createMockPdfBuffer(15); |
| | const result = await validatePdf(pdfBuffer, pdfBuffer.length, provider, configuredLimit); |
| |
|
| | expect(result.isValid).toBe(false); |
| | expect(result.error).toContain('10MB'); |
| | }); |
| | }); |
| |
|
| | describe('validatePdf - Azure OpenAI provider', () => { |
| | const provider = Providers.AZURE; |
| |
|
| | it('should accept PDF within OpenAI-like provider limit', async () => { |
| | const pdfBuffer = createMockPdfBuffer(8); |
| | const result = await validatePdf(pdfBuffer, pdfBuffer.length, provider); |
| |
|
| | expect(result.isValid).toBe(true); |
| | }); |
| |
|
| | it('should respect configured limit for Azure', async () => { |
| | const configuredLimit = 5 * 1024 * 1024; |
| | const pdfBuffer = createMockPdfBuffer(7); |
| | const result = await validatePdf(pdfBuffer, pdfBuffer.length, provider, configuredLimit); |
| |
|
| | expect(result.isValid).toBe(false); |
| | }); |
| | }); |
| |
|
| | describe('validatePdf - Unsupported providers', () => { |
| | it('should return valid for providers without specific validation', async () => { |
| | const pdfBuffer = createMockPdfBuffer(100); |
| | const provider = 'unsupported' as Providers; |
| | const result = await validatePdf(pdfBuffer, pdfBuffer.length, provider); |
| |
|
| | expect(result.isValid).toBe(true); |
| | }); |
| | }); |
| |
|
| | describe('Edge cases', () => { |
| | it('should handle zero-configured limit', async () => { |
| | const configuredLimit = 0; |
| | const pdfBuffer = createMockPdfBuffer(1); |
| | const result = await validatePdf( |
| | pdfBuffer, |
| | pdfBuffer.length, |
| | Providers.OPENAI, |
| | configuredLimit, |
| | ); |
| |
|
| | expect(result.isValid).toBe(false); |
| | expect(result.error).toContain('0MB'); |
| | }); |
| |
|
| | it('should handle very small PDF files', async () => { |
| | const pdfBuffer = Buffer.alloc(100); |
| | pdfBuffer.write('%PDF-1.4\n', 0); |
| | const result = await validatePdf( |
| | pdfBuffer, |
| | pdfBuffer.length, |
| | Providers.OPENAI, |
| | 10 * 1024 * 1024, |
| | ); |
| |
|
| | expect(result.isValid).toBe(true); |
| | }); |
| |
|
| | it('should handle configured limit equal to provider limit', async () => { |
| | const configuredLimit = 10 * 1024 * 1024; |
| | const pdfBuffer = createMockPdfBuffer(12); |
| | const result = await validatePdf( |
| | pdfBuffer, |
| | pdfBuffer.length, |
| | Providers.OPENAI, |
| | configuredLimit, |
| | ); |
| |
|
| | expect(result.isValid).toBe(false); |
| | expect(result.error).toContain('10MB'); |
| | }); |
| |
|
| | it('should use provider limit when configured limit is undefined', async () => { |
| | const pdfBuffer = createMockPdfBuffer(12); |
| | const result = await validatePdf(pdfBuffer, pdfBuffer.length, Providers.OPENAI, undefined); |
| |
|
| | expect(result.isValid).toBe(false); |
| | expect(result.error).toContain('10MB'); |
| | }); |
| | }); |
| |
|
| | describe('Bug reproduction - Original issue', () => { |
| | it('should reproduce the original bug scenario from issue description', async () => { |
| | |
| | |
| | |
| | |
| | |
| | |
| | const configuredLimit = mbToBytes(50); |
| | const pdfBuffer = createMockPdfBuffer(15); |
| |
|
| | const result = await validatePdf( |
| | pdfBuffer, |
| | pdfBuffer.length, |
| | Providers.OPENAI, |
| | configuredLimit, |
| | ); |
| |
|
| | |
| | |
| | |
| | |
| | expect(result.isValid).toBe(true); |
| | expect(result.error).toBeUndefined(); |
| | }); |
| |
|
| | it('should allow user to set stricter limits than provider', async () => { |
| | |
| | |
| | |
| | |
| | |
| | |
| | const configuredLimit = mbToBytes(5); |
| | const pdfBuffer = createMockPdfBuffer(7); |
| |
|
| | const result = await validatePdf( |
| | pdfBuffer, |
| | pdfBuffer.length, |
| | Providers.OPENAI, |
| | configuredLimit, |
| | ); |
| |
|
| | expect(result.isValid).toBe(false); |
| | expect(result.error).toContain('7MB'); |
| | expect(result.error).toContain('5MB'); |
| | }); |
| |
|
| | it('should allow upload within stricter user-configured limit', async () => { |
| | |
| | |
| | |
| | |
| | |
| | const configuredLimit = mbToBytes(5); |
| | const pdfBuffer = createMockPdfBuffer(4); |
| |
|
| | const result = await validatePdf( |
| | pdfBuffer, |
| | pdfBuffer.length, |
| | Providers.OPENAI, |
| | configuredLimit, |
| | ); |
| |
|
| | expect(result.isValid).toBe(true); |
| | expect(result.error).toBeUndefined(); |
| | }); |
| | }); |
| |
|
| | describe('Video and Audio Validation with fileConfig', () => { |
| | |
| | const createMockMediaBuffer = (sizeInMB: number): Buffer => { |
| | const bytes = Math.floor(sizeInMB * 1024 * 1024); |
| | return Buffer.alloc(bytes); |
| | }; |
| |
|
| | describe('validateVideo - Google provider', () => { |
| | const provider = Providers.GOOGLE; |
| |
|
| | it('should accept video within provider limit when no config provided', async () => { |
| | const videoBuffer = createMockMediaBuffer(15); |
| | const result = await validateVideo(videoBuffer, videoBuffer.length, provider); |
| |
|
| | expect(result.isValid).toBe(true); |
| | expect(result.error).toBeUndefined(); |
| | }); |
| |
|
| | it('should reject video exceeding provider limit when no config provided', async () => { |
| | const videoBuffer = createMockMediaBuffer(25); |
| | const result = await validateVideo(videoBuffer, videoBuffer.length, provider); |
| |
|
| | expect(result.isValid).toBe(false); |
| | expect(result.error).toContain('25MB'); |
| | expect(result.error).toContain('20MB'); |
| | }); |
| |
|
| | it('should use configured limit when it is lower than provider limit', async () => { |
| | const configuredLimit = mbToBytes(10); |
| | const videoBuffer = createMockMediaBuffer(15); |
| | const result = await validateVideo( |
| | videoBuffer, |
| | videoBuffer.length, |
| | provider, |
| | configuredLimit, |
| | ); |
| |
|
| | expect(result.isValid).toBe(false); |
| | expect(result.error).toContain('15MB'); |
| | expect(result.error).toContain('10MB'); |
| | }); |
| |
|
| | it('should allow configured limit higher than provider default', async () => { |
| | const configuredLimit = mbToBytes(50); |
| | const videoBuffer = createMockMediaBuffer(25); |
| | const result = await validateVideo( |
| | videoBuffer, |
| | videoBuffer.length, |
| | provider, |
| | configuredLimit, |
| | ); |
| |
|
| | expect(result.isValid).toBe(true); |
| | expect(result.error).toBeUndefined(); |
| | }); |
| |
|
| | it('should accept video within lower configured limit', async () => { |
| | const configuredLimit = mbToBytes(8); |
| | const videoBuffer = createMockMediaBuffer(7); |
| | const result = await validateVideo( |
| | videoBuffer, |
| | videoBuffer.length, |
| | provider, |
| | configuredLimit, |
| | ); |
| |
|
| | expect(result.isValid).toBe(true); |
| | expect(result.error).toBeUndefined(); |
| | }); |
| |
|
| | it('should reject videos that are too small', async () => { |
| | const videoBuffer = Buffer.alloc(5); |
| | const result = await validateVideo(videoBuffer, videoBuffer.length, provider); |
| |
|
| | expect(result.isValid).toBe(false); |
| | expect(result.error).toContain('too small'); |
| | }); |
| | }); |
| |
|
| | describe('validateAudio - Google provider', () => { |
| | const provider = Providers.GOOGLE; |
| |
|
| | it('should accept audio within provider limit when no config provided', async () => { |
| | const audioBuffer = createMockMediaBuffer(15); |
| | const result = await validateAudio(audioBuffer, audioBuffer.length, provider); |
| |
|
| | expect(result.isValid).toBe(true); |
| | expect(result.error).toBeUndefined(); |
| | }); |
| |
|
| | it('should reject audio exceeding provider limit when no config provided', async () => { |
| | const audioBuffer = createMockMediaBuffer(25); |
| | const result = await validateAudio(audioBuffer, audioBuffer.length, provider); |
| |
|
| | expect(result.isValid).toBe(false); |
| | expect(result.error).toContain('25MB'); |
| | expect(result.error).toContain('20MB'); |
| | }); |
| |
|
| | it('should use configured limit when it is lower than provider limit', async () => { |
| | const configuredLimit = mbToBytes(10); |
| | const audioBuffer = createMockMediaBuffer(15); |
| | const result = await validateAudio( |
| | audioBuffer, |
| | audioBuffer.length, |
| | provider, |
| | configuredLimit, |
| | ); |
| |
|
| | expect(result.isValid).toBe(false); |
| | expect(result.error).toContain('15MB'); |
| | expect(result.error).toContain('10MB'); |
| | }); |
| |
|
| | it('should allow configured limit higher than provider default', async () => { |
| | const configuredLimit = mbToBytes(50); |
| | const audioBuffer = createMockMediaBuffer(25); |
| | const result = await validateAudio( |
| | audioBuffer, |
| | audioBuffer.length, |
| | provider, |
| | configuredLimit, |
| | ); |
| |
|
| | expect(result.isValid).toBe(true); |
| | expect(result.error).toBeUndefined(); |
| | }); |
| |
|
| | it('should accept audio within lower configured limit', async () => { |
| | const configuredLimit = mbToBytes(8); |
| | const audioBuffer = createMockMediaBuffer(7); |
| | const result = await validateAudio( |
| | audioBuffer, |
| | audioBuffer.length, |
| | provider, |
| | configuredLimit, |
| | ); |
| |
|
| | expect(result.isValid).toBe(true); |
| | expect(result.error).toBeUndefined(); |
| | }); |
| |
|
| | it('should reject audio files that are too small', async () => { |
| | const audioBuffer = Buffer.alloc(5); |
| | const result = await validateAudio(audioBuffer, audioBuffer.length, provider); |
| |
|
| | expect(result.isValid).toBe(false); |
| | expect(result.error).toContain('too small'); |
| | }); |
| | }); |
| |
|
| | describe('validateVideo and validateAudio - VertexAI provider', () => { |
| | const provider = Providers.VERTEXAI; |
| |
|
| | it('should respect configured video limit for VertexAI', async () => { |
| | const configuredLimit = mbToBytes(10); |
| | const videoBuffer = createMockMediaBuffer(15); |
| | const result = await validateVideo( |
| | videoBuffer, |
| | videoBuffer.length, |
| | provider, |
| | configuredLimit, |
| | ); |
| |
|
| | expect(result.isValid).toBe(false); |
| | expect(result.error).toContain('10MB'); |
| | }); |
| |
|
| | it('should respect configured audio limit for VertexAI', async () => { |
| | const configuredLimit = mbToBytes(10); |
| | const audioBuffer = createMockMediaBuffer(15); |
| | const result = await validateAudio( |
| | audioBuffer, |
| | audioBuffer.length, |
| | provider, |
| | configuredLimit, |
| | ); |
| |
|
| | expect(result.isValid).toBe(false); |
| | expect(result.error).toContain('10MB'); |
| | }); |
| | }); |
| |
|
| | describe('validateVideo and validateAudio - Unsupported providers', () => { |
| | it('should return valid for video from unsupported provider', async () => { |
| | const videoBuffer = createMockMediaBuffer(100); |
| | const provider = Providers.OPENAI; |
| | const result = await validateVideo(videoBuffer, videoBuffer.length, provider); |
| |
|
| | expect(result.isValid).toBe(true); |
| | }); |
| |
|
| | it('should return valid for audio from unsupported provider', async () => { |
| | const audioBuffer = createMockMediaBuffer(100); |
| | const provider = Providers.OPENAI; |
| | const result = await validateAudio(audioBuffer, audioBuffer.length, provider); |
| |
|
| | expect(result.isValid).toBe(true); |
| | }); |
| | }); |
| | }); |
| | }); |
| |
|