mirror of
https://github.com/R0m1k3/Loki.git
synced 2026-10-22 22:48:11 +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:
|
if cfg.get("ponytail", True) and is_code_like:
|
||||||
convo.insert(1, {"role": "system", "content": skills.PONYTAIL_GUIDANCE})
|
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:
|
if plan:
|
||||||
yield _sse("plan", {"steps": plan})
|
yield _sse("plan", {"steps": plan})
|
||||||
|
|
||||||
@@ -443,7 +449,9 @@ async def chat(req: ChatRequest) -> StreamingResponse:
|
|||||||
if recap:
|
if recap:
|
||||||
extra = f"\n\n{recap}" + extra
|
extra = f"\n\n{recap}" + extra
|
||||||
# Le moteur code (Aider) ne voit pas convo : on lui redonne Ponytail
|
# 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):
|
if cfg.get("ponytail", True):
|
||||||
extra = "\n\n" + skills.PONYTAIL_GUIDANCE + extra
|
extra = "\n\n" + skills.PONYTAIL_GUIDANCE + extra
|
||||||
code_files = _mentioned_files(req.content) or session_files[:8]
|
code_files = _mentioned_files(req.content) or session_files[:8]
|
||||||
|
|||||||
@@ -64,6 +64,43 @@ def _load() -> dict[str, dict]:
|
|||||||
return out
|
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()
|
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)
|
base_dir = os.path.dirname(target)
|
||||||
|
|
||||||
# Références locales cassées (href/src vers un fichier absent).
|
# Références href/src : cassées (fichier local absent) ou externes
|
||||||
for _, ref in re.findall(r"""(href|src)=["']([^"'#]+)["']""", content, re.I):
|
# (CDN/WASM qui ne se chargeront pas dans un sandbox hors-ligne).
|
||||||
if re.match(r"^(https?:|data:|mailto:|tel:|//|javascript:)", ref, re.I):
|
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
|
continue
|
||||||
ref_path = os.path.normpath(os.path.join(base_dir, ref.split("?")[0]))
|
ref_path = os.path.normpath(os.path.join(base_dir, ref.split("?")[0]))
|
||||||
if not os.path.exists(ref_path):
|
if not os.path.exists(ref_path):
|
||||||
|
|||||||
Reference in new issue
Block a user