uipath 2.1.17__py3-none-any.whl → 2.1.20__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.
@@ -3,18 +3,20 @@
3
3
  This package contains all evaluator types and the factory for creating them.
4
4
  """
5
5
 
6
- from ._agent_scorer_evaluator import AgentScorerEvaluator
7
- from ._deterministic_evaluator import DeterministicEvaluator
6
+ from ._deterministic_evaluator_base import DeterministicEvaluatorBase
8
7
  from ._evaluator_base import EvaluatorBase
9
8
  from ._evaluator_factory import EvaluatorFactory
9
+ from ._exact_match_evaluator import ExactMatchEvaluator
10
+ from ._json_similarity_evaluator import JsonSimilarityEvaluator
10
11
  from ._llm_as_judge_evaluator import LlmAsAJudgeEvaluator
11
12
  from ._trajectory_evaluator import TrajectoryEvaluator
12
13
 
13
14
  __all__ = [
14
15
  "EvaluatorBase",
16
+ "DeterministicEvaluatorBase",
15
17
  "EvaluatorFactory",
16
- "DeterministicEvaluator",
18
+ "JsonSimilarityEvaluator",
19
+ "ExactMatchEvaluator",
17
20
  "LlmAsAJudgeEvaluator",
18
- "AgentScorerEvaluator",
19
21
  "TrajectoryEvaluator",
20
22
  ]
@@ -0,0 +1,46 @@
1
+ import copy
2
+ import json
3
+ from abc import ABC
4
+ from typing import Any, Dict, Tuple
5
+
6
+ from ._evaluator_base import EvaluatorBase
7
+
8
+
9
+ class DeterministicEvaluatorBase(EvaluatorBase, ABC):
10
+ def __init__(self, target_output_key: str = "*"):
11
+ super().__init__()
12
+ self.target_output_key = target_output_key
13
+
14
+ def _select_targets(
15
+ self, expected_output: Dict[str, Any], actual_output: Dict[str, Any]
16
+ ) -> Tuple[Any, Any]:
17
+ actual_output_copy = copy.deepcopy(actual_output)
18
+ expected_output_copy = copy.deepcopy(expected_output)
19
+ if self.target_output_key != "*":
20
+ if (
21
+ self.target_output_key not in actual_output
22
+ or self.target_output_key not in expected_output
23
+ ):
24
+ raise ValueError(
25
+ f"Field '{self.target_output_key}' missing from expected or actual output"
26
+ )
27
+ actual_output_copy = actual_output_copy[self.target_output_key]
28
+ expected_output_copy = expected_output[self.target_output_key]
29
+ return actual_output_copy, expected_output_copy
30
+
31
+ def _canonical_json(self, obj: Any) -> str:
32
+ return json.dumps(
33
+ self._normalize_numbers(obj),
34
+ sort_keys=True,
35
+ separators=(",", ":"),
36
+ ensure_ascii=False,
37
+ )
38
+
39
+ def _normalize_numbers(self, obj: Any) -> Any:
40
+ if isinstance(obj, dict):
41
+ return {k: self._normalize_numbers(v) for k, v in obj.items()}
42
+ if isinstance(obj, (list, tuple)):
43
+ return [self._normalize_numbers(v) for v in obj]
44
+ if isinstance(obj, (int, float)) and not isinstance(obj, bool):
45
+ return float(obj)
46
+ return obj
@@ -1,9 +1,9 @@
1
1
  from typing import Any, Dict
2
2
 
3
3
  from .._models import EvaluatorCategory, EvaluatorType
4
- from ._agent_scorer_evaluator import AgentScorerEvaluator
5
- from ._deterministic_evaluator import DeterministicEvaluator
6
4
  from ._evaluator_base import EvaluatorBase, EvaluatorBaseParams
5
+ from ._exact_match_evaluator import ExactMatchEvaluator
6
+ from ._json_similarity_evaluator import JsonSimilarityEvaluator
7
7
  from ._llm_as_judge_evaluator import LlmAsAJudgeEvaluator
8
8
  from ._trajectory_evaluator import TrajectoryEvaluator
9
9
 
@@ -50,23 +50,50 @@ class EvaluatorFactory:
50
50
  )
51
51
 
52
52
  # Create evaluator based on category
53
- if category == EvaluatorCategory.Deterministic:
54
- return EvaluatorFactory._create_deterministic_evaluator(base_params, data)
55
- elif category == EvaluatorCategory.LlmAsAJudge:
56
- return EvaluatorFactory._create_llm_as_judge_evaluator(base_params, data)
57
- elif category == EvaluatorCategory.AgentScorer:
58
- return EvaluatorFactory._create_agent_scorer_evaluator(base_params, data)
59
- elif category == EvaluatorCategory.Trajectory:
60
- return EvaluatorFactory._create_trajectory_evaluator(base_params, data)
61
- else:
62
- raise ValueError(f"Unknown evaluator category: {category}")
53
+ match category:
54
+ case EvaluatorCategory.Deterministic:
55
+ if evaluator_type == evaluator_type.Equals:
56
+ return EvaluatorFactory._create_exact_match_evaluator(
57
+ base_params, data
58
+ )
59
+ elif evaluator_type == evaluator_type.JsonSimilarity:
60
+ return EvaluatorFactory._create_json_similarity_evaluator(
61
+ base_params, data
62
+ )
63
+ else:
64
+ raise ValueError(
65
+ f"Unknown evaluator type {evaluator_type} for category {category}"
66
+ )
67
+ case EvaluatorCategory.LlmAsAJudge:
68
+ return EvaluatorFactory._create_llm_as_judge_evaluator(
69
+ base_params, data
70
+ )
71
+ case EvaluatorCategory.AgentScorer:
72
+ raise NotImplementedError()
73
+ case EvaluatorCategory.Trajectory:
74
+ return EvaluatorFactory._create_trajectory_evaluator(base_params, data)
75
+ case _:
76
+ raise ValueError(f"Unknown evaluator category: {category}")
63
77
 
64
78
  @staticmethod
65
- def _create_deterministic_evaluator(
79
+ def _create_exact_match_evaluator(
66
80
  base_params: EvaluatorBaseParams, data: Dict[str, Any]
67
- ) -> DeterministicEvaluator:
81
+ ) -> ExactMatchEvaluator:
68
82
  """Create a deterministic evaluator."""
69
- raise NotImplementedError()
83
+ return ExactMatchEvaluator.from_params(
84
+ base_params,
85
+ target_output_key=data.get("targetOutputKey", "*"),
86
+ )
87
+
88
+ @staticmethod
89
+ def _create_json_similarity_evaluator(
90
+ base_params: EvaluatorBaseParams, data: Dict[str, Any]
91
+ ) -> JsonSimilarityEvaluator:
92
+ """Create a deterministic evaluator."""
93
+ return JsonSimilarityEvaluator.from_params(
94
+ base_params,
95
+ target_output_key=data.get("targetOutputKey", "*"),
96
+ )
70
97
 
71
98
  @staticmethod
72
99
  def _create_llm_as_judge_evaluator(
@@ -88,13 +115,6 @@ class EvaluatorFactory:
88
115
  target_output_key=data.get("targetOutputKey", "*"),
89
116
  )
90
117
 
91
- @staticmethod
92
- def _create_agent_scorer_evaluator(
93
- base_params: EvaluatorBaseParams, data: Dict[str, Any]
94
- ) -> AgentScorerEvaluator:
95
- """Create an agent scorer evaluator."""
96
- raise NotImplementedError()
97
-
98
118
  @staticmethod
99
119
  def _create_trajectory_evaluator(
100
120
  base_params: EvaluatorBaseParams, data: Dict[str, Any]
@@ -0,0 +1,40 @@
1
+ import copy
2
+ from typing import Any, Dict
3
+
4
+ from uipath._cli._evals._evaluators._deterministic_evaluator_base import (
5
+ DeterministicEvaluatorBase,
6
+ )
7
+ from uipath._cli._evals._models import EvaluationResult
8
+ from uipath._cli._evals._models._evaluators import ScoreType
9
+
10
+
11
+ class ExactMatchEvaluator(DeterministicEvaluatorBase):
12
+ async def evaluate(
13
+ self,
14
+ evaluation_id: str,
15
+ evaluation_name: str,
16
+ input_data: Dict[str, Any],
17
+ expected_output: Dict[str, Any],
18
+ actual_output: Dict[str, Any],
19
+ ) -> EvaluationResult:
20
+ actual_output_copy = copy.deepcopy(actual_output)
21
+ expected_output_copy = copy.deepcopy(expected_output)
22
+
23
+ actual_output, expected_output = self._select_targets(
24
+ expected_output, actual_output
25
+ )
26
+ are_equal = self._canonical_json(actual_output) == self._canonical_json(
27
+ expected_output
28
+ )
29
+
30
+ return EvaluationResult(
31
+ evaluation_id=evaluation_id,
32
+ evaluation_name=evaluation_name,
33
+ evaluator_id=self.id,
34
+ evaluator_name=self.name,
35
+ score=are_equal,
36
+ input=input_data,
37
+ expected_output=expected_output_copy,
38
+ actual_output=actual_output_copy,
39
+ score_type=ScoreType.BOOLEAN,
40
+ )
@@ -0,0 +1,168 @@
1
+ import copy
2
+ import math
3
+ from typing import Any, Dict, Tuple
4
+
5
+ from uipath._cli._evals._evaluators._deterministic_evaluator_base import (
6
+ DeterministicEvaluatorBase,
7
+ )
8
+ from uipath._cli._evals._models import EvaluationResult
9
+ from uipath._cli._evals._models._evaluators import ScoreType
10
+
11
+
12
+ class JsonSimilarityEvaluator(DeterministicEvaluatorBase):
13
+ """Deterministic evaluator that scores structural JSON similarity.
14
+
15
+ Compares expected versus actual JSON-like structures and returns a
16
+ numerical score in the range [0, 100]. The comparison is token-based
17
+ and tolerant for numbers and strings (via Levenshtein distance).
18
+ """
19
+
20
+ async def evaluate(
21
+ self,
22
+ evaluation_id: str,
23
+ evaluation_name: str,
24
+ input_data: Dict[str, Any],
25
+ expected_output: Dict[str, Any],
26
+ actual_output: Dict[str, Any],
27
+ ) -> EvaluationResult:
28
+ """Evaluate similarity between expected and actual JSON outputs.
29
+
30
+ Args:
31
+ evaluation_id: Unique identifier for this evaluation run.
32
+ evaluation_name: Human friendly evaluation name.
33
+ input_data: Input payload used to produce the outputs.
34
+ expected_output: Ground-truth JSON structure.
35
+ actual_output: Produced JSON structure to compare against the ground truth.
36
+
37
+ Returns:
38
+ EvaluationResult: Structured result with the numerical similarity score.
39
+ """
40
+ actual_output_copy = copy.deepcopy(actual_output)
41
+ expected_output_copy = copy.deepcopy(expected_output)
42
+
43
+ actual_output, expected_output = self._select_targets(
44
+ expected_output, actual_output
45
+ )
46
+ similarity = self._compare_json(expected_output, actual_output)
47
+
48
+ return EvaluationResult(
49
+ evaluation_id=evaluation_id,
50
+ evaluation_name=evaluation_name,
51
+ evaluator_id=self.id,
52
+ evaluator_name=self.name,
53
+ score=similarity,
54
+ input=input_data,
55
+ expected_output=expected_output_copy,
56
+ actual_output=actual_output_copy,
57
+ score_type=ScoreType.NUMERICAL,
58
+ )
59
+
60
+ def _compare_json(self, expected: Any, actual: Any) -> float:
61
+ matched_leaves, total_leaves = self._compare_tokens(expected, actual)
62
+ if total_leaves == 0:
63
+ return 100.0
64
+ sim = (matched_leaves / total_leaves) * 100.0
65
+ return max(0.0, min(100.0, sim))
66
+
67
+ def _compare_tokens(
68
+ self, expected_token: Any, actual_token: Any
69
+ ) -> Tuple[float, float]:
70
+ if self._is_number(expected_token) and self._is_number(actual_token):
71
+ return self._compare_numbers(float(expected_token), float(actual_token))
72
+
73
+ if type(expected_token) is not type(actual_token):
74
+ return 0.0, self._count_leaves(expected_token)
75
+
76
+ if isinstance(expected_token, dict):
77
+ matched_leaves = total_leaves = 0.0
78
+ # Only expected keys count
79
+ for expected_key, expected_value in expected_token.items():
80
+ if isinstance(actual_token, dict) and expected_key in actual_token:
81
+ matched, total = self._compare_tokens(
82
+ expected_value, actual_token[expected_key]
83
+ )
84
+ else:
85
+ matched, total = (0.0, self._count_leaves(expected_value))
86
+ matched_leaves += matched
87
+ total_leaves += total
88
+ return matched_leaves, total_leaves
89
+
90
+ if isinstance(expected_token, list):
91
+ matched_leaves = total_leaves = 0.0
92
+ common_length = min(len(expected_token), len(actual_token))
93
+ for index in range(common_length):
94
+ matched, total = self._compare_tokens(
95
+ expected_token[index], actual_token[index]
96
+ )
97
+ matched_leaves += matched
98
+ total_leaves += total
99
+ for index in range(common_length, len(expected_token)):
100
+ total_leaves += self._count_leaves(expected_token[index])
101
+ return (matched_leaves, total_leaves)
102
+
103
+ if isinstance(expected_token, bool):
104
+ return (1.0, 1.0) if expected_token == actual_token else (0.0, 1.0)
105
+
106
+ if isinstance(expected_token, str):
107
+ return self._compare_strings(expected_token, actual_token)
108
+
109
+ return (1.0, 1.0) if str(expected_token) == str(actual_token) else (0.0, 1.0)
110
+
111
+ def _compare_numbers(
112
+ self, expected_number: float, actual_number: float
113
+ ) -> Tuple[float, float]:
114
+ total = 1.0
115
+ if math.isclose(expected_number, 0.0, abs_tol=1e-12):
116
+ matched = 1.0 if math.isclose(actual_number, 0.0, abs_tol=1e-12) else 0.0
117
+ else:
118
+ ratio = abs(expected_number - actual_number) / abs(expected_number)
119
+ matched = max(0.0, min(1.0, 1.0 - ratio))
120
+ return matched, total
121
+
122
+ def _compare_strings(
123
+ self, expected_string: str, actual_string: str
124
+ ) -> Tuple[float, float]:
125
+ total = 1.0
126
+ if not expected_string and not actual_string:
127
+ return 1.0, total
128
+ distance = self._levenshtein(expected_string, actual_string)
129
+ max_length = max(len(expected_string), len(actual_string))
130
+ similarity = 1.0 - (distance / max_length) if max_length else 1.0
131
+ similarity = max(0.0, min(1.0, similarity))
132
+ return similarity, total
133
+
134
+ def _count_leaves(self, token_node: Any) -> float:
135
+ if isinstance(token_node, dict):
136
+ return sum(
137
+ self._count_leaves(child_value) for child_value in token_node.values()
138
+ )
139
+ if isinstance(token_node, list):
140
+ return sum(self._count_leaves(child_value) for child_value in token_node)
141
+ return 1.0
142
+
143
+ def _levenshtein(self, source_text: str, target_text: str) -> int:
144
+ if not source_text:
145
+ return len(target_text)
146
+ if not target_text:
147
+ return len(source_text)
148
+ source_len, target_len = len(source_text), len(target_text)
149
+ distance_matrix = [[0] * (target_len + 1) for _ in range(source_len + 1)]
150
+ for row_idx in range(source_len + 1):
151
+ distance_matrix[row_idx][0] = row_idx
152
+ for col_idx in range(target_len + 1):
153
+ distance_matrix[0][col_idx] = col_idx
154
+ for row_idx in range(1, source_len + 1):
155
+ for col_idx in range(1, target_len + 1):
156
+ substitution_cost = (
157
+ 0 if source_text[row_idx - 1] == target_text[col_idx - 1] else 1
158
+ )
159
+ distance_matrix[row_idx][col_idx] = min(
160
+ distance_matrix[row_idx - 1][col_idx] + 1, # deletion
161
+ distance_matrix[row_idx][col_idx - 1] + 1, # insertion
162
+ distance_matrix[row_idx - 1][col_idx - 1]
163
+ + substitution_cost, # substitution
164
+ )
165
+ return distance_matrix[source_len][target_len]
166
+
167
+ def _is_number(self, value: Any) -> bool:
168
+ return isinstance(value, (int, float)) and not isinstance(value, bool)
@@ -11,6 +11,7 @@ from ...._utils.constants import (
11
11
  COMMUNITY_agents_SUFFIX,
12
12
  )
13
13
  from .._models import EvaluationResult, LLMResponse
14
+ from .._models._evaluators import ScoreType
14
15
  from ._evaluator_base import EvaluatorBase
15
16
 
16
17
 
@@ -86,6 +87,7 @@ class LlmAsAJudgeEvaluator(EvaluatorBase):
86
87
  expected_output=expected_output,
87
88
  actual_output=actual_output,
88
89
  details=llm_response.justification,
90
+ score_type=ScoreType.NUMERICAL,
89
91
  )
90
92
 
91
93
  def _extract_target_value(self, output: Dict[str, Any]) -> Any:
@@ -1,8 +1,8 @@
1
- from datetime import datetime
1
+ from datetime import datetime, timezone
2
2
  from enum import IntEnum
3
3
  from typing import Any, Dict, List, Optional
4
4
 
5
- from pydantic import BaseModel, Field
5
+ from pydantic import BaseModel
6
6
 
7
7
 
8
8
  class LLMResponse(BaseModel):
@@ -50,6 +50,12 @@ class EvaluatorType(IntEnum):
50
50
  raise ValueError(f"{value} is not a valid EvaluatorType value")
51
51
 
52
52
 
53
+ class ScoreType(IntEnum):
54
+ BOOLEAN = 0
55
+ NUMERICAL = 1
56
+ ERROR = 2
57
+
58
+
53
59
  class EvaluationResult(BaseModel):
54
60
  """Result of a single evaluation."""
55
61
 
@@ -57,13 +63,14 @@ class EvaluationResult(BaseModel):
57
63
  evaluation_name: str
58
64
  evaluator_id: str
59
65
  evaluator_name: str
60
- score: float
66
+ score: float | bool
67
+ score_type: ScoreType
61
68
  # this is marked as optional, as it is populated inside the 'measure_execution_time' decorator
62
69
  evaluation_time: Optional[float] = None
63
70
  input: Dict[str, Any]
64
71
  expected_output: Dict[str, Any]
65
72
  actual_output: Dict[str, Any]
66
- timestamp: datetime = Field(default_factory=datetime.utcnow)
73
+ timestamp: datetime = datetime.now(timezone.utc)
67
74
  details: Optional[str] = None
68
75
 
69
76
 
@@ -76,12 +83,6 @@ class EvaluationSetResult(BaseModel):
76
83
  average_score: float
77
84
 
78
85
 
79
- class ScoreType(IntEnum):
80
- BOOLEAN = 0
81
- NUMERICAL = 1
82
- ERROR = 2
83
-
84
-
85
86
  class EvalItemResult(BaseModel):
86
87
  """Result of a single evaluation item."""
87
88
 
@@ -139,12 +139,23 @@ class ProgressReporter:
139
139
  actual_output: dict[str, Any] = {}
140
140
  for eval_result in eval_results:
141
141
  # keep track of evaluator scores. this should be removed after this computation is done server-side
142
- self._evaluator_scores[eval_result.evaluator_id].append(
143
- eval_result.result.score
144
- )
142
+
143
+ # check the evaluator score type
144
+ match eval_result.result.score_type:
145
+ case ScoreType.NUMERICAL:
146
+ self._evaluator_scores[eval_result.evaluator_id].append(
147
+ eval_result.result.score
148
+ )
149
+ case ScoreType.BOOLEAN:
150
+ self._evaluator_scores[eval_result.evaluator_id].append(
151
+ 100 if eval_result.result.score else 0
152
+ )
153
+ case ScoreType.ERROR:
154
+ self._evaluator_scores[eval_result.evaluator_id].append(0)
155
+
145
156
  evaluator_scores.append(
146
157
  {
147
- "type": ScoreType.NUMERICAL.value,
158
+ "type": eval_result.result.score_type.value,
148
159
  "value": eval_result.result.score,
149
160
  "justification": eval_result.result.details,
150
161
  "evaluatorId": eval_result.evaluator_id,
@@ -11,6 +11,7 @@ from typing import Any, Dict, Optional, Type, TypeVar, cast, get_type_hints
11
11
  from opentelemetry import trace
12
12
  from opentelemetry.sdk.trace import TracerProvider
13
13
  from opentelemetry.sdk.trace.export import BatchSpanProcessor
14
+ from pydantic import BaseModel
14
15
 
15
16
  from uipath.tracing import LlmOpsHttpExporter
16
17
 
@@ -162,9 +163,11 @@ class UiPathRuntime(UiPathBaseRuntime):
162
163
  input_param = params[0]
163
164
  input_type = input_param.annotation
164
165
 
165
- # Case 2: Class or dataclass parameter
166
+ # Case 2: Class, dataclass, or Pydantic model parameter
166
167
  if input_type != inspect.Parameter.empty and (
167
- is_dataclass(input_type) or hasattr(input_type, "__annotations__")
168
+ is_dataclass(input_type)
169
+ or self._is_pydantic_model(input_type)
170
+ or hasattr(input_type, "__annotations__")
168
171
  ):
169
172
  try:
170
173
  valid_type = cast(Type[Any], input_type)
@@ -216,7 +219,16 @@ class UiPathRuntime(UiPathBaseRuntime):
216
219
  )
217
220
 
218
221
  def _convert_to_class(self, data: Dict[str, Any], cls: Type[T]) -> T:
219
- """Convert a dictionary to either a dataclass or regular class instance."""
222
+ """Convert a dictionary to either a dataclass, Pydantic model, or regular class instance."""
223
+ # Handle Pydantic models
224
+ try:
225
+ if inspect.isclass(cls) and issubclass(cls, BaseModel):
226
+ return cast(T, cls.model_validate(data))
227
+ except TypeError:
228
+ # issubclass can raise TypeError if cls is not a class
229
+ pass
230
+
231
+ # Handle dataclasses
220
232
  if is_dataclass(cls):
221
233
  field_types = get_type_hints(cls)
222
234
  converted_data = {}
@@ -227,13 +239,17 @@ class UiPathRuntime(UiPathBaseRuntime):
227
239
 
228
240
  value = data[field_name]
229
241
  if (
230
- is_dataclass(field_type) or hasattr(field_type, "__annotations__")
242
+ is_dataclass(field_type)
243
+ or self._is_pydantic_model(field_type)
244
+ or hasattr(field_type, "__annotations__")
231
245
  ) and isinstance(value, dict):
232
246
  typed_field = cast(Type[Any], field_type)
233
247
  value = self._convert_to_class(value, typed_field)
234
248
  converted_data[field_name] = value
235
249
 
236
250
  return cast(T, cls(**converted_data))
251
+
252
+ # Handle regular classes
237
253
  else:
238
254
  sig = inspect.signature(cls.__init__)
239
255
  params = sig.parameters
@@ -254,6 +270,7 @@ class UiPathRuntime(UiPathBaseRuntime):
254
270
 
255
271
  if (
256
272
  is_dataclass(param_type)
273
+ or self._is_pydantic_model(param_type)
257
274
  or hasattr(param_type, "__annotations__")
258
275
  ) and isinstance(value, dict):
259
276
  typed_param = cast(Type[Any], param_type)
@@ -265,22 +282,41 @@ class UiPathRuntime(UiPathBaseRuntime):
265
282
 
266
283
  return cls(**init_args)
267
284
 
285
+ def _is_pydantic_model(self, cls: Type[Any]) -> bool:
286
+ """Safely check if a class is a Pydantic model."""
287
+ try:
288
+ return inspect.isclass(cls) and issubclass(cls, BaseModel)
289
+ except TypeError:
290
+ # issubclass can raise TypeError if cls is not a class
291
+ return False
292
+
268
293
  def _convert_from_class(self, obj: Any) -> Dict[str, Any]:
269
- """Convert a class instance (dataclass or regular) to a dictionary."""
294
+ """Convert a class instance (dataclass, Pydantic model, or regular) to a dictionary."""
270
295
  if obj is None:
271
296
  return {}
272
297
 
273
- if is_dataclass(obj):
298
+ # Handle Pydantic models
299
+ if isinstance(obj, BaseModel):
300
+ return obj.model_dump()
301
+
302
+ # Handle dataclasses
303
+ elif is_dataclass(obj):
274
304
  # Make sure obj is an instance, not a class
275
305
  if isinstance(obj, type):
276
306
  return {}
277
307
  return asdict(obj)
308
+
309
+ # Handle regular classes
278
310
  elif hasattr(obj, "__dict__"):
279
311
  result = {}
280
312
  for key, value in obj.__dict__.items():
281
313
  # Skip private attributes
282
314
  if not key.startswith("_"):
283
- if hasattr(value, "__dict__") or is_dataclass(value):
315
+ if (
316
+ isinstance(value, BaseModel)
317
+ or hasattr(value, "__dict__")
318
+ or is_dataclass(value)
319
+ ):
284
320
  result[key] = self._convert_from_class(value)
285
321
  else:
286
322
  result[key] = value
@@ -14,6 +14,8 @@ from typing import (
14
14
  get_type_hints,
15
15
  )
16
16
 
17
+ from pydantic import BaseModel
18
+
17
19
  SchemaType = Literal["object", "integer", "double", "string", "boolean", "array"]
18
20
 
19
21
  TYPE_MAP: Dict[str, SchemaType] = {
@@ -50,7 +52,30 @@ def get_type_schema(type_hint: Any) -> Dict[str, Any]:
50
52
  return {"type": "object"}
51
53
 
52
54
  if inspect.isclass(type_hint):
53
- if is_dataclass(type_hint):
55
+ # Handle Pydantic models
56
+ if issubclass(type_hint, BaseModel):
57
+ properties = {}
58
+ required = []
59
+
60
+ # Get the model fields
61
+ model_fields = type_hint.model_fields
62
+
63
+ for field_name, field_info in model_fields.items():
64
+ # Use alias if defined, otherwise use field name
65
+ schema_field_name = field_info.alias if field_info.alias else field_name
66
+
67
+ # Get the field type schema
68
+ field_schema = get_type_schema(field_info.annotation)
69
+ properties[schema_field_name] = field_schema
70
+
71
+ # Check if field is required using Pydantic's built-in method
72
+ if field_info.is_required():
73
+ required.append(schema_field_name)
74
+
75
+ return {"type": "object", "properties": properties, "required": required}
76
+
77
+ # Handle dataclasses
78
+ elif is_dataclass(type_hint):
54
79
  properties = {}
55
80
  required = []
56
81
 
@@ -61,6 +86,8 @@ def get_type_schema(type_hint: Any) -> Dict[str, Any]:
61
86
  required.append(field.name)
62
87
 
63
88
  return {"type": "object", "properties": properties, "required": required}
89
+
90
+ # Handle regular classes with annotations
64
91
  elif hasattr(type_hint, "__annotations__"):
65
92
  properties = {}
66
93
  required = []
@@ -8,6 +8,7 @@ from typing import Any, Dict, List, Optional, Tuple
8
8
  from ..._services import (
9
9
  AssetsService,
10
10
  BucketsService,
11
+ ConnectionsService,
11
12
  ContextGroundingService,
12
13
  ProcessesService,
13
14
  )
@@ -47,6 +48,7 @@ supported_bindings_by_service = {
47
48
  "processes": ProcessesService,
48
49
  "buckets": BucketsService,
49
50
  "context_grounding": ContextGroundingService,
51
+ "connections": ConnectionsService,
50
52
  }
51
53
 
52
54
 
@@ -103,7 +105,17 @@ class ServiceUsage:
103
105
 
104
106
  # custom logic for connections bindings
105
107
  elif self.service_name == "connections":
108
+ # First, try to get inferred bindings for connections if they exist
109
+ connections_service = supported_bindings_by_service.get("connections")
110
+ inferred_bindings = {}
111
+ if connections_service:
112
+ inferred_bindings = get_inferred_bindings_names(connections_service)
113
+
106
114
  for call in self.method_calls:
115
+ # Skip methods that are decorated with @infer_bindings(ignore=False)
116
+ if call.method_name in inferred_bindings:
117
+ continue
118
+
107
119
  if len(call.args) > 0:
108
120
  connection_id = call.args[0]
109
121
  if connection_id:
@@ -68,6 +68,7 @@ def get_project_config(directory: str) -> dict[str, str]:
68
68
  "version": toml_data["version"],
69
69
  "authors": toml_data["authors"],
70
70
  "dependencies": toml_data.get("dependencies", {}),
71
+ "requires-python": toml_data.get("requires-python", {}),
71
72
  }
72
73
 
73
74
 
@@ -97,6 +98,11 @@ def validate_config(config: dict[str, str]) -> None:
97
98
  'Project authors cannot be empty. Please specify authors in pyproject.toml:\n authors = [{ name = "John Doe" }]'
98
99
  )
99
100
 
101
+ if not config["requires-python"] or config["requires-python"].strip() == "":
102
+ console.error(
103
+ "'requires-python' field cannot be empty. Please specify it in pyproject.toml: requires-python = \">=3.10\""
104
+ )
105
+
100
106
  invalid_chars = ["&", "<", ">", '"', "'", ";"]
101
107
  for char in invalid_chars:
102
108
  if char in config["project_name"]:
@@ -296,6 +302,7 @@ def read_toml_project(file_path: str) -> dict:
296
302
  "version": project["version"].strip(),
297
303
  "authors": author_name.strip(),
298
304
  "dependencies": dependencies,
305
+ "requires-python": project.get("requires-python", "").strip(),
299
306
  }
300
307
 
301
308
 
@@ -1,9 +1,11 @@
1
+ import json
1
2
  import logging
3
+ from typing import Any, Dict
2
4
 
3
5
  from .._config import Config
4
6
  from .._execution_context import ExecutionContext
5
- from .._utils import Endpoint, RequestSpec
6
- from ..models import Connection, ConnectionToken
7
+ from .._utils import Endpoint, RequestSpec, infer_bindings
8
+ from ..models import Connection, ConnectionToken, EventArguments
7
9
  from ..tracing._traced import traced
8
10
  from ._base_service import BaseService
9
11
 
@@ -112,6 +114,84 @@ class ConnectionsService(BaseService):
112
114
  )
113
115
  return ConnectionToken.model_validate(response.json())
114
116
 
117
+ @traced(
118
+ name="connections_retrieve_event_payload",
119
+ run_type="uipath",
120
+ )
121
+ @infer_bindings(resource_type="ignored", ignore=True)
122
+ def retrieve_event_payload(self, event_args: EventArguments) -> Dict[str, Any]:
123
+ """Retrieve event payload from UiPath Integration Service.
124
+
125
+ Args:
126
+ event_args (EventArguments): The event arguments. Should be passed along from the job's input.
127
+
128
+ Returns:
129
+ Dict[str, Any]: The event payload data
130
+ """
131
+ if not event_args.additional_event_data:
132
+ raise ValueError("additional_event_data is required")
133
+
134
+ # Parse additional event data to get event id
135
+ event_data = json.loads(event_args.additional_event_data)
136
+
137
+ event_id = None
138
+ if "processedEventId" in event_data:
139
+ event_id = event_data["processedEventId"]
140
+ elif "rawEventId" in event_data:
141
+ event_id = event_data["rawEventId"]
142
+ else:
143
+ raise ValueError("Event Id not found in additional event data")
144
+
145
+ # Build request URL using connection token's API base URI
146
+ spec = self._retrieve_event_payload_spec("v1", event_id)
147
+
148
+ response = self.request(spec.method, url=spec.endpoint)
149
+
150
+ return response.json()
151
+
152
+ @traced(
153
+ name="connections_retrieve_event_payload",
154
+ run_type="uipath",
155
+ )
156
+ @infer_bindings(resource_type="ignored", ignore=True)
157
+ async def retrieve_event_payload_async(
158
+ self, event_args: EventArguments
159
+ ) -> Dict[str, Any]:
160
+ """Retrieve event payload from UiPath Integration Service.
161
+
162
+ Args:
163
+ event_args (EventArguments): The event arguments. Should be passed along from the job's input.
164
+
165
+ Returns:
166
+ Dict[str, Any]: The event payload data
167
+ """
168
+ if not event_args.additional_event_data:
169
+ raise ValueError("additional_event_data is required")
170
+
171
+ # Parse additional event data to get event id
172
+ event_data = json.loads(event_args.additional_event_data)
173
+
174
+ event_id = None
175
+ if "processedEventId" in event_data:
176
+ event_id = event_data["processedEventId"]
177
+ elif "rawEventId" in event_data:
178
+ event_id = event_data["rawEventId"]
179
+ else:
180
+ raise ValueError("Event Id not found in additional event data")
181
+
182
+ # Build request URL using connection token's API base URI
183
+ spec = self._retrieve_event_payload_spec("v1", event_id)
184
+
185
+ response = await self.request_async(spec.method, url=spec.endpoint)
186
+
187
+ return response.json()
188
+
189
+ def _retrieve_event_payload_spec(self, version: str, event_id: str) -> RequestSpec:
190
+ return RequestSpec(
191
+ method="GET",
192
+ endpoint=Endpoint(f"/elements_/{version}/events/{event_id}"),
193
+ )
194
+
115
195
  def _retrieve_spec(self, key: str) -> RequestSpec:
116
196
  return RequestSpec(
117
197
  method="GET",
@@ -8,7 +8,10 @@ T = TypeVar("T")
8
8
 
9
9
 
10
10
  def infer_bindings(
11
- resource_type: str, name: str = "name", folder_path: str = "folder_path"
11
+ resource_type: str,
12
+ name: str = "name",
13
+ folder_path: str = "folder_path",
14
+ ignore: bool = False,
12
15
  ) -> Callable[..., Any]:
13
16
  def decorator(func: Callable[..., Any]):
14
17
  @functools.wraps(func)
@@ -30,7 +33,7 @@ def infer_bindings(
30
33
 
31
34
  return func(**all_args)
32
35
 
33
- wrapper._should_infer_bindings = True # type: ignore
36
+ wrapper._should_infer_bindings = not ignore # type: ignore
34
37
  wrapper._infer_bindings_mappings = {"name": name, "folder_path": folder_path} # type: ignore
35
38
  return wrapper
36
39
 
uipath/models/__init__.py CHANGED
@@ -3,7 +3,7 @@ from .actions import Action
3
3
  from .assets import Asset, UserAsset
4
4
  from .attachment import Attachment
5
5
  from .buckets import Bucket
6
- from .connections import Connection, ConnectionToken
6
+ from .connections import Connection, ConnectionToken, EventArguments
7
7
  from .context_grounding import ContextGroundingQueryResponse
8
8
  from .context_grounding_index import ContextGroundingIndex
9
9
  from .errors import BaseUrlMissingError, SecretMissingError
@@ -39,6 +39,7 @@ __all__ = [
39
39
  "TransactionItemResult",
40
40
  "Connection",
41
41
  "ConnectionToken",
42
+ "EventArguments",
42
43
  "Job",
43
44
  "InvokeProcess",
44
45
  "ActionSchema",
@@ -49,3 +49,20 @@ class ConnectionToken(BaseModel):
49
49
  expires_in: Optional[int] = Field(default=None, alias="expiresIn")
50
50
  api_base_uri: Optional[str] = Field(default=None, alias="apiBaseUri")
51
51
  element_instance_id: Optional[int] = Field(default=None, alias="elementInstanceId")
52
+
53
+
54
+ class EventArguments(BaseModel):
55
+ event_connector: Optional[str] = Field(default=None, alias="UiPathEventConnector")
56
+ event: Optional[str] = Field(default=None, alias="UiPathEvent")
57
+ event_object_type: Optional[str] = Field(
58
+ default=None, alias="UiPathEventObjectType"
59
+ )
60
+ event_object_id: Optional[str] = Field(default=None, alias="UiPathEventObjectId")
61
+ additional_event_data: Optional[str] = Field(
62
+ default=None, alias="UiPathAdditionalEventData"
63
+ )
64
+
65
+ model_config = ConfigDict(
66
+ populate_by_name=True,
67
+ extra="allow",
68
+ )
@@ -1,5 +1,6 @@
1
1
  import logging
2
2
  import os
3
+ import re
3
4
  from enum import Enum
4
5
  from typing import Optional
5
6
 
@@ -18,9 +19,14 @@ class UiPathEndpoints(Enum):
18
19
  )
19
20
  AH_CAPABILITIES_ENDPOINT = "agenthub_/llm/api/capabilities"
20
21
 
21
- NORMALIZED_COMPLETION_ENDPOINT = "llmgateway_/api/chat/completions"
22
- PASSTHROUGH_COMPLETION_ENDPOINT = "llmgateway_/openai/deployments/{model}/chat/completions?api-version={api_version}"
23
- EMBEDDING_ENDPOINT = (
22
+ OR_NORMALIZED_COMPLETION_ENDPOINT = "orchestrator_/llm/api/chat/completions"
23
+ OR_PASSTHROUGH_COMPLETION_ENDPOINT = "orchestrator_/llm/openai/deployments/{model}/chat/completions?api-version={api_version}"
24
+ OR_EMBEDDING_ENDPOINT = "orchestrator_/llm/openai/deployments/{model}/embeddings?api-version={api_version}"
25
+ OR_CAPABILITIES_ENDPOINT = "orchestrator_/llm/api/capabilities"
26
+
27
+ LG_NORMALIZED_COMPLETION_ENDPOINT = "llmgateway_/api/chat/completions"
28
+ LG_PASSTHROUGH_COMPLETION_ENDPOINT = "llmgateway_/openai/deployments/{model}/chat/completions?api-version={api_version}"
29
+ LG_EMBEDDING_ENDPOINT = (
24
30
  "llmgateway_/openai/deployments/{model}/embeddings?api-version={api_version}"
25
31
  )
26
32
 
@@ -28,24 +34,39 @@ class UiPathEndpoints(Enum):
28
34
  class EndpointManager:
29
35
  """Manages and caches the UiPath endpoints.
30
36
  This class provides functionality to determine which UiPath endpoints to use based on
31
- the availability of AgentHub. It checks for AgentHub capabilities and caches the result
32
- to avoid repeated network calls.
37
+ the availability of AgentHub and Orchestrator. It checks for capabilities and caches
38
+ the results to avoid repeated network calls.
39
+
40
+ The endpoint selection follows a fallback order:
41
+ 1. AgentHub (if available)
42
+ 2. Orchestrator (if available)
43
+ 3. LLMGateway (default fallback)
44
+
45
+ Environment Variable Override:
46
+ The fallback behavior can be bypassed using the UIPATH_LLM_SERVICE environment variable:
47
+ - 'agenthub' or 'ah': Force use of AgentHub endpoints (skips capability checks)
48
+ - 'orchestrator' or 'or': Force use of Orchestrator endpoints (skips capability checks)
49
+ - 'llmgateway' or 'gateway': Force use of LLMGateway endpoints (skips capability checks)
50
+
33
51
  Class Attributes:
34
52
  _base_url (str): The base URL for UiPath services, retrieved from the UIPATH_URL
35
53
  environment variable.
36
54
  _agenthub_available (Optional[bool]): Cached result of AgentHub availability check.
55
+ _orchestrator_available (Optional[bool]): Cached result of Orchestrator availability check.
37
56
 
38
57
  Methods:
39
58
  is_agenthub_available(): Checks if AgentHub is available, caching the result.
59
+ is_orchestrator_available(): Checks if Orchestrator is available, caching the result.
40
60
  get_passthrough_endpoint(): Returns the appropriate passthrough completion endpoint.
41
61
  get_normalized_endpoint(): Returns the appropriate normalized completion endpoint.
42
62
  get_embeddings_endpoint(): Returns the appropriate embeddings endpoint.
43
- All endpoint methods automatically select between AgentHub and standard endpoints
44
- based on availability.
63
+ All endpoint methods automatically select the best available endpoint using the fallback order,
64
+ unless overridden by the UIPATH_LLM_SERVICE environment variable.
45
65
  """ # noqa: D205
46
66
 
47
67
  _base_url = os.getenv("UIPATH_URL", "")
48
68
  _agenthub_available: Optional[bool] = None
69
+ _orchestrator_available: Optional[bool] = None
49
70
 
50
71
  @classmethod
51
72
  def is_agenthub_available(cls) -> bool:
@@ -55,13 +76,30 @@ class EndpointManager:
55
76
  return cls._agenthub_available
56
77
 
57
78
  @classmethod
58
- def _check_agenthub(cls) -> bool:
59
- """Perform the actual check for AgentHub capabilities."""
79
+ def is_orchestrator_available(cls) -> bool:
80
+ """Check if Orchestrator is available and cache the result."""
81
+ if cls._orchestrator_available is None:
82
+ cls._orchestrator_available = cls._check_orchestrator()
83
+ return cls._orchestrator_available
84
+
85
+ @classmethod
86
+ def _check_capabilities(cls, endpoint: UiPathEndpoints, service_name: str) -> bool:
87
+ """Perform the actual check for service capabilities.
88
+
89
+ Args:
90
+ endpoint: The capabilities endpoint to check
91
+ service_name: Human-readable service name for logging
92
+
93
+ Returns:
94
+ bool: True if the service is available and has valid capabilities
95
+ """
60
96
  try:
61
97
  with httpx.Client(**get_httpx_client_kwargs()) as http_client:
62
98
  base_url = os.getenv("UIPATH_URL", "")
63
- capabilities_url = f"{base_url.rstrip('/')}/{UiPathEndpoints.AH_CAPABILITIES_ENDPOINT.value}"
64
- loggger.debug(f"Checking AgentHub capabilities at {capabilities_url}")
99
+ capabilities_url = f"{base_url.rstrip('/')}/{endpoint.value}"
100
+ loggger.debug(
101
+ f"Checking {service_name} capabilities at {capabilities_url}"
102
+ )
65
103
  response = http_client.get(capabilities_url)
66
104
 
67
105
  if response.status_code != 200:
@@ -76,26 +114,87 @@ class EndpointManager:
76
114
  return True
77
115
 
78
116
  except Exception as e:
79
- loggger.error(f"Error checking AgentHub capabilities: {e}", exc_info=True)
117
+ loggger.error(
118
+ f"Error checking {service_name} capabilities: {e}", exc_info=True
119
+ )
80
120
  return False
81
121
 
82
122
  @classmethod
83
- def get_passthrough_endpoint(cls) -> str:
84
- if cls.is_agenthub_available():
85
- return UiPathEndpoints.AH_PASSTHROUGH_COMPLETION_ENDPOINT.value
123
+ def _check_agenthub(cls) -> bool:
124
+ """Perform the actual check for AgentHub capabilities."""
125
+ return cls._check_capabilities(
126
+ UiPathEndpoints.AH_CAPABILITIES_ENDPOINT, "AgentHub"
127
+ )
86
128
 
87
- return UiPathEndpoints.PASSTHROUGH_COMPLETION_ENDPOINT.value
129
+ @classmethod
130
+ def _check_orchestrator(cls) -> bool:
131
+ """Perform the actual check for Orchestrator capabilities."""
132
+ return cls._check_capabilities(
133
+ UiPathEndpoints.OR_CAPABILITIES_ENDPOINT, "Orchestrator"
134
+ )
88
135
 
89
136
  @classmethod
90
- def get_normalized_endpoint(cls) -> str:
91
- if cls.is_agenthub_available():
92
- return UiPathEndpoints.AH_NORMALIZED_COMPLETION_ENDPOINT.value
137
+ def _select_endpoint(
138
+ cls, ah: UiPathEndpoints, orc: UiPathEndpoints, gw: UiPathEndpoints
139
+ ) -> str:
140
+ """Select an endpoint based on UIPATH_LLM_SERVICE override or capability checks."""
141
+ service_override = os.getenv("UIPATH_LLM_SERVICE", "").lower()
142
+
143
+ if service_override in ("agenthub", "ah"):
144
+ return ah.value
145
+ if service_override in ("orchestrator", "or"):
146
+ return orc.value
147
+ if service_override in ("llmgateway", "gateway"):
148
+ return gw.value
149
+
150
+ # Determine fallback order based on environment hints
151
+ uipath_url = os.getenv("UIPATH_URL", "")
152
+ hdens_env = os.getenv("HDENS_ENV", "").lower()
153
+
154
+ is_cloud_url = re.match(r"https?://[^/]+\.uipath\.com", uipath_url)
155
+
156
+ # Default order: AgentHub -> Orchestrator
157
+ check_order = [
158
+ ("ah", ah, cls.is_agenthub_available),
159
+ ("orc", orc, cls.is_orchestrator_available),
160
+ ]
161
+
162
+ # Prioritize Orchestrator if HDENS_ENV is 'sf' or url is cloud-based
163
+ # Note: The default order already prioritizes AgentHub
164
+ if hdens_env == "sf" or is_cloud_url:
165
+ check_order.reverse()
166
+
167
+ # Execute fallback checks in the determined order
168
+ for _, endpoint, is_available in check_order:
169
+ if is_available():
170
+ return endpoint.value
171
+
172
+ # Final fallback to LLMGateway
173
+ return gw.value
174
+
175
+ @classmethod
176
+ def get_passthrough_endpoint(cls) -> str:
177
+ """Get the passthrough completion endpoint."""
178
+ return cls._select_endpoint(
179
+ UiPathEndpoints.AH_PASSTHROUGH_COMPLETION_ENDPOINT,
180
+ UiPathEndpoints.OR_PASSTHROUGH_COMPLETION_ENDPOINT,
181
+ UiPathEndpoints.LG_PASSTHROUGH_COMPLETION_ENDPOINT,
182
+ )
93
183
 
94
- return UiPathEndpoints.NORMALIZED_COMPLETION_ENDPOINT.value
184
+ @classmethod
185
+ def get_normalized_endpoint(cls) -> str:
186
+ """Get the normalized completion endpoint."""
187
+ return cls._select_endpoint(
188
+ UiPathEndpoints.AH_NORMALIZED_COMPLETION_ENDPOINT,
189
+ UiPathEndpoints.OR_NORMALIZED_COMPLETION_ENDPOINT,
190
+ UiPathEndpoints.LG_NORMALIZED_COMPLETION_ENDPOINT,
191
+ )
95
192
 
96
193
  @classmethod
97
194
  def get_embeddings_endpoint(cls) -> str:
98
- if cls.is_agenthub_available():
99
- return UiPathEndpoints.AH_EMBEDDING_ENDPOINT.value
100
-
101
- return UiPathEndpoints.EMBEDDING_ENDPOINT.value
195
+ """Get the embeddings endpoint."""
196
+ return cls._select_endpoint(
197
+ UiPathEndpoints.AH_EMBEDDING_ENDPOINT,
198
+ UiPathEndpoints.OR_EMBEDDING_ENDPOINT,
199
+ UiPathEndpoints.LG_EMBEDDING_ENDPOINT,
200
+ )
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: uipath
3
- Version: 2.1.17
3
+ Version: 2.1.20
4
4
  Summary: Python SDK and CLI for UiPath Platform, enabling programmatic interaction with automation services, process management, and deployment tools.
5
5
  Project-URL: Homepage, https://uipath.com
6
6
  Project-URL: Repository, https://github.com/UiPath/uipath-python
@@ -30,23 +30,24 @@ uipath/_cli/_auth/index.html,sha256=_Q2OtqPfapG_6vumbQYqtb2PfFe0smk7TlGERKEBvB4,
30
30
  uipath/_cli/_auth/localhost.crt,sha256=oGl9oLLOiouHubAt39B4zEfylFvKEtbtr_43SIliXJc,1226
31
31
  uipath/_cli/_auth/localhost.key,sha256=X31VYXD8scZtmGA837dGX5l6G-LXHLo5ItWJhZXaz3c,1679
32
32
  uipath/_cli/_evals/evaluation_service.py,sha256=VVxZxoCJoB2SUhej_c0DzC9AlnIlWMKnug7z5weNSoE,22077
33
- uipath/_cli/_evals/progress_reporter.py,sha256=6IVALHC-_vblLWMMKiI0k8xERf7HmQfCYM58GXsVa8s,10999
34
- uipath/_cli/_evals/_evaluators/__init__.py,sha256=eXUozXTNJIVCoV54_btA5mXmm1uNnp0qcfysrz9JQu4,629
35
- uipath/_cli/_evals/_evaluators/_agent_scorer_evaluator.py,sha256=qv4YjNiwqi5gWA24mRTC3QQ73o2Djkn1aY-AnHRyUMI,1545
36
- uipath/_cli/_evals/_evaluators/_deterministic_evaluator.py,sha256=P0du9KWz5MP5Pw70Ze7piqeBfFq7w0aU7DLeEiNC3k4,1398
33
+ uipath/_cli/_evals/progress_reporter.py,sha256=m1Dio1vG-04nFTFz5ijM_j1dhudlgOzQukmTkkg6wS4,11490
34
+ uipath/_cli/_evals/_evaluators/__init__.py,sha256=jD7KNLjbsUpsESFXX11eW2MEPXDNuPp2-t-IPB-inlM,734
35
+ uipath/_cli/_evals/_evaluators/_deterministic_evaluator_base.py,sha256=BTl0puBjp9iCsU3YFfYWqk4TOz4iE19O3q1-dK6qUOI,1723
37
36
  uipath/_cli/_evals/_evaluators/_evaluator_base.py,sha256=knHUwYFt0gMG1uJhq5TGEab6M_YevxX019yT3yYwZsw,3787
38
- uipath/_cli/_evals/_evaluators/_evaluator_factory.py,sha256=YvWi5DS8XKKvfgwxurv2ZP3Jmylv1hgshIw9VEfevoY,3954
39
- uipath/_cli/_evals/_evaluators/_llm_as_judge_evaluator.py,sha256=GdX5CsdfcPxCeSkkD-JpYLBddGhU8YieTIMcyENiWns,6506
37
+ uipath/_cli/_evals/_evaluators/_evaluator_factory.py,sha256=RJtCuFREZ8Ijlldpa0521poZLmcR7vTU3WyYOmhJOkc,4688
38
+ uipath/_cli/_evals/_evaluators/_exact_match_evaluator.py,sha256=lvEtAitrZy9myoZLMXLqlBWBPX06Msu67kuFMGSbikM,1319
39
+ uipath/_cli/_evals/_evaluators/_json_similarity_evaluator.py,sha256=HpmkvuwU4Az3IIqFVLUmDvzkqb21pFMxY0sg2biZOMM,7093
40
+ uipath/_cli/_evals/_evaluators/_llm_as_judge_evaluator.py,sha256=nSLZ29xWqALEI53ifr79JPXjyx0T4sr7p-4NygwgAio,6594
40
41
  uipath/_cli/_evals/_evaluators/_trajectory_evaluator.py,sha256=dnogQTOskpI4_cNF0Ge3hBceJJocvOgxBWAwaCWnzB0,1595
41
42
  uipath/_cli/_evals/_models/__init__.py,sha256=Ewjp3u2YeTH2MmzY9LWf7EIbAoIf_nW9fMYbj7pGlPs,420
42
43
  uipath/_cli/_evals/_models/_evaluation_set.py,sha256=UIapFwn_Ti9zHUIcL3xyHDcLZ4lq4sHJ3JXLvY5OYI0,1080
43
- uipath/_cli/_evals/_models/_evaluators.py,sha256=TW6bcGZk7cn9JVfzM9MFWIzog5x-7_BG9Zo0h8GfZOk,2091
44
+ uipath/_cli/_evals/_models/_evaluators.py,sha256=l57NEVyYmzSKuoIXuGkE94Br01hAMg35fiS2MlTkaQM,2115
44
45
  uipath/_cli/_push/sw_file_handler.py,sha256=tRE9n68xv0r20ulwOyALHtYwzbjGneiASwzNm8xtBN0,16372
45
46
  uipath/_cli/_runtime/_contracts.py,sha256=WlpaiQAMWCo-JFHjee35Klf49A3GsKjOU1Mf2IpUGHY,16033
46
47
  uipath/_cli/_runtime/_escalation.py,sha256=x3vI98qsfRA-fL_tNkRVTFXioM5Gv2w0GFcXJJ5eQtg,7981
47
48
  uipath/_cli/_runtime/_hitl.py,sha256=aexwe0dIXvh6SlVS1jVnO_aGZc6e3gLsmGkCyha5AHo,11300
48
49
  uipath/_cli/_runtime/_logging.py,sha256=0_8OeF2w2zcryvozOsB3h4sFktiwnUqJr_fMRxwUFOc,8004
49
- uipath/_cli/_runtime/_runtime.py,sha256=dHfL6McYC9BwBB9Dk4Y_syvAft-1b-jTG1nbG_d07m8,10647
50
+ uipath/_cli/_runtime/_runtime.py,sha256=Lee055XQBFe5sUiwo5T7XKOxKRCsv8gvy9wSZBnqVak,11917
50
51
  uipath/_cli/_templates/.psmdcp.template,sha256=C7pBJPt98ovEljcBvGtEUGoWjjQhu9jls1bpYjeLOKA,611
51
52
  uipath/_cli/_templates/.rels.template,sha256=-fTcw7OA1AcymHr0LzBqbMAAtzZTRXLTNa_ljq087Jk,406
52
53
  uipath/_cli/_templates/[Content_Types].xml.template,sha256=bYsKDz31PkIF9QksjgAY_bqm57YC8U_owsZeNZAiBxQ,584
@@ -57,10 +58,10 @@ uipath/_cli/_utils/_console.py,sha256=scvnrrFoFX6CE451K-PXKV7UN0DUkInbOtDZ5jAdPP
57
58
  uipath/_cli/_utils/_constants.py,sha256=rS8lQ5Nzull8ytajK6lBsz398qiCp1REoAwlHtyBwF0,1415
58
59
  uipath/_cli/_utils/_debug.py,sha256=zamzIR4VgbdKADAE4gbmjxDsbgF7wvdr7C5Dqp744Oc,1739
59
60
  uipath/_cli/_utils/_folders.py,sha256=UVJcKPfPAVR5HF4AP6EXdlNVcfEF1v5pwGCpoAgBY34,1155
60
- uipath/_cli/_utils/_input_args.py,sha256=pyQhEcQXHdFHYTVNzvfWp439aii5StojoptnmCv5lfs,4094
61
- uipath/_cli/_utils/_parse_ast.py,sha256=A-QToBIf-oP7yP2DQTHO6blkk6ik5z_IeaIwtEWO4e0,19516
61
+ uipath/_cli/_utils/_input_args.py,sha256=3LGNqVpJItvof75VGm-ZNTUMUH9-c7-YgleM5b2YgRg,5088
62
+ uipath/_cli/_utils/_parse_ast.py,sha256=8Iohz58s6bYQ7rgWtOTjrEInLJ-ETikmOMZzZdIY2Co,20072
62
63
  uipath/_cli/_utils/_processes.py,sha256=q7DfEKHISDWf3pngci5za_z0Pbnf_shWiYEcTOTCiyk,1855
63
- uipath/_cli/_utils/_project_files.py,sha256=-zwoPePypqMvC-UxuoGuTGWn3dTP0EYUIz-mfQrgDyg,12742
64
+ uipath/_cli/_utils/_project_files.py,sha256=MMexSE6BapxitYBl1UUWy_AgkJMdGNFD1t2MkU0hwz4,13115
64
65
  uipath/_cli/_utils/_studio_project.py,sha256=iVcCm-aps-EQ7Pym_OWGOA48xeDigzcofUxXKy29x6U,13727
65
66
  uipath/_cli/_utils/_tracing.py,sha256=2igb03j3EHjF_A406UhtCKkPfudVfFPjUq5tXUEG4oo,1541
66
67
  uipath/_cli/_utils/_uv_helpers.py,sha256=6SvoLnZPoKIxW0sjMvD1-ENV_HOXDYzH34GjBqwT138,3450
@@ -71,7 +72,7 @@ uipath/_services/api_client.py,sha256=AbRmpXQScrJIVfDQM309G1GNP3ILLKOrusouhxNQZf
71
72
  uipath/_services/assets_service.py,sha256=acqWogfhZiSO1eeVYqFxmqWGSTmrW46QxI1J0bJe3jo,11918
72
73
  uipath/_services/attachments_service.py,sha256=NPQYK7CGjfBaNT_1S5vEAfODmOChTbQZforllFM2ofU,26678
73
74
  uipath/_services/buckets_service.py,sha256=5s8tuivd7GUZYj774DDUYTa0axxlUuesc4EBY1V5sdk,18496
74
- uipath/_services/connections_service.py,sha256=Hi8QJ1exhuYYlkGdm3BXAblJ95JGotmhxH7tdNF-qG0,4586
75
+ uipath/_services/connections_service.py,sha256=Rf-DCm43tsDM6Cfp41iwGR4gUk_YCdobGcmbSoKvQ6E,7480
75
76
  uipath/_services/context_grounding_service.py,sha256=EBf7lIIYz_s1ubf_07OAZXQHjS8kpZ2vqxo4mI3VL-A,25009
76
77
  uipath/_services/folder_service.py,sha256=9JqgjKhWD-G_KUnfUTP2BADxL6OK9QNZsBsWZHAULdE,2749
77
78
  uipath/_services/jobs_service.py,sha256=CnDd7BM4AMqcMIR1qqu5ohhxf9m0AF4dnGoF4EX38kw,30872
@@ -80,7 +81,7 @@ uipath/_services/processes_service.py,sha256=Pk6paw7e_a-WvVcfKDLuyj1p--pvNRTXwZN
80
81
  uipath/_services/queues_service.py,sha256=VaG3dWL2QK6AJBOLoW2NQTpkPfZjsqsYPl9-kfXPFzA,13534
81
82
  uipath/_utils/__init__.py,sha256=VdcpnENJIa0R6Y26NoxY64-wUVyvb4pKfTh1wXDQeMk,526
82
83
  uipath/_utils/_endpoint.py,sha256=yYHwqbQuJIevpaTkdfYJS9CrtlFeEyfb5JQK5osTCog,2489
83
- uipath/_utils/_infer_bindings.py,sha256=cgsXUedRkVoplR3xGIACGuUge_mBq6H90QiQ6zG9fhY,1686
84
+ uipath/_utils/_infer_bindings.py,sha256=yTl3JBgoLwtQV-RCUkDY4qZne9FtE3HHIiYgCAKAOKw,1727
84
85
  uipath/_utils/_logs.py,sha256=adfX_0UAn3YBeKJ8DQDeZs94rJyHGQO00uDfkaTpNWQ,510
85
86
  uipath/_utils/_read_overwrites.py,sha256=OQgG9ycPpFnLub5ELQdX9V2Fyh6F9_zDR3xoYagJaMI,5287
86
87
  uipath/_utils/_request_override.py,sha256=fIVHzgHVXITUlWcp8osNBwIafM1qm4_ejx0ng5UzfJ4,573
@@ -89,13 +90,13 @@ uipath/_utils/_ssl_context.py,sha256=xSYitos0eJc9cPHzNtHISX9PBvL6D2vas5G_GiBdLp8
89
90
  uipath/_utils/_url.py,sha256=-4eluSrIZCUlnQ3qU17WPJkgaC2KwF9W5NeqGnTNGGo,2512
90
91
  uipath/_utils/_user_agent.py,sha256=pVJkFYacGwaQBomfwWVAvBQgdBUo62e4n3-fLIajWUU,563
91
92
  uipath/_utils/constants.py,sha256=9sjOPn2y4mU2KzBwKpkDOd1QW6AgL7omJBoCk4XebKk,1038
92
- uipath/models/__init__.py,sha256=Kwqv1LzWNfSxJLMQrInVen3KDJ1z0eCcr6szQa0G0VE,1251
93
+ uipath/models/__init__.py,sha256=d_DkK1AtRUetM1t2NrH5UKgvJOBiynzaKnK5pMY7aIc,1289
93
94
  uipath/models/action_schema.py,sha256=lKDhP7Eix23fFvfQrqqNmSOiPyyNF6tiRpUu0VZIn_M,714
94
95
  uipath/models/actions.py,sha256=ekSH4YUQR4KPOH-heBm9yOgOfirndx0In4_S4VYWeEU,2993
95
96
  uipath/models/assets.py,sha256=Q-7_xmm503XHTKgCDrDtXsFl3VWBSVSyiWYW0mZjsnA,2942
96
97
  uipath/models/attachment.py,sha256=prBlhhTvaBnLXJ3PKKxxHWbus35dCuag3_5HngksUjU,843
97
98
  uipath/models/buckets.py,sha256=N3Lj_dVCv709-ywhOOdyCSvsuLn41eGuAfSiik6Q6F8,1285
98
- uipath/models/connections.py,sha256=perIqW99YEg_0yWZPdpZlmNpZcwY_toR1wkqDUBdAN0,2014
99
+ uipath/models/connections.py,sha256=Kej_t2mH-JOomf8pDXPWW1SrvOd8OraOjOH0nKBrVlU,2598
99
100
  uipath/models/context_grounding.py,sha256=S9PeOlFlw7VxzzJVR_Fs28OObW3MLHUPCFqNgkEz24k,1315
100
101
  uipath/models/context_grounding_index.py,sha256=0ADlH8fC10qIbakgwU89pRVawzJ36TiSDKIqOhUdhuA,2580
101
102
  uipath/models/errors.py,sha256=gPyU4sKYn57v03aOVqm97mnU9Do2e7bwMQwiSQVp9qc,461
@@ -113,9 +114,9 @@ uipath/tracing/_otel_exporters.py,sha256=X7cnuGqvxGbACZuFD2XYTWXwIse8pokOEAjeTPE
113
114
  uipath/tracing/_traced.py,sha256=qeVDrds2OUnpdUIA0RhtF0kg2dlAZhyC1RRkI-qivTM,18528
114
115
  uipath/tracing/_utils.py,sha256=ZeensQexnw69jVcsVrGyED7mPlAU-L1agDGm6_1A3oc,10388
115
116
  uipath/utils/__init__.py,sha256=VD-KXFpF_oWexFg6zyiWMkxl2HM4hYJMIUDZ1UEtGx0,105
116
- uipath/utils/_endpoints_manager.py,sha256=hiGEu6vyfQJoeiiql6w21TNiG6tADUfXlVBimxPU1-Q,4160
117
- uipath-2.1.17.dist-info/METADATA,sha256=OHfpvhVLjNz9n7-lTN7huLmlhpbjxMi-wruUh0DMFAk,6367
118
- uipath-2.1.17.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
119
- uipath-2.1.17.dist-info/entry_points.txt,sha256=9C2_29U6Oq1ExFu7usihR-dnfIVNSKc-0EFbh0rskB4,43
120
- uipath-2.1.17.dist-info/licenses/LICENSE,sha256=-KBavWXepyDjimmzH5fVAsi-6jNVpIKFc2kZs0Ri4ng,1058
121
- uipath-2.1.17.dist-info/RECORD,,
117
+ uipath/utils/_endpoints_manager.py,sha256=iRTl5Q0XAm_YgcnMcJOXtj-8052sr6jpWuPNz6CgT0Q,8408
118
+ uipath-2.1.20.dist-info/METADATA,sha256=CMJ4e0Xkauc6EZhmTQW6kVrQ3mnhWjZte2atCM4JyyE,6367
119
+ uipath-2.1.20.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
120
+ uipath-2.1.20.dist-info/entry_points.txt,sha256=9C2_29U6Oq1ExFu7usihR-dnfIVNSKc-0EFbh0rskB4,43
121
+ uipath-2.1.20.dist-info/licenses/LICENSE,sha256=-KBavWXepyDjimmzH5fVAsi-6jNVpIKFc2kZs0Ri4ng,1058
122
+ uipath-2.1.20.dist-info/RECORD,,
@@ -1,48 +0,0 @@
1
- from typing import Any, Dict
2
-
3
- from .._models import EvaluationResult
4
- from ._evaluator_base import EvaluatorBase
5
-
6
-
7
- class AgentScorerEvaluator(EvaluatorBase):
8
- """Evaluator that uses an agent to score outputs."""
9
-
10
- def __init__(
11
- self,
12
- agent_config: Dict[str, Any],
13
- scoring_criteria: Dict[str, Any],
14
- target_output_key: str = "*",
15
- ):
16
- """Initialize the agent scorer evaluator.
17
-
18
- Args:
19
- agent_config: Configuration for the scoring agent
20
- scoring_criteria: Criteria used for scoring
21
- target_output_key: Key in output to evaluate ("*" for entire output)
22
- """
23
- super().__init__()
24
- self.agent_config = agent_config or {}
25
- self.scoring_criteria = scoring_criteria or {}
26
- self.target_output_key = target_output_key
27
-
28
- async def evaluate(
29
- self,
30
- evaluation_id: str,
31
- evaluation_name: str,
32
- input_data: Dict[str, Any],
33
- expected_output: Dict[str, Any],
34
- actual_output: Dict[str, Any],
35
- ) -> EvaluationResult:
36
- """Evaluate using an agent scorer.
37
-
38
- Args:
39
- evaluation_id: The ID of the evaluation being processed
40
- evaluation_name: The name of the evaluation
41
- input_data: The input data for the evaluation
42
- expected_output: The expected output
43
- actual_output: The actual output from the agent
44
-
45
- Returns:
46
- EvaluationResult containing the score and details
47
- """
48
- raise NotImplementedError()
@@ -1,41 +0,0 @@
1
- from typing import Any, Dict
2
-
3
- from .._models import EvaluationResult
4
- from ._evaluator_base import EvaluatorBase
5
-
6
-
7
- class DeterministicEvaluator(EvaluatorBase):
8
- """Evaluator for deterministic/rule-based evaluations."""
9
-
10
- def __init__(self, rule_config: Dict[str, Any], target_output_key: str = "*"):
11
- """Initialize the deterministic evaluator.
12
-
13
- Args:
14
- rule_config: Configuration for the rule (expected_value, regex_pattern, etc.)
15
- target_output_key: Key in output to evaluate ("*" for entire output)
16
- """
17
- super().__init__()
18
- self.rule_config = rule_config or {}
19
- self.target_output_key = target_output_key
20
-
21
- async def evaluate(
22
- self,
23
- evaluation_id: str,
24
- evaluation_name: str,
25
- input_data: Dict[str, Any],
26
- expected_output: Dict[str, Any],
27
- actual_output: Dict[str, Any],
28
- ) -> EvaluationResult:
29
- """Evaluate using deterministic rules.
30
-
31
- Args:
32
- evaluation_id: The ID of the evaluation being processed
33
- evaluation_name: The name of the evaluation
34
- input_data: The input data for the evaluation
35
- expected_output: The expected output
36
- actual_output: The actual output from the agent
37
-
38
- Returns:
39
- EvaluationResult containing the score and details
40
- """
41
- raise NotImplementedError()