agent: switch from tokio::sync::Mutex to std::sync::Mutex

The agent lock is never held across await points — turns lock briefly,
do work, drop, then do async API calls. std::sync::Mutex works and
can be locked from sync contexts (screen tick inside terminal.draw).

Fixes: blocking_lock() panic when called inside tokio runtime.

Co-Authored-By: Kent Overstreet <kent.overstreet@linux.dev>
This commit is contained in:
Kent Overstreet 2026-04-05 19:56:56 -04:00
parent f29b4be09c
commit 3e1be4d353
8 changed files with 41 additions and 39 deletions

View file

@ -29,7 +29,7 @@ fn default_timeout() -> u64 { 120 }
/// Async tool handler function.
/// Agent is None when called from contexts without an agent (MCP server, subconscious).
pub type ToolHandler = fn(
Option<std::sync::Arc<tokio::sync::Mutex<super::Agent>>>,
Option<std::sync::Arc<std::sync::Mutex<super::Agent>>>,
serde_json::Value,
) -> Pin<Box<dyn Future<Output = anyhow::Result<String>> + Send>>;
@ -94,11 +94,11 @@ pub async fn dispatch(
pub async fn dispatch_with_agent(
name: &str,
args: &serde_json::Value,
agent: Option<std::sync::Arc<tokio::sync::Mutex<super::Agent>>>,
agent: Option<std::sync::Arc<std::sync::Mutex<super::Agent>>>,
) -> String {
// Look up in agent's tools if available, otherwise global
let tool = if let Some(ref a) = agent {
let guard = a.lock().await;
let guard = a.lock().unwrap();
guard.tools.iter().find(|t| t.name == name).copied()
} else {
None