Skip to content

[js_repl] Hard-stop active js_repl execs on explicit user interrupts#13329

Merged
aaronl-openai merged 9 commits intomainfrom
dev/aaronl/js-repl-interrupt
Mar 13, 2026
Merged

[js_repl] Hard-stop active js_repl execs on explicit user interrupts#13329
aaronl-openai merged 9 commits intomainfrom
dev/aaronl/js-repl-interrupt

Conversation

@aaronl-openai
Copy link
Copy Markdown
Contributor

@aaronl-openai aaronl-openai commented Mar 3, 2026

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.

@aaronl-openai aaronl-openai changed the title Hard-stop active js_repl execs on explicit user interrupts [js_repl] Hard-stop active js_repl execs on explicit user interrupts Mar 3, 2026
@aaronl-openai aaronl-openai requested a review from fjord-oai March 3, 2026 04:51
@fjord-oai
Copy link
Copy Markdown
Contributor

@codex review

@chatgpt-codex-connector
Copy link
Copy Markdown
Contributor

Codex Review: Didn't find any major issues. Chef's kiss.

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@fjord-oai
Copy link
Copy Markdown
Contributor

my local codex claimed this was an issue, not sure why it wasn't caught by the review bot. can you take a look?

[P2] mod.rs (line 714) still misses one interrupt race. execute() starts/stashes the kernel earlier at mod.rs (line 749) and only registers/marks the active exec later at mod.rs (line 794). If Ctrl-C lands in that gap, handle_task_abort() calls interrupt_turn_exec(), it sees submitted == false, returns false, and the turn can leave behind a live Node kernel. I’d ask for that window to be cleaned up before approving.

aaronl-openai and others added 2 commits March 3, 2026 11:27
Track when a turn has started a fresh js_repl kernel for the current exec attempt so interrupt cleanup can reset it before any exec is formally submitted.

This closes the remaining startup-window race where an explicit stop could land after the kernel was created but before current exec state was visible, leaving a live Node kernel behind.

Add regression coverage for interrupting that pending-kernel-start state.

Co-authored-by: Codex <noreply@openai.com>
@aaronl-openai aaronl-openai marked this pull request as ready for review March 3, 2026 23:13
.abort(session_ctx, Arc::clone(&task.turn_context))
.await;

if reason == TurnAbortReason::Interrupted
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we avoid making Session::handle_task_abort() know about js_repl specifically? I agree we need explicit interrupt cleanup for long-lived runtimes, but this feels like orchestration code accumulating tool-specific teardown. Since we already have a separate interrupt-cleanup path for unified_exec, could we push this behind something like a more generic turn/session-level cleanup_after_interrupt() hook instead, so tasks/mod.rs stays responsible for abort flow rather than individual tool/runtime details?

Move interrupt cleanup behind a Session-level hook and collapse js_repl interrupt tracking into a single top-level exec state machine.

Co-authored-by: Codex <noreply@openai.com>
Copy link
Copy Markdown
Contributor

@fjord-oai fjord-oai left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

approved, but get codex team input on the new interrupt cleanup mechanism

.await;
}

pub(crate) async fn cleanup_after_interrupt(&self, turn_context: &Arc<TurnContext>) {
Copy link
Copy Markdown
Collaborator

@owenlin0 owenlin0 Mar 12, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

interesting, why break this out into a separate file? don't see a lot of value in doing so. could this just be methods in tasks/mod.rs?

@aaronl-openai aaronl-openai merged commit d9a403a into main Mar 13, 2026
32 checks passed
@aaronl-openai aaronl-openai deleted the dev/aaronl/js-repl-interrupt branch March 13, 2026 00:51
@github-actions github-actions bot locked and limited conversation to collaborators Mar 13, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants