feat: add generated scene skill platform hardening
This commit is contained in:
@@ -8,14 +8,13 @@ use std::sync::{Arc, Mutex, OnceLock};
|
||||
use std::thread;
|
||||
use std::time::Duration;
|
||||
|
||||
use chrono::{Datelike, Local};
|
||||
use common::MockTransport;
|
||||
use serde_json::{json, Value};
|
||||
use sgclaw::agent::{
|
||||
handle_browser_message, handle_browser_message_with_context, AgentRuntimeContext,
|
||||
};
|
||||
use sgclaw::compat::workflow_executor::finalize_screen_export;
|
||||
use sgclaw::compat::runtime::{execute_task, execute_task_with_sgclaw_settings, CompatTaskContext};
|
||||
use sgclaw::compat::workflow_executor::finalize_screen_export;
|
||||
use sgclaw::config::{DeepSeekSettings, SgClawSettings};
|
||||
use sgclaw::pipe::{
|
||||
Action, AgentMessage, BrowserMessage, BrowserPipeTool, ConversationMessage, Timing,
|
||||
@@ -268,7 +267,9 @@ fn task_complete_summary(sent: &[AgentMessage]) -> String {
|
||||
AgentMessage::TaskComplete { success, summary } if *success => Some(summary.clone()),
|
||||
_ => None,
|
||||
})
|
||||
.unwrap_or_else(|| panic!("expected successful task completion, sent messages were: {sent:?}"))
|
||||
.unwrap_or_else(|| {
|
||||
panic!("expected successful task completion, sent messages were: {sent:?}")
|
||||
})
|
||||
}
|
||||
|
||||
fn extract_generated_artifact_path(summary: &str, extension: &str) -> PathBuf {
|
||||
@@ -279,24 +280,6 @@ fn extract_generated_artifact_path(summary: &str, extension: &str) -> PathBuf {
|
||||
.expect("expected artifact path in task summary")
|
||||
}
|
||||
|
||||
fn expected_default_month() -> String {
|
||||
let today = Local::now().date_naive();
|
||||
let (year, month) = if today.month() == 1 {
|
||||
(today.year() - 1, 12)
|
||||
} else {
|
||||
(today.year(), today.month() - 1)
|
||||
};
|
||||
format!("{year}-{month:02}")
|
||||
}
|
||||
|
||||
fn expected_default_week_range() -> (String, String, String) {
|
||||
let today = Local::now().date_naive();
|
||||
let month_start = today.with_day(1).expect("current month should have day 1");
|
||||
let start = month_start.format("%Y-%m-%d").to_string();
|
||||
let end = today.format("%Y-%m-%d").to_string();
|
||||
(format!("{start}至{end}"), start, end)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn compat_runtime_uses_zeroclaw_provider_path_and_executes_browser_actions() {
|
||||
let _guard = env_lock().lock().unwrap_or_else(|err| err.into_inner());
|
||||
@@ -2217,7 +2200,9 @@ fn handle_browser_message_chains_hotlist_skill_into_xlsx_export_and_auto_open()
|
||||
let summary = task_complete_summary(&sent);
|
||||
let generated = extract_generated_artifact_path(&summary, ".xlsx");
|
||||
|
||||
assert!(summary.contains("已导出知乎热榜 Excel") || summary.contains("已导出并打开知乎热榜 Excel"));
|
||||
assert!(
|
||||
summary.contains("已导出知乎热榜 Excel") || summary.contains("已导出并打开知乎热榜 Excel")
|
||||
);
|
||||
assert!(summary.contains(".xlsx"));
|
||||
assert!(generated.exists());
|
||||
assert!(sent.iter().any(|message| {
|
||||
@@ -2333,7 +2318,10 @@ fn handle_browser_message_chains_hotlist_skill_into_screen_export_and_auto_open(
|
||||
security,
|
||||
..
|
||||
} if action == &Action::Navigate
|
||||
&& security.expected_domain == "__sgclaw_local_dashboard__" => Some((params, security)),
|
||||
&& security.expected_domain == "__sgclaw_local_dashboard__" =>
|
||||
{
|
||||
Some((params, security))
|
||||
}
|
||||
_ => None,
|
||||
})
|
||||
.expect("dashboard route should emit local-dashboard navigate request");
|
||||
@@ -2405,7 +2393,8 @@ fn handle_browser_message_chains_hotlist_skill_into_screen_export_and_auto_open(
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn handle_browser_message_reports_dashboard_auto_open_protocol_error_when_presentation_url_is_missing() {
|
||||
fn handle_browser_message_reports_dashboard_auto_open_protocol_error_when_presentation_url_is_missing(
|
||||
) {
|
||||
let _guard = env_lock().lock().unwrap_or_else(|err| err.into_inner());
|
||||
|
||||
let transport = Arc::new(MockTransport::new(vec![]));
|
||||
@@ -2437,7 +2426,8 @@ fn handle_browser_message_reports_dashboard_auto_open_protocol_error_when_presen
|
||||
|
||||
assert!(summary.contains("已生成知乎热榜大屏"));
|
||||
assert!(summary.contains(output_path.to_string_lossy().as_ref()));
|
||||
assert!(summary.contains("但浏览器自动打开失败:screen_html_export did not return presentation.url"));
|
||||
assert!(summary
|
||||
.contains("但浏览器自动打开失败:screen_html_export did not return presentation.url"));
|
||||
|
||||
let sent = transport.sent_messages();
|
||||
assert!(!sent.iter().any(|message| {
|
||||
@@ -2710,11 +2700,13 @@ fn ws_cleanup_no_longer_detects_fault_details_scene_route() {
|
||||
|
||||
#[test]
|
||||
fn ws_cleanup_scene_keywords_do_not_trigger_primary_orchestration() {
|
||||
assert!(!sgclaw::compat::orchestration::should_use_primary_orchestration(
|
||||
"请处理95598抢修市指监测",
|
||||
Some("https://95598.example.invalid/dispatch"),
|
||||
Some("95598抢修市指监测"),
|
||||
));
|
||||
assert!(
|
||||
!sgclaw::compat::orchestration::should_use_primary_orchestration(
|
||||
"请处理95598抢修市指监测",
|
||||
Some("https://95598.example.invalid/dispatch"),
|
||||
Some("95598抢修市指监测"),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -3916,7 +3908,7 @@ fn handle_browser_message_executes_real_zhihu_write_skill_flow() {
|
||||
}
|
||||
|
||||
fn staged_lineloss_skills_root() -> PathBuf {
|
||||
PathBuf::from("D:/data/ideaSpace/rust/sgClaw/claw/claw/skills/skill_staging/skills")
|
||||
PathBuf::from("D:/data/ideaSpace/rust/sgClaw/claw-new/examples/generated_scene_platform/skills")
|
||||
}
|
||||
|
||||
fn build_fault_details_direct_skill_root() -> PathBuf {
|
||||
@@ -4033,9 +4025,10 @@ fn deterministic_lineloss_runtime_passes_canonical_args_to_browser_script_tool()
|
||||
AgentMessage::TaskComplete { success, summary }
|
||||
if *success
|
||||
&& summary.contains("tq-lineloss-report")
|
||||
&& summary.contains("国网兰州供电公司")
|
||||
&& summary.contains("2026-03")
|
||||
&& summary.contains("rows=1")
|
||||
&& summary.contains("status=ok")
|
||||
&& summary.contains("detail_rows=1")
|
||||
&& summary.contains("summary_rows=0")
|
||||
)
|
||||
}));
|
||||
assert!(sent.iter().any(|message| {
|
||||
@@ -4064,7 +4057,6 @@ fn deterministic_lineloss_runtime_passes_canonical_args_to_browser_script_tool()
|
||||
#[test]
|
||||
fn deterministic_lineloss_runtime_defaults_missing_month_period_to_page_semantics() {
|
||||
let _guard = env_lock().lock().unwrap_or_else(|err| err.into_inner());
|
||||
let expected_month = expected_default_month();
|
||||
|
||||
let workspace_root = temp_workspace_root();
|
||||
let config_path = write_deepseek_config_with_skills_dir(
|
||||
@@ -4076,35 +4068,7 @@ fn deterministic_lineloss_runtime_defaults_missing_month_period_to_page_semantic
|
||||
);
|
||||
let runtime_context = AgentRuntimeContext::new(Some(config_path), workspace_root.clone());
|
||||
|
||||
let transport = Arc::new(MockTransport::new(vec![success_browser_response(
|
||||
1,
|
||||
json!({
|
||||
"text": {
|
||||
"type": "report-artifact",
|
||||
"report_name": "tq-lineloss-report",
|
||||
"status": "ok",
|
||||
"org": {
|
||||
"label": "国网兰州供电公司",
|
||||
"code": "62401"
|
||||
},
|
||||
"period": {
|
||||
"mode": "month",
|
||||
"mode_code": "1",
|
||||
"value": expected_month,
|
||||
"payload": {
|
||||
"fdate": expected_default_month()
|
||||
}
|
||||
},
|
||||
"rows": [
|
||||
{ "ORG_NAME": "国网兰州供电公司", "LINE_LOSS_RATE": "3.21" }
|
||||
],
|
||||
"counts": {
|
||||
"rows": 1
|
||||
},
|
||||
"reasons": []
|
||||
}
|
||||
}),
|
||||
)]));
|
||||
let transport = Arc::new(MockTransport::new(vec![]));
|
||||
let browser_tool = BrowserPipeTool::new(
|
||||
transport.clone(),
|
||||
policy_for_domains(&["20.76.57.61"]),
|
||||
@@ -4132,39 +4096,18 @@ fn deterministic_lineloss_runtime_defaults_missing_month_period_to_page_semantic
|
||||
matches!(
|
||||
message,
|
||||
AgentMessage::TaskComplete { success, summary }
|
||||
if *success
|
||||
&& summary.contains("tq-lineloss-report")
|
||||
&& summary.contains("国网兰州供电公司")
|
||||
&& summary.contains(&expected_default_month())
|
||||
&& summary.contains("rows=1")
|
||||
)
|
||||
}));
|
||||
assert!(sent.iter().any(|message| {
|
||||
matches!(
|
||||
message,
|
||||
AgentMessage::Command {
|
||||
action,
|
||||
params,
|
||||
security,
|
||||
..
|
||||
}
|
||||
if action == &Action::Eval
|
||||
&& security.expected_domain == "20.76.57.61"
|
||||
&& params["script"].as_str().is_some_and(|script|
|
||||
script.contains("\"period_mode\":\"month\"")
|
||||
&& script.contains("\"period_mode_code\":\"1\"")
|
||||
&& script.contains(&format!("\"period_value\":\"{}\"", expected_default_month()))
|
||||
&& script.contains("\"period_payload\":\"{")
|
||||
&& script.contains(&format!("\\\"fdate\\\":\\\"{}\\\"", expected_default_month()))
|
||||
)
|
||||
if !*success
|
||||
&& summary.contains("已命中台区线损报表技能,但缺少统计周期,请补充如“2026-03”或“2026年第12周”。")
|
||||
)
|
||||
}), "sent messages were: {sent:?}");
|
||||
assert!(!sent
|
||||
.iter()
|
||||
.any(|message| matches!(message, AgentMessage::Command { .. })));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn deterministic_lineloss_runtime_defaults_missing_week_period_to_page_semantics() {
|
||||
let _guard = env_lock().lock().unwrap_or_else(|err| err.into_inner());
|
||||
let (expected_value, expected_start, expected_end) = expected_default_week_range();
|
||||
|
||||
let workspace_root = temp_workspace_root();
|
||||
let config_path = write_deepseek_config_with_skills_dir(
|
||||
@@ -4176,38 +4119,7 @@ fn deterministic_lineloss_runtime_defaults_missing_week_period_to_page_semantics
|
||||
);
|
||||
let runtime_context = AgentRuntimeContext::new(Some(config_path), workspace_root.clone());
|
||||
|
||||
let transport = Arc::new(MockTransport::new(vec![success_browser_response(
|
||||
1,
|
||||
json!({
|
||||
"text": {
|
||||
"type": "report-artifact",
|
||||
"report_name": "tq-lineloss-report",
|
||||
"status": "ok",
|
||||
"org": {
|
||||
"label": "国网兰州供电公司",
|
||||
"code": "62401"
|
||||
},
|
||||
"period": {
|
||||
"mode": "week",
|
||||
"mode_code": "2",
|
||||
"value": expected_value,
|
||||
"payload": {
|
||||
"tjzq": "week",
|
||||
"level": "00",
|
||||
"weekSfdate": expected_start,
|
||||
"weekEfdate": expected_end
|
||||
}
|
||||
},
|
||||
"rows": [
|
||||
{ "ORG_NAME3": "国网兰州供电公司", "LINELOSS_RATE": "3.21" }
|
||||
],
|
||||
"counts": {
|
||||
"rows": 1
|
||||
},
|
||||
"reasons": []
|
||||
}
|
||||
}),
|
||||
)]));
|
||||
let transport = Arc::new(MockTransport::new(vec![]));
|
||||
let browser_tool = BrowserPipeTool::new(
|
||||
transport.clone(),
|
||||
policy_for_domains(&["20.76.57.61"]),
|
||||
@@ -4235,34 +4147,13 @@ fn deterministic_lineloss_runtime_defaults_missing_week_period_to_page_semantics
|
||||
matches!(
|
||||
message,
|
||||
AgentMessage::TaskComplete { success, summary }
|
||||
if *success
|
||||
&& summary.contains("tq-lineloss-report")
|
||||
&& summary.contains("国网兰州供电公司")
|
||||
&& summary.contains(&expected_value)
|
||||
&& summary.contains("rows=1")
|
||||
)
|
||||
}));
|
||||
assert!(sent.iter().any(|message| {
|
||||
matches!(
|
||||
message,
|
||||
AgentMessage::Command {
|
||||
action,
|
||||
params,
|
||||
security,
|
||||
..
|
||||
}
|
||||
if action == &Action::Eval
|
||||
&& security.expected_domain == "20.76.57.61"
|
||||
&& params["script"].as_str().is_some_and(|script|
|
||||
script.contains("\"period_mode\":\"week\"")
|
||||
&& script.contains("\"period_mode_code\":\"2\"")
|
||||
&& script.contains(&format!("\"period_value\":\"{}\"", expected_value))
|
||||
&& script.contains("\"period_payload\":\"{")
|
||||
&& script.contains(&format!("\\\"weekSfdate\\\":\\\"{}\\\"", expected_start))
|
||||
&& script.contains(&format!("\\\"weekEfdate\\\":\\\"{}\\\"", expected_end))
|
||||
)
|
||||
if !*success
|
||||
&& summary.contains("已命中台区线损报表技能,但缺少统计周期,请补充如“2026-03”或“2026年第12周”。")
|
||||
)
|
||||
}), "sent messages were: {sent:?}");
|
||||
assert!(!sent
|
||||
.iter()
|
||||
.any(|message| matches!(message, AgentMessage::Command { .. })));
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -4307,10 +4198,13 @@ fn deterministic_lineloss_missing_company_prompt_skips_browser_execution() {
|
||||
matches!(
|
||||
message,
|
||||
AgentMessage::TaskComplete { success, summary }
|
||||
if !*success && (summary.contains("缺少供电单位") || summary.contains("兰州公司"))
|
||||
if !*success
|
||||
&& summary.contains("已命中台区线损报表技能,但缺少供电单位。")
|
||||
)
|
||||
}));
|
||||
assert!(!sent.iter().any(|message| matches!(message, AgentMessage::Command { .. })));
|
||||
assert!(!sent
|
||||
.iter()
|
||||
.any(|message| matches!(message, AgentMessage::Command { .. })));
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -4385,7 +4279,8 @@ fn deterministic_lineloss_runtime_maps_partial_artifact_to_success_summary() {
|
||||
AgentMessage::TaskComplete { success, summary }
|
||||
if *success
|
||||
&& summary.contains("status=partial")
|
||||
&& summary.contains("rows=1")
|
||||
&& summary.contains("detail_rows=1")
|
||||
&& summary.contains("summary_rows=0")
|
||||
&& summary.contains("reasons=report_log_failed")
|
||||
)
|
||||
}));
|
||||
@@ -4508,10 +4403,13 @@ fn deterministic_suffix_non_lineloss_request_does_not_fall_into_zhihu_logic() {
|
||||
matches!(
|
||||
message,
|
||||
AgentMessage::TaskComplete { success, summary }
|
||||
if !*success && summary.contains("台区线损")
|
||||
if !*success
|
||||
&& summary.contains("确定性提交当前只支持已注册的报表采集场景")
|
||||
)
|
||||
}));
|
||||
assert!(!sent.iter().any(|message| matches!(message, AgentMessage::Command { .. })));
|
||||
assert!(!sent
|
||||
.iter()
|
||||
.any(|message| matches!(message, AgentMessage::Command { .. })));
|
||||
assert!(!sent.iter().any(|message| {
|
||||
matches!(
|
||||
message,
|
||||
|
||||
Reference in New Issue
Block a user