Add WebRTC transport to realtime start (#16960)

Adds WebRTC startup to the experimental app-server
`thread/realtime/start` method with an optional transport enum. The
websocket path remains the default; WebRTC offers create the realtime
session through the shared start flow and emit the answer SDP via
`thread/realtime/sdp`.

---------

Co-authored-by: Codex <noreply@openai.com>
This commit is contained in:
Ahmed Ibrahim
2026-04-07 15:43:38 -07:00
committed by GitHub
parent 6c36e7d688
commit fb3dcfde1d
42 changed files with 1574 additions and 85 deletions

View File

@@ -135,6 +135,16 @@ pub struct ConversationStartParams {
pub prompt: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub session_id: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub transport: Option<ConversationStartTransport>,
}
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, JsonSchema, TS)]
#[serde(tag = "type", rename_all = "snake_case")]
#[ts(tag = "type")]
pub enum ConversationStartTransport {
Websocket,
Webrtc { sdp: String },
}
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Eq, JsonSchema, TS)]
@@ -1223,6 +1233,9 @@ pub enum EventMsg {
/// Realtime conversation lifecycle close event.
RealtimeConversationClosed(RealtimeConversationClosedEvent),
/// Realtime session description protocol payload.
RealtimeConversationSdp(RealtimeConversationSdpEvent),
/// Model routing changed from the requested model to a different model.
ModelReroute(ModelRerouteEvent),
@@ -1525,6 +1538,11 @@ pub struct RealtimeConversationClosedEvent {
pub reason: Option<String>,
}
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, JsonSchema, TS)]
pub struct RealtimeConversationSdpEvent {
pub sdp: String,
}
impl From<CollabAgentSpawnBeginEvent> for EventMsg {
fn from(event: CollabAgentSpawnBeginEvent) -> Self {
EventMsg::CollabAgentSpawnBegin(event)
@@ -4393,6 +4411,14 @@ mod tests {
let start = Op::RealtimeConversationStart(ConversationStartParams {
prompt: "be helpful".to_string(),
session_id: Some("conv_1".to_string()),
transport: None,
});
let webrtc_start = Op::RealtimeConversationStart(ConversationStartParams {
prompt: "be helpful".to_string(),
session_id: Some("conv_1".to_string()),
transport: Some(ConversationStartTransport::Webrtc {
sdp: "v=offer\r\n".to_string(),
}),
});
let text = Op::RealtimeConversationText(ConversationTextParams {
text: "hello".to_string(),
@@ -4433,6 +4459,18 @@ mod tests {
serde_json::from_value::<Op>(serde_json::to_value(&close).unwrap()).unwrap(),
close
);
assert_eq!(
serde_json::to_value(&webrtc_start).unwrap(),
json!({
"type": "realtime_conversation_start",
"prompt": "be helpful",
"session_id": "conv_1",
"transport": {
"type": "webrtc",
"sdp": "v=offer\r\n"
}
})
);
}
#[test]