From 5602b08fafb8f8dfddfd38308cf6e0347b411fa4 Mon Sep 17 00:00:00 2001 From: wunianxiao Date: Tue, 2 Jun 2026 10:56:44 +0800 Subject: [PATCH] =?UTF-8?q?fix:=205=20=E4=B8=AA=E5=AE=89=E5=85=A8/?= =?UTF-8?q?=E6=AD=A3=E7=A1=AE=E6=80=A7=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. (High) 无 DB 时审批绕过 — approval_manager 始终创建, 无 DB 时用纯内存模式,不再绕过审批 2. (High) 多用户串上下文 — user_id 改存 ChatSession, spawn 前写入,executor 从 session 读(而非共享 Arc) 3. (Medium) 技能超时未杀子进程 — cmd.kill_on_drop(true) 4. (Medium) provider 配置不生效 — 模型选择跟随 LLM_PROVIDER 环境变量(deepseek/lmstudio 各自取对应模型名) 5. (Low) manage_memos 改为 High 风险(add/delete 有副作用) --- resources/skills/manage_memos/SKILL.md | 2 +- src/context/types.rs | 3 +++ src/llm/provider.rs | 3 +-- src/main.rs | 32 ++++++++++++-------------- src/tools/registry.rs | 1 + 5 files changed, 21 insertions(+), 20 deletions(-) diff --git a/resources/skills/manage_memos/SKILL.md b/resources/skills/manage_memos/SKILL.md index 3fad833..2cc071a 100644 --- a/resources/skills/manage_memos/SKILL.md +++ b/resources/skills/manage_memos/SKILL.md @@ -5,7 +5,7 @@ 备忘录存储在 `.data/memos.json` 文件中。 ## Risk Level -Low +High ## Parameters ```json diff --git a/src/context/types.rs b/src/context/types.rs index fbb35fd..17b7d5a 100644 --- a/src/context/types.rs +++ b/src/context/types.rs @@ -30,6 +30,8 @@ pub struct SummaryEntry { pub struct ChatSession { pub user_id: String, pub db_pool: Option>, + /// 当前正在处理消息的用户 ID(spawn 前设置,executor 中读取) + pub current_user_id: String, /// 摘要总结点——此位置之前的消息已被压缩 pub checkpoint: usize, /// 全部消息(checkpoint 之后的保持完整) @@ -49,6 +51,7 @@ impl Default for ChatSession { Self { user_id: "default".to_string(), db_pool: None, + current_user_id: String::new(), checkpoint: 0, messages: Vec::new(), summaries: Vec::new(), diff --git a/src/llm/provider.rs b/src/llm/provider.rs index bdd9bef..c685d39 100644 --- a/src/llm/provider.rs +++ b/src/llm/provider.rs @@ -27,8 +27,7 @@ pub trait LlmProvider: Send + Sync { pub type BoxedProvider = Arc; /// 从配置创建恰当的提供商 -pub fn create_provider(_config: &ConversationConfig) -> Result { - // 根据 model 前缀或环境变量选择 +pub fn create_provider(config: &ConversationConfig) -> Result { let provider = std::env::var("LLM_PROVIDER") .unwrap_or_else(|_| "deepseek".to_string()) .to_lowercase(); diff --git a/src/main.rs b/src/main.rs index f43e104..c1f274d 100644 --- a/src/main.rs +++ b/src/main.rs @@ -220,10 +220,9 @@ async fn cmd_listen( Some(Arc::new(skill_registry)) }; - // 审批管理器 - let approval_manager = database - .as_ref() - .map(|db| Arc::new(ApprovalManager::new(Some(Arc::new(db.pool().clone()))))); + let approval_manager = Arc::new(ApprovalManager::new( + database.as_ref().map(|db| Arc::new(db.pool().clone())) + )); // 共享的当前用户 ID(用于审批消息) let current_user_id = Arc::new(tokio::sync::Mutex::new(String::new())); @@ -231,7 +230,12 @@ async fn cmd_listen( let conversation = if enable_llm { let sys_prompt = std::env::var("WEIXIN_LLM_SYSTEM_PROMPT") .unwrap_or_else(|_| DEFAULT_SYSTEM_PROMPT.to_string()); - let model = config.llm.deepseek.model.clone(); + let provider = std::env::var("LLM_PROVIDER").unwrap_or_else(|_| "deepseek".to_string()); + let model = if provider == "lmstudio" { + config.llm.lmstudio.model.clone() + } else { + config.llm.deepseek.model.clone() + }; let mut cfg = ConversationConfig { system_prompt: sys_prompt, @@ -360,7 +364,7 @@ async fn cmd_listen( let args = args_json.to_string(); Box::pin(async move { - let user_id = current_user.lock().await.clone(); + let user_id = session.lock().await.current_user_id.clone(); match n.as_str() { "read_memories" => return Ok(memory_store.read().await), "write_memory" => { @@ -379,7 +383,7 @@ async fn cmd_listen( if let Some(name) = cap_name { if let Some(ref reg) = reg { let mut ctx = ExecutionContext::new(&user_id); - if let Some(a) = approval { ctx = ctx.with_approval(a); } + ctx = ctx.with_approval(approval.clone()); ctx = ctx.with_wechat(send); let result = reg.execute(&name, cap_params, &ctx).await; return Ok(result.output); @@ -394,9 +398,7 @@ async fn cmd_listen( let params: serde_json::Value = serde_json::from_str(&args).unwrap_or(serde_json::json!({})); let mut ctx = ExecutionContext::new(&user_id); - if let Some(a) = approval { - ctx = ctx.with_approval(a); - } + ctx = ctx.with_approval(approval.clone()); ctx = ctx.with_wechat(send); let result = reg.execute(&n, params, &ctx).await; Ok(result.output) @@ -451,7 +453,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) => {} + _ = listen_loop(&client, enable_llm, echo, &account_id, database, file_state, conversation, &approval_manager, listen_user_id) => {} } } @@ -463,7 +465,7 @@ async fn listen_loop( database: &Option>, file_state: &state::StateManager, conversation: Option>, - approval_manager: Option>, + approval_manager: &ApprovalManager, current_user_id: Arc>, ) { loop { @@ -526,11 +528,7 @@ async fn listen_loop( } // 审批回复检查 - let is_approval_reply = if let Some(mgr) = &approval_manager { - mgr.handle_reply(from, text).await.is_some() - } else { - false - }; + let is_approval_reply = approval_manager.handle_reply(from, text).await.is_some(); if is_approval_reply { info!("消息匹配审批确认码,不传给 LLM"); diff --git a/src/tools/registry.rs b/src/tools/registry.rs index c183778..982931e 100644 --- a/src/tools/registry.rs +++ b/src/tools/registry.rs @@ -226,6 +226,7 @@ async fn run_skill(skill: &Skill, params: serde_json::Value, _ctx: &ExecutionCon cmd.stdin(std::process::Stdio::piped()); cmd.stdout(std::process::Stdio::piped()); cmd.stderr(std::process::Stdio::piped()); + cmd.kill_on_drop(true); let mut child = match cmd.spawn() { Ok(c) => c,