@@ -31,6 +31,22 @@ def process_resource():
3131 )
3232
3333
34+ @pytest .fixture
35+ def flow_resource ():
36+ """Create a process tool resource config of type Flow (Maestro Flow release)."""
37+ return AgentProcessToolResourceConfig (
38+ type = AgentToolType .FLOW ,
39+ name = "test_flow" ,
40+ description = "Test flow description" ,
41+ input_schema = {"type" : "object" , "properties" : {}},
42+ output_schema = {"type" : "object" , "properties" : {}},
43+ properties = AgentProcessToolProperties (
44+ process_name = "MyFlow" ,
45+ folder_path = "/Shared/Flows" ,
46+ ),
47+ )
48+
49+
3450@pytest .fixture
3551def process_resource_with_inputs ():
3652 """Create a process tool resource config with input arguments."""
@@ -453,3 +469,84 @@ async def test_run_as_me_default_sends_none(
453469
454470 call_kwargs = mock_client .processes .invoke_async .call_args [1 ]
455471 assert call_kwargs ["run_as_me" ] is None
472+
473+
474+ class TestProcessToolFlowType :
475+ """Test that a Flow-type resource flows through create_process_tool correctly."""
476+
477+ def test_flow_tool_metadata_has_flow_tool_type (self , flow_resource ):
478+ """A Flow resource produces a tool with metadata.tool_type == 'flow'."""
479+ tool = create_process_tool (flow_resource )
480+ assert tool .metadata is not None
481+ assert tool .metadata ["tool_type" ] == "flow"
482+
483+ def test_flow_tool_metadata_has_display_name (self , flow_resource ):
484+ """Flow tool metadata exposes the process_name as display_name."""
485+ tool = create_process_tool (flow_resource )
486+ assert tool .metadata is not None
487+ assert tool .metadata ["display_name" ] == "MyFlow"
488+
489+ @pytest .mark .asyncio
490+ @patch .dict (os .environ , {"UIPATH_FOLDER_PATH" : "/Shared/Flows" })
491+ @patch ("uipath_langchain._utils.durable_interrupt.decorator.interrupt" )
492+ @patch ("uipath_langchain.agent.tools.process_tool.UiPath" )
493+ async def test_flow_tool_invokes_processes_invoke_async (
494+ self , mock_uipath_class , mock_interrupt , flow_resource
495+ ):
496+ """Flow tool invokes client.processes.invoke_async (same path as Process)."""
497+ mock_job = MagicMock (spec = Job )
498+ mock_job .key = "flow-job-key"
499+ mock_job .folder_key = "flow-folder-key"
500+
501+ mock_resumed_job = MagicMock (spec = Job )
502+ mock_resumed_job .state = "successful"
503+
504+ mock_client = MagicMock ()
505+ mock_client .processes .invoke_async = AsyncMock (return_value = mock_job )
506+ mock_client .jobs .extract_output_async = AsyncMock (return_value = None )
507+ mock_uipath_class .return_value = mock_client
508+
509+ mock_interrupt .return_value = mock_resumed_job
510+
511+ tool = create_process_tool (flow_resource )
512+ await tool .ainvoke ({})
513+
514+ mock_client .processes .invoke_async .assert_called_once_with (
515+ name = "MyFlow" ,
516+ input_arguments = {},
517+ folder_path = "/Shared/Flows" ,
518+ attachments = [],
519+ parent_span_id = None ,
520+ parent_operation_id = None ,
521+ run_as_me = None ,
522+ )
523+
524+ @pytest .mark .asyncio
525+ @patch ("uipath_langchain._utils.durable_interrupt.decorator.interrupt" )
526+ @patch ("uipath_langchain.agent.tools.process_tool.UiPath" )
527+ async def test_flow_tool_uses_non_agent_bts_key (
528+ self , mock_uipath_class , mock_interrupt , flow_resource
529+ ):
530+ """Flow tool stores the BTS tracking key under 'wait_for_job_key' (not agent variant)."""
531+ mock_job = MagicMock (spec = Job )
532+ mock_job .key = "flow-job-key"
533+ mock_job .folder_key = "flow-folder-key"
534+
535+ mock_resumed_job = MagicMock (spec = Job )
536+ mock_resumed_job .state = "successful"
537+
538+ mock_client = MagicMock ()
539+ mock_client .processes .invoke_async = AsyncMock (return_value = mock_job )
540+ mock_client .jobs .extract_output_async = AsyncMock (return_value = None )
541+ mock_uipath_class .return_value = mock_client
542+
543+ mock_interrupt .return_value = mock_resumed_job
544+
545+ tool = create_process_tool (flow_resource )
546+ assert tool .metadata is not None
547+
548+ await tool .ainvoke ({})
549+
550+ bts_context = tool .metadata ["_bts_context" ]
551+ assert bts_context .get ("wait_for_job_key" ) == "flow-job-key"
552+ assert "wait_for_agent_job_key" not in bts_context
0 commit comments