Skip to content

fix: reject failed and incomplete Responses statuses in non-streaming path#3387

Open
ioleksiuk wants to merge 1 commit into
openai:mainfrom
ioleksiuk:fix/reject-failed-non-streaming-response-status
Open

fix: reject failed and incomplete Responses statuses in non-streaming path#3387
ioleksiuk wants to merge 1 commit into
openai:mainfrom
ioleksiuk:fix/reject-failed-non-streaming-response-status

Conversation

@ioleksiuk
Copy link
Copy Markdown
Contributor

Summary

Mirror the streaming-side fix in #3107 (`fix: reject failed responses stream terminals`) for the non-streaming `get_response` paths.

Streaming responses are guarded today: when the streaming code sees a `response.failed` or `response.incomplete` terminal event, it raises `response_terminal_failure_error` (defined in `src/agents/models/_response_terminal.py`). The non-streaming HTTP paths in `OpenAIResponsesModel.get_response` (`src/agents/models/openai_responses.py:462-525`) and `AnyLLMModel._get_response_via_responses` (`src/agents/extensions/models/any_llm_model.py:335-397`) previously did not inspect `response.status` at all and would silently return a `ModelResponse` built from the partial/empty `response.output`.

That violates parity with the streaming guard: identical underlying failures (provider backend error, content-filter `incomplete`, `max_output_tokens` hit) crash one path and silently succeed on the other. Users who pick streaming vs non-streaming dynamically would observe inconsistent agent-run results.

Check `response.status in {"failed", "incomplete"}` right after the non-streaming fetch returns and raise the same `response_terminal_failure_error` helper used by the streaming path.

Test plan

  • New parametrized test `test_get_response_rejects_failed_or_incomplete_response_status` in `tests/models/test_openai_responses.py` — covers `status="failed"` and `status="incomplete"` for the OpenAI Responses model.
  • New parametrized test `test_any_llm_responses_path_rejects_failed_or_incomplete_status` in `tests/models/test_any_llm_model.py` — same coverage for the `any_llm` Responses path.
  • `uv run pytest tests/models/test_openai_responses.py tests/models/test_any_llm_model.py` — 131 passed, 4 skipped (skipped tests are environment-dependent, unrelated to this change).
  • `uv run ruff check` on the touched files — All checks passed.

Issue number

N/A — found while auditing for the same fix-pattern that #3107 applied to streaming.

Checks

  • I've added new tests (if relevant)
  • I've added/updated the relevant documentation (no doc changes needed)
  • I've run `make lint` and `make format`
  • I've made sure tests pass

… path

Mirror the streaming-side fix in openai#3107 (reject failed responses stream
terminals) for the non-streaming `get_response` paths.

Streaming responses are already guarded: when the streaming code sees a
`response.failed` or `response.incomplete` terminal event, it raises
`response_terminal_failure_error` via
`src/agents/models/_response_terminal.py`. The non-streaming HTTP paths
in `OpenAIResponsesModel.get_response` and
`AnyLLMModel._get_response_via_responses` previously did not inspect
`response.status` at all and would silently return a `ModelResponse`
built from the partial/empty `response.output`. This violates parity
with the streaming guard: identical underlying failures (provider
backend error, content-filter incomplete, `max_output_tokens` hit) now
crash one path and silently succeed on the other.

Check `response.status in {"failed", "incomplete"}` right after the
non-streaming fetch returns and raise the same
`response_terminal_failure_error` used by the streaming path.

Tests cover both terminal statuses for both the OpenAI Responses model
and the any_llm responses path.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants