from __future__ import annotations from app.modules.rag.intent_router_v2.models import ConversationState, IntentDecision class ConversationPolicy: _SWITCH_MARKERS = ( "теперь", "а теперь", "давай теперь", "переключ", "new task", "switch to", "instead", ) _DOCS_SIGNALS = ("документац", "readme", "docs/", ".md") _CODE_SIGNALS = ("по коду", "класс", "метод", "файл", "блок кода", "function", "class") def resolve(self, decision: IntentDecision, user_query: str, conversation_state: ConversationState) -> tuple[str, str]: active_intent = conversation_state.active_intent if active_intent is None: return decision.intent, "START" if active_intent == decision.intent: return active_intent, "CONTINUE" if self._has_explicit_switch(user_query): return decision.intent, "SWITCH" if self._is_hard_mismatch(active_intent, decision.intent, user_query): return decision.intent, "SWITCH" return active_intent, "CONTINUE" def _has_explicit_switch(self, user_query: str) -> bool: text = " ".join((user_query or "").lower().split()) return any(marker in text for marker in self._SWITCH_MARKERS) def _is_hard_mismatch(self, active_intent: str, candidate_intent: str, user_query: str) -> bool: if active_intent == candidate_intent: return False text = " ".join((user_query or "").lower().split()) if candidate_intent == "GENERATE_DOCS_FROM_CODE": return True if candidate_intent == "DOCS_QA": return any(signal in text for signal in self._DOCS_SIGNALS) if candidate_intent == "CODE_QA" and active_intent == "DOCS_QA": return any(signal in text for signal in self._CODE_SIGNALS) return False