diff --git a/codex-rs/core/src/codex.rs b/codex-rs/core/src/codex.rs index faf8570be7..f8e96f9b29 100644 --- a/codex-rs/core/src/codex.rs +++ b/codex-rs/core/src/codex.rs @@ -2233,36 +2233,29 @@ impl Session { } } + pub async fn take_pending_user_input_items(&self) -> Vec { + let mut state = self.state.lock().await; + state.take_pending_user_input_items() + } + + #[cfg(test)] + pub async fn has_pending_user_input_items(&self) -> bool { + let state = self.state.lock().await; + state.has_pending_user_input_items() + } + pub async fn get_pending_input(&self) -> Vec { - let pending_turn_input = { - let mut active = self.active_turn.lock().await; - match active.as_mut() { - Some(at) => { - let mut ts = at.turn_state.lock().await; - ts.take_pending_input() - } - None => Vec::with_capacity(0), + let mut active = self.active_turn.lock().await; + match active.as_mut() { + Some(at) => { + let mut ts = at.turn_state.lock().await; + ts.take_pending_input() } - }; - - let pending_user_input_items = { - let mut state = self.state.lock().await; - state.take_pending_user_input_items() - }; - - let mut pending = pending_user_input_items; - pending.extend(pending_turn_input); - pending + None => Vec::with_capacity(0), + } } pub async fn has_pending_input(&self) -> bool { - { - let state = self.state.lock().await; - if state.has_pending_user_input_items() { - return true; - } - } - let active = self.active_turn.lock().await; match active.as_ref() { Some(at) => { @@ -3480,6 +3473,17 @@ pub(crate) async fn run_turn( .await; } + // Replay interrupted request_user_input outputs before the new user prompt. + let pending_user_input_items = sess.take_pending_user_input_items().await; + if !pending_user_input_items.is_empty() { + let pending_response_items = pending_user_input_items + .into_iter() + .map(ResponseItem::from) + .collect::>(); + sess.record_conversation_items(&turn_context, &pending_response_items) + .await; + } + let initial_input_for_turn: ResponseInputItem = ResponseInputItem::from(input.clone()); let response_item: ResponseItem = initial_input_for_turn.clone().into(); sess.record_user_prompt_and_emit_turn_item(turn_context.as_ref(), &input, response_item) diff --git a/codex-rs/core/src/codex_delegate.rs b/codex-rs/core/src/codex_delegate.rs index 38f77d8c29..fe97215dbb 100644 --- a/codex-rs/core/src/codex_delegate.rs +++ b/codex-rs/core/src/codex_delegate.rs @@ -556,11 +556,11 @@ mod tests { .notify_user_input_response(&ctx.sub_id, RequestUserInputResponse { answers }) .await; - assert!(session.has_pending_input().await); + assert!(session.has_pending_user_input_items().await); session.cancel_pending_user_input(&ctx.sub_id).await; - assert!(!session.has_pending_input().await); + assert!(!session.has_pending_user_input_items().await); assert!(rx.await.is_err(), "sender should be dropped on cancel"); }