style(tools, llm): 统一导入顺序与代码格式
This commit is contained in:
@@ -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 完成");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
@@ -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=== 权限检查(默认 PermissionConfig,denied = [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 完成");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 完成");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 完成");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 完成");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 完成");
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user