Reject empty Vision Model responses
Alessandro committed
Aug 25, 2026 at 22:01 UTC
1d922aaab27fb583f16647e93718310de4c22b98
3 files changed
+44
tests/test_vision_load_image_refs.py
+41
@@ -242,6 +242,47 @@ async def test_vision_model_sends_multiple_images_once_and_keeps_history_text_on
242
assert tool_results[0][1]["_responses_output_item"]["output"] == response.message
243
244
245
+@pytest.mark.anyio
246
+async def test_vision_model_empty_response_is_reported_as_error(monkeypatch):
247
+ _install_tool_stub(monkeypatch)
248
+ import tools.vision_load as vision_load_module
249
+
250
+ class FakeVisionModel:
251
+ async def unified_call(self, **kwargs):
252
+ return "", ""
253
+
254
+ monkeypatch.setattr(
255
+ vision_load_module,
256
+ "build_vision_model",
257
+ lambda _agent: FakeVisionModel(),
258
+ )
259
+ monkeypatch.setattr(
260
+ vision_load_module,
261
+ "get_vision_model_config",
262
+ lambda _agent: {"provider": "test", "name": "vision", "max_embeds": 10},
263
+ )
264
+
265
+ agent = SimpleNamespace(
266
+ context=SimpleNamespace(id="", get_data=lambda _key: ""),
267
+ last_user_message=SimpleNamespace(output_text=lambda: "Inspect the image."),
268
+ read_prompt=lambda _name, request: request,
269
+ )
270
+ tool = vision_load_module.VisionLoad(
271
+ agent=agent,
272
+ name="vision_load",
273
+ method=None,
274
+ args={"paths": ["data:image/png;base64,AA=="]},
275
+ message="",
276
+ loop_data=None,
277
+ )
278
+
279
+ response = await tool.execute(paths=["data:image/png;base64,AA=="])
280
+
281
+ assert response.message == (
282
+ "Image analysis error: Vision Model returned an empty response."
283
+ )
284
+
285
+
286
@pytest.mark.anyio
287
async def test_parallel_worker_consumes_parent_ephemeral_image(monkeypatch, tmp_path):
288
_install_tool_stub(monkeypatch)
tools/vision_load.py
+2
@@ -116,6 +116,8 @@ class VisionLoad(Tool):
116
response, _ = await build_vision_model(self.agent).unified_call(
117
messages=[HumanMessage(content=content)],
118
)
119
+ if not str(response or "").strip():
120
+ raise RuntimeError("Vision Model returned an empty response.")
121
return str(response)
122
123
def _store_ephemeral_image(self, image: ephemeral_images.EphemeralImage) -> str:
tools/vision_load.py.dox.md
+1
@@ -27,6 +27,7 @@
27
- Direct parallel workers inherit the parent's model override generically. This tool uses their recorded parent context only to resolve ephemeral refs and durable chat media.
28
- `max_embeds` comes from the model that actually receives the images.
29
- Vision Model calls use the selected model's Advanced `kwargs`; this tool does not impose a separate timeout or output-token limit.
30
+- An empty Vision Model response is reported as an image-analysis error instead of a successful empty capsule.
31
- Update this file whenever tool arguments, output shape, `break_loop` behavior, intervention handling, prompt instructions, or side effects change.
32
- `VisionLoad` is a `Tool`.
33
- `VisionLoad` defines `execute(...)`.