use serde::{Deserialize, Serialize};
pub const PROTOCOL_VERSION: u32 = 1;
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
#[serde(tag = "type")]
#[non_exhaustive]
pub enum CallClientEvent {
#[serde(rename = "auth")]
Auth {
token: String,
},
#[serde(rename = "session.update")]
SessionUpdate {
#[serde(flatten)]
options: serde_json::Map<String, serde_json::Value>,
},
#[serde(rename = "response.cancel")]
ResponseCancel,
#[serde(rename = "output_audio.started")]
OutputAudioStarted {
response_id: String,
index: u32,
},
#[serde(rename = "output_audio.idle")]
OutputAudioIdle {
response_id: String,
},
#[serde(rename = "action.resolve")]
ActionResolve {
id: String,
approve: bool,
},
#[serde(rename = "ping")]
Ping,
}
#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)]
#[serde(rename_all = "snake_case")]
#[non_exhaustive]
pub enum CallState {
Listening,
UserSpeaking,
Thinking,
Speaking,
AwaitingApproval,
}
#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)]
#[serde(rename_all = "snake_case")]
#[non_exhaustive]
pub enum CallResponseStatus {
Completed,
Interrupted,
PendingApproval,
Failed,
}
#[derive(Debug, Clone, Default, Serialize, Deserialize, PartialEq)]
#[non_exhaustive]
pub struct CallMetrics {
#[serde(default, skip_serializing_if = "Option::is_none")]
pub endpoint_ms: Option<u64>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub stt_ms: Option<u64>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub llm_first_text_ms: Option<u64>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub tts_first_ms: Option<u64>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub speech_end_to_first_audio_ms: Option<u64>,
#[serde(default)]
pub tool_rounds: u32,
#[serde(default)]
pub filler: bool,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
#[serde(tag = "type")]
#[non_exhaustive]
pub enum CallServerEvent {
#[serde(rename = "session.created")]
SessionCreated {
protocol: u32,
call_id: String,
sample_rate: u32,
end_of_turn_ms: u32,
barge_in_ms: u32,
},
#[serde(rename = "call.state")]
State {
state: CallState,
},
#[serde(rename = "input_audio_buffer.speech_started")]
SpeechStarted,
#[serde(rename = "input_audio_buffer.speech_stopped")]
SpeechStopped,
#[serde(rename = "conversation.item.input_audio_transcription.partial")]
TranscriptionPartial {
text: String,
},
#[serde(rename = "conversation.item.input_audio_transcription.completed")]
TranscriptionCompleted {
text: String,
},
#[serde(rename = "response.created")]
ResponseCreated {
response_id: String,
},
#[serde(rename = "response.text.delta")]
ResponseTextDelta {
response_id: String,
delta: String,
},
#[serde(rename = "response.audio.start")]
ResponseAudioStart {
response_id: String,
index: u32,
text: String,
content_type: String,
bytes: u64,
},
#[serde(rename = "response.done")]
ResponseDone {
response_id: String,
status: CallResponseStatus,
#[serde(default, skip_serializing_if = "Option::is_none")]
text: Option<String>,
metrics: CallMetrics,
},
#[serde(rename = "output_audio.clear")]
OutputAudioClear {
response_id: String,
},
#[serde(rename = "conversation.item.truncated")]
ItemTruncated {
response_id: String,
text: String,
},
#[serde(rename = "approval.pending")]
ApprovalPending {
card: serde_json::Value,
},
#[serde(rename = "approval.resolved")]
ApprovalResolved {
id: String,
approved: bool,
},
#[serde(rename = "error")]
Error {
message: String,
},
#[serde(rename = "pong")]
Pong,
}