mirror of
https://github.com/openai/codex.git
synced 2026-05-05 22:01:37 +03:00
[js_repl] Hard-stop active js_repl execs on explicit user interrupts (#13329)
## Summary - hard-stop `js_repl` only for `TurnAbortReason::Interrupted`, preserving the persistent REPL across replaced turns - track the current top-level exec by turn and only reset when the interrupted turn owns submitted work or a freshly started kernel for the current exec attempt - close both interrupt races: the write-window race by marking the exec as submitted before async pipe writes begin, and the startup-window race by tracking fresh-kernel ownership until submission - add regression coverage for interrupted in-flight execs and the pending-kernel-start window ## Why Stopping a turn previously surfaced `aborted by user after Xs` even though the underlying `js_repl` kernel could continue executing. Earlier fixes also risked resetting the session-scoped REPL too broadly or missing already-dispatched work. This change keeps cleanup scoped to explicit stop semantics and makes the interrupt path line up with both submitted execs and newly started kernels. ## Testing - `just fmt` - `cargo test -p codex-core` - `just fix -p codex-core` `cargo test -p codex-core` passes the updated `js_repl` coverage, including the new startup-window regression test, but still has unrelated integration failures in this environment outside `js_repl`. --------- Co-authored-by: Codex <noreply@openai.com>
This commit is contained in:
@@ -227,9 +227,6 @@ impl Session {
|
||||
// in-flight approval wait can surface as a model-visible rejection before TurnAborted.
|
||||
active_turn.clear_pending().await;
|
||||
}
|
||||
if reason == TurnAbortReason::Interrupted {
|
||||
self.close_unified_exec_processes().await;
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn on_task_finished(
|
||||
@@ -396,6 +393,16 @@ impl Session {
|
||||
.await;
|
||||
}
|
||||
|
||||
pub(crate) async fn cleanup_after_interrupt(&self, turn_context: &Arc<TurnContext>) {
|
||||
self.close_unified_exec_processes().await;
|
||||
|
||||
if let Some(manager) = turn_context.js_repl.manager_if_initialized()
|
||||
&& let Err(err) = manager.interrupt_turn_exec(&turn_context.sub_id).await
|
||||
{
|
||||
warn!("failed to interrupt js_repl kernel: {err}");
|
||||
}
|
||||
}
|
||||
|
||||
async fn handle_task_abort(self: &Arc<Self>, task: RunningTask, reason: TurnAbortReason) {
|
||||
let sub_id = task.turn_context.sub_id.clone();
|
||||
if task.cancellation_token.is_cancelled() {
|
||||
@@ -425,6 +432,8 @@ impl Session {
|
||||
.await;
|
||||
|
||||
if reason == TurnAbortReason::Interrupted {
|
||||
self.cleanup_after_interrupt(&task.turn_context).await;
|
||||
|
||||
let marker = ResponseItem::Message {
|
||||
id: None,
|
||||
role: "user".to_string(),
|
||||
|
||||
Reference in New Issue
Block a user