From 7b37a0350f40c646e5cd36d55892da3fc4df4891 Mon Sep 17 00:00:00 2001 From: Ahmed Ibrahim Date: Wed, 18 Mar 2026 15:19:49 -0700 Subject: [PATCH] Add final message prefix to realtime handoff output (#15077) - prefix realtime handoff output with the agent final message label for both realtime v1 and v2 - update realtime websocket and core expectations to match --- .../codex-api/src/endpoint/realtime_websocket/methods.rs | 7 +++++-- .../src/endpoint/realtime_websocket/methods_common.rs | 2 ++ codex-rs/core/tests/suite/realtime_conversation.rs | 8 ++++---- 3 files changed, 11 insertions(+), 6 deletions(-) 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 fe83c751a..c78bac432 100644 --- a/codex-rs/codex-api/src/endpoint/realtime_websocket/methods.rs +++ b/codex-rs/codex-api/src/endpoint/realtime_websocket/methods.rs @@ -1173,7 +1173,10 @@ mod tests { let fourth_json: Value = serde_json::from_str(&fourth).expect("json"); assert_eq!(fourth_json["type"], "conversation.handoff.append"); assert_eq!(fourth_json["handoff_id"], "handoff_1"); - assert_eq!(fourth_json["output_text"], "hello from codex"); + assert_eq!( + fourth_json["output_text"], + "\"Agent Final Message\":\n\nhello from codex" + ); ws.send(Message::Text( json!({ @@ -1504,7 +1507,7 @@ mod tests { ); assert_eq!( third_json["item"]["output"], - Value::String("delegated result".to_string()) + Value::String("\"Agent Final Message\":\n\ndelegated result".to_string()) ); }); 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 48f21964a..1b79122b2 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 @@ -12,6 +12,7 @@ use crate::endpoint::realtime_websocket::protocol::RealtimeSessionMode; use crate::endpoint::realtime_websocket::protocol::SessionUpdateSession; pub(super) const REALTIME_AUDIO_SAMPLE_RATE: u32 = 24_000; +const AGENT_FINAL_MESSAGE_PREFIX: &str = "\"Agent Final Message\":\n\n"; pub(super) fn normalized_session_mode( event_parser: RealtimeEventParser, @@ -38,6 +39,7 @@ pub(super) fn conversation_handoff_append_message( handoff_id: String, output_text: String, ) -> RealtimeOutboundMessage { + let output_text = format!("{AGENT_FINAL_MESSAGE_PREFIX}{output_text}"); match event_parser { RealtimeEventParser::V1 => v1_conversation_handoff_append_message(handoff_id, output_text), RealtimeEventParser::RealtimeV2 => { diff --git a/codex-rs/core/tests/suite/realtime_conversation.rs b/codex-rs/core/tests/suite/realtime_conversation.rs index 87044eb86..06cb31630 100644 --- a/codex-rs/core/tests/suite/realtime_conversation.rs +++ b/codex-rs/core/tests/suite/realtime_conversation.rs @@ -1144,7 +1144,7 @@ async fn conversation_mirrors_assistant_message_text_to_realtime_handoff() -> Re ); assert_eq!( realtime_connections[0][1].body_json()["output_text"].as_str(), - Some("assistant says hi") + Some("\"Agent Final Message\":\n\nassistant says hi") ); realtime_server.shutdown().await; @@ -1249,7 +1249,7 @@ async fn conversation_handoff_persists_across_item_done_until_turn_complete() -> ); assert_eq!( first_append.body_json()["output_text"].as_str(), - Some("assistant message 1") + Some("\"Agent Final Message\":\n\nassistant message 1") ); let _ = wait_for_event_match(&test.codex, |msg| match msg { @@ -1273,7 +1273,7 @@ async fn conversation_handoff_persists_across_item_done_until_turn_complete() -> ); assert_eq!( second_append.body_json()["output_text"].as_str(), - Some("assistant message 2") + Some("\"Agent Final Message\":\n\nassistant message 2") ); let completion = completions @@ -1796,7 +1796,7 @@ async fn delegated_turn_user_role_echo_does_not_redelegate_and_still_forwards_au ); assert_eq!( mirrored_request_body["output_text"].as_str(), - Some("assistant says hi") + Some("\"Agent Final Message\":\n\nassistant says hi") ); let audio_out = wait_for_event_match(&test.codex, |msg| match msg {