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:
parent
f29b4be09c
commit
3e1be4d353
8 changed files with 41 additions and 39 deletions
|
|
@ -232,14 +232,14 @@ impl Agent {
|
|||
/// Takes Arc<Mutex<Agent>> and manages locking internally so the
|
||||
/// lock is never held across I/O (API streaming, tool dispatch).
|
||||
pub async fn turn(
|
||||
agent: Arc<tokio::sync::Mutex<Agent>>,
|
||||
agent: Arc<std::sync::Mutex<Agent>>,
|
||||
user_input: &str,
|
||||
ui_tx: &UiSender,
|
||||
target: StreamTarget,
|
||||
) -> Result<TurnResult> {
|
||||
// --- Pre-loop setup (lock 1): agent cycle, memories, user input ---
|
||||
let active_tools = {
|
||||
let mut me = agent.lock().await;
|
||||
let mut me = agent.lock().unwrap();
|
||||
|
||||
let cycle = me.run_agent_cycle();
|
||||
for key in &cycle.surfaced_keys {
|
||||
|
|
@ -285,9 +285,10 @@ impl Agent {
|
|||
me.push_message(Message::user(user_input));
|
||||
let _ = ui_tx.send(UiMessage::AgentUpdate(me.agent_cycles.snapshots()));
|
||||
|
||||
me.active_tools.clone()
|
||||
let tools = me.active_tools.clone();
|
||||
drop(me);
|
||||
tools
|
||||
};
|
||||
// --- Lock released ---
|
||||
|
||||
let mut overflow_retries: u32 = 0;
|
||||
let mut empty_retries: u32 = 0;
|
||||
|
|
@ -298,7 +299,7 @@ impl Agent {
|
|||
|
||||
// --- Lock 2: assemble messages, start stream ---
|
||||
let (mut rx, _stream_guard) = {
|
||||
let me = agent.lock().await;
|
||||
let me = agent.lock().unwrap();
|
||||
let api_messages = me.assemble_api_messages();
|
||||
let sampling = api::SamplingParams {
|
||||
temperature: me.temperature,
|
||||
|
|
@ -328,7 +329,7 @@ impl Agent {
|
|||
|
||||
// --- Lock 3: process results ---
|
||||
{
|
||||
let mut me = agent.lock().await;
|
||||
let mut me = agent.lock().unwrap();
|
||||
|
||||
// Handle stream errors with retry logic
|
||||
if let Some(e) = stream_error {
|
||||
|
|
@ -433,7 +434,7 @@ impl Agent {
|
|||
}
|
||||
}
|
||||
// Reacquire to apply results
|
||||
let mut me = agent.lock().await;
|
||||
let mut me = agent.lock().unwrap();
|
||||
for (call, output) in results {
|
||||
me.apply_tool_result(&call, output, ui_tx, &mut ds);
|
||||
}
|
||||
|
|
@ -482,7 +483,7 @@ impl Agent {
|
|||
/// Dispatch a tool call without holding the agent lock across I/O.
|
||||
/// Used by `turn()` which manages its own locking.
|
||||
async fn dispatch_tool_call_unlocked(
|
||||
agent: &Arc<tokio::sync::Mutex<Agent>>,
|
||||
agent: &Arc<std::sync::Mutex<Agent>>,
|
||||
active_tools: &crate::user::ui_channel::SharedActiveTools,
|
||||
call: &ToolCall,
|
||||
ui_tx: &UiSender,
|
||||
|
|
@ -493,7 +494,7 @@ impl Agent {
|
|||
Err(e) => {
|
||||
let err = format!("Error: malformed tool call arguments: {e}");
|
||||
let _ = ui_tx.send(UiMessage::Activity(format!("rejected: {} (bad args)", call.function.name)));
|
||||
let mut me = agent.lock().await;
|
||||
let mut me = agent.lock().unwrap();
|
||||
me.apply_tool_result(call, err, ui_tx, ds);
|
||||
return;
|
||||
}
|
||||
|
|
@ -531,7 +532,7 @@ impl Agent {
|
|||
};
|
||||
if let Ok((call, output)) = entry.handle.await {
|
||||
// Brief lock to apply result
|
||||
let mut me = agent.lock().await;
|
||||
let mut me = agent.lock().unwrap();
|
||||
me.apply_tool_result(&call, output, ui_tx, ds);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue