Skip to content

Commit 3e18950

Browse files
fix(cli): add --type to uipath new so function projects stay reachable (#1886)
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
1 parent 7e2bad4 commit 3e18950

11 files changed

Lines changed: 544 additions & 15 deletions

File tree

‎packages/uipath/docs/cli/index.md‎

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,66 @@ Treat `--client-secret` as a credential. In CI, prefer reading it from a secret
6767

6868
---
6969

70+
::: mkdocs-click
71+
:module: uipath._cli
72+
:command: new
73+
:depth: 1
74+
:style: table
75+
76+
Scaffolds a project in the current directory. `--type` selects what gets created:
77+
78+
- **`auto`** (default) — an installed agent framework integration (e.g. `uipath-langchain`) claims the scaffold and creates a coded agent project; with none installed, a coded function project is created.
79+
- **`function`** — always creates a coded function project, regardless of installed integrations.
80+
- **`agent`** — creates a coded agent project with the installed framework integration, and fails if none is installed rather than quietly creating a function project.
81+
82+
| Installed framework integrations | `uipath new x` (auto) | `uipath new x --type agent` |
83+
|----------------------------------|------------------------|------------------------------|
84+
| none | coded function project | error: install an agent framework |
85+
| one | that framework's coded agent project | that framework's coded agent project |
86+
| several | warns, scaffolds with the first discovered | warns, scaffolds with the first discovered |
87+
88+
With one framework installed there is nothing to choose, so `uipath new` uses it. With several, it warns and scaffolds with the first one discovered — pass `--agent-framework` to choose deliberately:
89+
90+
```shell
91+
uipath new my-agent --type agent --agent-framework uipath-langchain
92+
```
93+
94+
`--agent-framework` takes the integration package name, is only valid together with `--type agent`, and scaffolds with that framework alone. The names it accepts are the packages installed in your environment — the same ones the error above lists — so `uipath` keeps no list of its own.
95+
96+
Scaffold a coded function:
97+
98+
<!-- termynal -->
99+
100+
```shell
101+
> uipath new my-function --type function
102+
⠋ Creating new project my-function in current directory ...
103+
✓ Created 'main.py' file.
104+
✓ Created 'pyproject.toml' file.
105+
✓ Created 'uipath.json' file.
106+
💡 Initialize project: uipath init
107+
💡 Run project: uipath run main '{"message": "Hello World!"}'
108+
```
109+
110+
Scaffold a coded agent — requires the framework's integration package in the environment:
111+
112+
<!-- termynal -->
113+
114+
```shell
115+
> uv add uipath-langchain
116+
Resolved 42 packages in 1.2s
117+
Installed 42 packages in 0.8s
118+
119+
> uipath new my-agent --type agent
120+
⠋ Creating new agent my-agent in current directory ...
121+
✓ Created 'main.py' file.
122+
✓ Created 'langgraph.json' file.
123+
✓ Created 'pyproject.toml' file.
124+
💡 Initialize project: uipath init
125+
💡 Run agent: uipath run agent '{"topic": "UiPath"}'
126+
```
127+
128+
---
129+
70130
::: mkdocs-click
71131
:module: uipath._cli
72132
:command: init

‎packages/uipath/docs/core/agents.md‎

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,9 @@ The `uipath` package is always required. Add one framework extension on top:
2525
| PydanticAI | `uipath-pydantic-ai` | Type-safe agents with Pydantic models |
2626
| Google ADK | `uipath-google-adk` | Gemini models, Google ecosystem |
2727
| UiPath Agent Framework | `uipath-agent-framework` | UiPath-native agent primitives |
28+
| Claude Agent SDK | `uipath-claude-sdk` | Claude models, Anthropic-native agent loop |
29+
30+
Installing one of these packages is what makes `uipath new` scaffold an agent. With more than one installed, name the one you want with `--agent-framework`, using the package exactly as it appears above.
2831

2932
---
3033

@@ -85,6 +88,20 @@ The example below uses LangChain. Swap `uipath-langchain` for the framework of y
8588

8689
////
8790

91+
/// info | Guaranteeing an agent project
92+
`uipath new` defaults to `--type auto`: the installed framework integration claims the scaffold, which is why the commands above create an agent project. Pass `--type agent` to make that a requirement — it fails with instructions instead of creating a function project when no framework is installed:
93+
94+
```shell
95+
uipath new agent --type agent
96+
```
97+
98+
With several framework integrations installed in the same environment, `uipath new` warns and uses the first one discovered; name the one you want instead with:
99+
100+
```shell
101+
uipath new agent --type agent --agent-framework uipath-langchain
102+
```
103+
///
104+
88105
---
89106

90107
## Project Structure

‎packages/uipath/docs/core/functions.md‎

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,14 @@ Use coded functions for deterministic compute steps: document extraction, ERP wr
7070

7171
////
7272

73+
/// info | Guaranteeing a function project
74+
`uipath new` defaults to `--type auto`: when an agent framework integration (e.g. `uipath-langchain`) is installed in the environment, it scaffolds a coded agent instead of a function. Pass `--type function` to always get a coded function project:
75+
76+
```shell
77+
uipath new my-function --type function
78+
```
79+
///
80+
7381
---
7482

7583
## Project Structure

‎packages/uipath/docs/core/studio_web.md‎

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,7 @@ First, install the SDK package for the framework you want to use:
171171
# uipath-pydantic-ai - PydanticAI
172172
# uipath-google-adk - Google ADK
173173
# uipath-agent-framework - UiPath Agent Framework
174+
# uipath-claude-sdk - Claude Agent SDK
174175
> uv add uipath-langchain
175176
Resolved 42 packages in 1.2s
176177
Installed 42 packages in 0.8s
@@ -190,6 +191,7 @@ Installed 42 packages in 0.8s
190191
# uipath-pydantic-ai - PydanticAI
191192
# uipath-google-adk - Google ADK
192193
# uipath-agent-framework - UiPath Agent Framework
194+
# uipath-claude-sdk - Claude Agent SDK
193195
> pip install uipath-langchain
194196
Successfully installed uipath-langchain
195197
```
@@ -221,9 +223,13 @@ Selected tenant: Tenant1
221223

222224
That's it, your agent should now be visible in Studio Web.
223225
226+
/// info
227+
`uipath new` defaults to `--type auto`, which lets the installed framework integration claim the scaffold. Pass `--type agent` to require an agent project — it fails rather than creating a function project when no framework is installed. With several integrations installed, `uipath new` warns and uses the first one discovered; pick explicitly with `uipath new agent --type agent --agent-framework uipath-langchain`.
228+
///
229+
224230
#### Coded Function
225231
226-
A coded function doesn't require an additional framework package. Authenticate, scaffold the project, and initialize it:
232+
A coded function doesn't require an additional framework package. Authenticate, scaffold the project, and initialize it (`--type function` guarantees a function project even when a framework integration is installed):
227233

228234
<!-- termynal -->
229235

@@ -238,7 +244,7 @@ Select tenant number: 0
238244
Selected tenant: Tenant1
239245
✓ Authentication successful.
240246
241-
> uipath new my-function
247+
> uipath new my-function --type function
242248
✓ Created 'main.py' file.
243249
✓ Created 'pyproject.toml' file.
244250
✓ Created 'uipath.json' file.

‎packages/uipath/pyproject.toml‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[project]
22
name = "uipath"
3-
version = "2.14.22"
3+
version = "2.14.23"
44
description = "Python SDK and CLI for UiPath Platform, enabling programmatic interaction with automation services, process management, and deployment tools."
55
readme = { file = "README.md", content-type = "text/markdown" }
66
requires-python = ">=3.11"

‎packages/uipath/src/uipath/_cli/_utils/_constants.py‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,3 +61,7 @@
6161
def is_binary_file(file_extension: str) -> bool:
6262
"""Determine if a file should be treated as binary."""
6363
return file_extension.lower() in BINARY_EXTENSIONS
64+
65+
66+
# Supported agent frameworks and their packages, for `uipath new --type agent`
67+
AGENT_FRAMEWORKS_DOCS_URL = "https://uipath.github.io/uipath-python/core/agents/"

‎packages/uipath/src/uipath/_cli/cli_new.py‎

Lines changed: 116 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import importlib.metadata
12
import json
23
import os
34
import shutil
@@ -9,8 +10,11 @@
910

1011
from ._telemetry import track_command
1112
from ._utils._console import ConsoleLogger
13+
from ._utils._constants import AGENT_FRAMEWORKS_DOCS_URL
1214
from ._utils._project_files import resolve_existing_project_id
13-
from .middlewares import Middlewares
15+
from .middlewares import MiddlewareResult, Middlewares
16+
from .models.agent_frameworks import AgentFramework
17+
from .models.project_types import ProjectType
1418

1519
console = ConsoleLogger()
1620

@@ -57,10 +61,91 @@ def generate_uipath_json(target_directory):
5761
json.dump(uipath_config, f, indent=2)
5862

5963

64+
def installed_agent_frameworks() -> list[AgentFramework]:
65+
"""Agent frameworks that can scaffold a project, in discovery order."""
66+
packages: dict[str, str] = {}
67+
for entry_point in importlib.metadata.entry_points(group="uipath.middlewares"):
68+
if entry_point.dist is not None:
69+
packages.setdefault(entry_point.module.split(".")[0], entry_point.dist.name)
70+
71+
frameworks = []
72+
for middleware in Middlewares.get("new"):
73+
package = packages.get(middleware.__module__.split(".")[0])
74+
if package is not None:
75+
frameworks.append(AgentFramework(package=package, scaffold=middleware))
76+
return frameworks
77+
78+
79+
def _select_agent_framework(
80+
frameworks: list[AgentFramework], requested: str
81+
) -> AgentFramework:
82+
"""Resolve `--agent-framework` against what is installed."""
83+
for framework in frameworks:
84+
if requested == framework.package:
85+
return framework
86+
87+
installed = (
88+
"Installed: "
89+
+ ", ".join(sorted(framework.package for framework in frameworks))
90+
+ "."
91+
if frameworks
92+
else "No agent framework is installed."
93+
)
94+
console.error(
95+
f"No installed agent framework matches '{requested}'.\n"
96+
f"{installed}\n"
97+
f"See {AGENT_FRAMEWORKS_DOCS_URL} for the supported frameworks and "
98+
"their packages."
99+
)
100+
101+
102+
def _scaffold_agent(name: str, agent_framework: str | None) -> MiddlewareResult:
103+
"""Offer the scaffold to the installed agent frameworks."""
104+
Middlewares.load_plugins()
105+
installed = installed_agent_frameworks()
106+
107+
if agent_framework:
108+
# Dispatch to the chosen framework alone, so that another one cannot
109+
# claim the scaffold ahead of it.
110+
return _select_agent_framework(installed, agent_framework).scaffold(name)
111+
112+
if len(installed) > 1:
113+
first = installed[0]
114+
console.warning(
115+
"Multiple agent frameworks are installed: "
116+
+ ", ".join(framework.package for framework in installed)
117+
+ f".\nScaffolding with the first one discovered: '{first.package}'. "
118+
f"To pick a different one, run `uipath new {name} --type agent "
119+
"--agent-framework <framework>`."
120+
)
121+
return first.scaffold(name)
122+
123+
return Middlewares.next("new", name)
124+
125+
60126
@click.command()
61127
@click.argument("name", type=str, default="")
128+
@click.option(
129+
"--type",
130+
"project_type",
131+
type=click.Choice([t.value for t in ProjectType]),
132+
default=ProjectType.AUTO.value,
133+
show_default=True,
134+
help="Project type to scaffold. 'auto' scaffolds an agent when an agent "
135+
"framework package (e.g. uipath-langchain) is installed and a function "
136+
"otherwise; 'function' always scaffolds a function; 'agent' scaffolds an "
137+
"agent and fails when no agent framework is installed.",
138+
)
139+
@click.option(
140+
"--agent-framework",
141+
"agent_framework",
142+
default=None,
143+
help="Agent framework to scaffold with, named by its package (e.g. "
144+
"`uipath-langchain`). Only valid together with `--type agent`; picks "
145+
"which framework scaffolds when several are installed.",
146+
)
62147
@track_command("new")
63-
def new(name: str):
148+
def new(name: str, project_type: str, agent_framework: str | None):
64149
"""Generate a quick-start project."""
65150
directory = os.getcwd()
66151

@@ -69,18 +154,39 @@ def new(name: str):
69154
"Please specify a name for your project:\n`uipath new hello-world`"
70155
)
71156

72-
result = Middlewares.next("new", name)
157+
scaffold_type = ProjectType(project_type)
73158

74-
if result.error_message:
159+
if agent_framework and scaffold_type is not ProjectType.AGENT:
75160
console.error(
76-
result.error_message, include_traceback=result.should_include_stacktrace
161+
"`--agent-framework` can only be used together with `--type agent`."
77162
)
78163

79-
if result.info_message:
80-
console.info(result.info_message)
81-
82-
if not result.should_continue:
83-
return
164+
# Agent frameworks scaffold through the `new` middleware chain. A function
165+
# project never consults them.
166+
if scaffold_type is not ProjectType.FUNCTION:
167+
result = _scaffold_agent(name, agent_framework)
168+
169+
if result.error_message:
170+
console.error(
171+
result.error_message, include_traceback=result.should_include_stacktrace
172+
)
173+
174+
if result.info_message:
175+
console.info(result.info_message)
176+
177+
if not result.should_continue:
178+
return # an agent framework scaffolded the project
179+
180+
if scaffold_type is ProjectType.AGENT:
181+
console.error(
182+
"No agent framework is installed, so there is nothing to "
183+
"scaffold an agent with.\n"
184+
"Install the framework you want to use and run this command "
185+
f"again — see {AGENT_FRAMEWORKS_DOCS_URL} for the supported "
186+
"frameworks and their packages.\n"
187+
f"Or run `uipath new {name} --type function` to create a "
188+
"function project."
189+
)
84190

85191
with console.spinner(f"Creating new project {name} in current directory ..."):
86192
generate_script(directory)
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
"""Agent frameworks that scaffold projects for `uipath new`."""
2+
3+
from dataclasses import dataclass
4+
5+
from ..middlewares import MiddlewareFunc
6+
7+
8+
@dataclass(frozen=True)
9+
class AgentFramework:
10+
"""An agent framework installed in this environment."""
11+
12+
package: str
13+
"""Package that provides it, and the value `--agent-framework` takes."""
14+
15+
scaffold: MiddlewareFunc
16+
"""Its `new` middleware."""
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
"""Project types scaffolded by `uipath new`."""
2+
3+
from enum import StrEnum
4+
5+
6+
class ProjectType(StrEnum):
7+
"""What `uipath new` scaffolds.
8+
9+
AUTO (the default) lets an installed agent framework claim the scaffold
10+
and falls back to a function project; FUNCTION and AGENT request one
11+
explicitly.
12+
"""
13+
14+
AUTO = "auto"
15+
FUNCTION = "function"
16+
AGENT = "agent"

0 commit comments

Comments
 (0)