From 02416190681e811dfd8b60de55d44beb645098bd Mon Sep 17 00:00:00 2001 From: Al Cooke Date: Thu, 21 May 2026 10:19:34 -0400 Subject: [PATCH] fix: retry text-only on Codex invalid image data errors Treat the ChatGPT Codex invalid image-data 400 as an image rejection so Hermes strips image parts and retries text-only instead of aborting the session. Add coverage for the exact error wording. --- agent/conversation_loop.py | 5 +++++ contributors/emails/alcookephilly@gmail.com | 1 + .../run_agent/test_image_rejection_fallback.py | 18 ++++++++++++++++++ 3 files changed, 24 insertions(+) create mode 100644 contributors/emails/alcookephilly@gmail.com diff --git a/agent/conversation_loop.py b/agent/conversation_loop.py index 99da6974ca..6480721fdc 100644 --- a/agent/conversation_loop.py +++ b/agent/conversation_loop.py @@ -4672,6 +4672,11 @@ def run_conversation( # we don't false-trip on other URL validation # errors. (issue #23570) "image_url'. expected", + # ChatGPT-account Codex can also reject corrupt/unsupported + # native image payloads with this wording. Treat it like a + # provider image rejection so the loop strips images and + # retries text-only instead of aborting the session. + "image data you provided does not represent a valid image", # DeepSeek's OpenAI-compatible API reports text-only # request-body variants as: # "unknown variant `image_url`, expected `text`". diff --git a/contributors/emails/alcookephilly@gmail.com b/contributors/emails/alcookephilly@gmail.com new file mode 100644 index 0000000000..506608db14 --- /dev/null +++ b/contributors/emails/alcookephilly@gmail.com @@ -0,0 +1 @@ +alcookephilly-lgtm diff --git a/tests/run_agent/test_image_rejection_fallback.py b/tests/run_agent/test_image_rejection_fallback.py index d4a643e7dd..d071df673c 100644 --- a/tests/run_agent/test_image_rejection_fallback.py +++ b/tests/run_agent/test_image_rejection_fallback.py @@ -140,6 +140,7 @@ class TestImageRejectionPhraseIsolation: "image_url'. expected", "no endpoints found that support image input", "failed to decode image", + "image data you provided does not represent a valid image", ) def _matches(self, body: str) -> bool: @@ -169,5 +170,22 @@ class TestImageRejectionPhraseIsolation: + def test_real_image_rejection_bodies_trip(self): + """Positive cases — real-world error wordings that should trigger.""" + bodies = [ + "Only 'text' content type is supported.", + "Bad request: multimodal is not supported by this model", + "This model does not support images", + "vision is not supported on this endpoint", + "model does not support image input", + # ChatGPT-account Codex backend (issue #23570) — rejects + # data:image/...base64 URLs in input_image fields. Without this + # match the agent cascaded into compression / context-too-large + # recovery instead of just stripping the images. + "Invalid 'input[56].content[1].image_url'. Expected a valid URL, but got a value with an invalid format.", + "The image data you provided does not represent a valid image. Please check your input and try again.", + ] + for body in bodies: + assert self._matches(body) is True, f"false negative on: {body}"