Files
agent_contas/tests/migration/test_invoice_explanation_handoff_policy.py

131 lines
4.9 KiB
Python

from __future__ import annotations
import asyncio
from types import SimpleNamespace
from app.agents.faturas_agent import FaturasAgent
from app.domain.contas.workflow_actions import build_contas_workflow_actions
from contas_mcp.servers.contas_mcp_server import main as mcp_main
def test_invoice_explanation_handoff_action_is_structural_and_uses_configured_message():
class Service:
pass
action = build_contas_workflow_actions(Service()).get("preparar_handoff_invoice_explanation")
result = action(
{
"mensagem": "Para continuar com a sua solicitação, aguarde um instante.",
"reason": "invoice_explanation_not_resolved",
},
{"input": {}},
)
assert result["mensagem"] == "Para continuar com a sua solicitação, aguarde um instante."
assert result["session_control"] == "HUMAN_HANDOFF"
assert result["human_handoff_requested"] is True
assert result["handoff"] is True
assert result["session_ended"] is True
assert result["terminal_status"] == "human_handoff"
def test_result_payload_promotes_invoice_explanation_handoff_control():
result = {
"execution_id": "exec-1",
"status": "COMPLETED",
"output": {
"handoff_pos_explicacao_nao": {
"success": True,
"mensagem": "Para continuar com a sua solicitação, aguarde um instante.",
"session_control": "HUMAN_HANDOFF",
"handoff_reason": "invoice_explanation_not_resolved",
}
},
"state": {"current_node": "handoff_pos_explicacao_nao"},
"trace": [{"node": "handoff_pos_explicacao_nao", "status": "COMPLETED"}],
}
payload = mcp_main._result_payload(result, workflow_name="invoice_explanation")
assert payload["mensagem"] == "Para continuar com a sua solicitação, aguarde um instante."
assert payload["session_control"] == "HUMAN_HANDOFF"
assert payload["human_handoff_requested"] is True
assert payload["handoff"] is True
assert payload["session_ended"] is True
def test_faturas_agent_promotes_handoff_from_tool_context_to_graph_state():
context = [{
"tool_name": "retomar_workflow",
"ok": True,
"result": {
"workflow_name": "invoice_explanation",
"status": "COMPLETED",
"mensagem": "Para continuar com a sua solicitação, aguarde um instante.",
"session_control": "HUMAN_HANDOFF",
"human_handoff_requested": True,
"session_ended": True,
"terminal_status": "human_handoff",
"handoff_reason": "invoice_explanation_not_resolved",
},
}]
patch = FaturasAgent._handoff_patch_from_tool_context(context)
assert patch == {
"session_control": "HUMAN_HANDOFF",
"human_handoff_requested": True,
"session_ended": True,
"terminal_status": "human_handoff",
"handoff_reason": "invoice_explanation_not_resolved",
}
def test_completed_terminal_workflow_short_circuits_llm_composition_directive():
agent = FaturasAgent.__new__(FaturasAgent)
context = [{
"tool_name": "retomar_workflow",
"ok": True,
"result": {
"status": "COMPLETED",
"workflow_name": "generic_workflow",
# Earlier node still carries a composition directive. It must not win
# over the terminal last node.
"requires_llm_composition": True,
"response_instruction": "Componha uma nova resposta.",
"output": {
"formatar": {
"requires_llm_composition": True,
"mensagem": "mensagem anterior",
},
"final": {
"mensagem": "Encaminhando para atendimento humano.",
"session_control": "HUMAN_HANDOFF",
"handoff": True,
"session_ended": True,
"terminal_status": "human_handoff",
},
},
"state": {"current_node": "final"},
},
}]
answer = agent.build_direct_mcp_answer({}, context, agent_label="AnyAgent")
assert answer == "Encaminhando para atendimento humano."
def test_result_payload_promotes_generic_terminal_last_node_contract():
result = {
"execution_id": "exec-generic",
"status": "COMPLETED",
"output": {
"final": {
"mensagem": "Sessão encerrada.",
"session_control": "END_SESSION",
"session_ended": True,
"terminal_status": "done",
}
},
"state": {"current_node": "final"},
"trace": [{"node": "final", "status": "COMPLETED"}],
}
payload = mcp_main._result_payload(result, workflow_name="generic_example")
assert payload["terminal"] is True
assert payload["terminal_action"] == "end_session"
assert payload["mensagem"] == "Sessão encerrada."
assert payload["session_ended"] is True