Skip to content

fix(cli): stop uipath --help loading every installed agent runtime - #1904

Draft
ionmincu wants to merge 1 commit into
mainfrom
fix/cli-startup-perf
Draft

ionmincu wants to merge 1 commit into
mainfrom
fix/cli-startup-perf

Conversation

@ionmincu

@ionmincu ionmincu commented Sep 17, 2026 •

Copy link
Copy Markdown
Collaborator

Problem

With uipath-langchain installed, uipath --help imported langgraph, langchain_core and openai just to print a help page.

Click resolves every command to read its short help when rendering the help table, and resolving a command in _RUNTIME_COMMANDS called _ensure_runtime_initialized(). That loads the uipath.runtime.factories entry points, so every installed plugin's agent stack was imported before anything was printed.

Fix

The six commands that execute an agent now carry @requires_runtime, which populates the factory registry when the callback runs. Click calls a callback only after it has parsed the arguments, so --help and shell completion resolve the command object and exit without ever loading a runtime. run, eval, dev, debug, server and init still initialize before they execute.

Each command now declares its own need for a runtime, instead of the group holding a list of which names are special. _cli/__init__.py is back to a plain lazy importer, and runtimes.py owns both the discovery and the decorator that triggers it.

Results

Same clean venv, same stock uipath-langchain 0.18.8 from PyPI, best of 3:

uipath 2.14.22 (main) this branch
uipath --help 3.85s 1.82s
uipath run --help 3.09s 1.20s
modules imported by --help 2995 1207
plugin stack imported by --help yes no

uipath --version and import uipath._cli are unchanged by this PR.

--help still resolves all 20 command modules, and some genuinely need aiohttp or the eval runtime, so most of what remains is real work. Getting below that means restructuring the command modules — a separate change.

Backwards compatibility

Verified with that stock plugin, which knows nothing about this change: uipath new (middleware) works, and uipath init + uipath run on a langgraph agent work, with factories langgraph and uipath registered on run.

load_runtime_factories() is unchanged: same entry-point group, same ep.load()(). A plugin has no way to observe when it gets loaded. Across uipath-langchain and all six uipath-llamaindex packages, every import from uipath._cli is middlewares, _utils._console or _utils._common — all untouched — and nothing references _ensure_runtime_initialized or load_runtime_factories.

Two things a reviewer should know. The private uipath._cli._ensure_runtime_initialized moved to uipath._cli.runtimes.ensure_runtime_initialized; nothing in this repo or either plugin repo imports the old name. And plugin tests that import a command object directly (from uipath._cli.cli_run import run) and invoke it via CliRunner now get the factories initialized where before they did not — strictly more working, not less.

Why the guards count modules, not seconds

Wall-clock cannot separate this fix from the noise. uipath --help opens ~1200 module files, so its runtime is dominated by the runner's filesystem — the same build measured 2.7s and 13.1s on one machine. The guards in tests/cli/test_lazy_commands.py and the langchain-cross testcase assert which modules get imported instead.

The testcase guard lives in langchain-cross because that testcase registers a uipath.runtime.factories entry point, which is where the regression appears. It fails against the previous revision with ['langchain_core', 'langgraph', 'openai', 'uipath_langchain'] loaded and passes here.

Verification

  • ruff check, ruff format --check, scripts/lint_httpx_client.py, mypy src tests (336 files) — all clean
  • tests/cli: exit 0. Ran with --ignore=tests/cli/test_auth_server.py; that file hangs in ~2 of 5 runs on origin/main with byte-identical code, a pre-existing Windows flake.
  • uipath --help output byte-identical to origin/main for --help, run --help, init --help, eval --help, server --help, assets --help, context-grounding --help and --help --format json.
  • Shell completion resolves run's options without initializing the runtime.
  • Version uniqueness check passes for 2.14.26.

Notes

Two related changes were tried and left out, because neither moves uipath --help:

  • Making resource_override a lazy re-export in uipath/_utils/__init__.py takes uipath --version from 0.92s to 0.23s, but rendering help imports uipath.platform.common through the command modules anyway. That is its own change.
  • Making uipath.platform.common itself lazy changed --help by 3 modules.

This PR touches only packages/uipath.

🤖 Generated with Claude Code

@github-actions github-actions Bot added test:uipath-langchain Triggers tests in the uipath-langchain-python repository test:uipath-runtime test:uipath-integrations labels Sep 17, 2026
With uipath-langchain installed, `uipath --help` imported langgraph,
langchain_core and openai just to print a help page.

Click resolves every command to read its short help when rendering the help
table, and resolving a command in `_RUNTIME_COMMANDS` called
`_ensure_runtime_initialized()`. That loads the `uipath.runtime.factories` entry
points, so every installed plugin's agent stack was imported before anything was
printed.

The six commands that execute an agent now carry `@requires_runtime`, which
populates the factory registry when the callback runs. Click calls a callback
only after it has parsed the arguments, so `--help` and shell completion resolve
the command object and exit without ever loading a runtime. `run`, `eval`, `dev`,
`debug`, `server` and `init` still initialize before they execute.

Each command now declares its own need for a runtime, instead of the group
holding a list of which names are special. `_cli/__init__.py` is back to a plain
lazy importer, and `runtimes.py` owns both the discovery and the decorator that
triggers it. The private `uipath._cli._ensure_runtime_initialized` moved to
`uipath._cli.runtimes.ensure_runtime_initialized`; nothing in this repo,
uipath-langchain or uipath-llamaindex imports the old name.

Measured against uipath 2.14.22 with the same stock uipath-langchain 0.18.8,
best of 3:

                        before    after
  uipath --help          3.85s    1.82s
  uipath run --help      3.09s    1.20s
  modules on --help       2995     1207

langgraph, langchain_core, openai and uipath_langchain are no longer imported by
`--help`. `uipath --version` and `import uipath._cli` are unchanged by this
commit.

Help output is byte-identical, diffed against origin/main for `--help`,
`run --help`, `init --help`, `eval --help`, `server --help`, `assets --help`,
`context-grounding --help` and `--help --format json`.

Guards, in tests/cli/test_lazy_commands.py and the langchain-cross testcase,
assert which modules get imported rather than wall-clock time. `uipath --help`
opens ~1200 module files, so its runtime is dominated by the runner's
filesystem; the same build measured 2.7s and 13.1s on one machine. The
langchain-cross guard registers a `uipath.runtime.factories` entry point, which
is where the regression appears; it fails against the previous revision with
['langchain_core', 'langgraph', 'openai', 'uipath_langchain'] loaded and passes
here.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@ionmincu
ionmincu force-pushed the fix/cli-startup-perf branch from e58da17 to ba64d9e Compare September 24, 2026 12:10
@github-actions

Copy link
Copy Markdown

🚨 Heads up: uipath-integrations cross-tests are FAILING 🚨

Your changes may break one or more integrations in uipath-integrations-python:

  • uipath-openai-agents
  • uipath-google-adk
  • uipath-agent-framework
  • uipath-llamaindex
  • uipath-pydantic-ai

⚠️ These checks are NOT enforced by branch protection rules. Please review the failures before merging.

🔍 Inspect the failed run →

@sonarqubecloud

Copy link
Copy Markdown

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

test:uipath-integrations test:uipath-langchain Triggers tests in the uipath-langchain-python repository test:uipath-runtime

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant