mirror of
https://github.com/openai/codex.git
synced 2026-10-14 16:38:43 +00:00
Add opt-in reasoning status for realtime V3 delegations (#47377)
## What changed Add `backend_reasoning_status`, disabled by default, to relay public reasoning summaries during active, server-managed realtime V3 delegations. Use the last non-empty summary from each completed reasoning item, truncate it to 256 bytes at a character boundary, and append it as `[STATUS]` context on the `commentary` channel. Discard queued updates if their delegation is no longer active. ## Testing Add an integration test covering enabled and disabled behavior, selection of the latest non-empty summary, exclusion of raw reasoning and partial summaries, and delivery without triggering `response.create` or changing the model's reasoning-summary setting. GitOrigin-RevId: 75ce87dbbbab15a6d9d0ad0b23737738837192fd
This commit is contained in:
BIN
Binary file not shown.
@@ -4009,6 +4009,7 @@ mod tests {
|
||||
codex_responses_as_items: None,
|
||||
codex_response_item_prefix: None,
|
||||
codex_response_handoff_mode: Some(CodexResponseHandoffMode::BemTags),
|
||||
backend_reasoning_status: false,
|
||||
codex_response_handoff_channel_prefixes: Some(std::collections::BTreeMap::from([
|
||||
("analysis".to_string(), vec!["[THINKING]".to_string()]),
|
||||
(
|
||||
@@ -4095,6 +4096,7 @@ mod tests {
|
||||
codex_responses_as_items: None,
|
||||
codex_response_item_prefix: None,
|
||||
codex_response_handoff_mode: None,
|
||||
backend_reasoning_status: false,
|
||||
codex_response_handoff_channel_prefixes: None,
|
||||
thread_id: "thr_123".to_string(),
|
||||
model: None,
|
||||
@@ -4147,6 +4149,7 @@ mod tests {
|
||||
codex_responses_as_items: None,
|
||||
codex_response_item_prefix: None,
|
||||
codex_response_handoff_mode: None,
|
||||
backend_reasoning_status: false,
|
||||
codex_response_handoff_channel_prefixes: None,
|
||||
thread_id: "thr_123".to_string(),
|
||||
model: None,
|
||||
@@ -4399,6 +4402,7 @@ mod tests {
|
||||
codex_responses_as_items: None,
|
||||
codex_response_item_prefix: None,
|
||||
codex_response_handoff_mode: None,
|
||||
backend_reasoning_status: false,
|
||||
codex_response_handoff_channel_prefixes: None,
|
||||
thread_id: "thr_123".to_string(),
|
||||
model: None,
|
||||
|
||||
@@ -220,6 +220,9 @@ pub struct ThreadRealtimeStartParams {
|
||||
/// default to `thinking`. Realtime V1 and V2 ignore this setting.
|
||||
#[ts(optional = nullable)]
|
||||
pub codex_response_handoff_mode: Option<CodexResponseHandoffMode>,
|
||||
/// Relays public reasoning summaries as quiet context for realtime V3 delegations. Defaults to false.
|
||||
#[serde(default, skip_serializing_if = "std::ops::Not::not")]
|
||||
pub backend_reasoning_status: bool,
|
||||
/// Overrides BEM channel prefixes by `analysis`, `commentary`, or `final`.
|
||||
/// Omitted channels retain their default uppercase bracketed prefixes.
|
||||
#[ts(optional = nullable)]
|
||||
|
||||
@@ -1238,6 +1238,7 @@ impl TurnRequestProcessor {
|
||||
codex_responses_as_items: params.codex_responses_as_items.unwrap_or(false),
|
||||
codex_response_item_prefix: params.codex_response_item_prefix,
|
||||
codex_response_handoff_mode: params.codex_response_handoff_mode.unwrap_or_default(),
|
||||
backend_reasoning_status: params.backend_reasoning_status,
|
||||
codex_response_handoff_channel_prefixes: params
|
||||
.codex_response_handoff_channel_prefixes,
|
||||
model: params.model,
|
||||
|
||||
@@ -99,6 +99,7 @@ async fn realtime_conversation_start_requires_experimental_api_capability() -> R
|
||||
codex_responses_as_items: None,
|
||||
codex_response_item_prefix: None,
|
||||
codex_response_handoff_mode: None,
|
||||
backend_reasoning_status: false,
|
||||
codex_response_handoff_channel_prefixes: None,
|
||||
thread_id: "thr_123".to_string(),
|
||||
model: None,
|
||||
@@ -240,6 +241,7 @@ async fn realtime_webrtc_start_requires_experimental_api_capability() -> Result<
|
||||
codex_responses_as_items: None,
|
||||
codex_response_item_prefix: None,
|
||||
codex_response_handoff_mode: None,
|
||||
backend_reasoning_status: false,
|
||||
codex_response_handoff_channel_prefixes: None,
|
||||
thread_id: "thr_123".to_string(),
|
||||
model: None,
|
||||
|
||||
@@ -393,6 +393,7 @@ impl RealtimeE2eHarness {
|
||||
.unwrap_or(false)
|
||||
.then(|| RESPONSE_ITEM_PREFIX.to_string()),
|
||||
codex_response_handoff_mode,
|
||||
backend_reasoning_status: false,
|
||||
codex_response_handoff_channel_prefixes: None,
|
||||
codex_responses_as_items,
|
||||
model: None,
|
||||
@@ -454,6 +455,7 @@ impl RealtimeE2eHarness {
|
||||
.unwrap_or(false)
|
||||
.then(|| RESPONSE_ITEM_PREFIX.to_string()),
|
||||
codex_response_handoff_mode: None,
|
||||
backend_reasoning_status: false,
|
||||
codex_response_handoff_channel_prefixes: None,
|
||||
codex_responses_as_items,
|
||||
model: None,
|
||||
@@ -491,6 +493,7 @@ impl RealtimeE2eHarness {
|
||||
flush_transcript_tail_on_session_end: None,
|
||||
codex_response_item_prefix: None,
|
||||
codex_response_handoff_mode,
|
||||
backend_reasoning_status: false,
|
||||
codex_response_handoff_channel_prefixes,
|
||||
codex_responses_as_items: None,
|
||||
model: None,
|
||||
@@ -709,6 +712,7 @@ async fn realtime_conversation_streams_timeline_items() -> Result<()> {
|
||||
codex_responses_as_items: None,
|
||||
codex_response_item_prefix: None,
|
||||
codex_response_handoff_mode: None,
|
||||
backend_reasoning_status: false,
|
||||
codex_response_handoff_channel_prefixes: None,
|
||||
model: None,
|
||||
output_modality: RealtimeOutputModality::Audio,
|
||||
@@ -905,6 +909,7 @@ async fn realtime_conversation_streams_v2_notifications() -> Result<()> {
|
||||
codex_responses_as_items: None,
|
||||
codex_response_item_prefix: None,
|
||||
codex_response_handoff_mode: None,
|
||||
backend_reasoning_status: false,
|
||||
codex_response_handoff_channel_prefixes: None,
|
||||
thread_id: thread_start.thread.id.clone(),
|
||||
model: Some("realtime-treatment-model".to_string()),
|
||||
@@ -1474,6 +1479,7 @@ async fn realtime_start_can_skip_startup_context() -> Result<()> {
|
||||
codex_responses_as_items: None,
|
||||
codex_response_item_prefix: None,
|
||||
codex_response_handoff_mode: None,
|
||||
backend_reasoning_status: false,
|
||||
codex_response_handoff_channel_prefixes: None,
|
||||
thread_id: thread_start.thread.id.clone(),
|
||||
model: None,
|
||||
@@ -1571,6 +1577,7 @@ async fn realtime_text_output_modality_requests_text_output_and_final_transcript
|
||||
codex_responses_as_items: None,
|
||||
codex_response_item_prefix: None,
|
||||
codex_response_handoff_mode: None,
|
||||
backend_reasoning_status: false,
|
||||
codex_response_handoff_channel_prefixes: None,
|
||||
thread_id: thread_start.thread.id.clone(),
|
||||
model: None,
|
||||
@@ -1748,6 +1755,7 @@ async fn realtime_conversation_stop_emits_closed_notification() -> Result<()> {
|
||||
codex_responses_as_items: None,
|
||||
codex_response_item_prefix: None,
|
||||
codex_response_handoff_mode: None,
|
||||
backend_reasoning_status: false,
|
||||
codex_response_handoff_channel_prefixes: None,
|
||||
thread_id: thread_start.thread.id.clone(),
|
||||
model: None,
|
||||
@@ -1822,6 +1830,7 @@ async fn realtime_mode_uses_client_instructions_on_entry_and_exit() -> Result<()
|
||||
codex_responses_as_items: None,
|
||||
codex_response_item_prefix: None,
|
||||
codex_response_handoff_mode: None,
|
||||
backend_reasoning_status: false,
|
||||
codex_response_handoff_channel_prefixes: None,
|
||||
model: None,
|
||||
output_modality: RealtimeOutputModality::Audio,
|
||||
@@ -2106,6 +2115,7 @@ async fn realtime_webrtc_start_emits_sdp_notification() -> Result<()> {
|
||||
codex_responses_as_items: None,
|
||||
codex_response_item_prefix: None,
|
||||
codex_response_handoff_mode: None,
|
||||
backend_reasoning_status: false,
|
||||
codex_response_handoff_channel_prefixes: None,
|
||||
thread_id: thread_id.clone(),
|
||||
model: None,
|
||||
@@ -2324,6 +2334,7 @@ async fn existing_call_attaches_without_reinitializing_the_client_session(
|
||||
flush_transcript_tail_on_session_end: None,
|
||||
codex_response_item_prefix: None,
|
||||
codex_response_handoff_mode: None,
|
||||
backend_reasoning_status: false,
|
||||
codex_response_handoff_channel_prefixes: None,
|
||||
codex_responses_as_items: None,
|
||||
model: None,
|
||||
@@ -2412,6 +2423,7 @@ async fn existing_call_rejects_client_owned_session_configuration(option: &str)
|
||||
flush_transcript_tail_on_session_end: None,
|
||||
codex_response_item_prefix: None,
|
||||
codex_response_handoff_mode: None,
|
||||
backend_reasoning_status: false,
|
||||
codex_response_handoff_channel_prefixes: None,
|
||||
codex_responses_as_items: None,
|
||||
model: None,
|
||||
@@ -3931,6 +3943,7 @@ async fn realtime_webrtc_start_surfaces_backend_error() -> Result<()> {
|
||||
codex_responses_as_items: None,
|
||||
codex_response_item_prefix: None,
|
||||
codex_response_handoff_mode: None,
|
||||
backend_reasoning_status: false,
|
||||
codex_response_handoff_channel_prefixes: None,
|
||||
thread_id: thread_start.thread.id,
|
||||
model: None,
|
||||
|
||||
@@ -100,6 +100,7 @@ const OUTPUT_EVENTS_QUEUE_CAPACITY: usize = 256;
|
||||
const REALTIME_THREAD_SOURCE_MAX_BYTES: usize = 256;
|
||||
const REALTIME_STARTUP_CONTEXT_TOKEN_BUDGET: usize = 5_300;
|
||||
const REALTIME_ASSISTANT_OUTPUT_TOKEN_BUDGET: usize = 1_000;
|
||||
const REALTIME_REASONING_STATUS_MAX_BYTES: usize = 256;
|
||||
const REALTIME_INITIAL_ITEMS_MAX_COUNT: usize = 128;
|
||||
const REALTIME_INITIAL_ITEMS_MAX_TOKENS: usize = 8_192;
|
||||
const REALTIME_MODE_INSTRUCTIONS_MAX_TOKENS: usize = 8_192;
|
||||
@@ -189,6 +190,7 @@ struct RealtimeHandoffState {
|
||||
codex_responses_as_items: bool,
|
||||
codex_response_item_prefix: Option<String>,
|
||||
codex_response_handoff_mode: CodexResponseHandoffMode,
|
||||
backend_reasoning_status: bool,
|
||||
codex_response_handoff_channel_prefixes: Arc<BTreeMap<String, Vec<String>>>,
|
||||
session_kind: RealtimeSessionKind,
|
||||
event_parser: RealtimeEventParser,
|
||||
@@ -361,6 +363,10 @@ fn take_last_bytes_at_char_boundary(text: &str, max_bytes: usize) -> &str {
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
enum RealtimeOutbound {
|
||||
QuietReasoningStatus {
|
||||
handoff_id: String,
|
||||
text: String,
|
||||
},
|
||||
StandaloneHandoff {
|
||||
text: String,
|
||||
phase: Option<MessagePhase>,
|
||||
@@ -516,6 +522,7 @@ struct RealtimeStart {
|
||||
codex_responses_as_items: bool,
|
||||
codex_response_item_prefix: Option<String>,
|
||||
codex_response_handoff_mode: CodexResponseHandoffMode,
|
||||
backend_reasoning_status: bool,
|
||||
codex_response_handoff_channel_prefixes: Option<BTreeMap<String, Vec<String>>>,
|
||||
realtime_call_api_provider: Option<ApiProvider>,
|
||||
session_config: RealtimeSessionConfig,
|
||||
@@ -610,6 +617,7 @@ impl RealtimeConversationManager {
|
||||
codex_responses_as_items,
|
||||
codex_response_item_prefix,
|
||||
codex_response_handoff_mode,
|
||||
backend_reasoning_status,
|
||||
codex_response_handoff_channel_prefixes,
|
||||
realtime_call_api_provider,
|
||||
session_config,
|
||||
@@ -644,6 +652,7 @@ impl RealtimeConversationManager {
|
||||
codex_responses_as_items,
|
||||
codex_response_item_prefix,
|
||||
codex_response_handoff_mode,
|
||||
backend_reasoning_status,
|
||||
codex_response_handoff_channel_prefixes: Arc::new(
|
||||
codex_response_handoff_channel_prefixes.unwrap_or_default(),
|
||||
),
|
||||
@@ -840,6 +849,34 @@ impl RealtimeConversationManager {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) async fn send_reasoning_status(&self, text: &str) -> CodexResult<()> {
|
||||
let handoff = self
|
||||
.state
|
||||
.lock()
|
||||
.await
|
||||
.as_ref()
|
||||
.map(|state| state.handoff.clone());
|
||||
let Some(handoff) = handoff.filter(|handoff| {
|
||||
handoff.backend_reasoning_status
|
||||
&& !handoff.client_managed_handoffs
|
||||
&& handoff.event_parser == RealtimeEventParser::FramelessBidi
|
||||
}) else {
|
||||
return Ok(());
|
||||
};
|
||||
let Some(handoff_id) = handoff.stream.lock().await.active_handoff.clone() else {
|
||||
return Ok(());
|
||||
};
|
||||
let text = take_bytes_at_char_boundary(text, REALTIME_REASONING_STATUS_MAX_BYTES);
|
||||
handoff
|
||||
.output_tx
|
||||
.send(RealtimeOutbound::QuietReasoningStatus {
|
||||
handoff_id,
|
||||
text: format!("[STATUS] {text}"),
|
||||
})
|
||||
.await
|
||||
.map_err(|_| CodexErr::InvalidRequest("conversation is not running".to_string()))
|
||||
}
|
||||
|
||||
pub(crate) async fn handoff_out(
|
||||
&self,
|
||||
output_text: String,
|
||||
@@ -1215,6 +1252,7 @@ struct PreparedRealtimeConversationStart {
|
||||
codex_responses_as_items: bool,
|
||||
codex_response_item_prefix: Option<String>,
|
||||
codex_response_handoff_mode: CodexResponseHandoffMode,
|
||||
backend_reasoning_status: bool,
|
||||
codex_response_handoff_channel_prefixes: Option<BTreeMap<String, Vec<String>>>,
|
||||
realtime_start_instructions: Option<String>,
|
||||
realtime_end_instructions: Option<String>,
|
||||
@@ -1357,6 +1395,7 @@ async fn prepare_realtime_start(
|
||||
codex_responses_as_items: params.codex_responses_as_items,
|
||||
codex_response_item_prefix: params.codex_response_item_prefix,
|
||||
codex_response_handoff_mode: params.codex_response_handoff_mode,
|
||||
backend_reasoning_status: params.backend_reasoning_status,
|
||||
codex_response_handoff_channel_prefixes: params.codex_response_handoff_channel_prefixes,
|
||||
realtime_start_instructions: params.realtime_start_instructions,
|
||||
realtime_end_instructions: params.realtime_end_instructions,
|
||||
@@ -1580,6 +1619,7 @@ async fn handle_start_inner(
|
||||
codex_responses_as_items,
|
||||
codex_response_item_prefix,
|
||||
codex_response_handoff_mode,
|
||||
backend_reasoning_status,
|
||||
codex_response_handoff_channel_prefixes,
|
||||
realtime_start_instructions,
|
||||
realtime_end_instructions,
|
||||
@@ -1609,6 +1649,7 @@ async fn handle_start_inner(
|
||||
codex_responses_as_items,
|
||||
codex_response_item_prefix,
|
||||
codex_response_handoff_mode,
|
||||
backend_reasoning_status,
|
||||
codex_response_handoff_channel_prefixes,
|
||||
realtime_call_api_provider,
|
||||
session_config,
|
||||
@@ -2190,6 +2231,7 @@ async fn handle_handoff_output(
|
||||
let handoff_output = handoff_output.context("handoff output channel closed")?;
|
||||
let result = match event_parser {
|
||||
RealtimeEventParser::V1 => match handoff_output {
|
||||
RealtimeOutbound::QuietReasoningStatus { .. } => Ok(()),
|
||||
RealtimeOutbound::StandaloneHandoff { text, phase: _ } => {
|
||||
writer
|
||||
.send_standalone_handoff(STANDALONE_HANDOFF_ID.to_string(), text)
|
||||
@@ -2231,6 +2273,18 @@ async fn handle_handoff_output(
|
||||
RealtimeOutbound::HandoffCompleteAck { .. } => Ok(()),
|
||||
},
|
||||
RealtimeEventParser::FramelessBidi => match handoff_output {
|
||||
RealtimeOutbound::QuietReasoningStatus { handoff_id, text } => {
|
||||
if handoff_state.stream.lock().await.active_handoff.as_deref() != Some(&handoff_id)
|
||||
{
|
||||
return Ok(());
|
||||
}
|
||||
// An omitted channel defaults to speakable on this wire protocol.
|
||||
writer
|
||||
.clone()
|
||||
.with_context_append_channel(RealtimeContextAppendChannel::Commentary)
|
||||
.send_conversation_handoff_append(handoff_id, text)
|
||||
.await
|
||||
}
|
||||
RealtimeOutbound::StandaloneHandoff { text, phase } => {
|
||||
v3_output_writer(
|
||||
writer,
|
||||
@@ -2298,6 +2352,7 @@ async fn handle_handoff_output(
|
||||
RealtimeOutbound::HandoffCompleteAck { .. } => Ok(()),
|
||||
},
|
||||
RealtimeEventParser::RealtimeV2 => match handoff_output {
|
||||
RealtimeOutbound::QuietReasoningStatus { .. } => Ok(()),
|
||||
RealtimeOutbound::StandaloneHandoff { text, phase: _ } => {
|
||||
if let Err(err) = writer
|
||||
.send_conversation_item_create(text, ConversationTextRole::User)
|
||||
|
||||
@@ -214,6 +214,7 @@ async fn clears_active_handoff_explicitly() {
|
||||
client_managed_handoffs: false,
|
||||
codex_responses_as_items: false,
|
||||
codex_response_item_prefix: None,
|
||||
backend_reasoning_status: false,
|
||||
codex_response_handoff_mode: CodexResponseHandoffMode::Thinking,
|
||||
codex_response_handoff_channel_prefixes: Arc::new(BTreeMap::new()),
|
||||
session_kind: RealtimeSessionKind::V1,
|
||||
|
||||
@@ -278,6 +278,7 @@ use self::session::SessionSettingsCommit;
|
||||
pub(crate) use self::session::SessionSettingsUpdate;
|
||||
#[cfg(test)]
|
||||
use self::turn::AssistantMessageStreamParsers;
|
||||
use self::turn::RealtimeEventText;
|
||||
use self::turn::agent_message_text;
|
||||
#[cfg(test)]
|
||||
use self::turn::collect_explicit_app_ids_from_skill_items;
|
||||
@@ -2491,10 +2492,16 @@ impl Session {
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
let Some((text, phase)) = realtime_text_for_event(msg) else {
|
||||
return;
|
||||
let result = match realtime_text_for_event(msg) {
|
||||
Some(RealtimeEventText::Handoff(text, phase)) => {
|
||||
self.conversation.handoff_out(text, phase).await
|
||||
}
|
||||
Some(RealtimeEventText::QuietReasoning(text)) => {
|
||||
self.conversation.send_reasoning_status(&text).await
|
||||
}
|
||||
None => return,
|
||||
};
|
||||
if let Err(err) = self.conversation.handoff_out(text, phase).await {
|
||||
if let Err(err) = result {
|
||||
debug!("failed to mirror event text to realtime conversation: {err}");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2000,7 +2000,13 @@ pub(super) fn agent_message_text(item: &codex_protocol::items::AgentMessageItem)
|
||||
.collect()
|
||||
}
|
||||
|
||||
pub(super) fn realtime_text_for_event(msg: &EventMsg) -> Option<(String, Option<MessagePhase>)> {
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub(super) enum RealtimeEventText {
|
||||
Handoff(String, Option<MessagePhase>),
|
||||
QuietReasoning(String),
|
||||
}
|
||||
|
||||
pub(super) fn realtime_text_for_event(msg: &EventMsg) -> Option<RealtimeEventText> {
|
||||
match msg {
|
||||
EventMsg::ElicitationRequest(request)
|
||||
if matches!(
|
||||
@@ -2008,11 +2014,27 @@ pub(super) fn realtime_text_for_event(msg: &EventMsg) -> Option<(String, Option<
|
||||
codex_protocol::approvals::ElicitationRequest::UserVerification { .. }
|
||||
) =>
|
||||
{
|
||||
Some((UserVerificationNotice.render(), None))
|
||||
Some(RealtimeEventText::Handoff(
|
||||
UserVerificationNotice.render(),
|
||||
None,
|
||||
))
|
||||
}
|
||||
EventMsg::AgentMessage(event) => Some((event.message.clone(), event.phase.clone())),
|
||||
EventMsg::AgentMessage(event) => Some(RealtimeEventText::Handoff(
|
||||
event.message.clone(),
|
||||
event.phase.clone(),
|
||||
)),
|
||||
EventMsg::ItemCompleted(event) => match &event.item {
|
||||
TurnItem::AgentMessage(item) => Some((agent_message_text(item), item.phase.clone())),
|
||||
TurnItem::AgentMessage(item) => Some(RealtimeEventText::Handoff(
|
||||
agent_message_text(item),
|
||||
item.phase.clone(),
|
||||
)),
|
||||
TurnItem::Reasoning(item) => item
|
||||
.summary_text
|
||||
.iter()
|
||||
.rev()
|
||||
.map(|summary| summary.trim())
|
||||
.find(|summary| !summary.is_empty())
|
||||
.map(|summary| RealtimeEventText::QuietReasoning(summary.to_owned())),
|
||||
_ => None,
|
||||
},
|
||||
EventMsg::ExecApprovalRequest(_)
|
||||
@@ -2030,7 +2052,7 @@ pub(super) fn realtime_text_for_event(msg: &EventMsg) -> Option<(String, Option<
|
||||
};
|
||||
serde_json::to_string(msg)
|
||||
.ok()
|
||||
.map(|request| (format!("{message}\n\n{request}"), None))
|
||||
.map(|request| RealtimeEventText::Handoff(format!("{message}\n\n{request}"), None))
|
||||
}
|
||||
EventMsg::Error(_)
|
||||
| EventMsg::Warning(_)
|
||||
|
||||
@@ -103,7 +103,7 @@ fn realtime_user_verification_notice_excludes_request_payload() {
|
||||
});
|
||||
assert_eq!(
|
||||
realtime_text_for_event(&event),
|
||||
Some((
|
||||
Some(RealtimeEventText::Handoff(
|
||||
"<user_verification_notice>User verification is required. Please respond in the app.</user_verification_notice>".to_string(),
|
||||
None,
|
||||
)),
|
||||
|
||||
@@ -104,6 +104,7 @@ async fn start_realtime_conversation(codex: &codex_core::CodexThread) -> Result<
|
||||
codex_response_item_prefix: None,
|
||||
codex_response_handoff_mode:
|
||||
codex_protocol::protocol::CodexResponseHandoffMode::Thinking,
|
||||
backend_reasoning_status: false,
|
||||
codex_response_handoff_channel_prefixes: None,
|
||||
model: None,
|
||||
output_modality: RealtimeOutputModality::Audio,
|
||||
|
||||
@@ -316,6 +316,7 @@ async fn conversation_start_audio_text_close_round_trip() -> Result<()> {
|
||||
codex_response_item_prefix: None,
|
||||
codex_response_handoff_mode:
|
||||
codex_protocol::protocol::CodexResponseHandoffMode::Thinking,
|
||||
backend_reasoning_status: false,
|
||||
codex_response_handoff_channel_prefixes: None,
|
||||
model: None,
|
||||
output_modality: RealtimeOutputModality::Audio,
|
||||
@@ -497,6 +498,7 @@ async fn conversation_records_history_without_an_event_observer(
|
||||
codex_response_item_prefix: None,
|
||||
codex_response_handoff_mode:
|
||||
codex_protocol::protocol::CodexResponseHandoffMode::Thinking,
|
||||
backend_reasoning_status: false,
|
||||
codex_response_handoff_channel_prefixes: None,
|
||||
model: None,
|
||||
output_modality: RealtimeOutputModality::Audio,
|
||||
@@ -607,6 +609,7 @@ async fn conversation_start_defaults_to_v2_and_gpt_realtime_1_5() -> Result<()>
|
||||
codex_response_item_prefix: None,
|
||||
codex_response_handoff_mode:
|
||||
codex_protocol::protocol::CodexResponseHandoffMode::Thinking,
|
||||
backend_reasoning_status: false,
|
||||
codex_response_handoff_channel_prefixes: None,
|
||||
model: None,
|
||||
output_modality: RealtimeOutputModality::Audio,
|
||||
@@ -702,6 +705,7 @@ async fn conversation_websocket_transports_send_codex_headers_without_creating_a
|
||||
codex_response_item_prefix: None,
|
||||
codex_response_handoff_mode:
|
||||
codex_protocol::protocol::CodexResponseHandoffMode::Thinking,
|
||||
backend_reasoning_status: false,
|
||||
codex_response_handoff_channel_prefixes: None,
|
||||
model: None,
|
||||
output_modality: RealtimeOutputModality::Audio,
|
||||
@@ -872,6 +876,7 @@ async fn conversation_webrtc_frameless_chatgpt_sends_codex_headers_to_backend(
|
||||
codex_response_item_prefix: None,
|
||||
codex_response_handoff_mode:
|
||||
codex_protocol::protocol::CodexResponseHandoffMode::Thinking,
|
||||
backend_reasoning_status: false,
|
||||
codex_response_handoff_channel_prefixes: None,
|
||||
model: model.map(str::to_string),
|
||||
output_modality: RealtimeOutputModality::Audio,
|
||||
@@ -1033,6 +1038,7 @@ async fn conversation_webrtc_start_posts_generated_session() -> Result<()> {
|
||||
codex_response_item_prefix: None,
|
||||
codex_response_handoff_mode:
|
||||
codex_protocol::protocol::CodexResponseHandoffMode::Thinking,
|
||||
backend_reasoning_status: false,
|
||||
codex_response_handoff_channel_prefixes: None,
|
||||
model: Some("session-override-model".to_string()),
|
||||
output_modality: RealtimeOutputModality::Audio,
|
||||
@@ -1397,6 +1403,7 @@ async fn conversation_webrtc_live_reconnects_sideband_after_unclean_disconnect(
|
||||
codex_response_item_prefix: None,
|
||||
codex_response_handoff_mode:
|
||||
codex_protocol::protocol::CodexResponseHandoffMode::Thinking,
|
||||
backend_reasoning_status: false,
|
||||
codex_response_handoff_channel_prefixes: None,
|
||||
model: None,
|
||||
output_modality: RealtimeOutputModality::Audio,
|
||||
@@ -1552,6 +1559,7 @@ async fn conversation_webrtc_start_uses_avas_query() -> Result<()> {
|
||||
codex_response_item_prefix: None,
|
||||
codex_response_handoff_mode:
|
||||
codex_protocol::protocol::CodexResponseHandoffMode::Thinking,
|
||||
backend_reasoning_status: false,
|
||||
codex_response_handoff_channel_prefixes: None,
|
||||
model: None,
|
||||
output_modality: RealtimeOutputModality::Audio,
|
||||
@@ -1657,6 +1665,7 @@ async fn conversation_webrtc_default_v1_ignores_configured_v2_voice() -> Result<
|
||||
codex_response_item_prefix: None,
|
||||
codex_response_handoff_mode:
|
||||
codex_protocol::protocol::CodexResponseHandoffMode::Thinking,
|
||||
backend_reasoning_status: false,
|
||||
codex_response_handoff_channel_prefixes: None,
|
||||
model: None,
|
||||
output_modality: RealtimeOutputModality::Audio,
|
||||
@@ -1724,6 +1733,7 @@ async fn conversation_webrtc_default_v1_rejects_explicit_v2_voice() -> Result<()
|
||||
codex_response_item_prefix: None,
|
||||
codex_response_handoff_mode:
|
||||
codex_protocol::protocol::CodexResponseHandoffMode::Thinking,
|
||||
backend_reasoning_status: false,
|
||||
codex_response_handoff_channel_prefixes: None,
|
||||
model: None,
|
||||
output_modality: RealtimeOutputModality::Audio,
|
||||
@@ -1801,6 +1811,7 @@ async fn conversation_webrtc_start_uses_configured_call_base_url_for_avas() -> R
|
||||
codex_response_item_prefix: None,
|
||||
codex_response_handoff_mode:
|
||||
codex_protocol::protocol::CodexResponseHandoffMode::Thinking,
|
||||
backend_reasoning_status: false,
|
||||
codex_response_handoff_channel_prefixes: None,
|
||||
model: None,
|
||||
output_modality: RealtimeOutputModality::Audio,
|
||||
@@ -1915,6 +1926,7 @@ async fn conversation_webrtc_close_while_sideband_connecting_drops_pending_join(
|
||||
codex_response_item_prefix: None,
|
||||
codex_response_handoff_mode:
|
||||
codex_protocol::protocol::CodexResponseHandoffMode::Thinking,
|
||||
backend_reasoning_status: false,
|
||||
codex_response_handoff_channel_prefixes: None,
|
||||
model: None,
|
||||
output_modality: RealtimeOutputModality::Audio,
|
||||
@@ -2022,6 +2034,7 @@ async fn conversation_webrtc_sideband_connect_failure_closes_with_error() -> Res
|
||||
codex_response_item_prefix: None,
|
||||
codex_response_handoff_mode:
|
||||
codex_protocol::protocol::CodexResponseHandoffMode::Thinking,
|
||||
backend_reasoning_status: false,
|
||||
codex_response_handoff_channel_prefixes: None,
|
||||
model: None,
|
||||
output_modality: RealtimeOutputModality::Audio,
|
||||
@@ -2122,6 +2135,7 @@ async fn conversation_start_uses_openai_env_key_fallback_with_chatgpt_auth() ->
|
||||
codex_response_item_prefix: None,
|
||||
codex_response_handoff_mode:
|
||||
codex_protocol::protocol::CodexResponseHandoffMode::Thinking,
|
||||
backend_reasoning_status: false,
|
||||
codex_response_handoff_channel_prefixes: None,
|
||||
model: None,
|
||||
output_modality: RealtimeOutputModality::Audio,
|
||||
@@ -2220,6 +2234,7 @@ async fn assert_transport_close_tail_flush(
|
||||
codex_response_item_prefix: None,
|
||||
codex_response_handoff_mode:
|
||||
codex_protocol::protocol::CodexResponseHandoffMode::Thinking,
|
||||
backend_reasoning_status: false,
|
||||
codex_response_handoff_channel_prefixes: None,
|
||||
model: None,
|
||||
output_modality: RealtimeOutputModality::Audio,
|
||||
@@ -2343,6 +2358,7 @@ async fn conversation_start_preflight_failure_emits_realtime_error_only() -> Res
|
||||
codex_response_item_prefix: None,
|
||||
codex_response_handoff_mode:
|
||||
codex_protocol::protocol::CodexResponseHandoffMode::Thinking,
|
||||
backend_reasoning_status: false,
|
||||
codex_response_handoff_channel_prefixes: None,
|
||||
model: None,
|
||||
output_modality: RealtimeOutputModality::Audio,
|
||||
@@ -2401,6 +2417,7 @@ async fn conversation_start_connect_failure_emits_realtime_error_only() -> Resul
|
||||
codex_response_item_prefix: None,
|
||||
codex_response_handoff_mode:
|
||||
codex_protocol::protocol::CodexResponseHandoffMode::Thinking,
|
||||
backend_reasoning_status: false,
|
||||
codex_response_handoff_channel_prefixes: None,
|
||||
model: None,
|
||||
output_modality: RealtimeOutputModality::Audio,
|
||||
@@ -2507,6 +2524,7 @@ async fn conversation_second_start_replaces_runtime() -> Result<()> {
|
||||
codex_response_item_prefix: None,
|
||||
codex_response_handoff_mode:
|
||||
codex_protocol::protocol::CodexResponseHandoffMode::Thinking,
|
||||
backend_reasoning_status: false,
|
||||
codex_response_handoff_channel_prefixes: None,
|
||||
model: None,
|
||||
output_modality: RealtimeOutputModality::Audio,
|
||||
@@ -2544,6 +2562,7 @@ async fn conversation_second_start_replaces_runtime() -> Result<()> {
|
||||
codex_response_item_prefix: None,
|
||||
codex_response_handoff_mode:
|
||||
codex_protocol::protocol::CodexResponseHandoffMode::Thinking,
|
||||
backend_reasoning_status: false,
|
||||
codex_response_handoff_channel_prefixes: None,
|
||||
model: None,
|
||||
output_modality: RealtimeOutputModality::Audio,
|
||||
@@ -2652,6 +2671,7 @@ async fn conversation_uses_experimental_realtime_ws_base_url_override() -> Resul
|
||||
codex_response_item_prefix: None,
|
||||
codex_response_handoff_mode:
|
||||
codex_protocol::protocol::CodexResponseHandoffMode::Thinking,
|
||||
backend_reasoning_status: false,
|
||||
codex_response_handoff_channel_prefixes: None,
|
||||
model: None,
|
||||
output_modality: RealtimeOutputModality::Audio,
|
||||
@@ -2728,6 +2748,7 @@ async fn conversation_uses_default_realtime_backend_prompt() -> Result<()> {
|
||||
codex_response_item_prefix: None,
|
||||
codex_response_handoff_mode:
|
||||
codex_protocol::protocol::CodexResponseHandoffMode::Thinking,
|
||||
backend_reasoning_status: false,
|
||||
codex_response_handoff_channel_prefixes: None,
|
||||
model: None,
|
||||
output_modality: RealtimeOutputModality::Audio,
|
||||
@@ -2812,6 +2833,7 @@ async fn conversation_uses_empty_instructions_for_null_or_empty_prompt() -> Resu
|
||||
codex_response_item_prefix: None,
|
||||
codex_response_handoff_mode:
|
||||
codex_protocol::protocol::CodexResponseHandoffMode::Thinking,
|
||||
backend_reasoning_status: false,
|
||||
codex_response_handoff_channel_prefixes: None,
|
||||
model: None,
|
||||
output_modality: RealtimeOutputModality::Audio,
|
||||
@@ -2889,6 +2911,7 @@ async fn conversation_uses_explicit_start_voice() -> Result<()> {
|
||||
codex_response_item_prefix: None,
|
||||
codex_response_handoff_mode:
|
||||
codex_protocol::protocol::CodexResponseHandoffMode::Thinking,
|
||||
backend_reasoning_status: false,
|
||||
codex_response_handoff_channel_prefixes: None,
|
||||
model: None,
|
||||
output_modality: RealtimeOutputModality::Audio,
|
||||
@@ -2958,6 +2981,7 @@ async fn conversation_uses_configured_realtime_voice() -> Result<()> {
|
||||
codex_response_item_prefix: None,
|
||||
codex_response_handoff_mode:
|
||||
codex_protocol::protocol::CodexResponseHandoffMode::Thinking,
|
||||
backend_reasoning_status: false,
|
||||
codex_response_handoff_channel_prefixes: None,
|
||||
model: None,
|
||||
output_modality: RealtimeOutputModality::Audio,
|
||||
@@ -3015,6 +3039,7 @@ async fn conversation_rejects_voice_for_wrong_realtime_version() -> Result<()> {
|
||||
codex_response_item_prefix: None,
|
||||
codex_response_handoff_mode:
|
||||
codex_protocol::protocol::CodexResponseHandoffMode::Thinking,
|
||||
backend_reasoning_status: false,
|
||||
codex_response_handoff_channel_prefixes: None,
|
||||
model: None,
|
||||
output_modality: RealtimeOutputModality::Audio,
|
||||
@@ -3073,6 +3098,7 @@ async fn conversation_uses_experimental_realtime_ws_backend_prompt_override() ->
|
||||
codex_response_item_prefix: None,
|
||||
codex_response_handoff_mode:
|
||||
codex_protocol::protocol::CodexResponseHandoffMode::Thinking,
|
||||
backend_reasoning_status: false,
|
||||
codex_response_handoff_channel_prefixes: None,
|
||||
model: None,
|
||||
output_modality: RealtimeOutputModality::Audio,
|
||||
@@ -3157,6 +3183,7 @@ async fn conversation_uses_experimental_realtime_ws_startup_context_override() -
|
||||
codex_response_item_prefix: None,
|
||||
codex_response_handoff_mode:
|
||||
codex_protocol::protocol::CodexResponseHandoffMode::Thinking,
|
||||
backend_reasoning_status: false,
|
||||
codex_response_handoff_channel_prefixes: None,
|
||||
model: None,
|
||||
output_modality: RealtimeOutputModality::Audio,
|
||||
@@ -3235,6 +3262,7 @@ async fn conversation_disables_realtime_startup_context_with_empty_override() ->
|
||||
codex_response_item_prefix: None,
|
||||
codex_response_handoff_mode:
|
||||
codex_protocol::protocol::CodexResponseHandoffMode::Thinking,
|
||||
backend_reasoning_status: false,
|
||||
codex_response_handoff_channel_prefixes: None,
|
||||
model: None,
|
||||
output_modality: RealtimeOutputModality::Audio,
|
||||
@@ -3306,6 +3334,7 @@ async fn conversation_start_injects_startup_context_from_thread_history() -> Res
|
||||
codex_response_item_prefix: None,
|
||||
codex_response_handoff_mode:
|
||||
codex_protocol::protocol::CodexResponseHandoffMode::Thinking,
|
||||
backend_reasoning_status: false,
|
||||
codex_response_handoff_channel_prefixes: None,
|
||||
model: None,
|
||||
output_modality: RealtimeOutputModality::Audio,
|
||||
@@ -3433,6 +3462,7 @@ async fn conversation_startup_context_current_thread_selects_many_turns_by_budge
|
||||
codex_response_item_prefix: None,
|
||||
codex_response_handoff_mode:
|
||||
codex_protocol::protocol::CodexResponseHandoffMode::Thinking,
|
||||
backend_reasoning_status: false,
|
||||
codex_response_handoff_channel_prefixes: None,
|
||||
model: None,
|
||||
output_modality: RealtimeOutputModality::Audio,
|
||||
@@ -3552,6 +3582,7 @@ async fn conversation_startup_context_falls_back_to_workspace_map() -> Result<()
|
||||
codex_response_item_prefix: None,
|
||||
codex_response_handoff_mode:
|
||||
codex_protocol::protocol::CodexResponseHandoffMode::Thinking,
|
||||
backend_reasoning_status: false,
|
||||
codex_response_handoff_channel_prefixes: None,
|
||||
model: None,
|
||||
output_modality: RealtimeOutputModality::Audio,
|
||||
@@ -3623,6 +3654,7 @@ async fn conversation_startup_context_is_truncated_and_sent_once_per_start() ->
|
||||
codex_response_item_prefix: None,
|
||||
codex_response_handoff_mode:
|
||||
codex_protocol::protocol::CodexResponseHandoffMode::Thinking,
|
||||
backend_reasoning_status: false,
|
||||
codex_response_handoff_channel_prefixes: None,
|
||||
model: None,
|
||||
output_modality: RealtimeOutputModality::Audio,
|
||||
@@ -3727,6 +3759,7 @@ async fn conversation_user_text_turn_is_not_sent_to_realtime(ephemeral: bool) ->
|
||||
codex_response_item_prefix: None,
|
||||
codex_response_handoff_mode:
|
||||
codex_protocol::protocol::CodexResponseHandoffMode::Thinking,
|
||||
backend_reasoning_status: false,
|
||||
codex_response_handoff_channel_prefixes: None,
|
||||
model: None,
|
||||
output_modality: RealtimeOutputModality::Audio,
|
||||
@@ -3867,6 +3900,7 @@ async fn realtime_v2_noop_tool_call_returns_empty_function_output_without_respon
|
||||
codex_response_item_prefix: None,
|
||||
codex_response_handoff_mode:
|
||||
codex_protocol::protocol::CodexResponseHandoffMode::Thinking,
|
||||
backend_reasoning_status: false,
|
||||
codex_response_handoff_channel_prefixes: None,
|
||||
model: None,
|
||||
output_modality: RealtimeOutputModality::Audio,
|
||||
@@ -3977,6 +4011,7 @@ async fn conversation_mirrors_assistant_message_text_to_realtime_handoff() -> Re
|
||||
codex_response_item_prefix: None,
|
||||
codex_response_handoff_mode:
|
||||
codex_protocol::protocol::CodexResponseHandoffMode::Thinking,
|
||||
backend_reasoning_status: false,
|
||||
codex_response_handoff_channel_prefixes: None,
|
||||
model: None,
|
||||
output_modality: RealtimeOutputModality::Audio,
|
||||
@@ -4051,6 +4086,137 @@ async fn conversation_mirrors_assistant_message_text_to_realtime_handoff() -> Re
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test_case(true; "enabled")]
|
||||
#[test_case(false; "disabled")]
|
||||
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
||||
async fn conversation_relays_only_public_reasoning_as_quiet_status(enabled: bool) -> Result<()> {
|
||||
skip_if_no_network!(Ok(()));
|
||||
let (item_tx, item_rx) = oneshot::channel();
|
||||
let (response_tx, response_rx) = oneshot::channel();
|
||||
let chunks = vec![
|
||||
StreamingSseChunk {
|
||||
gate: None,
|
||||
body: responses::sse(vec![
|
||||
responses::ev_response_created("summary_response"),
|
||||
responses::ev_reasoning_item_added("reasoning", &[""]),
|
||||
responses::ev_reasoning_text_delta("Private raw reasoning."),
|
||||
responses::ev_reasoning_summary_text_delta("Partial summary."),
|
||||
]),
|
||||
},
|
||||
StreamingSseChunk {
|
||||
gate: Some(item_rx),
|
||||
body: sse_event(responses::ev_reasoning_item(
|
||||
"reasoning",
|
||||
&["Older public summary", "Checking availability.", " "],
|
||||
&["Private raw reasoning."],
|
||||
)),
|
||||
},
|
||||
StreamingSseChunk {
|
||||
gate: Some(response_rx),
|
||||
body: sse_event(responses::ev_completed("summary_response")),
|
||||
},
|
||||
];
|
||||
let (api_server, completions) = start_streaming_sse_server(vec![chunks]).await;
|
||||
let realtime_server = start_websocket_server(vec![vec![vec![
|
||||
json!({"type":"session.started", "session":{"id":"summary_session"}}),
|
||||
json!({"type":"delegation.created", "item":{"id":"summary_delegation", "type":"delegation", "target":"client", "content":[{"type":"input_text","text":"check availability"}]}}),
|
||||
], vec![]]]).await;
|
||||
let mut builder = test_codex().with_config({
|
||||
let realtime_base_url = realtime_server.uri().to_string();
|
||||
move |config| {
|
||||
config.experimental_realtime_ws_base_url = Some(realtime_base_url);
|
||||
config.realtime.version = RealtimeWsVersion::V3;
|
||||
config.model_reasoning_summary =
|
||||
Some(codex_protocol::config_types::ReasoningSummary::None);
|
||||
}
|
||||
});
|
||||
let test = builder.build_with_streaming_server(&api_server).await?;
|
||||
test.codex
|
||||
.submit(Op::RealtimeConversationStart(ConversationStartParams {
|
||||
client_managed_handoffs: false,
|
||||
delegation_ack_filler: None,
|
||||
flush_transcript_tail_on_session_end: false,
|
||||
codex_responses_as_items: false,
|
||||
codex_response_item_prefix: None,
|
||||
// The generic default omits its wire channel; quiet status must override it.
|
||||
codex_response_handoff_mode:
|
||||
codex_protocol::protocol::CodexResponseHandoffMode::Thinking,
|
||||
backend_reasoning_status: enabled,
|
||||
codex_response_handoff_channel_prefixes: None,
|
||||
model: None,
|
||||
output_modality: RealtimeOutputModality::Audio,
|
||||
include_startup_context: false,
|
||||
initial_items: Vec::new(),
|
||||
realtime_start_instructions: None,
|
||||
realtime_end_instructions: None,
|
||||
prompt: None,
|
||||
realtime_session_id: None,
|
||||
transport: None,
|
||||
version: None,
|
||||
voice: None,
|
||||
}))
|
||||
.await?;
|
||||
wait_for_event(&test.codex, |event| {
|
||||
matches!(event,
|
||||
EventMsg::ReasoningContentDelta(delta) if delta.delta == "Partial summary."
|
||||
)
|
||||
})
|
||||
.await;
|
||||
let next_request = || {
|
||||
wait_for_websocket_request(
|
||||
&realtime_server,
|
||||
/*connection_index*/ 0,
|
||||
/*request_index*/ 1,
|
||||
)
|
||||
};
|
||||
assert!(
|
||||
timeout(Duration::from_millis(150), next_request())
|
||||
.await
|
||||
.is_err()
|
||||
);
|
||||
let requests = api_server.requests().await;
|
||||
let model_request: Value = serde_json::from_slice(&requests[0])?;
|
||||
assert_eq!(model_request["reasoning"].get("summary"), None);
|
||||
let _ = item_tx.send(());
|
||||
wait_for_event(&test.codex, |event| matches!(event,
|
||||
EventMsg::ItemCompleted(item) if matches!(&item.item, codex_protocol::items::TurnItem::Reasoning(reasoning) if reasoning.id == "reasoning")
|
||||
)).await;
|
||||
if enabled {
|
||||
assert_eq!(
|
||||
next_request().await?.body_json(),
|
||||
json!({
|
||||
"type":"delegation.context.append", "delegation_item_id":"summary_delegation", "channel":"commentary",
|
||||
"content":[{"type":"input_text","text":"[STATUS] Checking availability."}]
|
||||
})
|
||||
);
|
||||
} else {
|
||||
assert!(
|
||||
timeout(Duration::from_millis(150), next_request())
|
||||
.await
|
||||
.is_err()
|
||||
);
|
||||
}
|
||||
let _ = response_tx.send(());
|
||||
completions
|
||||
.into_iter()
|
||||
.next()
|
||||
.expect("one response")
|
||||
.await?;
|
||||
wait_for_event(&test.codex, |event| {
|
||||
matches!(event, EventMsg::TurnComplete(_))
|
||||
})
|
||||
.await;
|
||||
let requests = realtime_server.single_connection();
|
||||
assert_eq!(requests.len(), if enabled { 2 } else { 1 });
|
||||
assert!(requests.iter().all(|request| {
|
||||
let body = request.body_json();
|
||||
body["type"] != "response.create" && !body.to_string().contains("Private raw reasoning")
|
||||
}));
|
||||
realtime_server.shutdown().await;
|
||||
api_server.shutdown().await;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
||||
async fn conversation_flushes_assistant_deltas_every_200ms_for_v3_handoff() -> Result<()> {
|
||||
skip_if_no_network!(Ok(()));
|
||||
@@ -4148,6 +4314,7 @@ async fn conversation_flushes_assistant_deltas_every_200ms_for_v3_handoff() -> R
|
||||
codex_response_item_prefix: None,
|
||||
codex_response_handoff_mode:
|
||||
codex_protocol::protocol::CodexResponseHandoffMode::BemTags,
|
||||
backend_reasoning_status: false,
|
||||
codex_response_handoff_channel_prefixes: Some(BTreeMap::from([
|
||||
(
|
||||
"commentary".to_string(),
|
||||
@@ -4327,6 +4494,7 @@ async fn conversation_handoff_persists_across_item_done_until_turn_complete() ->
|
||||
codex_response_item_prefix: None,
|
||||
codex_response_handoff_mode:
|
||||
codex_protocol::protocol::CodexResponseHandoffMode::BemTags,
|
||||
backend_reasoning_status: false,
|
||||
codex_response_handoff_channel_prefixes: None,
|
||||
model: None,
|
||||
output_modality: RealtimeOutputModality::Audio,
|
||||
@@ -4492,6 +4660,7 @@ async fn inbound_handoff_request_starts_turn_and_promotes_its_artifact() -> Resu
|
||||
codex_response_item_prefix: None,
|
||||
codex_response_handoff_mode:
|
||||
codex_protocol::protocol::CodexResponseHandoffMode::Thinking,
|
||||
backend_reasoning_status: false,
|
||||
codex_response_handoff_channel_prefixes: None,
|
||||
model: None,
|
||||
output_modality: RealtimeOutputModality::Audio,
|
||||
@@ -4656,6 +4825,7 @@ async fn inbound_handoff_request_uses_active_transcript() -> Result<()> {
|
||||
codex_response_item_prefix: None,
|
||||
codex_response_handoff_mode:
|
||||
codex_protocol::protocol::CodexResponseHandoffMode::Thinking,
|
||||
backend_reasoning_status: false,
|
||||
codex_response_handoff_channel_prefixes: None,
|
||||
model: None,
|
||||
output_modality: RealtimeOutputModality::Audio,
|
||||
@@ -4770,6 +4940,7 @@ async fn inbound_handoff_request_sends_transcript_delta_after_each_handoff() ->
|
||||
codex_response_item_prefix: None,
|
||||
codex_response_handoff_mode:
|
||||
codex_protocol::protocol::CodexResponseHandoffMode::Thinking,
|
||||
backend_reasoning_status: false,
|
||||
codex_response_handoff_channel_prefixes: None,
|
||||
model: None,
|
||||
output_modality: RealtimeOutputModality::Audio,
|
||||
@@ -4903,6 +5074,7 @@ async fn conversation_close_routes_only_remaining_transcript_tail_once() -> Resu
|
||||
codex_response_item_prefix: None,
|
||||
codex_response_handoff_mode:
|
||||
codex_protocol::protocol::CodexResponseHandoffMode::Thinking,
|
||||
backend_reasoning_status: false,
|
||||
codex_response_handoff_channel_prefixes: None,
|
||||
model: None,
|
||||
output_modality: RealtimeOutputModality::Audio,
|
||||
@@ -4997,6 +5169,7 @@ async fn inbound_conversation_item_does_not_start_turn_and_still_forwards_audio(
|
||||
codex_response_item_prefix: None,
|
||||
codex_response_handoff_mode:
|
||||
codex_protocol::protocol::CodexResponseHandoffMode::Thinking,
|
||||
backend_reasoning_status: false,
|
||||
codex_response_handoff_channel_prefixes: None,
|
||||
model: None,
|
||||
output_modality: RealtimeOutputModality::Audio,
|
||||
@@ -5131,6 +5304,7 @@ async fn delegated_turn_user_role_echo_does_not_redelegate_and_still_forwards_au
|
||||
codex_response_item_prefix: None,
|
||||
codex_response_handoff_mode:
|
||||
codex_protocol::protocol::CodexResponseHandoffMode::Thinking,
|
||||
backend_reasoning_status: false,
|
||||
codex_response_handoff_channel_prefixes: None,
|
||||
model: None,
|
||||
output_modality: RealtimeOutputModality::Audio,
|
||||
@@ -5295,6 +5469,7 @@ async fn inbound_handoff_request_does_not_block_realtime_event_forwarding() -> R
|
||||
codex_response_item_prefix: None,
|
||||
codex_response_handoff_mode:
|
||||
codex_protocol::protocol::CodexResponseHandoffMode::Thinking,
|
||||
backend_reasoning_status: false,
|
||||
codex_response_handoff_channel_prefixes: None,
|
||||
model: None,
|
||||
output_modality: RealtimeOutputModality::Audio,
|
||||
@@ -5448,6 +5623,7 @@ async fn inbound_handoff_request_steers_active_turn() -> Result<()> {
|
||||
codex_response_item_prefix: None,
|
||||
codex_response_handoff_mode:
|
||||
codex_protocol::protocol::CodexResponseHandoffMode::Thinking,
|
||||
backend_reasoning_status: false,
|
||||
codex_response_handoff_channel_prefixes: None,
|
||||
model: None,
|
||||
output_modality: RealtimeOutputModality::Audio,
|
||||
@@ -5606,6 +5782,7 @@ async fn inbound_handoff_request_starts_turn_and_does_not_block_realtime_audio()
|
||||
codex_response_item_prefix: None,
|
||||
codex_response_handoff_mode:
|
||||
codex_protocol::protocol::CodexResponseHandoffMode::Thinking,
|
||||
backend_reasoning_status: false,
|
||||
codex_response_handoff_channel_prefixes: None,
|
||||
model: None,
|
||||
output_modality: RealtimeOutputModality::Audio,
|
||||
|
||||
@@ -204,6 +204,7 @@ fn start_params(version: RealtimeConversationVersion) -> ConversationStartParams
|
||||
codex_responses_as_items: false,
|
||||
codex_response_item_prefix: None,
|
||||
codex_response_handoff_mode: CodexResponseHandoffMode::Thinking,
|
||||
backend_reasoning_status: false,
|
||||
codex_response_handoff_channel_prefixes: None,
|
||||
model: None,
|
||||
output_modality: RealtimeOutputModality::Audio,
|
||||
|
||||
@@ -97,6 +97,7 @@ async fn misalignment_retires_late_voice_handoff_before_it_starts_a_turn() -> Re
|
||||
codex_response_item_prefix: None,
|
||||
codex_response_handoff_mode:
|
||||
codex_protocol::protocol::CodexResponseHandoffMode::Thinking,
|
||||
backend_reasoning_status: false,
|
||||
codex_response_handoff_channel_prefixes: None,
|
||||
model: None,
|
||||
output_modality: RealtimeOutputModality::Audio,
|
||||
|
||||
@@ -66,6 +66,7 @@ async fn existing_call_uses_selected_endpoint_and_runtime_auth(
|
||||
codex_responses_as_items: false,
|
||||
codex_response_item_prefix: None,
|
||||
codex_response_handoff_mode: CodexResponseHandoffMode::Thinking,
|
||||
backend_reasoning_status: false,
|
||||
codex_response_handoff_channel_prefixes: None,
|
||||
model: None,
|
||||
output_modality: RealtimeOutputModality::Audio,
|
||||
|
||||
@@ -140,6 +140,7 @@ async fn webrtc_sideband_honors_configured_system_proxy() -> Result<()> {
|
||||
codex_responses_as_items: false,
|
||||
codex_response_item_prefix: None,
|
||||
codex_response_handoff_mode: CodexResponseHandoffMode::Thinking,
|
||||
backend_reasoning_status: false,
|
||||
codex_response_handoff_channel_prefixes: None,
|
||||
model: None,
|
||||
output_modality: RealtimeOutputModality::Audio,
|
||||
|
||||
@@ -269,6 +269,7 @@ async fn host_drain_closes_realtime_after_handoff_error() -> anyhow::Result<()>
|
||||
codex_response_item_prefix: None,
|
||||
codex_response_handoff_mode:
|
||||
codex_protocol::protocol::CodexResponseHandoffMode::Thinking,
|
||||
backend_reasoning_status: false,
|
||||
codex_response_handoff_channel_prefixes: None,
|
||||
model: None,
|
||||
output_modality: codex_protocol::protocol::RealtimeOutputModality::Audio,
|
||||
|
||||
@@ -215,6 +215,8 @@ pub struct ConversationStartParams {
|
||||
/// Selects how automatic Codex handoffs are routed in Frameless Bidi sessions.
|
||||
/// Realtime V1 and V2 ignore this setting.
|
||||
pub codex_response_handoff_mode: CodexResponseHandoffMode,
|
||||
/// Relays public reasoning summaries as quiet context for realtime V3 delegations.
|
||||
pub backend_reasoning_status: bool,
|
||||
/// Optional client-selected BEM prefixes keyed by `analysis`, `commentary`, and `final`.
|
||||
pub codex_response_handoff_channel_prefixes: Option<BTreeMap<String, Vec<String>>>,
|
||||
/// Overrides the configured realtime model for this session only.
|
||||
|
||||
@@ -37,6 +37,7 @@ impl AppServerSession {
|
||||
codex_responses_as_items: None,
|
||||
codex_response_item_prefix: None,
|
||||
codex_response_handoff_mode: None,
|
||||
backend_reasoning_status: false,
|
||||
codex_response_handoff_channel_prefixes: None,
|
||||
model,
|
||||
output_modality: RealtimeOutputModality::Audio,
|
||||
|
||||
Reference in New Issue
Block a user