Source code for veupath_chatbot.services.strategies.engine.id_mapping

"""WDK ID <-> local ID mapping and record-type resolution."""

from veupath_chatbot.domain.strategy.ast import PlanStepNode
from veupath_chatbot.integrations.veupathdb.discovery import (
    SearchCatalog,
    get_discovery_service,
)
from veupath_chatbot.integrations.veupathdb.param_utils import wdk_search_matches
from veupath_chatbot.platform.logging import get_logger
from veupath_chatbot.services.wdk.record_types import resolve_record_type

from .base import StrategyToolsBase

logger = get_logger(__name__)


[docs] class IdMappingMixin(StrategyToolsBase): def _infer_record_type(self, step: PlanStepNode) -> str | None: # Plan steps no longer store record_type; prefer graph-level context when available. graph = self._get_graph(None) return graph.record_type if graph else None async def _get_catalog(self) -> SearchCatalog: """Get the search catalog for the current site.""" discovery = get_discovery_service() return await discovery.get_catalog(self.session.site_id) async def _resolve_record_type(self, record_type: str | None) -> str | None: if not record_type: return record_type catalog = await self._get_catalog() return ( resolve_record_type(catalog.get_record_types(), record_type) or record_type ) async def _find_record_type_for_search( self, record_type: str | None, search_name: str | None, require_match: bool = False, allow_fallback: bool = True, ) -> str | None: resolved = await self._resolve_record_type(record_type) if not search_name: return resolved catalog = await self._get_catalog() # Fast path: search exists in the resolved record type. if resolved: searches = catalog.get_searches(resolved) if any(wdk_search_matches(s, search_name) for s in searches): return resolved if not allow_fallback: return None if require_match else resolved if not allow_fallback: return None if require_match else resolved # Global lookup across all record types. found = catalog.find_record_type_for_search(search_name) if found: return found return None if require_match else resolved async def _find_record_type_hint( self, search_name: str, exclude: str | None = None ) -> str | None: try: catalog = await self._get_catalog() except Exception as exc: logger.warning( "Failed to fetch search catalog for record type hint", search_name=search_name, error=str(exc), ) return None found = catalog.find_record_type_for_search(search_name) # If the result matches the excluded record type, fall back to # manual scanning (the catalog only returns the first match). if found and found == exclude: for rt_name, searches in catalog._searches.items(): if rt_name == exclude: continue if any(wdk_search_matches(s, search_name) for s in searches): return rt_name return None return found