diff --git a/src/agent/task_runner.rs b/src/agent/task_runner.rs index 3912132..eae5cbc 100644 --- a/src/agent/task_runner.rs +++ b/src/agent/task_runner.rs @@ -253,6 +253,36 @@ pub fn run_submit_task( }; return sink.send(&completion); } + if RuntimeEngine::new(settings.runtime_profile).browser_surface_enabled() + && crate::compat::orchestration::should_use_primary_orchestration( + &instruction, + task_context.page_url.as_deref(), + task_context.page_title.as_deref(), + ) + { + let _ = send_mode_log(sink, "zeroclaw_process_message_primary"); + match crate::compat::orchestration::execute_task_with_sgclaw_settings( + transport, + browser_tool.clone(), + &instruction, + &task_context, + &context.workspace_root, + &settings, + ) { + Ok(summary) => { + return sink.send(&AgentMessage::TaskComplete { + success: true, + summary, + }); + } + Err(err) => { + return sink.send(&AgentMessage::TaskComplete { + success: false, + summary: err.to_string(), + }); + } + } + } if settings .direct_submit_skill .as_deref() @@ -289,36 +319,6 @@ pub fn run_submit_task( } } } - if RuntimeEngine::new(settings.runtime_profile).browser_surface_enabled() - && crate::compat::orchestration::should_use_primary_orchestration( - &instruction, - task_context.page_url.as_deref(), - task_context.page_title.as_deref(), - ) - { - let _ = send_mode_log(sink, "zeroclaw_process_message_primary"); - match crate::compat::orchestration::execute_task_with_sgclaw_settings( - transport, - browser_tool.clone(), - &instruction, - &task_context, - &context.workspace_root, - &settings, - ) { - Ok(summary) => { - return sink.send(&AgentMessage::TaskComplete { - success: true, - summary, - }); - } - Err(err) => { - return sink.send(&AgentMessage::TaskComplete { - success: false, - summary: err.to_string(), - }); - } - } - } let _ = send_mode_log(sink, "compat_llm_primary"); match crate::compat::runtime::execute_task_with_sgclaw_settings( transport, @@ -443,6 +443,36 @@ pub fn run_submit_task_with_browser_backend( }; return sink.send(&completion); } + if RuntimeEngine::new(settings.runtime_profile).browser_surface_enabled() + && crate::compat::orchestration::should_use_primary_orchestration( + &instruction, + task_context.page_url.as_deref(), + task_context.page_title.as_deref(), + ) + { + let _ = send_mode_log(sink, "zeroclaw_process_message_primary"); + match crate::compat::orchestration::execute_task_with_browser_backend( + sink, + browser_backend.clone(), + &instruction, + &task_context, + &context.workspace_root, + &settings, + ) { + Ok(summary) => { + return sink.send(&AgentMessage::TaskComplete { + success: true, + summary, + }); + } + Err(err) => { + return sink.send(&AgentMessage::TaskComplete { + success: false, + summary: err.to_string(), + }); + } + } + } if settings .direct_submit_skill .as_deref() @@ -479,36 +509,6 @@ pub fn run_submit_task_with_browser_backend( } } } - if RuntimeEngine::new(settings.runtime_profile).browser_surface_enabled() - && crate::compat::orchestration::should_use_primary_orchestration( - &instruction, - task_context.page_url.as_deref(), - task_context.page_title.as_deref(), - ) - { - let _ = send_mode_log(sink, "zeroclaw_process_message_primary"); - match crate::compat::orchestration::execute_task_with_browser_backend( - sink, - browser_backend.clone(), - &instruction, - &task_context, - &context.workspace_root, - &settings, - ) { - Ok(summary) => { - return sink.send(&AgentMessage::TaskComplete { - success: true, - summary, - }); - } - Err(err) => { - return sink.send(&AgentMessage::TaskComplete { - success: false, - summary: err.to_string(), - }); - } - } - } let _ = send_mode_log(sink, "compat_llm_primary"); match crate::compat::runtime::execute_task_with_browser_backend( sink, diff --git a/tests/agent_runtime_test.rs b/tests/agent_runtime_test.rs index 9c6f0cd..ea2c111 100644 --- a/tests/agent_runtime_test.rs +++ b/tests/agent_runtime_test.rs @@ -38,6 +38,7 @@ fn write_config( model: &str, skills_dir: Option<&str>, browser_ws_url: Option<&str>, + direct_submit_skill: Option<&str>, ) -> PathBuf { let config_path = root.join("sgclaw_config.json"); let mut payload = json!({ @@ -52,6 +53,9 @@ fn write_config( if let Some(browser_ws_url) = browser_ws_url { payload["browserWsUrl"] = json!(browser_ws_url); } + if let Some(direct_submit_skill) = direct_submit_skill { + payload["directSubmitSkill"] = json!(direct_submit_skill); + } fs::write(&config_path, serde_json::to_string_pretty(&payload).unwrap()).unwrap(); config_path } @@ -726,6 +730,76 @@ fn direct_skill_mode_logs_direct_skill_primary() { ); } +#[test] +fn production_submit_task_with_ws_and_direct_submit_config_routes_zhihu_before_direct_submit() { + let _guard = env_lock().lock().unwrap_or_else(|err| err.into_inner()); + std::env::set_var("SGCLAW_DISABLE_POST_EXPORT_OPEN", "1"); + std::env::remove_var("DEEPSEEK_API_KEY"); + std::env::remove_var("DEEPSEEK_BASE_URL"); + std::env::remove_var("DEEPSEEK_MODEL"); + + let workspace_root = temp_workspace_root(); + let (ws_url, _frames, ws_handle) = start_browser_ws_server(); + let config_path = write_config( + &workspace_root, + "deepseek-test-key", + "http://127.0.0.1:9", + "deepseek-chat", + Some(real_skill_lib_root().to_str().unwrap()), + Some(&ws_url), + Some("fault-details-report.collect_fault_details"), + ); + + let transport = Arc::new(MockTransport::new(vec![])); + let browser_tool = BrowserPipeTool::new( + transport.clone(), + test_policy(), + vec![1, 2, 3, 4, 5, 6, 7, 8], + ) + .with_response_timeout(Duration::from_secs(1)); + let runtime_context = AgentRuntimeContext::new(Some(config_path), workspace_root); + + handle_browser_message_with_context( + transport.as_ref(), + &browser_tool, + &runtime_context, + BrowserMessage::SubmitTask { + instruction: "打开知乎热榜,获取前10条数据,并导出 Excel".to_string(), + conversation_id: String::new(), + messages: vec![], + page_url: String::new(), + page_title: String::new(), + }, + ) + .unwrap(); + + ws_handle.join().unwrap(); + + let sent = transport.sent_messages(); + let mode_logs = direct_submit_mode_logs(&sent); + let completion = direct_submit_completion(&sent).expect("task completion"); + + assert!( + mode_logs + .iter() + .any(|mode| mode == "zeroclaw_process_message_primary"), + "expected orchestration mode log before direct submit: {sent:?}" + ); + assert!( + !mode_logs.iter().any(|mode| mode == "direct_skill_primary"), + "unexpected direct submit mode log for zhihu ws submit: {sent:?}" + ); + assert!(completion.0, "expected zhihu ws submit to succeed: {sent:?}"); + assert!( + !completion + .1 + .contains("direct submit skill requires page_url so expected_domain can be derived"), + "unexpected direct-submit page_url failure: {sent:?}" + ); + + std::env::remove_var("SGCLAW_DISABLE_POST_EXPORT_OPEN"); +} + #[test] fn production_submit_task_routes_zhihu_through_ws_backend_without_helper_bootstrap() { let _guard = env_lock().lock().unwrap_or_else(|err| err.into_inner()); @@ -744,6 +818,7 @@ fn production_submit_task_routes_zhihu_through_ws_backend_without_helper_bootstr "deepseek-chat", Some(real_skill_lib_root().to_str().unwrap()), Some(&ws_url), + None, ); let transport = Arc::new(MockTransport::new(vec![]));