Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
[project]
name = "uipath"
version = "2.2.23"
version = "2.2.24"
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-runtime>=0.2.2, <0.3.0",
"uipath-runtime>=0.2.3, <0.3.0",
"click>=8.3.1",
"httpx>=0.28.1",
"pyjwt>=2.10.1",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
logger = logging.getLogger(__name__)


class WebSocketChatBridge:
class SocketIOChatBridge:
"""WebSocket-based chat bridge for streaming conversational events to CAS.

Implements UiPathChatBridgeProtocol using python-socketio library.
Expand Down Expand Up @@ -221,8 +221,6 @@ async def _cleanup_client(self) -> None:

def get_chat_bridge(
context: UiPathRuntimeContext,
conversation_id: str,
exchange_id: str,
) -> UiPathChatProtocol:
"""Factory to get WebSocket chat bridge for conversational agents.

Expand All @@ -245,6 +243,9 @@ def get_chat_bridge(
await bridge.disconnect(conversation_id, exchange_id)
```
"""
assert context.conversation_id is not None, "conversation_id must be set in context"
assert context.exchange_id is not None, "exchange_id must be set in context"

# Extract host from UIPATH_URL
base_url = os.environ.get("UIPATH_URL")
if not base_url:
Expand All @@ -259,7 +260,7 @@ def get_chat_bridge(
host = parsed.netloc

# Construct WebSocket URL for CAS
websocket_url = f"wss://{host}/autopilotforeveryone_/websocket_/socket.io?conversationId={conversation_id}"
websocket_url = f"wss://{host}/autopilotforeveryone_/websocket_/socket.io?conversationId={context.conversation_id}"

# Build headers from context
headers = {
Expand All @@ -268,12 +269,15 @@ def get_chat_bridge(
or os.environ.get("UIPATH_TENANT_ID", ""),
"X-UiPath-Internal-AccountId": context.org_id
or os.environ.get("UIPATH_ORGANIZATION_ID", ""),
"X-UiPath-ConversationId": conversation_id,
"X-UiPath-ConversationId": context.conversation_id,
}

return WebSocketChatBridge(
return SocketIOChatBridge(
websocket_url=websocket_url,
conversation_id=conversation_id,
exchange_id=exchange_id,
conversation_id=context.conversation_id,
exchange_id=context.exchange_id,
headers=headers,
)


__all__ = ["get_chat_bridge"]
28 changes: 20 additions & 8 deletions src/uipath/_cli/cli_debug.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,17 @@
UiPathRuntimeFactoryRegistry,
UiPathRuntimeProtocol,
)
from uipath.runtime.chat import UiPathChatProtocol, UiPathChatRuntime
from uipath.runtime.debug import UiPathDebugBridgeProtocol, UiPathDebugRuntime

from uipath._cli._chat._bridge import get_chat_bridge
from uipath._cli._debug._bridge import get_debug_bridge
from uipath._cli._utils._debug import setup_debugging
from uipath._cli._utils._studio_project import StudioClient
from uipath._utils._bindings import ResourceOverwritesContext
from uipath.platform.common import UiPathConfig
from uipath.tracing import LlmOpsHttpExporter

from ._debug._bridge import get_debug_bridge
from ._utils._console import ConsoleLogger
from .middlewares import Middlewares

Expand Down Expand Up @@ -108,28 +110,36 @@ async def execute_debug_runtime():
command="debug",
) as ctx:
runtime: UiPathRuntimeProtocol | None = None
chat_runtime: UiPathRuntimeProtocol | None = None
debug_runtime: UiPathRuntimeProtocol | None = None
factory: UiPathRuntimeFactoryProtocol | None = None

try:
trigger_poll_interval: float = 5.0

factory = UiPathRuntimeFactoryRegistry.get(context=ctx)

runtime = await factory.new_runtime(
entrypoint, ctx.conversation_id or ctx.job_id or "default"
)

if ctx.job_id:
trace_manager.add_span_exporter(LlmOpsHttpExporter())
trigger_poll_interval = (
0.0 # Polling disabled for production jobs
)

factory = UiPathRuntimeFactoryRegistry.get(context=ctx)

runtime = await factory.new_runtime(
entrypoint, ctx.job_id or "default"
)
if ctx.conversation_id and ctx.exchange_id:
chat_bridge: UiPathChatProtocol = get_chat_bridge(
context=ctx
)
chat_runtime = UiPathChatRuntime(
delegate=runtime, chat_bridge=chat_bridge
)

debug_bridge: UiPathDebugBridgeProtocol = get_debug_bridge(ctx)

debug_runtime = UiPathDebugRuntime(
delegate=runtime,
delegate=chat_runtime or runtime,
debug_bridge=debug_bridge,
trigger_poll_interval=trigger_poll_interval,
)
Expand All @@ -155,6 +165,8 @@ async def execute_debug_runtime():
finally:
if debug_runtime:
await debug_runtime.dispose()
if chat_runtime:
await chat_runtime.dispose()
if runtime:
await runtime.dispose()
if factory:
Expand Down
22 changes: 20 additions & 2 deletions src/uipath/_cli/cli_run.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,13 @@
UiPathRuntimeResult,
UiPathStreamOptions,
)
from uipath.runtime.chat import UiPathChatProtocol, UiPathChatRuntime
from uipath.runtime.context import UiPathRuntimeContext
from uipath.runtime.debug import UiPathDebugBridgeProtocol
from uipath.runtime.errors import UiPathRuntimeError
from uipath.runtime.events import UiPathRuntimeStateEvent

from uipath._cli._chat._bridge import get_chat_bridge
from uipath._cli._debug._bridge import ConsoleDebugBridge
from uipath._cli._utils._common import read_resource_overwrites_from_file
from uipath._cli._utils._debug import setup_debugging
Expand Down Expand Up @@ -122,6 +124,7 @@ async def debug_runtime(
ctx: UiPathRuntimeContext, runtime: UiPathRuntimeProtocol
) -> UiPathRuntimeResult | None:
debug_bridge: UiPathDebugBridgeProtocol = ConsoleDebugBridge()

await debug_bridge.emit_execution_started()
options = UiPathStreamOptions(resume=resume)
async for event in runtime.stream(ctx.get_input(), options=options):
Expand Down Expand Up @@ -156,19 +159,34 @@ async def execute() -> None:
):
with ctx:
runtime: UiPathRuntimeProtocol | None = None
chat_runtime: UiPathRuntimeProtocol | None = None
factory: UiPathRuntimeFactoryProtocol | None = None
try:
factory = UiPathRuntimeFactoryRegistry.get(context=ctx)
runtime = await factory.new_runtime(
entrypoint, ctx.job_id or "default"
entrypoint,
ctx.conversation_id or ctx.job_id or "default",
)

if ctx.job_id:
trace_manager.add_span_exporter(LlmOpsHttpExporter())
ctx.result = await execute_runtime(ctx, runtime)

if ctx.conversation_id and ctx.exchange_id:
chat_bridge: UiPathChatProtocol = get_chat_bridge(
context=ctx
)
chat_runtime = UiPathChatRuntime(
delegate=runtime, chat_bridge=chat_bridge
)

ctx.result = await execute_runtime(
ctx, chat_runtime or runtime
)
else:
ctx.result = await debug_runtime(ctx, runtime)
finally:
if chat_runtime:
await chat_runtime.dispose()
if runtime:
await runtime.dispose()
if factory:
Expand Down
10 changes: 5 additions & 5 deletions uv.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.