refactor(otel v2): build Langfuse trace attributes from pairs to satisfy the type discipline gate

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
This commit is contained in:
yucheng 2026-09-17 00:49:12 +00:00
parent 126e257062
commit 79aae7f062
3 changed files with 17 additions and 12 deletions

View file

@ -17,7 +17,7 @@ from typing import Final
from litellm.integrations.otel.mappers.base import AttributeMap, AttrValue, SpanData
from litellm.integrations.otel.mappers.utils import (
collect,
drop_none,
drop_none_pairs,
json_if,
output_messages,
serialize_messages,
@ -84,13 +84,13 @@ class LangfuseMapper:
@staticmethod
def trace_attributes(trace: TraceControls) -> AttributeMap:
return drop_none(
{
LANGFUSE_TRACE_NAME: trace.name or None,
LANGFUSE_TRACE_USER_ID: trace.user_id or None,
LANGFUSE_TRACE_SESSION_ID: trace.session_id or None,
LANGFUSE_TRACE_TAGS: trace.tags or None,
}
return drop_none_pairs(
(
(LANGFUSE_TRACE_NAME, trace.name or None),
(LANGFUSE_TRACE_USER_ID, trace.user_id or None),
(LANGFUSE_TRACE_SESSION_ID, trace.session_id or None),
(LANGFUSE_TRACE_TAGS, trace.tags or None),
)
)
@classmethod

View file

@ -6,7 +6,7 @@ they live in one place.
"""
import json
from collections.abc import Callable, Mapping, Sequence
from collections.abc import Callable, Iterable, Mapping, Sequence
from typing import Final
from litellm.integrations.otel.mappers.base import AttributeMap, AttrValue
@ -47,7 +47,12 @@ def tool_attr_budget(vocabularies: int) -> int:
def drop_none(values: Mapping[str, AttrValue | None]) -> AttributeMap:
"""Return ``values`` with ``None``-valued entries removed."""
return {k: v for k, v in values.items() if v is not None}
return drop_none_pairs(values.items())
def drop_none_pairs(pairs: Iterable[tuple[str, AttrValue | None]]) -> AttributeMap:
"""Return ``pairs`` as a map with ``None``-valued entries removed."""
return {k: v for k, v in pairs if v is not None}
def tool_definition_attrs(

View file

@ -32,7 +32,7 @@ def caller_trace_controls(kwargs: Mapping[str, object]) -> TraceControls:
if request is None:
return TraceControls()
proxy_request: Final = as_str_mapping(request.get("proxy_server_request"))
headers: Final = (as_str_mapping(proxy_request.get("headers")) if proxy_request is not None else None) or {}
headers: Final = as_str_mapping(proxy_request.get("headers")) if proxy_request is not None else None
bodies: Final = tuple(
metadata
for key in ("metadata", "litellm_metadata")
@ -40,7 +40,7 @@ def caller_trace_controls(kwargs: Mapping[str, object]) -> TraceControls:
)
def scalar(control: str) -> str | None:
from_header: Final = as_str(headers.get(f"{LANGFUSE_HEADER_PREFIX}{control}"))
from_header: Final = as_str(headers.get(f"{LANGFUSE_HEADER_PREFIX}{control}")) if headers is not None else None
if from_header:
return from_header
return next((value for body in bodies if (value := as_str(body.get(control)))), None)