use std::sync::{Mutex, OnceLock}; use serde_json::json; use sgclaw::config::DeepSeekSettings; use sgclaw::llm::{ChatMessage, DeepSeekProvider, ToolDefinition}; fn env_lock() -> &'static Mutex<()> { static LOCK: OnceLock> = OnceLock::new(); LOCK.get_or_init(|| Mutex::new(())) } #[test] fn deepseek_settings_load_defaults_from_env() { let _guard = env_lock().lock().unwrap(); std::env::set_var("DEEPSEEK_API_KEY", "test-key"); std::env::remove_var("DEEPSEEK_BASE_URL"); std::env::remove_var("DEEPSEEK_MODEL"); let settings = DeepSeekSettings::from_env().unwrap(); assert_eq!(settings.api_key, "test-key"); assert_eq!(settings.base_url, "https://api.deepseek.com"); assert_eq!(settings.model, "deepseek-chat"); } #[test] fn deepseek_request_shape_matches_openai_compatible_chat_format() { let provider = DeepSeekProvider::new(DeepSeekSettings { api_key: "test-key".to_string(), base_url: "https://api.deepseek.com".to_string(), model: "deepseek-chat".to_string(), }); let messages = vec![ ChatMessage { role: "system".to_string(), content: "You are sgClaw.".to_string(), }, ChatMessage { role: "user".to_string(), content: "打开百度搜索天气".to_string(), }, ]; let tools = vec![ToolDefinition { name: "browser_action".to_string(), description: "Execute browser actions".to_string(), parameters: json!({ "type": "object", "properties": { "action": { "type": "string" } }, "required": ["action"] }), }]; let request = provider.build_chat_request(&messages, &tools); let serialized = serde_json::to_value(&request).unwrap(); assert_eq!(serialized["model"], "deepseek-chat"); assert_eq!(serialized["stream"], false); assert_eq!(serialized["messages"][0]["role"], "system"); assert_eq!(serialized["messages"][1]["content"], "打开百度搜索天气"); assert_eq!(serialized["tools"][0]["type"], "function"); assert_eq!( serialized["tools"][0]["function"]["name"], "browser_action" ); }