use serde::Deserialize;
use serde_json::Value;
#[derive(Debug, Deserialize)]
pub struct Response {
#[serde(default)]
pub status: Option<String>,
pub output: Vec<OutputItem>,
#[serde(default)]
pub usage: Option<Usage>,
}
#[derive(Debug, Deserialize)]
#[serde(tag = "type", rename_all = "snake_case")]
pub enum OutputItem {
Message {
#[serde(default)]
content: Vec<MessageContentPart>,
},
Reasoning {
#[serde(default)]
id: Option<String>,
#[serde(default)]
summary: Vec<ReasoningSummaryPart>,
},
FunctionCall {
#[serde(default)]
id: Option<String>,
call_id: String,
name: String,
arguments: String,
},
#[serde(other)]
Unknown,
}
#[derive(Debug, Deserialize)]
#[serde(tag = "type", rename_all = "snake_case")]
pub enum MessageContentPart {
OutputText {
text: String,
},
#[serde(other)]
Unknown,
}
#[derive(Debug, Deserialize)]
#[serde(tag = "type", rename_all = "snake_case")]
pub enum ReasoningSummaryPart {
SummaryText {
text: String,
},
#[serde(other)]
Unknown,
}
#[derive(Debug, Deserialize)]
pub struct Usage {
#[serde(default)]
pub input_tokens: u32,
#[serde(default)]
pub output_tokens: u32,
#[serde(default)]
pub total_tokens: u32,
#[serde(default)]
pub input_tokens_details: Option<InputTokensDetails>,
#[serde(default)]
pub output_tokens_details: Option<OutputTokensDetails>,
}
#[derive(Debug, Deserialize, Default)]
pub struct InputTokensDetails {
#[serde(default)]
pub cached_tokens: u32,
}
#[derive(Debug, Deserialize, Default)]
pub struct OutputTokensDetails {
#[serde(default)]
pub reasoning_tokens: u32,
}
impl From<Usage> for crate::types::UsageStats {
fn from(u: Usage) -> Self {
let cached = u
.input_tokens_details
.as_ref()
.map(|d| d.cached_tokens)
.unwrap_or(0);
let reasoning = u
.output_tokens_details
.as_ref()
.map(|d| d.reasoning_tokens)
.unwrap_or(0);
let total = if u.total_tokens > 0 {
u.total_tokens
} else {
u.input_tokens + u.output_tokens
};
Self {
prompt_tokens: u.input_tokens as usize,
completion_tokens: u.output_tokens as usize,
total_tokens: total as usize,
cache_read_tokens: cached as usize,
cache_creation_tokens: 0,
reasoning_tokens: reasoning as usize,
}
}
}
#[derive(Debug, Deserialize)]
#[serde(tag = "type")]
pub enum StreamEvent {
#[serde(rename = "response.created")]
ResponseCreated,
#[serde(rename = "response.in_progress")]
ResponseInProgress,
#[serde(rename = "response.output_item.added")]
OutputItemAdded {
output_index: u32,
item: OutputItemLite,
},
#[serde(rename = "response.output_item.done")]
OutputItemDone,
#[serde(rename = "response.output_text.delta")]
OutputTextDelta { output_index: u32, delta: String },
#[serde(rename = "response.output_text.done")]
OutputTextDone,
#[serde(rename = "response.reasoning_summary_text.delta")]
ReasoningSummaryTextDelta { output_index: u32, delta: String },
#[serde(rename = "response.reasoning_summary_text.done")]
ReasoningSummaryTextDone,
#[serde(rename = "response.function_call_arguments.delta")]
FunctionCallArgumentsDelta { output_index: u32, delta: String },
#[serde(rename = "response.function_call_arguments.done")]
FunctionCallArgumentsDone,
#[serde(rename = "response.completed")]
ResponseCompleted { response: CompletedResponse },
#[serde(rename = "response.failed")]
ResponseFailed { response: CompletedResponse },
#[serde(rename = "error")]
Error { message: String },
#[serde(other)]
Other,
}
#[derive(Debug, Deserialize)]
#[serde(tag = "type", rename_all = "snake_case")]
pub enum OutputItemLite {
Message {
#[serde(default)]
id: Option<String>,
},
Reasoning {
#[serde(default)]
id: Option<String>,
},
FunctionCall {
#[serde(default)]
id: Option<String>,
#[serde(default)]
call_id: Option<String>,
#[serde(default)]
name: Option<String>,
},
#[serde(other)]
Unknown,
}
#[derive(Debug, Deserialize)]
pub struct CompletedResponse {
#[serde(default)]
pub status: Option<String>,
#[serde(default)]
pub output: Vec<Value>,
#[serde(default)]
pub usage: Option<Usage>,
}