2626from sentry_sdk .utils import (
2727 capture_internal_exceptions ,
2828 event_from_exception ,
29+ has_data_collection_enabled ,
2930 package_version ,
3031 reraise ,
3132 safe_serialize ,
@@ -390,74 +391,6 @@ def _set_common_input_data(
390391 )
391392 set_on_span (SPANDATA .GEN_AI_SYSTEM , "anthropic" )
392393 set_on_span (SPANDATA .GEN_AI_OPERATION_NAME , "chat" )
393- if (
394- messages is not None
395- and len (messages ) > 0 # type: ignore
396- and should_send_default_pii ()
397- and integration .include_prompts
398- ):
399- if isinstance (system , str ) or isinstance (system , Iterable ):
400- set_on_span (
401- SPANDATA .GEN_AI_SYSTEM_INSTRUCTIONS ,
402- json .dumps (_transform_system_instructions (system )),
403- )
404-
405- normalized_messages = []
406- for message in messages :
407- if (
408- message .get ("role" ) == GEN_AI_ALLOWED_MESSAGE_ROLES .USER
409- and "content" in message
410- and isinstance (message ["content" ], (list , tuple ))
411- ):
412- transformed_content = []
413- for item in message ["content" ]:
414- # Skip tool_result items - they can contain images/documents
415- # with nested structures that are difficult to redact properly
416- if isinstance (item , dict ) and item .get ("type" ) == "tool_result" :
417- continue
418-
419- # Transform content blocks (images, documents, etc.)
420- transformed_content .append (
421- _transform_anthropic_content_block (item )
422- if isinstance (item , dict )
423- else item
424- )
425-
426- # If there are non-tool-result items, add them as a message
427- if transformed_content :
428- normalized_messages .append (
429- {
430- "role" : message .get ("role" ),
431- "content" : transformed_content ,
432- }
433- )
434- else :
435- # Transform content for non-list messages or assistant messages
436- transformed_message = message .copy ()
437- if "content" in transformed_message :
438- content = transformed_message ["content" ]
439- if isinstance (content , (list , tuple )):
440- transformed_message ["content" ] = [
441- _transform_anthropic_content_block (item )
442- if isinstance (item , dict )
443- else item
444- for item in content
445- ]
446- normalized_messages .append (transformed_message )
447-
448- role_normalized_messages = normalize_message_roles (normalized_messages )
449-
450- client = sentry_sdk .get_client ()
451- scope = sentry_sdk .get_current_scope ()
452- messages_data = (
453- truncate_and_annotate_messages (role_normalized_messages , span , scope )
454- if should_truncate_gen_ai_input (client .options )
455- else role_normalized_messages
456- )
457- if messages_data is not None :
458- set_data_normalized (
459- span , SPANDATA .GEN_AI_REQUEST_MESSAGES , messages_data , unpack = False
460- )
461394
462395 if max_tokens is not None and _is_given (max_tokens ):
463396 set_on_span (SPANDATA .GEN_AI_REQUEST_MAX_TOKENS , max_tokens )
@@ -470,8 +403,154 @@ def _set_common_input_data(
470403 if top_p is not None and _is_given (top_p ):
471404 set_on_span (SPANDATA .GEN_AI_REQUEST_TOP_P , top_p )
472405
473- if tools is not None and _is_given (tools ) and len (tools ) > 0 : # type: ignore
474- set_on_span (SPANDATA .GEN_AI_REQUEST_AVAILABLE_TOOLS , safe_serialize (tools ))
406+ client = sentry_sdk .get_client ()
407+
408+ if has_data_collection_enabled (client .options ):
409+ if client .options ["data_collection" ]["gen_ai" ]["inputs" ]:
410+ if tools is not None and _is_given (tools ) and len (tools ) > 0 : # type: ignore
411+ set_on_span (
412+ SPANDATA .GEN_AI_REQUEST_AVAILABLE_TOOLS , safe_serialize (tools )
413+ )
414+ else :
415+ # Tools were unconditionally added pre-data collection configuration.
416+ # This can be removed once data collection is fully rolled out
417+ if tools is not None and _is_given (tools ) and len (tools ) > 0 : # type: ignore
418+ set_on_span (SPANDATA .GEN_AI_REQUEST_AVAILABLE_TOOLS , safe_serialize (tools ))
419+
420+ if messages is not None and len (messages ) > 0 : # type: ignore
421+ if has_data_collection_enabled (client .options ):
422+ if client .options ["data_collection" ]["gen_ai" ]["inputs" ]:
423+ if isinstance (system , str ) or isinstance (system , Iterable ):
424+ set_on_span (
425+ SPANDATA .GEN_AI_SYSTEM_INSTRUCTIONS ,
426+ json .dumps (_transform_system_instructions (system )),
427+ )
428+
429+ normalized_messages = []
430+ for message in messages :
431+ if (
432+ message .get ("role" ) == GEN_AI_ALLOWED_MESSAGE_ROLES .USER
433+ and "content" in message
434+ and isinstance (message ["content" ], (list , tuple ))
435+ ):
436+ transformed_content = []
437+ for item in message ["content" ]:
438+ # Skip tool_result items - they can contain images/documents
439+ # with nested structures that are difficult to redact properly
440+ if (
441+ isinstance (item , dict )
442+ and item .get ("type" ) == "tool_result"
443+ ):
444+ continue
445+
446+ # Transform content blocks (images, documents, etc.)
447+ transformed_content .append (
448+ _transform_anthropic_content_block (item )
449+ if isinstance (item , dict )
450+ else item
451+ )
452+
453+ # If there are non-tool-result items, add them as a message
454+ if transformed_content :
455+ normalized_messages .append (
456+ {
457+ "role" : message .get ("role" ),
458+ "content" : transformed_content ,
459+ }
460+ )
461+ else :
462+ # Transform content for non-list messages or assistant messages
463+ transformed_message = message .copy ()
464+ if "content" in transformed_message :
465+ content = transformed_message ["content" ]
466+ if isinstance (content , (list , tuple )):
467+ transformed_message ["content" ] = [
468+ _transform_anthropic_content_block (item )
469+ if isinstance (item , dict )
470+ else item
471+ for item in content
472+ ]
473+ normalized_messages .append (transformed_message )
474+
475+ role_normalized_messages = normalize_message_roles (normalized_messages )
476+
477+ scope = sentry_sdk .get_current_scope ()
478+ messages_data = (
479+ truncate_and_annotate_messages (
480+ role_normalized_messages , span , scope
481+ )
482+ if should_truncate_gen_ai_input (client .options )
483+ else role_normalized_messages
484+ )
485+ if messages_data is not None :
486+ set_data_normalized (
487+ span ,
488+ SPANDATA .GEN_AI_REQUEST_MESSAGES ,
489+ messages_data ,
490+ unpack = False ,
491+ )
492+ elif should_send_default_pii () and integration .include_prompts :
493+ if isinstance (system , str ) or isinstance (system , Iterable ):
494+ set_on_span (
495+ SPANDATA .GEN_AI_SYSTEM_INSTRUCTIONS ,
496+ json .dumps (_transform_system_instructions (system )),
497+ )
498+
499+ normalized_messages = []
500+ for message in messages :
501+ if (
502+ message .get ("role" ) == GEN_AI_ALLOWED_MESSAGE_ROLES .USER
503+ and "content" in message
504+ and isinstance (message ["content" ], (list , tuple ))
505+ ):
506+ transformed_content = []
507+ for item in message ["content" ]:
508+ # Skip tool_result items - they can contain images/documents
509+ # with nested structures that are difficult to redact properly
510+ if isinstance (item , dict ) and item .get ("type" ) == "tool_result" :
511+ continue
512+
513+ # Transform content blocks (images, documents, etc.)
514+ transformed_content .append (
515+ _transform_anthropic_content_block (item )
516+ if isinstance (item , dict )
517+ else item
518+ )
519+
520+ # If there are non-tool-result items, add them as a message
521+ if transformed_content :
522+ normalized_messages .append (
523+ {
524+ "role" : message .get ("role" ),
525+ "content" : transformed_content ,
526+ }
527+ )
528+ else :
529+ # Transform content for non-list messages or assistant messages
530+ transformed_message = message .copy ()
531+ if "content" in transformed_message :
532+ content = transformed_message ["content" ]
533+ if isinstance (content , (list , tuple )):
534+ transformed_message ["content" ] = [
535+ _transform_anthropic_content_block (item )
536+ if isinstance (item , dict )
537+ else item
538+ for item in content
539+ ]
540+ normalized_messages .append (transformed_message )
541+
542+ role_normalized_messages = normalize_message_roles (normalized_messages )
543+
544+ scope = sentry_sdk .get_current_scope ()
545+ messages_data = (
546+ truncate_and_annotate_messages (role_normalized_messages , span , scope )
547+ if should_truncate_gen_ai_input (client .options )
548+ else role_normalized_messages
549+ )
550+ if messages_data is not None :
551+ set_data_normalized (
552+ span , SPANDATA .GEN_AI_REQUEST_MESSAGES , messages_data , unpack = False
553+ )
475554
476555
477556def _set_create_input_data (
0 commit comments