fix: strip base64 image blobs from session DB to prevent context overflow - #31705
Closed
i-xoxol wants to merge 1 commit into
Closed
fix: strip base64 image blobs from session DB to prevent context overflow#31705i-xoxol wants to merge 1 commit into
i-xoxol wants to merge 1 commit into
Conversation
…flow
When a user sends a photo as a file (uncompressed document), the native-vision
path encodes the full image as a data: base64 URL and stores it in the session
DB. On every subsequent turn, load_transcript decodes and re-injects the full
blob into conversation history, pushing outgoing API requests past provider
body-size or context-window limits ('session overflow').
Fix: add SessionDB._strip_image_blobs() called by _encode_content() to replace
data: base64 blobs with a short text placeholder before the content list is
serialised to SQLite. The local file path hint is already present in the
companion text part (added by build_native_content_parts), so the model can
re-access the image via vision_analyze without any round-trip penalty.
- Plain https:// URLs (Telegram CDN etc.) are unaffected
- _strip_historical_media in context_compressor still fires for any blobs that
entered history before this fix (existing sessions)
- 12 new tests cover the strip logic and encode/decode roundtrip
Contributor
There was a problem hiding this comment.
Pull request overview
Note
Copilot was unable to run its full agentic suite in this review.
Adds protection against session DB bloat by stripping base64 data: image blobs from multimodal message content before persistence, with accompanying unit tests to prevent regressions.
Changes:
- Introduces
SessionDB._strip_image_blobs()to replacedata:image URLs with a short placeholder. - Updates
_encode_content()to call_strip_image_blobs()prior to JSON serialization. - Adds tests covering stripping behavior and
_encode_content()integration.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.
| File | Description |
|---|---|
| tests/gateway/test_session_db_strip_image_blobs.py | Adds unit tests for stripping base64 image blobs and verifying encoded/decoded content doesn’t reintroduce them. |
| hermes_state.py | Implements _strip_image_blobs() and integrates it into _encode_content() to prevent persisting large base64 data URLs. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Comment on lines
+1449
to
+1452
| new_parts.append({ | ||
| "type": "text", | ||
| "text": "[Attached image — base64 stripped for storage; re-read from the path above if needed]", | ||
| }) |
Comment on lines
+1432
to
+1456
| if not any( | ||
| isinstance(p, dict) | ||
| and p.get("type") == "image_url" | ||
| and isinstance(p.get("image_url"), dict) | ||
| and str(p["image_url"].get("url", "")).startswith("data:") | ||
| for p in content | ||
| ): | ||
| return content # fast path — nothing to strip | ||
|
|
||
| new_parts: list = [] | ||
| for p in content: | ||
| if ( | ||
| isinstance(p, dict) | ||
| and p.get("type") == "image_url" | ||
| and isinstance(p.get("image_url"), dict) | ||
| and str(p["image_url"].get("url", "")).startswith("data:") | ||
| ): | ||
| new_parts.append({ | ||
| "type": "text", | ||
| "text": "[Attached image — base64 stripped for storage; re-read from the path above if needed]", | ||
| }) | ||
| else: | ||
| new_parts.append(p) | ||
| return new_parts | ||
|
|
Comment on lines
1477
to
1482
| if content is None or isinstance(content, (str, bytes, int, float)): | ||
| return content | ||
| if isinstance(content, list): | ||
| content = cls._strip_image_blobs(content) | ||
| try: | ||
| return cls._CONTENT_JSON_PREFIX + json.dumps(content) |
Collaborator
Contributor
|
Thanks for the focused regression coverage. This is an automated hermes-sweeper review: the reported persistence/replay overflow is already prevented on current
Closing as implemented on main. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
Sending a photo as an uncompressed file (document) in Telegram caused session context overflow. The native-vision path encodes the image as a
data:image/...;base64,...URL and persists it in the SQLite messages table.get_messages_as_conversation()decodes and re-injects the full blob on every subsequent turn, growing the outgoing API request by ~7 MB per image until the provider rejects it.Normal compressed photos are worse than URLs but still manageable; uncompressed documents (5–20 MB originals) hit the limit quickly.
Fix
Add
SessionDB._strip_image_blobs(), called from_encode_content(), that replacesdata:base64 blobs in multimodal content lists with a short text placeholder before the JSON is written to SQLite.https://URLs (Telegram CDN etc.) are not affectedtextpart ([Image attached at: /tmp/...]), so the model can re-read the image viavision_analyzeif needed_strip_historical_mediain the context compressor (existing safety net, now a last resort rather than first line of defence)Tests
12 new unit tests in
tests/gateway/test_session_db_strip_image_blobs.pycovering:https://URL untoucheddata:blobs replaceddata:/https:content_encode_contentintegration