An AI agent built to do Ralph loops - plan mode for planning and ralph mode for implementing.
at main 116 lines 3.4 kB view raw
1use rustagent::llm::{Message, ToolDefinition}; 2use serde_json::json; 3 4#[test] 5fn test_message_serialization() { 6 let msg = Message::user("Hello"); 7 8 let json = serde_json::to_value(&msg).unwrap(); 9 assert_eq!(json["role"], "user"); 10 assert_eq!(json["content"], "Hello"); 11} 12 13#[test] 14fn test_tool_definition_parameters() { 15 let tool = ToolDefinition { 16 name: "read_file".to_string(), 17 description: "Read a file".to_string(), 18 parameters: json!({ 19 "type": "object", 20 "properties": { 21 "path": {"type": "string"} 22 }, 23 "required": ["path"] 24 }), 25 }; 26 27 assert_eq!(tool.name, "read_file"); 28} 29 30use rustagent::llm::anthropic::AnthropicClient; 31 32#[tokio::test] 33async fn test_anthropic_message_format() { 34 // This test validates request structure, doesn't actually call API 35 let client = AnthropicClient::new("test-key".to_string(), "claude-sonnet-4".to_string(), 4096); 36 37 let messages = vec![Message::user("Hello")]; 38 39 // We'll test this by mocking in future, for now just construct 40 assert!(client.format_request(&messages, &[]).is_ok()); 41} 42 43#[test] 44fn test_format_request_with_system_message() { 45 let client = AnthropicClient::new("test-key".to_string(), "claude-sonnet-4".to_string(), 4096); 46 47 let messages = vec![ 48 Message::system("You are a helpful assistant"), 49 Message::user("Hello"), 50 ]; 51 52 let request = client.format_request(&messages, &[]).unwrap(); 53 54 // Should have system field 55 assert!(request.get("system").is_some()); 56 assert_eq!( 57 request.get("system").unwrap().as_str().unwrap(), 58 "You are a helpful assistant" 59 ); 60 61 // Should not include system message in messages array 62 let msgs = request.get("messages").unwrap().as_array().unwrap(); 63 assert_eq!(msgs.len(), 1); 64 assert_eq!(msgs[0].get("role").unwrap().as_str().unwrap(), "user"); 65} 66 67use reqwest::StatusCode; 68use rustagent::llm::error::{ErrorKind, classify_status}; 69use rustagent::llm::retry::parse_retry_from_message; 70 71#[test] 72fn test_classify_status_retryable() { 73 assert_eq!( 74 classify_status(StatusCode::TOO_MANY_REQUESTS), 75 ErrorKind::RateLimited 76 ); 77 assert_eq!( 78 classify_status(StatusCode::BAD_GATEWAY), 79 ErrorKind::Transient 80 ); 81 assert_eq!( 82 classify_status(StatusCode::SERVICE_UNAVAILABLE), 83 ErrorKind::Transient 84 ); 85 assert_eq!( 86 classify_status(StatusCode::GATEWAY_TIMEOUT), 87 ErrorKind::Transient 88 ); 89 assert_eq!( 90 classify_status(StatusCode::REQUEST_TIMEOUT), 91 ErrorKind::Transient 92 ); 93} 94 95#[test] 96fn test_classify_status_non_retryable() { 97 assert_eq!( 98 classify_status(StatusCode::BAD_REQUEST), 99 ErrorKind::BadRequest 100 ); 101 assert_eq!(classify_status(StatusCode::UNAUTHORIZED), ErrorKind::Auth); 102 assert_eq!(classify_status(StatusCode::FORBIDDEN), ErrorKind::Auth); 103} 104 105#[test] 106fn test_parse_retry_from_message() { 107 let msg = "Rate limit reached. Please try again in 45.622s."; 108 let dur = parse_retry_from_message(msg).unwrap(); 109 assert!(dur.as_millis() >= 45000 && dur.as_millis() <= 46000); 110 111 let msg2 = "Try again in 500ms"; 112 let dur2 = parse_retry_from_message(msg2).unwrap(); 113 assert_eq!(dur2.as_millis(), 500); 114 115 assert!(parse_retry_from_message("Something went wrong").is_none()); 116}