Spaces:
Configuration error
Configuration error
File size: 4,609 Bytes
9f28034 6eab95b 69c3767 008716e 6eab95b 69c3767 6eab95b 69c3767 6eab95b 69c3767 6eab95b 20e22df 6eab95b 008716e 6eab95b d20fbec 69c3767 008716e 69c3767 9f28034 69c3767 008716e 69c3767 008716e 69c3767 3b74b7c 20e22df 69c3767 9f28034 69c3767 6eab95b 69c3767 d20fbec 69c3767 20e22df 69c3767 20e22df 69c3767 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 | # core/fable_engine.py
"""
FableEngine – Optimisation itérative et création automatique de skills.
Utilise BlackBoxAdapter pour interagir avec le LLM.
"""
import asyncio
import logging
import time
from typing import Optional, Dict, Any
from core.skill_schema import Skill, SkillMetadata
from core.vector_memory import VectorMemory
logger = logging.getLogger("vortex.fable_engine")
class FableEngine:
def __init__(self, llm_engine, memory, error_tree, vector_memory: VectorMemory, blackbox=None):
"""
llm_engine : conservé pour compatibilité, mais non utilisé directement pour les appels LLM.
blackbox : instance de BlackBoxAdapter qui expose une méthode async `query(prompt)`.
"""
self.llm = llm_engine
self.memory = memory
self.error_tree = error_tree
self.vm = vector_memory
self.blackbox = blackbox
async def run(self, task: str, max_iter: int = 3, min_score: float = 0.85) -> Dict[str, Any]:
logger.info(f"[Fable] Début optimisation – tâche : {task[:80]} (max {max_iter} itérations)")
best_code = None
best_score = 0.0
best_skill = None
if not self.blackbox:
raise RuntimeError("FableEngine a besoin d'une instance BlackBoxAdapter (blackbox).")
for i in range(max_iter):
prompt = self._build_prompt(task, best_code, best_score, i)
# Appel via BlackBoxAdapter (même interface que le chat)
response = await self.blackbox.query(prompt)
# Extraire le texte : réponse peut être un objet avec .content ou une chaîne
if hasattr(response, 'content'):
text = response.content
else:
text = str(response)
code = self._extract_code(text)
if not code:
continue
score = await self._evaluate(code, task)
logger.info(f"[Fable] Itération {i+1}/{max_iter} : score {score:.3f}")
if score > best_score:
best_score = score
best_code = code
if score >= min_score:
skill = self._create_skill(task, best_code, best_score)
best_skill = skill
logger.info(f"[Fable] Skill sauvegardé : {skill.metadata.name} (score {best_score:.3f})")
if score >= 0.99:
break
return {
"skill": best_skill.to_dict() if best_skill else None,
"score": best_score,
"iterations": i + 1,
"code": best_code
}
def _build_prompt(self, task: str, current_code: Optional[str], current_score: float, iteration: int) -> str:
if current_code is None:
return f"Écris du code Python pour résoudre cette tâche :\n{task}\nFournis uniquement le code."
return (
f"Tâche : {task}\n"
f"Code actuel (score {current_score:.3f}) :\n```python\n{current_code}\n```\n"
f"Améliore ce code (itération {iteration+1}). Fournis uniquement le code amélioré."
)
def _extract_code(self, response: str) -> Optional[str]:
if "```" in response:
parts = response.split("```")
for i, part in enumerate(parts):
if i % 2 == 1: # contenu entre les backticks
if part.startswith("python"):
part = part[6:]
return part.strip()
return response.strip()
async def _evaluate(self, code: str, task: str) -> float:
"""Évaluation heuristique simple (à remplacer par un vrai sandbox si besoin)."""
score = 0.5
if len(code) > 50: score += 0.1
if len(code) > 100: score += 0.1
if "def " in code: score += 0.1
if "return " in code: score += 0.1
if "import " in code: score += 0.05
# Bonus mots-clés de la tâche
task_words = set(task.lower().split())
code_words = set(code.lower().split())
common = task_words.intersection(code_words)
score += min(0.1, len(common) * 0.02)
return min(score, 1.0)
def _create_skill(self, task: str, code: str, score: float) -> Skill:
name = f"skill_{int(time.time())}"
metadata = SkillMetadata(
name=name,
description=task[:100],
category="auto_fable",
version="1.0",
tags=["fable", "optimized"]
)
skill = Skill(metadata=metadata, code=code, score=score)
self.vm.add_skill(skill)
return skill |