mirror of
https://github.com/R0m1k3/Loki.git
synced 2026-10-22 14:38:12 +02:00
Lot 33 : préchauffage (PREWARM) tenu par la façade
PREWARM ne garde plus la conversation au Go. La façade tient l'historique : elle assemble et envoie la requête du prochain tour ; le Go garde le compteur des requêtes en vol et ce qui l'annule. Go (facade_prewarm.go) : - /internal/v1/prewarm/check : moteur libre d'un vrai travail, loin de minuit, en bonne santé, slot visé ; - /internal/v1/prewarm/begin : rechargement SLOT_PERSIST puis inscription comme LA requête en vol ; son annulation est relayée à la façade ; - /internal/v1/prewarm/end : place rendue, cache repris noté ; - /internal/v1/oai/begin : prewarm_keep pour l'étape qui le prolonge ; - fin de tâche planifiée : le déclencheur part à la façade. Rust (chat/prewarm.rs) : - assemblage par les mêmes fonctions que le tour, sentinelle « . », un seul jeton, non streamé ; abstention (capacités inconnues, tour en cours, discussion vide, compaction attendue, assemblage inattendu) ; - déclencheurs : fin de tour, fin de tâche, changement de discussion ou de projet (full : après 3 s) ; - le tour garde le préchauffage qu'il prolonge (empreintes des messages et des options de rendu) et coupe tout de suite les autres ; - télémétrie kind=prewarm. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016tcGfJWefW5kUGoC2wL8cv
This commit is contained in:
21 files changed
+1457
-35
No files matched your search
@@ -196,7 +196,7 @@ impl EngineSummarizer {
|
||||
{
|
||||
o.insert("id_slot".into(), Value::from(n));
|
||||
}
|
||||
_gate = engine_begin(store, "", slot == Some(1)).await;
|
||||
_gate = engine_begin(store, "", slot == Some(1), false).await;
|
||||
}
|
||||
let body = serde_json::to_vec(&payload).unwrap_or_default();
|
||||
let resp = self
|
||||
@@ -328,6 +328,8 @@ pub struct ChatShared {
|
||||
pub patterns: Arc<RetryPatterns>,
|
||||
/// Sonde de gabarit (`chat_tplprobe.go`) : derniers verdicts et cache.
|
||||
pub tpl: Arc<super::tplprobe::TplProbe>,
|
||||
/// Préchauffage (PREWARM) : celui en vol, capacités des discussions.
|
||||
pub prewarm: super::prewarm::Prewarm,
|
||||
}
|
||||
|
||||
/// Ce que la compaction sait du tour.
|
||||
@@ -397,15 +399,21 @@ pub async fn engine_slot_for(store: &Store, conv: &str, main: bool) -> Option<u8
|
||||
|
||||
/// Ouvre un ticket « en vol » auprès du Go (`engineRequestBeginSide`) : le
|
||||
/// slot de la discussion n'est pas effacé pendant la requête, et un
|
||||
/// préchauffage est annulé. `main_conv` : étape d'un tour de cette
|
||||
/// discussion ; `side` : requête sur le second slot. `None` si le Go ne
|
||||
/// répond pas — la requête part quand même.
|
||||
pub async fn engine_begin(store: &Store, main_conv: &str, side: bool) -> Option<GateTicket> {
|
||||
/// préchauffage est annulé — sauf `keep_prewarm`, une étape de tour qui le
|
||||
/// prolonge. `main_conv` : étape d'un tour de cette discussion ; `side` :
|
||||
/// requête sur le second slot. `None` si le Go ne répond pas — la requête
|
||||
/// part quand même.
|
||||
pub async fn engine_begin(
|
||||
store: &Store,
|
||||
main_conv: &str,
|
||||
side: bool,
|
||||
keep_prewarm: bool,
|
||||
) -> Option<GateTicket> {
|
||||
match store
|
||||
.internal_json(
|
||||
hyper::Method::POST,
|
||||
"/internal/v1/oai/begin",
|
||||
Some(&json!({ "main_conv": main_conv, "side": side })),
|
||||
Some(&json!({ "main_conv": main_conv, "side": side, "prewarm_keep": keep_prewarm })),
|
||||
)
|
||||
.await
|
||||
{
|
||||
@@ -461,14 +469,14 @@ impl Drop for GateTicket {
|
||||
}
|
||||
|
||||
impl GoTurnHost {
|
||||
async fn gate_begin(&self) -> Option<GateTicket> {
|
||||
async fn gate_begin(&self, keep_prewarm: bool) -> Option<GateTicket> {
|
||||
let main_conv = if self.perf_kind == super::perf::KIND_MAIN {
|
||||
self.conv_id.as_str()
|
||||
} else {
|
||||
""
|
||||
};
|
||||
let side = self.side_slot.load(Ordering::SeqCst);
|
||||
engine_begin(&self.shared.store, main_conv, side).await
|
||||
engine_begin(&self.shared.store, main_conv, side, keep_prewarm).await
|
||||
}
|
||||
}
|
||||
|
||||
@@ -527,13 +535,23 @@ pub fn see_image_message(label: &str, img: Value) -> Message {
|
||||
}
|
||||
|
||||
impl TurnHost for GoTurnHost {
|
||||
async fn send(&self, ep: &ChatEndpoint, body: Vec<u8>) -> Result<Reply, SendError> {
|
||||
async fn send(
|
||||
&self,
|
||||
ep: &ChatEndpoint,
|
||||
body: Vec<u8>,
|
||||
keep_prewarm: bool,
|
||||
) -> Result<Reply, SendError> {
|
||||
// Moteur local : requête comptée en vol jusqu'à la fin de lecture du
|
||||
// flux (le ticket voyage avec le corps). Rien pour une API externe.
|
||||
// Un préchauffage qu'elle ne prolonge pas est coupé tout de suite (le
|
||||
// Go l'annulerait aussi, un aller-retour plus tard).
|
||||
let gate = if ep.external {
|
||||
None
|
||||
} else {
|
||||
self.gate_begin().await
|
||||
if !keep_prewarm {
|
||||
self.shared.prewarm.stop();
|
||||
}
|
||||
self.gate_begin(keep_prewarm).await
|
||||
};
|
||||
match self.shared.http.post(&ep.url, &ep.key, body).await {
|
||||
Ok(resp) => {
|
||||
@@ -720,6 +738,15 @@ impl TurnHost for GoTurnHost {
|
||||
self.shared.echo_refusals.refuse(model);
|
||||
}
|
||||
|
||||
fn prewarm_keeps(&self, prefix: &[u64], payload: &Value) -> bool {
|
||||
self.perf_kind == super::perf::KIND_MAIN
|
||||
&& self.shared.prewarm.live()
|
||||
&& self
|
||||
.shared
|
||||
.prewarm
|
||||
.keeps(prefix, super::prewarm::opts_hash(payload))
|
||||
}
|
||||
|
||||
async fn keep_images(&self) -> Option<i64> {
|
||||
// Fil principal d'une discussion seulement : la vérification ne
|
||||
// persiste pas son historique.
|
||||
|
||||
Reference in new issue
Block a user