This commit is contained in:
bhumikadangayach 2026-10-29 16:39:38 +07:00 • committed by GitHub
commit e90aa9454c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 37 additions and 0 deletions

View file

@ -2578,6 +2578,11 @@ class OpenTelemetry(OTELGenAISemconvMixin, CustomLogger):
value=optional_params.get("user"),
)
# Some responses (MCP CallToolResult, DecisionsResponse, list) have no
# .get(). They carry no LLM response fields, so treat them as None.
if not callable(getattr(response_obj, "get", None)):
response_obj = None # rebind-ok: no .get() means no LLM response fields
# The unique identifier for the LLM call.
# Completions have a provider response ID (e.g. "chatcmpl-xxx"),
# but Embeddings and Image-gen responses do not. Fall back to

View file

@ -4195,6 +4195,38 @@ class TestResponseIdFallback(unittest.TestCase):
mock_span.set_attribute.assert_any_call("litellm.call_id", call_id)
def test_litellm_call_id_set_when_response_obj_has_no_get(self):
"""Responses without .get() (MCP CallToolResult, DecisionsResponse, list)
must not abort set_attributes before litellm.call_id is set."""
from pydantic import BaseModel
class NoGetResponse(BaseModel):
id: str = "dec-1"
call_id = "my-litellm-call-uuid-789"
for response_obj in (NoGetResponse(), ["tool output"]):
with self.subTest(response_type=type(response_obj).__name__):
otel = OpenTelemetry()
mock_span = MagicMock()
kwargs = {
"model": "my-model",
"optional_params": {},
"litellm_params": {},
"standard_logging_object": {
"id": "litellm-call-id-1",
"litellm_call_id": call_id,
"call_type": "call_mcp_tool",
"metadata": {},
},
}
otel.set_attributes(mock_span, kwargs, response_obj)
mock_span.set_attribute.assert_any_call("litellm.call_id", call_id)
mock_span.set_attribute.assert_any_call(
"gen_ai.response.id", "litellm-call-id-1"
)
class TestOpenTelemetryResponsesAPI(unittest.TestCase):
"""