1111
1212from ..._events ._event_bus import EventBus
1313from ..._events ._events import (
14+ EvalItemExceptionDetails ,
1415 EvalRunCreatedEvent ,
1516 EvalRunUpdatedEvent ,
1617 EvalSetRunCreatedEvent ,
3132from .._utils ._eval_set import EvalHelpers
3233from ._evaluator_factory import EvaluatorFactory
3334from ._models ._evaluation_set import EvaluationItem , EvaluationSet
35+ from ._models ._exceptions import EvaluationRuntimeException
3436from ._models ._output import (
3537 EvaluationResultDto ,
3638 EvaluationRunResult ,
@@ -232,8 +234,7 @@ async def execute(self) -> Optional[UiPathRuntimeResult]:
232234 wait_for_completion = False ,
233235 )
234236 except Exception as e :
235- error_msg = str (e )
236- eval_item ._error_message = error_msg # type: ignore[attr-defined]
237+ exception_details = EvalItemExceptionDetails (exception = e )
237238
238239 for evaluator in evaluators :
239240 evaluator_counts [evaluator .id ] += 1
@@ -242,18 +243,28 @@ async def execute(self) -> Optional[UiPathRuntimeResult]:
242243 0.0 - evaluator_averages [evaluator .id ]
243244 ) / count
244245
246+ eval_run_updated_event = EvalRunUpdatedEvent (
247+ execution_id = self .execution_id ,
248+ eval_item = eval_item ,
249+ eval_results = [],
250+ success = False ,
251+ agent_output = {},
252+ agent_execution_time = 0.0 ,
253+ exception_details = exception_details ,
254+ spans = [],
255+ logs = [],
256+ )
257+ if isinstance (e , EvaluationRuntimeException ):
258+ eval_run_updated_event .spans = e .spans
259+ eval_run_updated_event .logs = e .logs
260+ eval_run_updated_event .exception_details .exception = ( # type: ignore
261+ e .root_exception
262+ )
263+ eval_run_updated_event .exception_details .runtime_exception = True # type: ignore
264+
245265 await event_bus .publish (
246266 EvaluationEvents .UPDATE_EVAL_RUN ,
247- EvalRunUpdatedEvent (
248- execution_id = self .execution_id ,
249- eval_item = eval_item ,
250- eval_results = [],
251- success = False ,
252- agent_output = {},
253- agent_execution_time = 0.0 ,
254- spans = [],
255- logs = [],
256- ),
267+ eval_run_updated_event ,
257268 wait_for_completion = False ,
258269 )
259270
@@ -274,6 +285,17 @@ async def execute(self) -> Optional[UiPathRuntimeResult]:
274285 )
275286 return self .context .result
276287
288+ def _get_and_clear_execution_data (
289+ self , execution_id : str
290+ ) -> tuple [List [ReadableSpan ], list [logging .LogRecord ]]:
291+ spans = self .span_exporter .get_spans (execution_id )
292+ self .span_exporter .clear (execution_id )
293+
294+ logs = self .logs_exporter .get_logs (execution_id )
295+ self .logs_exporter .clear (execution_id )
296+
297+ return spans , logs
298+
277299 async def execute_runtime (
278300 self , eval_item : EvaluationItem
279301 ) -> UiPathEvalRunExecutionOutput :
@@ -284,6 +306,9 @@ async def execute_runtime(
284306 is_eval_run = True ,
285307 log_handler = self ._setup_execution_logging (eval_item_id ),
286308 )
309+ if runtime_context .execution_id is None :
310+ raise ValueError ("execution_id must be set for eval runs" )
311+
287312 attributes = {
288313 "evalId" : eval_item .id ,
289314 "span_type" : "eval" ,
@@ -292,21 +317,22 @@ async def execute_runtime(
292317 attributes ["execution.id" ] = runtime_context .execution_id
293318
294319 start_time = time ()
295-
296- result = await self .factory .execute_in_root_span (
297- runtime_context , root_span = eval_item .name , attributes = attributes
298- )
320+ try :
321+ result = await self .factory .execute_in_root_span (
322+ runtime_context , root_span = eval_item .name , attributes = attributes
323+ )
324+ except Exception as e :
325+ spans , logs = self ._get_and_clear_execution_data (
326+ runtime_context .execution_id
327+ )
328+ raise EvaluationRuntimeException (
329+ spans = spans ,
330+ logs = logs ,
331+ root_exception = e ,
332+ ) from e
299333
300334 end_time = time ()
301-
302- if runtime_context .execution_id is None :
303- raise ValueError ("execution_id must be set for eval runs" )
304-
305- spans = self .span_exporter .get_spans (runtime_context .execution_id )
306- self .span_exporter .clear (runtime_context .execution_id )
307-
308- logs = self .logs_exporter .get_logs (runtime_context .execution_id )
309- self .logs_exporter .clear (runtime_context .execution_id )
335+ spans , logs = self ._get_and_clear_execution_data (runtime_context .execution_id )
310336
311337 if result is None :
312338 raise ValueError ("Execution result cannot be None for eval runs" )
0 commit comments