Fix input blocked during scoring: release agent lock before disk write

The scoring callback was holding the agent lock while doing a
synchronous file write (save_memory_scores). This blocked the event
loop from acquiring the lock to process user input.

Fix: collect the scores snapshot while holding the lock, drop the
lock, then write to disk.

Co-Authored-By: Proof of Concept <poc@bcachefs.org>
This commit is contained in:
Kent Overstreet 2026-04-07 22:32:10 -04:00
parent 1be16b9f7b
commit 7c5fddcb19

View file

@ -56,9 +56,9 @@ fn load_memory_scores(section: &mut ContextSection, path: &std::path::Path) {
} }
} }
/// Save all memory scores to disk. /// Collect scored memory keys from conversation entries.
fn save_memory_scores(section: &ContextSection, path: &std::path::Path) { fn collect_memory_scores(section: &ContextSection) -> std::collections::BTreeMap<String, f64> {
let scores: std::collections::BTreeMap<String, f64> = section.entries().iter() section.entries().iter()
.filter_map(|ce| { .filter_map(|ce| {
if let ConversationEntry::Memory { key, score: Some(s), .. } = &ce.entry { if let ConversationEntry::Memory { key, score: Some(s), .. } = &ce.entry {
Some((key.clone(), *s)) Some((key.clone(), *s))
@ -66,8 +66,12 @@ fn save_memory_scores(section: &ContextSection, path: &std::path::Path) {
None None
} }
}) })
.collect(); .collect()
if let Ok(json) = serde_json::to_string_pretty(&scores) { }
/// Save memory scores to disk.
fn save_memory_scores(scores: &std::collections::BTreeMap<String, f64>, path: &std::path::Path) {
if let Ok(json) = serde_json::to_string_pretty(scores) {
let _ = std::fs::write(path, json); let _ = std::fs::write(path, json);
dbglog!("[scoring] saved {} scores to {}", scores.len(), path.display()); dbglog!("[scoring] saved {} scores to {}", scores.len(), path.display());
} }
@ -402,6 +406,7 @@ impl Mind {
let agent = agent.clone(); let agent = agent.clone();
let path = scores_path.clone(); let path = scores_path.clone();
async move { async move {
let scores_snapshot = {
let mut ag = agent.lock().await; let mut ag = agent.lock().await;
for i in 0..ag.context.conversation.len() { for i in 0..ag.context.conversation.len() {
if let ConversationEntry::Memory { key: k, .. } = &ag.context.conversation.entries()[i].entry { if let ConversationEntry::Memory { key: k, .. } = &ag.context.conversation.entries()[i].entry {
@ -410,8 +415,12 @@ impl Mind {
} }
} }
} }
save_memory_scores(&ag.context.conversation, &path);
ag.changed.notify_one(); ag.changed.notify_one();
// Snapshot scores while we have the lock
collect_memory_scores(&ag.context.conversation)
};
// Write to disk after releasing the lock
save_memory_scores(&scores_snapshot, &path);
} }
}, },
).await; ).await;