Instrument OpenAI Responses.retrieve and AsyncResponses.retrieve - #184
Conversation
These fetch a stored response by id without going through create(), so the existing create wrappers don't cover them. Wrap both sync and async, reusing the create wrappers since the result is the same Response shape. Add sync/async tests and cassettes. Refs open-telemetry#141 Assisted-by: Claude Opus 4.8 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Cover the 404 NotFoundError path for sync and async retrieve, matching the happy-path-plus-error coverage of the other Responses operations. Assisted-by: Claude Opus 4.8 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
Adds OpenAI Responses retrieve() coverage to the existing opentelemetry-instrumentation-genai-openai package so stored responses fetched by ID emit the same GenAI telemetry as create(), including content-capture behavior and error recording.
Changes:
- Wrap
openai.resources.responses.responses.Responses.retrieveandAsyncResponses.retrieveusing the existingresponses_create/async_responses_createwrappers. - Add sync + async unit tests for
retrieve()covering basic attributes, content capture, and 404 errors (with new VCR cassettes). - Add a towncrier changelog fragment documenting the new API coverage.
Reviewed changes
Copilot reviewed 10 out of 10 changed files in this pull request and generated no comments.
Show a summary per file
| File | Description |
|---|---|
| instrumentation/opentelemetry-instrumentation-genai-openai/src/opentelemetry/instrumentation/genai/openai/init.py | Instruments/uninstruments Responses.retrieve and AsyncResponses.retrieve using existing response wrappers. |
| instrumentation/opentelemetry-instrumentation-genai-openai/tests/test_responses.py | Adds sync retrieve() tests for basic attributes, content capture, and API error behavior. |
| instrumentation/opentelemetry-instrumentation-genai-openai/tests/test_async_responses.py | Adds async retrieve() tests for basic attributes, content capture, and API error behavior (explicit cassette usage). |
| instrumentation/opentelemetry-instrumentation-genai-openai/tests/cassettes/test_responses_retrieve_basic[content_mode0].yaml | VCR cassette for sync retrieve() happy path (no content capture). |
| instrumentation/opentelemetry-instrumentation-genai-openai/tests/cassettes/test_responses_retrieve_captures_content[content_mode0].yaml | VCR cassette for sync retrieve() happy path with output content capture. |
| instrumentation/opentelemetry-instrumentation-genai-openai/tests/cassettes/test_responses_retrieve_api_error[content_mode0].yaml | VCR cassette for sync retrieve() 404 / NotFoundError path. |
| instrumentation/opentelemetry-instrumentation-genai-openai/tests/cassettes/test_async_responses_retrieve_basic[content_mode0].yaml | VCR cassette for async retrieve() happy path (no content capture). |
| instrumentation/opentelemetry-instrumentation-genai-openai/tests/cassettes/test_async_responses_retrieve_captures_content[content_mode0].yaml | VCR cassette for async retrieve() happy path with output content capture. |
| instrumentation/opentelemetry-instrumentation-genai-openai/tests/cassettes/test_async_responses_retrieve_api_error[content_mode0].yaml | VCR cassette for async retrieve() 404 / NotFoundError path. |
| instrumentation/opentelemetry-instrumentation-genai-openai/.changelog/184.added | Changelog fragment for the new retrieve() instrumentation coverage. |
Pull request dashboard statusMerged · refreshed 2026-08-07 02:31 UTC Status above doesn't look right?
|
|
This PR has been automatically marked as stale because it has not had any activity for 14 days. It will be closed if no further activity occurs within 14 days of this comment. |
Resolve conflict in the OpenAI instrumentor: keep the Responses.stream / AsyncResponses.stream unwraps from main alongside the retrieve unwraps, and update the retrieve error tests for the fully-qualified openai.* error.type values now emitted by util-genai. Assisted-by: Claude Opus 5 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The six retrieve cassettes reuse the CF-RAY, x-request-id and Date headers of the existing responses create cassettes, so they were synthesized rather than recorded against the provider. AGENTS.md requires such cassettes to carry the re-record marker. Assisted-by: Claude Opus 5 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
|
Hi @JacksonWeber — just a friendly reminder that this pull request is waiting on you. There are still items that need your attention. See the dashboard status comment for the full list. You don't need to push a code change to hand it back — replying to move each discussion forward is enough, whether that's answering a question, explaining why no change is needed, or asking a follow-up. The dashboard then automatically routes it back to reviewers. If you believe this pull request is incorrectly routed as waiting on the author, comment |
Adds a FetchResponseInvocation to opentelemetry-util-genai and wires the OpenAI Responses retrieve instrumentation to it, so fetching a stored response is no longer reported as an inference operation and does not record token usage. Assisted-by: Claude Opus 5 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
A fetched response carries the tool definitions the original generation was made with, and semconv lists gen_ai.tool.definitions as opt-in content on the fetch_response span, but set_fetch_response_attributes never recorded them. Responses API tools are flat, so the Chat Completions helper _prepare_tool_definitions() does not apply: it reads tool.function.name and would return nothing here. Add a Responses-specific extractor that maps function tools onto FunctionToolDefinition and built-in tools, which carry no name, onto GenericToolDefinition keyed by their type. Assisted-by: Claude Opus 5 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Assisted-by: GPT-5.6 Sol Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Assisted-by: GPT-5.6 Sol Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Assisted-by: GPT-5.6 Sol Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Assisted-by: GPT-5.6 Sol Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Assisted-by: GPT-5.6 Sol Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Assisted-by: GPT-5.6 Sol Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Assisted-by: GPT-5.6 Sol Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Assisted-by: GPT-5.6 Sol Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Assisted-by: GitHub Copilot CLI Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Adds instrumentation for the OpenAI Responses
retrieveAPI (sync and async), addressing the OpenAI item in #141.Responses.retrieve/AsyncResponses.retrievefetch a stored response by id without going throughcreate(), so the existing create wrappers don't cover them. Both are now wrapped (reusing the create wrappers, since the result is the sameResponseshape) and unwrapped on uninstrument.Note:
retrieveonly takes aresponse_id, so the span has nogen_ai.request.model— all attributes come from the fetched response.Tests: sync/async basic + content-capture cases with cassettes.
The retrieve cassettes were synthesized without provider access, so per CONTRIBUTING.md they carry a
# TODO: this is generated by AI, re-recordmarker. Re-recording is tracked in #341.Refs #141