test(e2e): otel trace completeness on /v1/responses - #33134
Conversation
Greptile SummaryThis test-only PR completes the LIT-3787 stack by adding an e2e OTEL trace-completeness scenario for
Confidence Score: 5/5Test-only changes confined entirely to tests/e2e; no production code is touched. All four changed files live under tests/e2e and have no effect on production behavior. The new test mirrors the established pattern of the other two trace-completeness tests exactly, uses proper key isolation with unique markers and deferred cleanup, and the author has provided passing test output and a fail-before-fix baseline. No logic paths, schemas, or existing assertions are weakened. No files require special attention.
|
| Filename | Overview |
|---|---|
| tests/e2e/logging/test_otel_trace_e2e.py | Adds test_responses_exports_complete_trace following the exact same two-sided contract (recorded state + enforced behavior) as the existing chat_completions and messages tests; also adds explicit exercised_on annotation to the chat_completions test for coverage-registry consistency. |
| tests/e2e/logging/logging_client.py | Adds ResponsesRequestBody (model/input/max_output_tokens) and responses_raw(), both consistent in style and typing with the existing messages_raw() method. |
| tests/e2e/e2e_config.py | Adds CHEAP_OPENAI_MODEL constant (env-overridable, defaults to gpt-5.5) following the same pattern as CHEAP_ANTHROPIC_MODEL. |
| tests/e2e/coverage_registry/logging.yaml | Adds responses to exercised_on for logging.otel.success.exports_metric; no structural changes to the registry schema. |
Reviews (3): Last reviewed commit: "test(e2e): declare the responses and cha..." | Re-trigger Greptile
328c04c to
a309013
Compare
e9ac83c to
01a47dd
Compare
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
a309013 to
f354f98
Compare
01a47dd to
4c1cbd3
Compare
f354f98 to
e74ff98
Compare
4c1cbd3 to
bf11211
Compare
e74ff98 to
4ceaa98
Compare
bf11211 to
0658e85
Compare
4ceaa98 to
c493eb5
Compare
0658e85 to
9aaa28f
Compare
c493eb5 to
c84907f
Compare
Extends the LIT-3787 trace-completeness suite to the OpenAI Responses API route: one successful non-streaming /v1/responses call must land at the destination as ONE connected trace. Adds the raw /v1/responses sender, a CHEAP_OPENAI_MODEL config constant, and registers responses in the otel registry cell's exercised_on.
0f45000 to
aaed3ac
Compare
97f102a
into
litellm_e2e_otel_messages_trace
* test(e2e): OTEL trace completeness on /v1/messages Extends the LIT-3787 trace-completeness suite to the Anthropic-native route: one successful non-streaming /v1/messages call must land at the destination as ONE connected trace (root SERVER span + auth/db/cost children + gen-AI CLIENT span, no dangling parents). Adds the raw /v1/messages sender to the logging suite client. * test(e2e): reuse the shared AnthropicMessagesBody per review Drops the duplicate /v1/messages request model in favor of the one models.py already provides (budget_client uses the same one), passes max_tokens at the call site to match the sibling chat test, notes in the docstring why the gen-AI span is named chat on this surface, and adopts the hardened read-back signature * test(e2e): author the messages trace test docstring * test(e2e): declare the messages surface on the covers marker * test(e2e): otel trace completeness on /v1/responses (#33134) * test(e2e): OTEL trace completeness on /v1/responses Extends the LIT-3787 trace-completeness suite to the OpenAI Responses API route: one successful non-streaming /v1/responses call must land at the destination as ONE connected trace. Adds the raw /v1/responses sender, a CHEAP_OPENAI_MODEL config constant, and registers responses in the otel registry cell's exercised_on. * test(e2e): author the responses trace test docstring * test(e2e): declare the responses and chat surfaces on the covers markers
Relevant issues
Resolves LIT-3787
Linear ticket
https://linear.app/litellm-ai/issue/LIT-3787
Pre-Submission checklist
Please complete all items before asking a LiteLLM maintainer to review your PR
Screenshots / Proof of Fix
Top of the 3-PR LIT-3787 stack (chat_completions -> messages -> responses); merge the two below first. Verification was run on 2026-07-13 at this branch's tip f354f98 (all three tests); see the bottom PR for the full setup. Proxies ran from source at exact refs since this machine has no docker buildx. Outputs verbatim.
Pass on current code, the whole suite:
The /v1/responses trace at the destination:
Fail-before-fix at 1bd603d (parent of fix(otel): one v2 logger owns the global provider; scope tenant OTLP creds per exporter #30590): all three fail, each with its own orphaned gen-AI span; note the responses route orphans
chat gpt-5.5:Static gates:
make lint-e2e-basedpyright-> 0 errors;coverage_registry.collector --strictpasses with the registry edit (responsesadded to the otel cell'sexercised_on).Before:
After:

Type
✅ Test
Changes
Third scenario of LIT-3787:
/v1/responsesis the newest of the three handlers with its own translation layer, which is exactly where span-anchor plumbing regressions land first, and it is the route agent frameworks increasingly default to; an orphaned gen-AI span there means agent steps with no originating request, auth identity, or cost linkage.logging/test_otel_trace_e2e.py: addstest_responses_exports_complete_trace(same two-sided contract as the chat/messages tests). The gen-AI span keeps the semconv operation namechaton this surface, so the expected span ischat gpt-5.5; the product maps the responses call type to the chat operation by design.logging/logging_client.py: addsresponses_raw, a typed non-streaming/v1/responsessender withmax_output_tokens(default 64) so a reasoning model cannot burn unbounded output tokens per run; a capped response is still a 200 and still exports the trace.e2e_config.py:CHEAP_OPENAI_MODEL(envE2E_CHEAP_OPENAI_MODEL, default gpt-5.5). gpt-5.5 is kept deliberately for stack-wide consistency: it is the model the compose config prewires and the rest of the e2e suite uses; the constant is env-overridable when the stack migrates.coverage_registry/logging.yaml:responsesadded tologging.otel.success.exports_metric'sexercised_on(the schema already lists it as a valid endpoint). The row'sembeddingssurface remains a tracked follow-up under LIT-3787.Known deferral:
/v1/responsesraw senders now exist in two suite clients (endpoints_client.pyand here); promoting a single sender toe2e_gateway.Gatewayis a follow-up, kept out of this PR to keep its scope one scenario.Behavior changes
None; test-only changes under tests/e2e.
QA runbook
OpenTelemetryV2appears insuccess_callbacks{"models":["gpt-5.5"],"key_alias":"otel-trace-responses-<uniq>"}and save the returned keymodel,inputwith a unique phrase,max_output_tokens: 64) with the key; retry the first call on 401 for a few seconds; confirm 200 and notex-litellm-call-idlitellm), search by taglitellm.call_id=<that id>and wait for the trace (spans flush in batches)POST /v1/responses(kind server) and no span referencing a parent missing from the traceauth /v1/responses, apostgres ...span, andbatch_write_to_db _PROXY_track_cost_callbackchat gpt-5.5(kind client) is in the SAME trace and its parent chain reaches the rootFinal attestation: "I agree this test is testing what the writer wanted to test."