use crate::openai::types::{FunctionCall, ToolCall};
use serde::Serialize;
use serde_json::{Map, Value};
#[derive(Debug, Clone, Serialize, PartialEq, Eq)]
pub struct ModelList {
pub object: &'static str,
pub data: Vec<ModelObject>,
}
#[derive(Debug, Clone, Serialize, PartialEq, Eq)]
pub struct ModelObject {
pub id: String,
pub object: &'static str,
pub owned_by: &'static str,
}
#[derive(Debug, Clone, Serialize, PartialEq, Eq)]
pub struct ChatCompletionResponse {
pub id: String,
pub object: &'static str,
pub created: i64,
pub model: String,
pub choices: Vec<ChatChoice>,
#[serde(skip_serializing_if = "Option::is_none")]
pub usage: Option<Usage>,
}
#[derive(Debug, Clone, Serialize, PartialEq, Eq)]
pub struct ChatChoice {
pub index: u32,
pub message: AssistantMessage,
pub finish_reason: String,
}
#[derive(Debug, Clone, Serialize, PartialEq, Eq)]
pub struct AssistantMessage {
pub role: &'static str,
pub content: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub tool_calls: Option<Vec<ToolCall>>,
}
#[derive(Debug, Clone, Serialize, PartialEq, Eq)]
pub struct Usage {
pub prompt_tokens: u32,
pub completion_tokens: u32,
pub total_tokens: u32,
}
#[derive(Debug, Clone, Serialize, PartialEq)]
pub struct ResponseObject {
pub id: String,
pub object: &'static str,
pub created_at: i64,
pub status: &'static str,
pub error: Option<Value>,
pub incomplete_details: Option<Value>,
pub instructions: Option<String>,
pub max_output_tokens: Option<u32>,
pub model: String,
pub output: Vec<ResponseOutputItem>,
pub parallel_tool_calls: bool,
pub store: bool,
pub temperature: Option<f64>,
pub tool_choice: Option<Value>,
pub tools: Vec<Value>,
pub usage: Option<Usage>,
pub metadata: Option<Map<String, Value>>,
pub previous_response_id: Option<String>,
}
#[derive(Debug, Clone, Serialize, PartialEq, Eq)]
pub struct ResponseOutputItem {
pub id: String,
#[serde(rename = "type")]
pub kind: &'static str,
#[serde(skip_serializing_if = "Option::is_none")]
pub role: Option<&'static str>,
pub status: &'static str,
#[serde(skip_serializing_if = "Vec::is_empty")]
pub content: Vec<ResponseOutputContent>,
#[serde(skip_serializing_if = "Option::is_none")]
pub call_id: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub name: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub arguments: Option<String>,
}
#[derive(Debug, Clone, Serialize, PartialEq, Eq)]
pub struct ResponseOutputContent {
#[serde(rename = "type")]
pub kind: &'static str,
pub text: String,
pub annotations: Vec<Value>,
}
#[derive(Debug, Clone, Serialize, PartialEq, Eq)]
pub struct ResponseInputTokens {
pub input_tokens: u32,
}
#[derive(Debug, Clone, Serialize, PartialEq, Eq)]
pub struct ResponseCompaction {
pub output: Vec<Value>,
}
#[derive(Debug, Clone, Serialize, PartialEq, Eq)]
pub struct ChatCompletionChunk {
pub id: String,
pub object: &'static str,
pub created: i64,
pub model: String,
pub choices: Vec<ChunkChoice>,
}
#[derive(Debug, Clone, Serialize, PartialEq, Eq)]
pub struct ChunkChoice {
pub index: u32,
pub delta: DeltaMessage,
#[serde(skip_serializing_if = "Option::is_none")]
pub finish_reason: Option<String>,
}
#[derive(Debug, Clone, Serialize, PartialEq, Eq)]
pub struct DeltaMessage {
#[serde(skip_serializing_if = "Option::is_none")]
pub role: Option<&'static str>,
#[serde(skip_serializing_if = "Option::is_none")]
pub content: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub tool_calls: Option<Vec<ToolCallDelta>>,
}
#[derive(Debug, Clone, Serialize, PartialEq, Eq)]
pub struct ToolCallDelta {
pub index: u32,
pub id: String,
#[serde(rename = "type")]
pub kind: &'static str,
pub function: FunctionCall,
}
impl ModelList {
#[must_use]
pub fn from_ids(ids: impl IntoIterator<Item = impl AsRef<str>>) -> Self {
Self {
object: "list",
data: ids
.into_iter()
.map(|id| ModelObject {
id: id.as_ref().to_owned(),
object: "model",
owned_by: "openai-codex",
})
.collect(),
}
}
}
#[must_use]
pub fn response_message_item(id: String, text: Option<String>) -> ResponseOutputItem {
let content = text
.filter(|value| !value.is_empty())
.map(|value| {
vec![ResponseOutputContent {
kind: "output_text",
text: value,
annotations: Vec::new(),
}]
})
.unwrap_or_default();
ResponseOutputItem {
id,
kind: "message",
role: Some("assistant"),
status: "completed",
content,
call_id: None,
name: None,
arguments: None,
}
}
#[must_use]
pub fn response_function_call_item(id: String, tool_call: ToolCall) -> ResponseOutputItem {
ResponseOutputItem {
id,
kind: "function_call",
role: None,
status: "completed",
content: Vec::new(),
call_id: Some(tool_call.id),
name: Some(tool_call.function.name),
arguments: Some(tool_call.function.arguments),
}
}
#[must_use]
pub fn chunk_with_role(id: &str, created: i64, model: &str) -> ChatCompletionChunk {
ChatCompletionChunk {
id: id.to_owned(),
object: "chat.completion.chunk",
created,
model: model.to_owned(),
choices: vec![ChunkChoice {
index: 0,
delta: DeltaMessage {
role: Some("assistant"),
content: None,
tool_calls: None,
},
finish_reason: None,
}],
}
}
#[must_use]
pub fn chunk_with_content(
id: &str,
created: i64,
model: &str,
content: String,
) -> ChatCompletionChunk {
ChatCompletionChunk {
id: id.to_owned(),
object: "chat.completion.chunk",
created,
model: model.to_owned(),
choices: vec![ChunkChoice {
index: 0,
delta: DeltaMessage {
role: None,
content: Some(content),
tool_calls: None,
},
finish_reason: None,
}],
}
}
#[must_use]
pub fn chunk_with_tool_call(
id: &str,
created: i64,
model: &str,
index: u32,
tool_call: ToolCall,
) -> ChatCompletionChunk {
ChatCompletionChunk {
id: id.to_owned(),
object: "chat.completion.chunk",
created,
model: model.to_owned(),
choices: vec![ChunkChoice {
index: 0,
delta: DeltaMessage {
role: None,
content: None,
tool_calls: Some(vec![ToolCallDelta {
index,
id: tool_call.id,
kind: "function",
function: tool_call.function,
}]),
},
finish_reason: None,
}],
}
}
#[must_use]
pub fn chunk_finished(id: &str, created: i64, model: &str, reason: &str) -> ChatCompletionChunk {
ChatCompletionChunk {
id: id.to_owned(),
object: "chat.completion.chunk",
created,
model: model.to_owned(),
choices: vec![ChunkChoice {
index: 0,
delta: DeltaMessage {
role: None,
content: None,
tool_calls: None,
},
finish_reason: Some(reason.to_owned()),
}],
}
}