Repository navigation
fix(tui): defer agent reload until the reactor's message run ends - #1486
Merged
corbits-triage[bot] merged 3 commits intoOct 17, 2026
Conversation
An approval resume resolves once the decision is handed to the reactor, while the resumed tool and the next inference still run inside the parked message run. Gating reload on send occupancy alone let a pending reload close and rebuild the agent mid-run, killing the approved call and rehydrating its pending operation on the new reactor. Each agent build now also logs its reason so a rebuild is visible in the log.
TheGreatAxios
requested changes
Oct 17, 2026
TheGreatAxios
left a comment
Collaborator
There was a problem hiding this comment.
Review · Request changes
A pending reload now waits out the same open message run, including an approval resume. A synchronous handoff to the next run still rebuilds before that run is tracked.
Findings
src/tui/runner/exit.ts:484—message.run.endeddrops the run and callsreloadIfIdlebefore the followingmessage.run.startedis applied. The reactor emits that pair with no await when it dequeues an uncorrelatedmessage.received(vendor/intx-inference/src/reactor.ts:1635). The stream buffers the start (vendor/intx-agent/src/stream.ts:69).enqueueschedules the rebuild as an earlier microtask than that start (src/tui/delivery-queue.ts:437), so both busy checks see an emptyopenMessageRunsandcloseAgentForRebuildruns. Compaction continuation, a queued steer, or any other uncorrelated deliver during a deferred MCP reload tears the agent down at the start of the next run. If the superseded run had committed a pending approval, the new reactor can re-arm it.
Notes
- The same-run case holds.
closeMessageRunis not called on suspend or between the resumed tool and the following inference. A regression that feedsmessage.run.endedand the nextmessage.run.startedin one burst, and asserts no rebuild until the successor run ends, would lock this.
bwachman
force-pushed
the
cl-10766-dont-reload-the-agent-while-an-approval-resumed-run-is-still
branch
from
October 17, 2026 03:41
463c4de to
d65bded
Compare
When the reactor dequeues an uncorrelated message while a run is still open, it emits message.run.ended and the next message.run.started with no await between them. The run-end path queued the rebuild op as a microtask ahead of the stream consumer handing the buffered start to the sink, so both busy checks saw no open run and the agent was torn down at the start of the successor run. The rebuild op now waits one macrotask before its busy re-check. The reactor moves from closing one run to opening the next without leaving the microtask queue, and the stream delivers buffered events through resolved promises, so by the next macrotask any such start has been applied and the reload re-defers to that run's end.
TheGreatAxios
requested changes
Oct 17, 2026
TheGreatAxios
left a comment
Collaborator
There was a problem hiding this comment.
Review · Request changes
A pending agent reload waits until the reactor's message run ends, and a one-macrotask re-check keeps a buffered successor run from being torn down at the hand-off.
Findings
src/tui/runner/exit.ts:477—buildLiveAgentclearsopenMessageRunsso a run abandoned by interrupt or rotation cannot keep the session busy, but it leavespendingReloadset and does not callreloadIfIdle. Interrupt (exit.ts:679) and session rotation (exit.ts:785) both rebuild through that helper. A reload that already deferred because the run was open (reloadIfIdlereturns atexit.ts:502whileagentBusy()is true, and only clears the flag atexit.ts:503once it proceeds) stays armed.message.run.ended(exit.ts:464-466) is the path that would have consumed it, and reactor shutdown does not emit that event for the abandoned run. The nextmessage.run.endedorinFlightdrop therefore sees an idle agent and builds again, closing the agent interrupt or/clearjust created — including one that already picked up the tools the reload was waiting on. ClearpendingReloadinbuildLiveAgentwhen it drops those runs, since that build is the reload.
The interrupt and session-rotation builds already construct the agent a deferred reload was waiting on, so leaving pendingReload set rebuilds again at the next idle edge.
TheGreatAxios
approved these changes
Oct 17, 2026
Contributor
|
Triage: Pass No changes needed from you. A maintainer will review this pull request. |
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
initial,reload,interrupt,session-rotation), so a rebuild is visible in the log.Verification
bun run checkandbun run testpass (9198 tests) on top of the run.json snapshot changes in main/clearand/newrunner tests pass unchangedFixes CL-10766
Part of CL-10763