mod common;

use std::fs;
use std::io::{Read, Write};
use std::net::TcpListener;
use std::path::PathBuf;
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::config::{DeepSeekSettings, SgClawSettings};
use sgclaw::pipe::{
    Action, AgentMessage, BrowserMessage, BrowserPipeTool, ConversationMessage, Timing,
};
use sgclaw::runtime::RuntimeProfile;
use sgclaw::security::MacPolicy;
use uuid::Uuid;

fn env_lock() -> &'static Mutex<()> {
    static LOCK: OnceLock<Mutex<()>> = OnceLock::new();
    LOCK.get_or_init(|| Mutex::new(()))
}

fn test_policy() -> MacPolicy {
    policy_for_domains(&["www.baidu.com"])
}

fn zhihu_test_policy() -> MacPolicy {
    policy_for_domains(&["www.zhihu.com", "zhuanlan.zhihu.com"])
}

fn policy_for_domains(domains: &[&str]) -> MacPolicy {
    MacPolicy::from_json_str(
        &json!({
            "version": "1.0",
            "domains": { "allowed": domains },
            "pipe_actions": {
                "allowed": ["click", "type", "navigate", "getText", "waitForSelector", "eval"],
                "blocked": []
            }
        })
        .to_string(),
    )
    .unwrap()
}

fn temp_workspace_root() -> PathBuf {
    let root = std::env::temp_dir().join(format!("sgclaw-compat-runtime-{}", Uuid::new_v4()));
    std::fs::create_dir_all(&root).unwrap();
    root
}

fn write_deepseek_config(root: &PathBuf, api_key: &str, base_url: &str, model: &str) -> PathBuf {
    write_deepseek_config_with_skills_dir(root, api_key, base_url, model, None)
}

fn write_deepseek_config_with_direct_submit_skill(
    root: &PathBuf,
    api_key: &str,
    base_url: &str,
    model: &str,
    skills_dir: Option<&str>,
    direct_submit_skill: Option<&str>,
) -> PathBuf {
    let config_path = root.join("sgclaw_config.json");
    let mut payload = json!({
        "apiKey": api_key,
        "baseUrl": base_url,
        "model": model,
    });
    if let Some(skills_dir) = skills_dir {
        payload["skillsDir"] = json!(skills_dir);
    }
    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
}

fn write_deepseek_config_with_skills_dir(
    root: &PathBuf,
    api_key: &str,
    base_url: &str,
    model: &str,
    skills_dir: Option<&str>,
) -> PathBuf {
    write_deepseek_config_with_direct_submit_skill(root, api_key, base_url, model, skills_dir, None)
}

fn write_skill_package(skills_dir: &std::path::Path, skill_name: &str, body: &str) {
    let skill_dir = skills_dir.join(skill_name);
    fs::create_dir_all(&skill_dir).unwrap();
    fs::write(skill_dir.join("SKILL.md"), body).unwrap();
}

fn write_skill_manifest_package(
    skills_dir: &std::path::Path,
    skill_name: &str,
    manifest: &str,
) -> PathBuf {
    let skill_dir = skills_dir.join(skill_name);
    fs::create_dir_all(&skill_dir).unwrap();
    fs::write(skill_dir.join("SKILL.toml"), manifest).unwrap();
    skill_dir
}

fn write_skill_script(skill_dir: &std::path::Path, relative_path: &str, body: &str) {
    let script_path = skill_dir.join(relative_path);
    if let Some(parent) = script_path.parent() {
        fs::create_dir_all(parent).unwrap();
    }
    fs::write(script_path, body).unwrap();
}

fn real_skill_lib_root() -> PathBuf {
    let repo_parent = PathBuf::from(env!("CARGO_MANIFEST_DIR"))
        .parent()
        .unwrap()
        .to_path_buf();
    let hyphenated = repo_parent.join("skill-lib");
    if hyphenated.exists() {
        return hyphenated;
    }
    repo_parent.join("skill_lib")
}

fn success_browser_response(seq: u64, data: Value) -> BrowserMessage {
    BrowserMessage::Response {
        seq,
        success: true,
        data,
        aom_snapshot: vec![],
        timing: Timing {
            queue_ms: 1,
            exec_ms: 10,
        },
    }
}

fn request_tool_names(request: &Value) -> Vec<String> {
    request["tools"]
        .as_array()
        .cloned()
        .unwrap_or_default()
        .into_iter()
        .filter_map(|tool| tool["function"]["name"].as_str().map(str::to_string))
        .collect::<Vec<_>>()
}

fn tool_message_content<'a>(request: &'a Value, tool_call_id: &str) -> Option<&'a str> {
    request["messages"].as_array().and_then(|messages| {
        messages.iter().find_map(|message| {
            (message["role"].as_str() == Some("tool")
                && message["tool_call_id"].as_str() == Some(tool_call_id))
            .then(|| message["content"].as_str())
            .flatten()
        })
    })
}

fn start_fake_deepseek_server(
    responses: Vec<Value>,
) -> (String, Arc<Mutex<Vec<Value>>>, thread::JoinHandle<()>) {
    let listener = TcpListener::bind("127.0.0.1:0").unwrap();
    listener.set_nonblocking(true).unwrap();
    let address = format!("http://{}", listener.local_addr().unwrap());
    let requests = Arc::new(Mutex::new(Vec::new()));
    let request_log = requests.clone();

    let handle = thread::spawn(move || {
        for response in responses {
            let deadline = std::time::Instant::now() + Duration::from_secs(5);
            let (mut stream, _) = loop {
                match listener.accept() {
                    Ok(pair) => break pair,
                    Err(err) if err.kind() == std::io::ErrorKind::WouldBlock => {
                        assert!(
                            std::time::Instant::now() < deadline,
                            "timed out waiting for provider request"
                        );
                        thread::sleep(Duration::from_millis(10));
                    }
                    Err(err) => panic!("failed to accept provider request: {err}"),
                }
            };
            stream.set_nonblocking(false).unwrap();
            let body = read_http_json_body(&mut stream);
            request_log.lock().unwrap().push(body);

            let payload = response.to_string();
            let reply = format!(
                "HTTP/1.1 200 OK\r\nContent-Type: application/json\r\nContent-Length: {}\r\nConnection: close\r\n\r\n{}",
                payload.as_bytes().len(),
                payload
            );
            stream.write_all(reply.as_bytes()).unwrap();
            stream.flush().unwrap();
        }
    });

    (address, requests, handle)
}

fn read_http_json_body(stream: &mut impl Read) -> Value {
    let mut buffer = Vec::new();
    let mut headers_end = None;

    while headers_end.is_none() {
        let mut chunk = [0_u8; 1024];
        match stream.read(&mut chunk) {
            Ok(bytes) => {
                assert!(bytes > 0, "unexpected EOF while reading headers");
                buffer.extend_from_slice(&chunk[..bytes]);
                headers_end = buffer.windows(4).position(|window| window == b"\r\n\r\n");
            }
            Err(err) if err.kind() == std::io::ErrorKind::WouldBlock => {
                thread::sleep(Duration::from_millis(10));
            }
            Err(err) => panic!("failed while reading headers: {err}"),
        }
    }

    let headers_end = headers_end.unwrap() + 4;
    let headers = String::from_utf8(buffer[..headers_end].to_vec()).unwrap();
    let content_length = headers
        .lines()
        .find_map(|line| {
            let (name, value) = line.split_once(':')?;
            name.eq_ignore_ascii_case("content-length")
                .then(|| value.trim().parse::<usize>().unwrap())
        })
        .unwrap();

    while buffer.len() < headers_end + content_length {
        let mut chunk = vec![0_u8; content_length];
        match stream.read(&mut chunk) {
            Ok(bytes) => {
                assert!(bytes > 0, "unexpected EOF while reading body");
                buffer.extend_from_slice(&chunk[..bytes]);
            }
            Err(err) if err.kind() == std::io::ErrorKind::WouldBlock => {
                thread::sleep(Duration::from_millis(10));
            }
            Err(err) => panic!("failed while reading body: {err}"),
        }
    }

    serde_json::from_slice(&buffer[headers_end..headers_end + content_length]).unwrap()
}

fn task_complete_summary(sent: &[AgentMessage]) -> String {
    sent.iter()
        .find_map(|message| match message {
            AgentMessage::TaskComplete { success, summary } if *success => Some(summary.clone()),
            _ => None,
        })
        .unwrap_or_else(|| panic!("expected successful task completion, sent messages were: {sent:?}"))
}

fn extract_generated_artifact_path(summary: &str, extension: &str) -> PathBuf {
    summary
        .split_whitespace()
        .find(|token| token.ends_with(extension))
        .map(PathBuf::from)
        .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());

    let first_response = json!({
        "choices": [{
            "message": {
                "content": "",
                "tool_calls": [
                    {
                        "id": "call_1",
                        "type": "function",
                        "function": {
                            "name": "browser_action",
                            "arguments": serde_json::to_string(&json!({
                                "action": "navigate",
                                "expected_domain": "www.baidu.com",
                                "url": "https://www.baidu.com"
                            })).unwrap()
                        }
                    },
                    {
                        "id": "call_2",
                        "type": "function",
                        "function": {
                            "name": "browser_action",
                            "arguments": serde_json::to_string(&json!({
                                "action": "type",
                                "expected_domain": "www.baidu.com",
                                "selector": "#kw",
                                "text": "天气",
                                "clear_first": true
                            })).unwrap()
                        }
                    }
                ]
            }
        }],
        "usage": {
            "prompt_tokens": 12,
            "completion_tokens": 7
        }
    });
    let second_response = json!({
        "choices": [{
            "message": {
                "content": "已通过 ZeroClaw 执行任务: 打开百度搜索天气"
            }
        }],
        "usage": {
            "prompt_tokens": 15,
            "completion_tokens": 8
        }
    });
    let (base_url, requests, server_handle) =
        start_fake_deepseek_server(vec![first_response, second_response]);

    std::env::set_var("DEEPSEEK_API_KEY", "deepseek-test-key");
    std::env::set_var("DEEPSEEK_BASE_URL", base_url);
    std::env::set_var("DEEPSEEK_MODEL", "deepseek-chat");

    let workspace_root = temp_workspace_root();
    let settings = DeepSeekSettings::from_env().unwrap();
    let transport = Arc::new(MockTransport::new(vec![
        BrowserMessage::Response {
            seq: 1,
            success: true,
            data: json!({ "navigated": true }),
            aom_snapshot: vec![],
            timing: Timing {
                queue_ms: 1,
                exec_ms: 10,
            },
        },
        BrowserMessage::Response {
            seq: 2,
            success: true,
            data: json!({ "typed": true }),
            aom_snapshot: vec![],
            timing: Timing {
                queue_ms: 1,
                exec_ms: 11,
            },
        },
    ]));
    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 summary = execute_task(
        transport.as_ref(),
        browser_tool,
        "打开百度搜索天气",
        &CompatTaskContext::default(),
        &workspace_root,
        &settings,
    )
    .unwrap();
    server_handle.join().unwrap();

    let request_bodies = requests.lock().unwrap().clone();
    std::env::remove_var("DEEPSEEK_API_KEY");
    std::env::remove_var("DEEPSEEK_BASE_URL");
    std::env::remove_var("DEEPSEEK_MODEL");
    let sent = transport.sent_messages();

    assert_eq!(summary, "已通过 ZeroClaw 执行任务: 打开百度搜索天气");
    assert_eq!(request_bodies.len(), 2);
    assert_eq!(request_bodies[0]["model"], json!("deepseek-chat"));
    assert!(request_tool_names(&request_bodies[0]).contains(&"browser_action".to_string()));
    assert!(request_tool_names(&request_bodies[0]).contains(&"superrpa_browser".to_string()));
    assert!(request_bodies[1].to_string().contains("tool_call_id"));
    assert!(sent.iter().any(|message| {
        matches!(
            message,
            AgentMessage::LogEntry { level, message }
                if level == "info" && message == "navigate https://www.baidu.com"
        )
    }));
    assert!(sent.iter().any(|message| {
        matches!(
            message,
            AgentMessage::LogEntry { level, message }
                if level == "info" && message == "type 天气 into #kw"
        )
    }));
    assert!(sent.iter().any(|message| {
        matches!(
            message,
            AgentMessage::Command { action, .. } if action == &Action::Navigate
        )
    }));
    assert!(sent.iter().any(|message| {
        matches!(
            message,
            AgentMessage::Command { action, .. } if action == &Action::Type
        )
    }));
}

#[test]
fn compat_runtime_includes_default_workspace_skills_in_provider_request() {
    let _guard = env_lock().lock().unwrap_or_else(|err| err.into_inner());

    let response = json!({
        "choices": [{
            "message": {
                "content": "已识别默认 workspace skill"
            }
        }]
    });
    let (base_url, requests, server_handle) = start_fake_deepseek_server(vec![response]);

    let workspace_root = temp_workspace_root();
    let default_skills_dir = workspace_root
        .join(".sgclaw-zeroclaw-workspace")
        .join("skills");
    write_skill_package(
        &default_skills_dir,
        "workspace-zhihu-skill",
        "# Workspace Zhihu Skill\nUse this workspace-local skill.\n",
    );

    let settings = DeepSeekSettings {
        api_key: "deepseek-test-key".to_string(),
        base_url,
        model: "deepseek-chat".to_string(),
        skills_dir: None,
    };
    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 summary = execute_task(
        transport.as_ref(),
        browser_tool,
        "列出当前可用 skill",
        &CompatTaskContext::default(),
        &workspace_root,
        &settings,
    )
    .unwrap();
    server_handle.join().unwrap();

    let request_bodies = requests.lock().unwrap().clone();

    assert_eq!(summary, "已识别默认 workspace skill");
    assert_eq!(request_bodies.len(), 1);
    assert!(request_bodies[0]
        .to_string()
        .contains("workspace-zhihu-skill"));
}

#[test]
fn handle_browser_message_loads_skills_from_configured_skills_dir() {
    let _guard = env_lock().lock().unwrap_or_else(|err| err.into_inner());

    let response = json!({
        "choices": [{
            "message": {
                "content": "已识别自定义 skill 目录"
            }
        }]
    });
    let (base_url, requests, server_handle) = start_fake_deepseek_server(vec![response]);

    let workspace_root = temp_workspace_root();
    let default_skills_dir = workspace_root
        .join(".sgclaw-zeroclaw-workspace")
        .join("skills");
    write_skill_package(
        &default_skills_dir,
        "workspace-only-skill",
        "# Workspace Only Skill\nThis skill should be ignored when skillsDir is set.\n",
    );

    let custom_skill_repo = workspace_root.join("skill_lib");
    let custom_skills_dir = custom_skill_repo.join("skills");
    write_skill_package(
        &custom_skills_dir,
        "configured-zhihu-skill",
        "# Configured Zhihu Skill\nUse the configured skills directory.\n",
    );

    std::env::remove_var("DEEPSEEK_API_KEY");
    std::env::remove_var("DEEPSEEK_BASE_URL");
    std::env::remove_var("DEEPSEEK_MODEL");

    let config_path = write_deepseek_config_with_skills_dir(
        &workspace_root,
        "deepseek-test-key",
        &base_url,
        "deepseek-chat",
        Some("skill_lib"),
    );
    let runtime_context = AgentRuntimeContext::new(Some(config_path), workspace_root.clone());

    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));

    handle_browser_message_with_context(
        transport.as_ref(),
        &browser_tool,
        &runtime_context,
        BrowserMessage::SubmitTask {
            instruction: "告诉我当前有哪些 zhihu skill".to_string(),
            conversation_id: String::new(),
            messages: vec![],
            page_url: String::new(),
            page_title: String::new(),
        },
    )
    .unwrap();
    server_handle.join().unwrap();

    let sent = transport.sent_messages();
    let request_bodies = requests.lock().unwrap().clone();
    let first_request = request_bodies[0].to_string();

    assert!(sent.iter().any(|message| {
        matches!(
            message,
            AgentMessage::TaskComplete { success, summary }
                if *success && summary == "已识别自定义 skill 目录"
        )
    }));
    assert!(sent.iter().any(|message| {
        matches!(
            message,
            AgentMessage::LogEntry { level, message }
                if level == "info" &&
                    message.contains("loaded skills: configured-zhihu-skill@0.1.0")
        )
    }));
    assert_eq!(request_bodies.len(), 1);
    assert!(first_request.contains("configured-zhihu-skill"));
    assert!(!first_request.contains("workspace-only-skill"));
}

#[test]
fn handle_browser_message_routes_supported_instruction_to_compat_runtime_when_llm_is_configured() {
    let _guard = env_lock().lock().unwrap_or_else(|err| err.into_inner());

    let first_response = json!({
        "choices": [{
            "message": {
                "content": "",
                "tool_calls": [
                    {
                        "id": "call_1",
                        "type": "function",
                        "function": {
                            "name": "browser_action",
                            "arguments": serde_json::to_string(&json!({
                                "action": "navigate",
                                "expected_domain": "www.baidu.com",
                                "url": "https://www.baidu.com"
                            })).unwrap()
                        }
                    },
                    {
                        "id": "call_2",
                        "type": "function",
                        "function": {
                            "name": "browser_action",
                            "arguments": serde_json::to_string(&json!({
                                "action": "type",
                                "expected_domain": "www.baidu.com",
                                "selector": "#kw",
                                "text": "天气",
                                "clear_first": true
                            })).unwrap()
                        }
                    },
                    {
                        "id": "call_3",
                        "type": "function",
                        "function": {
                            "name": "browser_action",
                            "arguments": serde_json::to_string(&json!({
                                "action": "click",
                                "expected_domain": "www.baidu.com",
                                "selector": "#su"
                            })).unwrap()
                        }
                    }
                ]
            }
        }]
    });
    let second_response = json!({
        "choices": [{
            "message": {
                "content": "已在百度搜索天气"
            }
        }]
    });
    let (base_url, requests, server_handle) =
        start_fake_deepseek_server(vec![first_response, second_response]);

    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 config_path = write_deepseek_config(
        &workspace_root,
        "deepseek-test-key",
        &base_url,
        "deepseek-chat",
    );
    let runtime_context = AgentRuntimeContext::new(Some(config_path), workspace_root.clone());

    let transport = Arc::new(MockTransport::new(vec![
        BrowserMessage::Response {
            seq: 1,
            success: true,
            data: json!({ "navigated": true }),
            aom_snapshot: vec![],
            timing: Timing {
                queue_ms: 1,
                exec_ms: 10,
            },
        },
        BrowserMessage::Response {
            seq: 2,
            success: true,
            data: json!({ "typed": true }),
            aom_snapshot: vec![],
            timing: Timing {
                queue_ms: 1,
                exec_ms: 10,
            },
        },
        BrowserMessage::Response {
            seq: 3,
            success: true,
            data: json!({ "clicked": true }),
            aom_snapshot: vec![],
            timing: Timing {
                queue_ms: 1,
                exec_ms: 10,
            },
        },
    ]));
    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));

    handle_browser_message_with_context(
        transport.as_ref(),
        &browser_tool,
        &runtime_context,
        BrowserMessage::SubmitTask {
            instruction: "打开百度搜索天气".to_string(),
            conversation_id: String::new(),
            messages: vec![],
            page_url: String::new(),
            page_title: String::new(),
        },
    )
    .unwrap();
    server_handle.join().unwrap();

    let sent = transport.sent_messages();
    let request_bodies = requests.lock().unwrap().clone();

    assert!(sent.iter().any(|message| {
        matches!(
            message,
            AgentMessage::TaskComplete { success, summary }
                if *success && summary == "已在百度搜索天气"
        )
    }));
    assert!(sent.iter().any(|message| {
        matches!(
            message,
            AgentMessage::LogEntry { level, message }
                if level == "info"
                    && message.starts_with("sgclaw runtime version=")
                    && message.ends_with(" protocol=1.0")
        )
    }));
    assert!(sent.iter().any(|message| {
        matches!(
            message,
            AgentMessage::LogEntry { level, message }
                if level == "mode" && message == "compat_llm_primary"
        )
    }));
    assert!(!sent.iter().any(|message| {
        matches!(
            message,
            AgentMessage::LogEntry { level, message }
                if level == "mode" && message == "deterministic_planner"
        )
    }));
    assert_eq!(request_bodies.len(), 2);
}

#[test]
fn handle_browser_message_executes_without_legacy_plan_preview() {
    let _guard = env_lock().lock().unwrap_or_else(|err| err.into_inner());

    let first_response = json!({
        "choices": [{
            "message": {
                "content": "",
                "tool_calls": [{
                    "id": "call_1",
                    "type": "function",
                    "function": {
                        "name": "browser_action",
                        "arguments": serde_json::to_string(&json!({
                            "action": "navigate",
                            "expected_domain": "www.baidu.com",
                            "url": "https://www.baidu.com"
                        })).unwrap()
                    }
                }]
            }
        }]
    });
    let second_response = json!({
        "choices": [{
            "message": {
                "content": "已打开百度首页"
            }
        }]
    });
    let (base_url, _requests, server_handle) =
        start_fake_deepseek_server(vec![first_response, second_response]);

    let workspace_root = temp_workspace_root();
    let config_path = workspace_root.join("sgclaw_config.json");
    fs::write(
        &config_path,
        serde_json::to_string_pretty(&json!({
            "apiKey": "deepseek-test-key",
            "baseUrl": base_url,
            "model": "deepseek-chat",
            "plannerMode": "zeroclawPlanFirst"
        }))
        .unwrap(),
    )
    .unwrap();
    let runtime_context = AgentRuntimeContext::new(Some(config_path), workspace_root.clone());

    let transport = Arc::new(MockTransport::new(vec![success_browser_response(
        1,
        json!({ "navigated": true }),
    )]));
    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));

    handle_browser_message_with_context(
        transport.as_ref(),
        &browser_tool,
        &runtime_context,
        BrowserMessage::SubmitTask {
            instruction: "打开百度".to_string(),
            conversation_id: String::new(),
            messages: vec![],
            page_url: String::new(),
            page_title: String::new(),
        },
    )
    .unwrap();
    server_handle.join().unwrap();

    let sent = transport.sent_messages();

    assert!(!sent.iter().any(|message| {
        matches!(
            message,
            AgentMessage::LogEntry { level, message }
                if level == "plan" && message.contains("navigate https://www.baidu.com")
        )
    }));
    assert!(sent.iter().any(|message| {
        matches!(
            message,
            AgentMessage::LogEntry { level, message }
                if level == "info" && message == "navigate https://www.baidu.com"
        )
    }));
}

#[test]
fn handle_browser_message_falls_back_to_compat_runtime_for_unsupported_instruction() {
    let _guard = env_lock().lock().unwrap_or_else(|err| err.into_inner());

    let first_response = json!({
        "choices": [{
            "message": {
                "content": "",
                "tool_calls": [{
                    "id": "call_1",
                    "type": "function",
                    "function": {
                        "name": "browser_action",
                        "arguments": serde_json::to_string(&json!({
                            "action": "navigate",
                            "expected_domain": "www.baidu.com",
                            "url": "https://www.baidu.com"
                        })).unwrap()
                    }
                }]
            }
        }]
    });
    let second_response = json!({
        "choices": [{
            "message": {
                "content": "来自 ZeroClaw runtime"
            }
        }]
    });
    let (base_url, requests, server_handle) =
        start_fake_deepseek_server(vec![first_response, second_response]);

    std::env::set_var("DEEPSEEK_API_KEY", "deepseek-test-key");
    std::env::set_var("DEEPSEEK_BASE_URL", base_url);
    std::env::set_var("DEEPSEEK_MODEL", "deepseek-chat");

    let workspace_root = temp_workspace_root();
    let original_dir = std::env::current_dir().unwrap();
    std::env::set_current_dir(&workspace_root).unwrap();

    let transport = Arc::new(MockTransport::new(vec![BrowserMessage::Response {
        seq: 1,
        success: true,
        data: json!({ "navigated": true }),
        aom_snapshot: vec![],
        timing: Timing {
            queue_ms: 1,
            exec_ms: 10,
        },
    }]));
    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));

    handle_browser_message(
        transport.as_ref(),
        &browser_tool,
        BrowserMessage::SubmitTask {
            instruction: "帮我打开百度首页".to_string(),
            conversation_id: String::new(),
            messages: vec![],
            page_url: String::new(),
            page_title: String::new(),
        },
    )
    .unwrap();
    server_handle.join().unwrap();
    std::env::set_current_dir(original_dir).unwrap();

    let sent = transport.sent_messages();
    let request_bodies = requests.lock().unwrap().clone();

    assert!(sent.iter().any(|message| {
        matches!(
            message,
            AgentMessage::TaskComplete { success, summary }
                if *success && summary == "来自 ZeroClaw runtime"
        )
    }));
    assert!(sent.iter().any(|message| {
        matches!(
            message,
            AgentMessage::LogEntry { level, message }
                if level == "mode" && message == "compat_llm_primary"
        )
    }));
    assert_eq!(request_bodies.len(), 2);
}

#[test]
fn handle_browser_message_requires_llm_configuration_when_no_model_is_available() {
    let _guard = env_lock().lock().unwrap_or_else(|err| err.into_inner());

    std::env::remove_var("DEEPSEEK_API_KEY");
    std::env::remove_var("DEEPSEEK_BASE_URL");
    std::env::remove_var("DEEPSEEK_MODEL");

    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));

    handle_browser_message(
        transport.as_ref(),
        &browser_tool,
        BrowserMessage::SubmitTask {
            instruction: "你好".to_string(),
            conversation_id: String::new(),
            messages: vec![],
            page_url: String::new(),
            page_title: String::new(),
        },
    )
    .unwrap();

    let sent = transport.sent_messages();
    assert!(matches!(
        sent.last(),
        Some(AgentMessage::TaskComplete { success, summary })
            if !success && summary.contains("未配置大语言模型")
    ));
}

#[test]
fn compat_runtime_includes_prior_turns_in_follow_up_provider_request() {
    let _guard = env_lock().lock().unwrap_or_else(|err| err.into_inner());

    let first_response = json!({
        "choices": [{
            "message": {
                "content": "",
                "tool_calls": [{
                    "id": "call_1",
                    "type": "function",
                    "function": {
                        "name": "browser_action",
                        "arguments": serde_json::to_string(&json!({
                            "action": "navigate",
                            "expected_domain": "www.zhihu.com",
                            "url": "https://www.zhihu.com/search?q=天气&type=content"
                        })).unwrap()
                    }
                }]
            }
        }]
    });
    let second_response = json!({
        "choices": [{
            "message": {
                "content": "已在知乎搜索天气"
            }
        }]
    });
    let (base_url, requests, server_handle) =
        start_fake_deepseek_server(vec![first_response, second_response]);

    let workspace_root = temp_workspace_root();
    let settings = DeepSeekSettings {
        api_key: "deepseek-test-key".to_string(),
        base_url,
        model: "deepseek-chat".to_string(),
        skills_dir: None,
    };
    let transport = Arc::new(MockTransport::new(vec![BrowserMessage::Response {
        seq: 1,
        success: true,
        data: json!({ "navigated": true }),
        aom_snapshot: vec![],
        timing: Timing {
            queue_ms: 1,
            exec_ms: 10,
        },
    }]));
    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 task_context = CompatTaskContext {
        conversation_id: Some("conversation-1".to_string()),
        messages: vec![
            ConversationMessage {
                role: "user".to_string(),
                content: "打开百度搜索天气".to_string(),
            },
            ConversationMessage {
                role: "assistant".to_string(),
                content: "已在百度搜索天气".to_string(),
            },
        ],
        page_url: Some("https://www.zhihu.com/".to_string()),
        page_title: Some("知乎".to_string()),
    };

    let summary = execute_task(
        transport.as_ref(),
        browser_tool,
        "打开知乎搜索天气",
        &task_context,
        &workspace_root,
        &settings,
    )
    .unwrap();
    server_handle.join().unwrap();

    let request_bodies = requests.lock().unwrap().clone();
    let first_request_messages = request_bodies[0]["messages"]
        .as_array()
        .cloned()
        .unwrap_or_default();

    assert_eq!(summary, "已在知乎搜索天气");
    assert!(first_request_messages.iter().any(|message| {
        message["role"] == json!("user") && message["content"] == json!("打开百度搜索天气")
    }));
    assert!(first_request_messages.iter().any(|message| {
        message["role"] == json!("assistant") && message["content"] == json!("已在百度搜索天气")
    }));
}

#[test]
fn compat_runtime_does_not_forward_raw_aom_snapshot_back_to_provider() {
    let _guard = env_lock().lock().unwrap_or_else(|err| err.into_inner());

    let first_response = json!({
        "choices": [{
            "message": {
                "content": "",
                "tool_calls": [{
                    "id": "call_1",
                    "type": "function",
                    "function": {
                        "name": "browser_action",
                        "arguments": serde_json::to_string(&json!({
                            "action": "navigate",
                            "expected_domain": "www.baidu.com",
                            "url": "https://www.baidu.com"
                        })).unwrap()
                    }
                }]
            }
        }]
    });
    let second_response = json!({
        "choices": [{
            "message": {
                "content": "来自 ZeroClaw runtime"
            }
        }]
    });
    let (base_url, requests, server_handle) =
        start_fake_deepseek_server(vec![first_response, second_response]);

    let workspace_root = temp_workspace_root();
    let settings = DeepSeekSettings {
        api_key: "deepseek-test-key".to_string(),
        base_url,
        model: "deepseek-chat".to_string(),
        skills_dir: None,
    };

    let large_snapshot_marker = "snapshot-marker ".repeat(2048);
    let transport = Arc::new(MockTransport::new(vec![BrowserMessage::Response {
        seq: 1,
        success: true,
        data: json!({ "navigated": true }),
        aom_snapshot: vec![json!({
            "role": "RootWebArea",
            "name": "百度一下，你就知道",
            "text": large_snapshot_marker
        })],
        timing: Timing {
            queue_ms: 1,
            exec_ms: 10,
        },
    }]));
    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 summary = execute_task(
        transport.as_ref(),
        browser_tool,
        "打开百度首页",
        &CompatTaskContext::default(),
        &workspace_root,
        &settings,
    )
    .unwrap();
    server_handle.join().unwrap();

    let request_bodies = requests.lock().unwrap().clone();
    let follow_up_request = request_bodies[1].to_string();

    assert_eq!(summary, "来自 ZeroClaw runtime");
    assert_eq!(request_bodies.len(), 2);
    assert!(!follow_up_request.contains("snapshot-marker"));
}

#[test]
fn compat_runtime_injects_browser_contract_and_page_context_into_provider_request() {
    let _guard = env_lock().lock().unwrap_or_else(|err| err.into_inner());

    let response = json!({
        "choices": [{
            "message": {
                "content": "已收到页面上下文"
            }
        }]
    });
    let (base_url, requests, server_handle) = start_fake_deepseek_server(vec![response]);

    let workspace_root = temp_workspace_root();
    let settings = DeepSeekSettings {
        api_key: "deepseek-test-key".to_string(),
        base_url,
        model: "deepseek-chat".to_string(),
        skills_dir: None,
    };
    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 task_context = CompatTaskContext {
        conversation_id: Some("conversation-ctx".to_string()),
        messages: vec![],
        page_url: Some("https://www.zhihu.com/hot".to_string()),
        page_title: Some("知乎热榜".to_string()),
    };

    let summary = execute_task(
        transport.as_ref(),
        browser_tool,
        "统计一下知乎热帮信息",
        &task_context,
        &workspace_root,
        &settings,
    )
    .unwrap();
    server_handle.join().unwrap();

    let request_bodies = requests.lock().unwrap().clone();
    let first_request_messages = request_bodies[0]["messages"]
        .as_array()
        .cloned()
        .unwrap_or_default();
    let flattened = first_request_messages
        .iter()
        .filter_map(|message| message["content"].as_str())
        .collect::<Vec<_>>()
        .join("\n");

    assert_eq!(summary, "已收到页面上下文");
    assert!(
        flattened.contains("expected_domain must be the bare hostname"),
        "missing browser tool contract guidance: {flattened}"
    );
    assert!(
        flattened.contains("document.querySelector"),
        "missing CSS selector guidance: {flattened}"
    );
    assert!(
        flattened.contains("https://www.zhihu.com/hot"),
        "missing page url context: {flattened}"
    );
    assert!(
        flattened.contains("知乎热榜"),
        "missing page title context: {flattened}"
    );
}

#[test]
fn compat_runtime_can_complete_a_text_only_turn_without_browser_tool_calls() {
    let _guard = env_lock().lock().unwrap_or_else(|err| err.into_inner());

    let response = json!({
        "choices": [{
            "message": {
                "content": "这是纯文本回答"
            }
        }]
    });
    let (base_url, requests, server_handle) = start_fake_deepseek_server(vec![response]);

    let workspace_root = temp_workspace_root();
    let mut settings = SgClawSettings::from_legacy_deepseek_fields(
        "deepseek-test-key".to_string(),
        base_url,
        "deepseek-chat".to_string(),
        None,
    )
    .unwrap();
    settings.runtime_profile = RuntimeProfile::GeneralAssistant;

    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 summary = execute_task_with_sgclaw_settings(
        transport.as_ref(),
        browser_tool,
        "直接回答：你好",
        &CompatTaskContext::default(),
        &workspace_root,
        &settings,
    )
    .unwrap();
    server_handle.join().unwrap();

    let request_bodies = requests.lock().unwrap().clone();
    let flattened = request_bodies[0]["messages"]
        .as_array()
        .cloned()
        .unwrap_or_default()
        .iter()
        .filter_map(|message| message["content"].as_str())
        .collect::<Vec<_>>()
        .join("\n");
    let tool_entries = request_bodies[0]["tools"]
        .as_array()
        .cloned()
        .unwrap_or_default();
    let tool_names = tool_entries
        .into_iter()
        .filter_map(|tool| tool["function"]["name"].as_str().map(str::to_string))
        .collect::<Vec<_>>();
    let sent = transport.sent_messages();

    assert_eq!(summary, "这是纯文本回答");
    assert!(!flattened.contains("Browser tool contract"));
    assert!(!tool_names.contains(&"browser_action".to_string()));
    assert!(!sent
        .iter()
        .any(|message| { matches!(message, AgentMessage::Command { .. }) }));
}

#[test]
fn compat_runtime_allows_read_skill_under_compact_mode_policy() {
    let _guard = env_lock().lock().unwrap_or_else(|err| err.into_inner());

    let response = json!({
        "choices": [{
            "message": {
                "content": "已看到 compact skill 工具"
            }
        }]
    });
    let (base_url, requests, server_handle) = start_fake_deepseek_server(vec![response]);

    let workspace_root = temp_workspace_root();
    let default_skills_dir = workspace_root
        .join(".sgclaw-zeroclaw-workspace")
        .join("skills");
    write_skill_package(
        &default_skills_dir,
        "workspace-zhihu-skill",
        "# Workspace Zhihu Skill\nUse this workspace-local skill.\n",
    );

    let settings = SgClawSettings::from_legacy_deepseek_fields(
        "deepseek-test-key".to_string(),
        base_url,
        "deepseek-chat".to_string(),
        None,
    )
    .unwrap();
    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 summary = execute_task_with_sgclaw_settings(
        transport.as_ref(),
        browser_tool,
        "告诉我当前有哪些 skill",
        &CompatTaskContext::default(),
        &workspace_root,
        &settings,
    )
    .unwrap();
    server_handle.join().unwrap();

    let request_bodies = requests.lock().unwrap().clone();
    let tool_entries = request_bodies[0]["tools"]
        .as_array()
        .cloned()
        .unwrap_or_default();
    let tool_names = tool_entries
        .into_iter()
        .filter_map(|tool| tool["function"]["name"].as_str().map(str::to_string))
        .collect::<Vec<_>>();

    assert_eq!(summary, "已看到 compact skill 工具");
    assert!(tool_names.contains(&"browser_action".to_string()));
    assert!(tool_names.contains(&"superrpa_browser".to_string()));
    assert!(tool_names.contains(&"read_skill".to_string()));
    assert!(!tool_names.contains(&"zhihu-hotlist_extract_hotlist".to_string()));
}

#[test]
fn compat_runtime_exposes_browser_script_skill_tools_in_browser_attached_mode() {
    let _guard = env_lock().lock().unwrap_or_else(|err| err.into_inner());

    let response = json!({
        "choices": [{
            "message": {
                "content": "已看到 browser_script skill 工具"
            }
        }]
    });
    let (base_url, requests, server_handle) = start_fake_deepseek_server(vec![response]);

    let workspace_root = temp_workspace_root();
    let default_skills_dir = workspace_root
        .join(".sgclaw-zeroclaw-workspace")
        .join("skills");
    let skill_dir = write_skill_manifest_package(
        &default_skills_dir,
        "workspace-zhihu-skill",
        r#"
[skill]
name = "workspace-zhihu-skill"
description = "Extract Zhihu hotlist rows with a packaged browser script."
version = "0.1.0"

[[tools]]
name = "extract_hotlist"
description = "Extract structured hotlist rows from the current Zhihu page."
kind = "browser_script"
command = "scripts/extract_hotlist.js"

[tools.args]
top_n = "How many hotlist rows to extract."
"#,
    );
    write_skill_script(
        &skill_dir,
        "scripts/extract_hotlist.js",
        "return { rows: [] };",
    );

    let mut settings = SgClawSettings::from_legacy_deepseek_fields(
        "deepseek-test-key".to_string(),
        base_url,
        "deepseek-chat".to_string(),
        None,
    )
    .unwrap();
    settings.runtime_profile = RuntimeProfile::BrowserAttached;

    let transport = Arc::new(MockTransport::new(vec![]));
    let browser_tool = BrowserPipeTool::new(
        transport.clone(),
        zhihu_test_policy(),
        vec![1, 2, 3, 4, 5, 6, 7, 8],
    )
    .with_response_timeout(Duration::from_secs(1));

    let summary = execute_task_with_sgclaw_settings(
        transport.as_ref(),
        browser_tool,
        "告诉我当前有哪些知乎热榜工具",
        &CompatTaskContext::default(),
        &workspace_root,
        &settings,
    )
    .unwrap();
    server_handle.join().unwrap();

    let request_bodies = requests.lock().unwrap().clone();
    let tool_names = request_tool_names(&request_bodies[0]);

    assert_eq!(summary, "已看到 browser_script skill 工具");
    assert!(tool_names.contains(&"browser_action".to_string()));
    assert!(tool_names.contains(&"superrpa_browser".to_string()));
    assert!(tool_names.contains(&"read_skill".to_string()));
    assert!(tool_names.contains(&"workspace-zhihu-skill_extract_hotlist".to_string()));
}

#[test]
fn compat_runtime_executes_browser_script_skill_via_eval_without_gettext_probing() {
    let _guard = env_lock().lock().unwrap_or_else(|err| err.into_inner());

    let first_response = json!({
        "choices": [{
            "message": {
                "content": "",
                "tool_calls": [{
                    "id": "call_1",
                    "type": "function",
                    "function": {
                        "name": "workspace-zhihu-skill_extract_hotlist",
                        "arguments": serde_json::to_string(&json!({
                            "expected_domain": "www.zhihu.com",
                            "top_n": "10"
                        })).unwrap()
                    }
                }]
            }
        }]
    });
    let second_response = json!({
        "choices": [{
            "message": {
                "content": "已执行 browser_script skill"
            }
        }]
    });
    let (base_url, requests, server_handle) =
        start_fake_deepseek_server(vec![first_response, second_response]);

    let workspace_root = temp_workspace_root();
    let default_skills_dir = workspace_root
        .join(".sgclaw-zeroclaw-workspace")
        .join("skills");
    let skill_dir = write_skill_manifest_package(
        &default_skills_dir,
        "workspace-zhihu-skill",
        r#"
[skill]
name = "workspace-zhihu-skill"
description = "Extract Zhihu hotlist rows with a packaged browser script."
version = "0.1.0"

[[tools]]
name = "extract_hotlist"
description = "Extract structured hotlist rows from the current Zhihu page."
kind = "browser_script"
command = "scripts/extract_hotlist.js"

[tools.args]
top_n = "How many hotlist rows to extract."
"#,
    );
    write_skill_script(
        &skill_dir,
        "scripts/extract_hotlist.js",
        r#"
const topN = Number(args.top_n || 10);
return {
  source: "https://www.zhihu.com/hot",
  sheet_name: "知乎热榜",
  columns: ["rank", "title", "heat"],
  rows: [[1, "标题", `${topN}条`]]
};
"#,
    );

    let mut settings = SgClawSettings::from_legacy_deepseek_fields(
        "deepseek-test-key".to_string(),
        base_url,
        "deepseek-chat".to_string(),
        None,
    )
    .unwrap();
    settings.runtime_profile = RuntimeProfile::BrowserAttached;

    let transport = Arc::new(MockTransport::new(vec![success_browser_response(
        1,
        json!({
            "text": {
                "source": "https://www.zhihu.com/hot",
                "sheet_name": "知乎热榜",
                "columns": ["rank", "title", "heat"],
                "rows": [[1, "标题", "10条"]]
            }
        }),
    )]));
    let browser_tool = BrowserPipeTool::new(
        transport.clone(),
        zhihu_test_policy(),
        vec![1, 2, 3, 4, 5, 6, 7, 8],
    )
    .with_response_timeout(Duration::from_secs(1));

    let summary = execute_task_with_sgclaw_settings(
        transport.as_ref(),
        browser_tool,
        "用知乎热榜 skill 提取前十条结构化数据",
        &CompatTaskContext::default(),
        &workspace_root,
        &settings,
    )
    .unwrap();
    server_handle.join().unwrap();

    let sent = transport.sent_messages();
    let request_bodies = requests.lock().unwrap().clone();
    let tool_names = request_tool_names(&request_bodies[0]);

    assert_eq!(summary, "已执行 browser_script skill");
    assert!(tool_names.contains(&"workspace-zhihu-skill_extract_hotlist".to_string()));
    assert!(sent.iter().any(|message| {
        matches!(message, AgentMessage::LogEntry { level, message }
            if level == "info" && message == "call workspace-zhihu-skill.extract_hotlist")
    }));
    assert!(sent.iter().any(|message| {
        matches!(message, AgentMessage::Command { action, .. } if action == &Action::Eval)
    }));
    assert!(!sent.iter().any(|message| {
        matches!(message, AgentMessage::LogEntry { level, message }
            if level == "info" && message.starts_with("getText "))
    }));
}

#[test]
fn zhihu_hotlist_browser_skill_flow_does_not_expose_shell_or_glob_tools() {
    let _guard = env_lock().lock().unwrap_or_else(|err| err.into_inner());

    let response = json!({
        "choices": [{
            "message": {
                "content": "已准备好知乎热榜技能"
            }
        }]
    });
    let (base_url, requests, server_handle) = start_fake_deepseek_server(vec![response]);

    let workspace_root = temp_workspace_root();
    let mut settings = SgClawSettings::from_legacy_deepseek_fields(
        "deepseek-test-key".to_string(),
        base_url,
        "deepseek-chat".to_string(),
        Some(real_skill_lib_root()),
    )
    .unwrap();
    settings.runtime_profile = RuntimeProfile::BrowserAttached;

    let transport = Arc::new(MockTransport::new(vec![]));
    let browser_tool = BrowserPipeTool::new(
        transport.clone(),
        zhihu_test_policy(),
        vec![1, 2, 3, 4, 5, 6, 7, 8],
    )
    .with_response_timeout(Duration::from_secs(1));

    let summary = execute_task_with_sgclaw_settings(
        transport.as_ref(),
        browser_tool,
        "统计一下知乎热榜前十，给出标题和热度",
        &CompatTaskContext::default(),
        &workspace_root,
        &settings,
    )
    .unwrap();
    server_handle.join().unwrap();

    let request_bodies = requests.lock().unwrap().clone();
    let tool_names = request_tool_names(&request_bodies[0]);

    assert_eq!(summary, "已准备好知乎热榜技能");
    assert!(tool_names.contains(&"superrpa_browser".to_string()));
    assert!(tool_names.contains(&"browser_action".to_string()));
    assert!(tool_names.contains(&"read_skill".to_string()));
    assert!(tool_names.contains(&"zhihu-hotlist_extract_hotlist".to_string()));
    assert!(!tool_names.contains(&"shell".to_string()));
    assert!(!tool_names.contains(&"glob_search".to_string()));
}

#[test]
fn compat_runtime_browser_attached_profile_keeps_file_read_available_for_local_paths() {
    let _guard = env_lock().lock().unwrap_or_else(|err| err.into_inner());

    let response = json!({
        "choices": [{
            "message": {
                "content": "已收到本地路径任务"
            }
        }]
    });
    let (base_url, requests, server_handle) = start_fake_deepseek_server(vec![response]);

    let workspace_root = temp_workspace_root();
    let mut settings = SgClawSettings::from_legacy_deepseek_fields(
        "deepseek-test-key".to_string(),
        base_url,
        "deepseek-chat".to_string(),
        None,
    )
    .unwrap();
    settings.runtime_profile = RuntimeProfile::BrowserAttached;

    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 summary = execute_task_with_sgclaw_settings(
        transport.as_ref(),
        browser_tool,
        "请读取本地文件 /home/zyl/data/report.md 的内容并总结",
        &CompatTaskContext::default(),
        &workspace_root,
        &settings,
    )
    .unwrap();
    server_handle.join().unwrap();

    let request_bodies = requests.lock().unwrap().clone();
    let tool_names = request_tool_names(&request_bodies[0]);

    assert_eq!(summary, "已收到本地路径任务");
    assert!(tool_names.contains(&"browser_action".to_string()));
    assert!(tool_names.contains(&"superrpa_browser".to_string()));
    assert!(tool_names.contains(&"file_read".to_string()));
}

#[test]
fn browser_attached_export_flow_exposes_browser_and_office_tools_only() {
    let _guard = env_lock().lock().unwrap_or_else(|err| err.into_inner());

    let response = json!({
        "choices": [{
            "message": {
                "content": "已准备好知乎导出流程"
            }
        }]
    });
    let (base_url, requests, server_handle) = start_fake_deepseek_server(vec![response]);

    let workspace_root = temp_workspace_root();
    let mut settings = SgClawSettings::from_legacy_deepseek_fields(
        "deepseek-test-key".to_string(),
        base_url,
        "deepseek-chat".to_string(),
        Some(real_skill_lib_root()),
    )
    .unwrap();
    settings.runtime_profile = RuntimeProfile::BrowserAttached;

    let transport = Arc::new(MockTransport::new(vec![]));
    let browser_tool = BrowserPipeTool::new(
        transport.clone(),
        zhihu_test_policy(),
        vec![1, 2, 3, 4, 5, 6, 7, 8],
    )
    .with_response_timeout(Duration::from_secs(1));

    let summary = execute_task_with_sgclaw_settings(
        transport.as_ref(),
        browser_tool,
        "读取知乎热榜数据，并导出 excel 文件",
        &CompatTaskContext::default(),
        &workspace_root,
        &settings,
    )
    .unwrap();
    server_handle.join().unwrap();

    let request_bodies = requests.lock().unwrap().clone();
    let tool_names = request_tool_names(&request_bodies[0]);

    assert_eq!(summary, "已准备好知乎导出流程");
    assert!(tool_names.contains(&"superrpa_browser".to_string()));
    assert!(tool_names.contains(&"browser_action".to_string()));
    assert!(tool_names.contains(&"read_skill".to_string()));
    assert!(tool_names.contains(&"zhihu-hotlist_extract_hotlist".to_string()));
    assert!(tool_names.contains(&"openxml_office".to_string()));
    assert!(!tool_names.contains(&"shell".to_string()));
    assert!(!tool_names.contains(&"glob_search".to_string()));
}

#[test]
fn compat_runtime_allows_zhihu_hotlist_screen_export_tool_in_browser_profile() {
    let _guard = env_lock().lock().unwrap_or_else(|err| err.into_inner());

    let response = json!({
        "choices": [{
            "message": {
                "content": "已准备好知乎热榜大屏流程"
            }
        }]
    });
    let (base_url, requests, server_handle) = start_fake_deepseek_server(vec![response]);

    let workspace_root = temp_workspace_root();
    let mut settings = SgClawSettings::from_legacy_deepseek_fields(
        "deepseek-test-key".to_string(),
        base_url,
        "deepseek-chat".to_string(),
        Some(real_skill_lib_root()),
    )
    .unwrap();
    settings.runtime_profile = RuntimeProfile::BrowserAttached;

    let transport = Arc::new(MockTransport::new(vec![]));
    let browser_tool = BrowserPipeTool::new(
        transport.clone(),
        zhihu_test_policy(),
        vec![1, 2, 3, 4, 5, 6, 7, 8],
    )
    .with_response_timeout(Duration::from_secs(1));

    let summary = execute_task_with_sgclaw_settings(
        transport.as_ref(),
        browser_tool,
        "读取知乎热榜数据并生成领导演示大屏，在新标签页展示",
        &CompatTaskContext::default(),
        &workspace_root,
        &settings,
    )
    .unwrap();
    server_handle.join().unwrap();

    let request_bodies = requests.lock().unwrap().clone();
    let tool_names = request_tool_names(&request_bodies[0]);

    assert_eq!(summary, "已准备好知乎热榜大屏流程");
    assert!(tool_names.contains(&"superrpa_browser".to_string()));
    assert!(tool_names.contains(&"browser_action".to_string()));
    assert!(tool_names.contains(&"read_skill".to_string()));
    assert!(tool_names.contains(&"zhihu-hotlist_extract_hotlist".to_string()));
    assert!(tool_names.contains(&"screen_html_export".to_string()));
    assert!(!tool_names.contains(&"shell".to_string()));
    assert!(!tool_names.contains(&"glob_search".to_string()));
}

#[test]
fn compat_runtime_logs_read_skill_usage_with_skill_name() {
    let _guard = env_lock().lock().unwrap_or_else(|err| err.into_inner());

    let first_response = json!({
        "choices": [{
            "message": {
                "content": "",
                "tool_calls": [{
                    "id": "call_1",
                    "type": "function",
                    "function": {
                        "name": "read_skill",
                        "arguments": serde_json::to_string(&json!({
                            "name": "workspace-zhihu-skill"
                        })).unwrap()
                    }
                }]
            }
        }]
    });
    let second_response = json!({
        "choices": [{
            "message": {
                "content": "已读取完整 skill"
            }
        }]
    });
    let (base_url, _requests, server_handle) =
        start_fake_deepseek_server(vec![first_response, second_response]);

    let workspace_root = temp_workspace_root();
    let default_skills_dir = workspace_root
        .join(".sgclaw-zeroclaw-workspace")
        .join("skills");
    write_skill_package(
        &default_skills_dir,
        "workspace-zhihu-skill",
        "# Workspace Zhihu Skill\nUse this workspace-local skill.\n",
    );

    let settings = SgClawSettings::from_legacy_deepseek_fields(
        "deepseek-test-key".to_string(),
        base_url,
        "deepseek-chat".to_string(),
        None,
    )
    .unwrap();
    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 summary = execute_task_with_sgclaw_settings(
        transport.as_ref(),
        browser_tool,
        "需要完整 zhihu skill 时先读取 skill",
        &CompatTaskContext::default(),
        &workspace_root,
        &settings,
    )
    .unwrap();
    server_handle.join().unwrap();

    let sent = transport.sent_messages();

    assert_eq!(summary, "已读取完整 skill");
    assert!(sent.iter().any(|message| {
        matches!(
            message,
            AgentMessage::LogEntry { level, message }
                if level == "info" &&
                    message == "read_skill workspace-zhihu-skill@0.1.0"
        )
    }));
}

#[test]
fn handle_browser_message_exposes_real_zhihu_skill_lib_to_provider_request() {
    let _guard = env_lock().lock().unwrap_or_else(|err| err.into_inner());

    let response = json!({
        "choices": [{
            "message": {
                "content": "已看到真实知乎 skill"
            }
        }]
    });
    let (base_url, requests, server_handle) = start_fake_deepseek_server(vec![response]);

    let workspace_root = temp_workspace_root();
    let skills_dir = real_skill_lib_root();
    let config_path = write_deepseek_config_with_skills_dir(
        &workspace_root,
        "deepseek-test-key",
        &base_url,
        "deepseek-chat",
        Some(skills_dir.to_str().unwrap()),
    );
    let runtime_context = AgentRuntimeContext::new(Some(config_path), workspace_root.clone());

    let transport = Arc::new(MockTransport::new(vec![]));
    let browser_tool = BrowserPipeTool::new(
        transport.clone(),
        zhihu_test_policy(),
        vec![1, 2, 3, 4, 5, 6, 7, 8],
    )
    .with_response_timeout(Duration::from_secs(1));

    handle_browser_message_with_context(
        transport.as_ref(),
        &browser_tool,
        &runtime_context,
        BrowserMessage::SubmitTask {
            instruction: "告诉我当前有哪些知乎 skill".to_string(),
            conversation_id: String::new(),
            messages: vec![],
            page_url: "https://example.net/".to_string(),
            page_title: "Example Domain".to_string(),
        },
    )
    .unwrap();
    server_handle.join().unwrap();

    let sent = transport.sent_messages();
    let request_bodies = requests.lock().unwrap().clone();
    let first_request = request_bodies[0].to_string();
    let tool_names = request_tool_names(&request_bodies[0]);

    assert!(sent.iter().any(|message| {
        matches!(
            message,
            AgentMessage::LogEntry { level, message }
                if level == "info"
                    && message.contains("loaded skills:")
                    && message.contains("office-export-xlsx@0.1.0")
                    && message.contains("zhihu-hotlist@0.1.0")
                    && message.contains("zhihu-hotlist-screen@0.1.0")
                    && message.contains("zhihu-navigate@0.1.0")
                    && message.contains("zhihu-write@0.1.0")
        )
    }));
    assert_eq!(request_bodies.len(), 1);
    assert!(first_request.contains("office-export-xlsx"));
    assert!(first_request.contains("zhihu-hotlist"));
    assert!(first_request.contains("zhihu-hotlist-screen"));
    assert!(first_request.contains("zhihu-navigate"));
    assert!(first_request.contains("zhihu-write"));
    assert!(tool_names.contains(&"browser_action".to_string()));
    assert!(tool_names.contains(&"superrpa_browser".to_string()));
    assert!(tool_names.contains(&"read_skill".to_string()));
}

#[test]
fn browser_attached_excel_request_uses_execution_contract_not_skill_source_stuffing() {
    let _guard = env_lock().lock().unwrap_or_else(|err| err.into_inner());

    let response = json!({
        "choices": [{
            "message": {
                "content": "已收到知乎导出任务"
            }
        }]
    });
    let (base_url, requests, server_handle) = start_fake_deepseek_server(vec![response]);

    let workspace_root = temp_workspace_root();
    let mut settings = SgClawSettings::from_legacy_deepseek_fields(
        "deepseek-test-key".to_string(),
        base_url,
        "deepseek-chat".to_string(),
        Some(real_skill_lib_root()),
    )
    .unwrap();
    settings.runtime_profile = RuntimeProfile::BrowserAttached;

    let transport = Arc::new(MockTransport::new(vec![]));
    let browser_tool = BrowserPipeTool::new(
        transport.clone(),
        zhihu_test_policy(),
        vec![1, 2, 3, 4, 5, 6, 7, 8],
    )
    .with_response_timeout(Duration::from_secs(1));

    let summary = execute_task_with_sgclaw_settings(
        transport.as_ref(),
        browser_tool,
        "读取知乎热榜数据，并导出 excel 文件",
        &CompatTaskContext::default(),
        &workspace_root,
        &settings,
    )
    .unwrap();
    server_handle.join().unwrap();

    let request_bodies = requests.lock().unwrap().clone();
    let first_request = request_bodies[0].to_string();

    assert_eq!(summary, "已收到知乎导出任务");
    assert!(first_request.contains("Zhihu hotlist execution contract"));
    assert!(first_request.contains("Export completion contract"));
    assert!(first_request.contains("openxml_office"));
    assert!(!first_request.contains("Preloaded skill context:"));
}

#[test]
fn browser_attached_publish_request_injects_confirmation_contract() {
    let _guard = env_lock().lock().unwrap_or_else(|err| err.into_inner());

    let response = json!({
        "choices": [{
            "message": {
                "content": "请先确认是否发布"
            }
        }]
    });
    let (base_url, requests, server_handle) = start_fake_deepseek_server(vec![response]);

    let workspace_root = temp_workspace_root();
    let mut settings = SgClawSettings::from_legacy_deepseek_fields(
        "deepseek-test-key".to_string(),
        base_url,
        "deepseek-chat".to_string(),
        Some(real_skill_lib_root()),
    )
    .unwrap();
    settings.runtime_profile = RuntimeProfile::BrowserAttached;

    let transport = Arc::new(MockTransport::new(vec![]));
    let browser_tool = BrowserPipeTool::new(
        transport.clone(),
        zhihu_test_policy(),
        vec![1, 2, 3, 4, 5, 6, 7, 8],
    )
    .with_response_timeout(Duration::from_secs(1));

    execute_task_with_sgclaw_settings(
        transport.as_ref(),
        browser_tool,
        "请直接发表这篇知乎文章，标题是测试标题，正文是第一段内容",
        &CompatTaskContext {
            conversation_id: None,
            messages: vec![],
            page_url: Some("https://www.zhihu.com/creator".to_string()),
            page_title: Some("知乎创作中心".to_string()),
        },
        &workspace_root,
        &settings,
    )
    .unwrap();
    server_handle.join().unwrap();

    let request_bodies = requests.lock().unwrap().clone();
    let first_request = request_bodies[0].to_string();

    assert!(first_request.contains("Zhihu article publish contract"));
    assert!(first_request.contains("must not click publish without explicit human confirmation"));
    assert!(first_request.contains("ask for confirmation concisely"));
    assert!(first_request.contains("stop after the confirmation request"));
}

#[test]
fn handle_browser_message_executes_real_zhihu_hotlist_skill_flow() {
    let _guard = env_lock().lock().unwrap_or_else(|err| err.into_inner());

    let first_response = json!({
        "choices": [{
            "message": {
                "content": "",
                "tool_calls": [{
                    "id": "call_1",
                    "type": "function",
                    "function": {
                        "name": "zhihu-hotlist_extract_hotlist",
                        "arguments": serde_json::to_string(&json!({
                            "expected_domain": "www.zhihu.com",
                            "top_n": "10"
                        })).unwrap()
                    }
                }]
            }
        }]
    });
    let second_response = json!({
        "choices": [{
            "message": {
                "content": "已完成知乎热榜采集"
            }
        }]
    });
    let (base_url, requests, server_handle) =
        start_fake_deepseek_server(vec![first_response, second_response]);

    let workspace_root = temp_workspace_root();
    let skills_dir = real_skill_lib_root();
    let config_path = write_deepseek_config_with_skills_dir(
        &workspace_root,
        "deepseek-test-key",
        &base_url,
        "deepseek-chat",
        Some(skills_dir.to_str().unwrap()),
    );
    let runtime_context = AgentRuntimeContext::new(Some(config_path), workspace_root.clone());

    let transport = Arc::new(MockTransport::new(vec![success_browser_response(
        1,
        json!({
            "text": {
                "source": "https://www.zhihu.com/hot",
                "sheet_name": "知乎热榜",
                "columns": ["rank", "title", "heat"],
                "rows": [[1, "热榜项目 1", "1707万"], [2, "热榜项目 2", "1150万"]]
            }
        }),
    )]));
    let browser_tool = BrowserPipeTool::new(
        transport.clone(),
        zhihu_test_policy(),
        vec![1, 2, 3, 4, 5, 6, 7, 8],
    )
    .with_response_timeout(Duration::from_secs(1));

    handle_browser_message_with_context(
        transport.as_ref(),
        &browser_tool,
        &runtime_context,
        BrowserMessage::SubmitTask {
            instruction: "统计一下知乎热榜前十".to_string(),
            conversation_id: String::new(),
            messages: vec![],
            page_url: "https://www.zhihu.com/".to_string(),
            page_title: "知乎".to_string(),
        },
    )
    .unwrap();
    server_handle.join().unwrap();

    let sent = transport.sent_messages();
    let request_bodies = requests.lock().unwrap().clone();
    let tool_content = tool_message_content(&request_bodies[1], "call_1").unwrap();

    assert!(sent.iter().any(|message| {
        matches!(
            message,
            AgentMessage::TaskComplete { success, summary }
                if *success && summary == "已完成知乎热榜采集"
        )
    }));
    assert!(sent.iter().any(|message| {
        matches!(
            message,
            AgentMessage::LogEntry { level, message }
                if level == "info" && message == "call zhihu-hotlist.extract_hotlist"
        )
    }));
    assert!(sent.iter().any(|message| {
        matches!(
            message,
            AgentMessage::Command { action, params, .. }
                if action == &Action::Eval &&
                    params["script"].as_str().unwrap_or_default().contains("columns: ['rank', 'title', 'heat']")
        )
    }));
    assert_eq!(request_bodies.len(), 2);
    assert!(tool_content.contains("知乎热榜"));
    assert!(tool_content.contains("rank"));
    assert!(tool_content.contains("heat"));
    assert!(tool_content.contains("热榜项目 1"));
}

#[test]
fn handle_browser_message_chains_hotlist_skill_into_xlsx_export_and_auto_open() {
    let _guard = env_lock().lock().unwrap_or_else(|err| err.into_inner());
    std::env::set_var("SGCLAW_DISABLE_POST_EXPORT_OPEN", "1");

    let workspace_root = temp_workspace_root();
    let config_path = write_deepseek_config_with_skills_dir(
        &workspace_root,
        "deepseek-test-key",
        "http://127.0.0.1:9",
        "deepseek-chat",
        Some(real_skill_lib_root().to_str().unwrap()),
    );
    let runtime_context = AgentRuntimeContext::new(Some(config_path), workspace_root.clone());

    let transport = Arc::new(MockTransport::new(vec![
        success_browser_response(
            1,
            json!({ "text": "知乎热榜\n1 问题一 344万热度\n2 问题二 266万热度" }),
        ),
        success_browser_response(
            2,
            json!({
                "text": {
                    "source": "https://www.zhihu.com/hot",
                    "sheet_name": "知乎热榜",
                    "columns": ["rank", "title", "heat"],
                    "rows": [[1, "问题一", "344万"], [2, "问题二", "266万"]]
                }
            }),
        ),
    ]));
    let browser_tool = BrowserPipeTool::new(
        transport.clone(),
        zhihu_test_policy(),
        vec![1, 2, 3, 4, 5, 6, 7, 8],
    )
    .with_response_timeout(Duration::from_secs(1));

    handle_browser_message_with_context(
        transport.as_ref(),
        &browser_tool,
        &runtime_context,
        BrowserMessage::SubmitTask {
            instruction: "读取知乎热榜数据，并导出 excel 文件".to_string(),
            conversation_id: String::new(),
            messages: vec![],
            page_url: "https://www.zhihu.com/hot".to_string(),
            page_title: "知乎热榜".to_string(),
        },
    )
    .unwrap();

    let sent = transport.sent_messages();
    let summary = task_complete_summary(&sent);
    let generated = extract_generated_artifact_path(&summary, ".xlsx");

    assert!(summary.contains("已导出知乎热榜 Excel") || summary.contains("已导出并打开知乎热榜 Excel"));
    assert!(summary.contains(".xlsx"));
    assert!(generated.exists());
    assert!(sent.iter().any(|message| {
        matches!(
            message,
            AgentMessage::TaskComplete { success, summary }
                if *success && summary.contains(".xlsx")
        )
    }));
    assert!(sent.iter().any(|message| {
        matches!(
            message,
            AgentMessage::LogEntry { level, message }
                if level == "mode" && message == "zeroclaw_process_message_primary"
        )
    }));
    assert!(sent.iter().any(|message| {
        matches!(
            message,
            AgentMessage::LogEntry { level, message }
                if level == "info" && message == "call zhihu-hotlist.extract_hotlist"
        )
    }));
    assert!(sent.iter().any(|message| {
        matches!(
            message,
            AgentMessage::LogEntry { level, message }
                if level == "info" && message == "call openxml_office"
        )
    }));
    assert!(sent.iter().any(|message| {
        matches!(message, AgentMessage::Command { action, .. } if action == &Action::Eval)
    }));
    assert!(!sent.iter().any(|message| {
        matches!(
            message,
            AgentMessage::Command { action, params, .. }
                if action == &Action::Navigate && params.get("sgclaw_local_dashboard_open").is_some()
        )
    }));
    assert!(!sent.iter().any(|message| {
        matches!(
            message,
            AgentMessage::LogEntry { level, message }
                if level == "mode" && (message == "compat_llm_primary" || message == "compat_skill_runner_primary")
        )
    }));
    std::env::remove_var("SGCLAW_DISABLE_POST_EXPORT_OPEN");
}

#[test]
fn handle_browser_message_chains_hotlist_skill_into_screen_export_and_auto_open() {
    let _guard = env_lock().lock().unwrap_or_else(|err| err.into_inner());

    let workspace_root = temp_workspace_root();
    let config_path = write_deepseek_config_with_skills_dir(
        &workspace_root,
        "deepseek-test-key",
        "http://127.0.0.1:9",
        "deepseek-chat",
        Some(real_skill_lib_root().to_str().unwrap()),
    );
    let runtime_context = AgentRuntimeContext::new(Some(config_path), workspace_root.clone());

    let transport = Arc::new(MockTransport::new(vec![
        success_browser_response(
            1,
            json!({ "text": "知乎热榜\n1 问题一 344万热度\n2 问题二 266万热度" }),
        ),
        success_browser_response(
            2,
            json!({
                "text": {
                    "source": "https://www.zhihu.com/hot",
                    "sheet_name": "知乎热榜",
                    "columns": ["rank", "title", "heat"],
                    "rows": [[1, "问题一", "344万"], [2, "问题二", "266万"]]
                }
            }),
        ),
        success_browser_response(3, json!({ "navigated": true })),
    ]));
    let browser_tool = BrowserPipeTool::new(
        transport.clone(),
        zhihu_test_policy(),
        vec![1, 2, 3, 4, 5, 6, 7, 8],
    )
    .with_response_timeout(Duration::from_secs(1));

    handle_browser_message_with_context(
        transport.as_ref(),
        &browser_tool,
        &runtime_context,
        BrowserMessage::SubmitTask {
            instruction: "读取知乎热榜数据并生成领导演示大屏，在新标签页展示".to_string(),
            conversation_id: String::new(),
            messages: vec![],
            page_url: "https://www.zhihu.com/hot".to_string(),
            page_title: "知乎热榜".to_string(),
        },
    )
    .unwrap();

    let sent = transport.sent_messages();
    let summary = task_complete_summary(&sent);
    let generated = extract_generated_artifact_path(&summary, ".html");
    let navigate = sent
        .iter()
        .find_map(|message| match message {
            AgentMessage::Command {
                action,
                params,
                security,
                ..
            } if action == &Action::Navigate
                && security.expected_domain == "__sgclaw_local_dashboard__" => Some((params, security)),
            _ => None,
        })
        .expect("dashboard route should emit local-dashboard navigate request");

    assert!(summary.contains("已在浏览器中打开知乎热榜大屏"));
    assert!(summary.contains(".html"));
    assert!(generated.exists());
    assert_eq!(
        navigate.0["sgclaw_local_dashboard_open"]["output_path"].as_str(),
        generated.to_str()
    );
    assert!(navigate.0["url"]
        .as_str()
        .expect("dashboard open url should be present")
        .starts_with("file://"));
    assert_eq!(
        navigate.0["sgclaw_local_dashboard_open"]["source"],
        json!("compat.workflow_executor")
    );
    assert_eq!(
        navigate.0["sgclaw_local_dashboard_open"]["kind"],
        json!("zhihu_hotlist_screen")
    );
    assert_eq!(
        navigate.0["sgclaw_local_dashboard_open"]["presentation_url"],
        navigate.0["url"]
    );
    assert!(sent.iter().any(|message| {
        matches!(
            message,
            AgentMessage::LogEntry { level, message }
                if level == "mode" && message == "zeroclaw_process_message_primary"
        )
    }));
    assert!(sent.iter().any(|message| {
        matches!(
            message,
            AgentMessage::LogEntry { level, message }
                if level == "info" && message == "call zhihu-hotlist.extract_hotlist"
        )
    }));
    assert!(sent.iter().any(|message| {
        matches!(
            message,
            AgentMessage::LogEntry { level, message }
                if level == "info" && message == "call screen_html_export"
        )
    }));
    assert!(sent.iter().any(|message| {
        matches!(
            message,
            AgentMessage::Command { action, .. } if action == &Action::Eval
        )
    }));
    assert!(!sent.iter().any(|message| {
        matches!(
            message,
            AgentMessage::LogEntry { level, message }
                if level == "info" && message == "call openxml_office"
        )
    }));
    assert!(!sent.iter().any(|message| {
        matches!(
            message,
            AgentMessage::LogEntry { level, message }
                if level == "mode" && (message == "compat_llm_primary" || message == "compat_skill_runner_primary")
        )
    }));
}

#[test]
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![]));
    let browser_tool = BrowserPipeTool::new(
        transport.clone(),
        zhihu_test_policy(),
        vec![1, 2, 3, 4, 5, 6, 7, 8],
    )
    .with_response_timeout(Duration::from_secs(1));
    let browser_backend = sgclaw::browser::PipeBrowserBackend::from_inner(browser_tool);

    let workspace_root = temp_workspace_root();
    let output_path = workspace_root.join("zhihu-hotlist-screen.html");
    fs::write(&output_path, "<html><body>fixture</body></html>").unwrap();
    let payload = json!({
        "title": "知乎热榜大屏",
        "output_path": output_path,
        "renderer": "screen_html_export",
        "row_count": 2,
        "snapshot_id": "snapshot-test",
        "presentation": {
            "mode": "new_tab",
            "title": "知乎热榜大屏",
            "open_in_new_tab": true
        }
    });

    let summary = finalize_screen_export(&browser_backend, &payload.to_string()).unwrap();

    assert!(summary.contains("已生成知乎热榜大屏"));
    assert!(summary.contains(output_path.to_string_lossy().as_ref()));
    assert!(summary.contains("但浏览器自动打开失败：screen_html_export did not return presentation.url"));

    let sent = transport.sent_messages();
    assert!(!sent.iter().any(|message| {
        matches!(
            message,
            AgentMessage::Command { action, params, .. }
                if action == &Action::Navigate && params.get("sgclaw_local_dashboard_open").is_some()
        )
    }));
}

#[test]
fn handle_browser_message_runs_zhihu_hotlist_export_via_zeroclaw_primary_orchestration() {
    let _guard = env_lock().lock().unwrap_or_else(|err| err.into_inner());
    std::env::set_var("SGCLAW_DISABLE_POST_EXPORT_OPEN", "1");

    let workspace_root = temp_workspace_root();
    let config_path = write_deepseek_config_with_skills_dir(
        &workspace_root,
        "deepseek-test-key",
        "http://127.0.0.1:9",
        "deepseek-chat",
        Some(real_skill_lib_root().to_str().unwrap()),
    );
    let runtime_context = AgentRuntimeContext::new(Some(config_path), workspace_root.clone());

    let transport = Arc::new(MockTransport::new(vec![
        success_browser_response(
            1,
            json!({ "text": "知乎热榜\n1 问题一 344万热度\n2 问题二 266万热度\n3 问题三 181万热度" }),
        ),
        success_browser_response(
            2,
            json!({
                "text": {
                    "source": "https://www.zhihu.com/hot",
                    "sheet_name": "知乎热榜",
                    "columns": ["rank", "title", "heat"],
                    "rows": [
                        [1, "问题一", "344万"],
                        [2, "问题二", "266万"],
                        [3, "问题三", "181万"]
                    ]
                }
            }),
        ),
    ]));
    let browser_tool = BrowserPipeTool::new(
        transport.clone(),
        zhihu_test_policy(),
        vec![1, 2, 3, 4, 5, 6, 7, 8],
    )
    .with_response_timeout(Duration::from_secs(1));

    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: "https://www.zhihu.com/hot".to_string(),
            page_title: "知乎热榜".to_string(),
        },
    )
    .unwrap();

    let sent = transport.sent_messages();
    let summary = task_complete_summary(&sent);
    let generated = extract_generated_artifact_path(&summary, ".xlsx");

    assert!(summary.contains(".xlsx"));
    assert!(generated.exists());

    assert!(sent.iter().any(|message| {
        matches!(
            message,
            AgentMessage::LogEntry { level, message }
                if level == "mode" && message == "zeroclaw_process_message_primary"
        )
    }));
    assert!(!sent.iter().any(|message| {
        matches!(
            message,
            AgentMessage::LogEntry { level, message }
                if level == "mode" && (message == "compat_llm_primary" || message == "compat_skill_runner_primary")
        )
    }));
    std::env::remove_var("SGCLAW_DISABLE_POST_EXPORT_OPEN");
}

#[test]
fn browser_submit_path_prefers_zeroclaw_process_message_orchestrator() {
    let _guard = env_lock().lock().unwrap_or_else(|err| err.into_inner());

    let workspace_root = temp_workspace_root();
    let config_path = write_deepseek_config_with_skills_dir(
        &workspace_root,
        "deepseek-test-key",
        "http://127.0.0.1:9",
        "deepseek-chat",
        Some(real_skill_lib_root().to_str().unwrap()),
    );
    let runtime_context = AgentRuntimeContext::new(Some(config_path), workspace_root.clone());

    let transport = Arc::new(MockTransport::new(vec![]));
    let browser_tool = BrowserPipeTool::new(
        transport.clone(),
        zhihu_test_policy(),
        vec![1, 2, 3, 4, 5, 6, 7, 8],
    )
    .with_response_timeout(Duration::from_secs(1));

    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: "https://www.zhihu.com/hot".to_string(),
            page_title: "知乎热榜".to_string(),
        },
    )
    .unwrap();

    let sent = transport.sent_messages();
    dbg!(&sent);

    assert!(sent.iter().any(|message| {
        matches!(
            message,
            AgentMessage::LogEntry { level, message }
                if level == "mode" && message == "zeroclaw_process_message_primary"
        )
    }));
    assert!(!sent.iter().any(|message| {
        matches!(
            message,
            AgentMessage::LogEntry { level, message }
                if level == "mode" && (message == "compat_llm_primary" || message == "compat_skill_runner_primary")
        )
    }));
}

#[test]
fn browser_submit_path_prefers_zeroclaw_process_message_orchestrator_for_zhihu_publish() {
    let _guard = env_lock().lock().unwrap_or_else(|err| err.into_inner());

    let workspace_root = temp_workspace_root();
    let config_path = write_deepseek_config_with_skills_dir(
        &workspace_root,
        "deepseek-test-key",
        "http://127.0.0.1:9",
        "deepseek-chat",
        Some(real_skill_lib_root().to_str().unwrap()),
    );
    let runtime_context = AgentRuntimeContext::new(Some(config_path), workspace_root.clone());

    let transport = Arc::new(MockTransport::new(vec![]));
    let browser_tool = BrowserPipeTool::new(
        transport.clone(),
        zhihu_test_policy(),
        vec![1, 2, 3, 4, 5, 6, 7, 8],
    )
    .with_response_timeout(Duration::from_secs(1));

    handle_browser_message_with_context(
        transport.as_ref(),
        &browser_tool,
        &runtime_context,
        BrowserMessage::SubmitTask {
            instruction: "请直接发表这篇知乎文章，标题是测试标题，正文是第一段内容".to_string(),
            conversation_id: String::new(),
            messages: vec![],
            page_url: "https://www.zhihu.com/".to_string(),
            page_title: "知乎".to_string(),
        },
    )
    .unwrap();

    let sent = transport.sent_messages();

    assert!(sent.iter().any(|message| {
        matches!(
            message,
            AgentMessage::LogEntry { level, message }
                if level == "mode" && message == "zeroclaw_process_message_primary"
        )
    }));
    assert!(!sent.iter().any(|message| {
        matches!(
            message,
            AgentMessage::LogEntry { level, message }
                if level == "mode" && (message == "compat_llm_primary" || message == "compat_skill_runner_primary")
        )
    }));
}

#[test]
fn browser_attached_zhihu_hotlist_request_keeps_zhihu_contract_without_scene_injection() {
    let _guard = env_lock().lock().unwrap_or_else(|err| err.into_inner());

    let response = json!({
        "choices": [{
            "message": {
                "content": "已收到知乎导出任务"
            }
        }]
    });
    let (base_url, requests, server_handle) = start_fake_deepseek_server(vec![response]);

    let workspace_root = temp_workspace_root();
    let mut settings = SgClawSettings::from_legacy_deepseek_fields(
        "deepseek-test-key".to_string(),
        base_url,
        "deepseek-chat".to_string(),
        Some(real_skill_lib_root()),
    )
    .unwrap();
    settings.runtime_profile = RuntimeProfile::BrowserAttached;

    let transport = Arc::new(MockTransport::new(vec![]));
    let browser_tool = BrowserPipeTool::new(
        transport.clone(),
        zhihu_test_policy(),
        vec![1, 2, 3, 4, 5, 6, 7, 8],
    )
    .with_response_timeout(Duration::from_secs(1));

    let summary = execute_task_with_sgclaw_settings(
        transport.as_ref(),
        browser_tool,
        "读取知乎热榜数据，并导出 excel 文件",
        &CompatTaskContext::default(),
        &workspace_root,
        &settings,
    )
    .unwrap();
    server_handle.join().unwrap();

    let request_bodies = requests.lock().unwrap().clone();
    let first_request = request_bodies[0].to_string();

    assert_eq!(summary, "已收到知乎导出任务");
    assert_eq!(request_bodies.len(), 1);
    assert!(first_request.contains("Zhihu hotlist execution contract"));
    assert!(first_request.contains("Export completion contract"));
    assert!(first_request.contains("openxml_office"));
    assert!(!first_request.contains("95598 repair city dispatch execution contract"));
    assert!(!first_request.contains("browser workflow, not a text-only task"));
    assert!(!first_request.contains("generic browser probing only after"));
}

#[test]
fn ws_cleanup_no_longer_detects_fault_details_scene_route() {
    use sgclaw::compat::workflow_executor::detect_route;

    assert_eq!(
        detect_route(
            "导出故障明细",
            Some("https://example.invalid/workbench"),
            Some("业务台账"),
        ),
        None,
    );
}

#[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抢修市指监测"),
    ));
}

#[test]
fn zhihu_generated_auto_publish_matches_primary_orchestration_gate() {
    assert!(
        sgclaw::compat::orchestration::should_use_primary_orchestration(
            "在知乎自动发表一篇名称为人工智能技能大全",
            Some("https://www.zhihu.com/"),
            Some("知乎"),
        )
    );
}

#[test]
fn zhihu_hotlist_export_route_stays_ahead_of_generated_article_publish() {
    use sgclaw::compat::workflow_executor::{detect_route, WorkflowRoute};

    assert_eq!(
        detect_route(
            "打开知乎热榜，获取前10条数据，并导出 Excel",
            Some("https://www.zhihu.com/"),
            Some("知乎")
        ),
        Some(WorkflowRoute::ZhihuHotlistExportXlsx)
    );
}

#[test]
fn zhihu_generated_auto_publish_uses_provider_and_submits_publish_without_confirmation() {
    let _guard = env_lock().lock().unwrap_or_else(|err| err.into_inner());

    let response = json!({
        "choices": [{
            "message": {
                "content": "标题：人工智能技能大全\n正文：第一段内容。\n\n第二段内容。"
            }
        }]
    });
    let (base_url, requests, server_handle) = start_fake_deepseek_server(vec![response]);

    let workspace_root = temp_workspace_root();
    let config_path = write_deepseek_config_with_skills_dir(
        &workspace_root,
        "deepseek-test-key",
        &base_url,
        "deepseek-chat",
        Some(real_skill_lib_root().to_str().unwrap()),
    );
    let runtime_context = AgentRuntimeContext::new(Some(config_path), workspace_root.clone());

    let transport = Arc::new(MockTransport::new(vec![
        success_browser_response(1, json!({ "navigated": true })),
        success_browser_response(
            2,
            json!({
                "text": {
                    "status": "creator_entry_clicked",
                    "current_url": "https://www.zhihu.com/creator",
                    "next_url": "https://zhuanlan.zhihu.com/write"
                }
            }),
        ),
        success_browser_response(3, json!({ "navigated": true })),
        success_browser_response(
            4,
            json!({
                "text": {
                    "status": "editor_ready",
                    "current_url": "https://zhuanlan.zhihu.com/write"
                }
            }),
        ),
        success_browser_response(
            5,
            json!({
                "text": {
                    "status": "publish_submitted",
                    "current_url": "https://zhuanlan.zhihu.com/write",
                    "title": "人工智能技能大全"
                }
            }),
        ),
    ]));
    let browser_tool = BrowserPipeTool::new(
        transport.clone(),
        zhihu_test_policy(),
        vec![1, 2, 3, 4, 5, 6, 7, 8],
    )
    .with_response_timeout(Duration::from_secs(1));

    handle_browser_message_with_context(
        transport.as_ref(),
        &browser_tool,
        &runtime_context,
        BrowserMessage::SubmitTask {
            instruction: "在知乎自动发表一篇名称为人工智能技能大全".to_string(),
            conversation_id: String::new(),
            messages: vec![],
            page_url: "https://www.zhihu.com/".to_string(),
            page_title: "知乎".to_string(),
        },
    )
    .unwrap();
    server_handle.join().unwrap();

    let sent = transport.sent_messages();
    let request_bodies = requests.lock().unwrap().clone();

    assert_eq!(request_bodies.len(), 1);
    assert!(request_bodies[0].to_string().contains("人工智能技能大全"));
    assert!(sent.iter().any(|message| {
        matches!(
            message,
            AgentMessage::TaskComplete { success, summary }
                if *success && summary == "已提交知乎文章发布流程《人工智能技能大全》"
        )
    }));
    assert!(sent.iter().any(|message| {
        matches!(
            message,
            AgentMessage::LogEntry { level, message }
                if level == "info" && message == "call zhihu-write.fill_article_draft"
        )
    }));
    assert!(sent.iter().any(|message| {
        matches!(
            message,
            AgentMessage::Command { action, .. } if action == &Action::Navigate
        )
    }));
    assert!(!sent.iter().any(|message| {
        matches!(
            message,
            AgentMessage::TaskComplete { success, summary }
                if *success && summary.contains("确认发布")
        )
    }));
}

#[test]
fn zhihu_publish_task_matches_primary_orchestration_gate() {
    assert!(
        sgclaw::compat::orchestration::should_use_primary_orchestration(
            "请直接发表这篇知乎文章，标题是测试标题，正文是第一段内容",
            Some("https://www.zhihu.com/"),
            Some("知乎"),
        )
    );
}

#[test]
fn zhihu_article_entry_task_matches_primary_orchestration_gate() {
    assert!(
        sgclaw::compat::orchestration::should_use_primary_orchestration(
            "打开知乎发文章页面",
            Some("https://www.zhihu.com/"),
            Some("知乎"),
        )
    );
}

#[test]
fn zhihu_hotlist_export_routes_prefer_direct_execution() {
    use sgclaw::compat::workflow_executor::{prefers_direct_execution, WorkflowRoute};

    assert!(prefers_direct_execution(
        &WorkflowRoute::ZhihuHotlistExportXlsx
    ));
    assert!(prefers_direct_execution(&WorkflowRoute::ZhihuHotlistScreen));
}

#[test]
fn zhihu_publish_without_article_inputs_returns_missing_fields_prompt() {
    let _guard = env_lock().lock().unwrap_or_else(|err| err.into_inner());

    let workspace_root = temp_workspace_root();
    let config_path = write_deepseek_config_with_skills_dir(
        &workspace_root,
        "deepseek-test-key",
        "http://127.0.0.1:9",
        "deepseek-chat",
        Some(real_skill_lib_root().to_str().unwrap()),
    );
    let runtime_context = AgentRuntimeContext::new(Some(config_path), workspace_root.clone());

    let transport = Arc::new(MockTransport::new(vec![]));
    let browser_tool = BrowserPipeTool::new(
        transport.clone(),
        zhihu_test_policy(),
        vec![1, 2, 3, 4, 5, 6, 7, 8],
    )
    .with_response_timeout(Duration::from_secs(1));

    handle_browser_message_with_context(
        transport.as_ref(),
        &browser_tool,
        &runtime_context,
        BrowserMessage::SubmitTask {
            instruction: "请发表知乎文章".to_string(),
            conversation_id: String::new(),
            messages: vec![],
            page_url: "https://www.zhihu.com/".to_string(),
            page_title: "知乎".to_string(),
        },
    )
    .unwrap();

    let sent = transport.sent_messages();

    assert!(sent.iter().any(|message| {
        matches!(
            message,
            AgentMessage::TaskComplete { success, summary }
                if *success &&
                    summary.contains("标题") &&
                    summary.contains("正文")
        )
    }));
    assert!(!sent
        .iter()
        .any(|message| { matches!(message, AgentMessage::Command { .. }) }));
}

#[test]
fn zhihu_publish_accepts_literal_backslash_n_between_title_and_body() {
    let _guard = env_lock().lock().unwrap_or_else(|err| err.into_inner());

    let workspace_root = temp_workspace_root();
    let config_path = write_deepseek_config_with_skills_dir(
        &workspace_root,
        "deepseek-test-key",
        "http://127.0.0.1:9",
        "deepseek-chat",
        Some(real_skill_lib_root().to_str().unwrap()),
    );
    let runtime_context = AgentRuntimeContext::new(Some(config_path), workspace_root.clone());

    let transport = Arc::new(MockTransport::new(vec![
        success_browser_response(1, json!({ "navigated": true })),
        success_browser_response(
            2,
            json!({
                "text": {
                    "status": "creator_entry_clicked",
                    "current_url": "https://www.zhihu.com/creator",
                    "next_url": "https://zhuanlan.zhihu.com/write"
                }
            }),
        ),
        success_browser_response(3, json!({ "navigated": true })),
        success_browser_response(
            4,
            json!({
                "text": {
                    "status": "editor_ready",
                    "current_url": "https://zhuanlan.zhihu.com/write"
                }
            }),
        ),
        success_browser_response(
            5,
            json!({
                "text": {
                    "status": "draft_ready",
                    "current_url": "https://zhuanlan.zhihu.com/write",
                    "title": "ai时代，普通人如何自救"
                }
            }),
        ),
    ]));
    let browser_tool = BrowserPipeTool::new(
        transport.clone(),
        zhihu_test_policy(),
        vec![1, 2, 3, 4, 5, 6, 7, 8],
    )
    .with_response_timeout(Duration::from_secs(1));

    handle_browser_message_with_context(
        transport.as_ref(),
        &browser_tool,
        &runtime_context,
        BrowserMessage::SubmitTask {
            instruction: "标题：ai时代，普通人如何自救 \\n正文：第一段内容。 第二段内容。"
                .to_string(),
            conversation_id: String::new(),
            messages: vec![],
            page_url: "https://www.zhihu.com/creator".to_string(),
            page_title: "知乎创作中心".to_string(),
        },
    )
    .unwrap();

    let sent = transport.sent_messages();

    assert!(sent.iter().any(|message| {
        matches!(
            message,
            AgentMessage::TaskComplete { success, summary }
                if *success && summary == "已进入知乎文章编辑器并写入草稿《ai时代，普通人如何自救》"
        )
    }));
}

#[test]
fn zhihu_article_entry_opens_editor_without_generic_selector_probing() {
    let _guard = env_lock().lock().unwrap_or_else(|err| err.into_inner());

    let workspace_root = temp_workspace_root();
    let config_path = write_deepseek_config_with_skills_dir(
        &workspace_root,
        "deepseek-test-key",
        "http://127.0.0.1:9",
        "deepseek-chat",
        Some(real_skill_lib_root().to_str().unwrap()),
    );
    let runtime_context = AgentRuntimeContext::new(Some(config_path), workspace_root.clone());

    let transport = Arc::new(MockTransport::new(vec![
        success_browser_response(1, json!({ "navigated": true })),
        success_browser_response(
            2,
            json!({
                "text": {
                    "status": "creator_entry_clicked",
                    "current_url": "https://www.zhihu.com/creator",
                    "next_url": "https://zhuanlan.zhihu.com/write"
                }
            }),
        ),
        success_browser_response(3, json!({ "navigated": true })),
        success_browser_response(
            4,
            json!({
                "text": {
                    "status": "editor_ready",
                    "current_url": "https://zhuanlan.zhihu.com/write"
                }
            }),
        ),
    ]));
    let browser_tool = BrowserPipeTool::new(
        transport.clone(),
        zhihu_test_policy(),
        vec![1, 2, 3, 4, 5, 6, 7, 8],
    )
    .with_response_timeout(Duration::from_secs(1));

    handle_browser_message_with_context(
        transport.as_ref(),
        &browser_tool,
        &runtime_context,
        BrowserMessage::SubmitTask {
            instruction: "打开知乎发文章页面".to_string(),
            conversation_id: String::new(),
            messages: vec![],
            page_url: "https://www.zhihu.com/".to_string(),
            page_title: "知乎".to_string(),
        },
    )
    .unwrap();

    let sent = transport.sent_messages();

    assert!(sent.iter().any(|message| {
        matches!(
            message,
            AgentMessage::TaskComplete { success, summary }
                if *success && summary.contains("编辑器")
        )
    }));
    assert!(sent.iter().any(|message| {
        matches!(
            message,
            AgentMessage::LogEntry { level, message }
                if level == "mode" && message == "zeroclaw_process_message_primary"
        )
    }));
    assert!(!sent.iter().any(|message| {
        matches!(
            message,
            AgentMessage::LogEntry { level, message }
                if level == "info" &&
                    (message.starts_with("getText ") || message.starts_with("click "))
        )
    }));
    assert!(sent.iter().any(|message| {
        matches!(
            message,
            AgentMessage::Command { action, params, .. }
                if action == &Action::Navigate &&
                    params["url"].as_str() == Some("https://zhuanlan.zhihu.com/write")
        )
    }));
}

#[test]
fn zhihu_article_entry_reports_editor_unavailable_without_protocol_error() {
    let _guard = env_lock().lock().unwrap_or_else(|err| err.into_inner());

    let workspace_root = temp_workspace_root();
    let config_path = write_deepseek_config_with_skills_dir(
        &workspace_root,
        "deepseek-test-key",
        "http://127.0.0.1:9",
        "deepseek-chat",
        Some(real_skill_lib_root().to_str().unwrap()),
    );
    let runtime_context = AgentRuntimeContext::new(Some(config_path), workspace_root.clone());

    let transport = Arc::new(MockTransport::new(vec![
        success_browser_response(1, json!({ "navigated": true })),
        success_browser_response(
            2,
            json!({
                "text": {
                    "status": "creator_entry_clicked",
                    "current_url": "https://www.zhihu.com/creator",
                    "next_url": "https://zhuanlan.zhihu.com/write"
                }
            }),
        ),
        success_browser_response(3, json!({ "navigated": true })),
        success_browser_response(
            4,
            json!({
                "text": {
                    "status": "editor_unavailable",
                    "current_url": "https://zhuanlan.zhihu.com/write"
                }
            }),
        ),
    ]));
    let browser_tool = BrowserPipeTool::new(
        transport.clone(),
        zhihu_test_policy(),
        vec![1, 2, 3, 4, 5, 6, 7, 8],
    )
    .with_response_timeout(Duration::from_secs(1));

    handle_browser_message_with_context(
        transport.as_ref(),
        &browser_tool,
        &runtime_context,
        BrowserMessage::SubmitTask {
            instruction: "打开知乎发文章页面".to_string(),
            conversation_id: String::new(),
            messages: vec![],
            page_url: "https://www.zhihu.com/".to_string(),
            page_title: "知乎".to_string(),
        },
    )
    .unwrap();

    let sent = transport.sent_messages();

    assert!(sent.iter().any(|message| {
        matches!(
            message,
            AgentMessage::TaskComplete { success, summary }
                if *success &&
                    summary.contains("未检测到文章编辑器")
        )
    }));
    assert!(sent.iter().any(|message| {
        matches!(
            message,
            AgentMessage::Command { action, params, .. }
                if action == &Action::Navigate &&
                    params["url"].as_str() == Some("https://zhuanlan.zhihu.com/write")
        )
    }));
}

#[test]
fn zhihu_article_entry_stops_when_creator_page_has_no_write_entry() {
    let _guard = env_lock().lock().unwrap_or_else(|err| err.into_inner());

    let workspace_root = temp_workspace_root();
    let config_path = write_deepseek_config_with_skills_dir(
        &workspace_root,
        "deepseek-test-key",
        "http://127.0.0.1:9",
        "deepseek-chat",
        Some(real_skill_lib_root().to_str().unwrap()),
    );
    let runtime_context = AgentRuntimeContext::new(Some(config_path), workspace_root.clone());

    let transport = Arc::new(MockTransport::new(vec![
        success_browser_response(1, json!({ "navigated": true })),
        success_browser_response(
            2,
            json!({
                "text": {
                    "status": "creator_home",
                    "current_url": "https://www.zhihu.com/creator",
                    "desired_target": "article_editor"
                }
            }),
        ),
    ]));
    let browser_tool = BrowserPipeTool::new(
        transport.clone(),
        zhihu_test_policy(),
        vec![1, 2, 3, 4, 5, 6, 7, 8],
    )
    .with_response_timeout(Duration::from_secs(1));

    handle_browser_message_with_context(
        transport.as_ref(),
        &browser_tool,
        &runtime_context,
        BrowserMessage::SubmitTask {
            instruction: "打开知乎发文章页面".to_string(),
            conversation_id: String::new(),
            messages: vec![],
            page_url: "https://www.zhihu.com/".to_string(),
            page_title: "知乎".to_string(),
        },
    )
    .unwrap();

    let sent = transport.sent_messages();

    assert!(sent.iter().any(|message| {
        matches!(
            message,
            AgentMessage::TaskComplete { success, summary }
                if *success && summary.contains("未找到“写文章”入口")
        )
    }));
    assert_eq!(
        sent.iter()
            .filter(|message| matches!(message, AgentMessage::Command { .. }))
            .count(),
        2
    );
    assert!(!sent.iter().any(|message| {
        matches!(
            message,
            AgentMessage::LogEntry { level, message }
                if level == "info" && message == "call zhihu-write.prepare_article_editor"
        )
    }));
}

#[test]
fn zhihu_publish_without_confirmation_returns_confirmation_before_any_browser_probing() {
    let _guard = env_lock().lock().unwrap_or_else(|err| err.into_inner());

    let workspace_root = temp_workspace_root();
    let config_path = write_deepseek_config_with_skills_dir(
        &workspace_root,
        "deepseek-test-key",
        "http://127.0.0.1:9",
        "deepseek-chat",
        Some(real_skill_lib_root().to_str().unwrap()),
    );
    let runtime_context = AgentRuntimeContext::new(Some(config_path), workspace_root.clone());

    let transport = Arc::new(MockTransport::new(vec![]));
    let browser_tool = BrowserPipeTool::new(
        transport.clone(),
        zhihu_test_policy(),
        vec![1, 2, 3, 4, 5, 6, 7, 8],
    )
    .with_response_timeout(Duration::from_secs(1));

    handle_browser_message_with_context(
        transport.as_ref(),
        &browser_tool,
        &runtime_context,
        BrowserMessage::SubmitTask {
            instruction: "请直接发表这篇知乎文章，标题是测试标题，正文是第一段内容".to_string(),
            conversation_id: String::new(),
            messages: vec![],
            page_url: "https://www.zhihu.com/".to_string(),
            page_title: "知乎".to_string(),
        },
    )
    .unwrap();

    let sent = transport.sent_messages();

    assert!(sent.iter().any(|message| {
        matches!(
            message,
            AgentMessage::TaskComplete { success, summary }
                if *success && summary.contains("确认发布")
        )
    }));
    assert!(!sent
        .iter()
        .any(|message| { matches!(message, AgentMessage::Command { .. }) }));
    assert!(!sent.iter().any(|message| {
        matches!(
            message,
            AgentMessage::LogEntry { level, message }
                if level == "info" &&
                    (message.starts_with("navigate ") ||
                        message.starts_with("getText ") ||
                        message.starts_with("click ") ||
                        message.starts_with("type "))
        )
    }));
}

#[test]
fn zhihu_publish_after_confirmation_reports_login_block_without_selector_probing() {
    let _guard = env_lock().lock().unwrap_or_else(|err| err.into_inner());

    let workspace_root = temp_workspace_root();
    let config_path = write_deepseek_config_with_skills_dir(
        &workspace_root,
        "deepseek-test-key",
        "http://127.0.0.1:9",
        "deepseek-chat",
        Some(real_skill_lib_root().to_str().unwrap()),
    );
    let runtime_context = AgentRuntimeContext::new(Some(config_path), workspace_root.clone());

    let transport = Arc::new(MockTransport::new(vec![
        success_browser_response(
            1,
            json!({ "navigated": true, "url": "https://www.zhihu.com/signin?next=%2Fcreator" }),
        ),
        success_browser_response(
            2,
            json!({
                "text": {
                    "status": "login_required",
                    "current_url": "https://www.zhihu.com/signin?next=%2Fcreator"
                }
            }),
        ),
    ]));
    let browser_tool = BrowserPipeTool::new(
        transport.clone(),
        zhihu_test_policy(),
        vec![1, 2, 3, 4, 5, 6, 7, 8],
    )
    .with_response_timeout(Duration::from_secs(1));

    handle_browser_message_with_context(
        transport.as_ref(),
        &browser_tool,
        &runtime_context,
        BrowserMessage::SubmitTask {
            instruction: "确认发布".to_string(),
            conversation_id: "conversation-1".to_string(),
            messages: vec![ConversationMessage {
                role: "user".to_string(),
                content: "请直接发表这篇知乎文章，标题是测试标题，正文是第一段内容".to_string(),
            }],
            page_url: "https://www.zhihu.com/".to_string(),
            page_title: "知乎".to_string(),
        },
    )
    .unwrap();

    let sent = transport.sent_messages();

    assert!(sent.iter().any(|message| {
        matches!(
            message,
            AgentMessage::TaskComplete { success, summary }
                if *success && (summary.contains("未登录") || summary.contains("登录"))
        )
    }));
    assert!(sent.iter().any(|message| {
        matches!(
            message,
            AgentMessage::Command { action, params, .. }
                if action == &Action::Navigate &&
                    params["url"].as_str() == Some("https://www.zhihu.com/creator")
        )
    }));
    assert!(sent.iter().any(|message| {
        matches!(message, AgentMessage::Command { action, .. } if action == &Action::Eval)
    }));
    assert!(!sent.iter().any(|message| {
        matches!(
            message,
            AgentMessage::LogEntry { level, message }
                if level == "info" &&
                    (message.starts_with("getText ") || message.starts_with("click "))
        )
    }));
}

#[test]
fn browser_orchestration_executes_hotlist_export_natively_from_hotlist_page() {
    let _guard = env_lock().lock().unwrap_or_else(|err| err.into_inner());
    std::env::set_var("SGCLAW_DISABLE_POST_EXPORT_OPEN", "1");

    let workspace_root = temp_workspace_root();
    let config_path = write_deepseek_config_with_skills_dir(
        &workspace_root,
        "deepseek-test-key",
        "http://127.0.0.1:9",
        "deepseek-chat",
        Some(real_skill_lib_root().to_str().unwrap()),
    );
    let runtime_context = AgentRuntimeContext::new(Some(config_path), workspace_root.clone());

    let transport = Arc::new(MockTransport::new(vec![
        success_browser_response(
            1,
            json!({ "text": "知乎热榜\n1 问题一 344万热度\n2 问题二 266万热度" }),
        ),
        success_browser_response(
            2,
            json!({
                "text": {
                    "source": "https://www.zhihu.com/hot",
                    "sheet_name": "知乎热榜",
                    "columns": ["rank", "title", "heat"],
                    "rows": [[1, "问题一", "344万"], [2, "问题二", "266万"]]
                }
            }),
        ),
    ]));
    let browser_tool = BrowserPipeTool::new(
        transport.clone(),
        zhihu_test_policy(),
        vec![1, 2, 3, 4, 5, 6, 7, 8],
    )
    .with_response_timeout(Duration::from_secs(1));

    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: "https://www.zhihu.com/hot".to_string(),
            page_title: "知乎热榜".to_string(),
        },
    )
    .unwrap();

    let sent = transport.sent_messages();
    let summary = task_complete_summary(&sent);
    let generated = extract_generated_artifact_path(&summary, ".xlsx");

    assert!(summary.contains(".xlsx"));
    assert!(generated.exists());
    assert!(sent.iter().any(|message| {
        matches!(
            message,
            AgentMessage::LogEntry { level, message }
                if level == "mode" && message == "zeroclaw_process_message_primary"
        )
    }));
    assert!(sent.iter().any(|message| {
        matches!(
            message,
            AgentMessage::LogEntry { level, message }
                if level == "info" && message == "call zhihu-hotlist.extract_hotlist"
        )
    }));
    assert!(sent.iter().any(|message| {
        matches!(
            message,
            AgentMessage::LogEntry { level, message }
                if level == "info" && message == "call openxml_office"
        )
    }));
    assert!(sent.iter().any(|message| {
        matches!(message, AgentMessage::Command { action, .. } if action == &Action::GetText)
    }));
    assert!(sent.iter().any(|message| {
        matches!(message, AgentMessage::Command { action, .. } if action == &Action::Eval)
    }));
    assert!(!sent.iter().any(|message| {
        matches!(message, AgentMessage::Command { action, .. } if action == &Action::Navigate)
    }));
    assert!(!sent.iter().any(|message| {
        matches!(
            message,
            AgentMessage::LogEntry { level, message }
                if level == "mode" && (message == "compat_llm_primary" || message == "compat_skill_runner_primary")
        )
    }));
    std::env::remove_var("SGCLAW_DISABLE_POST_EXPORT_OPEN");
}

#[test]
fn zhihu_export_does_not_use_frontend_owned_mainline() {
    let _guard = env_lock().lock().unwrap_or_else(|err| err.into_inner());

    let workspace_root = temp_workspace_root();
    let config_path = write_deepseek_config_with_skills_dir(
        &workspace_root,
        "deepseek-test-key",
        "http://127.0.0.1:9",
        "deepseek-chat",
        Some(real_skill_lib_root().to_str().unwrap()),
    );
    let runtime_context = AgentRuntimeContext::new(Some(config_path), workspace_root.clone());

    let transport = Arc::new(MockTransport::new(vec![]));
    let browser_tool = BrowserPipeTool::new(
        transport.clone(),
        zhihu_test_policy(),
        vec![1, 2, 3, 4, 5, 6, 7, 8],
    )
    .with_response_timeout(Duration::from_secs(1));

    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: "https://www.zhihu.com/hot".to_string(),
            page_title: "知乎热榜".to_string(),
        },
    )
    .unwrap();

    let sent = transport.sent_messages();

    assert!(sent.iter().any(|message| {
        matches!(
            message,
            AgentMessage::LogEntry { level, message }
                if level == "mode" && message == "zeroclaw_process_message_primary"
        )
    }));
    assert!(!sent.iter().any(|message| {
        matches!(
            message,
            AgentMessage::LogEntry { level, message }
                if level == "mode" &&
                    (message == "compat_llm_primary" || message == "compat_skill_runner_primary")
        )
    }));
}

#[test]
fn browser_skill_usage_is_execution_not_prompt_only() {
    let _guard = env_lock().lock().unwrap_or_else(|err| err.into_inner());
    std::env::set_var("SGCLAW_DISABLE_POST_EXPORT_OPEN", "1");

    let workspace_root = temp_workspace_root();
    let config_path = write_deepseek_config_with_skills_dir(
        &workspace_root,
        "deepseek-test-key",
        "http://127.0.0.1:9",
        "deepseek-chat",
        Some(real_skill_lib_root().to_str().unwrap()),
    );
    let runtime_context = AgentRuntimeContext::new(Some(config_path), workspace_root.clone());

    let transport = Arc::new(MockTransport::new(vec![
        success_browser_response(
            1,
            json!({ "text": "知乎热榜\n1 问题一 344万热度\n2 问题二 266万热度" }),
        ),
        success_browser_response(
            2,
            json!({
                "text": {
                    "source": "https://www.zhihu.com/hot",
                    "sheet_name": "知乎热榜",
                    "columns": ["rank", "title", "heat"],
                    "rows": [[1, "问题一", "344万"], [2, "问题二", "266万"]]
                }
            }),
        ),
    ]));
    let browser_tool = BrowserPipeTool::new(
        transport.clone(),
        zhihu_test_policy(),
        vec![1, 2, 3, 4, 5, 6, 7, 8],
    )
    .with_response_timeout(Duration::from_secs(1));

    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: "https://www.zhihu.com/hot".to_string(),
            page_title: "知乎热榜".to_string(),
        },
    )
    .unwrap();

    let sent = transport.sent_messages();
    let summary = task_complete_summary(&sent);
    let generated = extract_generated_artifact_path(&summary, ".xlsx");

    assert!(summary.contains(".xlsx"));
    assert!(generated.exists());
    assert!(sent.iter().any(|message| {
        matches!(
            message,
            AgentMessage::TaskComplete { success, summary }
                if *success && summary.contains(".xlsx")
        )
    }));
    assert!(sent.iter().any(|message| {
        matches!(
            message,
            AgentMessage::LogEntry { level, message }
                if level == "mode" && message == "zeroclaw_process_message_primary"
        )
    }));
    assert!(sent.iter().any(|message| {
        matches!(
            message,
            AgentMessage::LogEntry { level, message }
                if level == "info" && message == "call openxml_office"
        )
    }));
    assert!(!sent.iter().any(|message| {
        matches!(
            message,
            AgentMessage::LogEntry { level, message }
                if level == "info" && message.starts_with("read_skill ")
        )
    }));
    assert!(sent.iter().any(|message| {
        matches!(message, AgentMessage::Command { action, .. } if action == &Action::GetText)
    }));
    assert!(!sent.iter().any(|message| {
        matches!(
            message,
            AgentMessage::LogEntry { level, message }
                if level == "mode" && (message == "compat_llm_primary" || message == "compat_skill_runner_primary")
        )
    }));
    std::env::remove_var("SGCLAW_DISABLE_POST_EXPORT_OPEN");
}

#[test]
fn handle_browser_message_executes_real_zhihu_navigate_skill_flow() {
    let _guard = env_lock().lock().unwrap_or_else(|err| err.into_inner());

    let first_response = json!({
        "choices": [{
            "message": {
                "content": "",
                "tool_calls": [{
                    "id": "call_1",
                    "type": "function",
                    "function": {
                        "name": "read_skill",
                        "arguments": serde_json::to_string(&json!({
                            "name": "zhihu-navigate"
                        })).unwrap()
                    }
                }]
            }
        }]
    });
    let second_response = json!({
        "choices": [{
            "message": {
                "content": "",
                "tool_calls": [{
                    "id": "call_2",
                    "type": "function",
                    "function": {
                        "name": "browser_action",
                        "arguments": serde_json::to_string(&json!({
                            "action": "navigate",
                            "expected_domain": "www.zhihu.com",
                            "url": "https://www.zhihu.com/hot"
                        })).unwrap()
                    }
                }]
            }
        }]
    });
    let third_response = json!({
        "choices": [{
            "message": {
                "content": "已打开知乎热榜"
            }
        }]
    });
    let (base_url, requests, server_handle) =
        start_fake_deepseek_server(vec![first_response, second_response, third_response]);

    let workspace_root = temp_workspace_root();
    let skills_dir = real_skill_lib_root();
    let config_path = write_deepseek_config_with_skills_dir(
        &workspace_root,
        "deepseek-test-key",
        &base_url,
        "deepseek-chat",
        Some(skills_dir.to_str().unwrap()),
    );
    let runtime_context = AgentRuntimeContext::new(Some(config_path), workspace_root.clone());

    let transport = Arc::new(MockTransport::new(vec![success_browser_response(
        1,
        json!({ "navigated": true }),
    )]));
    let browser_tool = BrowserPipeTool::new(
        transport.clone(),
        zhihu_test_policy(),
        vec![1, 2, 3, 4, 5, 6, 7, 8],
    )
    .with_response_timeout(Duration::from_secs(1));

    handle_browser_message_with_context(
        transport.as_ref(),
        &browser_tool,
        &runtime_context,
        BrowserMessage::SubmitTask {
            instruction: "打开知乎热榜".to_string(),
            conversation_id: String::new(),
            messages: vec![],
            page_url: "https://www.zhihu.com/".to_string(),
            page_title: "知乎".to_string(),
        },
    )
    .unwrap();
    server_handle.join().unwrap();

    let sent = transport.sent_messages();
    let request_bodies = requests.lock().unwrap().clone();
    let tool_content = tool_message_content(&request_bodies[1], "call_1").unwrap();

    assert!(sent.iter().any(|message| {
        matches!(
            message,
            AgentMessage::TaskComplete { success, summary }
                if *success && summary == "已打开知乎热榜"
        )
    }));
    assert!(sent.iter().any(|message| {
        matches!(
            message,
            AgentMessage::LogEntry { level, message }
                if level == "info" && message == "read_skill zhihu-navigate@0.1.0"
        )
    }));
    assert!(sent.iter().any(|message| {
        matches!(
            message,
            AgentMessage::Command { action, params, .. }
                if action == &Action::Navigate &&
                    params["url"].as_str() == Some("https://www.zhihu.com/hot")
        )
    }));
    assert_eq!(request_bodies.len(), 3);
    assert!(tool_content.len() > 100);
    assert!(tool_content.contains("Zhihu page"));
}

#[test]
fn handle_browser_message_executes_real_zhihu_write_skill_flow() {
    let _guard = env_lock().lock().unwrap_or_else(|err| err.into_inner());

    let workspace_root = temp_workspace_root();
    let skills_dir = real_skill_lib_root();
    let config_path = write_deepseek_config_with_skills_dir(
        &workspace_root,
        "deepseek-test-key",
        "http://127.0.0.1:9",
        "deepseek-chat",
        Some(skills_dir.to_str().unwrap()),
    );
    let runtime_context = AgentRuntimeContext::new(Some(config_path), workspace_root.clone());

    let transport = Arc::new(MockTransport::new(vec![
        success_browser_response(1, json!({ "navigated": true })),
        success_browser_response(
            2,
            json!({
                "text": {
                    "status": "creator_entry_clicked",
                    "current_url": "https://www.zhihu.com/creator",
                    "next_url": "https://zhuanlan.zhihu.com/write"
                }
            }),
        ),
        success_browser_response(3, json!({ "navigated": true })),
        success_browser_response(
            4,
            json!({
                "text": {
                    "status": "editor_ready",
                    "current_url": "https://zhuanlan.zhihu.com/write"
                }
            }),
        ),
        success_browser_response(
            5,
            json!({
                "text": {
                    "status": "draft_ready",
                    "current_url": "https://zhuanlan.zhihu.com/write",
                    "title": "测试标题"
                }
            }),
        ),
    ]));
    let browser_tool = BrowserPipeTool::new(
        transport.clone(),
        zhihu_test_policy(),
        vec![1, 2, 3, 4, 5, 6, 7, 8],
    )
    .with_response_timeout(Duration::from_secs(1));

    handle_browser_message_with_context(
        transport.as_ref(),
        &browser_tool,
        &runtime_context,
        BrowserMessage::SubmitTask {
            instruction: "帮我写一篇知乎文章，标题是测试标题，正文是第一段内容".to_string(),
            conversation_id: String::new(),
            messages: vec![],
            page_url: "https://www.zhihu.com/creator".to_string(),
            page_title: "知乎创作中心".to_string(),
        },
    )
    .unwrap();

    let sent = transport.sent_messages();

    assert!(sent.iter().any(|message| {
        matches!(
            message,
            AgentMessage::TaskComplete { success, summary }
                if *success && summary == "已进入知乎文章编辑器并写入草稿《测试标题》"
        )
    }));
    assert!(sent.iter().any(|message| {
        matches!(
            message,
            AgentMessage::LogEntry { level, message }
                if level == "mode" && message == "zeroclaw_process_message_primary"
        )
    }));
    assert!(sent.iter().any(|message| {
        matches!(
            message,
            AgentMessage::LogEntry { level, message }
                if level == "info" && message == "call zhihu-navigate.open_creator_entry"
        )
    }));
    assert!(sent.iter().any(|message| {
        matches!(
            message,
            AgentMessage::LogEntry { level, message }
                if level == "info" && message == "call zhihu-write.prepare_article_editor"
        )
    }));
    assert!(sent.iter().any(|message| {
        matches!(
            message,
            AgentMessage::LogEntry { level, message }
                if level == "info" && message == "call zhihu-write.fill_article_draft"
        )
    }));
    assert!(sent.iter().any(|message| {
        matches!(
            message,
            AgentMessage::Command { action, params, .. }
                if action == &Action::Navigate &&
                    params["url"].as_str() == Some("https://www.zhihu.com/creator")
        )
    }));
    assert!(sent.iter().any(|message| {
        matches!(
            message,
            AgentMessage::Command { action, params, .. }
                if action == &Action::Navigate &&
                    params["url"].as_str() == Some("https://zhuanlan.zhihu.com/write")
        )
    }));
    assert!(
        sent.iter()
            .filter(|message| {
                matches!(message, AgentMessage::Command { action, .. } if action == &Action::Eval)
            })
            .count()
            >= 2
    );
    assert!(!sent.iter().any(|message| {
        matches!(
            message,
            AgentMessage::LogEntry { level, message }
                if level == "mode" && (message == "compat_llm_primary" || message == "compat_skill_runner_primary")
        )
    }));
}

fn staged_lineloss_skills_root() -> PathBuf {
    PathBuf::from("D:/data/ideaSpace/rust/sgClaw/claw/claw/skills/skill_staging/skills")
}

fn build_fault_details_direct_skill_root() -> PathBuf {
    let root = temp_workspace_root();
    let skill_dir = write_skill_manifest_package(
        &root,
        "fault-details-report",
        r#"
[skill]
name = "fault-details-report"
description = "Collect 95598 fault detail data via browser eval."
version = "0.1.0"

[[tools]]
name = "collect_fault_details"
description = "Collect structured fault detail rows for a specific period."
kind = "browser_script"
command = "scripts/collect_fault_details.js"

[tools.args]
period = "YYYY-MM period to collect."
"#,
    );
    write_skill_script(
        &skill_dir,
        "scripts/collect_fault_details.js",
        r#"
return {
  fault_type: "outage",
  observed_at: `${args.period}-15 09:00`,
  affected_scope: "line-7"
};
"#,
    );
    root
}

#[test]
fn deterministic_lineloss_runtime_passes_canonical_args_to_browser_script_tool() {
    let _guard = env_lock().lock().unwrap_or_else(|err| err.into_inner());

    let workspace_root = temp_workspace_root();
    let config_path = write_deepseek_config_with_skills_dir(
        &workspace_root,
        "deepseek-test-key",
        "http://127.0.0.1:9",
        "deepseek-chat",
        Some(staged_lineloss_skills_root().to_str().unwrap()),
    );
    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": "2026-03",
                    "payload": {
                        "fdate": "2026-03"
                    }
                },
                "rows": [
                    { "ORG_NAME": "国网兰州供电公司", "LINE_LOSS_RATE": "3.21" }
                ],
                "counts": {
                    "rows": 1
                },
                "reasons": []
            }
        }),
    )]));
    let browser_tool = BrowserPipeTool::new(
        transport.clone(),
        policy_for_domains(&["20.76.57.61"]),
        vec![1, 2, 3, 4, 5, 6, 7, 8],
    )
    .with_response_timeout(Duration::from_secs(1));

    handle_browser_message_with_context(
        transport.as_ref(),
        &browser_tool,
        &runtime_context,
        BrowserMessage::SubmitTask {
            instruction: "兰州公司 月累计 2026-03。。。".to_string(),
            conversation_id: String::new(),
            messages: vec![],
            page_url: "http://20.76.57.61:8080/#/lineloss".to_string(),
            page_title: "台区线损报表".to_string(),
        },
    )
    .unwrap();

    let sent = transport.sent_messages();

    assert!(sent.iter().any(|message| {
        matches!(
            message,
            AgentMessage::LogEntry { level, message }
                if level == "mode" && message == "direct_skill_primary"
        )
    }));
    assert!(sent.iter().any(|message| {
        matches!(
            message,
            AgentMessage::TaskComplete { success, summary }
                if *success
                    && summary.contains("tq-lineloss-report")
                    && summary.contains("国网兰州供电公司")
                    && summary.contains("2026-03")
                    && 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("\"org_label\":\"国网兰州供电公司\"")
                            && script.contains("\"org_code\":\"62401\"")
                            && script.contains("\"period_mode\":\"month\"")
                            && script.contains("\"period_mode_code\":\"1\"")
                            && script.contains("\"period_value\":\"2026-03\"")
                            && script.contains("fdate")
                    )
        )
    }));
}

#[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(
        &workspace_root,
        "deepseek-test-key",
        "http://127.0.0.1:9",
        "deepseek-chat",
        Some(staged_lineloss_skills_root().to_str().unwrap()),
    );
    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 browser_tool = BrowserPipeTool::new(
        transport.clone(),
        policy_for_domains(&["20.76.57.61"]),
        vec![1, 2, 3, 4, 5, 6, 7, 8],
    )
    .with_response_timeout(Duration::from_secs(1));

    handle_browser_message_with_context(
        transport.as_ref(),
        &browser_tool,
        &runtime_context,
        BrowserMessage::SubmitTask {
            instruction: "兰州公司 月累计。。。".to_string(),
            conversation_id: String::new(),
            messages: vec![],
            page_url: "http://20.76.57.61:8080/#/lineloss".to_string(),
            page_title: "台区线损报表".to_string(),
        },
    )
    .unwrap();

    let sent = transport.sent_messages();

    assert!(sent.iter().any(|message| {
        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()))
                    )
        )
    }), "sent messages were: {sent:?}");
}

#[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(
        &workspace_root,
        "deepseek-test-key",
        "http://127.0.0.1:9",
        "deepseek-chat",
        Some(staged_lineloss_skills_root().to_str().unwrap()),
    );
    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 browser_tool = BrowserPipeTool::new(
        transport.clone(),
        policy_for_domains(&["20.76.57.61"]),
        vec![1, 2, 3, 4, 5, 6, 7, 8],
    )
    .with_response_timeout(Duration::from_secs(1));

    handle_browser_message_with_context(
        transport.as_ref(),
        &browser_tool,
        &runtime_context,
        BrowserMessage::SubmitTask {
            instruction: "兰州公司 周累计。。。".to_string(),
            conversation_id: String::new(),
            messages: vec![],
            page_url: "http://20.76.57.61:8080/#/lineloss".to_string(),
            page_title: "台区线损报表".to_string(),
        },
    )
    .unwrap();

    let sent = transport.sent_messages();

    assert!(sent.iter().any(|message| {
        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))
                    )
        )
    }), "sent messages were: {sent:?}");
}

#[test]
fn deterministic_lineloss_missing_company_prompt_skips_browser_execution() {
    let _guard = env_lock().lock().unwrap_or_else(|err| err.into_inner());

    let workspace_root = temp_workspace_root();
    let config_path = write_deepseek_config_with_skills_dir(
        &workspace_root,
        "deepseek-test-key",
        "http://127.0.0.1:9",
        "deepseek-chat",
        Some(staged_lineloss_skills_root().to_str().unwrap()),
    );
    let runtime_context = AgentRuntimeContext::new(Some(config_path), workspace_root.clone());

    let transport = Arc::new(MockTransport::new(vec![]));
    let browser_tool = BrowserPipeTool::new(
        transport.clone(),
        policy_for_domains(&["20.76.57.61"]),
        vec![1, 2, 3, 4, 5, 6, 7, 8],
    )
    .with_response_timeout(Duration::from_secs(1));

    handle_browser_message_with_context(
        transport.as_ref(),
        &browser_tool,
        &runtime_context,
        BrowserMessage::SubmitTask {
            instruction: "月累计 2026-03。。。".to_string(),
            conversation_id: String::new(),
            messages: vec![],
            page_url: "http://20.76.57.61:8080/#/lineloss".to_string(),
            page_title: "台区线损报表".to_string(),
        },
    )
    .unwrap();

    let sent = transport.sent_messages();

    assert!(sent.iter().any(|message| {
        matches!(
            message,
            AgentMessage::TaskComplete { success, summary }
                if !*success && (summary.contains("缺少供电单位") || summary.contains("兰州公司"))
        )
    }));
    assert!(!sent.iter().any(|message| matches!(message, AgentMessage::Command { .. })));
}

#[test]
fn deterministic_lineloss_runtime_maps_partial_artifact_to_success_summary() {
    let _guard = env_lock().lock().unwrap_or_else(|err| err.into_inner());

    let workspace_root = temp_workspace_root();
    let config_path = write_deepseek_config_with_skills_dir(
        &workspace_root,
        "deepseek-test-key",
        "http://127.0.0.1:9",
        "deepseek-chat",
        Some(staged_lineloss_skills_root().to_str().unwrap()),
    );
    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": "partial",
                "org": {
                    "label": "国网兰州供电公司",
                    "code": "62401"
                },
                "period": {
                    "mode": "month",
                    "mode_code": "1",
                    "value": "2026-03",
                    "payload": {
                        "fdate": "2026-03"
                    }
                },
                "rows": [
                    { "ORG_NAME": "国网兰州供电公司", "LINE_LOSS_RATE": "3.21" }
                ],
                "counts": {
                    "rows": 1
                },
                "reasons": ["report_log_failed"]
            }
        }),
    )]));
    let browser_tool = BrowserPipeTool::new(
        transport.clone(),
        policy_for_domains(&["20.76.57.61"]),
        vec![1, 2, 3, 4, 5, 6, 7, 8],
    )
    .with_response_timeout(Duration::from_secs(1));

    handle_browser_message_with_context(
        transport.as_ref(),
        &browser_tool,
        &runtime_context,
        BrowserMessage::SubmitTask {
            instruction: "兰州公司 月累计 2026-03。。。".to_string(),
            conversation_id: String::new(),
            messages: vec![],
            page_url: "http://20.76.57.61:8080/#/lineloss".to_string(),
            page_title: "台区线损报表".to_string(),
        },
    )
    .unwrap();

    let sent = transport.sent_messages();

    assert!(sent.iter().any(|message| {
        matches!(
            message,
            AgentMessage::TaskComplete { success, summary }
                if *success
                    && summary.contains("status=partial")
                    && summary.contains("rows=1")
                    && summary.contains("reasons=report_log_failed")
        )
    }));
}

#[test]
fn deterministic_lineloss_runtime_maps_blocked_artifact_to_failed_completion() {
    let _guard = env_lock().lock().unwrap_or_else(|err| err.into_inner());

    let workspace_root = temp_workspace_root();
    let config_path = write_deepseek_config_with_skills_dir(
        &workspace_root,
        "deepseek-test-key",
        "http://127.0.0.1:9",
        "deepseek-chat",
        Some(staged_lineloss_skills_root().to_str().unwrap()),
    );
    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": "blocked",
                "org": {
                    "label": "国网兰州供电公司",
                    "code": "62401"
                },
                "period": {
                    "mode": "month",
                    "mode_code": "1",
                    "value": "2026-03",
                    "payload": {
                        "fdate": "2026-03"
                    }
                },
                "rows": [],
                "counts": {
                    "rows": 0
                },
                "reasons": ["selected_range_unavailable"]
            }
        }),
    )]));
    let browser_tool = BrowserPipeTool::new(
        transport.clone(),
        policy_for_domains(&["20.76.57.61"]),
        vec![1, 2, 3, 4, 5, 6, 7, 8],
    )
    .with_response_timeout(Duration::from_secs(1));

    handle_browser_message_with_context(
        transport.as_ref(),
        &browser_tool,
        &runtime_context,
        BrowserMessage::SubmitTask {
            instruction: "兰州公司 月累计 2026-03。。。".to_string(),
            conversation_id: String::new(),
            messages: vec![],
            page_url: "http://20.76.57.61:8080/#/lineloss".to_string(),
            page_title: "台区线损报表".to_string(),
        },
    )
    .unwrap();

    let sent = transport.sent_messages();

    assert!(sent.iter().any(|message| {
        matches!(
            message,
            AgentMessage::TaskComplete { success, summary }
                if !*success
                    && summary.contains("status=blocked")
                    && summary.contains("reasons=selected_range_unavailable")
        )
    }));
}

#[test]
fn deterministic_suffix_non_lineloss_request_does_not_fall_into_zhihu_logic() {
    let _guard = env_lock().lock().unwrap_or_else(|err| err.into_inner());

    let workspace_root = temp_workspace_root();
    let config_path = write_deepseek_config_with_skills_dir(
        &workspace_root,
        "deepseek-test-key",
        "http://127.0.0.1:9",
        "deepseek-chat",
        Some(real_skill_lib_root().to_str().unwrap()),
    );
    let runtime_context = AgentRuntimeContext::new(Some(config_path), workspace_root.clone());

    let transport = Arc::new(MockTransport::new(vec![]));
    let browser_tool = BrowserPipeTool::new(
        transport.clone(),
        zhihu_test_policy(),
        vec![1, 2, 3, 4, 5, 6, 7, 8],
    )
    .with_response_timeout(Duration::from_secs(1));

    handle_browser_message_with_context(
        transport.as_ref(),
        &browser_tool,
        &runtime_context,
        BrowserMessage::SubmitTask {
            instruction: "打开知乎热榜。。。".to_string(),
            conversation_id: String::new(),
            messages: vec![],
            page_url: "https://www.zhihu.com/hot".to_string(),
            page_title: "知乎热榜".to_string(),
        },
    )
    .unwrap();

    let sent = transport.sent_messages();

    assert!(sent.iter().any(|message| {
        matches!(
            message,
            AgentMessage::TaskComplete { success, summary }
                if !*success && summary.contains("台区线损")
        )
    }));
    assert!(!sent.iter().any(|message| matches!(message, AgentMessage::Command { .. })));
    assert!(!sent.iter().any(|message| {
        matches!(
            message,
            AgentMessage::LogEntry { level, message }
                if level == "mode"
                    && (message == "zeroclaw_process_message_primary"
                        || message == "compat_llm_primary")
        )
    }));
}

#[test]
fn existing_fault_details_direct_browser_script_path_remains_unchanged() {
    let _guard = env_lock().lock().unwrap_or_else(|err| err.into_inner());

    let skill_root = build_fault_details_direct_skill_root();
    let workspace_root = temp_workspace_root();
    let config_path = write_deepseek_config_with_direct_submit_skill(
        &workspace_root,
        "deepseek-test-key",
        "http://127.0.0.1:9",
        "deepseek-chat",
        Some(skill_root.to_str().unwrap()),
        Some("fault-details-report.collect_fault_details"),
    );
    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": "fault-details-report",
                "period": "2026-03",
                "counts": {
                    "detail_rows": 1,
                    "summary_rows": 1
                },
                "rows": [{ "qxdbh": "QX-1" }],
                "sections": [{
                    "name": "summary-sheet",
                    "rows": [{ "index": 1 }]
                }],
                "status": "partial",
                "partial_reasons": ["report_log_failed"]
            }
        }),
    )]));
    let browser_tool = BrowserPipeTool::new(
        transport.clone(),
        policy_for_domains(&["95598.sgcc.com.cn"]),
        vec![1, 2, 3, 4, 5, 6, 7, 8],
    )
    .with_response_timeout(Duration::from_secs(1));

    handle_browser_message_with_context(
        transport.as_ref(),
        &browser_tool,
        &runtime_context,
        BrowserMessage::SubmitTask {
            instruction: "请采集 2026-03 的故障明细并返回结果".to_string(),
            conversation_id: String::new(),
            messages: vec![],
            page_url: "https://95598.sgcc.com.cn/".to_string(),
            page_title: "网上国网".to_string(),
        },
    )
    .unwrap();

    let sent = transport.sent_messages();

    assert!(sent.iter().any(|message| {
        matches!(
            message,
            AgentMessage::LogEntry { level, message }
                if level == "mode" && message == "direct_skill_primary"
        )
    }));
    assert!(sent.iter().any(|message| {
        matches!(
            message,
            AgentMessage::TaskComplete { success, summary }
                if *success
                    && summary.contains("fault-details-report")
                    && summary.contains("status=partial")
                    && summary.contains("detail_rows=1")
                    && summary.contains("summary_rows=1")
                    && summary.contains("report_log_failed")
        )
    }));
    assert!(sent.iter().any(|message| {
        matches!(
            message,
            AgentMessage::Command {
                action,
                params,
                security,
                ..
            }
                if action == &Action::Eval
                    && security.expected_domain == "95598.sgcc.com.cn"
                    && params["script"].as_str().is_some_and(|script|
                        script.contains("\"period\":\"2026-03\"")
                    )
        )
    }));
}
