From a3ced453b90665c64f106ffd0dc41ac03ec0086b Mon Sep 17 00:00:00 2001 From: Pavan Kumar VH Date: Fri, 4 Sep 2026 01:09:51 +0530 Subject: [PATCH] Add defensive check for data URL prefix in summarizeDataUrl The summarizeDataUrl function was called from summarizeLargeValue which checks if a string starts with 'data:' before calling it. However, if summarizeDataUrl were ever called from a different context or if the prefix check were removed, the function would incorrectly try to parse non-data-URL strings. Added a defensive check at the start of summarizeDataUrl that returns the value unchanged if it doesn't start with 'data:'. This makes the function safer to use independently and prevents incorrect parsing of malformed inputs. Also added comprehensive test coverage demonstrating: 1. Valid data URLs are properly summarized 2. Non-data-URL strings pass through unchanged 3. Edge case: data URL-like strings without comma are handled gracefully All 3 tests pass. --- common/src/util/__tests__/cache-debug.test.ts | 70 +++++++++++++++++++ common/src/util/cache-debug.ts | 3 + 2 files changed, 73 insertions(+) create mode 100644 common/src/util/__tests__/cache-debug.test.ts diff --git a/common/src/util/__tests__/cache-debug.test.ts b/common/src/util/__tests__/cache-debug.test.ts new file mode 100644 index 0000000000..c3bf96ae9b --- /dev/null +++ b/common/src/util/__tests__/cache-debug.test.ts @@ -0,0 +1,70 @@ +import { describe, expect, it } from 'bun:test' + +import { normalizeProviderRequestBodyForCacheDebug } from '../cache-debug' + +describe('cache-debug data URL handling', () => { + it('summarizes valid data URLs', () => { + const result = normalizeProviderRequestBodyForCacheDebug({ + provider: 'openai', + body: { + model: 'gpt-4', + messages: [ + { + role: 'user', + content: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8/5+hHgAHggJ/PchI7wAAAABJRU5ErkJggg==', + }, + ], + }, + }) + + const message = (result as { messages: unknown[] }).messages[0] as { + content: { type: string; mediaType: string; payloadLength: number } + } + expect(message.content.type).toBe('data-url') + expect(message.content.mediaType).toBe('image/png') + expect(message.content.payloadLength).toBeGreaterThan(0) + }) + + it('passes through non-data-URL strings unchanged', () => { + const result = normalizeProviderRequestBodyForCacheDebug({ + provider: 'openai', + body: { + model: 'gpt-4', + messages: [ + { + role: 'user', + content: 'https://example.com/image.png', + }, + ], + }, + }) + + const message = (result as { messages: unknown[] }).messages[0] as { + content: string + } + expect(message.content).toBe('https://example.com/image.png') + }) + + it('handles data URL-like strings without comma gracefully', () => { + // Edge case: string starts with "data:" but has no comma + const result = normalizeProviderRequestBodyForCacheDebug({ + provider: 'openai', + body: { + model: 'gpt-4', + messages: [ + { + role: 'user', + content: 'data:image/png;base64', + }, + ], + }, + }) + + const message = (result as { messages: unknown[] }).messages[0] as { + content: { type: string; mediaType: string; payloadLength: number } + } + expect(message.content.type).toBe('data-url') + expect(message.content.mediaType).toBe('image/png') + expect(message.content.payloadLength).toBe(0) + }) +}) diff --git a/common/src/util/cache-debug.ts b/common/src/util/cache-debug.ts index 594ffb3faf..31e6e9cdd6 100644 --- a/common/src/util/cache-debug.ts +++ b/common/src/util/cache-debug.ts @@ -48,6 +48,9 @@ function normalizeForJson(value: unknown): SerializableValue { } function summarizeDataUrl(value: string): SerializableValue { + if (!value.startsWith('data:')) { + return value + } const firstComma = value.indexOf(',') const header = firstComma >= 0 ? value.slice(0, firstComma) : value const payload = firstComma >= 0 ? value.slice(firstComma + 1) : ''