фиксирую состояние
This commit is contained in:
@@ -78,3 +78,32 @@ def test_find_files_prefers_exact_path_match() -> None:
|
||||
|
||||
assert files[0].path == "docs/domains/runtime-health-entity.md"
|
||||
assert files[0].match_reason in {"exact_path", "alias_match"}
|
||||
|
||||
|
||||
def test_summary_ranking_penalizes_overview_doc_when_specific_api_doc_exists() -> None:
|
||||
rows = [
|
||||
{
|
||||
"path": "docs/overview/health-overview.md",
|
||||
"title": "Health overview",
|
||||
"content": "",
|
||||
"layer": "D1_DOCUMENT_CATALOG",
|
||||
"metadata": {"summary_text": "Navigation page with related docs.", "document_id": "docs.health_overview"},
|
||||
},
|
||||
{
|
||||
"path": "docs/api/health-endpoint.md",
|
||||
"title": "Health endpoint",
|
||||
"content": "",
|
||||
"layer": "D1_DOCUMENT_CATALOG",
|
||||
"metadata": {"summary_text": "GET /health returns runtime status.", "document_id": "api.health"},
|
||||
},
|
||||
]
|
||||
route = _route(
|
||||
hints=["health", "/health", "health endpoint"],
|
||||
terms=["health"],
|
||||
)
|
||||
|
||||
docs = DocsEvidenceAssembler().assemble_summaries(rows, route)
|
||||
|
||||
assert docs[0].path == "docs/api/health-endpoint.md"
|
||||
assert docs[0].score_breakdown["specificity_boost"] > docs[1].score_breakdown["specificity_boost"]
|
||||
assert docs[1].score_breakdown["generic_penalty"] < 0
|
||||
|
||||
@@ -96,3 +96,38 @@ def test_router_reduces_confidence_for_short_vague_query() -> None:
|
||||
result = V2IntentRouter(llm=FakeLlm(_llm_response("GENERAL", "GENERAL_QA", "SUMMARY", confidence=0.8))).route("Что это?")
|
||||
|
||||
assert result.confidence < 0.8
|
||||
|
||||
|
||||
def test_router_routes_doc_path_to_find_files() -> None:
|
||||
result = V2IntentRouter(llm=FakeLlm(_llm_response("DOCS", "DOC_EXPLAIN", "SUMMARY"))).route("docs/api/health-endpoint.md")
|
||||
|
||||
assert result.subintent == "FIND_FILES"
|
||||
assert result.anchors.file_names == ["docs/api/health-endpoint.md"]
|
||||
assert result.anchors.endpoint_paths == []
|
||||
|
||||
|
||||
def test_router_routes_file_token_to_find_files() -> None:
|
||||
result = V2IntentRouter(llm=FakeLlm(_llm_response("DOCS", "DOC_EXPLAIN", "SUMMARY"))).route("health-endpoint.md")
|
||||
|
||||
assert result.subintent == "FIND_FILES"
|
||||
assert result.anchors.file_names == ["health-endpoint.md"]
|
||||
assert result.anchors.endpoint_paths == []
|
||||
|
||||
|
||||
def test_router_promotes_api_method_query_to_endpoint_specific_docs_summary() -> None:
|
||||
result = V2IntentRouter(llm=FakeLlm(_llm_response("DOCS", "DOC_EXPLAIN", "SUMMARY"))).route("Как работает метод health?")
|
||||
|
||||
assert result.intent == "DOC_EXPLAIN"
|
||||
assert result.subintent == "SUMMARY"
|
||||
assert result.anchors.endpoint_paths == ["/health"]
|
||||
assert "docs/api/health-endpoint.md" in result.anchors.target_doc_hints
|
||||
|
||||
|
||||
def test_router_keeps_short_api_like_token_as_strong_hint_without_explicit_path() -> None:
|
||||
result = V2IntentRouter(llm=FakeLlm(_llm_response("DOCS", "DOC_EXPLAIN", "SUMMARY"))).route("Что делает health?")
|
||||
|
||||
assert result.intent == "DOC_EXPLAIN"
|
||||
assert result.subintent == "SUMMARY"
|
||||
assert result.anchors.endpoint_paths == []
|
||||
assert "health endpoint" in result.anchors.target_doc_hints
|
||||
assert "health" in result.target_terms
|
||||
|
||||
@@ -51,6 +51,7 @@ def test_file_names_accepts_real_doc_path() -> None:
|
||||
anchors = V2AnchorExtractor().extract("docs/api/health.md", terms).anchors
|
||||
|
||||
assert anchors.file_names == ["docs/api/health.md"]
|
||||
assert anchors.endpoint_paths == []
|
||||
|
||||
|
||||
def test_file_names_rejects_endpoint_path() -> None:
|
||||
@@ -60,8 +61,63 @@ def test_file_names_rejects_endpoint_path() -> None:
|
||||
assert anchors.file_names == []
|
||||
|
||||
|
||||
def test_target_terms_drop_noisy_english_file_words() -> None:
|
||||
analysis = V2TargetTermsExtractor().extract("pls show doc for /health")
|
||||
|
||||
assert analysis.target_terms == ["/health"]
|
||||
|
||||
|
||||
def test_doc_path_does_not_become_endpoint_path() -> None:
|
||||
analysis = V2TargetTermsExtractor().extract("docs/api/health-endpoint.md")
|
||||
|
||||
assert analysis.endpoint_paths == []
|
||||
|
||||
|
||||
def test_target_terms_drop_architecture_marker_words() -> None:
|
||||
analysis = V2TargetTermsExtractor().extract("Объясни architecture overview сервиса уведомлений")
|
||||
|
||||
assert "объясни" not in analysis.target_terms
|
||||
assert "architecture" not in analysis.target_terms
|
||||
assert "overview" not in analysis.target_terms
|
||||
|
||||
|
||||
def test_anchor_extractor_extracts_process_domain_and_subdomain() -> None:
|
||||
terms = V2TargetTermsExtractor().extract("Объясни billing invoice process")
|
||||
anchors = V2AnchorExtractor().extract("Объясни billing invoice process", terms).anchors
|
||||
|
||||
assert anchors.process_domain == "billing"
|
||||
assert anchors.process_subdomain == "invoice"
|
||||
|
||||
|
||||
def test_file_names_rejects_identifier_like_token() -> None:
|
||||
terms = V2TargetTermsExtractor().extract("telegram_notify")
|
||||
anchors = V2AnchorExtractor().extract("telegram_notify", terms).anchors
|
||||
|
||||
assert anchors.file_names == []
|
||||
|
||||
|
||||
def test_target_terms_extracts_api_like_anchor_from_method_query() -> None:
|
||||
analysis = V2TargetTermsExtractor().extract("Как работает метод health?")
|
||||
|
||||
assert analysis.target_terms == ["/health", "health"]
|
||||
assert analysis.endpoint_paths == ["/health"]
|
||||
assert analysis.api_like_terms == ["health"]
|
||||
|
||||
|
||||
def test_anchor_extractor_builds_endpoint_hints_for_short_api_like_query() -> None:
|
||||
terms = V2TargetTermsExtractor().extract("Что делает health?")
|
||||
anchors = V2AnchorExtractor().extract("Что делает health?", terms).anchors
|
||||
|
||||
assert anchors.endpoint_paths == []
|
||||
assert "health" in anchors.target_doc_hints
|
||||
assert "/health" in anchors.target_doc_hints
|
||||
assert "health endpoint" in anchors.target_doc_hints
|
||||
|
||||
|
||||
def test_anchor_extractor_keeps_templated_endpoint_for_docs_query() -> None:
|
||||
terms = V2TargetTermsExtractor().extract("Расскажи про endpoint /users/{id}")
|
||||
anchors = V2AnchorExtractor().extract("Расскажи про endpoint /users/{id}", terms).anchors
|
||||
|
||||
assert anchors.endpoint_paths == ["/users/{id}"]
|
||||
assert "/users/{id}" in anchors.target_doc_hints
|
||||
assert "users endpoint" in anchors.target_doc_hints
|
||||
|
||||
@@ -284,3 +284,42 @@ def test_v2_process_can_disable_workflow_llm_for_general_summary() -> None:
|
||||
|
||||
assert "агрегированный статус runtime" in result.answer
|
||||
assert llm.calls == []
|
||||
|
||||
|
||||
def test_v2_process_prefers_canonical_health_doc_over_readme_for_method_query() -> None:
|
||||
llm = FakeLlm("Health explanation.")
|
||||
adapter = FakeRagAdapter(
|
||||
summary_rows=[
|
||||
{
|
||||
"path": "docs/README.md",
|
||||
"title": "README",
|
||||
"content": "",
|
||||
"layer": "D1_DOCUMENT_CATALOG",
|
||||
"metadata": {"summary_text": "General documentation index.", "document_id": "docs.readme"},
|
||||
},
|
||||
{
|
||||
"path": "docs/api/health-endpoint.md",
|
||||
"title": "Health endpoint",
|
||||
"content": "",
|
||||
"layer": "D1_DOCUMENT_CATALOG",
|
||||
"metadata": {
|
||||
"summary_text": "GET /health returns aggregated runtime status.",
|
||||
"document_id": "api.health",
|
||||
},
|
||||
},
|
||||
],
|
||||
file_rows=[],
|
||||
)
|
||||
process = _v2_process(llm, adapter)
|
||||
runtime = _context("Как работает метод health?")
|
||||
|
||||
result = asyncio.run(process.run(runtime))
|
||||
|
||||
assert result.answer == "Health explanation."
|
||||
assert llm.calls
|
||||
assert "docs/api/health-endpoint.md" in llm.calls[0][1]
|
||||
assert "docs/README.md" not in llm.calls[0][1]
|
||||
pipeline_events = [payload for _, title, payload in runtime.trace.events if title == "retrieval_profile_selected"]
|
||||
assert pipeline_events[0]["profile"] == "docs_api_method_explain"
|
||||
evidence_events = [payload for _, title, payload in runtime.trace.events if title == "evidence_assembled"]
|
||||
assert any(event.get("primary_doc") == "docs/api/health-endpoint.md" for event in evidence_events if isinstance(event, dict))
|
||||
|
||||
@@ -0,0 +1,81 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import asyncio
|
||||
|
||||
from app.core.agent.processes.v2.retrieval.v2_rag_adapter import V2RagRetrievalAdapter
|
||||
from app.core.rag.retrieval.session_retriever import RetrievalPlan
|
||||
|
||||
|
||||
class FakeRetriever:
|
||||
def __init__(self) -> None:
|
||||
self.calls: list[tuple[str, object]] = []
|
||||
|
||||
async def retrieve(self, _rag_session_id: str, _query_text: str, _plan: RetrievalPlan) -> list[dict]:
|
||||
self.calls.append(("semantic", None))
|
||||
return [
|
||||
{
|
||||
"path": "docs/api/health-endpoint.md",
|
||||
"layer": "D1_DOCUMENT_CATALOG",
|
||||
"metadata": {},
|
||||
},
|
||||
{
|
||||
"path": "docs/api/secondary.md",
|
||||
"layer": "D0_DOC_CHUNKS",
|
||||
"metadata": {},
|
||||
},
|
||||
]
|
||||
|
||||
async def retrieve_exact_files(self, _rag_session_id: str, *, paths: list[str], layers=None, limit: int = 200) -> list[dict]:
|
||||
del layers, limit
|
||||
self.calls.append(("exact", list(paths)))
|
||||
if "docs/api/health-endpoint.md" in paths:
|
||||
return [
|
||||
{
|
||||
"path": "docs/api/health-endpoint.md",
|
||||
"layer": "D1_DOCUMENT_CATALOG",
|
||||
"metadata": {},
|
||||
}
|
||||
]
|
||||
return []
|
||||
|
||||
async def retrieve_chunks_by_path_substrings(
|
||||
self,
|
||||
_rag_session_id: str,
|
||||
*,
|
||||
path_needles: list[str],
|
||||
layers=None,
|
||||
limit: int = 200,
|
||||
) -> list[dict]:
|
||||
del layers, limit
|
||||
self.calls.append(("substring", list(path_needles)))
|
||||
return []
|
||||
|
||||
|
||||
def test_v2_rag_adapter_seeds_exact_rows_from_plan_hints() -> None:
|
||||
adapter = V2RagRetrievalAdapter(FakeRetriever())
|
||||
plan = RetrievalPlan(
|
||||
profile="docs_summary_api_endpoint",
|
||||
layers=["D1_DOCUMENT_CATALOG", "D2_FACT_INDEX", "D0_DOC_CHUNKS"],
|
||||
limit=8,
|
||||
filters={"target_doc_hints": ["docs/api/health-endpoint.md"]},
|
||||
)
|
||||
|
||||
rows = asyncio.run(adapter.fetch_rows("rag-1", "explain /health", plan))
|
||||
|
||||
assert rows[0]["path"] == "docs/api/health-endpoint.md"
|
||||
assert len(rows) == 2
|
||||
|
||||
|
||||
def test_v2_rag_adapter_uses_substring_fallback_for_missing_hint() -> None:
|
||||
retriever = FakeRetriever()
|
||||
adapter = V2RagRetrievalAdapter(retriever)
|
||||
plan = RetrievalPlan(
|
||||
profile="file_lookup",
|
||||
layers=["D1_DOCUMENT_CATALOG", "D3_ENTITY_CATALOG"],
|
||||
limit=12,
|
||||
filters={"target_doc_hints": ["docs/api/missing-health-endpoint.md"]},
|
||||
)
|
||||
|
||||
asyncio.run(adapter.fetch_rows("rag-1", "find file", plan))
|
||||
|
||||
assert ("substring", ["missing-health-endpoint.md"]) in retriever.calls
|
||||
@@ -4,46 +4,132 @@ from app.core.agent.processes.v2.models import V2Domain, V2Intent, V2RouteAnchor
|
||||
from app.core.agent.processes.v2.retrieval.policy_resolver import V2RetrievalPolicyResolver
|
||||
|
||||
|
||||
def _route(*, hints: list[str], endpoint_paths: list[str] | None = None, subintent: str = "SUMMARY", intent: str = "DOC_EXPLAIN") -> V2RouteResult:
|
||||
def _route(
|
||||
*,
|
||||
intent: str = V2Intent.DOC_EXPLAIN,
|
||||
subintent: str = V2Subintent.SUMMARY,
|
||||
entity_names: list[str] | None = None,
|
||||
file_names: list[str] | None = None,
|
||||
endpoint_paths: list[str] | None = None,
|
||||
target_doc_hints: list[str] | None = None,
|
||||
matched_aliases: list[str] | None = None,
|
||||
process_domain: str | None = None,
|
||||
process_subdomain: str | None = None,
|
||||
) -> V2RouteResult:
|
||||
return V2RouteResult(
|
||||
routing_domain=V2Domain.DOCS if intent == V2Intent.DOC_EXPLAIN else V2Domain.GENERAL,
|
||||
intent=intent,
|
||||
subintent=subintent,
|
||||
user_query="q",
|
||||
normalized_query="q",
|
||||
anchors=V2RouteAnchors(target_doc_hints=hints, endpoint_paths=endpoint_paths or []),
|
||||
anchors=V2RouteAnchors(
|
||||
entity_names=entity_names or [],
|
||||
file_names=file_names or [],
|
||||
endpoint_paths=endpoint_paths or [],
|
||||
target_doc_hints=target_doc_hints or [],
|
||||
matched_aliases=matched_aliases or [],
|
||||
process_domain=process_domain,
|
||||
process_subdomain=process_subdomain,
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
def test_policy_prefers_api_docs_for_endpoint_queries() -> None:
|
||||
def test_policy_maps_api_summary_to_fact_layers() -> None:
|
||||
plan = V2RetrievalPolicyResolver().resolve(
|
||||
_route(hints=["docs/api/health-endpoint.md"], endpoint_paths=["/health"])
|
||||
_route(
|
||||
endpoint_paths=["/health"],
|
||||
target_doc_hints=["docs/api/health-endpoint.md"],
|
||||
)
|
||||
)
|
||||
|
||||
assert plan.profile == "docs_summary_api_endpoint"
|
||||
assert plan.filters["path_prefixes"] == ["docs/api/", "docs/architecture/", "docs/"]
|
||||
assert plan.filters["prefer_path_prefixes"][0] == "docs/api/"
|
||||
assert plan.profile == "docs_api_method_explain"
|
||||
assert plan.layers == ["D1_DOCUMENT_CATALOG", "D2_FACT_INDEX", "D0_DOC_CHUNKS"]
|
||||
assert plan.filters["path_prefixes"] == [
|
||||
"docs/api/",
|
||||
"docs/endpoints/",
|
||||
"docs/methods/",
|
||||
"api/",
|
||||
"endpoints/",
|
||||
"methods/",
|
||||
]
|
||||
assert plan.filters["target_doc_hints"] == ["docs/api/health-endpoint.md"]
|
||||
|
||||
|
||||
def test_policy_prefers_logic_docs_for_logic_queries() -> None:
|
||||
plan = V2RetrievalPolicyResolver().resolve(_route(hints=["docs/logic/telegram-notification-loop.md"]))
|
||||
def test_policy_maps_logic_summary_to_workflow_layers_and_metadata_filters() -> None:
|
||||
plan = V2RetrievalPolicyResolver().resolve(
|
||||
_route(
|
||||
matched_aliases=["logic flow"],
|
||||
process_domain="notifications",
|
||||
process_subdomain="delivery_loop",
|
||||
)
|
||||
)
|
||||
|
||||
assert plan.profile == "docs_summary_logic_flow"
|
||||
assert plan.layers == ["D4_WORKFLOW_INDEX", "D1_DOCUMENT_CATALOG", "D0_DOC_CHUNKS"]
|
||||
assert plan.filters["metadata.domain"] == "notifications"
|
||||
assert plan.filters["metadata.subdomain"] == "delivery_loop"
|
||||
assert plan.filters["prefer_path_prefixes"][0] == "docs/logic/"
|
||||
|
||||
|
||||
def test_policy_uses_deterministic_find_files_profile() -> None:
|
||||
def test_policy_maps_entity_summary_to_entity_layers() -> None:
|
||||
plan = V2RetrievalPolicyResolver().resolve(_route(entity_names=["RuntimeManager"]))
|
||||
|
||||
assert plan.profile == "docs_summary_domain_entity"
|
||||
assert plan.layers == ["D3_ENTITY_CATALOG", "D1_DOCUMENT_CATALOG", "D0_DOC_CHUNKS"]
|
||||
assert "%runtimemanager%" in plan.filters["prefer_like_patterns"]
|
||||
|
||||
|
||||
def test_policy_keeps_api_method_profile_even_with_additional_entity_signal() -> None:
|
||||
plan = V2RetrievalPolicyResolver().resolve(
|
||||
_route(hints=["docs/api/health-endpoint.md"], endpoint_paths=["/health"], subintent=V2Subintent.FIND_FILES)
|
||||
_route(
|
||||
endpoint_paths=["/health"],
|
||||
entity_names=["RuntimeManager"],
|
||||
)
|
||||
)
|
||||
|
||||
assert plan.profile == "docs_api_method_explain"
|
||||
assert plan.layers == ["D1_DOCUMENT_CATALOG", "D2_FACT_INDEX", "D0_DOC_CHUNKS"]
|
||||
|
||||
|
||||
def test_policy_uses_api_method_profile_for_endpoint_like_hints_without_explicit_path() -> None:
|
||||
plan = V2RetrievalPolicyResolver().resolve(
|
||||
_route(
|
||||
target_doc_hints=["health", "/health", "health endpoint"],
|
||||
)
|
||||
)
|
||||
|
||||
assert plan.profile == "docs_api_method_explain"
|
||||
assert "%health%" in plan.filters["prefer_like_patterns"]
|
||||
|
||||
|
||||
def test_policy_uses_hard_and_soft_filters_for_find_files() -> None:
|
||||
plan = V2RetrievalPolicyResolver().resolve(
|
||||
_route(
|
||||
subintent=V2Subintent.FIND_FILES,
|
||||
file_names=["docs/workflows/manual-send.md"],
|
||||
entity_names=["ManualSendWorker"],
|
||||
matched_aliases=["manual send"],
|
||||
process_domain="messaging",
|
||||
process_subdomain="manual_send",
|
||||
)
|
||||
)
|
||||
|
||||
assert plan.profile == "file_lookup"
|
||||
assert plan.layers == ["D1_DOCUMENT_CATALOG", "D3_ENTITY_CATALOG"]
|
||||
assert "health-endpoint.md" in plan.filters["prefer_like_patterns"][0]
|
||||
assert plan.filters["path_prefixes"] == ["docs/workflows/"]
|
||||
assert plan.filters["metadata.domain"] == "messaging"
|
||||
assert "%manualsendworker%" in plan.filters["prefer_like_patterns"]
|
||||
|
||||
|
||||
def test_policy_uses_grounded_general_profile() -> None:
|
||||
plan = V2RetrievalPolicyResolver().resolve(_route(hints=[], intent=V2Intent.GENERAL_QA))
|
||||
def test_policy_keeps_general_routes_in_general_profile() -> None:
|
||||
plan = V2RetrievalPolicyResolver().resolve(
|
||||
_route(
|
||||
intent=V2Intent.GENERAL_QA,
|
||||
endpoint_paths=["/health"],
|
||||
target_doc_hints=["docs/api/health-endpoint.md"],
|
||||
)
|
||||
)
|
||||
|
||||
assert plan.profile == "general_qa_grounded_summary"
|
||||
assert plan.filters["prefer_path_prefixes"][0] == "docs/architecture/"
|
||||
assert plan.layers == ["D1_DOCUMENT_CATALOG", "D0_DOC_CHUNKS"]
|
||||
assert "path_prefixes" not in plan.filters
|
||||
|
||||
@@ -1,4 +1,8 @@
|
||||
import logging
|
||||
|
||||
from app.core.rag.contracts.enums import RagLayer
|
||||
from app.core.rag.indexing.docs.chunkers.markdown_chunker import SectionChunk
|
||||
from app.core.rag.indexing.docs.integration_extractor import DocsIntegrationExtractor
|
||||
from app.core.rag.indexing.docs.pipeline import DocsIndexingPipeline
|
||||
|
||||
|
||||
@@ -153,3 +157,150 @@ Create invoice
|
||||
assert integration_doc.metadata["target"] == "db.billing.invoices"
|
||||
assert integration_doc.metadata["target_type"] == "db"
|
||||
assert integration_doc.metadata["details"]["transaction"] == "required"
|
||||
|
||||
|
||||
def test_docs_integration_extractor_keeps_valid_blocks() -> None:
|
||||
extractor = DocsIntegrationExtractor()
|
||||
sections = [
|
||||
SectionChunk(
|
||||
section_path="Details > Интеграции > Billing DB",
|
||||
section_title="Billing DB",
|
||||
content=(
|
||||
"- target: db.billing.invoices\n"
|
||||
"- target_type: db\n"
|
||||
"- direction: outbound\n"
|
||||
"- interaction: writes\n"
|
||||
"- via: invoice repository\n"
|
||||
"- purpose: persist created invoices\n"
|
||||
"- details:\n"
|
||||
" - transaction: required\n"
|
||||
" - tables:\n"
|
||||
" - invoices\n"
|
||||
" - invoice_items\n"
|
||||
),
|
||||
order=0,
|
||||
)
|
||||
]
|
||||
|
||||
records = extractor.extract(sections, path="docs/billing/create_invoice.md")
|
||||
|
||||
assert len(records) == 1
|
||||
assert records[0].target == "db.billing.invoices"
|
||||
assert records[0].details["transaction"] == "required"
|
||||
assert records[0].details["tables"] == ["invoices", "invoice_items"]
|
||||
|
||||
|
||||
def test_docs_integration_extractor_soft_fails_on_markdown_like_yaml(caplog) -> None:
|
||||
extractor = DocsIntegrationExtractor()
|
||||
sections = [
|
||||
SectionChunk(
|
||||
section_path="Details > Интеграции > Runtime health provider",
|
||||
section_title="Runtime health provider",
|
||||
content=(
|
||||
"- target: runtime.health_provider\n"
|
||||
"- target_type: service\n"
|
||||
"- direction: outbound\n"
|
||||
"- interaction: depends_on\n"
|
||||
"- via: async callback `health_provider()`\n"
|
||||
"- purpose: получить агрегированный health runtime\n"
|
||||
"- details:\n"
|
||||
" - timeout_ms: 5000\n"
|
||||
" - response_type: `HealthPayload`\n"
|
||||
),
|
||||
order=0,
|
||||
)
|
||||
]
|
||||
|
||||
with caplog.at_level(logging.WARNING):
|
||||
records = extractor.extract(sections, path="docs/api/health-endpoint.md")
|
||||
|
||||
assert len(records) == 1
|
||||
assert records[0].target == "runtime.health_provider"
|
||||
assert records[0].via == "async callback `health_provider()`"
|
||||
assert records[0].details == {}
|
||||
assert "docs integration parse warning" in caplog.text
|
||||
assert "docs/api/health-endpoint.md" in caplog.text
|
||||
|
||||
|
||||
def test_docs_pipeline_keeps_other_layers_when_integration_block_is_invalid(caplog) -> None:
|
||||
pipeline = DocsIndexingPipeline()
|
||||
content = """---
|
||||
id: api.runtime.health
|
||||
type: api_method
|
||||
doc_type: api_method
|
||||
name: runtime_health
|
||||
title: Runtime Health API
|
||||
module: runtime
|
||||
domain: platform
|
||||
sub_domain: observability
|
||||
layer: application
|
||||
status: active
|
||||
related_docs: []
|
||||
links:
|
||||
uses_logic:
|
||||
- logic.runtime.health
|
||||
---
|
||||
# Runtime Health API
|
||||
|
||||
## Summary
|
||||
|
||||
Returns current runtime health.
|
||||
|
||||
## Details
|
||||
|
||||
### Описание
|
||||
|
||||
Возвращает агрегированное состояние runtime.
|
||||
|
||||
### Сценарий
|
||||
|
||||
**Название:**
|
||||
Read health
|
||||
|
||||
**Предусловия:**
|
||||
- runtime is running
|
||||
|
||||
**Триггер:**
|
||||
- client calls health endpoint
|
||||
|
||||
**Основной сценарий:**
|
||||
1. Read current state.
|
||||
2. Return payload.
|
||||
|
||||
### Входные параметры
|
||||
|
||||
| field | type | required |
|
||||
| --- | --- | --- |
|
||||
| verbose | boolean | no |
|
||||
|
||||
### Интеграции
|
||||
|
||||
#### Runtime health provider
|
||||
- target: runtime.health_provider
|
||||
- target_type: service
|
||||
- direction: outbound
|
||||
- interaction: depends_on
|
||||
- via: async callback `health_provider()`
|
||||
- purpose: получить агрегированный health runtime
|
||||
- details:
|
||||
- timeout_ms: 5000
|
||||
- response_type: `HealthPayload`
|
||||
"""
|
||||
|
||||
with caplog.at_level(logging.WARNING):
|
||||
docs = pipeline.index_file(
|
||||
repo_id="acme/proj",
|
||||
commit_sha="abc123",
|
||||
path="docs/api/health-endpoint.md",
|
||||
content=content,
|
||||
)
|
||||
|
||||
layers = {doc.layer for doc in docs}
|
||||
assert RagLayer.DOCS_DOCUMENT_CATALOG in layers
|
||||
assert RagLayer.DOCS_DOC_CHUNKS in layers
|
||||
assert RagLayer.DOCS_FACT_INDEX in layers
|
||||
assert RagLayer.DOCS_WORKFLOW_INDEX in layers
|
||||
assert RagLayer.DOCS_RELATION_GRAPH in layers
|
||||
assert RagLayer.DOCS_INTEGRATION_INDEX in layers
|
||||
assert "docs integration parse warning" in caplog.text
|
||||
assert all(doc.source.path == "docs/api/health-endpoint.md" for doc in docs)
|
||||
|
||||
@@ -45,6 +45,23 @@ def test_retrieve_builder_adds_prefer_bonus_sorting() -> None:
|
||||
assert params["prefer_like_0"] == "%/test\\_%.py"
|
||||
|
||||
|
||||
def test_retrieve_builder_adds_metadata_filters() -> None:
|
||||
builder = RetrievalStatementBuilder()
|
||||
|
||||
sql, params = builder.build_retrieve(
|
||||
"rag-1",
|
||||
[0.1, 0.2],
|
||||
query_text="notification flow",
|
||||
metadata_domain="notifications",
|
||||
metadata_subdomain="delivery_loop",
|
||||
)
|
||||
|
||||
assert "metadata_json->>'domain'" in sql
|
||||
assert "metadata_json->>'subdomain'" in sql
|
||||
assert params["metadata_domain"] == "notifications"
|
||||
assert params["metadata_subdomain"] == "delivery_loop"
|
||||
|
||||
|
||||
def test_lexical_builder_omits_test_filters_when_not_requested() -> None:
|
||||
builder = RetrievalStatementBuilder()
|
||||
|
||||
|
||||
Reference in New Issue
Block a user