diff --git a/src/main.rs b/src/main.rs index 74615c4..304ca5e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -208,9 +208,6 @@ async fn cmd_listen( database.as_ref().map(|db| 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()); @@ -326,14 +323,12 @@ 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(); @@ -447,8 +442,6 @@ 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!("收到退出信号,注销监听器..."); @@ -456,7 +449,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_user_id, memory_store) => {} + _ = listen_loop(&client, enable_llm, echo, &account_id, database, file_state, conversation, &approval_manager, memory_store) => {} } } @@ -469,7 +462,6 @@ async fn listen_loop( file_state: &state::StateManager, conversation: Option>, approval_manager: &ApprovalManager, - current_user_id: Arc>, memory_store: &Arc, ) { let last_user_id = Arc::new(tokio::sync::Mutex::new(String::new())); diff --git a/src/tools/approval.rs b/src/tools/approval.rs index db218e6..1eaba85 100644 --- a/src/tools/approval.rs +++ b/src/tools/approval.rs @@ -89,7 +89,7 @@ impl ApprovalManager { /// 处理用户回复(由消息循环调用) /// 匹配成功时返回 Some(技能名),匹配失败返回 None pub async fn handle_reply(&self, user_id: &str, reply: &str) -> Option { - let (result, name) = { + let (result, name, code_hash) = { let mut map = self.pending.lock().await; let entries = map.get_mut(user_id)?; if entries.is_empty() { return None; } @@ -99,19 +99,22 @@ impl ApprovalManager { if reply_trimmed == "0" || reply_trimmed == "取消" { let entry = entries.remove(0); + let hash = entry.code_hash.clone(); let _ = entry.sender.send(ApprovalDecision::Rejected); - (ApprovalDecision::Rejected, entry.skill_name.clone()) + (ApprovalDecision::Rejected, entry.skill_name.clone(), hash) } else if let Some(idx) = entries.iter().position(|e| e.code_hash == reply_hash) { let entry = entries.remove(idx); + let hash = entry.code_hash.clone(); let _ = entry.sender.send(ApprovalDecision::Approved); - (ApprovalDecision::Approved, entry.skill_name.clone()) + (ApprovalDecision::Approved, entry.skill_name.clone(), hash) } else if let Some(entry) = entries.first_mut() { entry.attempts_left -= 1; if entry.attempts_left <= 0 { let entry = entries.remove(0); let n = entry.skill_name.clone(); + let hash = entry.code_hash.clone(); let _ = entry.sender.send(ApprovalDecision::Rejected); - (ApprovalDecision::Rejected, n) + (ApprovalDecision::Rejected, n, hash) } else { return None; } @@ -128,10 +131,10 @@ impl ApprovalManager { }; // 按 user_id + 最近 pending 记录更新 let _ = sqlx::query( - "UPDATE pending_approvals SET status = $1, consumed_at = NOW() WHERE id = (SELECT id FROM pending_approvals WHERE user_id = $2 AND status = 'pending' ORDER BY created_at DESC LIMIT 1)", + "UPDATE pending_approvals SET status = $1, consumed_at = NOW() WHERE code_hash = $2 AND status = 'pending'", ) .bind(status) - .bind(user_id) + .bind(&code_hash) .execute(pool.as_ref()) .await; } diff --git a/src/tools/builtin.rs b/src/tools/builtin.rs index da31c24..6b97945 100644 --- a/src/tools/builtin.rs +++ b/src/tools/builtin.rs @@ -61,7 +61,8 @@ async fn handle_memos(args_json: &str) -> SkillResult { "list" }; let content = params.get("prompt").and_then(|v| v.as_str()).unwrap_or(""); - params = serde_json::json!({"action": action, "content": content}); + let memo_id: i32 = content.chars().filter(|c| c.is_ascii_digit()).collect::().parse().unwrap_or(0); + params = serde_json::json!({"action": action, "content": content, "id": memo_id}); } let action = params.get("action").and_then(|v| v.as_str()).unwrap_or("list"); let path = ".data/memos.json";