From cc1896b70836ed9eda545483348aa7ee62b418fb Mon Sep 17 00:00:00 2001 From: Chibi Vikram Date: Mon, 5 Jan 2026 15:58:19 -0800 Subject: [PATCH 1/4] fix: create isolated runtime per eval execution MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Each eval execution now gets its own runtime with a unique runtime_id (using execution_id). This ensures each eval has its own LangGraph thread_id with clean state, preventing message accumulation across sequential eval runs. Previously, all evals shared a single runtime with the same thread_id, causing the LangGraph checkpointer to persist and accumulate messages across eval runs, leading to 400 bad request errors. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 --- src/uipath/_cli/_evals/_runtime.py | 66 ++++++++++++++++++------------ 1 file changed, 39 insertions(+), 27 deletions(-) diff --git a/src/uipath/_cli/_evals/_runtime.py b/src/uipath/_cli/_evals/_runtime.py index 2fe0ce443..19fc69733 100644 --- a/src/uipath/_cli/_evals/_runtime.py +++ b/src/uipath/_cli/_evals/_runtime.py @@ -613,42 +613,54 @@ async def execute_runtime( "evalId": eval_item.id, "span_type": "eval", } - execution_runtime = UiPathExecutionRuntime( - delegate=runtime, - trace_manager=self.trace_manager, - log_handler=log_handler, - execution_id=execution_id, - span_attributes=attributes, + + # Create a new runtime with unique runtime_id for this eval execution. + # This ensures each eval has its own LangGraph thread_id (clean state), + # preventing message accumulation across eval runs. + eval_runtime = await self.factory.new_runtime( + entrypoint=self.context.entrypoint or "", + runtime_id=execution_id, ) - start_time = time() try: - result = await execution_runtime.execute( - input=eval_item.inputs, + execution_runtime = UiPathExecutionRuntime( + delegate=eval_runtime, + trace_manager=self.trace_manager, + log_handler=log_handler, + execution_id=execution_id, + span_attributes=attributes, ) - except Exception as e: + + start_time = time() + try: + result = await execution_runtime.execute( + input=eval_item.inputs, + ) + except Exception as e: + end_time = time() + spans, logs = self._get_and_clear_execution_data(execution_id) + + raise EvaluationRuntimeException( + spans=spans, + logs=logs, + root_exception=e, + execution_time=end_time - start_time, + ) from e + end_time = time() spans, logs = self._get_and_clear_execution_data(execution_id) - raise EvaluationRuntimeException( + if result is None: + raise ValueError("Execution result cannot be None for eval runs") + + return UiPathEvalRunExecutionOutput( + execution_time=end_time - start_time, spans=spans, logs=logs, - root_exception=e, - execution_time=end_time - start_time, - ) from e - - end_time = time() - spans, logs = self._get_and_clear_execution_data(execution_id) - - if result is None: - raise ValueError("Execution result cannot be None for eval runs") - - return UiPathEvalRunExecutionOutput( - execution_time=end_time - start_time, - spans=spans, - logs=logs, - result=result, - ) + result=result, + ) + finally: + await eval_runtime.dispose() def _setup_execution_logging( self, eval_item_id: str From 53962395e2312ab6c1943ca75513e335b7fcbdcf Mon Sep 17 00:00:00 2001 From: Chibi Vikram Date: Mon, 5 Jan 2026 17:07:03 -0800 Subject: [PATCH 2/4] chore: bump version to 2.4.3 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 4ee7375e3..fe189713c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "uipath" -version = "2.4.2" +version = "2.4.3" description = "Python SDK and CLI for UiPath Platform, enabling programmatic interaction with automation services, process management, and deployment tools." readme = { file = "README.md", content-type = "text/markdown" } requires-python = ">=3.11" From 4f5d7505f80cc7ed87314a733db35e45fe09bfa7 Mon Sep 17 00:00:00 2001 From: Chibi Vikram Date: Mon, 5 Jan 2026 17:39:42 -0800 Subject: [PATCH 3/4] fix: handle new_runtime failure in execute_runtime MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If new_runtime fails, eval_runtime would be unassigned and the finally block would raise NameError when trying to dispose. Initialize to None and check before disposing. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 --- src/uipath/_cli/_evals/_runtime.py | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/uipath/_cli/_evals/_runtime.py b/src/uipath/_cli/_evals/_runtime.py index 19fc69733..8db78ab43 100644 --- a/src/uipath/_cli/_evals/_runtime.py +++ b/src/uipath/_cli/_evals/_runtime.py @@ -617,12 +617,12 @@ async def execute_runtime( # Create a new runtime with unique runtime_id for this eval execution. # This ensures each eval has its own LangGraph thread_id (clean state), # preventing message accumulation across eval runs. - eval_runtime = await self.factory.new_runtime( - entrypoint=self.context.entrypoint or "", - runtime_id=execution_id, - ) - + eval_runtime = None try: + eval_runtime = await self.factory.new_runtime( + entrypoint=self.context.entrypoint or "", + runtime_id=execution_id, + ) execution_runtime = UiPathExecutionRuntime( delegate=eval_runtime, trace_manager=self.trace_manager, @@ -660,7 +660,8 @@ async def execute_runtime( result=result, ) finally: - await eval_runtime.dispose() + if eval_runtime is not None: + await eval_runtime.dispose() def _setup_execution_logging( self, eval_item_id: str From bedb6d9f8913c38240cf4ff82bcebaa57a56b5a5 Mon Sep 17 00:00:00 2001 From: Chibi Vikram Date: Mon, 5 Jan 2026 18:44:30 -0800 Subject: [PATCH 4/4] chore: update uv.lock after version bump MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 --- uv.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/uv.lock b/uv.lock index 987b7b2f1..73dfaffb8 100644 --- a/uv.lock +++ b/uv.lock @@ -2477,7 +2477,7 @@ wheels = [ [[package]] name = "uipath" -version = "2.4.2" +version = "2.4.3" source = { editable = "." } dependencies = [ { name = "click" },