Skip to content

Commit 2b82871

Browse files
feat(agent/tools): finalize QuickForm escalation tool + display_name fallback
Fold the standalone QuickForm escalation tool into escalation_tool, and default the tool's display_name metadata to the channel name when the channel has no app_name (QuickForm). A None display_name previously broke automation-tracker OperationPayload validation downstream. Adds a test covering the QuickForm fallback. Bumps uipath-langchain to 0.11.14. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent 5113cad commit 2b82871

10 files changed

Lines changed: 320 additions & 296 deletions

File tree

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[project]
22
name = "uipath-langchain"
3-
version = "0.11.13"
3+
version = "0.11.14"
44
description = "Python SDK that enables developers to build and deploy LangGraph agents to the UiPath Cloud Platform"
55
readme = { file = "README.md", content-type = "text/markdown" }
66
requires-python = ">=3.11"

src/uipath_langchain/agent/tools/__init__.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88
from .ixp_escalation_tool import create_ixp_escalation_tool
99
from .mcp import open_mcp_tools
1010
from .process_tool import create_process_tool
11-
from .quick_form_escalation_tool import create_quick_form_escalation_tool
1211
from .tool_factory import (
1312
create_tools_from_resources,
1413
)
@@ -33,7 +32,6 @@
3332
"create_escalation_tool",
3433
"create_ixp_extraction_tool",
3534
"create_ixp_escalation_tool",
36-
"create_quick_form_escalation_tool",
3735
"UiPathToolNode",
3836
"RunnableCallableWithTool",
3937
"ToolWrapperMixin",

src/uipath_langchain/agent/tools/escalation_memory.py

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,9 @@
77
from uuid import UUID
88

99
from pydantic import BaseModel, ConfigDict, Field, ValidationError, field_validator
10-
from uipath.agent.models.agent import AgentEscalationResourceConfig
10+
from uipath.agent.models.agent import (
11+
AgentEscalationResourceConfig,
12+
)
1113
from uipath.platform import UiPath
1214
from uipath.platform.common import UiPathConfig
1315
from uipath.platform.common._bindings import _resource_overwrites
@@ -360,7 +362,9 @@ def _get_escalation_memory_settings(
360362
return _coerce_memory_settings(memory)
361363

362364

363-
def _is_escalation_memory_enabled(resource: AgentEscalationResourceConfig) -> bool:
365+
def _is_escalation_memory_enabled(
366+
resource: AgentEscalationResourceConfig,
367+
) -> bool:
364368
memory = _get_escalation_memory_properties(resource)
365369
memory_enabled = _read_value(memory, "isEnabled", "is_enabled")
366370
if memory_enabled is not None:
@@ -370,7 +374,9 @@ def _is_escalation_memory_enabled(resource: AgentEscalationResourceConfig) -> bo
370374
)
371375

372376

373-
def _get_escalation_memory_properties(resource: AgentEscalationResourceConfig) -> Any:
377+
def _get_escalation_memory_properties(
378+
resource: AgentEscalationResourceConfig,
379+
) -> Any:
374380
properties = _read_value(resource, "properties")
375381
return _read_value(properties, "memory") if properties is not None else None
376382

src/uipath_langchain/agent/tools/escalation_tool.py

Lines changed: 49 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
AgentEscalationRecipient,
1515
AgentEscalationRecipientType,
1616
AgentEscalationResourceConfig,
17+
AgentQuickFormEscalationChannel,
1718
ArgumentEmailRecipient,
1819
ArgumentGroupNameRecipient,
1920
AssetRecipient,
@@ -254,10 +255,19 @@ def create_escalation_tool(
254255
resource: AgentEscalationResourceConfig,
255256
agent: LowCodeAgentDefinition | None = None,
256257
) -> StructuredTool:
257-
"""Uses interrupt() for Action Center human-in-the-loop."""
258+
"""Uses interrupt() for Action Center human-in-the-loop.
259+
260+
Handles both Action Center app-task channels (``actionCenter``) and
261+
quick-form channels (``actionCenterQuickForm``). Quick-form channels render
262+
a schema-first FormLib task via
263+
:meth:`uipath.platform.action_center.tasks.TasksService.create_quickform_async`
264+
using ``channel.properties.schema`` instead of dispatching to an Action
265+
Center app.
266+
"""
258267

259268
tool_name: str = f"escalate_{sanitize_tool_name(resource.name)}"
260269
channel: AgentEscalationChannel = resource.channels[0]
270+
is_quick_form = isinstance(channel, AgentQuickFormEscalationChannel)
261271

262272
input_model: Any = create_model(channel.input_schema)
263273
output_model: Any = create_model(channel.output_schema)
@@ -327,25 +337,50 @@ async def escalate(**_tool_kwargs: Any):
327337
@durable_interrupt
328338
async def create_escalation_task():
329339
client = UiPath()
330-
created_task = await client.tasks.create_async(
331-
title=task_title,
332-
data=serialized_data,
333-
app_name=channel.properties.app_name,
334-
app_folder_path=folder_path,
335-
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,
340-
)
340+
if isinstance(channel, AgentQuickFormEscalationChannel):
341+
schema_id = channel.properties.schema_id
342+
if schema_id is None:
343+
raise AgentRuntimeError(
344+
code=AgentRuntimeErrorCode.TERMINATION_ESCALATION_ERROR,
345+
title="Quick form escalation is missing a schema id",
346+
detail=(
347+
f"Escalation '{resource.name}' has a quick form "
348+
"schema without a schemaId."
349+
),
350+
category=UiPathErrorCategory.USER,
351+
)
352+
created_task = await client.tasks.create_quickform_async(
353+
title=task_title,
354+
task_schema_key=schema_id,
355+
schema=channel.properties.schema,
356+
data=serialized_data,
357+
folder_path=folder_path,
358+
recipient=recipient,
359+
priority=channel.priority,
360+
labels=channel.labels,
361+
is_actionable_message_enabled=channel.properties.is_actionable_message_enabled,
362+
actionable_message_metadata=channel.properties.actionable_message_meta_data,
363+
)
364+
else:
365+
created_task = await client.tasks.create_async(
366+
title=task_title,
367+
data=serialized_data,
368+
app_name=channel.properties.app_name,
369+
app_folder_path=folder_path,
370+
recipient=recipient,
371+
priority=channel.priority,
372+
labels=channel.labels,
373+
is_actionable_message_enabled=channel.properties.is_actionable_message_enabled,
374+
actionable_message_metadata=channel.properties.actionable_message_meta_data,
375+
)
341376

342377
if created_task.id is not None:
343378
_bts_context["task_key"] = str(created_task.id)
344379

345380
return WaitEscalation(
346381
action=created_task,
347382
app_folder_path=folder_path,
348-
app_name=channel.properties.app_name,
383+
app_name=None if is_quick_form else channel.properties.app_name,
349384
recipient=recipient,
350385
)
351386

@@ -487,7 +522,7 @@ async def escalation_wrapper(
487522
argument_properties=channel.argument_properties,
488523
metadata={
489524
"tool_type": "escalation",
490-
"display_name": channel.properties.app_name,
525+
"display_name": channel.properties.app_name or channel.name,
491526
"channel_type": channel.type,
492527
"recipient": None,
493528
"args_schema": input_model,

0 commit comments

Comments
 (0)