From af5681967263ca7539ecc4901fbde4c8ef8ecdee Mon Sep 17 00:00:00 2001 From: Clement Fauchere Date: Wed, 1 Apr 2026 11:36:48 -0500 Subject: [PATCH 1/7] feat(platform): inject x-uipath-traceparent-id header on all outbound HTTP requests Adds UiPath trace context propagation to BaseService so every outbound HTTP call (ECS, Orchestrator, LLM Gateway, etc.) carries the x-uipath-traceparent-id header with the active OTEL trace/span IDs. This enables downstream services to correlate requests back to agent traces in App Insights, which is critical for debugging failures like "DeepRAG content not available" where today there is no way to link the agent trace to the CG service logs. Header format follows UiPath convention (per TraceView client SDK spec): x-uipath-traceparent-id: 00-{trace_id}-{span_id}-01 Co-Authored-By: Claude Opus 4.6 (1M context) --- .../src/uipath/platform/common/_base_service.py | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/packages/uipath-platform/src/uipath/platform/common/_base_service.py b/packages/uipath-platform/src/uipath/platform/common/_base_service.py index 41b90011d..57fca7a68 100644 --- a/packages/uipath-platform/src/uipath/platform/common/_base_service.py +++ b/packages/uipath-platform/src/uipath/platform/common/_base_service.py @@ -3,6 +3,8 @@ from logging import getLogger from typing import Any, Literal, Union +from opentelemetry import trace + from httpx import ( URL, AsyncClient, @@ -61,6 +63,19 @@ def _get_caller_component() -> str: return "" +_TRACE_PARENT_HEADER = "x-uipath-traceparent-id" + + +def _inject_trace_context(headers: dict[str, str]) -> None: + """Inject UiPath trace context header from the active OTEL span.""" + span = trace.get_current_span() + ctx = span.get_span_context() + if ctx.trace_id and ctx.span_id: + trace_id = format(ctx.trace_id, "032x") + span_id = format(ctx.span_id, "016x") + headers[_TRACE_PARENT_HEADER] = f"00-{trace_id}-{span_id}-01" + + class BaseService: def __init__( self, config: UiPathApiConfig, execution_context: UiPathExecutionContext @@ -106,6 +121,7 @@ def request( kwargs.setdefault("headers", {}) kwargs["headers"][HEADER_USER_AGENT] = user_agent_value(specific_component) + _inject_trace_context(kwargs["headers"]) override = resolve_service_url(str(url)) if override: @@ -150,6 +166,7 @@ async def request_async( kwargs["headers"][HEADER_USER_AGENT] = user_agent_value( self._specific_component ) + _inject_trace_context(kwargs["headers"]) override = resolve_service_url(str(url)) if override: From f7ff305e4a4753e1068f19c36766baa97070f335 Mon Sep 17 00:00:00 2001 From: Clement Fauchere Date: Wed, 1 Apr 2026 11:44:40 -0500 Subject: [PATCH 2/7] fix: move opentelemetry import to correct group for ruff import sorting Co-Authored-By: Claude Opus 4.6 (1M context) --- .../src/uipath/platform/common/_base_service.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/uipath-platform/src/uipath/platform/common/_base_service.py b/packages/uipath-platform/src/uipath/platform/common/_base_service.py index 57fca7a68..f86fca6a3 100644 --- a/packages/uipath-platform/src/uipath/platform/common/_base_service.py +++ b/packages/uipath-platform/src/uipath/platform/common/_base_service.py @@ -3,8 +3,6 @@ from logging import getLogger from typing import Any, Literal, Union -from opentelemetry import trace - from httpx import ( URL, AsyncClient, @@ -13,6 +11,7 @@ HTTPStatusError, Response, ) +from opentelemetry import trace from tenacity import ( retry, retry_if_exception, From 42fe785e03570434d7989dcaceee3816ddb440f4 Mon Sep 17 00:00:00 2001 From: Clement Fauchere Date: Wed, 1 Apr 2026 12:24:45 -0500 Subject: [PATCH 3/7] fix: use opentelemetry format_trace_id/format_span_id helpers Co-Authored-By: Claude Opus 4.6 (1M context) --- .../src/uipath/platform/common/_base_service.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/packages/uipath-platform/src/uipath/platform/common/_base_service.py b/packages/uipath-platform/src/uipath/platform/common/_base_service.py index f86fca6a3..1b7f0bbd1 100644 --- a/packages/uipath-platform/src/uipath/platform/common/_base_service.py +++ b/packages/uipath-platform/src/uipath/platform/common/_base_service.py @@ -12,6 +12,7 @@ Response, ) from opentelemetry import trace +from opentelemetry.trace import format_span_id, format_trace_id from tenacity import ( retry, retry_if_exception, @@ -70,9 +71,7 @@ def _inject_trace_context(headers: dict[str, str]) -> None: span = trace.get_current_span() ctx = span.get_span_context() if ctx.trace_id and ctx.span_id: - trace_id = format(ctx.trace_id, "032x") - span_id = format(ctx.span_id, "016x") - headers[_TRACE_PARENT_HEADER] = f"00-{trace_id}-{span_id}-01" + headers[_TRACE_PARENT_HEADER] = f"00-{format_trace_id(ctx.trace_id)}-{format_span_id(ctx.span_id)}-01" class BaseService: From 9f9c0f1f6ca25d2c608dc34adac6fd8de07170b7 Mon Sep 17 00:00:00 2001 From: Clement Fauchere Date: Wed, 1 Apr 2026 12:30:20 -0500 Subject: [PATCH 4/7] fix: ruff format _base_service.py Co-Authored-By: Claude Opus 4.6 (1M context) --- .../src/uipath/platform/common/_base_service.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/uipath-platform/src/uipath/platform/common/_base_service.py b/packages/uipath-platform/src/uipath/platform/common/_base_service.py index 1b7f0bbd1..d236e4ef5 100644 --- a/packages/uipath-platform/src/uipath/platform/common/_base_service.py +++ b/packages/uipath-platform/src/uipath/platform/common/_base_service.py @@ -71,7 +71,9 @@ def _inject_trace_context(headers: dict[str, str]) -> None: span = trace.get_current_span() ctx = span.get_span_context() if ctx.trace_id and ctx.span_id: - headers[_TRACE_PARENT_HEADER] = f"00-{format_trace_id(ctx.trace_id)}-{format_span_id(ctx.span_id)}-01" + headers[_TRACE_PARENT_HEADER] = ( + f"00-{format_trace_id(ctx.trace_id)}-{format_span_id(ctx.span_id)}-01" + ) class BaseService: From a7653a88f9549dbfa4bac1c791c5361df0514a73 Mon Sep 17 00:00:00 2001 From: Clement Fauchere Date: Wed, 1 Apr 2026 16:58:21 -0500 Subject: [PATCH 5/7] chore: bump version to 0.1.18, update lockfiles Co-Authored-By: Claude Opus 4.6 (1M context) --- .vscode/launch.json | 18 +++++++++++------- packages/uipath-platform/pyproject.toml | 2 +- .../uipath/platform/common/_base_service.py | 3 +++ packages/uipath-platform/uv.lock | 2 +- packages/uipath/uv.lock | 2 +- 5 files changed, 17 insertions(+), 10 deletions(-) diff --git a/.vscode/launch.json b/.vscode/launch.json index 3a80f747c..71d9ed3dc 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -2,13 +2,17 @@ "version": "0.2.0", "configurations": [ { - "name": "Python Debugger: Attach", + "name": "Python: UiPath Agent", "type": "debugpy", - "request": "attach", - "connect": { - "host": "localhost", - "port": 5678 - } + "request": "launch", + "module": "uipath", + "args": [ + "run", + "agent.json", + "{}" + ], + "console": "integratedTerminal", + "justMyCode": false } ] -} +} \ No newline at end of file diff --git a/packages/uipath-platform/pyproject.toml b/packages/uipath-platform/pyproject.toml index c5cdf13ee..ba5634ef1 100644 --- a/packages/uipath-platform/pyproject.toml +++ b/packages/uipath-platform/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "uipath-platform" -version = "0.1.17" +version = "0.1.18" description = "HTTP client library for programmatic access to UiPath Platform" readme = { file = "README.md", content-type = "text/markdown" } requires-python = ">=3.11" diff --git a/packages/uipath-platform/src/uipath/platform/common/_base_service.py b/packages/uipath-platform/src/uipath/platform/common/_base_service.py index d236e4ef5..8ebba3711 100644 --- a/packages/uipath-platform/src/uipath/platform/common/_base_service.py +++ b/packages/uipath-platform/src/uipath/platform/common/_base_service.py @@ -67,6 +67,7 @@ def _get_caller_component() -> str: def _inject_trace_context(headers: dict[str, str]) -> None: + """Inject UiPath trace context header from the active OTEL span.""" span = trace.get_current_span() ctx = span.get_span_context() @@ -75,6 +76,8 @@ def _inject_trace_context(headers: dict[str, str]) -> None: f"00-{format_trace_id(ctx.trace_id)}-{format_span_id(ctx.span_id)}-01" ) + print(f"DEBUG: Injecting {_TRACE_PARENT_HEADER} = {headers[_TRACE_PARENT_HEADER]}") + class BaseService: def __init__( diff --git a/packages/uipath-platform/uv.lock b/packages/uipath-platform/uv.lock index 4360ed46b..0ea4a2f63 100644 --- a/packages/uipath-platform/uv.lock +++ b/packages/uipath-platform/uv.lock @@ -1088,7 +1088,7 @@ dev = [ [[package]] name = "uipath-platform" -version = "0.1.17" +version = "0.1.18" source = { editable = "." } dependencies = [ { name = "httpx" }, diff --git a/packages/uipath/uv.lock b/packages/uipath/uv.lock index 41ecc6a40..77434aaa8 100644 --- a/packages/uipath/uv.lock +++ b/packages/uipath/uv.lock @@ -2682,7 +2682,7 @@ dev = [ [[package]] name = "uipath-platform" -version = "0.1.17" +version = "0.1.18" source = { editable = "../uipath-platform" } dependencies = [ { name = "httpx" }, From 1357dec835a586b1ff374d8093fbe9966b492470 Mon Sep 17 00:00:00 2001 From: Clement Fauchere Date: Wed, 1 Apr 2026 17:02:20 -0500 Subject: [PATCH 6/7] fix: remove accidentally committed .vscode/launch.json Co-Authored-By: Claude Opus 4.6 (1M context) --- .vscode/launch.json | 18 ------------------ 1 file changed, 18 deletions(-) delete mode 100644 .vscode/launch.json diff --git a/.vscode/launch.json b/.vscode/launch.json deleted file mode 100644 index 71d9ed3dc..000000000 --- a/.vscode/launch.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "version": "0.2.0", - "configurations": [ - { - "name": "Python: UiPath Agent", - "type": "debugpy", - "request": "launch", - "module": "uipath", - "args": [ - "run", - "agent.json", - "{}" - ], - "console": "integratedTerminal", - "justMyCode": false - } - ] -} \ No newline at end of file From 0c8254a88054866848e97b39df5faf646fe103f8 Mon Sep 17 00:00:00 2001 From: Clement Fauchere Date: Wed, 1 Apr 2026 17:07:42 -0500 Subject: [PATCH 7/7] fix: restore .vscode/launch.json to match main Co-Authored-By: Claude Opus 4.6 (1M context) --- .vscode/launch.json | 14 ++++++++++++++ .../src/uipath/platform/common/_base_service.py | 3 --- 2 files changed, 14 insertions(+), 3 deletions(-) create mode 100644 .vscode/launch.json diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 000000000..3a80f747c --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,14 @@ +{ + "version": "0.2.0", + "configurations": [ + { + "name": "Python Debugger: Attach", + "type": "debugpy", + "request": "attach", + "connect": { + "host": "localhost", + "port": 5678 + } + } + ] +} diff --git a/packages/uipath-platform/src/uipath/platform/common/_base_service.py b/packages/uipath-platform/src/uipath/platform/common/_base_service.py index 8ebba3711..d236e4ef5 100644 --- a/packages/uipath-platform/src/uipath/platform/common/_base_service.py +++ b/packages/uipath-platform/src/uipath/platform/common/_base_service.py @@ -67,7 +67,6 @@ def _get_caller_component() -> str: def _inject_trace_context(headers: dict[str, str]) -> None: - """Inject UiPath trace context header from the active OTEL span.""" span = trace.get_current_span() ctx = span.get_span_context() @@ -76,8 +75,6 @@ def _inject_trace_context(headers: dict[str, str]) -> None: f"00-{format_trace_id(ctx.trace_id)}-{format_span_id(ctx.span_id)}-01" ) - print(f"DEBUG: Injecting {_TRACE_PARENT_HEADER} = {headers[_TRACE_PARENT_HEADER]}") - class BaseService: def __init__(