fix: 审批死锁修复 — LLM 调用异步化

listen_loop 核心改动:
  新消息到达 → tokio::spawn(generate_reply) → 主循环立即继续
  LLM 调用 High 工具 → approval_flow 阻塞 spawn 的 task
  → 主循环不受影响 → receive_messages() 继续接收
  → 用户回复确认码 → handle_reply 触发 oneshot
  → spawned task 从 approval_flow 恢复 → LLM 生成最终回复

Conversation 用 Arc 包裹以支持跨 task 共享
send_text + 入库移到 spawned task 内部完成
This commit is contained in:
2026-06-01 18:07:03 +08:00
parent a6bb4dc1ec
commit a31afaba80
+27 -22
View File
@@ -335,7 +335,7 @@ async fn cmd_listen(
conv.set_tool_executor(executor);
Some(conv)
Some(Arc::new(conv))
} else {
None
};
@@ -387,7 +387,7 @@ async fn listen_loop(
account_id: &str,
database: &Option<Arc<Database>>,
file_state: &state::StateManager,
conversation: Option<Conversation>,
conversation: Option<Arc<Conversation>>,
approval_manager: Option<Arc<ApprovalManager>>,
current_user_id: Arc<tokio::sync::Mutex<String>>,
) {
@@ -465,32 +465,37 @@ async fn listen_loop(
// 更新当前用户(审批流程需要)
*current_user_id.lock().await = from.to_string();
// LLM 回复
// LLM 回复(异步执行,避免审批阻塞主循环)
if enable_llm {
if let Some(conv) = &conversation {
let reply_result = if conv.spec().tools.is_some() {
generate_reply_with_tools(conv, text.to_string(), database).await
} else {
generate_reply(conv, text.to_string(), database).await
};
let conv = conv.clone();
let client = client.clone();
let database = database.clone();
let from_owned = from.to_string();
let text_owned = text.to_string();
let ctx_owned = ctx_token.map(String::from);
let aid = account_id.to_string();
match reply_result {
Ok(reply) => {
match client.send_text(from, &reply, ctx_token).await {
Ok(sent_id) => {
info!("LLM 回复成功 msg_id={}", sent_id);
if let Some(db) = database {
let _ = db::models::insert_chat_record(
db.pool(), "outbound", from, account_id,
&reply, "llm", ctx_token, &sent_id,
).await;
}
tokio::spawn(async move {
let reply_result = if conv.spec().tools.is_some() {
generate_reply_with_tools(&conv, text_owned, &database).await
} else {
generate_reply(&conv, text_owned, &database).await
};
let reply = reply_result.ok().unwrap_or_default();
match client.send_text(&from_owned, &reply, ctx_owned.as_deref()).await {
Ok(sent_id) => {
info!("LLM 回复成功 msg_id={}", sent_id);
if let Some(db) = database {
let _ = db::models::insert_chat_record(
db.pool(), "outbound", &from_owned, &aid,
&reply, "llm", ctx_owned.as_deref(), &sent_id,
).await;
}
Err(e) => error!("发送 LLM 回复失败: {}", e),
}
Err(e) => error!("发送 LLM 回复失败: {}", e),
}
Err(e) => error!("生成 LLM 回复失败: {}", e),
}
});
}
}
}