use matrixcode_core::{
event::{AgentEvent, EventData, EventType},
tools::{ProxyMetadata, ProxyTool, ToolDefinition},
};
use serde_json::json;
use std::time::{Duration, SystemTime, UNIX_EPOCH};
async fn search_internal_knowledge(query: &str, limit: usize) -> Result<String, String> {
tokio::time::sleep(Duration::from_millis(100)).await;
let results = vec![
"MatrixCode 是一个 AI 编程助手",
"支持自定义工具注入",
"事件驱动架构",
"Rust 和 TypeScript 混合开发",
"支持多种 LLM 提供商",
];
let filtered: Vec<_> = results
.iter()
.filter(|r| r.contains(query) || query.is_empty())
.take(limit)
.collect();
Ok(json!({
"query": query,
"total": filtered.len(),
"results": filtered
})
.to_string())
}
async fn query_database(sql: &str) -> Result<String, String> {
tokio::time::sleep(Duration::from_millis(150)).await;
Ok(json!({
"sql": sql,
"rows": [
{"id": 1, "name": "Alice", "role": "admin"},
{"id": 2, "name": "Bob", "role": "user"},
],
"rowCount": 2
})
.to_string())
}
async fn execute_custom_tool(
tool_name: &str,
tool_input: serde_json::Value,
metadata: &ProxyMetadata,
) -> Result<String, String> {
println!("🔧 执行工具: {}", tool_name);
println!(
"📥 输入参数: {}",
serde_json::to_string_pretty(&tool_input).unwrap()
);
println!("📋 元数据: {:?}\n", metadata);
match tool_name {
"search_knowledge" => {
let query = tool_input
.get("query")
.and_then(|v| v.as_str())
.ok_or("Missing 'query' parameter")?;
let limit = tool_input
.get("limit")
.and_then(|v| v.as_u64())
.unwrap_or(10) as usize;
search_internal_knowledge(query, limit).await
}
"query_database" => {
let sql = tool_input
.get("sql")
.and_then(|v| v.as_str())
.ok_or("Missing 'sql' parameter")?;
if sql.to_lowercase().contains("drop") || sql.to_lowercase().contains("delete") {
return Err("Dangerous SQL detected".to_string());
}
query_database(sql).await
}
_ => Err(format!("Unknown tool: {}", tool_name)),
}
}
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
env_logger::Builder::from_env(env_logger::Env::default().default_filter_or("info")).init();
println!("╔══════════════════════════════════════════════╗");
println!("║ MatrixCode 自定义工具注入示例 ║");
println!("╚══════════════════════════════════════════════╝\n");
println!("📝 创建代理工具...\n");
let search_tool = ProxyTool::new(
ToolDefinition {
name: "search_knowledge".to_string(),
description: "搜索内部知识库".to_string(),
parameters: json!({
"type": "object",
"properties": {
"query": {
"type": "string",
"description": "搜索关键词"
},
"limit": {
"type": "integer",
"description": "返回结果数量",
"default": 10
}
},
"required": ["query"]
}),
..Default::default()
},
ProxyMetadata {
tool_type: "search".to_string(),
endpoint: Some("http://internal-api:8080/search".to_string()),
timeout_ms: 5000,
custom: Some(json!({
"auth_required": true,
"cache_enabled": true
})),
},
);
let database_tool = ProxyTool::new(
ToolDefinition {
name: "query_database".to_string(),
description: "查询内部数据库(只读)".to_string(),
parameters: json!({
"type": "object",
"properties": {
"sql": {
"type": "string",
"description": "SELECT 查询语句"
}
},
"required": ["sql"]
}),
..Default::default()
},
ProxyMetadata {
tool_type: "database".to_string(),
endpoint: Some("postgresql://internal-db:5432".to_string()),
timeout_ms: 10000,
custom: Some(json!({
"read_only": true,
"max_rows": 1000
})),
},
);
println!("✅ 已创建 2 个代理工具:");
println!(" - search_knowledge (搜索知识库)");
println!(" - query_database (查询数据库)\n");
println!("🤖 模拟 Agent 运行...\n");
println!("━━━━━━ 场景 1: 搜索知识库 ━━━━━━");
let event = AgentEvent {
event_type: EventType::ProxyToolRequest,
timestamp: SystemTime::now()
.duration_since(UNIX_EPOCH)
.unwrap()
.as_secs(),
data: Some(EventData::ProxyToolRequest {
request_id: "req-001".to_string(),
tool_name: "search_knowledge".to_string(),
tool_input: json!({
"query": "工具",
"limit": 5
}),
metadata: search_tool.metadata().clone(),
}),
};
if let Some(EventData::ProxyToolRequest {
request_id: _,
tool_name,
tool_input,
metadata,
..
}) = event.data
{
let result = execute_custom_tool(&tool_name, tool_input.clone(), &metadata).await;
match result {
Ok(output) => {
println!("✅ 执行成功:");
println!("📤 结果: {}\n", output);
}
Err(e) => {
println!("❌ 执行失败: {}\n", e);
}
}
}
println!("━━━━━━ 场景 2: 查询数据库 ━━━━━━");
let event = AgentEvent {
event_type: EventType::ProxyToolRequest,
timestamp: SystemTime::now()
.duration_since(UNIX_EPOCH)
.unwrap()
.as_secs(),
data: Some(EventData::ProxyToolRequest {
request_id: "req-002".to_string(),
tool_name: "query_database".to_string(),
tool_input: json!({
"sql": "SELECT * FROM users LIMIT 5"
}),
metadata: database_tool.metadata().clone(),
}),
};
if let Some(EventData::ProxyToolRequest {
request_id: _,
tool_name,
tool_input,
metadata,
..
}) = event.data
{
let result = execute_custom_tool(&tool_name, tool_input.clone(), &metadata).await;
match result {
Ok(output) => {
println!("✅ 执行成功:");
println!("📤 结果: {}\n", output);
}
Err(e) => {
println!("❌ 执行失败: {}\n", e);
}
}
}
println!("━━━━━━ 场景 3: 错误处理 ━━━━━━");
let event = AgentEvent {
event_type: EventType::ProxyToolRequest,
timestamp: SystemTime::now()
.duration_since(UNIX_EPOCH)
.unwrap()
.as_secs(),
data: Some(EventData::ProxyToolRequest {
request_id: "req-003".to_string(),
tool_name: "query_database".to_string(),
tool_input: json!({
"sql": "DROP TABLE users"
}),
metadata: database_tool.metadata().clone(),
}),
};
if let Some(EventData::ProxyToolRequest {
request_id: _,
tool_name,
tool_input,
metadata,
..
}) = event.data
{
let result = execute_custom_tool(&tool_name, tool_input.clone(), &metadata).await;
match result {
Ok(output) => {
println!("✅ 执行成功:");
println!("📤 结果: {}\n", output);
}
Err(e) => {
println!("❌ 执行失败: {}\n", e);
}
}
}
println!("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━");
println!("✨ 示例完成!\n");
println!("📚 关键概念:");
println!(" 1. ProxyTool 定义工具,外部系统执行");
println!(" 2. Agent 通过事件通知调用方");
println!(" 3. 调用方自行执行工具逻辑");
println!(" 4. 通过 channel 返回结果给 Agent\n");
println!("💡 下一步:");
println!(" - 查看文档: docs/CUSTOM_TOOLS.md");
println!(" - 查看源码: core/src/tools/toolproxy.rs");
println!(" - 集成到你的应用中\n");
Ok(())
}