33import time
44from collections .abc import Iterable
55from functools import wraps
6- from typing import TYPE_CHECKING
6+ from typing import TYPE_CHECKING , cast
77
88import sentry_sdk
99from sentry_sdk import consts
4848from sentry_sdk .utils import (
4949 capture_internal_exceptions ,
5050 event_from_exception ,
51+ has_data_collection_enabled ,
5152 reraise ,
5253)
5354
@@ -329,19 +330,11 @@ def _set_responses_api_input_data(
329330 kwargs : "dict[str, Any]" ,
330331 integration : "OpenAIIntegration" ,
331332) -> None :
332- explicit_instructions : "Union[Optional[str], Omit]" = kwargs .get ("instructions" )
333- messages : "Optional[Union[str, ResponseInputParam]]" = kwargs .get ("input" )
334-
335333 set_on_span = (
336334 span .set_attribute if isinstance (span , StreamedSpan ) else span .set_data
337335 )
338336
339- tools = kwargs .get ("tools" )
340- if tools is not None and _is_given (tools ):
341- set_on_span (
342- SPANDATA .GEN_AI_TOOL_DEFINITIONS ,
343- json .dumps (_transform_tool_definitions_responses (tools )),
344- )
337+ set_data_normalized (span , SPANDATA .GEN_AI_OPERATION_NAME , "responses" )
345338
346339 model = kwargs .get ("model" )
347340 if model is not None :
@@ -376,54 +369,81 @@ def _set_responses_api_input_data(
376369 reasoning ["effort" ],
377370 )
378371
379- if not should_send_default_pii () or not integration .include_prompts :
380- set_data_normalized (span , SPANDATA .GEN_AI_OPERATION_NAME , "responses" )
381- return
382-
383- if (
384- messages is None
385- and explicit_instructions is not None
386- and _is_given (explicit_instructions )
387- ):
388- set_on_span (
389- SPANDATA .GEN_AI_SYSTEM_INSTRUCTIONS ,
390- json .dumps (
391- [
392- {
393- "type" : "text" ,
394- "content" : explicit_instructions ,
395- }
396- ]
397- ),
398- )
372+ client_options = sentry_sdk .get_client ().options
373+ if has_data_collection_enabled (client_options ):
374+ if (
375+ integration .include_prompts
376+ and client_options ["data_collection" ]["gen_ai" ]["inputs" ]
377+ ):
378+ tools = kwargs .get ("tools" )
379+ if tools is not None and _is_given (tools ):
380+ set_on_span (
381+ SPANDATA .GEN_AI_TOOL_DEFINITIONS ,
382+ json .dumps (_transform_tool_definitions_responses (tools )),
383+ )
384+ else :
385+ # Pre-data collection this was always set, so this needs to be left here for now until
386+ # we deprecate `send_default_pii`. Once we do, this 'else' branch should be removed,
387+ # and the above branch placed below the "if not should_send_default_pii() or not integration.include_prompts"
388+ # line below
389+ tools = kwargs .get ("tools" )
390+ if tools is not None and _is_given (tools ):
391+ set_on_span (
392+ SPANDATA .GEN_AI_TOOL_DEFINITIONS ,
393+ json .dumps (_transform_tool_definitions_responses (tools )),
394+ )
399395
400- set_data_normalized (span , SPANDATA .GEN_AI_OPERATION_NAME , "responses" )
396+ if has_data_collection_enabled (client_options ):
397+ # This takes precedence over the global data collection settings
398+ if not integration .include_prompts :
399+ return
400+ if not client_options ["data_collection" ]["gen_ai" ]["inputs" ]:
401+ return
402+ elif not should_send_default_pii () or not integration .include_prompts :
401403 return
402404
405+ explicit_instructions : "Union[Optional[str], Omit]" = kwargs .get ("instructions" )
406+ has_explicit_instructions = explicit_instructions is not None and _is_given (
407+ explicit_instructions
408+ )
409+ messages : "Optional[Union[str, ResponseInputParam]]" = kwargs .get ("input" )
410+ instructions_text_parts : "list[TextPart]" = []
411+
403412 if messages is None :
404- set_data_normalized (span , SPANDATA .GEN_AI_OPERATION_NAME , "responses" )
413+ if has_explicit_instructions :
414+ set_on_span (
415+ SPANDATA .GEN_AI_SYSTEM_INSTRUCTIONS ,
416+ json .dumps (
417+ [
418+ {
419+ "type" : "text" ,
420+ "content" : explicit_instructions ,
421+ }
422+ ]
423+ ),
424+ )
425+ # No messages to record (only instructions at most)
405426 return
406427
407- instructions_text_parts : "list[TextPart]" = []
408- if explicit_instructions is not None and _is_given (explicit_instructions ):
428+ if has_explicit_instructions :
409429 instructions_text_parts .append (
410430 {
411431 "type" : "text" ,
412- "content" : explicit_instructions ,
432+ "content" : cast ( str , explicit_instructions ) ,
413433 }
414434 )
415435
416436 system_instructions = _get_system_instructions_responses (messages )
417437 # Deliberate use of function accepting completions API type because
418438 # of shared structure FOR THIS PURPOSE ONLY.
419439 instructions_text_parts += _transform_system_instructions (system_instructions )
420-
421440 if len (instructions_text_parts ) > 0 :
422441 set_on_span (
423442 SPANDATA .GEN_AI_SYSTEM_INSTRUCTIONS ,
424443 json .dumps (instructions_text_parts ),
425444 )
426445
446+ # Input was provided as a single string
427447 if isinstance (messages , str ):
428448 normalized_messages = normalize_message_roles ([messages ]) # type: ignore
429449 client = sentry_sdk .get_client ()
@@ -437,10 +457,9 @@ def _set_responses_api_input_data(
437457 set_data_normalized (
438458 span , SPANDATA .GEN_AI_REQUEST_MESSAGES , messages_data , unpack = False
439459 )
440-
441- set_data_normalized (span , SPANDATA .GEN_AI_OPERATION_NAME , "responses" )
442460 return
443461
462+ # Input was provided as a list (potentially a multi-turn conversation)
444463 non_system_messages = [
445464 message for message in messages if not _is_system_instruction_responses (message )
446465 ]
@@ -458,8 +477,6 @@ def _set_responses_api_input_data(
458477 span , SPANDATA .GEN_AI_REQUEST_MESSAGES , messages_data , unpack = False
459478 )
460479
461- set_data_normalized (span , SPANDATA .GEN_AI_OPERATION_NAME , "responses" )
462-
463480
464481def _set_completions_api_input_data (
465482 span : "Union[Span, StreamedSpan]" ,
0 commit comments