1+ import contextvars
12import itertools
23from collections import OrderedDict
34from functools import wraps
7273}
7374
7475
76+ # Contextvar to track agent names in a stack for re-entrant agent support
77+ _agent_stack = contextvars .ContextVar ("langchain_agent_stack" , default = None )
78+
79+
80+ def _push_agent (agent_name ):
81+ # type: (Optional[str]) -> None
82+ """Push an agent name onto the stack."""
83+ stack = _agent_stack .get ()
84+ if stack is None :
85+ stack = []
86+ stack .append (agent_name )
87+ _agent_stack .set (stack )
88+
89+
90+ def _pop_agent ():
91+ # type: () -> Optional[str]
92+ """Pop an agent name from the stack and return it."""
93+ stack = _agent_stack .get ()
94+ if stack and len (stack ) > 0 :
95+ agent_name = stack .pop ()
96+ _agent_stack .set (stack )
97+ return agent_name
98+ return None
99+
100+
101+ def _get_current_agent ():
102+ # type: () -> Optional[str]
103+ """Get the current agent name (top of stack) without removing it."""
104+ stack = _agent_stack .get ()
105+ if stack and len (stack ) > 0 :
106+ return stack [- 1 ]
107+ return None
108+
109+
75110class LangchainIntegration (Integration ):
76111 identifier = "langchain"
77112 origin = f"auto.ai.{ identifier } "
@@ -276,11 +311,7 @@ def on_chat_model_start(self, serialized, messages, *, run_id, **kwargs):
276311 elif "openai" in ai_type :
277312 span .set_data (SPANDATA .GEN_AI_SYSTEM , "openai" )
278313
279- agent_name = (
280- sentry_sdk .get_current_scope ()
281- ._contexts .get ("langchain_agent" , {})
282- .get ("agent_name" )
283- )
314+ agent_name = _get_current_agent ()
284315 if agent_name :
285316 span .set_data (SPANDATA .GEN_AI_AGENT_NAME , agent_name )
286317
@@ -436,11 +467,7 @@ def on_tool_start(self, serialized, input_str, *, run_id, **kwargs):
436467 if tool_description is not None :
437468 span .set_data (SPANDATA .GEN_AI_TOOL_DESCRIPTION , tool_description )
438469
439- agent_name = (
440- sentry_sdk .get_current_scope ()
441- ._contexts .get ("langchain_agent" , {})
442- .get ("agent_name" )
443- )
470+ agent_name = _get_current_agent ()
444471 if agent_name :
445472 span .set_data (SPANDATA .GEN_AI_AGENT_NAME , agent_name )
446473
@@ -772,9 +799,7 @@ def new_invoke(self, *args, **kwargs):
772799 name = f"invoke_agent { agent_name } " if agent_name else "invoke_agent" ,
773800 origin = LangchainIntegration .origin ,
774801 ) as span :
775- sentry_sdk .get_current_scope ().set_context (
776- "langchain_agent" , {"agent_name" : agent_name , "tools" : tools }
777- )
802+ _push_agent (agent_name )
778803 if agent_name :
779804 span .set_data (SPANDATA .GEN_AI_AGENT_NAME , agent_name )
780805
@@ -813,7 +838,7 @@ def new_invoke(self, *args, **kwargs):
813838 ):
814839 set_data_normalized (span , SPANDATA .GEN_AI_RESPONSE_TEXT , output )
815840
816- sentry_sdk . get_current_scope (). remove_context ( "langchain_agent" )
841+ _pop_agent ( )
817842
818843 return result
819844
@@ -840,9 +865,7 @@ def new_stream(self, *args, **kwargs):
840865 )
841866 span .__enter__ ()
842867
843- sentry_sdk .get_current_scope ().set_context (
844- "langchain_agent" , {"agent_name" : agent_name , "tools" : tools }
845- )
868+ _push_agent (agent_name )
846869
847870 if agent_name :
848871 span .set_data (SPANDATA .GEN_AI_AGENT_NAME , agent_name )
@@ -893,7 +916,7 @@ def new_iterator():
893916 ):
894917 set_data_normalized (span , SPANDATA .GEN_AI_RESPONSE_TEXT , output )
895918
896- sentry_sdk . get_current_scope (). remove_context ( "langchain_agent" )
919+ _pop_agent ( )
897920
898921 span .__exit__ (None , None , None )
899922
@@ -914,7 +937,7 @@ async def new_iterator_async():
914937 ):
915938 set_data_normalized (span , SPANDATA .GEN_AI_RESPONSE_TEXT , output )
916939
917- sentry_sdk . get_current_scope (). remove_context ( "langchain_agent" )
940+ _pop_agent ( )
918941
919942 span .__exit__ (None , None , None )
920943
0 commit comments