use openai_tools::common::models::RealtimeModel;
use openai_tools::common::{parameters::ParameterProperty, tool::Tool};
use openai_tools::realtime::events::server::ServerEvent;
use openai_tools::realtime::vad::ServerVadConfig;
use openai_tools::realtime::{Modality, RealtimeClient, Voice};
#[tokio::test]
async fn test_realtime_connection() {
let mut client = RealtimeClient::new();
client.model(RealtimeModel::GptRealtime_2025_08_28);
let session_result = client.connect().await;
match session_result {
Ok(mut session) => {
session.close().await.expect("Should close cleanly");
}
Err(e) => {
eprintln!("Connection failed (expected if no API key): {}", e);
}
}
}
#[tokio::test]
async fn test_text_conversation() {
let mut client = RealtimeClient::new();
client
.model(RealtimeModel::GptRealtime_2025_08_28)
.modalities(vec![Modality::Text])
.instructions("You are a helpful assistant. Keep responses brief.");
let session_result = client.connect().await;
match session_result {
Ok(mut session) => {
session.send_text("Hello! Please respond with just 'Hi there!'").await.expect("Should send text");
session.create_response(None).await.expect("Should create response");
let mut response_text = String::new();
let mut received_response = false;
let timeout = tokio::time::Duration::from_secs(30);
let start = tokio::time::Instant::now();
while start.elapsed() < timeout {
match tokio::time::timeout(tokio::time::Duration::from_secs(5), session.recv()).await {
Ok(Ok(Some(event))) => match event {
ServerEvent::ResponseTextDelta(e) => {
response_text.push_str(&e.delta);
}
ServerEvent::ResponseTextDone(_) => {
received_response = true;
}
ServerEvent::ResponseDone(_) => {
break;
}
ServerEvent::Error(e) => {
panic!("Error from API: {}", e.error.message);
}
_ => {}
},
Ok(Ok(None)) => {
break; }
Ok(Err(e)) => {
panic!("Error receiving event: {}", e);
}
Err(_) => {
break;
}
}
}
assert!(received_response, "Should receive a response");
assert!(!response_text.is_empty(), "Response should not be empty");
println!("Response: {}", response_text);
session.close().await.expect("Should close cleanly");
}
Err(e) => {
eprintln!("Connection failed (expected if no API key): {}", e);
}
}
}
#[tokio::test]
async fn test_function_calling() {
let weather_tool = Tool::function(
"get_weather",
"Get the current weather for a location",
vec![("location", ParameterProperty::from_string("The city name"))],
false,
);
let mut client = RealtimeClient::new();
client
.model(RealtimeModel::GptRealtime_2025_08_28)
.modalities(vec![Modality::Text])
.tools(vec![weather_tool])
.instructions("You are a helpful assistant with access to weather information.");
let session_result = client.connect().await;
match session_result {
Ok(mut session) => {
session.send_text("What's the weather like in Tokyo?").await.expect("Should send text");
session.create_response(None).await.expect("Should create response");
let mut received_function_call = false;
let timeout = tokio::time::Duration::from_secs(30);
let start = tokio::time::Instant::now();
while start.elapsed() < timeout {
match tokio::time::timeout(tokio::time::Duration::from_secs(5), session.recv()).await {
Ok(Ok(Some(event))) => match event {
ServerEvent::ResponseFunctionCallArgumentsDone(e) => {
assert_eq!(e.name, "get_weather");
received_function_call = true;
let result = r#"{"temperature": "22C", "condition": "sunny", "humidity": "45%"}"#;
session.submit_function_output(&e.call_id, result).await.expect("Should submit function output");
session.create_response(None).await.expect("Should create follow-up response");
}
ServerEvent::ResponseDone(_) => {
if received_function_call {
break; }
}
ServerEvent::Error(e) => {
panic!("Error from API: {}", e.error.message);
}
_ => {}
},
Ok(Ok(None)) => break,
Ok(Err(e)) => panic!("Error: {}", e),
Err(_) => break,
}
}
println!("Function call received: {} (may vary based on model behavior)", received_function_call);
session.close().await.expect("Should close cleanly");
}
Err(e) => {
eprintln!("Connection failed (expected if no API key): {}", e);
}
}
}
#[tokio::test]
async fn test_session_update() {
let mut client = RealtimeClient::new();
client.model(RealtimeModel::GptRealtime_2025_08_28);
let session_result = client.connect().await;
match session_result {
Ok(mut session) => {
use openai_tools::realtime::SessionConfig;
let new_config = SessionConfig::new()
.with_modalities(vec![Modality::Text])
.with_instructions("You are a pirate. Speak like one!")
.with_temperature(0.9);
session.update_session(new_config).await.expect("Should update session");
let timeout = tokio::time::Duration::from_secs(10);
let start = tokio::time::Instant::now();
let mut updated = false;
while start.elapsed() < timeout {
match tokio::time::timeout(tokio::time::Duration::from_secs(2), session.recv()).await {
Ok(Ok(Some(ServerEvent::SessionUpdated(_)))) => {
updated = true;
break;
}
Ok(Ok(Some(ServerEvent::Error(e)))) => {
panic!("Error: {}", e.error.message);
}
_ => continue,
}
}
assert!(updated, "Should receive session.updated event");
session.close().await.expect("Should close cleanly");
}
Err(e) => {
eprintln!("Connection failed (expected if no API key): {}", e);
}
}
}
#[tokio::test]
async fn test_audio_configuration() {
use openai_tools::realtime::AudioFormat;
let mut client = RealtimeClient::new();
client
.model(RealtimeModel::GptRealtime_2025_08_28)
.modalities(vec![Modality::Text, Modality::Audio])
.voice(Voice::Alloy)
.input_audio_format(AudioFormat::Pcm16)
.output_audio_format(AudioFormat::Pcm16)
.server_vad(ServerVadConfig { threshold: Some(0.5), silence_duration_ms: Some(500), ..Default::default() });
let session_result = client.connect().await;
match session_result {
Ok(mut session) => {
session.close().await.expect("Should close cleanly");
println!("Audio-configured session connected successfully");
}
Err(e) => {
eprintln!("Connection failed (expected if no API key): {}", e);
}
}
}