uipath 2.1.89__py3-none-any.whl → 2.1.91__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of uipath might be problematic. Click here for more details.
- uipath/_cli/_evals/_runtime.py +4 -4
- uipath/_cli/_evals/mocks/llm_mocker.py +8 -3
- uipath/_cli/_evals/mocks/mocks.py +8 -1
- uipath/_cli/_push/sw_file_handler.py +3 -3
- uipath/_cli/_utils/_parse_ast.py +58 -32
- uipath/_cli/_utils/_project_files.py +8 -10
- uipath/_cli/cli_init.py +58 -40
- uipath/_cli/cli_pack.py +13 -11
- uipath/_cli/cli_push.py +4 -4
- uipath/_cli/models/__init__.py +0 -0
- uipath/_cli/models/runtime_schema.py +71 -0
- uipath/_resources/AGENTS.md +2 -20
- uipath/_resources/REQUIRED_STRUCTURE.md +23 -52
- uipath/_resources/SDK_REFERENCE.md +1 -1
- uipath/agent/models/agent.py +227 -55
- uipath/agent/models/evals.py +56 -0
- uipath/telemetry/_track.py +1 -0
- {uipath-2.1.89.dist-info → uipath-2.1.91.dist-info}/METADATA +1 -1
- {uipath-2.1.89.dist-info → uipath-2.1.91.dist-info}/RECORD +22 -19
- {uipath-2.1.89.dist-info → uipath-2.1.91.dist-info}/WHEEL +0 -0
- {uipath-2.1.89.dist-info → uipath-2.1.91.dist-info}/entry_points.txt +0 -0
- {uipath-2.1.89.dist-info → uipath-2.1.91.dist-info}/licenses/LICENSE +0 -0
uipath/_cli/_evals/_runtime.py
CHANGED
|
@@ -326,7 +326,8 @@ class UiPathEvalRuntime(UiPathBaseRuntime, Generic[T, C]):
|
|
|
326
326
|
if eval_item.input_mocking_strategy:
|
|
327
327
|
eval_item = await self._generate_input_for_eval(eval_item)
|
|
328
328
|
|
|
329
|
-
|
|
329
|
+
execution_id = str(uuid.uuid4())
|
|
330
|
+
set_execution_context(eval_item, self.span_collector, execution_id)
|
|
330
331
|
|
|
331
332
|
await event_bus.publish(
|
|
332
333
|
EvaluationEvents.CREATE_EVAL_RUN,
|
|
@@ -341,7 +342,7 @@ class UiPathEvalRuntime(UiPathBaseRuntime, Generic[T, C]):
|
|
|
341
342
|
)
|
|
342
343
|
|
|
343
344
|
try:
|
|
344
|
-
agent_execution_output = await self.execute_runtime(eval_item)
|
|
345
|
+
agent_execution_output = await self.execute_runtime(eval_item, execution_id)
|
|
345
346
|
evaluation_item_results: list[EvalItemResult] = []
|
|
346
347
|
|
|
347
348
|
for evaluator in evaluators:
|
|
@@ -448,9 +449,8 @@ class UiPathEvalRuntime(UiPathBaseRuntime, Generic[T, C]):
|
|
|
448
449
|
return spans, logs
|
|
449
450
|
|
|
450
451
|
async def execute_runtime(
|
|
451
|
-
self, eval_item: EvaluationItem
|
|
452
|
+
self, eval_item: EvaluationItem, execution_id: str
|
|
452
453
|
) -> UiPathEvalRunExecutionOutput:
|
|
453
|
-
execution_id = str(uuid.uuid4())
|
|
454
454
|
runtime_context: C = self.factory.new_context(
|
|
455
455
|
execution_id=execution_id,
|
|
456
456
|
input_json=eval_item.inputs,
|
|
@@ -96,7 +96,11 @@ class LLMMocker(Mocker):
|
|
|
96
96
|
from uipath import UiPath
|
|
97
97
|
from uipath._services.llm_gateway_service import _cleanup_schema
|
|
98
98
|
|
|
99
|
-
from .mocks import
|
|
99
|
+
from .mocks import (
|
|
100
|
+
evaluation_context,
|
|
101
|
+
execution_id_context,
|
|
102
|
+
span_collector_context,
|
|
103
|
+
)
|
|
100
104
|
|
|
101
105
|
llm = UiPath().llm
|
|
102
106
|
return_type: Any = func.__annotations__.get("return", None)
|
|
@@ -126,8 +130,9 @@ class LLMMocker(Mocker):
|
|
|
126
130
|
test_run_history = "(empty)"
|
|
127
131
|
eval_item = evaluation_context.get()
|
|
128
132
|
span_collector = span_collector_context.get()
|
|
129
|
-
|
|
130
|
-
|
|
133
|
+
execution_id = execution_id_context.get()
|
|
134
|
+
if eval_item and span_collector and execution_id:
|
|
135
|
+
spans = span_collector.get_spans(execution_id)
|
|
131
136
|
test_run_history = _SpanUtils.spans_to_llm_context(spans)
|
|
132
137
|
|
|
133
138
|
prompt_input: dict[str, Any] = {
|
|
@@ -21,11 +21,16 @@ span_collector_context: ContextVar[Optional[ExecutionSpanCollector]] = ContextVa
|
|
|
21
21
|
"span_collector", default=None
|
|
22
22
|
)
|
|
23
23
|
|
|
24
|
+
# Execution ID for the current evaluation item
|
|
25
|
+
execution_id_context: ContextVar[Optional[str]] = ContextVar(
|
|
26
|
+
"execution_id", default=None
|
|
27
|
+
)
|
|
28
|
+
|
|
24
29
|
logger = logging.getLogger(__name__)
|
|
25
30
|
|
|
26
31
|
|
|
27
32
|
def set_execution_context(
|
|
28
|
-
eval_item: EvaluationItem, span_collector: ExecutionSpanCollector
|
|
33
|
+
eval_item: EvaluationItem, span_collector: ExecutionSpanCollector, execution_id: str
|
|
29
34
|
) -> None:
|
|
30
35
|
"""Set the execution context for an evaluation run for mocking and trace access."""
|
|
31
36
|
evaluation_context.set(eval_item)
|
|
@@ -40,6 +45,7 @@ def set_execution_context(
|
|
|
40
45
|
mocker_context.set(None)
|
|
41
46
|
|
|
42
47
|
span_collector_context.set(span_collector)
|
|
48
|
+
execution_id_context.set(execution_id)
|
|
43
49
|
|
|
44
50
|
|
|
45
51
|
def clear_execution_context() -> None:
|
|
@@ -47,6 +53,7 @@ def clear_execution_context() -> None:
|
|
|
47
53
|
evaluation_context.set(None)
|
|
48
54
|
mocker_context.set(None)
|
|
49
55
|
span_collector_context.set(None)
|
|
56
|
+
execution_id_context.set(None)
|
|
50
57
|
|
|
51
58
|
|
|
52
59
|
async def get_mocked_response(
|
|
@@ -453,7 +453,7 @@ class SwFileHandler:
|
|
|
453
453
|
)
|
|
454
454
|
logger.info("Uploading 'agent.json'")
|
|
455
455
|
|
|
456
|
-
async def upload_source_files(self,
|
|
456
|
+
async def upload_source_files(self, settings: Optional[dict[str, Any]]) -> None:
|
|
457
457
|
"""Main method to upload source files to the UiPath project.
|
|
458
458
|
|
|
459
459
|
- Gets project structure
|
|
@@ -462,7 +462,7 @@ class SwFileHandler:
|
|
|
462
462
|
- Deletes removed files
|
|
463
463
|
|
|
464
464
|
Args:
|
|
465
|
-
|
|
465
|
+
settings: File handling settings
|
|
466
466
|
|
|
467
467
|
Returns:
|
|
468
468
|
Dict[str, ProjectFileExtended]: Root level files for agent.json handling
|
|
@@ -493,7 +493,7 @@ class SwFileHandler:
|
|
|
493
493
|
|
|
494
494
|
# Get files to upload and process them
|
|
495
495
|
files = files_to_include(
|
|
496
|
-
|
|
496
|
+
settings,
|
|
497
497
|
self.directory,
|
|
498
498
|
self.include_uv_lock,
|
|
499
499
|
directories_to_ignore=["evals"],
|
uipath/_cli/_utils/_parse_ast.py
CHANGED
|
@@ -13,6 +13,7 @@ from ..._services import (
|
|
|
13
13
|
ProcessesService,
|
|
14
14
|
)
|
|
15
15
|
from ..._utils import get_inferred_bindings_names
|
|
16
|
+
from ..models.runtime_schema import BindingResource, BindingResourceValue, Bindings
|
|
16
17
|
from ._constants import BINDINGS_VERSION
|
|
17
18
|
|
|
18
19
|
|
|
@@ -428,7 +429,7 @@ def parse_sdk_usage(
|
|
|
428
429
|
return results
|
|
429
430
|
|
|
430
431
|
|
|
431
|
-
def convert_to_bindings_format(sdk_usage_data):
|
|
432
|
+
def convert_to_bindings_format(sdk_usage_data) -> Bindings:
|
|
432
433
|
"""Convert the output of parse_sdk_usage to a structure similar to bindings_v2.json.
|
|
433
434
|
|
|
434
435
|
Args:
|
|
@@ -437,7 +438,7 @@ def convert_to_bindings_format(sdk_usage_data):
|
|
|
437
438
|
Returns:
|
|
438
439
|
Dictionary in bindings_v2.json format
|
|
439
440
|
"""
|
|
440
|
-
bindings =
|
|
441
|
+
bindings = Bindings(version="2.0", resources=[])
|
|
441
442
|
|
|
442
443
|
for resource_type, components in sdk_usage_data.items():
|
|
443
444
|
for component in components:
|
|
@@ -448,24 +449,24 @@ def convert_to_bindings_format(sdk_usage_data):
|
|
|
448
449
|
)
|
|
449
450
|
is_connection_id_expression = connection_id.startswith("EXPR$")
|
|
450
451
|
connection_id = connection_id.replace("EXPR$", "")
|
|
451
|
-
resource_entry =
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
"ConnectionId":
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
"
|
|
459
|
-
|
|
452
|
+
resource_entry = BindingResource(
|
|
453
|
+
resource="connection",
|
|
454
|
+
key=connection_id,
|
|
455
|
+
value={
|
|
456
|
+
"ConnectionId": BindingResourceValue(
|
|
457
|
+
default_value=connection_id,
|
|
458
|
+
is_expression=is_connection_id_expression,
|
|
459
|
+
display_name="Connection",
|
|
460
|
+
),
|
|
460
461
|
},
|
|
461
|
-
|
|
462
|
+
metadata={
|
|
462
463
|
"BindingsVersion": BINDINGS_VERSION,
|
|
463
464
|
"Connector": connector_name,
|
|
464
465
|
"UseConnectionService": "True",
|
|
465
466
|
},
|
|
466
|
-
|
|
467
|
+
)
|
|
467
468
|
|
|
468
|
-
bindings
|
|
469
|
+
bindings.resources.append(resource_entry)
|
|
469
470
|
continue
|
|
470
471
|
|
|
471
472
|
resource_name = component.get("name", "")
|
|
@@ -481,36 +482,61 @@ def convert_to_bindings_format(sdk_usage_data):
|
|
|
481
482
|
key = name
|
|
482
483
|
if folder_path:
|
|
483
484
|
key = f"{folder_path}.{name}"
|
|
484
|
-
resource_entry =
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
"name":
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
"
|
|
492
|
-
|
|
485
|
+
resource_entry = BindingResource(
|
|
486
|
+
resource=service_name_resource_mapping[resource_type],
|
|
487
|
+
key=key,
|
|
488
|
+
value={
|
|
489
|
+
"name": BindingResourceValue(
|
|
490
|
+
default_value=name,
|
|
491
|
+
is_expression=is_expression,
|
|
492
|
+
display_name="Name",
|
|
493
|
+
),
|
|
493
494
|
},
|
|
494
|
-
|
|
495
|
+
metadata={
|
|
495
496
|
"ActivityName": method_name,
|
|
496
497
|
"BindingsVersion": BINDINGS_VERSION,
|
|
497
498
|
"DisplayLabel": "FullName",
|
|
498
499
|
},
|
|
499
|
-
|
|
500
|
+
)
|
|
500
501
|
|
|
501
502
|
if folder_path:
|
|
502
|
-
resource_entry
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
"
|
|
506
|
-
|
|
503
|
+
resource_entry.value["folderPath"] = BindingResourceValue(
|
|
504
|
+
default_value=folder_path,
|
|
505
|
+
is_expression=is_folder_path_expression,
|
|
506
|
+
display_name="Folder Path",
|
|
507
|
+
)
|
|
507
508
|
|
|
508
|
-
bindings
|
|
509
|
+
bindings.resources.append(resource_entry)
|
|
509
510
|
|
|
510
511
|
return bindings
|
|
511
512
|
|
|
512
513
|
|
|
513
|
-
def generate_bindings_json(file_path: str) -> str:
|
|
514
|
+
def generate_bindings_json(file_path: str) -> dict[str, Any]:
|
|
515
|
+
"""Generate bindings JSON from a Python file.
|
|
516
|
+
|
|
517
|
+
Args:
|
|
518
|
+
file_path: Path to the Python file to analyze
|
|
519
|
+
|
|
520
|
+
Returns:
|
|
521
|
+
JSON string representation of the bindings
|
|
522
|
+
"""
|
|
523
|
+
try:
|
|
524
|
+
with open(file_path, "r") as f:
|
|
525
|
+
source_code = f.read()
|
|
526
|
+
|
|
527
|
+
# Get the base directory for resolving imports
|
|
528
|
+
base_dir = os.path.dirname(os.path.abspath(file_path))
|
|
529
|
+
|
|
530
|
+
sdk_usage = parse_sdk_usage(source_code, base_dir)
|
|
531
|
+
bindings = convert_to_bindings_format(sdk_usage)
|
|
532
|
+
|
|
533
|
+
return bindings.model_dump(by_alias=True)
|
|
534
|
+
|
|
535
|
+
except Exception as e:
|
|
536
|
+
raise Exception(f"Error generating bindings JSON: {e}") from e
|
|
537
|
+
|
|
538
|
+
|
|
539
|
+
def generate_bindings(file_path: str) -> Bindings:
|
|
514
540
|
"""Generate bindings JSON from a Python file.
|
|
515
541
|
|
|
516
542
|
Args:
|
|
@@ -7,9 +7,10 @@ import re
|
|
|
7
7
|
from pathlib import Path
|
|
8
8
|
from typing import Any, Dict, Optional, Protocol, Tuple
|
|
9
9
|
|
|
10
|
-
from pydantic import BaseModel
|
|
10
|
+
from pydantic import BaseModel, TypeAdapter
|
|
11
11
|
|
|
12
12
|
from .._utils._console import ConsoleLogger
|
|
13
|
+
from ..models.runtime_schema import RuntimeSchema
|
|
13
14
|
from ._constants import is_binary_file
|
|
14
15
|
from ._studio_project import (
|
|
15
16
|
ProjectFile,
|
|
@@ -93,21 +94,19 @@ def get_project_config(directory: str) -> dict[str, str]:
|
|
|
93
94
|
console.error("pyproject.toml not found.")
|
|
94
95
|
|
|
95
96
|
with open(config_path, "r") as config_file:
|
|
96
|
-
config_data = json.load(config_file)
|
|
97
|
-
|
|
98
|
-
validate_config_structure(config_data)
|
|
97
|
+
config_data = TypeAdapter(RuntimeSchema).validate_python(json.load(config_file))
|
|
99
98
|
|
|
100
99
|
toml_data = read_toml_project(toml_path)
|
|
101
100
|
|
|
102
101
|
return {
|
|
103
102
|
"project_name": toml_data["name"],
|
|
104
103
|
"description": toml_data["description"],
|
|
105
|
-
"entryPoints": config_data
|
|
104
|
+
"entryPoints": [ep.model_dump(by_alias=True) for ep in config_data.entrypoints],
|
|
106
105
|
"version": toml_data["version"],
|
|
107
106
|
"authors": toml_data["authors"],
|
|
108
107
|
"dependencies": toml_data.get("dependencies", {}),
|
|
109
108
|
"requires-python": toml_data.get("requires-python", None),
|
|
110
|
-
"settings": config_data.
|
|
109
|
+
"settings": config_data.settings or {},
|
|
111
110
|
}
|
|
112
111
|
|
|
113
112
|
|
|
@@ -347,7 +346,7 @@ def read_toml_project(file_path: str) -> dict:
|
|
|
347
346
|
|
|
348
347
|
|
|
349
348
|
def files_to_include(
|
|
350
|
-
|
|
349
|
+
settings: Optional[dict[str, Any]],
|
|
351
350
|
directory: str,
|
|
352
351
|
include_uv_lock: bool = True,
|
|
353
352
|
directories_to_ignore: list[str] | None = None,
|
|
@@ -358,7 +357,7 @@ def files_to_include(
|
|
|
358
357
|
and explicit inclusion rules. Skips virtual environments and hidden directories.
|
|
359
358
|
|
|
360
359
|
Args:
|
|
361
|
-
|
|
360
|
+
settings: File handling settings
|
|
362
361
|
directory: Root directory to search for files
|
|
363
362
|
include_uv_lock: Whether to include uv.lock file
|
|
364
363
|
directories_to_ignore: List of directories to ignore
|
|
@@ -374,8 +373,7 @@ def files_to_include(
|
|
|
374
373
|
directories_to_ignore = []
|
|
375
374
|
if include_uv_lock:
|
|
376
375
|
files_included += ["uv.lock"]
|
|
377
|
-
if
|
|
378
|
-
settings = config_data["settings"]
|
|
376
|
+
if settings is not None:
|
|
379
377
|
if "fileExtensionsIncluded" in settings:
|
|
380
378
|
file_extensions_included.extend(settings["fileExtensionsIncluded"])
|
|
381
379
|
if "filesIncluded" in settings:
|
uipath/_cli/cli_init.py
CHANGED
|
@@ -15,8 +15,9 @@ from ..telemetry import track
|
|
|
15
15
|
from ..telemetry._constants import _PROJECT_KEY, _TELEMETRY_CONFIG_FILE
|
|
16
16
|
from ._utils._console import ConsoleLogger
|
|
17
17
|
from ._utils._input_args import generate_args
|
|
18
|
-
from ._utils._parse_ast import
|
|
18
|
+
from ._utils._parse_ast import generate_bindings
|
|
19
19
|
from .middlewares import Middlewares
|
|
20
|
+
from .models.runtime_schema import Bindings, Entrypoint, RuntimeSchema
|
|
20
21
|
|
|
21
22
|
console = ConsoleLogger()
|
|
22
23
|
logger = logging.getLogger(__name__)
|
|
@@ -60,20 +61,17 @@ def generate_env_file(target_directory):
|
|
|
60
61
|
console.success(f"Created '{relative_path}' file.")
|
|
61
62
|
|
|
62
63
|
|
|
63
|
-
def
|
|
64
|
+
def generate_agent_md_file(target_directory: str, file_name: str) -> None:
|
|
64
65
|
"""Generate an agent-specific file from the packaged resource.
|
|
65
66
|
|
|
66
67
|
Args:
|
|
67
68
|
target_directory: The directory where the file should be created.
|
|
68
69
|
file_name: The name of the file should be created.
|
|
69
70
|
"""
|
|
70
|
-
|
|
71
|
-
os.makedirs(agent_dir, exist_ok=True)
|
|
72
|
-
|
|
73
|
-
target_path = os.path.join(agent_dir, file_name)
|
|
71
|
+
target_path = os.path.join(target_directory, file_name)
|
|
74
72
|
|
|
75
73
|
if os.path.exists(target_path):
|
|
76
|
-
logger.debug(f"File '
|
|
74
|
+
logger.debug(f"File '{target_path}' already exists.")
|
|
77
75
|
return
|
|
78
76
|
|
|
79
77
|
try:
|
|
@@ -82,11 +80,32 @@ def generate_agent_specific_file_md(target_directory: str, file_name: str) -> No
|
|
|
82
80
|
with importlib.resources.as_file(source_path) as s_path:
|
|
83
81
|
shutil.copy(s_path, target_path)
|
|
84
82
|
|
|
85
|
-
console.success(f"Created '{f'.agent/{file_name}'}' file.")
|
|
86
83
|
except Exception as e:
|
|
87
84
|
console.warning(f"Could not create {file_name}: {e}")
|
|
88
85
|
|
|
89
86
|
|
|
87
|
+
def generate_agent_md_files(target_directory: str) -> None:
|
|
88
|
+
"""Generate an agent-specific file from the packaged resource.
|
|
89
|
+
|
|
90
|
+
Args:
|
|
91
|
+
target_directory: The directory where the files should be created.
|
|
92
|
+
"""
|
|
93
|
+
agent_dir = os.path.join(target_directory, ".agent")
|
|
94
|
+
os.makedirs(agent_dir, exist_ok=True)
|
|
95
|
+
|
|
96
|
+
root_files = ["AGENTS.md", "CLAUDE.md"]
|
|
97
|
+
|
|
98
|
+
agent_files = ["CLI_REFERENCE.md", "REQUIRED_STRUCTURE.md", "SDK_REFERENCE.md"]
|
|
99
|
+
|
|
100
|
+
for file_name in root_files:
|
|
101
|
+
generate_agent_md_file(target_directory, file_name)
|
|
102
|
+
|
|
103
|
+
for file_name in agent_files:
|
|
104
|
+
generate_agent_md_file(agent_dir, file_name)
|
|
105
|
+
|
|
106
|
+
console.success(f"Created {click.style('AGENTS.md', fg='cyan')} file.")
|
|
107
|
+
|
|
108
|
+
|
|
90
109
|
def get_existing_settings(config_path: str) -> Optional[Dict[str, Any]]:
|
|
91
110
|
"""Read existing settings from uipath.json if it exists.
|
|
92
111
|
|
|
@@ -134,13 +153,17 @@ def get_user_script(directory: str, entrypoint: Optional[str] = None) -> Optiona
|
|
|
134
153
|
return None
|
|
135
154
|
|
|
136
155
|
|
|
137
|
-
def write_config_file(config_data: Dict[str, Any]) -> None:
|
|
156
|
+
def write_config_file(config_data: Dict[str, Any] | RuntimeSchema) -> None:
|
|
138
157
|
existing_settings = get_existing_settings(CONFIG_PATH)
|
|
139
158
|
if existing_settings is not None:
|
|
140
|
-
config_data
|
|
159
|
+
config_data.settings = existing_settings
|
|
141
160
|
|
|
142
161
|
with open(CONFIG_PATH, "w") as config_file:
|
|
143
|
-
|
|
162
|
+
if isinstance(config_data, RuntimeSchema):
|
|
163
|
+
json_object = config_data.model_dump(by_alias=True, exclude_unset=True)
|
|
164
|
+
else:
|
|
165
|
+
json_object = config_data
|
|
166
|
+
json.dump(json_object, config_file, indent=4)
|
|
144
167
|
|
|
145
168
|
return CONFIG_PATH
|
|
146
169
|
|
|
@@ -161,11 +184,6 @@ def init(entrypoint: str, infer_bindings: bool) -> None:
|
|
|
161
184
|
current_directory = os.getcwd()
|
|
162
185
|
generate_env_file(current_directory)
|
|
163
186
|
create_telemetry_config_file(current_directory)
|
|
164
|
-
generate_agent_specific_file_md(current_directory, "AGENTS.md")
|
|
165
|
-
generate_agent_specific_file_md(current_directory, "CLI_REFERENCE.md")
|
|
166
|
-
generate_agent_specific_file_md(current_directory, "REQUIRED_STRUCTURE.md")
|
|
167
|
-
generate_agent_specific_file_md(current_directory, "SDK_REFERENCE.md")
|
|
168
|
-
generate_agent_specific_file_md(current_directory, "CLAUDE.md")
|
|
169
187
|
|
|
170
188
|
result = Middlewares.next(
|
|
171
189
|
"init",
|
|
@@ -185,6 +203,7 @@ def init(entrypoint: str, infer_bindings: bool) -> None:
|
|
|
185
203
|
if not result.should_continue:
|
|
186
204
|
return
|
|
187
205
|
|
|
206
|
+
generate_agent_md_files(current_directory)
|
|
188
207
|
script_path = get_user_script(current_directory, entrypoint=entrypoint)
|
|
189
208
|
|
|
190
209
|
if not script_path:
|
|
@@ -194,30 +213,29 @@ def init(entrypoint: str, infer_bindings: bool) -> None:
|
|
|
194
213
|
args = generate_args(script_path)
|
|
195
214
|
|
|
196
215
|
relative_path = Path(script_path).relative_to(current_directory).as_posix()
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
console.warning(f"Warning: Could not generate bindings: {str(e)}")
|
|
216
|
+
bindings = None
|
|
217
|
+
if infer_bindings:
|
|
218
|
+
try:
|
|
219
|
+
bindings = generate_bindings(script_path)
|
|
220
|
+
except Exception as e:
|
|
221
|
+
console.warning(f"Warning: Could not generate bindings: {str(e)}")
|
|
222
|
+
if bindings is None:
|
|
223
|
+
bindings = Bindings(
|
|
224
|
+
version="2.0",
|
|
225
|
+
resources=[],
|
|
226
|
+
)
|
|
227
|
+
config_data = RuntimeSchema(
|
|
228
|
+
entrypoints=[
|
|
229
|
+
Entrypoint(
|
|
230
|
+
file_path=relative_path,
|
|
231
|
+
unique_id=str(uuid.uuid4()),
|
|
232
|
+
type="agent",
|
|
233
|
+
input=args["input"],
|
|
234
|
+
output=args["output"],
|
|
235
|
+
)
|
|
236
|
+
],
|
|
237
|
+
bindings=bindings,
|
|
238
|
+
)
|
|
221
239
|
|
|
222
240
|
config_path = write_config_file(config_data)
|
|
223
241
|
console.success(f"Created '{config_path}' file.")
|
uipath/_cli/cli_pack.py
CHANGED
|
@@ -6,8 +6,10 @@ import zipfile
|
|
|
6
6
|
from string import Template
|
|
7
7
|
|
|
8
8
|
import click
|
|
9
|
+
from pydantic import TypeAdapter
|
|
9
10
|
|
|
10
11
|
from uipath._cli._utils._constants import UIPATH_PROJECT_ID
|
|
12
|
+
from uipath._cli.models.runtime_schema import Bindings, RuntimeSchema
|
|
11
13
|
|
|
12
14
|
from ..telemetry import track
|
|
13
15
|
from ..telemetry._constants import _PROJECT_KEY, _TELEMETRY_CONFIG_FILE
|
|
@@ -101,10 +103,11 @@ def generate_entrypoints_file(entryPoints):
|
|
|
101
103
|
return entrypoint_json_data
|
|
102
104
|
|
|
103
105
|
|
|
104
|
-
def generate_bindings_content():
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
106
|
+
def generate_bindings_content() -> Bindings:
|
|
107
|
+
return Bindings(
|
|
108
|
+
version="2.0",
|
|
109
|
+
resources=[],
|
|
110
|
+
)
|
|
108
111
|
|
|
109
112
|
|
|
110
113
|
def generate_content_types_content():
|
|
@@ -214,11 +217,7 @@ def pack_fn(
|
|
|
214
217
|
console.error("uipath.json not found, please run `uipath init`.")
|
|
215
218
|
|
|
216
219
|
with open(config_path, "r") as f:
|
|
217
|
-
config_data = json.load(f)
|
|
218
|
-
if "bindings" in config_data:
|
|
219
|
-
bindings_content = config_data["bindings"]
|
|
220
|
-
else:
|
|
221
|
-
bindings_content = generate_bindings_content()
|
|
220
|
+
config_data = TypeAdapter(RuntimeSchema).validate_python(json.load(f))
|
|
222
221
|
|
|
223
222
|
content_types_content = generate_content_types_content()
|
|
224
223
|
[psmdcp_file_name, psmdcp_content] = generate_psmdcp_content(
|
|
@@ -249,11 +248,14 @@ def pack_fn(
|
|
|
249
248
|
)
|
|
250
249
|
z.writestr("content/operate.json", json.dumps(operate_file, indent=4))
|
|
251
250
|
z.writestr("content/entry-points.json", json.dumps(entrypoints_file, indent=4))
|
|
252
|
-
z.writestr(
|
|
251
|
+
z.writestr(
|
|
252
|
+
"content/bindings_v2.json",
|
|
253
|
+
json.dumps(config_data.bindings.model_dump(by_alias=True), indent=4),
|
|
254
|
+
)
|
|
253
255
|
z.writestr(f"{projectName}.nuspec", nuspec_content)
|
|
254
256
|
z.writestr("_rels/.rels", rels_content)
|
|
255
257
|
|
|
256
|
-
files = files_to_include(config_data, directory, include_uv_lock)
|
|
258
|
+
files = files_to_include(config_data.settings, directory, include_uv_lock)
|
|
257
259
|
|
|
258
260
|
for file in files:
|
|
259
261
|
if file.is_binary:
|
uipath/_cli/cli_push.py
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# type: ignore
|
|
2
2
|
import asyncio
|
|
3
3
|
import os
|
|
4
|
-
from typing import Any
|
|
4
|
+
from typing import Any, Optional
|
|
5
5
|
from urllib.parse import urlparse
|
|
6
6
|
|
|
7
7
|
import click
|
|
@@ -32,7 +32,7 @@ def get_org_scoped_url(base_url: str) -> str:
|
|
|
32
32
|
|
|
33
33
|
async def upload_source_files_to_project(
|
|
34
34
|
project_id: str,
|
|
35
|
-
|
|
35
|
+
settings: Optional[dict[str, Any]],
|
|
36
36
|
directory: str,
|
|
37
37
|
include_uv_lock: bool = True,
|
|
38
38
|
) -> None:
|
|
@@ -50,7 +50,7 @@ async def upload_source_files_to_project(
|
|
|
50
50
|
include_uv_lock=include_uv_lock,
|
|
51
51
|
)
|
|
52
52
|
|
|
53
|
-
await sw_file_handler.upload_source_files(
|
|
53
|
+
await sw_file_handler.upload_source_files(settings)
|
|
54
54
|
|
|
55
55
|
|
|
56
56
|
@click.command()
|
|
@@ -99,7 +99,7 @@ def push(root: str, nolock: bool) -> None:
|
|
|
99
99
|
asyncio.run(
|
|
100
100
|
upload_source_files_to_project(
|
|
101
101
|
os.getenv(UIPATH_PROJECT_ID),
|
|
102
|
-
config,
|
|
102
|
+
config.get("settings", {}),
|
|
103
103
|
root,
|
|
104
104
|
include_uv_lock=not nolock,
|
|
105
105
|
)
|
|
File without changes
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
from typing import Any, Dict, List, Optional
|
|
2
|
+
|
|
3
|
+
from pydantic import BaseModel, ConfigDict, Field
|
|
4
|
+
|
|
5
|
+
COMMON_MODEL_SCHEMA = ConfigDict(
|
|
6
|
+
validate_by_name=True,
|
|
7
|
+
validate_by_alias=True,
|
|
8
|
+
use_enum_values=True,
|
|
9
|
+
arbitrary_types_allowed=True,
|
|
10
|
+
extra="allow",
|
|
11
|
+
)
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class Entrypoint(BaseModel):
|
|
15
|
+
file_path: str = Field(..., alias="filePath")
|
|
16
|
+
unique_id: str = Field(..., alias="uniqueId")
|
|
17
|
+
type: str = Field(..., alias="type")
|
|
18
|
+
input: Dict[str, Any] = Field(..., alias="input")
|
|
19
|
+
output: Dict[str, Any] = Field(..., alias="output")
|
|
20
|
+
|
|
21
|
+
model_config = COMMON_MODEL_SCHEMA
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class BindingResourceValue(BaseModel):
|
|
25
|
+
default_value: str = Field(..., alias="defaultValue")
|
|
26
|
+
is_expression: bool = Field(..., alias="isExpression")
|
|
27
|
+
display_name: str = Field(..., alias="displayName")
|
|
28
|
+
|
|
29
|
+
model_config = COMMON_MODEL_SCHEMA
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
# TODO: create stronger binding resource definition with discriminator based on resource enum.
|
|
33
|
+
class BindingResource(BaseModel):
|
|
34
|
+
resource: str = Field(..., alias="resource")
|
|
35
|
+
key: str = Field(..., alias="key")
|
|
36
|
+
value: dict[str, BindingResourceValue] = Field(..., alias="value")
|
|
37
|
+
metadata: Any = Field(..., alias="metadata")
|
|
38
|
+
|
|
39
|
+
model_config = COMMON_MODEL_SCHEMA
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
class Bindings(BaseModel):
|
|
43
|
+
version: str = Field(..., alias="version")
|
|
44
|
+
resources: List[BindingResource] = Field(..., alias="resources")
|
|
45
|
+
|
|
46
|
+
model_config = COMMON_MODEL_SCHEMA
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
class RuntimeInternalArguments(BaseModel):
|
|
50
|
+
resource_overwrites: dict[str, Any] = Field(..., alias="resourceOverwrites")
|
|
51
|
+
|
|
52
|
+
model_config = COMMON_MODEL_SCHEMA
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
class RuntimeArguments(BaseModel):
|
|
56
|
+
internal_arguments: Optional[RuntimeInternalArguments] = Field(
|
|
57
|
+
default=None, alias="internalArguments"
|
|
58
|
+
)
|
|
59
|
+
|
|
60
|
+
model_config = COMMON_MODEL_SCHEMA
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
class RuntimeSchema(BaseModel):
|
|
64
|
+
runtime: Optional[RuntimeArguments] = Field(default=None, alias="runtime")
|
|
65
|
+
entrypoints: List[Entrypoint] = Field(..., alias="entryPoints")
|
|
66
|
+
bindings: Bindings = Field(
|
|
67
|
+
default=Bindings(version="2.0", resources=[]), alias="bindings"
|
|
68
|
+
)
|
|
69
|
+
settings: Optional[Dict[str, Any]] = Field(default=None, alias="setting")
|
|
70
|
+
|
|
71
|
+
model_config = COMMON_MODEL_SCHEMA
|