Skip to content

feat(tracing): migrate span ingestion to v3 API with string enums#1684

Open
saksharthakkar wants to merge 19 commits into
mainfrom
feat/trace-v3-migration
Open

feat(tracing): migrate span ingestion to v3 API with string enums#1684
saksharthakkar wants to merge 19 commits into
mainfrom
feat/trace-v3-migration

Conversation

@saksharthakkar

@saksharthakkar saksharthakkar commented May 26, 2026

Copy link
Copy Markdown
Contributor

Motivation

The UiPath LLM Observability backend is introducing V3 span APIs with insert-only ingestion semantics. The V3 endpoint rejects integer enum values — all status, source, verbosity, and execution type fields must be strings (e.g. "Ok" not 1). This PR migrates the Python SDK's span ingestion pipeline to conform to the V3 contract.

Summary

  • _span_utils.py: Replace IntEnum-based VerbosityLevel with StrEnum; add SpanStatus, SpanSource, ExecutionType as StrEnum types with values matching C# server enum names exactly ("Ok", "CodedAgents", "Information", "Runtime"). Add int→StrEnum lookup dicts for bridging raw OTEL attribute integers to enum members. Update UiPathSpan field types from int to the new enums. Update otel_span_to_uipath_span() to produce string enum values.
  • _otel_exporters.py: Remove the old integer SpanStatus class and inner Status class. Import SpanStatus from _span_utils. Update _build_url() from /api/Traces/spans/api/Traces/v3/spans. Update _determine_status() return type and upsert_span() parameter type.
  • _live_tracking_processor.py: Update SpanStatus import to come from _span_utils instead of _otel_exporters. Update _upsert_span_async type annotation from int | None to SpanStatus | None.
  • platform/common/__init__.py: Export ExecutionType, SpanSource, SpanStatus (new public types).
  • tracing/__init__.py: Re-export SpanStatus from _span_utils instead of _otel_exporters.
  • Tests: Updated test_span_utils.py with StrEnum unit tests and enum value assertions. Updated test_otel_exporters.py with v3 URL assertions, string enum body assertions, and a new TestV3EndToEnd integration test.

Verification in OR - hacked-coded

image

Test plan

  • packages/uipath-platform: 1212 passed, 0 failed
  • packages/uipath: 1866 passed, 0 failed
  • mypy src tests clean on both packages (0 errors)
  • ruff check + ruff format --check clean on both packages
  • TestV3EndToEnd.test_export_posts_to_v3_url_with_string_enums — end-to-end: real OTel span → LlmOpsHttpExporter → asserts POST to v3/spans with "Status": "Ok" and "Source": "CodedAgents" as strings

🤖 Generated with Claude Code

saksharthakkar and others added 11 commits May 26, 2026 12:01
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…vel StrEnums

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…rEnum types

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…string enums

- Import SpanStatus from uipath.platform.common._span_utils (StrEnum)
- Remove local int-based SpanStatus class and inner Status class
- Update _build_url to /api/Traces/v3/spans
- Update _determine_status() return type to SpanStatus (string values)
- Update upsert_span status_override param type to Optional[SpanStatus]
- Update debug log message to reference v3 path
- Add 4 new tests verifying v3 URL and string enum status values
- Fix VerbosityLevel.OFF assertion from int 6 to string "Off"

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…m platform.common

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…gration

Fix ruff import-sort and formatting in span_utils tests and otel_exporters;
add TestV3EndToEnd integration test asserting v3/spans URL and string enum
values (Status="Ok", Source="CodedAgents") reach the HTTP layer end-to-end.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…wboat doc

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@github-actions github-actions Bot added test:uipath-langchain Triggers tests in the uipath-langchain-python repository test:uipath-integrations labels May 26, 2026
saksharthakkar and others added 4 commits May 26, 2026 14:31
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…onflicts

- Keep both StrEnum imports and lru_cache import
- Combine StrEnum types (v3 migration) with resolve_project_id() (stable span id from main)
- Merge TestStrEnums with the _clear_id_cache fixture and constants imports

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016228TgPXqjJTxmZDY4Jtmd
…ions

- Emit ReferenceVersion (was AgentVersion) — SpanV3Req has no AgentVersion
  field; agent version is carried by ReferenceVersion (pairs with ReferenceId)
- Default org/tenant/folder Guid fields to None instead of "" so unset env
  vars omit cleanly rather than 400 the v3 ingest serializer
- Bump uipath 2.11.12->2.11.13, uipath-platform 0.1.76->0.1.77 (versions
  already on PyPI)
- ruff format test_otel_exporters.py

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016228TgPXqjJTxmZDY4Jtmd
uipath's tracing code now imports SpanStatus from uipath-platform, so a
standalone uipath install must require the new 0.1.77. Satisfies the
check-dependency-bumps CI gate for co-changed internal packages.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016228TgPXqjJTxmZDY4Jtmd
@github-actions

Copy link
Copy Markdown

🚨 Heads up: uipath-integrations cross-tests are FAILING 🚨

Your changes may break one or more integrations in uipath-integrations-python:

  • uipath-openai-agents
  • uipath-google-adk
  • uipath-agent-framework
  • uipath-llamaindex
  • uipath-pydantic-ai

⚠️ These checks are NOT enforced by branch protection rules. Please review the failures before merging.

🔍 Inspect the failed run →

Bump versions above main (uipath 2.11.14, uipath-platform 0.1.79): main
published 2.11.13 and bumped platform to 0.1.78. Keep main's
uipath-runtime>=0.11.4. Pin uipath -> uipath-platform>=0.1.79 for the
dependency-bump gate.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016228TgPXqjJTxmZDY4Jtmd
@saksharthakkar saksharthakkar force-pushed the feat/trace-v3-migration branch from 5dd81eb to e2e3d73 Compare June 25, 2026 18:16
@saksharthakkar saksharthakkar changed the title (wip) feat(tracing): migrate span ingestion to v3 API with string enums feat(tracing): migrate span ingestion to v3 API with string enums Jun 25, 2026
- _determine_status: GraphInterrupt is a HITL pause, map to SpanStatus.RUNNING
  (restores v2 int-3==Running semantics; StatusEnum has no Interrupted member)
- SpanSource / _SOURCE_BY_INT: mirror the server's full 17-member SourceEnum
  (0-16) so every server-known source round-trips; previously only {1,2,3,4,10}
  were mapped and other ints were silently relabeled CodedAgents (data-fidelity
  regression, since v3 rejects raw int forwarding)
- Unknown uipath.source int now logs a warning instead of silent relabel
- Tests: graph_interrupt expects Running; parametrized full int->source map;
  unknown-int warning test

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016228TgPXqjJTxmZDY4Jtmd
@saksharthakkar saksharthakkar force-pushed the feat/trace-v3-migration branch from 276c821 to 8639147 Compare June 25, 2026 21:48
@saksharthakkar saksharthakkar marked this pull request as ready for review June 25, 2026 21:59
Copilot AI review requested due to automatic review settings June 25, 2026 21:59

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Migrates the Python SDK’s tracing/span ingestion to the LLM Observability v3 spans API, ensuring enum fields are sent as string values (per the v3 contract) and updating public exports and tests accordingly.

Changes:

  • Introduce StrEnum-backed SpanStatus, SpanSource, ExecutionType, and migrate VerbosityLevel to StrEnum, including int→enum bridging for OTEL attribute integers.
  • Update LlmOpsHttpExporter to post to /api/Traces/v3/spans and to use the new SpanStatus type throughout.
  • Update re-exports and expand tests to assert v3 URL usage and string-enum payloads end-to-end.

Reviewed changes

Copilot reviewed 9 out of 11 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
packages/uipath/uv.lock Bumps local package versions in lockfile to match release increment.
packages/uipath/pyproject.toml Bumps uipath version and updates uipath-platform minimum dependency.
packages/uipath/src/uipath/tracing/_otel_exporters.py Switches exporter to v3 endpoint and uses SpanStatus string enums.
packages/uipath/src/uipath/tracing/_live_tracking_processor.py Updates SpanStatus import and type annotations for status overrides.
packages/uipath/src/uipath/tracing/init.py Re-exports SpanStatus from the new common enum source.
packages/uipath/tests/tracing/test_otel_exporters.py Updates tests for v3 URL + string enums and adds an end-to-end v3 payload assertion.
packages/uipath-platform/uv.lock Bumps uipath-platform version in lockfile.
packages/uipath-platform/pyproject.toml Bumps uipath-platform version.
packages/uipath-platform/src/uipath/platform/common/_span_utils.py Adds string enums + int→enum mappings and updates UiPathSpan serialization for v3.
packages/uipath-platform/src/uipath/platform/common/init.py Exposes new public enum types (SpanStatus, SpanSource, ExecutionType, VerbosityLevel).
packages/uipath-platform/tests/services/test_span_utils.py Updates/extends unit tests for StrEnum behavior, v3 field names, and string serialization.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread packages/uipath-platform/src/uipath/platform/common/_span_utils.py Outdated
Comment thread packages/uipath-platform/src/uipath/platform/common/_span_utils.py Outdated
Comment thread packages/uipath/src/uipath/tracing/_live_tracking_processor.py
saksharthakkar and others added 2 commits June 25, 2026 15:26
- _enum_from_int helper now backs executionType/verbosityLevel/source so all
  three ignore bool (int subclass) identically — previously only source was
  guarded, so executionType=True/verbosityLevel=True still mapped to the
  value-1 member (Runtime/Trace)
- to_dict now omits OrganizationId/TenantId/FolderKey when None instead of
  emitting null; corrected the stale comment that claimed they were omitted
- Tests: bool-attributes-do-not-map; None Guid keys omitted from to_dict;
  set Guid keys still present

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016228TgPXqjJTxmZDY4Jtmd
status_override is SpanStatus | None; branch on 'is not None' to match the
type contract rather than truthiness (Copilot review).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016228TgPXqjJTxmZDY4Jtmd
@sonarqubecloud

Copy link
Copy Markdown

@github-actions

Copy link
Copy Markdown

🚨 Heads up: uipath-langchain cross-tests are FAILING 🚨

Your changes may break the uipath-langchain-python integration.

⚠️ These checks are NOT enforced by branch protection rules. Please review the failures before merging.

🔍 Inspect the failed run →

6: VerbosityLevel.OFF,
}

_SOURCE_BY_INT: dict[int, SpanSource] = {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

todo: we should probably expose these enums as a package so there isn't a copy-paste dependency

"AgentVersion": self.agent_version,
# v3 ingest (SpanV3Req) has no AgentVersion field; the agent version
# is carried by ReferenceVersion (pairs with ReferenceId above).
"ReferenceVersion": self.agent_version,

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

cc @jepadil23 are your referencehierarchy changes in yet?

# Agent Builder runtime, which keeps interrupted runs Running
# (ConversationalEngineWorkflow waits via WaitConditionAsync; no
# terminal status). StatusEnum has no Interrupted member.
return SpanStatus.RUNNING

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

a little confused, where did Status.INTERRUPTED come from if it's not in the span schema?

@JosephMar JosephMar left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

test:uipath-integrations test:uipath-langchain Triggers tests in the uipath-langchain-python repository

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants