Refactor tool execution pipeline

This commit is contained in:
2026-06-21 14:30:40 +08:00
parent 3e5f0658b3
commit 99c1e9cd6c
81 changed files with 3587 additions and 5317 deletions
+105
View File
@@ -0,0 +1,105 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 4
[[package]]
name = "amap"
version = "0.1.0"
dependencies = [
"serde_json",
]
[[package]]
name = "itoa"
version = "1.0.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682"
[[package]]
name = "memchr"
version = "2.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "88904434abc2901f197fe8cc55f0445e7ded921dba5911dad2e2b39b48e663c4"
[[package]]
name = "proc-macro2"
version = "1.0.106"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quote"
version = "1.0.45"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924"
dependencies = [
"proc-macro2",
]
[[package]]
name = "serde"
version = "1.0.228"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e"
dependencies = [
"serde_core",
]
[[package]]
name = "serde_core"
version = "1.0.228"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
version = "1.0.228"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "serde_json"
version = "1.0.150"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e8014e44b4736ed0538adeecded0fce2a272f22dc9578a7eb6b2d9993c74cfb9"
dependencies = [
"itoa",
"memchr",
"serde",
"serde_core",
"zmij",
]
[[package]]
name = "syn"
version = "2.0.118"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1b9ae57f904213ebb649ce6895b8a66c66f0203b9319718f69a5612a065b1422"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "unicode-ident"
version = "1.0.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75"
[[package]]
name = "zmij"
version = "1.0.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa"
+11
View File
@@ -0,0 +1,11 @@
[package]
name = "amap"
version = "0.1.0"
edition = "2024"
[[bin]]
name = "amap"
path = "src/main.rs"
[dependencies]
serde_json = "1.0"
+17
View File
@@ -0,0 +1,17 @@
name: amap_geocode
desc: 将文字地址转换为经纬度坐标。输入地址名称返回坐标。用于"天安门的坐标是什么"等需要将地名转为坐标的场景,通常作为其他地图工具的前置步骤
type: http
tool: amap
command: geocode
path: /target/release/amap
risk_level: low
timeout_secs: 15
env:
- AMAP_KEY
params:
- name: address
required: true
desc: 详细地址名称,如"北京市朝阳区天安门"、"合肥火车站"。越详细越精确
- name: city
required: false
desc: 城市名称,可选。限定地理编码的城市范围
+14
View File
@@ -0,0 +1,14 @@
name: amap_map_link
desc: 生成高德地图可视化链接。输入中心点坐标返回可分享的地图标记链接。用于"把这个位置发给我"等需要可视化展示的场景
type: http
tool: amap
command: map_link
path: /target/release/amap
risk_level: low
timeout_secs: 15
env:
- AMAP_KEY
params:
- name: center
required: false
desc: 地图中心点经纬度坐标,格式"经度,纬度",默认天安门坐标
@@ -0,0 +1,20 @@
name: amap_poi_search
desc: 搜索指定城市内的POI地点(餐饮、酒店、景点、商场、加油站、银行等)。返回名称和地址。用于"附近有什么好吃的""北京有什么景点"等问题
type: http
tool: amap
command: poi_search
path: /target/release/amap
risk_level: low
timeout_secs: 15
env:
- AMAP_KEY
params:
- name: keywords
required: true
desc: 搜索关键词,如"咖啡厅"、"银行"、"加油站"。支持POI类型名称
- name: city
required: false
desc: 城市名称,限定搜索范围。不填则在当前城市搜索
- name: radius
required: false
desc: 搜索半径(米),如 500、1000、3000。默认 1000 米
@@ -0,0 +1,14 @@
name: amap_reverse_geocode
desc: 将经纬度坐标转换为详细文字地址。输入"经度,纬度"返回结构化地址。用于"这个坐标是哪里"等反向查询
type: http
tool: amap
command: reverse_geocode
path: /target/release/amap
risk_level: low
timeout_secs: 15
env:
- AMAP_KEY
params:
- name: location
required: true
desc: 经纬度坐标,格式为"经度,纬度",如"116.397,39.908"
@@ -0,0 +1,20 @@
name: amap_route_plan
desc: 规划两点之间的出行路线。支持驾车(driving)、步行(walking)、骑行(riding)、公交(transit)四种方式。返回距离和预计耗时。用于"从家到公司怎么走""走过去要多久"等问题
type: http
tool: amap
command: route_plan
path: /target/release/amap
risk_level: low
timeout_secs: 15
env:
- AMAP_KEY
params:
- name: origin
required: true
desc: 起点经纬度坐标,格式"经度,纬度"。可先用 amap_geocode 将地名转为坐标
- name: destination
required: true
desc: 终点经纬度坐标,格式"经度,纬度"。可先用 amap_geocode 将地名转为坐标
- name: type
required: false
desc: 出行方式:driving(驾车)、walking(步行)、riding(骑行)、transit(公交)。默认 driving
@@ -0,0 +1,17 @@
name: amap_travel_plan
desc: 为指定城市生成旅游规划。自动搜索城市内的热门景点、美食、住宿等POI。用于"北京三日游怎么安排""合肥有什么好玩的"等旅游咨询
type: http
tool: amap
command: travel_plan
path: /target/release/amap
risk_level: low
timeout_secs: 15
env:
- AMAP_KEY
params:
- name: city
required: true
desc: 目标城市名称,如"北京"、"杭州"、"成都"
- name: interests
required: false
desc: 感兴趣的关键词,逗号分隔,如"景点,美食,酒店"。默认"景点,美食"
+50
View File
@@ -0,0 +1,50 @@
fn main() {
let input: serde_json::Value = serde_json::from_reader(std::io::stdin()).unwrap();
let mode = std::env::args().nth(2).unwrap_or_default();
let p = &input["params"];
let key = match std::env::var("AMAP_KEY") {
Ok(k) if !k.is_empty() => k,
_ => {
println!(r#"{{"type":"result","content":"错误: 缺少环境变量 AMAP_KEY(高德地图 API Key),请在 .env 中设置"}}"#);
return;
}
};
if input.get("response").is_none() && input.get("db_response").is_none() {
let (url, desc) = match mode.as_str() {
"poi_search" => (format!("https://restapi.amap.com/v5/place/text?keywords={}&city={}&key={key}",
p["keywords"].as_str().unwrap_or(""), p["city"].as_str().unwrap_or("")), format!("搜索: {}", p["keywords"].as_str().unwrap_or(""))),
"geocode" => (format!("https://restapi.amap.com/v3/geocode/geo?address={}&city={}&key={key}",
p["address"].as_str().unwrap_or(""), p["city"].as_str().unwrap_or("")), format!("编码: {}", p["address"].as_str().unwrap_or(""))),
"reverse_geocode" => (format!("https://restapi.amap.com/v3/geocode/regeo?location={}&key={key}",
p["location"].as_str().unwrap_or("")), "逆编码".into()),
"route_plan" => (format!("https://restapi.amap.com/v5/direction/{}?origin={}&destination={}&key={key}",
p["type"].as_str().unwrap_or("driving"), p["origin"].as_str().unwrap_or(""), p["destination"].as_str().unwrap_or("")), "路径规划".into()),
"travel_plan" => (format!("https://restapi.amap.com/v5/place/text?keywords={}&city={}&key={key}",
p["interests"].as_str().unwrap_or(""), p["city"].as_str().unwrap_or("")), format!("旅游: {}", p["city"].as_str().unwrap_or(""))),
"map_link" => (format!("https://uri.amap.com/marker?position={}",
p["center"].as_str().unwrap_or("116.397,39.908")), "地图链接".into()),
_ => { println!(r#"{{"type":"result","content":"未知模式"}}"#); return; }
};
println!("{}", serde_json::json!({"type":"http","method":"GET","url":url,"desc":desc}));
} else {
let b = &input["response"]["body"];
let content = match mode.as_str() {
"poi_search"|"travel_plan" => {
let n = b["pois"].as_array().map(|a| a.len()).unwrap_or(0);
let items: Vec<String> = b["pois"].as_array().unwrap_or(&vec![]).iter().take(5)
.map(|x| format!("{} ({})", x["name"].as_str().unwrap_or(""), x["address"].as_str().unwrap_or(""))).collect();
format!("找到 {n} 个:\n{}", items.join("\n"))
}
"geocode" => {
let empty = vec![]; let g = b["geocodes"].as_array().unwrap_or(&empty);
g.first().map(|x| format!("{}{}", x["formatted_address"].as_str().unwrap_or(""), x["location"].as_str().unwrap_or(""))).unwrap_or("未找到".into())
}
"reverse_geocode" => b["regeocode"]["formatted_address"].as_str().unwrap_or("未找到").into(),
"route_plan" => format!("距离: {}m, 耗时: {}s", b["route"]["distance"].as_str().unwrap_or("?"), b["route"]["duration"].as_str().unwrap_or("?")),
"map_link" => "地图链接已生成".into(),
_ => format!("{b}"),
};
println!("{}", serde_json::json!({"type":"result","content":content}));
}
}