Skip to content

Commit bb789ee

Browse files
authored
Merge pull request #1034 from UiPath/feature/update-uipath-runtime-version
feat: update runtime version
2 parents 75f6238 + eabb4aa commit bb789ee

File tree

6 files changed

+92
-41
lines changed

6 files changed

+92
-41
lines changed

pyproject.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
[project]
22
name = "uipath"
3-
version = "2.2.45"
3+
version = "2.3.0"
44
description = "Python SDK and CLI for UiPath Platform, enabling programmatic interaction with automation services, process management, and deployment tools."
55
readme = { file = "README.md", content-type = "text/markdown" }
66
requires-python = ">=3.11"
77
dependencies = [
8-
"uipath-runtime>=0.2.7, <0.3.0",
98
"uipath-core>=0.1.4, <0.2.0",
9+
"uipath-runtime>=0.3.1, <0.4.0",
1010
"click>=8.3.1",
1111
"httpx>=0.28.1",
1212
"pyjwt>=2.10.1",

src/uipath/_cli/_chat/_bridge.py

Lines changed: 78 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import asyncio
44
import logging
55
import os
6+
import uuid
67
from typing import Any
78
from urllib.parse import urlparse
89

@@ -12,7 +13,11 @@
1213
UiPathConversationEvent,
1314
UiPathConversationExchangeEndEvent,
1415
UiPathConversationExchangeEvent,
16+
UiPathConversationInterruptEvent,
17+
UiPathConversationInterruptStartEvent,
18+
UiPathConversationMessageEvent,
1519
)
20+
from uipath.runtime import UiPathRuntimeResult
1621
from uipath.runtime.chat import UiPathChatProtocol
1722
from uipath.runtime.context import UiPathRuntimeContext
1823

@@ -82,7 +87,6 @@ async def connect(self, timeout: float = 10.0) -> None:
8287
self._client.on("disconnect", self._handle_disconnect)
8388
self._client.on("connect_error", self._handle_connect_error)
8489

85-
# Clear connection event
8690
self._connected_event.clear()
8791

8892
try:
@@ -98,11 +102,8 @@ async def connect(self, timeout: float = 10.0) -> None:
98102
timeout=timeout,
99103
)
100104

101-
# Wait for connection confirmation
102105
await asyncio.wait_for(self._connected_event.wait(), timeout=timeout)
103106

104-
logger.info("WebSocket connection established successfully")
105-
106107
except asyncio.TimeoutError as e:
107108
error_message = (
108109
f"Failed to connect to WebSocket server within {timeout}s timeout"
@@ -127,34 +128,16 @@ async def disconnect(self) -> None:
127128
logger.warning("WebSocket client not connected")
128129
return
129130

130-
# Send exchange end event using stored IDs
131-
if self._client and self._connected_event.is_set():
132-
try:
133-
end_event = UiPathConversationEvent(
134-
conversation_id=self.conversation_id,
135-
exchange=UiPathConversationExchangeEvent(
136-
exchange_id=self.exchange_id,
137-
end=UiPathConversationExchangeEndEvent(),
138-
),
139-
)
140-
event_data = end_event.model_dump(
141-
mode="json", exclude_none=True, by_alias=True
142-
)
143-
await self._client.emit("ConversationEvent", event_data)
144-
logger.info("Exchange end event sent")
145-
except Exception as e:
146-
logger.warning(f"Error sending exchange end event: {e}")
147-
148131
try:
149-
logger.info("Disconnecting from WebSocket server")
150132
await self._client.disconnect()
151-
logger.info("WebSocket disconnected successfully")
152133
except Exception as e:
153134
logger.error(f"Error during WebSocket disconnect: {e}")
154135
finally:
155136
await self._cleanup_client()
156137

157-
async def emit_message_event(self, message_event: Any) -> None:
138+
async def emit_message_event(
139+
self, message_event: UiPathConversationMessageEvent
140+
) -> None:
158141
"""Wrap and send a message event to the WebSocket server.
159142
160143
Args:
@@ -183,14 +166,82 @@ async def emit_message_event(self, message_event: Any) -> None:
183166
mode="json", exclude_none=True, by_alias=True
184167
)
185168

186-
logger.debug("Sending conversation event to WebSocket")
187169
await self._client.emit("ConversationEvent", event_data)
188-
logger.debug("Conversation event sent successfully")
170+
171+
# Store the current message ID, used for emitting interrupt events.
172+
self._current_message_id = message_event.message_id
173+
174+
except Exception as e:
175+
logger.error(f"Error sending conversation event to WebSocket: {e}")
176+
raise RuntimeError(f"Failed to send conversation event: {e}") from e
177+
178+
async def emit_exchange_end_event(self) -> None:
179+
"""Send an exchange end event.
180+
181+
Raises:
182+
RuntimeError: If client is not connected
183+
"""
184+
if self._client is None:
185+
raise RuntimeError("WebSocket client not connected. Call connect() first.")
186+
187+
if not self._connected_event.is_set():
188+
raise RuntimeError("WebSocket client not in connected state")
189+
190+
try:
191+
exchange_end_event = UiPathConversationEvent(
192+
conversation_id=self.conversation_id,
193+
exchange=UiPathConversationExchangeEvent(
194+
exchange_id=self.exchange_id,
195+
end=UiPathConversationExchangeEndEvent(),
196+
),
197+
)
198+
199+
event_data = exchange_end_event.model_dump(
200+
mode="json", exclude_none=True, by_alias=True
201+
)
202+
203+
await self._client.emit("ConversationEvent", event_data)
189204

190205
except Exception as e:
191206
logger.error(f"Error sending conversation event to WebSocket: {e}")
192207
raise RuntimeError(f"Failed to send conversation event: {e}") from e
193208

209+
async def emit_interrupt_event(self, runtime_result: UiPathRuntimeResult):
210+
if self._client and self._connected_event.is_set():
211+
try:
212+
self._interrupt_id = str(uuid.uuid4())
213+
214+
interrupt_event = UiPathConversationEvent(
215+
conversation_id=self.conversation_id,
216+
exchange=UiPathConversationExchangeEvent(
217+
exchange_id=self.exchange_id,
218+
message=UiPathConversationMessageEvent(
219+
message_id=self._current_message_id,
220+
interrupt=UiPathConversationInterruptEvent(
221+
interrupt_id=self._interrupt_id,
222+
start=UiPathConversationInterruptStartEvent(
223+
type="coded-agent-interrupt",
224+
value=runtime_result.output,
225+
),
226+
),
227+
),
228+
),
229+
)
230+
event_data = interrupt_event.model_dump(
231+
mode="json", exclude_none=True, by_alias=True
232+
)
233+
await self._client.emit("ConversationEvent", event_data)
234+
except Exception as e:
235+
logger.warning(f"Error sending interrupt event: {e}")
236+
237+
async def wait_for_resume(self) -> dict[str, Any]:
238+
"""Wait for the interrupt_end event to be received.
239+
240+
Returns:
241+
Resume data from the interrupt end event
242+
"""
243+
return {}
244+
194245
@property
195246
def is_connected(self) -> bool:
196247
"""Check if the WebSocket is currently connected.

src/uipath/_cli/_debug/_bridge.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
UiPathRuntimeResult,
1919
UiPathRuntimeStatus,
2020
)
21-
from uipath.runtime.debug import UiPathDebugBridgeProtocol, UiPathDebugQuitError
21+
from uipath.runtime.debug import UiPathDebugProtocol, UiPathDebugQuitError
2222
from uipath.runtime.events import UiPathRuntimeStateEvent
2323
from uipath.runtime.resumable import UiPathResumeTriggerType
2424

@@ -846,7 +846,7 @@ async def _handle_error(self, error: Any) -> None:
846846
logger.error(f"SignalR error: {error}")
847847

848848

849-
def get_remote_debug_bridge(context: UiPathRuntimeContext) -> UiPathDebugBridgeProtocol:
849+
def get_remote_debug_bridge(context: UiPathRuntimeContext) -> UiPathDebugProtocol:
850850
"""Factory to get SignalR debug bridge for remote debugging."""
851851
uipath_url = os.environ.get("UIPATH_URL")
852852
if not uipath_url or not context.job_id:
@@ -869,7 +869,7 @@ def get_remote_debug_bridge(context: UiPathRuntimeContext) -> UiPathDebugBridgeP
869869

870870
def get_debug_bridge(
871871
context: UiPathRuntimeContext, verbose: bool = True
872-
) -> UiPathDebugBridgeProtocol:
872+
) -> UiPathDebugProtocol:
873873
"""Factory to get appropriate debug bridge based on context.
874874
875875
Args:

src/uipath/_cli/cli_debug.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
UiPathRuntimeProtocol,
1111
)
1212
from uipath.runtime.chat import UiPathChatProtocol, UiPathChatRuntime
13-
from uipath.runtime.debug import UiPathDebugBridgeProtocol, UiPathDebugRuntime
13+
from uipath.runtime.debug import UiPathDebugProtocol, UiPathDebugRuntime
1414

1515
from uipath._cli._chat._bridge import get_chat_bridge
1616
from uipath._cli._debug._bridge import get_debug_bridge
@@ -136,7 +136,7 @@ async def execute_debug_runtime():
136136
delegate=runtime, chat_bridge=chat_bridge
137137
)
138138

139-
debug_bridge: UiPathDebugBridgeProtocol = get_debug_bridge(ctx)
139+
debug_bridge: UiPathDebugProtocol = get_debug_bridge(ctx)
140140

141141
debug_runtime = UiPathDebugRuntime(
142142
delegate=chat_runtime or runtime,

src/uipath/_cli/cli_run.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
)
1313
from uipath.runtime.chat import UiPathChatProtocol, UiPathChatRuntime
1414
from uipath.runtime.context import UiPathRuntimeContext
15-
from uipath.runtime.debug import UiPathDebugBridgeProtocol
15+
from uipath.runtime.debug import UiPathDebugProtocol
1616
from uipath.runtime.errors import UiPathRuntimeError
1717
from uipath.runtime.events import UiPathRuntimeStateEvent
1818

@@ -123,7 +123,7 @@ async def execute_runtime(
123123
async def debug_runtime(
124124
ctx: UiPathRuntimeContext, runtime: UiPathRuntimeProtocol
125125
) -> UiPathRuntimeResult | None:
126-
debug_bridge: UiPathDebugBridgeProtocol = ConsoleDebugBridge()
126+
debug_bridge: UiPathDebugProtocol = ConsoleDebugBridge()
127127

128128
await debug_bridge.emit_execution_started()
129129
options = UiPathStreamOptions(resume=resume)

uv.lock

Lines changed: 5 additions & 5 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)