← Back to PRs

#23662: fix: cache sanitized images to avoid redundant re-processing per turn

by davidemanuelDEV open 2026-02-22 15:20 View on GitHub →
agents size: M
## Problem Fixes #23590 When images are sent in a conversation (e.g. via Telegram), every image in session history gets re-processed on every subsequent turn — decoded from base64, metadata read, and potentially resized. In a conversation with 3 images and 10 follow-up messages, that's 30 redundant resize operations instead of 3. The logs fill with repeated identical entries: ``` [agents/tool-images] Image resized to fit limits: 875x1280px 106.0KB -> 109.4KB (--3.2%) [agents/tool-images] Image resized to fit limits: 1280x772px 136.0KB -> 137.1KB (--0.8%) ``` ## Fix Add a bounded in-memory LRU cache (max 64 entries) in `resizeImageBase64IfNeeded` that stores sanitization results keyed by a fast composite key (base64 prefix + length + sanitization parameters). On cache hit, the function returns immediately without: - Decoding base64 to Buffer - Reading image metadata (dimensions, format) - Running resize operations The cache is bounded to prevent unbounded memory growth in very long sessions — when full, the oldest entry is evicted (Map insertion order). ## Cache key design Uses `base64.slice(0, 64) + ":" + base64.length + ":" + maxDimensionPx + ":" + maxBytes` for O(1) lookups. This is sufficient because: - Same base64 string = identical image content (the string IS the content) - The prefix + length combo has effectively zero collision risk - No expensive hashing needed for large images ## Testing Added test that verifies `getImageMetadata` is NOT called on the second pass of the same image through `sanitizeToolResultImages`. ``` ✓ src/agents/tool-images.cache.test.ts (1 test) 2ms ``` --- *This PR was AI-assisted (per CONTRIBUTING.md guidelines).* <!-- greptile_comment --> <h3>Greptile Summary</h3> Adds bounded LRU cache (max 64 entries) to `resizeImageBase64IfNeeded` that prevents redundant image processing across conversation turns. Cache uses composite key (base64 prefix + length + sanitization params) for O(1) lookups without expensive hashing. When cache hits, the function returns immediately without decoding base64, reading metadata, or resizing. Implementation correctly caches both pass-through (no resize) and resized results, with proper Map-based LRU eviction when at capacity. <h3>Confidence Score: 5/5</h3> - This PR is safe to merge with minimal risk - Clean performance optimization with proper bounds, correct LRU eviction logic, effective test coverage validating cache behavior, and no changes to external API surface. The cache key design is sound (prefix + length creates unique identifiers for base64 images), bounded size prevents memory issues, and the implementation only affects the internal performance path. - No files require special attention <sub>Last reviewed commit: 2561966</sub> <!-- greptile_other_comments_section --> <sub>(3/5) Reply to the agent's comments like "Can you suggest a fix for this @greptileai?" or ask follow-up questions!</sub> <!-- /greptile_comment -->

Most Similar PRs