mirror of
https://github.com/hoshikawa2/agent_platform_oci.git
synced 2026-09-07 18:23:46 +00:00
241 lines
9.2 KiB
Python
241 lines
9.2 KiB
Python
import pytest
|
|
from types import SimpleNamespace
|
|
|
|
from agent_framework.routing.enterprise_router import EnterpriseRouter
|
|
from agent_framework.routing.models import RouteDecision
|
|
|
|
|
|
def test_explicit_keyword_shift_preempts_stickiness():
|
|
d = RouteDecision(route="support_agent", agent="support_agent", intent="retail_support_exchange_return", method="keyword", metadata={"matched_keyword": "devolver pedido"})
|
|
assert EnterpriseRouter._is_explicit_intent_shift(d) is True
|
|
|
|
|
|
def test_configured_keyword_is_explicit_regardless_of_literal_length():
|
|
d = RouteDecision(route="x", agent="x", intent="x", method="keyword", metadata={"matched_keyword": "id"})
|
|
assert EnterpriseRouter._is_explicit_intent_shift(d) is True
|
|
|
|
|
|
def test_same_agent_explicit_intent_shift_must_preempt_stickiness():
|
|
router = object.__new__(EnterpriseRouter)
|
|
router.intents = []
|
|
# This test documents the key regression: changing from a read-only intent
|
|
# to a transactional intent handled by the SAME agent must still be treated
|
|
# as an explicit intent shift. The route() integration tests exercise the
|
|
# full async path; here we lock the explicitness predicate itself.
|
|
d = RouteDecision(
|
|
route="orders_agent",
|
|
agent="orders_agent",
|
|
intent="retail_order_cancel",
|
|
method="keyword",
|
|
metadata={"matched_keyword": "cancelar pedido"},
|
|
)
|
|
assert EnterpriseRouter._is_explicit_intent_shift(d) is True
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_same_agent_transaction_keyword_preempts_continuity(monkeypatch):
|
|
"""Regression: tracking -> cancelar pedido must not reuse tracking intent."""
|
|
from agent_framework.routing.models import IntentDefinition
|
|
|
|
class _Continuity:
|
|
async def evaluate(self, state, *, intents):
|
|
raise AssertionError("continuity must be preempted by explicit intent shift")
|
|
|
|
router = object.__new__(EnterpriseRouter)
|
|
router.state_policies = []
|
|
router.intents = [
|
|
IntentDefinition(
|
|
name="retail_order_cancel",
|
|
domain="retail",
|
|
agent="orders_agent",
|
|
description="cancelamento",
|
|
priority=20,
|
|
mcp_tools=["consultar_pedido", "cancelar_pedido"],
|
|
keywords=["cancelar pedido"],
|
|
examples=[],
|
|
enabled=True,
|
|
),
|
|
IntentDefinition(
|
|
name="retail_order_tracking",
|
|
domain="retail",
|
|
agent="orders_agent",
|
|
description="tracking",
|
|
priority=30,
|
|
mcp_tools=["consultar_pedido", "consultar_entrega"],
|
|
keywords=["pedido"],
|
|
examples=[],
|
|
enabled=True,
|
|
),
|
|
]
|
|
router.continuity = _Continuity()
|
|
router.enable_llm_router = False
|
|
router.llm = None
|
|
router.telemetry = None
|
|
router.fallback_agent = "billing_agent"
|
|
|
|
decision = await router.route({
|
|
"user_text": "quero cancelar pedido",
|
|
"sanitized_input": "quero cancelar pedido",
|
|
"active_agent": "orders_agent",
|
|
"intent": "retail_order_tracking",
|
|
"route_decision": {
|
|
"route": "orders_agent",
|
|
"agent": "orders_agent",
|
|
"intent": "retail_order_tracking",
|
|
"domain": "retail",
|
|
"mcp_tools": ["consultar_pedido", "consultar_entrega"],
|
|
},
|
|
"context": {"session": {}},
|
|
})
|
|
|
|
assert decision.agent == "orders_agent"
|
|
assert decision.intent == "retail_order_cancel"
|
|
assert decision.method == "keyword"
|
|
assert decision.mcp_tools == ["consultar_pedido", "cancelar_pedido"]
|
|
assert decision.metadata["route_stickiness_preempted"] is True
|
|
assert decision.metadata["previous_agent"] == "orders_agent"
|
|
assert decision.metadata["previous_intent"] == "retail_order_tracking"
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
"message",
|
|
[
|
|
"quero cancelar meu pedido",
|
|
"quero cancelar o meu pedido",
|
|
"pode cancelar esse pedido",
|
|
"gostaria de cancelar meu pedido",
|
|
],
|
|
)
|
|
@pytest.mark.asyncio
|
|
async def test_same_agent_transaction_shift_with_inserted_words_is_deterministic(message):
|
|
"""Inserted connector/pronoun words must not force an LLM continuity call."""
|
|
from agent_framework.routing.models import IntentDefinition
|
|
|
|
class _Continuity:
|
|
async def evaluate(self, state, *, intents):
|
|
raise AssertionError("continuity LLM must not run for explicit deterministic transaction shift")
|
|
|
|
router = object.__new__(EnterpriseRouter)
|
|
router.state_policies = []
|
|
router.intents = [
|
|
IntentDefinition(
|
|
name="retail_order_cancel", domain="retail", agent="orders_agent",
|
|
description="cancelamento", priority=20,
|
|
mcp_tools=["consultar_pedido", "cancelar_pedido"],
|
|
keywords=["cancelar pedido"], examples=[], enabled=True,
|
|
),
|
|
IntentDefinition(
|
|
name="retail_order_tracking", domain="retail", agent="orders_agent",
|
|
description="tracking", priority=30,
|
|
mcp_tools=["consultar_pedido", "consultar_entrega"],
|
|
keywords=["pedido"], examples=[], enabled=True,
|
|
),
|
|
]
|
|
router.continuity = _Continuity()
|
|
router.enable_llm_router = False
|
|
router.llm = None
|
|
router.telemetry = None
|
|
router.fallback_agent = "billing_agent"
|
|
|
|
decision = await router.route({
|
|
"user_text": message, "sanitized_input": message,
|
|
"active_agent": "orders_agent", "intent": "retail_order_tracking",
|
|
"route_decision": {
|
|
"route": "orders_agent", "agent": "orders_agent",
|
|
"intent": "retail_order_tracking", "domain": "retail",
|
|
"mcp_tools": ["consultar_pedido", "consultar_entrega"],
|
|
},
|
|
"context": {"session": {}},
|
|
})
|
|
|
|
assert decision.intent == "retail_order_cancel"
|
|
assert decision.agent == "orders_agent"
|
|
assert decision.mcp_tools == ["consultar_pedido", "cancelar_pedido"]
|
|
assert decision.metadata["route_stickiness_preempted"] is True
|
|
assert decision.metadata["keyword_match_strategy"] == "ordered_tokens"
|
|
|
|
|
|
def test_ordered_keyword_match_is_conservative():
|
|
assert EnterpriseRouter._ordered_keyword_match("cancelar pedido", "quero cancelar meu pedido") is True
|
|
assert EnterpriseRouter._ordered_keyword_match("cancelar pedido", "quero pedido e talvez cancelar depois") is False
|
|
assert EnterpriseRouter._ordered_keyword_match("pedido", "meu pedido") is False
|
|
|
|
|
|
def test_ordered_content_keyword_match_tolerates_omitted_short_connectors():
|
|
assert EnterpriseRouter._ordered_content_keyword_match(
|
|
"qual é o meu plano", "qual o meu plano"
|
|
) is True
|
|
assert EnterpriseRouter._ordered_content_keyword_match(
|
|
"qual é o meu plano", "quero ver minha fatura"
|
|
) is False
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_loaded_domain_style_plan_shift_preempts_continuity_without_llm():
|
|
"""Regression: invoice -> plan must work from configured keywords, even same agent.
|
|
|
|
This mirrors applications such as Contas where two intents may be handled by
|
|
the same agent but require different MCP tools. The routing core must not
|
|
know application-specific intent or agent names.
|
|
"""
|
|
from agent_framework.routing.models import IntentDefinition
|
|
|
|
class _Continuity:
|
|
async def evaluate(self, state, *, intents):
|
|
raise AssertionError("continuity LLM must not run for explicit configured intent shift")
|
|
|
|
router = object.__new__(EnterpriseRouter)
|
|
router.state_policies = []
|
|
router.intents = [
|
|
IntentDefinition(
|
|
name="domain_plan_information",
|
|
domain="customer_domain",
|
|
agent="customer_agent",
|
|
description="informações de plano",
|
|
priority=142,
|
|
mcp_tools=["consultar_plano"],
|
|
keywords=["qual é o meu plano", "plano contratado"],
|
|
examples=[],
|
|
enabled=True,
|
|
),
|
|
IntentDefinition(
|
|
name="domain_invoice_query",
|
|
domain="customer_domain",
|
|
agent="customer_agent",
|
|
description="consulta de fatura",
|
|
priority=140,
|
|
mcp_tools=["consultar_faturas"],
|
|
keywords=["quero minha fatura", "fatura atual"],
|
|
examples=[],
|
|
enabled=True,
|
|
),
|
|
]
|
|
router.continuity = _Continuity()
|
|
router.enable_llm_router = False
|
|
router.llm = None
|
|
router.telemetry = None
|
|
router.fallback_agent = "customer_agent"
|
|
|
|
message = "qual o meu plano"
|
|
decision = await router.route({
|
|
"user_text": message,
|
|
"sanitized_input": message,
|
|
"active_agent": "customer_agent",
|
|
"intent": "domain_invoice_query",
|
|
"route_decision": {
|
|
"route": "customer_agent",
|
|
"agent": "customer_agent",
|
|
"intent": "domain_invoice_query",
|
|
"domain": "customer_domain",
|
|
"mcp_tools": ["consultar_faturas"],
|
|
},
|
|
"context": {"session": {}},
|
|
})
|
|
|
|
assert decision.intent == "domain_plan_information"
|
|
assert decision.agent == "customer_agent"
|
|
assert decision.mcp_tools == ["consultar_plano"]
|
|
assert decision.method == "keyword"
|
|
assert decision.metadata["route_stickiness_preempted"] is True
|
|
assert decision.metadata["previous_intent"] == "domain_invoice_query"
|
|
assert decision.metadata["keyword_match_strategy"] == "ordered_content_tokens"
|