From 567f0f624fa1005fade3b7b2c460c19cd1aa1d5c Mon Sep 17 00:00:00 2001 From: Thomas Mildner Date: Tue, 12 May 2026 14:20:47 +0200 Subject: [PATCH 1/5] fix: enhance Opik metadata extraction to include user API key auth context fixed after refactoring to extractor logic --- .../opik/opik_payload_builder/extractors.py | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/litellm/integrations/opik/opik_payload_builder/extractors.py b/litellm/integrations/opik/opik_payload_builder/extractors.py index 9779ccddacfc..51c17092e2e8 100644 --- a/litellm/integrations/opik/opik_payload_builder/extractors.py +++ b/litellm/integrations/opik/opik_payload_builder/extractors.py @@ -39,20 +39,28 @@ def extract_opik_metadata( standard_logging_metadata: Dict[str, Any], ) -> Dict[str, Any]: """ - Extract and merge Opik metadata from request and requester. + Extract and merge Opik metadata from the request or user api auth key context. Args: - litellm_metadata: Metadata from litellm_params - standard_logging_metadata: Metadata from standard_logging_object + litellm_metadata: Metadata from litellm_params. + standard_logging_metadata: Metadata from standard_logging_object. Returns: - Merged Opik metadata dictionary + Merged Opik metadata dictionary. """ opik_meta = litellm_metadata.get("opik", {}).copy() + # Fall back to API key auth metadata when the request does not provide Opik data. + if not opik_meta: + auth_meta = standard_logging_metadata.get("user_api_key_auth_metadata") or {} + opik_meta = (auth_meta.get("opik") or {}).copy() + requester_metadata = standard_logging_metadata.get("requester_metadata", {}) or {} requester_opik = requester_metadata.get("opik", {}) or {} - opik_meta.update(requester_opik) + + # Requester-level metadata should override or extend earlier values. + if requester_opik: + opik_meta.update(requester_opik) _logging.verbose_logger.debug( f"litellm_opik_metadata - {json.dumps(opik_meta, default=str)}" From beacbf8af8ce3bce373a70ac69ba9630df487820 Mon Sep 17 00:00:00 2001 From: Thomas Mildner Date: Wed, 20 May 2026 22:55:13 +0200 Subject: [PATCH 2/5] test: add unit tests for OPik metadata extraction logic --- .../integrations/opik/test_opik_extractors.py | 83 +++++++++++++++++++ 1 file changed, 83 insertions(+) create mode 100644 tests/litellm/integrations/opik/test_opik_extractors.py diff --git a/tests/litellm/integrations/opik/test_opik_extractors.py b/tests/litellm/integrations/opik/test_opik_extractors.py new file mode 100644 index 000000000000..73b70a62b3c3 --- /dev/null +++ b/tests/litellm/integrations/opik/test_opik_extractors.py @@ -0,0 +1,83 @@ +from litellm.integrations.opik.opik_payload_builder.extractors import ( + extract_opik_metadata, +) + + +def test_extract_opik_metadata_fills_missing_keys_from_auth_metadata(): + litellm_metadata = {"opik": {"project_name": "my-proj"}} + standard_logging_metadata = { + "user_api_key_auth_metadata": { + "opik": { + "workspace": "auth-workspace", + "project_name": "auth-project", + } + } + } + + result = extract_opik_metadata( + litellm_metadata=litellm_metadata, + standard_logging_metadata=standard_logging_metadata, + ) + + assert result == { + "project_name": "my-proj", + "workspace": "auth-workspace", + } + + +def test_extract_opik_metadata_request_metadata_overrides_auth_metadata(): + litellm_metadata = { + "opik": { + "workspace": "request-workspace", + "thread_id": "request-thread", + } + } + standard_logging_metadata = { + "user_api_key_auth_metadata": { + "opik": { + "workspace": "auth-workspace", + "thread_id": "auth-thread", + "project_name": "auth-project", + } + } + } + + result = extract_opik_metadata( + litellm_metadata=litellm_metadata, + standard_logging_metadata=standard_logging_metadata, + ) + + assert result == { + "workspace": "request-workspace", + "thread_id": "request-thread", + "project_name": "auth-project", + } + + +def test_extract_opik_metadata_requester_metadata_overrides_all_other_sources(): + litellm_metadata = {"opik": {"project_name": "request-project"}} + standard_logging_metadata = { + "user_api_key_auth_metadata": { + "opik": { + "workspace": "auth-workspace", + "project_name": "auth-project", + } + }, + "requester_metadata": { + "opik": { + "workspace": "requester-workspace", + "thread_id": "requester-thread", + } + }, + } + + result = extract_opik_metadata( + litellm_metadata=litellm_metadata, + standard_logging_metadata=standard_logging_metadata, + ) + + assert result == { + "project_name": "request-project", + "workspace": "requester-workspace", + "thread_id": "requester-thread", + } \ No newline at end of file From f2f64765bcc16299d31d55ad82e35da79ea209fc Mon Sep 17 00:00:00 2001 From: Thomas Mildner Date: Wed, 20 May 2026 23:04:10 +0200 Subject: [PATCH 3/5] fix: enhance extract_opik_metadata function to prioritize metadata sources for improved accuracy --- .../opik/opik_payload_builder/extractors.py | 20 +++++++++++-------- .../integrations/opik/test_opik_extractors.py | 2 +- 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/litellm/integrations/opik/opik_payload_builder/extractors.py b/litellm/integrations/opik/opik_payload_builder/extractors.py index 51c17092e2e8..13157113f477 100644 --- a/litellm/integrations/opik/opik_payload_builder/extractors.py +++ b/litellm/integrations/opik/opik_payload_builder/extractors.py @@ -39,7 +39,11 @@ def extract_opik_metadata( standard_logging_metadata: Dict[str, Any], ) -> Dict[str, Any]: """ - Extract and merge Opik metadata from the request or user api auth key context. + Merge Opik metadata from three sources in increasing priority order: + + 1. user_api_key_auth_metadata – lowest priority (operator-level defaults) + 2. litellm_metadata (request) – overrides auth-key defaults + 3. requester_metadata – highest priority (e.g. proxy header overrides) Args: litellm_metadata: Metadata from litellm_params. @@ -48,17 +52,17 @@ def extract_opik_metadata( Returns: Merged Opik metadata dictionary. """ - opik_meta = litellm_metadata.get("opik", {}).copy() + # Start with auth-key defaults (lowest priority). + auth_meta = standard_logging_metadata.get("user_api_key_auth_metadata") or {} + opik_meta = (auth_meta.get("opik") or {}).copy() - # Fall back to API key auth metadata when the request does not provide Opik data. - if not opik_meta: - auth_meta = standard_logging_metadata.get("user_api_key_auth_metadata") or {} - opik_meta = (auth_meta.get("opik") or {}).copy() + # Request-level values override auth-key defaults. + request_opik = litellm_metadata.get("opik") or {} + opik_meta.update(request_opik) + # Requester-level values win over everything else. requester_metadata = standard_logging_metadata.get("requester_metadata", {}) or {} requester_opik = requester_metadata.get("opik", {}) or {} - - # Requester-level metadata should override or extend earlier values. if requester_opik: opik_meta.update(requester_opik) diff --git a/tests/litellm/integrations/opik/test_opik_extractors.py b/tests/litellm/integrations/opik/test_opik_extractors.py index 73b70a62b3c3..5af90c0a31af 100644 --- a/tests/litellm/integrations/opik/test_opik_extractors.py +++ b/tests/litellm/integrations/opik/test_opik_extractors.py @@ -80,4 +80,4 @@ def test_extract_opik_metadata_requester_metadata_overrides_all_other_sources(): "project_name": "request-project", "workspace": "requester-workspace", "thread_id": "requester-thread", - } \ No newline at end of file + } From 1b56f4e85d1242d7840e23835f21da1d67ef3265 Mon Sep 17 00:00:00 2001 From: Thomas Mildner Date: Wed, 20 May 2026 23:19:59 +0200 Subject: [PATCH 4/5] fix(ci): clarified comments and edited unit tests --- .../integrations/opik/opik_payload_builder/extractors.py | 8 ++++---- tests/litellm/integrations/opik/test_opik_extractors.py | 3 ++- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/litellm/integrations/opik/opik_payload_builder/extractors.py b/litellm/integrations/opik/opik_payload_builder/extractors.py index 13157113f477..1e3a664acc1f 100644 --- a/litellm/integrations/opik/opik_payload_builder/extractors.py +++ b/litellm/integrations/opik/opik_payload_builder/extractors.py @@ -41,12 +41,12 @@ def extract_opik_metadata( """ Merge Opik metadata from three sources in increasing priority order: - 1. user_api_key_auth_metadata – lowest priority (operator-level defaults) - 2. litellm_metadata (request) – overrides auth-key defaults - 3. requester_metadata – highest priority (e.g. proxy header overrides) + 1. user_api_key_auth_metadata– lowest priority (operator-level defaults) + 2. litellm_metadata (request)– overrides auth-key defaults + 3. requester_metadata – highest priority (e.g. proxy header overrides) Args: - litellm_metadata: Metadata from litellm_params. + litellm_metadata: Metadata from litellm_params.mak standard_logging_metadata: Metadata from standard_logging_object. Returns: diff --git a/tests/litellm/integrations/opik/test_opik_extractors.py b/tests/litellm/integrations/opik/test_opik_extractors.py index 5af90c0a31af..6f85a1c6090b 100644 --- a/tests/litellm/integrations/opik/test_opik_extractors.py +++ b/tests/litellm/integrations/opik/test_opik_extractors.py @@ -67,6 +67,7 @@ def test_extract_opik_metadata_requester_metadata_overrides_all_other_sources(): "opik": { "workspace": "requester-workspace", "thread_id": "requester-thread", + "project_name": "requester-project", } }, } @@ -77,7 +78,7 @@ def test_extract_opik_metadata_requester_metadata_overrides_all_other_sources(): ) assert result == { - "project_name": "request-project", + "project_name": "requester-project", "workspace": "requester-workspace", "thread_id": "requester-thread", } From 4d0fce0aa27345d44c0ef998f8c2469878d3b6b7 Mon Sep 17 00:00:00 2001 From: Thomas Mildner Date: Wed, 20 May 2026 23:36:21 +0200 Subject: [PATCH 5/5] test: add unit tests for OPik metadata extraction with auth and requester overrides --- .../integrations/opik/test_opik_extractors.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename tests/{litellm => test_litellm}/integrations/opik/test_opik_extractors.py (100%) diff --git a/tests/litellm/integrations/opik/test_opik_extractors.py b/tests/test_litellm/integrations/opik/test_opik_extractors.py similarity index 100% rename from tests/litellm/integrations/opik/test_opik_extractors.py rename to tests/test_litellm/integrations/opik/test_opik_extractors.py