OpenAI v2: completion hook support and minor fixes#4315
Conversation
7271e7e to
fe0c61d
Compare
MikeGoldsmith
left a comment
There was a problem hiding this comment.
Sorry for delay getting this reviewed. It got lost and wasn't added to the PR review board.
|
I'm going to put it on hold and rebase on top of #4315 given the amount of conflicts it's going to introduce. |
Nik-Reddy
left a comment
There was a problem hiding this comment.
Reviewed thoroughly - this is a clean and well-structured refactor. A few observations:
What I like:
- Moving
should_capture_content()intoTelemetryHandleris the right call. Individual instrumentations (like the Cohere one I'm adding in #4418) shouldn't need to manage content capture logic themselves - this centralizes it properly. - The
_maybe_build_llm_event_recordrename (from_maybe_emit_llm_event) is a good separation of concerns - building the record vs emitting it lets the completion hook inspect it first. - Handling
openai.Omitinvalue_is_set()is a nice forward-compatibility fix for newer OpenAI SDK versions. _openai_response_format_to_output_typecorrectly mapsjson_object/json_schematojson.
One question:
In the TelemetryHandler.__init__ content capture logic (lines ~164-177), the fallback for non-experimental mode checks OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT == "true" only. Should this also handle the newer span_only/event_only/span_and_event values for consistency, or is that intentionally left as experimental-only?
Note: This PR supersedes my #4417 (content capture fix) - I'll close that one and reference this instead. Happy to help test once merged.
LGTM overall.
0ddc569 to
6d21ce7
Compare
@Nik-Reddy it makes sense, update the PR to support new valued on legacy path |
There was a problem hiding this comment.
Pull request overview
Adds completion hook support to the GenAI telemetry utilities and wires it into the OpenAI v2 instrumentation so consumers can capture inputs/outputs (and optionally stamp log records) after an invocation completes.
Changes:
- Add
completion_hookplumbing toTelemetryHandlerand pass it through all invocation types; call the hook on inference/workflow completion. - Introduce
TelemetryHandler.should_capture_content()to centralize content-capture decisions for instrumentations. - Update OpenAI v2 instrumentation/tests for the hook, latest OpenAI SDK (
openai==2.26.0),Omithandling, andresponse_formatmapping.
Reviewed changes
Copilot reviewed 16 out of 16 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| util/opentelemetry-util-genai/tests/test_handler_completion_hook.py | New unit tests for hook invocation, log_record passing, and should_capture_content() behavior. |
| util/opentelemetry-util-genai/src/opentelemetry/util/genai/handler.py | Adds completion_hook param, computes capture policy, and exposes should_capture_content(). |
| util/opentelemetry-util-genai/src/opentelemetry/util/genai/_inference_invocation.py | Calls completion hook and passes created log record before emission. |
| util/opentelemetry-util-genai/src/opentelemetry/util/genai/_workflow_invocation.py | Calls completion hook when workflows finish. |
| util/opentelemetry-util-genai/src/opentelemetry/util/genai/_invocation.py | Threads completion_hook through base invocation class. |
| util/opentelemetry-util-genai/src/opentelemetry/util/genai/_tool_invocation.py | Plumbs completion_hook through tool invocation construction. |
| util/opentelemetry-util-genai/src/opentelemetry/util/genai/_embedding_invocation.py | Plumbs completion_hook through embedding invocation construction. |
| util/opentelemetry-util-genai/CHANGELOG.md | Documents completion hook support in util package. |
| instrumentation-genai/opentelemetry-instrumentation-openai-v2/tests/test_completion_hook.py | New integration tests verifying hook invocation and content routing. |
| instrumentation-genai/opentelemetry-instrumentation-openai-v2/tests/requirements.latest.txt | Bumps OpenAI SDK used in “latest” tests to 2.26.0. |
| instrumentation-genai/opentelemetry-instrumentation-openai-v2/tests/conftest.py | Minor formatting-only fixture signature change. |
| instrumentation-genai/opentelemetry-instrumentation-openai-v2/src/opentelemetry/instrumentation/openai_v2/utils.py | Handles openai.Omit and normalizes response_format output types. |
| instrumentation-genai/opentelemetry-instrumentation-openai-v2/src/opentelemetry/instrumentation/openai_v2/patch.py | Uses handler.should_capture_content() in v2 wrappers. |
| instrumentation-genai/opentelemetry-instrumentation-openai-v2/src/opentelemetry/instrumentation/openai_v2/init.py | Loads hook (explicit kwarg preferred, else entry point) and passes into TelemetryHandler. |
| instrumentation-genai/opentelemetry-instrumentation-openai-v2/CHANGELOG.md | Documents hook support and OpenAI v2 fixes. |
| instrumentation-genai/AGENTS.md | Adds guidance on initializing TelemetryHandler with completion hooks. |
MikeGoldsmith
left a comment
There was a problem hiding this comment.
Looks good - I think we need to address a couple of the copilot points:
_call_completion_hook()is called inside_apply_finish(), we should add a try/except- use
GenAiOutputTypeValues.JSON.valueinstead of"json"in utils.py
852a965 to
616f0d0
Compare
|
@MikeGoldsmith thanks! I think completion hook should take care of exceptions - if it comes straight from user, we should be wrapping it into exception handling and then using here. We're going to call it a lot, it's easier to wrap once inside than make every caller handle errors. I can look into this in a separate PR. UPDATE: Follow up: #4506 |
lzchen
left a comment
There was a problem hiding this comment.
Overall LGTM but just some questions :)
From spec: https://github.com/open-telemetry/semantic-conventions/blob/v1.40.0/docs/gen-ai/gen-ai-spans.md#uploading-content-to-external-storage