bugfix: oci_openai provider

This commit is contained in:
2026-08-27 20:34:15 -03:00
parent fc64c6ddd7
commit 0ecff719b7
329 changed files with 864 additions and 144 deletions

View File

@@ -393,3 +393,97 @@ def test_output_guardrail_context_nao_duplica_user_text_ja_no_historico():
}
)
assert len(ctx["conversation_history"]) == 1
def test_output_guardrail_context_isola_transacao_terminal_apos_intent_shift():
from app.workflows.agent_graph import AgentWorkflow
ctx = AgentWorkflow._output_guardrail_context(
{
"context": {
"transaction_pre_validation": {
"status": "OUT_OF_SCOPE",
"terminal": True,
"error": "TIM CTRL Redes Sociais 8.0",
},
},
"history": [
{"role": "user", "content": "nao contratei TIM CTRL Redes Sociais 8.0"},
{"role": "assistant", "content": "Esse item nao e contestavel."},
],
"user_text": "quais sao meus servicos",
"route": "vas_agent",
"intent": "contas_vas_information",
"route_decision": {
"route": "vas_agent",
"intent": "contas_vas_information",
"metadata": {
"route_stickiness_preempted": True,
"previous_agent": "contestacao_agent",
"previous_intent": "contas_contestation",
},
},
"transaction_status": "OUT_OF_SCOPE",
"transaction_pre_validation": {
"status": "OUT_OF_SCOPE",
"terminal": True,
"error": "TIM CTRL Redes Sociais 8.0",
},
"mcp_results": [],
}
)
assert ctx["conversation_history"] == [
{"role": "user", "content": "quais sao meus servicos"}
]
assert ctx["history_texts"] == ["quais sao meus servicos"]
assert ctx["current_user_message"] == "quais sao meus servicos"
assert ctx["current_route"] == "vas_agent"
assert ctx["current_intent"] == "contas_vas_information"
assert ctx["historical_transaction_ignored"] is True
assert ctx["historical_transaction_status"] == "OUT_OF_SCOPE"
assert "transaction_pre_validation" not in ctx
assert "TIM CTRL Redes Sociais" not in str(ctx)
def test_output_guardrail_context_preserva_historico_no_turno_terminal_sem_intent_shift():
from app.workflows.agent_graph import AgentWorkflow
ctx = AgentWorkflow._output_guardrail_context(
{
"context": {},
"history": [
{"role": "user", "content": "nao contratei TIM CTRL Redes Sociais 8.0"},
],
"user_text": "o valor e 71,99",
"route": "contestacao_agent",
"intent": "state:COLLECTING_CONTESTACAO_PARAMETERS",
"route_decision": {
"route": "contestacao_agent",
"intent": "state:COLLECTING_CONTESTACAO_PARAMETERS",
"metadata": {},
},
"transaction_status": "OUT_OF_SCOPE",
"transaction_pre_validation": {
"status": "OUT_OF_SCOPE",
"terminal": True,
},
"mcp_results": [],
}
)
assert ctx["history_texts"] == [
"nao contratei TIM CTRL Redes Sociais 8.0",
"o valor e 71,99",
]
assert "historical_transaction_ignored" not in ctx
def test_vas_prompt_nao_expoe_capacidade_cancelamento_em_consulta_informativa():
from pathlib import Path
prompt = Path("config/prompts/vas.yaml").read_text(encoding="utf-8")
assert "não exponha capacidades transacionais" in prompt
assert "can.cancel" in prompt
assert '"Cancelamento disponível"' in prompt
assert "a menos que o cliente tenha perguntado explicitamente" in prompt

View File

@@ -0,0 +1,11 @@
from app.agents.contas_prompting import load_domain_prompt
def test_contestation_prompt_closes_terminal_out_of_scope_without_proactive_next_step():
prompt = load_domain_prompt("contestation")
assert "Se a tool retornar OUT_OF_SCOPE, bloqueio ou categoria não tratável:" in prompt
assert "encerre a resposta imediatamente após explicar o motivo" in prompt
assert "não ofereça outra ação, outro item, cancelamento, alteração, nova contestação" in prompt
assert 'não convide o cliente a continuar com frases como "se desejar", "caso queira"' in prompt
assert "Em resultado terminal, a resposta deve terminar na explicação do resultado atual." in prompt

View File

@@ -92,3 +92,40 @@ def test_invoice_resolver_exact_plan_identity_wins_before_similarity_matcher():
assert outcome.resolved == []
assert len(outcome.out_of_scope) == 1
assert outcome.out_of_scope[0].matches[0].canonical_name == "TIM CTRL Redes Sociais 8.0"
def test_recovers_explicit_subject_from_runtime_query_fields_without_motivo():
args = _args(subject="TIM CTRL Redes Sociais")
args.pop("motivo", None)
args["query"] = "nao contratei TIM CTRL Redes Sociais 8.0"
args["operator_instructions"] = "nao contratei TIM CTRL Redes Sociais 8.0"
args["valor"] = 8
item = _recover_explicit_contestation_subject(args)
assert item is not None
assert item["name"] == "TIM CTRL Redes Sociais 8.0"
assert str(item["value"]) == "71.99"
assert item["category"] == "plano"
result = _preflight_subject("contestar_cobranca", args)
assert result is not None
assert result["status"] == "OUT_OF_SCOPE"
assert result["subject"] == "TIM CTRL Redes Sociais 8.0"
assert result["resolved_value"] == "71.99"
assert result["metadata"]["subject_corrected_from"] == "TIM CTRL Redes Sociais"
assert args["subject"] == "TIM CTRL Redes Sociais 8.0"
assert args["resolved_value"] == "71.99"
def test_all_supported_original_text_fields_recover_explicit_subject():
for field in ("query", "operator_instructions", "message", "text", "motivo", "descricao"):
args = _args(subject="TIM CTRL Redes Sociais")
for candidate in ("query", "operator_instructions", "message", "text", "motivo", "descricao"):
args.pop(candidate, None)
args[field] = "nao contratei TIM CTRL Redes Sociais 8.0"
args["valor"] = 8
item = _recover_explicit_contestation_subject(args)
assert item is not None, field
assert item["name"] == "TIM CTRL Redes Sociais 8.0", field
assert str(item["value"]) == "71.99", field