@@ -1997,12 +1997,11 @@ def test_malformed_config_file_falls_back_to_default(self):
19971997
19981998
19991999class TestImageInputModelResolution (unittest .TestCase ):
2000- """_payload consults image_input_models config to decide whether to
2001- strip image parts, and a malformed section must not crash the
2002- request path (mirrors the defensive context_window property)."""
2000+ """_payload uses the supports_image_input flag to decide whether to
2001+ strip image parts."""
20032002
2004- def _client (self , model : str , config_path : str | None = None ) -> Client :
2005- c = Client (base_url = "http://x/v1" , api_key = "k" , model = model , config_path = config_path )
2003+ def _client (self , model : str = "test-model" ) -> Client :
2004+ c = Client (base_url = "http://x/v1" , api_key = "k" , model = model )
20062005 self .addCleanup (c .close )
20072006 return c
20082007
@@ -2011,86 +2010,23 @@ def _img_msg(self):
20112010
20122011 return Message (role = "user" , content = [ImagePart (data = b"\x89 PNG" , media_type = "image/png" )])
20132012
2014- def test_config_declared_model_keeps_images (self ):
2015- """A model listed in image_input_models keeps its image parts."""
2016- with tempfile .TemporaryDirectory () as d :
2017- p = Path (d ) / "config.json"
2018- p .write_text ('{"image_input_models": ["my-vlm"]}' , encoding = "utf-8" )
2019- c = self ._client ("my-vlm-v2" , str (p ))
2020- payload = c ._payload ([self ._img_msg ()])
2021- content = payload ["messages" ][0 ]["content" ]
2022- self .assertIsInstance (content , list )
2023- self .assertEqual (content [0 ]["type" ], "image_url" )
2024-
2025- def test_unlisted_model_strips_images (self ):
2026- """A model not in config nor built-in table strips image parts
2027- (image-only content collapses to the placeholder)."""
2028- with tempfile .TemporaryDirectory () as d :
2029- p = Path (d ) / "config.json"
2030- p .write_text ('{"image_input_models": ["my-vlm"]}' , encoding = "utf-8" )
2031- c = self ._client ("some-text-model" , str (p ))
2032- payload = c ._payload ([self ._img_msg ()])
2033- self .assertEqual (
2034- payload ["messages" ][0 ]["content" ],
2035- "[1 image omitted: model does not support image input]" ,
2036- )
2037-
2038- def test_malformed_config_does_not_crash_payload (self ):
2039- """A broken image_input_models section must not break _payload:
2040- it falls back to the built-in table instead of raising."""
2041- with tempfile .TemporaryDirectory () as d :
2042- p = Path (d ) / "config.json"
2043- # object instead of array -> loader raises ValueError
2044- p .write_text ('{"image_input_models": {"x": 1}}' , encoding = "utf-8" )
2045- # gpt-4o is image-capable via the BUILT-IN table, so a
2046- # successful fallback keeps its image parts (no crash).
2047- c = self ._client ("gpt-4o" , str (p ))
2048- payload = c ._payload ([self ._img_msg ()])
2049- content = payload ["messages" ][0 ]["content" ]
2050- self .assertIsInstance (content , list )
2051- self .assertEqual (content [0 ]["type" ], "image_url" )
2052-
2053- def test_malformed_config_text_model_still_strips (self ):
2054- """Fallback path for a text-only model still strips images
2055- rather than crashing on the malformed config."""
2056- with tempfile .TemporaryDirectory () as d :
2057- p = Path (d ) / "config.json"
2058- p .write_text ('{"image_input_models": [123]}' , encoding = "utf-8" )
2059- c = self ._client ("plain-text-model" , str (p ))
2060- payload = c ._payload ([self ._img_msg ()])
2061- self .assertEqual (
2062- payload ["messages" ][0 ]["content" ],
2063- "[1 image omitted: model does not support image input]" ,
2064- )
2065-
2066- def test_strip_image_parts_handles_raw_dict_parts (self ):
2067- """_strip_image_parts also drops raw OpenAI-shaped dict parts
2068- ({"type": "image_url", ...}) and collapses the remaining text
2069- parts to a plain string."""
2070- from python_agent_harness .client import _strip_image_parts
2071-
2072- msg = Message (
2073- role = "user" ,
2074- content = [
2075- {"type" : "text" , "text" : "look at " },
2076- {"type" : "image_url" , "image_url" : {"url" : "data:image/png;base64,xx" }},
2077- "this" ,
2078- ],
2079- )
2080- out = _strip_image_parts (msg )
2081- self .assertEqual (out .content , "look at this" )
2082- # the original message is not mutated
2083- self .assertEqual (len (msg .content ), 3 )
2084-
2085- def test_strip_image_parts_dict_only_collapses_to_placeholder (self ):
2086- from python_agent_harness .client import _strip_image_parts
2087-
2088- msg = Message (
2089- role = "user" ,
2090- content = [{"type" : "image_url" , "image_url" : {"url" : "data:image/png;base64,xx" }}],
2013+ def test_supports_image_input_keeps_images (self ):
2014+ """When supports_image_input is True, image parts are kept."""
2015+ c = self ._client ()
2016+ payload = c ._payload ([self ._img_msg ()], supports_image_input = True )
2017+ content = payload ["messages" ][0 ]["content" ]
2018+ self .assertIsInstance (content , list )
2019+ self .assertEqual (content [0 ]["type" ], "image_url" )
2020+
2021+ def test_no_support_strips_images (self ):
2022+ """When supports_image_input is False (default), image parts
2023+ are stripped (image-only content collapses to the placeholder)."""
2024+ c = self ._client ()
2025+ payload = c ._payload ([self ._img_msg ()])
2026+ self .assertEqual (
2027+ payload ["messages" ][0 ]["content" ],
2028+ "[1 image omitted: model does not support image input]" ,
20912029 )
2092- out = _strip_image_parts (msg )
2093- self .assertEqual (out .content , "[1 image omitted: model does not support image input]" )
20942030
20952031
20962032if __name__ == "__main__" :
0 commit comments