[openai] No side effects when streaming; stay resilient to edge cases with parse(custom_type)#278
Open
lmolkova wants to merge 7 commits into
Open
Conversation
Merges the two +-prefixed openai changelog fragments into a single 278.fixed fragment so the changelog CI check passes (it requires a fragment named <PR_NUMBER>.<type> and rejects the + orphan names). Assisted-by: Claude Opus 4.8
lmolkova
force-pushed
the
no-side-effects-when-streaming
branch
from
July 16, 2026 06:44
f7b478a to
17f8d86
Compare
Contributor
There was a problem hiding this comment.
Pull request overview
This PR improves the OpenAI GenAI instrumentation’s handling of with_raw_response.create(stream=True) by avoiding eager parse() side effects, keeping raw-response metadata accessible (e.g., headers, request_id), and ensuring spans are finalized even when callers drain the underlying http_response without parsing.
Changes:
- Introduces a transparent raw-response streaming proxy that defers
parse()and finalizes spans viahttp_response.close/aclosefallback when needed. - Updates chat and Responses API wrappers/patching to avoid stream-type side effects and to tolerate caller-defined
parse(to=...)types without breaking iteration. - Adds unit + VCR-backed tests for sync/async raw-response streaming, custom parse targets, and “read without parse” span finalization.
Reviewed changes
Copilot reviewed 14 out of 14 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| instrumentation/opentelemetry-instrumentation-genai-openai/tests/test_responses.py | Adds coverage for Responses API with_raw_response streaming (metadata access, unknown event type, span closure). |
| instrumentation/opentelemetry-instrumentation-genai-openai/tests/test_raw_response_proxy.py | Adds focused unit tests for RawResponseStreamProxy behavior (memoization, non-stream passthrough, close fallback). |
| instrumentation/opentelemetry-instrumentation-genai-openai/tests/test_chat_completions.py | Adds tests for chat raw-response parse(to=...) custom types and streaming custom/unknown chunk types + read-without-parse. |
| instrumentation/opentelemetry-instrumentation-genai-openai/tests/test_async_responses.py | Async equivalents for Responses API with_raw_response streaming tests (including unknown event type). |
| instrumentation/opentelemetry-instrumentation-genai-openai/tests/test_async_chat_completions.py | Async equivalents for chat raw-response custom parse + unknown chunk + read-without-parse. |
| instrumentation/opentelemetry-instrumentation-genai-openai/src/opentelemetry/instrumentation/genai/openai/response_wrappers.py | Makes Responses stream telemetry resilient to unknown event shapes; integrates shared wrap_result path. |
| instrumentation/opentelemetry-instrumentation-genai-openai/src/opentelemetry/instrumentation/genai/openai/response_extractors.py | Adjusts extraction to handle raw responses by parsing on non-streaming paths. |
| instrumentation/opentelemetry-instrumentation-genai-openai/src/opentelemetry/instrumentation/genai/openai/patch.py | Stops eagerly parsing streaming raw responses; routes streaming through wrap_result. |
| instrumentation/opentelemetry-instrumentation-genai-openai/src/opentelemetry/instrumentation/genai/openai/patch_responses.py | Aligns Responses patching with lazy/raw-response-safe streaming behavior and avoids double-invocation under Responses.stream(). |
| instrumentation/opentelemetry-instrumentation-genai-openai/src/opentelemetry/instrumentation/genai/openai/chat_wrappers.py | Makes chat stream telemetry resilient to unknown chunk shapes; integrates shared wrap_result path. |
| instrumentation/opentelemetry-instrumentation-genai-openai/src/opentelemetry/instrumentation/genai/openai/_raw_response.py | Adds RawResponseStreamProxy and StreamResultFactory to proxy raw streaming results and finalize spans on close. |
| instrumentation/opentelemetry-instrumentation-genai-openai/.changelog/+openai-raw-response-streaming-close.fixed | Changelog fragment for span finalization when draining via underlying http_response without parse(). |
| instrumentation/opentelemetry-instrumentation-genai-openai/.changelog/+openai-raw-response-streaming-attrs.fixed | Changelog fragment for preserving raw-response metadata and custom parse(to=...) resilience. |
| AGENTS.md | Documents new guidance about preserving SDK return contract / avoiding side effects. |
| .github/instructions/instrumentation.instructions.md | Adds reviewer guidance to flag SDK-side-effect and return-contract changes. |
Pull request dashboard status
|
When a raw-response stream is parsed into a caller-defined type, the unknown-shape debug log fired once per chunk/event, spamming logs on long streams. Guard it with an explicitly-initialized per-stream flag so it logs at most once per stream instance (chat chunks and response events). Addresses Copilot review feedback on PR open-telemetry#278. Assisted-by: Claude Opus 4.8
A wrapt.ObjectProxy preserves isinstance and __class__ (only type() identity differs), so it satisfies the 'don't change the returned type' rule and reconciles it with the 'keep the wrapper transparent' bullet. Keeps the parallel reviewer instructions in sync. Assisted-by: Claude Opus 4.8
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.
Replaces #147
Today we call
parseon legacy streams introducing side-effects (changing stream type for end users). This leads to issues like #46 (not having methods / properties that stream has without instrumentation being applied).This PR uses different approach: