use serde_json::json; use sgclaw::agent::planner::{build_execution_preview, plan_instruction, PlannerError}; use sgclaw::config::PlannerMode; use sgclaw::pipe::Action; #[test] fn planner_module_is_explicitly_legacy_dev_only() { assert!(sgclaw::agent::planner::LEGACY_DEV_ONLY); } #[test] fn planner_converts_baidu_search_instruction_into_three_steps() { let plan = plan_instruction("打开百度搜索天气").unwrap(); assert_eq!(plan.summary, "已在百度搜索天气"); assert_eq!(plan.steps.len(), 3); assert_eq!(plan.steps[0].action, Action::Navigate); assert_eq!( plan.steps[0].params, json!({ "url": "https://www.baidu.com" }) ); assert_eq!(plan.steps[1].action, Action::Type); assert_eq!( plan.steps[1].params, json!({ "selector": "#kw", "text": "天气", "clear_first": true }) ); assert_eq!(plan.steps[2].action, Action::Click); assert_eq!(plan.steps[2].params, json!({ "selector": "#su" })); } #[test] fn planner_supports_baidu_search_variant_with_conjunction() { let plan = plan_instruction("打开百度并搜索电网调度").unwrap(); assert_eq!(plan.summary, "已在百度搜索电网调度"); assert_eq!(plan.steps[1].params["text"], "电网调度"); } #[test] fn planner_supports_zhihu_search_instruction_with_direct_search_url() { let plan = plan_instruction("打开知乎搜索天气").unwrap(); assert_eq!(plan.summary, "已在知乎搜索天气"); assert_eq!(plan.steps.len(), 1); assert_eq!(plan.steps[0].action, Action::Navigate); assert_eq!( plan.steps[0].params, json!({ "url": "https://www.zhihu.com/search?type=content&q=%E5%A4%A9%E6%B0%94" }) ); assert_eq!(plan.steps[0].expected_domain, "www.zhihu.com"); assert_eq!( plan.steps[0].log_message, "navigate https://www.zhihu.com/search?type=content&q=%E5%A4%A9%E6%B0%94" ); } #[test] fn planner_supports_open_zhihu_homepage_instruction() { let plan = plan_instruction("打开知乎").unwrap(); assert_eq!(plan.summary, "已打开知乎首页"); assert_eq!(plan.steps.len(), 1); assert_eq!(plan.steps[0].action, Action::Navigate); assert_eq!( plan.steps[0].params, json!({ "url": "https://www.zhihu.com" }) ); assert_eq!(plan.steps[0].expected_domain, "www.zhihu.com"); assert_eq!(plan.steps[0].log_message, "navigate https://www.zhihu.com"); } #[test] fn planner_supports_open_baidu_homepage_instruction() { let plan = plan_instruction("打开百度").unwrap(); assert_eq!(plan.summary, "已打开百度首页"); assert_eq!(plan.steps.len(), 1); assert_eq!(plan.steps[0].action, Action::Navigate); assert_eq!( plan.steps[0].params, json!({ "url": "https://www.baidu.com" }) ); assert_eq!(plan.steps[0].expected_domain, "www.baidu.com"); assert_eq!(plan.steps[0].log_message, "navigate https://www.baidu.com"); } #[test] fn planner_rejects_unrelated_instruction() { let err = plan_instruction("打开谷歌搜索天气").unwrap_err(); assert_eq!( err, PlannerError::UnsupportedInstruction("打开谷歌搜索天气".to_string()) ); } #[test] fn plan_first_mode_builds_visible_preview_for_zhihu_excel_flow() { let preview = build_execution_preview( PlannerMode::ZeroclawPlanFirst, "读取知乎热榜数据,并导出 excel 文件", Some("https://www.zhihu.com/hot"), Some("知乎热榜"), ) .expect("expected plan preview"); assert_eq!(preview.summary, "先规划再执行知乎热榜 Excel 导出"); assert!(preview .steps .iter() .any(|step| step.contains("navigate https://www.zhihu.com/hot"))); assert!(preview.steps.iter().any(|step| step.contains("getText main"))); assert!(preview .steps .iter() .any(|step| step.contains("call openxml_office"))); } #[test] fn legacy_planner_mode_skips_runtime_preview() { let preview = build_execution_preview( PlannerMode::LegacyDeterministic, "打开百度搜索天气", None, None, ); assert!(preview.is_none()); }