Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 61 additions & 3 deletions crates/protocols/src/realtime_session.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,20 @@ use std::collections::HashMap;

use serde::{Deserialize, Serialize};
use serde_json::Value;
use validator::{Validate, ValidationError};

use crate::common::{Redacted, ResponsePrompt, ToolReference};
use crate::{
common::{Redacted, ResponsePrompt, ToolReference},
validated::Normalizable,
};

// ============================================================================
// Session Configuration
// ============================================================================

#[serde_with::skip_serializing_none]
#[derive(Debug, Clone, Serialize, Deserialize)]
#[derive(Debug, Clone, Serialize, Deserialize, Validate)]
#[validate(schema(function = "validate_session_create_request"))]
pub struct RealtimeSessionCreateRequest {
#[serde(rename = "type")]
pub r#type: RealtimeSessionType,
Expand All @@ -31,6 +36,18 @@ pub struct RealtimeSessionCreateRequest {
pub truncation: Option<RealtimeTruncation>,
}

impl Normalizable for RealtimeSessionCreateRequest {}

fn validate_session_create_request(
req: &RealtimeSessionCreateRequest,
) -> Result<(), ValidationError> {
let has_model = req.model.as_deref().is_some_and(|m| !m.trim().is_empty());
if !has_model {
return Err(ValidationError::new("model is required"));
}
Ok(())
}
Comment thread
coderabbitai[bot] marked this conversation as resolved.

// ============================================================================
// Session Object
// ============================================================================
Expand Down Expand Up @@ -60,12 +77,30 @@ pub struct RealtimeSessionCreateResponse {
// ============================================================================

#[serde_with::skip_serializing_none]
#[derive(Debug, Clone, Serialize, Deserialize)]
#[derive(Debug, Clone, Serialize, Deserialize, Validate)]
#[validate(schema(function = "validate_transcription_session_create_request"))]
pub struct RealtimeTranscriptionSessionCreateRequest {
#[serde(rename = "type")]
pub r#type: RealtimeTranscriptionSessionType,
pub audio: Option<RealtimeTranscriptionSessionAudio>,
pub include: Option<Vec<RealtimeIncludeOption>>,
pub model: Option<String>,
pub language: Option<String>,
pub prompt: Option<String>,
}

impl Normalizable for RealtimeTranscriptionSessionCreateRequest {
// Use default no-op implementation
}

fn validate_transcription_session_create_request(
req: &RealtimeTranscriptionSessionCreateRequest,
) -> Result<(), ValidationError> {
let has_model = req.model.as_deref().is_some_and(|m| !m.trim().is_empty());
if !has_model {
return Err(ValidationError::new("model is required"));
}
Ok(())
}

// ============================================================================
Expand Down Expand Up @@ -446,6 +481,29 @@ pub enum RealtimeTruncation {
// Client Secret
// ============================================================================

#[serde_with::skip_serializing_none]
#[derive(Debug, Clone, Serialize, Deserialize, Validate)]
#[validate(schema(function = "validate_client_secret_create_request"))]
pub struct RealtimeClientSecretCreateRequest {
pub session: RealtimeSessionCreateRequest,
}

impl Normalizable for RealtimeClientSecretCreateRequest {}

fn validate_client_secret_create_request(
req: &RealtimeClientSecretCreateRequest,
) -> Result<(), ValidationError> {
let has_model = req
.session
.model
.as_deref()
.is_some_and(|m| !m.trim().is_empty());
if !has_model {
return Err(ValidationError::new("session.model is required"));
}
Ok(())
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct RealtimeSessionClientSecret {
pub expires_at: i64,
Expand Down
7 changes: 7 additions & 0 deletions model_gateway/src/observability/metrics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -389,6 +389,13 @@ pub mod metrics_labels {
pub const ENDPOINT_RERANK: &str = "rerank";
pub const ENDPOINT_EMBEDDINGS: &str = "embeddings";
pub const ENDPOINT_CLASSIFY: &str = "classify";
pub const ENDPOINT_REALTIME: &str = "realtime";
pub const ENDPOINT_REALTIME_SESSIONS: &str = "realtime_sessions";
pub const ENDPOINT_REALTIME_CLIENT_SECRETS: &str = "realtime_client_secrets";
pub const ENDPOINT_REALTIME_TRANSCRIPTION: &str = "realtime_transcription";

// Connection modes
pub const CONNECTION_WEBSOCKET: &str = "websocket";

// Worker types
pub const WORKER_REGULAR: &str = "regular";
Expand Down
52 changes: 52 additions & 0 deletions model_gateway/src/routers/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@ use openai_protocol::{
generate::GenerateRequest,
interactions::InteractionsRequest,
messages::CreateMessageRequest,
realtime_session::{
RealtimeClientSecretCreateRequest, RealtimeSessionCreateRequest,
RealtimeTranscriptionSessionCreateRequest,
},
rerank::RerankRequest,
responses::{ResponsesGetParams, ResponsesRequest},
};
Expand Down Expand Up @@ -233,6 +237,54 @@ pub trait RouterTrait: Send + Sync + Debug {
.into_response()
}

/// Route a realtime session create request (/v1/realtime/sessions)
async fn route_realtime_session(
&self,
_headers: Option<&HeaderMap>,
_body: &RealtimeSessionCreateRequest,
) -> Response {
(
StatusCode::NOT_IMPLEMENTED,
"Realtime sessions not implemented",
)
.into_response()
}

/// Route a realtime client secret create request (/v1/realtime/client_secrets)
async fn route_realtime_client_secret(
&self,
_headers: Option<&HeaderMap>,
_body: &RealtimeClientSecretCreateRequest,
) -> Response {
(
StatusCode::NOT_IMPLEMENTED,
"Realtime client secrets not implemented",
)
.into_response()
}

/// Route a realtime transcription session create request (/v1/realtime/transcription_sessions)
async fn route_realtime_transcription_session(
&self,
_headers: Option<&HeaderMap>,
_body: &RealtimeTranscriptionSessionCreateRequest,
) -> Response {
(
StatusCode::NOT_IMPLEMENTED,
"Realtime transcription sessions not implemented",
)
.into_response()
}

/// Route a realtime WebSocket upgrade request
async fn route_realtime_ws(&self, _req: Request<Body>, _model_id: &str) -> Response {
(
StatusCode::NOT_IMPLEMENTED,
"Realtime WebSocket not implemented",
)
.into_response()
}

/// Get router type name
fn router_type(&self) -> &'static str;

Expand Down
Loading