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:
@ -2,7 +2,10 @@
|
||||
|
||||
use std::sync::Arc;
|
||||
|
||||
use domain::{ConversationId, ConversationLog, ConversationTurn, HandoffStore, HandoffSummarizer};
|
||||
use domain::{
|
||||
bound_handoff_summary, ConversationId, ConversationLog, ConversationTurn, HandoffStore,
|
||||
HandoffSummarizer, HANDOFF_SUMMARY_MAX_CHARS,
|
||||
};
|
||||
|
||||
use crate::error::AppError;
|
||||
|
||||
@ -63,6 +66,9 @@ impl RecordTurn {
|
||||
/// 1. **append** the turn to the canonical log (source of truth) ;
|
||||
/// 2. **load** the previous handoff (`None` on a first checkpoint) ;
|
||||
/// 3. **fold** `prev` with the single new turn (incremental, best-effort) ;
|
||||
/// 3b. **bound** the folded handoff's summary to [`HANDOFF_SUMMARY_MAX_CHARS`] — a
|
||||
/// **universal cap independent of the summarizer** (heuristic *or* a future LLM):
|
||||
/// idempotent, never rejecting, so it never blocks the checkpoint (LS5) ;
|
||||
/// 4. **save** the advanced handoff.
|
||||
///
|
||||
/// The append happens **first** so the durable source of truth is never behind
|
||||
@ -92,6 +98,13 @@ impl RecordTurn {
|
||||
.fold(prev, std::slice::from_ref(&turn))
|
||||
.await;
|
||||
|
||||
// 3b. **Universal bound** (LS5): clamp the resume summary to
|
||||
// `HANDOFF_SUMMARY_MAX_CHARS`, *independently of the summarizer*. Whatever
|
||||
// produced the handoff — the heuristic or a future LLM summarizer — the
|
||||
// persisted (and later injected) summary is size-bounded. Idempotent and
|
||||
// never rejecting, so it can never block the checkpoint.
|
||||
let handoff = bound_handoff_summary(handoff, HANDOFF_SUMMARY_MAX_CHARS);
|
||||
|
||||
// 4. Persist the advanced handoff (overwrites the previous resume point).
|
||||
self.handoffs.save(conversation, handoff).await?;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user