Skip to content

feat(langgraph): Gate prompt/response collection on data_collection option - #7175

Open
ericapisani wants to merge 2 commits into
masterfrom
py-2588-langgraph
Open

feat(langgraph): Gate prompt/response collection on data_collection option#7175
ericapisani wants to merge 2 commits into
masterfrom
py-2588-langgraph

Conversation

@ericapisani

Copy link
Copy Markdown
Member

Modify the LangGraph integration to respect the data_collection config for controlling whether prompts, responses, tool calls, and available tools are captured in spans.

When data collection is enabled, the gen_ai.inputs flag controls request messages, tool calls, and available tools, while gen_ai.outputs controls the response text. Tool calls are gated on inputs because they are fed back to the model as input. Available tools are only gated once data collection is configured, since they were never gated on the legacy PII settings.

When data collection is not configured, falls back to legacy send_default_pii and include_prompts settings for compatibility.

Refs PY-2588
Refs #6748

…ption

Modify the LangGraph integration to respect the data_collection config for
controlling whether prompts, responses, tool calls, and available tools are
captured in spans.

When data collection is enabled, the gen_ai.inputs flag controls request
messages, tool calls, and available tools, while gen_ai.outputs controls the
response text. Tool calls are gated on inputs because they are fed back to
the model as input. Available tools are only gated once data collection is
configured, since they were never gated on the legacy PII settings.

When data collection is not configured, falls back to legacy send_default_pii
and include_prompts settings for compatibility.

Refs PY-2588
Refs #6748
@ericapisani
ericapisani requested a review from a team as a code owner August 11, 2026 20:24
@linear-code

linear-code Bot commented Aug 11, 2026

Copy link
Copy Markdown

PY-2588

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit f54e39e. Configure here.

and should_send_default_pii()
and integration.include_prompts
):
if len(args) > 0 and _should_record_inputs(integration):

Copy link
Copy Markdown

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_messages is gated on _should_record_inputs, but those messages are also required by _get_new_messages to compute the output delta. With gen_ai.inputs false and gen_ai.outputs true, input_messages stays None, so the full history is treated as new. That can put prior-turn or user input content into gen_ai.response.text and inflate usage totals.

Additional Locations (2)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit f54e39e. Configure here.

Rename the data collection tests and the invoke span helper so the names state what is being verified, and drop the now-redundant docstrings.
@github-actions

Copy link
Copy Markdown
Contributor

Codecov Results 📊

104618 passed | ⏭️ 6677 skipped | Total: 111295 | Pass Rate: 94% | Execution Time: 366m 57s

📊 Comparison with Base Branch

Metric Change
Total Tests 📈 +216
Passed Tests 📈 +216
Failed Tests
Skipped Tests

All tests are passing successfully.

✅ Patch coverage is 96.67%. Project has 2478 uncovered lines.
✅ Project coverage is 90.16%. Comparing base (base) to head (head).

Files with missing lines (1)
File Patch % Lines
sentry_sdk/integrations/langgraph.py 96.67% ⚠️ 1 Missing and 1 partials
Coverage diff
@@            Coverage Diff             @@
##          main       #PR       +/-##
==========================================
+ Coverage    90.14%    90.16%    +0.02%
==========================================
  Files          193       193         —
  Lines        25183     25192        +9
  Branches      9176      9186       +10
==========================================
+ Hits         22700     22714       +14
- Misses        2483      2478        -5
- Partials      1429      1431        +2

Generated by Codecov Action

Comment on lines +2358 to +2361
True,
False,
True,
id="gen-ai-inputs-disabled-outputs-enabled",

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Disabling gen_ai.inputs still leaks prompts via response collection

When gen_ai.inputs is false and gen_ai.outputs is true, invoke wrappers leave input_messages as None, so _get_new_messages() treats the full result history as new output and can attach user prompts to gen_ai.response.text (especially non-string/multimodal assistant content or the raw-result fallback). Always parse inputs for diffing; only gate writing gen_ai.request.messages.

Evidence
  • In sentry_sdk/integrations/langgraph.py, _wrap_pregel_invoke / _wrap_pregel_ainvoke only call _parse_langgraph_messages(args[0]) when _should_record_inputs() is true; otherwise input_messages stays None.
  • _set_response_attributes() still runs when _should_record_outputs() is true and calls _get_new_messages(input_messages, parsed_response_messages).
  • _get_new_messages() returns the entire output message list when input_messages is falsy, so prior user/system messages are treated as new output.
  • If _extract_llm_response_text() does not find string assistant content, the code sets GEN_AI_RESPONSE_TEXT to that full new_messages list (or raw result), sending prompts despite gen_ai.inputs: false.
  • This independent inputs/outputs split is new; legacy gating tied both to the same PII/include_prompts check, so this path was not reachable before.

Identified by Warden · security-review · WEN-SJ5

Comment on lines +505 to +506
elif new_messages:
set_data_normalized(span, SPANDATA.GEN_AI_RESPONSE_TEXT, new_messages)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The 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 gen_ai.inputs is disabled but gen_ai.outputs is enabled, and the LLM returns a non-text response (e.g. a tool call), the fallback that writes new_messages into gen_ai.response.text serialises the full result state—including the original user prompts that were meant to be withheld.

Evidence
  • _wrap_pregel_invoke parses input_messages only when _should_record_inputs(integration) is True, otherwise passing None into _set_response_attributes.
  • _get_new_messages(None, output_messages) returns the entire result state, not just newly-added messages, because it has no input list to slice against.
  • _extract_llm_response_text returns None for assistant messages whose content is empty or missing (typical for pure tool-call responses).
  • The elif new_messages: branch then writes that full state list into GEN_AI_RESPONSE_TEXT, which includes the original user prompts that gen_ai.inputs=False was intended to suppress.
Also found at 1 additional location
  • tests/integrations/langgraph/test_langgraph.py:2443

Identified by Warden · find-bugs · VW6-3TE

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant