realtime: rename provider session ids (#20361)

## Summary

Codex is repurposing `session` to mean a thread group, so the realtime
provider session id should no longer use `session_id` / `sessionId` in
Codex-facing protocol payloads. This PR renames that provider-specific
field to `realtime_session_id` / `realtimeSessionId` and intentionally
breaks clients that still send the old field names.

## What Changed

- Renamed realtime provider session fields in `ConversationStartParams`,
`RealtimeConversationStartedEvent`, and `RealtimeEvent::SessionUpdated`.
- Renamed app-server v2 realtime request and notification fields to
`realtimeSessionId`.
- Removed legacy serde aliases for `session_id` / `sessionId`; clients
must send the new names.
- Propagated the rename through core realtime startup, app-server
adapters, codex-api websocket handling, and TUI realtime state.
- Regenerated app-server protocol schema/TypeScript outputs and updated
app-server README examples.
- Kept upstream Realtime API concepts unchanged: provider `session.id`
parsing and `x-session-id` headers still use the upstream wire names.

## Testing

- CI is running on the latest pushed commit.
- Earlier local verification on this PR:
  - `cargo test -p codex-protocol`
- `CODEX_SKIP_VENDORED_BWRAP=1 cargo test -p codex-core
realtime_conversation`
  - `cargo test -p codex-app-server-protocol`
- `CODEX_SKIP_VENDORED_BWRAP=1 cargo test -p codex-app-server
realtime_conversation`
- attempted `CODEX_SKIP_VENDORED_BWRAP=1 cargo test -p codex-tui` (local
linker bus error while linking the test binary)

---------

Co-authored-by: Codex <noreply@openai.com>
This commit is contained in:
Ahmed Ibrahim
2026-04-30 13:39:48 +03:00
committed by GitHub
Unverified
parent c37f7434ba
commit 8a97f3cf03
23 changed files with 271 additions and 146 deletions
+1 -1
View File
@@ -642,7 +642,7 @@ fn server_notification_thread_events(
vec![Event {
id: String::new(),
msg: EventMsg::RealtimeConversationStarted(RealtimeConversationStartedEvent {
session_id: notification.session_id,
realtime_session_id: notification.realtime_session_id,
version: notification.version,
}),
}],
+1 -1
View File
@@ -922,7 +922,7 @@ impl AppServerSession {
thread_id: thread_id.to_string(),
output_modality: params.output_modality,
prompt: params.prompt,
session_id: params.session_id,
realtime_session_id: params.realtime_session_id,
voice: params.voice,
transport: params.transport.map(|transport| match transport {
ConversationStartTransport::Websocket => {
+1 -1
View File
@@ -6954,7 +6954,7 @@ impl ChatWidget {
if !from_replay {
self.on_realtime_conversation_started(
codex_protocol::protocol::RealtimeConversationStartedEvent {
session_id: notification.session_id,
realtime_session_id: notification.realtime_session_id,
version: notification.version,
},
);
+10 -7
View File
@@ -29,7 +29,7 @@ pub(super) enum RealtimeConversationPhase {
pub(super) struct RealtimeConversationUiState {
pub(super) phase: RealtimeConversationPhase,
requested_close: bool,
session_id: Option<String>,
realtime_session_id: Option<String>,
transport: RealtimeConversationUiTransport,
#[cfg(not(target_os = "linux"))]
pub(super) meter_placeholder_id: Option<String>,
@@ -214,7 +214,7 @@ impl ChatWidget {
pub(super) fn start_realtime_conversation(&mut self) {
self.realtime_conversation.phase = RealtimeConversationPhase::Starting;
self.realtime_conversation.requested_close = false;
self.realtime_conversation.session_id = None;
self.realtime_conversation.realtime_session_id = None;
self.set_footer_hint_override(Some(Self::realtime_footer_hint_items()));
match self.config.realtime.transport {
RealtimeTransport::Websocket => {
@@ -238,7 +238,7 @@ impl ChatWidget {
ConversationStartParams {
output_modality: RealtimeOutputModality::Audio,
prompt: None,
session_id: None,
realtime_session_id: None,
transport,
voice: self.config.realtime.voice,
},
@@ -273,7 +273,7 @@ impl ChatWidget {
self.set_footer_hint_override(/*items*/ None);
self.realtime_conversation.phase = RealtimeConversationPhase::Inactive;
self.realtime_conversation.requested_close = false;
self.realtime_conversation.session_id = None;
self.realtime_conversation.realtime_session_id = None;
self.realtime_conversation.transport = RealtimeConversationUiTransport::Websocket;
}
@@ -295,7 +295,7 @@ impl ChatWidget {
self.request_realtime_conversation_close(/*info_message*/ None);
return;
}
self.realtime_conversation.session_id = ev.session_id;
self.realtime_conversation.realtime_session_id = ev.realtime_session_id;
self.set_footer_hint_override(Some(Self::realtime_footer_hint_items()));
if self.realtime_conversation_uses_webrtc() {
self.realtime_conversation.phase = RealtimeConversationPhase::Starting;
@@ -323,8 +323,11 @@ impl ChatWidget {
return;
}
match ev.payload {
RealtimeEvent::SessionUpdated { session_id, .. } => {
self.realtime_conversation.session_id = Some(session_id);
RealtimeEvent::SessionUpdated {
realtime_session_id,
..
} => {
self.realtime_conversation.realtime_session_id = Some(realtime_session_id);
}
RealtimeEvent::InputAudioSpeechStarted(_) => self.interrupt_realtime_audio_playback(),
RealtimeEvent::InputTranscriptDelta(_) => {}