#[cfg(test)]
mod tests {
use dotenv::dotenv;
use llm_bridge::client::{ClientLlm, LlmClient};
use llm_bridge::error::ApiError;
use pretty_assertions::{assert_eq};
#[tokio::test]
async fn test_send_message_anthropic() {
dotenv().ok();
let api_key = std::env::var("ANTHROPIC_API_KEY")
.expect("ANTHROPIC_API_KEY must be set.");
let client_type = ClientLlm::Anthropic;
let mut client = LlmClient::new(client_type, api_key);
let response = client
.request()
.model("claude-3-haiku-20240307")
.user_message("Hello, Claude!")
.max_tokens(100)
.temperature(1.0)
.system_prompt("You are a haiku assistant.") .send()
.await
.expect("Failed to send message");
println!("Response: {:?}", response);
assert_eq!(response.role(), "assistant");
assert_eq!(response.model(), "claude-3-haiku-20240307");
assert_eq!(response.stop_reason(), "end_turn");
assert_eq!(response.usage().input_tokens, 18);
assert!(response.usage().output_tokens > 0);
assert!(!response.first_message().is_empty());
if let ResponseMessage::OpenAI(_) = response {
panic!("Expected Anthropic response, but received OpenAI response");
}
}
#[tokio::test]
async fn test_send_message_openai() {
dotenv().ok();
let api_key = std::env::var("OPENAI_API_KEY")
.expect("ANTHROPIC_API_KEY must be set.");
let client_type = ClientLlm::OpenAI;
let mut client = LlmClient::new(client_type, api_key);
let response = client
.request()
.model("gpt-4o")
.user_message("Hello, GPT!")
.max_tokens(100)
.temperature(1.0)
.system_prompt("You are a haiku assistant.") .send()
.await
.expect("Failed to send message");
println!("Response: {:?}", response);
assert_eq!(response.role(), "assistant");
assert!(response.model().starts_with("gpt-4o"));
assert_eq!(response.stop_reason(), "stop");
assert_eq!(response.usage().input_tokens, 22);
assert!(response.usage().output_tokens > 0);
assert!(!response.first_message().is_empty());
if let ResponseMessage::Anthropic(_) = response {
panic!("Expected Anthropic response, but received Anthropic response");
}
}
#[tokio::test]
async fn test_invalid_api_key() {
let api_key = "i am invalid".to_string();
let client_type = ClientLlm::Anthropic;
let mut client = LlmClient::new(client_type, api_key);
let response = client
.request()
.user_message("Hello, Claude!")
.send()
.await;
assert!(matches!(response, Err(ApiError::ClientError(_))));
}
use std::sync::{Arc, Mutex};
use std::thread;
use llm_bridge::response::ResponseMessage;
use llm_bridge::tool::Tool;
#[tokio::test]
async fn test_llm_client_sync() {
let api_key = "mock_api_key".to_string();
let client_type = ClientLlm::Anthropic;
let llm_client = LlmClient::new(client_type, api_key);
let shared_client = Arc::new(Mutex::new(llm_client));
let mut handles = vec![];
for _ in 0..4 {
let client = shared_client.clone();
let handle = thread::spawn(move || {
let mut client_guard = client.lock().unwrap();
let request_builder = client_guard
.request()
.model("claude-3-haiku-20240307")
.user_message("Hello, Claude!")
.max_tokens(100)
.temperature(1.0)
.system_prompt("You are a haiku assistant.");
});
handles.push(handle);
}
for handle in handles {
handle.join().expect("Thread panicked");
}
}
#[tokio::test]
async fn test_tool_use_anthropic() {
dotenv().ok();
let api_key = std::env::var("ANTHROPIC_API_KEY")
.expect("ANTHROPIC_API_KEY must be set.");
let client_type = ClientLlm::Anthropic;
let mut client = LlmClient::new(client_type, api_key);
let tool = Tool::builder()
.name("get_weather")
.description("Get the current weather in a given location")
.add_parameter("location", "string", "The city and state, e.g. San Francisco, CA", true)
.add_enum_parameter("unit", "The unit of temperature, either 'celsius' or 'fahrenheit'", false, vec!["celsius".to_string(), "fahrenheit".to_string()])
.build()
.expect("Failed to build tool");
let response = client
.request()
.add_tool(tool)
.model("claude-3-haiku-20240307")
.user_message("What is the current weather in San Francisco, California")
.max_tokens(100)
.temperature(1.0)
.system_prompt("You are a weather assistant.")
.send()
.await
.expect("Failed to send message");
assert_eq!(response.stop_reason(), "tool_use");
if let Some(tools) = response.tools() {
assert_eq!(tools.len(), 1);
assert_eq!(tools[0].name, "get_weather");
assert_eq!(tools[0].input["location"], "San Francisco, CA");
} else {
panic!("Expected tool use, but no tools were returned");
}
}
#[tokio::test]
async fn test_tool_use_gpt() {
dotenv().ok();
let api_key = std::env::var("OPENAI_API_KEY")
.expect("OPENAI_API_KEY must be set.");
let client_type = ClientLlm::OpenAI;
let mut client = LlmClient::new(client_type, api_key);
let tool = Tool::builder()
.name("get_weather")
.description("Get the current weather in a given location")
.add_parameter("location", "string", "The city and state, e.g. San Francisco, CA", true)
.add_enum_parameter("unit", "The unit of temperature, either 'celsius' or 'fahrenheit'", false, vec!["celsius".to_string(), "fahrenheit".to_string()])
.build()
.expect("Failed to build tool");
let response = client
.request()
.add_tool(tool)
.model("gpt-4o")
.user_message("What is the current weather in San Francisco, California")
.max_tokens(100)
.temperature(1.0)
.system_prompt("You are a weather assistant.")
.send()
.await
.expect("Failed to send message");
assert_eq!(response.stop_reason(), "tool_calls");
if let Some(tools) = response.tools() {
assert_eq!(tools.len(), 1);
assert_eq!(tools[0].name, "get_weather");
assert_eq!(tools[0].input["location"], "San Francisco, CA");
} else {
panic!("Expected tool use, but no tools were returned");
}
}
}