//! 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 完成"); }