from __future__ import annotations from dataclasses import dataclass, field from app.modules.rag.explain.models import ExplainPack @dataclass(slots=True) class EvidenceGateDecision: passed: bool answer: str = "" diagnostics: dict[str, list[str]] = field(default_factory=dict) class CodeExplainEvidenceGate: def __init__(self, min_excerpts: int = 2) -> None: self._min_excerpts = min_excerpts def evaluate(self, pack: ExplainPack) -> EvidenceGateDecision: diagnostics = self._diagnostics(pack) if len(pack.code_excerpts) >= self._min_excerpts: return EvidenceGateDecision(passed=True, diagnostics=diagnostics) return EvidenceGateDecision( passed=False, answer=self._build_answer(pack, diagnostics), diagnostics=diagnostics, ) def _diagnostics(self, pack: ExplainPack) -> dict[str, list[str]]: return { "entrypoints": [item.title for item in pack.selected_entrypoints[:3] if item.title], "symbols": [item.title for item in pack.seed_symbols[:5] if item.title], "paths": self._paths(pack), "missing": list(pack.missing), } def _paths(self, pack: ExplainPack) -> list[str]: values: list[str] = [] for item in pack.selected_entrypoints + pack.seed_symbols: path = item.source or (item.location.path if item.location else "") if path and path not in values: values.append(path) for excerpt in pack.code_excerpts: if excerpt.path and excerpt.path not in values: values.append(excerpt.path) return values[:6] def _build_answer(self, pack: ExplainPack, diagnostics: dict[str, list[str]]) -> str: lines = [ "Недостаточно опоры в коде, чтобы дать объяснение без догадок.", "", f"Найдено фрагментов кода: {len(pack.code_excerpts)} из {self._min_excerpts} минимально необходимых.", ] if diagnostics["paths"]: lines.append(f"Пути: {', '.join(diagnostics['paths'])}") if diagnostics["entrypoints"]: lines.append(f"Entrypoints: {', '.join(diagnostics['entrypoints'])}") if diagnostics["symbols"]: lines.append(f"Символы: {', '.join(diagnostics['symbols'])}") if diagnostics["missing"]: lines.append(f"Диагностика: {', '.join(diagnostics['missing'])}") return "\n".join(lines).strip()