uipath 2.1.42__py3-none-any.whl → 2.1.44__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.
@@ -0,0 +1,14 @@
1
+ from opentelemetry.sdk.trace import ReadableSpan
2
+ from pydantic import BaseModel, ConfigDict
3
+
4
+ from uipath._cli._runtime._contracts import UiPathRuntimeResult
5
+
6
+
7
+ class UiPathEvalRunExecutionOutput(BaseModel):
8
+ """Result of a single agent response."""
9
+
10
+ model_config = ConfigDict(arbitrary_types_allowed=True)
11
+
12
+ execution_time: float
13
+ spans: list[ReadableSpan]
14
+ result: UiPathRuntimeResult
@@ -0,0 +1,172 @@
1
+ import copy
2
+ from collections import defaultdict
3
+ from time import time
4
+ from typing import Dict, Generic, List, Optional, Sequence, TypeVar
5
+
6
+ from opentelemetry.sdk.trace import ReadableSpan
7
+ from opentelemetry.sdk.trace.export import SpanExporter, SpanExportResult
8
+
9
+ from uipath.eval._helpers import auto_discover_entrypoint
10
+
11
+ from .._runtime._contracts import (
12
+ UiPathBaseRuntime,
13
+ UiPathRuntimeContext,
14
+ UiPathRuntimeFactory,
15
+ UiPathRuntimeResult,
16
+ UiPathRuntimeStatus,
17
+ )
18
+ from .._utils._eval_set import EvalHelpers
19
+ from ._models import EvaluationItem
20
+ from ._models._agent_execution_output import UiPathEvalRunExecutionOutput
21
+
22
+ T = TypeVar("T", bound=UiPathBaseRuntime)
23
+ C = TypeVar("C", bound=UiPathRuntimeContext)
24
+
25
+
26
+ class ExecutionSpanExporter(SpanExporter):
27
+ """Custom exporter that stores spans grouped by execution ids."""
28
+
29
+ def __init__(self):
30
+ # { execution_id -> list of spans }
31
+ self._spans: Dict[str, List[ReadableSpan]] = defaultdict(list)
32
+
33
+ def export(self, spans: Sequence[ReadableSpan]) -> SpanExportResult:
34
+ for span in spans:
35
+ if span.attributes is not None:
36
+ exec_id = span.attributes.get("execution.id")
37
+ if exec_id is not None and isinstance(exec_id, str):
38
+ self._spans[exec_id].append(span)
39
+
40
+ return SpanExportResult.SUCCESS
41
+
42
+ def get_spans(self, execution_id: str) -> List[ReadableSpan]:
43
+ """Retrieve spans for a given execution id."""
44
+ return self._spans.get(execution_id, [])
45
+
46
+ def clear(self, execution_id: Optional[str] = None) -> None:
47
+ """Clear stored spans for one or all executions."""
48
+ if execution_id:
49
+ self._spans.pop(execution_id, None)
50
+ else:
51
+ self._spans.clear()
52
+
53
+ def shutdown(self) -> None:
54
+ self.clear()
55
+
56
+
57
+ class UiPathEvalContext(UiPathRuntimeContext, Generic[C]):
58
+ """Context used for evaluation runs."""
59
+
60
+ runtime_context: C
61
+ no_report: bool
62
+ workers: int
63
+ eval_set: Optional[str] = None
64
+ eval_ids: Optional[List[str]] = None
65
+
66
+ def __init__(
67
+ self,
68
+ runtime_context: C,
69
+ no_report: bool,
70
+ workers: int,
71
+ eval_set: Optional[str] = None,
72
+ eval_ids: Optional[List[str]] = None,
73
+ **kwargs,
74
+ ):
75
+ super().__init__(
76
+ runtime_context=runtime_context, # type: ignore
77
+ no_report=no_report,
78
+ workers=workers,
79
+ eval_set=eval_set,
80
+ eval_ids=eval_ids,
81
+ **kwargs,
82
+ )
83
+ self._auto_discover()
84
+
85
+ def _auto_discover(self):
86
+ self.runtime_context.entrypoint = (
87
+ self.runtime_context.entrypoint or auto_discover_entrypoint()
88
+ )
89
+ self.eval_set = self.eval_set or EvalHelpers.auto_discover_eval_set()
90
+
91
+
92
+ class UiPathEvalRuntime(UiPathBaseRuntime, Generic[T, C]):
93
+ """Specialized runtime for evaluation runs, with access to the factory."""
94
+
95
+ def __init__(
96
+ self, context: "UiPathEvalContext[C]", factory: "UiPathRuntimeFactory[T, C]"
97
+ ):
98
+ super().__init__(context)
99
+ self.context: "UiPathEvalContext[C]" = context
100
+ self.factory: UiPathRuntimeFactory[T, C] = factory
101
+ self.span_exporter: ExecutionSpanExporter = ExecutionSpanExporter()
102
+ self.factory.add_span_exporter(self.span_exporter)
103
+
104
+ @classmethod
105
+ def from_eval_context(
106
+ cls,
107
+ context: "UiPathEvalContext[C]",
108
+ factory: "UiPathRuntimeFactory[T, C]",
109
+ ) -> "UiPathEvalRuntime[T, C]":
110
+ return cls(context, factory)
111
+
112
+ async def execute(self) -> Optional[UiPathRuntimeResult]:
113
+ """Evaluation logic. Can spawn other runtimes through the factory."""
114
+ if self.context.eval_set is None:
115
+ raise ValueError("eval_set must be provided for evaluation runs")
116
+
117
+ evaluation_set = EvalHelpers.load_eval_set(
118
+ self.context.eval_set, self.context.eval_ids
119
+ )
120
+ execution_output_list: list[UiPathEvalRunExecutionOutput] = []
121
+ for eval_item in evaluation_set.evaluations:
122
+ execution_output_list.append(await self.execute_agent(eval_item))
123
+
124
+ self.context.result = UiPathRuntimeResult(
125
+ output={
126
+ "results": execution_output_list,
127
+ },
128
+ status=UiPathRuntimeStatus.SUCCESSFUL,
129
+ resume=None,
130
+ )
131
+
132
+ return self.context.runtime_context.result
133
+
134
+ def _prepare_new_runtime_context(self, eval_item: EvaluationItem) -> C:
135
+ runtime_context = copy.deepcopy(self.context.runtime_context)
136
+ runtime_context.execution_id = eval_item.id
137
+ runtime_context.input_json = eval_item.inputs
138
+ # here we can pass other values from eval_item: expectedAgentBehavior, simulationInstructions etc.
139
+ return runtime_context
140
+
141
+ # TODO: this would most likely need to be ported to a public AgentEvaluator class
142
+ async def execute_agent(
143
+ self, eval_item: EvaluationItem
144
+ ) -> "UiPathEvalRunExecutionOutput":
145
+ runtime_context = self._prepare_new_runtime_context(eval_item)
146
+ start_time = time()
147
+ result = await self.factory.execute_in_root_span(
148
+ runtime_context, root_span=eval_item.name
149
+ )
150
+ end_time = time()
151
+ if runtime_context.execution_id is None:
152
+ raise ValueError("execution_id must be set for eval runs")
153
+
154
+ spans = self.span_exporter.get_spans(runtime_context.execution_id)
155
+ self.span_exporter.clear(runtime_context.execution_id)
156
+
157
+ if result is None:
158
+ raise ValueError("Execution result cannot be None for eval runs")
159
+
160
+ return UiPathEvalRunExecutionOutput(
161
+ execution_time=end_time - start_time,
162
+ spans=spans,
163
+ result=result,
164
+ )
165
+
166
+ async def cleanup(self) -> None:
167
+ """Cleanup runtime resources."""
168
+ pass
169
+
170
+ async def validate(self) -> None:
171
+ """Cleanup runtime resources."""
172
+ pass
@@ -9,6 +9,7 @@ from abc import ABC, abstractmethod
9
9
  from enum import Enum
10
10
  from functools import cached_property
11
11
  from typing import Any, Callable, Dict, Generic, List, Optional, Type, TypeVar, Union
12
+ from uuid import uuid4
12
13
 
13
14
  from opentelemetry import context as context_api
14
15
  from opentelemetry import trace
@@ -23,7 +24,7 @@ from opentelemetry.trace import Tracer
23
24
  from pydantic import BaseModel, Field
24
25
 
25
26
  from uipath.agent.conversation import UiPathConversationEvent, UiPathConversationMessage
26
- from uipath.tracing import TracingManager
27
+ from uipath.tracing import LlmOpsHttpExporter, TracingManager
27
28
 
28
29
  from ._logging import LogsInterceptor
29
30
 
@@ -161,6 +162,128 @@ class UiPathTraceContext(BaseModel):
161
162
  reference_id: Optional[str] = None
162
163
 
163
164
 
165
+ class UiPathRuntimeContextBuilder:
166
+ """Builder class for UiPathRuntimeContext following the builder pattern."""
167
+
168
+ def __init__(self):
169
+ self._kwargs = {}
170
+
171
+ def with_defaults(
172
+ self, config_path: Optional[str] = None, **kwargs
173
+ ) -> "UiPathRuntimeContextBuilder":
174
+ """Apply default configuration similar to UiPathRuntimeContext.with_defaults().
175
+
176
+ Args:
177
+ config_path: Path to the configuration file (defaults to UIPATH_CONFIG_PATH env var or "uipath.json")
178
+ **kwargs: Additional keyword arguments to pass to with_defaults
179
+
180
+ Returns:
181
+ Self for method chaining
182
+ """
183
+ from os import environ as env
184
+
185
+ resolved_config_path = config_path or env.get(
186
+ "UIPATH_CONFIG_PATH", "uipath.json"
187
+ )
188
+ self._kwargs["config_path"] = resolved_config_path
189
+
190
+ self._kwargs.update(
191
+ {
192
+ "job_id": env.get("UIPATH_JOB_KEY"),
193
+ "trace_id": env.get("UIPATH_TRACE_ID"),
194
+ "tracing_enabled": env.get("UIPATH_TRACING_ENABLED", True),
195
+ "logs_min_level": env.get("LOG_LEVEL", "INFO"),
196
+ **kwargs, # Allow overriding defaults with provided kwargs
197
+ }
198
+ )
199
+
200
+ self._kwargs["trace_context"] = UiPathTraceContext(
201
+ trace_id=env.get("UIPATH_TRACE_ID"),
202
+ parent_span_id=env.get("UIPATH_PARENT_SPAN_ID"),
203
+ root_span_id=env.get("UIPATH_ROOT_SPAN_ID"),
204
+ enabled=env.get("UIPATH_TRACING_ENABLED", True),
205
+ job_id=env.get("UIPATH_JOB_KEY"),
206
+ org_id=env.get("UIPATH_ORGANIZATION_ID"),
207
+ tenant_id=env.get("UIPATH_TENANT_ID"),
208
+ process_key=env.get("UIPATH_PROCESS_UUID"),
209
+ folder_key=env.get("UIPATH_FOLDER_KEY"),
210
+ reference_id=env.get("UIPATH_JOB_KEY") or str(uuid4()),
211
+ )
212
+
213
+ return self
214
+
215
+ def with_entrypoint(self, entrypoint: str) -> "UiPathRuntimeContextBuilder":
216
+ """Set the entrypoint for the runtime context.
217
+
218
+ Args:
219
+ entrypoint: The entrypoint to execute
220
+
221
+ Returns:
222
+ Self for method chaining
223
+ """
224
+ self._kwargs["entrypoint"] = entrypoint
225
+ return self
226
+
227
+ def with_input(
228
+ self, input_data: Optional[str] = None, input_file: Optional[str] = None
229
+ ) -> "UiPathRuntimeContextBuilder":
230
+ """Set the input data for the runtime context.
231
+
232
+ Args:
233
+ input_data: The input data as a string
234
+ input_file: Path to the input file
235
+
236
+ Returns:
237
+ Self for method chaining
238
+ """
239
+ if input_data is not None:
240
+ self._kwargs["input"] = input_data
241
+ if input_file is not None:
242
+ self._kwargs["input_file"] = input_file
243
+ return self
244
+
245
+ def with_resume(self, enable: bool = True) -> "UiPathRuntimeContextBuilder":
246
+ """Enable or disable resume mode for the runtime context.
247
+
248
+ Args:
249
+ enable: Whether to enable resume mode (defaults to True)
250
+
251
+ Returns:
252
+ Self for method chaining
253
+ """
254
+ self._kwargs["resume"] = enable
255
+ return self
256
+
257
+ def mark_eval_run(self, enable: bool = True) -> "UiPathRuntimeContextBuilder":
258
+ """Mark this as an evaluation run.
259
+
260
+ Args:
261
+ enable: Whether this is an eval run (defaults to True)
262
+
263
+ Returns:
264
+ Self for method chaining
265
+ """
266
+ self._kwargs["is_eval_run"] = enable
267
+ return self
268
+
269
+ def build(self) -> "UiPathRuntimeContext":
270
+ """Build and return the UiPathRuntimeContext instance.
271
+
272
+ Returns:
273
+ A configured UiPathRuntimeContext instance
274
+ """
275
+ config_path = self._kwargs.pop("config_path", None)
276
+ if config_path:
277
+ # Create context from config first, then update with any additional kwargs
278
+ context = UiPathRuntimeContext.from_config(config_path)
279
+ for key, value in self._kwargs.items():
280
+ if hasattr(context, key):
281
+ setattr(context, key, value)
282
+ return context
283
+ else:
284
+ return UiPathRuntimeContext(**self._kwargs)
285
+
286
+
164
287
  class UiPathRuntimeContext(BaseModel):
165
288
  """Context information passed throughout the runtime execution."""
166
289
 
@@ -422,8 +545,8 @@ class UiPathBaseRuntime(ABC):
422
545
  content = execution_result.to_dict()
423
546
  logger.debug(content)
424
547
 
425
- # Always write output file at runtime
426
- if self.context.job_id:
548
+ # Always write output file at runtime, except evaluation runs
549
+ if self.context.job_id and not self.context.is_eval_run:
427
550
  with open(self.output_file_path, "w") as f:
428
551
  json.dump(content, f, indent=2, default=str)
429
552
 
@@ -521,6 +644,9 @@ class UiPathRuntimeFactory(Generic[T, C]):
521
644
  self.tracer_span_processors: List[SpanProcessor] = []
522
645
  trace.set_tracer_provider(self.tracer_provider)
523
646
 
647
+ if os.getenv("UIPATH_JOB_KEY"):
648
+ self.add_span_exporter(LlmOpsHttpExporter())
649
+
524
650
  def add_span_exporter(
525
651
  self,
526
652
  span_exporter: SpanExporter,
@@ -591,9 +717,12 @@ class UiPathExecutionTraceProcessorMixin:
591
717
  parent_span = trace.get_current_span()
592
718
 
593
719
  if parent_span and parent_span.is_recording():
594
- run_id = parent_span.attributes.get("execution.id") # type: ignore[attr-defined]
595
- if run_id:
596
- span.set_attribute("execution.id", run_id)
720
+ execution_id = parent_span.attributes.get("execution.id") # type: ignore[attr-defined]
721
+ if execution_id:
722
+ span.set_attribute("execution.id", execution_id)
723
+ evaluation_id = parent_span.attributes.get("evaluation.id") # type: ignore[attr-defined]
724
+ if evaluation_id:
725
+ span.set_attribute("evaluation.id", evaluation_id)
597
726
 
598
727
 
599
728
  class UiPathExecutionBatchTraceProcessor(
@@ -0,0 +1,84 @@
1
+ import json
2
+ from pathlib import Path
3
+ from typing import List, Optional
4
+
5
+ import click
6
+
7
+ from uipath._cli._evals._models import EvaluationSet
8
+ from uipath._cli._utils._console import ConsoleLogger
9
+
10
+ console = ConsoleLogger()
11
+
12
+
13
+ class EvalHelpers:
14
+ @staticmethod
15
+ def auto_discover_eval_set() -> str:
16
+ """Auto-discover evaluation set from evals/eval-sets directory.
17
+
18
+ Returns:
19
+ Path to the evaluation set file
20
+
21
+ Raises:
22
+ ValueError: If no eval set found or multiple eval sets exist
23
+ """
24
+ eval_sets_dir = Path("evals/eval-sets")
25
+
26
+ if not eval_sets_dir.exists():
27
+ raise ValueError(
28
+ "No 'evals/eval-sets' directory found. "
29
+ "Please set 'UIPATH_PROJECT_ID' env var and run 'uipath pull'."
30
+ )
31
+
32
+ eval_set_files = list(eval_sets_dir.glob("*.json"))
33
+
34
+ if not eval_set_files:
35
+ raise ValueError(
36
+ "No evaluation set files found in 'evals/eval-sets' directory. "
37
+ )
38
+
39
+ if len(eval_set_files) > 1:
40
+ file_names = [f.name for f in eval_set_files]
41
+ raise ValueError(
42
+ f"Multiple evaluation sets found: {file_names}. "
43
+ f"Please specify which evaluation set to use: 'uipath eval [entrypoint] <eval_set_path>'"
44
+ )
45
+
46
+ eval_set_path = str(eval_set_files[0])
47
+ console.info(
48
+ f"Auto-discovered evaluation set: {click.style(eval_set_path, fg='cyan')}"
49
+ )
50
+
51
+ eval_set_path_obj = Path(eval_set_path)
52
+ if not eval_set_path_obj.is_file() or eval_set_path_obj.suffix != ".json":
53
+ raise ValueError("Evaluation set must be a JSON file")
54
+
55
+ return eval_set_path
56
+
57
+ @staticmethod
58
+ def load_eval_set(
59
+ eval_set_path: str, eval_ids: Optional[List[str]] = None
60
+ ) -> EvaluationSet:
61
+ """Load the evaluation set from file.
62
+
63
+ Returns:
64
+ The loaded evaluation set as EvaluationSet model
65
+ """
66
+ try:
67
+ with open(eval_set_path, "r", encoding="utf-8") as f:
68
+ data = json.load(f)
69
+ except json.JSONDecodeError as e:
70
+ raise ValueError(
71
+ f"Invalid JSON in evaluation set file '{eval_set_path}': {str(e)}. "
72
+ f"Please check the file for syntax errors."
73
+ ) from e
74
+
75
+ try:
76
+ eval_set = EvaluationSet(**data)
77
+ except (TypeError, ValueError) as e:
78
+ raise ValueError(
79
+ f"Invalid evaluation set format in '{eval_set_path}': {str(e)}. "
80
+ f"Please verify the evaluation set structure."
81
+ ) from e
82
+ if eval_ids:
83
+ eval_set.extract_selected_evals(eval_ids)
84
+ return eval_set
uipath/_cli/cli_eval.py CHANGED
@@ -2,13 +2,22 @@
2
2
  import ast
3
3
  import asyncio
4
4
  import os
5
- from typing import List, Optional, Tuple
5
+ from datetime import datetime, timezone
6
+ from typing import List, Optional
6
7
 
7
8
  import click
8
9
 
10
+ from uipath._cli._evals._runtime import UiPathEvalContext, UiPathEvalRuntime
11
+ from uipath._cli._runtime._contracts import (
12
+ UiPathRuntimeContext,
13
+ UiPathRuntimeContextBuilder,
14
+ UiPathRuntimeFactory,
15
+ )
16
+ from uipath._cli._runtime._runtime import UiPathRuntime
17
+ from uipath._cli.middlewares import MiddlewareResult, Middlewares
18
+
9
19
  from .._utils.constants import ENV_JOB_ID
10
20
  from ..telemetry import track
11
- from ._evals.evaluation_service import EvaluationService
12
21
  from ._utils._console import ConsoleLogger
13
22
 
14
23
  console = ConsoleLogger()
@@ -22,48 +31,60 @@ class LiteralOption(click.Option):
22
31
  raise click.BadParameter(value) from e
23
32
 
24
33
 
25
- def eval_agent(
34
+ def eval_agent_middleware(
26
35
  entrypoint: Optional[str] = None,
27
36
  eval_set: Optional[str] = None,
28
37
  eval_ids: Optional[List[str]] = None,
29
38
  workers: int = 8,
30
39
  no_report: bool = False,
31
40
  **kwargs,
32
- ) -> Tuple[bool, Optional[str], Optional[str]]:
33
- """Core evaluation logic that can be called programmatically.
34
-
35
- Args:
36
- entrypoint: Path to the agent script to evaluate (optional, will auto-discover if not provided)
37
- eval_set: Path to the evaluation set JSON file (optional, will auto-discover if not provided)
38
- eval_ids: Optional list of evaluation IDs
39
- workers: Number of parallel workers for running evaluations
40
- no_report: Do not report the evaluation results
41
- **kwargs: Additional arguments for future extensibility
41
+ ) -> MiddlewareResult:
42
+ def generate_eval_context(
43
+ runtime_context: UiPathRuntimeContext,
44
+ ) -> UiPathEvalContext:
45
+ os.makedirs("evals/results", exist_ok=True)
46
+ timestamp = datetime.now(timezone.utc).strftime("%M-%H-%d-%m-%Y")
47
+ base_context = UiPathRuntimeContextBuilder().with_defaults().build()
48
+ # TODO: the name should include the eval_set name. those files should not be commited to SW
49
+ base_context.execution_output_file = (
50
+ f"evals/results/{timestamp}.json"
51
+ if not os.getenv("UIPATH_JOB_KEY")
52
+ else None
53
+ )
54
+ return UiPathEvalContext(
55
+ runtime_context=runtime_context,
56
+ no_report=no_report,
57
+ workers=workers,
58
+ eval_set=eval_set,
59
+ eval_ids=eval_ids,
60
+ **kwargs,
61
+ **base_context.model_dump(),
62
+ )
42
63
 
43
- Returns:
44
- Tuple containing:
45
- - success: True if evaluation was successful
46
- - error_message: Error message if any
47
- - info_message: Info message if any
48
- """
49
64
  try:
50
- if workers < 1:
51
- return False, "Number of workers must be at least 1", None
52
-
53
- print("EVAL SET")
54
- print(eval_set)
55
- if eval_set is not None and len(eval_set) == 0:
56
- return False, "Evaluation set must not be empty", None
57
-
58
- service = EvaluationService(
59
- entrypoint, eval_set, eval_ids, workers, report_progress=not no_report
65
+ runtime_factory = UiPathRuntimeFactory(UiPathRuntime, UiPathRuntimeContext)
66
+ context = (
67
+ UiPathRuntimeContextBuilder()
68
+ .with_defaults(**kwargs)
69
+ .with_entrypoint(entrypoint)
70
+ .with_entrypoint(entrypoint)
71
+ .mark_eval_run()
72
+ .build()
60
73
  )
61
- asyncio.run(service.run_evaluation())
62
74
 
63
- return True, None, "Evaluation completed successfully"
75
+ async def execute():
76
+ async with UiPathEvalRuntime.from_eval_context(
77
+ factory=runtime_factory, context=generate_eval_context(context)
78
+ ) as eval_runtime:
79
+ await eval_runtime.execute()
80
+
81
+ asyncio.run(execute())
82
+ return MiddlewareResult(should_continue=False)
64
83
 
65
84
  except Exception as e:
66
- return False, f"Error running evaluation: {str(e)}", None
85
+ return MiddlewareResult(
86
+ should_continue=False, error_message=f"Error running evaluation: {str(e)}"
87
+ )
67
88
 
68
89
 
69
90
  @click.command()
@@ -99,19 +120,29 @@ def eval(
99
120
  workers: Number of parallel workers for running evaluations
100
121
  no_report: Do not report the evaluation results
101
122
  """
102
- success, error_message, info_message = eval_agent(
103
- entrypoint=entrypoint,
104
- eval_set=eval_set,
105
- eval_ids=eval_ids,
106
- workers=workers,
123
+ result = Middlewares.next(
124
+ "eval",
125
+ entrypoint,
126
+ eval_set,
127
+ eval_ids,
107
128
  no_report=no_report,
129
+ workers=workers,
108
130
  )
109
- if error_message:
110
- console.error(error_message)
111
- click.get_current_context().exit(1)
112
131
 
113
- if info_message:
114
- console.success(info_message)
132
+ if result.should_continue:
133
+ result = eval_agent_middleware(
134
+ entrypoint=entrypoint,
135
+ eval_set=eval_set,
136
+ eval_ids=eval_ids,
137
+ workers=workers,
138
+ no_report=no_report,
139
+ )
140
+ if result.should_continue:
141
+ console.error("Could not process the request with any available handler.")
142
+ if result.error_message:
143
+ console.error(result.error_message)
144
+
145
+ console.success("Evaluation completed successfully")
115
146
 
116
147
 
117
148
  if __name__ == "__main__":
uipath/_cli/cli_run.py CHANGED
@@ -4,12 +4,10 @@ import os
4
4
  import traceback
5
5
  from os import environ as env
6
6
  from typing import Optional, Tuple
7
- from uuid import uuid4
8
7
 
9
8
  import click
10
9
 
11
10
  from uipath._cli._utils._debug import setup_debugging
12
- from uipath.tracing import LlmOpsHttpExporter
13
11
 
14
12
  from .._utils.constants import (
15
13
  ENV_JOB_ID,
@@ -17,9 +15,9 @@ from .._utils.constants import (
17
15
  from ..telemetry import track
18
16
  from ._runtime._contracts import (
19
17
  UiPathRuntimeContext,
18
+ UiPathRuntimeContextBuilder,
20
19
  UiPathRuntimeError,
21
20
  UiPathRuntimeFactory,
22
- UiPathTraceContext,
23
21
  )
24
22
  from ._runtime._runtime import UiPathRuntime
25
23
  from ._utils._console import ConsoleLogger
@@ -61,41 +59,17 @@ Usage: `uipath run <entrypoint_path> <input_arguments> [-f <input_json_file_path
61
59
  )
62
60
 
63
61
  try:
64
- context = UiPathRuntimeContext.from_config(
65
- env.get("UIPATH_CONFIG_PATH", "uipath.json"), **kwargs
66
- )
67
- context.entrypoint = entrypoint
68
- context.input = input
69
- context.resume = resume
70
- context.job_id = env.get("UIPATH_JOB_KEY")
71
- context.trace_id = env.get("UIPATH_TRACE_ID")
72
- context.input_file = kwargs.get("input_file", None)
73
- context.execution_output_file = kwargs.get("execution_output_file", None)
74
- context.is_eval_run = kwargs.get("is_eval_run", False)
75
- context.logs_min_level = env.get("LOG_LEVEL", "INFO")
76
- context.tracing_enabled = env.get("UIPATH_TRACING_ENABLED", True)
77
- context.trace_context = UiPathTraceContext(
78
- trace_id=env.get("UIPATH_TRACE_ID"),
79
- parent_span_id=env.get("UIPATH_PARENT_SPAN_ID"),
80
- root_span_id=env.get("UIPATH_ROOT_SPAN_ID"),
81
- enabled=env.get("UIPATH_TRACING_ENABLED", True),
82
- job_id=env.get("UIPATH_JOB_KEY"),
83
- org_id=env.get("UIPATH_ORGANIZATION_ID"),
84
- tenant_id=env.get("UIPATH_TENANT_ID"),
85
- process_key=env.get("UIPATH_PROCESS_UUID"),
86
- folder_key=env.get("UIPATH_FOLDER_KEY"),
87
- reference_id=env.get("UIPATH_JOB_KEY") or str(uuid4()),
88
- )
89
-
90
62
  runtime_factory = UiPathRuntimeFactory(UiPathRuntime, UiPathRuntimeContext)
63
+ context = (
64
+ UiPathRuntimeContextBuilder()
65
+ .with_defaults(**kwargs)
66
+ .with_entrypoint(entrypoint)
67
+ .with_input(input, input_file=kwargs.get("input_file"))
68
+ .with_resume(resume)
69
+ .build()
70
+ )
91
71
 
92
- if context.job_id:
93
- runtime_factory.add_span_exporter(LlmOpsHttpExporter())
94
-
95
- async def execute():
96
- await runtime_factory.execute(context)
97
-
98
- asyncio.run(execute())
72
+ asyncio.run(runtime_factory.execute(context))
99
73
 
100
74
  return MiddlewareResult(should_continue=False)
101
75
 
@@ -30,6 +30,7 @@ class Middlewares:
30
30
  "run": [],
31
31
  "dev": [],
32
32
  "invoke": [],
33
+ "eval": [],
33
34
  }
34
35
  _plugins_loaded = False
35
36