feat(domain,infra,app): borne summary_md du handoff + durcissement seam LLM (LS5)
Clôt le must-have perf du handoff : - domain : HANDOFF_SUMMARY_MAX_CHARS + bound_handoff_summary (helpers privés), re-export lib. - infrastructure : TURN_LINE_MAX_CHARS + élision dans render_turn (summarizer), re-exports. - application : borne entre fold et save (conversation/record), borne défensive dans resolve_handoff (agent/lifecycle) + module test. - seam LLM prêt mais NON activé (aucun LLM câblé). - tests (QA, verts) : conversation_log, conversation_record, agent_lifecycle. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@ -49,7 +49,7 @@ mod summarizer;
|
||||
|
||||
pub use handoff::FsHandoffStore;
|
||||
pub use providers::FsProviderSessionStore;
|
||||
pub use summarizer::{HeuristicHandoffSummarizer, WINDOW};
|
||||
pub use summarizer::{HeuristicHandoffSummarizer, TURN_LINE_MAX_CHARS, WINDOW};
|
||||
|
||||
/// Dossier `.ideai/` à la racine d'un project root.
|
||||
pub(crate) const IDEAI_DIR: &str = ".ideai";
|
||||
|
||||
@ -51,6 +51,14 @@ pub const WINDOW: usize = 20;
|
||||
/// Longueur maximale (en caractères) de l'objectif extrait d'un premier prompt.
|
||||
const OBJECTIVE_MAX_CHARS: usize = 200;
|
||||
|
||||
/// Longueur maximale (en caractères) du **texte aplati** d'un tour rendu sur une ligne
|
||||
/// (lot LS5). C'est le correctif central du trou de perf : sans borne, un gros
|
||||
/// `Response` produit une ligne géante qui gonfle le `summary_md` (et donc le contexte
|
||||
/// injecté à chaque lancement). Au-delà, le texte est tronqué avec une élision `…` ; le
|
||||
/// préfixe `- **role:**` reste **intact** (la ligne reste reparsable). Borne **publique**
|
||||
/// pour que l'agent Test la vérifie sans la deviner.
|
||||
pub const TURN_LINE_MAX_CHARS: usize = 240;
|
||||
|
||||
/// Préfixe de la ligne d'objectif dans le `summary_md` (sert au rendu **et** au reparse).
|
||||
const OBJECTIVE_PREFIX: &str = "**Objectif :** ";
|
||||
|
||||
@ -80,7 +88,9 @@ fn render_turn(turn: &ConversationTurn) -> String {
|
||||
TurnRole::Response => "Response",
|
||||
TurnRole::ToolActivity => "Tool",
|
||||
};
|
||||
let flat = flatten(&turn.text);
|
||||
// Borne LS5 : le texte aplati est tronqué à `TURN_LINE_MAX_CHARS` (élision `…`) pour
|
||||
// éviter qu'un gros Response ne produise une ligne géante. Le préfixe reste intact.
|
||||
let flat = elide(&flatten(&turn.text), TURN_LINE_MAX_CHARS);
|
||||
format!("- **{label}:** {flat}")
|
||||
}
|
||||
|
||||
@ -89,6 +99,17 @@ fn flatten(text: &str) -> String {
|
||||
text.split_whitespace().collect::<Vec<_>>().join(" ")
|
||||
}
|
||||
|
||||
/// Tronque `text` à `max_chars` caractères (char-boundary safe), en ajoutant une
|
||||
/// élision `…` quand il a effectivement été coupé. En deçà, renvoie le texte tel quel.
|
||||
fn elide(text: &str, max_chars: usize) -> String {
|
||||
if text.chars().count() <= max_chars {
|
||||
text.to_owned()
|
||||
} else {
|
||||
let kept: String = text.chars().take(max_chars).collect();
|
||||
format!("{kept}…")
|
||||
}
|
||||
}
|
||||
|
||||
/// Reparse les lignes de tours déjà rendues dans un `summary_md` précédent.
|
||||
///
|
||||
/// Ne récupère que les lignes-tours (préfixe `- **`), en ignorant la ligne d'objectif et
|
||||
|
||||
Reference in New Issue
Block a user