refactor: 删除 config.json + 内置工具抽离 + 统一接口

删除:
  - config.rs / config.json(AppConfig/LmStudioConfig)
  - LM Studio 残留(lmstudio.rs 已在之前删除)
  - main.rs 中散落的内置工具 match arms

新增:
  - src/tools/builtin.rs — BuiltinRegistry 统一切入
    get_current_datetime、manage_memos 为核心内置工具
    统一参数校验、风险等级、错误返回

改动:
  - 模型名直接从 DEEPSEEK_MODEL 环境变量读取
  - builtin 工具与 skills 工具统一经过 SkillRegistry 审批
  - query_capabilities 合并内置 + 外部技能列表
This commit is contained in:
2026-06-02 15:07:33 +08:00
parent a32593bc25
commit 079150b1d0
9 changed files with 106 additions and 404 deletions
+85
View File
@@ -0,0 +1,85 @@
use crate::tools::skill::{RiskLevel, SkillResult};
use chrono::Local;
/// 内置工具执行器:统一处理参数校验、执行、错误返回
pub struct BuiltinRegistry;
impl BuiltinRegistry {
/// 执行内置工具,返回 Some(SkillResult) 或 None(不是内置工具)
pub async fn execute(name: &str, args_json: &str) -> Option<SkillResult> {
match name {
"get_current_datetime" => Some(execute_datetime()),
"manage_memos" => Some(handle_memos(args_json).await),
_ => None,
}
}
/// 返回所有内置工具的 spec 列表
pub fn specs() -> Vec<super::skill::SkillSpec> {
vec![
super::skill::SkillSpec {
name: "get_current_datetime".into(),
description: "获取当前日期时间(北京时间 UTC+8)".into(),
risk_level: RiskLevel::Low,
parameters: serde_json::json!({"type":"object","properties":{"format":{"type":"string"}}}),
timeout_secs: 5,
},
super::skill::SkillSpec {
name: "manage_memos".into(),
description: "管理备忘录:添加/列出/删除。高风险操作(add/delete)需确认".into(),
risk_level: RiskLevel::High,
parameters: serde_json::json!({"type":"object","properties":{"action":{"type":"string","enum":["add","list","delete"]},"content":{"type":"string"},"id":{"type":"integer"}}}),
timeout_secs: 10,
},
]
}
}
fn execute_datetime() -> SkillResult {
let now = Local::now().format("%Y-%m-%d %H:%M:%S").to_string();
SkillResult::ok(serde_json::json!({"datetime": now}).to_string())
}
async fn handle_memos(args_json: &str) -> SkillResult {
let params: serde_json::Value = serde_json::from_str(args_json).unwrap_or_default();
let action = params.get("action").and_then(|v| v.as_str()).unwrap_or("list");
let path = ".data/memos.json";
std::fs::create_dir_all(".data").ok();
let mut data: Vec<serde_json::Value> = if std::path::Path::new(path).exists() {
serde_json::from_str(&std::fs::read_to_string(path).unwrap_or_default()).unwrap_or_default()
} else {
vec![]
};
match action {
"add" => {
let content = params.get("content").and_then(|v| v.as_str()).unwrap_or("");
if content.is_empty() { return SkillResult::error("请提供 content 参数"); }
let next_id = data.iter().filter_map(|m| m.get("id").and_then(|v| v.as_i64())).max().unwrap_or(0) + 1;
data.push(serde_json::json!({
"id": next_id, "content": content,
"created_at": Local::now().format("%Y-%m-%d %H:%M").to_string()
}));
std::fs::write(path, serde_json::to_string_pretty(&data).unwrap()).ok();
SkillResult::ok(format!("已添加备忘录 #{}", next_id))
}
"list" => {
if data.is_empty() { return SkillResult::ok("暂无备忘录".to_string()); }
let lines: Vec<String> = data.iter().map(|m| format!(
"#{} [{}] {}",
m["id"], m.get("created_at").and_then(|v| v.as_str()).unwrap_or("?"), m["content"].as_str().unwrap_or("?")
)).collect();
SkillResult::ok(lines.join("\n"))
}
"delete" => {
let id = params.get("id").and_then(|v| v.as_i64()).unwrap_or(0);
let before = data.len();
data.retain(|m| m.get("id").and_then(|v| v.as_i64()) != Some(id));
if data.len() == before { return SkillResult::error(format!("未找到备忘录 #{}", id)); }
std::fs::write(path, serde_json::to_string_pretty(&data).unwrap()).ok();
SkillResult::ok(format!("已删除备忘录 #{}", id))
}
_ => SkillResult::error("未知操作,支持: add, list, delete"),
}
}
+1
View File
@@ -1,4 +1,5 @@
pub mod approval;
pub mod builtin;
pub mod parser;
pub mod registry;
pub mod skill;