🐛 fix(policy): corrigir troca explicita de contexto com fluxo aberto

- impede que uma compra explicita durante revisao aberta seja enfileirada cedo demais com prompt pendente do fluxo atual
- deixa a mudanca seguir para a confirmacao normal de context switch via pending_switch
- adiciona teste para garantir que a policy nao devolve resposta antecipada nem fila automatica nesse cenario
main
parent b2e17d0c29
commit 8a00b6a68e

@ -171,10 +171,10 @@ class ConversationPolicy:
and inferred != active_domain
and self.has_open_flow(user_id=user_id, domain=active_domain)
):
self.queue_order(user_id=user_id, domain=inferred, order_message=message)
queue_hint = self.render_queue_notice(1)
prompt = self.render_open_flow_prompt(user_id=user_id, domain=active_domain)
return message, None, f"{prompt}\n{queue_hint}" if queue_hint else prompt
# Para uma troca explicita de dominio com fluxo aberto,
# deixa a confirmacao de context switch acontecer no ponto
# normal da policy em vez de enfileirar cedo demais.
return message, None, None
return message, None, None
if self.has_open_flow(user_id=user_id, domain=active_domain):

@ -96,6 +96,9 @@ class FakePolicyService:
def _new_tab_memory(self, user_id: int | None):
return {}
def _coerce_extraction_contract(self, payload):
return payload if isinstance(payload, dict) else self.normalizer.empty_extraction_payload()
def _is_affirmative_message(self, text: str) -> bool:
normalized = self.normalizer.normalize_text(text).strip().rstrip(".!?,;:")
return normalized in {"sim", "pode", "ok", "confirmo", "aceito", "fechado", "pode sim"}
@ -1220,6 +1223,40 @@ class TurnDecisionContractTests(unittest.IsolatedAsyncioTestCase):
self.assertEqual(response, "Certo, contexto anterior encerrado. Vamos seguir com agendamento de revisao.")
def test_prepare_message_for_single_order_defers_explicit_domain_switch_with_open_flow(self):
state = FakeState(
entries={
"pending_review_drafts": {
9: {
"payload": {"placa": "ABC1234"},
"expires_at": datetime.utcnow() + timedelta(minutes=15),
}
}
},
contexts={
9: {
"active_domain": "review",
"generic_memory": {},
"order_queue": [],
"pending_order_selection": None,
"pending_switch": None,
}
},
)
service = FakePolicyService(state)
policy = ConversationPolicy(service=service)
routed_message, queue_notice, early_response = policy.prepare_message_for_single_order(
message="quero comprar um carro de ate 62 mil",
user_id=9,
routing_plan={"orders": [{"domain": "sales", "message": "quero comprar um carro de ate 62 mil"}]},
)
self.assertEqual(routed_message, "quero comprar um carro de ate 62 mil")
self.assertIsNone(queue_notice)
self.assertIsNone(early_response)
self.assertEqual(service._get_user_context(9).get("order_queue"), [])
if __name__ == "__main__":
unittest.main()

Loading…
Cancel
Save