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:
Claude committed 2026-10-15 10:48:38 +00:00
1 parent ef11454a21
commit f2d2669690
3 files changed
+93 -3

No files matched your search

+12
View File
@@ -40,6 +40,8 @@ pub struct FakeGo {
/// Résultat imposé à tout outil (sinon « exec:<nom> »), et archive recall.
pub tool_result: Mutex<Option<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).
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(),
)
}
"/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" => {
st.lease_log.lock().unwrap().push("stop".into());
*st.go_busy.lock().unwrap() = None;
+39 -2
View File
@@ -258,6 +258,9 @@ impl SessionHooks for Crochets {
async fn switched(&self, id: &str) {
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() -> (
@@ -361,9 +364,19 @@ async fn creer_basculer_renommer() {
assert_eq!(textes(&s), ["seulement dans A"]);
s.switch(&b).await.unwrap();
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!(
*h.0.lock().unwrap(),
[format!("switched {a}"), format!("switched {b}")]
log[log.len() - 2..],
[format!("activated {b}"), format!("switched {b}")],
"la discussion active suit chaque bascule"
);
// L'index porte les titres déduits.
let idx = s.read_index().await;
@@ -610,3 +623,27 @@ async fn tour_complet_par_le_go() {
.collect();
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}")
]
);
}