use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
#[serde(rename_all = "lowercase")]
pub enum Role {
System,
User,
Assistant,
Tool,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Message {
pub role: Role,
#[serde(skip_serializing_if = "Option::is_none")]
pub content: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub tool_calls: Option<Vec<ToolCall>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub tool_call_id: Option<String>,
}
impl Message {
pub fn system(content: impl Into<String>) -> Self {
Self {
role: Role::System,
content: Some(content.into()),
tool_calls: None,
tool_call_id: None,
}
}
pub fn user(content: impl Into<String>) -> Self {
Self {
role: Role::User,
content: Some(content.into()),
tool_calls: None,
tool_call_id: None,
}
}
pub fn assistant(content: impl Into<String>) -> Self {
Self {
role: Role::Assistant,
content: Some(content.into()),
tool_calls: None,
tool_call_id: None,
}
}
pub fn assistant_with_tool_calls(tool_calls: Vec<ToolCall>) -> Self {
Self {
role: Role::Assistant,
content: None,
tool_calls: Some(tool_calls),
tool_call_id: None,
}
}
pub fn tool(tool_call_id: impl Into<String>, content: impl Into<String>) -> Self {
Self {
role: Role::Tool,
content: Some(content.into()),
tool_calls: None,
tool_call_id: Some(tool_call_id.into()),
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ToolCall {
pub id: String,
#[serde(rename = "type")]
pub tool_type: String,
pub function: FunctionCall,
}
impl ToolCall {
pub fn new(
id: impl Into<String>,
name: impl Into<String>,
arguments: impl Into<String>,
) -> Self {
Self {
id: id.into(),
tool_type: "function".to_string(),
function: FunctionCall {
name: name.into(),
arguments: arguments.into(),
},
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct FunctionCall {
pub name: String,
pub arguments: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Tool {
#[serde(rename = "type")]
pub tool_type: String,
pub function: FunctionDefinition,
}
impl Tool {
pub fn function(
name: impl Into<String>,
description: impl Into<String>,
parameters: serde_json::Value,
) -> Self {
Self {
tool_type: "function".to_string(),
function: FunctionDefinition {
name: name.into(),
description: description.into(),
parameters,
},
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct FunctionDefinition {
pub name: String,
pub description: String,
pub parameters: serde_json::Value,
}
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct ProviderPreferences {
#[serde(skip_serializing_if = "Option::is_none")]
pub allow_fallbacks: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub require_parameters: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub data_collection: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub order: Option<Vec<String>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub ignore: Option<Vec<String>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub quantizations: Option<Vec<String>>,
}
#[derive(Debug, Clone, Serialize)]
pub struct CreateChatCompletionRequest {
pub model: String,
pub messages: Vec<Message>,
#[serde(skip_serializing_if = "Option::is_none")]
pub max_tokens: Option<usize>,
#[serde(skip_serializing_if = "Option::is_none")]
pub temperature: Option<f32>,
#[serde(skip_serializing_if = "Option::is_none")]
pub top_p: Option<f32>,
#[serde(skip_serializing_if = "Option::is_none")]
pub stop: Option<Vec<String>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub tools: Option<Vec<Tool>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub stream: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub n: Option<usize>,
#[serde(skip_serializing_if = "Option::is_none")]
pub presence_penalty: Option<f32>,
#[serde(skip_serializing_if = "Option::is_none")]
pub frequency_penalty: Option<f32>,
#[serde(skip_serializing_if = "Option::is_none")]
pub provider: Option<ProviderPreferences>,
#[serde(skip_serializing_if = "Option::is_none")]
pub models: Option<Vec<String>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub route: Option<String>,
}
impl CreateChatCompletionRequest {
pub fn new(model: impl Into<String>, messages: Vec<Message>) -> Self {
Self {
model: model.into(),
messages,
max_tokens: None,
temperature: None,
top_p: None,
stop: None,
tools: None,
stream: None,
n: None,
presence_penalty: None,
frequency_penalty: None,
provider: None,
models: None,
route: None,
}
}
pub fn with_max_tokens(mut self, max_tokens: usize) -> Self {
self.max_tokens = Some(max_tokens);
self
}
pub fn with_temperature(mut self, temperature: f32) -> Self {
self.temperature = Some(temperature);
self
}
pub fn with_top_p(mut self, top_p: f32) -> Self {
self.top_p = Some(top_p);
self
}
pub fn with_stop(mut self, stop: Vec<String>) -> Self {
self.stop = Some(stop);
self
}
pub fn with_tools(mut self, tools: Vec<Tool>) -> Self {
self.tools = Some(tools);
self
}
pub fn with_provider(mut self, provider: ProviderPreferences) -> Self {
self.provider = Some(provider);
self
}
pub fn with_fallback_models(mut self, models: Vec<String>) -> Self {
self.models = Some(models);
self
}
pub fn with_route(mut self, route: impl Into<String>) -> Self {
self.route = Some(route.into());
self
}
}
#[derive(Debug, Clone, Deserialize)]
pub struct Usage {
pub prompt_tokens: usize,
pub completion_tokens: usize,
pub total_tokens: usize,
}
#[derive(Debug, Clone, Deserialize)]
pub struct Choice {
pub index: usize,
pub message: Message,
pub finish_reason: Option<String>,
}
#[derive(Debug, Clone, Deserialize)]
pub struct CreateChatCompletionResponse {
pub id: String,
pub object: String,
pub created: u64,
pub model: String,
pub choices: Vec<Choice>,
pub usage: Option<Usage>,
}
impl CreateChatCompletionResponse {
pub fn content(&self) -> Option<&str> {
self.choices
.first()
.and_then(|c| c.message.content.as_deref())
}
pub fn tool_calls(&self) -> Option<&Vec<ToolCall>> {
self.choices
.first()
.and_then(|c| c.message.tool_calls.as_ref())
}
pub fn has_tool_calls(&self) -> bool {
self.choices
.first()
.is_some_and(|c| c.message.tool_calls.is_some())
}
}
#[derive(Debug, Clone, Deserialize)]
pub struct ModelPricing {
pub prompt: String,
pub completion: String,
#[serde(default)]
pub image: Option<String>,
#[serde(default)]
pub request: Option<String>,
}
#[derive(Debug, Clone, Deserialize)]
pub struct Model {
pub id: String,
pub name: String,
#[serde(default)]
pub description: Option<String>,
pub context_length: usize,
pub pricing: ModelPricing,
#[serde(default)]
pub top_provider: Option<TopProvider>,
#[serde(default)]
pub architecture: Option<ModelArchitecture>,
}
#[derive(Debug, Clone, Deserialize)]
pub struct TopProvider {
#[serde(default)]
pub context_length: Option<usize>,
#[serde(default)]
pub max_completion_tokens: Option<usize>,
#[serde(default)]
pub is_moderated: Option<bool>,
}
#[derive(Debug, Clone, Deserialize)]
pub struct ModelArchitecture {
#[serde(default)]
pub modality: Option<String>,
#[serde(default)]
pub tokenizer: Option<String>,
#[serde(default)]
pub instruct_type: Option<String>,
}
#[derive(Debug, Clone, Deserialize)]
pub struct ModelList {
pub data: Vec<Model>,
}
#[derive(Debug, Clone, Deserialize)]
pub struct GenerationStats {
pub id: String,
#[serde(default)]
pub total_cost: Option<f64>,
#[serde(default)]
pub tokens_prompt: Option<usize>,
#[serde(default)]
pub tokens_completion: Option<usize>,
#[serde(default)]
pub native_tokens_prompt: Option<usize>,
#[serde(default)]
pub native_tokens_completion: Option<usize>,
}
#[derive(Debug, Clone, Deserialize)]
pub struct CreditsResponse {
#[serde(default)]
pub data: Option<CreditsData>,
}
#[derive(Debug, Clone, Deserialize)]
pub struct CreditsData {
#[serde(default)]
pub label: Option<String>,
#[serde(default)]
pub balance: Option<f64>,
#[serde(default)]
pub usage: Option<f64>,
#[serde(default)]
pub limit: Option<f64>,
#[serde(default)]
pub is_free_tier: Option<bool>,
}
#[derive(Debug, Clone, Deserialize)]
pub struct ErrorResponse {
pub error: ErrorDetail,
}
#[derive(Debug, Clone, Deserialize)]
pub struct ErrorDetail {
pub message: String,
#[serde(rename = "type")]
#[serde(default)]
pub error_type: Option<String>,
#[serde(default)]
pub code: Option<i32>,
}