Conversation
…-interrupt responses When a user presses ESC to interrupt a running task, the ACP backend emits TurnLifecycle::Aborted immediately. However, the background tokio task that was handling the prompt continues and unconditionally emits TurnLifecycle::Completed. If the user submits a new message before this stale Completed arrives, it races with the new turn's Started event, setting turn_finished=true and causing tool events to be silently discarded. Fix with defense in depth at two levels: Backend (ACP): Add turn_interrupted AtomicBool flag. Set on Op::Interrupt, reset on new handle_user_input. The spawned task checks the flag before emitting Completed and skips it if the turn was interrupted. TUI (ChatWidget): Add pending_stale_completes counter. Each on_interrupted_turn increments it; on_task_complete decrements and skips processing while the counter is positive. 🤖 Generated with [Nori](https://noriagentic.com) Co-Authored-By: Nori <contact@tilework.tech>
…pt-hidden-response-bug-20260403-050410
theahura
added a commit
that referenced
this pull request
Apr 6, 2026
The previous approach used a shared AtomicBool flag to suppress stale TurnLifecycle::Completed events from cancelled tasks. This had an unavoidable TOCTOU race: when a user interrupted and quickly sent a new message, the flag was reset for the new turn before the old task could check it, allowing stale events to interfere with subsequent turns. Two prior attempts (PRs #416, #418) tried to fix this with variations of the same boolean+counter architecture. Each fix introduced a new bug: #416 caused hangs, #418 brought back hidden responses. This commit replaces the architecture entirely: - AtomicBool → AtomicU64 monotonic turn counter in ACP backend - Each spawned task captures its own turn ID at spawn time - ALL tail events (ErrorEvent + Completed + idle timer) are guarded by a single turn_id match check - TUI's pending_stale_completes counter is removed (no longer needed) The monotonic counter eliminates the race because it only increments— there is no "reset" that a stale task can observe. 🤖 Generated with [Nori](https://noriagentic.com) Co-Authored-By: Nori <contact@tilework.tech>
6 tasks
theahura
added a commit
that referenced
this pull request
Apr 6, 2026
The previous approach used a shared AtomicBool flag to suppress stale TurnLifecycle::Completed events from cancelled tasks. This had an unavoidable TOCTOU race: when a user interrupted and quickly sent a new message, the flag was reset for the new turn before the old task could check it, allowing stale events to interfere with subsequent turns. Two prior attempts (PRs #416, #418) tried to fix this with variations of the same boolean+counter architecture. Each fix introduced a new bug: #416 caused hangs, #418 brought back hidden responses. This commit replaces the architecture entirely: - AtomicBool → AtomicU64 monotonic turn counter in ACP backend - Each spawned task captures its own turn ID at spawn time - ALL tail events (ErrorEvent + Completed + idle timer) are guarded by a single turn_id match check - TUI's pending_stale_completes counter is removed (no longer needed) The monotonic counter eliminates the race because it only increments— there is no "reset" that a stale task can observe. 🤖 Generated with [Nori](https://noriagentic.com) Co-Authored-By: Nori <contact@tilework.tech>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
🤖 Generated with Nori
TurnLifecycle::Completedfrom a cancelled background task prematurely terminates the next turn, causing agent responses to be silently hidden after ESC interruptturn_interruptedAtomicBool flag in ACP backend to suppress stale Completed emissionpending_stale_completescounter in TUI ChatWidget as defense-in-depthhandle_compactwhich had the identical raceTest Plan
Share Nori with your team: https://www.npmjs.com/package/nori-skillsets