#!/usr/bin/env python3 # build_vortex.py – Génère tous les modules VORTEX v5.1 (23 innovations) import os from pathlib import Path BASE = Path("/app") def write_file(path, content): filepath = BASE / path filepath.parent.mkdir(parents=True, exist_ok=True) filepath.write_text(content, encoding='utf-8') print(f"✅ {filepath}") def build_all(): # ============================================================ # 1. agents/cognitive_engine.py # ============================================================ write_file("agents/cognitive_engine.py", ''' import requests, hashlib, json, logging, os log = logging.getLogger("vortex.llm") OLLAMA_URL = os.environ.get("OLLAMA_URL","http://localhost:11434") MODEL_MAIN = os.environ.get("LLM_MODEL","gemma4:e4b") MODEL_FAST = os.environ.get("LLM_MODEL_FAST","phi3:mini") TEMP_PROFILES = {"reasoning":0.1,"code_gen":0.35,"creative":0.65,"summary":0.15} class MultiLLMEngine: def __init__(self, memory=None): self.memory=memory; self._cache={}; self.tools={}; self.call_stats={"main":0,"fast":0,"errors":0} def register_tool(self, name, fn, desc, params): self.tools[name] = {"fn":fn,"schema":{"type":"function","function":{"name":name,"description":desc,"parameters":{"type":"object","properties":params,"required":list(params.keys())}}}} async def call(self, agent, system, user, max_tokens=512, temperature=0.3, use_cache=True, use_tools=False, fast=False, profile=None, **kw): if profile and profile in TEMP_PROFILES: temperature = TEMP_PROFILES[profile] model = MODEL_FAST if fast else MODEL_MAIN key = hashlib.sha256(f"{model}|{system}|{user}|{max_tokens}|{temperature}".encode()).hexdigest()[:20] if use_cache and key in self._cache: return type("R",(),{"content":self._cache[key],"tokens":0,"cached":True})() payload = {"model":model,"messages":[{"role":"system","content":system or "Tu es VORTEX."},{"role":"user","content":user}],"options":{"num_predict":max_tokens,"temperature":temperature},"stream":False} if use_tools and self.tools: payload["tools"] = [t["schema"] for t in self.tools.values()] try: resp = requests.post(f"{OLLAMA_URL}/api/chat", json=payload, timeout=180); msg = resp.json().get("message",{}) if msg.get("tool_calls"): for tc in msg["tool_calls"]: fname = tc["function"]["name"]; fargs = tc["function"]["arguments"] if isinstance(fargs, str): fargs = json.loads(fargs) if fname in self.tools: result = self.tools[fname]["fn"](**fargs) payload["messages"] += [msg, {"role":"tool","content":str(result)}] resp = requests.post(f"{OLLAMA_URL}/api/chat", json=payload, timeout=180); msg = resp.json().get("message",{}) content = msg.get("content","") if use_cache: self._cache[key] = content self.call_stats["fast" if fast else "main"] += 1 return type("R",(),{"content":content,"tokens":len(content.split()),"cached":False}) except Exception as e: self.call_stats["errors"] += 1; log.error(f"LLM error: {e}") return type("R",(),{"content":f"[Erreur LLM: {e}]","tokens":0,"cached":False}) ''') # ============================================================ # 2. core/cybershield.py # ============================================================ write_file("core/cybershield.py", ''' import ast, re, logging log = logging.getLogger("vortex.cybershield") CRITICAL_PATTERNS = { "shell_injection": (r"os\\.system|os\\.popen|subprocess\\.(call|Popen|run)", -40), "code_injection": (r"\\beval\\s*\\(|\\bexec\\s*\\(", -35), "pickle_exploit": (r"\\bpickle\\.(loads|load)\\b", -30), "import_hijack": (r"__import__\\s*\\(", -25), "file_overwrite": (r"open\\s*\\([^)]*['\\\"w]['\\\"\\)]", -15), "network_exfil": (r"(requests|urllib|aiohttp|socket)\\.", -10), } WARNING_PATTERNS = { "bare_except": (r"except\\s*:", -8), "infinite_loop": (r"while\\s+True(?!.*break)", -12), "global_var": (r"\\bglobal\\s+\\w+", -5), "hardcoded_secret": (r"(password|secret|token|api_key)\\s*=\\s*['\\\"][^'\\\"]{4,}", -15), } class CyberShield: def __init__(self, llm_engine=None): self.llm = llm_engine; self.scan_history = [] def scan_ast(self, code): issues = [] try: tree = ast.parse(code) except SyntaxError as e: return 0.0, [f"SyntaxError: {e}"] for node in ast.walk(tree): if isinstance(node, (ast.Import, ast.ImportFrom)): mods = [a.name.split(".")[0] for a in node.names] if isinstance(node, ast.Import) else ([node.module.split(".")[0]] if node.module else []) for m in mods: if m in {"os","subprocess","socket","pickle","ctypes","importlib","shutil","signal","resource","mmap","cffi"}: issues.append(f"Import risqué : {m}") if isinstance(node, ast.Call) and isinstance(node.func, ast.Name) and node.func.id in {"eval","exec","compile","__import__"}: issues.append(f"Appel dangereux : {node.func.id}()") return len(issues), issues def scan_patterns(self, code): score, issues = 100.0, [] for name, (pattern, penalty) in {**CRITICAL_PATTERNS, **WARNING_PATTERNS}.items(): if re.search(pattern, code, re.MULTILINE): issues.append(f"{name.replace('_',' ').title()} (−{abs(penalty)}pts)") score += penalty return max(0, score), issues async def full_scan(self, code, context=""): ast_cnt, ast_issues = self.scan_ast(code) pat_score, pat_issues = self.scan_patterns(code) base_score = max(0, pat_score - min(ast_cnt * 20, 60)) llm_score, llm_note = base_score, "" if self.llm and base_score > 20: try: resp = await self.llm.call(None, "Expert sécurité Python.", f"Analyse sécurité : {code[:1000]}\\nScore actuel : {base_score}\\nRép : SCORE=XX NOTE=...", max_tokens=60, temperature=0.1, fast=True) m_s = re.search(r"SCORE=([0-9]+)", resp.content) if m_s: llm_score = (float(m_s.group(1)) + base_score) / 2 m_n = re.search(r"NOTE=(.+)", resp.content) if m_n: llm_note = m_n.group(1).strip() except: pass final = round(llm_score, 1); level = "CRITICAL" if final < 30 else ("WARNING" if final < 65 else "SAFE") result = {"score":final,"level":level,"passed":final>=60,"ast_issues":ast_issues,"pattern_issues":pat_issues,"llm_note":llm_note,"all_issues":list(set(ast_issues+pat_issues))[:8]} self.scan_history.append(result); log.info(f"CyberShield: {level} ({final}/100)"); return result def quick_scan(self, code): _, ast_issues = self.scan_ast(code) _, pat_issues = self.scan_patterns(code) critical = [i for i in pat_issues if any(k in i.lower() for k in ["shell","injection","pickle","import hijack"])] return len(ast_issues) == 0 and len(critical) == 0 def stats(self): if not self.scan_history: return {"total":0} passed = sum(1 for s in self.scan_history if s["passed"]) return {"total":len(self.scan_history),"passed":passed,"blocked":len(self.scan_history)-passed,"avg_score":round(sum(s["score"] for s in self.scan_history)/len(self.scan_history),1)} ''') # ============================================================ # 3. core/web_search.py # ============================================================ write_file("core/web_search.py", ''' import asyncio, hashlib, json, logging, time, aiohttp from pathlib import Path log = logging.getLogger("vortex.websearch") CACHE_DIR = Path("data/web_cache"); CACHE_DIR.mkdir(parents=True, exist_ok=True) class WebSearchAgent: def __init__(self, llm_engine=None): self.llm = llm_engine; self.search_log = [] def _cache_key(self, query): return CACHE_DIR / (hashlib.sha256(query.encode()).hexdigest()[:16] + ".json") def _load_cache(self, query): k = self._cache_key(query) if k.exists(): data = json.loads(k.read_text()) if time.time() - data.get("ts", 0) < 3600: return data["results"] return None def _save_cache(self, query, results): self._cache_key(query).write_text(json.dumps({"results": results, "ts": time.time()}, ensure_ascii=False)) async def search_duckduckgo(self, query, max_results=5): cached = self._load_cache(query) if cached: return cached results = [] try: url = f"https://api.duckduckgo.com/?q={query}&format=json&no_html=1&skip_disambig=1" async with aiohttp.ClientSession() as session: async with session.get(url, timeout=aiohttp.ClientTimeout(total=8)) as resp: data = await resp.json(content_type=None) for item in data.get("RelatedTopics", [])[:max_results]: if isinstance(item, dict) and "Text" in item: results.append({"title": item.get("Text","")[:100], "snippet": item.get("Text","")[:300], "url": item.get("FirstURL","")}) if data.get("Abstract"): results.insert(0, {"title": data.get("Heading",""), "snippet": data.get("Abstract","")[:400], "url": data.get("AbstractURL","")}) except Exception as e: log.warning(f"DuckDuckGo unavailable: {e}") results = [{"title": f"Recherche: {query}", "snippet": "Web indisponible.", "url": ""}] self._save_cache(query, results); return results async def research_for_rsi(self, domain): queries = [f"{domain} optimization algorithm Python", f"best {domain} techniques 2024", f"{domain} benchmark comparison"] all_snippets = [] for q in queries[:2]: results = await self.search_duckduckgo(q, max_results=3) all_snippets.extend([r["snippet"] for r in results if r["snippet"]]) if not all_snippets: return f"Aucune information web pour : {domain}" raw_context = "\\n".join(all_snippets[:6])[:2000] if self.llm: try: resp = await self.llm.call(None, "Tu résumes des résultats de recherche.", f"Résume en 3 points clés les techniques de {domain} :\\n{raw_context}\\n\\nRésumé :", max_tokens=150, temperature=0.15, fast=True, profile="summary") summary = resp.content.strip() if len(summary) > 20: self.search_log.append({"domain":domain,"summary":summary,"ts":time.time()}) return f"[WebSearch] {domain} :\\n{summary}" except: pass return f"[WebSearch] {domain} :\\n" + raw_context[:500] ''') # ============================================================ # 4. core/gitautofix.py # ============================================================ write_file("core/gitautofix.py", ''' import subprocess, sys, tempfile, shutil, ast, re, logging, time from pathlib import Path log = logging.getLogger("vortex.gitautofix") PATCHES_DIR = Path("data/git_patches"); PATCHES_DIR.mkdir(parents=True, exist_ok=True) class GitAutoFix: def __init__(self, llm_engine, cybershield): self.llm=llm_engine; self.shield=cybershield; self.patch_log=[]; self.fix_count=0 def detect_bugs(self, code): bugs = [] try: ast.parse(code) except SyntaxError as e: bugs.append(f"SyntaxError ligne {e.lineno}: {e.msg}") patterns = [(r"(\\w+)\\s*=\\s*\\1\\s*\\+\\s*1", "Auto-incrémentation sans déclaration"), (r"for\\s+\\w+\\s+in\\s+range\\([^)]*\\):\\s*$", "Boucle sans corps"), (r"def\\s+\\w+\\([^)]*\\):\\s*$", "Fonction sans corps"), (r"if\\s+\\w+\\s*=\\s*\\w+", "Assignation dans condition (=)")] for pattern, msg in patterns: if re.search(pattern, code, re.MULTILINE): bugs.append(msg) return bugs def run_tests(self, code): with tempfile.NamedTemporaryFile(mode="w", suffix=".py", delete=False) as f: f.write(code); tmp = Path(f.name) try: proc = subprocess.run([sys.executable, str(tmp)], capture_output=True, text=True, timeout=8) return {"passed": proc.returncode == 0, "stdout": proc.stdout[:300], "stderr": proc.stderr[:300]} except subprocess.TimeoutExpired: return {"passed": False, "stderr": "Timeout"} except Exception as e: return {"passed": False, "stderr": str(e)} finally: tmp.unlink(missing_ok=True) async def fix_code(self, code, error_context=""): bugs = self.detect_bugs(code) if not bugs and not error_context: return {"fixed":False,"reason":"Aucun bug","code":code} prompt = (f"ÉTAPE 1 — Identifie les bugs.\\nÉTAPE 2 — Cause racine.\\nÉTAPE 3 — Code corrigé.\\n\\nBugs: {bugs}\\nErreur: {error_context[:300]}\\n\\nCODE:\\n{code[:2000]}\\n\\nCODE CORRIGÉ (uniquement):") try: resp = await self.llm.call(None, "Expert Python.", prompt, max_tokens=800, temperature=0.2, profile="reasoning") fixed_code = resp.content.strip().replace("```python","").replace("```","").strip() try: ast.parse(fixed_code) except SyntaxError as e: return {"fixed":False,"reason":f"Patch invalide: {e}","code":code} if not self.shield.quick_scan(fixed_code): return {"fixed":False,"reason":"Blocage CyberShield","code":code} test_result = self.run_tests(fixed_code) patch_id = f"fix_{int(time.time())}" (PATCHES_DIR / f"{patch_id}.py").write_text(fixed_code) self.fix_count += 1 return {"fixed":True,"patch_id":patch_id,"bugs_fixed":bugs,"test_passed":test_result["passed"],"code":fixed_code} except Exception as e: return {"fixed":False,"reason":str(e),"code":code} async def devin_deploy(self, filepath, auto_fix=True): path = Path(filepath) if not path.exists(): return {"status":"error","reason":"fichier introuvable"} original = path.read_text(); backup = path.with_suffix(".py.bak"); shutil.copy(path, backup) orig_test = self.run_tests(original) if orig_test["passed"] and not self.detect_bugs(original): return {"status":"ok","reason":"Aucun bug"} if auto_fix: fix_result = await self.fix_code(original, orig_test.get("stderr","")) if fix_result["fixed"]: final_test = self.run_tests(fix_result["code"]) if final_test["passed"]: path.write_text(fix_result["code"]); return {"status":"deployed","file":filepath,"bugs_fixed":fix_result["bugs_fixed"]} else: shutil.copy(backup, path); return {"status":"rollback","reason":"Tests échoués après correction"} return {"status":"unchanged","bugs":self.detect_bugs(original)} ''') # ============================================================ # 5. federation/nexus.py # ============================================================ write_file("federation/nexus.py", ''' import asyncio, aiohttp, logging log = logging.getLogger("vortex.nexus") class NexusCore: def __init__(self, base_url="http://localhost:7861"): self.base_url = base_url; self.peers = [] async def register_peer(self, url): try: async with aiohttp.ClientSession() as s: async with s.get(f"{url}/health", timeout=3) as r: if r.status == 200: if url not in self.peers: self.peers.append(url); log.info(f"Pair: {url}") return True except: pass return False async def get_agents(self, url): try: async with aiohttp.ClientSession() as s: async with s.get(f"{url}/api/agents", timeout=5) as r: if r.status == 200: return (await r.json()).get("agents", []) except: return [] async def broadcast_task(self, task, agent_type=None): results = {} for peer in self.peers: try: async with aiohttp.ClientSession() as s: payload = {"task": task, "agent_type": agent_type or "all"} async with s.post(f"{peer}/api/execute", json=payload, timeout=10) as r: if r.status == 200: results[peer] = await r.json() except: pass return results nexus = NexusCore() ''') # ============================================================ # 6. core/nexus_server.py # ============================================================ write_file("core/nexus_server.py", ''' import asyncio, json, time, logging from fastapi import FastAPI, HTTPException from pydantic import BaseModel import uvicorn log = logging.getLogger("vortex.nexus.server") app = FastAPI(title="Nexus Core", version="1.0") class AgentData(BaseModel): id: str; code: str; score: float; ts: float class TaskRequest(BaseModel): task: str; agent_type: str = "all" agents_db = {} @app.get("/health") async def health(): return {"status": "ok", "ts": time.time()} @app.get("/api/agents") async def list_agents(): return {"agents": list(agents_db.values())} @app.post("/api/agents") async def add_agent(agent: AgentData): agents_db[agent.id] = agent.dict() log.info(f"Agent reçu: {agent.id} (score {agent.score})") return {"status": "ok", "id": agent.id} @app.post("/api/execute") async def execute_task(req: TaskRequest): # Simule l'exécution d'une tâche return {"status": "ok", "result": f"Task '{req.task}' executed on {req.agent_type}"} def run_nexus_server(port=7861): log.info(f"Démarrage Nexus Server sur le port {port}") uvicorn.run(app, host="0.0.0.0", port=port, log_level="warning") ''') # ============================================================ # 7. benchmarks/swe_bench_adapter.py # ============================================================ write_file("benchmarks/swe_bench_adapter.py", ''' import subprocess, sys, tempfile, json, random from pathlib import Path PROBLEMS = [ {"id": "fib", "desc": "Fibonacci", "code": "def fib(n): return n if n<2 else fib(n-1)+fib(n-2)", "test": "assert fib(10)==55"}, {"id": "rev", "desc": "Reverse list", "code": "def rev(l): return l[::-1]", "test": "assert rev([1,2,3])==[3,2,1]"}, {"id": "pal", "desc": "Palindrome", "code": "def pal(s): return s==s[::-1]", "test": "assert pal('radar') and not pal('hello')"}, {"id": "vowels", "desc": "Count vowels", "code": "def count(s): return sum(1 for c in s if c in 'aeiou')", "test": "assert count('hello')==2"}, {"id": "max_list", "desc": "Max", "code": "def max_l(l): return max(l)", "test": "assert max_l([1,5,3])==5"}, ] def run_swe_bench(agent_code, max_instances=4): passed = 0 for p in PROBLEMS[:max_instances]: full = agent_code + "\\n" + p["code"] + "\\n" + p["test"] with tempfile.NamedTemporaryFile(mode="w", suffix=".py", delete=False) as f: f.write(full); tmp = Path(f.name) try: r = subprocess.run([sys.executable, str(tmp)], capture_output=True, timeout=4) if r.returncode == 0: passed += 1 except: pass finally: tmp.unlink(missing_ok=True) return {"resolved": passed, "total": max_instances, "rate": round(passed/max_instances*100, 1)} ''') # ============================================================ # 8. core/rsi_loop.py # ============================================================ write_file("core/rsi_loop.py", ''' import asyncio, importlib.util, shutil, time, math, json, logging from pathlib import Path log = logging.getLogger("vortex.rsi") ARCHIVE_DIR = Path("data/rsi_archive"); ARCHIVE_DIR.mkdir(parents=True, exist_ok=True) DREAM_PATH = Path("data/dream_state.json") BENCH_FUNCS = [ ("sphere", lambda p: sum(x**2 for x in p), [(-5,5)]*5, 0.0), ("rastrigin", lambda p: 10*len(p)+sum(xi**2-10*math.cos(2*math.pi*xi) for xi in p), [(-5.12,5.12)]*5, 0.0), ("rosenbrock", lambda p: sum(100*(p[i+1]-p[i]**2)**2+(1-p[i])**2 for i in range(len(p)-1)), [(-2,2)]*5, 0.0), ] class RSILoop: def __init__(self, llm, opt_path, shield=None, web=None, gitfix=None): self.llm=llm; self.path=Path(opt_path); self.backup=self.path.with_suffix(".py.bak") self.shield=shield; self.web=web; self.gitfix=gitfix self.generation=0; self.best_score=self._bench_file(self.path); self.archive=self._load_archive() log.info(f"RSI v2 init — score={self.best_score:.4f} arch={len(self.archive)}") def _load_archive(self): idx = ARCHIVE_DIR / "index.json" return json.loads(idx.read_text()) if idx.exists() else [] def _save_archive(self): (ARCHIVE_DIR/"index.json").write_text(json.dumps(self.archive, indent=2)) def _bench_module(self, mod): try: Opt = getattr(mod, "FellowOptimizer") except: return 0.0 scores = [] for _, fn, bounds, opt_v in BENCH_FUNCS: try: o = Opt(fn, bounds, max_evals=100) best, _ = o.optimize() scores.append(1.0 - math.tanh(abs(fn(best)-opt_v))) except: scores.append(0.0) return sum(scores)/len(scores) if scores else 0.0 def _bench_file(self, path): try: spec = importlib.util.spec_from_file_location("_b", path) mod = importlib.util.module_from_spec(spec); spec.loader.exec_module(mod) return self._bench_module(mod) except: return 0.0 def _load_dream(self): if DREAM_PATH.exists(): try: state = json.loads(DREAM_PATH.read_text()) summary = state.get("summary","") if summary and len(summary)>20: return f"\\n\\nCONTEXTE MÉMORIEL:\\n{summary[:400]}\\n" except: pass return "" async def _gen_variant(self): if not self.llm: return None current = self.path.read_text() dream_ctx = self._load_dream() top_arc = sorted(self.archive, key=lambda x:x["score"], reverse=True)[:2] arc_ctx = "\\n".join([f"# Archive score={a['score']:.3f}\\n{a['snippet']}" for a in top_arc]) web_ctx = "" if self.web: try: web_ctx = await asyncio.wait_for(self.web.research_for_rsi("evolutionary optimization Python"), timeout=6.0) except: web_ctx = "" prompt = (f"ÉTAPE 1 — Analyse les forces/faiblesses de ce code :\\n{current[:1500]}\\n\\n" f"ÉTAPE 2 — Identifie la meilleure technique (DE, PSO, CMA-ES).\\n" f"Archives: {arc_ctx[:400] if arc_ctx else 'aucune'}\\n" f"Web: {web_ctx[:400] if web_ctx else 'non disponible'}" f"{dream_ctx}" f"ÉTAPE 3 — Écris la nouvelle version de FellowOptimizer.\\n" f"CODE UNIQUEMENT (pas de markdown) :") try: resp = await self.llm.call(None, "Expert optimisation.", prompt, max_tokens=900, temperature=0.4, profile="code_gen", use_cache=False) code = resp.content.strip().replace("```python","").replace("```","").strip() return code if "class FellowOptimizer" in code else None except: return None async def run_generation(self): self.generation += 1 code = await self._gen_variant() if not code: return {"gen":self.generation,"action":"skip","reason":"bad_code","score":self.best_score} if self.shield and not self.shield.quick_scan(code): return {"gen":self.generation,"action":"blocked","reason":"CyberShield","score":self.best_score} if self.gitfix: bugs = self.gitfix.detect_bugs(code) if bugs: fix = await self.gitfix.fix_code(code, f"RSI gen {self.generation}") if fix["fixed"]: code = fix["code"] tmp = self.path.with_suffix(".py.new") try: ast.parse(code) tmp.write_text(code) spec = importlib.util.spec_from_file_location("_n", tmp) mod = importlib.util.module_from_spec(spec); spec.loader.exec_module(mod) new_score = self._bench_module(mod) if new_score > self.best_score: shutil.copy(self.path, self.backup) shutil.move(str(tmp), str(self.path)) old = self.best_score; self.best_score = new_score self.archive.append({"gen":self.generation,"score":round(new_score,4),"snippet":code[:300],"ts":time.time()}) self._save_archive() return {"gen":self.generation,"action":"deployed","old":old,"new":new_score} self.archive.append({"gen":self.generation,"score":self.best_score*0.85,"snippet":code[:300],"ts":time.time()}) self._save_archive() return {"gen":self.generation,"action":"archived","score":self.best_score} except Exception as e: return {"gen":self.generation,"action":"error","reason":str(e)} finally: if tmp.exists(): tmp.unlink(missing_ok=True) def status(self): return {"generation":self.generation,"best_score":round(self.best_score,4),"archive_size":len(self.archive)} ''') # ============================================================ # 9. core/agent_registry.py # ============================================================ write_file("core/agent_registry.py", ''' import logging log = logging.getLogger("vortex.registry") class AgentRegistry: def __init__(self): self.agents = {} def register(self, name, instance, description, capabilities=None): self.agents[name] = {"instance": instance, "description": description, "capabilities": capabilities or []} log.info(f"Agent enregistré : {name}") def list(self): return {name: info["description"] for name, info in self.agents.items()} def get(self, name): return self.agents.get(name, {}).get("instance") def get_capabilities(self, name): return self.agents.get(name, {}).get("capabilities", []) def filter_by_capability(self, cap): return [n for n, info in self.agents.items() if cap in info.get("capabilities", [])] registry = AgentRegistry() ''') # ============================================================ # 10. core/judge_layer.py # ============================================================ write_file("core/judge_layer.py", ''' import asyncio, json, logging, re log = logging.getLogger("vortex.judge") class JudgeLayer: def __init__(self, llm_engine, registry=None): self.llm = llm_engine; self.registry = registry; self.history = [] async def evaluate_candidates(self, task, candidates): if not candidates: return {"error": "Aucun candidat"} if len(candidates) == 1: name = list(candidates.keys())[0]; return {"winner": name, "scores": {name: 1.0}, "confidence": 1.0} prompt = f"Juge expert. Évalue les réponses pour la tâche : \\"{task}\\"\\n" for name, content in candidates.items(): prompt += f"\\n--- Agent {name} ---\\n{content[:1000]}\\n" prompt += """Attribue un score 0-1 pour chaque (précision, exhaustivité, qualité). Réponds UNIQUEMENT en JSON : {"scores": {"agent1": 0.9, ...}, "winner": "agent1", "confidence": 0.85}""" try: resp = await self.llm.call(None, "Expert évaluateur.", prompt, max_tokens=200, temperature=0.1, fast=True) match = re.search(r"\\{.*\\}", resp.content, re.DOTALL) if match: result = json.loads(match.group()) if "winner" in result and result["winner"] not in candidates: if "scores" in result: best = max(result["scores"], key=lambda k: result["scores"][k]) result["winner"] = best return result else: best_name = max(candidates, key=lambda k: len(candidates[k])) return {"winner": best_name, "scores": {k: 0.5 for k in candidates}, "confidence": 0.5} except Exception as e: log.error(f"Judge error: {e}") best_name = max(candidates, key=lambda k: len(candidates[k])) return {"winner": best_name, "scores": {k: 0.5 for k in candidates}, "confidence": 0.3} async def dispatch(self, task, agent_names=None): if self.registry is None: return {"error": "AgentRegistry manquant"} if agent_names is None: agent_names = list(self.registry.agents.keys()) results = {}; tasks = {} for name in agent_names: agent = self.registry.get(name) if agent is None: results[name] = "Agent non trouvé"; continue if hasattr(agent, "run"): tasks[name] = asyncio.create_task(agent.run(task)) elif hasattr(agent, "evaluate"): tasks[name] = asyncio.create_task(agent.evaluate(task)) elif hasattr(agent, "research_for_rsi"): tasks[name] = asyncio.create_task(agent.research_for_rsi(task)) else: results[name] = "Agent sans méthode" for name, future in tasks.items(): try: result = await future if hasattr(result, "content"): results[name] = result.content elif isinstance(result, dict): results[name] = json.dumps(result, ensure_ascii=False) else: results[name] = str(result) except Exception as e: results[name] = f"Erreur: {e}" judge_result = await self.evaluate_candidates(task, results) judge_result["all_responses"] = results self.history.append({"task": task, "judge_result": judge_result}) return judge_result judge = None ''') # ============================================================ # 11. core/orchestrator.py # ============================================================ write_file("core/orchestrator.py", ''' import asyncio, json, logging, re log = logging.getLogger("vortex.orchestrator") class Orchestrator: def __init__(self, llm_engine, judge_layer, registry): self.llm = llm_engine; self.judge = judge_layer; self.registry = registry self.roles = {"planner": "Planifier l'architecture", "writer": "Écrire le code", "reviewer": "Vérifier sécurité", "optimizer": "Optimiser performances"} async def decompose(self, task): prompt = f"Décompose cette tâche en 2-4 sous-tâches claires. Tâche : {task}\\nRetourne UNIQUEMENT une liste JSON : [\\"sous-tâche 1\\", ...]" try: resp = await self.llm.call(None, "Planificateur.", prompt, max_tokens=200, temperature=0.3, fast=True) match = re.search(r"\\[.*\\]", resp.content, re.DOTALL) if match: subtasks = json.loads(match.group()); return [s.strip() for s in subtasks if s.strip()] else: return [task] except Exception as e: log.error(f"Decomp error: {e}"); return [task] async def run(self, task, roles=None): if roles is None: roles = self.roles subtasks = await self.decompose(task) if not subtasks: return {"error": "Impossible de décomposer"} assigned = {} role_names = list(roles.keys()) for i, st in enumerate(subtasks): role = role_names[i % len(role_names)] assigned[role] = st results = {} for role, st in assigned.items(): log.info(f"Orchestrator: {role} → {st}") judge_result = await self.judge.dispatch(st) results[role] = { "task": st, "winner": judge_result.get("winner"), "score": judge_result.get("confidence", 0), "content": judge_result.get("all_responses", {}).get(judge_result.get("winner"), "") } synth_prompt = f"Tâche initiale : {task}\\nSynthétise les résultats :\\n" for role, data in results.items(): synth_prompt += f"\\n--- {role} ---\\n{data['content'][:500]}\\n" synth_prompt += "\\nDonne la solution finale complète." try: synth_resp = await self.llm.call(None, "Synthétiseur.", synth_prompt, max_tokens=800, temperature=0.2, profile="reasoning") synthesis = synth_resp.content.strip() except Exception as e: synthesis = f"Erreur synthèse: {e}" return {"task": task, "subtasks": assigned, "results": results, "synthesis": synthesis} orchestrator = None ''') # ============================================================ # 12. core/agent_manager.py # ============================================================ write_file("core/agent_manager.py", ''' import logging log = logging.getLogger("vortex.agent_manager") class AgentManager: def __init__(self, registry, judge, orchestrator): self.registry = registry; self.judge = judge; self.orchestrator = orchestrator; self.default_agent = None async def multi(self, task, agent_names=None): return await self.judge.dispatch(task, agent_names) async def judge_task(self, task): return await self.judge.dispatch(task) async def orchestrate(self, task, roles=None): return await self.orchestrator.run(task, roles) async def switch_agent(self, name): if name in self.registry.agents: self.default_agent = name; return True return False def list_agents(self): return self.registry.list() ''') # ============================================================ # 13. core/optimizer.py # ============================================================ write_file("core/optimizer.py", ''' import random, math class FellowOptimizer: def __init__(self, func, bounds, max_evals=200): self.func=func; self.bounds=bounds; self.max_evals=max_evals def optimize(self): dim=len(self.bounds); F,CR=0.8,0.9 pop=[[random.uniform(l,u) for l,u in self.bounds] for _ in range(15)] vals=[self.func(p) for p in pop] best=pop[vals.index(min(vals))][:]; best_val=min(vals); evals=15 while evals < self.max_evals: for i in range(len(pop)): a,b,c=random.sample([j for j in range(len(pop)) if j!=i],3) trial=[max(l,min(u,pop[a][d]+F*(pop[b][d]-pop[c][d]))) if random.random()=self.max_evals: break return best,[best_val] ''') # ============================================================ # 14. core/peer_review.py # ============================================================ write_file("core/peer_review.py", ''' import re class PeerReview: def __init__(self, llm, shield=None): self.llm=llm; self.shield=shield async def evaluate(self, code, context=""): if not code: return {"score":0,"passed":False} if self.shield: r=await self.shield.full_scan(code,context) if not r["passed"]: return {"score":0,"passed":False,"comment":"CyberShield bloque","issues":r["all_issues"]} if not self.llm: return {"score":0.7,"passed":True} try: resp=await self.llm.call(None,"Expert revue.",f"Note ce code (0-1):\\n{code[:1200]}\\nRéponds: SCORE=0.XX", max_tokens=60, fast=True) m=re.search(r"SCORE=([0-9.]+)", resp.content); s=float(m.group(1)) if m else 0.7 return {"score":round(s,3),"passed":s>=0.6} except: return {"score":0.65,"passed":True} ''') # ============================================================ # 15. core/dream_consolidator.py # ============================================================ write_file("core/dream_consolidator.py", ''' import json, time, logging; from pathlib import Path log=logging.getLogger("vortex.dream"); DREAM_PATH=Path("data/dream_state.json") class DreamConsolidator: def __init__(self, mem, llm): self.mem=mem; self.llm=llm self.state = {} if DREAM_PATH.exists(): try: self.state = json.loads(DREAM_PATH.read_text()) except: self.state = {"summary":"","last_ts":0,"count":0} else: self.state = {"summary":"","last_ts":0,"count":0} def _save(self): DREAM_PATH.write_text(json.dumps(self.state, indent=2)) async def consolidate(self): entries = self.mem.retrieve("", top_k=30) if self.mem else [] ctx = "\\n".join([e.content[:200] for e in entries if hasattr(e,"content")]) if not ctx: self.state["summary"] = "Aucun apprentissage récent." self._save() return self.state try: resp = await self.llm.call(None, "Résumeur.", f"Résume en 5 points les apprentissages :\\n{ctx[:3000]}\\nRésumé :", max_tokens=200, fast=True, profile="summary") self.state.update({"summary":resp.content.strip(),"last_ts":time.time(),"count":self.state.get("count",0)+1}) self._save() except Exception as e: log.error(f"Dream consolidation failed: {e}") return self.state ''') # ============================================================ # 16. core/autodev.py # ============================================================ write_file("core/autodev.py", ''' import shutil, ast class AutoDev: def __init__(self, llm): self.llm=llm async def improve(self, filepath): from pathlib import Path path=Path(filepath) if not path.exists(): return {"error":"File not found"} orig=path.read_text() try: resp=await self.llm.call(None,"Expert Python.",f"Améliore ce code:\\n{orig[:2000]}\\nCode uniquement:", max_tokens=900, temperature=0.4) new=resp.content.strip().replace("```python","").replace("```","").strip() try: ast.parse(new) except SyntaxError as e: return {"error":f"SyntaxError dans le patch: {e}"} backup=path.with_suffix(".py.bak"); shutil.copy(path,backup); path.write_text(new) return {"status":"deployed","backup":str(backup)} except Exception as e: return {"error":str(e)} ''') # ============================================================ # 17. sandbox/secure_sandbox.py # ============================================================ write_file("sandbox/secure_sandbox.py", ''' import subprocess, sys, tempfile, resource; from pathlib import Path def run_in_sandbox(code, timeout=5, memory_mb=128): with tempfile.NamedTemporaryFile(mode="w", suffix=".py", delete=False) as f: f.write(code); tmp=Path(f.name) try: def _lim(): try: resource.setrlimit(resource.RLIMIT_AS,(memory_mb*1024*1024,memory_mb*1024*1024)); resource.setrlimit(resource.RLIMIT_CPU,(timeout,timeout+1)) except: pass proc=subprocess.Popen([sys.executable,str(tmp)], stdout=subprocess.PIPE, stderr=subprocess.PIPE, preexec_fn=_lim) out,err=proc.communicate(timeout=timeout+1) return {"success":proc.returncode==0,"result":out.decode()[:2000],"error":err.decode()[:500]} except subprocess.TimeoutExpired: proc.kill(); return {"success":False,"error":"Timeout"} except Exception as e: return {"success":False,"error":str(e)} finally: tmp.unlink(missing_ok=True) ''') # ============================================================ # 18. benchmarks/humaneval_adapter.py # ============================================================ write_file("benchmarks/humaneval_adapter.py", ''' import subprocess, sys, tempfile; from pathlib import Path CASES=[("def add(a,b): return a+b","assert add(2,3)==5"),("def is_even(n): return n%2==0","assert is_even(4)"),("def fact(n): return 1 if n<=1 else n*fact(n-1)","assert fact(5)==120"),("def rev(s): return s[::-1]","assert rev('abc')=='cba'"),("def fib(n): return n if n<2 else fib(n-1)+fib(n-2)","assert fib(10)==55")] def run_humaneval(preamble="",max_cases=5): passed=0 for sol,test in CASES[:max_cases]: full=(preamble+"\\n"+sol+"\\n"+test) if preamble else sol+"\\n"+test with tempfile.NamedTemporaryFile(mode="w",suffix=".py",delete=False) as f: f.write(full); tmp=Path(f.name) try: r=subprocess.run([sys.executable,str(tmp)],capture_output=True,timeout=3) if r.returncode==0: passed+=1 except: pass finally: tmp.unlink(missing_ok=True) return {"pass@1":round(passed/max_cases*100,1),"passed":passed,"total":max_cases} ''') # ============================================================ # 19. core/hf_mcp.py – Intégration Hugging Face MCP # ============================================================ write_file("core/hf_mcp.py", ''' import asyncio, json, logging, os, aiohttp from typing import Dict, List, Optional log = logging.getLogger("vortex.hf_mcp") HF_MCP_URL = os.environ.get("HF_MCP_URL", "https://huggingface.co/api") class HFMCPClient: def __init__(self, use_mcp=False): self.use_mcp = use_mcp self.hub_api = "https://huggingface.co/api" self.history = [] async def _hub_api_request(self, method: str, params: Dict) -> Dict: if method == "search_models": query = params.get("query", "") url = f"{self.hub_api}/models?search={query}&limit=10" async with aiohttp.ClientSession() as session: async with session.get(url, timeout=aiohttp.ClientTimeout(total=10)) as resp: if resp.status != 200: return {"error": f"API error {resp.status}"} data = await resp.json() return {"models": [{"id": m["id"], "downloads": m.get("downloads", 0)} for m in data[:5]]} elif method == "search_datasets": query = params.get("query", "") url = f"{self.hub_api}/datasets?search={query}&limit=10" async with aiohttp.ClientSession() as session: async with session.get(url, timeout=aiohttp.ClientTimeout(total=10)) as resp: if resp.status != 200: return {"error": f"API error {resp.status}"} data = await resp.json() return {"datasets": [{"id": d["id"]} for d in data[:5]]} elif method == "get_space": space_name = params.get("name", "") url = f"{self.hub_api}/spaces/{space_name}" async with aiohttp.ClientSession() as session: async with session.get(url, timeout=aiohttp.ClientTimeout(total=10)) as resp: if resp.status != 200: return {"error": f"Space not found or API error {resp.status}"} data = await resp.json() return {"space": {"id": data.get("id"), "likes": data.get("likes", 0)}} elif method == "search_papers": query = params.get("query", "") url = f"http://export.arxiv.org/api/query?search_query=all:{query}&start=0&max_results=5" async with aiohttp.ClientSession() as session: try: async with session.get(url, timeout=aiohttp.ClientTimeout(total=15)) as resp: if resp.status != 200: return {"error": f"arXiv error {resp.status}"} text = await resp.text() import xml.etree.ElementTree as ET root = ET.fromstring(text) papers = [] for entry in root.findall("{http://www.w3.org/2005/Atom}entry"): title = entry.find("{http://www.w3.org/2005/Atom}title") if title is not None: papers.append({"title": title.text.strip(), "id": "N/A"}) return {"papers": papers[:3]} except Exception as e: log.warning(f"arXiv API error: {e}") return {"papers": [{"title": f"Recherche simulée pour '{query}'", "id": "arxiv"}]} return {"error": "Méthode non supportée"} async def search_models(self, query: str, limit: int = 5) -> List[Dict]: result = await self._hub_api_request("search_models", {"query": query, "limit": limit}) return result.get("models", []) async def search_datasets(self, query: str, limit: int = 5) -> List[Dict]: result = await self._hub_api_request("search_datasets", {"query": query, "limit": limit}) return result.get("datasets", []) async def get_space_info(self, space_name: str) -> Dict: result = await self._hub_api_request("get_space", {"name": space_name}) return result.get("space", {}) async def search_papers(self, query: str) -> List[Dict]: result = await self._hub_api_request("search_papers", {"query": query}) return result.get("papers", []) def stats(self) -> Dict: return {"history": len(self.history)} hf_mcp = HFMCPClient(use_mcp=False) ''') # ============================================================ # 20. app.py – VERSION HEADLESS FASTAPI (déjà fournie) # ============================================================ write_file("app.py", ''' #!/usr/bin/env python3 import os, sys, asyncio, json, logging, time from pathlib import Path from fastapi import FastAPI, HTTPException from pydantic import BaseModel import uvicorn import nest_asyncio nest_asyncio.apply() BASE = Path("/app") os.chdir(BASE); sys.path.insert(0, str(BASE)) DATA_DIR = Path(os.environ.get("DATA_DIR", "/data")) DATA_DIR.mkdir(parents=True, exist_ok=True) logging.basicConfig(level=logging.INFO, format="%(levelname)s [%(name)s] %(message)s") log = logging.getLogger("vortex.headless") from agents.cognitive_engine import MultiLLMEngine from core.cybershield import CyberShield from core.web_search import WebSearchAgent from core.gitautofix import GitAutoFix from core.rsi_loop import RSILoop from core.peer_review import PeerReview from core.autodev import AutoDev from core.dream_consolidator import DreamConsolidator from federation.nexus import nexus from sandbox.secure_sandbox import run_in_sandbox from benchmarks.humaneval_adapter import run_humaneval from benchmarks.swe_bench_adapter import run_swe_bench from core.agent_registry import registry from core.judge_layer import JudgeLayer from core.orchestrator import Orchestrator from core.agent_manager import AgentManager from core.hf_mcp import hf_mcp class _Mem: def __init__(self): self.store=[] def ingest(self,c,**k): self.store.append({"content":c}) def retrieve(self,q,top_k=5): return [type("E",(),{"content":e["content"]})() for e in self.store[-top_k:]] class _K: def run_code(self,code,timeout=10): return run_in_sandbox(code,timeout=int(timeout)) def get_health(self): try: import psutil; cpu=psutil.cpu_percent(0.1); mem=psutil.virtual_memory().percent except: cpu,mem=0.0,0.0 return {"status":"healthy","cpu_percent":cpu,"memory_percent":mem} KERNEL=_K(); mem=_Mem(); llm=MultiLLMEngine(mem); shield=CyberShield(llm); web=WebSearchAgent(llm) gitfix=GitAutoFix(llm, shield); pr=PeerReview(llm, shield) rsi=RSILoop(llm, "core/optimizer.py", shield, web, gitfix) autodev=AutoDev(llm); dreamer=DreamConsolidator(mem, llm) registry.register("rsi", rsi, "Auto-amélioration récursive", ["code_gen","optimization"]) registry.register("shield", shield, "Analyse de sécurité CyberShield", ["security","audit"]) registry.register("gitfix", gitfix, "Correction automatique de bugs", ["code_fix","deployment"]) registry.register("web", web, "Recherche web structurée", ["research","search"]) registry.register("dreamer", dreamer, "Consolidation mémoire", ["memory"]) registry.register("nexus", nexus, "Fédération P2P", ["federation"]) judge = JudgeLayer(llm, registry) orchestrator = Orchestrator(llm, judge, registry) manager = AgentManager(registry, judge, orchestrator) # Scheduler try: from apscheduler.schedulers.background import BackgroundScheduler sched=BackgroundScheduler(timezone="UTC") def _j(coro): loop=asyncio.new_event_loop() try: loop.run_until_complete(coro) finally: loop.close() sched.add_job(lambda:_j(rsi.run_generation()), "interval", hours=2, id="rsi") sched.add_job(lambda:_j(dreamer.consolidate()), "cron", hour=3, id="dream") sched.start() log.info("✅ Scheduler: RSI/2h, Dream/3h") except Exception as e: log.warning(f"Scheduler non démarré: {e}") # ---- FastAPI ---- app = FastAPI(title="VORTEX v5.1 API", version="5.1") class CommandRequest(BaseModel): command: str args: dict = {} class CodeRequest(BaseModel): code: str timeout: int = 10 @app.get("/") async def root(): return {"message": "VORTEX v5.1 Headless API"} @app.post("/command") async def execute_command(req: CommandRequest): msg = req.command if msg.startswith("@health"): h = KERNEL.get_health() return f"CPU {h['cpu_percent']:.0f}% · RAM {h['memory_percent']:.0f}% · RSI gen {rsi.generation}" elif msg.startswith("@rsi"): r = await rsi.run_generation() return f"RSI gen={r['gen']} score={r.get('new', r.get('score',0))}" elif msg.startswith("@shield"): code = msg.replace("@shield","").strip() if not code: return "Syntaxe: @shield " r = await shield.full_scan(code) return f"{r['level']} {r['score']}/100 · Issues: {r['all_issues']}" elif msg.startswith("@gitfix"): path = msg.replace("@gitfix","").strip() or "core/optimizer.py" r = await gitfix.devin_deploy(path) return f"GitAutoFix: {r.get('status','?')} - {r.get('reason','')}" elif msg.startswith("@web"): q = msg.replace("@web","").strip() or "optimization" r = await web.research_for_rsi(q) return r[:600] elif msg.startswith("@multi"): parts = msg.split("--agents") task = parts[0].replace("@multi","").strip() agents = None if len(parts)>1: agents = [a.strip() for a in parts[1].strip().split(",")] result = await manager.multi(task, agents) return f"Gagnant: {result.get('winner','?')} (confiance {result.get('confidence',0)})" elif msg.startswith("@judge"): task = msg.replace("@judge","").strip() if not task: return "Syntaxe: @judge " result = await manager.judge_task(task) return f"Meilleur agent: {result.get('winner','?')}" elif msg.startswith("@orchestrate"): task = msg.replace("@orchestrate","").strip() if not task: return "Syntaxe: @orchestrate " result = await manager.orchestrate(task) return f"Synthèse: {result.get('synthesis','')[:500]}" elif msg.startswith("@hfsearch"): query = msg.replace("@hfsearch","").strip() if not query: return "Syntaxe: @hfsearch " models = await hf_mcp.search_models(query) return "\\n".join([f"- {m['id']}" for m in models[:5]]) if models else "Aucun modèle" elif msg.startswith("@nexus"): parts = msg.replace("@nexus","").strip().split() if not parts: return "Syntaxe: @nexus add | list | broadcast " if parts[0] == "add": ok = await nexus.register_peer(parts[1]) return f"Pair {parts[1]} {'ajouté' if ok else 'inaccessible'}" elif parts[0] == "list": return f"Pairs: {', '.join(nexus.peers) if nexus.peers else 'Aucun'}" elif parts[0] == "broadcast": task = " ".join(parts[1:]) results = await nexus.broadcast_task(task) return "\\n".join([f"{p}: {r}" for p,r in results.items()]) else: return "Commande invalide" else: return "Commande non reconnue" @app.post("/sandbox") async def sandbox(req: CodeRequest): result = KERNEL.run_code(req.code, timeout=req.timeout) return result @app.get("/health") async def health(): h = KERNEL.get_health() return {"status": "ok", **h} if __name__ == "__main__": log.info("🚀 VORTEX v5.1 Headless API démarre sur le port 7860") uvicorn.run(app, host="0.0.0.0", port=7860) ''') # ============================================================ # 21. requirements.txt (explicit) # ============================================================ write_file("requirements.txt", ''' gradio>=4.0.0 nest_asyncio>=1.5.0 psutil>=5.9.0 apscheduler>=3.10.0 aiohttp>=3.9.0 fastapi>=0.100.0 uvicorn>=0.23.0 requests>=2.31.0 pydantic>=2.0.0 ''') # ============================================================ # 22. Dockerfile (pour HF Spaces) # ============================================================ write_file("Dockerfile", ''' FROM python:3.11-slim ENV PYTHONDONTWRITEBYTECODE=1 ENV PYTHONUNBUFFERED=1 WORKDIR /app RUN apt-get update && apt-get install -y curl git && rm -rf /var/lib/apt/lists/* COPY build_vortex.py . COPY requirements.txt . COPY app.py . RUN python build_vortex.py RUN pip install --no-cache-dir -r requirements.txt CMD ["python", "app.py"] ''') print("✅ Tous les fichiers VORTEX v5.1 ont été générés.") if __name__ == "__main__": build_all()