-
Notifications
You must be signed in to change notification settings - Fork 648
feat(langgraph): Gate prompt/response collection on data_collection option #7175
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -19,7 +19,7 @@ | |
| has_span_streaming_enabled, | ||
| should_truncate_gen_ai_input, | ||
| ) | ||
| from sentry_sdk.utils import safe_serialize | ||
| from sentry_sdk.utils import has_data_collection_enabled, safe_serialize | ||
|
|
||
| try: | ||
| from langgraph.errors import GraphBubbleUp | ||
|
|
@@ -53,6 +53,24 @@ | |
| Pregel.ainvoke = _wrap_pregel_ainvoke(Pregel.ainvoke) | ||
|
|
||
|
|
||
| def _should_record_inputs(integration: "LanggraphIntegration") -> bool: | ||
| client = sentry_sdk.get_client() | ||
| if has_data_collection_enabled(client.options): | ||
| return bool(client.options["data_collection"]["gen_ai"]["inputs"]) | ||
|
|
||
| # To remove once data collection has been fully rolled out | ||
| return should_send_default_pii() and integration.include_prompts | ||
|
|
||
|
|
||
| def _should_record_outputs(integration: "LanggraphIntegration") -> bool: | ||
| client = sentry_sdk.get_client() | ||
| if has_data_collection_enabled(client.options): | ||
| return bool(client.options["data_collection"]["gen_ai"]["outputs"]) | ||
|
|
||
| # To remove once data collection has been fully rolled out | ||
| return should_send_default_pii() and integration.include_prompts | ||
|
|
||
|
|
||
| def _get_graph_name(graph_obj: "Any") -> "Optional[str]": | ||
| for attr in ["name", "graph_name", "__name__", "_name"]: | ||
| if hasattr(graph_obj, attr): | ||
|
|
@@ -153,7 +171,13 @@ | |
| tools = list(data.tools_by_name.keys()) | ||
|
|
||
| if tools is not None: | ||
| span.set_data(SPANDATA.GEN_AI_REQUEST_AVAILABLE_TOOLS, tools) | ||
| # Available tools aren't gated on the legacy PII settings, so they're | ||
| # only gated when data collection has been configured. | ||
| if has_data_collection_enabled(client.options): | ||
| if client.options["data_collection"]["gen_ai"]["inputs"]: | ||
| span.set_data(SPANDATA.GEN_AI_REQUEST_AVAILABLE_TOOLS, tools) | ||
| else: | ||
| span.set_data(SPANDATA.GEN_AI_REQUEST_AVAILABLE_TOOLS, tools) | ||
|
|
||
| return compiled_graph | ||
|
|
||
|
|
@@ -188,18 +212,13 @@ | |
|
|
||
| # Store input messages to later compare with output | ||
| input_messages = None | ||
| if ( | ||
| len(args) > 0 | ||
| and should_send_default_pii() | ||
| and integration.include_prompts | ||
| ): | ||
| if len(args) > 0 and _should_record_inputs(integration): | ||
| input_messages = _parse_langgraph_messages(args[0]) | ||
| if input_messages: | ||
| normalized_input_messages = normalize_message_roles( | ||
| input_messages | ||
| ) | ||
|
|
||
| client = sentry_sdk.get_client() | ||
| scope = sentry_sdk.get_current_scope() | ||
| messages_data = ( | ||
| truncate_and_annotate_messages( | ||
|
|
@@ -235,18 +254,13 @@ | |
|
|
||
| # Store input messages to later compare with output | ||
| input_messages = None | ||
| if ( | ||
| len(args) > 0 | ||
| and should_send_default_pii() | ||
| and integration.include_prompts | ||
| ): | ||
| if len(args) > 0 and _should_record_inputs(integration): | ||
| input_messages = _parse_langgraph_messages(args[0]) | ||
| if input_messages: | ||
| normalized_input_messages = normalize_message_roles( | ||
| input_messages | ||
| ) | ||
|
|
||
| client = sentry_sdk.get_client() | ||
| scope = sentry_sdk.get_current_scope() | ||
| messages_data = ( | ||
| truncate_and_annotate_messages( | ||
|
|
@@ -299,18 +313,13 @@ | |
| span.set_attribute(SPANDATA.GEN_AI_AGENT_NAME, graph_name) | ||
|
|
||
| input_messages = None | ||
| if ( | ||
| len(args) > 0 | ||
| and should_send_default_pii() | ||
| and integration.include_prompts | ||
| ): | ||
| if len(args) > 0 and _should_record_inputs(integration): | ||
| input_messages = _parse_langgraph_messages(args[0]) | ||
| if input_messages: | ||
| normalized_input_messages = normalize_message_roles( | ||
| input_messages | ||
| ) | ||
|
|
||
| client = sentry_sdk.get_client() | ||
| scope = sentry_sdk.get_current_scope() | ||
| messages_data = ( | ||
| truncate_and_annotate_messages( | ||
|
|
@@ -345,16 +354,11 @@ | |
| span.set_data(SPANDATA.GEN_AI_OPERATION_NAME, "invoke_agent") | ||
|
|
||
| input_messages = None | ||
| if ( | ||
| len(args) > 0 | ||
| and should_send_default_pii() | ||
| and integration.include_prompts | ||
| ): | ||
| if len(args) > 0 and _should_record_inputs(integration): | ||
| input_messages = _parse_langgraph_messages(args[0]) | ||
| if input_messages: | ||
| normalized_input_messages = normalize_message_roles(input_messages) | ||
|
|
||
| client = sentry_sdk.get_client() | ||
| scope = sentry_sdk.get_current_scope() | ||
| messages_data = ( | ||
| truncate_and_annotate_messages( | ||
|
|
@@ -494,22 +498,22 @@ | |
| _set_usage_data(span, new_messages) | ||
| _set_response_model_name(span, new_messages) | ||
|
|
||
| if not (should_send_default_pii() and integration.include_prompts): | ||
| return | ||
|
|
||
| llm_response_text = _extract_llm_response_text(new_messages) | ||
| if llm_response_text: | ||
| set_data_normalized(span, SPANDATA.GEN_AI_RESPONSE_TEXT, llm_response_text) | ||
| elif new_messages: | ||
| set_data_normalized(span, SPANDATA.GEN_AI_RESPONSE_TEXT, new_messages) | ||
| else: | ||
| set_data_normalized(span, SPANDATA.GEN_AI_RESPONSE_TEXT, result) | ||
|
|
||
| tool_calls = _extract_tool_calls(new_messages) | ||
| if tool_calls: | ||
| set_data_normalized( | ||
| span, | ||
| SPANDATA.GEN_AI_RESPONSE_TOOL_CALLS, | ||
| safe_serialize(tool_calls), | ||
| unpack=False, | ||
| ) | ||
| if _should_record_outputs(integration): | ||
| llm_response_text = _extract_llm_response_text(new_messages) | ||
| if llm_response_text: | ||
| set_data_normalized(span, SPANDATA.GEN_AI_RESPONSE_TEXT, llm_response_text) | ||
| elif new_messages: | ||
| set_data_normalized(span, SPANDATA.GEN_AI_RESPONSE_TEXT, new_messages) | ||
|
Check warning on line 506 in sentry_sdk/integrations/langgraph.py
|
||
|
Comment on lines
+505
to
+506
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Disabling gen_ai.inputs leaks original prompts via gen_ai.response.text fallback When Evidence
Also found at 1 additional location
Identified by Warden · find-bugs · VW6-3TE |
||
| else: | ||
| set_data_normalized(span, SPANDATA.GEN_AI_RESPONSE_TEXT, result) | ||
|
|
||
| # Tool calls are an input to the model, so they're gated on inputs | ||
| if _should_record_inputs(integration): | ||
| tool_calls = _extract_tool_calls(new_messages) | ||
| if tool_calls: | ||
| set_data_normalized( | ||
| span, | ||
| SPANDATA.GEN_AI_RESPONSE_TOOL_CALLS, | ||
| safe_serialize(tool_calls), | ||
| unpack=False, | ||
| ) | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Inputs gate breaks message delta
Medium Severity
Parsing
input_messagesis gated on_should_record_inputs, but those messages are also required by_get_new_messagesto compute the output delta. Withgen_ai.inputsfalse andgen_ai.outputstrue,input_messagesstaysNone, so the full history is treated as new. That can put prior-turn or user input content intogen_ai.response.textand inflate usage totals.Additional Locations (2)
sentry_sdk/integrations/langgraph.py#L256-L258sentry_sdk/integrations/langgraph.py#L315-L357Reviewed by Cursor Bugbot for commit f54e39e. Configure here.