mirror of
https://github.com/R0m1k3/Loki.git
synced 2026-10-22 06:28:11 +02:00
Lot 6 : effets des discussions par le Go (GoSessionHooks)
Les outils exécutés par le Go lisent la discussion active (dossier de la discussion, mode Code, critères) : chaque chargement, création ou bascule la lui annonce (hook activated, /internal/v1/conv/active). Une discussion supprimée fait nettoyer ses fichiers, travaux, critères, mode et résultats d'outils (/internal/v1/conv/dropped). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016tcGfJWefW5kUGoC2wL8cv
This commit is contained in:
3 files changed
+93
-3
No files matched your search
@@ -14,7 +14,8 @@
|
|||||||
//!
|
//!
|
||||||
//! Ce qui vit hors de la conversation reste derrière [`SessionHooks`] : les
|
//! Ce qui vit hors de la conversation reste derrière [`SessionHooks`] : les
|
||||||
//! fichiers, travaux, critères et mode d'une discussion supprimée, ses
|
//! fichiers, travaux, critères et mode d'une discussion supprimée, ses
|
||||||
//! résultats d'outils, et le préchauffage après une bascule. Le changement de
|
//! résultats d'outils, le préchauffage après une bascule, et la discussion
|
||||||
|
//! active vue par les outils du Go ([`GoSessionHooks`]). Le changement de
|
||||||
//! projet (`projectSwitch`) reste au Go pour l'instant.
|
//! projet (`projectSwitch`) reste au Go pour l'instant.
|
||||||
|
|
||||||
use std::future::Future;
|
use std::future::Future;
|
||||||
@@ -44,6 +45,44 @@ pub trait SessionHooks: Send + Sync + 'static {
|
|||||||
fn dropped(&self, id: &str) -> impl Future<Output = ()> + Send;
|
fn dropped(&self, id: &str) -> impl Future<Output = ()> + Send;
|
||||||
/// Bascule faite (`prewarmAfterSwitch`).
|
/// Bascule faite (`prewarmAfterSwitch`).
|
||||||
fn switched(&self, id: &str) -> impl Future<Output = ()> + Send;
|
fn switched(&self, id: &str) -> impl Future<Output = ()> + Send;
|
||||||
|
/// La discussion ouverte a changé (chargement, création, bascule) : ce
|
||||||
|
/// qui lit l'identifiant actif ailleurs (outils du Go) doit suivre.
|
||||||
|
fn activated(&self, _id: &str) -> impl Future<Output = ()> + Send {
|
||||||
|
async {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Les effets réels, par l'API interne du Go.
|
||||||
|
pub struct GoSessionHooks(pub Store);
|
||||||
|
|
||||||
|
impl SessionHooks for GoSessionHooks {
|
||||||
|
async fn dropped(&self, id: &str) {
|
||||||
|
let body = serde_json::json!({ "id": id });
|
||||||
|
if let Err(e) = self
|
||||||
|
.0
|
||||||
|
.internal_json(
|
||||||
|
hyper::Method::POST,
|
||||||
|
"/internal/v1/conv/dropped",
|
||||||
|
Some(&body),
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
{
|
||||||
|
eprintln!("[conv] nettoyage de la discussion {id} non fait : {e}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn switched(&self, _id: &str) {}
|
||||||
|
|
||||||
|
async fn activated(&self, id: &str) {
|
||||||
|
let body = serde_json::json!({ "id": id });
|
||||||
|
if let Err(e) = self
|
||||||
|
.0
|
||||||
|
.internal_json(hyper::Method::POST, "/internal/v1/conv/active", Some(&body))
|
||||||
|
.await
|
||||||
|
{
|
||||||
|
eprintln!("[conv] discussion active non transmise au Go ({id}) : {e}");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Refus d'une opération sur les discussions.
|
/// Refus d'une opération sur les discussions.
|
||||||
@@ -169,6 +208,7 @@ impl<H: SessionHooks> Sessions<H> {
|
|||||||
match self.store.get_open(BK_CHAT, &conv_key(&id)).await {
|
match self.store.get_open(BK_CHAT, &conv_key(&id)).await {
|
||||||
Ok(body) => {
|
Ok(body) => {
|
||||||
self.conv.load_from(&id, &body.unwrap_or_default());
|
self.conv.load_from(&id, &body.unwrap_or_default());
|
||||||
|
self.hooks.activated(&id).await;
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
Err(e) => last_err = e,
|
Err(e) => last_err = e,
|
||||||
@@ -241,6 +281,7 @@ impl<H: SessionHooks> Sessions<H> {
|
|||||||
.flatten()
|
.flatten()
|
||||||
.unwrap_or_default();
|
.unwrap_or_default();
|
||||||
self.conv.load_from(id, &body);
|
self.conv.load_from(id, &body);
|
||||||
|
self.hooks.activated(id).await;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -40,6 +40,8 @@ pub struct FakeGo {
|
|||||||
/// Résultat imposé à tout outil (sinon « exec:<nom> »), et archive recall.
|
/// Résultat imposé à tout outil (sinon « exec:<nom> »), et archive recall.
|
||||||
pub tool_result: Mutex<Option<String>>,
|
pub tool_result: Mutex<Option<String>>,
|
||||||
pub recall: Mutex<Vec<String>>,
|
pub recall: Mutex<Vec<String>>,
|
||||||
|
/// Discussion active annoncée et discussions supprimées.
|
||||||
|
pub conv_log: Mutex<Vec<String>>,
|
||||||
/// Adresse d'écoute du faux Go (pour un client `Store` direct).
|
/// Adresse d'écoute du faux Go (pour un client `Store` direct).
|
||||||
pub backend: Mutex<Option<SocketAddr>>,
|
pub backend: Mutex<Option<SocketAddr>>,
|
||||||
}
|
}
|
||||||
@@ -179,6 +181,16 @@ async fn handle(st: Arc<FakeGo>, req: Request<Incoming>) -> Response<Full<Bytes>
|
|||||||
serde_json::json!({"id": format!("r{}", r.len())}).to_string(),
|
serde_json::json!({"id": format!("r{}", r.len())}).to_string(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
"/internal/v1/conv/active" | "/internal/v1/conv/dropped" => {
|
||||||
|
let body = req.into_body().collect().await.unwrap().to_bytes();
|
||||||
|
let v: serde_json::Value = serde_json::from_slice(&body).unwrap_or_default();
|
||||||
|
let what = path.rsplit('/').next().unwrap();
|
||||||
|
st.conv_log
|
||||||
|
.lock()
|
||||||
|
.unwrap()
|
||||||
|
.push(format!("{what} {}", v["id"].as_str().unwrap_or_default()));
|
||||||
|
resp(204, "")
|
||||||
|
}
|
||||||
"/internal/v1/engine/stop" => {
|
"/internal/v1/engine/stop" => {
|
||||||
st.lease_log.lock().unwrap().push("stop".into());
|
st.lease_log.lock().unwrap().push("stop".into());
|
||||||
*st.go_busy.lock().unwrap() = None;
|
*st.go_busy.lock().unwrap() = None;
|
||||||
|
|||||||
@@ -258,6 +258,9 @@ impl SessionHooks for Crochets {
|
|||||||
async fn switched(&self, id: &str) {
|
async fn switched(&self, id: &str) {
|
||||||
self.0.lock().unwrap().push(format!("switched {id}"));
|
self.0.lock().unwrap().push(format!("switched {id}"));
|
||||||
}
|
}
|
||||||
|
async fn activated(&self, id: &str) {
|
||||||
|
self.0.lock().unwrap().push(format!("activated {id}"));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn sessions() -> (
|
async fn sessions() -> (
|
||||||
@@ -361,9 +364,19 @@ async fn creer_basculer_renommer() {
|
|||||||
assert_eq!(textes(&s), ["seulement dans A"]);
|
assert_eq!(textes(&s), ["seulement dans A"]);
|
||||||
s.switch(&b).await.unwrap();
|
s.switch(&b).await.unwrap();
|
||||||
assert_eq!(textes(&s), ["seulement dans B"]);
|
assert_eq!(textes(&s), ["seulement dans B"]);
|
||||||
|
let switched: Vec<String> =
|
||||||
|
h.0.lock()
|
||||||
|
.unwrap()
|
||||||
|
.iter()
|
||||||
|
.filter(|l| l.starts_with("switched"))
|
||||||
|
.cloned()
|
||||||
|
.collect();
|
||||||
|
assert_eq!(switched, [format!("switched {a}"), format!("switched {b}")]);
|
||||||
|
let log = h.0.lock().unwrap().clone();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
*h.0.lock().unwrap(),
|
log[log.len() - 2..],
|
||||||
[format!("switched {a}"), format!("switched {b}")]
|
[format!("activated {b}"), format!("switched {b}")],
|
||||||
|
"la discussion active suit chaque bascule"
|
||||||
);
|
);
|
||||||
// L'index porte les titres déduits.
|
// L'index porte les titres déduits.
|
||||||
let idx = s.read_index().await;
|
let idx = s.read_index().await;
|
||||||
@@ -610,3 +623,27 @@ async fn tour_complet_par_le_go() {
|
|||||||
.collect();
|
.collect();
|
||||||
assert_eq!(answer, "Voilà.");
|
assert_eq!(answer, "Voilà.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn crochets_go_des_discussions() {
|
||||||
|
let (st, go, _stop, _t) = store().await;
|
||||||
|
let s = Sessions::new(
|
||||||
|
st.clone(),
|
||||||
|
Conversation::new(),
|
||||||
|
loki_rs::chat::sessions::GoSessionHooks(st),
|
||||||
|
);
|
||||||
|
s.load().await.unwrap();
|
||||||
|
let a = s.conv().id();
|
||||||
|
let b = s.new_conv().await.unwrap();
|
||||||
|
s.delete(&b).await.unwrap();
|
||||||
|
let log = go.conv_log.lock().unwrap().clone();
|
||||||
|
assert_eq!(
|
||||||
|
log,
|
||||||
|
[
|
||||||
|
format!("active {a}"),
|
||||||
|
format!("active {b}"),
|
||||||
|
format!("dropped {b}"),
|
||||||
|
format!("active {a}")
|
||||||
|
]
|
||||||
|
);
|
||||||
|
}
|
||||||
Reference in new issue
Block a user