Repository navigation
feat(runtime): end a stopped run as stopped, and stop a run on a debug quit - #171
Open
robert-ursu wants to merge 3 commits into
Open
robert-ursu wants to merge 3 commits into
robert-ursu wants to merge 3 commits into
Conversation
A run cancelled because its host asked it to stop was reported as faulted with ERROR_CancelledError, indistinguishable from a crash. A host can now install a stop-requested probe (uipath.runtime.stop). When the run ends in a cancellation, or in an error raised because of one, and the probe says a stop was requested, the context writes the new stopped status with no error, and the result sink receives it like any final result. Without a probe, or when the probe says no, nothing changes. Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
The debug runtime looked at the bridge's terminate signal only while it was waiting: before the first resume, at a breakpoint, or while polling a trigger. A Quit from Studio Web while the agent was running was logged and then ignored, and the run went on to completion. The delegate's stream is now watched for a quit. One that arrives while the delegate is working cancels it where it waits, as a stop would; one that arrives while an event is being handled ends the stream before the next. The delegate is closed either way and the run ends with the result a quit has always produced. A cancellation from anywhere else still propagates. Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
There was a problem hiding this comment.
Copilot review overview
🟡 Changes recommended
Debug quit can restart a cancellation-swallowing delegate and remains ignored by the non-streaming fallback.
Review effort: Balanced
Findings: 1
Open (1)
What changed in this PR
Adds stopped-run reporting and makes debug quit interrupt active streaming executions.
Changes:
- Introduces the
STOPPEDstatus and host stop-request probe. - Detects cancellation-related stops and delivers stopped results.
- Watches streaming delegates for debug termination.
| File | Description |
|---|---|
src/uipath/runtime/stop.py |
Adds the stop-request probe. |
src/uipath/runtime/result.py |
Adds STOPPED status. |
src/uipath/runtime/context.py |
Classifies requested cancellations as stopped. |
src/uipath/runtime/debug/runtime.py |
Adds debug-quit monitoring. |
tests/test_stop.py |
Tests stopped-result behavior. |
tests/test_debugger.py |
Tests debug termination handling. |
pyproject.toml |
Bumps package version. |
uv.lock |
Updates the locked project version. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Comment on lines
177
to
179
| async for event in self._until_quit( | ||
| self.delegate.stream(current_input, options=debug_options) | ||
| ): |
…in execute() A stopped run is now told apart from a failure by Task.cancelling() on the task that entered the context: a cancel() someone called keeps it above zero through cleanup, and a stray CancelledError leaves it at zero. This replaces the host-installed stop-requested probe and the walk of the exception chain, so uipath.runtime.stop goes away and hosts install nothing. The debug quit is watched in execute(), which runs the stream in its own task and races it against wait_for_terminate(). A quit cancels that task instead of the caller's, so no uncancel() bookkeeping or in-delegate tracking is needed, and the execute() fallback for a delegate that cannot stream is covered too. Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]> Claude-Session: https://claude.ai/code/session_011be41L1VE33oixHNnJRPhw
|
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.




A run that its host stops now ends as stopped instead of faulted, and a debug session that quits while the agent is running stops the run instead of letting it finish.
Why
CancelledErrorinto a faulted result withERROR_CancelledError.output.jsonand the result sink could not tell a stop from a failure.What: a stopped status
UiPathRuntimeStatus.STOPPED("stopped").uipath.runtime.stop: a per-execution slot for a stop-requested probe that the host installs. It is a contextvar, like the output sinks, so concurrent jobs in one process each see their own host's answer.UiPathRuntimeContext.__exit__writesstopped, with no error, when two things hold:What: a debug quit while the run is going
The delegate's stream is now watched for a quit:
Either way the delegate is closed, and the run ends with the result a quit has always produced. A cancellation from anywhere else still propagates.
Worth a careful look
_until_quitcancels the task only while it is inside the delegate's__anext__. It clears its own cancellation withTask.uncancel(), so a cancellation it did not send keeps propagating. If the delegate swallows the cancellation, the watch still takes it back.wait_for_terminate()returning now ends a running session. The bridges in uipath (console and SignalR) and the detached bridge here block until the user quits. A bridge whosewait_for_terminatereturns at once would end every run at its first event. One test fake inuipath-claude-sdkdoes this.output.json. A coded agent can also run a newer runtime than its host, so switching the quit's status is left for when those handlers are gone.Compatibility
Testing
tests/test_stop.py:ERROR_CancelledError;tests/test_debugger.py:wait_for_terminatenow blocks like a real bridge.uipath server, a stopped job'soutput.jsonis{"output": {}, "status": "stopped"}.🤖 Generated with Claude Code