@@ -56,6 +56,12 @@ class SpanType(str, Enum):
5656 AGENT = "AGENT"
5757
5858
59+ SPAN_TYPE_TO_ENTITY_TYPE : Dict [SpanType , str ] = {
60+ SpanType .AGENT : "agent" ,
61+ SpanType .TOOL : "task" ,
62+ }
63+
64+
5965class SpanWrapper :
6066 """
6167 Context manager for tracking observability data for external API calls.
@@ -96,14 +102,20 @@ def __init__(
96102
97103 if isinstance (as_type , SpanType ):
98104 self .attributes ["netra.span.type" ] = as_type .value
105+ self ._entity_type : Optional [str ] = SPAN_TYPE_TO_ENTITY_TYPE .get (as_type )
99106 else :
100107 logger .error ("Invalid span type: %s" , as_type )
108+ self ._entity_type = None
101109 return
102110
103111 def __enter__ (self ) -> "SpanWrapper" :
104112 """Start the span wrapper, begin time tracking, and create OpenTelemetry span."""
105113 self .start_time = time .time ()
106114
115+ # Push entity before span starts so SessionSpanProcessor can capture the name
116+ if self ._entity_type :
117+ SessionManager .push_entity (self ._entity_type , self .name )
118+
107119 # If user provided local blocked patterns in attributes, attach them as baggage
108120 try :
109121 patterns = None
@@ -191,6 +203,10 @@ def __exit__(self, exc_type: Optional[type], exc_val: Optional[Exception], exc_t
191203 finally :
192204 self ._local_block_token = None
193205
206+ # Pop entity from session stack so nested spans get correct parentage
207+ if self ._entity_type :
208+ SessionManager .pop_entity (self ._entity_type )
209+
194210 # Don't suppress exceptions
195211 return False
196212
0 commit comments