[Bug]: OTel v2: gen_ai.output.messages and gen_ai.response.finish_reasons missing on Responses API (/v1/responses) spans
Check for existing issues
- I have searched the existing issues and checked that my issue is not a duplicate.
What happened?
With LITELLM_OTEL_V2=true and OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT=span_only, the chat span for a /v1/responses request carries gen_ai.input.messages, usage and cost, but neither gen_ai.output.messages nor gen_ai.response.finish_reasons.
The same request through /v1/chat/completions has both.
User Flow
Root cause: litellm/integrations/otel/model/payloads.py, LLMCallSpanData.from_standard_logging_payload, reads only payload["response"]["choices"] (choices_out = _dicts(response.get("choices")), finish_reasons = _finish_reasons(choices_out)). For call_type in ("responses", "aresponses") the payload response is ResponsesAPIResponse.model_dump(): it has output (message / function_call / reasoning items), status and incomplete_details, but no choices, so GenAIMapper returns None for both attributes and they are dropped. The Weave and Langtrace mappers lose the output through the same choices_out field.
The legacy v1 integration handles this (integrations/opentelemetry.py, _transform_responses_api_output_to_otel, added for #25840 in c0da139), but the fix was never ported to v2 and is still missing on main.
Proposed fix: in from_standard_logging_payload, when choices is absent and output is a list, synthesize one choice: message items → assistant content from output_text parts; function_call items → tool_calls (call_id, name, arguments); finish_reason from status / incomplete_details (completed → stop / tool_calls, incomplete + max_output_tokens → length, content_filter → content_filter). Alternatively build on model/request_io.response_output, which already knows the ResponsesAPIResponse shape. Happy to send a PR.
Proof the bug occurs
proxy with litellm_settings.callbacks: [otel], OTEL_EXPORTER=console; POST /v1/responses {"model": "", "input": "Say hi"}; inspect the printed span.
What part of LiteLLM is this about?
Proxy
What LiteLLM version are you on ?
1.101.0
Twitter / LinkedIn details
No response
Source: BerriAI/litellm