mirror of
https://github.com/R0m1k3/Loki.git
synced 2026-10-24 07:28:13 +02:00
Façade : changement de projet sans écraser la discussion, détenteur décidé par le Go
Avec LOKI_CHAT=rust, changer de projet passait par projectSwitch du Go, qui enregistrait SA copie de la discussion — chargée au démarrage, périmée — par-dessus celle de la façade, ouvrait une autre discussion que la façade ignorait, et ne voyait pas un tour de la façade en cours. Désormais : - /api/projects (switch) remet le changement à la façade (/internal/facade/v1/project/switch) : elle enregistre sa discussion avec le projet quitté, fait changer le projet actif au Go (/internal/v1/project/activate), ouvre la plus récente du nouveau projet (une neuve s'il n'en a pas) ; refusé pendant un tour (409) ; - supprimer un projet : la façade le quitte d'abord s'il est actif, puis supprime ses discussions (/internal/facade/v1/project/drop). Réglages que la façade ne sait pas honorer (PROJ_SNAPSHOT, KEEP_TURN_IMAGES, NUDGE_IN_TOOL, SIDE_SLOT, SLOT_PERSIST, PREWARM, motifs retry_patterns) : le Go garde la conversation, décidé une fois au démarrage (facadeChatBlocker) ; la façade le lit (/internal/v1/chat/holder) avant de servir quoi que ce soit, au lieu d'échouer en plein tour. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016tcGfJWefW5kUGoC2wL8cv
This commit is contained in:
14 files changed
+655
-20
No files matched your search
@@ -617,6 +617,39 @@ impl ChatService {
|
||||
Some(String::from_utf8_lossy(&b).into_owned())
|
||||
}
|
||||
|
||||
/// Changement de projet (`/api/projects`, action switch), remis par le
|
||||
/// Go : refusé pendant un tour.
|
||||
pub async fn project_switch(&self, slug: &str) -> Result<(), Refused> {
|
||||
if self.sessions.conv().is_generating() {
|
||||
return Err(Refused {
|
||||
status: 409,
|
||||
error: "une génération est en cours".into(),
|
||||
});
|
||||
}
|
||||
self.sessions
|
||||
.project_switch(slug)
|
||||
.await
|
||||
.map_err(|e| Refused {
|
||||
status: 400,
|
||||
error: e.to_string(),
|
||||
})
|
||||
}
|
||||
|
||||
/// Suppression d'un projet (`deleteProject`) : ses discussions d'abord,
|
||||
/// refusé pendant un tour.
|
||||
pub async fn drop_project(&self, slug: &str) -> Result<usize, Refused> {
|
||||
if self.sessions.conv().is_generating() {
|
||||
return Err(Refused {
|
||||
status: 409,
|
||||
error: "une génération est en cours".into(),
|
||||
});
|
||||
}
|
||||
self.sessions.drop_project(slug).await.map_err(|e| Refused {
|
||||
status: 400,
|
||||
error: e.to_string(),
|
||||
})
|
||||
}
|
||||
|
||||
/// Un événement d'affichage né hors d'un tour (bascule du mode Code,
|
||||
/// critères édités), sur le fil courant.
|
||||
pub fn push_delta(&self, d: Delta) {
|
||||
@@ -998,6 +1031,20 @@ impl ChatService {
|
||||
}
|
||||
}
|
||||
|
||||
/// Qui tient la conversation, d'après le Go (`/internal/v1/chat/holder`) :
|
||||
/// `None` : la façade ; `Some(raison)` : le Go la garde (réglage que la façade
|
||||
/// ne sait pas honorer). Décidé une fois par process, côté Go.
|
||||
pub async fn go_keeps_chat(store: &crate::store::Store) -> Result<Option<String>, String> {
|
||||
let v = store
|
||||
.internal_json(hyper::Method::GET, "/internal/v1/chat/holder", None)
|
||||
.await?;
|
||||
match v["holder"].as_str() {
|
||||
Some("rust") => Ok(None),
|
||||
Some("go") => Ok(Some(v["reason"].as_str().unwrap_or("").to_string())),
|
||||
_ => Err(format!("détenteur de la conversation illisible : {v}")),
|
||||
}
|
||||
}
|
||||
|
||||
impl ChatShared {
|
||||
/// L'état partagé des tours, autour de l'écrivain des discussions.
|
||||
/// `img_dir` : `LOKI_HOME/chatimg`.
|
||||
|
||||
Reference in new issue
Block a user