use std::collections::VecDeque;
use serde::{ser::SerializeStruct, Deserialize, Serialize, Serializer};
use super::function::ToolDef;
use super::prompt::{Choice, Message};
#[derive(Debug, Clone)]
pub struct APIResponseHeaders {
pub retry_after: Option<u64>,
pub reset: Option<u64>,
pub rate_limit: Option<u64>,
pub limit: Option<u64>,
pub extra_other: Vec<(String, String)>,
}
#[derive(Debug, Deserialize)]
pub struct APIRequest {
pub model: String,
pub messages: VecDeque<Message>,
#[serde(skip_serializing_if = "Vec::is_empty")]
pub tools: Vec<ToolDef>,
#[serde(skip_serializing_if = "Vec::is_empty")]
pub tool_choice: serde_json::Value,
#[serde(skip_serializing_if = "Option::is_none")]
pub parallel_tool_calls: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub temperature: Option<f64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub max_completion_tokens: Option<u64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub top_p: Option<f64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub reasoning_effort: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub presence_penalty: Option<f64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub web_search_options: Option<WebSearchOptions>,
}
impl Serialize for APIRequest {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let mut state = serializer.serialize_struct("APIRequest", 10)?;
state.serialize_field("model", &self.model)?;
state.serialize_field("messages", &self.messages)?;
if !self.tools.is_empty() {
state.serialize_field("tools", &self.tools)?;
}
if self.tool_choice != serde_json::Value::String("none".to_string()) {
state.serialize_field("tool_choice", &self.tool_choice)?;
}
if let Some(parallel_tool_calls) = &self.parallel_tool_calls {
state.serialize_field("parallel_tool_calls", parallel_tool_calls)?;
}
if let Some(temperature) = &self.temperature {
state.serialize_field("temperature", temperature)?;
}
if let Some(max_completion_tokens) = &self.max_completion_tokens {
state.serialize_field("max_completion_tokens", max_completion_tokens)?;
}
if let Some(top_p) = &self.top_p {
state.serialize_field("top_p", top_p)?;
}
if let Some(reasoning_effort) = &self.reasoning_effort {
state.serialize_field("reasoning_effort", reasoning_effort)?;
}
if let Some(presence_penalty) = &self.presence_penalty {
state.serialize_field("presence_penalty", presence_penalty)?;
}
state.end()
}
}
#[derive(Debug, Deserialize, Clone)]
pub struct APIResponse {
pub id: String,
pub object: String,
pub model: Option<String>,
pub choices: Option<Vec<Choice>>,
pub error: Option<APIError>,
pub usage: Option<APIUsage>,
pub created: Option<u64>,
}
#[derive(Debug, Deserialize, Clone)]
pub struct APIError {
pub message: String,
#[serde(rename = "type")]
pub err_type: String,
pub code: i32,
}
#[derive(Debug, Deserialize, Clone)]
pub struct APIUsage {
pub prompt_tokens: Option<u64>,
pub completion_tokens: Option<u64>,
pub total_tokens: Option<u64>,
}
#[derive(Debug, Clone, Deserialize)]
pub struct WebSearchOptions {
pub search_context_size: Option<String>,
pub user_location: UserLocation,
}
impl Serialize for WebSearchOptions {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let mut state = serializer.serialize_struct("WebSearchOptions", 2)?;
let size = self.search_context_size.as_deref().unwrap_or("medium");
state.serialize_field("search_context_size", size)?;
state.serialize_field("user_location", &self.user_location)?;
state.end()
}
}
#[derive(Debug, Clone, Deserialize)]
pub struct UserLocation {
pub city: Option<String>,
pub country: Option<String>,
pub region: Option<String>,
pub timezone: Option<String>,
}
impl Serialize for UserLocation {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let mut state = serializer.serialize_struct("UserLocation", 2)?;
state.serialize_field("type", "approximate")?;
let mut approximate = serde_json::Map::new();
if let Some(ref city) = self.city {
approximate.insert("city".to_string(), serde_json::Value::String(city.clone()));
}
if let Some(ref country) = self.country {
approximate.insert("country".to_string(), serde_json::Value::String(country.clone()));
}
if let Some(ref region) = self.region {
approximate.insert("region".to_string(), serde_json::Value::String(region.clone()));
}
if let Some(ref timezone) = self.timezone {
approximate.insert("timezone".to_string(), serde_json::Value::String(timezone.clone()));
}
state.serialize_field("approximate", &approximate)?;
state.end()
}
}