fix: 4 项问题
1. (High) SQL 语法错误 — UPDATE ... ORDER BY ... LIMIT 1 → CTE 子查询 2. (High) 用户串扰 — 暂保持单用户序列,多用户场景后续重构 3. (Medium) 用户记忆 — 切换时 memory_store.load(from) 4. (Medium) call_capability prompt — 完整参数透传到目标工具
This commit is contained in:
+12
-8
@@ -365,13 +365,14 @@ async fn cmd_listen(
|
|||||||
return Ok(build_capability_list(&spec_list));
|
return Ok(build_capability_list(&spec_list));
|
||||||
}
|
}
|
||||||
|
|
||||||
// 确定目标工具名(call_capability 需要提取 name 参数)
|
// 确定目标工具名和参数(call_capability 提取 name + 透传完整参数)
|
||||||
let target_name = if n == "call_capability" {
|
let (target_name, target_args) = if n == "call_capability" {
|
||||||
let cp: serde_json::Value = serde_json::from_str(&args).unwrap_or_default();
|
let cp: serde_json::Value = serde_json::from_str(&args).unwrap_or_default();
|
||||||
cp.get("name").and_then(|v| v.as_str()).map(|s| s.to_string()).unwrap_or_default()
|
let name = cp.get("name").and_then(|v| v.as_str()).map(|s| s.to_string()).unwrap_or_default();
|
||||||
} else { n.clone() };
|
(name, serde_json::to_string(&cp).unwrap_or_default())
|
||||||
|
} else { (n.clone(), args.clone()) };
|
||||||
|
|
||||||
// 内置工具(高风险先审批再执行)
|
// 内置工具
|
||||||
if tools::builtin::BuiltinRegistry::is_builtin(&target_name) {
|
if tools::builtin::BuiltinRegistry::is_builtin(&target_name) {
|
||||||
if tools::builtin::BuiltinRegistry::is_high_risk(&target_name) {
|
if tools::builtin::BuiltinRegistry::is_high_risk(&target_name) {
|
||||||
let mut ctx = ExecutionContext::new(&user_id);
|
let mut ctx = ExecutionContext::new(&user_id);
|
||||||
@@ -384,14 +385,14 @@ async fn cmd_listen(
|
|||||||
Err(e) => return Ok(e),
|
Err(e) => return Ok(e),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if let Some(result) = tools::builtin::BuiltinRegistry::execute(&target_name, &args).await {
|
if let Some(result) = tools::builtin::BuiltinRegistry::execute(&target_name, &target_args).await {
|
||||||
return Ok(result.output);
|
return Ok(result.output);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 回退到外部 SkillRegistry
|
// 回退到外部 SkillRegistry
|
||||||
if let Some(ref r) = reg {
|
if let Some(ref r) = reg {
|
||||||
let params: serde_json::Value = serde_json::from_str(&args).unwrap_or(serde_json::json!({}));
|
let params: serde_json::Value = serde_json::from_str(&target_args).unwrap_or(serde_json::json!({}));
|
||||||
let mut ctx = ExecutionContext::new(&user_id);
|
let mut ctx = ExecutionContext::new(&user_id);
|
||||||
ctx = ctx.with_approval(approval.clone());
|
ctx = ctx.with_approval(approval.clone());
|
||||||
ctx = ctx.with_wechat(send);
|
ctx = ctx.with_wechat(send);
|
||||||
@@ -455,7 +456,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) => {}
|
_ = listen_loop(&client, enable_llm, echo, &account_id, database, file_state, conversation, &approval_manager, listen_user_id, memory_store) => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -469,6 +470,7 @@ async fn listen_loop(
|
|||||||
conversation: Option<Arc<Conversation>>,
|
conversation: Option<Arc<Conversation>>,
|
||||||
approval_manager: &ApprovalManager,
|
approval_manager: &ApprovalManager,
|
||||||
current_user_id: Arc<tokio::sync::Mutex<String>>,
|
current_user_id: Arc<tokio::sync::Mutex<String>>,
|
||||||
|
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()));
|
||||||
loop {
|
loop {
|
||||||
@@ -553,6 +555,8 @@ async fn listen_loop(
|
|||||||
s.current_user_id = from.to_string();
|
s.current_user_id = from.to_string();
|
||||||
// 加载该用户最近 20 条历史
|
// 加载该用户最近 20 条历史
|
||||||
s.load_recent_messages(20).await;
|
s.load_recent_messages(20).await;
|
||||||
|
drop(s);
|
||||||
|
memory_store.load(from).await;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
*last_user = from.to_string();
|
*last_user = from.to_string();
|
||||||
|
|||||||
@@ -128,7 +128,7 @@ impl ApprovalManager {
|
|||||||
};
|
};
|
||||||
// 按 user_id + 最近 pending 记录更新
|
// 按 user_id + 最近 pending 记录更新
|
||||||
let _ = sqlx::query(
|
let _ = sqlx::query(
|
||||||
"UPDATE pending_approvals SET status = $1, consumed_at = NOW() WHERE user_id = $2 AND status = 'pending' ORDER BY created_at DESC LIMIT 1",
|
"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)",
|
||||||
)
|
)
|
||||||
.bind(status)
|
.bind(status)
|
||||||
.bind(user_id)
|
.bind(user_id)
|
||||||
|
|||||||
+15
-1
@@ -48,7 +48,21 @@ fn execute_datetime() -> SkillResult {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async fn handle_memos(args_json: &str) -> SkillResult {
|
async fn handle_memos(args_json: &str) -> SkillResult {
|
||||||
let params: serde_json::Value = serde_json::from_str(args_json).unwrap_or_default();
|
let mut params: serde_json::Value = serde_json::from_str(args_json).unwrap_or_default();
|
||||||
|
// call_capability 透传完整参数,action/content 在顶层
|
||||||
|
// 如果顶层没有 action,尝试从 prompt 推断
|
||||||
|
if params.get("action").is_none() {
|
||||||
|
let prompt = params.get("prompt").and_then(|v| v.as_str()).unwrap_or("");
|
||||||
|
let action = if prompt.contains("添加") || prompt.contains("新增") || prompt.contains("add") {
|
||||||
|
"add"
|
||||||
|
} else if prompt.contains("删除") || prompt.contains("移除") || prompt.contains("delete") {
|
||||||
|
"delete"
|
||||||
|
} else {
|
||||||
|
"list"
|
||||||
|
};
|
||||||
|
let content = params.get("prompt").and_then(|v| v.as_str()).unwrap_or("");
|
||||||
|
params = serde_json::json!({"action": action, "content": content});
|
||||||
|
}
|
||||||
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";
|
||||||
if let Err(e) = std::fs::create_dir_all(".data") { return SkillResult::error(format!("创建目录失败: {}", e)); }
|
if let Err(e) = std::fs::create_dir_all(".data") { return SkillResult::error(format!("创建目录失败: {}", e)); }
|
||||||
|
|||||||
Reference in New Issue
Block a user