Skip to content

Commit 81b4308

Browse files
committed
feat: add resumable runtime
1 parent d0db5e5 commit 81b4308

File tree

10 files changed

+369
-62
lines changed

10 files changed

+369
-62
lines changed

src/uipath/runtime/__init__.py

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,19 +8,33 @@
88
UiPathStreamOptions,
99
)
1010
from uipath.runtime.context import UiPathRuntimeContext
11+
from uipath.runtime.debug.breakpoint import UiPathBreakpointResult
12+
from uipath.runtime.debug.bridge import UiPathDebugBridgeProtocol
13+
from uipath.runtime.debug.exception import UiPathDebugQuitError
14+
from uipath.runtime.debug.runtime import (
15+
UiPathDebugRuntime,
16+
)
1117
from uipath.runtime.events import UiPathRuntimeEvent
1218
from uipath.runtime.factory import (
1319
UiPathRuntimeCreatorProtocol,
1420
UiPathRuntimeFactoryProtocol,
1521
UiPathRuntimeScannerProtocol,
1622
)
1723
from uipath.runtime.result import (
24+
UiPathRuntimeResult,
25+
UiPathRuntimeStatus,
26+
)
27+
from uipath.runtime.resumable.protocols import (
28+
UiPathResumableStorageProtocol,
29+
UiPathResumeTriggerProtocol,
30+
)
31+
from uipath.runtime.resumable.runtime import (
32+
UiPathResumableRuntime,
33+
)
34+
from uipath.runtime.resumable.trigger import (
1835
UiPathApiTrigger,
19-
UiPathBreakpointResult,
2036
UiPathResumeTrigger,
2137
UiPathResumeTriggerType,
22-
UiPathRuntimeResult,
23-
UiPathRuntimeStatus,
2438
)
2539

2640
__all__ = [
@@ -35,9 +49,15 @@
3549
"UiPathRuntimeResult",
3650
"UiPathRuntimeStatus",
3751
"UiPathRuntimeEvent",
38-
"UiPathBreakpointResult",
52+
"UiPathResumableStorageProtocol",
53+
"UiPathResumeTriggerProtocol",
3954
"UiPathApiTrigger",
4055
"UiPathResumeTrigger",
4156
"UiPathResumeTriggerType",
57+
"UiPathResumableRuntime",
58+
"UiPathDebugQuitError",
59+
"UiPathDebugBridgeProtocol",
60+
"UiPathDebugRuntime",
61+
"UiPathBreakpointResult",
4262
"UiPathStreamNotSupportedError",
4363
]

src/uipath/runtime/debug/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
"""Initialization module for the debug package."""
22

3+
from uipath.runtime.debug.breakpoint import UiPathBreakpointResult
34
from uipath.runtime.debug.bridge import UiPathDebugBridgeProtocol
45
from uipath.runtime.debug.exception import (
56
UiPathDebugQuitError,
@@ -10,4 +11,5 @@
1011
"UiPathDebugQuitError",
1112
"UiPathDebugBridgeProtocol",
1213
"UiPathDebugRuntime",
14+
"UiPathBreakpointResult",
1315
]
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
"""Module defining the result for execution suspended at a breakpoint."""
2+
3+
from typing import Any, Literal
4+
5+
from pydantic import Field
6+
7+
from uipath.runtime.result import UiPathRuntimeResult, UiPathRuntimeStatus
8+
9+
10+
class UiPathBreakpointResult(UiPathRuntimeResult):
11+
"""Result for execution suspended at a breakpoint."""
12+
13+
# Force status to always be SUSPENDED
14+
status: UiPathRuntimeStatus = Field(
15+
default=UiPathRuntimeStatus.SUSPENDED, frozen=True
16+
)
17+
breakpoint_node: str # Which node the breakpoint is at
18+
breakpoint_type: Literal["before", "after"] # Before or after the node
19+
current_state: dict[str, Any] | Any # Current workflow state at breakpoint
20+
next_nodes: list[str] # Which node(s) will execute next

src/uipath/runtime/debug/bridge.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,11 @@
22

33
from typing import Any, Literal, Protocol
44

5-
from uipath.runtime import (
6-
UiPathBreakpointResult,
5+
from uipath.runtime.debug.breakpoint import UiPathBreakpointResult
6+
from uipath.runtime.events import UiPathRuntimeStateEvent
7+
from uipath.runtime.result import (
78
UiPathRuntimeResult,
89
)
9-
from uipath.runtime.events import UiPathRuntimeStateEvent
1010

1111

1212
class UiPathDebugBridgeProtocol(Protocol):

src/uipath/runtime/debug/runtime.py

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,19 +3,24 @@
33
import logging
44
from typing import Any, Optional
55

6-
from uipath.runtime import (
7-
UiPathBreakpointResult,
6+
from uipath.runtime.base import (
87
UiPathExecuteOptions,
98
UiPathRuntimeProtocol,
10-
UiPathRuntimeResult,
11-
UiPathRuntimeStatus,
129
UiPathStreamNotSupportedError,
1310
UiPathStreamOptions,
1411
)
15-
from uipath.runtime.debug import UiPathDebugBridgeProtocol, UiPathDebugQuitError
12+
from uipath.runtime.debug import (
13+
UiPathBreakpointResult,
14+
UiPathDebugBridgeProtocol,
15+
UiPathDebugQuitError,
16+
)
1617
from uipath.runtime.events import (
1718
UiPathRuntimeStateEvent,
1819
)
20+
from uipath.runtime.result import (
21+
UiPathRuntimeResult,
22+
UiPathRuntimeStatus,
23+
)
1924
from uipath.runtime.schema import UiPathRuntimeSchema
2025

2126
logger = logging.getLogger(__name__)

src/uipath/runtime/result.py

Lines changed: 2 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
"""Result of an execution with status and optional error information."""
22

33
from enum import Enum
4-
from typing import Any, Literal, Optional, Union
4+
from typing import Any, Optional, Union
55

66
from pydantic import BaseModel, Field
77

88
from uipath.runtime.errors import UiPathErrorContract
99
from uipath.runtime.events import UiPathRuntimeEvent, UiPathRuntimeEventType
10+
from uipath.runtime.resumable.trigger import UiPathResumeTrigger
1011

1112

1213
class UiPathRuntimeStatus(str, Enum):
@@ -17,42 +18,6 @@ class UiPathRuntimeStatus(str, Enum):
1718
SUSPENDED = "suspended"
1819

1920

20-
class UiPathResumeTriggerType(str, Enum):
21-
"""Constants representing different types of resume job triggers in the system."""
22-
23-
NONE = "None"
24-
QUEUE_ITEM = "QueueItem"
25-
JOB = "Job"
26-
ACTION = "Task"
27-
TIMER = "Timer"
28-
INBOX = "Inbox"
29-
API = "Api"
30-
31-
32-
class UiPathApiTrigger(BaseModel):
33-
"""API resume trigger request."""
34-
35-
inbox_id: Optional[str] = Field(default=None, alias="inboxId")
36-
request: Any = None
37-
38-
model_config = {"populate_by_name": True}
39-
40-
41-
class UiPathResumeTrigger(BaseModel):
42-
"""Information needed to resume execution."""
43-
44-
trigger_type: UiPathResumeTriggerType = Field(
45-
default=UiPathResumeTriggerType.API, alias="triggerType"
46-
)
47-
item_key: Optional[str] = Field(default=None, alias="itemKey")
48-
api_resume: Optional[UiPathApiTrigger] = Field(default=None, alias="apiResume")
49-
folder_path: Optional[str] = Field(default=None, alias="folderPath")
50-
folder_key: Optional[str] = Field(default=None, alias="folderKey")
51-
payload: Optional[Any] = Field(default=None, alias="interruptObject")
52-
53-
model_config = {"populate_by_name": True}
54-
55-
5621
class UiPathRuntimeResult(UiPathRuntimeEvent):
5722
"""Result of an execution with status and optional error information."""
5823

@@ -86,16 +51,3 @@ def to_dict(self) -> dict[str, Any]:
8651
result["error"] = self.error.model_dump()
8752

8853
return result
89-
90-
91-
class UiPathBreakpointResult(UiPathRuntimeResult):
92-
"""Result for execution suspended at a breakpoint."""
93-
94-
# Force status to always be SUSPENDED
95-
status: UiPathRuntimeStatus = Field(
96-
default=UiPathRuntimeStatus.SUSPENDED, frozen=True
97-
)
98-
breakpoint_node: str # Which node the breakpoint is at
99-
breakpoint_type: Literal["before", "after"] # Before or after the node
100-
current_state: dict[str, Any] | Any # Current workflow state at breakpoint
101-
next_nodes: list[str] # Which node(s) will execute next
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
"""Module for resumable runtime features."""
2+
3+
from uipath.runtime.resumable.protocols import (
4+
UiPathResumableStorageProtocol,
5+
UiPathResumeTriggerCreatorProtocol,
6+
UiPathResumeTriggerProtocol,
7+
UiPathResumeTriggerReaderProtocol,
8+
)
9+
from uipath.runtime.resumable.trigger import (
10+
UiPathApiTrigger,
11+
UiPathResumeTrigger,
12+
UiPathResumeTriggerType,
13+
)
14+
15+
__all__ = [
16+
"UiPathResumableStorageProtocol",
17+
"UiPathResumeTriggerCreatorProtocol",
18+
"UiPathResumeTriggerReaderProtocol",
19+
"UiPathResumeTriggerProtocol",
20+
"UiPathResumeTrigger",
21+
"UiPathResumeTriggerType",
22+
"UiPathApiTrigger",
23+
]
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
"""Module defining the protocol for resume trigger storage."""
2+
3+
from typing import Any, Optional, Protocol
4+
5+
from uipath.runtime.resumable.trigger import UiPathResumeTrigger
6+
7+
8+
class UiPathResumableStorageProtocol(Protocol):
9+
"""Protocol for storing and retrieving resume triggers."""
10+
11+
async def save_trigger(self, trigger: UiPathResumeTrigger) -> None:
12+
"""Save a resume trigger to storage.
13+
14+
Args:
15+
trigger: The resume trigger to persist
16+
17+
Raises:
18+
Exception: If storage operation fails
19+
"""
20+
...
21+
22+
async def get_latest_trigger(self) -> Optional[UiPathResumeTrigger]:
23+
"""Retrieve the most recent resume trigger from storage.
24+
25+
Returns:
26+
The latest resume trigger, or None if no triggers exist
27+
28+
Raises:
29+
Exception: If retrieval operation fails
30+
"""
31+
...
32+
33+
34+
class UiPathResumeTriggerCreatorProtocol(Protocol):
35+
"""Protocol for creating resume triggers from suspend values."""
36+
37+
async def create_trigger(self, suspend_value: Any) -> UiPathResumeTrigger:
38+
"""Create a resume trigger from a suspend value.
39+
40+
Args:
41+
suspend_value: The value that caused the suspension.
42+
Can be UiPath models (CreateAction, InvokeProcess, etc.),
43+
strings, or any other value that needs HITL processing.
44+
45+
Returns:
46+
UiPathResumeTrigger ready to be persisted
47+
48+
Raises:
49+
UiPathRuntimeError: If trigger creation fails
50+
"""
51+
...
52+
53+
54+
class UiPathResumeTriggerReaderProtocol(Protocol):
55+
"""Protocol for reading resume triggers and converting them to runtime input."""
56+
57+
async def read_trigger(self, trigger: UiPathResumeTrigger) -> Optional[Any]:
58+
"""Read a resume trigger and convert it to runtime-compatible input.
59+
60+
This method retrieves data from UiPath services (Actions, Jobs, API)
61+
based on the trigger type and returns it in a format that the
62+
runtime can use to resume execution.
63+
64+
Args:
65+
trigger: The resume trigger to read
66+
67+
Returns:
68+
The data retrieved from UiPath services, ready to be used
69+
as resume input. Format depends on trigger type:
70+
- ACTION: Action data (possibly with escalation processing)
71+
- JOB: Job output data
72+
- API: API payload
73+
Returns None if no data is available.
74+
75+
Raises:
76+
UiPathRuntimeError: If reading fails or job failed
77+
"""
78+
...
79+
80+
81+
class UiPathResumeTriggerProtocol(
82+
UiPathResumeTriggerCreatorProtocol, UiPathResumeTriggerReaderProtocol, Protocol
83+
):
84+
"""Protocol combining both creation and reading of resume triggers."""

0 commit comments

Comments
 (0)