diff --git a/litellm/proxy/litellm_pre_call_utils.py b/litellm/proxy/litellm_pre_call_utils.py index b739ee46af9..c4f635b69b5 100644 --- a/litellm/proxy/litellm_pre_call_utils.py +++ b/litellm/proxy/litellm_pre_call_utils.py @@ -149,23 +149,6 @@ def _extract_generic_session_id_from_headers( return None -def _is_generic_session_header_capture_enabled() -> bool: - """ - Check whether capturing generic ``x--session-id`` headers as the - LiteLLM trace/session id is opted-in via env var. - - Defaults to False to preserve backwards compatibility — existing deployments - that send vendor session-id headers for non-LiteLLM purposes must not have - those values silently re-used as the call's ``litellm_trace_id`` / - ``litellm_session_id`` (which would regroup their spend logs and traces). - - Set ``LITELLM_CAPTURE_VENDOR_SESSION_HEADERS=true`` to enable. - """ - from litellm.secret_managers.main import get_secret_bool - - return bool(get_secret_bool("LITELLM_CAPTURE_VENDOR_SESSION_HEADERS", False)) - - def get_chain_id_from_headers(headers: Optional[Dict[str, str]]) -> Optional[str]: """ Extract chain id for call chaining from request headers. @@ -173,10 +156,8 @@ def get_chain_id_from_headers(headers: Optional[Dict[str, str]]) -> Optional[str Priority order: 1. ``x-litellm-trace-id`` (explicit, highest priority) 2. ``x-litellm-session-id`` (explicit) - 3. (OPT-IN) Any ``x--session-id`` header whose value looks like a - session id. E.g. ``x-claude-code-session-id``. Only consulted when the - ``LITELLM_CAPTURE_VENDOR_SESSION_HEADERS`` env var is truthy — keeping - the default behavior backwards-compatible. + 3. Any ``x--session-id`` header whose value looks like a session id + (alphanumeric / UUID, at least 8 chars). E.g. ``x-claude-code-session-id``. Header keys are matched case-insensitively so this works with raw header dicts from any transport. @@ -187,14 +168,11 @@ def get_chain_id_from_headers(headers: Optional[Dict[str, str]]) -> Optional[str if not headers: return None normalized = {k.lower(): v for k, v in headers.items() if isinstance(k, str)} - explicit = normalized.get("x-litellm-trace-id") or normalized.get( - "x-litellm-session-id" + return ( + normalized.get("x-litellm-trace-id") + or normalized.get("x-litellm-session-id") + or _extract_generic_session_id_from_headers(normalized) ) - if explicit: - return explicit - if _is_generic_session_header_capture_enabled(): - return _extract_generic_session_id_from_headers(normalized) - return None def safe_add_api_version_from_query_params(data: dict, request: Request): diff --git a/tests/test_litellm/proxy/test_litellm_pre_call_utils.py b/tests/test_litellm/proxy/test_litellm_pre_call_utils.py index 29490af12c9..e4734711469 100644 --- a/tests/test_litellm/proxy/test_litellm_pre_call_utils.py +++ b/tests/test_litellm/proxy/test_litellm_pre_call_utils.py @@ -1213,15 +1213,8 @@ def test_add_litellm_metadata_from_request_headers_both_headers_trace_id_precede assert data["litellm_trace_id"] == "trace-value" -def test_add_litellm_metadata_from_request_headers_generic_session_id_header( - monkeypatch, -): - """ - A generic x--session-id header is used when no explicit litellm - header is set — only when the opt-in env var is enabled. - """ - monkeypatch.setenv("LITELLM_CAPTURE_VENDOR_SESSION_HEADERS", "true") - +def test_add_litellm_metadata_from_request_headers_generic_session_id_header(): + """A generic x--session-id header is used when no explicit litellm header is set.""" headers = {"x-claude-code-session-id": "e96634a3-fa28-4083-b354-55542e2dca01"} data = {"metadata": {}} LiteLLMProxyRequestSetup.add_litellm_metadata_from_request_headers( @@ -1232,31 +1225,8 @@ def test_add_litellm_metadata_from_request_headers_generic_session_id_header( assert data["litellm_trace_id"] == "e96634a3-fa28-4083-b354-55542e2dca01" -def test_add_litellm_metadata_from_request_headers_generic_session_id_header_ignored_by_default( - monkeypatch, -): - """ - Default (flag off): a generic x--session-id header must NOT be - treated as a litellm chain id — prior users who sent such headers for - non-LiteLLM purposes continue to work unchanged. - """ - monkeypatch.delenv("LITELLM_CAPTURE_VENDOR_SESSION_HEADERS", raising=False) - - headers = {"x-claude-code-session-id": "e96634a3-fa28-4083-b354-55542e2dca01"} - data = {"metadata": {}} - LiteLLMProxyRequestSetup.add_litellm_metadata_from_request_headers( - headers=headers, data=data, _metadata_variable_name="metadata" - ) - assert "litellm_session_id" not in data - assert "litellm_trace_id" not in data - - -def test_add_litellm_metadata_from_request_headers_explicit_header_beats_generic( - monkeypatch, -): +def test_add_litellm_metadata_from_request_headers_explicit_header_beats_generic(): """Explicit x-litellm-trace-id wins over a generic x-*-session-id header.""" - monkeypatch.setenv("LITELLM_CAPTURE_VENDOR_SESSION_HEADERS", "true") - headers = { "x-litellm-trace-id": "explicit-trace-id-value", "x-claude-code-session-id": "e96634a3-fa28-4083-b354-55542e2dca01", @@ -1269,16 +1239,10 @@ def test_add_litellm_metadata_from_request_headers_explicit_header_beats_generic assert data["litellm_trace_id"] == "explicit-trace-id-value" -def test_get_chain_id_from_headers_generic_vendor_session_id(monkeypatch): - """ - Generic ``x--session-id`` capture is opt-in via - ``LITELLM_CAPTURE_VENDOR_SESSION_HEADERS``; when enabled, valid values are - picked up and explicit headers still take precedence. - """ +def test_get_chain_id_from_headers_generic_vendor_session_id(): + """get_chain_id_from_headers picks up any x--session-id with a valid value.""" from litellm.proxy.litellm_pre_call_utils import get_chain_id_from_headers - monkeypatch.setenv("LITELLM_CAPTURE_VENDOR_SESSION_HEADERS", "true") - assert ( get_chain_id_from_headers( {"x-claude-code-session-id": "e96634a3-fa28-4083-b354-55542e2dca01"} @@ -1300,33 +1264,6 @@ def test_get_chain_id_from_headers_generic_vendor_session_id(monkeypatch): ) -def test_get_chain_id_from_headers_generic_vendor_session_id_disabled_by_default( - monkeypatch, -): - """ - Generic vendor session-id capture must stay OFF by default — otherwise - existing deployments that send such headers for non-LiteLLM purposes would - have their spend logs / traces silently regrouped under those IDs. - """ - from litellm.proxy.litellm_pre_call_utils import get_chain_id_from_headers - - monkeypatch.delenv("LITELLM_CAPTURE_VENDOR_SESSION_HEADERS", raising=False) - - # Without the opt-in env var, generic vendor session headers are ignored. - assert ( - get_chain_id_from_headers( - {"x-claude-code-session-id": "e96634a3-fa28-4083-b354-55542e2dca01"} - ) - is None - ) - - # Explicit litellm headers still work (unchanged behavior). - assert ( - get_chain_id_from_headers({"x-litellm-trace-id": "explicit-id-value"}) - == "explicit-id-value" - ) - - def test_get_internal_user_header_from_mapping_returns_expected_header(): mappings = [ {"header_name": "X-OpenWebUI-User-Id", "litellm_user_role": "internal_user"},