Files
claw/tests/runtime_profile_test.rs
木炎 b454fa3f54 refactor: remove ws-only scene routing remnants
Keep the ws branch focused on websocket and Zhihu behavior by dropping staged scene-routing artifacts and restoring single-path skills dir semantics.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-10 22:35:43 +08:00

186 lines
6.4 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
use std::fs;
use std::path::PathBuf;
use sgclaw::compat::config_adapter::{
build_zeroclaw_config_from_sgclaw_settings, resolve_skills_dir_from_sgclaw_settings,
};
use sgclaw::config::{BrowserBackend, OfficeBackend, PlannerMode, SgClawSettings};
use sgclaw::runtime::{RuntimeEngine, RuntimeProfile, ToolPolicy};
use uuid::Uuid;
fn temp_skill_root() -> PathBuf {
let root = std::env::temp_dir().join(format!(
"sgclaw-runtime-profile-skills-{}",
Uuid::new_v4()
));
fs::create_dir_all(root.join("skills")).unwrap();
root
}
fn write_browser_script_skill(skill_root: &std::path::Path, skill_name: &str) {
let skill_dir = skill_root.join("skills").join(skill_name);
fs::create_dir_all(&skill_dir).unwrap();
fs::write(
skill_dir.join("SKILL.toml"),
format!(
r#"
[skill]
name = "{skill_name}"
description = "Browser-only test skill."
version = "0.1.0"
[[tools]]
name = "run"
description = "Run browser-only script."
kind = "browser_script"
command = "scripts/run.js"
"#
),
)
.unwrap();
fs::create_dir_all(skill_dir.join("scripts")).unwrap();
fs::write(skill_dir.join("scripts/run.js"), "return { ok: true };\n").unwrap();
}
#[test]
fn loaded_skills_excludes_browser_script_tools_when_browser_surface_is_unavailable() {
let workspace_root = std::env::temp_dir().join(format!(
"sgclaw-runtime-profile-workspace-{}",
Uuid::new_v4()
));
fs::create_dir_all(&workspace_root).unwrap();
let skill_root = temp_skill_root();
write_browser_script_skill(&skill_root, "workspace-browser-skill");
let mut settings = SgClawSettings::from_legacy_deepseek_fields(
"sk-test".to_string(),
"https://api.deepseek.com".to_string(),
"deepseek-chat".to_string(),
Some(skill_root.clone()),
)
.unwrap();
settings.runtime_profile = RuntimeProfile::GeneralAssistant;
let config = build_zeroclaw_config_from_sgclaw_settings(&workspace_root, &settings);
let skills_dir = resolve_skills_dir_from_sgclaw_settings(&workspace_root, &settings);
let engine = RuntimeEngine::new(RuntimeProfile::GeneralAssistant);
let loaded_skills = engine.loaded_skills(&config, std::slice::from_ref(&skills_dir));
assert!(loaded_skills.is_empty());
}
#[test]
fn browser_attached_profile_exposes_browser_surface_without_becoming_browser_only() {
let profile = RuntimeProfile::BrowserAttached;
let policy = ToolPolicy::for_profile(profile);
assert!(policy.allowed_tools.contains(&"browser_action".to_string()));
assert!(policy
.allowed_tools
.contains(&"superrpa_browser".to_string()));
assert!(policy.may_use_non_browser_tools);
}
#[test]
fn general_assistant_profile_does_not_require_browser_surface() {
let profile = RuntimeProfile::GeneralAssistant;
let policy = ToolPolicy::for_profile(profile);
assert!(!policy.requires_browser_surface);
}
#[test]
fn browser_attached_export_prompt_requires_openxml_completion() {
let engine = RuntimeEngine::new(RuntimeProfile::BrowserAttached);
let instruction = engine.build_instruction(
"读取知乎热榜数据,并导出 excel 文件",
Some("https://www.zhihu.com/hot"),
Some("知乎热榜"),
true,
);
assert!(instruction.contains("must call openxml_office"));
assert!(instruction.contains("Do not stop after describing how you will parse"));
assert!(instruction.contains("Never fabricate, simulate, or invent substitute hotlist data"));
assert!(instruction.contains("Do not repeat the same sentence or section"));
assert!(instruction.contains("final answer must include the generated local .xlsx path"));
}
#[test]
fn browser_attached_publish_prompt_requires_explicit_confirmation_before_clicking_publish() {
let engine = RuntimeEngine::new(RuntimeProfile::BrowserAttached);
let instruction = engine.build_instruction(
"请直接发表这篇知乎文章,标题是测试标题,正文是第一段内容",
Some("https://www.zhihu.com/creator"),
Some("知乎创作中心"),
true,
);
assert!(instruction.contains("publish a Zhihu article"));
assert!(instruction.contains("must not click publish without explicit human confirmation"));
assert!(instruction.contains("ask for confirmation concisely"));
assert!(instruction.contains("stop after the confirmation request"));
}
#[test]
fn ws_cleanup_browser_profile_does_not_inject_95598_scene_contract() {
let engine = RuntimeEngine::new(RuntimeProfile::BrowserAttached);
let instruction = engine.build_instruction(
"请处理95598抢修市指监测查看抢修市指派单并汇总当前队列",
Some("https://95598.example.invalid/dispatch"),
Some("95598抢修市指监测"),
true,
);
assert!(!instruction.contains("collect_repair_orders"));
}
#[test]
fn browser_attached_unrelated_task_does_not_receive_95598_scene_contract() {
let engine = RuntimeEngine::new(RuntimeProfile::BrowserAttached);
let instruction = engine.build_instruction(
"帮我总结今天的会议纪要",
None,
None,
true,
);
assert!(!instruction.contains("collect_repair_orders"));
assert!(!instruction.contains("browser workflow, not a text-only task"));
assert!(!instruction.contains("generic browser probing only after"));
}
#[test]
fn general_assistant_95598_scene_prompt_does_not_receive_browser_scene_contract() {
let engine = RuntimeEngine::new(RuntimeProfile::GeneralAssistant);
let instruction = engine.build_instruction(
"请处理95598抢修市指监测查看抢修市指派单并汇总当前队列",
Some("https://95598.example.invalid/dispatch"),
Some("95598抢修市指监测"),
false,
);
assert!(!instruction.contains("collect_repair_orders"));
assert!(!instruction.contains("browser workflow, not a text-only task"));
assert!(!instruction.contains("generic browser probing only after"));
}
#[test]
fn legacy_settings_default_to_plan_first_superrpa_and_openxml_backends() {
let settings = SgClawSettings::from_legacy_deepseek_fields(
"sk-test".to_string(),
"https://api.deepseek.com".to_string(),
"deepseek-chat".to_string(),
None,
)
.unwrap();
assert_eq!(settings.planner_mode, PlannerMode::ZeroclawPlanFirst);
assert_eq!(settings.browser_backend, BrowserBackend::SuperRpa);
assert_eq!(settings.office_backend, OfficeBackend::OpenXml);
}