fix: 3 项问题
1. 审批DB更新精确匹配 — code_hash 从 removed entry 提取 2. delete memo 提取 id — prompt 中数字 → id 参数 3. 清理未使用的 current_user_id 全局变量
This commit is contained in:
+1
-9
@@ -208,9 +208,6 @@ async fn cmd_listen(
|
|||||||
database.as_ref().map(|db| Arc::new(db.pool().clone()))
|
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 conversation = if enable_llm {
|
||||||
let sys_prompt = std::env::var("WEIXIN_LLM_SYSTEM_PROMPT")
|
let sys_prompt = std::env::var("WEIXIN_LLM_SYSTEM_PROMPT")
|
||||||
.unwrap_or_else(|_| DEFAULT_SYSTEM_PROMPT.to_string());
|
.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 executor: ToolExecutor = Arc::new(move |name: &str, args_json: &str| {
|
||||||
let reg = registry_opt.clone();
|
let reg = registry_opt.clone();
|
||||||
let approval = approval.clone();
|
let approval = approval.clone();
|
||||||
let send = send_wechat.clone();
|
let send = send_wechat.clone();
|
||||||
let session = session.clone();
|
let session = session.clone();
|
||||||
let memory_store = memory_store.clone();
|
let memory_store = memory_store.clone();
|
||||||
let current_user = executor_user_id.clone();
|
|
||||||
let n = name.to_string();
|
let n = name.to_string();
|
||||||
let args = args_json.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 shutdown = async { tokio::signal::ctrl_c().await.expect("Ctrl+C 失败") };
|
||||||
|
|
||||||
let listen_user_id = current_user_id.clone();
|
|
||||||
|
|
||||||
tokio::select! {
|
tokio::select! {
|
||||||
_ = shutdown => {
|
_ = shutdown => {
|
||||||
info!("收到退出信号,注销监听器...");
|
info!("收到退出信号,注销监听器...");
|
||||||
@@ -456,7 +449,7 @@ async fn cmd_listen(
|
|||||||
file_state.save_runtime(&client.get_updates_buf().await);
|
file_state.save_runtime(&client.get_updates_buf().await);
|
||||||
info!("已退出");
|
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,
|
file_state: &state::StateManager,
|
||||||
conversation: Option<Arc<Conversation>>,
|
conversation: Option<Arc<Conversation>>,
|
||||||
approval_manager: &ApprovalManager,
|
approval_manager: &ApprovalManager,
|
||||||
current_user_id: Arc<tokio::sync::Mutex<String>>,
|
|
||||||
memory_store: &Arc<MemoryStore>,
|
memory_store: &Arc<MemoryStore>,
|
||||||
) {
|
) {
|
||||||
let last_user_id = Arc::new(tokio::sync::Mutex::new(String::new()));
|
let last_user_id = Arc::new(tokio::sync::Mutex::new(String::new()));
|
||||||
|
|||||||
@@ -89,7 +89,7 @@ impl ApprovalManager {
|
|||||||
/// 处理用户回复(由消息循环调用)
|
/// 处理用户回复(由消息循环调用)
|
||||||
/// 匹配成功时返回 Some(技能名),匹配失败返回 None
|
/// 匹配成功时返回 Some(技能名),匹配失败返回 None
|
||||||
pub async fn handle_reply(&self, user_id: &str, reply: &str) -> Option<String> {
|
pub async fn handle_reply(&self, user_id: &str, reply: &str) -> Option<String> {
|
||||||
let (result, name) = {
|
let (result, name, code_hash) = {
|
||||||
let mut map = self.pending.lock().await;
|
let mut map = self.pending.lock().await;
|
||||||
let entries = map.get_mut(user_id)?;
|
let entries = map.get_mut(user_id)?;
|
||||||
if entries.is_empty() { return None; }
|
if entries.is_empty() { return None; }
|
||||||
@@ -99,19 +99,22 @@ impl ApprovalManager {
|
|||||||
|
|
||||||
if reply_trimmed == "0" || reply_trimmed == "取消" {
|
if reply_trimmed == "0" || reply_trimmed == "取消" {
|
||||||
let entry = entries.remove(0);
|
let entry = entries.remove(0);
|
||||||
|
let hash = entry.code_hash.clone();
|
||||||
let _ = entry.sender.send(ApprovalDecision::Rejected);
|
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) {
|
} else if let Some(idx) = entries.iter().position(|e| e.code_hash == reply_hash) {
|
||||||
let entry = entries.remove(idx);
|
let entry = entries.remove(idx);
|
||||||
|
let hash = entry.code_hash.clone();
|
||||||
let _ = entry.sender.send(ApprovalDecision::Approved);
|
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() {
|
} else if let Some(entry) = entries.first_mut() {
|
||||||
entry.attempts_left -= 1;
|
entry.attempts_left -= 1;
|
||||||
if entry.attempts_left <= 0 {
|
if entry.attempts_left <= 0 {
|
||||||
let entry = entries.remove(0);
|
let entry = entries.remove(0);
|
||||||
let n = entry.skill_name.clone();
|
let n = entry.skill_name.clone();
|
||||||
|
let hash = entry.code_hash.clone();
|
||||||
let _ = entry.sender.send(ApprovalDecision::Rejected);
|
let _ = entry.sender.send(ApprovalDecision::Rejected);
|
||||||
(ApprovalDecision::Rejected, n)
|
(ApprovalDecision::Rejected, n, hash)
|
||||||
} else {
|
} else {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
@@ -128,10 +131,10 @@ impl ApprovalManager {
|
|||||||
};
|
};
|
||||||
// 按 user_id + 最近 pending 记录更新
|
// 按 user_id + 最近 pending 记录更新
|
||||||
let _ = sqlx::query(
|
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(status)
|
||||||
.bind(user_id)
|
.bind(&code_hash)
|
||||||
.execute(pool.as_ref())
|
.execute(pool.as_ref())
|
||||||
.await;
|
.await;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -61,7 +61,8 @@ async fn handle_memos(args_json: &str) -> SkillResult {
|
|||||||
"list"
|
"list"
|
||||||
};
|
};
|
||||||
let content = params.get("prompt").and_then(|v| v.as_str()).unwrap_or("");
|
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::<String>().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 action = params.get("action").and_then(|v| v.as_str()).unwrap_or("list");
|
||||||
let path = ".data/memos.json";
|
let path = ".data/memos.json";
|
||||||
|
|||||||
Reference in New Issue
Block a user