fix(voice): unwedge scheduler when reply is interrupted before playout starts#2070
Open
Raysharr wants to merge 1 commit into
Open
fix(voice): unwedge scheduler when reply is interrupted before playout starts#2070Raysharr wants to merge 1 commit into
Raysharr wants to merge 1 commit into
Conversation
🦋 Changeset detectedLatest commit: 6663341 The changes in this PR will be included in the next version bump. This PR includes changesets to release 37 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
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.
Fixes #2065
Problem
When a pipeline reply is interrupted before its playout has started,
AgentActivity.mainTaskhangs forever on the interrupted handle's generation future and_currentSpeechis never cleared — the agent goes permanently silent for the rest of the session, until an external mechanism (idle/duration guard, user disconnect) tears it down.Mechanism (full trace in #2065): the reply task's interrupted branch awaits
raceWithAbort(audioOutput.waitForPlayout(), replyAbortController.signal). The playback-finished event never fires because playback never began, andreplyAbortController.abort()only happens in code that runs after the segment loop returns — the same loop that is blocked on that await. The reply task therefore never settles the generation future, andmainTask's second wait on it (ThrowsPromise.race([generation, abortFuture.await])) deadlocks, sinceabortFutureonly resolves on activity teardown.Change
In
mainTask's interrupted-generation branch:INTERRUPTED_GENERATION_TIMEOUT, 3 s) in addition toabortFuture;cancelAndWaitutil — cancelling the reply task trips its ownreplyAbortController, so the parkedraceWithAbortresolves and the reply task runs its normal interrupted-reply cleanup (partial-transcript commit, speaking→listening transition,_markGenerationDone());_markDone()only as a safety net if the tasks don't settle withinREPLY_TASK_CANCEL_TIMEOUT.Healthy paths are untouched: an uninterrupted reply never enters this branch; a post-playout-start interruption settles the generation within milliseconds (the timer is cleared in
finally, and the settled flag prevents any force-abort); activity shutdown still exits viaabortFuture/signal.aborted.Validation
agents/src/voice/agent_activity_pre_playout_interrupt.test.ts: an audio output that accepts frames but never reports playback started/finished, plus a non-force interrupt fired on the first captured frame. Without the fix the test hangs until timeout; with the fix the wedged handle settles (~3 s) and a follow-up reply reaches the output.agentspackage suite passes (101 files / 1290 tests);typecheck,throws:check, and lint on the touched files are clean.