style(tools, llm): 统一导入顺序与代码格式

This commit is contained in:
徐涛
2026-07-05 08:19:13 +08:00
parent 98dfe6c1ed
commit 5648b1d217
39 changed files with 390 additions and 397 deletions
+7 -8
View File
@@ -15,9 +15,9 @@ use std::sync::Arc;
use agcore::agent::{Agent, AgentBuilder, AgentSession};
use agcore::llm::hooks::HookExecutor;
use agcore::llm::mock::MockProvider;
use agcore::llm::types::Usage;
use agcore::llm::types::message::{ContentBlock, Message};
use agcore::llm::types::response_v2::{MessageResponse, StopReason};
use agcore::llm::types::Usage;
use agcore::tools::ToolRegistry;
/// 计算器角色 Agent。
@@ -72,7 +72,10 @@ async fn main() {
// 4. 提交第一轮
println!("=== 提交第 1 轮 ===");
let resp = session.submit_turn("1+1=?").await.expect("submit_turn 失败");
let resp = session
.submit_turn("1+1=?")
.await
.expect("submit_turn 失败");
println!("LLM: {}", resp.text());
session
.set_session_data("last_q", "1+1=?")
@@ -107,11 +110,7 @@ async fn main() {
// 8. 跨 session 数据隔离验证
println!("=== 数据隔离验证 ===");
let other = AgentSession::new(
Arc::new(CalculatorAgent),
"other-session",
bundle,
);
let other = AgentSession::new(Arc::new(CalculatorAgent), "other-session", bundle);
assert!(
other.get_session_data("last_q").await.unwrap().is_none(),
"新会话不应看到旧 session 的 last_q"
@@ -127,4 +126,4 @@ async fn main() {
);
println!("\n✓ agent_session_demo 完成");
}
}
+8 -17
View File
@@ -80,11 +80,8 @@ async fn main() {
// 3. 多角色混合 + clear
println!("\n=== 多角色写入 + clear ===");
let store3 = Arc::new(InMemoryStore::new());
let mut memory3 = ConversationMemory::new(
store3,
"session-3",
ConversationMemoryConfig::default(),
);
let mut memory3 =
ConversationMemory::new(store3, "session-3", ConversationMemoryConfig::default());
memory3
.add_message(Message::user_text("你好"))
.await
@@ -98,7 +95,9 @@ async fn main() {
.await
.unwrap();
memory3
.add_message(Message::assistant("我无法查询实时天气,但你可以查看天气应用。"))
.add_message(Message::assistant(
"我无法查询实时天气,但你可以查看天气应用。",
))
.await
.unwrap();
println!(
@@ -119,16 +118,8 @@ async fn main() {
// 4. Session 隔离
println!("\n=== Session 隔离(共用 InMemoryStore===");
let store4 = Arc::new(InMemoryStore::new());
let mut a = ConversationMemory::new(
store4.clone(),
"s-a",
ConversationMemoryConfig::default(),
);
let mut b = ConversationMemory::new(
store4.clone(),
"s-b",
ConversationMemoryConfig::default(),
);
let mut a = ConversationMemory::new(store4.clone(), "s-a", ConversationMemoryConfig::default());
let mut b = ConversationMemory::new(store4.clone(), "s-b", ConversationMemoryConfig::default());
a.add_message(Message::user_text("A 的消息")).await.unwrap();
b.add_message(Message::user_text("B 的消息")).await.unwrap();
println!(
@@ -140,4 +131,4 @@ async fn main() {
assert_eq!(b.len(), 1);
println!("\n✓ conversation_memory_demo 完成");
}
}
+11 -16
View File
@@ -17,7 +17,7 @@ use agcore::tools::{
ToolRegistry,
};
use async_trait::async_trait;
use serde_json::{json, Value};
use serde_json::{Value, json};
/// 天气查询工具 —— 模拟根据城市返回天气数据。
struct WeatherTool;
@@ -42,11 +42,7 @@ impl BaseTool for WeatherTool {
fn required_permissions(&self) -> Vec<Permission> {
vec![Permission::Network]
}
async fn execute(
&self,
args: Value,
_ctx: &ToolContext<'_>,
) -> Result<Value, ToolError> {
async fn execute(&self, args: Value, _ctx: &ToolContext<'_>) -> Result<Value, ToolError> {
let city = args["city"].as_str().unwrap_or("未知");
// 模拟查询:根据城市名给出不同温度
let (temperature, condition) = match city {
@@ -84,11 +80,7 @@ impl BaseTool for DeleteFileTool {
fn required_permissions(&self) -> Vec<Permission> {
vec![Permission::Delete]
}
async fn execute(
&self,
_args: Value,
_ctx: &ToolContext<'_>,
) -> Result<Value, ToolError> {
async fn execute(&self, _args: Value, _ctx: &ToolContext<'_>) -> Result<Value, ToolError> {
Ok(json!({"deleted": true}))
}
}
@@ -138,9 +130,8 @@ async fn main() {
// 5. 权限检查:默认 PermissionConfig 黑名单含 Delete
println!("\n=== 权限检查(默认 PermissionConfigdenied = [Delete, Shell]===");
let mut registry_with_checker = ToolRegistry::new().with_permission_checker(PermissionChecker::new(
PermissionConfig::default(),
));
let mut registry_with_checker = ToolRegistry::new()
.with_permission_checker(PermissionChecker::new(PermissionConfig::default()));
registry_with_checker
.register(Arc::new(WeatherTool) as ToolRef)
.unwrap();
@@ -155,7 +146,11 @@ async fn main() {
.unwrap();
println!(
"get_weather 权限检查: {}",
if r.output.is_ok() { "通过 ✓" } else { "阻断 ✗" }
if r.output.is_ok() {
"通过 ✓"
} else {
"阻断 ✗"
}
);
// delete_file 声明 Delete → 在 denied 列表 → 阻断
@@ -166,4 +161,4 @@ async fn main() {
println!("delete_file 权限检查: 阻断 ✗ ({err})");
println!("\n✓ custom_tool 完成");
}
}
+20 -20
View File
@@ -38,14 +38,26 @@ async fn main() {
let ks = KnowledgeStore::new(store);
let pages = vec![
make_page("rust-1", "Rust 入门", "Rust 是一门系统级编程语言,注重安全性与并发。"),
make_page("python-1", "Python 简介", "Python 是一门动态类型的高级编程语言。"),
make_page(
"rust-1",
"Rust 入门",
"Rust 是一门系统级编程语言,注重安全性与并发。",
),
make_page(
"python-1",
"Python 简介",
"Python 是一门动态类型的高级编程语言。",
),
make_page(
"langgraph-1",
"LangGraph 框架",
"LangGraph 是 LangChain 的状态图扩展,用于构建多步 Agent。",
),
make_page("rust-async", "Rust 异步编程", "Rust 异步基于 tokio 与 futures 抽象。"),
make_page(
"rust-async",
"Rust 异步编程",
"Rust 异步基于 tokio 与 futures 抽象。",
),
];
for p in &pages {
ks.add_page(p.clone()).await.expect("保存页面失败");
@@ -62,14 +74,8 @@ async fn main() {
let result = retriever.retrieve("Rust 异步").await.unwrap();
println!("query: {}", result.query);
for item in &result.items {
println!(
" 命中: {} (score={:.3})",
item.page.title, item.score
);
assert!(
(0.0..=1.0).contains(&item.score),
"score 应在 [0, 1] 区间"
);
println!(" 命中: {} (score={:.3})", item.page.title, item.score);
assert!((0.0..=1.0).contains(&item.score), "score 应在 [0, 1] 区间");
}
assert!(!result.items.is_empty(), "应至少命中一个页面");
@@ -85,14 +91,8 @@ async fn main() {
min_score: 0.5,
};
let retriever2 = MemoryRetriever::new(ks2, cfg);
let result = retriever2
.retrieve("完全不相关的火锅配方")
.await
.unwrap();
println!(
"无关 query → items.len = {} (期望 0)",
result.items.len()
);
let result = retriever2.retrieve("完全不相关的火锅配方").await.unwrap();
println!("无关 query → items.len = {} (期望 0)", result.items.len());
assert!(result.items.is_empty());
// 4. max_results 截断
@@ -146,4 +146,4 @@ async fn main() {
assert!(only_stop.items.is_empty(), "纯停用词 query 必须返回空结果");
println!("\n✓ knowledge_search_demo 完成");
}
}
+9 -7
View File
@@ -11,7 +11,7 @@
use agcore::llm::types::message::{ContentBlock, Message};
use agcore::prompt::{
validate_messages, PromptComposer, PromptTemplate, PromptTemplateRegistry, TemplateContext,
PromptComposer, PromptTemplate, PromptTemplateRegistry, TemplateContext, validate_messages,
};
fn message_text(msg: &Message) -> String {
@@ -33,10 +33,9 @@ fn message_text(msg: &Message) -> String {
fn main() {
// 1. PromptTemplate::compile + render —— 直接构造模板
println!("=== PromptTemplate::compile + render ===");
let tpl = PromptTemplate::compile(
"今日 {{location}} 天气:{{condition}},温度 {{temperature}}",
)
.expect("编译失败");
let tpl =
PromptTemplate::compile("今日 {{location}} 天气:{{condition}},温度 {{temperature}}")
.expect("编译失败");
let mut ctx = TemplateContext::new();
ctx.insert("location", "北京");
ctx.insert("condition", "");
@@ -58,7 +57,10 @@ fn main() {
.register("weather", "今日 {{location}}{{condition}}")
.expect("注册失败");
registry
.register("greet", "你好 {{name}}{{#if formal}} 见到您很荣幸。{{/if}}")
.register(
"greet",
"你好 {{name}}{{#if formal}} 见到您很荣幸。{{/if}}",
)
.expect("注册失败");
let mut ctx = TemplateContext::new();
@@ -105,4 +107,4 @@ fn main() {
}
println!("\n✓ prompt_composer 完成");
}
}
+3 -5
View File
@@ -17,9 +17,9 @@ use std::sync::Arc;
use agcore::llm::cycle::{CycleConfig, LlmCycle};
use agcore::llm::mock::MockProvider;
use agcore::llm::provider::LlmProvider;
use agcore::llm::types::Usage;
use agcore::llm::types::message::{ContentBlock, Message};
use agcore::llm::types::response_v2::{MessageResponse, StopReason, StreamEvent};
use agcore::llm::types::Usage;
use futures_util::StreamExt;
/// 构造预设的纯文本响应。
@@ -99,9 +99,7 @@ async fn main() {
// 上层 Agent 通过 `match` 或 `?` 处理 `AgentError::Llm(_)`。
println!("\n=== 阶段 2:错误路径(队列耗尽)===");
let mut cycle = LlmCycle::new_with_arc(dyn_provider, CycleConfig::default());
let result = cycle
.submit_stream("第二次提问".to_string(), vec![])
.await;
let result = cycle.submit_stream("第二次提问".to_string(), vec![]).await;
match result {
Ok(_) => panic!("阶段 2 必须失败(队列耗尽)"),
Err(e) => {
@@ -114,4 +112,4 @@ async fn main() {
}
println!("\n✓ streaming_events_demo 完成");
}
}
+16 -4
View File
@@ -67,21 +67,33 @@ async fn main() {
assert!(step.status.is_pending());
step.status = StepStatus::Running;
println!("Running: pending={}, terminal={}", step.status.is_pending(), step.status.is_terminal());
println!(
"Running: pending={}, terminal={}",
step.status.is_pending(),
step.status.is_terminal()
);
step.status = StepStatus::Completed(ChatResponse {
message: OpenaiChatMessage::assistant_text("天气:晴,22°C"),
usage: Usage::from_input_output(5, 10),
stop_reason: Some(FinishReason::Stop),
});
println!("Completed: pending={}, terminal={}", step.status.is_pending(), step.status.is_terminal());
println!(
"Completed: pending={}, terminal={}",
step.status.is_pending(),
step.status.is_terminal()
);
assert!(step.status.is_terminal());
// 3. 失败路径
println!("\n=== Step 状态机:失败路径 ===");
let mut fail_step = Step::new(0, "调用天气 API");
fail_step.status = StepStatus::Failed(AgentError::Other("API 不可用".into()));
println!("Failed: pending={}, terminal={}", fail_step.status.is_pending(), fail_step.status.is_terminal());
println!(
"Failed: pending={}, terminal={}",
fail_step.status.is_pending(),
fail_step.status.is_terminal()
);
assert!(fail_step.status.is_terminal());
// 4. 跳过路径
@@ -110,4 +122,4 @@ async fn main() {
assert!(matches!(err, AgentError::PlanParse(_)));
println!("\n✓ task_agent_demo 完成");
}
}