Compare commits

...

2 Commits

Author SHA1 Message Date
Ahmed Ibrahim
aea44bd1c7 Avoid realtime final answer progress echo 2026-04-13 23:56:26 -07:00
Ahmed Ibrahim
c4118845b2 Log realtime call location 2026-04-13 23:31:37 -07:00
3 changed files with 32 additions and 7 deletions

View File

@@ -19,6 +19,7 @@ use serde_json::to_string;
use serde_json::to_value;
use std::sync::Arc;
use tracing::instrument;
use tracing::trace;
const MULTIPART_BOUNDARY: &str = "codex-realtime-call-boundary";
const MULTIPART_CONTENT_TYPE: &str = "multipart/form-data; boundary=codex-realtime-call-boundary";
@@ -200,6 +201,7 @@ fn decode_call_id_from_location(headers: &HeaderMap) -> Result<String, ApiError>
.ok_or_else(|| ApiError::Stream("realtime call response missing Location".to_string()))?
.to_str()
.map_err(|err| ApiError::Stream(format!("invalid realtime call Location: {err}")))?;
trace!("realtime call Location: {location}");
location
.split('?')

View File

@@ -107,6 +107,7 @@ use codex_protocol::items::UserMessageItem;
use codex_protocol::items::build_hook_prompt_message;
use codex_protocol::mcp::CallToolResult;
use codex_protocol::models::BaseInstructions;
use codex_protocol::models::MessagePhase;
use codex_protocol::models::PermissionProfile;
use codex_protocol::models::format_allow_prefixes;
use codex_protocol::openai_models::ModelInfo;
@@ -2935,10 +2936,14 @@ impl Session {
}
async fn maybe_clear_realtime_handoff_for_event(&self, msg: &EventMsg) {
if !matches!(msg, EventMsg::TurnComplete(_)) {
let EventMsg::TurnComplete(event) = msg else {
return;
}
if let Err(err) = self.conversation.handoff_complete().await {
};
if let Err(err) = self
.conversation
.handoff_complete(event.last_agent_message.clone())
.await
{
debug!("failed to finalize realtime handoff output: {err}");
}
self.conversation.clear_active_handoff().await;
@@ -7349,7 +7354,12 @@ fn realtime_text_for_event(msg: &EventMsg) -> Option<String> {
match msg {
EventMsg::AgentMessage(event) => Some(event.message.clone()),
EventMsg::ItemCompleted(event) => match &event.item {
TurnItem::AgentMessage(item) => Some(agent_message_text(item)),
TurnItem::AgentMessage(item)
if item.phase.as_ref() != Some(&MessagePhase::FinalAnswer) =>
{
Some(agent_message_text(item))
}
TurnItem::AgentMessage(_) => None,
_ => None,
},
EventMsg::Error(_)

View File

@@ -448,7 +448,10 @@ impl RealtimeConversationManager {
Ok(())
}
pub(crate) async fn handoff_complete(&self) -> CodexResult<()> {
pub(crate) async fn handoff_complete(
&self,
final_output_text: Option<String>,
) -> CodexResult<()> {
let handoff = {
let guard = self.state.lock().await;
guard.as_ref().map(|state| state.handoff.clone())
@@ -464,10 +467,20 @@ impl RealtimeConversationManager {
let Some(handoff_id) = handoff.active_handoff.lock().await.clone() else {
return Ok(());
};
let Some(output_text) = handoff.last_output_text.lock().await.clone() else {
return Ok(());
let output_text = match final_output_text {
Some(output_text) => output_text,
None => {
let Some(output_text) = handoff.last_output_text.lock().await.clone() else {
return Ok(());
};
output_text
}
};
if output_text.is_empty() {
return Ok(());
}
handoff
.output_tx
.send(HandoffOutput::FinalUpdate {