diff --git a/pyproject.toml b/pyproject.toml index 9d841d9..a9d504e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,11 +1,11 @@ [project] name = "uipath-runtime" -version = "0.8.4" +version = "0.8.5" 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" dependencies = [ - "uipath-core>=0.4.0, <0.5.0", + "uipath-core>=0.4.1, <0.5.0", ] classifiers = [ "Intended Audience :: Developers", diff --git a/src/uipath/runtime/resumable/runtime.py b/src/uipath/runtime/resumable/runtime.py index fd6ea35..b11f50c 100644 --- a/src/uipath/runtime/resumable/runtime.py +++ b/src/uipath/runtime/resumable/runtime.py @@ -83,11 +83,8 @@ async def execute( suspension_result = await self._handle_suspension(result) # check if any trigger may be resumed - # api triggers cannot be completed before suspending the job, skip them if suspension_result.status != UiPathRuntimeStatus.SUSPENDED or not ( - fired_triggers := await self._restore_resume_input( - None, skip_trigger_types=[UiPathResumeTriggerType.API] - ) + fired_triggers := await self._get_fired_triggers() ): return suspension_result @@ -133,11 +130,8 @@ async def stream( suspension_result = await self._handle_suspension(final_result) # check if any trigger may be resumed - # api triggers cannot be completed before suspending the job, skip them if suspension_result.status != UiPathRuntimeStatus.SUSPENDED or not ( - fired_triggers := await self._restore_resume_input( - None, skip_trigger_types=[UiPathResumeTriggerType.API] - ) + fired_triggers := await self._get_fired_triggers() ): yield suspension_result execution_completed = True @@ -151,10 +145,26 @@ async def stream( else: options.resume = True + async def _get_fired_triggers(self) -> dict[str, Any] | None: + """Check stored triggers for any that have already fired (excluding API triggers). + + API triggers cannot be completed before suspending the job, so they are skipped. + + Returns: + A resume map of {interrupt_id: resume_data} for fired triggers, or None. + """ + triggers = await self.storage.get_triggers(self.runtime_id) + if not triggers: + return None + + non_api_triggers = [ + t for t in triggers if t.trigger_type != UiPathResumeTriggerType.API + ] + return await self._build_resume_map(non_api_triggers) + async def _restore_resume_input( self, input: dict[str, Any] | None, - skip_trigger_types: list[UiPathResumeTriggerType] | None = None, ) -> dict[str, Any] | None: """Restore resume input from storage if not provided. @@ -191,18 +201,22 @@ async def _restore_resume_input( if not triggers: return None - return await self._build_resume_map(triggers, skip_trigger_types) + return await self._build_resume_map(triggers) async def _build_resume_map( self, triggers: list[UiPathResumeTrigger], - skip_trigger_types: list[UiPathResumeTriggerType] | None, ) -> dict[str, Any]: - # Build resume map: {interrupt_id: resume_data} + """Build resume map from triggers: {interrupt_id: resume_data}. + + Args: + triggers: List of triggers to read and map + + Returns: + A dict mapping interrupt_id to the trigger's resume data. + """ resume_map: dict[str, Any] = {} for trigger in triggers: - if skip_trigger_types and trigger.trigger_type in skip_trigger_types: - continue try: data = await self.trigger_manager.read_trigger(trigger) assert trigger.interrupt_id is not None, ( diff --git a/uv.lock b/uv.lock index 9baafab..fc5c14a 100644 --- a/uv.lock +++ b/uv.lock @@ -991,21 +991,21 @@ wheels = [ [[package]] name = "uipath-core" -version = "0.4.0" +version = "0.4.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "opentelemetry-instrumentation" }, { name = "opentelemetry-sdk" }, { name = "pydantic" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/75/bc/c75fcd9830cbd02391807b3e9e5bace0aecfad6a0402bb7cf915d7d3a40e/uipath_core-0.4.0.tar.gz", hash = "sha256:930876cb8dd3f79457201e1a0e210f799ec2c940ef178bc0cd00a4680538a8d4", size = 110697, upload-time = "2026-02-12T06:15:18.545Z" } +sdist = { url = "https://files.pythonhosted.org/packages/8b/9a/c343d4a3716b962b588f0297e458b8e61126104167f6c86583571aa7d53f/uipath_core-0.4.1.tar.gz", hash = "sha256:f4a3213ade5e1badefef99fdf80b2318a33ae9b495723962fb937160703a6e79", size = 111183, upload-time = "2026-02-16T11:53:38.857Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/d3/88/182e695bfe0d06392480cbb3e772f3099061bd3b8028cacef285172dd41f/uipath_core-0.4.0-py3-none-any.whl", hash = "sha256:c89d22e78e25ccc2eae8dd85f68f47a048deb195807af6f956cae4bad08e9bc6", size = 35362, upload-time = "2026-02-12T06:15:17.245Z" }, + { url = "https://files.pythonhosted.org/packages/a0/b6/703a9b715fa6adb84840ade9ecb49123fc600046c6caa7acfa4abe7682cc/uipath_core-0.4.1-py3-none-any.whl", hash = "sha256:140af50ce0c2a54124dee63c1798d2f729dbc002f739e91190588b10a13a53fd", size = 35559, upload-time = "2026-02-16T11:53:37.666Z" }, ] [[package]] name = "uipath-runtime" -version = "0.8.4" +version = "0.8.5" source = { editable = "." } dependencies = [ { name = "uipath-core" }, @@ -1027,7 +1027,7 @@ dev = [ ] [package.metadata] -requires-dist = [{ name = "uipath-core", specifier = ">=0.4.0,<0.5.0" }] +requires-dist = [{ name = "uipath-core", specifier = ">=0.4.1,<0.5.0" }] [package.metadata.requires-dev] dev = [