diff --git a/codex-rs/app-server-protocol/schema/json/ClientRequest.json b/codex-rs/app-server-protocol/schema/json/ClientRequest.json index a0c9bc90b4..7a20865f05 100644 --- a/codex-rs/app-server-protocol/schema/json/ClientRequest.json +++ b/codex-rs/app-server-protocol/schema/json/ClientRequest.json @@ -1499,7 +1499,7 @@ } ] }, - "RealtimeConnection": { + "RealtimeOutputModality": { "enum": [ "text", "audio" diff --git a/codex-rs/app-server-protocol/schema/json/codex_app_server_protocol.schemas.json b/codex-rs/app-server-protocol/schema/json/codex_app_server_protocol.schemas.json index 30d4e3b92b..7446569e2c 100644 --- a/codex-rs/app-server-protocol/schema/json/codex_app_server_protocol.schemas.json +++ b/codex-rs/app-server-protocol/schema/json/codex_app_server_protocol.schemas.json @@ -10608,13 +10608,6 @@ } ] }, - "RealtimeConnection": { - "enum": [ - "text", - "audio" - ], - "type": "string" - }, "RealtimeConversationVersion": { "enum": [ "v1", @@ -10622,6 +10615,13 @@ ], "type": "string" }, + "RealtimeOutputModality": { + "enum": [ + "text", + "audio" + ], + "type": "string" + }, "RealtimeTranscriptUpdateKind": { "enum": [ "delta", diff --git a/codex-rs/app-server-protocol/schema/json/codex_app_server_protocol.v2.schemas.json b/codex-rs/app-server-protocol/schema/json/codex_app_server_protocol.v2.schemas.json index d1ba7646c9..139125006d 100644 --- a/codex-rs/app-server-protocol/schema/json/codex_app_server_protocol.v2.schemas.json +++ b/codex-rs/app-server-protocol/schema/json/codex_app_server_protocol.v2.schemas.json @@ -7404,13 +7404,6 @@ } ] }, - "RealtimeConnection": { - "enum": [ - "text", - "audio" - ], - "type": "string" - }, "RealtimeConversationVersion": { "enum": [ "v1", @@ -7418,6 +7411,13 @@ ], "type": "string" }, + "RealtimeOutputModality": { + "enum": [ + "text", + "audio" + ], + "type": "string" + }, "RealtimeTranscriptUpdateKind": { "enum": [ "delta", diff --git a/codex-rs/app-server-protocol/schema/typescript/RealtimeConnection.ts b/codex-rs/app-server-protocol/schema/typescript/RealtimeOutputModality.ts similarity index 73% rename from codex-rs/app-server-protocol/schema/typescript/RealtimeConnection.ts rename to codex-rs/app-server-protocol/schema/typescript/RealtimeOutputModality.ts index bcd9e1b00e..78e00e7143 100644 --- a/codex-rs/app-server-protocol/schema/typescript/RealtimeConnection.ts +++ b/codex-rs/app-server-protocol/schema/typescript/RealtimeOutputModality.ts @@ -2,4 +2,4 @@ // This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. -export type RealtimeConnection = "text" | "audio"; +export type RealtimeOutputModality = "text" | "audio"; diff --git a/codex-rs/app-server-protocol/schema/typescript/index.ts b/codex-rs/app-server-protocol/schema/typescript/index.ts index d3d4c57e62..fe9c81917b 100644 --- a/codex-rs/app-server-protocol/schema/typescript/index.ts +++ b/codex-rs/app-server-protocol/schema/typescript/index.ts @@ -48,8 +48,8 @@ export type { NetworkPolicyRuleAction } from "./NetworkPolicyRuleAction"; export type { ParsedCommand } from "./ParsedCommand"; export type { Personality } from "./Personality"; export type { PlanType } from "./PlanType"; -export type { RealtimeConnection } from "./RealtimeConnection"; export type { RealtimeConversationVersion } from "./RealtimeConversationVersion"; +export type { RealtimeOutputModality } from "./RealtimeOutputModality"; export type { RealtimeTranscriptUpdateKind } from "./RealtimeTranscriptUpdateKind"; export type { RealtimeVoice } from "./RealtimeVoice"; export type { RealtimeVoicesList } from "./RealtimeVoicesList"; diff --git a/codex-rs/app-server-protocol/src/protocol/common.rs b/codex-rs/app-server-protocol/src/protocol/common.rs index 04ac2a5742..3846d5984f 100644 --- a/codex-rs/app-server-protocol/src/protocol/common.rs +++ b/codex-rs/app-server-protocol/src/protocol/common.rs @@ -1050,8 +1050,8 @@ mod tests { use codex_protocol::ThreadId; use codex_protocol::account::PlanType; use codex_protocol::parse_command::ParsedCommand; - use codex_protocol::protocol::RealtimeConnection; use codex_protocol::protocol::RealtimeConversationVersion; + use codex_protocol::protocol::RealtimeOutputModality; use codex_protocol::protocol::RealtimeVoice; use codex_utils_absolute_path::AbsolutePathBuf; use pretty_assertions::assert_eq; @@ -1781,7 +1781,7 @@ mod tests { request_id: RequestId::Integer(9), params: v2::ThreadRealtimeStartParams { thread_id: "thr_123".to_string(), - connection: RealtimeConnection::Audio, + output_modality: RealtimeOutputModality::Audio, prompt: Some(Some("You are on a call".to_string())), session_id: Some("sess_456".to_string()), transport: None, @@ -1794,7 +1794,7 @@ mod tests { "id": 9, "params": { "threadId": "thr_123", - "connection": "audio", + "outputModality": "audio", "prompt": "You are on a call", "sessionId": "sess_456", "transport": null, @@ -1812,7 +1812,7 @@ mod tests { request_id: RequestId::Integer(9), params: v2::ThreadRealtimeStartParams { thread_id: "thr_123".to_string(), - connection: RealtimeConnection::Audio, + output_modality: RealtimeOutputModality::Audio, prompt: None, session_id: None, transport: None, @@ -1825,7 +1825,7 @@ mod tests { "id": 9, "params": { "threadId": "thr_123", - "connection": "audio", + "outputModality": "audio", "sessionId": null, "transport": null, "voice": null @@ -1838,7 +1838,7 @@ mod tests { request_id: RequestId::Integer(9), params: v2::ThreadRealtimeStartParams { thread_id: "thr_123".to_string(), - connection: RealtimeConnection::Audio, + output_modality: RealtimeOutputModality::Audio, prompt: Some(None), session_id: None, transport: None, @@ -1851,7 +1851,7 @@ mod tests { "id": 9, "params": { "threadId": "thr_123", - "connection": "audio", + "outputModality": "audio", "prompt": null, "sessionId": null, "transport": null, @@ -1866,7 +1866,7 @@ mod tests { "id": 9, "params": { "threadId": "thr_123", - "connection": "audio", + "outputModality": "audio", "sessionId": null, "transport": null, "voice": null @@ -1882,7 +1882,7 @@ mod tests { "id": 9, "params": { "threadId": "thr_123", - "connection": "audio", + "outputModality": "audio", "prompt": null, "sessionId": null, "transport": null, @@ -1967,7 +1967,7 @@ mod tests { request_id: RequestId::Integer(1), params: v2::ThreadRealtimeStartParams { thread_id: "thr_123".to_string(), - connection: RealtimeConnection::Audio, + output_modality: RealtimeOutputModality::Audio, prompt: Some(Some("You are on a call".to_string())), session_id: None, transport: None, diff --git a/codex-rs/app-server-protocol/src/protocol/v2.rs b/codex-rs/app-server-protocol/src/protocol/v2.rs index 7bd8206f3f..2c91b7d728 100644 --- a/codex-rs/app-server-protocol/src/protocol/v2.rs +++ b/codex-rs/app-server-protocol/src/protocol/v2.rs @@ -73,8 +73,8 @@ use codex_protocol::protocol::RateLimitSnapshot as CoreRateLimitSnapshot; use codex_protocol::protocol::RateLimitWindow as CoreRateLimitWindow; use codex_protocol::protocol::ReadOnlyAccess as CoreReadOnlyAccess; use codex_protocol::protocol::RealtimeAudioFrame as CoreRealtimeAudioFrame; -use codex_protocol::protocol::RealtimeConnection; use codex_protocol::protocol::RealtimeConversationVersion; +use codex_protocol::protocol::RealtimeOutputModality; use codex_protocol::protocol::RealtimeTranscriptUpdateKind; use codex_protocol::protocol::RealtimeVoice; use codex_protocol::protocol::RealtimeVoicesList; @@ -3963,7 +3963,7 @@ pub struct ThreadRealtimeStartParams { pub thread_id: String, /// Selects text or audio output for the realtime session. Transport and voice stay /// independent so clients can choose how they connect separately from what the model emits. - pub connection: RealtimeConnection, + pub output_modality: RealtimeOutputModality, #[serde( default, deserialize_with = "super::serde_helpers::deserialize_double_option", diff --git a/codex-rs/app-server/README.md b/codex-rs/app-server/README.md index f67ac7596c..cf820e28aa 100644 --- a/codex-rs/app-server/README.md +++ b/codex-rs/app-server/README.md @@ -153,7 +153,7 @@ Example with notification opt-out: - `turn/start` — add user input to a thread and begin Codex generation; responds with the initial `turn` object and streams `turn/started`, `item/*`, and `turn/completed` notifications. For `collaborationMode`, `settings.developer_instructions: null` means "use built-in instructions for the selected mode". - `turn/steer` — add user input to an already in-flight regular turn without starting a new turn; returns the active `turnId` that accepted the input. Review and manual compaction turns reject `turn/steer`. - `turn/interrupt` — request cancellation of an in-flight turn by `(thread_id, turn_id)`; success is an empty `{}` response and the turn finishes with `status: "interrupted"`. -- `thread/realtime/start` — start a thread-scoped realtime session (experimental); pass `connection: "text"` or `connection: "audio"` to choose model output, returns `{}` and streams `thread/realtime/*` notifications. Omit `transport` for the websocket transport, or pass `{ "type": "webrtc", "sdp": "..." }` to create a WebRTC session from a browser-generated SDP offer; the remote answer SDP is emitted as `thread/realtime/sdp`. +- `thread/realtime/start` — start a thread-scoped realtime session (experimental); pass `outputModality: "text"` or `outputModality: "audio"` to choose model output, returns `{}` and streams `thread/realtime/*` notifications. Omit `transport` for the websocket transport, or pass `{ "type": "webrtc", "sdp": "..." }` to create a WebRTC session from a browser-generated SDP offer; the remote answer SDP is emitted as `thread/realtime/sdp`. - `thread/realtime/appendAudio` — append an input audio chunk to the active realtime session (experimental); returns `{}`. - `thread/realtime/appendText` — append text input to the active realtime session (experimental); returns `{}`. - `thread/realtime/stop` — stop the active realtime session for the thread (experimental); returns `{}`. @@ -608,7 +608,7 @@ Then send `offer.sdp` to app-server. Core uses `experimental_realtime_ws_backend ```json { "method": "thread/realtime/start", "id": 40, "params": { "threadId": "thr_123", - "connection": "audio", + "outputModality": "audio", "prompt": "You are on a call.", "sessionId": null, "transport": { "type": "webrtc", "sdp": "v=0\r\no=..." } diff --git a/codex-rs/app-server/src/codex_message_processor.rs b/codex-rs/app-server/src/codex_message_processor.rs index 7ab7e42070..b9e1f65b81 100644 --- a/codex-rs/app-server/src/codex_message_processor.rs +++ b/codex-rs/app-server/src/codex_message_processor.rs @@ -7163,7 +7163,7 @@ impl CodexMessageProcessor { &request_id, thread.as_ref(), Op::RealtimeConversationStart(ConversationStartParams { - connection: params.connection, + output_modality: params.output_modality, prompt: params.prompt, session_id: params.session_id, transport: params.transport.map(|transport| match transport { diff --git a/codex-rs/app-server/tests/suite/v2/experimental_api.rs b/codex-rs/app-server/tests/suite/v2/experimental_api.rs index 4dc400984a..2fd457faf2 100644 --- a/codex-rs/app-server/tests/suite/v2/experimental_api.rs +++ b/codex-rs/app-server/tests/suite/v2/experimental_api.rs @@ -17,7 +17,7 @@ use codex_app_server_protocol::ThreadRealtimeStartParams; use codex_app_server_protocol::ThreadRealtimeStartTransport; use codex_app_server_protocol::ThreadStartParams; use codex_app_server_protocol::ThreadStartResponse; -use codex_protocol::protocol::RealtimeConnection; +use codex_protocol::protocol::RealtimeOutputModality; use pretty_assertions::assert_eq; use std::path::Path; use std::time::Duration; @@ -77,7 +77,7 @@ async fn realtime_conversation_start_requires_experimental_api_capability() -> R let request_id = mcp .send_thread_realtime_start_request(ThreadRealtimeStartParams { thread_id: "thr_123".to_string(), - connection: RealtimeConnection::Audio, + output_modality: RealtimeOutputModality::Audio, prompt: Some(Some("hello".to_string())), session_id: None, transport: None, @@ -147,7 +147,7 @@ async fn realtime_webrtc_start_requires_experimental_api_capability() -> Result< let request_id = mcp .send_thread_realtime_start_request(ThreadRealtimeStartParams { thread_id: "thr_123".to_string(), - connection: RealtimeConnection::Audio, + output_modality: RealtimeOutputModality::Audio, prompt: Some(Some("hello".to_string())), session_id: None, transport: Some(ThreadRealtimeStartTransport::Webrtc { diff --git a/codex-rs/app-server/tests/suite/v2/realtime_conversation.rs b/codex-rs/app-server/tests/suite/v2/realtime_conversation.rs index 60fc8efd45..47d17a9aa1 100644 --- a/codex-rs/app-server/tests/suite/v2/realtime_conversation.rs +++ b/codex-rs/app-server/tests/suite/v2/realtime_conversation.rs @@ -38,8 +38,8 @@ use codex_app_server_protocol::TurnCompletedNotification; use codex_app_server_protocol::TurnStartedNotification; use codex_features::FEATURES; use codex_features::Feature; -use codex_protocol::protocol::RealtimeConnection; use codex_protocol::protocol::RealtimeConversationVersion; +use codex_protocol::protocol::RealtimeOutputModality; use codex_protocol::protocol::RealtimeTranscriptUpdateKind; use codex_protocol::protocol::RealtimeVoice; use codex_protocol::protocol::RealtimeVoicesList; @@ -303,7 +303,7 @@ impl RealtimeE2eHarness { .mcp .send_thread_realtime_start_request(ThreadRealtimeStartParams { thread_id: self.thread_id.clone(), - connection: RealtimeConnection::Audio, + output_modality: RealtimeOutputModality::Audio, prompt: Some(Some("backend prompt".to_string())), session_id: None, transport: Some(ThreadRealtimeStartTransport::Webrtc { @@ -530,7 +530,7 @@ async fn realtime_conversation_streams_v2_notifications() -> Result<()> { let start_request_id = mcp .send_thread_realtime_start_request(ThreadRealtimeStartParams { thread_id: thread_start.thread.id.clone(), - connection: RealtimeConnection::Audio, + output_modality: RealtimeOutputModality::Audio, prompt: None, session_id: None, transport: None, @@ -727,7 +727,7 @@ async fn realtime_conversation_streams_v2_notifications() -> Result<()> { } #[tokio::test] -async fn realtime_text_connection_requests_text_output_and_final_transcript() -> Result<()> { +async fn realtime_text_output_modality_requests_text_output_and_final_transcript() -> Result<()> { skip_if_no_network!(Ok(())); let responses_server = create_mock_responses_server_sequence_unchecked(Vec::new()).await; @@ -777,7 +777,7 @@ async fn realtime_text_connection_requests_text_output_and_final_transcript() -> let start_request_id = mcp .send_thread_realtime_start_request(ThreadRealtimeStartParams { thread_id: thread_start.thread.id.clone(), - connection: RealtimeConnection::Text, + output_modality: RealtimeOutputModality::Text, prompt: None, session_id: None, transport: None, @@ -942,7 +942,7 @@ async fn realtime_conversation_stop_emits_closed_notification() -> Result<()> { let start_request_id = mcp .send_thread_realtime_start_request(ThreadRealtimeStartParams { thread_id: thread_start.thread.id.clone(), - connection: RealtimeConnection::Audio, + output_modality: RealtimeOutputModality::Audio, prompt: Some(Some("backend prompt".to_string())), session_id: None, transport: None, @@ -1039,7 +1039,7 @@ async fn realtime_webrtc_start_emits_sdp_notification() -> Result<()> { let start_request_id = mcp .send_thread_realtime_start_request(ThreadRealtimeStartParams { thread_id: thread_id.clone(), - connection: RealtimeConnection::Audio, + output_modality: RealtimeOutputModality::Audio, prompt: Some(Some("backend prompt".to_string())), session_id: None, transport: Some(ThreadRealtimeStartTransport::Webrtc { @@ -1889,7 +1889,7 @@ async fn realtime_webrtc_start_surfaces_backend_error() -> Result<()> { let start_request_id = mcp .send_thread_realtime_start_request(ThreadRealtimeStartParams { thread_id: thread_start.thread.id, - connection: RealtimeConnection::Audio, + output_modality: RealtimeOutputModality::Audio, prompt: Some(Some("backend prompt".to_string())), session_id: None, transport: Some(ThreadRealtimeStartTransport::Webrtc { @@ -1948,7 +1948,7 @@ async fn realtime_conversation_requires_feature_flag() -> Result<()> { let start_request_id = mcp .send_thread_realtime_start_request(ThreadRealtimeStartParams { thread_id: thread_start.thread.id.clone(), - connection: RealtimeConnection::Audio, + output_modality: RealtimeOutputModality::Audio, prompt: Some(Some("backend prompt".to_string())), session_id: None, transport: None, diff --git a/codex-rs/codex-api/src/endpoint/mod.rs b/codex-rs/codex-api/src/endpoint/mod.rs index 815c3fbba1..515487074f 100644 --- a/codex-rs/codex-api/src/endpoint/mod.rs +++ b/codex-rs/codex-api/src/endpoint/mod.rs @@ -12,8 +12,8 @@ pub use memories::MemoriesClient; pub use models::ModelsClient; pub use realtime_call::RealtimeCallClient; pub use realtime_call::RealtimeCallResponse; -pub use realtime_websocket::RealtimeConnection; pub use realtime_websocket::RealtimeEventParser; +pub use realtime_websocket::RealtimeOutputModality; pub use realtime_websocket::RealtimeSessionConfig; pub use realtime_websocket::RealtimeSessionMode; pub use realtime_websocket::RealtimeTranscriptUpdateKind; diff --git a/codex-rs/codex-api/src/endpoint/realtime_call.rs b/codex-rs/codex-api/src/endpoint/realtime_call.rs index 1900c3443e..fbcdbf519e 100644 --- a/codex-rs/codex-api/src/endpoint/realtime_call.rs +++ b/codex-rs/codex-api/src/endpoint/realtime_call.rs @@ -218,8 +218,8 @@ fn decode_call_id_from_location(headers: &HeaderMap) -> Result #[cfg(test)] mod tests { use super::*; - use crate::endpoint::realtime_websocket::RealtimeConnection; use crate::endpoint::realtime_websocket::RealtimeEventParser; + use crate::endpoint::realtime_websocket::RealtimeOutputModality; use crate::endpoint::realtime_websocket::RealtimeSessionMode; use crate::provider::RetryConfig; use async_trait::async_trait; @@ -310,7 +310,7 @@ mod tests { session_id: Some(session_id.to_string()), event_parser: RealtimeEventParser::RealtimeV2, session_mode: RealtimeSessionMode::Conversational, - connection: RealtimeConnection::Audio, + output_modality: RealtimeOutputModality::Audio, voice: RealtimeVoice::Marin, } } diff --git a/codex-rs/codex-api/src/endpoint/realtime_websocket/methods.rs b/codex-rs/codex-api/src/endpoint/realtime_websocket/methods.rs index f4d3f0648e..36bb8cecd0 100644 --- a/codex-rs/codex-api/src/endpoint/realtime_websocket/methods.rs +++ b/codex-rs/codex-api/src/endpoint/realtime_websocket/methods.rs @@ -4,10 +4,10 @@ use crate::endpoint::realtime_websocket::methods_common::normalized_session_mode use crate::endpoint::realtime_websocket::methods_common::session_update_session; use crate::endpoint::realtime_websocket::methods_common::websocket_intent; use crate::endpoint::realtime_websocket::protocol::RealtimeAudioFrame; -use crate::endpoint::realtime_websocket::protocol::RealtimeConnection; use crate::endpoint::realtime_websocket::protocol::RealtimeEvent; use crate::endpoint::realtime_websocket::protocol::RealtimeEventParser; use crate::endpoint::realtime_websocket::protocol::RealtimeOutboundMessage; +use crate::endpoint::realtime_websocket::protocol::RealtimeOutputModality; use crate::endpoint::realtime_websocket::protocol::RealtimeSessionConfig; use crate::endpoint::realtime_websocket::protocol::RealtimeSessionMode; use crate::endpoint::realtime_websocket::protocol::RealtimeTranscriptDelta; @@ -309,7 +309,7 @@ impl RealtimeWebsocketWriter { &self, instructions: String, session_mode: RealtimeSessionMode, - connection: RealtimeConnection, + output_modality: RealtimeOutputModality, voice: RealtimeVoice, ) -> Result<(), ApiError> { let session_mode = normalized_session_mode(self.event_parser, session_mode); @@ -317,7 +317,7 @@ impl RealtimeWebsocketWriter { self.event_parser, instructions, session_mode, - connection, + output_modality, voice, ); self.send_json(&RealtimeOutboundMessage::SessionUpdate { session }) @@ -628,7 +628,7 @@ impl RealtimeWebsocketClient { .send_session_update( config.instructions, config.session_mode, - config.connection, + config.output_modality, config.voice, ) .await?; @@ -1445,7 +1445,7 @@ mod tests { session_id: Some("conv_1".to_string()), event_parser: RealtimeEventParser::V1, session_mode: RealtimeSessionMode::Conversational, - connection: RealtimeConnection::Audio, + output_modality: RealtimeOutputModality::Audio, voice: RealtimeVoice::Breeze, }, HeaderMap::new(), @@ -1723,7 +1723,7 @@ mod tests { session_id: Some("conv_1".to_string()), event_parser: RealtimeEventParser::RealtimeV2, session_mode: RealtimeSessionMode::Conversational, - connection: RealtimeConnection::Audio, + output_modality: RealtimeOutputModality::Audio, voice: RealtimeVoice::Cedar, }, HeaderMap::new(), @@ -1829,7 +1829,7 @@ mod tests { session_id: Some("conv_1".to_string()), event_parser: RealtimeEventParser::RealtimeV2, session_mode: RealtimeSessionMode::Transcription, - connection: RealtimeConnection::Audio, + output_modality: RealtimeOutputModality::Audio, voice: RealtimeVoice::Marin, }, HeaderMap::new(), @@ -1933,7 +1933,7 @@ mod tests { session_id: Some("conv_1".to_string()), event_parser: RealtimeEventParser::V1, session_mode: RealtimeSessionMode::Transcription, - connection: RealtimeConnection::Audio, + output_modality: RealtimeOutputModality::Audio, voice: RealtimeVoice::Cove, }, HeaderMap::new(), @@ -2023,7 +2023,7 @@ mod tests { session_id: Some("conv_1".to_string()), event_parser: RealtimeEventParser::V1, session_mode: RealtimeSessionMode::Conversational, - connection: RealtimeConnection::Audio, + output_modality: RealtimeOutputModality::Audio, voice: RealtimeVoice::Cove, }, HeaderMap::new(), diff --git a/codex-rs/codex-api/src/endpoint/realtime_websocket/methods_common.rs b/codex-rs/codex-api/src/endpoint/realtime_websocket/methods_common.rs index fe4ca8d2cd..67345bdc7e 100644 --- a/codex-rs/codex-api/src/endpoint/realtime_websocket/methods_common.rs +++ b/codex-rs/codex-api/src/endpoint/realtime_websocket/methods_common.rs @@ -6,9 +6,9 @@ use crate::endpoint::realtime_websocket::methods_v2::conversation_handoff_append use crate::endpoint::realtime_websocket::methods_v2::conversation_item_create_message as v2_conversation_item_create_message; use crate::endpoint::realtime_websocket::methods_v2::session_update_session as v2_session_update_session; use crate::endpoint::realtime_websocket::methods_v2::websocket_intent as v2_websocket_intent; -use crate::endpoint::realtime_websocket::protocol::RealtimeConnection; use crate::endpoint::realtime_websocket::protocol::RealtimeEventParser; use crate::endpoint::realtime_websocket::protocol::RealtimeOutboundMessage; +use crate::endpoint::realtime_websocket::protocol::RealtimeOutputModality; use crate::endpoint::realtime_websocket::protocol::RealtimeSessionConfig; use crate::endpoint::realtime_websocket::protocol::RealtimeSessionMode; use crate::endpoint::realtime_websocket::protocol::RealtimeVoice; @@ -58,14 +58,14 @@ pub(super) fn session_update_session( event_parser: RealtimeEventParser, instructions: String, session_mode: RealtimeSessionMode, - connection: RealtimeConnection, + output_modality: RealtimeOutputModality, voice: RealtimeVoice, ) -> SessionUpdateSession { let session_mode = normalized_session_mode(event_parser, session_mode); match event_parser { RealtimeEventParser::V1 => v1_session_update_session(instructions, voice), RealtimeEventParser::RealtimeV2 => { - v2_session_update_session(instructions, session_mode, connection, voice) + v2_session_update_session(instructions, session_mode, output_modality, voice) } } } @@ -75,7 +75,7 @@ pub fn session_update_session_json(config: RealtimeSessionConfig) -> JsonResult< config.event_parser, config.instructions, config.session_mode, - config.connection, + config.output_modality, config.voice, ); session.id = config.session_id; diff --git a/codex-rs/codex-api/src/endpoint/realtime_websocket/methods_v2.rs b/codex-rs/codex-api/src/endpoint/realtime_websocket/methods_v2.rs index 4b2f0323c8..204909b7f6 100644 --- a/codex-rs/codex-api/src/endpoint/realtime_websocket/methods_v2.rs +++ b/codex-rs/codex-api/src/endpoint/realtime_websocket/methods_v2.rs @@ -8,8 +8,8 @@ use crate::endpoint::realtime_websocket::protocol::ConversationItemType; use crate::endpoint::realtime_websocket::protocol::ConversationMessageItem; use crate::endpoint::realtime_websocket::protocol::ConversationRole; use crate::endpoint::realtime_websocket::protocol::NoiseReductionType; -use crate::endpoint::realtime_websocket::protocol::RealtimeConnection; use crate::endpoint::realtime_websocket::protocol::RealtimeOutboundMessage; +use crate::endpoint::realtime_websocket::protocol::RealtimeOutputModality; use crate::endpoint::realtime_websocket::protocol::RealtimeSessionMode; use crate::endpoint::realtime_websocket::protocol::RealtimeVoice; use crate::endpoint::realtime_websocket::protocol::SessionAudio; @@ -61,7 +61,7 @@ pub(super) fn conversation_handoff_append_message( pub(super) fn session_update_session( instructions: String, session_mode: RealtimeSessionMode, - connection: RealtimeConnection, + output_modality: RealtimeOutputModality, voice: RealtimeVoice, ) -> SessionUpdateSession { match session_mode { @@ -70,7 +70,7 @@ pub(super) fn session_update_session( r#type: SessionType::Realtime, model: None, instructions: Some(instructions), - output_modalities: Some(vec![output_modality(connection).to_string()]), + output_modalities: Some(vec![output_modality_value(output_modality).to_string()]), audio: SessionAudio { input: SessionAudioInput { format: SessionAudioFormat { @@ -135,10 +135,10 @@ pub(super) fn session_update_session( } } -fn output_modality(connection: RealtimeConnection) -> &'static str { - match connection { - RealtimeConnection::Text => REALTIME_V2_OUTPUT_MODALITY_TEXT, - RealtimeConnection::Audio => REALTIME_V2_OUTPUT_MODALITY_AUDIO, +fn output_modality_value(output_modality: RealtimeOutputModality) -> &'static str { + match output_modality { + RealtimeOutputModality::Text => REALTIME_V2_OUTPUT_MODALITY_TEXT, + RealtimeOutputModality::Audio => REALTIME_V2_OUTPUT_MODALITY_AUDIO, } } diff --git a/codex-rs/codex-api/src/endpoint/realtime_websocket/mod.rs b/codex-rs/codex-api/src/endpoint/realtime_websocket/mod.rs index c93f6cf2ef..254849b7fd 100644 --- a/codex-rs/codex-api/src/endpoint/realtime_websocket/mod.rs +++ b/codex-rs/codex-api/src/endpoint/realtime_websocket/mod.rs @@ -12,8 +12,8 @@ pub use methods::RealtimeWebsocketConnection; pub use methods::RealtimeWebsocketEvents; pub use methods::RealtimeWebsocketWriter; pub use methods_common::session_update_session_json; -pub use protocol::RealtimeConnection; pub use protocol::RealtimeEventParser; +pub use protocol::RealtimeOutputModality; pub use protocol::RealtimeSessionConfig; pub use protocol::RealtimeSessionMode; pub use protocol::RealtimeTranscriptUpdateKind; diff --git a/codex-rs/codex-api/src/endpoint/realtime_websocket/protocol.rs b/codex-rs/codex-api/src/endpoint/realtime_websocket/protocol.rs index 1aa7e1473a..b193de2e16 100644 --- a/codex-rs/codex-api/src/endpoint/realtime_websocket/protocol.rs +++ b/codex-rs/codex-api/src/endpoint/realtime_websocket/protocol.rs @@ -1,8 +1,8 @@ use crate::endpoint::realtime_websocket::protocol_v1::parse_realtime_event_v1; use crate::endpoint::realtime_websocket::protocol_v2::parse_realtime_event_v2; pub use codex_protocol::protocol::RealtimeAudioFrame; -pub use codex_protocol::protocol::RealtimeConnection; pub use codex_protocol::protocol::RealtimeEvent; +pub use codex_protocol::protocol::RealtimeOutputModality; pub use codex_protocol::protocol::RealtimeTranscriptDelta; pub use codex_protocol::protocol::RealtimeTranscriptEntry; pub use codex_protocol::protocol::RealtimeTranscriptUpdateKind; @@ -29,7 +29,7 @@ pub struct RealtimeSessionConfig { pub session_id: Option, pub event_parser: RealtimeEventParser, pub session_mode: RealtimeSessionMode, - pub connection: RealtimeConnection, + pub output_modality: RealtimeOutputModality, pub voice: RealtimeVoice, } diff --git a/codex-rs/codex-api/src/lib.rs b/codex-rs/codex-api/src/lib.rs index bd592bfcee..1a280c8bf4 100644 --- a/codex-rs/codex-api/src/lib.rs +++ b/codex-rs/codex-api/src/lib.rs @@ -40,8 +40,8 @@ pub use crate::endpoint::MemoriesClient; pub use crate::endpoint::ModelsClient; pub use crate::endpoint::RealtimeCallClient; pub use crate::endpoint::RealtimeCallResponse; -pub use crate::endpoint::RealtimeConnection; pub use crate::endpoint::RealtimeEventParser; +pub use crate::endpoint::RealtimeOutputModality; pub use crate::endpoint::RealtimeSessionConfig; pub use crate::endpoint::RealtimeSessionMode; pub use crate::endpoint::RealtimeTranscriptUpdateKind; diff --git a/codex-rs/codex-api/tests/realtime_websocket_e2e.rs b/codex-rs/codex-api/tests/realtime_websocket_e2e.rs index c03743d776..abafaef2ae 100644 --- a/codex-rs/codex-api/tests/realtime_websocket_e2e.rs +++ b/codex-rs/codex-api/tests/realtime_websocket_e2e.rs @@ -4,9 +4,9 @@ use std::time::Duration; use codex_api::Provider; use codex_api::RealtimeAudioFrame; -use codex_api::RealtimeConnection; use codex_api::RealtimeEvent; use codex_api::RealtimeEventParser; +use codex_api::RealtimeOutputModality; use codex_api::RealtimeSessionConfig; use codex_api::RealtimeSessionMode; use codex_api::RealtimeWebsocketClient; @@ -146,7 +146,7 @@ async fn realtime_ws_e2e_session_create_and_event_flow() { session_id: Some("conv_123".to_string()), event_parser: RealtimeEventParser::V1, session_mode: RealtimeSessionMode::Conversational, - connection: RealtimeConnection::Audio, + output_modality: RealtimeOutputModality::Audio, voice: RealtimeVoice::Cove, }, HeaderMap::new(), @@ -250,7 +250,7 @@ async fn realtime_ws_connect_webrtc_sideband_retries_join_until_server_is_availa session_id: Some("conv_123".to_string()), event_parser: RealtimeEventParser::RealtimeV2, session_mode: RealtimeSessionMode::Conversational, - connection: RealtimeConnection::Audio, + output_modality: RealtimeOutputModality::Audio, voice: RealtimeVoice::Marin, }, "rtc_test", @@ -322,7 +322,7 @@ async fn realtime_ws_e2e_send_while_next_event_waits() { session_id: Some("conv_123".to_string()), event_parser: RealtimeEventParser::V1, session_mode: RealtimeSessionMode::Conversational, - connection: RealtimeConnection::Audio, + output_modality: RealtimeOutputModality::Audio, voice: RealtimeVoice::Cove, }, HeaderMap::new(), @@ -390,7 +390,7 @@ async fn realtime_ws_e2e_disconnected_emitted_once() { session_id: Some("conv_123".to_string()), event_parser: RealtimeEventParser::V1, session_mode: RealtimeSessionMode::Conversational, - connection: RealtimeConnection::Audio, + output_modality: RealtimeOutputModality::Audio, voice: RealtimeVoice::Cove, }, HeaderMap::new(), @@ -454,7 +454,7 @@ async fn realtime_ws_e2e_ignores_unknown_text_events() { session_id: Some("conv_123".to_string()), event_parser: RealtimeEventParser::V1, session_mode: RealtimeSessionMode::Conversational, - connection: RealtimeConnection::Audio, + output_modality: RealtimeOutputModality::Audio, voice: RealtimeVoice::Cove, }, HeaderMap::new(), @@ -521,7 +521,7 @@ async fn realtime_ws_e2e_realtime_v2_parser_emits_handoff_requested() { session_id: Some("conv_123".to_string()), event_parser: RealtimeEventParser::RealtimeV2, session_mode: RealtimeSessionMode::Conversational, - connection: RealtimeConnection::Audio, + output_modality: RealtimeOutputModality::Audio, voice: RealtimeVoice::Marin, }, HeaderMap::new(), diff --git a/codex-rs/core/src/realtime_conversation.rs b/codex-rs/core/src/realtime_conversation.rs index f1291ef333..be9568cb3a 100644 --- a/codex-rs/core/src/realtime_conversation.rs +++ b/codex-rs/core/src/realtime_conversation.rs @@ -37,12 +37,12 @@ use codex_protocol::protocol::ConversationTextParams; use codex_protocol::protocol::ErrorEvent; use codex_protocol::protocol::Event; use codex_protocol::protocol::EventMsg; -use codex_protocol::protocol::RealtimeConnection; use codex_protocol::protocol::RealtimeConversationClosedEvent; use codex_protocol::protocol::RealtimeConversationRealtimeEvent; use codex_protocol::protocol::RealtimeConversationSdpEvent; use codex_protocol::protocol::RealtimeConversationStartedEvent; use codex_protocol::protocol::RealtimeHandoffRequested; +use codex_protocol::protocol::RealtimeOutputModality; use codex_protocol::protocol::RealtimeVoice; use codex_protocol::protocol::RealtimeVoicesList; use http::HeaderMap; @@ -598,7 +598,7 @@ async fn prepare_realtime_start( sess, params.prompt, params.session_id, - params.connection, + params.output_modality, params.voice, ) .await?; @@ -629,7 +629,7 @@ pub(crate) async fn build_realtime_session_config( sess: &Arc, prompt: Option>, session_id: Option, - connection: RealtimeConnection, + output_modality: RealtimeOutputModality, voice: Option, ) -> CodexResult { let config = sess.get_config().await; @@ -662,10 +662,10 @@ pub(crate) async fn build_realtime_session_config( RealtimeWsVersion::V2 => RealtimeEventParser::RealtimeV2, }; if config.realtime.version == RealtimeWsVersion::V1 - && matches!(connection, RealtimeConnection::Text) + && matches!(output_modality, RealtimeOutputModality::Text) { return Err(CodexErr::InvalidRequest( - "text realtime connection requires realtime v2".to_string(), + "text realtime output modality requires realtime v2".to_string(), )); } let session_mode = match config.realtime.session_type { @@ -682,7 +682,7 @@ pub(crate) async fn build_realtime_session_config( session_id: Some(session_id.unwrap_or_else(|| sess.conversation_id.to_string())), event_parser, session_mode, - connection, + output_modality, voice, }) } diff --git a/codex-rs/core/tests/suite/compact_remote.rs b/codex-rs/core/tests/suite/compact_remote.rs index 9e32b4c1a9..8322046d10 100644 --- a/codex-rs/core/tests/suite/compact_remote.rs +++ b/codex-rs/core/tests/suite/compact_remote.rs @@ -15,9 +15,9 @@ use codex_protocol::protocol::EventMsg; use codex_protocol::protocol::ItemCompletedEvent; use codex_protocol::protocol::ItemStartedEvent; use codex_protocol::protocol::Op; -use codex_protocol::protocol::RealtimeConnection; use codex_protocol::protocol::RealtimeConversationRealtimeEvent; use codex_protocol::protocol::RealtimeEvent; +use codex_protocol::protocol::RealtimeOutputModality; use codex_protocol::protocol::RolloutItem; use codex_protocol::protocol::RolloutLine; use codex_protocol::user_input::UserInput; @@ -117,7 +117,7 @@ async fn start_remote_realtime_server() -> responses::WebSocketTestServer { async fn start_realtime_conversation(codex: &codex_core::CodexThread) -> Result<()> { codex .submit(Op::RealtimeConversationStart(ConversationStartParams { - connection: RealtimeConnection::Audio, + output_modality: RealtimeOutputModality::Audio, prompt: Some(Some("backend prompt".to_string())), session_id: None, transport: None, diff --git a/codex-rs/core/tests/suite/realtime_conversation.rs b/codex-rs/core/tests/suite/realtime_conversation.rs index fb59578586..9ee05b49ba 100644 --- a/codex-rs/core/tests/suite/realtime_conversation.rs +++ b/codex-rs/core/tests/suite/realtime_conversation.rs @@ -18,10 +18,10 @@ use codex_protocol::protocol::EventMsg; use codex_protocol::protocol::InitialHistory; use codex_protocol::protocol::Op; use codex_protocol::protocol::RealtimeAudioFrame; -use codex_protocol::protocol::RealtimeConnection; use codex_protocol::protocol::RealtimeConversationRealtimeEvent; use codex_protocol::protocol::RealtimeConversationVersion; use codex_protocol::protocol::RealtimeEvent; +use codex_protocol::protocol::RealtimeOutputModality; use codex_protocol::protocol::RealtimeVoice; use codex_protocol::protocol::RolloutItem; use codex_protocol::protocol::SessionSource; @@ -248,7 +248,7 @@ async fn conversation_start_audio_text_close_round_trip() -> Result<()> { test.codex .submit(Op::RealtimeConversationStart(ConversationStartParams { - connection: RealtimeConnection::Audio, + output_modality: RealtimeOutputModality::Audio, prompt: Some(Some("backend prompt".to_string())), session_id: None, transport: None, @@ -382,7 +382,7 @@ async fn conversation_start_defaults_to_v2_and_gpt_realtime_1_5() -> Result<()> test.codex .submit(Op::RealtimeConversationStart(ConversationStartParams { - connection: RealtimeConnection::Audio, + output_modality: RealtimeOutputModality::Audio, prompt: Some(Some("backend prompt".to_string())), session_id: None, transport: None, @@ -466,7 +466,7 @@ async fn conversation_webrtc_start_posts_generated_session() -> Result<()> { test.codex .submit(Op::RealtimeConversationStart(ConversationStartParams { - connection: RealtimeConnection::Audio, + output_modality: RealtimeOutputModality::Audio, prompt: Some(Some("backend prompt".to_string())), session_id: None, transport: Some(ConversationStartTransport::Webrtc { @@ -604,7 +604,7 @@ async fn conversation_start_uses_openai_env_key_fallback_with_chatgpt_auth() -> test.codex .submit(Op::RealtimeConversationStart(ConversationStartParams { - connection: RealtimeConnection::Audio, + output_modality: RealtimeOutputModality::Audio, prompt: Some(Some("backend prompt".to_string())), session_id: None, transport: None, @@ -666,7 +666,7 @@ async fn conversation_transport_close_emits_closed_event() -> Result<()> { test.codex .submit(Op::RealtimeConversationStart(ConversationStartParams { - connection: RealtimeConnection::Audio, + output_modality: RealtimeOutputModality::Audio, prompt: Some(Some("backend prompt".to_string())), session_id: None, transport: None, @@ -752,7 +752,7 @@ async fn conversation_start_preflight_failure_emits_realtime_error_only() -> Res test.codex .submit(Op::RealtimeConversationStart(ConversationStartParams { - connection: RealtimeConnection::Audio, + output_modality: RealtimeOutputModality::Audio, prompt: Some(Some("backend prompt".to_string())), session_id: None, transport: None, @@ -796,7 +796,7 @@ async fn conversation_start_connect_failure_emits_realtime_error_only() -> Resul test.codex .submit(Op::RealtimeConversationStart(ConversationStartParams { - connection: RealtimeConnection::Audio, + output_modality: RealtimeOutputModality::Audio, prompt: Some(Some("backend prompt".to_string())), session_id: None, transport: None, @@ -887,7 +887,7 @@ async fn conversation_second_start_replaces_runtime() -> Result<()> { test.codex .submit(Op::RealtimeConversationStart(ConversationStartParams { - connection: RealtimeConnection::Audio, + output_modality: RealtimeOutputModality::Audio, prompt: Some(Some("old".to_string())), session_id: Some("conv_old".to_string()), transport: None, @@ -906,7 +906,7 @@ async fn conversation_second_start_replaces_runtime() -> Result<()> { test.codex .submit(Op::RealtimeConversationStart(ConversationStartParams { - connection: RealtimeConnection::Audio, + output_modality: RealtimeOutputModality::Audio, prompt: Some(Some("new".to_string())), session_id: Some("conv_new".to_string()), transport: None, @@ -996,7 +996,7 @@ async fn conversation_uses_experimental_realtime_ws_base_url_override() -> Resul test.codex .submit(Op::RealtimeConversationStart(ConversationStartParams { - connection: RealtimeConnection::Audio, + output_modality: RealtimeOutputModality::Audio, prompt: Some(Some("backend prompt".to_string())), session_id: None, transport: None, @@ -1054,7 +1054,7 @@ async fn conversation_uses_default_realtime_backend_prompt() -> Result<()> { test.codex .submit(Op::RealtimeConversationStart(ConversationStartParams { - connection: RealtimeConnection::Audio, + output_modality: RealtimeOutputModality::Audio, prompt: None, session_id: None, transport: None, @@ -1120,7 +1120,7 @@ async fn conversation_uses_empty_instructions_for_null_or_empty_prompt() -> Resu ] { test.codex .submit(Op::RealtimeConversationStart(ConversationStartParams { - connection: RealtimeConnection::Audio, + output_modality: RealtimeOutputModality::Audio, prompt, session_id: None, transport: None, @@ -1179,7 +1179,7 @@ async fn conversation_uses_explicit_start_voice() -> Result<()> { test.codex .submit(Op::RealtimeConversationStart(ConversationStartParams { - connection: RealtimeConnection::Audio, + output_modality: RealtimeOutputModality::Audio, prompt: Some(Some("backend prompt".to_string())), session_id: None, transport: None, @@ -1230,7 +1230,7 @@ async fn conversation_uses_configured_realtime_voice() -> Result<()> { test.codex .submit(Op::RealtimeConversationStart(ConversationStartParams { - connection: RealtimeConnection::Audio, + output_modality: RealtimeOutputModality::Audio, prompt: Some(Some("backend prompt".to_string())), session_id: None, transport: None, @@ -1269,7 +1269,7 @@ async fn conversation_rejects_voice_for_wrong_realtime_version() -> Result<()> { test.codex .submit(Op::RealtimeConversationStart(ConversationStartParams { - connection: RealtimeConnection::Audio, + output_modality: RealtimeOutputModality::Audio, prompt: Some(Some("backend prompt".to_string())), session_id: None, transport: None, @@ -1313,7 +1313,7 @@ async fn conversation_uses_experimental_realtime_ws_backend_prompt_override() -> test.codex .submit(Op::RealtimeConversationStart(ConversationStartParams { - connection: RealtimeConnection::Audio, + output_modality: RealtimeOutputModality::Audio, prompt: Some(Some("prompt from op".to_string())), session_id: None, transport: None, @@ -1379,7 +1379,7 @@ async fn conversation_uses_experimental_realtime_ws_startup_context_override() - test.codex .submit(Op::RealtimeConversationStart(ConversationStartParams { - connection: RealtimeConnection::Audio, + output_modality: RealtimeOutputModality::Audio, prompt: Some(Some("prompt from op".to_string())), session_id: None, transport: None, @@ -1443,7 +1443,7 @@ async fn conversation_disables_realtime_startup_context_with_empty_override() -> test.codex .submit(Op::RealtimeConversationStart(ConversationStartParams { - connection: RealtimeConnection::Audio, + output_modality: RealtimeOutputModality::Audio, prompt: Some(Some("prompt from op".to_string())), session_id: None, transport: None, @@ -1500,7 +1500,7 @@ async fn conversation_start_injects_startup_context_from_thread_history() -> Res test.codex .submit(Op::RealtimeConversationStart(ConversationStartParams { - connection: RealtimeConnection::Audio, + output_modality: RealtimeOutputModality::Audio, prompt: Some(Some("backend prompt".to_string())), session_id: None, transport: None, @@ -1612,7 +1612,7 @@ async fn conversation_startup_context_current_thread_selects_many_turns_by_budge codex .submit(Op::RealtimeConversationStart(ConversationStartParams { - connection: RealtimeConnection::Audio, + output_modality: RealtimeOutputModality::Audio, prompt: Some(Some("backend prompt".to_string())), session_id: None, transport: None, @@ -1717,7 +1717,7 @@ async fn conversation_startup_context_falls_back_to_workspace_map() -> Result<() test.codex .submit(Op::RealtimeConversationStart(ConversationStartParams { - connection: RealtimeConnection::Audio, + output_modality: RealtimeOutputModality::Audio, prompt: Some(Some("backend prompt".to_string())), session_id: None, transport: None, @@ -1772,7 +1772,7 @@ async fn conversation_startup_context_is_truncated_and_sent_once_per_start() -> test.codex .submit(Op::RealtimeConversationStart(ConversationStartParams { - connection: RealtimeConnection::Audio, + output_modality: RealtimeOutputModality::Audio, prompt: Some(Some("backend prompt".to_string())), session_id: None, transport: None, @@ -1848,7 +1848,7 @@ async fn conversation_user_text_turn_is_sent_to_realtime_when_active() -> Result test.codex .submit(Op::RealtimeConversationStart(ConversationStartParams { - connection: RealtimeConnection::Audio, + output_modality: RealtimeOutputModality::Audio, prompt: Some(Some("backend prompt".to_string())), session_id: None, transport: None, @@ -1981,7 +1981,7 @@ async fn conversation_mirrors_assistant_message_text_to_realtime_handoff() -> Re test.codex .submit(Op::RealtimeConversationStart(ConversationStartParams { - connection: RealtimeConnection::Audio, + output_modality: RealtimeOutputModality::Audio, prompt: Some(Some("backend prompt".to_string())), session_id: None, transport: None, @@ -2111,7 +2111,7 @@ async fn conversation_handoff_persists_across_item_done_until_turn_complete() -> test.codex .submit(Op::RealtimeConversationStart(ConversationStartParams { - connection: RealtimeConnection::Audio, + output_modality: RealtimeOutputModality::Audio, prompt: Some(Some("backend prompt".to_string())), session_id: None, transport: None, @@ -2256,7 +2256,7 @@ async fn inbound_handoff_request_starts_turn() -> Result<()> { test.codex .submit(Op::RealtimeConversationStart(ConversationStartParams { - connection: RealtimeConnection::Audio, + output_modality: RealtimeOutputModality::Audio, prompt: Some(Some("backend prompt".to_string())), session_id: None, transport: None, @@ -2354,7 +2354,7 @@ async fn inbound_handoff_request_uses_active_transcript() -> Result<()> { test.codex .submit(Op::RealtimeConversationStart(ConversationStartParams { - connection: RealtimeConnection::Audio, + output_modality: RealtimeOutputModality::Audio, prompt: Some(Some("backend prompt".to_string())), session_id: None, transport: None, @@ -2450,7 +2450,7 @@ async fn inbound_handoff_request_clears_active_transcript_after_each_handoff() - test.codex .submit(Op::RealtimeConversationStart(ConversationStartParams { - connection: RealtimeConnection::Audio, + output_modality: RealtimeOutputModality::Audio, prompt: Some(Some("backend prompt".to_string())), session_id: None, transport: None, @@ -2553,7 +2553,7 @@ async fn inbound_conversation_item_does_not_start_turn_and_still_forwards_audio( test.codex .submit(Op::RealtimeConversationStart(ConversationStartParams { - connection: RealtimeConnection::Audio, + output_modality: RealtimeOutputModality::Audio, prompt: Some(Some("backend prompt".to_string())), session_id: None, transport: None, @@ -2669,7 +2669,7 @@ async fn delegated_turn_user_role_echo_does_not_redelegate_and_still_forwards_au test.codex .submit(Op::RealtimeConversationStart(ConversationStartParams { - connection: RealtimeConnection::Audio, + output_modality: RealtimeOutputModality::Audio, prompt: Some(Some("backend prompt".to_string())), session_id: None, transport: None, @@ -2815,7 +2815,7 @@ async fn inbound_handoff_request_does_not_block_realtime_event_forwarding() -> R test.codex .submit(Op::RealtimeConversationStart(ConversationStartParams { - connection: RealtimeConnection::Audio, + output_modality: RealtimeOutputModality::Audio, prompt: Some(Some("backend prompt".to_string())), session_id: None, transport: None, @@ -2946,7 +2946,7 @@ async fn inbound_handoff_request_steers_active_turn() -> Result<()> { test.codex .submit(Op::RealtimeConversationStart(ConversationStartParams { - connection: RealtimeConnection::Audio, + output_modality: RealtimeOutputModality::Audio, prompt: Some(Some("backend prompt".to_string())), session_id: None, transport: None, @@ -3098,7 +3098,7 @@ async fn inbound_handoff_request_starts_turn_and_does_not_block_realtime_audio() test.codex .submit(Op::RealtimeConversationStart(ConversationStartParams { - connection: RealtimeConnection::Audio, + output_modality: RealtimeOutputModality::Audio, prompt: Some(Some("backend prompt".to_string())), session_id: None, transport: None, diff --git a/codex-rs/protocol/src/protocol.rs b/codex-rs/protocol/src/protocol.rs index ba56cc3508..83d1fab536 100644 --- a/codex-rs/protocol/src/protocol.rs +++ b/codex-rs/protocol/src/protocol.rs @@ -135,7 +135,7 @@ pub struct McpServerRefreshConfig { #[derive(Debug, Clone, Deserialize, Serialize, PartialEq, JsonSchema, TS)] pub struct ConversationStartParams { /// Selects whether the realtime session should produce text or audio output. - pub connection: RealtimeConnection, + pub output_modality: RealtimeOutputModality, #[serde( default, deserialize_with = "conversation_start_prompt_serde::deserialize", @@ -161,7 +161,7 @@ pub enum ConversationStartTransport { #[derive(Debug, Clone, Copy, Deserialize, Serialize, PartialEq, Eq, JsonSchema, TS)] #[serde(rename_all = "snake_case")] -pub enum RealtimeConnection { +pub enum RealtimeOutputModality { Text, Audio, } @@ -4603,14 +4603,14 @@ mod tests { }, }); let start = Op::RealtimeConversationStart(ConversationStartParams { - connection: RealtimeConnection::Audio, + output_modality: RealtimeOutputModality::Audio, prompt: Some(Some("be helpful".to_string())), session_id: Some("conv_1".to_string()), transport: None, voice: None, }); let webrtc_start = Op::RealtimeConversationStart(ConversationStartParams { - connection: RealtimeConnection::Audio, + output_modality: RealtimeOutputModality::Audio, prompt: Some(Some("be helpful".to_string())), session_id: Some("conv_1".to_string()), transport: Some(ConversationStartTransport::Webrtc { @@ -4623,14 +4623,14 @@ mod tests { }); let close = Op::RealtimeConversationClose; let default_prompt_start = Op::RealtimeConversationStart(ConversationStartParams { - connection: RealtimeConnection::Audio, + output_modality: RealtimeOutputModality::Audio, prompt: None, session_id: None, transport: None, voice: None, }); let null_prompt_start = Op::RealtimeConversationStart(ConversationStartParams { - connection: RealtimeConnection::Audio, + output_modality: RealtimeOutputModality::Audio, prompt: Some(None), session_id: None, transport: None, @@ -4642,7 +4642,7 @@ mod tests { serde_json::to_value(&start).unwrap(), json!({ "type": "realtime_conversation_start", - "connection": "audio", + "output_modality": "audio", "prompt": "be helpful", "session_id": "conv_1" }) @@ -4651,21 +4651,21 @@ mod tests { serde_json::to_value(&default_prompt_start).unwrap(), json!({ "type": "realtime_conversation_start", - "connection": "audio" + "output_modality": "audio" }) ); assert_eq!( serde_json::to_value(&null_prompt_start).unwrap(), json!({ "type": "realtime_conversation_start", - "connection": "audio", + "output_modality": "audio", "prompt": null }) ); assert_eq!( serde_json::from_value::(json!({ "type": "realtime_conversation_start", - "connection": "audio" + "output_modality": "audio" })) .unwrap(), default_prompt_start @@ -4673,7 +4673,7 @@ mod tests { assert_eq!( serde_json::from_value::(json!({ "type": "realtime_conversation_start", - "connection": "audio", + "output_modality": "audio", "prompt": null })) .unwrap(), @@ -4719,7 +4719,7 @@ mod tests { serde_json::to_value(&webrtc_start).unwrap(), json!({ "type": "realtime_conversation_start", - "connection": "audio", + "output_modality": "audio", "prompt": "be helpful", "session_id": "conv_1", "transport": { diff --git a/codex-rs/tui/src/app_server_session.rs b/codex-rs/tui/src/app_server_session.rs index b86e9829e0..1afa040d70 100644 --- a/codex-rs/tui/src/app_server_session.rs +++ b/codex-rs/tui/src/app_server_session.rs @@ -657,7 +657,7 @@ impl AppServerSession { request_id, params: ThreadRealtimeStartParams { thread_id: thread_id.to_string(), - connection: params.connection, + output_modality: params.output_modality, prompt: params.prompt, session_id: params.session_id, voice: params.voice, diff --git a/codex-rs/tui/src/chatwidget/realtime.rs b/codex-rs/tui/src/chatwidget/realtime.rs index 88c2eab953..e6c6ed49be 100644 --- a/codex-rs/tui/src/chatwidget/realtime.rs +++ b/codex-rs/tui/src/chatwidget/realtime.rs @@ -3,11 +3,11 @@ use codex_config::config_toml::RealtimeTransport; use codex_protocol::protocol::ConversationStartParams; use codex_protocol::protocol::ConversationStartTransport; use codex_protocol::protocol::RealtimeAudioFrame; -use codex_protocol::protocol::RealtimeConnection; use codex_protocol::protocol::RealtimeConversationClosedEvent; use codex_protocol::protocol::RealtimeConversationRealtimeEvent; use codex_protocol::protocol::RealtimeConversationStartedEvent; use codex_protocol::protocol::RealtimeEvent; +use codex_protocol::protocol::RealtimeOutputModality; use codex_realtime_webrtc::RealtimeWebrtcEvent; use codex_realtime_webrtc::RealtimeWebrtcSession; use codex_realtime_webrtc::RealtimeWebrtcSessionHandle; @@ -237,7 +237,7 @@ impl ChatWidget { ) { self.submit_op(AppCommand::realtime_conversation_start( ConversationStartParams { - connection: RealtimeConnection::Audio, + output_modality: RealtimeOutputModality::Audio, prompt: None, session_id: None, transport,