use serde::{Deserialize, Serialize};
use crate::common::Redacted;
#[serde_with::skip_serializing_none]
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(tag = "type", rename_all = "snake_case")]
pub enum RealtimeConversationItem {
Message {
content: Vec<RealtimeContentPart>,
role: ConversationItemRole,
id: Option<String>,
object: Option<ConversationItemObject>,
status: Option<ConversationItemStatus>,
},
FunctionCall {
arguments: String,
name: String,
id: Option<String>,
call_id: Option<String>,
object: Option<ConversationItemObject>,
status: Option<ConversationItemStatus>,
},
FunctionCallOutput {
call_id: String,
output: String,
id: Option<String>,
object: Option<ConversationItemObject>,
status: Option<ConversationItemStatus>,
},
McpApprovalResponse {
id: String,
approval_request_id: String,
approve: bool,
reason: Option<String>,
},
McpListTools {
server_label: String,
tools: Vec<McpListToolEntry>,
id: Option<String>,
},
McpCall {
id: String,
arguments: String,
name: String,
server_label: String,
approval_request_id: Option<String>,
error: Option<McpCallError>,
output: Option<String>,
},
McpApprovalRequest {
id: String,
arguments: String,
name: String,
server_label: String,
},
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub enum ConversationItemObject {
#[serde(rename = "realtime.item")]
RealtimeItem,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
#[serde(rename_all = "snake_case")]
pub enum ConversationItemStatus {
Completed,
Incomplete,
InProgress,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
#[serde(rename_all = "snake_case")]
pub enum ConversationItemRole {
User,
Assistant,
System,
}
#[serde_with::skip_serializing_none]
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(tag = "type", rename_all = "snake_case")]
pub enum RealtimeContentPart {
InputText {
text: Option<String>,
},
InputAudio {
audio: Option<Redacted>,
transcript: Option<String>,
},
InputImage {
detail: Option<ImageDetail>,
image_url: Option<Redacted>,
},
OutputText {
text: Option<String>,
},
OutputAudio {
audio: Option<Redacted>,
transcript: Option<String>,
},
}
impl RealtimeContentPart {
pub const fn type_name(&self) -> &'static str {
match self {
Self::InputText { .. } => "input_text",
Self::InputAudio { .. } => "input_audio",
Self::InputImage { .. } => "input_image",
Self::OutputText { .. } => "output_text",
Self::OutputAudio { .. } => "output_audio",
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
#[serde(rename_all = "snake_case")]
pub enum ImageDetail {
#[default]
Auto,
Low,
High,
}
#[serde_with::skip_serializing_none]
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct McpListToolEntry {
pub input_schema: serde_json::Value,
pub name: String,
pub annotations: Option<serde_json::Value>,
pub description: Option<String>,
}
#[expect(clippy::enum_variant_names)]
#[serde_with::skip_serializing_none]
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(tag = "type", rename_all = "snake_case")]
pub enum McpCallError {
ProtocolError { code: i64, message: String },
ToolExecutionError { message: String },
HttpError { code: i64, message: String },
}