1414 AgentEscalationRecipient ,
1515 AgentEscalationRecipientType ,
1616 AgentEscalationResourceConfig ,
17+ AgentQuickFormEscalationChannel ,
1718 ArgumentEmailRecipient ,
1819 ArgumentGroupNameRecipient ,
1920 AssetRecipient ,
21+ EscalationChannel ,
2022 LowCodeAgentDefinition ,
2123 StandardRecipient ,
2224)
3739 StructuredToolWithArgumentProperties ,
3840)
3941
40- from ..exceptions import AgentRuntimeError , AgentRuntimeErrorCode
42+ from ..exceptions import (
43+ AgentRuntimeError ,
44+ AgentRuntimeErrorCode ,
45+ AgentStartupError ,
46+ AgentStartupErrorCode ,
47+ )
4148from ..react .types import AgentGraphState
4249from .escalation_memory import (
4350 EscalationMemorySettings ,
@@ -250,14 +257,79 @@ def _get_exported_trace_id(trace_id: str | None) -> str | None:
250257 return trace_id
251258
252259
260+ def _try_get_channel_app_name (channel : EscalationChannel ) -> str | None :
261+ return (
262+ channel .properties .app_name
263+ if isinstance (channel , AgentEscalationChannel )
264+ else None
265+ )
266+
267+
268+ async def create_task_for_channel (
269+ client : UiPath ,
270+ channel : EscalationChannel ,
271+ * ,
272+ title : str ,
273+ data : dict [str , Any ],
274+ recipient : TaskRecipient | None ,
275+ folder_path : str | None ,
276+ ) -> Task :
277+ """Create the human task backing an escalation channel."""
278+ if isinstance (channel , AgentQuickFormEscalationChannel ):
279+ schema_id = channel .properties .schema_id
280+ assert schema_id is not None
281+ return await client .tasks .create_quickform_async (
282+ title = title ,
283+ task_schema_key = schema_id ,
284+ schema = channel .properties .form_schema ,
285+ data = data ,
286+ folder_path = folder_path ,
287+ recipient = recipient ,
288+ priority = channel .priority ,
289+ labels = channel .labels ,
290+ is_actionable_message_enabled = channel .properties .is_actionable_message_enabled ,
291+ actionable_message_metadata = channel .properties .actionable_message_meta_data ,
292+ )
293+ return await client .tasks .create_async (
294+ title = title ,
295+ data = data ,
296+ app_name = channel .properties .app_name ,
297+ app_folder_path = folder_path ,
298+ recipient = recipient ,
299+ priority = channel .priority ,
300+ labels = channel .labels ,
301+ is_actionable_message_enabled = channel .properties .is_actionable_message_enabled ,
302+ actionable_message_metadata = channel .properties .actionable_message_meta_data ,
303+ )
304+
305+
306+ def _resolve_channel (resource : AgentEscalationResourceConfig ) -> EscalationChannel :
307+ """Return the escalation's channel, validating quick-form configuration."""
308+ channel = resource .channels [0 ]
309+ if (
310+ isinstance (channel , AgentQuickFormEscalationChannel )
311+ and channel .properties .schema_id is None
312+ ):
313+ raise AgentStartupError (
314+ code = AgentStartupErrorCode .INVALID_TOOL_CONFIG ,
315+ title = "Quick form escalation is missing a schema id" ,
316+ detail = (
317+ f"Escalation '{ channel .name } ' has a quick form "
318+ "schema without a schemaId."
319+ ),
320+ category = UiPathErrorCategory .USER ,
321+ )
322+ return channel
323+
324+
253325def create_escalation_tool (
254326 resource : AgentEscalationResourceConfig ,
255327 agent : LowCodeAgentDefinition | None = None ,
256328) -> StructuredTool :
257- """Uses interrupt() for Action Center human-in-the-loop."""
329+ """Build the human-in-the-loop escalation tool for an escalation resource ."""
258330
259331 tool_name : str = f"escalate_{ sanitize_tool_name (resource .name )} "
260- channel : AgentEscalationChannel = resource . channels [ 0 ]
332+ channel : EscalationChannel = _resolve_channel ( resource )
261333
262334 input_model : Any = create_model (channel .input_schema )
263335 output_model : Any = create_model (channel .output_schema )
@@ -327,16 +399,13 @@ async def escalate(**_tool_kwargs: Any):
327399 @durable_interrupt
328400 async def create_escalation_task ():
329401 client = UiPath ()
330- created_task = await client .tasks .create_async (
402+ created_task = await create_task_for_channel (
403+ client ,
404+ channel ,
331405 title = task_title ,
332406 data = serialized_data ,
333- app_name = channel .properties .app_name ,
334- app_folder_path = folder_path ,
335407 recipient = recipient ,
336- priority = channel .priority ,
337- labels = channel .labels ,
338- is_actionable_message_enabled = channel .properties .is_actionable_message_enabled ,
339- actionable_message_metadata = channel .properties .actionable_message_meta_data ,
408+ folder_path = folder_path ,
340409 )
341410
342411 if created_task .id is not None :
@@ -345,7 +414,7 @@ async def create_escalation_task():
345414 return WaitEscalation (
346415 action = created_task ,
347416 app_folder_path = folder_path ,
348- app_name = channel . properties . app_name ,
417+ app_name = _try_get_channel_app_name ( channel ) ,
349418 recipient = recipient ,
350419 )
351420
@@ -487,7 +556,7 @@ async def escalation_wrapper(
487556 argument_properties = channel .argument_properties ,
488557 metadata = {
489558 "tool_type" : "escalation" ,
490- "display_name" : channel . properties . app_name ,
559+ "display_name" : _try_get_channel_app_name ( channel ) or channel . name ,
491560 "channel_type" : channel .type ,
492561 "recipient" : None ,
493562 "args_schema" : input_model ,
0 commit comments