From 7edb96d127bd1eccd4792b0e6f8b73de5b782c7c Mon Sep 17 00:00:00 2001 From: Erica Pisani Date: Thu, 30 Jul 2026 13:11:24 -0400 Subject: [PATCH 1/5] feat(openai): Gate Responses API inputs behind data collection Respect `data_collection.gen_ai.inputs` when recording Responses API messages, system instructions, and tool definitions, while preserving legacy `send_default_pii` behavior. Add coverage for enabled, disabled, default, and instruction-only inputs. Refs PY-2588 --- sentry_sdk/integrations/openai.py | 91 +++++---- tests/integrations/openai/test_openai.py | 230 +++++++++++++++++++++++ 2 files changed, 281 insertions(+), 40 deletions(-) diff --git a/sentry_sdk/integrations/openai.py b/sentry_sdk/integrations/openai.py index 8a77668329..8609f40b36 100644 --- a/sentry_sdk/integrations/openai.py +++ b/sentry_sdk/integrations/openai.py @@ -3,7 +3,7 @@ import time from collections.abc import Iterable from functools import wraps -from typing import TYPE_CHECKING +from typing import TYPE_CHECKING, cast import sentry_sdk from sentry_sdk import consts @@ -42,6 +42,7 @@ from sentry_sdk.utils import ( capture_internal_exceptions, event_from_exception, + has_data_collection_enabled, reraise, safe_serialize, ) @@ -324,18 +325,12 @@ def _set_responses_api_input_data( kwargs: "dict[str, Any]", integration: "OpenAIIntegration", ) -> None: - explicit_instructions: "Union[Optional[str], Omit]" = kwargs.get("instructions") - messages: "Optional[Union[str, ResponseInputParam]]" = kwargs.get("input") - - tools = kwargs.get("tools") - if tools is not None and _is_given(tools) and len(tools) > 0: - set_data_normalized( - span, SPANDATA.GEN_AI_REQUEST_AVAILABLE_TOOLS, safe_serialize(tools) - ) - set_on_span = ( span.set_attribute if isinstance(span, StreamedSpan) else span.set_data ) + + set_data_normalized(span, SPANDATA.GEN_AI_OPERATION_NAME, "responses") + model = kwargs.get("model") if model is not None: set_on_span(SPANDATA.GEN_AI_REQUEST_MODEL, model) @@ -369,40 +364,59 @@ def _set_responses_api_input_data( reasoning["effort"], ) - if not should_send_default_pii() or not integration.include_prompts: - set_data_normalized(span, SPANDATA.GEN_AI_OPERATION_NAME, "responses") - return - - if ( - messages is None - and explicit_instructions is not None - and _is_given(explicit_instructions) - ): - set_on_span( - SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS, - json.dumps( - [ - { - "type": "text", - "content": explicit_instructions, - } - ] - ), - ) + client_options = sentry_sdk.get_client().options + if has_data_collection_enabled(client_options): + if client_options["data_collection"]["gen_ai"]["inputs"]: + tools = kwargs.get("tools") + if tools is not None and _is_given(tools) and len(tools) > 0: + set_data_normalized( + span, SPANDATA.GEN_AI_REQUEST_AVAILABLE_TOOLS, safe_serialize(tools) + ) + else: + # Pre-data collection this was always set, so this needs to be left here for now until + # we deprecate `send_default_pii`. Once we do, this 'else' branch should be removed, + # and the above branch placed below the "if not should_send_default_pii() or not integration.include_prompts" + # line below + tools = kwargs.get("tools") + if tools is not None and _is_given(tools) and len(tools) > 0: + set_data_normalized( + span, SPANDATA.GEN_AI_REQUEST_AVAILABLE_TOOLS, safe_serialize(tools) + ) - set_data_normalized(span, SPANDATA.GEN_AI_OPERATION_NAME, "responses") + if has_data_collection_enabled(client_options): + if not client_options["data_collection"]["gen_ai"]["inputs"]: + return + elif not should_send_default_pii() or not integration.include_prompts: return + explicit_instructions: "Union[Optional[str], Omit]" = kwargs.get("instructions") + has_explicit_instructions = explicit_instructions is not None and _is_given( + explicit_instructions + ) + messages: "Optional[Union[str, ResponseInputParam]]" = kwargs.get("input") + instructions_text_parts: "list[TextPart]" = [] + if messages is None: - set_data_normalized(span, SPANDATA.GEN_AI_OPERATION_NAME, "responses") + if has_explicit_instructions: + set_on_span( + SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS, + json.dumps( + [ + { + "type": "text", + "content": explicit_instructions, + } + ] + ), + ) + # No messages to record (only instructions at most) return - instructions_text_parts: "list[TextPart]" = [] - if explicit_instructions is not None and _is_given(explicit_instructions): + if has_explicit_instructions: instructions_text_parts.append( { "type": "text", - "content": explicit_instructions, + "content": cast(str, explicit_instructions), } ) @@ -410,13 +424,13 @@ def _set_responses_api_input_data( # Deliberate use of function accepting completions API type because # of shared structure FOR THIS PURPOSE ONLY. instructions_text_parts += _transform_system_instructions(system_instructions) - if len(instructions_text_parts) > 0: set_on_span( SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS, json.dumps(instructions_text_parts), ) + # Input was provided as a single string if isinstance(messages, str): normalized_messages = normalize_message_roles([messages]) # type: ignore client = sentry_sdk.get_client() @@ -430,10 +444,9 @@ def _set_responses_api_input_data( set_data_normalized( span, SPANDATA.GEN_AI_REQUEST_MESSAGES, messages_data, unpack=False ) - - set_data_normalized(span, SPANDATA.GEN_AI_OPERATION_NAME, "responses") return + # Input was provided as a list (potentially a multi-turn conversation) non_system_messages = [ message for message in messages if not _is_system_instruction_responses(message) ] @@ -451,8 +464,6 @@ def _set_responses_api_input_data( span, SPANDATA.GEN_AI_REQUEST_MESSAGES, messages_data, unpack=False ) - set_data_normalized(span, SPANDATA.GEN_AI_OPERATION_NAME, "responses") - def _set_completions_api_input_data( span: "Union[Span, StreamedSpan]", diff --git a/tests/integrations/openai/test_openai.py b/tests/integrations/openai/test_openai.py index 7d243657f7..d10a5eb066 100644 --- a/tests/integrations/openai/test_openai.py +++ b/tests/integrations/openai/test_openai.py @@ -107,6 +107,25 @@ async def __call__(self, *args, **kwargs): ) +EXAMPLE_TOOLS = [ + { + "type": "function", + "name": "get_current_weather", + "description": "Get the current weather in a given location", + "parameters": { + "type": "object", + "properties": { + "location": { + "type": "string", + "description": "The city and state, e.g. San Francisco, CA", + }, + }, + "required": ["location"], + }, + } +] + + @pytest.mark.parametrize("span_streaming", [True, False]) @pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) @pytest.mark.parametrize( @@ -3891,6 +3910,7 @@ def test_ai_client_span_responses_api_no_pii( temperature=0.7, top_p=0.9, reasoning={"effort": "high"}, + tools=EXAMPLE_TOOLS, ) sentry_sdk.flush() @@ -3915,6 +3935,8 @@ def test_ai_client_span_responses_api_no_pii( "sentry.op": "gen_ai.responses", "sentry.origin": "auto.ai.openai", "sentry.segment.name": "openai tx", + # Tools are recorded regardless of PII in legacy (send_default_pii) mode + "gen_ai.request.available_tools": safe_serialize(EXAMPLE_TOOLS), } for attr, value in expected_attributes.items(): @@ -3936,6 +3958,7 @@ def test_ai_client_span_responses_api_no_pii( temperature=0.7, top_p=0.9, reasoning={"effort": "high"}, + tools=EXAMPLE_TOOLS, ) spans = [item.payload for item in items] @@ -3959,6 +3982,8 @@ def test_ai_client_span_responses_api_no_pii( "sentry.op": "gen_ai.responses", "sentry.origin": "auto.ai.openai", "sentry.segment.name": "openai tx", + # Tools are recorded regardless of PII in legacy (send_default_pii) mode + "gen_ai.request.available_tools": safe_serialize(EXAMPLE_TOOLS), } for attr, value in expected_attributes.items(): @@ -3979,6 +4004,7 @@ def test_ai_client_span_responses_api_no_pii( temperature=0.7, top_p=0.9, reasoning={"effort": "high"}, + tools=EXAMPLE_TOOLS, ) (transaction,) = events @@ -4002,6 +4028,8 @@ def test_ai_client_span_responses_api_no_pii( "gen_ai.usage.output_tokens": 10, "gen_ai.usage.output_tokens.reasoning": 8, "gen_ai.usage.total_tokens": 30, + # Tools are recorded regardless of PII in legacy (send_default_pii) mode + "gen_ai.request.available_tools": safe_serialize(EXAMPLE_TOOLS), } for key, value in expected_data.items(): @@ -4327,6 +4355,208 @@ def test_ai_client_span_responses_api( assert spans[0]["data"][attr] == value +@pytest.mark.parametrize("span_streaming", [True, False]) +@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) +@pytest.mark.parametrize( + "data_collection,extra_kwargs,expected_present,expected_absent", + [ + pytest.param( + {"gen_ai": {"inputs": True}}, + { + "instructions": "You are a coding assistant that talks like a pirate.", + "input": "How do I check if a Python object is an instance of a class?", + "tools": EXAMPLE_TOOLS, + }, + { + SPANDATA.GEN_AI_REQUEST_MESSAGES: safe_serialize( + ["How do I check if a Python object is an instance of a class?"] + ), + SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS: safe_serialize( + [ + { + "type": "text", + "content": "You are a coding assistant that talks like a pirate.", + } + ] + ), + SPANDATA.GEN_AI_REQUEST_AVAILABLE_TOOLS: safe_serialize(EXAMPLE_TOOLS), + }, + [], + id="inputs-enabled-string-input", + ), + pytest.param( + {"gen_ai": {"inputs": True}}, + { + "instructions": "You are a coding assistant that talks like a pirate.", + }, + { + SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS: safe_serialize( + [ + { + "type": "text", + "content": "You are a coding assistant that talks like a pirate.", + } + ] + ), + }, + [ + SPANDATA.GEN_AI_REQUEST_MESSAGES, + SPANDATA.GEN_AI_REQUEST_AVAILABLE_TOOLS, + ], + id="inputs-enabled-instructions-only", + ), + pytest.param( + {"gen_ai": {"inputs": True}}, + { + "instructions": "You are a coding assistant that talks like a pirate.", + "input": [ + {"role": "system", "content": "You are a helpful assistant."}, + {"role": "user", "content": "hello"}, + ], + }, + { + SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS: safe_serialize( + [ + { + "type": "text", + "content": "You are a coding assistant that talks like a pirate.", + }, + {"type": "text", "content": "You are a helpful assistant."}, + ] + ), + SPANDATA.GEN_AI_REQUEST_MESSAGES: safe_serialize( + [{"role": "user", "content": "hello"}] + ), + }, + [SPANDATA.GEN_AI_REQUEST_AVAILABLE_TOOLS], + id="inputs-enabled-list-input-with-system-message", + ), + pytest.param( + {"gen_ai": {"inputs": False}}, + { + "instructions": "You are a coding assistant that talks like a pirate.", + "input": "How do I check if a Python object is an instance of a class?", + "tools": EXAMPLE_TOOLS, + }, + {}, + [ + SPANDATA.GEN_AI_REQUEST_MESSAGES, + SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS, + SPANDATA.GEN_AI_REQUEST_AVAILABLE_TOOLS, + ], + id="inputs-disabled", + ), + pytest.param( + {}, + { + "input": "How do I check if a Python object is an instance of a class?", + "tools": EXAMPLE_TOOLS, + }, + { + SPANDATA.GEN_AI_REQUEST_MESSAGES: safe_serialize( + ["How do I check if a Python object is an instance of a class?"] + ), + SPANDATA.GEN_AI_REQUEST_AVAILABLE_TOOLS: safe_serialize(EXAMPLE_TOOLS), + }, + [SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS], + id="gen-ai-omitted-defaults-to-enabled", + ), + pytest.param( + {"gen_ai": {"inputs": True}}, + {}, + {}, + [ + SPANDATA.GEN_AI_REQUEST_MESSAGES, + SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS, + SPANDATA.GEN_AI_REQUEST_AVAILABLE_TOOLS, + ], + id="inputs-enabled-no-input-provided", + ), + ], +) +@pytest.mark.skipif(SKIP_RESPONSES_TESTS, reason="Responses API not available") +def test_responses_api_data_collection( + sentry_init, + capture_events, + capture_items, + data_collection, + extra_kwargs, + expected_present, + expected_absent, + stream_gen_ai_spans, + span_streaming, +): + sentry_init( + integrations=[OpenAIIntegration()], + disabled_integrations=[StdlibIntegration], + traces_sample_rate=1.0, + _experiments={"data_collection": data_collection}, + stream_gen_ai_spans=stream_gen_ai_spans, + trace_lifecycle="stream" if span_streaming else "static", + ) + + client = OpenAI(api_key="z") + client.responses._post = mock.Mock(return_value=EXAMPLE_RESPONSE) + + create_kwargs = { + "model": "gpt-4o", + "max_output_tokens": 100, + "temperature": 0.7, + "top_p": 0.9, + "reasoning": {"effort": "high"}, + } + create_kwargs.update(extra_kwargs) + + if span_streaming: + items = capture_items("span") + + with sentry_sdk.traces.start_span(name="openai tx"): + client.responses.create(**create_kwargs) + + sentry_sdk.flush() + spans = [item.payload for item in items] + + assert len(spans) == 2 + span_data = spans[0]["attributes"] + elif stream_gen_ai_spans: + items = capture_items("span") + + with start_transaction(name="openai tx"): + client.responses.create(**create_kwargs) + + spans = [item.payload for item in items] + + assert len(spans) == 1 + span_data = spans[0]["attributes"] + else: + events = capture_events() + + with start_transaction(name="openai tx"): + client.responses.create(**create_kwargs) + + (transaction,) = events + spans = transaction["spans"] + + assert len(spans) == 1 + assert spans[0]["op"] == "gen_ai.responses" + span_data = spans[0]["data"] + + # Non-input data is always collected, regardless of data collection config + assert span_data["gen_ai.operation.name"] == "responses" + assert span_data["gen_ai.request.model"] == "gpt-4o" + assert span_data["gen_ai.request.max_tokens"] == 100 + assert span_data["gen_ai.request.temperature"] == 0.7 + assert span_data["gen_ai.request.top_p"] == 0.9 + assert span_data["gen_ai.request.reasoning.level"] == "high" + assert span_data["gen_ai.system"] == "openai" + + for key, value in expected_present.items(): + assert span_data[key] == value + + for key in expected_absent: + assert key not in span_data + + @pytest.mark.parametrize("span_streaming", [True, False]) @pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) @pytest.mark.parametrize( From 454e7ffff7d5720ceb278141d7f61a63d27560b1 Mon Sep 17 00:00:00 2001 From: Erica Pisani Date: Thu, 30 Jul 2026 13:26:43 -0400 Subject: [PATCH 2/5] need to ensure that if the override is present and is false, that it takes precedence over data collection --- sentry_sdk/integrations/openai.py | 3 +++ tests/integrations/openai/test_openai.py | 27 ++++++++++++++++++++++-- 2 files changed, 28 insertions(+), 2 deletions(-) diff --git a/sentry_sdk/integrations/openai.py b/sentry_sdk/integrations/openai.py index 8609f40b36..ddaa01bc82 100644 --- a/sentry_sdk/integrations/openai.py +++ b/sentry_sdk/integrations/openai.py @@ -384,6 +384,9 @@ def _set_responses_api_input_data( ) if has_data_collection_enabled(client_options): + # This takes precedence over the global data collection settings + if not integration.include_prompts: + return if not client_options["data_collection"]["gen_ai"]["inputs"]: return elif not should_send_default_pii() or not integration.include_prompts: diff --git a/tests/integrations/openai/test_openai.py b/tests/integrations/openai/test_openai.py index d10a5eb066..4e1b0dc229 100644 --- a/tests/integrations/openai/test_openai.py +++ b/tests/integrations/openai/test_openai.py @@ -4358,7 +4358,7 @@ def test_ai_client_span_responses_api( @pytest.mark.parametrize("span_streaming", [True, False]) @pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) @pytest.mark.parametrize( - "data_collection,extra_kwargs,expected_present,expected_absent", + "data_collection,extra_kwargs,expected_present,expected_absent,include_prompts", [ pytest.param( {"gen_ai": {"inputs": True}}, @@ -4382,6 +4382,7 @@ def test_ai_client_span_responses_api( SPANDATA.GEN_AI_REQUEST_AVAILABLE_TOOLS: safe_serialize(EXAMPLE_TOOLS), }, [], + True, id="inputs-enabled-string-input", ), pytest.param( @@ -4403,6 +4404,7 @@ def test_ai_client_span_responses_api( SPANDATA.GEN_AI_REQUEST_MESSAGES, SPANDATA.GEN_AI_REQUEST_AVAILABLE_TOOLS, ], + True, id="inputs-enabled-instructions-only", ), pytest.param( @@ -4429,6 +4431,7 @@ def test_ai_client_span_responses_api( ), }, [SPANDATA.GEN_AI_REQUEST_AVAILABLE_TOOLS], + True, id="inputs-enabled-list-input-with-system-message", ), pytest.param( @@ -4444,6 +4447,7 @@ def test_ai_client_span_responses_api( SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS, SPANDATA.GEN_AI_REQUEST_AVAILABLE_TOOLS, ], + True, id="inputs-disabled", ), pytest.param( @@ -4459,6 +4463,7 @@ def test_ai_client_span_responses_api( SPANDATA.GEN_AI_REQUEST_AVAILABLE_TOOLS: safe_serialize(EXAMPLE_TOOLS), }, [SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS], + True, id="gen-ai-omitted-defaults-to-enabled", ), pytest.param( @@ -4470,8 +4475,25 @@ def test_ai_client_span_responses_api( SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS, SPANDATA.GEN_AI_REQUEST_AVAILABLE_TOOLS, ], + True, id="inputs-enabled-no-input-provided", ), + pytest.param( + {"gen_ai": {"inputs": True}}, + { + "instructions": "You are a coding assistant that talks like a pirate.", + "input": "How do I check if a Python object is an instance of a class?", + "tools": EXAMPLE_TOOLS, + }, + {}, + [ + SPANDATA.GEN_AI_REQUEST_MESSAGES, + SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS, + SPANDATA.GEN_AI_REQUEST_AVAILABLE_TOOLS, + ], + False, + id="include-prompts-disabled-overrides-inputs-enabled", + ), ], ) @pytest.mark.skipif(SKIP_RESPONSES_TESTS, reason="Responses API not available") @@ -4483,11 +4505,12 @@ def test_responses_api_data_collection( extra_kwargs, expected_present, expected_absent, + include_prompts, stream_gen_ai_spans, span_streaming, ): sentry_init( - integrations=[OpenAIIntegration()], + integrations=[OpenAIIntegration(include_prompts=include_prompts)], disabled_integrations=[StdlibIntegration], traces_sample_rate=1.0, _experiments={"data_collection": data_collection}, From ac8eae75233493a49feaedbbd7264b7b0d884b7c Mon Sep 17 00:00:00 2001 From: Erica Pisani Date: Thu, 30 Jul 2026 13:38:42 -0400 Subject: [PATCH 3/5] forgot to add the include_prompts check in a spot --- sentry_sdk/integrations/openai.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/sentry_sdk/integrations/openai.py b/sentry_sdk/integrations/openai.py index ddaa01bc82..cdb0a123a3 100644 --- a/sentry_sdk/integrations/openai.py +++ b/sentry_sdk/integrations/openai.py @@ -366,7 +366,10 @@ def _set_responses_api_input_data( client_options = sentry_sdk.get_client().options if has_data_collection_enabled(client_options): - if client_options["data_collection"]["gen_ai"]["inputs"]: + if ( + integration.include_prompts + and client_options["data_collection"]["gen_ai"]["inputs"] + ): tools = kwargs.get("tools") if tools is not None and _is_given(tools) and len(tools) > 0: set_data_normalized( From ecea21da346fb2934e7e6a7abe8adc4b88b734cc Mon Sep 17 00:00:00 2001 From: Alexander Alderman Webb Date: Fri, 31 Jul 2026 13:52:16 +0200 Subject: [PATCH 4/5] untangle responses and chat completions from merge --- sentry_sdk/integrations/openai.py | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/sentry_sdk/integrations/openai.py b/sentry_sdk/integrations/openai.py index b62c9a0d45..f2a45b60ae 100644 --- a/sentry_sdk/integrations/openai.py +++ b/sentry_sdk/integrations/openai.py @@ -26,6 +26,9 @@ from sentry_sdk.ai._openai_responses_api import ( _is_system_instruction as _is_system_instruction_responses, ) +from sentry_sdk.ai._openai_responses_api import ( + _transform_tool_definitions as _transform_tool_definitions_responses, +) from sentry_sdk.ai.monitoring import record_token_usage from sentry_sdk.ai.utils import ( get_start_span_function, @@ -376,7 +379,7 @@ def _set_responses_api_input_data( if tools is not None and _is_given(tools): set_on_span( SPANDATA.GEN_AI_TOOL_DEFINITIONS, - json.dumps(_transform_tool_definitions_completions(tools)), + json.dumps(_transform_tool_definitions_responses(tools)), ) else: # Pre-data collection this was always set, so this needs to be left here for now until @@ -387,7 +390,7 @@ def _set_responses_api_input_data( if tools is not None and _is_given(tools): set_on_span( SPANDATA.GEN_AI_TOOL_DEFINITIONS, - json.dumps(_transform_tool_definitions_completions(tools)), + json.dumps(_transform_tool_definitions_responses(tools)), ) if has_data_collection_enabled(client_options): @@ -487,6 +490,12 @@ def _set_completions_api_input_data( set_on_span = ( span.set_attribute if isinstance(span, StreamedSpan) else span.set_data ) + tools = kwargs.get("tools") + if tools is not None and _is_given(tools): + set_on_span( + SPANDATA.GEN_AI_TOOL_DEFINITIONS, + json.dumps(_transform_tool_definitions_completions(tools)), + ) model = kwargs.get("model") if model is not None: From cfe2ea96e38996679d0407c818b18d48ba906a0b Mon Sep 17 00:00:00 2001 From: Alexander Alderman Webb Date: Fri, 31 Jul 2026 14:01:18 +0200 Subject: [PATCH 5/5] fix tests following merge --- tests/integrations/openai/test_openai.py | 22 +++++++--------------- 1 file changed, 7 insertions(+), 15 deletions(-) diff --git a/tests/integrations/openai/test_openai.py b/tests/integrations/openai/test_openai.py index d365e2cd52..9ffa1b39cf 100644 --- a/tests/integrations/openai/test_openai.py +++ b/tests/integrations/openai/test_openai.py @@ -4085,7 +4085,6 @@ def test_ai_client_span_responses_api_no_pii( temperature=0.7, top_p=0.9, reasoning={"effort": "high"}, - tools=EXAMPLE_TOOLS, ) sentry_sdk.flush() @@ -4110,8 +4109,6 @@ def test_ai_client_span_responses_api_no_pii( "sentry.op": "gen_ai.responses", "sentry.origin": "auto.ai.openai", "sentry.segment.name": "openai tx", - # Tools are recorded regardless of PII in legacy (send_default_pii) mode - "gen_ai.request.available_tools": safe_serialize(EXAMPLE_TOOLS), } for attr, value in expected_attributes.items(): @@ -4157,8 +4154,6 @@ def test_ai_client_span_responses_api_no_pii( "sentry.op": "gen_ai.responses", "sentry.origin": "auto.ai.openai", "sentry.segment.name": "openai tx", - # Tools are recorded regardless of PII in legacy (send_default_pii) mode - "gen_ai.request.available_tools": safe_serialize(EXAMPLE_TOOLS), } for attr, value in expected_attributes.items(): @@ -4179,7 +4174,6 @@ def test_ai_client_span_responses_api_no_pii( temperature=0.7, top_p=0.9, reasoning={"effort": "high"}, - tools=EXAMPLE_TOOLS, ) (transaction,) = events @@ -4203,8 +4197,6 @@ def test_ai_client_span_responses_api_no_pii( "gen_ai.usage.output_tokens": 10, "gen_ai.usage.output_tokens.reasoning": 8, "gen_ai.usage.total_tokens": 30, - # Tools are recorded regardless of PII in legacy (send_default_pii) mode - "gen_ai.request.available_tools": safe_serialize(EXAMPLE_TOOLS), } for key, value in expected_data.items(): @@ -4745,7 +4737,7 @@ def test_ai_client_span_responses_api( } ] ), - SPANDATA.GEN_AI_REQUEST_AVAILABLE_TOOLS: safe_serialize(EXAMPLE_TOOLS), + SPANDATA.GEN_AI_TOOL_DEFINITIONS: safe_serialize(EXAMPLE_TOOLS), }, [], True, @@ -4768,7 +4760,7 @@ def test_ai_client_span_responses_api( }, [ SPANDATA.GEN_AI_REQUEST_MESSAGES, - SPANDATA.GEN_AI_REQUEST_AVAILABLE_TOOLS, + SPANDATA.GEN_AI_TOOL_DEFINITIONS, ], True, id="inputs-enabled-instructions-only", @@ -4796,7 +4788,7 @@ def test_ai_client_span_responses_api( [{"role": "user", "content": "hello"}] ), }, - [SPANDATA.GEN_AI_REQUEST_AVAILABLE_TOOLS], + [SPANDATA.GEN_AI_TOOL_DEFINITIONS], True, id="inputs-enabled-list-input-with-system-message", ), @@ -4811,7 +4803,7 @@ def test_ai_client_span_responses_api( [ SPANDATA.GEN_AI_REQUEST_MESSAGES, SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS, - SPANDATA.GEN_AI_REQUEST_AVAILABLE_TOOLS, + SPANDATA.GEN_AI_TOOL_DEFINITIONS, ], True, id="inputs-disabled", @@ -4826,7 +4818,7 @@ def test_ai_client_span_responses_api( SPANDATA.GEN_AI_REQUEST_MESSAGES: safe_serialize( ["How do I check if a Python object is an instance of a class?"] ), - SPANDATA.GEN_AI_REQUEST_AVAILABLE_TOOLS: safe_serialize(EXAMPLE_TOOLS), + SPANDATA.GEN_AI_TOOL_DEFINITIONS: safe_serialize(EXAMPLE_TOOLS), }, [SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS], True, @@ -4839,7 +4831,7 @@ def test_ai_client_span_responses_api( [ SPANDATA.GEN_AI_REQUEST_MESSAGES, SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS, - SPANDATA.GEN_AI_REQUEST_AVAILABLE_TOOLS, + SPANDATA.GEN_AI_TOOL_DEFINITIONS, ], True, id="inputs-enabled-no-input-provided", @@ -4855,7 +4847,7 @@ def test_ai_client_span_responses_api( [ SPANDATA.GEN_AI_REQUEST_MESSAGES, SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS, - SPANDATA.GEN_AI_REQUEST_AVAILABLE_TOOLS, + SPANDATA.GEN_AI_TOOL_DEFINITIONS, ], False, id="include-prompts-disabled-overrides-inputs-enabled",