mirror of
https://github.com/hoshikawa2/agent_platform_oci.git
synced 2026-11-06 03:14:12 +00:00
new feature: LOCALE pt-BR/en
This commit is contained in:
@@ -1285,11 +1285,14 @@ async def test_prevalidation_parameter_message_is_used_once_without_changing_tra
|
||||
assert runtime.transaction_clarification_message(state) != expected
|
||||
assert "transaction_parameter_message_override" not in state
|
||||
|
||||
class _TemporalFallbackRuntime(AgentRuntimeMixin):
|
||||
class _SingleExtractorValidationRuntime(AgentRuntimeMixin):
|
||||
def __init__(self):
|
||||
from types import SimpleNamespace
|
||||
self.calls = []
|
||||
self.llm = None
|
||||
self.extractions = iter([
|
||||
{"subject": "dezenove e noventa e nove"},
|
||||
{"subject": "Tamboro Mensal"},
|
||||
])
|
||||
self.tool_router = SimpleNamespace(
|
||||
registry=SimpleNamespace(
|
||||
get_tool=lambda name: SimpleNamespace(
|
||||
@@ -1308,72 +1311,63 @@ class _TemporalFallbackRuntime(AgentRuntimeMixin):
|
||||
},
|
||||
)
|
||||
|
||||
async def _extract_transaction_parameters_current_only(self, state, *, tool_name, missing_parameters, known_arguments=None):
|
||||
# Simula o collector tradicional interpretando literalmente a fala atual.
|
||||
return {"subject": "dezenove e noventa e nove"}
|
||||
|
||||
async def _reconcile_transaction_parameters(self, state, *, tool_name, parameter_names, known_arguments=None):
|
||||
# Simula o reconciliador temporal usando tools.yaml + contexto newest->oldest.
|
||||
return {
|
||||
"values": {"subject": "Tamboro Mensal"},
|
||||
"decisions": {"subject": "resolved"},
|
||||
"provenance": {"subject": "history:2"},
|
||||
"clear_fields": [],
|
||||
}
|
||||
async def _extract_transaction_parameters(self, state, *, tool_name, missing_parameters, known_arguments=None):
|
||||
# Simula a saída do extractor por turno; não interpreta frases do prompt.
|
||||
return next(self.extractions)
|
||||
|
||||
async def _call_mcp_tool(self, tool_name, arguments, state):
|
||||
self.calls.append((tool_name, dict(arguments)))
|
||||
if tool_name == "validar_vas_subject":
|
||||
subject = arguments.get("subject")
|
||||
if subject == "Tamboro Mensal":
|
||||
if arguments.get("subject") == "Tamboro Mensal":
|
||||
return {"ok": True, "tool_name": tool_name, "result": {"eligible": True, "status": "ELIGIBLE"}}
|
||||
return {"ok": True, "tool_name": tool_name, "result": {
|
||||
"eligible": False,
|
||||
"status": "NEEDS_PARAMETER",
|
||||
"parameter": "subject",
|
||||
"reason": "subject_not_resolved",
|
||||
"eligible": False, "status": "NEEDS_PARAMETER",
|
||||
"parameter": "subject", "reason": "subject_not_resolved",
|
||||
}}
|
||||
return {"ok": True, "tool_name": tool_name, "result": {"status": "OK"}}
|
||||
raise AssertionError("A operação não pode executar antes da confirmação")
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_temporal_reconciler_is_fallback_after_traditional_candidate_fails_prevalidation():
|
||||
runtime = _TemporalFallbackRuntime()
|
||||
async def test_prevalidation_rejection_recollects_next_turn_without_hidden_retry():
|
||||
# Histórico: 1711575 (2026-09-07) removeu candidatos estruturais;
|
||||
# 82636ec (2026-09-08) adotou single_extractor. O antigo teste exigia
|
||||
# uma segunda reconciliação/validação escondida no mesmo turno.
|
||||
# Contrato atual: respeitar NEEDS_PARAMETER, aguardar nova informação e
|
||||
# validar novamente antes de pedir confirmação, sem executar a operação.
|
||||
runtime = _SingleExtractorValidationRuntime()
|
||||
state = {
|
||||
"user_text": "é a de dezenove e noventa e nove",
|
||||
"sanitized_input": "é a de dezenove e noventa e nove",
|
||||
"route": "contestacao_agent",
|
||||
"intent": "state:COLLECTING_CONTESTACAO_PARAMETERS",
|
||||
"route": "contestacao_agent", "intent": "state:COLLECTING_CONTESTACAO_PARAMETERS",
|
||||
"transaction_status": "COLLECTING_PARAMETERS",
|
||||
"selected_tool_call": {"tool_name": "cancelar_vas_avulso", "arguments": {}},
|
||||
"active_transaction": {
|
||||
"transaction_id": "tx-1",
|
||||
"tool_name": "cancelar_vas_avulso",
|
||||
"arguments": {},
|
||||
"status": "COLLECTING_PARAMETERS",
|
||||
"started_from_intent": "contas_vas_cancel",
|
||||
"requires": ["subject"],
|
||||
"transaction_id": "tx-1", "tool_name": "cancelar_vas_avulso",
|
||||
"arguments": {}, "status": "COLLECTING_PARAMETERS",
|
||||
"started_from_intent": "contas_vas_cancel", "requires": ["subject"],
|
||||
"parameter_schema": {"subject": {"type": "string", "description": "Nome do serviço ou VAS alvo do cancelamento."}},
|
||||
"tool_description": "Cancela o serviço VAS selecionado pelo cliente.",
|
||||
"parameter_conversational_context": (
|
||||
"user: não reconheço esse Tamboro Mensal na minha fatura\n"
|
||||
"assistant: identifiquei Tamboro Mensal por R$ 14,99 e R$ 19,99"
|
||||
),
|
||||
},
|
||||
"context": {},
|
||||
}
|
||||
|
||||
result = await runtime.execute_tools_for_intent(state, tools=[])
|
||||
await runtime.execute_tools_for_intent(state, tools=[])
|
||||
assert [(name, args["subject"]) for name, args in runtime.calls] == [
|
||||
("validar_vas_subject", "dezenove e noventa e nove")
|
||||
]
|
||||
assert state["transaction_status"] == "COLLECTING_PARAMETERS"
|
||||
assert "subject" in state["missing_parameters"]
|
||||
assert not state["active_transaction"]["arguments"].get("subject")
|
||||
assert not state.get("confirmation_received")
|
||||
|
||||
validations = [(name, args.get("subject")) for name, args in runtime.calls if name == "validar_vas_subject"]
|
||||
assert validations == [
|
||||
state["user_text"] = state["sanitized_input"] = "o serviço Tamboro Mensal"
|
||||
result = await runtime.execute_tools_for_intent(state, tools=[])
|
||||
assert [(name, args["subject"]) for name, args in runtime.calls] == [
|
||||
("validar_vas_subject", "dezenove e noventa e nove"),
|
||||
("validar_vas_subject", "Tamboro Mensal"),
|
||||
]
|
||||
assert state["transaction_parameter_collection"]["mode"] == "current_turn"
|
||||
assert state["transaction_parameter_reconciliation"]["trigger"] == "prevalidation_needs_parameter"
|
||||
assert state["pending_tool_call"]["arguments"]["subject"] == "Tamboro Mensal"
|
||||
assert state["transaction_status"] == "AWAITING_CONFIRMATION"
|
||||
assert not state.get("confirmation_received")
|
||||
assert result[-1]["awaiting_confirmation"] is True
|
||||
|
||||
@pytest.mark.asyncio
|
||||
|
||||
Reference in New Issue
Block a user