diff --git a/sentry_sdk/integrations/openai.py b/sentry_sdk/integrations/openai.py index 78fcdd49e2..187f795807 100644 --- a/sentry_sdk/integrations/openai.py +++ b/sentry_sdk/integrations/openai.py @@ -20,6 +20,11 @@ from sentry_sdk.tracing import Span try: + 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 @@ -192,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 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 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) ) diff --git a/tests/integrations/openai/test_openai.py b/tests/integrations/openai/test_openai.py index 5767f84d04..a3c7bdd9d9 100644 --- a/tests/integrations/openai/test_openai.py +++ b/tests/integrations/openai/test_openai.py @@ -1,4 +1,12 @@ import pytest + +from sentry_sdk.utils import package_version + +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 @@ -43,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=[ @@ -1387,3 +1396,34 @@ 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.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], +) +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"]