Files
agent/tests/unit_tests/rag/test_intent_router_invariants.py
T
2026-03-27 15:51:10 +03:00

205 lines
8.6 KiB
Python

import pytest
from tests.unit_tests.rag.asserts_intent_router import (
assert_domain_layer_prefixes,
assert_domains,
assert_file_only_scope,
assert_has_file_path,
assert_intent,
assert_no_symbol_keyword,
assert_no_symbol_leakage_from_paths,
assert_spans_valid,
assert_sub_intent,
assert_test_policy,
)
from tests.unit_tests.rag.intent_router_testkit import run_sequence
pytestmark = pytest.mark.intent_router
def test_invariant_code_file_path_with_canonical_key_term() -> None:
result = run_sequence(["Уточни по файлу app/core/config.py"])[0]
assert_intent(result, "CODE_QA")
assert_has_file_path(result, "app/core/config.py")
assert_file_only_scope(result, "app/core/config.py")
key_terms = [anchor.value for anchor in result.query_plan.anchors if anchor.type == "KEY_TERM"]
assert "файл" in key_terms
assert "файлу" not in key_terms
assert_spans_valid(result)
assert_domain_layer_prefixes(result)
def test_invariant_open_file_for_specified_file_phrase_uses_narrow_layers() -> None:
result = run_sequence(["Уточни по файлу app/core/config.py"])[0]
assert_intent(result, "CODE_QA")
assert_sub_intent(result, "OPEN_FILE")
assert_file_only_scope(result, "app/core/config.py")
layer_ids = [item.layer_id for item in result.retrieval_spec.layer_queries]
assert layer_ids == ["C0_SOURCE_CHUNKS"]
assert result.evidence_policy.require_flow is False
def test_invariant_inline_code_span_routes_to_code_and_extracts_symbol() -> None:
result = run_sequence(["Уточни по коду `def build(x): return x`"])[0]
assert_intent(result, "CODE_QA")
assert_spans_valid(result)
assert_no_symbol_keyword(result)
symbols = [anchor.value for anchor in result.query_plan.anchors if anchor.type == "SYMBOL"]
key_terms = [anchor.value for anchor in result.query_plan.anchors if anchor.type == "KEY_TERM"]
assert "build" in symbols
assert "def" in key_terms
def test_invariant_docs_cyrillic_path_with_quotes() -> None:
result = run_sequence(["Что сказано в «docs/архитектура.md»?"])[0]
assert_intent(result, "DOCUMENTATION_EXPLAIN")
assert_sub_intent(result, "COMPONENT_EXPLAIN")
assert_domains(result, ["DOCS"])
assert "docs/архитектура.md" in result.query_plan.normalized
assert_has_file_path(result, "docs/архитектура.md")
assert any(anchor.type == "DOC_REF" for anchor in result.query_plan.anchors)
assert result.retrieval_spec.filters.doc_kinds == []
assert_spans_valid(result)
assert_domain_layer_prefixes(result)
def test_invariant_file_check_phrase_not_project_misc() -> None:
result = run_sequence(["Проверь app/modules/rag/explain/intent_builder.py и объясни"])[0]
assert_intent(result, "CODE_QA")
assert_domains(result, ["CODE"])
assert_no_symbol_leakage_from_paths(result)
assert_domain_layer_prefixes(result)
def test_invariant_tests_include_routing() -> None:
result = run_sequence(["Где тесты на ConfigManager?"])[0]
assert_intent(result, "CODE_QA")
assert_test_policy(result, "INCLUDE")
symbols = [anchor.value for anchor in result.query_plan.anchors if anchor.type == "SYMBOL"]
key_terms = [anchor.value for anchor in result.query_plan.anchors if anchor.type == "KEY_TERM"]
assert "ConfigManager" in symbols
assert "тест" in key_terms
def test_invariant_keyword_hints_and_expansions_for_function_identifier() -> None:
result = run_sequence(["Теперь объясни функцию load_config"])[0]
assert_intent(result, "CODE_QA")
assert "load_config" in result.query_plan.keyword_hints
assert "функция" not in result.query_plan.keyword_hints
assert "def" not in result.query_plan.expansions
def test_invariant_open_file_sub_intent_uses_narrow_retrieval_profile() -> None:
result = run_sequence(["Открой файл app/core/config.py"])[0]
assert_intent(result, "CODE_QA")
assert_sub_intent(result, "OPEN_FILE")
assert_file_only_scope(result, "app/core/config.py")
layer_ids = [item.layer_id for item in result.retrieval_spec.layer_queries]
assert "C0_SOURCE_CHUNKS" in layer_ids
assert "C1_SYMBOL_CATALOG" not in layer_ids
assert "C2_DEPENDENCY_GRAPH" not in layer_ids
assert "C3_ENTRYPOINTS" not in layer_ids
assert result.evidence_policy.require_flow is False
def test_invariant_docs_question_routes_to_docs() -> None:
result = run_sequence(["Что сказано в документации?"])[0]
assert_intent(result, "DOCUMENTATION_EXPLAIN")
assert_domains(result, ["DOCS"])
assert_domain_layer_prefixes(result)
assert result.query_plan.keyword_hints
assert any(item in result.query_plan.expansions for item in result.query_plan.keyword_hints)
def test_invariant_docs_flow_sub_intent_uses_workflow_layers() -> None:
result = run_sequence(["Как работает процесс создания заказа по документации?"])[0]
assert_intent(result, "DOCUMENTATION_EXPLAIN")
assert_sub_intent(result, "SYSTEM_FLOW_EXPLAIN")
layer_ids = [item.layer_id for item in result.retrieval_spec.layer_queries]
assert layer_ids == ["D4_WORKFLOW_INDEX", "D5_RELATION_GRAPH", "D1_DOCUMENT_CATALOG", "D0_DOC_CHUNKS"]
def test_invariant_docs_entity_sub_intent_uses_entity_layers() -> None:
result = run_sequence(["Что такое сущность Order в документации?"])[0]
assert_intent(result, "DOCUMENTATION_EXPLAIN")
assert_sub_intent(result, "ENTITY_EXPLAIN")
layer_ids = [item.layer_id for item in result.retrieval_spec.layer_queries]
assert layer_ids == ["D3_ENTITY_CATALOG", "D5_RELATION_GRAPH", "D1_DOCUMENT_CATALOG", "D0_DOC_CHUNKS"]
def test_invariant_entity_like_camel_case_prefers_entity_explain() -> None:
result = run_sequence(["Что такое WorkerHealth?"])[0]
assert_intent(result, "DOCUMENTATION_EXPLAIN")
assert_sub_intent(result, "ENTITY_EXPLAIN")
def test_invariant_related_docs_routes_to_docs_explain() -> None:
result = run_sequence(["Найди документацию по billing"])[0]
assert_intent(result, "DOCUMENTATION_EXPLAIN")
assert_sub_intent(result, "RELATED_DOCS_EXPLAIN")
layer_ids = [item.layer_id for item in result.retrieval_spec.layer_queries]
assert layer_ids == ["D5_RELATION_GRAPH", "D1_DOCUMENT_CATALOG", "D0_DOC_CHUNKS"]
def test_invariant_docs_navigation_uses_related_docs_explain() -> None:
result = run_sequence(["Что связано с checkout документацией?"])[0]
assert_intent(result, "DOCUMENTATION_EXPLAIN")
assert_sub_intent(result, "RELATED_DOCS_EXPLAIN")
layer_ids = [item.layer_id for item in result.retrieval_spec.layer_queries]
assert layer_ids == ["D5_RELATION_GRAPH", "D1_DOCUMENT_CATALOG", "D0_DOC_CHUNKS"]
def test_invariant_openapi_routes_to_docs_layers_with_api_filter() -> None:
result = run_sequence(["Сгенерируй openapi yaml для создания заказа"])[0]
assert_intent(result, "OPENAPI_GENERATION")
assert_sub_intent(result, "OPENAPI_METHOD_GENERATE")
layer_ids = [item.layer_id for item in result.retrieval_spec.layer_queries]
assert layer_ids == ["D1_DOCUMENT_CATALOG", "D2_FACT_INDEX", "D0_DOC_CHUNKS"]
assert result.retrieval_spec.filters.doc_type == "api_method"
def test_invariant_general_qa_routes_to_generic_docs_layers() -> None:
result = run_sequence(["Помоги разобраться"])[0]
assert_intent(result, "GENERAL_QA")
assert_sub_intent(result, "GENERIC_QA")
assert_domains(result, ["DOCS"])
layer_ids = [item.layer_id for item in result.retrieval_spec.layer_queries]
assert layer_ids == ["D1_DOCUMENT_CATALOG", "D0_DOC_CHUNKS"]
def test_invariant_component_like_manager_routes_to_component_explain() -> None:
result = run_sequence(["Какую роль в системе играет RuntimeManager?"])[0]
assert_intent(result, "DOCUMENTATION_EXPLAIN")
assert_sub_intent(result, "COMPONENT_EXPLAIN")
def test_invariant_cycle_query_routes_to_system_flow_explain() -> None:
result = run_sequence(["Объясни как работает цикл отправки уведомлений"])[0]
assert_intent(result, "DOCUMENTATION_EXPLAIN")
assert_sub_intent(result, "SYSTEM_FLOW_EXPLAIN")
def test_invariant_overview_question_routes_to_general_qa() -> None:
result = run_sequence(["Что вообще описано в документации по этому сервису?"])[0]
assert_intent(result, "GENERAL_QA")
assert_sub_intent(result, "GENERIC_QA")