Lot 6 : le tour branché sur le moteur, les outils et la base (chat::host)

GoTurnHost est le TurnHost de la façade : envoi par EngineHttp (clé de
l'endpoint, pannes classées comme friendlyLLMError), outils par l'API du Go
avec leurs suites (capture, aperçu, image relayée), résultats complets
confiés à l'écrivain des discussions (id « <discussion>.<aléa> »),
compaction par Compactor avec un résumeur qui interroge le moteur
(EngineSummarizer) et l'archive recall du Go (StoreRecall), images jointes
lues sur disque et ouvertes par le Go, en cache borné à 64 Mio.

RecallArchive devient asynchrone ; la boucle consulte la mémoire des
refus de compaction avant d'annoncer une compaction en cours de tour.

Écarts : pas de résumé en continuation (état du slot tenu par le Go), ni
conseil de cache, ni garde d'écriture du mode Code.

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:34:15 +00:00
1 parent e114ba3800
commit fea055fd52
7 files changed
+843 -7

No files matched your search

+9 -4
View File
@@ -644,7 +644,12 @@ pub struct RecallEntry {
pub trait RecallArchive {
/// Range `content` VERBATIM et rend son id (« r7 »). Une erreur (base
/// absente…) laisse le bloc non archivé : repli transparent.
fn archive(&self, label: &str, role: &str, content: &str) -> Result<String, String>;
fn archive(
&self,
label: &str,
role: &str,
content: &str,
) -> impl Future<Output = Result<String, String>> + Send;
}
/// Archive absente : rien n'est jamais archivé.
@@ -652,7 +657,7 @@ pub trait RecallArchive {
pub struct NoRecall;
impl RecallArchive for NoRecall {
fn archive(&self, _label: &str, _role: &str, _content: &str) -> Result<String, String> {
async fn archive(&self, _label: &str, _role: &str, _content: &str) -> Result<String, String> {
Err("archive recall indisponible".into())
}
}
@@ -1587,7 +1592,7 @@ impl<S: Summarizer, R: RecallArchive> Compactor<'_, S, R> {
let content = msg_text(m);
let tool = names.get(&m.tool_call_id).map_or("", String::as_str);
let label = recall_label(&m.role, tool, &content);
let Ok(id) = self.recall.archive(&label, &m.role, &content) else {
let Ok(id) = self.recall.archive(&label, &m.role, &content).await else {
continue;
};
let e = RecallEntry { id, label };
@@ -2011,7 +2016,7 @@ mod tests {
}
impl RecallArchive for MemRecall {
fn archive(&self, label: &str, role: &str, content: &str) -> Result<String, String> {
async fn archive(&self, label: &str, role: &str, content: &str) -> Result<String, String> {
let mut b = self.blocks.lock().unwrap();
b.push((label.into(), role.into(), content.into()));
Ok(format!("r{}", b.len()))