use serde::{Deserialize, Serialize};
use serde_json::Value;
use std::collections::HashMap;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum MessageRole {
User,
Assistant,
System,
Developer,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum ItemStatus {
InProgress,
Completed,
Incomplete,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum ReasoningEffort {
None,
Low,
Medium,
High,
#[serde(rename = "xhigh")]
XHigh,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum ReasoningSummary {
Concise,
Detailed,
Auto,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum ToolChoiceMode {
None,
Auto,
Required,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum ServiceTier {
Auto,
Default,
Flex,
Priority,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum Truncation {
Auto,
Disabled,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum ImageDetail {
Low,
High,
Auto,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum Verbosity {
Low,
Medium,
High,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum ResponseStatus {
Completed,
Failed,
Cancelled,
InProgress,
Queued,
Incomplete,
#[serde(other)]
Unknown,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct InputTextContent {
#[serde(rename = "type")]
pub type_: String,
pub text: String,
}
impl InputTextContent {
pub fn new(text: impl Into<String>) -> Self {
Self {
type_: "input_text".to_string(),
text: text.into(),
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct InputImageContent {
#[serde(rename = "type")]
pub type_: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub image_url: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub detail: Option<ImageDetail>,
}
impl InputImageContent {
pub fn new(url: impl Into<String>) -> Self {
Self {
type_: "input_image".to_string(),
image_url: Some(url.into()),
detail: None,
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct InputAudioContent {
#[serde(rename = "type")]
pub type_: String,
pub input_audio: InputAudioData,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct InputAudioData {
pub data: String,
pub format: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct InputFileContent {
#[serde(rename = "type")]
pub type_: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub filename: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub file_data: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub file_url: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct InputVideoContent {
#[serde(rename = "type")]
pub type_: String,
pub video_url: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(tag = "type")]
#[non_exhaustive]
pub enum ContentPart {
#[serde(rename = "input_text")]
InputText { text: String },
#[serde(rename = "input_image")]
InputImage {
#[serde(skip_serializing_if = "Option::is_none")]
image_url: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
detail: Option<ImageDetail>,
},
#[serde(rename = "input_audio")]
InputAudio { input_audio: InputAudioData },
#[serde(rename = "input_file")]
InputFile {
#[serde(skip_serializing_if = "Option::is_none")]
filename: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
file_data: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
file_url: Option<String>,
},
#[serde(rename = "input_video")]
InputVideo { video_url: String },
#[serde(rename = "output_text")]
OutputText {
text: String,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
annotations: Vec<UrlCitation>,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
logprobs: Vec<LogProb>,
},
#[serde(rename = "text")]
Text { text: String },
#[serde(rename = "summary_text")]
SummaryText { text: String },
#[serde(rename = "reasoning_text")]
ReasoningText { text: String },
#[serde(rename = "refusal")]
Refusal { refusal: String },
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(untagged)]
pub enum MessageContent {
Text(String),
Parts(Vec<ContentPart>),
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct MessageItem {
#[serde(rename = "type")]
pub type_: String,
pub role: String,
pub content: MessageContent,
#[serde(skip_serializing_if = "Option::is_none")]
pub id: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub status: Option<String>,
}
impl MessageItem {
pub fn new(role: &str, content: MessageContent) -> Self {
Self {
type_: "message".to_string(),
role: role.to_string(),
content,
id: None,
status: None,
}
}
pub fn user(text: impl Into<String>) -> Self {
Self::new("user", MessageContent::Text(text.into()))
}
pub fn developer(text: impl Into<String>) -> Self {
Self::new("developer", MessageContent::Text(text.into()))
}
pub fn assistant(text: impl Into<String>) -> Self {
Self::new("assistant", MessageContent::Text(text.into()))
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct FunctionCallItem {
#[serde(rename = "type")]
pub type_: String,
pub call_id: String,
pub name: String,
pub arguments: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub id: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub status: Option<ItemStatus>,
}
impl FunctionCallItem {
pub fn new(
call_id: impl Into<String>,
name: impl Into<String>,
arguments: impl Into<String>,
) -> Self {
Self {
type_: "function_call".to_string(),
call_id: call_id.into(),
name: name.into(),
arguments: arguments.into(),
id: None,
status: None,
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct FunctionCallOutputItem {
#[serde(rename = "type")]
pub type_: String,
pub call_id: String,
pub output: FunctionCallOutput,
#[serde(skip_serializing_if = "Option::is_none")]
pub id: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub status: Option<ItemStatus>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(untagged)]
pub enum FunctionCallOutput {
Text(String),
Parts(Vec<ContentPart>),
}
impl FunctionCallOutputItem {
pub fn new(call_id: impl Into<String>, output: impl Into<String>) -> Self {
Self {
type_: "function_call_output".to_string(),
call_id: call_id.into(),
output: FunctionCallOutput::Text(output.into()),
id: None,
status: None,
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ReasoningItem {
#[serde(rename = "type")]
pub type_: String,
pub id: String,
#[serde(default)]
pub summary: Vec<ContentPart>,
#[serde(skip_serializing_if = "Option::is_none")]
pub content: Option<Vec<ContentPart>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub encrypted_content: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ItemReference {
#[serde(rename = "type")]
pub type_: String,
pub id: String,
}
#[derive(Debug, Clone, Serialize)]
#[serde(untagged)]
pub enum InputItem {
Message(MessageItem),
FunctionCall(FunctionCallItem),
FunctionCallOutput(FunctionCallOutputItem),
Reasoning(ReasoningItem),
Reference(ItemReference),
}
impl<'de> Deserialize<'de> for InputItem {
fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
let value = Value::deserialize(deserializer)?;
match value.get("type").and_then(Value::as_str) {
Some("message") => serde_json::from_value(value).map(Self::Message),
Some("function_call") => serde_json::from_value(value).map(Self::FunctionCall),
Some("function_call_output") => {
serde_json::from_value(value).map(Self::FunctionCallOutput)
}
Some("reasoning") => serde_json::from_value(value).map(Self::Reasoning),
Some("item_reference") => serde_json::from_value(value).map(Self::Reference),
_ => {
return Err(serde::de::Error::custom(
"unsupported or missing input item type",
));
}
}
.map_err(serde::de::Error::custom)
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct FunctionTool {
#[serde(rename = "type")]
pub type_: String,
pub name: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub description: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub parameters: Option<Value>,
#[serde(skip_serializing_if = "Option::is_none")]
pub strict: Option<bool>,
}
impl FunctionTool {
pub fn new(name: impl Into<String>) -> Self {
Self {
type_: "function".to_string(),
name: name.into(),
description: None,
parameters: None,
strict: None,
}
}
pub fn with_description(mut self, description: impl Into<String>) -> Self {
self.description = Some(description.into());
self
}
pub fn with_parameters(mut self, parameters: Value) -> Self {
self.parameters = Some(parameters);
self
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(tag = "type")]
pub enum Tool {
#[serde(rename = "function")]
Function {
name: String,
#[serde(skip_serializing_if = "Option::is_none")]
description: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
parameters: Option<Value>,
#[serde(skip_serializing_if = "Option::is_none")]
strict: Option<bool>,
},
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SpecificFunction {
#[serde(rename = "type")]
pub type_: String,
pub name: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(untagged)]
pub enum ToolChoice {
Mode(ToolChoiceMode),
Specific(SpecificFunction),
AllowedTools {
#[serde(rename = "type")]
type_: String,
tools: Vec<SpecificFunction>,
#[serde(skip_serializing_if = "Option::is_none")]
mode: Option<ToolChoiceMode>,
},
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Reasoning {
#[serde(skip_serializing_if = "Option::is_none")]
pub effort: Option<ReasoningEffort>,
#[serde(skip_serializing_if = "Option::is_none")]
pub summary: Option<ReasoningSummary>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(tag = "type")]
pub enum TextFormat {
#[serde(rename = "text")]
Text,
#[serde(rename = "json_object")]
JsonObject,
#[serde(rename = "json_schema")]
JsonSchema {
name: String,
#[serde(skip_serializing_if = "Option::is_none")]
description: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
schema: Option<Value>,
#[serde(skip_serializing_if = "Option::is_none")]
strict: Option<bool>,
},
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TextConfig {
#[serde(skip_serializing_if = "Option::is_none")]
pub format: Option<TextFormat>,
#[serde(skip_serializing_if = "Option::is_none")]
pub verbosity: Option<Verbosity>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CreateResponseBody {
#[serde(skip_serializing_if = "Option::is_none")]
pub model: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub input: Option<Input>,
#[serde(skip_serializing_if = "Option::is_none")]
pub previous_response_id: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub instructions: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub tools: Option<Vec<Tool>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub tool_choice: Option<ToolChoice>,
#[serde(skip_serializing_if = "Option::is_none")]
pub metadata: Option<HashMap<String, String>>,
#[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 presence_penalty: Option<f32>,
#[serde(skip_serializing_if = "Option::is_none")]
pub frequency_penalty: Option<f32>,
#[serde(skip_serializing_if = "Option::is_none")]
pub max_output_tokens: Option<u32>,
#[serde(skip_serializing_if = "Option::is_none")]
pub max_tool_calls: Option<u32>,
#[serde(skip_serializing_if = "Option::is_none")]
pub stream: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub background: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub store: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub parallel_tool_calls: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub reasoning: Option<Reasoning>,
#[serde(skip_serializing_if = "Option::is_none")]
pub text: Option<TextConfig>,
#[serde(skip_serializing_if = "Option::is_none")]
pub truncation: Option<Truncation>,
#[serde(skip_serializing_if = "Option::is_none")]
pub service_tier: Option<ServiceTier>,
#[serde(skip_serializing_if = "Option::is_none")]
pub include: Option<Vec<String>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub top_logprobs: Option<u8>,
#[serde(skip_serializing_if = "Option::is_none")]
pub safety_identifier: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub prompt_cache_key: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(untagged)]
pub enum Input {
Text(String),
Items(Vec<InputItem>),
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct UrlCitation {
#[serde(rename = "type")]
pub type_: String,
pub url: String,
pub title: String,
pub start_index: u32,
pub end_index: u32,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct LogProb {
pub token: String,
pub logprob: f64,
pub bytes: Vec<u8>,
#[serde(default)]
pub top_logprobs: Vec<TopLogProb>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TopLogProb {
pub token: String,
pub logprob: f64,
pub bytes: Vec<u8>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Usage {
pub input_tokens: u32,
pub output_tokens: u32,
pub total_tokens: u32,
#[serde(skip_serializing_if = "Option::is_none")]
pub input_tokens_details: Option<InputTokensDetails>,
#[serde(skip_serializing_if = "Option::is_none")]
pub output_tokens_details: Option<OutputTokensDetails>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub cost: Option<f64>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct InputTokensDetails {
#[serde(default)]
pub cached_tokens: u32,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub cache_write_tokens: Option<u32>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct OutputTokensDetails {
pub reasoning_tokens: u32,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct IncompleteDetails {
pub reason: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(tag = "type")]
pub enum OutputItem {
#[serde(rename = "message")]
Message {
id: String,
status: ItemStatus,
role: MessageRole,
content: Vec<ContentPart>,
#[serde(skip_serializing_if = "Option::is_none")]
phase: Option<String>,
},
#[serde(rename = "function_call")]
FunctionCall {
id: String,
call_id: String,
name: String,
#[serde(skip_serializing_if = "Option::is_none")]
namespace: Option<String>,
arguments: String,
#[serde(rename = "async", default, skip_serializing_if = "std::ops::Not::not")]
asynchronous: bool,
status: ItemStatus,
},
#[serde(rename = "function_call_output")]
FunctionCallOutput {
id: String,
call_id: String,
output: FunctionCallOutput,
status: ItemStatus,
},
#[serde(rename = "reasoning")]
Reasoning {
id: String,
summary: Vec<ContentPart>,
#[serde(skip_serializing_if = "Option::is_none")]
content: Option<Vec<ContentPart>>,
#[serde(skip_serializing_if = "Option::is_none")]
encrypted_content: Option<String>,
},
#[serde(rename = "tool_search_call")]
ToolSearchCall {
execution: String,
#[serde(skip_serializing_if = "Option::is_none")]
call_id: Option<String>,
status: ItemStatus,
arguments: Value,
},
#[serde(rename = "tool_search_output")]
ToolSearchOutput {
execution: String,
#[serde(skip_serializing_if = "Option::is_none")]
call_id: Option<String>,
status: ItemStatus,
tools: Vec<Value>,
},
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ResponseResource {
pub id: String,
pub object: String,
pub created_at: i64,
#[serde(skip_serializing_if = "Option::is_none")]
pub completed_at: Option<i64>,
pub status: ResponseStatus,
#[serde(skip_serializing_if = "Option::is_none")]
pub incomplete_details: Option<IncompleteDetails>,
pub model: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub previous_response_id: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub instructions: Option<String>,
#[serde(default)]
pub output: Vec<OutputItem>,
#[serde(skip_serializing_if = "Option::is_none")]
pub error: Option<Error>,
#[serde(default)]
pub tools: Vec<Tool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub tool_choice: Option<ToolChoice>,
#[serde(skip_serializing_if = "Option::is_none")]
pub truncation: Option<Truncation>,
#[serde(skip_serializing_if = "Option::is_none")]
pub parallel_tool_calls: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub text: Option<TextConfig>,
#[serde(skip_serializing_if = "Option::is_none")]
pub top_p: Option<f32>,
#[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 top_logprobs: Option<u8>,
#[serde(skip_serializing_if = "Option::is_none")]
pub temperature: Option<f32>,
#[serde(skip_serializing_if = "Option::is_none")]
pub reasoning: Option<Reasoning>,
#[serde(skip_serializing_if = "Option::is_none")]
pub usage: Option<Usage>,
#[serde(skip_serializing_if = "Option::is_none")]
pub max_output_tokens: Option<u32>,
#[serde(skip_serializing_if = "Option::is_none")]
pub max_tool_calls: Option<u32>,
#[serde(skip_serializing_if = "Option::is_none")]
pub store: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub background: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub service_tier: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub metadata: Option<HashMap<String, String>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub safety_identifier: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub prompt_cache_key: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Error {
pub code: String,
pub message: String,
}
impl std::fmt::Display for Error {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}: {}", self.code, self.message)
}
}
impl std::error::Error for Error {}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ErrorPayload {
#[serde(rename = "type")]
pub type_: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub code: Option<String>,
pub message: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub param: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub headers: Option<HashMap<String, String>>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(tag = "type")]
pub enum StreamingEvent {
#[serde(rename = "response.created")]
ResponseCreated {
sequence_number: u32,
response: ResponseResource,
},
#[serde(rename = "response.queued")]
ResponseQueued {
sequence_number: u32,
response: ResponseResource,
},
#[serde(rename = "response.in_progress")]
ResponseInProgress {
sequence_number: u32,
response: ResponseResource,
},
#[serde(rename = "response.completed")]
ResponseCompleted {
sequence_number: u32,
response: ResponseResource,
},
#[serde(rename = "response.failed")]
ResponseFailed {
sequence_number: u32,
response: ResponseResource,
},
#[serde(rename = "response.incomplete")]
ResponseIncomplete {
sequence_number: u32,
response: ResponseResource,
},
#[serde(rename = "response.output_item.added")]
OutputItemAdded {
sequence_number: u32,
output_index: u32,
item: Option<OutputItem>,
},
#[serde(rename = "response.output_item.done")]
OutputItemDone {
sequence_number: u32,
output_index: u32,
item: Option<OutputItem>,
},
#[serde(rename = "response.content_part.added")]
ContentPartAdded {
sequence_number: u32,
item_id: String,
output_index: u32,
content_index: u32,
part: ContentPart,
},
#[serde(rename = "response.content_part.done")]
ContentPartDone {
sequence_number: u32,
item_id: String,
output_index: u32,
content_index: u32,
part: ContentPart,
},
#[serde(rename = "response.output_text.delta")]
OutputTextDelta {
sequence_number: u32,
item_id: String,
output_index: u32,
content_index: u32,
delta: String,
#[serde(default)]
logprobs: Vec<LogProb>,
#[serde(skip_serializing_if = "Option::is_none")]
obfuscation: Option<String>,
},
#[serde(rename = "response.output_text.done")]
OutputTextDone {
sequence_number: u32,
item_id: String,
output_index: u32,
content_index: u32,
text: String,
#[serde(default)]
logprobs: Vec<LogProb>,
},
#[serde(rename = "response.output_text.annotation.added")]
OutputTextAnnotationAdded {
sequence_number: u32,
item_id: String,
output_index: u32,
content_index: u32,
annotation_index: u32,
annotation: Option<UrlCitation>,
},
#[serde(rename = "response.refusal.delta")]
RefusalDelta {
sequence_number: u32,
item_id: String,
output_index: u32,
content_index: u32,
delta: String,
},
#[serde(rename = "response.refusal.done")]
RefusalDone {
sequence_number: u32,
item_id: String,
output_index: u32,
content_index: u32,
refusal: String,
},
#[serde(rename = "response.reasoning.delta")]
ReasoningDelta {
sequence_number: u32,
item_id: String,
output_index: u32,
content_index: u32,
delta: String,
#[serde(skip_serializing_if = "Option::is_none")]
obfuscation: Option<String>,
},
#[serde(rename = "response.reasoning.done")]
ReasoningDone {
sequence_number: u32,
item_id: String,
output_index: u32,
content_index: u32,
text: String,
},
#[serde(rename = "response.reasoning_text.delta")]
ReasoningTextDelta {
#[serde(default)]
sequence_number: u32,
#[serde(default)]
item_id: String,
#[serde(default)]
output_index: u32,
#[serde(default)]
content_index: u32,
delta: String,
},
#[serde(rename = "response.reasoning_summary_part.added")]
ReasoningSummaryPartAdded {
sequence_number: u32,
item_id: String,
output_index: u32,
summary_index: u32,
part: ContentPart,
},
#[serde(rename = "response.reasoning_summary_part.done")]
ReasoningSummaryPartDone {
sequence_number: u32,
item_id: String,
output_index: u32,
summary_index: u32,
part: ContentPart,
},
#[serde(rename = "response.reasoning_summary_text.delta")]
ReasoningSummaryDelta {
sequence_number: u32,
item_id: String,
output_index: u32,
summary_index: u32,
delta: String,
#[serde(skip_serializing_if = "Option::is_none")]
obfuscation: Option<String>,
},
#[serde(rename = "response.reasoning_summary_text.done")]
ReasoningSummaryDone {
sequence_number: u32,
item_id: String,
output_index: u32,
summary_index: u32,
text: String,
},
#[serde(rename = "response.function_call_arguments.delta")]
FunctionCallArgumentsDelta {
sequence_number: u32,
item_id: String,
output_index: u32,
delta: String,
#[serde(skip_serializing_if = "Option::is_none")]
obfuscation: Option<String>,
},
#[serde(rename = "response.function_call_arguments.done")]
FunctionCallArgumentsDone {
sequence_number: u32,
item_id: String,
output_index: u32,
arguments: String,
},
#[serde(rename = "error")]
Error {
sequence_number: u32,
error: ErrorPayload,
},
}
pub const MAX_TEXT_LENGTH: usize = 10 * 1024 * 1024;
pub const MAX_IMAGE_URL_LENGTH: usize = 20 * 1024 * 1024;
pub const MAX_FILE_DATA_LENGTH: usize = 32 * 1024 * 1024;
pub const MAX_FUNCTION_NAME_LENGTH: usize = 64;
pub const MIN_FUNCTION_NAME_LENGTH: usize = 1;
pub const MAX_METADATA_KEYS: usize = 16;
pub const MAX_METADATA_KEY_LENGTH: usize = 64;
pub const MAX_METADATA_VALUE_LENGTH: usize = 512;
pub const MIN_MAX_OUTPUT_TOKENS: u32 = 16;
pub const MAX_TOP_LOGPROBS: u8 = 20;
pub fn validate_function_name(name: &str) -> bool {
if name.len() < MIN_FUNCTION_NAME_LENGTH || name.len() > MAX_FUNCTION_NAME_LENGTH {
return false;
}
name.chars()
.all(|c| c.is_ascii_alphanumeric() || c == '_' || c == '-')
}
pub fn validate_metadata(metadata: &HashMap<String, String>) -> bool {
if metadata.len() > MAX_METADATA_KEYS {
return false;
}
metadata.iter().all(|(k, v)| {
k.chars().take(MAX_METADATA_KEY_LENGTH + 1).count() <= MAX_METADATA_KEY_LENGTH
&& v.chars().take(MAX_METADATA_VALUE_LENGTH + 1).count() <= MAX_METADATA_VALUE_LENGTH
})
}
#[cfg(test)]
#[path = "openresponses_types_tests.rs"]
mod tests;