Skip to content

Commit 8124543

Browse files
RunnanJiaclaude
andauthored
feat(platform): include jobKey in LLM Gateway trace baggage (#1731)
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent e1eac9c commit 8124543

5 files changed

Lines changed: 24 additions & 11 deletions

File tree

packages/uipath-platform/pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[project]
22
name = "uipath-platform"
3-
version = "0.2.6"
3+
version = "0.2.7"
44
description = "HTTP client library for programmatic access to UiPath Platform"
55
readme = { file = "README.md", content-type = "text/markdown" }
66
requires-python = ">=3.11"

packages/uipath-platform/src/uipath/platform/chat/llm_trace_context.py

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,14 @@ def build_trace_context_headers(
3434
ctx = span.get_span_context()
3535
if config_trace_id and ctx and ctx.span_id:
3636
trace_id = _SpanUtils.normalize_trace_id(config_trace_id)
37-
span_id = format(ctx.span_id, "032x")
38-
headers["x-uipath-traceparent-id"] = f"00-{trace_id}-{span_id}"
37+
# An OTEL span id is 64-bit => 16 lowercase hex chars, and the W3C traceparent
38+
# requires the trailing trace-flags segment. The LLM Gateway's strict parser
39+
# (UiPath.Tracing.TraceParent.TryParse) rejects the header unless it is exactly
40+
# {version}-{32-hex trace}-{16-hex span}-{2-hex flags}; on rejection the gateway
41+
# synthesizes a fresh root trace and drops inbound baggage, orphaning the audit
42+
# span from the caller's trace. Emitting 32-hex span / no flags was the bug.
43+
span_id = format(ctx.span_id, "016x")
44+
headers["x-uipath-traceparent-id"] = f"00-{trace_id}-{span_id}-01"
3945

4046
baggage_parts: list[str] = list(extra_baggage) if extra_baggage else []
4147
if folder_key := UiPathConfig.folder_key:
@@ -44,6 +50,8 @@ def build_trace_context_headers(
4450
baggage_parts.append(f"agentId={agent_id}")
4551
if process_uuid := UiPathConfig.process_uuid:
4652
baggage_parts.append(f"processKey={process_uuid}")
53+
if job_key := UiPathConfig.job_key:
54+
baggage_parts.append(f"jobKey={job_key}")
4755
if baggage_parts:
4856
headers["x-uipath-tracebaggage"] = ",".join(baggage_parts)
4957

packages/uipath-platform/tests/services/test_llm_trace_context.py

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,9 @@ def setup_method(self) -> None:
4444
def test_traceparent_from_config_and_span(self) -> None:
4545
span = _make_span()
4646
ctx = span.get_span_context()
47-
expected_span_id = format(ctx.span_id, "032x")
47+
# OTEL span id is 64-bit => 16 hex chars; traceparent carries the trailing flags
48+
# segment. The gateway's strict W3C parser requires exactly this shape.
49+
expected_span_id = format(ctx.span_id, "016x")
4850
config_trace = "abcdef1234567890abcdef1234567890"
4951
env = {"UIPATH_TRACE_ID": config_trace}
5052
with (
@@ -58,12 +60,13 @@ def test_traceparent_from_config_and_span(self) -> None:
5860

5961
assert "x-uipath-traceparent-id" in headers
6062
value = headers["x-uipath-traceparent-id"]
61-
assert value == f"00-{config_trace}-{expected_span_id}"
63+
assert value == f"00-{config_trace}-{expected_span_id}-01"
6264
parts = value.split("-")
63-
assert len(parts) == 3
65+
assert len(parts) == 4
6466
assert parts[0] == "00"
6567
assert len(parts[1]) == 32
66-
assert len(parts[2]) == 32
68+
assert len(parts[2]) == 16
69+
assert parts[3] == "01"
6770

6871
def test_no_traceparent_without_config_trace_id(self) -> None:
6972
headers = build_trace_context_headers()
@@ -122,6 +125,7 @@ def test_all_env_vars_present(self) -> None:
122125
"UIPATH_FOLDER_KEY": "folder-abc",
123126
ENV_PROJECT_KEY: "agent-123",
124127
"UIPATH_PROCESS_UUID": "process-789",
128+
"UIPATH_JOB_KEY": "job-456",
125129
}
126130
with patch.dict(os.environ, env, clear=True):
127131
headers = build_trace_context_headers()
@@ -130,6 +134,7 @@ def test_all_env_vars_present(self) -> None:
130134
assert "folderKey=folder-abc" in baggage
131135
assert "agentId=agent-123" in baggage
132136
assert "processKey=process-789" in baggage
137+
assert "jobKey=job-456" in baggage
133138

134139
def test_partial_env_vars(self) -> None:
135140
env = {"UIPATH_FOLDER_KEY": "folder-only"}

packages/uipath-platform/uv.lock

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/uipath/uv.lock

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)