diff --git a/litellm/integrations/langfuse/langfuse_otel.py b/litellm/integrations/langfuse/langfuse_otel.py index 917a58973cb..e232d6d282a 100644 --- a/litellm/integrations/langfuse/langfuse_otel.py +++ b/litellm/integrations/langfuse/langfuse_otel.py @@ -409,12 +409,18 @@ class LangfuseOtelLogger(OpenTelemetry): Per-key Langfuse credentials are only valid against the host that issued them, so the host must travel with the credentials. Returns None when no per-key host is set, falling back to the env-configured endpoint. + + Prefers ``langfuse_base_url`` (the Langfuse v3 naming) and falls back to + the deprecated ``langfuse_host`` for backward compatibility, mirroring the + SDK's own ``base_url`` -> ``host`` resolution order. """ - dynamic_langfuse_host = standard_callback_dynamic_params.get("langfuse_host") - if not dynamic_langfuse_host: + dynamic_langfuse_base_url = standard_callback_dynamic_params.get( + "langfuse_base_url" + ) or standard_callback_dynamic_params.get("langfuse_host") + if not dynamic_langfuse_base_url: return None return LangfuseOtelLogger._construct_langfuse_otel_endpoint( - dynamic_langfuse_host + dynamic_langfuse_base_url ) def create_litellm_proxy_request_started_span( diff --git a/litellm/litellm_core_utils/initialize_dynamic_callback_params.py b/litellm/litellm_core_utils/initialize_dynamic_callback_params.py index a89dae52316..e969f677141 100644 --- a/litellm/litellm_core_utils/initialize_dynamic_callback_params.py +++ b/litellm/litellm_core_utils/initialize_dynamic_callback_params.py @@ -36,6 +36,7 @@ _supported_callback_params = [ "langfuse_secret", "langfuse_secret_key", "langfuse_host", + "langfuse_base_url", "langfuse_prompt_version", "langsmith_api_key", "langsmith_project", diff --git a/litellm/types/utils.py b/litellm/types/utils.py index 63c2513aed2..9eee8b213c0 100644 --- a/litellm/types/utils.py +++ b/litellm/types/utils.py @@ -2994,6 +2994,8 @@ class StandardCallbackDynamicParams(TypedDict, total=False): langfuse_secret: Optional[str] langfuse_secret_key: Optional[str] langfuse_host: Optional[str] + # Langfuse v3 naming for the host; preferred over langfuse_host where set + langfuse_base_url: Optional[str] # Langfuse prompt version langfuse_prompt_version: Optional[int] diff --git a/tests/test_litellm/integrations/test_langfuse_otel.py b/tests/test_litellm/integrations/test_langfuse_otel.py index 30737650431..acadeda3030 100644 --- a/tests/test_litellm/integrations/test_langfuse_otel.py +++ b/tests/test_litellm/integrations/test_langfuse_otel.py @@ -419,6 +419,31 @@ class TestLangfuseOtelIntegration: is None ) + def test_construct_dynamic_otel_endpoint_with_base_url(self): + """Per-key langfuse_base_url (the Langfuse v3 naming) is honored.""" + from litellm.types.utils import StandardCallbackDynamicParams + + logger = LangfuseOtelLogger() + endpoint = logger.construct_dynamic_otel_endpoint( + StandardCallbackDynamicParams( + langfuse_base_url="https://us.cloud.langfuse.com" + ) + ) + assert endpoint == "https://us.cloud.langfuse.com/api/public/otel" + + def test_construct_dynamic_otel_endpoint_base_url_preferred_over_host(self): + """When both are set, langfuse_base_url wins (mirrors the SDK's resolution order).""" + from litellm.types.utils import StandardCallbackDynamicParams + + logger = LangfuseOtelLogger() + endpoint = logger.construct_dynamic_otel_endpoint( + StandardCallbackDynamicParams( + langfuse_base_url="https://us.cloud.langfuse.com", + langfuse_host="https://cloud.langfuse.com", + ) + ) + assert endpoint == "https://us.cloud.langfuse.com/api/public/otel" + def test_get_langfuse_otel_config_with_otel_host_priority(self): """LANGFUSE_OTEL_HOST should take priority over LANGFUSE_HOST.""" with patch.dict(