Skip to content

Commit e6b0b08

Browse files
committed
feat(action_flag): add option to get the whole action
1 parent fbcd73f commit e6b0b08

File tree

4 files changed

+69
-1
lines changed

4 files changed

+69
-1
lines changed

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"
3-
version = "2.1.84"
3+
version = "2.1.85"
44
description = "Python SDK and CLI for UiPath Platform, enabling programmatic interaction with automation services, process management, and deployment tools."
55
readme = { file = "README.md", content-type = "text/markdown" }
66
requires-python = ">=3.10"

src/uipath/_cli/_runtime/_hitl.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,13 +62,24 @@ async def read(cls, resume_trigger: UiPathResumeTrigger) -> Optional[str]:
6262
default_escalation = Escalation()
6363
match resume_trigger.trigger_type:
6464
case UiPathResumeTriggerType.ACTION:
65+
include_metadata = False
66+
if resume_trigger.payload:
67+
try:
68+
payload_data = json.loads(resume_trigger.payload)
69+
include_metadata = payload_data.get("include_metadata", False)
70+
except (json.JSONDecodeError, AttributeError):
71+
include_metadata = False
72+
6573
if resume_trigger.item_key:
6674
action = await uipath.actions.retrieve_async(
6775
resume_trigger.item_key,
6876
app_folder_key=resume_trigger.folder_key,
6977
app_folder_path=resume_trigger.folder_path,
7078
)
7179

80+
if include_metadata:
81+
return action
82+
7283
if default_escalation.enabled:
7384
return default_escalation.extract_response_value(action.data)
7485

src/uipath/models/interrupt_models.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,11 @@ class CreateAction(BaseModel):
2828
app_folder_key: Optional[str] = None
2929
app_key: Optional[str] = None
3030
app_version: Optional[int] = 1
31+
include_metadata: bool = False
3132

3233

3334
class WaitAction(BaseModel):
3435
action: Action
3536
app_folder_path: Optional[str] = None
3637
app_folder_key: Optional[str] = None
38+
include_metadata: bool = False

tests/cli/test_hitl.py

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import json
12
import uuid
23
from unittest.mock import AsyncMock, patch
34

@@ -312,3 +313,57 @@ async def test_create_resume_trigger_api(
312313
assert resume_trigger.api_resume is not None
313314
assert isinstance(resume_trigger.api_resume.inbox_id, str)
314315
assert resume_trigger.api_resume.request == api_input
316+
317+
@pytest.mark.anyio
318+
async def test_interrupt_with_include_metadata_true_returns_full_action(
319+
self,
320+
setup_test_env: None,
321+
) -> None:
322+
"""Test that interrupt() with include_metadata=True returns the whole action object."""
323+
action_key = "test-action-key"
324+
325+
# Create an action with include_metadata=True
326+
create_action = CreateAction(
327+
title="Test Action",
328+
app_name="TestApp",
329+
app_folder_path="/test/path",
330+
data={"input": "test-input"},
331+
include_metadata=True,
332+
)
333+
334+
# Mock the action that would be retrieved after user interaction
335+
mock_action = Action(
336+
key=action_key,
337+
action="Reject",
338+
data={"input": "test-input"},
339+
status=2,
340+
title="Test Action",
341+
id=12345,
342+
)
343+
344+
with (
345+
patch(
346+
"uipath._services.actions_service.ActionsService.create_async"
347+
) as mock_create,
348+
patch(
349+
"uipath._services.actions_service.ActionsService.retrieve_async"
350+
) as mock_retrieve,
351+
):
352+
mock_create.return_value = Action(key=action_key)
353+
mock_retrieve.return_value = mock_action
354+
355+
# Simulate interrupt()
356+
processor = HitlProcessor(create_action)
357+
resume_trigger = await processor.create_resume_trigger()
358+
if isinstance(resume_trigger.payload, dict):
359+
resume_trigger.payload = json.dumps(resume_trigger.payload)
360+
361+
action_data = await HitlReader.read(resume_trigger)
362+
363+
# verify we got the whole action object
364+
assert isinstance(action_data, Action)
365+
assert action_data.action == "Reject", "Should contain 'action' field"
366+
assert action_data.data == {"input": "test-input"}, (
367+
"Should contain correct 'data' field"
368+
)
369+
assert action_data != mock_action.data

0 commit comments

Comments
 (0)