From 52b504ef5ce392d3f0eba7d6bc04ca5e186c46ea Mon Sep 17 00:00:00 2001 From: Ahmed Ibrahim Date: Mon, 13 Apr 2026 23:01:04 -0700 Subject: [PATCH] codex: avoid duplicate realtime audio transcript done --- .../tests/suite/v2/realtime_conversation.rs | 13 +++++++++++++ .../src/endpoint/realtime_websocket/protocol_v2.rs | 4 ---- 2 files changed, 13 insertions(+), 4 deletions(-) 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 a08b041286..fb8a369bf5 100644 --- a/codex-rs/app-server/tests/suite/v2/realtime_conversation.rs +++ b/codex-rs/app-server/tests/suite/v2/realtime_conversation.rs @@ -731,6 +731,10 @@ async fn realtime_text_output_modality_requests_text_output_and_final_transcript "type": "response.output_text.delta", "delta": "world" }), + json!({ + "type": "response.output_audio_transcript.done", + "transcript": "hello world" + }), json!({ "type": "conversation.item.done", "item": { @@ -829,6 +833,15 @@ async fn realtime_text_output_modality_requests_text_output_and_final_transcript text: "hello world".to_string(), } ); + assert!( + timeout( + Duration::from_millis(200), + mcp.read_stream_until_notification_message("thread/realtime/transcript/done"), + ) + .await + .is_err(), + "should not emit duplicate transcript done from audio transcript done" + ); realtime_server.shutdown().await; Ok(()) diff --git a/codex-rs/codex-api/src/endpoint/realtime_websocket/protocol_v2.rs b/codex-rs/codex-api/src/endpoint/realtime_websocket/protocol_v2.rs index 344d7b86dd..559e83426b 100644 --- a/codex-rs/codex-api/src/endpoint/realtime_websocket/protocol_v2.rs +++ b/codex-rs/codex-api/src/endpoint/realtime_websocket/protocol_v2.rs @@ -38,10 +38,6 @@ pub(super) fn parse_realtime_event_v2(payload: &str) -> Option { "response.output_text.delta" | "response.output_audio_transcript.delta" => { parse_transcript_delta_event(&parsed, "delta").map(RealtimeEvent::OutputTranscriptDelta) } - "response.output_audio_transcript.done" => { - parse_transcript_done_event(&parsed, "transcript") - .map(RealtimeEvent::OutputTranscriptDone) - } "input_audio_buffer.speech_started" => Some(RealtimeEvent::InputAudioSpeechStarted( RealtimeInputAudioSpeechStarted { item_id: parsed