From d278aa8057a0be158e1747f0360a42ccdf0e0fa2 Mon Sep 17 00:00:00 2001 From: Sun <2114377220@qq.com> Date: Tue, 22 Sep 2026 22:56:30 +0800 Subject: [PATCH] [Bugfix] Mark image edit benchmark stream errors as failed (#8015) Signed-off-by: levius <2114377220@qq.com> --- tests/benchmarks/patch/test_patch.py | 36 ++++++++++++++++++++++++++++ vllm_omni/benchmarks/patch/patch.py | 10 +++++++- 2 files changed, 45 insertions(+), 1 deletion(-) diff --git a/tests/benchmarks/patch/test_patch.py b/tests/benchmarks/patch/test_patch.py index 5f84bcbb7..309b4bc74 100644 --- a/tests/benchmarks/patch/test_patch.py +++ b/tests/benchmarks/patch/test_patch.py @@ -1476,6 +1476,42 @@ async def test_image_edits_stream_true_uses_sse_path(mocker: MockerFixture) -> N assert output.image_count == 1 +@pytest.mark.asyncio +async def test_image_edits_stream_error_marks_request_failed(mocker: MockerFixture) -> None: + """HTTP 200 image-edit streams can terminate with an error event.""" + sse_chunk = ( + b'data: {"object":"image.edit.chunk","type":"ar_delta","delta":"partial"}\n\n' + b'data: {"object":"error","error":{"message":"image generation failed",' + b'"type":"server_error","code":500}}\n\n' + b"data: [DONE]\n\n" + ) + mock_response = MockResponse(200, [sse_chunk]) + mock_session = mocker.AsyncMock() + mock_session.post = mocker.MagicMock(return_value=mock_response) + + request = RequestFuncInput( + model="multi-stage-edit", + model_name="multi-stage-edit", + prompt="edit", + api_url="http://test.com/v1/images/edits", + prompt_len=2, + output_len=1, + multi_modal_content=[ + { + "type": "image_url", + "image_url": {"url": f"data:image/png;base64,{_MIN_PNG_B64}"}, + } + ], + extra_body={"stream": True}, + ) + + output = await async_request_openai_image_edits_omni(request, mock_session, pbar=None) + + assert output.success is False + assert output.error == "image generation failed" + assert output.generated_text == "partial" + + @pytest.mark.asyncio async def test_image_generations_e2el_includes_json_body_consume(mocker: MockerFixture) -> None: """E2EL must include body transfer/decode, not stop at HTTP headers.""" diff --git a/vllm_omni/benchmarks/patch/patch.py b/vllm_omni/benchmarks/patch/patch.py index 90e2dd0ef..40ad584bd 100644 --- a/vllm_omni/benchmarks/patch/patch.py +++ b/vllm_omni/benchmarks/patch/patch.py @@ -2409,6 +2409,7 @@ async def async_request_openai_image_edits_omni( timestamp = st most_recent_text_timestamp = st generated_text = "" + streaming_error_received = False handler = StreamedResponseHandler() async for chunk_bytes in response.content.iter_any(): if not chunk_bytes: @@ -2424,6 +2425,13 @@ async def async_request_openai_image_edits_omni( timestamp = time.perf_counter() data = json.loads(chunk) + if (streaming_error := data.get("error")) is not None: + streaming_error_received = True + if isinstance(streaming_error, dict): + output.error = str(streaming_error.get("message") or streaming_error) + else: + output.error = str(streaming_error) + continue _update_output_stage_metrics_from_payload( output, data, @@ -2464,7 +2472,7 @@ async def async_request_openai_image_edits_omni( output.denoise_step_latency_ms = metrics_denoise_step_ms output.latency = timestamp - st output.generated_text = generated_text - output.success = True + output.success = not streaming_error_received else: data = await response.json() _finalize_image_json_http_response(