fix: 审批流程 user_id 动态绑定 + email 降为 Low 风险

- current_user_id 从 'wechat_user' 改为动态共享变量
- listen_loop 中每条消息更新 current_user_id
- 修复 Rust 2024 edition 的 ref/move 问题
- email 读操作降为 Low(无副作用,避免审批死锁)
- 审批死锁根因:approval_flow 阻塞 listen_loop,
  receive_messages 无法被再次调用
  后续需重构为异步审批模式(工具返回 pending,listen_loop 驱动确认)
This commit is contained in:
2026-06-01 17:56:52 +08:00
parent 00002e4740
commit a6bb4dc1ec
2 changed files with 19 additions and 7 deletions
+1 -1
View File
@@ -3,7 +3,7 @@
收发邮件(IMAP)。
## Risk Level
High
Low
## Parameters
```json
+18 -6
View File
@@ -194,6 +194,9 @@ async fn cmd_listen(
Arc::new(ApprovalManager::new(Some(Arc::new(db.pool().clone()))))
});
// 共享的当前用户 ID(用于审批消息)
let current_user_id = Arc::new(tokio::sync::Mutex::new(String::new()));
let conversation = if enable_llm {
let sys_prompt = std::env::var("WEIXIN_LLM_SYSTEM_PROMPT")
.unwrap_or_else(|_| DEFAULT_SYSTEM_PROMPT.to_string());
@@ -293,12 +296,14 @@ async fn cmd_listen(
})
};
let executor_user_id = current_user_id.clone();
let executor: ToolExecutor = Arc::new(move |name: &str, args_json: &str| {
let reg = registry_opt.clone();
let approval = approval.clone();
let send = send_wechat.clone();
let session = session.clone();
let memory_store = memory_store.clone();
let current_user = executor_user_id.clone();
let n = name.to_string();
let args = args_json.to_string();
@@ -314,9 +319,10 @@ async fn cmd_listen(
"read_summaries" => return Ok(context::tools::read_summaries(&session).await),
_ => {}
}
let user_id = current_user.lock().await.clone();
if let Some(ref reg) = reg {
let params: serde_json::Value = serde_json::from_str(&args).unwrap_or(serde_json::json!({}));
let mut ctx = ExecutionContext::new("wechat_user");
let mut ctx = ExecutionContext::new(&user_id);
if let Some(a) = approval { ctx = ctx.with_approval(a); }
ctx = ctx.with_wechat(send);
let result = reg.execute(&n, params, &ctx).await;
@@ -361,6 +367,8 @@ async fn cmd_listen(
let shutdown = async { tokio::signal::ctrl_c().await.expect("Ctrl+C 失败") };
let listen_user_id = current_user_id.clone();
tokio::select! {
_ = shutdown => {
info!("收到退出信号,注销监听器...");
@@ -368,7 +376,7 @@ async fn cmd_listen(
file_state.save_runtime(&client.get_updates_buf().await);
info!("已退出");
}
_ = listen_loop(&client, enable_llm, echo, &account_id, database, file_state, conversation, approval_manager) => {}
_ = listen_loop(&client, enable_llm, echo, &account_id, database, file_state, conversation, approval_manager, listen_user_id) => {}
}
}
@@ -381,6 +389,7 @@ async fn listen_loop(
file_state: &state::StateManager,
conversation: Option<Conversation>,
approval_manager: Option<Arc<ApprovalManager>>,
current_user_id: Arc<tokio::sync::Mutex<String>>,
) {
loop {
match client.receive_messages().await {
@@ -441,21 +450,24 @@ async fn listen_loop(
}
}
// 审批回复检查:是否匹配待审批的确认码
let is_approval_reply = if let Some(ref mgr) = approval_manager {
// 审批回复检查
let is_approval_reply = if let Some(mgr) = &approval_manager {
mgr.handle_reply(from, text).await.is_some()
} else {
false
};
if is_approval_reply {
info!("消息匹配审批确认码,不传给 LLM(已由审批系统处理)");
info!("消息匹配审批确认码,不传给 LLM");
continue;
}
// 更新当前用户(审批流程需要)
*current_user_id.lock().await = from.to_string();
// LLM 回复
if enable_llm {
if let Some(ref conv) = conversation {
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 {