feat: 为全部 39 个 Rust 源文件添加系统性中文注释
为整个项目添加了详尽的中文文档注释,覆盖所有模块: 入口与架构: - main.rs — 架构图、数据流、4 个关键设计决策 - cli.rs — 所有 CLI 子命令中文化 - Cargo.toml — 每个依赖的作用说明 - channel/mod.rs — 渠道标识设计意图 核心守护进程与消息队列: - daemon.rs — 三消费者架构图、审批流 - queue/* — 公平轮转算法、路由调度架构 LLM 层: - types.rs — Role/Message/ToolCall 等每个字段含义 - provider.rs — Provider trait 设计 + SSE 解析 - conversation.rs — 工具循环流程图、摘要机制 - deepseek.rs — API 请求格式 上下文管理: - context/types.rs — ChatSession 消息生命周期 - context/builder.rs — Token 预算管理策略 - context/tools.rs — MemoryStore 双写策略 工具系统: - tools/mod.rs — 两层元工具架构图 - tools/approval.rs — 审批流程 - tools/definitions.rs — 声明式工具三要素 - tools/subprocess.rs — 执行流程 + 缓存策略 数据库与状态: - db/* — 5 张表用途、回退策略 - state.rs — 文件存储回退方案 - scheduler.rs — SKIP LOCKED 防重复 已废弃模块: - ipc.rs — 旧 UDS 协议 - worker.rs — 旧 vs 新架构对比
This commit is contained in:
+22
-2
@@ -6,7 +6,11 @@ use std::sync::Arc;
|
||||
use std::time::Instant;
|
||||
use tokio::sync::{Mutex, oneshot};
|
||||
|
||||
/// 审批决策
|
||||
/// ## 审批决策
|
||||
///
|
||||
/// * `Approved` — 用户输入了正确的确认码
|
||||
/// * `Rejected` — 用户拒绝了(输入 0 或"取消")
|
||||
/// * `Expired` — 超时未确认(5 分钟有效)
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub enum ApprovalDecision {
|
||||
Approved,
|
||||
@@ -24,7 +28,23 @@ struct PendingEntry {
|
||||
sender: oneshot::Sender<ApprovalDecision>,
|
||||
}
|
||||
|
||||
/// 审批管理器
|
||||
/// ## 审批管理器
|
||||
///
|
||||
/// 管理高风险工具的用户确认流程。
|
||||
///
|
||||
/// ### 流程
|
||||
/// 1. `create(user_id, skill_name)` → 生成 6 位随机确认码,哈希后存储
|
||||
/// 2. 向用户发送"⚠️ 操作确认\n\n技能:{name}\n确认码:{code}"
|
||||
/// 3. 用户在微信聊天中输入确认码
|
||||
/// 4. `handle_reply(user_id, reply)` → 验证确认码哈希
|
||||
/// - 匹配 → Approved
|
||||
/// - 不匹配 → 减少尝试次数(最多 3 次)
|
||||
/// - 输入 0 或"取消" → Rejected
|
||||
/// - 超时 → Expired(每 60 秒清理一次)
|
||||
///
|
||||
/// ### 存储
|
||||
/// * 内存 — `HashMap<user_id, Vec<PendingEntry>>`(快速访问)
|
||||
/// * 数据库 — `pending_approvals` 表(持久化审计)
|
||||
pub struct ApprovalManager {
|
||||
pool: Option<Arc<PgPool>>,
|
||||
/// user_id → 该用户的待审批队列
|
||||
|
||||
+16
-1
@@ -1,6 +1,21 @@
|
||||
use crate::tools::types::{RiskLevel, SkillResult};
|
||||
|
||||
/// 内置工具注册表:名称 → 执行、spec 列表、风险判断
|
||||
/// ## 内置工具注册表
|
||||
///
|
||||
/// 连接 LLM 的元工具调用和实际 Rust 实现的工具函数。
|
||||
///
|
||||
/// ### 职责
|
||||
/// 1. `execute(name, args)` — 按名称路由到对应的 builtin 工具执行
|
||||
/// 2. `specs()` — 返回所有内置工具的 SkillSpec(给元工具 `query_capabilities` 使用)
|
||||
/// 3. `is_high_risk(name)` — 判断工具是否需要审批
|
||||
///
|
||||
/// ### 当前内置工具
|
||||
/// * `get_current_datetime` — 获取当前北京时间
|
||||
/// * `manage_memos` — 管理备忘录(CRUD)
|
||||
/// * `query_weather` — 查询天气(和风天气 API)
|
||||
/// * `web_search` — 联网搜索(Tavily API)
|
||||
/// * `fetch_page` — 抓取网页内容
|
||||
/// * `amap_*` — 高德地图系列(POI搜索、地理编码、路径规划等)
|
||||
pub struct BuiltinRegistry;
|
||||
|
||||
impl BuiltinRegistry {
|
||||
|
||||
@@ -1,16 +1,30 @@
|
||||
//! JSON 工具定义 — 像 curl + jq 一样描述一个工具
|
||||
//! ## JSON 工具定义格式
|
||||
//!
|
||||
//! 三要素:URL → 取节点 → 选字段
|
||||
//! 本模块定义了一种"声明式工具"格式 —— 只需要写一个 JSON 文件就能注册一个新工具,
|
||||
//! 无需改 Rust 代码、重新编译。
|
||||
//!
|
||||
//! ### 设计理念:像 curl + jq 一样描述工具
|
||||
//!
|
||||
//! ```json
|
||||
//! {
|
||||
//! "name": "stocks",
|
||||
//! "description": "股票行情",
|
||||
//! "url": "https://api.example.com/stocks",
|
||||
//! "description": "股票行情查询",
|
||||
//! "url": "https://api.example.com/stocks/{{code}}",
|
||||
//! "method": "GET",
|
||||
//! "headers": { "Authorization": "${env:API_KEY}" },
|
||||
//! "extract": "data.items",
|
||||
//! "fields": ["name", "price"]
|
||||
//! }
|
||||
//! ```
|
||||
//!
|
||||
//! ### 三要素
|
||||
//! 1. **URL** — API 端点模板(支持 `{{var}}` 和 `${param:name:type}` 传参)
|
||||
//! 2. **取节点** — `extract` 字段指定 JSON 点路径(类似 jq)
|
||||
//! 3. **选字段** — `fields` 字段只保留需要的字段
|
||||
//!
|
||||
//! ### 参数推导
|
||||
//! 自动从 URL/Body/Headers 中推导参数定义(无需手动写 parameters 字段),
|
||||
//! 也支持显式 `parameters` 声明以获得更精确的类型描述。
|
||||
|
||||
use std::collections::HashMap;
|
||||
|
||||
@@ -60,7 +74,22 @@ impl<'de> serde::Deserialize<'de> for HttpMethod {
|
||||
}
|
||||
}
|
||||
|
||||
/// 一个 JSON 工具定义
|
||||
/// ## JSON 工具定义(ToolDef)
|
||||
///
|
||||
/// 描述一个通过 HTTP API 调用的外部工具。
|
||||
///
|
||||
/// ### 字段说明
|
||||
/// * `name` — 工具名称,用作 `call_capability` 的 name
|
||||
/// * `description` — 工具描述(给 LLM 看的)
|
||||
/// * `url` — URL 模板,支持 `{{var}}` 和 `${param:name:type}` 两种传参
|
||||
/// * `method` — HTTP 方法(GET/POST/PUT/DELETE),默认 GET
|
||||
/// * `headers` — HTTP 请求头,值可包含 `${env:KEY}`(环境变量)、
|
||||
/// `${cmd:command}`(命令输出)、`${param:name:type}`(参数值)
|
||||
/// * `body` — POST/PUT 的 JSON body 模板,同样支持变量替换
|
||||
/// * `parameters` — 显式参数声明(可选,未声明时自动推导)
|
||||
/// * `extract` — JSON 提取路径,如 "data.items"
|
||||
/// * `fields` — 筛选要保留的字段
|
||||
/// * `timeout` — 超时秒数,默认 30
|
||||
#[derive(Debug, Clone, serde::Deserialize)]
|
||||
pub struct ToolDef {
|
||||
/// 工具名称,用作 call_capability 的 name
|
||||
|
||||
+36
-5
@@ -1,14 +1,45 @@
|
||||
//! ## 工具系统 —— 元工具 + 分离式内置工具
|
||||
//!
|
||||
//! 本模块是 iAs 的"工具系统",让 LLM 能够调用外部功能。
|
||||
//!
|
||||
//! ### 架构设计(两层元工具)
|
||||
//!
|
||||
//! LLM 不直接感知每个具体工具,而是通过两个**元工具**间接调用:
|
||||
//!
|
||||
//! 1. **`query_capabilities`** — 列出所有可用工具的名称、描述、参数格式
|
||||
//! 2. **`call_capability`** — 按名称调用工具,参数通过 JSON 传递
|
||||
//!
|
||||
//! 这样做的优势:新增工具时只需要在服务端注册,不需要修改 LLM 的 tool definitions。
|
||||
//!
|
||||
//! ### 工具类型
|
||||
//! * **内置工具** (builtins/) — Rust 代码实现的工具(天气、搜索、高德地图等)
|
||||
//! * **JSON 工具** (definitions.rs) — 从 `~/.ias/tools/*.json` 加载,由 ToolDef 定义
|
||||
//! * **上下文工具** — read_memories, write_memory, read_summaries(直接在 daemon 中处理)
|
||||
//!
|
||||
//! ### 工具执行流程
|
||||
//! ```text
|
||||
//! LLM 请求 call_capability("query_weather", {"location":"北京"})
|
||||
//! → daemon 解析出 target_name="query_weather",提取参数
|
||||
//! → 高风险?→ 走 ApprovalManager 审批流
|
||||
//! → 低风险?→ BuiltinRegistry::execute() 或 SubprocessRunner::execute()
|
||||
//! → 结果返回 LLM 继续对话
|
||||
|
||||
pub mod approval;
|
||||
pub mod builtin;
|
||||
pub mod builtins;
|
||||
pub mod definitions;
|
||||
pub mod subprocess;
|
||||
pub mod types;
|
||||
|
||||
/// 从 call_capability 的 `{name, prompt}` JSON 中提取目标工具的真实参数。
|
||||
/// ## 从 `call_capability` 的 `{name, prompt}` JSON 中提取目标工具的真实参数
|
||||
///
|
||||
/// 逻辑:
|
||||
/// - 如果 prompt 是 JSON 字符串 → parse 后合并
|
||||
/// - 如果 prompt 是 JSON 对象 → 直接合并
|
||||
/// - 顶层字段(非 name/prompt)也合并进去
|
||||
/// `call_capability` 的参数格式为 `{name: "工具名", prompt: "参数JSON字符串"}`。
|
||||
/// 这个函数负责从这种格式中提取出工具真正的参数。
|
||||
///
|
||||
/// ### 提取逻辑
|
||||
/// 1. 如果 `prompt` 是 JSON 字符串 → parse 后合并
|
||||
/// 2. 如果 `prompt` 是 JSON 对象 → 直接合并
|
||||
/// 3. 顶层字段(非 name/prompt)也合并进去(支持直接传参)
|
||||
pub fn unpack_call_params(cp: &serde_json::Value) -> serde_json::Value {
|
||||
let mut params = serde_json::Map::new();
|
||||
|
||||
|
||||
+33
-10
@@ -1,14 +1,30 @@
|
||||
//! JSON 工具子进程执行器
|
||||
//! ## JSON 工具子进程执行器
|
||||
//!
|
||||
//! 从 ~/.ias/tools/*.json 加载 ToolDef,运行时通过 HTTP 执行。
|
||||
//! 无需编译,放 JSON 即用。
|
||||
//! ### 设计理念:"放 JSON 即用"
|
||||
//!
|
||||
//! 执行流程:
|
||||
//! 模板替换 → HTTP 请求 → JSON 解析
|
||||
//! ├─ 失败 → 返回纯文本
|
||||
//! ├─ 提取 → json_select()
|
||||
//! ├─ 筛选 → filter_fields()
|
||||
//! └─ 格式化输出
|
||||
//! 从 `~/.ias/tools/*.json` 加载 `ToolDef`,运行时通过 HTTP 执行。
|
||||
//! 不需要修改 Rust 代码、不需要重新编译,放一个 JSON 文件就能注册新工具。
|
||||
//!
|
||||
//! ### 执行流程
|
||||
//!
|
||||
//! ```text
|
||||
//! 1. 模板替换
|
||||
//! {{var}} → args.var(URL 编码)
|
||||
//! ${param:name:type} → args.name
|
||||
//! ${env:KEY} → 环境变量
|
||||
//! ${cmd:command} → shell 命令输出(有缓存,TTL=300s)
|
||||
//!
|
||||
//! 2. HTTP 请求(GET/POST/PUT/DELETE)
|
||||
//!
|
||||
//! 3. 返回处理
|
||||
//! ├─ 不是 JSON → 直接返回纯文本
|
||||
//! ├─ 有 extract → json_select() 按点路径取子节点
|
||||
//! ├─ 有 fields → filter_fields() 只保留指定字段
|
||||
//! └─ 格式化输出 → 可读文本
|
||||
//! ```
|
||||
//!
|
||||
//! ### 缓存
|
||||
//! `${cmd:...}` 的结果会被缓存 300 秒,适合 JWT token 等有时效的值。
|
||||
|
||||
use crate::tools::definitions::{HttpMethod, ToolDef};
|
||||
use crate::tools::types::{SkillResult, SkillSpec};
|
||||
@@ -102,7 +118,14 @@ pub fn runner() -> &'static SubprocessRunner {
|
||||
&RUNNER
|
||||
}
|
||||
|
||||
/// 子进程执行器
|
||||
/// ## 子进程执行器 —— 管理所有从 JSON 文件加载的工具
|
||||
///
|
||||
/// ### 全局单例
|
||||
/// 通过 `LazyLock` 在首次访问时初始化,从 `~/ias/tools/*.json` 加载全部工具。
|
||||
///
|
||||
/// ### 运行时热加载
|
||||
/// `reload()` 方法可以重新扫描工具目录(目前未在运行时调用,
|
||||
/// 但为后续热更新保留了接口)。
|
||||
pub struct SubprocessRunner {
|
||||
tools: RwLock<HashMap<String, ToolDef>>,
|
||||
}
|
||||
|
||||
+23
-4
@@ -3,7 +3,10 @@ use std::future::Future;
|
||||
use std::pin::Pin;
|
||||
use std::sync::Arc;
|
||||
|
||||
// ─── 风险等级 ───
|
||||
/// ## 风险等级 —— 工具的安全级别
|
||||
///
|
||||
/// * `Low` — 低风险,直接执行(如天气查询、日期时间)
|
||||
/// * `High` — 高风险,需要用户输入确认码审批(如写备忘录、发消息)
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Deserialize)]
|
||||
#[serde(rename_all = "lowercase")]
|
||||
@@ -14,7 +17,14 @@ pub enum RiskLevel {
|
||||
|
||||
impl RiskLevel {}
|
||||
|
||||
// ─── 工具元数据 ───
|
||||
/// ## 工具元数据(SkillSpec)—— 工具的自描述信息
|
||||
///
|
||||
/// 用于给 LLM 展示"有什么工具可用、怎么用"。
|
||||
/// * `name` — 工具名称
|
||||
/// * `description` — 工具描述
|
||||
/// * `risk_level` — 风险等级(Low/High)
|
||||
/// * `parameters` — JSON Schema 格式的参数定义
|
||||
/// * `timeout_secs` — 执行超时时间
|
||||
|
||||
#[derive(Debug, Clone, Deserialize)]
|
||||
pub struct SkillSpec {
|
||||
@@ -36,7 +46,11 @@ fn default_timeout() -> u64 {
|
||||
30
|
||||
}
|
||||
|
||||
// ─── 工具执行结果 ───
|
||||
/// ## 工具执行结果
|
||||
///
|
||||
/// * `success` — 执行是否成功
|
||||
/// * `output` — 可读的输出文本(将返回给 LLM)
|
||||
/// * `data` — 结构化数据(可选),用于后续处理
|
||||
|
||||
#[derive(Debug, Clone, Serialize)]
|
||||
pub struct SkillResult {
|
||||
@@ -89,7 +103,12 @@ impl SkillResult {
|
||||
}
|
||||
}
|
||||
|
||||
// ─── 执行上下文 ───
|
||||
/// ## 执行上下文 —— 工具执行时需要的环境信息
|
||||
///
|
||||
/// 当工具在 daemon 上下文中执行时,携带以下信息:
|
||||
/// * `user_id` — 触发工具的用户
|
||||
/// * `approval_manager` — 审批管理器(高风险工具需要)
|
||||
/// * `send_wechat` — 微信发送回调(用于向用户发送审批提示)
|
||||
|
||||
pub type WechatSender = Arc<
|
||||
dyn Fn(&str, &str) -> Pin<Box<dyn Future<Output = Result<(), String>> + Send>> + Send + Sync,
|
||||
|
||||
Reference in New Issue
Block a user