@ -78,6 +78,21 @@ class FakeRegistry:
{ " id " : 1 , " modelo " : " Honda Civic 2021 " , " categoria " : " sedan " , " preco " : 48500.0 } ,
{ " id " : 2 , " modelo " : " Toyota Yaris 2020 " , " categoria " : " hatch " , " preco " : 49900.0 } ,
]
if tool_name == " listar_pedidos " :
return [
{
" numero_pedido " : " PED-TESTE-001 " ,
" modelo_veiculo " : " Fiat Argo 2020 " ,
" valor_veiculo " : 61857.0 ,
" status " : " Ativo " ,
} ,
{
" numero_pedido " : " PED-TESTE-002 " ,
" modelo_veiculo " : " Toyota Corolla 2020 " ,
" valor_veiculo " : 58476.0 ,
" status " : " Cancelado " ,
} ,
]
if tool_name == " realizar_pedido " :
vehicle_map = {
1 : ( " Honda Civic 2021 " , 51524.0 ) ,
@ -92,6 +107,36 @@ class FakeRegistry:
" modelo_veiculo " : modelo_veiculo ,
" valor_veiculo " : valor_veiculo ,
}
if tool_name == " agendar_revisao " :
return {
" protocolo " : " REV-TESTE-123 " ,
" placa " : arguments [ " placa " ] ,
" data_hora " : arguments [ " data_hora " ] ,
" valor_revisao " : 840.60 ,
}
if tool_name == " listar_agendamentos_revisao " :
return [
{
" protocolo " : " REV-TESTE-001 " ,
" placa " : " ABC1234 " ,
" data_hora " : " 13/03/2026 16:00 " ,
" status " : " Agendado " ,
}
]
if tool_name == " cancelar_agendamento_revisao " :
return {
" protocolo " : arguments [ " protocolo " ] ,
" placa " : " ABC1269 " ,
" data_hora " : " 13/03/2026 16:00 " ,
" status " : " Cancelado " ,
}
if tool_name == " editar_data_revisao " :
return {
" protocolo " : arguments [ " protocolo " ] ,
" placa " : " ABC1269 " ,
" data_hora " : arguments [ " nova_data_hora " ] ,
" status " : " Remarcado " ,
}
return {
" numero_pedido " : arguments [ " numero_pedido " ] ,
" status " : " Cancelado " ,
@ -155,6 +200,14 @@ class OrderFlowHarness(OrderFlowMixin):
f " Veiculo: { tool_result [ ' modelo_veiculo ' ] } \n "
f " Valor: R$ { tool_result [ ' valor_veiculo ' ] : .2f } "
)
if tool_name == " listar_pedidos " :
lines = [ f " Encontrei { len ( tool_result ) } pedido(s): " ]
for idx , item in enumerate ( tool_result , start = 1 ) :
lines . append (
f " { idx } . { item [ ' numero_pedido ' ] } | { item [ ' modelo_veiculo ' ] } | "
f " { item [ ' status ' ] } | R$ { item [ ' valor_veiculo ' ] : .2f } "
)
return " \n " . join ( lines )
return (
f " Pedido { tool_result [ ' numero_pedido ' ] } atualizado. \n "
f " Status: { tool_result [ ' status ' ] } \n "
@ -179,6 +232,7 @@ class ReviewFlowHarness(ReviewFlowMixin):
self . tool_executor = registry
self . normalizer = EntityNormalizer ( )
self . captured_suggestions = [ ]
self . logged_events = [ ]
def _normalize_intents ( self , data ) - > dict :
return self . normalizer . normalize_intents ( data )
@ -192,10 +246,16 @@ class ReviewFlowHarness(ReviewFlowMixin):
def _normalize_text ( self , text : str ) - > str :
return self . normalizer . normalize_text ( text )
def _normalize_review_datetime_text ( self , value ) - > str | None :
return self . normalizer . normalize_review_datetime_text ( value )
def _http_exception_detail ( self , exc ) - > str :
detail = exc . detail if isinstance ( exc . detail , dict ) else { }
return str ( detail . get ( " message " ) or exc )
def _get_user_context ( self , user_id : int | None ) :
return self . state . get_user_context ( user_id )
def _fallback_format_tool_result ( self , tool_name : str , tool_result ) - > str :
return f " { tool_name } : { tool_result } "
@ -216,6 +276,15 @@ class ReviewFlowHarness(ReviewFlowMixin):
def _try_prefill_review_fields_from_memory ( self , user_id : int | None , payload : dict ) - > None :
return None
def _log_turn_event ( self , event : str , * * payload ) - > None :
self . logged_events . append ( ( event , payload ) )
def _reset_pending_review_states ( self , user_id : int | None ) - > None :
self . state . pop_entry ( " pending_review_drafts " , user_id )
self . state . pop_entry ( " pending_review_management_drafts " , user_id )
self . state . pop_entry ( " pending_review_confirmations " , user_id )
self . state . pop_entry ( " pending_review_reuse_confirmations " , user_id )
class ConversationAdjustmentsTests ( unittest . TestCase ) :
def test_telegram_satellite_requires_redis_in_production ( self ) :
@ -263,6 +332,35 @@ class ConversationAdjustmentsTests(unittest.TestCase):
self . assertEqual ( parsed , datetime ( 2026 , 3 , 10 , 9 , 0 ) )
def test_normalize_review_datetime_extracts_datetime_from_long_review_sentence ( self ) :
normalizer = EntityNormalizer ( )
self . assertEqual (
normalizer . normalize_review_datetime_text (
" para ABC1234 em 28/03/2026 as 8:00, Corolla, 2020, 30000 km, ja fiz revisao "
) ,
" 28/03/2026 08:00 " ,
)
def test_normalize_review_fields_discards_invalid_datetime_noise ( self ) :
normalizer = EntityNormalizer ( )
self . assertEqual (
normalizer . normalize_review_fields ( { " data_hora " : " quero agendar uma revisao qualquer " } ) ,
{ } ,
)
def test_reset_message_variants_strip_previous_context_prefix ( self ) :
state = FakeState ( )
policy = ConversationPolicy ( service = FakeService ( state ) )
message = " Esqueça as operações anteriores, agora quero agendar revisão para ABC1234 "
cleaned = policy . remove_order_selection_reset_prefix ( message )
self . assertTrue ( policy . is_order_selection_reset_message ( message ) )
self . assertEqual ( cleaned , " quero agendar revisão para ABC1234 " )
class CancelOrderFlowTests ( unittest . IsolatedAsyncioTestCase ) :
async def test_cancel_order_flow_accepts_turn_decision_without_legacy_intents ( self ) :
state = FakeState ( )
@ -277,7 +375,7 @@ class CancelOrderFlowTests(unittest.IsolatedAsyncioTestCase):
turn_decision = { " intent " : " order_cancel " , " domain " : " sales " , " action " : " collect_order_cancel " } ,
)
self . assert In( " o motivo do cancelamento " , response )
self . assert Equal( response , " Encontrei o pedido informado. Qual o motivo do cancelamento? " )
self . assertIsNotNone ( state . get_entry ( " pending_cancel_order_drafts " , 42 ) )
async def test_cancel_order_flow_consumes_free_text_reason ( self ) :
@ -310,6 +408,38 @@ class CancelOrderFlowTests(unittest.IsolatedAsyncioTestCase):
self . assertIn ( " Status: Cancelado " , response )
self . assertIsNone ( state . get_entry ( " pending_cancel_order_drafts " , 42 ) )
async def test_cancel_order_flow_consumes_free_text_reason_even_when_model_repeats_order_cancel_intent ( self ) :
state = FakeState (
entries = {
" pending_cancel_order_drafts " : {
42 : {
" payload " : { " numero_pedido " : " PED-20260305120000-ABC123 " } ,
" expires_at " : datetime . utcnow ( ) + timedelta ( minutes = 30 ) ,
}
}
}
)
registry = FakeRegistry ( )
flow = OrderFlowHarness ( state = state , registry = registry )
response = await flow . _try_collect_and_cancel_order (
message = " Eu desisti dessa compra " ,
user_id = 42 ,
extracted_fields = { } ,
intents = { } ,
turn_decision = { " intent " : " order_cancel " , " domain " : " sales " , " action " : " answer_user " } ,
)
self . assertEqual ( len ( registry . calls ) , 1 )
tool_name , arguments , tool_user_id = registry . calls [ 0 ]
self . assertEqual ( tool_name , " cancelar_pedido " )
self . assertEqual ( tool_user_id , 42 )
self . assertEqual ( arguments [ " numero_pedido " ] , " PED-20260305120000-ABC123 " )
self . assertEqual ( arguments [ " motivo " ] , " Eu desisti dessa compra " )
self . assertIn ( " Pedido PED-20260305120000-ABC123 atualizado. " , response )
self . assertIn ( " Status: Cancelado " , response )
self . assertIsNone ( state . get_entry ( " pending_cancel_order_drafts " , 42 ) )
async def test_cancel_order_flow_still_requests_reason_when_message_is_too_short ( self ) :
state = FakeState (
entries = {
@ -361,6 +491,46 @@ class CancelOrderFlowTests(unittest.IsolatedAsyncioTestCase):
class CreateOrderFlowWithVehicleTests ( unittest . IsolatedAsyncioTestCase ) :
async def test_order_listing_preserves_open_order_draft ( self ) :
state = FakeState (
entries = {
" pending_order_drafts " : {
10 : {
" payload " : { " cpf " : " 12345678909 " } ,
" expires_at " : datetime . utcnow ( ) + timedelta ( minutes = 30 ) ,
}
}
}
)
registry = FakeRegistry ( )
flow = OrderFlowHarness ( state = state , registry = registry )
response = await flow . _try_handle_order_listing (
message = " Liste os meus pedidos " ,
user_id = 10 ,
intents = { } ,
turn_decision = { " intent " : " order_list " , " domain " : " sales " , " action " : " call_tool " } ,
)
self . assertEqual ( registry . calls [ 0 ] [ 0 ] , " listar_pedidos " )
self . assertIn ( " Encontrei 2 pedido(s): " , response )
self . assertIsNotNone ( state . get_entry ( " pending_order_drafts " , 10 ) )
async def test_order_listing_ignores_review_appointment_listing_message ( self ) :
state = FakeState ( )
registry = FakeRegistry ( )
flow = OrderFlowHarness ( state = state , registry = registry )
response = await flow . _try_handle_order_listing (
message = " liste para mim os meus agendamentos de revisao " ,
user_id = 10 ,
intents = { } ,
turn_decision = { " intent " : " order_list " , " domain " : " sales " , " action " : " call_tool " } ,
)
self . assertIsNone ( response )
self . assertEqual ( registry . calls , [ ] )
async def test_order_flow_auto_lists_stock_on_first_purchase_message_when_budget_exists ( self ) :
state = FakeState (
contexts = {
@ -819,6 +989,224 @@ class CreateOrderFlowWithVehicleTests(unittest.IsolatedAsyncioTestCase):
class ReviewFlowDraftTests ( unittest . IsolatedAsyncioTestCase ) :
async def test_review_flow_extracts_relative_datetime_from_followup_message ( self ) :
state = FakeState (
entries = {
" pending_review_drafts " : {
21 : {
" payload " : { " placa " : " ABC1269 " } ,
" expires_at " : datetime . utcnow ( ) + timedelta ( minutes = 30 ) ,
}
}
}
)
registry = FakeRegistry ( )
flow = ReviewFlowHarness ( state = state , registry = registry )
response = await flow . _try_collect_and_schedule_review (
message = " Eu gostaria de marcar amanha as 16 horas " ,
user_id = 21 ,
extracted_fields = { } ,
intents = { } ,
turn_decision = { " intent " : " review_schedule " , " domain " : " review " , " action " : " answer_user " } ,
)
draft = state . get_entry ( " pending_review_drafts " , 21 )
self . assertIsNotNone ( draft )
self . assertIn ( " data_hora " , draft [ " payload " ] )
self . assertEqual ( draft [ " payload " ] [ " data_hora " ] [ - 5 : ] , " 16:00 " )
self . assertIn ( " o modelo do veiculo " , response )
self . assertTrue ( any ( payload . get ( " review_flow_source " ) == " draft " for _ , payload in flow . logged_events ) )
async def test_review_flow_extracts_model_year_km_and_review_history_from_free_text ( self ) :
state = FakeState (
entries = {
" pending_review_drafts " : {
21 : {
" payload " : { " placa " : " ABC1269 " , " data_hora " : " 13/03/2026 16:00 " } ,
" expires_at " : datetime . utcnow ( ) + timedelta ( minutes = 30 ) ,
}
}
}
)
registry = FakeRegistry ( )
flow = ReviewFlowHarness ( state = state , registry = registry )
response = await flow . _try_collect_and_schedule_review (
message = " O modelo do meu carro e um Onix e ele e 2021, 30000 km, nunca fiz revisao " ,
user_id = 21 ,
extracted_fields = { } ,
intents = { } ,
turn_decision = { " intent " : " review_schedule " , " domain " : " review " , " action " : " answer_user " } ,
)
self . assertIsNone ( state . get_entry ( " pending_review_drafts " , 21 ) )
self . assertEqual ( registry . calls [ 0 ] [ 0 ] , " agendar_revisao " )
_ , arguments , tool_user_id = registry . calls [ 0 ]
self . assertEqual ( tool_user_id , 21 )
self . assertEqual ( arguments . get ( " modelo " ) , " Um Onix " )
self . assertEqual ( arguments . get ( " ano " ) , 2021 )
self . assertEqual ( arguments . get ( " km " ) , 30000 )
self . assertFalse ( arguments . get ( " revisao_previa_concessionaria " ) )
self . assertIn ( " REV-TESTE-123 " , response )
async def test_review_flow_keeps_plate_and_datetime_across_incremental_messages ( self ) :
state = FakeState ( )
registry = FakeRegistry ( )
flow = ReviewFlowHarness ( state = state , registry = registry )
await flow . _try_collect_and_schedule_review (
message = " gostaria de marcar uma nova revisao agora " ,
user_id = 21 ,
extracted_fields = { } ,
intents = { } ,
turn_decision = { " intent " : " review_schedule " , " domain " : " review " , " action " : " ask_missing_fields " } ,
)
await flow . _try_collect_and_schedule_review (
message = " placa ABC1269 " ,
user_id = 21 ,
extracted_fields = { } ,
intents = { } ,
turn_decision = { " intent " : " review_schedule " , " domain " : " review " , " action " : " answer_user " } ,
)
await flow . _try_collect_and_schedule_review (
message = " Eu gostaria de marcar amanha as 16 horas " ,
user_id = 21 ,
extracted_fields = { } ,
intents = { } ,
turn_decision = { " intent " : " review_schedule " , " domain " : " review " , " action " : " answer_user " } ,
)
await flow . _try_collect_and_schedule_review (
message = " O modelo do meu carro e um Onix e ele e 2021 " ,
user_id = 21 ,
extracted_fields = { } ,
intents = { } ,
turn_decision = { " intent " : " review_schedule " , " domain " : " review " , " action " : " answer_user " } ,
)
response = await flow . _try_collect_and_schedule_review (
message = " 30000 km, nunca fiz revisao " ,
user_id = 21 ,
extracted_fields = { } ,
intents = { } ,
turn_decision = { " intent " : " review_schedule " , " domain " : " review " , " action " : " answer_user " } ,
)
self . assertIsNone ( state . get_entry ( " pending_review_drafts " , 21 ) )
self . assertEqual ( registry . calls [ 0 ] [ 0 ] , " agendar_revisao " )
_ , arguments , tool_user_id = registry . calls [ 0 ]
self . assertEqual ( tool_user_id , 21 )
self . assertEqual ( arguments . get ( " placa " ) , " ABC1269 " )
self . assertEqual ( arguments . get ( " data_hora " ) , " 13/03/2026 16:00 " )
self . assertEqual ( arguments . get ( " modelo " ) , " Um Onix " )
self . assertEqual ( arguments . get ( " ano " ) , 2021 )
self . assertEqual ( arguments . get ( " km " ) , 30000 )
self . assertFalse ( arguments . get ( " revisao_previa_concessionaria " ) )
self . assertIn ( " REV-TESTE-123 " , response )
async def test_review_flow_bootstraps_from_active_review_context_when_draft_is_missing ( self ) :
state = FakeState (
contexts = {
21 : {
" active_domain " : " review " ,
" generic_memory " : { } ,
" shared_memory " : { } ,
" order_queue " : [ ] ,
" pending_order_selection " : None ,
" pending_switch " : None ,
" last_stock_results " : [ ] ,
" selected_vehicle " : None ,
}
}
)
registry = FakeRegistry ( )
flow = ReviewFlowHarness ( state = state , registry = registry )
response = await flow . _try_collect_and_schedule_review (
message = " placa ABC1269 " ,
user_id = 21 ,
extracted_fields = { } ,
intents = { } ,
turn_decision = { " intent " : " general " , " domain " : " general " , " action " : " answer_user " } ,
)
draft = state . get_entry ( " pending_review_drafts " , 21 )
self . assertIsNotNone ( draft )
self . assertEqual ( draft [ " payload " ] [ " placa " ] , " ABC1269 " )
self . assertIn ( " a data e hora desejada para a revisao " , response )
self . assertTrue (
any ( payload . get ( " review_flow_source " ) == " active_domain_fallback " for _ , payload in flow . logged_events )
)
async def test_review_flow_offers_reuse_of_last_vehicle_package ( self ) :
state = FakeState (
entries = {
" last_review_packages " : {
21 : {
" payload " : {
" placa " : " ABC1234 " ,
" modelo " : " Corolla " ,
" ano " : 2020 ,
" km " : 30000 ,
" revisao_previa_concessionaria " : True ,
} ,
" expires_at " : datetime . utcnow ( ) + timedelta ( minutes = 30 ) ,
}
}
}
)
registry = FakeRegistry ( )
flow = ReviewFlowHarness ( state = state , registry = registry )
response = await flow . _try_collect_and_schedule_review (
message = " gostaria de agendar uma nova revisao agora " ,
user_id = 21 ,
extracted_fields = { } ,
intents = { } ,
turn_decision = { " intent " : " review_schedule " , " domain " : " review " , " action " : " collect_review_schedule " } ,
)
self . assertIn ( " Posso reutilizar os dados do ultimo veiculo " , response )
self . assertIn ( " Corolla " , response )
self . assertIn ( " ABC1234 " , response )
self . assertIsNotNone ( state . get_entry ( " pending_review_reuse_confirmations " , 21 ) )
self . assertTrue (
any ( payload . get ( " review_flow_source " ) == " last_review_package " for _ , payload in flow . logged_events )
)
async def test_review_flow_rejects_reuse_and_accepts_new_vehicle_in_same_message ( self ) :
state = FakeState (
entries = {
" pending_review_reuse_confirmations " : {
21 : {
" payload " : {
" placa " : " ABC1234 " ,
" modelo " : " Corolla " ,
" ano " : 2020 ,
" km " : 30000 ,
" revisao_previa_concessionaria " : True ,
} ,
" expires_at " : datetime . utcnow ( ) + timedelta ( minutes = 30 ) ,
}
}
}
)
registry = FakeRegistry ( )
flow = ReviewFlowHarness ( state = state , registry = registry )
response = await flow . _try_collect_and_schedule_review (
message = " nao, agora e outro veiculo, placa ABC1269 " ,
user_id = 21 ,
extracted_fields = { " placa " : " ABC1269 " } ,
intents = { } ,
turn_decision = { " intent " : " review_schedule " , " domain " : " review " , " action " : " collect_review_schedule " } ,
)
draft = state . get_entry ( " pending_review_drafts " , 21 )
self . assertIsNone ( state . get_entry ( " pending_review_reuse_confirmations " , 21 ) )
self . assertIsNotNone ( draft )
self . assertEqual ( draft [ " payload " ] . get ( " placa " ) , " ABC1269 " )
self . assertIn ( " a data e hora desejada para a revisao " , response )
async def test_review_flow_keeps_draft_and_clears_data_hora_on_retryable_error ( self ) :
state = FakeState (
entries = {
@ -864,6 +1252,184 @@ class ReviewFlowDraftTests(unittest.IsolatedAsyncioTestCase):
self . assertEqual ( draft [ " payload " ] . get ( " placa " ) , " ABC1234 " )
self . assertNotIn ( " data_hora " , draft [ " payload " ] )
async def test_review_management_infers_cancel_intent_from_protocol_message ( self ) :
state = FakeState ( )
registry = FakeRegistry ( )
flow = ReviewFlowHarness ( state = state , registry = registry )
response = await flow . _try_handle_review_management (
message = " eu gostaria de cancelar o meu agendamento REV-20260313-F754AF27 " ,
user_id = 21 ,
extracted_fields = { } ,
intents = { } ,
turn_decision = { " intent " : " review_schedule " , " domain " : " review " , " action " : " answer_user " } ,
)
self . assertEqual ( registry . calls [ 0 ] [ 0 ] , " cancelar_agendamento_revisao " )
self . assertEqual ( registry . calls [ 0 ] [ 1 ] [ " protocolo " ] , " REV-20260313-F754AF27 " )
self . assertIn ( " cancelar_agendamento_revisao " , response )
self . assertIn ( " REV-20260313-F754AF27 " , response )
async def test_review_management_infers_listing_intent_from_agendamentos_message ( self ) :
state = FakeState ( )
registry = FakeRegistry ( )
flow = ReviewFlowHarness ( state = state , registry = registry )
response = await flow . _try_handle_review_management (
message = " liste para mim os meus agendamentos de revisao " ,
user_id = 21 ,
extracted_fields = { } ,
intents = { } ,
turn_decision = { " intent " : " general " , " domain " : " general " , " action " : " answer_user " } ,
)
self . assertEqual ( registry . calls [ 0 ] [ 0 ] , " listar_agendamentos_revisao " )
self . assertIn ( " listar_agendamentos_revisao " , response )
async def test_review_schedule_clears_open_management_draft ( self ) :
state = FakeState (
entries = {
" pending_review_management_drafts " : {
21 : {
" action " : " reschedule " ,
" payload " : { " protocolo " : " REV-20260313-F754AF27 " } ,
" expires_at " : datetime . utcnow ( ) + timedelta ( minutes = 30 ) ,
}
}
}
)
registry = FakeRegistry ( )
flow = ReviewFlowHarness ( state = state , registry = registry )
response = await flow . _try_handle_review_management (
message = " quero agendar uma revisao " ,
user_id = 21 ,
extracted_fields = { } ,
intents = { } ,
turn_decision = { " intent " : " review_schedule " , " domain " : " review " , " action " : " answer_user " } ,
)
self . assertIsNone ( response )
self . assertIsNone ( state . get_entry ( " pending_review_management_drafts " , 21 ) )
async def test_review_management_does_not_override_open_schedule_draft_without_protocol ( self ) :
state = FakeState (
entries = {
" pending_review_drafts " : {
21 : {
" payload " : {
" placa " : " ABC1234 " ,
" modelo " : " Corolla " ,
" ano " : 2020 ,
" km " : 30000 ,
" revisao_previa_concessionaria " : True ,
} ,
" expires_at " : datetime . utcnow ( ) + timedelta ( minutes = 30 ) ,
}
}
}
)
registry = FakeRegistry ( )
flow = ReviewFlowHarness ( state = state , registry = registry )
response = await flow . _try_handle_review_management (
message = " pode ser hoje as 17:30 " ,
user_id = 21 ,
extracted_fields = { } ,
intents = { } ,
turn_decision = { " intent " : " review_reschedule " , " domain " : " review " , " action " : " answer_user " } ,
)
self . assertIsNone ( response )
self . assertIsNone ( state . get_entry ( " pending_review_management_drafts " , 21 ) )
async def test_review_schedule_flow_ignores_management_message_with_protocol ( self ) :
state = FakeState (
contexts = {
21 : {
" active_domain " : " review " ,
" generic_memory " : { } ,
" shared_memory " : { } ,
" order_queue " : [ ] ,
" pending_order_selection " : None ,
" pending_switch " : None ,
" last_stock_results " : [ ] ,
" selected_vehicle " : None ,
}
}
)
registry = FakeRegistry ( )
flow = ReviewFlowHarness ( state = state , registry = registry )
response = await flow . _try_collect_and_schedule_review (
message = " eu gostaria de cancelar o meu agendamento REV-20260313-F754AF27 " ,
user_id = 21 ,
extracted_fields = { } ,
intents = { } ,
turn_decision = { " intent " : " review_schedule " , " domain " : " review " , " action " : " answer_user " } ,
)
self . assertIsNone ( response )
self . assertEqual ( registry . calls , [ ] )
async def test_review_flow_does_not_bootstrap_sales_message_from_active_review_context ( self ) :
state = FakeState (
contexts = {
21 : {
" active_domain " : " review " ,
" generic_memory " : { } ,
" shared_memory " : { } ,
" order_queue " : [ ] ,
" pending_order_selection " : None ,
" pending_switch " : None ,
" last_stock_results " : [ ] ,
" selected_vehicle " : None ,
}
}
)
registry = FakeRegistry ( )
flow = ReviewFlowHarness ( state = state , registry = registry )
response = await flow . _try_collect_and_schedule_review (
message = " quero comprar um carro de ate 70 mil " ,
user_id = 21 ,
extracted_fields = { } ,
intents = { } ,
turn_decision = { " intent " : " general " , " domain " : " general " , " action " : " answer_user " } ,
)
self . assertIsNone ( response )
self . assertIsNone ( state . get_entry ( " pending_review_drafts " , 21 ) )
class ContextSwitchPolicyTests ( unittest . TestCase ) :
def test_handle_context_switch_drops_stale_pending_switch_when_user_starts_other_domain ( self ) :
state = FakeState (
contexts = {
9 : {
" pending_switch " : {
" target_domain " : " sales " ,
" expires_at " : datetime . utcnow ( ) + timedelta ( minutes = 15 ) ,
} ,
" active_domain " : " general " ,
" generic_memory " : { } ,
" pending_order_selection " : None ,
}
}
)
service = FakeService ( state )
policy = ConversationPolicy ( service = service )
response = policy . handle_context_switch (
message = " quero agendar revisao " ,
user_id = 9 ,
target_domain_hint = " review " ,
turn_decision = { " domain " : " review " , " intent " : " review_schedule " , " action " : " collect_review_schedule " } ,
)
self . assertIsNone ( response )
self . assertIsNone ( service . _get_user_context ( 9 ) . get ( " pending_switch " ) )
if __name__ == " __main__ " :
unittest . main ( )