diff --git a/pyproject.toml b/pyproject.toml index 729e4b731..7fe96929e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "uipath" -version = "2.6.30" +version = "2.7.0" 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/src/uipath/_cli/cli_init.py b/src/uipath/_cli/cli_init.py index dadb2987a..f1d3d41ca 100644 --- a/src/uipath/_cli/cli_init.py +++ b/src/uipath/_cli/cli_init.py @@ -293,7 +293,7 @@ async def initialize() -> None: if not entrypoints: console.warning( - 'No function entrypoints found. Add them to `uipath.json` under "functions": {"my_function": "src/main.py:main"}' + 'No entrypoints found. Add them to `uipath.json` under "functions" or "agents": {"my_function": "src/main.py:main"}' ) # Gather schemas from all discovered runtimes diff --git a/src/uipath/_cli/models/uipath_json_schema.py b/src/uipath/_cli/models/uipath_json_schema.py index bfcfa0ed2..f1cd30202 100644 --- a/src/uipath/_cli/models/uipath_json_schema.py +++ b/src/uipath/_cli/models/uipath_json_schema.py @@ -89,6 +89,12 @@ class UiPathJsonConfig(BaseModelWithDefaultConfig): "Each key is an entrypoint name, and each value is a path in format 'file_path:function_name'", ) + agents: dict[str, str] = Field( + default_factory=dict, + description="Entrypoint definitions for agent scripts. " + "Each key is an entrypoint name, and each value is a path in format 'file_path:agent_name'", + ) + def to_json_string(self, indent: int = 2) -> str: """Export to JSON string with proper formatting.""" return self.model_dump_json( @@ -110,6 +116,7 @@ def create_default(cls) -> "UiPathJsonConfig": include_uv_lock=True, ), functions={}, + agents={}, ) @classmethod diff --git a/src/uipath/functions/factory.py b/src/uipath/functions/factory.py index 7f9f68f48..ef472ea0e 100644 --- a/src/uipath/functions/factory.py +++ b/src/uipath/functions/factory.py @@ -44,22 +44,18 @@ def _load_config(self) -> dict[str, Any]: return self._config def discover_entrypoints(self) -> list[str]: - """Discover all function entrypoints from uipath.json.""" + """Discover all entrypoints (functions and agents) from uipath.json.""" config = self._load_config() - return list(config.get("functions", {}).keys()) + functions = list(config.get("functions", {}).keys()) + agents = list(config.get("agents", {}).keys()) + return functions + agents async def get_storage(self) -> UiPathRuntimeStorageProtocol | None: """Get storage protocol if any (placeholder for protocol compliance).""" return None async def get_settings(self) -> UiPathRuntimeFactorySettings | None: - """Get factory settings for coded functions. - - Coded functions don't need span filtering - all spans are relevant - since developers have full control over instrumentation. - - Low-code agents (LangGraph) need filtering due to framework overhead. - """ + """Get factory settings for coded functions.""" return None async def new_runtime( @@ -76,15 +72,22 @@ def _create_runtime(self, entrypoint: str) -> UiPathRuntimeProtocol: """Create runtime instance from entrypoint specification.""" config = self._load_config() functions = config.get("functions", {}) - - if entrypoint not in functions: + agents = config.get("agents", {}) + + # Check both functions and agents + if entrypoint in functions: + func_spec = functions[entrypoint] + entrypoint_type = "function" + elif entrypoint in agents: + func_spec = agents[entrypoint] + entrypoint_type = "agent" + else: + available = list(functions.keys()) + list(agents.keys()) raise ValueError( f"Entrypoint '{entrypoint}' not found in uipath.json. " - f"Available: {', '.join(functions.keys())}" + f"Available: {', '.join(available)}" ) - func_spec = functions[entrypoint] - if ":" not in func_spec: raise ValueError( f"Invalid function specification: '{func_spec}'. " @@ -97,4 +100,6 @@ def _create_runtime(self, entrypoint: str) -> UiPathRuntimeProtocol: if not full_path.exists(): raise ValueError(f"File not found: {full_path}") - return UiPathFunctionsRuntime(str(full_path), function_name, entrypoint) + return UiPathFunctionsRuntime( + str(full_path), function_name, entrypoint, entrypoint_type + ) diff --git a/src/uipath/functions/runtime.py b/src/uipath/functions/runtime.py index 2bd91b12c..37a7e38df 100644 --- a/src/uipath/functions/runtime.py +++ b/src/uipath/functions/runtime.py @@ -37,11 +37,25 @@ class UiPathFunctionsRuntime: """Runtime wrapper for a single Python function with full script executor compatibility.""" - def __init__(self, file_path: str, function_name: str, entrypoint_name: str): - """Initialize the function runtime.""" + def __init__( + self, + file_path: str, + function_name: str, + entrypoint_name: str, + entrypoint_type: str = "function", + ): + """Initialize the function runtime. + + Args: + file_path: Path to the Python file containing the function + function_name: Name of the function to execute + entrypoint_name: Name of the entrypoint + entrypoint_type: Type of entrypoint - 'function' or 'agent' + """ self.file_path = Path(file_path) self.function_name = function_name self.entrypoint_name = entrypoint_name + self.entrypoint_type = entrypoint_type self._function: Callable[..., Any] | None = None self._module: ModuleType | None = None @@ -180,10 +194,11 @@ async def get_schema(self) -> UiPathRuntimeSchema: # Determine output schema raw_output_schema = get_type_schema(hints.get("return")) output_schema = transform_attachments(raw_output_schema) + return UiPathRuntimeSchema( filePath=self.entrypoint_name, uniqueId=str(uuid.uuid4()), - type="agent", + type=self.entrypoint_type, input=input_schema, output=output_schema, ) diff --git a/uv.lock b/uv.lock index 5cb6decfb..0cac305ce 100644 --- a/uv.lock +++ b/uv.lock @@ -2491,7 +2491,7 @@ wheels = [ [[package]] name = "uipath" -version = "2.6.30" +version = "2.7.0" source = { editable = "." } dependencies = [ { name = "applicationinsights" },