|
16 | 16 | UiPathConversationMessageEvent, |
17 | 17 | UiPathConversationToolCallConfirmationEvent, |
18 | 18 | ) |
| 19 | +from uipath.core.triggers import UiPathResumeTrigger |
19 | 20 | from uipath.runtime.chat import UiPathChatProtocol |
20 | 21 | from uipath.runtime.context import UiPathRuntimeContext |
21 | 22 |
|
@@ -122,7 +123,9 @@ def __init__( |
122 | 123 | self._connected_event = asyncio.Event() |
123 | 124 |
|
124 | 125 | self._tool_confirmation_event = asyncio.Event() |
125 | | - self._tool_confirmation_value: UiPathConversationToolCallConfirmationEvent | None = None |
| 126 | + self._tool_confirmation_value: ( |
| 127 | + UiPathConversationToolCallConfirmationEvent | None |
| 128 | + ) = None |
126 | 129 | self._current_message_id: str | None = None |
127 | 130 |
|
128 | 131 | # Set CAS_WEBSOCKET_DISABLED when using the debugger to prevent websocket errors from |
@@ -265,6 +268,7 @@ async def emit_message_event( |
265 | 268 | else: |
266 | 269 | await self._client.emit("ConversationEvent", event_data) |
267 | 270 |
|
| 271 | + # Store the current message ID, used for emitting interrupt events. |
268 | 272 | self._current_message_id = message_event.message_id |
269 | 273 |
|
270 | 274 | except Exception as e: |
@@ -355,15 +359,37 @@ async def emit_exchange_error_event(self, error: Exception) -> None: |
355 | 359 | logger.error(f"Error sending exchange error event to WebSocket: {e}") |
356 | 360 | raise RuntimeError(f"Failed to send exchange error event: {e}") from e |
357 | 361 |
|
358 | | - async def wait_for_tool_confirmation(self) -> dict[str, Any]: |
| 362 | + async def emit_interrupt_event(self, resume_trigger: UiPathResumeTrigger): |
| 363 | + """No-op. |
| 364 | +
|
| 365 | + Tool confirmation — the only interrupt pattern CAS uses today — is |
| 366 | + handled end-to-end via ``startToolCall`` with ``requireConfirmation: |
| 367 | + true`` paired with ``wait_for_resume()`` for the ``confirmToolCall`` |
| 368 | + response. This is deliberately simpler than the old interrupt-based |
| 369 | + flow: CAS needs ``requireConfirmation`` and ``inputSchema`` on the |
| 370 | + tool call event itself to render the confirmation UI, so a parallel |
| 371 | + ``startInterrupt`` event would be redundant. |
| 372 | +
|
| 373 | + The only hypothetical reason to put work here is a generic, |
| 374 | + non-tool-call agent interrupt (e.g. a coded agent calling |
| 375 | + ``interrupt("do you want to continue?")``). Nothing uses that today |
| 376 | + and it's not a near-term requirement — but the method is kept as a |
| 377 | + protocol hook so the ``UiPathChatProtocol`` contract doesn't have |
| 378 | + to churn if that ever becomes real. |
| 379 | + """ |
| 380 | + return None |
| 381 | + |
| 382 | + async def wait_for_resume(self) -> dict[str, Any]: |
359 | 383 | """Wait for a confirmToolCall event to be received.""" |
360 | 384 | self._tool_confirmation_event.clear() |
361 | 385 | self._tool_confirmation_value = None |
362 | 386 |
|
363 | 387 | await self._tool_confirmation_event.wait() |
364 | 388 |
|
365 | 389 | if self._tool_confirmation_value: |
366 | | - return self._tool_confirmation_value.model_dump(mode="python", by_alias=False) |
| 390 | + return self._tool_confirmation_value.model_dump( |
| 391 | + mode="python", by_alias=False |
| 392 | + ) |
367 | 393 | return {} |
368 | 394 |
|
369 | 395 | @property |
@@ -395,11 +421,15 @@ async def _handle_conversation_event( |
395 | 421 |
|
396 | 422 | try: |
397 | 423 | parsed_event = UiPathConversationEvent(**event) |
398 | | - message = parsed_event.exchange.message if parsed_event.exchange else None |
399 | | - if message and message.tool_call and message.tool_call.confirm: |
400 | | - confirm = message.tool_call.confirm |
| 424 | + tool_call = ( |
| 425 | + parsed_event.exchange.message.tool_call |
| 426 | + if parsed_event.exchange and parsed_event.exchange.message |
| 427 | + else None |
| 428 | + ) |
| 429 | + confirm = tool_call.confirm if tool_call else None |
| 430 | + if tool_call and confirm: |
401 | 431 | logger.info( |
402 | | - f"Received confirmToolCall for tool_call_id: {message.tool_call.tool_call_id}, approved: {confirm.approved}" |
| 432 | + f"Received confirmToolCall for tool_call_id: {tool_call.tool_call_id}, approved: {confirm.approved}" |
403 | 433 | ) |
404 | 434 | self._tool_confirmation_value = confirm |
405 | 435 | self._tool_confirmation_event.set() |
|
0 commit comments