mirror of
https://github.com/R0m1k3/Loki.git
synced 2026-10-14 18:58:43 +02:00
- coder.py : enveloppe Aider (version figée 0.86.2), commits git auto dans le workspace, verrou d'exécution, dégradation propre si absent - router.py : classification automatique de chaque message (heuristique lexicale + micro-classification LLM sur les cas ambigus) — invisible pour l'utilisateur - routes/chat.py : routage code/agent, chemin code avec keepalive SSE, cartes fichier + commit dans le fil, meta.engine persisté - agent.py : outil code_task exécuté en thread — l'agent peut coder lui-même - tools/agent_config : code_task enregistré (actif par défaut), invite système mise à jour - main.py : workspace auto-initialisé en dépôt git au démarrage - Dockerfile : git ; requirements : aider-chat==0.86.2 - UI : glyphe code_task, description outil, aperçu d'instruction Tests : heuristiques 7/7, routage HTTP code+agent de bout en bout (SSE, meta persistée), agent appelant code_task, build front. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01SVay7z3y7q2gEe54ByAE6N
107 lines
3.4 KiB
Python
107 lines
3.4 KiB
Python
"""Moteur code : enveloppe Aider pour l'édition multi-fichiers fiable.
|
|
|
|
Aider apporte ce qui fait la force de Claude Code/Codex : formats d'édition
|
|
diff/search-replace robustes (même avec de petits modèles), repo map, et
|
|
commits git automatiques dans le workspace.
|
|
|
|
L'API Python d'Aider n'étant pas officiellement stable, la version est FIGÉE
|
|
dans requirements.txt (aider-chat==0.86.2) et tout l'import est local à la
|
|
fonction (l'app démarre même si Aider est absent).
|
|
"""
|
|
from __future__ import annotations
|
|
|
|
import os
|
|
import subprocess
|
|
import threading
|
|
|
|
from .config import settings
|
|
|
|
# Aider utilise le répertoire courant : un seul run à la fois.
|
|
_RUN_LOCK = threading.Lock()
|
|
|
|
|
|
def ensure_git(root: str) -> None:
|
|
"""Initialise un dépôt git dans le workspace (requis pour les commits Aider)."""
|
|
os.makedirs(root, exist_ok=True)
|
|
if os.path.isdir(os.path.join(root, ".git")):
|
|
return
|
|
subprocess.run(["git", "init", "-q"], cwd=root, check=False)
|
|
subprocess.run(["git", "config", "user.email", "loki@local"], cwd=root, check=False)
|
|
subprocess.run(["git", "config", "user.name", "Loki"], cwd=root, check=False)
|
|
|
|
|
|
def available() -> bool:
|
|
"""Aider est-il installé ?"""
|
|
try:
|
|
import aider # noqa: F401
|
|
return True
|
|
except ImportError:
|
|
return False
|
|
|
|
|
|
def run_code_task(
|
|
instruction: str,
|
|
model: str,
|
|
files: list[str] | None = None,
|
|
) -> dict:
|
|
"""Exécute une tâche de code via Aider (synchrone — lancer dans un thread).
|
|
|
|
Renvoie {ok, text, files, commit, commit_message, summary}.
|
|
"""
|
|
if not available():
|
|
return {
|
|
"ok": False,
|
|
"summary": "moteur code indisponible (aider non installé)",
|
|
"text": "", "files": [], "commit": None,
|
|
}
|
|
|
|
from aider.coders import Coder
|
|
from aider.io import InputOutput
|
|
from aider.models import Model
|
|
|
|
root = os.path.abspath(settings.workspace_dir)
|
|
ensure_git(root)
|
|
|
|
# Aider parle à Ollama via litellm : on pointe vers notre instance.
|
|
os.environ["OLLAMA_API_BASE"] = settings.ollama_host
|
|
|
|
with _RUN_LOCK:
|
|
prev_cwd = os.getcwd()
|
|
os.chdir(root)
|
|
try:
|
|
io = InputOutput(yes=True, pretty=False, fancy_input=False)
|
|
coder = Coder.create(
|
|
main_model=Model(f"ollama_chat/{model}"),
|
|
io=io,
|
|
fnames=[os.path.join(root, f) for f in (files or [])],
|
|
auto_commits=True,
|
|
stream=False,
|
|
use_git=True,
|
|
suggest_shell_commands=False,
|
|
detect_urls=False,
|
|
)
|
|
text = coder.run(instruction) or ""
|
|
edited = sorted(coder.aider_edited_files or [])
|
|
commit = getattr(coder, "last_aider_commit_hash", None)
|
|
commit_msg = getattr(coder, "last_aider_commit_message", None)
|
|
except Exception as exc: # aider peut lever des erreurs variées
|
|
return {
|
|
"ok": False,
|
|
"summary": f"échec moteur code : {exc}",
|
|
"text": "", "files": [], "commit": None,
|
|
}
|
|
finally:
|
|
os.chdir(prev_cwd)
|
|
|
|
summary = f"{len(edited)} fichier(s) modifié(s)"
|
|
if commit:
|
|
summary += f" · commit {str(commit)[:7]}"
|
|
return {
|
|
"ok": True,
|
|
"text": text.strip(),
|
|
"files": edited,
|
|
"commit": commit,
|
|
"commit_message": commit_msg,
|
|
"summary": summary,
|
|
}
|