mirror of
https://github.com/R0m1k3/Loki.git
synced 2026-10-17 20:26:35 +02:00
La façade sert la liste des presets (pastilles, mesures du bench quand elles correspondent à la configuration), leur ordre, l'éditeur (lecture, graine d'un preset neuf, enregistrement avec nom de fichier unique, prompt système), la suppression (refusée pour l'actif, modèle compris sur demande), les aperçus de l'éditeur (cache de prompts, second slot, avis MoE et de chargement, réutilisant le port de loki serve), la copie en placement auto, les presets externes (la clé n'est jamais rendue, test par un vrai appel de complétion) et la bascule, quand LOKI_PRESETS=rust (expérimental ; le Go reste le défaut). Ce qui touche au moteur reste au Go jusqu'à son lot : facade_presets.go expose /internal/v1/preset/apply (bascule avec état du slot gardé et moteur relancé ou arrêté, preset en service réappliqué) et /internal/v1/tune/guard (verrou de l'optimiseur), et remet les routes du tunnel à la façade. Parité : parity_presets_test.go tire du Go les fonctions pures et 70 appels de route avec presets/, models/ et la base après chacun, rejoués par tests/presets_api.rs ; bascule et application vérifiées de bout en bout contre le faux Go, presetApply côté Go. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016tcGfJWefW5kUGoC2wL8cv
137 lines
4.6 KiB
Go
137 lines
4.6 KiB
Go
package loki
|
|
|
|
import (
|
|
"fmt"
|
|
"net/http"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
)
|
|
|
|
// facade_presets.go — presets tenus par la façade Rust (LOKI_PRESETS=rust,
|
|
// lot 15 de la migration ; expérimental, le Go reste le défaut) : liste,
|
|
// ordre, lecture, éditeur, suppression, aperçus de l'éditeur, copie en
|
|
// placement auto, presets externes, bascule.
|
|
//
|
|
// Les presets restent des fichiers presets/*.env et leur prompt système une
|
|
// clé de la base. Ce qui touche au moteur reste ici jusqu'au lot qui le
|
|
// portera : verrou de l'optimiseur (/internal/v1/tune/guard) et application
|
|
// d'un preset à la configuration vivante, avec l'état du slot gardé et le
|
|
// moteur relancé ou arrêté (/internal/v1/preset/apply).
|
|
|
|
const facadePresetsEnv = "LOKI_PRESETS"
|
|
|
|
// facadePresets : la façade tient-elle les presets ?
|
|
func facadePresets() bool {
|
|
return strings.EqualFold(strings.TrimSpace(os.Getenv(facadePresetsEnv)), "rust") &&
|
|
facadeAddr() != "" && internalToken() != ""
|
|
}
|
|
|
|
// facadePresetsRoutes : les routes que la façade sert alors (presets_api.rs).
|
|
var facadePresetsRoutes = map[string]bool{
|
|
"/api/presets": true,
|
|
"/api/presets/order": true,
|
|
"/api/preset": true,
|
|
"/api/preset/save": true,
|
|
"/api/preset/cacheram": true,
|
|
"/api/preset/moe": true,
|
|
"/api/preset/autoplace": true,
|
|
"/api/preset/delete": true,
|
|
"/api/preset/external": true,
|
|
"/api/preset/external/save": true,
|
|
"/api/preset/external/test": true,
|
|
"/api/switch": true,
|
|
}
|
|
|
|
// presetServiceAction : le pilotage du moteur après une application de
|
|
// preset. Variable pour les tests (aucun moteur n'y tourne).
|
|
var presetServiceAction = serviceAction
|
|
|
|
// presetApply applique un preset (chemin dans presets/) à la configuration
|
|
// vivante, comme les handlers d'origine :
|
|
//
|
|
// switch : bascule (handleSwitch) — état du slot relevé avant, moteur arrêté
|
|
// pour un preset externe, relancé sinon, en arrière-plan ;
|
|
// save : preset en service modifié (handlePresetSave) — relancé ;
|
|
// apply : preset externe en service modifié (handlePresetExternalSave) —
|
|
// configuration seule.
|
|
func presetApply(path, mode string) error {
|
|
root, err := filepath.Abs(presetsDir())
|
|
if err != nil {
|
|
return err
|
|
}
|
|
abs, err := filepath.Abs(path)
|
|
if err != nil || !strings.HasPrefix(abs, root+string(filepath.Separator)) || !strings.HasSuffix(abs, ".env") {
|
|
return fmt.Errorf("preset hors du dossier des presets")
|
|
}
|
|
switch mode {
|
|
case "switch":
|
|
persist := slotPersistPrepare()
|
|
if err := applyPresetFile(abs); err != nil {
|
|
return err
|
|
}
|
|
fmt.Printf("%s config.env <- %s\n", green("[ok]"), filepath.Base(abs))
|
|
if isExternalConfig(ReadConfig()) {
|
|
fmt.Println(dim("[info] preset externe — arrêt du moteur local"))
|
|
go func() {
|
|
if serviceIsActive() {
|
|
persist.save()
|
|
if err := presetServiceAction("stop"); err != nil {
|
|
fmt.Printf("%s arrêt du moteur après bascule externe : %v\n", red("[ERREUR]"), err)
|
|
}
|
|
}
|
|
}()
|
|
return nil
|
|
}
|
|
fmt.Println(dim("[info] redémarrage du service..."))
|
|
go func() {
|
|
persist.save()
|
|
if err := presetServiceAction("restart"); err != nil {
|
|
fmt.Printf("%s redémarrage après bascule: %v\n", red("[ERREUR]"), err)
|
|
}
|
|
}()
|
|
return nil
|
|
case "save":
|
|
if err := applyPresetFile(abs); err != nil {
|
|
return err
|
|
}
|
|
fmt.Printf("%s config.env <- %s (preset actif modifié)\n", green("[ok]"), filepath.Base(abs))
|
|
fmt.Println(dim("[info] redémarrage du service..."))
|
|
go func() {
|
|
if err := presetServiceAction("restart"); err != nil {
|
|
fmt.Printf("%s redémarrage après modification du preset: %v\n", red("[ERREUR]"), err)
|
|
}
|
|
}()
|
|
return nil
|
|
case "apply":
|
|
return applyPresetFile(abs)
|
|
}
|
|
return fmt.Errorf("mode inconnu : %q", mode)
|
|
}
|
|
|
|
// handleInternalPresetApply : POST {path, mode} → 204, ou 400/500 + {error}.
|
|
func handleInternalPresetApply(w http.ResponseWriter, r *http.Request) {
|
|
var in struct {
|
|
Path string `json:"path"`
|
|
Mode string `json:"mode"`
|
|
}
|
|
if !readInternalJSON(w, r, &in) {
|
|
return
|
|
}
|
|
if err := presetApply(in.Path, in.Mode); err != nil {
|
|
sendJSON(w, http.StatusInternalServerError, map[string]any{"error": err.Error()})
|
|
return
|
|
}
|
|
w.WriteHeader(http.StatusNoContent)
|
|
}
|
|
|
|
// handleInternalTuneGuard : GET → {busy, error} — une optimisation tient-elle
|
|
// le moteur (tuneGuard) ?
|
|
func handleInternalTuneGuard(w http.ResponseWriter, r *http.Request) {
|
|
if err := tuneGuard(); err != nil {
|
|
sendJSON(w, http.StatusOK, map[string]any{"busy": true, "error": err.Error()})
|
|
return
|
|
}
|
|
sendJSON(w, http.StatusOK, map[string]any{"busy": false})
|
|
}
|