清理废弃代码,重构长期记忆系统
核心变更: - 删除 worker.rs + ipc.rs(废弃进程架构) - 删除 ias listen 路径(cmd_listen / listen_loop / ToolExecutor) - 合并 ias service → ias daemon --log-file - 修复 main.rs call_capability 不处理上下文工具的 bug MemoryStore 重构: - write_for 空内容防御 + 精确去重 - 缓存结构 Vec<String> → Vec<(i32, String)>(用数据库 id 标识) - 新增 delete_for / update_for 方法 + LLM 工具定义 - load_if_needed 避免每次消息查 DB - 缓存 TTL(1h) + 每用户 200 条上限 - read_for limit 参数(默认 30 条) daemon.rs: - execute_tool 统一为递归派发,消除 call_capability 重复路由 净减少约 1400 行代码,0 warning,20 测试通过
This commit is contained in:
+98
-88
@@ -34,15 +34,14 @@
|
||||
//! - **Tool Consumer** — 执行内置工具,高风险工具先走审批
|
||||
//! - **Send Consumer** — 将 LLM 回复通过 WeChat API 发回给用户
|
||||
//!
|
||||
//! ### 与旧架构的关系
|
||||
//! ### 架构
|
||||
//!
|
||||
//! 旧架构使用 `daemon + worker` 分离模式(UDS IPC),worker 已废弃。
|
||||
//! 当前是统一的单进程 tokio task 架构。
|
||||
//! 采用统一的单进程 tokio task 架构。旧版 daemon+worker 分离模式(UDS IPC)已在 v2 中移除。
|
||||
|
||||
use crate::channel::ChannelId;
|
||||
use crate::context::MemoryStore;
|
||||
use crate::db::Database;
|
||||
use crate::ipc::HistoryEntry;
|
||||
use crate::context::HistoryEntry;
|
||||
use crate::llm::{ChatResult, Conversation, ConversationConfig, ToolExecutor, DEFAULT_SYSTEM_PROMPT, ASYNC_MARKER};
|
||||
use crate::queue::{ConsumerChannels, EnqueueHandle, MessageKind, PipelineMessage, QueueRunner};
|
||||
use crate::state::StateManager;
|
||||
@@ -100,7 +99,7 @@ pub async fn run(
|
||||
if let Some(r) = file_state.load_runtime() { client.set_updates_buf(&r.get_updates_buf).await; }
|
||||
if let Err(e) = client.notify_start().await { error!("注册监听器失败: {}", e); return; }
|
||||
let account_id = auth.account_id.clone();
|
||||
info!("Daemon 已启动 (无 worker 进程模式)");
|
||||
info!("Daemon 已启动");
|
||||
|
||||
// 4-6. 审批管理器、工具列表、模型配置
|
||||
let approval_manager = Arc::new(ApprovalManager::new(
|
||||
@@ -315,7 +314,7 @@ async fn llm_consumer_loop(
|
||||
info!("LLM Consumer: user={} text={:.60}", user_id, text);
|
||||
|
||||
// 加载数据
|
||||
ctx.memory_store.load(&user_id).await;
|
||||
ctx.memory_store.load_if_needed(&user_id).await;
|
||||
let history = load_history(&ctx.db, &user_id).await;
|
||||
|
||||
let sys_prompt = if ctx.system_prompt.is_empty() {
|
||||
@@ -595,86 +594,77 @@ async fn tool_consumer_loop(
|
||||
// ─── 统一工具执行 ───
|
||||
|
||||
/// 所有工具的统一执行入口 — 仅此一处
|
||||
async fn execute_tool(name: &str, arguments: &str, ctx: &DaemonCtx, user_id: &str) -> String {
|
||||
// 上下文工具
|
||||
match name {
|
||||
"read_memories" => {
|
||||
let mems = load_memories(&ctx.memory_store, user_id).await;
|
||||
if mems.is_empty() { return "暂无长期记忆".to_string(); }
|
||||
let lines: Vec<String> = mems.iter().enumerate()
|
||||
.map(|(i, v)| format!("{}. {}", i + 1, v)).collect();
|
||||
return lines.join("\n");
|
||||
}
|
||||
"write_memory" => {
|
||||
let params: serde_json::Value = serde_json::from_str(arguments).unwrap_or_default();
|
||||
let content = params.get("content").and_then(|v| v.as_str()).unwrap_or("");
|
||||
if content.is_empty() { return "请提供 content 参数".to_string(); }
|
||||
ctx.memory_store.write_for(user_id, content).await;
|
||||
return format!("已添加长期记忆: {}", content);
|
||||
}
|
||||
"read_summaries" => {
|
||||
let sums = load_summaries(&ctx.db, user_id).await;
|
||||
if sums.is_empty() { return "暂无历史摘要".to_string(); }
|
||||
return sums.iter().enumerate()
|
||||
.map(|(i, s)| format!("{}. {}", i + 1, s))
|
||||
.collect::<Vec<_>>().join("\n---\n");
|
||||
}
|
||||
"query_capabilities" => {
|
||||
let specs = crate::tools::specs();
|
||||
return crate::tools::build_capability_guide(&specs);
|
||||
}
|
||||
"call_capability" => {
|
||||
// 解包 {name, prompt} → 提取目标工具名和参数,直接派发
|
||||
let cp: serde_json::Value = serde_json::from_str(arguments).unwrap_or_default();
|
||||
let target_name = cp.get("name").and_then(|v| v.as_str()).unwrap_or("").to_string();
|
||||
if target_name.is_empty() {
|
||||
return "请提供 name 参数".to_string();
|
||||
///
|
||||
/// `call_capability` 通过递归派发到此函数,需 boxing 避免无限大小。
|
||||
fn execute_tool<'a>(
|
||||
name: &'a str,
|
||||
arguments: &'a str,
|
||||
ctx: &'a DaemonCtx,
|
||||
user_id: &'a str,
|
||||
) -> std::pin::Pin<std::boxed::Box<dyn std::future::Future<Output = String> + Send + 'a>> {
|
||||
Box::pin(async move {
|
||||
// 上下文工具
|
||||
match name {
|
||||
"read_memories" => {
|
||||
return ctx.memory_store.read_for(user_id, None).await;
|
||||
}
|
||||
let target_args = serde_json::to_string(&crate::tools::unpack_call_params(&cp))
|
||||
.unwrap_or_default();
|
||||
// 重新派发到 execute_tool(通过顶层 match 分支避免 async 递归)
|
||||
// 上下文工具
|
||||
match target_name.as_str() {
|
||||
"read_memories" => {
|
||||
let mems = load_memories(&ctx.memory_store, user_id).await;
|
||||
if mems.is_empty() { return "暂无长期记忆".to_string(); }
|
||||
return mems.iter().enumerate()
|
||||
.map(|(i, v)| format!("{}. {}", i + 1, v)).collect::<Vec<_>>().join("\n");
|
||||
}
|
||||
"write_memory" => {
|
||||
let params: serde_json::Value = serde_json::from_str(&target_args).unwrap_or_default();
|
||||
let content = params.get("content").and_then(|v| v.as_str()).unwrap_or("");
|
||||
if content.is_empty() { return "请提供 content 参数".to_string(); }
|
||||
ctx.memory_store.write_for(user_id, content).await;
|
||||
return format!("已添加长期记忆: {}", content);
|
||||
}
|
||||
"read_summaries" => {
|
||||
let sums = load_summaries(&ctx.db, user_id).await;
|
||||
if sums.is_empty() { return "暂无历史摘要".to_string(); }
|
||||
return sums.iter().enumerate()
|
||||
.map(|(i, s)| format!("{}. {}", i + 1, s))
|
||||
.collect::<Vec<_>>().join("\n---\n");
|
||||
}
|
||||
"query_capabilities" => {
|
||||
let specs = crate::tools::specs();
|
||||
return crate::tools::build_capability_guide(&specs);
|
||||
}
|
||||
_ => {}
|
||||
"write_memory" => {
|
||||
let params: serde_json::Value = serde_json::from_str(arguments).unwrap_or_default();
|
||||
let content = params.get("content").and_then(|v| v.as_str()).unwrap_or("");
|
||||
if content.is_empty() { return "请提供 content 参数".to_string(); }
|
||||
ctx.memory_store.write_for(user_id, content).await;
|
||||
return format!("已添加长期记忆: {}", content);
|
||||
}
|
||||
// 内置工具注册表
|
||||
match crate::tools::execute(&target_name, &target_args).await {
|
||||
Some(r) => return r.output,
|
||||
None => return format!("未知工具: {}", target_name),
|
||||
"delete_memory" => {
|
||||
let params: serde_json::Value = serde_json::from_str(arguments).unwrap_or_default();
|
||||
let memory_id = params.get("memory_id").and_then(|v| v.as_i64()).unwrap_or(-1) as i32;
|
||||
if memory_id <= 0 { return "请提供有效的 memory_id 参数".to_string(); }
|
||||
return ctx.memory_store.delete_for(user_id, memory_id).await;
|
||||
}
|
||||
"update_memory" => {
|
||||
let params: serde_json::Value = serde_json::from_str(arguments).unwrap_or_default();
|
||||
let memory_id = params.get("memory_id").and_then(|v| v.as_i64()).unwrap_or(-1) as i32;
|
||||
let content = params.get("content").and_then(|v| v.as_str()).unwrap_or("");
|
||||
if memory_id <= 0 { return "请提供有效的 memory_id 参数".to_string(); }
|
||||
if content.is_empty() { return "请提供 content 参数".to_string(); }
|
||||
return ctx.memory_store.update_for(user_id, memory_id, content).await;
|
||||
}
|
||||
"read_summaries" => {
|
||||
let sums = load_summaries(&ctx.db, user_id).await;
|
||||
if sums.is_empty() { return "暂无历史摘要".to_string(); }
|
||||
return sums.iter().enumerate()
|
||||
.map(|(i, s)| format!("{}. {}", i + 1, s))
|
||||
.collect::<Vec<_>>().join("\n---\n");
|
||||
}
|
||||
"query_capabilities" => {
|
||||
let specs = crate::tools::specs();
|
||||
return crate::tools::build_capability_guide(&specs);
|
||||
}
|
||||
"call_capability" => {
|
||||
// 解包 {name, prompt} → 提取目标工具名和参数,递归派发
|
||||
let cp: serde_json::Value = serde_json::from_str(arguments).unwrap_or_default();
|
||||
let target_name = cp.get("name").and_then(|v| v.as_str()).unwrap_or("").to_string();
|
||||
if target_name.is_empty() {
|
||||
return "请提供 name 参数".to_string();
|
||||
}
|
||||
// 防止嵌套 call_capability
|
||||
if target_name == "call_capability" {
|
||||
return "不支持嵌套调用 call_capability".to_string();
|
||||
}
|
||||
let target_args = serde_json::to_string(&crate::tools::unpack_call_params(&cp))
|
||||
.unwrap_or_default();
|
||||
// 递归派发
|
||||
return execute_tool(&target_name, &target_args, ctx, user_id).await;
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
// 内置工具注册表
|
||||
match crate::tools::execute(name, arguments).await {
|
||||
Some(r) => r.output,
|
||||
None => format!("未知工具: {}", name),
|
||||
}
|
||||
// 内置工具注册表
|
||||
match crate::tools::execute(name, arguments).await {
|
||||
Some(r) => r.output,
|
||||
None => format!("未知工具: {}", name),
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// ─── Send Consumer ───
|
||||
@@ -738,13 +728,6 @@ async fn load_history(db: &Option<Arc<Database>>, user_id: &str) -> Vec<HistoryE
|
||||
}
|
||||
}
|
||||
|
||||
async fn load_memories(memory_store: &MemoryStore, user_id: &str) -> Vec<String> {
|
||||
let text = memory_store.read_for(user_id).await;
|
||||
// read_for() 返回 "暂无长期记忆" 表示无记忆,否则返回 "1. ...\n2. ..." 格式
|
||||
if text.starts_with("暂无") { vec![] }
|
||||
else { text.lines().map(|l| l.trim().to_string()).filter(|l| !l.is_empty()).collect() }
|
||||
}
|
||||
|
||||
async fn load_summaries(db: &Option<Arc<Database>>, user_id: &str) -> Vec<String> {
|
||||
let Some(db) = db else { return vec![]; };
|
||||
match crate::db::models::load_summaries(db.pool(), user_id, 5).await {
|
||||
@@ -794,6 +777,33 @@ fn build_tools_list() -> Vec<serde_json::Value> {
|
||||
"parameters": { "type": "object", "properties": {} }
|
||||
}
|
||||
}));
|
||||
list.push(serde_json::json!({
|
||||
"type": "function", "function": {
|
||||
"name": "delete_memory",
|
||||
"description": "删除指定 id 的长期记忆。id 来自 read_memories 返回的 [id] 前缀。",
|
||||
"parameters": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"memory_id": { "type": "integer", "description": "要删除的记忆 id" }
|
||||
},
|
||||
"required": ["memory_id"]
|
||||
}
|
||||
}
|
||||
}));
|
||||
list.push(serde_json::json!({
|
||||
"type": "function", "function": {
|
||||
"name": "update_memory",
|
||||
"description": "更新指定 id 的长期记忆内容。id 来自 read_memories 返回的 [id] 前缀。",
|
||||
"parameters": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"memory_id": { "type": "integer", "description": "要更新的记忆 id" },
|
||||
"content": { "type": "string", "description": "新的记忆内容" }
|
||||
},
|
||||
"required": ["memory_id", "content"]
|
||||
}
|
||||
}
|
||||
}));
|
||||
|
||||
let specs = crate::tools::specs();
|
||||
for spec in &specs {
|
||||
|
||||
Reference in New Issue
Block a user