MORSATIPIK / core /research_loop.py
RDS777's picture
Update core/research_loop.py
dd1ad1f verified
Raw
History Blame Contribute Delete
5.24 kB
# core/research_loop.py
import re
import time
import uuid
from typing import Dict, Any
from core.memory import MemoryTier
class ResearchLoop:
def __init__(self, llm_engine, memory, executor):
self.llm = llm_engine
self.memory = memory
self.executor = executor # execute_safe
self.error_tree = None # sera injecté plus tard (via app.py)
self.publications = []
def set_error_tree(self, error_tree):
self.error_tree = error_tree
async def generate_hypothesis(self, domain: str) -> str:
if not self.llm:
return f"L'utilisation d'un cache LRU réduit le temps d'exécution de 20% pour des appels répétés dans {domain}."
prompt = (
f"Propose une hypothèse précise et testable sur l'optimisation de {domain}. "
"Elle doit être formulée en une phrase et contenir un indicateur quantifiable (ex: 'réduit de X%', 'accélère de Y ms'). "
"Exemple : 'L'indexation des colonnes fréquemment jointes réduit le temps de requête SQL de 30%'. "
"Réponse (une phrase) :"
)
try:
resp = await self.llm.call(
agent="research",
system="Tu es un chercheur en optimisation.",
user=prompt,
max_tokens=80,
temperature=0.3,
use_cache=False
)
raw = resp.content if hasattr(resp, "content") else str(resp)
raw = raw.strip().split('\n')[0]
raw = re.sub(r'^(Answer|Hypothesis|Réponse|Hypothèse):\s*', '', raw, flags=re.IGNORECASE)
if len(raw) < 10:
return f"L'optimisation de {domain} améliore les performances de 15%."
return raw
except Exception as e:
# 🔥 Enregistrer l'échec de génération dans Harbor
if self.error_tree is not None:
try:
self.error_tree.add_error(str(e), f"ResearchLoop generate_hypothesis domain={domain}")
except Exception:
pass
return f"L'optimisation de {domain} améliore les performances de 15%."
async def run_experiment(self, hypothesis: str) -> float:
try:
# 1. Générer un code de test basé sur l'hypothèse
code_prompt = (
f"Écris un court code Python qui teste l'hypothèse suivante : {hypothesis}\n"
"Le code doit définir une fonction `run_test()` qui retourne un score entre 0 et 1 "
"(0 = échec, 1 = succès parfait). Exemple :\n"
"def run_test():\n"
" # ... test ...\n"
" return 0.85\n"
"Ne retourne que le code, sans commentaires."
)
resp = await self.llm.call(
agent="research",
system="Tu es un ingénieur de test.",
user=code_prompt,
max_tokens=200,
temperature=0.2,
use_cache=False
)
code = resp.content if hasattr(resp, "content") else str(resp)
code = re.sub(r'```(?:python)?\n?', '', code).replace('```', '').strip()
# 2. Exécuter le code dans le sandbox
result = self.executor(code, timeout=10)
if not result.get("success"):
if self.error_tree is not None:
try:
self.error_tree.add_error(
f"Exécution échouée: {result.get('error', '')}",
f"Hypothèse: {hypothesis[:100]}"
)
except Exception:
pass
return 0.0
# 3. Récupérer la sortie
output = result.get("result", "").strip()
match = re.search(r'(\d+\.?\d*)', output)
if match:
score = float(match.group(1))
score = max(0.0, min(1.0, score))
return score
else:
return 0.0
except Exception as e:
if self.error_tree is not None:
try:
self.error_tree.add_error(str(e), f"ResearchLoop run_experiment")
except Exception:
pass
return 0.0
async def publish(self, hypothesis: str, score: float):
pub = {
"id": str(uuid.uuid4())[:8],
"hypothesis": hypothesis,
"score": round(score, 3),
"timestamp": time.time()
}
self.publications.append(pub)
self.memory.ingest(
f"Research: {hypothesis[:150]} (score={score:.3f})",
MemoryTier.SEMANTIC,
"research_loop",
importance=score,
confidence=score
)
async def run_one_cycle(self, domain: str) -> Dict[str, Any]:
hypothesis = await self.generate_hypothesis(domain)
score = await self.run_experiment(hypothesis)
await self.publish(hypothesis, score)
return {
"hypothesis": hypothesis,
"score": round(score, 3),
"domain": domain
}