[azure-ai-projects] ResponsesInstrumentor breaks openai with_raw_response streaming (AsyncStreamWrapper wraps an unparsed LegacyAPIResponse)
Maintainer thường phản hồi trong vòng 1 ngày
@M-Hietala đang làm issue này rồi.
Từ ngày 20/8/2026.
Đánh giá
Issue này chưa được đánh giá.
Mô tả
Describe the bug
With the Responses instrumentor active, client.responses.with_raw_response.create(..., stream=True) no longer returns a raw response. It returns AsyncStreamWrapper, which:
- does not expose
.parse()or.headers, both part of thewith_raw_responsecontract; and - cannot be iterated, because its
stream_async_iteris the still-unparsedLegacyAPIResponse, which has no__anext__.
So any caller that uses with_raw_response together with streaming breaks as soon as tracing is enabled, with:
AttributeError: 'LegacyAPIResponse' object has no attribute '__anext__'
with_raw_response is the only way to read response headers (e.g. x-ms-served-model) while streaming, so this affects callers that need per-response header data.
Root cause
The instrumentor patches openai.resources.responses.AsyncResponses.create. with_raw_response.create() delegates to that same method, but sets the SDK's raw-response flag, so create returns a LegacyAPIResponse rather than an AsyncStream.
_wrap_async_streaming_response treats whatever create returned as the event stream and stores it as stream_async_iter, and AsyncStreamWrapper.__anext__ calls self.stream_async_iter.__anext__(). For the raw-response path that object is a LegacyAPIResponse, which is not an async iterator — it must have .parse() called on it first.
Verified with a debug hook on _wrap_async_streaming_response:
[wrap] _wrap_async_streaming_response receives stream=openai._legacy_response.LegacyAPIResponse
To Reproduce
Standalone: openai + azure-ai-projects only, no Azure resources needed (the transport is mocked, so the object graph is wrong before any real network call matters).
import asyncio
import httpx
from opentelemetry import trace
from opentelemetry.sdk.trace import TracerProvider
from azure.core.settings import settings
from azure.core.tracing.ext.opentelemetry_span import OpenTelemetrySpan
from azure.ai.projects.telemetry._responses_instrumentor import ResponsesInstrumentor
from openai import AsyncOpenAI
trace.set_tracer_provider(TracerProvider())
settings.tracing_implementation = OpenTelemetrySpan
SSE = (
'data: {"type":"response.output_text.delta","delta":"Hello","item_id":"m1",'
'"output_index":0,"content_index":0,"sequence_number":1,"logprobs":[]}\n\n'
"data: [DONE]\n\n"
)
transport = httpx.MockTransport(
lambda r: httpx.Response(200, headers={"content-type": "text/event-stream"}, content=SSE.encode())
)
async def main() -> None:
ResponsesInstrumentor().instrument()
client = AsyncOpenAI(api_key="k", http_client=httpx.AsyncClient(transport=transport))
raw = await client.responses.with_raw_response.create(model="gpt-4o", input="hi", stream=True)
print(f"returned type : {type(raw).__module__}.{type(raw).__name__}")
print(f" .parse() : {hasattr(raw, 'parse')}")
print(f" .headers : {hasattr(raw, 'headers')}")
inner = getattr(raw, "stream_async_iter", None)
print(f" .stream_async_iter: {type(inner).__module__}.{type(inner).__name__}")
print(f" __anext__ : {hasattr(inner, '__anext__')}")
async for _ in raw:
pass
asyncio.run(main())
Note both an OpenTelemetry TracerProvider and azure-core-tracing-opentelemetry are required — without them _create_responses_span_from_parameters returns None, the instrumentor returns the result unwrapped, and the bug does not appear. That makes it easy to miss when reproducing.
Expected behavior
with_raw_response.create(..., stream=True) should keep behaving like a raw response when tracing is on: .parse() and .headers available, and the parsed stream iterable — ideally with the wrapper still in the iteration path so telemetry is still recorded.
Actual behavior
returned type : azure.ai.projects.telemetry._responses_instrumentor.AsyncStreamWrapper
.parse() : False <- raw-response API expects True
.headers : False <- raw-response API expects True
.stream_async_iter: openai._legacy_response.LegacyAPIResponse
__anext__ : False <- wrapper iterates this
iterating the returned object:
AttributeError: 'LegacyAPIResponse' object has no attribute '__anext__'
With the instrumentor uninstrumented, the same call correctly returns:
openai._legacy_response.LegacyAPIResponse .parse()=True .headers=True
Environment
azure-ai-projects==2.3.0openai==2.53.0azure-core-tracing-opentelemetry==1.0.0b13,opentelemetry-sdk==1.44.0- Python 3.13, macOS (not platform specific)
Notes
Reported downstream as microsoft/agent-framework#7461, where enabling AZURE_EXPERIMENTAL_ENABLE_GENAI_TRACING=true made all streaming agent requests fail. microsoft/agent-framework#7705 works around it by parsing the wrapper's inner raw response and handing it back, so the wrapper stays in the iteration path and telemetry is preserved. That workaround could be dropped once this is fixed upstream.
- Ngôn ngữ chính
- Python
- Star
- 5.6k
- Fork
- 3.4k
- Merge trung bình
- 2 ngày 7 giờ
- Pull request đã merge (30 ngày)
- 206
Chuẩn bị môi trường
Khởi chạy dev container của dự án ngay trên trình duyệt, bằng tài khoản GitHub của bạn.
- Không có Dockerfile hay tệp Docker Compose
- Có mẫu pull request
- Đọc hướng dẫn đóng góp
Bắt đầu từ đâu
- Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
- Bình luận trên issue rằng bạn sẽ nhận — tránh hai người làm cùng một việc.
- Fork repository và làm thay đổi trên một nhánh.
- Mở pull request có tham chiếu số hiệu của issue.
Issue khác của Azure/azure-sdk-for-python
-
EngSys
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 78/100
Azure/azure-sdk-for-python#49614 · 1 reaction ·
Maintainer thường phản hồi trong vòng 1 ngày
-
[Teams Chatbot]: Clarify Python dev-feed publication from a branch versus PyPI releaseCó thể đã có người làm @jianingwang123 đã nhận 5 ngày trước. Đang mởcustomer-reported question
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 62/100
Azure/azure-sdk-for-python#49548 · 1 bình luận · 2 reaction · 2 người được giao ·
Maintainer thường phản hồi trong vòng 1 ngày
-
Client customer-reported Hosted Agents needs-team-attention question Service Attention
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 78/100
Azure/azure-sdk-for-python#49477 · 4 bình luận · 1 reaction ·
Maintainer thường phản hồi trong vòng 1 ngày
-
azure-ai-evaluation: a content-harm score of 0 (no harm) is parsed as NaN in _parse_content_harm_response (numeric branch uses 0 < x instead of 0 <= x)Có thể đã có người làm @pujitha24 đã nhận 21 ngày trước. Đang mởEvaluation Service Attention
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 84/100
Azure/azure-sdk-for-python#49190 · 1 bình luận · 1 reaction ·
Maintainer thường phản hồi trong vòng 1 ngày
-
Update CODEOWNERSĐang mở
Độ khó 1/5 Dưới một giờ Mức phù hợp với người mới 90/100
Azure/azure-sdk-for-python#49183 · 1 reaction ·
Maintainer thường phản hồi trong vòng 1 ngày
Tất cả issue của Azure/azure-sdk-for-python
Issue tương tự
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 74/100
eclipse-score/inc_someip_gateway#356 ·
Maintainer thường phản hồi trong vòng 2 ngày
-
[BUG]: `GitHubRestAdapter.check_user_permission` and `has_write_access` raise `TypeError` (missing `params`), silently disabling the inactivity lifecycleCó thể đã có người làm @tarunagnihotri534 đã nhận hôm nay. Đang mởbug
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 67/100
AOSSIE-Org/Gitcord-GithubDiscordBot#167 · 1 bình luận ·
Maintainer thường phản hồi trong vòng 2 ngày
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 77/100
mihai-vlc/sublime-jsfmt#56 ·
-
comp/cli comp/plugins P2 type/bug
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 75/100
NousResearch/hermes-agent#141917 · 1 bình luận ·
Maintainer thường phản hồi trong vòng 1 ngày
-
Độ khó 1/5 Dưới một giờ Mức phù hợp với người mới 78/100
riscv/riscv-opcodes#441 ·