@ -1312,6 +1312,140 @@ class TurnDecisionContractTests(unittest.IsolatedAsyncioTestCase):
self . assertTrue ( prioritized )
async def test_handle_message_prioritizes_review_management_over_model_answer_for_reschedule_intent ( self ) :
state = FakeState (
contexts = {
1 : {
" active_domain " : " general " ,
" generic_memory " : { } ,
" shared_memory " : { } ,
" order_queue " : [ ] ,
" pending_order_selection " : None ,
" pending_switch " : None ,
" last_stock_results " : [ ] ,
" selected_vehicle " : None ,
}
}
)
service = OrquestradorService . __new__ ( OrquestradorService )
service . state = state
service . normalizer = EntityNormalizer ( )
service . policy = ConversationPolicy ( service = service )
service . _empty_extraction_payload = service . normalizer . empty_extraction_payload
service . _log_turn_event = lambda * args , * * kwargs : None
service . _compose_order_aware_response = lambda response , user_id , queue_notice = None : response
async def fake_maybe_auto_advance_next_order ( base_response : str , user_id : int | None ) :
return base_response
service . _maybe_auto_advance_next_order = fake_maybe_auto_advance_next_order
service . _upsert_user_context = lambda user_id : None
async def fake_extract_turn_decision ( message : str , user_id : int | None ) :
return {
" intent " : " review_reschedule " ,
" domain " : " review " ,
" action " : " answer_user " ,
" entities " : service . normalizer . empty_extraction_payload ( ) ,
" missing_fields " : [ ] ,
" selection_index " : None ,
" tool_name " : None ,
" tool_arguments " : { } ,
" response_to_user " : " Claro, para qual data e horario voce gostaria de remarcar? " ,
}
service . _extract_turn_decision_with_llm = fake_extract_turn_decision
async def fake_try_handle_immediate_context_reset ( * * kwargs ) :
return None
service . _try_handle_immediate_context_reset = fake_try_handle_immediate_context_reset
async def fake_try_resolve_pending_order_selection ( * * kwargs ) :
return None
service . _try_resolve_pending_order_selection = fake_try_resolve_pending_order_selection
async def fake_try_continue_queued_order ( * * kwargs ) :
return None
service . _try_continue_queued_order = fake_try_continue_queued_order
async def fake_extract_message_plan ( message : str , user_id : int | None ) :
return {
" orders " : [
{
" domain " : " review " ,
" message " : message ,
" entities " : service . normalizer . empty_extraction_payload ( ) ,
}
]
}
service . _extract_message_plan_with_llm = fake_extract_message_plan
service . _prepare_message_for_single_order = lambda message , user_id , routing_plan = None : ( message , None , None )
service . _resolve_entities_for_message_plan = lambda message_plan , routed_message : service . normalizer . empty_extraction_payload ( )
async def fake_extract_entities ( message : str , user_id : int | None ) :
return service . normalizer . empty_extraction_payload ( )
service . _extract_entities_with_llm = fake_extract_entities
async def fake_extract_missing_sales_search_context_with_llm ( * * kwargs ) :
return { }
service . _extract_missing_sales_search_context_with_llm = fake_extract_missing_sales_search_context_with_llm
service . _domain_from_intents = lambda intents : " general "
service . _handle_context_switch = lambda * * kwargs : None
service . _update_active_domain = lambda * * kwargs : None
async def fake_try_execute_orchestration_control_tool ( * * kwargs ) :
return None
service . _try_execute_orchestration_control_tool = fake_try_execute_orchestration_control_tool
async def fake_try_execute_business_tool_from_turn_decision ( * * kwargs ) :
return None
service . _try_execute_business_tool_from_turn_decision = fake_try_execute_business_tool_from_turn_decision
async def fake_try_handle_review_management ( * * kwargs ) :
return " Para remarcar sua revisao, preciso dos dados abaixo: \n - a nova data e hora desejada para a revisao "
service . _try_handle_review_management = fake_try_handle_review_management
async def fake_try_confirm_pending_review ( * * kwargs ) :
return None
service . _try_confirm_pending_review = fake_try_confirm_pending_review
async def fake_try_collect_and_schedule_review ( * * kwargs ) :
return None
service . _try_collect_and_schedule_review = fake_try_collect_and_schedule_review
async def fake_try_collect_and_cancel_order ( * * kwargs ) :
return None
service . _try_collect_and_cancel_order = fake_try_collect_and_cancel_order
async def fake_try_handle_order_listing ( * * kwargs ) :
return None
service . _try_handle_order_listing = fake_try_handle_order_listing
async def fake_try_collect_and_create_order ( * * kwargs ) :
return None
service . _try_collect_and_create_order = fake_try_collect_and_create_order
response = await service . handle_message (
" quero remarcar o meu agendamento REV-20260317-54E9D3CB " ,
user_id = 1 ,
)
self . assertIn ( " a nova data e hora desejada " , response )
async def test_handle_message_prioritizes_review_flow_over_model_answer_for_followup ( self ) :
state = FakeState (
entries = {
@ -1832,6 +1966,199 @@ class TurnDecisionContractTests(unittest.IsolatedAsyncioTestCase):
self . assertEqual ( response , " Pedido criado com sucesso. " )
async def test_handle_message_short_circuits_active_review_time_follow_up_before_llm ( self ) :
state = FakeState (
entries = {
" pending_review_drafts " : {
1 : {
" payload " : {
" placa " : " ABC1234 " ,
" data_hora_base " : " 17/03/2026 " ,
} ,
" expires_at " : utc_now ( ) + timedelta ( minutes = 15 ) ,
}
}
} ,
contexts = {
1 : {
" active_domain " : " review " ,
" generic_memory " : { " placa " : " ABC1234 " } ,
" shared_memory " : { " placa " : " ABC1234 " } ,
" order_queue " : [ ] ,
" pending_order_selection " : None ,
" pending_switch " : None ,
" last_stock_results " : [ ] ,
" selected_vehicle " : None ,
}
}
)
service = OrquestradorService . __new__ ( OrquestradorService )
service . state = state
service . normalizer = EntityNormalizer ( )
service . _empty_extraction_payload = service . normalizer . empty_extraction_payload
service . _log_turn_event = lambda * args , * * kwargs : None
service . _compose_order_aware_response = lambda response , user_id , queue_notice = None : response
service . _get_user_context = lambda user_id : state . get_user_context ( user_id )
service . _save_user_context = lambda user_id , context : state . save_user_context ( user_id , context )
async def fake_maybe_auto_advance_next_order ( base_response : str , user_id : int | None ) :
return base_response
service . _maybe_auto_advance_next_order = fake_maybe_auto_advance_next_order
service . _upsert_user_context = lambda user_id : None
async def fake_try_handle_pending_stock_selection_follow_up ( * * kwargs ) :
return None
service . _try_handle_pending_stock_selection_follow_up = fake_try_handle_pending_stock_selection_follow_up
async def fake_extract_turn_decision ( message : str , user_id : int | None ) :
raise AssertionError ( " nao deveria consultar o LLM para um follow-up temporal de revisao com draft aberto " )
service . _extract_turn_decision_with_llm = fake_extract_turn_decision
async def fake_try_collect_and_schedule_review ( * * kwargs ) :
self . assertEqual ( kwargs [ " turn_decision " ] [ " intent " ] , " review_schedule " )
return " Para agendar sua revisao, preciso dos dados abaixo: \n - o modelo do veiculo "
service . _try_collect_and_schedule_review = fake_try_collect_and_schedule_review
async def fake_try_handle_review_management ( * * kwargs ) :
return None
service . _try_handle_review_management = fake_try_handle_review_management
async def fake_try_confirm_pending_review ( * * kwargs ) :
return None
service . _try_confirm_pending_review = fake_try_confirm_pending_review
response = await service . handle_message (
" 15h " ,
user_id = 1 ,
)
self . assertIn ( " o modelo do veiculo " , response )
async def test_handle_message_allows_explicit_sales_shift_before_active_review_follow_up_short_circuit ( self ) :
state = FakeState (
entries = {
" pending_review_drafts " : {
1 : {
" payload " : {
" placa " : " ABC1234 " ,
" data_hora_base " : " 17/03/2026 " ,
} ,
" expires_at " : utc_now ( ) + timedelta ( minutes = 15 ) ,
}
}
} ,
contexts = {
1 : {
" active_domain " : " review " ,
" generic_memory " : { " placa " : " ABC1234 " } ,
" shared_memory " : { " placa " : " ABC1234 " } ,
" order_queue " : [ ] ,
" pending_order_selection " : None ,
" pending_switch " : None ,
" last_stock_results " : [ ] ,
" selected_vehicle " : None ,
}
}
)
service = OrquestradorService . __new__ ( OrquestradorService )
service . state = state
service . normalizer = EntityNormalizer ( )
service . _empty_extraction_payload = service . normalizer . empty_extraction_payload
service . _log_turn_event = lambda * args , * * kwargs : None
service . _compose_order_aware_response = lambda response , user_id , queue_notice = None : response
service . _get_user_context = lambda user_id : state . get_user_context ( user_id )
service . _save_user_context = lambda user_id , context : state . save_user_context ( user_id , context )
async def fake_maybe_auto_advance_next_order ( base_response : str , user_id : int | None ) :
return base_response
service . _maybe_auto_advance_next_order = fake_maybe_auto_advance_next_order
service . _upsert_user_context = lambda user_id : None
async def fake_try_handle_pending_stock_selection_follow_up ( * * kwargs ) :
return None
service . _try_handle_pending_stock_selection_follow_up = fake_try_handle_pending_stock_selection_follow_up
async def fake_try_handle_immediate_context_reset ( * * kwargs ) :
return None
service . _try_handle_immediate_context_reset = fake_try_handle_immediate_context_reset
async def fake_try_resolve_pending_order_selection ( * * kwargs ) :
return None
service . _try_resolve_pending_order_selection = fake_try_resolve_pending_order_selection
async def fake_try_continue_queued_order ( * * kwargs ) :
return None
service . _try_continue_queued_order = fake_try_continue_queued_order
async def fake_extract_turn_decision ( message : str , user_id : int | None ) :
return {
" intent " : " order_create " ,
" domain " : " sales " ,
" action " : " collect_order_create " ,
" entities " : service . normalizer . empty_extraction_payload ( ) ,
" missing_fields " : [ ] ,
" selection_index " : None ,
" tool_name " : None ,
" tool_arguments " : { } ,
" response_to_user " : " " ,
}
service . _extract_turn_decision_with_llm = fake_extract_turn_decision
async def fake_extract_message_plan ( message : str , user_id : int | None ) :
return {
" orders " : [
{
" domain " : " sales " ,
" message " : message ,
" entities " : service . normalizer . empty_extraction_payload ( ) ,
}
]
}
service . _extract_message_plan_with_llm = fake_extract_message_plan
service . _prepare_message_for_single_order = lambda message , user_id , routing_plan = None : ( message , None , None )
service . _resolve_entities_for_message_plan = lambda message_plan , routed_message : service . normalizer . empty_extraction_payload ( )
async def fake_extract_entities ( message : str , user_id : int | None ) :
return service . normalizer . empty_extraction_payload ( )
service . _extract_entities_with_llm = fake_extract_entities
async def fake_extract_missing_sales_search_context_with_llm ( * * kwargs ) :
return { }
service . _extract_missing_sales_search_context_with_llm = fake_extract_missing_sales_search_context_with_llm
service . _domain_from_intents = lambda intents : " general "
service . _update_active_domain = lambda * * kwargs : None
service . _handle_context_switch = lambda * * kwargs : " Entendi que voce quer sair de agendamento de revisao e ir para compra de veiculo. Tem certeza? "
async def fake_try_collect_and_schedule_review ( * * kwargs ) :
raise AssertionError ( " nao deveria consumir uma solicitacao explicita de compra como follow-up de revisao " )
service . _try_collect_and_schedule_review = fake_try_collect_and_schedule_review
response = await service . handle_message (
" quero comprar um carro ate 80 mil " ,
user_id = 1 ,
)
self . assertEqual (
response ,
" Entendi que voce quer sair de agendamento de revisao e ir para compra de veiculo. Tem certeza? " ,
)
async def test_handle_message_prioritizes_pending_switch_confirmation_before_sales_follow_up ( self ) :
state = FakeState (
entries = {