v0.9.3 : statut moteur plus précis + réglages d'interface

- statut : la pastille ne dit plus toujours « modèle incompatible » (prêt /
  chargement… / erreur / arrêté) ; le détail n'accuse l'incompatibilité que
  quand le journal le montre (quant/architecture), sinon renvoie au journal
- panneau Actions : bouton « refresh » retiré ; mise à jour + exporter sur une
  ligne, bench + clear chat sur l'autre
- modale preset : titre sans le mot « Preset » redondant (juste le nom)
- mémoire : « auto (proactive) » → « auto »
This commit is contained in:
nathaninline committed 2026-08-14 11:20:18 +02:00
1 parent e3957fa749
commit d4989f2991
10 files changed
+54 -55

No files matched your search

+1 -1
View File
@@ -10,7 +10,7 @@ import (
"strings"
)
const Version = "0.9.2"
const Version = "0.9.3"
// Main est le vrai main() du binaire (cmd/ajean ne fait que l'appeler).
func Main() {
+15 -18
View File
@@ -1249,7 +1249,7 @@ button:hover{border-color:var(--dim);color:var(--text)}
<div class="slist">
<label class="switchrow"><span>mode</span>
<select id="mem-mode" onchange="setMemMode()" class="sctl">
<option value="always">auto (proactive)</option>
<option value="always">auto</option>
<option value="ondemand">sur demande</option>
<option value="off">désactivée</option>
</select>
@@ -1460,23 +1460,17 @@ button:hover{border-color:var(--dim);color:var(--text)}
</details>
<details id="upd-details"><summary><span class="stitle">Actions</span></summary>
<div class="slist"><div class="rowbody">
<!-- Ligne 1 : mise à jour + export du fil. Depuis la 0.8 la conversation vit
dans ajean.db (bbolt, verrouillé tant que le service tourne) : sans le
bouton exporter, plus personne ne peut relire/archiver ses échanges. -->
<div class="row" style="margin:0">
<button id="upd-check" onclick="checkUpdate()">↥ Vérifier les mises à jour</button>
</div>
<div id="upd-msg" class="muted"></div>
<!-- Export du fil. Depuis la 0.8 la conversation vit dans ajean.db (bbolt,
binaire et verrouillé tant que le service tourne) : sans ce bouton,
plus personne ne peut relire ni archiver ses échanges, ce que
permettait l'ancien conversation.json. -->
<div class="row" style="margin-bottom:0">
<button onclick="loadAll()">↻ refresh</button>
<button id="btn-bench" onclick="runBenchUI()">bench</button>
<button onclick="openExportModal()" title="choisir le format et ce qu'on emporte">⤓ exporter…</button>
</div>
<!-- « clear chat » est en DERNIER, et seul sur sa ligne : c'est la seule
action destructive du panneau, elle ne doit pas se trouver sous le
doigt qui visait « refresh ». -->
<div id="upd-msg" class="muted"></div>
<!-- Ligne 2 : bench + clear chat (seule action destructive, gardée en dernier). -->
<div class="row" style="margin-bottom:0">
<button id="btn-bench" onclick="runBenchUI()">bench</button>
<button onclick="resetChat()">⌫ clear chat</button>
</div>
</div></div>
@@ -2280,9 +2274,12 @@ async function loadStatus(){
const el=document.getElementById('status-svc');
// Trois états : service coupé (err) · service actif mais modèle pas encore
// chargé (loading, llama-server renvoie 503) · modèle prêt (ok).
let cls='err', txt=s.state;
// Pastille COURTE et honnête. Le détail (cause exacte) va dans #model-err
// dessous : la pastille ne doit pas affirmer « incompatible » quand l'échec
// peut être tout autre chose.
let cls='err', txt='arrêté';
if(s.active && s.health){ cls='ok'; txt='prêt'; }
else if(s.load_error){ cls='err'; txt='modèle incompatible'; }
else if(s.load_error){ cls='err'; txt='erreur'; }
else if(s.active){ cls='loading'; txt='chargement…'; }
el.className='statuspill '+cls;
el.innerHTML='<span class="dot"></span>'+txt;
@@ -3020,7 +3017,7 @@ const KINDS = {
// skills keep name-as-identity (param 'name').
// newLabel / nameHint : « Nouveau Page » et « Nom du preset » dans l'éditeur de
// mémoire venaient d'un libellé unique décliné mécaniquement.
preset: {label:'Preset', newLabel:'Nouveau preset', nameHint:'Nom du preset',
preset: {label:'', newLabel:'Nouveau preset', nameHint:'Nom du preset',
param:'id', getUrl:'/api/preset', saveUrl:'/api/preset/save', delUrl:'/api/preset/delete', reload:()=>loadPresets()},
mem: {label:'Page', newLabel:'Nouvelle page', nameHint:'Nom de la page',
param:'name', getUrl:'/api/mem', saveUrl:'/api/mem/save', delUrl:'/api/mem/delete', reload:()=>loadMem()},
@@ -3039,7 +3036,7 @@ async function openItem(kind, key){
const K = KINDS[kind];
const seq = ++openSeq;
editingKind = kind; editingKey = key || '';
document.getElementById('modal-title').textContent = key ? (K.label + ' · ' + key) : K.newLabel;
document.getElementById('modal-title').textContent = key ? (K.label ? K.label + ' · ' + key : key) : K.newLabel;
document.getElementById('m-name').value = key || '';
document.getElementById('m-name').placeholder = K.nameHint;
document.getElementById('m-content').value = '';
@@ -3091,7 +3088,7 @@ async function openItem(kind, key){
const d = await r.json();
if(seq !== openSeq) return; // une autre ouverture a pris la main
const display = d.name || key || '';
document.getElementById('modal-title').textContent = key ? (K.label + ' · ' + display) : K.newLabel;
document.getElementById('modal-title').textContent = key ? (K.label ? K.label + ' · ' + display : display) : K.newLabel;
document.getElementById('m-name').value = display;
document.getElementById('m-content').value = d.content || '';
if(kind === 'preset'){
+7 -13
View File
@@ -79,7 +79,7 @@
<div class="slist">
<label class="switchrow"><span>mode</span>
<select id="mem-mode" onchange="setMemMode()" class="sctl">
<option value="always">auto (proactive)</option>
<option value="always">auto</option>
<option value="ondemand">sur demande</option>
<option value="off">désactivée</option>
</select>
@@ -290,23 +290,17 @@
</details>
<details id="upd-details"><summary><span class="stitle">Actions</span></summary>
<div class="slist"><div class="rowbody">
<!-- Ligne 1 : mise à jour + export du fil. Depuis la 0.8 la conversation vit
dans ajean.db (bbolt, verrouillé tant que le service tourne) : sans le
bouton exporter, plus personne ne peut relire/archiver ses échanges. -->
<div class="row" style="margin:0">
<button id="upd-check" onclick="checkUpdate()">↥ Vérifier les mises à jour</button>
</div>
<div id="upd-msg" class="muted"></div>
<!-- Export du fil. Depuis la 0.8 la conversation vit dans ajean.db (bbolt,
binaire et verrouillé tant que le service tourne) : sans ce bouton,
plus personne ne peut relire ni archiver ses échanges, ce que
permettait l'ancien conversation.json. -->
<div class="row" style="margin-bottom:0">
<button onclick="loadAll()">↻ refresh</button>
<button id="btn-bench" onclick="runBenchUI()">bench</button>
<button onclick="openExportModal()" title="choisir le format et ce qu'on emporte">⤓ exporter…</button>
</div>
<!-- « clear chat » est en DERNIER, et seul sur sa ligne : c'est la seule
action destructive du panneau, elle ne doit pas se trouver sous le
doigt qui visait « refresh ». -->
<div id="upd-msg" class="muted"></div>
<!-- Ligne 2 : bench + clear chat (seule action destructive, gardée en dernier). -->
<div class="row" style="margin-bottom:0">
<button id="btn-bench" onclick="runBenchUI()">bench</button>
<button onclick="resetChat()">⌫ clear chat</button>
</div>
</div></div>
+5 -2
View File
@@ -3,9 +3,12 @@ async function loadStatus(){
const el=document.getElementById('status-svc');
// Trois états : service coupé (err) · service actif mais modèle pas encore
// chargé (loading, llama-server renvoie 503) · modèle prêt (ok).
let cls='err', txt=s.state;
// Pastille COURTE et honnête. Le détail (cause exacte) va dans #model-err
// dessous : la pastille ne doit pas affirmer « incompatible » quand l'échec
// peut être tout autre chose.
let cls='err', txt='arrêté';
if(s.active && s.health){ cls='ok'; txt='prêt'; }
else if(s.load_error){ cls='err'; txt='modèle incompatible'; }
else if(s.load_error){ cls='err'; txt='erreur'; }
else if(s.active){ cls='loading'; txt='chargement…'; }
el.className='statuspill '+cls;
el.innerHTML='<span class="dot"></span>'+txt;
+3 -3
View File
@@ -74,7 +74,7 @@ const KINDS = {
// skills keep name-as-identity (param 'name').
// newLabel / nameHint : « Nouveau Page » et « Nom du preset » dans l'éditeur de
// mémoire venaient d'un libellé unique décliné mécaniquement.
preset: {label:'Preset', newLabel:'Nouveau preset', nameHint:'Nom du preset',
preset: {label:'', newLabel:'Nouveau preset', nameHint:'Nom du preset',
param:'id', getUrl:'/api/preset', saveUrl:'/api/preset/save', delUrl:'/api/preset/delete', reload:()=>loadPresets()},
mem: {label:'Page', newLabel:'Nouvelle page', nameHint:'Nom de la page',
param:'name', getUrl:'/api/mem', saveUrl:'/api/mem/save', delUrl:'/api/mem/delete', reload:()=>loadMem()},
@@ -93,7 +93,7 @@ async function openItem(kind, key){
const K = KINDS[kind];
const seq = ++openSeq;
editingKind = kind; editingKey = key || '';
document.getElementById('modal-title').textContent = key ? (K.label + ' · ' + key) : K.newLabel;
document.getElementById('modal-title').textContent = key ? (K.label ? K.label + ' · ' + key : key) : K.newLabel;
document.getElementById('m-name').value = key || '';
document.getElementById('m-name').placeholder = K.nameHint;
document.getElementById('m-content').value = '';
@@ -145,7 +145,7 @@ async function openItem(kind, key){
const d = await r.json();
if(seq !== openSeq) return; // une autre ouverture a pris la main
const display = d.name || key || '';
document.getElementById('modal-title').textContent = key ? (K.label + ' · ' + display) : K.newLabel;
document.getElementById('modal-title').textContent = key ? (K.label ? K.label + ' · ' + display : display) : K.newLabel;
document.getElementById('m-name').value = display;
document.getElementById('m-content').value = d.content || '';
if(kind === 'preset'){
+13 -2
View File
@@ -102,8 +102,19 @@ func modelLoadError() string {
if loaded || reason == "" {
return ""
}
return "Le modèle n'a pas pu être chargé : " + reason +
". Il est probablement incompatible avec le moteur sélectionné — choisis un autre backend pour ce modèle (édite le modèle → section Moteur)."
// Message PRÉCIS selon la cause : n'affirmer l'incompatibilité que quand le
// journal la montre vraiment (quant/architecture). Un échec générique de
// chargement peut avoir bien d'autres causes (mémoire, fichier, tenseur) — on
// renvoie alors vers le journal plutôt que d'accuser à tort le moteur.
switch reason {
case "format de quantification non reconnu par ce moteur",
"type/architecture de modèle inconnu de ce moteur":
return "Modèle incompatible avec le moteur : " + reason +
". Choisis un autre backend (édite le modèle → Moteur)."
default:
return "Le modèle n'a pas pu être chargé (" + reason +
"). Ouvre le journal du moteur pour le détail."
}
}
// handleServiceLog (GET /api/service/log) : dernières lignes du journal du