forked from kent/consciousness
replace try_lock() with lock_blocking() across UI thread
Add lock_blocking() to TrackedMutex: blocks current thread using block_in_place + futures::executor::block_on, safe for sync contexts. Replace all try_lock() calls with lock_blocking() in slash commands, UI rendering, and status reads. Lock hold times are fast enough that blocking briefly is fine, and this eliminates the spurious 'lock unavailable' paths that were never actually hit. Kept rx_mutex.try_lock() in mod.rs (std::sync::Mutex for stderr rx).
This commit is contained in:
parent
5210f7dd66
commit
4225294d16
28 changed files with 4199 additions and 67 deletions
|
|
@ -34,12 +34,12 @@ fn commands() -> Vec<SlashCommand> { vec![
|
|||
handler: |s, _| { let _ = s.mind_tx.send(MindCommand::NewSession); } },
|
||||
SlashCommand { name: "/save", help: "Save session to disk",
|
||||
handler: |s, _| {
|
||||
if let Ok(mut ag) = s.agent.state.try_lock() { ag.notify("saved"); }
|
||||
{ let mut ag = s.agent.state.lock_blocking(); ag.notify("saved"); }
|
||||
} },
|
||||
SlashCommand { name: "/model", help: "Show/switch model (/model <name>)",
|
||||
handler: |s, arg| {
|
||||
if arg.is_empty() {
|
||||
if let Ok(mut ag) = s.agent.state.try_lock() {
|
||||
{ let mut ag = s.agent.state.lock_blocking();
|
||||
let names = s.agent.app_config.model_names();
|
||||
let label = if names.is_empty() {
|
||||
format!("model: {}", s.agent.model())
|
||||
|
|
@ -62,7 +62,7 @@ fn commands() -> Vec<SlashCommand> { vec![
|
|||
SlashCommand { name: "/dmn", help: "Show DMN state",
|
||||
handler: |s, _| {
|
||||
let st = s.shared_mind.lock().unwrap();
|
||||
if let Ok(mut ag) = s.agent.state.try_lock() {
|
||||
{ let mut ag = s.agent.state.lock_blocking();
|
||||
ag.notify(format!("DMN: {:?} ({}/{})", st.dmn, st.dmn_turns, st.max_dmn_turns));
|
||||
}
|
||||
} },
|
||||
|
|
@ -71,7 +71,7 @@ fn commands() -> Vec<SlashCommand> { vec![
|
|||
let mut st = s.shared_mind.lock().unwrap();
|
||||
st.dmn = crate::mind::subconscious::State::Resting { since: std::time::Instant::now() };
|
||||
st.dmn_turns = 0;
|
||||
if let Ok(mut ag) = s.agent.state.try_lock() { ag.notify("DMN sleeping"); }
|
||||
{ let mut ag = s.agent.state.lock_blocking(); ag.notify("DMN sleeping"); }
|
||||
} },
|
||||
SlashCommand { name: "/wake", help: "Wake DMN to foraging",
|
||||
handler: |s, _| {
|
||||
|
|
@ -79,14 +79,14 @@ fn commands() -> Vec<SlashCommand> { vec![
|
|||
if matches!(st.dmn, crate::mind::subconscious::State::Off) { crate::mind::subconscious::set_off(false); }
|
||||
st.dmn = crate::mind::subconscious::State::Foraging;
|
||||
st.dmn_turns = 0;
|
||||
if let Ok(mut ag) = s.agent.state.try_lock() { ag.notify("DMN foraging"); }
|
||||
{ let mut ag = s.agent.state.lock_blocking(); ag.notify("DMN foraging"); }
|
||||
} },
|
||||
SlashCommand { name: "/pause", help: "Full stop — no autonomous ticks (Ctrl+P)",
|
||||
handler: |s, _| {
|
||||
let mut st = s.shared_mind.lock().unwrap();
|
||||
st.dmn = crate::mind::subconscious::State::Paused;
|
||||
st.dmn_turns = 0;
|
||||
if let Ok(mut ag) = s.agent.state.try_lock() { ag.notify("DMN paused"); }
|
||||
{ let mut ag = s.agent.state.lock_blocking(); ag.notify("DMN paused"); }
|
||||
} },
|
||||
SlashCommand { name: "/help", help: "Show this help",
|
||||
handler: |s, _| { notify_help(&s.agent); } },
|
||||
|
|
@ -116,7 +116,7 @@ pub async fn cmd_switch_model(
|
|||
}
|
||||
|
||||
fn notify_help(agent: &std::sync::Arc<crate::agent::Agent>) {
|
||||
if let Ok(mut ag) = agent.state.try_lock() {
|
||||
{ let mut ag = agent.state.lock_blocking();
|
||||
let mut help = String::new();
|
||||
for cmd in &commands() {
|
||||
help.push_str(&format!("{:12} {}\n", cmd.name, cmd.help));
|
||||
|
|
@ -581,16 +581,10 @@ impl InteractScreen {
|
|||
self.pending_display_count = 0;
|
||||
|
||||
let (generation, entries) = {
|
||||
let st = match self.agent.state.try_lock() {
|
||||
Ok(st) => st,
|
||||
Err(_) => return,
|
||||
};
|
||||
let st = self.agent.state.lock_blocking();
|
||||
let generation = st.generation;
|
||||
drop(st);
|
||||
let ctx = match self.agent.context.try_lock() {
|
||||
Ok(ctx) => ctx,
|
||||
Err(_) => return,
|
||||
};
|
||||
let ctx = self.agent.context.lock_blocking();
|
||||
(generation, ctx.conversation().to_vec())
|
||||
};
|
||||
|
||||
|
|
@ -654,7 +648,7 @@ impl InteractScreen {
|
|||
if let Some(cmd) = dispatch_command(input) {
|
||||
(cmd.handler)(self, &input[cmd.name.len()..].trim_start());
|
||||
} else {
|
||||
if let Ok(mut ag) = self.agent.state.try_lock() {
|
||||
{ let mut ag = self.agent.state.lock_blocking();
|
||||
ag.notify(format!("unknown: {}", input.split_whitespace().next().unwrap_or(input)));
|
||||
}
|
||||
}
|
||||
|
|
@ -770,9 +764,8 @@ impl InteractScreen {
|
|||
/// Draw the main (F1) screen — four-pane layout with status bar.
|
||||
fn draw_main(&mut self, frame: &mut Frame, size: Rect, app: &App) {
|
||||
// Main layout: content area + active tools overlay + status bar
|
||||
let st_guard = app.agent.state.try_lock().ok();
|
||||
let tool_lines = st_guard.as_ref()
|
||||
.map(|st| st.active_tools.len() as u16).unwrap_or(0);
|
||||
let st_guard = app.agent.state.lock_blocking();
|
||||
let tool_lines = st_guard.active_tools.len() as u16;
|
||||
let main_chunks = Layout::default()
|
||||
.direction(Direction::Vertical)
|
||||
.constraints([
|
||||
|
|
@ -861,10 +854,9 @@ impl InteractScreen {
|
|||
frame.render_widget(gutter, input_chunks[0]);
|
||||
frame.render_widget(&self.textarea, input_chunks[1]);
|
||||
|
||||
if let Some(ref st) = st_guard {
|
||||
if !st.active_tools.is_empty() {
|
||||
if !st_guard.active_tools.is_empty() {
|
||||
let tool_style = Style::default().fg(Color::Yellow).add_modifier(Modifier::DIM);
|
||||
let tool_text: Vec<Line> = st.active_tools.iter().map(|t| {
|
||||
let tool_text: Vec<Line> = st_guard.active_tools.iter().map(|t| {
|
||||
let elapsed = t.started.elapsed().as_secs();
|
||||
let line = if t.detail.is_empty() {
|
||||
format!(" [{}] ({}s)", t.name, elapsed)
|
||||
|
|
@ -875,7 +867,7 @@ impl InteractScreen {
|
|||
}).collect();
|
||||
let tool_para = Paragraph::new(tool_text);
|
||||
frame.render_widget(tool_para, tools_overlay_area);
|
||||
}}
|
||||
}
|
||||
|
||||
// Draw status bar with live activity indicator
|
||||
let timer = if !app.activity.is_empty() {
|
||||
|
|
@ -1026,7 +1018,7 @@ impl ScreenView for InteractScreen {
|
|||
self.sync_from_agent();
|
||||
|
||||
// Read status from agent + mind state
|
||||
if let Ok(mut st) = self.agent.state.try_lock() {
|
||||
{ let mut st = self.agent.state.lock_blocking();
|
||||
st.expire_activities();
|
||||
app.status.prompt_tokens = st.last_prompt_tokens;
|
||||
app.status.model = self.agent.model().to_string();
|
||||
|
|
@ -1036,7 +1028,7 @@ impl ScreenView for InteractScreen {
|
|||
app.activity_started = st.activities.last()
|
||||
.map(|a| a.started);
|
||||
}
|
||||
if let Ok(ctx) = self.agent.context.try_lock() {
|
||||
{ let ctx = self.agent.context.lock_blocking();
|
||||
let window = crate::agent::context::context_window();
|
||||
if window > 0 {
|
||||
let sys = ctx.system().iter().map(|n| n.tokens()).sum::<usize>();
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue