Repository navigation
feat(tracing): add a run_id-keyed span provider to UiPathSpanUtils [PLT-112227] - #1941
kshitij858 wants to merge 2 commits into
Conversation
…LT-112227] The existing current-span providers answer for whatever is executing now. A caller holding a framework run id (e.g. a LangChain callback's run_id) has no way to ask for the span that run opened, so consumers read framework internals instead. Add register_run_span_provider / get_run_span, mirroring the existing providers' fail-safe lookup. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
🟡 Changes recommended
The public setter lacks its required return annotation, and the documented warning behavior is not asserted.
2 open findings
What changed in this PR
Adds run-ID-based span lookup to support concurrent external framework callbacks.
Changes:
- Adds registration and lookup APIs for run-specific spans.
- Adds provider behavior tests.
- Bumps
uipath-coreto 0.5.34.
| File | Description |
|---|---|
packages/uipath-core/src/uipath/core/tracing/span_utils.py |
Implements the run span provider. |
packages/uipath-core/tests/tracing/test_external_integration.py |
Tests lookup and error handling. |
packages/uipath-core/pyproject.toml |
Bumps package version. |
packages/uipath-core/uv.lock |
Updates locked core version. |
packages/uipath-platform/uv.lock |
Updates locked core version. |
packages/uipath/uv.lock |
Updates locked core version. |
🧠 Review effort: Balanced
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
| def register_run_span_provider( | ||
| run_span_provider: Optional[Callable[[UUID], Optional[Span]]], | ||
| ): |
| def test_run_span_provider_raises_exception(): | ||
| """Test that exceptions from the run span provider are caught.""" | ||
| from uuid import UUID, uuid4 | ||
|
|
||
| from uipath.core.tracing.span_utils import UiPathSpanUtils | ||
|
|
||
| def failing_provider(run_id: UUID): | ||
| raise RuntimeError("Provider failed!") | ||
|
|
||
| UiPathSpanUtils.register_run_span_provider(failing_provider) | ||
|
|
||
| assert UiPathSpanUtils.get_run_span(uuid4()) is None | ||
|
|
||
| # Clean up | ||
| UiPathSpanUtils.register_run_span_provider(None) |
🚨 Heads up:
|
|
🚨 Heads up:
|




Why
UiPathSpanUtilslets a framework register providers for the current span and its ancestors. Both take no arguments: they answer for whatever is running right now.A LangChain callback handler only has the
run_idof the call it is handling, and it needs the span the runtime opened for that call. The current span is the wrong question for two reasons: callbacks for concurrent calls interleave, and an end hook can run after the runtime has already moved on.Today the only way to get that span is to read framework internals. uipath-governance-python does exactly that: it reads
uipath_agents._observability.llmops.span_hierarchy.SpanHierarchyManagerto parent its policy-check spans under the LLM or tool call they checked. This PR adds a public seam so that private read can go away.What
UiPathSpanUtils.register_run_span_provider(Callable[[UUID], Optional[Span]] | None)UiPathSpanUtils.get_run_span(run_id) -> Optional[Span]These follow the existing providers' pattern: the provider is stored as a ClassVar,
Noneunregisters it, and a provider that raises is logged at WARNING and returnsNone. No existing behaviour changes.uipath-agents will register the provider, backed by
SpanHierarchyManager, in a companion PR.Version
uipath-coregoes from 0.5.33 to 0.5.34.Testing
tests/tracing/test_external_integration.py: the lookup resolves through the provider, no provider returnsNone, and a raising provider returnsNone.pytest tests/tracing,ruff check,ruff format --check,mypy src tests, anduv lock --checkin all three packages all pass.🤖 Generated with Claude Code