From 920f575507945f7bdb894dc8aecd1939693c8321 Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 21 Jul 2026 08:57:09 +0000 Subject: [PATCH] =?UTF-8?q?Applis=20web=20fiables=20:=20fichier=20autonome?= =?UTF-8?q?,=20z=C3=A9ro=20d=C3=A9pendance=20externe,=20pas=20de=20bluff?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Les modèles promettaient des libs qui ne se chargent jamais hors-ligne (Stockfish, CDN…), éclataient le code en fichiers incohérents, puis déclaraient « ça marche » sans rien vérifier. - Contraintes « appli web » injectées pour toute tâche web (agent + moteur code) : UN seul index.html autonome (CSS/JS inline), AUCUNE ressource externe (implémenter en JS natif à la place), rendu réel au chargement, interdiction de « simuler » une lib en la disant réelle. - check_html signale désormais les scripts/styles externes (CDN/WASM) qui ne se chargeront pas dans le sandbox hors-ligne, en plus des références locales cassées. Co-Authored-By: Claude Opus 4.8 Claude-Session: https://claude.ai/code/session_01SVay7z3y7q2gEe54ByAE6N --- backend/app/routes/chat.py | 10 +++++++++- backend/app/skills.py | 37 +++++++++++++++++++++++++++++++++++++ backend/app/tools.py | 15 ++++++++++++--- 3 files changed, 58 insertions(+), 4 deletions(-) diff --git a/backend/app/routes/chat.py b/backend/app/routes/chat.py index 43c1505..d5512a1 100644 --- a/backend/app/routes/chat.py +++ b/backend/app/routes/chat.py @@ -425,6 +425,12 @@ async def chat(req: ChatRequest) -> StreamingResponse: if cfg.get("ponytail", True) and is_code_like: convo.insert(1, {"role": "system", "content": skills.PONYTAIL_GUIDANCE}) + # Appli web : contraintes dures (fichier autonome, zéro dépendance + # externe, rendu réel) pour que ça marche vraiment hors-ligne. + want_web = is_code_like and skills.is_web_task(req.content) + if want_web: + convo.insert(1, {"role": "system", "content": skills.WEBAPP_GUIDANCE}) + if plan: yield _sse("plan", {"steps": plan}) @@ -443,7 +449,9 @@ async def chat(req: ChatRequest) -> StreamingResponse: if recap: extra = f"\n\n{recap}" + extra # Le moteur code (Aider) ne voit pas convo : on lui redonne Ponytail - # directement dans la consigne. + # (et les contraintes web) directement dans la consigne. + if want_web: + extra = "\n\n" + skills.WEBAPP_GUIDANCE + extra if cfg.get("ponytail", True): extra = "\n\n" + skills.PONYTAIL_GUIDANCE + extra code_files = _mentioned_files(req.content) or session_files[:8] diff --git a/backend/app/skills.py b/backend/app/skills.py index b9814c7..4867bf3 100644 --- a/backend/app/skills.py +++ b/backend/app/skills.py @@ -64,6 +64,43 @@ def _load() -> dict[str, dict]: return out +_WEB_RE = re.compile( + r"\b(html|css|javascript|js|page|site|web|appli|application|interface|" + r"bouton|formulaire|canvas|animation|jeu|game|échiquier|echiquier|" + r"dashboard|landing|maquette|ui|front)\b", + re.I, +) + + +def is_web_task(message: str) -> bool: + """La demande porte-t-elle sur une page / appli web ?""" + return bool(_WEB_RE.search(message or "")) + + +# Contraintes « appli web » : le sandbox de prévisualisation est HORS-LIGNE et +# isolé (pas de CDN, pas de WASM téléchargé). Sans ces règles, les modèles +# promettent des libs (Stockfish, React…) qui ne se chargent jamais, éclatent +# le code en plusieurs fichiers incohérents, puis déclarent « ça marche ». +WEBAPP_GUIDANCE = ( + "Contraintes STRICTES pour une page/appli web :\n" + "1. UN SEUL fichier index.html AUTONOME : tout le CSS dans