From 795815fdd3fe7fb71a0e691f41b3c45b5ba752ee Mon Sep 17 00:00:00 2001 From: Josh Park <50765702+JoshParkSJ@users.noreply.github.com> Date: Mon, 6 Jul 2026 08:02:13 -0400 Subject: [PATCH 1/3] fix: backport voice session end detail to uipath 2.11 --- packages/uipath/pyproject.toml | 4 +- .../src/uipath/_cli/_chat/_voice_bridge.py | 22 +++++++++- .../tests/cli/chat/test_voice_bridge.py | 41 +++++++++++++++++++ 3 files changed, 63 insertions(+), 4 deletions(-) diff --git a/packages/uipath/pyproject.toml b/packages/uipath/pyproject.toml index 63c4777a2..999ac1cc9 100644 --- a/packages/uipath/pyproject.toml +++ b/packages/uipath/pyproject.toml @@ -1,12 +1,12 @@ [project] name = "uipath" -version = "2.11.18" +version = "2.11.19" 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.26, <0.6.0", - "uipath-runtime>=0.11.5, <0.12.0", + "uipath-runtime>=0.11.9, <0.12.0", "uipath-platform>=0.1.83, <0.2.0", "click>=8.3.1", "httpx>=0.28.1", diff --git a/packages/uipath/src/uipath/_cli/_chat/_voice_bridge.py b/packages/uipath/src/uipath/_cli/_chat/_voice_bridge.py index b575404b3..b19394131 100644 --- a/packages/uipath/src/uipath/_cli/_chat/_voice_bridge.py +++ b/packages/uipath/src/uipath/_cli/_chat/_voice_bridge.py @@ -6,6 +6,7 @@ import logging import os from collections.abc import Awaitable, Callable +from copy import deepcopy from enum import Enum from typing import Any from urllib.parse import urlparse @@ -82,6 +83,12 @@ def __init__( self._done = asyncio.Event() self._in_flight: set[asyncio.Task[None]] = set() self._end_reason: VoiceSessionEndReason | None = None + self._end_detail: dict[str, Any] = {} + + @property + def end_detail(self) -> dict[str, Any]: + """CAS payload from voice_session_ended, preserved for the job runtime.""" + return deepcopy(self._end_detail) async def run(self) -> VoiceSessionEndReason: """Connect, dispatch tool calls until session ends, then disconnect. @@ -214,8 +221,19 @@ async def _execute_tool_call(self, call: UiPathVoiceToolCallRequest) -> None: tool_result.is_error, ) - async def _handle_session_ended(self, _data: Any, *_: Any) -> None: - logger.info("[Voice] voice_session_ended received") + async def _handle_session_ended(self, data: Any = None, *_: Any) -> None: + if self._done.is_set(): + return + + detail = deepcopy(data) if isinstance(data, dict) else {} + self._end_detail = detail + logger.info( + "[Voice] voice_session_ended received " + "(endedBy=%s, callEnded=%s, reason=%s)", + detail.get("endedBy"), + detail.get("callEnded"), + detail.get("reason"), + ) self._end_session(VoiceSessionEndReason.COMPLETED) diff --git a/packages/uipath/tests/cli/chat/test_voice_bridge.py b/packages/uipath/tests/cli/chat/test_voice_bridge.py index a9c8c1baf..dda7acd31 100644 --- a/packages/uipath/tests/cli/chat/test_voice_bridge.py +++ b/packages/uipath/tests/cli/chat/test_voice_bridge.py @@ -46,6 +46,47 @@ async def test_session_ended_sets_completed(self) -> None: await session._handle_session_ended(None) assert session._end_reason == VoiceSessionEndReason.COMPLETED + async def test_session_ended_preserves_payload_opaquely(self) -> None: + session = _make_session() + payload = { + "callContext": { + "type": "phone", + "id": "CA123", + "conversationId": "conv-1", + }, + "endedBy": "agent", + "callEnded": False, + "reason": "agent_completed", + "someFutureKey": {"nested": True}, + } + + await session._handle_session_ended(payload) + + assert session.end_detail == payload + assert session._end_reason == VoiceSessionEndReason.COMPLETED + returned_detail = session.end_detail + returned_detail["reason"] = "mutated" + returned_detail["callContext"]["id"] = "CA999" + payload["endedBy"] = "system" + assert session.end_detail["reason"] == "agent_completed" + assert session.end_detail["callContext"]["id"] == "CA123" + assert session.end_detail["endedBy"] == "agent" + + async def test_session_ended_non_dict_payload_is_empty_detail(self) -> None: + session = _make_session() + await session._handle_session_ended("not-a-dict") + assert session.end_detail == {} + assert session._end_reason == VoiceSessionEndReason.COMPLETED + + async def test_late_session_ended_does_not_overwrite_terminal_state(self) -> None: + session = _make_session() + await session._handle_session_ended({"endedBy": "agent", "callEnded": False}) + + await session._handle_session_ended({"endedBy": "system", "callEnded": True}) + + assert session.end_detail == {"endedBy": "agent", "callEnded": False} + assert session._end_reason == VoiceSessionEndReason.COMPLETED + async def test_disconnect_sets_disconnected(self) -> None: session = _make_session() await session._handle_disconnect() From ea1f90730df8005f5ec91455bc3f79041c91865f Mon Sep 17 00:00:00 2001 From: Josh Park <50765702+JoshParkSJ@users.noreply.github.com> Date: Mon, 6 Jul 2026 09:25:25 -0400 Subject: [PATCH 2/3] fix: keep uipath-runtime floor at >=0.11.5 (skip runtime 0.11.9 hotfix) --- packages/uipath/pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/uipath/pyproject.toml b/packages/uipath/pyproject.toml index 999ac1cc9..e891545da 100644 --- a/packages/uipath/pyproject.toml +++ b/packages/uipath/pyproject.toml @@ -6,7 +6,7 @@ readme = { file = "README.md", content-type = "text/markdown" } requires-python = ">=3.11" dependencies = [ "uipath-core>=0.5.26, <0.6.0", - "uipath-runtime>=0.11.9, <0.12.0", + "uipath-runtime>=0.11.5, <0.12.0", "uipath-platform>=0.1.83, <0.2.0", "click>=8.3.1", "httpx>=0.28.1", From 0268f2f5eae6e7ec1c7a8ede0cfa6bd8d8b9aa70 Mon Sep 17 00:00:00 2001 From: Joshua Park Date: Mon, 6 Jul 2026 09:31:17 -0400 Subject: [PATCH 3/3] chore: sync uv.lock for uipath 2.11.19 Co-Authored-By: Claude Opus 4.8 --- packages/uipath/uv.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/uipath/uv.lock b/packages/uipath/uv.lock index 0c265e9d0..5fef843c9 100644 --- a/packages/uipath/uv.lock +++ b/packages/uipath/uv.lock @@ -2552,7 +2552,7 @@ wheels = [ [[package]] name = "uipath" -version = "2.11.18" +version = "2.11.19" source = { editable = "." } dependencies = [ { name = "applicationinsights" },