Make compaction transitions recoverable
This commit is contained in:
55
src/app.rs
55
src/app.rs
@@ -212,6 +212,8 @@ pub(crate) enum Message {
|
||||
SessionTitleChanged(String),
|
||||
ConfirmRenameSession,
|
||||
RetitleSession(i32),
|
||||
CompactSession(i32),
|
||||
RebuildSessionContext(i32),
|
||||
SetSessionState(i32, SessionState),
|
||||
ToggleArchivedSessions(i32),
|
||||
ShowChat,
|
||||
@@ -773,6 +775,10 @@ impl App {
|
||||
if let Some(active) = &self.active_tools {
|
||||
active.cancel.store(true, Ordering::Relaxed);
|
||||
}
|
||||
#[cfg(target_os = "macos")]
|
||||
if let Some(compaction) = &self.active_compaction {
|
||||
compaction.active.cancel.store(true, Ordering::Relaxed);
|
||||
}
|
||||
}
|
||||
Message::GenerationTick => {
|
||||
#[cfg(target_os = "macos")]
|
||||
@@ -924,6 +930,44 @@ impl App {
|
||||
self.error = Some("Local Metal generation requires macOS.".into());
|
||||
}
|
||||
}
|
||||
Message::CompactSession(session_id) => {
|
||||
self.session_menu = None;
|
||||
if self.generating || self.selected_session != Some(session_id) {
|
||||
self.error = Some("Open an idle session before compacting it.".into());
|
||||
} else {
|
||||
#[cfg(target_os = "macos")]
|
||||
if let Err(error) = self.start_compaction(
|
||||
generation::PendingContinuation::None,
|
||||
"manual compact action",
|
||||
) {
|
||||
self.error = Some(error);
|
||||
}
|
||||
#[cfg(not(target_os = "macos"))]
|
||||
{
|
||||
self.error = Some("Local Metal generation requires macOS.".into());
|
||||
}
|
||||
}
|
||||
}
|
||||
Message::RebuildSessionContext(session_id) => {
|
||||
self.session_menu = None;
|
||||
if self.generating && self.selected_session == Some(session_id) {
|
||||
self.error =
|
||||
Some("Stop the active generation before rebuilding context.".into());
|
||||
} else {
|
||||
match fs::remove_file(session_checkpoint_path(session_id)) {
|
||||
Ok(()) => {
|
||||
self.error = None;
|
||||
self.finish_cache_change();
|
||||
}
|
||||
Err(error) if error.kind() == std::io::ErrorKind::NotFound => {
|
||||
self.error = None;
|
||||
}
|
||||
Err(error) => {
|
||||
self.error = Some(format!("Could not discard the checkpoint: {error}"));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Message::SetSessionState(session_id, state) => {
|
||||
self.session_menu = None;
|
||||
if let Some(database) = &mut self.database {
|
||||
@@ -1402,6 +1446,13 @@ fn sweep_orphan_checkpoints(directory: &Path, projects: &[ProjectWithSessions])
|
||||
let mut removed = false;
|
||||
for file in files.flatten() {
|
||||
let path = file.path();
|
||||
if path
|
||||
.extension()
|
||||
.is_some_and(|value| value == "compacting" || value == "tmp")
|
||||
{
|
||||
removed |= fs::remove_file(&path).is_ok();
|
||||
continue;
|
||||
}
|
||||
if path.extension().is_none_or(|value| value != "bin") {
|
||||
continue;
|
||||
}
|
||||
@@ -1427,6 +1478,10 @@ fn session_checkpoint_path(session_id: i32) -> PathBuf {
|
||||
kv_cache_path().join(format!("{session_id}.bin"))
|
||||
}
|
||||
|
||||
fn session_compaction_checkpoint_path(session_id: i32) -> PathBuf {
|
||||
kv_cache_path().join(format!("{session_id}.compacting"))
|
||||
}
|
||||
|
||||
/// Content-addressed KV cache for turns that belong to no stored session: the
|
||||
/// HTTP endpoint and the app's own one-shot requests share it.
|
||||
fn transient_cache_path() -> PathBuf {
|
||||
|
||||
Reference in New Issue
Block a user