5baa170508
- README 添加 feature 组合表 + 模块级 features 清单 + 升级指南 - 18 个 example 顶部添加 Required features 注释 - roadmap.md 和 roadmap-v0.3.2.md 同步 Phase 26-27 完成状态 - cargo fmt 全量格式化(修复预存格式问题,CI format job 可通过)
116 lines
4.2 KiB
Rust
116 lines
4.2 KiB
Rust
//! task_agent_demo —— Plan 解析、Step 状态机、错误路径。
|
|
//! Required features: cargo run --example task_agent_demo --features "agent"
|
|
//!
|
|
//! 演示:
|
|
//! 1. `JsonPlanParser::parse` 解析合法 JSON 输入
|
|
//! 2. `Plan` / `Step` 数据结构遍历
|
|
//! 3. `StepStatus` 状态机:Pending → Running → Completed / Failed / Skipped
|
|
//! 4. `is_pending()` / `is_terminal()` 语义
|
|
//! 5. 错误路径:非法 JSON / 空 steps / 缺字段 → `AgentError::PlanParse`
|
|
//!
|
|
//! 运行:`cargo run --example task_agent_demo`
|
|
|
|
use std::collections::HashMap;
|
|
|
|
use agcore::agent::{AgentError, JsonPlanParser, PlanParser, Step, StepStatus};
|
|
use agcore::llm::types::Usage;
|
|
use agcore::llm::types::message::Message;
|
|
use agcore::llm::types::response_v2::{MessageResponse, StopReason};
|
|
|
|
#[tokio::main]
|
|
async fn main() {
|
|
// 1. JsonPlanParser 解析合法 JSON
|
|
println!("=== JsonPlanParser 解析合法 JSON ===");
|
|
let parser = JsonPlanParser;
|
|
let input = r#"{
|
|
"steps": [
|
|
{"description": "查询北京天气"},
|
|
{"description": "根据天气计算穿衣建议"},
|
|
{"description": "生成最终回复"}
|
|
]
|
|
}"#;
|
|
let plan = parser
|
|
.parse(input, "为用户生成今日出行建议")
|
|
.await
|
|
.expect("合法 JSON 应解析成功");
|
|
println!("Plan goal: {}", plan.goal);
|
|
println!("Plan id: {}", plan.id);
|
|
println!("Steps: {}", plan.steps.len());
|
|
for (i, step) in plan.steps.iter().enumerate() {
|
|
println!(
|
|
" [{}] {} (pending={}, terminal={})",
|
|
i,
|
|
step.description,
|
|
step.status.is_pending(),
|
|
step.status.is_terminal()
|
|
);
|
|
}
|
|
assert!(plan.steps.iter().all(|s| s.status.is_pending()));
|
|
|
|
// 2. Step 状态机:Pending → Running → Completed
|
|
println!("\n=== Step 状态机:Pending → Running → Completed ===");
|
|
let mut step = plan.steps.into_iter().next().expect("应有 step");
|
|
println!("初始: pending={}", step.status.is_pending());
|
|
assert!(step.status.is_pending());
|
|
|
|
step.status = StepStatus::Running;
|
|
println!(
|
|
"Running: pending={}, terminal={}",
|
|
step.status.is_pending(),
|
|
step.status.is_terminal()
|
|
);
|
|
|
|
step.status = StepStatus::Completed(MessageResponse {
|
|
id: String::new(),
|
|
model: "mock".into(),
|
|
message: Message::assistant("天气:晴,22°C"),
|
|
usage: Usage::from_input_output(5, 10),
|
|
stop_reason: StopReason::Stop,
|
|
extra: HashMap::new(),
|
|
});
|
|
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()
|
|
);
|
|
assert!(fail_step.status.is_terminal());
|
|
|
|
// 4. 跳过路径
|
|
let mut skipped = Step::new(0, "可选步骤");
|
|
skipped.status = StepStatus::Skipped;
|
|
println!("Skipped: terminal={}", skipped.status.is_terminal());
|
|
assert!(skipped.status.is_terminal());
|
|
|
|
// 5. 错误路径 1:非法 JSON
|
|
println!("\n=== 错误路径:非法 JSON ===");
|
|
let err = parser.parse("not json", "goal").await.unwrap_err();
|
|
println!("错误: {err}");
|
|
assert!(matches!(err, AgentError::PlanParse(_)));
|
|
|
|
// 6. 错误路径 2:空 steps
|
|
println!("\n=== 错误路径:空 steps ===");
|
|
let err = parser.parse(r#"{"steps": []}"#, "goal").await.unwrap_err();
|
|
println!("错误: {err}");
|
|
assert!(matches!(err, AgentError::PlanParse(_)));
|
|
|
|
// 7. 错误路径 3:缺 description 字段
|
|
println!("\n=== 错误路径:缺 description 字段 ===");
|
|
let bad_input = r#"{"steps": [{"description": "ok"}, {"no_desc": true}]}"#;
|
|
let err = parser.parse(bad_input, "goal").await.unwrap_err();
|
|
println!("错误: {err}");
|
|
assert!(matches!(err, AgentError::PlanParse(_)));
|
|
|
|
println!("\n✓ task_agent_demo 完成");
|
|
}
|