From 9c762aa1b6934ab26f5a90cf59b35402de5cb8ae Mon Sep 17 00:00:00 2001 From: Vlad Cimpeanu Date: Mon, 7 Sep 2026 17:53:44 +0300 Subject: [PATCH 01/11] fix(cli): add --type and --agent-framework options to uipath new Installing an agent framework integration (e.g. uipath-langchain) made its middleware claim `uipath new` unconditionally, so the base function scaffold was unreachable. Add a --type function|agent option (default: function) and an --agent-framework option (default: langchain, only valid together with --type agent), forward both to the middleware chain, and error when an agent scaffold is requested but no installed integration claims it. The scaffold types live in uipath._cli.models.project_types and uipath._cli.models.agent_frameworks so framework integrations can import them and gate their middlewares. Bump version to 2.14.13. Fixes #1543 Co-Authored-By: Claude Fable 5 --- packages/uipath/src/uipath/_cli/cli_new.py | 42 ++++- .../uipath/_cli/models/agent_frameworks.py | 38 +++++ .../src/uipath/_cli/models/project_types.py | 15 ++ packages/uipath/tests/cli/test_new.py | 160 ++++++++++++++++++ 4 files changed, 253 insertions(+), 2 deletions(-) create mode 100644 packages/uipath/src/uipath/_cli/models/agent_frameworks.py create mode 100644 packages/uipath/src/uipath/_cli/models/project_types.py diff --git a/packages/uipath/src/uipath/_cli/cli_new.py b/packages/uipath/src/uipath/_cli/cli_new.py index 6d021a867..9240d7791 100644 --- a/packages/uipath/src/uipath/_cli/cli_new.py +++ b/packages/uipath/src/uipath/_cli/cli_new.py @@ -11,6 +11,8 @@ from ._utils._console import ConsoleLogger from ._utils._project_files import resolve_existing_project_id from .middlewares import Middlewares +from .models.agent_frameworks import DEFAULT_AGENT_FRAMEWORK, AgentFramework +from .models.project_types import ProjectType console = ConsoleLogger() @@ -59,8 +61,24 @@ def generate_uipath_json(target_directory): @click.command() @click.argument("name", type=str, default="") +@click.option( + "--type", + "project_type", + type=click.Choice([t.value for t in ProjectType]), + default=ProjectType.FUNCTION.value, + show_default=True, + help="Project type to scaffold. 'agent' requires an agent framework package (e.g. uipath-langchain).", +) +@click.option( + "--agent-framework", + "agent_framework", + type=click.Choice([f.value for f in AgentFramework]), + default=None, + show_default=DEFAULT_AGENT_FRAMEWORK.value, + help="Agent framework to scaffold for. Only valid together with `--type agent`.", +) @track_command("new") -def new(name: str): +def new(name: str, project_type: str, agent_framework: str | None): """Generate a quick-start project.""" directory = os.getcwd() @@ -69,7 +87,20 @@ def new(name: str): "Please specify a name for your project:\n`uipath new hello-world`" ) - result = Middlewares.next("new", name) + scaffold_type = ProjectType(project_type) + framework = AgentFramework(agent_framework) if agent_framework else None + + if framework and scaffold_type is not ProjectType.AGENT: + console.error( + "`--agent-framework` can only be used together with `--type agent`." + ) + + if scaffold_type is ProjectType.AGENT and framework is None: + framework = DEFAULT_AGENT_FRAMEWORK + + result = Middlewares.next( + "new", name, project_type=scaffold_type, agent_framework=framework + ) if result.error_message: console.error( @@ -82,6 +113,13 @@ def new(name: str): if not result.should_continue: return + if framework is not None: # only set for agent scaffolds + console.error( + f"The '{framework}' agent framework is not installed.\n" + f"Install `{framework.package}` to scaffold this agent, " + f"or run `uipath new {name}` to create a function project." + ) + with console.spinner(f"Creating new project {name} in current directory ..."): generate_script(directory) console.success("Created 'main.py' file.") diff --git a/packages/uipath/src/uipath/_cli/models/agent_frameworks.py b/packages/uipath/src/uipath/_cli/models/agent_frameworks.py new file mode 100644 index 000000000..57b38fe78 --- /dev/null +++ b/packages/uipath/src/uipath/_cli/models/agent_frameworks.py @@ -0,0 +1,38 @@ +"""Agent frameworks supported by `uipath new --type agent`. + +Each framework's integration package registers a middleware that claims +agent scaffolds for its framework. +""" + +from enum import StrEnum + + +class AgentFramework(StrEnum): + """Agent frameworks with a UiPath integration package.""" + + GOOGLE_ADK = "google-adk" + LANGCHAIN = "langchain" + LLAMAINDEX = "llamaindex" + MICROSOFT_AGENT_FRAMEWORK = "microsoft-agent-framework" + OPENAI_AGENTS = "openai-agents" + PYDANTIC_AI = "pydantic-ai" + + @property + def package(self) -> str: + """PyPI package that provides this framework's UiPath integration.""" + return _AGENT_FRAMEWORK_PACKAGES[self] + + +# uipath-langchain lives in its own repo; the rest come from +# UiPath/uipath-integrations-python (note: microsoft-agent-framework ships +# as `uipath-agent-framework`). +_AGENT_FRAMEWORK_PACKAGES = { + AgentFramework.GOOGLE_ADK: "uipath-google-adk", + AgentFramework.LANGCHAIN: "uipath-langchain", + AgentFramework.LLAMAINDEX: "uipath-llamaindex", + AgentFramework.MICROSOFT_AGENT_FRAMEWORK: "uipath-agent-framework", + AgentFramework.OPENAI_AGENTS: "uipath-openai-agents", + AgentFramework.PYDANTIC_AI: "uipath-pydantic-ai", +} + +DEFAULT_AGENT_FRAMEWORK = AgentFramework.LANGCHAIN diff --git a/packages/uipath/src/uipath/_cli/models/project_types.py b/packages/uipath/src/uipath/_cli/models/project_types.py new file mode 100644 index 000000000..f074f7ae7 --- /dev/null +++ b/packages/uipath/src/uipath/_cli/models/project_types.py @@ -0,0 +1,15 @@ +"""Project types scaffolded by `uipath new`. + +Framework integrations (uipath-langchain and the packages in +UiPath/uipath-integrations-python) import this to decide whether a +`uipath new` invocation is theirs to handle. +""" + +from enum import StrEnum + + +class ProjectType(StrEnum): + """What `uipath new` scaffolds.""" + + FUNCTION = "function" + AGENT = "agent" diff --git a/packages/uipath/tests/cli/test_new.py b/packages/uipath/tests/cli/test_new.py index d2d278a62..24b0ce2c0 100644 --- a/packages/uipath/tests/cli/test_new.py +++ b/packages/uipath/tests/cli/test_new.py @@ -11,6 +11,8 @@ from uipath._cli import cli from uipath._cli.middlewares import MiddlewareResult +from uipath._cli.models.agent_frameworks import AgentFramework +from uipath._cli.models.project_types import ProjectType class TestNew: @@ -84,6 +86,164 @@ def test_new_project_middleware_interaction( assert result.exit_code == 0 assert os.path.exists("main.py") + def test_new_default_type_is_function( + self, runner: CliRunner, temp_dir: str + ) -> None: + """Without --type, middlewares receive project_type='function'.""" + with runner.isolated_filesystem(temp_dir=temp_dir): + with patch("uipath._cli.cli_new.Middlewares.next") as mock_middleware: + mock_middleware.return_value = MiddlewareResult(should_continue=True) + + result = runner.invoke(cli, ["new", "my_project"]) + assert result.exit_code == 0 + mock_middleware.assert_called_once_with( + "new", + "my_project", + project_type=ProjectType.FUNCTION, + agent_framework=None, + ) + assert os.path.exists("uipath.json") + + def test_new_explicit_type_function( + self, runner: CliRunner, temp_dir: str + ) -> None: + """--type function scaffolds the base function project.""" + with runner.isolated_filesystem(temp_dir=temp_dir): + result = runner.invoke(cli, ["new", "my_project", "--type", "function"]) + assert result.exit_code == 0 + with open("uipath.json") as f: + config = json.load(f) + assert config["functions"] == {"main": "main.py:main"} + + def test_new_type_agent_without_framework_errors( + self, runner: CliRunner, temp_dir: str + ) -> None: + """--type agent with no framework handling it must not fall back to a function scaffold.""" + with runner.isolated_filesystem(temp_dir=temp_dir): + with patch("uipath._cli.cli_new.Middlewares.next") as mock_middleware: + # No agent framework middleware claimed the command. + mock_middleware.return_value = MiddlewareResult(should_continue=True) + + result = runner.invoke(cli, ["new", "my_agent", "--type", "agent"]) + assert result.exit_code == 1 + assert "'langchain' agent framework is not installed" in result.output + assert "uipath-langchain" in result.output + assert not os.path.exists("main.py") + assert not os.path.exists("uipath.json") + + def test_new_type_agent_defaults_to_langchain_framework( + self, runner: CliRunner, temp_dir: str + ) -> None: + """--type agent without --agent-framework resolves to langchain.""" + with runner.isolated_filesystem(temp_dir=temp_dir): + with patch("uipath._cli.cli_new.Middlewares.next") as mock_middleware: + mock_middleware.return_value = MiddlewareResult(should_continue=False) + + result = runner.invoke(cli, ["new", "my_agent", "--type", "agent"]) + assert result.exit_code == 0 + mock_middleware.assert_called_once_with( + "new", + "my_agent", + project_type=ProjectType.AGENT, + agent_framework=AgentFramework.LANGCHAIN, + ) + + def test_new_agent_framework_forwarded_to_middlewares( + self, runner: CliRunner, temp_dir: str + ) -> None: + """An explicit --agent-framework reaches the middleware chain unchanged.""" + with runner.isolated_filesystem(temp_dir=temp_dir): + with patch("uipath._cli.cli_new.Middlewares.next") as mock_middleware: + mock_middleware.return_value = MiddlewareResult(should_continue=False) + + result = runner.invoke( + cli, + [ + "new", + "my_agent", + "--type", + "agent", + "--agent-framework", + "pydantic-ai", + ], + ) + assert result.exit_code == 0 + mock_middleware.assert_called_once_with( + "new", + "my_agent", + project_type=ProjectType.AGENT, + agent_framework=AgentFramework.PYDANTIC_AI, + ) + + def test_new_agent_framework_not_installed_names_package( + self, runner: CliRunner, temp_dir: str + ) -> None: + """The error for an unhandled framework names its integration package.""" + with runner.isolated_filesystem(temp_dir=temp_dir): + with patch("uipath._cli.cli_new.Middlewares.next") as mock_middleware: + mock_middleware.return_value = MiddlewareResult(should_continue=True) + + result = runner.invoke( + cli, + [ + "new", + "my_agent", + "--type", + "agent", + "--agent-framework", + "microsoft-agent-framework", + ], + ) + assert result.exit_code == 1 + assert ( + "'microsoft-agent-framework' agent framework is not installed" + in result.output + ) + assert "uipath-agent-framework" in result.output + assert not os.path.exists("main.py") + + def test_new_agent_framework_requires_agent_type( + self, runner: CliRunner, temp_dir: str + ) -> None: + """--agent-framework without --type agent is rejected.""" + with runner.isolated_filesystem(temp_dir=temp_dir): + for extra_args in ( + [], # implicit --type function + ["--type", "function"], + ): + result = runner.invoke( + cli, + ["new", "my_project", "--agent-framework", "langchain"] + + extra_args, + ) + assert result.exit_code == 1 + assert ( + "`--agent-framework` can only be used together with " + "`--type agent`" in result.output + ) + assert not os.path.exists("main.py") + + def test_new_invalid_type_rejected( + self, runner: CliRunner, temp_dir: str + ) -> None: + """Unknown --type values are rejected by click.""" + with runner.isolated_filesystem(temp_dir=temp_dir): + result = runner.invoke(cli, ["new", "my_project", "--type", "workflow"]) + assert result.exit_code == 2 + assert not os.path.exists("main.py") + + def test_new_invalid_agent_framework_rejected( + self, runner: CliRunner, temp_dir: str + ) -> None: + """Unknown --agent-framework values are rejected by click.""" + with runner.isolated_filesystem(temp_dir=temp_dir): + result = runner.invoke( + cli, + ["new", "my_agent", "--type", "agent", "--agent-framework", "crewai"], + ) + assert result.exit_code == 2 + assert not os.path.exists("main.py") + def test_new_project_error_handling(self, runner: CliRunner, temp_dir: str) -> None: """Test error handling in new command.""" with runner.isolated_filesystem(temp_dir=temp_dir): From 80559c9a7995dc5e0b4ddd813a2279f50b8ea815 Mon Sep 17 00:00:00 2001 From: Vlad Cimpeanu Date: Mon, 7 Sep 2026 18:19:24 +0300 Subject: [PATCH 02/11] style: format test_new.py with ruff Co-Authored-By: Claude Fable 5 --- packages/uipath/tests/cli/test_new.py | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/packages/uipath/tests/cli/test_new.py b/packages/uipath/tests/cli/test_new.py index 24b0ce2c0..d1092e917 100644 --- a/packages/uipath/tests/cli/test_new.py +++ b/packages/uipath/tests/cli/test_new.py @@ -104,9 +104,7 @@ def test_new_default_type_is_function( ) assert os.path.exists("uipath.json") - def test_new_explicit_type_function( - self, runner: CliRunner, temp_dir: str - ) -> None: + def test_new_explicit_type_function(self, runner: CliRunner, temp_dir: str) -> None: """--type function scaffolds the base function project.""" with runner.isolated_filesystem(temp_dir=temp_dir): result = runner.invoke(cli, ["new", "my_project", "--type", "function"]) @@ -223,9 +221,7 @@ def test_new_agent_framework_requires_agent_type( ) assert not os.path.exists("main.py") - def test_new_invalid_type_rejected( - self, runner: CliRunner, temp_dir: str - ) -> None: + def test_new_invalid_type_rejected(self, runner: CliRunner, temp_dir: str) -> None: """Unknown --type values are rejected by click.""" with runner.isolated_filesystem(temp_dir=temp_dir): result = runner.invoke(cli, ["new", "my_project", "--type", "workflow"]) From f5ffe59ec8d537dd6e899487be8c228bada3f135 Mon Sep 17 00:00:00 2001 From: Vlad Cimpeanu Date: Mon, 7 Sep 2026 18:20:53 +0300 Subject: [PATCH 03/11] fix(cli): document the conditional --agent-framework default in help text show_default rendered '[default: (langchain)]' even though the option is invalid without --type agent; state the conditional default in the help sentence instead. Co-Authored-By: Claude Fable 5 --- packages/uipath/src/uipath/_cli/cli_new.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/uipath/src/uipath/_cli/cli_new.py b/packages/uipath/src/uipath/_cli/cli_new.py index 9240d7791..fd6ea350a 100644 --- a/packages/uipath/src/uipath/_cli/cli_new.py +++ b/packages/uipath/src/uipath/_cli/cli_new.py @@ -74,8 +74,10 @@ def generate_uipath_json(target_directory): "agent_framework", type=click.Choice([f.value for f in AgentFramework]), default=None, - show_default=DEFAULT_AGENT_FRAMEWORK.value, - help="Agent framework to scaffold for. Only valid together with `--type agent`.", + help=( + "Agent framework to scaffold for. Only valid together with `--type agent`; " + f"defaults to '{DEFAULT_AGENT_FRAMEWORK.value}' when `--type agent` is used." + ), ) @track_command("new") def new(name: str, project_type: str, agent_framework: str | None): From e38a16649f06f70b67b3017f7bb1af189ca5e6ea Mon Sep 17 00:00:00 2001 From: Vlad Cimpeanu Date: Wed, 9 Sep 2026 14:22:44 +0300 Subject: [PATCH 04/11] chore: bump version to 2.14.14 2.14.13 was released from main in the meantime; rebase and take the next patch slot. Co-Authored-By: Claude Fable 5 --- packages/uipath/pyproject.toml | 2 +- packages/uipath/uv.lock | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/uipath/pyproject.toml b/packages/uipath/pyproject.toml index 0b1b056fc..86bb4d18f 100644 --- a/packages/uipath/pyproject.toml +++ b/packages/uipath/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "uipath" -version = "2.14.13" +version = "2.14.14" 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" diff --git a/packages/uipath/uv.lock b/packages/uipath/uv.lock index adc2c346e..e4b20d6f2 100644 --- a/packages/uipath/uv.lock +++ b/packages/uipath/uv.lock @@ -2599,7 +2599,7 @@ wheels = [ [[package]] name = "uipath" -version = "2.14.13" +version = "2.14.14" source = { editable = "." } dependencies = [ { name = "applicationinsights" }, From 6d5bcf6bf1eda6686bb8ce332188e7380ddd85c9 Mon Sep 17 00:00:00 2001 From: Vlad Cimpeanu Date: Thu, 10 Sep 2026 16:16:00 +0300 Subject: [PATCH 05/11] feat(cli): add --type auto as the default for uipath new 'auto' preserves the pre-flag behaviour: an installed agent framework claims the scaffold, otherwise the base function project is created. --agent-framework stays valid only with an explicit --type agent; callers that need a guaranteed function project pass --type function. Co-Authored-By: Claude Fable 5 --- packages/uipath/src/uipath/_cli/cli_new.py | 6 ++-- .../src/uipath/_cli/models/project_types.py | 8 ++++- packages/uipath/tests/cli/test_new.py | 32 +++++++++++++++---- 3 files changed, 37 insertions(+), 9 deletions(-) diff --git a/packages/uipath/src/uipath/_cli/cli_new.py b/packages/uipath/src/uipath/_cli/cli_new.py index fd6ea350a..65f9dc485 100644 --- a/packages/uipath/src/uipath/_cli/cli_new.py +++ b/packages/uipath/src/uipath/_cli/cli_new.py @@ -65,9 +65,11 @@ def generate_uipath_json(target_directory): "--type", "project_type", type=click.Choice([t.value for t in ProjectType]), - default=ProjectType.FUNCTION.value, + default=ProjectType.AUTO.value, show_default=True, - help="Project type to scaffold. 'agent' requires an agent framework package (e.g. uipath-langchain).", + help="Project type to scaffold. 'auto' scaffolds an agent when an agent " + "framework package (e.g. uipath-langchain) is installed and a function " + "otherwise; 'agent' requires one explicitly.", ) @click.option( "--agent-framework", diff --git a/packages/uipath/src/uipath/_cli/models/project_types.py b/packages/uipath/src/uipath/_cli/models/project_types.py index f074f7ae7..1721f5999 100644 --- a/packages/uipath/src/uipath/_cli/models/project_types.py +++ b/packages/uipath/src/uipath/_cli/models/project_types.py @@ -9,7 +9,13 @@ class ProjectType(StrEnum): - """What `uipath new` scaffolds.""" + """What `uipath new` scaffolds. + AUTO (the default) lets an installed agent framework claim the scaffold + and falls back to a function project; FUNCTION and AGENT request one + explicitly. + """ + + AUTO = "auto" FUNCTION = "function" AGENT = "agent" diff --git a/packages/uipath/tests/cli/test_new.py b/packages/uipath/tests/cli/test_new.py index d1092e917..bb85377f8 100644 --- a/packages/uipath/tests/cli/test_new.py +++ b/packages/uipath/tests/cli/test_new.py @@ -86,10 +86,10 @@ def test_new_project_middleware_interaction( assert result.exit_code == 0 assert os.path.exists("main.py") - def test_new_default_type_is_function( - self, runner: CliRunner, temp_dir: str - ) -> None: - """Without --type, middlewares receive project_type='function'.""" + def test_new_default_type_is_auto(self, runner: CliRunner, temp_dir: str) -> None: + """Without --type, middlewares receive project_type='auto' so an + installed agent framework can claim the scaffold; unclaimed, the + base falls back to a function project.""" with runner.isolated_filesystem(temp_dir=temp_dir): with patch("uipath._cli.cli_new.Middlewares.next") as mock_middleware: mock_middleware.return_value = MiddlewareResult(should_continue=True) @@ -99,11 +99,30 @@ def test_new_default_type_is_function( mock_middleware.assert_called_once_with( "new", "my_project", - project_type=ProjectType.FUNCTION, + project_type=ProjectType.AUTO, agent_framework=None, ) assert os.path.exists("uipath.json") + def test_new_explicit_type_auto_claimed_by_middleware( + self, runner: CliRunner, temp_dir: str + ) -> None: + """--type auto lets a framework middleware claim the scaffold.""" + with runner.isolated_filesystem(temp_dir=temp_dir): + with patch("uipath._cli.cli_new.Middlewares.next") as mock_middleware: + mock_middleware.return_value = MiddlewareResult(should_continue=False) + + result = runner.invoke(cli, ["new", "my_agent", "--type", "auto"]) + assert result.exit_code == 0 + mock_middleware.assert_called_once_with( + "new", + "my_agent", + project_type=ProjectType.AUTO, + agent_framework=None, + ) + # Claimed by the middleware: no base function scaffold. + assert not os.path.exists("uipath.json") + def test_new_explicit_type_function(self, runner: CliRunner, temp_dir: str) -> None: """--type function scaffolds the base function project.""" with runner.isolated_filesystem(temp_dir=temp_dir): @@ -206,7 +225,8 @@ def test_new_agent_framework_requires_agent_type( """--agent-framework without --type agent is rejected.""" with runner.isolated_filesystem(temp_dir=temp_dir): for extra_args in ( - [], # implicit --type function + [], # implicit --type auto + ["--type", "auto"], ["--type", "function"], ): result = runner.invoke( From 9d5769586130ee0196ee668d7f1ae65e8c5c485d Mon Sep 17 00:00:00 2001 From: Vlad Cimpeanu Date: Thu, 10 Sep 2026 17:13:00 +0300 Subject: [PATCH 06/11] feat(cli): resolve an unset --agent-framework from the installed integration `uipath new --type agent` without --agent-framework now uses the framework whose integration package is installed instead of hard-defaulting to langchain: a single installed integration wins, langchain breaks ties and stays the fallback when none are installed, and several non-langchain integrations produce a pick-one error instead of an arbitrary choice. Co-Authored-By: Claude Fable 5 --- packages/uipath/src/uipath/_cli/cli_new.py | 32 ++++++- .../uipath/_cli/models/agent_frameworks.py | 13 +++ packages/uipath/tests/cli/test_new.py | 89 ++++++++++++++++++- 3 files changed, 128 insertions(+), 6 deletions(-) diff --git a/packages/uipath/src/uipath/_cli/cli_new.py b/packages/uipath/src/uipath/_cli/cli_new.py index 65f9dc485..83c862eb8 100644 --- a/packages/uipath/src/uipath/_cli/cli_new.py +++ b/packages/uipath/src/uipath/_cli/cli_new.py @@ -11,7 +11,11 @@ from ._utils._console import ConsoleLogger from ._utils._project_files import resolve_existing_project_id from .middlewares import Middlewares -from .models.agent_frameworks import DEFAULT_AGENT_FRAMEWORK, AgentFramework +from .models.agent_frameworks import ( + DEFAULT_AGENT_FRAMEWORK, + AgentFramework, + installed_agent_frameworks, +) from .models.project_types import ProjectType console = ConsoleLogger() @@ -59,6 +63,27 @@ def generate_uipath_json(target_directory): json.dump(uipath_config, f, indent=2) +def _detect_agent_framework() -> AgentFramework: + """Resolve an unset --agent-framework from the installed integrations. + + A single installed integration wins; langchain breaks ties when several + are installed and is the fallback when none are. + """ + installed = installed_agent_frameworks() + if len(installed) == 1: + framework = installed[0] + if framework is not DEFAULT_AGENT_FRAMEWORK: + console.info(f"Using the installed '{framework}' agent framework.") + return framework + if not installed or DEFAULT_AGENT_FRAMEWORK in installed: + return DEFAULT_AGENT_FRAMEWORK + console.error( + "Multiple agent frameworks are installed: " + + ", ".join(sorted(installed)) + + ".\nPick one with `--agent-framework`." + ) + + @click.command() @click.argument("name", type=str, default="") @click.option( @@ -78,7 +103,8 @@ def generate_uipath_json(target_directory): default=None, help=( "Agent framework to scaffold for. Only valid together with `--type agent`; " - f"defaults to '{DEFAULT_AGENT_FRAMEWORK.value}' when `--type agent` is used." + "defaults to the framework whose integration package is installed, or to " + f"'{DEFAULT_AGENT_FRAMEWORK.value}'." ), ) @track_command("new") @@ -100,7 +126,7 @@ def new(name: str, project_type: str, agent_framework: str | None): ) if scaffold_type is ProjectType.AGENT and framework is None: - framework = DEFAULT_AGENT_FRAMEWORK + framework = _detect_agent_framework() result = Middlewares.next( "new", name, project_type=scaffold_type, agent_framework=framework diff --git a/packages/uipath/src/uipath/_cli/models/agent_frameworks.py b/packages/uipath/src/uipath/_cli/models/agent_frameworks.py index 57b38fe78..bc8d994af 100644 --- a/packages/uipath/src/uipath/_cli/models/agent_frameworks.py +++ b/packages/uipath/src/uipath/_cli/models/agent_frameworks.py @@ -4,6 +4,7 @@ agent scaffolds for its framework. """ +import importlib.metadata from enum import StrEnum @@ -36,3 +37,15 @@ def package(self) -> str: } DEFAULT_AGENT_FRAMEWORK = AgentFramework.LANGCHAIN + + +def installed_agent_frameworks() -> list[AgentFramework]: + """Agent frameworks whose integration package is installed in this environment.""" + installed = [] + for framework in AgentFramework: + try: + importlib.metadata.distribution(framework.package) + except importlib.metadata.PackageNotFoundError: + continue + installed.append(framework) + return installed diff --git a/packages/uipath/tests/cli/test_new.py b/packages/uipath/tests/cli/test_new.py index bb85377f8..ed4661e1d 100644 --- a/packages/uipath/tests/cli/test_new.py +++ b/packages/uipath/tests/cli/test_new.py @@ -137,7 +137,12 @@ def test_new_type_agent_without_framework_errors( ) -> None: """--type agent with no framework handling it must not fall back to a function scaffold.""" with runner.isolated_filesystem(temp_dir=temp_dir): - with patch("uipath._cli.cli_new.Middlewares.next") as mock_middleware: + with ( + patch("uipath._cli.cli_new.Middlewares.next") as mock_middleware, + patch( + "uipath._cli.cli_new.installed_agent_frameworks", return_value=[] + ), + ): # No agent framework middleware claimed the command. mock_middleware.return_value = MiddlewareResult(should_continue=True) @@ -151,9 +156,14 @@ def test_new_type_agent_without_framework_errors( def test_new_type_agent_defaults_to_langchain_framework( self, runner: CliRunner, temp_dir: str ) -> None: - """--type agent without --agent-framework resolves to langchain.""" + """--type agent with no integration installed resolves to langchain.""" with runner.isolated_filesystem(temp_dir=temp_dir): - with patch("uipath._cli.cli_new.Middlewares.next") as mock_middleware: + with ( + patch("uipath._cli.cli_new.Middlewares.next") as mock_middleware, + patch( + "uipath._cli.cli_new.installed_agent_frameworks", return_value=[] + ), + ): mock_middleware.return_value = MiddlewareResult(should_continue=False) result = runner.invoke(cli, ["new", "my_agent", "--type", "agent"]) @@ -165,6 +175,79 @@ def test_new_type_agent_defaults_to_langchain_framework( agent_framework=AgentFramework.LANGCHAIN, ) + def test_new_type_agent_uses_the_single_installed_framework( + self, runner: CliRunner, temp_dir: str + ) -> None: + """--type agent without --agent-framework picks the one installed integration.""" + with runner.isolated_filesystem(temp_dir=temp_dir): + with ( + patch("uipath._cli.cli_new.Middlewares.next") as mock_middleware, + patch( + "uipath._cli.cli_new.installed_agent_frameworks", + return_value=[AgentFramework.LLAMAINDEX], + ), + ): + mock_middleware.return_value = MiddlewareResult(should_continue=False) + + result = runner.invoke(cli, ["new", "my_agent", "--type", "agent"]) + assert result.exit_code == 0 + assert "Using the installed 'llamaindex' agent framework" in ( + result.output + ) + mock_middleware.assert_called_once_with( + "new", + "my_agent", + project_type=ProjectType.AGENT, + agent_framework=AgentFramework.LLAMAINDEX, + ) + + def test_new_type_agent_prefers_langchain_among_installed( + self, runner: CliRunner, temp_dir: str + ) -> None: + """langchain breaks the tie when several integrations are installed.""" + with runner.isolated_filesystem(temp_dir=temp_dir): + with ( + patch("uipath._cli.cli_new.Middlewares.next") as mock_middleware, + patch( + "uipath._cli.cli_new.installed_agent_frameworks", + return_value=[AgentFramework.LLAMAINDEX, AgentFramework.LANGCHAIN], + ), + ): + mock_middleware.return_value = MiddlewareResult(should_continue=False) + + result = runner.invoke(cli, ["new", "my_agent", "--type", "agent"]) + assert result.exit_code == 0 + mock_middleware.assert_called_once_with( + "new", + "my_agent", + project_type=ProjectType.AGENT, + agent_framework=AgentFramework.LANGCHAIN, + ) + + def test_new_type_agent_ambiguous_installed_frameworks_error( + self, runner: CliRunner, temp_dir: str + ) -> None: + """Several non-langchain integrations installed: ask the user to pick.""" + with runner.isolated_filesystem(temp_dir=temp_dir): + with ( + patch("uipath._cli.cli_new.Middlewares.next") as mock_middleware, + patch( + "uipath._cli.cli_new.installed_agent_frameworks", + return_value=[ + AgentFramework.LLAMAINDEX, + AgentFramework.PYDANTIC_AI, + ], + ), + ): + mock_middleware.return_value = MiddlewareResult(should_continue=True) + + result = runner.invoke(cli, ["new", "my_agent", "--type", "agent"]) + assert result.exit_code == 1 + assert "Multiple agent frameworks are installed" in result.output + assert "llamaindex, pydantic-ai" in result.output + assert not os.path.exists("main.py") + mock_middleware.assert_not_called() + def test_new_agent_framework_forwarded_to_middlewares( self, runner: CliRunner, temp_dir: str ) -> None: From 26be64bed8f22cf8121576d571beb00f508798c5 Mon Sep 17 00:00:00 2001 From: Vlad Cimpeanu Date: Thu, 10 Sep 2026 17:24:23 +0300 Subject: [PATCH 07/11] fix(cli): give the missing agent-framework error install instructions Match the `uipath dev` missing-package style: name the required integration package and show copy-pasteable pip and uv install commands, keeping the function-project alternative as the last line. Co-Authored-By: Claude Fable 5 --- packages/uipath/src/uipath/_cli/cli_new.py | 11 ++++++++--- packages/uipath/tests/cli/test_new.py | 14 +++++++++----- 2 files changed, 17 insertions(+), 8 deletions(-) diff --git a/packages/uipath/src/uipath/_cli/cli_new.py b/packages/uipath/src/uipath/_cli/cli_new.py index 83c862eb8..5e3d37767 100644 --- a/packages/uipath/src/uipath/_cli/cli_new.py +++ b/packages/uipath/src/uipath/_cli/cli_new.py @@ -145,9 +145,14 @@ def new(name: str, project_type: str, agent_framework: str | None): if framework is not None: # only set for agent scaffolds console.error( - f"The '{framework}' agent framework is not installed.\n" - f"Install `{framework.package}` to scaffold this agent, " - f"or run `uipath new {name}` to create a function project." + f"The '{framework.package}' package is required to scaffold a " + f"'{framework}' agent.\n" + "Please install it:\n\n" + " # Using pip:\n" + f" pip install {framework.package}\n\n" + " # Using uv:\n" + f" uv add {framework.package}\n\n" + f"Or run `uipath new {name}` to create a function project." ) with console.spinner(f"Creating new project {name} in current directory ..."): diff --git a/packages/uipath/tests/cli/test_new.py b/packages/uipath/tests/cli/test_new.py index ed4661e1d..3b7060a0c 100644 --- a/packages/uipath/tests/cli/test_new.py +++ b/packages/uipath/tests/cli/test_new.py @@ -148,8 +148,12 @@ def test_new_type_agent_without_framework_errors( result = runner.invoke(cli, ["new", "my_agent", "--type", "agent"]) assert result.exit_code == 1 - assert "'langchain' agent framework is not installed" in result.output - assert "uipath-langchain" in result.output + assert ( + "'uipath-langchain' package is required to scaffold a " + "'langchain' agent" in result.output + ) + assert "pip install uipath-langchain" in result.output + assert "uv add uipath-langchain" in result.output assert not os.path.exists("main.py") assert not os.path.exists("uipath.json") @@ -296,10 +300,10 @@ def test_new_agent_framework_not_installed_names_package( ) assert result.exit_code == 1 assert ( - "'microsoft-agent-framework' agent framework is not installed" - in result.output + "'uipath-agent-framework' package is required to scaffold a " + "'microsoft-agent-framework' agent" in result.output ) - assert "uipath-agent-framework" in result.output + assert "uv add uipath-agent-framework" in result.output assert not os.path.exists("main.py") def test_new_agent_framework_requires_agent_type( From 7eb1fff6fed3800e4f0fc92328e3e3e807ec6795 Mon Sep 17 00:00:00 2001 From: Vlad Cimpeanu Date: Thu, 10 Sep 2026 17:46:40 +0300 Subject: [PATCH 08/11] fix(cli): require an explicit --agent-framework when several are installed Drop the langchain tie-break: with more than one integration installed, `uipath new --type agent` errors and asks for --agent-framework instead of silently preferring langchain. langchain stays the fallback only when no integration is installed. Co-Authored-By: Claude Fable 5 --- packages/uipath/src/uipath/_cli/cli_new.py | 6 +++--- packages/uipath/tests/cli/test_new.py | 15 ++++++--------- 2 files changed, 9 insertions(+), 12 deletions(-) diff --git a/packages/uipath/src/uipath/_cli/cli_new.py b/packages/uipath/src/uipath/_cli/cli_new.py index 5e3d37767..3494f3bad 100644 --- a/packages/uipath/src/uipath/_cli/cli_new.py +++ b/packages/uipath/src/uipath/_cli/cli_new.py @@ -66,8 +66,8 @@ def generate_uipath_json(target_directory): def _detect_agent_framework() -> AgentFramework: """Resolve an unset --agent-framework from the installed integrations. - A single installed integration wins; langchain breaks ties when several - are installed and is the fallback when none are. + A single installed integration wins; several installed require an + explicit choice, and langchain is the fallback when none are installed. """ installed = installed_agent_frameworks() if len(installed) == 1: @@ -75,7 +75,7 @@ def _detect_agent_framework() -> AgentFramework: if framework is not DEFAULT_AGENT_FRAMEWORK: console.info(f"Using the installed '{framework}' agent framework.") return framework - if not installed or DEFAULT_AGENT_FRAMEWORK in installed: + if not installed: return DEFAULT_AGENT_FRAMEWORK console.error( "Multiple agent frameworks are installed: " diff --git a/packages/uipath/tests/cli/test_new.py b/packages/uipath/tests/cli/test_new.py index 3b7060a0c..12bc08b72 100644 --- a/packages/uipath/tests/cli/test_new.py +++ b/packages/uipath/tests/cli/test_new.py @@ -205,10 +205,10 @@ def test_new_type_agent_uses_the_single_installed_framework( agent_framework=AgentFramework.LLAMAINDEX, ) - def test_new_type_agent_prefers_langchain_among_installed( + def test_new_type_agent_multiple_installed_requires_explicit_choice( self, runner: CliRunner, temp_dir: str ) -> None: - """langchain breaks the tie when several integrations are installed.""" + """Several integrations installed (langchain included) must be disambiguated.""" with runner.isolated_filesystem(temp_dir=temp_dir): with ( patch("uipath._cli.cli_new.Middlewares.next") as mock_middleware, @@ -220,13 +220,10 @@ def test_new_type_agent_prefers_langchain_among_installed( mock_middleware.return_value = MiddlewareResult(should_continue=False) result = runner.invoke(cli, ["new", "my_agent", "--type", "agent"]) - assert result.exit_code == 0 - mock_middleware.assert_called_once_with( - "new", - "my_agent", - project_type=ProjectType.AGENT, - agent_framework=AgentFramework.LANGCHAIN, - ) + assert result.exit_code == 1 + assert "Multiple agent frameworks are installed" in result.output + assert "langchain, llamaindex" in result.output + mock_middleware.assert_not_called() def test_new_type_agent_ambiguous_installed_frameworks_error( self, runner: CliRunner, temp_dir: str From fc9e2507feb236c535dca16e82e563db9e4c498a Mon Sep 17 00:00:00 2001 From: Vlad Cimpeanu Date: Thu, 10 Sep 2026 17:52:03 +0300 Subject: [PATCH 09/11] fix(cli): error on ambiguous --type auto scaffolds too MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit With several agent framework integrations installed, `--type auto` used to resolve by middleware registration order — effectively arbitrary. Move the multiple-integrations check in front of the middleware dispatch so both auto and agent scaffolds error and ask for an explicit `--type agent --agent-framework ` (or `--type function`). Co-Authored-By: Claude Fable 5 --- packages/uipath/src/uipath/_cli/cli_new.py | 32 ++++++++++-------- packages/uipath/tests/cli/test_new.py | 38 ++++++++++++++++++++-- 2 files changed, 54 insertions(+), 16 deletions(-) diff --git a/packages/uipath/src/uipath/_cli/cli_new.py b/packages/uipath/src/uipath/_cli/cli_new.py index 3494f3bad..1b42846be 100644 --- a/packages/uipath/src/uipath/_cli/cli_new.py +++ b/packages/uipath/src/uipath/_cli/cli_new.py @@ -63,25 +63,19 @@ def generate_uipath_json(target_directory): json.dump(uipath_config, f, indent=2) -def _detect_agent_framework() -> AgentFramework: +def _detect_agent_framework(installed: list[AgentFramework]) -> AgentFramework: """Resolve an unset --agent-framework from the installed integrations. - A single installed integration wins; several installed require an - explicit choice, and langchain is the fallback when none are installed. + Called with at most one installed integration (several error out before + this): the single installed one wins, langchain is the fallback when + none are installed. """ - installed = installed_agent_frameworks() - if len(installed) == 1: + if installed: framework = installed[0] if framework is not DEFAULT_AGENT_FRAMEWORK: console.info(f"Using the installed '{framework}' agent framework.") return framework - if not installed: - return DEFAULT_AGENT_FRAMEWORK - console.error( - "Multiple agent frameworks are installed: " - + ", ".join(sorted(installed)) - + ".\nPick one with `--agent-framework`." - ) + return DEFAULT_AGENT_FRAMEWORK @click.command() @@ -125,8 +119,18 @@ def new(name: str, project_type: str, agent_framework: str | None): "`--agent-framework` can only be used together with `--type agent`." ) - if scaffold_type is ProjectType.AGENT and framework is None: - framework = _detect_agent_framework() + if framework is None and scaffold_type is not ProjectType.FUNCTION: + installed = installed_agent_frameworks() + if len(installed) > 1: + console.error( + "Multiple agent frameworks are installed: " + + ", ".join(sorted(installed)) + + ".\nPick one with `--type agent --agent-framework `, " + f"or run `uipath new {name} --type function` to create a " + "function project." + ) + if scaffold_type is ProjectType.AGENT: + framework = _detect_agent_framework(installed) result = Middlewares.next( "new", name, project_type=scaffold_type, agent_framework=framework diff --git a/packages/uipath/tests/cli/test_new.py b/packages/uipath/tests/cli/test_new.py index 12bc08b72..5d9a22f7d 100644 --- a/packages/uipath/tests/cli/test_new.py +++ b/packages/uipath/tests/cli/test_new.py @@ -91,7 +91,12 @@ def test_new_default_type_is_auto(self, runner: CliRunner, temp_dir: str) -> Non installed agent framework can claim the scaffold; unclaimed, the base falls back to a function project.""" with runner.isolated_filesystem(temp_dir=temp_dir): - with patch("uipath._cli.cli_new.Middlewares.next") as mock_middleware: + with ( + patch("uipath._cli.cli_new.Middlewares.next") as mock_middleware, + patch( + "uipath._cli.cli_new.installed_agent_frameworks", return_value=[] + ), + ): mock_middleware.return_value = MiddlewareResult(should_continue=True) result = runner.invoke(cli, ["new", "my_project"]) @@ -109,7 +114,13 @@ def test_new_explicit_type_auto_claimed_by_middleware( ) -> None: """--type auto lets a framework middleware claim the scaffold.""" with runner.isolated_filesystem(temp_dir=temp_dir): - with patch("uipath._cli.cli_new.Middlewares.next") as mock_middleware: + with ( + patch("uipath._cli.cli_new.Middlewares.next") as mock_middleware, + patch( + "uipath._cli.cli_new.installed_agent_frameworks", + return_value=[AgentFramework.LLAMAINDEX], + ), + ): mock_middleware.return_value = MiddlewareResult(should_continue=False) result = runner.invoke(cli, ["new", "my_agent", "--type", "auto"]) @@ -123,6 +134,29 @@ def test_new_explicit_type_auto_claimed_by_middleware( # Claimed by the middleware: no base function scaffold. assert not os.path.exists("uipath.json") + def test_new_type_auto_multiple_installed_requires_explicit_choice( + self, runner: CliRunner, temp_dir: str + ) -> None: + """Auto with several integrations installed must not pick one by + middleware registration order — it errors before dispatch.""" + with runner.isolated_filesystem(temp_dir=temp_dir): + with ( + patch("uipath._cli.cli_new.Middlewares.next") as mock_middleware, + patch( + "uipath._cli.cli_new.installed_agent_frameworks", + return_value=[AgentFramework.LANGCHAIN, AgentFramework.LLAMAINDEX], + ), + ): + mock_middleware.return_value = MiddlewareResult(should_continue=False) + + result = runner.invoke(cli, ["new", "my_agent"]) + assert result.exit_code == 1 + assert "Multiple agent frameworks are installed" in result.output + assert "langchain, llamaindex" in result.output + assert "--type function" in result.output + assert not os.path.exists("main.py") + mock_middleware.assert_not_called() + def test_new_explicit_type_function(self, runner: CliRunner, temp_dir: str) -> None: """--type function scaffolds the base function project.""" with runner.isolated_filesystem(temp_dir=temp_dir): From 8d2b2e929c086a2bf32852091a2798de9021ffd5 Mon Sep 17 00:00:00 2001 From: Vlad Cimpeanu Date: Thu, 10 Sep 2026 17:57:19 +0300 Subject: [PATCH 10/11] fix(cli): drop the hardcoded langchain default for --type agent With --type auto covering "use what is installed", a langchain fallback on bare --type agent is arbitrary: when no integration is installed, error with the list of frameworks and their integration packages instead. Remove DEFAULT_AGENT_FRAMEWORK; a single installed integration still resolves automatically (now always announced with an info line). Co-Authored-By: Claude Fable 5 --- packages/uipath/src/uipath/_cli/cli_new.py | 25 ++++++++-------- .../uipath/_cli/models/agent_frameworks.py | 2 -- packages/uipath/tests/cli/test_new.py | 30 +++++++++---------- 3 files changed, 28 insertions(+), 29 deletions(-) diff --git a/packages/uipath/src/uipath/_cli/cli_new.py b/packages/uipath/src/uipath/_cli/cli_new.py index 1b42846be..10a65d316 100644 --- a/packages/uipath/src/uipath/_cli/cli_new.py +++ b/packages/uipath/src/uipath/_cli/cli_new.py @@ -11,11 +11,7 @@ from ._utils._console import ConsoleLogger from ._utils._project_files import resolve_existing_project_id from .middlewares import Middlewares -from .models.agent_frameworks import ( - DEFAULT_AGENT_FRAMEWORK, - AgentFramework, - installed_agent_frameworks, -) +from .models.agent_frameworks import AgentFramework, installed_agent_frameworks from .models.project_types import ProjectType console = ConsoleLogger() @@ -67,15 +63,21 @@ def _detect_agent_framework(installed: list[AgentFramework]) -> AgentFramework: """Resolve an unset --agent-framework from the installed integrations. Called with at most one installed integration (several error out before - this): the single installed one wins, langchain is the fallback when - none are installed. + this): the single installed one wins, none installed errors with the + list of frameworks and their packages. """ if installed: framework = installed[0] - if framework is not DEFAULT_AGENT_FRAMEWORK: - console.info(f"Using the installed '{framework}' agent framework.") + console.info(f"Using the installed '{framework}' agent framework.") return framework - return DEFAULT_AGENT_FRAMEWORK + frameworks = "\n".join( + f" {framework.value:<27}{framework.package}" for framework in AgentFramework + ) + console.error( + "No agent framework integration is installed.\n" + "Please install the package for the framework you want " + "(`pip install ` or `uv add `):\n\n" + frameworks + ) @click.command() @@ -97,8 +99,7 @@ def _detect_agent_framework(installed: list[AgentFramework]) -> AgentFramework: default=None, help=( "Agent framework to scaffold for. Only valid together with `--type agent`; " - "defaults to the framework whose integration package is installed, or to " - f"'{DEFAULT_AGENT_FRAMEWORK.value}'." + "defaults to the framework whose integration package is installed." ), ) @track_command("new") diff --git a/packages/uipath/src/uipath/_cli/models/agent_frameworks.py b/packages/uipath/src/uipath/_cli/models/agent_frameworks.py index bc8d994af..40e5e51ff 100644 --- a/packages/uipath/src/uipath/_cli/models/agent_frameworks.py +++ b/packages/uipath/src/uipath/_cli/models/agent_frameworks.py @@ -36,8 +36,6 @@ def package(self) -> str: AgentFramework.PYDANTIC_AI: "uipath-pydantic-ai", } -DEFAULT_AGENT_FRAMEWORK = AgentFramework.LANGCHAIN - def installed_agent_frameworks() -> list[AgentFramework]: """Agent frameworks whose integration package is installed in this environment.""" diff --git a/packages/uipath/tests/cli/test_new.py b/packages/uipath/tests/cli/test_new.py index 5d9a22f7d..e4847da58 100644 --- a/packages/uipath/tests/cli/test_new.py +++ b/packages/uipath/tests/cli/test_new.py @@ -166,18 +166,20 @@ def test_new_explicit_type_function(self, runner: CliRunner, temp_dir: str) -> N config = json.load(f) assert config["functions"] == {"main": "main.py:main"} - def test_new_type_agent_without_framework_errors( + def test_new_type_agent_single_installed_but_unclaimed_errors( self, runner: CliRunner, temp_dir: str ) -> None: - """--type agent with no framework handling it must not fall back to a function scaffold.""" + """A resolved framework nothing claims must not fall back to a function scaffold.""" with runner.isolated_filesystem(temp_dir=temp_dir): with ( patch("uipath._cli.cli_new.Middlewares.next") as mock_middleware, patch( - "uipath._cli.cli_new.installed_agent_frameworks", return_value=[] + "uipath._cli.cli_new.installed_agent_frameworks", + return_value=[AgentFramework.LANGCHAIN], ), ): - # No agent framework middleware claimed the command. + # Installed, but its middleware did not claim the command + # (e.g. an outdated integration). mock_middleware.return_value = MiddlewareResult(should_continue=True) result = runner.invoke(cli, ["new", "my_agent", "--type", "agent"]) @@ -191,10 +193,10 @@ def test_new_type_agent_without_framework_errors( assert not os.path.exists("main.py") assert not os.path.exists("uipath.json") - def test_new_type_agent_defaults_to_langchain_framework( + def test_new_type_agent_no_integration_installed_lists_frameworks( self, runner: CliRunner, temp_dir: str ) -> None: - """--type agent with no integration installed resolves to langchain.""" + """--type agent with nothing installed lists every framework and package.""" with runner.isolated_filesystem(temp_dir=temp_dir): with ( patch("uipath._cli.cli_new.Middlewares.next") as mock_middleware, @@ -202,16 +204,14 @@ def test_new_type_agent_defaults_to_langchain_framework( "uipath._cli.cli_new.installed_agent_frameworks", return_value=[] ), ): - mock_middleware.return_value = MiddlewareResult(should_continue=False) - result = runner.invoke(cli, ["new", "my_agent", "--type", "agent"]) - assert result.exit_code == 0 - mock_middleware.assert_called_once_with( - "new", - "my_agent", - project_type=ProjectType.AGENT, - agent_framework=AgentFramework.LANGCHAIN, - ) + assert result.exit_code == 1 + assert "No agent framework integration is installed" in result.output + for framework in AgentFramework: + assert framework.value in result.output + assert framework.package in result.output + assert not os.path.exists("main.py") + mock_middleware.assert_not_called() def test_new_type_agent_uses_the_single_installed_framework( self, runner: CliRunner, temp_dir: str From 8bb23b28e9ca20e9c457bdb11cc7fd309e9e20be Mon Sep 17 00:00:00 2001 From: Vlad Cimpeanu Date: Thu, 10 Sep 2026 18:01:03 +0300 Subject: [PATCH 11/11] style(cli): list only package names in the no-framework error Co-Authored-By: Claude Fable 5 --- packages/uipath/src/uipath/_cli/cli_new.py | 6 ++---- packages/uipath/tests/cli/test_new.py | 1 - 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/packages/uipath/src/uipath/_cli/cli_new.py b/packages/uipath/src/uipath/_cli/cli_new.py index 10a65d316..1d9712a79 100644 --- a/packages/uipath/src/uipath/_cli/cli_new.py +++ b/packages/uipath/src/uipath/_cli/cli_new.py @@ -70,13 +70,11 @@ def _detect_agent_framework(installed: list[AgentFramework]) -> AgentFramework: framework = installed[0] console.info(f"Using the installed '{framework}' agent framework.") return framework - frameworks = "\n".join( - f" {framework.value:<27}{framework.package}" for framework in AgentFramework - ) + packages = "\n".join(f" {framework.package}" for framework in AgentFramework) console.error( "No agent framework integration is installed.\n" "Please install the package for the framework you want " - "(`pip install ` or `uv add `):\n\n" + frameworks + "(`pip install ` or `uv add `):\n\n" + packages ) diff --git a/packages/uipath/tests/cli/test_new.py b/packages/uipath/tests/cli/test_new.py index e4847da58..42bbbcfc3 100644 --- a/packages/uipath/tests/cli/test_new.py +++ b/packages/uipath/tests/cli/test_new.py @@ -208,7 +208,6 @@ def test_new_type_agent_no_integration_installed_lists_frameworks( assert result.exit_code == 1 assert "No agent framework integration is installed" in result.output for framework in AgentFramework: - assert framework.value in result.output assert framework.package in result.output assert not os.path.exists("main.py") mock_middleware.assert_not_called()