From 66093446139e8b2efa220f341d461d62c2d4f85d Mon Sep 17 00:00:00 2001 From: Mayank Jha Date: Fri, 27 Feb 2026 22:22:42 -0800 Subject: [PATCH 1/2] feat: add internal tenant/account headers for local flow tracing When UIPATH_TRACE_BASE_URL is set (local flow mode), include X-UiPath-Internal-TenantId and X-UiPath-Internal-AccountId headers in LlmOpsHttpExporter requests so the IngestSpans endpoint can identify the tenant and organization. Co-Authored-By: Claude Opus 4.6 --- src/uipath/tracing/_otel_exporters.py | 6 ++++- tests/tracing/test_otel_exporters.py | 38 +++++++++++++++++++++++++++ 2 files changed, 43 insertions(+), 1 deletion(-) diff --git a/src/uipath/tracing/_otel_exporters.py b/src/uipath/tracing/_otel_exporters.py index 033022b07..86f9752d7 100644 --- a/src/uipath/tracing/_otel_exporters.py +++ b/src/uipath/tracing/_otel_exporters.py @@ -122,11 +122,15 @@ def __init__( super().__init__() self.base_url = self._get_base_url() self.auth_token = os.environ.get("UIPATH_ACCESS_TOKEN") - self.headers = { + self.headers: dict[str, str] = { "Content-Type": "application/json", "Authorization": f"Bearer {self.auth_token}", } + if os.environ.get("UIPATH_TRACE_BASE_URL"): + self.headers["X-UiPath-Internal-TenantId"] = os.environ.get("UIPATH_TENANT_ID", "") + self.headers["X-UiPath-Internal-AccountId"] = os.environ.get("UIPATH_ORGANIZATION_ID", "") + client_kwargs = get_httpx_client_kwargs() self.http_client = httpx.Client(**client_kwargs, headers=self.headers) diff --git a/tests/tracing/test_otel_exporters.py b/tests/tracing/test_otel_exporters.py index 8513e829b..53295caa5 100644 --- a/tests/tracing/test_otel_exporters.py +++ b/tests/tracing/test_otel_exporters.py @@ -216,6 +216,44 @@ def test_get_base_url(): assert exporter.base_url == "https://custom-trace.example.com/prefix" +def test_internal_headers_set_when_trace_base_url_present(): + """Test that internal tenant/account headers are set when UIPATH_TRACE_BASE_URL is configured.""" + with patch.dict( + os.environ, + { + "UIPATH_TRACE_BASE_URL": "http://localhost:8888/llmops_", + "UIPATH_ACCESS_TOKEN": "test-token", + "UIPATH_TENANT_ID": "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee", + "UIPATH_ORGANIZATION_ID": "11111111-2222-3333-4444-555555555555", + }, + clear=True, + ): + with patch("uipath.tracing._otel_exporters.httpx.Client"): + exporter = LlmOpsHttpExporter() + + assert exporter.headers["X-UiPath-Internal-TenantId"] == "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee" + assert exporter.headers["X-UiPath-Internal-AccountId"] == "11111111-2222-3333-4444-555555555555" + + +def test_internal_headers_not_set_without_trace_base_url(): + """Test that internal headers are NOT set when UIPATH_TRACE_BASE_URL is absent (cloud mode).""" + with patch.dict( + os.environ, + { + "UIPATH_URL": "https://cloud.uipath.com/org/tenant", + "UIPATH_ACCESS_TOKEN": "test-token", + "UIPATH_TENANT_ID": "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee", + "UIPATH_ORGANIZATION_ID": "11111111-2222-3333-4444-555555555555", + }, + clear=True, + ): + with patch("uipath.tracing._otel_exporters.httpx.Client"): + exporter = LlmOpsHttpExporter() + + assert "X-UiPath-Internal-TenantId" not in exporter.headers + assert "X-UiPath-Internal-AccountId" not in exporter.headers + + def test_send_with_retries_success(): """Test _send_with_retries method with successful response.""" with patch("uipath.tracing._otel_exporters.httpx.Client"): From 831e63360342b979d3a00fbe99d28450c6079044 Mon Sep 17 00:00:00 2001 From: Mayank Jha Date: Fri, 27 Feb 2026 22:33:38 -0800 Subject: [PATCH 2/2] style: fix ruff format line-length violations Co-Authored-By: Claude Opus 4.6 --- src/uipath/tracing/_otel_exporters.py | 8 ++++++-- tests/tracing/test_otel_exporters.py | 10 ++++++++-- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/src/uipath/tracing/_otel_exporters.py b/src/uipath/tracing/_otel_exporters.py index 86f9752d7..fc81b4d4a 100644 --- a/src/uipath/tracing/_otel_exporters.py +++ b/src/uipath/tracing/_otel_exporters.py @@ -128,8 +128,12 @@ def __init__( } if os.environ.get("UIPATH_TRACE_BASE_URL"): - self.headers["X-UiPath-Internal-TenantId"] = os.environ.get("UIPATH_TENANT_ID", "") - self.headers["X-UiPath-Internal-AccountId"] = os.environ.get("UIPATH_ORGANIZATION_ID", "") + self.headers["X-UiPath-Internal-TenantId"] = os.environ.get( + "UIPATH_TENANT_ID", "" + ) + self.headers["X-UiPath-Internal-AccountId"] = os.environ.get( + "UIPATH_ORGANIZATION_ID", "" + ) client_kwargs = get_httpx_client_kwargs() diff --git a/tests/tracing/test_otel_exporters.py b/tests/tracing/test_otel_exporters.py index 53295caa5..a55fa5d60 100644 --- a/tests/tracing/test_otel_exporters.py +++ b/tests/tracing/test_otel_exporters.py @@ -231,8 +231,14 @@ def test_internal_headers_set_when_trace_base_url_present(): with patch("uipath.tracing._otel_exporters.httpx.Client"): exporter = LlmOpsHttpExporter() - assert exporter.headers["X-UiPath-Internal-TenantId"] == "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee" - assert exporter.headers["X-UiPath-Internal-AccountId"] == "11111111-2222-3333-4444-555555555555" + assert ( + exporter.headers["X-UiPath-Internal-TenantId"] + == "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee" + ) + assert ( + exporter.headers["X-UiPath-Internal-AccountId"] + == "11111111-2222-3333-4444-555555555555" + ) def test_internal_headers_not_set_without_trace_base_url():