Skip to content

Commit 23ec398

Browse files
authored
fix(ai): add message truncation to langgraph (#4954)
1 parent cc432a6 commit 23ec398

File tree

2 files changed

+82
-11
lines changed

2 files changed

+82
-11
lines changed

sentry_sdk/integrations/langgraph.py

Lines changed: 25 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,11 @@
22
from typing import Any, Callable, List, Optional
33

44
import sentry_sdk
5-
from sentry_sdk.ai.utils import set_data_normalized, normalize_message_roles
5+
from sentry_sdk.ai.utils import (
6+
set_data_normalized,
7+
normalize_message_roles,
8+
truncate_and_annotate_messages,
9+
)
610
from sentry_sdk.consts import OP, SPANDATA
711
from sentry_sdk.integrations import DidNotEnable, Integration
812
from sentry_sdk.scope import should_send_default_pii
@@ -181,12 +185,17 @@ def new_invoke(self, *args, **kwargs):
181185
input_messages = _parse_langgraph_messages(args[0])
182186
if input_messages:
183187
normalized_input_messages = normalize_message_roles(input_messages)
184-
set_data_normalized(
185-
span,
186-
SPANDATA.GEN_AI_REQUEST_MESSAGES,
187-
normalized_input_messages,
188-
unpack=False,
188+
scope = sentry_sdk.get_current_scope()
189+
messages_data = truncate_and_annotate_messages(
190+
normalized_input_messages, span, scope
189191
)
192+
if messages_data is not None:
193+
set_data_normalized(
194+
span,
195+
SPANDATA.GEN_AI_REQUEST_MESSAGES,
196+
messages_data,
197+
unpack=False,
198+
)
190199

191200
result = f(self, *args, **kwargs)
192201

@@ -232,12 +241,17 @@ async def new_ainvoke(self, *args, **kwargs):
232241
input_messages = _parse_langgraph_messages(args[0])
233242
if input_messages:
234243
normalized_input_messages = normalize_message_roles(input_messages)
235-
set_data_normalized(
236-
span,
237-
SPANDATA.GEN_AI_REQUEST_MESSAGES,
238-
normalized_input_messages,
239-
unpack=False,
244+
scope = sentry_sdk.get_current_scope()
245+
messages_data = truncate_and_annotate_messages(
246+
normalized_input_messages, span, scope
240247
)
248+
if messages_data is not None:
249+
set_data_normalized(
250+
span,
251+
SPANDATA.GEN_AI_REQUEST_MESSAGES,
252+
messages_data,
253+
unpack=False,
254+
)
241255

242256
result = await f(self, *args, **kwargs)
243257

tests/integrations/langgraph/test_langgraph.py

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -696,3 +696,60 @@ def __init__(self, content, message_type="human"):
696696
# Verify no "ai" roles remain
697697
roles = [msg["role"] for msg in stored_messages if "role" in msg]
698698
assert "ai" not in roles
699+
700+
701+
def test_langgraph_message_truncation(sentry_init, capture_events):
702+
"""Test that large messages are truncated properly in Langgraph integration."""
703+
import json
704+
705+
sentry_init(
706+
integrations=[LanggraphIntegration(include_prompts=True)],
707+
traces_sample_rate=1.0,
708+
send_default_pii=True,
709+
)
710+
events = capture_events()
711+
712+
large_content = (
713+
"This is a very long message that will exceed our size limits. " * 1000
714+
)
715+
test_state = {
716+
"messages": [
717+
MockMessage("small message 1", name="user"),
718+
MockMessage(large_content, name="assistant"),
719+
MockMessage(large_content, name="user"),
720+
MockMessage("small message 4", name="assistant"),
721+
MockMessage("small message 5", name="user"),
722+
]
723+
}
724+
725+
pregel = MockPregelInstance("test_graph")
726+
727+
def original_invoke(self, *args, **kwargs):
728+
return {"messages": args[0].get("messages", [])}
729+
730+
with start_transaction():
731+
wrapped_invoke = _wrap_pregel_invoke(original_invoke)
732+
result = wrapped_invoke(pregel, test_state)
733+
734+
assert result is not None
735+
assert len(events) > 0
736+
tx = events[0]
737+
assert tx["type"] == "transaction"
738+
739+
invoke_spans = [
740+
span for span in tx.get("spans", []) if span.get("op") == OP.GEN_AI_INVOKE_AGENT
741+
]
742+
assert len(invoke_spans) > 0
743+
744+
invoke_span = invoke_spans[0]
745+
assert SPANDATA.GEN_AI_REQUEST_MESSAGES in invoke_span["data"]
746+
747+
messages_data = invoke_span["data"][SPANDATA.GEN_AI_REQUEST_MESSAGES]
748+
assert isinstance(messages_data, str)
749+
750+
parsed_messages = json.loads(messages_data)
751+
assert isinstance(parsed_messages, list)
752+
assert len(parsed_messages) == 2
753+
assert "small message 4" in str(parsed_messages[0])
754+
assert "small message 5" in str(parsed_messages[1])
755+
assert tx["_meta"]["spans"]["0"]["data"]["gen_ai.request.messages"][""]["len"] == 5

0 commit comments

Comments
 (0)