import pytest from agent_framework.guardrails.rails import LoopRail @pytest.mark.asyncio async def test_vloop_allows_repeated_reply_while_transaction_awaits_confirmation(): rail = LoopRail() decision = await rail.evaluate( "sim", { "transaction_status": "AWAITING_CONFIRMATION", "history_texts": ["sim", "outra fala", "sim"], }, ) assert decision.allowed is True assert decision.metadata["mechanism"] == "deterministic_transaction_bypass" assert decision.metadata["transaction_status"] == "AWAITING_CONFIRMATION" @pytest.mark.asyncio async def test_vloop_reads_awaiting_confirmation_from_active_transaction(): rail = LoopRail() decision = await rail.evaluate( "sim", { "active_transaction": {"status": "AWAITING_CONFIRMATION"}, "history_texts": ["sim", "sim"], }, ) assert decision.allowed is True assert decision.metadata["mechanism"] == "deterministic_transaction_bypass" @pytest.mark.asyncio async def test_vloop_allows_repeated_parameter_during_transaction_collection(): rail = LoopRail() decision = await rail.evaluate( "PED-1001", { "transaction_status": "COLLECTING_PARAMETERS", "missing_parameters": ["order_id"], "history_texts": ["PED-1001", "outra fala", "PED-1001"], }, ) assert decision.allowed is True assert decision.reason == "continuidade_transacional:COLLECTING_PARAMETERS" assert decision.metadata["repeated"] is False assert decision.metadata["mechanism"] == "deterministic_transaction_bypass" assert decision.metadata["transaction_status"] == "COLLECTING_PARAMETERS" @pytest.mark.asyncio async def test_vloop_prefers_latest_live_mcp_transaction_over_stale_completed_status(): rail = LoopRail() decision = await rail.evaluate( "sim", { "transaction_status": "COMPLETED", "active_transaction": {"status": "COMPLETED"}, "mcp_results": [ {"tool_name": "devolver_pedido", "transaction_status": "COMPLETED"}, { "tool_name": "cancelar_pedido", "transaction_status": "AWAITING_CONFIRMATION", "awaiting_confirmation": True, }, ], "history_texts": ["sim", "outra fala", "sim"], }, ) assert decision.allowed is True assert decision.metadata["mechanism"] == "deterministic_transaction_bypass" assert decision.metadata["transaction_status"] == "AWAITING_CONFIRMATION" @pytest.mark.asyncio async def test_vloop_still_blocks_actual_repetition_outside_transaction_confirmation(): rail = LoopRail() decision = await rail.evaluate( "sim", { "transaction_status": None, "history_texts": ["sim", "outra fala", "sim"], }, ) assert decision.allowed is False assert decision.reason == "Possível loop conversacional" assert decision.metadata["repeated"] is True