Fix UI lag: try_lock on unconscious mutex, don't re-log restored nodes

The unconscious trigger holds the tokio mutex during heavy sync work
(store load, graph build, agent creation), blocking the UI tick which
needs the same lock for snapshots. Fix: try_lock in the UI — skip
the update if the trigger is running.

Also: restore_from_log was re-logging every restored node back to the
log file via push()'s auto-log. Added push_no_log() for restore path.

Co-Authored-By: Proof of Concept <poc@bcachefs.org>
This commit is contained in:
ProofOfConcept 2026-04-09 01:07:55 -04:00
parent b7e053edc3
commit 6529aba069
3 changed files with 11 additions and 12 deletions

View file

@ -776,6 +776,11 @@ impl ContextState {
self.section_mut(section).push(node); self.section_mut(section).push(node);
} }
/// Push without logging — for restoring from an existing log.
pub fn push_no_log(&mut self, section: Section, node: AstNode) {
self.section_mut(section).push(node);
}
/// Replace the body of a leaf at `index` in `section`. /// Replace the body of a leaf at `index` in `section`.
/// Re-tokenizes to maintain the invariant. /// Re-tokenizes to maintain the invariant.
pub fn set_message(&mut self, section: Section, index: usize, body: NodeBody) { pub fn set_message(&mut self, section: Section, index: usize, body: NodeBody) {

View file

@ -572,8 +572,9 @@ impl Agent {
{ {
let mut ctx = self.context.lock().await; let mut ctx = self.context.lock().await;
ctx.clear(Section::Conversation); ctx.clear(Section::Conversation);
// Push without logging — these are already in the log
for node in nodes { for node in nodes {
ctx.push(Section::Conversation, node); ctx.push_no_log(Section::Conversation, node);
} }
} }
self.compact().await; self.compact().await;

View file

@ -377,20 +377,13 @@ async fn run(
idle_state.decay_ewma(); idle_state.decay_ewma();
app.update_idle(&idle_state); app.update_idle(&idle_state);
app.agent_state = mind.subconscious_snapshots().await; app.agent_state = mind.subconscious_snapshots().await;
{ if let Ok(mut unc) = mind.unconscious.try_lock() {
let toggles: Vec<String> = app.agent_toggles.drain(..).collect(); let toggles: Vec<String> = app.agent_toggles.drain(..).collect();
if !toggles.is_empty() { for name in &toggles {
let mut sub = mind.subconscious.lock().await; if mind.subconscious.lock().await.toggle(name).is_none() {
let mut unc = mind.unconscious.lock().await; unc.toggle(name).await;
for name in &toggles {
if sub.toggle(name).is_none() {
unc.toggle(name).await;
}
} }
} }
}
{
let unc = mind.unconscious.lock().await;
app.unconscious_state = unc.snapshots(); app.unconscious_state = unc.snapshots();
app.graph_health = unc.graph_health.clone(); app.graph_health = unc.graph_health.clone();
} }