diff --git a/packages/uipath/pyproject.toml b/packages/uipath/pyproject.toml index b95894996..b07b09ce4 100644 --- a/packages/uipath/pyproject.toml +++ b/packages/uipath/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "uipath" -version = "2.14.42" +version = "2.14.43" description = "Python SDK and CLI for UiPath Platform, enabling programmatic interaction with automation services, process management, and deployment tools." readme = { file = "README.md", content-type = "text/markdown" } requires-python = ">=3.11" diff --git a/packages/uipath/src/uipath/_cli/_run_telemetry.py b/packages/uipath/src/uipath/_cli/_run_telemetry.py index d0751496a..17d25f14c 100644 --- a/packages/uipath/src/uipath/_cli/_run_telemetry.py +++ b/packages/uipath/src/uipath/_cli/_run_telemetry.py @@ -9,7 +9,7 @@ import time import uuid from enum import Enum -from importlib.metadata import version +from importlib.metadata import PackageNotFoundError, version from typing import Any from uipath.platform.common import UiPathConfig, resolve_trace_id @@ -50,6 +50,16 @@ def classify_run(agent_type: str | None, agent_framework: str | None) -> RunKind return RunKind.CODED_AGENT +def _integration_version(factory: object | None) -> str | None: + """Installed version of the package the factory class ships in.""" + if factory is None: + return None + try: + return version(type(factory).__module__.split(".")[0]) + except PackageNotFoundError: + return None + + def _cloud_user_id() -> str | None: if configured := UiPathConfig.cloud_user_id: return configured @@ -113,6 +123,7 @@ def __init__( *, kind: RunKind, agent_framework: str | None, + integration_version: str | None, entrypoint: str | None, execution_source: str | None, is_conversational: bool, @@ -120,6 +131,7 @@ def __init__( """Key the run on its job so a suspend/resume pair stays one run.""" self._kind = kind self._agent_framework = agent_framework + self._integration_version = integration_version self._entrypoint = entrypoint self._execution_source = execution_source self._is_conversational = is_conversational @@ -135,6 +147,7 @@ def start( entrypoint: str | None, execution_source: str | None = None, is_conversational: bool = False, + factory: object | None = None, ) -> "RunTelemetry | None": """Emit Start and return a handle, or ``None`` when not reporting. @@ -150,6 +163,7 @@ def start( instance = cls( kind=kind, agent_framework=agent_framework, + integration_version=_integration_version(factory), entrypoint=entrypoint, execution_source=execution_source, is_conversational=is_conversational, @@ -198,6 +212,7 @@ def _emit( "AgentRunId": self._run_id, "AgentType": "Coded", "AgentFramework": self._agent_framework, + "IntegrationVersion": self._integration_version, "AgentRunSource": self._execution_source, "Entrypoint": self._entrypoint, "IsConversational": self._is_conversational, diff --git a/packages/uipath/src/uipath/_cli/cli_debug.py b/packages/uipath/src/uipath/_cli/cli_debug.py index fc2372f0d..e66dc153b 100644 --- a/packages/uipath/src/uipath/_cli/cli_debug.py +++ b/packages/uipath/src/uipath/_cli/cli_debug.py @@ -181,6 +181,7 @@ async def execute_debug_runtime(): entrypoint=entrypoint, execution_source=ctx.execution_source, is_conversational=ctx.conversation_id is not None, + factory=factory, ) governance_bootstrap = await resolve_governance( diff --git a/packages/uipath/src/uipath/_cli/cli_run.py b/packages/uipath/src/uipath/_cli/cli_run.py index d98b92653..b31be036b 100644 --- a/packages/uipath/src/uipath/_cli/cli_run.py +++ b/packages/uipath/src/uipath/_cli/cli_run.py @@ -276,6 +276,7 @@ async def execute() -> None: entrypoint=resolved_entrypoint, execution_source=ctx.execution_source, is_conversational=ctx.conversation_id is not None, + factory=factory, ) governance_bootstrap = await resolve_governance( diff --git a/packages/uipath/tests/cli/test_run_telemetry.py b/packages/uipath/tests/cli/test_run_telemetry.py index 236a6c6ff..eea7badd0 100644 --- a/packages/uipath/tests/cli/test_run_telemetry.py +++ b/packages/uipath/tests/cli/test_run_telemetry.py @@ -1,5 +1,6 @@ """Tests for coded run lifecycle telemetry.""" +from importlib.metadata import version from typing import Any from unittest.mock import patch @@ -71,6 +72,7 @@ def start( entrypoint=kwargs.pop("entrypoint", "main"), execution_source=kwargs.pop("execution_source", "runtime"), is_conversational=kwargs.pop("is_conversational", False), + factory=kwargs.pop("factory", None), ) @@ -130,6 +132,26 @@ def test_framework_is_reported_on_every_event(self, emitted): assert properties.get("AgentFramework") == "llamaindex", name +class TestIntegrationVersion: + def test_version_of_the_factory_package_is_reported_on_every_event(self, emitted): + factory_cls = type("Factory", (), {"__module__": "pluggy._factory"}) + handle = start(factory=factory_cls()) + assert handle is not None + handle.finished(successful()) + + assert names(emitted) == ["CodedAgentRun.Start", "CodedAgentRun.End"] + for name, properties in emitted: + assert properties.get("IntegrationVersion") == version("pluggy"), name + + def test_factory_outside_an_installed_package_reports_no_version(self, emitted): + factory_cls = type("Factory", (), {"__module__": "main"}) + + start(factory=factory_cls()) + + assert names(emitted) == ["CodedAgentRun.Start"] + assert "IntegrationVersion" not in emitted[0][1] + + class TestScopeBlock: def test_scope_is_present_on_start_and_terminal_events(self, emitted): started().finished(successful()) diff --git a/packages/uipath/uv.lock b/packages/uipath/uv.lock index 19132255f..845266b09 100644 --- a/packages/uipath/uv.lock +++ b/packages/uipath/uv.lock @@ -2599,7 +2599,7 @@ wheels = [ [[package]] name = "uipath" -version = "2.14.42" +version = "2.14.43" source = { editable = "." } dependencies = [ { name = "applicationinsights" },