Skip to content

Commit 0a8fef4

Browse files
feat: add chat bridge protocol
1 parent 4a4868d commit 0a8fef4

File tree

7 files changed

+628
-180
lines changed

7 files changed

+628
-180
lines changed

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[project]
22
name = "uipath-runtime"
3-
version = "0.2.0"
3+
version = "0.2.1"
44
description = "Runtime abstractions and interfaces for building agents and automation scripts in the UiPath ecosystem"
55
readme = { file = "README.md", content-type = "text/markdown" }
66
requires-python = ">=3.11"

src/uipath/runtime/__init__.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77
UiPathStreamNotSupportedError,
88
UiPathStreamOptions,
99
)
10+
from uipath.runtime.chat.bridge import UiPathChatBridgeProtocol
11+
from uipath.runtime.chat.runtime import UiPathChatRuntime
1012
from uipath.runtime.context import UiPathRuntimeContext
1113
from uipath.runtime.debug.breakpoint import UiPathBreakpointResult
1214
from uipath.runtime.debug.bridge import UiPathDebugBridgeProtocol
@@ -66,4 +68,6 @@
6668
"UiPathBreakpointResult",
6769
"UiPathStreamNotSupportedError",
6870
"UiPathResumeTriggerName",
71+
"UiPathChatBridgeProtocol",
72+
"UiPathChatRuntime",
6973
]
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
"""Chat bridge protocol and runtime for conversational agents."""
2+
3+
from uipath.runtime.chat.bridge import UiPathChatBridgeProtocol
4+
from uipath.runtime.chat.runtime import UiPathChatRuntime
5+
6+
__all__ = ["UiPathChatBridgeProtocol", "UiPathChatRuntime"]

src/uipath/runtime/chat/bridge.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
"""Abstract conversation bridge interface."""
2+
3+
from typing import Any, Protocol
4+
5+
from uipath.core.chat import UiPathConversationMessageEvent
6+
7+
8+
class UiPathChatBridgeProtocol(Protocol):
9+
"""Abstract interface for chat communication.
10+
11+
Implementations: WebSocket, etc.
12+
"""
13+
14+
async def connect(self) -> None:
15+
"""Establish connection to chat service."""
16+
...
17+
18+
async def disconnect(self) -> None:
19+
"""Close connection and send exchange end event."""
20+
...
21+
22+
async def emit_message_event(self, message_event: UiPathConversationMessageEvent) -> None:
23+
"""Wrap and send a message event.
24+
25+
Args:
26+
message_event: UiPathConversationMessageEvent to wrap and send
27+
"""
28+
...

src/uipath/runtime/chat/runtime.py

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
"""Chat runtime implementation."""
2+
3+
import logging
4+
from typing import Any, AsyncGenerator, cast
5+
6+
from uipath.runtime.base import (
7+
UiPathExecuteOptions,
8+
UiPathRuntimeProtocol,
9+
UiPathStreamOptions,
10+
)
11+
from uipath.runtime.chat.bridge import UiPathChatBridgeProtocol
12+
from uipath.runtime.events import (
13+
UiPathRuntimeEvent,
14+
UiPathRuntimeMessageEvent,
15+
)
16+
from uipath.runtime.result import (
17+
UiPathRuntimeResult,
18+
UiPathRuntimeStatus,
19+
)
20+
from uipath.runtime.schema import UiPathRuntimeSchema
21+
22+
logger = logging.getLogger(__name__)
23+
24+
25+
class UiPathChatRuntime:
26+
"""Specialized runtime for chat mode that streams message events to a chat bridge."""
27+
28+
def __init__(
29+
self,
30+
delegate: UiPathRuntimeProtocol,
31+
chat_bridge: UiPathChatBridgeProtocol,
32+
):
33+
"""Initialize the UiPathChatRuntime.
34+
35+
Args:
36+
delegate: The underlying runtime to wrap
37+
chat_bridge: Bridge for chat event communication
38+
"""
39+
super().__init__()
40+
self.delegate = delegate
41+
self.chat_bridge = chat_bridge
42+
43+
async def execute(
44+
self,
45+
input: dict[str, Any] | None = None,
46+
options: UiPathExecuteOptions | None = None,
47+
) -> UiPathRuntimeResult:
48+
"""Execute the workflow with chat support."""
49+
result: UiPathRuntimeResult | None = None
50+
async for event in self.stream(input, cast(UiPathStreamOptions, options)):
51+
if isinstance(event, UiPathRuntimeResult):
52+
result = event
53+
54+
return (
55+
result
56+
if result
57+
else UiPathRuntimeResult(status=UiPathRuntimeStatus.SUCCESSFUL)
58+
)
59+
60+
async def stream(
61+
self,
62+
input: dict[str, Any] | None = None,
63+
options: UiPathStreamOptions | None = None,
64+
) -> AsyncGenerator[UiPathRuntimeEvent, None]:
65+
"""Stream execution events with chat support."""
66+
await self.chat_bridge.connect()
67+
68+
result: UiPathRuntimeResult | None = None
69+
70+
async for event in self.delegate.stream(input, options=options):
71+
# Send message events to chat bridge
72+
if isinstance(event, UiPathRuntimeMessageEvent):
73+
if event.payload:
74+
await self.chat_bridge.emit_message_event(event.payload)
75+
76+
yield event
77+
78+
if isinstance(event, UiPathRuntimeResult):
79+
result = event
80+
81+
if result:
82+
logger.info(f"Chat execution completed with status: {result.status}")
83+
84+
# Always disconnect from chat bridge
85+
await self.chat_bridge.disconnect()
86+
87+
async def get_schema(self) -> UiPathRuntimeSchema:
88+
"""Get schema from the delegate runtime."""
89+
return await self.delegate.get_schema()
90+
91+
async def dispose(self) -> None:
92+
"""Dispose the delegate runtime."""
93+
await self.delegate.dispose()

0 commit comments

Comments
 (0)