Skip to content

fix(interruption): bind inference responses to the overlap they were requested for - #2306

Open
mastermanas805 wants to merge 2 commits into
livekit:mainfrom
mastermanas805:fix/interruption-overlap-binding
Open

fix(interruption): bind inference responses to the overlap they were requested for#2306
mastermanas805 wants to merge 2 commits into
livekit:mainfrom
mastermanas805:fix/interruption-overlap-binding

Conversation

@mastermanas805

@mastermanas805 mastermanas805 commented Aug 19, 2026

Copy link
Copy Markdown

The issue notes this wasn't reproduced at runtime, so this starts with a failing test: overlap A sends a request, A ends, B opens, and A's bargein_detected lands and is reported as an interruption of B. Ordinary response latency is enough to hit it.

InterruptionAudioSlice.overlapGeneration from #2116 isn't on main#2116 and #2117 were both closed unmerged. So this adds an overlapGeneration that bumps per overlap and never resets, stamps it onto each request in sendAudioData(), and rejects responses whose generation has since closed. It's deliberately separate from the existing overlapCount, which restarts each agent turn for the audio-prefix shift — reusing that would let turn N's generation collide with turn N+1's.

inference_done needed the same guard. It emits no event, but it writes into cache, and a stale write poisons the entry overlap-speech-ended later pops for its verdict.

The check fails open: an unrecorded generation counts as current, since treating an evicted request as stale would suppress a real interruption — worse than the misattribution being fixed. Same reason the ledger sits outside cache, which is cleared at every overlap boundary.

Regression covers the late response, the cross-turn case, the fail-open path, and a control that still interrupts normally.

Fixes #2119

…requested for

`bargein_detected` / `inference_done` were matched to whichever overlap was open
when they landed, not the one their request was cut for. A response arriving
after its own overlap ended, while a later overlap was open, was accepted and
attributed to that later overlap — emitting `isInterruption: true` for user
audio the model never scored that way, and cutting the agent off.

The cache clear at each overlap boundary was not a filter: `setOrUpdate()`
recreates a missing entry from scratch, and `detectionDelayInS` was computed
from the new overlap's start, so the result looked like a well-formed verdict.
Plain response latency reaches this — the gap between two overlaps in one agent
turn is often only a few hundred ms.

Stamp the overlap generation onto each request in `sendAudioData()` and reject
responses whose generation is no longer open. The generation ledger is kept
outside `cache`, since `cache` is cleared at exactly the boundary where a late
response still needs to be identifiable, and is bounded well above the request
rate of a single overlap.

The check fails open: a request whose generation is no longer on record counts
as current, so losing the bookkeeping degrades to the previous behaviour rather
than suppressing a genuine interruption.

Fixes livekit#2119
@mastermanas805
mastermanas805 requested a review from a team as a code owner August 19, 2026 17:32
@changeset-bot

changeset-bot Bot commented Aug 19, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: b078075

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 39 packages
Name Type
@livekit/agents Patch
@livekit/agents-plugin-anam Patch
@livekit/agents-plugin-anthropic Patch
@livekit/agents-plugin-assemblyai Patch
@livekit/agents-plugin-azure Patch
@livekit/agents-plugin-baseten Patch
@livekit/agents-plugin-bey Patch
@livekit/agents-plugin-cartesia Patch
@livekit/agents-plugin-cerebras Patch
@livekit/agents-plugin-deepgram Patch
@livekit/agents-plugin-did Patch
@livekit/agents-plugin-elevenlabs Patch
@livekit/agents-plugin-fishaudio Patch
@livekit/agents-plugin-google Patch
@livekit/agents-plugin-hedra Patch
@livekit/agents-plugin-hume Patch
@livekit/agents-plugin-inworld Patch
@livekit/agents-plugin-krisp Patch
@livekit/agents-plugin-lemonslice Patch
@livekit/agents-plugin-liveavatar Patch
@livekit/agents-plugin-livekit Patch
@livekit/agents-plugin-minimax Patch
@livekit/agents-plugin-mistral Patch
@livekit/agents-plugin-mistralai Patch
@livekit/agents-plugin-neuphonic Patch
@livekit/agents-plugin-openai Patch
@livekit/agents-plugin-perplexity Patch
@livekit/agents-plugin-phonic Patch
@livekit/agents-plugin-protoface Patch
@livekit/agents-plugin-resemble Patch
@livekit/agents-plugin-rime Patch
@livekit/agents-plugin-runway Patch
@livekit/agents-plugin-sarvam Patch
@livekit/agents-plugin-silero Patch
@livekit/agents-plugin-soniox Patch
@livekit/agents-plugin-tavus Patch
@livekit/agents-plugins-test Patch
@livekit/agents-plugin-trugen Patch
@livekit/agents-plugin-xai Patch

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

@CLAassistant

CLAassistant commented Aug 19, 2026

Copy link
Copy Markdown

CLA assistant check
All committers have signed the CLA.

devin-ai-integration[bot]

This comment was marked as resolved.

`overlapCount` restarts at 0 every agent turn, and the request ledger was
cleared at that same boundary, so a response outliving its turn found no record,
took the fail-open path, and was credited to whatever overlap was open in the
next turn — the same misattribution this fixes within a turn.

Track `overlapGeneration` separately and never reset or clear it. `overlapCount`
keeps its per-turn meaning for the audio-prefix shift.

Add the release-notes changeset.
@mastermanas805

Copy link
Copy Markdown
Author

Both review points addressed in b078075.

The cross-turn one was real: clearing the ledger at the agent-speech boundary sent stale responses straight down the fail-open path, and overlapCount restarting at 0 each turn meant keeping the entries wouldn't have helped either. There's now a separate overlapGeneration that never resets, and a regression test that fails without it. Changeset added.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Adaptive interruption: responses are not bound to the overlap they were requested for, so a late bargein can falsely interrupt a later overlap

2 participants