diff --git a/src/uipath/tracing/_live_tracking_processor.py b/src/uipath/tracing/_live_tracking_processor.py index 6ca3cb307..2e8bdf41e 100644 --- a/src/uipath/tracing/_live_tracking_processor.py +++ b/src/uipath/tracing/_live_tracking_processor.py @@ -57,7 +57,7 @@ def _upsert_span_async( def _upsert(): try: - if status_override: + if status_override is not None: self.exporter.upsert_span(span, status_override=status_override) else: self.exporter.upsert_span(span) diff --git a/src/uipath/tracing/_otel_exporters.py b/src/uipath/tracing/_otel_exporters.py index a47c3acd1..15052fa05 100644 --- a/src/uipath/tracing/_otel_exporters.py +++ b/src/uipath/tracing/_otel_exporters.py @@ -326,28 +326,32 @@ def _process_span_attributes(self, span_data: Dict[str, Any]) -> None: else: return - # Determine SpanType - if "openinference.span.kind" in attributes: + # Determine SpanType from OpenInference spans + is_openinference = "openinference.span.kind" in attributes + if is_openinference: span_type = attributes["openinference.span.kind"] span_data["SpanType"] = self.SPAN_TYPE_MAPPING.get(span_type, span_type) - # Apply basic attribute mapping - for old_key, mapping in self.ATTRIBUTE_MAPPING.items(): - if old_key in attributes: - if isinstance(mapping, tuple): - new_key, func = mapping - attributes[new_key] = func(attributes[old_key]) - else: - new_key = mapping - attributes[new_key] = attributes[old_key] - - # Apply detailed mapping based on SpanType - # Modify attributes dict in place to avoid allocations - span_type = span_data.get("SpanType") - if span_type == "completion": - self._map_llm_call_attributes(attributes) - elif span_type == "toolCall": - self._map_tool_call_attributes(attributes) + # Apply basic attribute mapping (only for OpenInference spans) + if is_openinference: + for old_key, mapping in self.ATTRIBUTE_MAPPING.items(): + if old_key in attributes: + if isinstance(mapping, tuple): + new_key, func = mapping + attributes[new_key] = func(attributes[old_key]) + else: + new_key = mapping + attributes[new_key] = attributes[old_key] + + # Apply detailed mapping based on SpanType (only for OpenInference spans) + # These mappings convert OpenInference-format attributes to UiPath format. + # Agent manual spans (from UiPathTracer) already have correctly formatted attributes. + if is_openinference: + span_type = span_data.get("SpanType") + if span_type == "completion": + self._map_llm_call_attributes(attributes) + elif span_type == "toolCall": + self._map_tool_call_attributes(attributes) # Parse JSON-encoded strings that should be objects (avoids double-encoding) # OTEL only accepts primitives, so agents serialize dicts to JSON strings. diff --git a/src/uipath/tracing/_utils.py b/src/uipath/tracing/_utils.py index 448648067..0e84f25be 100644 --- a/src/uipath/tracing/_utils.py +++ b/src/uipath/tracing/_utils.py @@ -276,7 +276,7 @@ def otel_span_to_uipath_span( reference_id = attributes_dict.get("referenceId") # Source: override via uipath.source attribute, else DEFAULT_SOURCE - uipath_source = attributes_dict.get("uipath.source") + uipath_source = attributes_dict.get("uipath.source", attributes_dict.get("source")) source = uipath_source if isinstance(uipath_source, int) else DEFAULT_SOURCE attachments = None