"""Tests de l'action pause_for_human (C.5). Vérifie la chaîne : - Validation côté replay_engine accepte le nouveau type - Conversion edge → action normalisée préserve le message - Bridge VWB → core mappe correctement - Le bridge VWB construit bien un edge avec action.type='pause_for_human' """ from agent_v0.server_v1.replay_engine import ( _ALLOWED_ACTION_TYPES, _validate_replay_action, _edge_to_normalized_actions, ) from visual_workflow_builder.backend.services.learned_workflow_bridge import ( VWB_ACTION_TO_CORE, convert_vwb_to_core_workflow, _vwb_params_to_core, ) # ---------------------------------------------------------------------- # Validation pipeline (replay_engine) # ---------------------------------------------------------------------- def test_pause_for_human_in_allowed_types(): assert "pause_for_human" in _ALLOWED_ACTION_TYPES def test_validate_pause_for_human_action_valid(): action = {"type": "pause_for_human", "parameters": {"message": "Valider UHCD ?"}} assert _validate_replay_action(action) is None def test_validate_pause_for_human_no_params_still_valid(): """Le validateur ne doit pas exiger 'message' (fallback côté handler).""" action = {"type": "pause_for_human"} assert _validate_replay_action(action) is None # ---------------------------------------------------------------------- # Conversion edge → action normalisée # ---------------------------------------------------------------------- class _FakeAction: def __init__(self, type_, parameters=None): self.type = type_ self.target = None self.parameters = parameters or {} class _FakeEdge: def __init__(self, action, edge_id="e1", from_node="n1", to_node="n2"): self.edge_id = edge_id self.from_node = from_node self.to_node = to_node self.action = action def test_edge_to_action_pause_for_human_preserves_message(): edge = _FakeEdge(_FakeAction( "pause_for_human", parameters={"message": "Tu valides UHCD ?"}, )) actions = _edge_to_normalized_actions(edge, params={}) assert len(actions) == 1 a = actions[0] assert a["type"] == "pause_for_human" assert a["parameters"]["message"] == "Tu valides UHCD ?" assert "x_pct" not in a # action logique, pas de coords assert "y_pct" not in a def test_edge_to_action_pause_for_human_default_message(): edge = _FakeEdge(_FakeAction("pause_for_human", parameters={})) actions = _edge_to_normalized_actions(edge, params={}) assert actions[0]["parameters"]["message"] == "Validation requise" def test_edge_to_action_pause_for_human_carries_edge_metadata(): edge = _FakeEdge( _FakeAction("pause_for_human", parameters={"message": "x"}), edge_id="edge_42", from_node="n_src", to_node="n_dst", ) actions = _edge_to_normalized_actions(edge, params={}) a = actions[0] assert a["edge_id"] == "edge_42" assert a["from_node"] == "n_src" assert a["to_node"] == "n_dst" assert "action_id" in a # ---------------------------------------------------------------------- # Bridge VWB → core # ---------------------------------------------------------------------- def test_vwb_action_to_core_passthrough(): assert VWB_ACTION_TO_CORE["pause_for_human"] == "pause_for_human" def test_vwb_params_to_core_preserves_message(): core_params = _vwb_params_to_core("pause_for_human", {"message": "Coucou"}) assert core_params == {"message": "Coucou"} def test_vwb_params_to_core_default_message(): core_params = _vwb_params_to_core("pause_for_human", {}) assert core_params["message"] == "Validation requise" def test_export_vwb_workflow_with_pause_step(): """Un workflow VWB contenant une step pause_for_human doit produire un edge avec action.type='pause_for_human' et message dans parameters.""" workflow_data = {"id": "wf_demo", "name": "Demo Urgences", "description": ""} steps_data = [ {"id": "s1", "action_type": "click_anchor", "parameters": {"target_text": "25003284"}, "label": "Clic IPP"}, {"id": "s2", "action_type": "pause_for_human", "parameters": {"message": "Valider UHCD ?"}, "label": "Pause"}, {"id": "s3", "action_type": "click_anchor", "parameters": {"target_text": "Enregistrer"}, "label": "Clic Enregistrer"}, ] core = convert_vwb_to_core_workflow(workflow_data, steps_data) assert core["learning_state"] == "COACHING" assert len(core["nodes"]) == 3 assert len(core["edges"]) == 2 # L'edge sortant du node de pause doit avoir le bon type + message pause_edges = [ e for e in core["edges"] if e["action"]["type"] == "pause_for_human" ] assert len(pause_edges) == 1 assert pause_edges[0]["action"]["parameters"]["message"] == "Valider UHCD ?"