fix(core): fix streamed response span losing response/input when consumer stops at completed event - #4692
Open
XuQuanxin04 wants to merge 1 commit into
Open
Conversation
When streaming Responses, the model I/O was attached to the response span only after the yield loop finished. A consumer that stops at the terminal response.completed event closes the generator at the yield, so that post-loop assignment never runs and the span is exported with response and input left as None, even when sensitive-data capture is enabled. The SDK own run loop consumes the stream this way (aclosing + break on ResponseCompletedEvent), so the common streamed path lost the model I/O. This is also asymmetric with the non-streamed get_response path, the sibling Chat Completions adapter, and the failure path in this method, all of which attach data before yielding. Attach response/input before yielding the completed event when data capture is enabled, mirroring the existing usage handling. Co-Authored-By: Claude <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
When streaming with
OpenAIResponsesModel, the model response and input were attached to theresponse_spanonly after the yield loop finished (lines 769-771). A consumer that stops iterating at the terminalresponse.completedevent closes the generator at theyield, so that post-loop assignment never runs. The span is then exported withresponseandinputset toNone, even when sensitive-data capture is enabled (ModelTracing.ENABLED).The SDK's own run loop consumes the stream exactly this way —
run_single_turn_streamedwraps the model stream inaclosing(...)and breaks once it seesResponseCompletedEvent— so the common streamed path silently lost the model I/O on the span.This is asymmetric with three places that already populate the span before yielding for exactly this reason:
get_responsepath setsresponse/inputinside the span (lines 612-614);The
usagefield was already handled correctly before the yield; onlyresponse/inputwere deferred.Fix
Attach
responseandinputto the span inside theResponseCompletedEventbranch, gated ontracing.include_data(), before the terminal event is yielded — mirroring the existingusageassignment right above it. Redaction when data capture is disabled is unchanged.Test plan
Added
test_stream_span_records_io_when_consumer_stops_at_completed, which mirrors the existing chatcompletions testtest_stream_span_is_recorded_for_a_consumer_that_stops_at_the_terminal_event. It monkeypatches_fetch_responseto emit a singleresponse.completed, stops iterating at that event (as the run loop does), closes the generator, and asserts theresponsespan carries non-Noneresponse,input, andusage.response/inputareNone(reproduced).ModelTracing.ENABLED_WITHOUT_DATA,response/inputremainNone(redaction preserved).pytest tests/models/test_openai_responses.py— 156 passedpytest tests/models/test_openai_chatcompletions_stream.py tests/test_provider_span_errors.py tests/tracing/ tests/test_agent_runner_streamed.py— 389 passed, 7 skippedruff format --checkandruff checkclean on changed files.No issue number; this is a self-contained observability correctness fix found while reading the span code.
Checks
.agents/skills/code-change-verification/scripts/run.sh— could not run the bash script end-to-end on this Windows/Git-Bash host (it manages POSIX process groups viasetsid/kill -TERM -PID); I ran its constituent steps directly (ruff format, ruff check, and the full relevant pytest suites above).