mirror of
https://github.com/openai/codex.git
synced 2026-11-10 21:00:47 +00:00
Route realtime V3 handoffs by response channel (#33903)
## What changed - Add `codexResponseHandoffMode` to `thread/realtime/start` for V3 sessions, with `thinking` as the default and `commentary` and `bemTags` routing modes. - Map BEM `analysis` and `commentary` output to the commentary channel and `final` output to the speakable channel, while preserving the original BEM envelope. Unrecognized output falls back to speakable. - Mark explicit speech appends as speakable and stop adding the legacy `"Agent Final Message"` prefix to V3 handoffs. V1 and V2 continue to ignore the new setting. ## Testing - Cover channel selection for every routing mode, streamed BEM header parsing, fallback behavior, explicit speech, and V1 compatibility. GitOrigin-RevId: 1974578257488f2914b252c9c1990ba38831c96b
This commit is contained in:
committed by
copyberry
parent
161748a68e
commit
025db22058
@@ -1764,6 +1764,7 @@ mod tests {
|
||||
use codex_protocol::config_types::MultiAgentMode;
|
||||
use codex_protocol::models::BUILT_IN_PERMISSION_PROFILE_READ_ONLY;
|
||||
use codex_protocol::parse_command::ParsedCommand;
|
||||
use codex_protocol::protocol::CodexResponseHandoffMode;
|
||||
use codex_protocol::protocol::RealtimeConversationVersion;
|
||||
use codex_protocol::protocol::RealtimeOutputModality;
|
||||
use codex_protocol::protocol::RealtimeVoice;
|
||||
@@ -3390,6 +3391,7 @@ mod tests {
|
||||
flush_transcript_tail_on_session_end: Some(true),
|
||||
codex_responses_as_items: None,
|
||||
codex_response_item_prefix: None,
|
||||
codex_response_handoff_mode: Some(CodexResponseHandoffMode::BemTags),
|
||||
thread_id: "thr_123".to_string(),
|
||||
model: Some("realtime-treatment-model".to_string()),
|
||||
output_modality: RealtimeOutputModality::Audio,
|
||||
@@ -3411,6 +3413,7 @@ mod tests {
|
||||
"flushTranscriptTailOnSessionEnd": true,
|
||||
"codexResponsesAsItems": null,
|
||||
"codexResponseItemPrefix": null,
|
||||
"codexResponseHandoffMode": "bemTags",
|
||||
"model": "realtime-treatment-model",
|
||||
"outputModality": "audio",
|
||||
"includeStartupContext": false,
|
||||
@@ -3435,6 +3438,7 @@ mod tests {
|
||||
flush_transcript_tail_on_session_end: None,
|
||||
codex_responses_as_items: None,
|
||||
codex_response_item_prefix: None,
|
||||
codex_response_handoff_mode: None,
|
||||
thread_id: "thr_123".to_string(),
|
||||
model: None,
|
||||
output_modality: RealtimeOutputModality::Audio,
|
||||
@@ -3456,6 +3460,7 @@ mod tests {
|
||||
"flushTranscriptTailOnSessionEnd": null,
|
||||
"codexResponsesAsItems": null,
|
||||
"codexResponseItemPrefix": null,
|
||||
"codexResponseHandoffMode": null,
|
||||
"model": null,
|
||||
"outputModality": "audio",
|
||||
"includeStartupContext": null,
|
||||
@@ -3475,6 +3480,7 @@ mod tests {
|
||||
flush_transcript_tail_on_session_end: None,
|
||||
codex_responses_as_items: None,
|
||||
codex_response_item_prefix: None,
|
||||
codex_response_handoff_mode: None,
|
||||
thread_id: "thr_123".to_string(),
|
||||
model: None,
|
||||
output_modality: RealtimeOutputModality::Audio,
|
||||
@@ -3496,6 +3502,7 @@ mod tests {
|
||||
"flushTranscriptTailOnSessionEnd": null,
|
||||
"codexResponsesAsItems": null,
|
||||
"codexResponseItemPrefix": null,
|
||||
"codexResponseHandoffMode": null,
|
||||
"model": null,
|
||||
"outputModality": "audio",
|
||||
"includeStartupContext": null,
|
||||
@@ -3715,6 +3722,7 @@ mod tests {
|
||||
flush_transcript_tail_on_session_end: None,
|
||||
codex_responses_as_items: None,
|
||||
codex_response_item_prefix: None,
|
||||
codex_response_handoff_mode: None,
|
||||
thread_id: "thr_123".to_string(),
|
||||
model: None,
|
||||
output_modality: RealtimeOutputModality::Audio,
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
use codex_protocol::protocol::CodexResponseHandoffMode;
|
||||
use codex_protocol::protocol::ConversationTextRole;
|
||||
use codex_protocol::protocol::RealtimeAudioFrame as CoreRealtimeAudioFrame;
|
||||
use codex_protocol::protocol::RealtimeConversationVersion;
|
||||
@@ -74,12 +75,18 @@ pub struct ThreadRealtimeStartParams {
|
||||
/// TODO: Remove this rollout knob once transcript-tail flushing is always enabled.
|
||||
#[ts(optional = nullable)]
|
||||
pub flush_transcript_tail_on_session_end: Option<bool>,
|
||||
// TODO: Remove this experiment-only delivery path after response-item testing is complete.
|
||||
/// Sends automatic Codex responses as realtime conversation items instead of handoff appends.
|
||||
#[ts(optional = nullable)]
|
||||
pub codex_responses_as_items: Option<bool>,
|
||||
// TODO: Remove this experiment-only prefix with `codex_responses_as_items`.
|
||||
/// Optional prefix added to automatic Codex response items when `codexResponsesAsItems` is true.
|
||||
#[ts(optional = nullable)]
|
||||
pub codex_response_item_prefix: Option<String>,
|
||||
/// Selects how automatic Codex responses are routed in Frameless Bidi sessions. Omitted values
|
||||
/// default to `thinking`. Realtime V1 and V2 ignore this setting.
|
||||
#[ts(optional = nullable)]
|
||||
pub codex_response_handoff_mode: Option<CodexResponseHandoffMode>,
|
||||
/// Overrides the configured realtime model for this session only.
|
||||
#[ts(optional = nullable)]
|
||||
pub model: Option<String>,
|
||||
|
||||
Reference in New Issue
Block a user