Skip to content

Conversation

@radu-mocanu
Copy link
Contributor

  • resume runtime on fired triggers

@radu-mocanu radu-mocanu force-pushed the feat/resume-runtime-on-fired-triggers branch from 29cd15f to 740e611 Compare January 22, 2026 17:41
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds “auto-resume” behavior to the resumable runtime so that if resume triggers are already fired at the time of suspension, the runtime immediately resumes without requiring an external resume call.

Changes:

  • Implement auto-resume flow in UiPathResumableRuntime.execute() and .stream() when fired triggers are detected.
  • Introduce UiPathSuspensionResult to carry both the suspension UiPathRuntimeResult and any fired trigger resume-map.
  • Add async tests covering auto-resume scenarios (none/partial/all fired; multiple auto-resumes; stream behavior).

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 6 comments.

File Description
src/uipath/runtime/resumable/runtime.py Adds fired-trigger detection at suspension time and recursive auto-resume for execute() and stream().
src/uipath/runtime/result.py Adds UiPathSuspensionResult model used to return both runtime result and fired trigger map.
tests/test_resumable.py Adds coverage for auto-resume behavior across several trigger-firing patterns.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +90 to +97
# some triggers are already fired, runtime can be resumed
resume_options = options or UiPathExecuteOptions(resume=True)
if not resume_options.resume:
resume_options = UiPathExecuteOptions(resume=True)
return await self.execute(
fired_triggers_map=suspension_result.fired_triggers_map,
options=resume_options,
)
Copy link

Copilot AI Jan 22, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Auto-resume is implemented via recursive self.execute(...) calls with no guardrail. If the delegate keeps returning SUSPENDED while triggers appear “fired” immediately (or if there’s a logic loop), this can lead to unbounded recursion and eventually RecursionError/stack growth. Consider rewriting as an iterative loop and/or enforcing a maximum auto-resume depth / progress check.

Copilot uses AI. Check for mistakes.
Comment on lines +138 to +140
resume_options = options or UiPathStreamOptions(resume=True)
if not resume_options.resume:
resume_options = UiPathStreamOptions(resume=True)
Copy link

Copilot AI Jan 22, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When auto-resuming in stream(), the code constructs a new UiPathStreamOptions(resume=True) if options.resume is false, which drops any other option fields (e.g., breakpoints). Preserve the caller’s options by copying/updating resume=True rather than replacing the options object.

Copilot uses AI. Check for mistakes.
Comment on lines +137 to +145
# some triggers are already fired, runtime can be resumed
resume_options = options or UiPathStreamOptions(resume=True)
if not resume_options.resume:
resume_options = UiPathStreamOptions(resume=True)
async for event in self.stream(
fired_triggers_map=suspension_result.fired_triggers_map,
options=resume_options,
):
yield event
Copy link

Copilot AI Jan 22, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Auto-resume in stream() uses recursive calls to self.stream(...) with no depth/progress guard. A run that repeatedly suspends with triggers that immediately appear fired can recurse indefinitely and grow the call stack. Consider an iterative loop and/or a maximum auto-resume depth similar to execute().

Copilot uses AI. Check for mistakes.
assert result.triggers is not None
assert {t.interrupt_id for t in result.triggers} == {"int-1", "int-2"}

# Delegate should have been executed only once)
Copy link

Copilot AI Jan 22, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Extra closing parenthesis in comment: “Delegate should have been executed only once)”.

Suggested change
# Delegate should have been executed only once)
# Delegate should have been executed only once.

Copilot uses AI. Check for mistakes.
Comment on lines +257 to +262
return UiPathSuspensionResult(
runtime_result=suspended_result,
fired_triggers_map=await self._build_resume_map(triggers)
if triggers
else None,
)
Copy link

Copilot AI Jan 22, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

_handle_suspension() now calls _build_resume_map() during suspension to decide whether to auto-resume. UiPathResumeTriggerReaderProtocol.read_trigger() is documented to return None when no data is available; treat that as still pending. Ensure _build_resume_map() does not delete triggers / include {interrupt_id: None} when read_trigger() returns None, otherwise triggers can be prematurely consumed and the runtime can auto-resume with missing data.

Copilot uses AI. Check for mistakes.
Comment on lines +91 to +94
resume_options = options or UiPathExecuteOptions(resume=True)
if not resume_options.resume:
resume_options = UiPathExecuteOptions(resume=True)
return await self.execute(
Copy link

Copilot AI Jan 22, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When auto-resuming, the code replaces user-provided options with a fresh UiPathExecuteOptions(resume=True) if options.resume is false. This drops any other option fields (e.g., breakpoints). Preserve existing options by copying/updating resume=True instead of creating a new instance that loses other settings.

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant