← Back to PRs

#19135: fix(agents): prune excess images from conversation history (#19099)

by pierreeurope open 2026-02-17 12:19 View on GitHub →
gateway agents size: M
## Problem In long sessions, every image sent by the user or returned by a tool accumulates in the conversation history. Providers that enforce a per-request image cap (commonly **8 images**) then reject subsequent requests with: ``` HTTP 400 – Max images exceeded ``` Fixes #19099 ## Solution Rather than letting images pile up indefinitely, we now keep only the **8 most recent** image blocks across the full conversation history. Older image blocks are replaced with a lightweight text placeholder (`[session:history] image removed from history`) so the message structure stays valid for all providers. The limit is controlled by the new `DEFAULT_MAX_HISTORY_IMAGES = 8` constant in `images.ts` and is surfaced through `TranscriptPolicy.maxHistoryImages`. It can be overridden per-provider if needed. ## Changes | File | Change | |------|--------| | `src/agents/pi-embedded-helpers/images.ts` | Add `DEFAULT_MAX_HISTORY_IMAGES`, `countHistoryImages`, `dropOldestImageBlocks` helpers; extend `sanitizeSessionMessagesImages()` with `maxHistoryImages` option | | `src/agents/transcript-policy.ts` | Add `maxHistoryImages` field to `TranscriptPolicy`; default to `DEFAULT_MAX_HISTORY_IMAGES` in `resolveTranscriptPolicy()` | | `src/agents/pi-embedded-runner/google.ts` | Forward `policy.maxHistoryImages` into `sanitizeSessionHistory()` | | `src/agents/pi-embedded-helpers.ts` | Re-export `DEFAULT_MAX_HISTORY_IMAGES` | | `src/agents/pi-embedded-helpers.sanitize-session-messages-images.prunes-history-images.test.ts` | Unit tests for the new pruning logic | ## Testing - New unit tests verify that images beyond the cap are replaced with placeholders and that the N most recent images are always preserved. - TypeScript compiles without errors (`npx tsc --noEmit`). <!-- greptile_comment --> <h3>Greptile Summary</h3> This PR adds image-count pruning to conversation history to prevent HTTP 400 "Max images exceeded" errors from providers that cap per-request images (commonly 8). When the total image count exceeds `maxHistoryImages` (default 8), the oldest image blocks are replaced with lightweight text placeholders (`[session:history] image removed from history`), preserving message structure while staying within provider limits. - Adds `DEFAULT_MAX_HISTORY_IMAGES = 8` constant, `countHistoryImages`, and `dropOldestImageBlocks` helper functions in `images.ts` - Extends `sanitizeSessionMessagesImages()` with a `maxHistoryImages` option that prunes oldest images using a shared mutable counter across all messages - Adds `maxHistoryImages` field to `TranscriptPolicy` type, defaulting to 8 for all providers via `resolveTranscriptPolicy()` - Forwards the option through both the `google.ts` runner and the main `attempt.ts` runner paths (via `sanitizeSessionHistory`) - Includes 6 unit tests covering within-limit, over-limit, disabled, zero, text-only, and newest-preserved scenarios - Separately, adds explicit `"utf-8"` encoding to SSE `res.write()` calls in the gateway HTTP handlers (defensive improvement) <h3>Confidence Score: 4/5</h3> - This PR is safe to merge with minimal risk; the pruning logic is well-structured, properly tested, and correctly integrated into all existing code paths. - The implementation is clean, well-documented, and follows existing patterns. The mutable counter approach for tracking drops across messages is correct. Tests cover key edge cases. The universal 8-image cap for all providers is a conservative safe default. The gateway UTF-8 changes are trivially correct. No logic bugs or security issues found. - No files require special attention. The core logic in `src/agents/pi-embedded-helpers/images.ts` has been thoroughly reviewed and the pruning approach is sound. <sub>Last reviewed commit: 236f287</sub> <!-- greptile_other_comments_section --> <!-- /greptile_comment -->

Most Similar PRs