Conversation
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
force-pushed
the
fix/cli-startup-perf
branch
from
September 24, 2026 12:10
e58da17 to
ba64d9e
Compare
🚨 Heads up:
|
|
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.



Problem
With
uipath-langchaininstalled,uipath --helpimported 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_COMMANDScalled_ensure_runtime_initialized(). That loads theuipath.runtime.factoriesentry 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--helpand shell completion resolve the command object and exit without ever loading a runtime.run,eval,dev,debug,serverandinitstill 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__.pyis back to a plain lazy importer, andruntimes.pyowns both the discovery and the decorator that triggers it.Results
Same clean venv, same stock
uipath-langchain0.18.8 from PyPI, best of 3:uipath --helpuipath run --help--help--helpuipath --versionandimport uipath._cliare unchanged by this PR.--helpstill 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, anduipath init+uipath runon a langgraph agent work, with factorieslanggraphanduipathregistered on run.load_runtime_factories()is unchanged: same entry-point group, sameep.load()(). A plugin has no way to observe when it gets loaded. Acrossuipath-langchainand all sixuipath-llamaindexpackages, every import fromuipath._cliismiddlewares,_utils._consoleor_utils._common— all untouched — and nothing references_ensure_runtime_initializedorload_runtime_factories.Two things a reviewer should know. The private
uipath._cli._ensure_runtime_initializedmoved touipath._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 viaCliRunnernow 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 --helpopens ~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 intests/cli/test_lazy_commands.pyand thelangchain-crosstestcase assert which modules get imported instead.The testcase guard lives in
langchain-crossbecause that testcase registers auipath.runtime.factoriesentry 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 cleantests/cli: exit 0. Ran with--ignore=tests/cli/test_auth_server.py; that file hangs in ~2 of 5 runs onorigin/mainwith byte-identical code, a pre-existing Windows flake.uipath --helpoutput byte-identical toorigin/mainfor--help,run --help,init --help,eval --help,server --help,assets --help,context-grounding --helpand--help --format json.run's options without initializing the runtime.Notes
Two related changes were tried and left out, because neither moves
uipath --help:resource_overridea lazy re-export inuipath/_utils/__init__.pytakesuipath --versionfrom 0.92s to 0.23s, but rendering help importsuipath.platform.commonthrough the command modules anyway. That is its own change.uipath.platform.commonitself lazy changed--helpby 3 modules.This PR touches only
packages/uipath.🤖 Generated with Claude Code