|
3 | 3 | import asyncio |
4 | 4 | import logging |
5 | 5 | import os |
| 6 | +import uuid |
6 | 7 | from typing import Any |
7 | 8 | from urllib.parse import urlparse |
8 | 9 |
|
|
12 | 13 | UiPathConversationEvent, |
13 | 14 | UiPathConversationExchangeEndEvent, |
14 | 15 | UiPathConversationExchangeEvent, |
| 16 | + UiPathConversationInterruptEvent, |
| 17 | + UiPathConversationInterruptStartEvent, |
| 18 | + UiPathConversationMessageEvent, |
15 | 19 | ) |
| 20 | +from uipath.runtime import UiPathRuntimeResult |
16 | 21 | from uipath.runtime.chat import UiPathChatProtocol |
17 | 22 | from uipath.runtime.context import UiPathRuntimeContext |
18 | 23 |
|
@@ -187,10 +192,81 @@ async def emit_message_event(self, message_event: Any) -> None: |
187 | 192 | await self._client.emit("ConversationEvent", event_data) |
188 | 193 | logger.debug("Conversation event sent successfully") |
189 | 194 |
|
| 195 | + # Store the current message ID, used for emitting interrupt events. |
| 196 | + self._current_message_id = message_event.message_id |
| 197 | + |
190 | 198 | except Exception as e: |
191 | 199 | logger.error(f"Error sending conversation event to WebSocket: {e}") |
192 | 200 | raise RuntimeError(f"Failed to send conversation event: {e}") from e |
193 | 201 |
|
| 202 | + async def emit_exchange_end_event(self) -> None: |
| 203 | + """Send an exchange end event. |
| 204 | +
|
| 205 | + Raises: |
| 206 | + RuntimeError: If client is not connected |
| 207 | + """ |
| 208 | + if self._client is None: |
| 209 | + raise RuntimeError("WebSocket client not connected. Call connect() first.") |
| 210 | + |
| 211 | + if not self._connected_event.is_set(): |
| 212 | + raise RuntimeError("WebSocket client not in connected state") |
| 213 | + |
| 214 | + try: |
| 215 | + exchange_end_event = UiPathConversationEvent( |
| 216 | + conversation_id=self.conversation_id, |
| 217 | + exchange=UiPathConversationExchangeEvent( |
| 218 | + exchange_id=self.exchange_id, |
| 219 | + end=UiPathConversationExchangeEndEvent(), |
| 220 | + ), |
| 221 | + ) |
| 222 | + |
| 223 | + event_data = exchange_end_event.model_dump( |
| 224 | + mode="json", exclude_none=True, by_alias=True |
| 225 | + ) |
| 226 | + |
| 227 | + await self._client.emit("ConversationEvent", event_data) |
| 228 | + |
| 229 | + except Exception as e: |
| 230 | + logger.error(f"Error sending conversation event to WebSocket: {e}") |
| 231 | + raise RuntimeError(f"Failed to send conversation event: {e}") from e |
| 232 | + |
| 233 | + async def emit_interrupt_event(self, runtime_result: UiPathRuntimeResult): |
| 234 | + if self._client and self._connected_event.is_set(): |
| 235 | + try: |
| 236 | + self._interrupt_id = str(uuid.uuid4()) |
| 237 | + |
| 238 | + interrupt_event = UiPathConversationEvent( |
| 239 | + conversation_id=self.conversation_id, |
| 240 | + exchange=UiPathConversationExchangeEvent( |
| 241 | + exchange_id=self.exchange_id, |
| 242 | + message=UiPathConversationMessageEvent( |
| 243 | + message_id=self._current_message_id, |
| 244 | + interrupt=UiPathConversationInterruptEvent( |
| 245 | + interrupt_id=self._interrupt_id, |
| 246 | + start=UiPathConversationInterruptStartEvent( |
| 247 | + type="coded-agent-interrupt", |
| 248 | + value=runtime_result.output, |
| 249 | + ), |
| 250 | + ), |
| 251 | + ), |
| 252 | + ), |
| 253 | + ) |
| 254 | + event_data = interrupt_event.model_dump( |
| 255 | + mode="json", exclude_none=True, by_alias=True |
| 256 | + ) |
| 257 | + await self._client.emit("ConversationEvent", event_data) |
| 258 | + logger.info("Interrupt event sent") |
| 259 | + except Exception as e: |
| 260 | + logger.warning(f"Error sending interrupt event: {e}") |
| 261 | + |
| 262 | + async def wait_for_resume(self) -> dict[str, Any]: |
| 263 | + """Wait for the interrupt_end event to be received. |
| 264 | +
|
| 265 | + Returns: |
| 266 | + Resume data from the interrupt end event |
| 267 | + """ |
| 268 | + return {} |
| 269 | + |
194 | 270 | @property |
195 | 271 | def is_connected(self) -> bool: |
196 | 272 | """Check if the WebSocket is currently connected. |
|
0 commit comments