From ec20883897aee8de7b7fcd4912552da288cec8d8 Mon Sep 17 00:00:00 2001 From: Valentina Bojan Date: Thu, 25 Jun 2026 13:24:27 +0300 Subject: [PATCH] feat(guardrails): send execution source and job key headers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Guardrail validation calls now send the execution source (x-uipath-guardrails-source) and job key (x-uipath-jobkey) headers for licensing/metering correlation. The source is derived from the executing CLI command (run -> runtime, debug/dev -> playground, eval -> eval) on UiPathRuntimeContext.execution_source (uipath-runtime 0.11.4) and flows through the execution-context boundary: the CLI enters ExecutionSourceContext(ctx.execution_source) — a scoped ContextVar that releases its token on exit — UiPathExecutionContext.execution_source reads it, and GuardrailsService builds the header from self._execution_context.execution_source. This keeps the source correctly scoped for concurrent/eval runs and works for both coded and low-code agents. Job key comes from UiPathConfig.job_key; both headers are omitted when unset. Bumps uipath-platform to 0.1.78 and pins uipath-runtime>=0.11.4. Co-Authored-By: Claude Opus 4.8 --- packages/uipath-platform/pyproject.toml | 2 +- .../src/uipath/platform/common/__init__.py | 3 +- .../platform/common/_execution_context.py | 37 +++++++ .../src/uipath/platform/common/constants.py | 1 + .../guardrails/_guardrails_service.py | 18 +++- .../tests/common/test_execution_context.py | 26 +++++ .../tests/services/test_guardrails_service.py | 98 +++++++++++++++++++ packages/uipath-platform/uv.lock | 4 +- packages/uipath/pyproject.toml | 6 +- packages/uipath/src/uipath/_cli/cli_debug.py | 11 ++- packages/uipath/src/uipath/_cli/cli_dev.py | 38 +++---- packages/uipath/src/uipath/_cli/cli_eval.py | 11 ++- packages/uipath/src/uipath/_cli/cli_run.py | 8 +- packages/uipath/tests/cli/test_dev.py | 70 +++++++++++++ packages/uipath/uv.lock | 14 +-- 15 files changed, 306 insertions(+), 41 deletions(-) create mode 100644 packages/uipath-platform/tests/common/test_execution_context.py create mode 100644 packages/uipath/tests/cli/test_dev.py diff --git a/packages/uipath-platform/pyproject.toml b/packages/uipath-platform/pyproject.toml index e4da0a0ce..21c693e7b 100644 --- a/packages/uipath-platform/pyproject.toml +++ b/packages/uipath-platform/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "uipath-platform" -version = "0.1.77" +version = "0.1.78" 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/__init__.py b/packages/uipath-platform/src/uipath/platform/common/__init__.py index 555d6901d..2407263ee 100644 --- a/packages/uipath-platform/src/uipath/platform/common/__init__.py +++ b/packages/uipath-platform/src/uipath/platform/common/__init__.py @@ -16,7 +16,7 @@ ) from ._config import UiPathApiConfig, UiPathConfig from ._endpoints_manager import EndpointManager -from ._execution_context import UiPathExecutionContext +from ._execution_context import ExecutionSourceContext, UiPathExecutionContext from ._external_application_service import ExternalApplicationService from ._folder_context import FolderContext, header_folder from ._http_config import get_ca_bundle_path, get_httpx_client_kwargs @@ -61,6 +61,7 @@ "BaseService", "UiPathApiConfig", "UiPathExecutionContext", + "ExecutionSourceContext", "ExternalApplicationService", "FolderContext", "TokenData", diff --git a/packages/uipath-platform/src/uipath/platform/common/_execution_context.py b/packages/uipath-platform/src/uipath/platform/common/_execution_context.py index de54c0c99..184a626db 100644 --- a/packages/uipath-platform/src/uipath/platform/common/_execution_context.py +++ b/packages/uipath-platform/src/uipath/platform/common/_execution_context.py @@ -1,7 +1,34 @@ +from contextvars import ContextVar, Token from os import environ as env from uipath.platform.common.constants import ENV_JOB_ID, ENV_JOB_KEY, ENV_ROBOT_KEY +_execution_source: ContextVar[str | None] = ContextVar("execution_source", default=None) + + +class ExecutionSourceContext: + """Scope the execution source for the duration of a run. + + Carries the source (e.g. ``runtime``/``playground``/``eval``) via a context + variable and releases it on exit so it stays correctly scoped in concurrent + runs. The CLI enters this with ``UiPathRuntimeContext.execution_source`` so + platform clients can read it via + :attr:`UiPathExecutionContext.execution_source`. + """ + + def __init__(self, execution_source: str | None) -> None: + self._execution_source = execution_source + self._token: Token[str | None] | None = None + + def __enter__(self) -> "ExecutionSourceContext": + self._token = _execution_source.set(self._execution_source) + return self + + def __exit__(self, exc_type: object, exc_val: object, exc_tb: object) -> None: + if self._token is not None: + _execution_source.reset(self._token) + self._token = None + class UiPathExecutionContext: """Manages the execution context for UiPath automation processes. @@ -76,3 +103,13 @@ def robot_key(self) -> str | None: raise ValueError(f"Robot key is not set ({ENV_ROBOT_KEY})") return self._robot_key + + @property + def execution_source(self) -> str | None: + """Get the execution source for the current run. + + Identifies the run context (e.g. ``runtime``/``playground``/``eval``), + derived from the CLI command and carried via + :class:`ExecutionSourceContext`. Returns ``None`` when not set. + """ + return _execution_source.get() diff --git a/packages/uipath-platform/src/uipath/platform/common/constants.py b/packages/uipath-platform/src/uipath/platform/common/constants.py index 304ef64a6..fa710993c 100644 --- a/packages/uipath-platform/src/uipath/platform/common/constants.py +++ b/packages/uipath-platform/src/uipath/platform/common/constants.py @@ -39,6 +39,7 @@ HEADER_PROCESS_KEY = "x-uipath-processkey" HEADER_TRACE_ID = "x-uipath-traceid" HEADER_AGENTHUB_CONFIG = "x-uipath-agenthub-config" +HEADER_GUARDRAILS_SOURCE = "x-uipath-guardrails-source" HEADER_LLMGATEWAY_BYO_CONNECTION_ID = "x-uipath-llmgateway-byoisconnectionid" HEADER_SW_LOCK_KEY = "x-uipath-sw-lockkey" HEADER_LICENSING_CONTEXT = "x-uipath-licensing-context" diff --git a/packages/uipath-platform/src/uipath/platform/guardrails/_guardrails_service.py b/packages/uipath-platform/src/uipath/platform/guardrails/_guardrails_service.py index 86856a6b4..5082843ab 100644 --- a/packages/uipath-platform/src/uipath/platform/guardrails/_guardrails_service.py +++ b/packages/uipath-platform/src/uipath/platform/guardrails/_guardrails_service.py @@ -12,7 +12,9 @@ from ..common._base_service import BaseService from ..common._config import UiPathApiConfig from ..common._execution_context import UiPathExecutionContext +from ..common._job_context import header_job_key from ..common._models import Endpoint, RequestSpec +from ..common.constants import HEADER_GUARDRAILS_SOURCE from ..errors import EnrichedException from .guardrails import BuiltInValidatorGuardrail @@ -123,9 +125,21 @@ def evaluate_guardrail( endpoint=Endpoint("/agentsruntime_/api/execution/guardrails/validate"), json=payload, ) - # Include trace context headers for server-side span correlation + # Include trace context headers for server-side span correlation, plus + # the execution source (x-uipath-guardrails-source) and job key headers + # for licensing/metering correlation. The execution source is read from + # the execution context, propagated from the runtime context. trace_headers = build_trace_context_headers() - request_headers = {**(spec.headers or {}), **trace_headers} + source_headers: dict[str, str] = {} + execution_source = self._execution_context.execution_source + if execution_source: + source_headers[HEADER_GUARDRAILS_SOURCE] = execution_source + request_headers = { + **(spec.headers or {}), + **trace_headers, + **source_headers, + **header_job_key(), + } span_id = None try: response = self.request( diff --git a/packages/uipath-platform/tests/common/test_execution_context.py b/packages/uipath-platform/tests/common/test_execution_context.py new file mode 100644 index 000000000..25b43c9b2 --- /dev/null +++ b/packages/uipath-platform/tests/common/test_execution_context.py @@ -0,0 +1,26 @@ +from uipath.platform.common import ExecutionSourceContext, UiPathExecutionContext + + +def test_execution_source_none_by_default() -> None: + assert UiPathExecutionContext().execution_source is None + + +def test_execution_source_set_within_context() -> None: + ctx = UiPathExecutionContext() + + with ExecutionSourceContext("runtime"): + assert ctx.execution_source == "runtime" + + assert ctx.execution_source is None + + +def test_execution_source_context_restores_previous_value() -> None: + ctx = UiPathExecutionContext() + + with ExecutionSourceContext("eval"): + assert ctx.execution_source == "eval" + with ExecutionSourceContext("playground"): + assert ctx.execution_source == "playground" + assert ctx.execution_source == "eval" + + assert ctx.execution_source is None diff --git a/packages/uipath-platform/tests/services/test_guardrails_service.py b/packages/uipath-platform/tests/services/test_guardrails_service.py index e9d73a06f..87fb7bb8c 100644 --- a/packages/uipath-platform/tests/services/test_guardrails_service.py +++ b/packages/uipath-platform/tests/services/test_guardrails_service.py @@ -10,6 +10,7 @@ ) from uipath.platform import UiPathApiConfig, UiPathExecutionContext +from uipath.platform.common import ExecutionSourceContext from uipath.platform.guardrails import ( BuiltInValidatorGuardrail, EnumListParameterValue, @@ -356,6 +357,103 @@ def capture_request(request): # header merging works even when no active span exists) assert "content-type" in headers + def test_evaluate_guardrail_sends_source_and_job_key_headers( + self, + httpx_mock: HTTPXMock, + service: GuardrailsService, + base_url: str, + org: str, + tenant: str, + monkeypatch: pytest.MonkeyPatch, + ) -> None: + """Outgoing request includes execution source and job key headers.""" + monkeypatch.setenv("UIPATH_JOB_KEY", "job-123") + + captured_request = None + + def capture_request(request): + nonlocal captured_request + captured_request = request + return httpx.Response( + status_code=200, + json={"result": "PASSED", "details": "OK"}, + ) + + httpx_mock.add_callback( + method="POST", + url=f"{base_url}{org}{tenant}/agentsruntime_/api/execution/guardrails/validate", + callback=capture_request, + ) + + pii_guardrail = BuiltInValidatorGuardrail( + id="test-id", + name="PII guardrail", + description="Test", + enabled_for_evals=True, + selector=GuardrailSelector( + scopes=[GuardrailScope.TOOL], match_names=["tool1"] + ), + guardrail_type="builtInValidator", + validator_type="pii_detection", + validator_parameters=[], + ) + + with ExecutionSourceContext("runtime"): + service.evaluate_guardrail("test input", pii_guardrail) + + assert captured_request is not None + headers = dict(captured_request.headers) + assert headers.get("x-uipath-guardrails-source") == "runtime" + assert headers.get("x-uipath-jobkey") == "job-123" + + def test_evaluate_guardrail_omits_source_and_job_key_when_unset( + self, + httpx_mock: HTTPXMock, + service: GuardrailsService, + base_url: str, + org: str, + tenant: str, + monkeypatch: pytest.MonkeyPatch, + ) -> None: + """Source/job key headers are absent when unset.""" + monkeypatch.delenv("UIPATH_JOB_KEY", raising=False) + + captured_request = None + + def capture_request(request): + nonlocal captured_request + captured_request = request + return httpx.Response( + status_code=200, + json={"result": "PASSED", "details": "OK"}, + ) + + httpx_mock.add_callback( + method="POST", + url=f"{base_url}{org}{tenant}/agentsruntime_/api/execution/guardrails/validate", + callback=capture_request, + ) + + pii_guardrail = BuiltInValidatorGuardrail( + id="test-id", + name="PII guardrail", + description="Test", + enabled_for_evals=True, + selector=GuardrailSelector( + scopes=[GuardrailScope.TOOL], match_names=["tool1"] + ), + guardrail_type="builtInValidator", + validator_type="pii_detection", + validator_parameters=[], + ) + + service.evaluate_guardrail("test input", pii_guardrail) + + assert captured_request is not None + headers = dict(captured_request.headers) + assert "x-uipath-guardrails-source" not in headers + assert "x-uipath-jobkey" not in headers + def test_evaluate_guardrail_extracts_span_id_from_traceparent( self, httpx_mock: HTTPXMock, diff --git a/packages/uipath-platform/uv.lock b/packages/uipath-platform/uv.lock index 19a00447a..0f0f36b5a 100644 --- a/packages/uipath-platform/uv.lock +++ b/packages/uipath-platform/uv.lock @@ -3,7 +3,7 @@ revision = 3 requires-python = ">=3.11" [options] -exclude-newer = "2026-06-22T13:55:56.0776194Z" +exclude-newer = "0001-01-01T00:00:00Z" # This has no effect and is included for backwards compatibility when using relative exclude-newer values. exclude-newer-span = "P2D" [options.exclude-newer-package] @@ -1095,7 +1095,7 @@ dev = [ [[package]] name = "uipath-platform" -version = "0.1.77" +version = "0.1.78" source = { editable = "." } dependencies = [ { name = "httpx" }, diff --git a/packages/uipath/pyproject.toml b/packages/uipath/pyproject.toml index 7acd8465d..62bb9a5e1 100644 --- a/packages/uipath/pyproject.toml +++ b/packages/uipath/pyproject.toml @@ -1,13 +1,13 @@ [project] name = "uipath" -version = "2.11.12" +version = "2.11.13" 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" dependencies = [ "uipath-core>=0.5.21, <0.6.0", - "uipath-runtime>=0.11.0, <0.12.0", - "uipath-platform>=0.1.76, <0.2.0", + "uipath-runtime>=0.11.4, <0.12.0", + "uipath-platform>=0.1.78, <0.2.0", "click>=8.3.1", "httpx>=0.28.1", "pyjwt>=2.10.1", diff --git a/packages/uipath/src/uipath/_cli/cli_debug.py b/packages/uipath/src/uipath/_cli/cli_debug.py index 92b8ea454..1e2df4770 100644 --- a/packages/uipath/src/uipath/_cli/cli_debug.py +++ b/packages/uipath/src/uipath/_cli/cli_debug.py @@ -11,7 +11,11 @@ from uipath.core.tracing import UiPathTraceManager from uipath.eval.mocks import UiPathMockRuntime from uipath.eval.mocks._mock_runtime import load_simulation_config -from uipath.platform.common import ResourceOverwritesContext, UiPathConfig +from uipath.platform.common import ( + ExecutionSourceContext, + ResourceOverwritesContext, + UiPathConfig, +) from uipath.runtime import ( UiPathExecuteOptions, UiPathRuntimeContext, @@ -122,14 +126,15 @@ def debug( async def execute_debug_runtime(): trace_manager = UiPathTraceManager() - with UiPathRuntimeContext.with_defaults( + ctx = UiPathRuntimeContext.with_defaults( input=input, input_file=input_file, output_file=output_file, resume=resume, trace_manager=trace_manager, command="debug", - ) as ctx: + ) + with ExecutionSourceContext(ctx.execution_source), ctx: factory: UiPathRuntimeFactoryProtocol | None = None try: diff --git a/packages/uipath/src/uipath/_cli/cli_dev.py b/packages/uipath/src/uipath/_cli/cli_dev.py index 62740dc4b..f6d7021bb 100644 --- a/packages/uipath/src/uipath/_cli/cli_dev.py +++ b/packages/uipath/src/uipath/_cli/cli_dev.py @@ -7,6 +7,7 @@ from uipath._cli._utils._debug import setup_debugging from uipath._cli.middlewares import Middlewares from uipath.core.tracing import UiPathTraceManager +from uipath.platform.common import ExecutionSourceContext from uipath.runtime import UiPathRuntimeContext, UiPathRuntimeFactoryRegistry from ._telemetry import track_command @@ -14,6 +15,12 @@ console = ConsoleLogger() +def _create_dev_context_and_factory(trace_manager: UiPathTraceManager): + """Build the dev runtime context and its factory.""" + context = UiPathRuntimeContext(trace_manager=trace_manager, command="dev") + return context, UiPathRuntimeFactoryRegistry.get(context=context) + + def _check_dev_dependency(interface: str) -> None: """Check if uipath-dev is installed and raise helpful error if not.""" import importlib.util @@ -80,17 +87,14 @@ async def run_terminal() -> None: factory = None try: trace_manager = UiPathTraceManager() - factory = UiPathRuntimeFactoryRegistry.get( - context=UiPathRuntimeContext( - trace_manager=trace_manager, command="dev" - ) - ) + context, factory = _create_dev_context_and_factory(trace_manager) app = UiPathDeveloperConsole( runtime_factory=factory, trace_manager=trace_manager ) - await app.run_async() + with ExecutionSourceContext(context.execution_source): + await app.run_async() except KeyboardInterrupt: console.info("Debug session interrupted by user") @@ -124,11 +128,7 @@ def signal_handler(sig, frame): try: trace_manager = UiPathTraceManager() - factory = UiPathRuntimeFactoryRegistry.get( - context=UiPathRuntimeContext( - trace_manager=trace_manager, command="dev" - ) - ) + context, factory = _create_dev_context_and_factory(trace_manager) app = UiPathDeveloperServer( runtime_factory=factory, @@ -140,13 +140,17 @@ def signal_handler(sig, frame): ), ) - server_task = asyncio.create_task(app.run_async()) - shutdown_task = asyncio.create_task(shutdown_event.wait()) + # Enter the execution source context before creating the server + # task so request tasks spawned during the run inherit it. + with ExecutionSourceContext(context.execution_source): + server_task = asyncio.create_task(app.run_async()) + shutdown_task = asyncio.create_task(shutdown_event.wait()) - # Wait for either server to complete or shutdown signal - done, pending = await asyncio.wait( - {server_task, shutdown_task}, return_when=asyncio.FIRST_COMPLETED - ) + # Wait for either server to complete or shutdown signal + done, pending = await asyncio.wait( + {server_task, shutdown_task}, + return_when=asyncio.FIRST_COMPLETED, + ) for task in pending: task.cancel() diff --git a/packages/uipath/src/uipath/_cli/cli_eval.py b/packages/uipath/src/uipath/_cli/cli_eval.py index e101717d6..86e028c67 100644 --- a/packages/uipath/src/uipath/_cli/cli_eval.py +++ b/packages/uipath/src/uipath/_cli/cli_eval.py @@ -21,7 +21,11 @@ from uipath.eval.models.evaluation_set import EvaluationSet from uipath.eval.runtime import UiPathEvalContext, evaluate from uipath.platform.chat import set_llm_concurrency -from uipath.platform.common import ResourceOverwritesContext, UiPathConfig +from uipath.platform.common import ( + ExecutionSourceContext, + ResourceOverwritesContext, + UiPathConfig, +) from uipath.runtime import ( UiPathRuntimeContext, UiPathRuntimeFactoryRegistry, @@ -309,12 +313,13 @@ async def execute_eval(): trace_manager = UiPathTraceManager() - with UiPathRuntimeContext.with_defaults( + ctx = UiPathRuntimeContext.with_defaults( output_file=output_file, trace_manager=trace_manager, command="eval", resume=resume, - ) as ctx: + ) + with ExecutionSourceContext(ctx.execution_source), ctx: # Set job_id in eval context for single runtime runs eval_context.job_id = ctx.job_id diff --git a/packages/uipath/src/uipath/_cli/cli_run.py b/packages/uipath/src/uipath/_cli/cli_run.py index 48f42018b..9a8571d03 100644 --- a/packages/uipath/src/uipath/_cli/cli_run.py +++ b/packages/uipath/src/uipath/_cli/cli_run.py @@ -9,7 +9,11 @@ from uipath._cli._utils._debug import setup_debugging from uipath.core.tracing import UiPathTraceManager from uipath.eval.mocks import SimulationConfig, UiPathMockRuntime, build_mocking_context -from uipath.platform.common import ResourceOverwritesContext, UiPathConfig +from uipath.platform.common import ( + ExecutionSourceContext, + ResourceOverwritesContext, + UiPathConfig, +) from uipath.runtime import ( UiPathExecuteOptions, UiPathRuntimeFactoryProtocol, @@ -209,7 +213,7 @@ async def execute() -> None: async with ResourceOverwritesContext( lambda: read_resource_overwrites_from_file(ctx.runtime_dir) ): - with ctx: + with ExecutionSourceContext(ctx.execution_source), ctx: base_runtime: UiPathRuntimeProtocol | None = None runtime: UiPathRuntimeProtocol | None = None chat_runtime: UiPathRuntimeProtocol | None = None diff --git a/packages/uipath/tests/cli/test_dev.py b/packages/uipath/tests/cli/test_dev.py new file mode 100644 index 000000000..8b2a93c04 --- /dev/null +++ b/packages/uipath/tests/cli/test_dev.py @@ -0,0 +1,70 @@ +import sys +import types +from unittest.mock import AsyncMock, MagicMock + +import pytest +from click.testing import CliRunner + +from uipath._cli import cli, cli_dev +from uipath._cli.middlewares import MiddlewareResult +from uipath.platform.common import UiPathExecutionContext + + +def test_create_dev_context_and_factory_uses_dev_command( + monkeypatch: pytest.MonkeyPatch, +) -> None: + """The helper builds a 'dev' context (source 'playground') and its factory.""" + sentinel_factory = MagicMock(name="factory") + captured: dict[str, object] = {} + + def fake_get(context: object) -> object: + captured["command"] = context.command # type: ignore[attr-defined] + return sentinel_factory + + monkeypatch.setattr( + "uipath._cli.cli_dev.UiPathRuntimeFactoryRegistry.get", fake_get + ) + + context, factory = cli_dev._create_dev_context_and_factory(None) # type: ignore[arg-type] + + assert factory is sentinel_factory + assert captured["command"] == "dev" + assert context.execution_source == "playground" + + +def test_dev_terminal_sets_execution_source_during_run( + monkeypatch: pytest.MonkeyPatch, +) -> None: + """Running `dev terminal` scopes the execution source to 'playground'.""" + seen: dict[str, object] = {} + + async def fake_run_async() -> None: + seen["source"] = UiPathExecutionContext().execution_source + + fake_console = MagicMock() + fake_console.run_async = fake_run_async + + fake_module = types.ModuleType("uipath.dev") + fake_module.UiPathDeveloperConsole = MagicMock(return_value=fake_console) # type: ignore[attr-defined] + monkeypatch.setitem(sys.modules, "uipath.dev", fake_module) + + mock_factory = MagicMock() + mock_factory.dispose = AsyncMock() + + monkeypatch.setattr(cli_dev, "_check_dev_dependency", lambda interface: None) + monkeypatch.setattr(cli_dev, "setup_debugging", lambda debug, port: True) + monkeypatch.setattr( + "uipath._cli.cli_dev.Middlewares.next", + lambda *a, **k: MiddlewareResult(should_continue=True), + ) + monkeypatch.setattr( + "uipath._cli.cli_dev.UiPathRuntimeFactoryRegistry.get", + lambda context: mock_factory, + ) + + result = CliRunner().invoke(cli, ["dev", "terminal"]) + + assert result.exit_code == 0, result.output + assert seen["source"] == "playground" + # token released once the run completes + assert UiPathExecutionContext().execution_source is None diff --git a/packages/uipath/uv.lock b/packages/uipath/uv.lock index 0d745bb8f..59e93a39d 100644 --- a/packages/uipath/uv.lock +++ b/packages/uipath/uv.lock @@ -3,7 +3,7 @@ revision = 3 requires-python = ">=3.11" [options] -exclude-newer = "2026-06-22T13:56:19.8527915Z" +exclude-newer = "0001-01-01T00:00:00Z" # This has no effect and is included for backwards compatibility when using relative exclude-newer values. exclude-newer-span = "P2D" [options.exclude-newer-package] @@ -2552,7 +2552,7 @@ wheels = [ [[package]] name = "uipath" -version = "2.11.12" +version = "2.11.13" source = { editable = "." } dependencies = [ { name = "applicationinsights" }, @@ -2625,7 +2625,7 @@ requires-dist = [ { name = "truststore", specifier = ">=0.10.1" }, { name = "uipath-core", editable = "../uipath-core" }, { name = "uipath-platform", editable = "../uipath-platform" }, - { name = "uipath-runtime", specifier = ">=0.11.0,<0.12.0" }, + { name = "uipath-runtime", specifier = ">=0.11.4,<0.12.0" }, ] [package.metadata.requires-dev] @@ -2691,7 +2691,7 @@ dev = [ [[package]] name = "uipath-platform" -version = "0.1.77" +version = "0.1.78" source = { editable = "../uipath-platform" } dependencies = [ { name = "httpx" }, @@ -2729,14 +2729,14 @@ dev = [ [[package]] name = "uipath-runtime" -version = "0.11.2" +version = "0.11.4" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "uipath-core" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/da/87/fed3a5bd3479b9e7dc6cba769b054f5f1c00e93762356a70010e32f1f03c/uipath_runtime-0.11.2.tar.gz", hash = "sha256:8b3cc986644d6c9f2365345c231577f97d3bad8fb105fe8a6c7e16508d00d9ef", size = 145770, upload-time = "2026-06-22T16:31:40.786Z" } +sdist = { url = "https://files.pythonhosted.org/packages/45/a4/944a7d6ef63aedea3592cdd73f2477b156562f3fb094ecf613117decbec5/uipath_runtime-0.11.4.tar.gz", hash = "sha256:7094b63f259249c763774d971ce0f3e611ca5abc160f2e4157e888b1690d9aa8", size = 152254, upload-time = "2026-06-24T14:26:07.11Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/da/62/c649c18ac39f53e5603abbcfa6917f6e880ac08047b1ce69d4c3ee937de8/uipath_runtime-0.11.2-py3-none-any.whl", hash = "sha256:a3a14dc2378bc934437bbd7523cf884d0cee0eeef26c736a9d6ce504d8a9fea0", size = 43874, upload-time = "2026-06-22T16:31:39.328Z" }, + { url = "https://files.pythonhosted.org/packages/c4/73/730469eb53fcb1bc6b05251323830bc6012993f8cc12b2bb302deeea5679/uipath_runtime-0.11.4-py3-none-any.whl", hash = "sha256:072a620a45584d745da7c7b0ab43d590768acfed846c1b860b15aaa8fb93071a", size = 49826, upload-time = "2026-06-24T14:26:05.831Z" }, ] [[package]]