mirror of
https://github.com/R0m1k3/Loki.git
synced 2026-10-11 17:26:57 +02:00
Applis web fiables : fichier autonome, zéro dépendance externe, pas de bluff
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 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01SVay7z3y7q2gEe54ByAE6N
This commit is contained in:
3 files changed
+58
-4
No files matched your search
@@ -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]
|
||||
|
||||
@@ -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 <style>, tout le "
|
||||
"JS dans <script> à la fin du <body>. Pas de fichiers .css/.js séparés.\n"
|
||||
"2. AUCUNE ressource externe : pas de CDN, pas de <script src=\"https://…\">, "
|
||||
"pas de bibliothèque à télécharger (jQuery, React, chess.js, Stockfish, "
|
||||
".wasm…). Le sandbox est hors-ligne : ça ne se charge JAMAIS. Si une "
|
||||
"fonctionnalité a besoin d'une lib, écris une version simple toi-même en "
|
||||
"JavaScript natif.\n"
|
||||
"3. Le rendu doit s'afficher AU CHARGEMENT : construis réellement le DOM "
|
||||
"dans un script qui s'exécute (ex. génère les 64 cases de l'échiquier en "
|
||||
"boucle). Pas de fonction jamais appelée, pas de conteneur laissé vide.\n"
|
||||
"4. Ne prétends JAMAIS qu'une fonctionnalité marche sans l'avoir codée, et "
|
||||
"ne « simule » pas un moteur en le faisant passer pour réel : dis "
|
||||
"clairement ce qui est réel et ce qui ne l'est pas.\n"
|
||||
"5. Design sobre, lisible et moderne — mais la priorité est que ça "
|
||||
"FONCTIONNE vraiment."
|
||||
)
|
||||
|
||||
|
||||
ALL_SKILLS: dict[str, dict] = _load()
|
||||
|
||||
|
||||
|
||||
+12
-3
@@ -123,9 +123,18 @@ def check_html(target: str) -> list[str]:
|
||||
|
||||
base_dir = os.path.dirname(target)
|
||||
|
||||
# Références locales cassées (href/src vers un fichier absent).
|
||||
for _, ref in re.findall(r"""(href|src)=["']([^"'#]+)["']""", content, re.I):
|
||||
if re.match(r"^(https?:|data:|mailto:|tel:|//|javascript:)", ref, re.I):
|
||||
# Références href/src : cassées (fichier local absent) ou externes
|
||||
# (CDN/WASM qui ne se chargeront pas dans un sandbox hors-ligne).
|
||||
for attr, ref in re.findall(r"""(href|src)=["']([^"'#]+)["']""", content, re.I):
|
||||
low = ref.lower()
|
||||
if low.startswith(("data:", "mailto:", "tel:", "javascript:")):
|
||||
continue
|
||||
if re.match(r"^(https?:)?//", ref, re.I):
|
||||
base = low.split("?")[0]
|
||||
if attr.lower() == "src" and base.endswith((".js", ".mjs", ".wasm")):
|
||||
issues.append(f"script externe (hors-ligne : ne se charge pas) : {ref}")
|
||||
elif attr.lower() == "href" and base.endswith(".css"):
|
||||
issues.append(f"style externe (hors-ligne : ne se charge pas) : {ref}")
|
||||
continue
|
||||
ref_path = os.path.normpath(os.path.join(base_dir, ref.split("?")[0]))
|
||||
if not os.path.exists(ref_path):
|
||||
|
||||
Reference in new issue
Block a user