Skip to content

Commit 885f4e9

Browse files
feat(tracing): derive LLM Ops URL source param from span Source field
Previously the source query parameter in the LLM Ops API URL was hardcoded to "Robots". Now it reads the Source field from the span data (set via uipath.source attribute) and maps it to the correct SourceEnum string name, defaulting to "Robots" if missing. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 6a64b4c commit 885f4e9

3 files changed

Lines changed: 62 additions & 1 deletion

File tree

packages/uipath-platform/src/uipath/platform/common/_span_utils.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,17 @@
1818
# SourceEnum.Robots = 4 (default for Python SDK / coded agents)
1919
DEFAULT_SOURCE = 4
2020

21+
SOURCE_NAMES: dict[int, str] = {
22+
0: "Testing",
23+
1: "Agents",
24+
2: "ProcessOrchestration",
25+
3: "ApiWorkflows",
26+
4: "Robots",
27+
5: "ConversationalAgentsService",
28+
6: "IntegrationServiceTrigger",
29+
7: "Playground",
30+
}
31+
2132

2233
class AttachmentProvider(IntEnum):
2334
ORCHESTRATOR = 0

packages/uipath/src/uipath/tracing/_otel_exporters.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313

1414
from uipath._utils._ssl_context import get_httpx_client_kwargs
1515
from uipath.platform.common import _SpanUtils
16+
from uipath.platform.common._span_utils import DEFAULT_SOURCE, SOURCE_NAMES
1617
from uipath.platform.common.retry import NON_RETRYABLE_STATUS_CODES
1718

1819
logger = logging.getLogger(__name__)
@@ -389,7 +390,11 @@ def _process_span_attributes(self, span_data: Dict[str, Any]) -> None:
389390
def _build_url(self, span_list: list[Dict[str, Any]]) -> str:
390391
"""Construct the URL for the API request."""
391392
trace_id = str(span_list[0]["TraceId"])
392-
return f"{self.base_url}/api/Traces/spans?traceId={trace_id}&source=Robots"
393+
source_int = span_list[0].get("Source", DEFAULT_SOURCE)
394+
source_name = SOURCE_NAMES.get(source_int, "Robots")
395+
return (
396+
f"{self.base_url}/api/Traces/spans?traceId={trace_id}&source={source_name}"
397+
)
393398

394399
def _send_with_retries(
395400
self, url: str, payload: list[Dict[str, Any]], max_retries: int = 4

packages/uipath/tests/tracing/test_otel_exporters.py

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -216,6 +216,51 @@ def test_get_base_url():
216216
assert exporter.base_url == "https://custom-trace.example.com/prefix"
217217

218218

219+
def test_build_url_uses_span_source():
220+
"""Test _build_url derives source query param from span's Source field."""
221+
with (
222+
patch("uipath.tracing._otel_exporters.httpx.Client"),
223+
patch.dict(os.environ, {"UIPATH_ACCESS_TOKEN": "t"}, clear=True),
224+
):
225+
exporter = LlmOpsHttpExporter()
226+
exporter.base_url = "https://example.com/llmops"
227+
228+
# Source=1 (Agents)
229+
url = exporter._build_url([{"TraceId": "abc", "Source": 1}])
230+
assert (
231+
url
232+
== "https://example.com/llmops/api/Traces/spans?traceId=abc&source=Agents"
233+
)
234+
235+
# Source=4 (Robots) - default
236+
url = exporter._build_url([{"TraceId": "abc", "Source": 4}])
237+
assert (
238+
url
239+
== "https://example.com/llmops/api/Traces/spans?traceId=abc&source=Robots"
240+
)
241+
242+
# Missing Source defaults to Robots
243+
url = exporter._build_url([{"TraceId": "abc"}])
244+
assert (
245+
url
246+
== "https://example.com/llmops/api/Traces/spans?traceId=abc&source=Robots"
247+
)
248+
249+
# Source=7 (Playground)
250+
url = exporter._build_url([{"TraceId": "abc", "Source": 7}])
251+
assert (
252+
url
253+
== "https://example.com/llmops/api/Traces/spans?traceId=abc&source=Playground"
254+
)
255+
256+
# Unknown source int falls back to Robots
257+
url = exporter._build_url([{"TraceId": "abc", "Source": 99}])
258+
assert (
259+
url
260+
== "https://example.com/llmops/api/Traces/spans?traceId=abc&source=Robots"
261+
)
262+
263+
219264
def test_internal_headers_set_when_trace_base_url_present():
220265
"""Test that internal tenant/account headers are set when UIPATH_TRACE_BASE_URL is configured."""
221266
with patch.dict(

0 commit comments

Comments
 (0)