From e6d4407604401f9c4b82ecb894d81da38d264c8b Mon Sep 17 00:00:00 2001 From: radu-mocanu Date: Sun, 20 Sep 2026 17:41:43 +0300 Subject: [PATCH 1/2] fix(advanced): warm the code interpreter before its first eval deadline quickjs_rs compiles its source transform WebAssembly module lazily, inside the first eval of the process, under the same per-call deadline as user code. On a CPU-starved instance the compile alone outlasts the deadline, so the first advanced run on a fresh process fails at its first model call with "interrupted" and a retry on the same process succeeds. Compile it when the graph is built instead, and expose the warm-up so a host that preloads modules at process start can run it earlier. Claude-Session: https://claude.ai/code/session_013CLJG6q56YoHrgNTgm3pA3 (cherry picked from commit 8fd0a1c41343736a913750370acd8a93f85d180f) --- .../agent/advanced/__init__.py | 2 + .../agent/advanced/code_interpreter.py | 28 ++++++++++ tests/agent/advanced/test_code_interpreter.py | 53 +++++++++++++++++++ 3 files changed, 83 insertions(+) diff --git a/src/uipath_langchain/agent/advanced/__init__.py b/src/uipath_langchain/agent/advanced/__init__.py index ad1ecd9a6..dc1946b5c 100644 --- a/src/uipath_langchain/agent/advanced/__init__.py +++ b/src/uipath_langchain/agent/advanced/__init__.py @@ -14,6 +14,7 @@ build_code_interpreter_middleware, ptc_tool_names, subagent_dispatch_is_replay_safe, + warm_code_interpreter, ) from .types import AdvancedAgentGraphState, ConversationalAdvancedAgentGraphState from .utils import ( @@ -42,4 +43,5 @@ "create_state_with_input", "ptc_tool_names", "subagent_dispatch_is_replay_safe", + "warm_code_interpreter", ] diff --git a/src/uipath_langchain/agent/advanced/code_interpreter.py b/src/uipath_langchain/agent/advanced/code_interpreter.py index ab8319a57..08108250a 100644 --- a/src/uipath_langchain/agent/advanced/code_interpreter.py +++ b/src/uipath_langchain/agent/advanced/code_interpreter.py @@ -17,6 +17,7 @@ """ import atexit +import functools import logging from collections.abc import Iterable, Sequence from typing import Any, Literal, get_args @@ -214,6 +215,7 @@ def build_code_interpreter_middleware( ImportError: If the ``code-interpreter`` extra is not installed. """ middleware_cls = _code_interpreter_middleware_cls() + warm_code_interpreter() exposed = ptc_tool_names(tools) dispatch = subagent_dispatch_is_replay_safe(subagents, tools) logger.info( @@ -234,6 +236,32 @@ def build_code_interpreter_middleware( return [middleware] +@functools.cache +def warm_code_interpreter() -> None: + """Compile the interpreter's WebAssembly modules before any eval deadline is armed. + + quickjs_rs compiles its source-transform module lazily, inside the first eval of + the process, and that eval runs under the same per-call deadline as user code. + On a CPU-starved instance the compile alone can outlast the deadline, which + fails the run at its first model call, before the model ever asks for ``eval``. + The compiled modules are cached for the life of the process, so one call here + serves every REPL built afterwards. A host that preloads modules at process + start can call it then. Without the ``code-interpreter`` extra it does nothing. + """ + try: + from quickjs_rs import Runtime, SourceTransform, transform_source + except ImportError: + return + transform_source( + "warmup.js", "const x = 1;", flags=SourceTransform.TOP_LEVEL_CONST_TO_VAR + ) + runtime = Runtime() + try: + runtime.new_context().close() + finally: + runtime.close() + + def _close_at_exit(middleware: Any) -> None: """Close the REPL registry from ``atexit`` instead of leaving it to ``__del__``. diff --git a/tests/agent/advanced/test_code_interpreter.py b/tests/agent/advanced/test_code_interpreter.py index 31a5ffb64..ae97d87ee 100644 --- a/tests/agent/advanced/test_code_interpreter.py +++ b/tests/agent/advanced/test_code_interpreter.py @@ -29,6 +29,7 @@ create_advanced_agent, ptc_tool_names, subagent_dispatch_is_replay_safe, + warm_code_interpreter, ) from uipath_langchain.agent.advanced.code_interpreter import ( EVAL_TOOL_NAME, @@ -293,6 +294,58 @@ def test_factory_closes_the_repl_registry_at_exit( assert registered == [cast(Any, middleware)._registry.close] +def test_factory_warms_the_interpreter_before_building_the_repl( + monkeypatch: pytest.MonkeyPatch, +) -> None: + """The WebAssembly compile happens at graph build, outside any eval deadline. + + Upstream compiles its source-transform module inside the first eval, under + the per-call deadline. On a slow instance that compile alone exceeds the + deadline and the first model call fails, so the factory must pay it first. + """ + calls: list[str] = [] + monkeypatch.setattr( + "uipath_langchain.agent.advanced.code_interpreter.warm_code_interpreter", + lambda: calls.append("warm"), + ) + + build_code_interpreter_middleware([_tool("read_invoice")]) + + assert calls == ["warm"] + + +def test_warm_up_compiles_the_transform_module_upstream_uses_once( + monkeypatch: pytest.MonkeyPatch, +) -> None: + import quickjs_rs + + seen: list[Any] = [] + + def fake_transform_source(name: str, source: str, *, flags: Any = None) -> str: + seen.append(flags) + return source + + monkeypatch.setattr(quickjs_rs, "transform_source", fake_transform_source) + warm_code_interpreter.cache_clear() + + warm_code_interpreter() + warm_code_interpreter() + + assert seen == [quickjs_rs.SourceTransform.TOP_LEVEL_CONST_TO_VAR] + warm_code_interpreter.cache_clear() + + +def test_warm_up_without_the_extra_is_a_no_op( + monkeypatch: pytest.MonkeyPatch, +) -> None: + monkeypatch.setitem(sys.modules, "quickjs_rs", None) + warm_code_interpreter.cache_clear() + + warm_code_interpreter() + + warm_code_interpreter.cache_clear() + + def test_factory_without_the_extra_raises_install_guidance( monkeypatch: pytest.MonkeyPatch, ) -> None: From 9659ea6dfd5afa40f11262102ce2ac5a3fec653f Mon Sep 17 00:00:00 2001 From: radu-mocanu Date: Fri, 18 Sep 2026 19:22:04 +0300 Subject: [PATCH 2/2] chore(release): bump to 0.16.22 Claude-Session: https://claude.ai/code/session_013CLJG6q56YoHrgNTgm3pA3 --- pyproject.toml | 2 +- uv.lock | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 6905cc92a..5bf6121ec 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "uipath-langchain" -version = "0.16.21" +version = "0.16.22" description = "Python SDK that enables developers to build and deploy LangGraph agents to the UiPath Cloud Platform" readme = { file = "README.md", content-type = "text/markdown" } requires-python = ">=3.11" diff --git a/uv.lock b/uv.lock index 8df08bf14..d405912a0 100644 --- a/uv.lock +++ b/uv.lock @@ -4671,7 +4671,7 @@ wheels = [ [[package]] name = "uipath-langchain" -version = "0.16.21" +version = "0.16.22" source = { editable = "." } dependencies = [ { name = "a2a-sdk" },