url-09: fetched images become vision input — fetch_url og:image/body images ride as input_image, direct image urls ingested, data urls never in json tool text

This commit is contained in:
Oleksandr Kozachuk
2026-07-21 13:01:21 +02:00
parent 6f2b3bc040
commit f3c25de310
5 changed files with 222 additions and 22 deletions
+31
View File
@@ -163,3 +163,34 @@ class TestResponsesPath(unittest.IsolatedAsyncioTestCase):
self.assertEqual(items[0]["content"][0], {"type": "input_text", "text": "look"})
self.assertEqual(items[0]["content"][1], {"type": "input_image", "image_url": "data:x"})
self.assertEqual(len(items), 2) # tool row dropped
class TestToolVisionInjection(unittest.IsolatedAsyncioTestCase):
def _responder(self, **extra):
return OpenAIResponder(dict(CONFIG, **extra), "chat")
async def test_tool_vision_images_attached_as_input_image(self):
"""URL-09: a tool result's vision data URLs become input_image items; never JSON text."""
responder = self._responder(**{"enable-news-tool": True})
responder.store = Mock()
responder._dispatch_tool = AsyncMock(
return_value={"url": "u", "text": "t", "images_cached": 1, "vision": ["data:image/png;base64,AAA"]}
)
first = _response([_call_item("fetch_url", {"url": "https://xkcd.com/1"}, "call-2")])
second = _response([_msg_item()], envelope(answer="seen", answer_needed=True))
with patch("fjerkroa_bot.openai_responder.openai_responses", new_callable=AsyncMock) as responses_mock:
responses_mock.side_effect = [first, second]
answer, _ = await responder.chat([{"role": "user", "content": "look at this"}], 10)
self.assertEqual(json.loads(answer["content"])["answer"], "seen")
followup = responses_mock.await_args_list[1].kwargs["input"]
image_parts = [
part
for item in followup
if isinstance(item, dict) and isinstance(item.get("content"), list)
for part in item["content"]
if part.get("type") == "input_image"
]
self.assertEqual(image_parts[0]["image_url"], "data:image/png;base64,AAA")
outputs = [item for item in followup if isinstance(item, dict) and item.get("type") == "function_call_output"]
self.assertNotIn("data:image", outputs[0]["output"]) # data URL never in JSON tool text
self.assertNotIn("vision", outputs[0]["output"])