From e728250595c280c1b7f56720ac1adda0f1180556 Mon Sep 17 00:00:00 2001 From: Anton Pirker Date: Wed, 30 Jul 2025 14:52:17 +0200 Subject: [PATCH 1/5] Better checking for empty tools list --- sentry_sdk/integrations/openai.py | 5 +++-- tests/integrations/openai/test_openai.py | 28 ++++++++++++++++++++++++ 2 files changed, 31 insertions(+), 2 deletions(-) diff --git a/sentry_sdk/integrations/openai.py b/sentry_sdk/integrations/openai.py index 78fcdd49e2..1283ab38d5 100644 --- a/sentry_sdk/integrations/openai.py +++ b/sentry_sdk/integrations/openai.py @@ -20,6 +20,7 @@ from sentry_sdk.tracing import Span try: + import openai from openai.resources.chat.completions import Completions, AsyncCompletions from openai.resources import Embeddings, AsyncEmbeddings @@ -192,12 +193,12 @@ def _set_input_data(span, kwargs, operation, integration): } for key, attribute in kwargs_keys_to_attributes.items(): value = kwargs.get(key) - if value is not None: + if value is not openai.NOT_GIVEN and value is not None: set_data_normalized(span, attribute, value) # Input attributes: Tools tools = kwargs.get("tools") - if tools is not None and len(tools) > 0: + if tools is not openai.NOT_GIVEN and tools is not None and len(tools) > 0: set_data_normalized( span, SPANDATA.GEN_AI_REQUEST_AVAILABLE_TOOLS, safe_serialize(tools) ) diff --git a/tests/integrations/openai/test_openai.py b/tests/integrations/openai/test_openai.py index 5767f84d04..2a2f5684b0 100644 --- a/tests/integrations/openai/test_openai.py +++ b/tests/integrations/openai/test_openai.py @@ -1,4 +1,5 @@ import pytest +import openai from openai import AsyncOpenAI, OpenAI, AsyncStream, Stream, OpenAIError from openai.types import CompletionUsage, CreateEmbeddingResponse, Embedding from openai.types.chat import ChatCompletion, ChatCompletionMessage, ChatCompletionChunk @@ -1387,3 +1388,30 @@ async def test_streaming_responses_api_async( assert span["data"]["gen_ai.usage.input_tokens"] == 20 assert span["data"]["gen_ai.usage.output_tokens"] == 10 assert span["data"]["gen_ai.usage.total_tokens"] == 30 + + +@pytest.mark.parametrize( + "tools", + [[], None, openai.NOT_GIVEN], +) +def test_empty_tools_in_chat_completion(sentry_init, capture_events, tools): + sentry_init( + integrations=[OpenAIIntegration()], + traces_sample_rate=1.0, + ) + events = capture_events() + + client = OpenAI(api_key="z") + client.chat.completions._post = mock.Mock(return_value=EXAMPLE_CHAT_COMPLETION) + + with start_transaction(name="openai tx"): + client.chat.completions.create( + model="some-model", + messages=[{"role": "system", "content": "hello"}], + tools=tools, + ) + + (event,) = events + span = event["spans"][0] + + assert "gen_ai.request.available_tools" not in span["data"] From f25acafde4615b60d86a1d4a50c95d431970844a Mon Sep 17 00:00:00 2001 From: Anton Pirker Date: Wed, 30 Jul 2025 15:25:43 +0200 Subject: [PATCH 2/5] fix for older openai libs --- sentry_sdk/integrations/openai.py | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/sentry_sdk/integrations/openai.py b/sentry_sdk/integrations/openai.py index 1283ab38d5..187f795807 100644 --- a/sentry_sdk/integrations/openai.py +++ b/sentry_sdk/integrations/openai.py @@ -20,7 +20,11 @@ from sentry_sdk.tracing import Span try: - import openai + try: + from openai import NOT_GIVEN + except ImportError: + NOT_GIVEN = None + from openai.resources.chat.completions import Completions, AsyncCompletions from openai.resources import Embeddings, AsyncEmbeddings @@ -193,12 +197,13 @@ def _set_input_data(span, kwargs, operation, integration): } for key, attribute in kwargs_keys_to_attributes.items(): value = kwargs.get(key) - if value is not openai.NOT_GIVEN and value is not None: + + if value is not NOT_GIVEN and value is not None: set_data_normalized(span, attribute, value) # Input attributes: Tools tools = kwargs.get("tools") - if tools is not openai.NOT_GIVEN and tools is not None and len(tools) > 0: + if tools is not NOT_GIVEN and tools is not None and len(tools) > 0: set_data_normalized( span, SPANDATA.GEN_AI_REQUEST_AVAILABLE_TOOLS, safe_serialize(tools) ) From 8d6b7392866e7f3b076caa415892911c6ab97de6 Mon Sep 17 00:00:00 2001 From: Anton Pirker Date: Wed, 30 Jul 2025 15:32:08 +0200 Subject: [PATCH 3/5] fix for older openai libs --- tests/integrations/openai/test_openai.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/integrations/openai/test_openai.py b/tests/integrations/openai/test_openai.py index 2a2f5684b0..b685988406 100644 --- a/tests/integrations/openai/test_openai.py +++ b/tests/integrations/openai/test_openai.py @@ -1392,7 +1392,7 @@ async def test_streaming_responses_api_async( @pytest.mark.parametrize( "tools", - [[], None, openai.NOT_GIVEN], + [[], None, openai.NOT_GIVEN if hasattr(openai, "NOT_GIVEN") else None], ) def test_empty_tools_in_chat_completion(sentry_init, capture_events, tools): sentry_init( From 324962585af1bb9d064a0f2d3af503e5022f4d2f Mon Sep 17 00:00:00 2001 From: Anton Pirker Date: Wed, 30 Jul 2025 15:33:44 +0200 Subject: [PATCH 4/5] fix for older openai libs --- tests/integrations/openai/test_openai.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/tests/integrations/openai/test_openai.py b/tests/integrations/openai/test_openai.py index b685988406..974d6a0ce2 100644 --- a/tests/integrations/openai/test_openai.py +++ b/tests/integrations/openai/test_openai.py @@ -1,5 +1,10 @@ import pytest -import openai + +try: + from openai import NOT_GIVEN +except ImportError: + NOT_GIVEN = None + from openai import AsyncOpenAI, OpenAI, AsyncStream, Stream, OpenAIError from openai.types import CompletionUsage, CreateEmbeddingResponse, Embedding from openai.types.chat import ChatCompletion, ChatCompletionMessage, ChatCompletionChunk @@ -1392,7 +1397,7 @@ async def test_streaming_responses_api_async( @pytest.mark.parametrize( "tools", - [[], None, openai.NOT_GIVEN if hasattr(openai, "NOT_GIVEN") else None], + [[], None, NOT_GIVEN], ) def test_empty_tools_in_chat_completion(sentry_init, capture_events, tools): sentry_init( From 8d8958420f92cfc90f35716270fedf51da83c0e0 Mon Sep 17 00:00:00 2001 From: Anton Pirker Date: Wed, 30 Jul 2025 17:54:43 +0200 Subject: [PATCH 5/5] skip test in old openai versions where there is no tools parameter --- tests/integrations/openai/test_openai.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/tests/integrations/openai/test_openai.py b/tests/integrations/openai/test_openai.py index 974d6a0ce2..a3c7bdd9d9 100644 --- a/tests/integrations/openai/test_openai.py +++ b/tests/integrations/openai/test_openai.py @@ -1,5 +1,7 @@ import pytest +from sentry_sdk.utils import package_version + try: from openai import NOT_GIVEN except ImportError: @@ -49,6 +51,7 @@ async def __call__(self, *args, **kwargs): return super(AsyncMock, self).__call__(*args, **kwargs) +OPENAI_VERSION = package_version("openai") EXAMPLE_CHAT_COMPLETION = ChatCompletion( id="chat-id", choices=[ @@ -1395,6 +1398,10 @@ async def test_streaming_responses_api_async( assert span["data"]["gen_ai.usage.total_tokens"] == 30 +@pytest.mark.skipif( + OPENAI_VERSION <= (1, 1, 0), + reason="OpenAI versions <=1.1.0 do not support the tools parameter.", +) @pytest.mark.parametrize( "tools", [[], None, NOT_GIVEN],