4343
4444if TYPE_CHECKING :
4545 from types import FrameType
46- from typing import Any , Dict , Generator , Iterator , Optional , Tuple , Union
46+ from typing import (
47+ Any ,
48+ Dict ,
49+ Generator ,
50+ Iterator ,
51+ Literal ,
52+ Optional ,
53+ Tuple ,
54+ Union ,
55+ )
4756
4857 from sentry_sdk ._types import Attributes
4958 from sentry_sdk .utils import ParsedUrl
@@ -1080,7 +1089,6 @@ def create_span_decorator(
10801089 use cases.
10811090 :type template: :py:class:`sentry_sdk.consts.SPANTEMPLATE`
10821091 """
1083- from sentry_sdk .scope import should_send_default_pii
10841092
10851093 def span_decorator (f : "Any" ) -> "Any" :
10861094 """
@@ -1110,20 +1118,21 @@ async def async_wrapper(*args: "Any", **kwargs: "Any") -> "Any":
11101118 span_op = op or _get_span_op (template )
11111119 function_name = name or qualname_from_function (f ) or ""
11121120 span_name = _get_span_name (template , function_name , kwargs )
1113- send_pii = should_send_default_pii ()
1121+ collect_inputs = _should_collect_gen_ai ("inputs" )
1122+ collect_outputs = _should_collect_gen_ai ("outputs" )
11141123
11151124 with current_span .start_child (
11161125 op = span_op ,
11171126 name = span_name ,
11181127 ) as span :
11191128 span .update_data (attributes or {})
11201129 _set_input_attributes (
1121- span , template , send_pii , function_name , f , args , kwargs
1130+ span , template , collect_inputs , function_name , f , args , kwargs
11221131 )
11231132
11241133 result = await f (* args , ** kwargs )
11251134
1126- _set_output_attributes (span , template , send_pii , result )
1135+ _set_output_attributes (span , template , collect_outputs , result )
11271136
11281137 return result
11291138
@@ -1155,20 +1164,21 @@ def sync_wrapper(*args: "Any", **kwargs: "Any") -> "Any":
11551164 span_op = op or _get_span_op (template )
11561165 function_name = name or qualname_from_function (f ) or ""
11571166 span_name = _get_span_name (template , function_name , kwargs )
1158- send_pii = should_send_default_pii ()
1167+ collect_inputs = _should_collect_gen_ai ("inputs" )
1168+ collect_outputs = _should_collect_gen_ai ("outputs" )
11591169
11601170 with current_span .start_child (
11611171 op = span_op ,
11621172 name = span_name ,
11631173 ) as span :
11641174 span .update_data (attributes or {})
11651175 _set_input_attributes (
1166- span , template , send_pii , function_name , f , args , kwargs
1176+ span , template , collect_inputs , function_name , f , args , kwargs
11671177 )
11681178
11691179 result = f (* args , ** kwargs )
11701180
1171- _set_output_attributes (span , template , send_pii , result )
1181+ _set_output_attributes (span , template , collect_outputs , result )
11721182
11731183 return result
11741184
@@ -1373,9 +1383,22 @@ def _get_span_op(template: "Union[str, SPANTEMPLATE]") -> str:
13731383 return str (op )
13741384
13751385
1386+ _AI_TEMPLATES = frozenset (
1387+ {SPANTEMPLATE .AI_AGENT , SPANTEMPLATE .AI_CHAT , SPANTEMPLATE .AI_TOOL }
1388+ )
1389+
1390+
1391+ def _should_collect_gen_ai (kind : 'Literal["inputs", "outputs"]' ) -> bool :
1392+ client = sentry_sdk .get_client ()
1393+ if has_data_collection_enabled (client .options ):
1394+ return bool (client .options ["data_collection" ]["gen_ai" ][kind ])
1395+
1396+ return client .should_send_default_pii ()
1397+
1398+
13761399def _get_input_attributes (
13771400 template : "Union[str, SPANTEMPLATE]" ,
1378- send_pii : bool ,
1401+ collect_inputs : bool ,
13791402 args : "tuple[Any, ...]" ,
13801403 kwargs : "dict[str, Any]" ,
13811404) -> "dict[str, Any]" :
@@ -1384,7 +1407,7 @@ def _get_input_attributes(
13841407 """
13851408 attributes : "dict[str, Any]" = {}
13861409
1387- if template in [ SPANTEMPLATE . AI_AGENT , SPANTEMPLATE . AI_TOOL , SPANTEMPLATE . AI_CHAT ] :
1410+ if template in _AI_TEMPLATES :
13881411 mapping = {
13891412 "model" : (SPANDATA .GEN_AI_REQUEST_MODEL , str ),
13901413 "model_name" : (SPANDATA .GEN_AI_REQUEST_MODEL , str ),
@@ -1404,22 +1427,25 @@ def _set_from_key(key: str, value: "Any") -> None:
14041427 if value is not None and isinstance (value , data_type ):
14051428 attributes [attribute ] = value
14061429
1407- for key , value in list (kwargs .items ()):
1408- if key == "prompt" and isinstance (value , str ):
1409- attributes .setdefault (SPANDATA .GEN_AI_REQUEST_MESSAGES , []).append (
1410- {"role" : "user" , "content" : value }
1411- )
1412- continue
1430+ # Pre-data collection, prompts were always recorded here, so they stay
1431+ # ungated until `send_default_pii` is removed.
1432+ collect_messages = True
1433+ if has_data_collection_enabled (sentry_sdk .get_client ().options ):
1434+ collect_messages = collect_inputs
14131435
1414- if key == "system_prompt" and isinstance (value , str ):
1415- attributes .setdefault (SPANDATA .GEN_AI_REQUEST_MESSAGES , []).append (
1416- {"role" : "system" , "content" : value }
1417- )
1436+ roles = {"prompt" : "user" , "system_prompt" : "system" }
1437+
1438+ for key , value in list (kwargs .items ()):
1439+ if key in roles :
1440+ if collect_messages and isinstance (value , str ):
1441+ attributes .setdefault (SPANDATA .GEN_AI_REQUEST_MESSAGES , []).append (
1442+ {"role" : roles [key ], "content" : value }
1443+ )
14181444 continue
14191445
14201446 _set_from_key (key , value )
14211447
1422- if template == SPANTEMPLATE .AI_TOOL and send_pii :
1448+ if template == SPANTEMPLATE .AI_TOOL and collect_inputs :
14231449 attributes [SPANDATA .GEN_AI_TOOL_INPUT ] = safe_repr (
14241450 {"args" : args , "kwargs" : kwargs }
14251451 )
@@ -1462,14 +1488,14 @@ def _set_from_keys(attribute: str, keys: "tuple[str, ...]") -> None:
14621488
14631489
14641490def _get_output_attributes (
1465- template : "Union[str, SPANTEMPLATE]" , send_pii : bool , result : "Any"
1491+ template : "Union[str, SPANTEMPLATE]" , collect_outputs : bool , result : "Any"
14661492) -> "dict[str, Any]" :
14671493 """
14681494 Get output attributes for the given span template.
14691495 """
14701496 attributes : "dict[str, Any]" = {}
14711497
1472- if template in [ SPANTEMPLATE . AI_AGENT , SPANTEMPLATE . AI_TOOL , SPANTEMPLATE . AI_CHAT ] :
1498+ if template in _AI_TEMPLATES :
14731499 with capture_internal_exceptions ():
14741500 # Usage from result, result.usage, and result.metadata.usage
14751501 usage_candidates = [result ]
@@ -1495,7 +1521,7 @@ def _get_output_attributes(
14951521 attributes [SPANDATA .GEN_AI_RESPONSE_MODEL ] = model_name
14961522
14971523 # Tool output
1498- if template == SPANTEMPLATE .AI_TOOL and send_pii :
1524+ if template == SPANTEMPLATE .AI_TOOL and collect_outputs :
14991525 attributes [SPANDATA .GEN_AI_TOOL_OUTPUT ] = safe_repr (result )
15001526
15011527 return attributes
@@ -1504,7 +1530,7 @@ def _get_output_attributes(
15041530def _set_input_attributes (
15051531 span : "Span" ,
15061532 template : "Union[str, SPANTEMPLATE]" ,
1507- send_pii : bool ,
1533+ collect_inputs : bool ,
15081534 name : str ,
15091535 f : "Any" ,
15101536 args : "tuple[Any, ...]" ,
@@ -1515,7 +1541,7 @@ def _set_input_attributes(
15151541
15161542 :param span: The span to set attributes on.
15171543 :param template: The template to use to set attributes on the span.
1518- :param send_pii : Whether to send PII data .
1544+ :param collect_inputs : Whether gen_ai inputs may be collected .
15191545 :param f: The wrapped function.
15201546 :param args: The arguments to the wrapped function.
15211547 :param kwargs: The keyword arguments to the wrapped function.
@@ -1541,22 +1567,25 @@ def _set_input_attributes(
15411567 if docstring is not None :
15421568 attributes [SPANDATA .GEN_AI_TOOL_DESCRIPTION ] = docstring
15431569
1544- attributes .update (_get_input_attributes (template , send_pii , args , kwargs ))
1570+ attributes .update (_get_input_attributes (template , collect_inputs , args , kwargs ))
15451571 span .update_data (attributes or {})
15461572
15471573
15481574def _set_output_attributes (
1549- span : "Span" , template : "Union[str, SPANTEMPLATE]" , send_pii : bool , result : "Any"
1575+ span : "Span" ,
1576+ template : "Union[str, SPANTEMPLATE]" ,
1577+ collect_outputs : bool ,
1578+ result : "Any" ,
15501579) -> None :
15511580 """
15521581 Set span output attributes based on the given span template.
15531582
15541583 :param span: The span to set attributes on.
15551584 :param template: The template to use to set attributes on the span.
1556- :param send_pii : Whether to send PII data .
1585+ :param collect_outputs : Whether gen_ai outputs may be collected .
15571586 :param result: The result of the wrapped function.
15581587 """
1559- span .update_data (_get_output_attributes (template , send_pii , result ) or {})
1588+ span .update_data (_get_output_attributes (template , collect_outputs , result ) or {})
15601589
15611590
15621591def _should_continue_trace (baggage : "Optional[Baggage]" ) -> bool :
0 commit comments