Presets : changer de modèle ramenait le moteur de l'image

Le moteur mis à jour depuis l'interface (Réglages → Moteur, BIN →
/data/engine/server-cuda-b10680/llama-server) ne tenait pas : à la
bascule de preset suivante — changer de modèle, tâche planifiée —
/app/llama-server revenait, et le modèle qui chargeait cinq minutes
plus tôt mourait sur « unknown model architecture: 'qwen4exp' ». Le
journal alternait les deux moteurs sans qu'aucun réglage visible ait
bougé, et le panneau Moteur affichait « fourni par l'image » juste
après un « ✓ moteur mis à jour ».

Cause : chaque preset créé depuis l'UI embarque BIN (newPresetSeedKeys),
donc le chemin de l'image de l'époque, et applyPresetFile remplace TOUTE
la configuration par le preset — BIN n'était pas dans preservedKeys.

Le moteur est un réglage de machine : le courant est conservé à la
bascule, sauf si le preset désigne un backend personnalisé (compilé pour
un modèle précis — là, c'est un vrai choix par modèle, il gagne). Et un
nouveau preset ne fige plus le moteur de l'image ni un moteur téléchargé.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01961iDyM6pwn2dE2SW23gYX
This commit is contained in:
MichaelandClaude Fable 5 committed 2026-08-30 08:27:42 +02:00
1 parent 78c258ab45
commit 6f6a3218ad
2 files changed
+95 -2

No files matched your search

+37 -2
View File
@@ -225,9 +225,38 @@ func applyPresetFile(target string) error {
}
next[k] = v
}
// Le moteur suit la machine, pas le preset (voir presetImposesEngine).
if cur["BIN"] != "" && !presetImposesEngine(next["BIN"]) {
next["BIN"] = cur["BIN"]
}
return WriteConfig(next)
}
// presetImposesEngine : le BIN d'un preset a-t-il son mot à dire ?
//
// Le moteur est un réglage de MACHINE. Un preset créé avant une mise à jour du
// moteur (Réglages → Moteur, qui installe sous $LOKI_HOME/engine/) embarque
// encore le chemin de l'image, /app/llama-server ; l'appliquer — changer de
// modèle, une tâche planifiée — ramenait silencieusement ce vieux moteur, et
// un modèle qui chargeait la veille mourait sur « unknown model architecture »
// sans qu'aucun réglage visible ait bougé. Le moteur de l'image, un moteur
// téléchargé par Loki ou un précompilé ne sont donc jamais imposés par un
// preset : le courant reste.
//
// Un backend PERSONNALISÉ (compilé pour un modèle précis, backend_llamacpp.go :
// « un backend custom se choisit par modèle »), lui, est un vrai choix par
// modèle : le preset gagne.
func presetImposesEngine(p string) bool {
p = strings.TrimSpace(p)
if p == "" || engineOwns(p) || prebuiltOwns(p) {
return false
}
if img := strings.TrimSpace(os.Getenv("LOKI_ENGINE_BIN")); img != "" && samePath(p, img) {
return false
}
return true
}
// SwitchToPreset installe le preset et redémarre le service. Les réglages
// « appareil » (preservedKeys) sont conservés à travers la bascule.
func SwitchToPreset(target string) error {
@@ -287,6 +316,10 @@ func cmdSwitch(args []string) error {
// mélangeaient donc aux options cochées pour le nouveau, et il fallait penser à
// tout nettoyer à la main. On repart d'une base vide : les valeurs non
// renseignées sont les défauts documentés (CTX 32768, NGL 999, BATCH 2048…).
//
// BIN n'est repris que s'il désigne un backend personnalisé (presetImposesEngine) :
// figer /app/llama-server dans chaque preset, c'est ce qui faisait perdre le
// moteur mis à jour à la première bascule.
var newPresetSeedKeys = []string{"BIN", "HOST", "PORT"}
// newPresetSeed renvoie la configuration de départ d'un preset créé depuis l'UI.
@@ -294,9 +327,11 @@ func newPresetSeed() map[string]string {
cur := ReadConfig()
seed := map[string]string{}
for _, k := range newPresetSeedKeys {
if v := cur[k]; v != "" {
seed[k] = v
v := cur[k]
if v == "" || (k == "BIN" && !presetImposesEngine(v)) {
continue
}
seed[k] = v
}
return seed
}