""" backend/api/prewarm.py — Predictive Pre-warming (S950) Rileva se un task richiederà i nodi HANDS (B) o MEMORY (C) e invia segnali di risveglio preventivi. Integrato con fire_speculative_tools per latenza zero. """ import asyncio import logging import os import re import httpx _logger = logging.getLogger("agente_ai.prewarm") # Configurazione nodi (Sync con daemon-health-autofix.mjs) WAKE_CONFIG = { "B": {"owner": "Baida07", "name": "ai-backend-collab", "token": "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", "url": "https://baida07-ai-backend-collab.hf.space"}, "C": {"owner": "Baida07", "name": "ai-memory-backend", "token": "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", "url": "https://baida07-ai-memory-backend.hf.space"} } # Regex per rilevare necessità di nodi specifici RE_HANDS = re.compile(r"\b(crea|fai|scrivi|build|deploy|git|push|commit|shell|terminal|esegui|run|installa|npm|pip|pnpm|setup)\b", re.I) RE_MEMORY = re.compile(r"\b(ricorda|memoria|storia|passato|semantica|rag|conoscenza|database|vecchi|precedenti|documenti)\b", re.I) async def _wake_hf_space(node_id: str): cfg = WAKE_CONFIG.get(node_id) if not cfg: return _logger.info(f"[S950] Pre-warming Nodo {node_id} ({cfg['owner']}/{cfg['name']})...") try: async with httpx.AsyncClient() as client: # 1. Soft Ping try: await client.get(f"{cfg['url']}/health", timeout=2.0) except: pass # 2. Hard Wake (API Restart) url = f"https://huggingface.co/api/spaces/{cfg['owner']}/{cfg['name']}/restart" headers = {"Authorization": f"Bearer {cfg['token']}"} await client.post(url, headers=headers, timeout=5.0) except Exception as e: _logger.error(f"[S950] Errore pre-warming {node_id}: {e}") async def predictive_prewarm(goal: str): tasks = [] if RE_HANDS.search(goal): tasks.append(_wake_hf_space("B")) if RE_MEMORY.search(goal): tasks.append(_wake_hf_space("C")) if tasks: await asyncio.gather(*tasks) def fire_predictive_prewarm(goal: str): try: asyncio.create_task(predictive_prewarm(goal)) except Exception as e: _logger.error(f"[S950] Impossibile avviare task prewarm: {e}")