@@ -28,10 +28,14 @@ def __init__(self, include_prompts=True):
2828 @staticmethod
2929 def setup_once ():
3030 # type: () -> None
31- # Wrap StateGraph methods - these get called when the graph is compiled
31+ # LangGraph lets users create agents using a StateGraph or the Functional API.
32+ # StateGraphs are then compiled to a CompiledStateGraph. Both CompiledStateGraph and
33+ # the functional API execute on a Pregel instance. Pregel is the runtime for the graph
34+ # and the invocation happens on Pregel, so patching the invoke methods takes care of both.
35+ # The streaming methods are not patched, because due to some internal reasons, LangGraph
36+ # will automatically patch the streaming methods to run through invoke, and by doing this
37+ # we prevent duplicate spans for invocations.
3238 StateGraph .compile = _wrap_state_graph_compile (StateGraph .compile )
33-
34- # Wrap Pregel methods - these are the actual execution methods on compiled graphs
3539 if hasattr (Pregel , "invoke" ):
3640 Pregel .invoke = _wrap_pregel_invoke (Pregel .invoke )
3741 if hasattr (Pregel , "ainvoke" ):
@@ -40,12 +44,6 @@ def setup_once():
4044
4145def _get_graph_name (graph_obj ):
4246 # type: (Any) -> Optional[str]
43- """Extract graph name from various possible attributes."""
44- # Check for Sentry-specific agent name first
45- if hasattr (graph_obj , "_sentry_agent_name" ):
46- return graph_obj ._sentry_agent_name
47-
48- # Try to get name from different possible attributes
4947 for attr in ["name" , "graph_name" , "__name__" , "_name" ]:
5048 if hasattr (graph_obj , attr ):
5149 name = getattr (graph_obj , attr )
@@ -54,41 +52,8 @@ def _get_graph_name(graph_obj):
5452 return None
5553
5654
57- def _get_graph_metadata (graph_obj ):
58- # type: (Any) -> tuple[Optional[str], Optional[List[str]]]
59- """Extract graph name and node names if available."""
60- graph_name = _get_graph_name (graph_obj )
61-
62- # Try to get node names from the graph
63- node_names = None
64- if hasattr (graph_obj , "nodes" ):
65- try :
66- nodes = graph_obj .nodes
67- if isinstance (nodes , dict ):
68- node_names = list (nodes .keys ())
69- elif hasattr (nodes , "__iter__" ):
70- node_names = list (nodes )
71- except Exception :
72- pass
73- elif hasattr (graph_obj , "graph" ) and hasattr (graph_obj .graph , "nodes" ):
74- try :
75- nodes = graph_obj .graph .nodes
76- if isinstance (nodes , dict ):
77- node_names = list (nodes .keys ())
78- elif hasattr (nodes , "__iter__" ):
79- node_names = list (nodes )
80- except Exception :
81- pass
82-
83- return graph_name , node_names
84-
85-
8655def _parse_langgraph_messages (state ):
8756 # type: (Any) -> Optional[List[Any]]
88- role_map = {
89- "human" : "user" ,
90- "ai" : "assistant" ,
91- }
9257 if not state :
9358 return None
9459
@@ -110,33 +75,15 @@ def _parse_langgraph_messages(state):
11075 normalized_messages = []
11176 for message in messages :
11277 try :
113- if isinstance (message , dict ):
114- role = message .get ("role" ) or message .get ("type" )
115- if role in role_map :
116- message = dict (message )
117- message ["role" ] = role_map [role ]
118- normalized_messages .append (message )
119- elif hasattr (message , "type" ) and hasattr (message , "content" ):
120- role = getattr (message , "type" , None )
121- mapped_role = role_map .get (role , role )
122- parsed = {"role" : mapped_role , "content" : message .content }
123- if hasattr (message , "additional_kwargs" ):
124- parsed .update (message .additional_kwargs )
125- normalized_messages .append (parsed )
126- elif hasattr (message , "role" ) and hasattr (message , "content" ):
127- role = getattr (message , "role" , None )
128- mapped_role = role_map .get (role , role )
129- parsed = {"role" : mapped_role , "content" : message .content }
78+ if hasattr (message , "content" ):
79+ parsed = {"content" : message .content }
13080 for attr in ["name" , "tool_calls" , "function_call" ]:
13181 if hasattr (message , attr ):
13282 value = getattr (message , attr )
13383 if value is not None :
13484 parsed [attr ] = value
13585 normalized_messages .append (parsed )
136- elif hasattr (message , "__dict__" ):
137- normalized_messages .append (vars (message ))
138- else :
139- normalized_messages .append ({"content" : str (message )})
86+
14087 except Exception :
14188 continue
14289
@@ -158,7 +105,6 @@ def new_compile(self, *args, **kwargs):
158105 name = "create_agent" ,
159106 origin = LanggraphIntegration .origin ,
160107 ) as span :
161- # import ipdb; ipdb.set_trace()
162108 span .set_data (SPANDATA .GEN_AI_OPERATION_NAME , "create_agent" )
163109 span .set_data (
164110 SPANDATA .GEN_AI_AGENT_NAME , getattr (compiled_graph , "name" , None )
@@ -176,9 +122,6 @@ def new_compile(self, *args, **kwargs):
176122 if data and hasattr (data , "tools_by_name" ):
177123 tools = list (data .tools_by_name .keys ())
178124 span .set_data (SPANDATA .GEN_AI_REQUEST_AVAILABLE_TOOLS , tools )
179- compiled_graph = f (self , * args , ** kwargs )
180- if hasattr (self , "__dict__" ):
181- compiled_graph ._sentry_source_graph = self
182125 return compiled_graph
183126
184127 return new_compile
@@ -194,7 +137,7 @@ def new_invoke(self, *args, **kwargs):
194137 if integration is None :
195138 return f (self , * args , ** kwargs )
196139
197- graph_name , node_names = _get_graph_metadata (self )
140+ graph_name = _get_graph_name (self )
198141
199142 with sentry_sdk .start_span (
200143 op = OP .GEN_AI_INVOKE_AGENT ,
@@ -258,18 +201,13 @@ async def new_ainvoke(self, *args, **kwargs):
258201 if integration is None :
259202 return await f (self , * args , ** kwargs )
260203
261- graph_name , node_names = _get_graph_metadata (self )
204+ graph_name = _get_graph_name (self )
262205
263206 with sentry_sdk .start_span (
264207 op = OP .GEN_AI_INVOKE_AGENT ,
265- name = (
266- f"invoke_agent ainvoke { graph_name } " .strip ()
267- if graph_name
268- else "invoke_agent"
269- ),
208+ name = "invoke_agent" ,
270209 origin = LanggraphIntegration .origin ,
271210 ) as span :
272- # Set agent metadata
273211 if graph_name :
274212 set_ai_pipeline_name (graph_name )
275213 span .set_data (SPANDATA .GEN_AI_PIPELINE_NAME , graph_name )
@@ -278,7 +216,6 @@ async def new_ainvoke(self, *args, **kwargs):
278216 span .set_data (SPANDATA .GEN_AI_OPERATION_NAME , "invoke_agent" )
279217 span .set_data (SPANDATA .GEN_AI_RESPONSE_STREAMING , False )
280218
281- # Capture input messages if PII is allowed
282219 if (
283220 len (args ) > 0
284221 and should_send_default_pii ()
0 commit comments