feat: 高德地图工具 + 多轮 bug 修复
新增: - 高德地图 6 个内置工具: amap_poi_search, amap_geocode, amap_reverse_geocode, amap_route_plan, amap_travel_plan, amap_map_link - CLI 子命令: ias tool amap (poi-search/geocode/route-plan/travel-plan/map-link) - 工具优先级指南: build_capability_guide() 含 amap > weather > web_search 优先级 - DEFAULT_SYSTEM_PROMPT 内置工具优先级说明(不再依赖环境变量) Bug 修复: 1. (HIGH) call_capability 参数契约修复 — 新增 unpack_call_params() 统一解包 prompt 字段 2. (MEDIUM) 天气 hours=0 不再调用逐时 API 3. (MEDIUM) 长期记忆 daemon 双写缓存+DB,无 DB 不丢失 4. (HIGH) 审批流程状态语义修复 — handle_reply 返回 ApprovalDecision,拒绝/过期不再当作通过 5. (HIGH) 审批有效期基于 expires_at 时间戳而非 receiver drop 6. (MEDIUM) 摘要保存改为 current_user_id 与读取一致 7. (MEDIUM) worker 审批通过后删除孤立 tool result,仅保留 approved_tool 状态放行 架构: - daemon + worker IPC 架构 (Unix Domain Socket) - build_capability_guide 共享函数消除 main.rs/worker.rs 重复
This commit is contained in:
+246
-28
@@ -2,8 +2,14 @@ use clap::{Parser, Subcommand};
|
||||
|
||||
/// iAs — 微信 AI 智能助手
|
||||
///
|
||||
/// 支持扫码登录、长轮询收发消息、AI 自动回复(DeepSeek/LM Studio)、
|
||||
/// 工具调用(天气/搜索/邮件/Shell/定时任务等)、Token 用量统计。
|
||||
/// 支持扫码登录、长轮询收发消息、AI 自动回复(DeepSeek)、
|
||||
/// 内置工具(天气/搜索/备忘录/日期时间等)、Token 用量统计。
|
||||
///
|
||||
/// 快速开始:
|
||||
/// ias login 扫码登录微信
|
||||
/// ias listen --llm 启动 AI 自动回复
|
||||
/// ias tool weather 北京 查询天气
|
||||
/// ias tool search "最新新闻" 联网搜索
|
||||
#[derive(Parser, Debug)]
|
||||
#[command(name = "ias", version, about, long_about = None)]
|
||||
pub struct Cli {
|
||||
@@ -15,8 +21,12 @@ pub struct Cli {
|
||||
pub enum Commands {
|
||||
/// 扫码登录微信
|
||||
///
|
||||
/// 在终端显示二维码,扫描后完成登录。
|
||||
/// 在终端显示登录二维码,扫描后完成登录。
|
||||
/// 认证信息存入 PostgreSQL 或本地文件。
|
||||
///
|
||||
/// 示例:
|
||||
/// ias login
|
||||
/// ias login --timeout 600
|
||||
Login {
|
||||
/// 登录超时秒数(默认 480s)
|
||||
#[arg(long, default_value = "480")]
|
||||
@@ -26,62 +36,55 @@ pub enum Commands {
|
||||
/// 监听微信消息(长轮询)
|
||||
///
|
||||
/// 启动微信消息监听,接收并处理消息。
|
||||
/// 使用 --llm 启用 AI 自动回复,--echo 原样回显。
|
||||
///
|
||||
/// 示例:
|
||||
/// ias listen # 仅监听,不做回复
|
||||
/// ias listen --llm # AI 自动回复
|
||||
/// ias listen --echo # 原样回显
|
||||
Listen {
|
||||
/// 启用 AI 自动回复(DeepSeek/LM Studio)
|
||||
#[arg(long, help = "启用 AI 自动回复")]
|
||||
/// 启用 AI 自动回复
|
||||
#[arg(long)]
|
||||
llm: bool,
|
||||
|
||||
/// 仅回显消息(不调用 AI)
|
||||
#[arg(long, help = "原样回显收到的消息")]
|
||||
/// 原样回显收到的消息
|
||||
#[arg(long)]
|
||||
echo: bool,
|
||||
},
|
||||
|
||||
/// 发送文本消息
|
||||
///
|
||||
/// 向指定微信用户发送文本。
|
||||
///
|
||||
/// 示例:
|
||||
/// ias send --to <user_id> --text "你好"
|
||||
/// ias send --to wxid_xxx --text "你好"
|
||||
Send {
|
||||
/// 目标用户 ID
|
||||
#[arg(long, help = "微信用户 ID")]
|
||||
#[arg(long)]
|
||||
to: String,
|
||||
|
||||
/// 消息内容
|
||||
#[arg(long, help = "文本消息内容")]
|
||||
#[arg(long)]
|
||||
text: String,
|
||||
|
||||
/// 上下文令牌
|
||||
#[arg(long, help = "微信上下文令牌")]
|
||||
#[arg(long)]
|
||||
context_token: Option<String>,
|
||||
},
|
||||
|
||||
/// 查看当前登录状态
|
||||
///
|
||||
/// 显示已登录的账号、Token 前缀、API 地址及存储方式。
|
||||
Whoami,
|
||||
|
||||
/// 查看 LLM Token 使用统计
|
||||
///
|
||||
/// 查询 LLM 调用的 Token 消耗、缓存命中率。
|
||||
/// 默认查询最近 7 天,支持时间范围和模型过滤。
|
||||
/// 默认查询最近 7 天。
|
||||
///
|
||||
/// 示例:
|
||||
/// ias usage
|
||||
/// ias usage --since 2026-06-01T00:00:00Z
|
||||
/// ias usage --model deepseek-v4-flash
|
||||
/// ias usage --since 2026-06-01T00:00:00Z --model deepseek-v4-flash
|
||||
Usage {
|
||||
/// 起始时间(RFC3339 格式,默认 7 天前)
|
||||
#[arg(long, help = "起始时间(如 2026-06-01T00:00:00Z)")]
|
||||
/// 起始时间(RFC3339 格式)
|
||||
#[arg(long)]
|
||||
since: Option<String>,
|
||||
|
||||
/// 结束时间(RFC3339 格式,默认现在)
|
||||
/// 结束时间(RFC3339 格式)
|
||||
#[arg(long)]
|
||||
until: Option<String>,
|
||||
|
||||
@@ -90,13 +93,228 @@ pub enum Commands {
|
||||
model: Option<String>,
|
||||
},
|
||||
|
||||
/// 后台服务模式
|
||||
/// 后台服务模式(等同 listen --llm + 文件日志)
|
||||
///
|
||||
/// 等同 listen --llm,同时日志写入 ~/.ias/logs/ 滚动文件。
|
||||
/// 配合 systemd 实现开机自启和进程守护。
|
||||
/// 配合 systemd 实现开机自启。
|
||||
///
|
||||
/// 示例:
|
||||
/// ias service # 前台运行
|
||||
/// sudo systemctl enable ias --now # systemd 管理
|
||||
/// ias service
|
||||
Service,
|
||||
|
||||
/// 守护进程模式(daemon + worker 分离架构)
|
||||
///
|
||||
/// Daemon 持有 WeChat 长连接和数据库,每条消息 spawn 独立 worker。
|
||||
/// Worker 代码更新后编译即可,下一条消息自动用新版本。
|
||||
///
|
||||
/// 示例:
|
||||
/// ias daemon
|
||||
/// ias daemon --sock /tmp/ias.sock
|
||||
Daemon {
|
||||
/// Unix Domain Socket 路径
|
||||
#[arg(long, default_value = "/tmp/ias_daemon.sock")]
|
||||
sock: String,
|
||||
},
|
||||
|
||||
/// Worker 进程(由 daemon 自动 spawn,也可手动测试)
|
||||
///
|
||||
/// 示例:
|
||||
/// ias worker --sock /tmp/ias_daemon.sock
|
||||
Worker {
|
||||
/// Unix Domain Socket 路径
|
||||
#[arg(long, default_value = "/tmp/ias_daemon.sock")]
|
||||
sock: String,
|
||||
},
|
||||
|
||||
/// 调用内置工具(无需登录,独立运行)
|
||||
///
|
||||
/// 可直接在终端调用天气、搜索、备忘录、日期时间、高德地图等工具。
|
||||
#[command(
|
||||
subcommand,
|
||||
after_help = "示例:\n ias tool datetime\n ias tool weather 北京\n ias tool weather 上海 --days 7\n ias tool search \"Rust 2024 edition\"\n ias tool fetch https://example.com/article\n ias tool memos list\n ias tool memos add \"明天下午2点开会\"\n ias tool memos delete 3\n ias tool amap poi-search --keywords 肯德基 --city 北京\n ias tool amap geocode --address 西直门\n ias tool amap route-plan --type walking --origin 116.397,39.909 --destination 116.427,39.903\n ias tool amap travel-plan --city 北京 --interests 景点,美食 --route-type walking"
|
||||
)]
|
||||
Tool(ToolCommand),
|
||||
}
|
||||
|
||||
// ─── 工具子命令 ───
|
||||
|
||||
#[derive(Subcommand, Debug, Clone)]
|
||||
pub enum ToolCommand {
|
||||
/// 获取当前日期时间(北京时间 UTC+8)
|
||||
Datetime,
|
||||
|
||||
/// 管理备忘录
|
||||
#[command(subcommand)]
|
||||
Memos(MemosAction),
|
||||
|
||||
/// 查询指定城市的天气
|
||||
///
|
||||
/// 示例:
|
||||
/// ias tool weather 北京
|
||||
/// ias tool weather 上海 --days 7
|
||||
Weather {
|
||||
/// 城市名称
|
||||
location: String,
|
||||
|
||||
/// 查询天数(1-7,默认 3)
|
||||
#[arg(long, default_value = "3")]
|
||||
days: u32,
|
||||
},
|
||||
|
||||
/// 联网搜索最新信息(需配置 TAVILY_API_KEY)
|
||||
///
|
||||
/// 示例:
|
||||
/// ias tool search "最新 AI 新闻"
|
||||
/// ias tool search "Rust async" --max-results 10 --no-answer
|
||||
/// ias tool search "比特币" --topic finance --time-range week
|
||||
Search {
|
||||
/// 搜索关键词
|
||||
query: String,
|
||||
|
||||
/// 最大结果数(默认 5)
|
||||
#[arg(long, default_value = "5")]
|
||||
max_results: u32,
|
||||
|
||||
/// 不包含 AI 生成的摘要
|
||||
#[arg(long)]
|
||||
no_answer: bool,
|
||||
|
||||
/// 搜索主题: general / news / finance
|
||||
#[arg(long)]
|
||||
topic: Option<String>,
|
||||
|
||||
/// 发布时间过滤: day / week / month / year
|
||||
#[arg(long)]
|
||||
time_range: Option<String>,
|
||||
},
|
||||
|
||||
/// 抓取网页并提取正文内容
|
||||
Fetch {
|
||||
/// 网页 URL
|
||||
url: String,
|
||||
},
|
||||
|
||||
/// 高德地图工具(POI搜索、地理编码、路径规划、旅游规划)
|
||||
#[command(subcommand)]
|
||||
Amap(AmapAction),
|
||||
}
|
||||
|
||||
#[derive(Subcommand, Debug, Clone)]
|
||||
pub enum AmapAction {
|
||||
/// POI(地点)搜索
|
||||
PoiSearch {
|
||||
/// 搜索关键词
|
||||
#[arg(long)]
|
||||
keywords: String,
|
||||
|
||||
/// 城市名称
|
||||
#[arg(long)]
|
||||
city: Option<String>,
|
||||
|
||||
/// 中心点坐标(经度,纬度),用于周边搜索
|
||||
#[arg(long)]
|
||||
location: Option<String>,
|
||||
|
||||
/// 搜索半径(米),默认 1000
|
||||
#[arg(long)]
|
||||
radius: Option<u32>,
|
||||
|
||||
/// 页码,默认 1
|
||||
#[arg(long, default_value = "1")]
|
||||
page: u32,
|
||||
|
||||
/// 每页数量,默认 10
|
||||
#[arg(long, default_value = "10")]
|
||||
offset: u32,
|
||||
},
|
||||
|
||||
/// 地理编码:地址 → 坐标
|
||||
Geocode {
|
||||
/// 地址名称
|
||||
#[arg(long)]
|
||||
address: String,
|
||||
|
||||
/// 城市名称(可选)
|
||||
#[arg(long)]
|
||||
city: Option<String>,
|
||||
},
|
||||
|
||||
/// 逆地理编码:坐标 → 地址
|
||||
ReverseGeocode {
|
||||
/// 坐标(经度,纬度)
|
||||
#[arg(long)]
|
||||
location: String,
|
||||
},
|
||||
|
||||
/// 路径规划
|
||||
RoutePlan {
|
||||
/// 出行方式:walking/driving/riding/transit
|
||||
#[arg(long)]
|
||||
r#type: String,
|
||||
|
||||
/// 起点坐标(经度,纬度)
|
||||
#[arg(long)]
|
||||
origin: String,
|
||||
|
||||
/// 终点坐标(经度,纬度)
|
||||
#[arg(long)]
|
||||
destination: String,
|
||||
|
||||
/// 城市名称(公交方式必填)
|
||||
#[arg(long)]
|
||||
city: Option<String>,
|
||||
|
||||
/// 途经点(驾车可选,多个用;分隔)
|
||||
#[arg(long)]
|
||||
waypoints: Option<String>,
|
||||
|
||||
/// 策略(驾车默认10躲避拥堵,公交默认0最快捷)
|
||||
#[arg(long)]
|
||||
strategy: Option<u32>,
|
||||
},
|
||||
|
||||
/// 智能旅游规划
|
||||
TravelPlan {
|
||||
/// 城市名称
|
||||
#[arg(long)]
|
||||
city: String,
|
||||
|
||||
/// 兴趣点关键词(逗号分隔),如 景点,美食,酒店
|
||||
#[arg(long, default_value = "景点,美食")]
|
||||
interests: String,
|
||||
|
||||
/// 路线类型:walking/driving/riding/transit
|
||||
#[arg(long, default_value = "walking")]
|
||||
route_type: String,
|
||||
},
|
||||
|
||||
/// 生成地图可视化链接
|
||||
MapLink {
|
||||
/// 地图数据 JSON 数组
|
||||
#[arg(long)]
|
||||
data: String,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Subcommand, Debug, Clone)]
|
||||
pub enum MemosAction {
|
||||
/// 列出所有备忘录
|
||||
List,
|
||||
|
||||
/// 添加备忘录
|
||||
///
|
||||
/// 示例:
|
||||
/// ias tool memos add "明天下午2点开会"
|
||||
Add {
|
||||
/// 备忘录内容
|
||||
content: String,
|
||||
},
|
||||
|
||||
/// 删除指定 ID 的备忘录
|
||||
///
|
||||
/// 示例:
|
||||
/// ias tool memos delete 3
|
||||
Delete {
|
||||
/// 备忘录 ID
|
||||
id: i64,
|
||||
},
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user