loopd: compact after a full turn and retry SessionFull once

Co-Authored-By: ornith-1.5-35b-a3b <agent@wntrmute.dev>
This commit is contained in:
2026-10-03 00:38:35 -07:00
co-authored by ornith-1.5-35b-a3b
parent fe8e3e9354
commit b274fa7d62
4 changed files with 353 additions and 11 deletions
+51
View File
@@ -11,6 +11,8 @@ use crate::memory::MemorySource;
use crate::session::Session;
use crate::tools::Registry;
use crate::turn::is_context_full;
use crate::turn::{Runtime, TurnError, TurnOutcome, run_turn};
use bxcore::TurnEvent;
/// Why a summary call or a next-epoch write failed. Every variant's `Display` ends with the
/// runbook pointer `session-compact-failed`.
@@ -133,3 +135,52 @@ pub fn commit(
})?;
Ok(())
}
/// After `run_turn`: compact when the last `Usage` is due, or on `SessionFull` (then retry the
/// user message once). Compact failure on a successful turn keeps the success; on `SessionFull`
/// keeps `SessionFull`. Other errors skip compact.
pub fn finish_turn(
session: &mut Session,
rt: &Runtime<'_>,
memory: &dyn MemorySource,
text: &str,
speaker: Option<&str>,
on_event: &mut dyn FnMut(&TurnEvent),
outcome: Result<TurnOutcome, TurnError>,
) -> Result<TurnOutcome, TurnError> {
match outcome {
Err(TurnError::SessionFull) => match compact_session(session, rt, memory) {
Ok(()) => run_turn(session, rt, text, speaker, on_event),
Err(e) => {
log_compact(session, &e);
Err(TurnError::SessionFull)
}
},
Ok(done) => {
if let Some(usage) = session.last_usage()
&& due(&usage, rt.cfg.compact.threshold, rt.cfg.expect.n_ctx)
&& let Err(e) = compact_session(session, rt, memory)
{
log_compact(session, &e);
}
Ok(done)
}
Err(e) => Err(e),
}
}
fn compact_session(
session: &mut Session,
rt: &Runtime<'_>,
memory: &dyn MemorySource,
) -> Result<(), CompactError> {
let summary = summarise(rt.cfg, rt.client, session)?;
commit(session, rt.cfg, rt.registry, memory, summary)
}
fn log_compact(session: &Session, e: &CompactError) {
eprintln!(
"loopd: could not compact session {}: {e}",
session.id().as_str()
);
}