Skip to content

Conversation

@OiPunk
Copy link
Contributor

@OiPunk OiPunk commented Feb 10, 2026

Summary

RunResultStreaming.stream_events() currently breaks as soon as _stored_exception is set, even if there are still queued run-item events waiting in _event_queue.

For max-turn failures this can drop the last tool_call_output_item from the stream, even though the item has already been produced and queued.

This PR changes the loop so we only break on _stored_exception when the event queue is empty.

Why

Issue: #526

This preserves event ordering and guarantees consumers receive all already-queued semantic events before the final exception is raised.

Changes

  • In RunResultStreaming.stream_events(), changed:
    • from: break immediately when _stored_exception is set
    • to: break only when _stored_exception is set and _event_queue is empty
  • Added regression test:
    • test_streaming_max_turns_emits_pending_tool_output_events
    • Verifies tool_call_item and tool_call_output_item are emitted before MaxTurnsExceeded

Validation

  • uv run ruff check src/agents/result.py tests/test_agent_runner_streamed.py
  • uv run mypy src/agents/result.py tests/test_agent_runner_streamed.py
  • env -u all_proxy -u ALL_PROXY -u http_proxy -u HTTP_PROXY -u https_proxy -u HTTPS_PROXY uv run pytest tests/test_agent_runner_streamed.py -k "max_turns" -q
  • env -u all_proxy -u ALL_PROXY -u http_proxy -u HTTP_PROXY -u https_proxy -u HTTPS_PROXY uv run pytest tests/test_agent_runner_streamed.py -q
  • make format-check
  • env -u all_proxy -u ALL_PROXY -u http_proxy -u HTTP_PROXY -u https_proxy -u HTTPS_PROXY uv run python -m trace --count --coverdir /tmp/openai_agents_526_trace --module pytest tests/test_agent_runner_streamed.py -k "max_turns" -q

Trace output confirms the modified branch in src/agents/result.py is executed.

Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 1744c15fd8

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

while True:
self._check_errors()
if self._stored_exception:
if self._stored_exception and self._event_queue.empty():

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Preserve immediate abort for guardrail-triggered exceptions

stream_events() now continues draining _event_queue whenever _stored_exception is set but the queue is non-empty, which changes behavior for all exception types, not just max-turns. _check_errors() sets _stored_exception for input/output guardrail failures and task exceptions, and parallel input guardrails run concurrently with model streaming, so a tripwire can be detected while response events are already queued; with this condition, those queued events are still yielded before raising, potentially leaking assistant output after a guardrail has fired. Please scope the queue-draining behavior to MaxTurnsExceeded (or another explicit allowlist) so guardrail-triggered runs still abort immediately.

Useful? React with 👍 / 👎.

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.

1 participant