uipath 2.1.107__py3-none-any.whl → 2.1.109__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.

Files changed (72) hide show
  1. uipath/_cli/__init__.py +4 -0
  2. uipath/_cli/_evals/_console_progress_reporter.py +2 -2
  3. uipath/_cli/_evals/_evaluator_factory.py +314 -29
  4. uipath/_cli/_evals/_helpers.py +194 -0
  5. uipath/_cli/_evals/_models/_evaluation_set.py +73 -7
  6. uipath/_cli/_evals/_models/_evaluator.py +183 -9
  7. uipath/_cli/_evals/_models/_evaluator_base_params.py +3 -3
  8. uipath/_cli/_evals/_models/_output.py +87 -3
  9. uipath/_cli/_evals/_progress_reporter.py +288 -28
  10. uipath/_cli/_evals/_runtime.py +80 -26
  11. uipath/_cli/_evals/mocks/input_mocker.py +1 -3
  12. uipath/_cli/_evals/mocks/llm_mocker.py +2 -2
  13. uipath/_cli/_evals/mocks/mocker_factory.py +2 -2
  14. uipath/_cli/_evals/mocks/mockito_mocker.py +2 -2
  15. uipath/_cli/_evals/mocks/mocks.py +5 -3
  16. uipath/_cli/_push/models.py +17 -0
  17. uipath/_cli/_push/sw_file_handler.py +336 -3
  18. uipath/_cli/_runtime/_contracts.py +25 -5
  19. uipath/_cli/_templates/custom_evaluator.py.template +65 -0
  20. uipath/_cli/_utils/_eval_set.py +30 -9
  21. uipath/_cli/_utils/_resources.py +21 -0
  22. uipath/_cli/_utils/_studio_project.py +18 -0
  23. uipath/_cli/cli_add.py +114 -0
  24. uipath/_cli/cli_eval.py +5 -1
  25. uipath/_cli/cli_pull.py +11 -26
  26. uipath/_cli/cli_push.py +2 -0
  27. uipath/_cli/cli_register.py +45 -0
  28. uipath/_events/_events.py +6 -5
  29. uipath/_resources/SDK_REFERENCE.md +0 -97
  30. uipath/_uipath.py +10 -37
  31. uipath/_utils/constants.py +4 -0
  32. uipath/eval/_helpers/evaluators_helpers.py +494 -0
  33. uipath/eval/_helpers/helpers.py +30 -2
  34. uipath/eval/evaluators/__init__.py +60 -5
  35. uipath/eval/evaluators/base_evaluator.py +546 -44
  36. uipath/eval/evaluators/contains_evaluator.py +80 -0
  37. uipath/eval/evaluators/exact_match_evaluator.py +43 -12
  38. uipath/eval/evaluators/json_similarity_evaluator.py +41 -12
  39. uipath/eval/evaluators/legacy_base_evaluator.py +89 -0
  40. uipath/eval/evaluators/{deterministic_evaluator_base.py → legacy_deterministic_evaluator_base.py} +2 -2
  41. uipath/eval/evaluators/legacy_exact_match_evaluator.py +37 -0
  42. uipath/eval/evaluators/legacy_json_similarity_evaluator.py +151 -0
  43. uipath/eval/evaluators/legacy_llm_as_judge_evaluator.py +137 -0
  44. uipath/eval/evaluators/{trajectory_evaluator.py → legacy_trajectory_evaluator.py} +5 -6
  45. uipath/eval/evaluators/llm_as_judge_evaluator.py +143 -78
  46. uipath/eval/evaluators/llm_judge_output_evaluator.py +112 -0
  47. uipath/eval/evaluators/llm_judge_trajectory_evaluator.py +142 -0
  48. uipath/eval/evaluators/output_evaluator.py +117 -0
  49. uipath/eval/evaluators/tool_call_args_evaluator.py +82 -0
  50. uipath/eval/evaluators/tool_call_count_evaluator.py +87 -0
  51. uipath/eval/evaluators/tool_call_order_evaluator.py +84 -0
  52. uipath/eval/evaluators/tool_call_output_evaluator.py +87 -0
  53. uipath/eval/evaluators_types/ContainsEvaluator.json +73 -0
  54. uipath/eval/evaluators_types/ExactMatchEvaluator.json +89 -0
  55. uipath/eval/evaluators_types/JsonSimilarityEvaluator.json +81 -0
  56. uipath/eval/evaluators_types/LLMJudgeOutputEvaluator.json +110 -0
  57. uipath/eval/evaluators_types/LLMJudgeSimulationTrajectoryEvaluator.json +88 -0
  58. uipath/eval/evaluators_types/LLMJudgeStrictJSONSimilarityOutputEvaluator.json +110 -0
  59. uipath/eval/evaluators_types/LLMJudgeTrajectoryEvaluator.json +88 -0
  60. uipath/eval/evaluators_types/ToolCallArgsEvaluator.json +131 -0
  61. uipath/eval/evaluators_types/ToolCallCountEvaluator.json +104 -0
  62. uipath/eval/evaluators_types/ToolCallOrderEvaluator.json +100 -0
  63. uipath/eval/evaluators_types/ToolCallOutputEvaluator.json +124 -0
  64. uipath/eval/evaluators_types/generate_types.py +31 -0
  65. uipath/eval/models/__init__.py +16 -1
  66. uipath/eval/models/llm_judge_types.py +196 -0
  67. uipath/eval/models/models.py +109 -7
  68. {uipath-2.1.107.dist-info → uipath-2.1.109.dist-info}/METADATA +1 -1
  69. {uipath-2.1.107.dist-info → uipath-2.1.109.dist-info}/RECORD +72 -40
  70. {uipath-2.1.107.dist-info → uipath-2.1.109.dist-info}/WHEEL +0 -0
  71. {uipath-2.1.107.dist-info → uipath-2.1.109.dist-info}/entry_points.txt +0 -0
  72. {uipath-2.1.107.dist-info → uipath-2.1.109.dist-info}/licenses/LICENSE +0 -0
uipath/_cli/cli_add.py ADDED
@@ -0,0 +1,114 @@
1
+ import logging
2
+ import os
3
+ import re
4
+ from pathlib import Path
5
+ from string import Template
6
+
7
+ import click
8
+
9
+ from ..telemetry import track
10
+ from ._utils._console import ConsoleLogger
11
+ from ._utils._resources import Resources
12
+
13
+ logger = logging.getLogger(__name__)
14
+ console = ConsoleLogger()
15
+
16
+
17
+ def to_pascal_case(text: str) -> str:
18
+ """Convert kebab-case or snake_case to PascalCase."""
19
+ return "".join(word.capitalize() for word in re.sub(r"[-_]", " ", text).split())
20
+
21
+
22
+ def to_snake_case(text: str) -> str:
23
+ """Convert kebab-case or PascalCase to snake_case."""
24
+ return re.sub(r"(?<!^)(?=[A-Z])|-", "_", text).lower()
25
+
26
+
27
+ def generate_evaluator_template(evaluator_name: str) -> str:
28
+ """Generate a generic evaluator template."""
29
+ class_name = to_pascal_case(evaluator_name)
30
+ if not class_name.endswith("Evaluator"):
31
+ class_name = class_name + "Evaluator"
32
+
33
+ variables = {
34
+ "class_name": class_name,
35
+ "evaluator_name": evaluator_name,
36
+ "criteria_class": class_name.replace("Evaluator", "EvaluationCriteria"),
37
+ "config_class": class_name + "Config",
38
+ }
39
+ templates_path = os.path.join(
40
+ os.path.dirname(__file__), "_templates", "custom_evaluator.py.template"
41
+ )
42
+ with open(templates_path, "r", encoding="utf-8-sig") as f:
43
+ content = f.read()
44
+
45
+ return Template(content).substitute(variables)
46
+
47
+
48
+ def create_evaluator(evaluator_name):
49
+ cwd = Path.cwd()
50
+ custom_evaluators_dir = cwd / "evals" / "evaluators" / "custom"
51
+
52
+ if not custom_evaluators_dir.exists():
53
+ console.info(
54
+ f"Creating {click.style('evals/evaluators/custom', fg='cyan')} folder"
55
+ )
56
+ custom_evaluators_dir.mkdir(parents=True, exist_ok=True)
57
+
58
+ filename = to_snake_case(evaluator_name)
59
+ if not filename.endswith(".py"):
60
+ filename = filename + ".py"
61
+
62
+ file_path = custom_evaluators_dir / filename
63
+
64
+ if file_path.exists():
65
+ console.error(f"Evaluator file already exists: {file_path}")
66
+
67
+ template_content = generate_evaluator_template(evaluator_name)
68
+
69
+ with open(file_path, "w") as f:
70
+ f.write(template_content)
71
+
72
+ relative_path = f"evals/evaluators/custom/{filename}"
73
+
74
+ console.success(f"Created new evaluator: {click.style(relative_path, fg='cyan')}")
75
+ console.hint("Next steps:")
76
+ console.hint(
77
+ f" 1. Edit {click.style(relative_path, fg='cyan')} to implement your evaluation logic"
78
+ )
79
+ console.hint(
80
+ f" 2. Run {click.style(f'uipath register evaluator {filename}', fg='cyan')} to generate the evaluator spec"
81
+ )
82
+
83
+
84
+ @click.command()
85
+ @click.argument("resource", required=True)
86
+ @click.argument("args", nargs=-1)
87
+ @track
88
+ def add(resource: str, args: tuple[str]) -> None:
89
+ """Create a local resource.
90
+
91
+ Examples:
92
+ uipath add evaluator my-custom-evaluator
93
+ """
94
+ match Resources.from_string(resource):
95
+ case Resources.EVALUATOR:
96
+ usage_hint = f"Usage: {click.style('uipath add evaluator <evaluator_name>', fg='cyan')}"
97
+ if len(args) < 1:
98
+ console.hint(usage_hint)
99
+ console.error("Missing required argument: evaluator_name")
100
+ return
101
+ if len(args) > 1:
102
+ console.hint(usage_hint)
103
+ console.error(
104
+ f"Too many arguments provided: {args}. Expected only evaluator_name."
105
+ )
106
+
107
+ evaluator_name = args[0]
108
+
109
+ if not isinstance(evaluator_name, str) or not evaluator_name.strip():
110
+ console.hint(usage_hint)
111
+ console.error("Invalid evaluator_name: must be a non-empty string")
112
+ return
113
+
114
+ create_evaluator(evaluator_name)
uipath/_cli/cli_eval.py CHANGED
@@ -130,7 +130,11 @@ def eval(
130
130
 
131
131
  eval_context.no_report = no_report
132
132
  eval_context.workers = workers
133
- eval_context.eval_set = eval_set or EvalHelpers.auto_discover_eval_set()
133
+
134
+ # Load eval set to resolve the path
135
+ eval_set_path = eval_set or EvalHelpers.auto_discover_eval_set()
136
+ _, resolved_eval_set_path = EvalHelpers.load_eval_set(eval_set_path, eval_ids)
137
+ eval_context.eval_set = resolved_eval_set_path
134
138
  eval_context.eval_ids = eval_ids
135
139
 
136
140
  console_reporter = ConsoleProgressReporter()
uipath/_cli/cli_pull.py CHANGED
@@ -24,20 +24,6 @@ from ._utils._project_files import ProjectPullError, pull_project
24
24
  console = ConsoleLogger()
25
25
 
26
26
 
27
- class InteractiveConflictHandler:
28
- """Handler that prompts user for each conflict."""
29
-
30
- def __init__(self, console: ConsoleLogger):
31
- self.console = console
32
-
33
- def should_overwrite(
34
- self, file_path: str, local_hash: str, remote_hash: str
35
- ) -> bool:
36
- self.console.warning(f" File {file_path} differs from remote version.")
37
- response = click.confirm("Do you want to overwrite it?", default=False)
38
- return response
39
-
40
-
41
27
  @click.command()
42
28
  @click.argument(
43
29
  "root",
@@ -66,22 +52,21 @@ def pull(root: Path) -> None:
66
52
  project_id = os.getenv(UIPATH_PROJECT_ID)
67
53
  if not project_id:
68
54
  console.error("UIPATH_PROJECT_ID environment variable not found.")
55
+ return
69
56
 
70
- default_download_configuration = {
57
+ download_configuration = {
71
58
  "source_code": root,
72
59
  "evals": root / "evals",
73
60
  }
74
61
 
75
- async def pull_with_updates():
76
- try:
77
- async for update in pull_project(
78
- project_id,
79
- default_download_configuration,
80
- InteractiveConflictHandler(console),
81
- ):
62
+ try:
63
+
64
+ async def run_pull():
65
+ async for update in pull_project(project_id, download_configuration):
66
+ console.info(f"Processing: {update.file_path}")
82
67
  console.info(update.message)
83
- except ProjectPullError as e:
84
- console.error(e.message, include_traceback=True)
85
68
 
86
- with console.spinner("Pulling UiPath project files..."):
87
- asyncio.run(pull_with_updates())
69
+ asyncio.run(run_pull())
70
+ console.success("Project pulled successfully")
71
+ except ProjectPullError as e:
72
+ console.error(f"Failed to pull UiPath project: {str(e)}")
uipath/_cli/cli_push.py CHANGED
@@ -61,6 +61,8 @@ async def upload_source_files_to_project(
61
61
  async for update in sw_file_handler.upload_source_files(settings):
62
62
  yield update
63
63
 
64
+ await sw_file_handler.upload_coded_evals_files()
65
+
64
66
 
65
67
  @click.command()
66
68
  @click.argument(
@@ -0,0 +1,45 @@
1
+ # type: ignore
2
+ import logging
3
+
4
+ import click
5
+
6
+ from ..telemetry import track
7
+ from ._evals._helpers import register_evaluator
8
+ from ._utils._console import ConsoleLogger
9
+ from ._utils._resources import Resources
10
+
11
+ logger = logging.getLogger(__name__)
12
+ console = ConsoleLogger()
13
+
14
+
15
+ @click.command()
16
+ @click.argument("resource", required=True)
17
+ @click.argument("args", nargs=-1)
18
+ @track
19
+ def register(resource: str, args: tuple[str]) -> None:
20
+ """Register a local resource.
21
+
22
+ Examples:
23
+ uipath register evaluator my-custom-evaluator.py
24
+ """
25
+ match Resources.from_string(resource):
26
+ case Resources.EVALUATOR:
27
+ usage_hint = f"Usage: {click.style('uipath register evaluator <evaluator_file_name> (ex. my_custom_evaluator.py)', fg='cyan')}"
28
+ if len(args) < 1:
29
+ console.hint(usage_hint)
30
+ console.error("Missing required argument: evaluator_file_name.")
31
+ return
32
+ if len(args) > 1:
33
+ console.hint(usage_hint)
34
+ console.error(
35
+ f"Too many arguments provided: {args}. Expected only evaluator_file_name (ex. my_custom_evaluator.py)"
36
+ )
37
+
38
+ filename = args[0]
39
+
40
+ if not isinstance(filename, str) or not filename.strip():
41
+ console.hint(usage_hint)
42
+ console.error("Invalid filename: must be a non-empty string")
43
+ return
44
+
45
+ register_evaluator(filename)
uipath/_events/_events.py CHANGED
@@ -3,9 +3,9 @@ from enum import Enum
3
3
  from typing import Any, Dict, List, Optional, Union
4
4
 
5
5
  from opentelemetry.sdk.trace import ReadableSpan
6
- from pydantic import BaseModel, ConfigDict, Field, model_validator
6
+ from pydantic import BaseModel, ConfigDict, Field, SkipValidation, model_validator
7
7
 
8
- from uipath._cli._evals._models._evaluation_set import EvaluationItem
8
+ from uipath._cli._evals._models._evaluation_set import AnyEvaluationItem, AnyEvaluator
9
9
  from uipath.eval.models import EvalItemResult
10
10
 
11
11
 
@@ -21,12 +21,13 @@ class EvalSetRunCreatedEvent(BaseModel):
21
21
  entrypoint: str
22
22
  eval_set_id: str
23
23
  no_of_evals: int
24
- evaluators: List[Any]
24
+ # skip validation to avoid abstract class instantiation
25
+ evaluators: SkipValidation[List[AnyEvaluator]]
25
26
 
26
27
 
27
28
  class EvalRunCreatedEvent(BaseModel):
28
29
  execution_id: str
29
- eval_item: EvaluationItem
30
+ eval_item: AnyEvaluationItem
30
31
 
31
32
 
32
33
  class EvalItemExceptionDetails(BaseModel):
@@ -40,7 +41,7 @@ class EvalRunUpdatedEvent(BaseModel):
40
41
  model_config = ConfigDict(arbitrary_types_allowed=True)
41
42
 
42
43
  execution_id: str
43
- eval_item: EvaluationItem
44
+ eval_item: AnyEvaluationItem
44
45
  eval_results: List[EvalItemResult]
45
46
  success: bool
46
47
  agent_output: Any
@@ -70,93 +70,6 @@ sdk.assets.update_async(robot_asset: uipath.models.assets.UserAsset, folder_key:
70
70
 
71
71
  ```
72
72
 
73
- ### Attachments
74
-
75
- Attachments service
76
-
77
- ```python
78
- # Delete an attachment.
79
- sdk.attachments.delete(key: uuid.UUID, folder_key: Optional[str]=None, folder_path: Optional[str]=None) -> None
80
-
81
- # Delete an attachment asynchronously.
82
- sdk.attachments.delete_async(key: uuid.UUID, folder_key: Optional[str]=None, folder_path: Optional[str]=None) -> None
83
-
84
- # Download an attachment.
85
- sdk.attachments.download(key: uuid.UUID, destination_path: str, folder_key: Optional[str]=None, folder_path: Optional[str]=None) -> str
86
-
87
- # Download an attachment asynchronously.
88
- sdk.attachments.download_async(key: uuid.UUID, destination_path: str, folder_key: Optional[str]=None, folder_path: Optional[str]=None) -> str
89
-
90
- # Upload a file or content to UiPath as an attachment.
91
- sdk.attachments.upload(name: str, content: Union[str, bytes, NoneType]=None, source_path: Optional[str]=None, folder_key: Optional[str]=None, folder_path: Optional[str]=None) -> uuid.UUID
92
-
93
- # Upload a file or content to UiPath as an attachment asynchronously.
94
- sdk.attachments.upload_async(name: str, content: Union[str, bytes, NoneType]=None, source_path: Optional[str]=None, folder_key: Optional[str]=None, folder_path: Optional[str]=None) -> uuid.UUID
95
-
96
- ```
97
-
98
- ### Buckets
99
-
100
- Buckets service
101
-
102
- ```python
103
- # Download a file from a bucket.
104
- sdk.buckets.download(name: Optional[str]=None, key: Optional[str]=None, blob_file_path: str, destination_path: str, folder_key: Optional[str]=None, folder_path: Optional[str]=None) -> None
105
-
106
- # Download a file from a bucket asynchronously.
107
- sdk.buckets.download_async(name: Optional[str]=None, key: Optional[str]=None, blob_file_path: str, destination_path: str, folder_key: Optional[str]=None, folder_path: Optional[str]=None) -> None
108
-
109
- # Retrieve bucket information by its name.
110
- sdk.buckets.retrieve(name: Optional[str]=None, key: Optional[str]=None, folder_key: Optional[str]=None, folder_path: Optional[str]=None) -> uipath.models.buckets.Bucket
111
-
112
- # Asynchronously retrieve bucket information by its name.
113
- sdk.buckets.retrieve_async(name: Optional[str]=None, key: Optional[str]=None, folder_key: Optional[str]=None, folder_path: Optional[str]=None) -> uipath.models.buckets.Bucket
114
-
115
- # Upload a file to a bucket.
116
- sdk.buckets.upload(key: Optional[str]=None, name: Optional[str]=None, blob_file_path: str, content_type: Optional[str]=None, source_path: Optional[str]=None, content: Union[str, bytes, NoneType]=None, folder_key: Optional[str]=None, folder_path: Optional[str]=None) -> None
117
-
118
- # Upload a file to a bucket asynchronously.
119
- sdk.buckets.upload_async(key: Optional[str]=None, name: Optional[str]=None, blob_file_path: str, content_type: Optional[str]=None, source_path: Optional[str]=None, content: Union[str, bytes, NoneType]=None, folder_key: Optional[str]=None, folder_path: Optional[str]=None) -> None
120
-
121
- ```
122
-
123
- ### Connections
124
-
125
- Connections service
126
-
127
- ```python
128
- # Lists all connections with optional filtering.
129
- sdk.connections.list(name: Optional[str]=None, folder_path: Optional[str]=None, folder_key: Optional[str]=None, connector_key: Optional[str]=None, skip: Optional[int]=None, top: Optional[int]=None) -> typing.List[uipath.models.connections.Connection]
130
-
131
- # Asynchronously lists all connections with optional filtering.
132
- sdk.connections.list_async(name: Optional[str]=None, folder_path: Optional[str]=None, folder_key: Optional[str]=None, connector_key: Optional[str]=None, skip: Optional[int]=None, top: Optional[int]=None) -> typing.List[uipath.models.connections.Connection]
133
-
134
- # Synchronously retrieve connection API metadata.
135
- sdk.connections.metadata(element_instance_id: int, tool_path: str, schema_mode: bool=True) -> uipath.models.connections.ConnectionMetadata
136
-
137
- # Asynchronously retrieve connection API metadata.
138
- sdk.connections.metadata_async(element_instance_id: int, tool_path: str, schema_mode: bool=True) -> uipath.models.connections.ConnectionMetadata
139
-
140
- # Retrieve connection details by its key.
141
- sdk.connections.retrieve(key: str) -> uipath.models.connections.Connection
142
-
143
- # Asynchronously retrieve connection details by its key.
144
- sdk.connections.retrieve_async(key: str) -> uipath.models.connections.Connection
145
-
146
- # Retrieve event payload from UiPath Integration Service.
147
- sdk.connections.retrieve_event_payload(event_args: uipath.models.connections.EventArguments) -> typing.Dict[str, typing.Any]
148
-
149
- # Retrieve event payload from UiPath Integration Service.
150
- sdk.connections.retrieve_event_payload_async(event_args: uipath.models.connections.EventArguments) -> typing.Dict[str, typing.Any]
151
-
152
- # Retrieve an authentication token for a connection.
153
- sdk.connections.retrieve_token(key: str, token_type: <enum 'ConnectionTokenType="direct") -> uipath.models.connections.ConnectionToken
154
-
155
- # Asynchronously retrieve an authentication token for a connection.
156
- sdk.connections.retrieve_token_async(key: str, token_type: <enum 'ConnectionTokenType="direct") -> uipath.models.connections.ConnectionToken
157
-
158
- ```
159
-
160
73
  ### Context Grounding
161
74
 
162
75
  Context Grounding service
@@ -274,16 +187,6 @@ sdk.entities.update_records_async(entity_key: str, records: List[Any], schema: O
274
187
 
275
188
  ```
276
189
 
277
- ### Folders
278
-
279
- Folders service
280
-
281
- ```python
282
- # Retrieve the folder key by folder path with pagination support.
283
- sdk.folders.retrieve_key(folder_path: str) -> typing.Optional[str]
284
-
285
- ```
286
-
287
190
  ### Jobs
288
191
 
289
192
  Jobs service
uipath/_uipath.py CHANGED
@@ -1,3 +1,4 @@
1
+ from functools import cached_property
1
2
  from typing import Optional
2
3
 
3
4
  from pydantic import ValidationError
@@ -51,10 +52,6 @@ class UiPath:
51
52
  raise BaseUrlMissingError() from e
52
53
  elif error["loc"][0] == "secret":
53
54
  raise SecretMissingError() from e
54
- self._folders_service: Optional[FolderService] = None
55
- self._buckets_service: Optional[BucketsService] = None
56
- self._attachments_service: Optional[AttachmentsService] = None
57
- self._connections_service: Optional[ConnectionsService] = None
58
55
  setup_logging(should_debug=debug)
59
56
  self._execution_context = ExecutionContext()
60
57
 
@@ -66,13 +63,9 @@ class UiPath:
66
63
  def assets(self) -> AssetsService:
67
64
  return AssetsService(self._config, self._execution_context)
68
65
 
69
- @property
66
+ @cached_property
70
67
  def attachments(self) -> AttachmentsService:
71
- if not self._attachments_service:
72
- self._attachments_service = AttachmentsService(
73
- self._config, self._execution_context
74
- )
75
- return self._attachments_service
68
+ return AttachmentsService(self._config, self._execution_context)
76
69
 
77
70
  @property
78
71
  def processes(self) -> ProcessesService:
@@ -82,39 +75,21 @@ class UiPath:
82
75
  def actions(self) -> ActionsService:
83
76
  return ActionsService(self._config, self._execution_context)
84
77
 
85
- @property
78
+ @cached_property
86
79
  def buckets(self) -> BucketsService:
87
- if not self._buckets_service:
88
- self._buckets_service = BucketsService(
89
- self._config, self._execution_context
90
- )
91
80
  return BucketsService(self._config, self._execution_context)
92
81
 
93
- @property
82
+ @cached_property
94
83
  def connections(self) -> ConnectionsService:
95
- if not self._connections_service:
96
- if not self._folders_service:
97
- self._folders_service = FolderService(
98
- self._config, self._execution_context
99
- )
100
- self._connections_service = ConnectionsService(
101
- self._config, self._execution_context, self._folders_service
102
- )
103
- return self._connections_service
84
+ return ConnectionsService(self._config, self._execution_context, self.folders)
104
85
 
105
86
  @property
106
87
  def context_grounding(self) -> ContextGroundingService:
107
- if not self._folders_service:
108
- self._folders_service = FolderService(self._config, self._execution_context)
109
- if not self._buckets_service:
110
- self._buckets_service = BucketsService(
111
- self._config, self._execution_context
112
- )
113
88
  return ContextGroundingService(
114
89
  self._config,
115
90
  self._execution_context,
116
- self._folders_service,
117
- self._buckets_service,
91
+ self.folders,
92
+ self.buckets,
118
93
  )
119
94
 
120
95
  @property
@@ -129,11 +104,9 @@ class UiPath:
129
104
  def jobs(self) -> JobsService:
130
105
  return JobsService(self._config, self._execution_context)
131
106
 
132
- @property
107
+ @cached_property
133
108
  def folders(self) -> FolderService:
134
- if not self._folders_service:
135
- self._folders_service = FolderService(self._config, self._execution_context)
136
- return self._folders_service
109
+ return FolderService(self._config, self._execution_context)
137
110
 
138
111
  @property
139
112
  def llm_openai(self) -> UiPathOpenAIService:
@@ -1,6 +1,7 @@
1
1
  # Environment variables
2
2
  DOTENV_FILE = ".env"
3
3
  ENV_BASE_URL = "UIPATH_URL"
4
+ ENV_EVAL_BACKEND_URL = "UIPATH_EVAL_BACKEND_URL"
4
5
  ENV_UNATTENDED_USER_ACCESS_TOKEN = "UNATTENDED_USER_ACCESS_TOKEN"
5
6
  ENV_UIPATH_ACCESS_TOKEN = "UIPATH_ACCESS_TOKEN"
6
7
  ENV_FOLDER_KEY = "UIPATH_FOLDER_KEY"
@@ -46,3 +47,6 @@ COMMUNITY_agents_SUFFIX = "-community-agents"
46
47
 
47
48
  # File names
48
49
  UIPATH_CONFIG_FILE = "uipath.json"
50
+
51
+ # Evaluators
52
+ CUSTOM_EVALUATOR_PREFIX = "file://"