Lot 15 : presets tenus par la façade (LOKI_PRESETS=rust)

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
This commit is contained in:
Claude committed 2026-10-15 18:13:13 +00:00
1 parent 13bcbc74fe
commit a50b8f3cc6
19 files changed
+4805 -3

No files matched your search

+24
View File
@@ -74,6 +74,10 @@ pub struct FakeGo {
pub turn_view: Mutex<Option<serde_json::Value>>,
pub turn_verifier: Mutex<Option<serde_json::Value>>,
pub tool_results: Mutex<HashMap<String, String>>,
/// /internal/v1/tune/guard : message d'une optimisation en cours.
pub tune_busy: Mutex<Option<String>>,
/// /internal/v1/preset/apply reçus : (chemin, mode).
pub preset_applies: Mutex<Vec<(String, String)>>,
/// Comportement de /internal/v1/crypt/* (préfixe « SCELLE: » par défaut).
pub crypt_mode: Mutex<CryptMode>,
/// Réponse de /internal/v1/conv/workspace (None : 404).
@@ -325,6 +329,24 @@ async fn handle(st: Arc<FakeGo>, req: Request<Incoming>) -> Response<Full<Bytes>
*st.go_busy.lock().unwrap() = None;
resp(204, "")
}
"/internal/v1/tune/guard" => match st.tune_busy.lock().unwrap().clone() {
Some(e) => resp(
200,
serde_json::json!({ "busy": true, "error": e }).to_string(),
),
None => resp(200, r#"{"busy":false}"#),
},
"/internal/v1/preset/apply" => {
let body = req.into_body().collect().await.unwrap().to_bytes();
let v: serde_json::Value = serde_json::from_slice(&body).unwrap_or_default();
let path = v["path"].as_str().unwrap_or("").to_string();
let mode = v["mode"].as_str().unwrap_or("").to_string();
if mode == "refus" || path.ends_with("refus.env") {
return resp(500, r#"{"error":"application refusée"}"#);
}
st.preset_applies.lock().unwrap().push((path, mode));
resp(204, "")
}
"/internal/v1/conv/workspace" => match st.conv_workspace.lock().unwrap().clone() {
Some(v) => resp(200, v.to_string()),
None => resp(404, "404 page not found"),
@@ -507,6 +529,7 @@ pub struct Opts {
pub files: Option<Arc<loki_rs::convfiles::ConvFiles>>,
pub push: Option<Arc<loki_rs::push::Push>>,
pub mem: Option<Arc<loki_rs::memory::Memory>>,
pub presets: bool,
}
/// Comme [`start`], avec la conversation tenue par la façade
@@ -602,6 +625,7 @@ pub async fn start_with(
files: opts.files,
push: opts.push,
mem: opts.mem,
presets: opts.presets,
};
tokio::spawn(loki_rs::proxy::serve(fl, cfg, async move {
let _ = rx.await;