fix(otel): skip only token-array entries so chat Message objects keep their output messages

This commit is contained in:
Michael Cusack 2026-10-21 03:29:43 -07:00
parent 611e2ab136
commit 00a38aa565
2 changed files with 16 additions and 2 deletions

View file

@ -2823,7 +2823,7 @@ class OpenTelemetry(OTELGenAISemconvMixin, CustomLogger):
primitive_value: Final = self._cast_as_primitive_value_type(value)
span.set_attribute(key, primitive_value)
def _transform_messages_to_otel_semantic_conventions(self, messages: list[dict] | str) -> list[dict]:
def _transform_messages_to_otel_semantic_conventions(self, messages: list[Any] | str) -> list[dict]:
"""
Transforms LiteLLM/OpenAI style messages into OTEL GenAI 1.38 compliant format.
OTEL expects a 'parts' array instead of a single 'content' string.
@ -2841,7 +2841,8 @@ class OpenTelemetry(OTELGenAISemconvMixin, CustomLogger):
for msg in messages:
# An embedding's input is logged as its messages, so a token-array input
# (`[[9906, 1917]]` or `[9906, 1917]`) yields lists or ints with no role or content.
if not isinstance(msg, dict):
# Anything else is message-like: a dict, or a `Message` object from chat output.
if isinstance(msg, (list, int)):
continue
role = msg.get("role", "user")
content = msg.get("content", "")

View file

@ -3344,6 +3344,19 @@ class TestOpenTelemetrySemanticConventions138(unittest.TestCase):
self.assertEqual(json.loads(attrs["gen_ai.input.messages"]), [])
self.assertEqual(attrs["gen_ai.operation.name"], "aembedding")
def test_choice_message_objects_are_still_transformed(self):
"""
Chat output reaches the message conversion as `Message` objects, not dicts, so
skipping token-array entries must not skip them.
"""
from litellm.types.utils import Choices, Message
choices = [Choices(finish_reason="stop", index=0, message=Message(role="assistant", content="Hi"))]
self.assertEqual(
OpenTelemetry()._transform_choices_to_otel_semantic_conventions(choices),
[{"role": "assistant", "parts": [{"type": "text", "content": "Hi"}], "finish_reason": "stop"}],
)
def test_output_messages_uses_parts_structure(self):
"""
Test that gen_ai.output.messages uses the OTEL 1.38 parts array structure.