33import json
44import os
55import uuid
6+ from functools import cache
67from typing import Any
78
89from uipath .core .errors import (
4950 WaitJobRaw ,
5051 WaitSystemAgent ,
5152 WaitTask ,
53+ WaitUntil ,
5254)
5355from uipath .platform .connections import EventArguments
5456from uipath .platform .context_grounding import DeepRagStatus , IndexStatus
@@ -129,12 +131,18 @@ async def read_trigger(self, trigger: UiPathResumeTrigger) -> Any | None:
129131 UiPathRuntimeError: If reading fails, job failed, API connection failed,
130132 trigger type is unknown, or HITL feedback retrieval failed.
131133 """
132- uipath = UiPath ()
134+
135+ @cache
136+ def get_uipath () -> UiPath :
137+ return UiPath ()
133138
134139 match trigger .trigger_type :
140+ case UiPathResumeTriggerType .TIMER :
141+ return {"resumeTime" : serialize_object (trigger .resume_time )}
142+
135143 case UiPathResumeTriggerType .TASK :
136144 if trigger .item_key :
137- task : Task = await uipath .tasks .retrieve_async (
145+ task : Task = await get_uipath () .tasks .retrieve_async (
138146 trigger .item_key ,
139147 app_folder_key = trigger .folder_key ,
140148 app_folder_path = trigger .folder_path ,
@@ -182,7 +190,7 @@ async def read_trigger(self, trigger: UiPathResumeTrigger) -> Any | None:
182190
183191 case UiPathResumeTriggerType .JOB :
184192 if trigger .item_key :
185- job = await uipath .jobs .retrieve_async (
193+ job = await get_uipath () .jobs .retrieve_async (
186194 trigger .item_key ,
187195 folder_key = trigger .folder_key ,
188196 folder_path = trigger .folder_path ,
@@ -223,7 +231,7 @@ async def read_trigger(self, trigger: UiPathResumeTrigger) -> Any | None:
223231 f"Process did not finish successfully. Error: { job_error } " ,
224232 )
225233
226- output_data = await uipath .jobs .extract_output_async (job )
234+ output_data = await get_uipath () .jobs .extract_output_async (job )
227235 trigger_response = _try_convert_to_json_format (output_data )
228236
229237 # if response is an empty dictionary, use job state as placeholder value
@@ -239,9 +247,13 @@ async def read_trigger(self, trigger: UiPathResumeTrigger) -> Any | None:
239247 return trigger_response
240248 case UiPathResumeTriggerType .DEEP_RAG :
241249 if trigger .item_key :
242- deep_rag = await uipath .context_grounding .retrieve_deep_rag_async (
243- trigger .item_key ,
244- index_name = self ._extract_field ("index_name" , trigger .payload ),
250+ deep_rag = (
251+ await get_uipath ().context_grounding .retrieve_deep_rag_async (
252+ trigger .item_key ,
253+ index_name = self ._extract_field (
254+ "index_name" , trigger .payload
255+ ),
256+ )
245257 )
246258 deep_rag_status = deep_rag .last_deep_rag_status
247259
@@ -279,7 +291,7 @@ async def read_trigger(self, trigger: UiPathResumeTrigger) -> Any | None:
279291
280292 case UiPathResumeTriggerType .INDEX_INGESTION :
281293 if trigger .item_key :
282- index = await uipath .context_grounding .retrieve_by_id_async (
294+ index = await get_uipath () .context_grounding .retrieve_by_id_async (
283295 trigger .item_key
284296 )
285297
@@ -319,7 +331,7 @@ async def read_trigger(self, trigger: UiPathResumeTrigger) -> Any | None:
319331 )
320332 assert destination_path is not None
321333 try :
322- await uipath .context_grounding .download_batch_transform_result_async (
334+ await get_uipath () .context_grounding .download_batch_transform_result_async (
323335 trigger .item_key ,
324336 destination_path ,
325337 validate_status = True ,
@@ -349,10 +361,8 @@ async def read_trigger(self, trigger: UiPathResumeTrigger) -> Any | None:
349361 assert tag is not None
350362
351363 try :
352- extraction_response = (
353- await uipath .documents .retrieve_ixp_extraction_result_async (
354- project_id , tag , trigger .item_key
355- )
364+ extraction_response = await get_uipath ().documents .retrieve_ixp_extraction_result_async (
365+ project_id , tag , trigger .item_key
356366 )
357367 except OperationNotCompleteException as e :
358368 raise UiPathPendingTriggerError (
@@ -370,7 +380,7 @@ async def read_trigger(self, trigger: UiPathResumeTrigger) -> Any | None:
370380 assert project_id is not None
371381 assert tag is not None
372382 try :
373- escalation_response = await uipath .documents .retrieve_ixp_extraction_validation_result_async (
383+ escalation_response = await get_uipath () .documents .retrieve_ixp_extraction_validation_result_async (
374384 project_id , tag , trigger .item_key
375385 )
376386 except OperationNotCompleteException as e :
@@ -394,7 +404,7 @@ async def read_trigger(self, trigger: UiPathResumeTrigger) -> Any | None:
394404 case UiPathResumeTriggerType .API :
395405 if trigger .api_resume and trigger .api_resume .inbox_id :
396406 try :
397- return await uipath .jobs .retrieve_api_payload_async (
407+ return await get_uipath () .jobs .retrieve_api_payload_async (
398408 trigger .api_resume .inbox_id
399409 )
400410 except Exception as e :
@@ -407,12 +417,16 @@ async def read_trigger(self, trigger: UiPathResumeTrigger) -> Any | None:
407417 case UiPathResumeTriggerType .INBOX :
408418 if trigger .integration_resume and trigger .integration_resume .inbox_id :
409419 try :
410- inbox_payload = await uipath .jobs .retrieve_inbox_payload_async (
411- trigger .integration_resume .inbox_id
420+ inbox_payload = (
421+ await get_uipath ().jobs .retrieve_inbox_payload_async (
422+ trigger .integration_resume .inbox_id
423+ )
412424 )
413425 event_args = EventArguments .model_validate (inbox_payload )
414- return await uipath .connections .retrieve_event_payload_async (
415- event_args
426+ return (
427+ await get_uipath ().connections .retrieve_event_payload_async (
428+ event_args
429+ )
416430 )
417431 except Exception as e :
418432 raise UiPathFaultedTriggerError (
@@ -484,6 +498,9 @@ async def create_trigger(self, suspend_value: Any) -> UiPathResumeTrigger:
484498 case UiPathResumeTriggerType .INBOX :
485499 await self ._handle_inbox_trigger (suspend_value , resume_trigger )
486500
501+ case UiPathResumeTriggerType .TIMER :
502+ self ._handle_time_trigger (suspend_value , resume_trigger )
503+
487504 case UiPathResumeTriggerType .DEEP_RAG :
488505 await self ._handle_deep_rag_job_trigger (
489506 suspend_value , resume_trigger
@@ -570,6 +587,8 @@ def _determine_trigger_type(self, value: Any) -> UiPathResumeTriggerType:
570587 return UiPathResumeTriggerType .IXP_VS_ESCALATION
571588 if isinstance (value , WaitIntegrationEvent ):
572589 return UiPathResumeTriggerType .INBOX
590+ if isinstance (value , WaitUntil ):
591+ return UiPathResumeTriggerType .TIMER
573592 # default to API trigger
574593 return UiPathResumeTriggerType .API
575594
@@ -606,6 +625,8 @@ def _determine_trigger_name(self, value: Any) -> UiPathResumeTriggerName:
606625 return UiPathResumeTriggerName .EXTRACTION
607626 if isinstance (value , WaitIntegrationEvent ):
608627 return UiPathResumeTriggerName .INBOX
628+ if isinstance (value , WaitUntil ):
629+ return UiPathResumeTriggerName .TIMER
609630 # default to API trigger
610631 return UiPathResumeTriggerName .API
611632
@@ -979,6 +1000,20 @@ async def _handle_inbox_trigger(
9791000 inbox_id = str (uuid .uuid4 ()),
9801001 )
9811002
1003+ def _handle_time_trigger (
1004+ self , value : WaitUntil , resume_trigger : UiPathResumeTrigger
1005+ ) -> None :
1006+ """Handle Timer-type resume triggers.
1007+
1008+ Orchestrator expects timer resume triggers as a top-level
1009+ `resumeTime` value on the resume trigger DTO.
1010+
1011+ Args:
1012+ value: The suspend value (WaitUntil)
1013+ resume_trigger: The resume trigger to populate
1014+ """
1015+ resume_trigger .resume_time = value .resume_time
1016+
9821017
9831018class UiPathResumeTriggerHandler :
9841019 """Combined handler for creating and reading resume triggers.
0 commit comments