From 43d3c79edad50d61f2aa8ac69e11a4ca0e0a42a9 Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 20 Jul 2026 13:10:20 +0000 Subject: [PATCH] =?UTF-8?q?Int=C3=A8gre=20Ponytail=20:=20m=C3=A9thode=20?= =?UTF-8?q?=C2=AB=20code=20minimal=20=C2=BB=20pour=20les=20t=C3=A2ches=20d?= =?UTF-8?q?e=20code?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adapte github.com/DietrichGebert/ponytail (philosophie anti sur-ingénierie) en méthode transverse de Loki, remède direct aux rendus trop ambitieux qui cassent (ex. « moteur IA » dans un jeu d'échecs). - Échelle de décision injectée pour toute tâche de code (YAGNI -> réutiliser -> natif -> minimum de code), sur les DEUX chemins : dans le contexte de l'agent ET dans la consigne du moteur code (Aider ne voit pas convo). - Nouvel interrupteur « Ponytail (code minimal) » dans Réglages > Intelligence, activé par défaut (fusionne sans migration). Co-Authored-By: Claude Opus 4.8 Claude-Session: https://claude.ai/code/session_01SVay7z3y7q2gEe54ByAE6N --- backend/app/agent_config.py | 4 ++++ backend/app/routes/chat.py | 10 ++++++++++ backend/app/skills.py | 19 +++++++++++++++++++ frontend/src/api/client.ts | 1 + frontend/src/panels/SettingsView.tsx | 2 ++ 5 files changed, 36 insertions(+) diff --git a/backend/app/agent_config.py b/backend/app/agent_config.py index 0553c35..6c04086 100644 --- a/backend/app/agent_config.py +++ b/backend/app/agent_config.py @@ -72,6 +72,7 @@ PROFILE_FIELDS = { "rag_enabled", "embed_model", "skills_enabled", + "ponytail", "keep_alive", *GENERATION_FIELDS, } @@ -125,6 +126,9 @@ DEFAULT_CONFIG: dict = { "embed_model": "auto", # Skills : méthodes expertes injectées automatiquement selon la tâche. "skills_enabled": True, + # Ponytail : méthode « code minimal » (anti sur-ingénierie) injectée pour + # toute tâche de code. Voir github.com/DietrichGebert/ponytail. + "ponytail": True, # Durée de maintien du modèle en VRAM (préchargement). "0" = décharge # aussitôt, "-1" = jamais, "30m" = 30 minutes. "keep_alive": "30m", diff --git a/backend/app/routes/chat.py b/backend/app/routes/chat.py index 24fe0e4..43c1505 100644 --- a/backend/app/routes/chat.py +++ b/backend/app/routes/chat.py @@ -419,6 +419,12 @@ async def chat(req: ChatRequest) -> StreamingResponse: }) yield _sse("notice", {"message": f"📘 Méthode : {skill['title']}"}) + # Ponytail : méthode « code minimal » injectée pour toute tâche de code + # (les deux chemins). Contre la sur-ingénierie qui casse les rendus. + is_code_like = use_code or msg_router.is_code_task(req.content) + if cfg.get("ponytail", True) and is_code_like: + convo.insert(1, {"role": "system", "content": skills.PONYTAIL_GUIDANCE}) + if plan: yield _sse("plan", {"steps": plan}) @@ -436,6 +442,10 @@ async def chat(req: ChatRequest) -> StreamingResponse: extra = instruction_plan if recap: extra = f"\n\n{recap}" + extra + # Le moteur code (Aider) ne voit pas convo : on lui redonne Ponytail + # directement dans la consigne. + if cfg.get("ponytail", True): + extra = "\n\n" + skills.PONYTAIL_GUIDANCE + extra code_files = _mentioned_files(req.content) or session_files[:8] async for chunk in _code_stream( req, code_model, extra=extra, plan=plan, files=code_files, diff --git a/backend/app/skills.py b/backend/app/skills.py index c9887e9..b9814c7 100644 --- a/backend/app/skills.py +++ b/backend/app/skills.py @@ -10,6 +10,25 @@ import re _SKILLS_DIR = os.path.join(os.path.dirname(__file__), "..", "skills") +# Ponytail (https://github.com/DietrichGebert/ponytail) : philosophie de code +# « paresseux » (anti sur-ingénierie). Adaptée en méthode transverse injectée +# pour toute tâche de code — indépendante du sélecteur de skill (mono-skill). +PONYTAIL_TITLE = "Ponytail · code minimal" +PONYTAIL_GUIDANCE = ( + "Méthode Ponytail — code minimal, anti sur-ingénierie. Avant d'écrire du " + "code, descends l'échelle de décision et arrête-toi au premier échelon qui " + "suffit :\n" + "1. NE PAS coder ce qui n'est pas explicitement demandé (YAGNI) ;\n" + "2. RÉUTILISER l'existant (fichiers/fonctions déjà présents) ;\n" + "3. UTILISER les fonctions natives du langage / du navigateur ;\n" + "4. en DERNIER recours seulement, écrire le minimum de code nécessaire.\n" + "Livre la solution la plus simple qui fonctionne : aucune dépendance ni " + "bibliothèque à installer, aucune abstraction prématurée, aucune " + "fonctionnalité en plus non demandée (pas de « moteur IA », d'options ou de " + "configuration superflues). Préfère un seul fichier clair à une " + "architecture élaborée." +) + # Seuil : nombre minimal de mots-clés distincts trouvés dans le message. _MIN_HITS = 2 diff --git a/frontend/src/api/client.ts b/frontend/src/api/client.ts index 6aa88be..f874458 100644 --- a/frontend/src/api/client.ts +++ b/frontend/src/api/client.ts @@ -279,6 +279,7 @@ export interface AgentConfig { rag_enabled: boolean; embed_model: string; skills_enabled: boolean; + ponytail: boolean; keep_alive: string; } diff --git a/frontend/src/panels/SettingsView.tsx b/frontend/src/panels/SettingsView.tsx index 2091c78..9c41443 100644 --- a/frontend/src/panels/SettingsView.tsx +++ b/frontend/src/panels/SettingsView.tsx @@ -436,6 +436,8 @@ export function SettingsView() { "Rappelle d'AUTRES discussions dans celle-ci. Désactivé par défaut : sinon une ancienne demande sans rapport ressurgit. Chaque discussion garde toujours sa propre mémoire."] as const, ["skills_enabled", "Skills automatiques", "Méthodes expertes injectées selon la tâche (débogage, web, refactor…)"] as const, + ["ponytail", "Ponytail (code minimal)", + "Anti sur-ingénierie : code le plus simple qui marche, sans dépendance ni fonctionnalité superflue (github.com/DietrichGebert/ponytail)"] as const, ].map(([key, label, desc], i) => (