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
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[project]
name = "uipath-runtime"
version = "0.0.22"
version = "0.0.23"
description = "Runtime abstractions and interfaces for building agents and automation scripts in the UiPath ecosystem"
readme = { file = "README.md", content-type = "text/markdown" }
requires-python = ">=3.11"
Expand Down
3 changes: 2 additions & 1 deletion src/uipath/runtime/result.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ class UiPathRuntimeStatus(str, Enum):
class UiPathRuntimeResult(UiPathRuntimeEvent):
"""Result of an execution with status and optional error information."""

output: dict[str, Any] | BaseModel | None = None
output: dict[str, Any] | BaseModel | str | None = None
status: UiPathRuntimeStatus = UiPathRuntimeStatus.SUCCESSFUL
trigger: UiPathResumeTrigger | None = None
error: UiPathErrorContract | None = None
Expand All @@ -32,6 +32,7 @@ class UiPathRuntimeResult(UiPathRuntimeEvent):

def to_dict(self) -> dict[str, Any]:
"""Convert to dictionary format for output."""
output_data: dict[str, Any] | str
if self.output is None:
output_data = {}
elif isinstance(self.output, BaseModel):
Expand Down
32 changes: 18 additions & 14 deletions src/uipath/runtime/resumable/runtime.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,9 +68,7 @@ async def execute(
result = await self.delegate.execute(input, options=options)

# If suspended, create and persist trigger
await self._handle_suspension(result)

return result
return await self._handle_suspension(result)

async def stream(
self,
Expand All @@ -90,18 +88,16 @@ async def stream(
if options and options.resume:
input = await self._restore_resume_input(input)

# Stream from delegate
final_result: UiPathRuntimeResult | None = None
async for event in self.delegate.stream(input, options=options):
yield event

# Capture final result
if isinstance(event, UiPathRuntimeResult):
final_result = event
else:
yield event

# If suspended, create and persist trigger
if final_result:
await self._handle_suspension(final_result)
yield await self._handle_suspension(final_result)

async def _restore_resume_input(
self, input: dict[str, Any] | None
Expand All @@ -128,27 +124,35 @@ async def _restore_resume_input(

return resume_data

async def _handle_suspension(self, result: UiPathRuntimeResult) -> None:
async def _handle_suspension(
self, result: UiPathRuntimeResult
) -> UiPathRuntimeResult:
"""Create and persist resume trigger if execution was suspended.

Args:
result: The execution result to check for suspension
"""
# Only handle suspensions
if result.status != UiPathRuntimeStatus.SUSPENDED:
return
return result

# Check if trigger already exists in result
if result.trigger:
await self.storage.save_trigger(result.trigger)
return
return result

suspended_result = UiPathRuntimeResult(
status=UiPathRuntimeStatus.SUSPENDED,
)

if result.output:
trigger = await self.trigger_manager.create_trigger(result.output)
suspended_result.trigger = await self.trigger_manager.create_trigger(
result.output
)

result.trigger = trigger
await self.storage.save_trigger(suspended_result.trigger)

await self.storage.save_trigger(trigger)
return suspended_result

async def get_schema(self) -> UiPathRuntimeSchema:
"""Passthrough schema from delegate runtime."""
Expand Down
2 changes: 1 addition & 1 deletion uv.lock

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