Codex Handbook
codex-api/src/endpoint/realtime_websocket/protocol.rs 223 lines
use crate::endpoint::realtime_websocket::protocol_v1::parse_realtime_event_v1;use crate::endpoint::realtime_websocket::protocol_v2::parse_realtime_event_v2;use codex_protocol::protocol::ConversationTextRole;pub use codex_protocol::protocol::RealtimeAudioFrame;pub use codex_protocol::protocol::RealtimeEvent;pub use codex_protocol::protocol::RealtimeOutputModality;pub use codex_protocol::protocol::RealtimeTranscriptEntry;pub use codex_protocol::protocol::RealtimeVoice;use serde::Serialize;use serde_json::Value;#[derive(Debug, Clone, Copy, PartialEq, Eq)]pub enum RealtimeEventParser {    V1,    RealtimeV2,}#[derive(Debug, Clone, Copy, PartialEq, Eq)]pub enum RealtimeSessionMode {    Conversational,    Transcription,}#[derive(Debug, Clone, PartialEq, Eq)]pub struct RealtimeSessionConfig {    pub instructions: String,    pub model: Option<String>,    pub session_id: Option<String>,    pub event_parser: RealtimeEventParser,    pub session_mode: RealtimeSessionMode,    pub output_modality: RealtimeOutputModality,    pub voice: RealtimeVoice,}#[derive(Debug, Clone, Serialize)]#[serde(tag = "type")]pub(super) enum RealtimeOutboundMessage {    #[serde(rename = "input_audio_buffer.append")]    InputAudioBufferAppend { audio: String },    #[serde(rename = "conversation.handoff.append")]    ConversationHandoffAppend {        handoff_id: String,        output_text: String,    },    #[serde(rename = "response.create")]    ResponseCreate,    #[serde(rename = "session.update")]    SessionUpdate { session: SessionUpdateSession },    #[serde(rename = "conversation.item.create")]    ConversationItemCreate { item: ConversationItemPayload },}#[derive(Debug, Clone, Serialize)]pub(super) struct SessionUpdateSession {    #[serde(skip_serializing_if = "Option::is_none")]    pub(super) id: Option<String>,    #[serde(rename = "type")]    pub(super) r#type: SessionType,    #[serde(skip_serializing_if = "Option::is_none")]    pub(super) model: Option<String>,    #[serde(skip_serializing_if = "Option::is_none")]    pub(super) instructions: Option<String>,    #[serde(skip_serializing_if = "Option::is_none")]    pub(super) output_modalities: Option<Vec<String>>,    pub(super) audio: SessionAudio,    #[serde(skip_serializing_if = "Option::is_none")]    pub(super) tools: Option<Vec<SessionFunctionTool>>,    #[serde(skip_serializing_if = "Option::is_none")]    pub(super) tool_choice: Option<String>,}#[derive(Debug, Clone, Copy, Serialize)]#[serde(rename_all = "snake_case")]pub(super) enum SessionType {    Quicksilver,    Realtime,    Transcription,}#[derive(Debug, Clone, Serialize)]pub(super) struct SessionAudio {    pub(super) input: SessionAudioInput,    #[serde(skip_serializing_if = "Option::is_none")]    pub(super) output: Option<SessionAudioOutput>,}#[derive(Debug, Clone, Serialize)]pub(super) struct SessionAudioInput {    pub(super) format: SessionAudioFormat,    #[serde(skip_serializing_if = "Option::is_none")]    pub(super) noise_reduction: Option<SessionNoiseReduction>,    #[serde(skip_serializing_if = "Option::is_none")]    pub(super) transcription: Option<SessionInputAudioTranscription>,    #[serde(skip_serializing_if = "Option::is_none")]    pub(super) turn_detection: Option<SessionTurnDetection>,}#[derive(Debug, Clone, Serialize)]pub(super) struct SessionInputAudioTranscription {    pub(super) model: String,}#[derive(Debug, Clone, Serialize)]pub(super) struct SessionAudioFormat {    #[serde(rename = "type")]    pub(super) r#type: AudioFormatType,    pub(super) rate: u32,}#[derive(Debug, Clone, Copy, Serialize)]pub(super) enum AudioFormatType {    #[serde(rename = "audio/pcm")]    AudioPcm,}#[derive(Debug, Clone, Serialize)]pub(super) struct SessionAudioOutput {    #[serde(skip_serializing_if = "Option::is_none")]    pub(super) format: Option<SessionAudioOutputFormat>,    pub(super) voice: RealtimeVoice,}#[derive(Debug, Clone, Serialize)]pub(super) struct SessionNoiseReduction {    #[serde(rename = "type")]    pub(super) r#type: NoiseReductionType,}#[derive(Debug, Clone, Copy, Serialize)]#[serde(rename_all = "snake_case")]pub(super) enum NoiseReductionType {    NearField,}#[derive(Debug, Clone, Serialize)]pub(super) struct SessionTurnDetection {    #[serde(rename = "type")]    pub(super) r#type: TurnDetectionType,    pub(super) interrupt_response: bool,    pub(super) create_response: bool,    pub(super) silence_duration_ms: u32,}#[derive(Debug, Clone, Copy, Serialize)]#[serde(rename_all = "snake_case")]pub(super) enum TurnDetectionType {    ServerVad,}#[derive(Debug, Clone, Serialize)]pub(super) struct SessionAudioOutputFormat {    #[serde(rename = "type")]    pub(super) r#type: AudioFormatType,    pub(super) rate: u32,}#[derive(Debug, Clone, Serialize)]pub(super) struct ConversationMessageItem {    #[serde(rename = "type")]    pub(super) r#type: ConversationItemType,    pub(super) role: ConversationTextRole,    pub(super) content: Vec<ConversationItemContent>,}#[derive(Debug, Clone, Copy, Serialize)]#[serde(rename_all = "snake_case")]pub(super) enum ConversationItemType {    Message,    FunctionCallOutput,}#[derive(Debug, Clone, Serialize)]#[serde(untagged)]pub(super) enum ConversationItemPayload {    Message(ConversationMessageItem),    FunctionCallOutput(ConversationFunctionCallOutputItem),}#[derive(Debug, Clone, Serialize)]pub(super) struct ConversationFunctionCallOutputItem {    #[serde(rename = "type")]    pub(super) r#type: ConversationItemType,    pub(super) call_id: String,    pub(super) output: String,}#[derive(Debug, Clone, Serialize)]pub(super) struct ConversationItemContent {    #[serde(rename = "type")]    pub(super) r#type: ConversationContentType,    pub(super) text: String,}#[derive(Debug, Clone, Copy, Serialize)]#[serde(rename_all = "snake_case")]pub(super) enum ConversationContentType {    InputText,}#[derive(Debug, Clone, Serialize)]pub(super) struct SessionFunctionTool {    #[serde(rename = "type")]    pub(super) r#type: SessionToolType,    pub(super) name: String,    pub(super) description: String,    pub(super) parameters: Value,}#[derive(Debug, Clone, Copy, Serialize)]#[serde(rename_all = "snake_case")]pub(super) enum SessionToolType {    Function,}pub(super) fn parse_realtime_event(    payload: &str,    event_parser: RealtimeEventParser,) -> Option<RealtimeEvent> {    match event_parser {        RealtimeEventParser::V1 => parse_realtime_event_v1(payload),        RealtimeEventParser::RealtimeV2 => parse_realtime_event_v2(payload),    }}