Niveau supérieur (inspiré de Jean) : modes Plan/Build/Yolo + panneau Git & Diff

Modes d'exécution (composer) :
- routes/chat : champ mode ; _apply_mode adapte la config —
  plan = outils lecture seule + plan forcé ; yolo = confirm_shell off ;
  build = comportement normal.
- Frontend : ModeSelector dans le composer, mode dans le store + requête chat.

Panneau Git & Diff (le workspace est un dépôt git, Aider commite) :
- routes/git : /api/git/log (commits), /api/git/diff (commit ou working),
  /api/git/revert (git revert --no-edit, confiné au workspace).
- Frontend : onglet Git dans le PreviewPanel — liste des commits, diff
  colorisé, bouton Annuler (revert) avec rafraîchissement de l'arbo.

Bonus : le panneau Matériel explique que « GPU déclaré 12 Go » vient de
GPU_VRAM_MB (valeur manuelle) — à corriger en 16000 pour une 16 Go.

Tests : git log/diff/revert, modes plan/yolo/build via la route chat, builds.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SVay7z3y7q2gEe54ByAE6N
This commit is contained in:
Claude committed 2026-07-15 23:48:06 +00:00
1 parent ffac092a7f
commit 552548e4b4
9 files changed
+388 -15

No files matched your search

+24 -1
View File
@@ -31,6 +31,29 @@ class ChatRequest(BaseModel):
session_id: str
content: str
model: str | None = None
# Mode d'exécution : "plan" (lecture seule), "build" (normal), "yolo" (auto).
mode: str = "build"
# Outils autorisés en mode Plan : lecture/analyse uniquement.
_READONLY_TOOLS = {"read_file", "list_dir", "grep_search"}
def _apply_mode(cfg: dict, mode: str) -> dict:
"""Adapte la config au mode d'exécution choisi dans le composer."""
cfg = dict(cfg)
if mode == "plan":
# Lecture seule : aucune écriture, aucun shell, aucun moteur code.
cfg["tools"] = {
name: (on and name in _READONLY_TOOLS)
for name, on in cfg["tools"].items()
}
cfg["plan_mode"] = True
elif mode == "yolo":
# Autonomie maximale : plus de validation shell.
cfg["confirm_shell"] = False
# "build" : comportement par défaut (inchangé).
return cfg
def _sse(event: str, data: dict) -> str:
@@ -153,7 +176,7 @@ async def chat(req: ChatRequest) -> StreamingResponse:
raise HTTPException(404, "session introuvable")
model = req.model or session.get("model") or settings.default_model
cfg = agent_config.get_config(model)
cfg = _apply_mode(agent_config.get_config(model), req.mode)
# Premier message : titre la session avec un extrait.
if not db.list_messages(req.session_id):