Skip to content

Support adaptive interruption for realtime models#2099

Open
rosetta-livekit-bot[bot] wants to merge 2 commits into
mainfrom
marjoram-fates-toted
Open

Support adaptive interruption for realtime models#2099
rosetta-livekit-bot[bot] wants to merge 2 commits into
mainfrom
marjoram-fates-toted

Conversation

@rosetta-livekit-bot

@rosetta-livekit-bot rosetta-livekit-bot Bot commented Jul 23, 2026

Copy link
Copy Markdown
Contributor

Summary

Port livekit/agents#6488 to agents-js.

  • Enables adaptive interruption for realtime models that use client-side turn handling, even without STT.
  • Carries agent-ended overlap metadata through adaptive interruption events so synthetic non-interruption verdicts are not treated as confirmed backchannels.
  • Drops realtime backchannel turns and clears buffered realtime audio so they cannot prefix the next committed user turn.
  • Adds parity coverage for realtime adaptive backchannel behavior.
Source diff coverage
  • livekit-agents/livekit/agents/inference/interruption.py: ported to agents/src/inference/interruption/types.ts, agents/src/inference/interruption/interruption_stream.ts, and agents/src/inference/interruption/ws_transport.ts. Adds the optional agentEnded overlap verdict bit to the target event/sentinel types and propagates it for synthetic non-interruption events; remote interruption detections set it to false.
  • livekit-agents/livekit/agents/voice/agent_activity.py: adapted to agents/src/voice/agent_activity.ts. Same behavior mapped to existing TS names and millisecond time units: adaptive interruption can gate realtime models without STT when server turn detection is off; realtime backchannel turns are dropped; confirmed backchannels clear realtime buffered audio; adaptive interruption eligibility no longer rejects all realtime models.
  • livekit-agents/livekit/agents/voice/audio_recognition.py: adapted to agents/src/voice/audio_recognition.ts. Same behavior mapped to the existing TS task/stream structure and millisecond time units: turn-scoped overlap/backchannel state, agent-ended overlap distinction, confirmed-backchannel hook, and end-of-turn backchannel verdict propagation.
  • tests/test_agent_session.py: not applicable as a direct file port. The changed Python assertion covers preserving realtime user transcription item IDs; the target counterpart already exists in agents/src/voice/agent_activity.test.ts and required no change for this PR.
  • tests/test_realtime_adaptive_interruption.py: adapted to agents/src/voice/realtime_adaptive_interruption.test.ts using Vitest and target test utilities. Ports the source behavior cases without adding unrelated coverage.

Verification

  • pnpm test -- agents/src/voice/realtime_adaptive_interruption.test.ts agents/src/voice/audio_recognition_interruption.test.ts agents/src/voice/audio_recognition_backchannel.test.ts
  • pnpm --filter @livekit/agents typecheck
  • pnpm build
  • pnpm --filter @livekit/agents lint (passes with existing warnings; isolated worktree config used to avoid duplicate parent-worktree plugin discovery)
  • Prettier check for the changeset and changed implementation files

Cue voice E2E

  • Exact head: 798b1505becfc2a4df86e8d17dac875d906ff4f6
  • Session: sid_67bbfe6fd281 (voice, ended/flushed)
  • Setup: OpenAI gpt-realtime, server turn detection disabled, text modality, no STT, Silero VAD/client-side turn detection, adaptive interruption, and Cartesia sonic-3 for a deterministic 317-second initial playout.
  • Turn 1 persisted agent_state_changed(.new_state="AS_SPEAKING") at 1995ms.
  • Turn 2 synthesized “uh huh” during playout and resolved in 6723ms with:
    {overlapping_speech(.is_interruption=false) or overlapping_speech(.is_interruption!=true)} -> {!agent_state_changed(.new_state="AS_THINKING")}[5s]
  • Decisive persisted overlap events occurred at 17526ms and 18542ms. The bounded window contained zero AS_THINKING or conversation_item_added events, so the backchannel caused no user-turn commit or reply.
  • Worker evidence records agentEnded: false, isInterruption: false, input_audio_buffer.clear, and the server acknowledgement input_audio_buffer.cleared for both overlap segments.
  • Artifacts:
    • ~/.cue-cli/sessions/sid_67bbfe6fd281/manifest.json
    • ~/.cue-cli/sessions/sid_67bbfe6fd281/events.jsonl
    • ~/.cue-cli/sessions/sid_67bbfe6fd281/recordings/001_run/result.json
    • ~/.cue-cli/sessions/sid_67bbfe6fd281/recordings/002_run/result.json
    • ~/.cue-cli/sessions/sid_67bbfe6fd281/recording.wav
    • ~/.cue-cli/sessions/sid_67bbfe6fd281/recordings/002_run/recording.wav
    • /tmp/pr-2099-worker-evidence.log
  • Limitation: Cue's proto3 JSON projection omits a scalar boolean when it is the default false, so the persisted overlapping_speech object has no printed is_interruption key and the literal =.false arm alone cannot resolve. The !=true arm is the equivalent persisted predicate; the exact worker event confirms isInterruption: false.

Ported from livekit/agents#6488

Original PR description

Enables client-side adaptive interruption (barge-in) for OpenAI-compatible realtime models when the model's own server-side turn detection is disabled — so a backchannel ("uh-huh") while the agent is speaking doesn't trigger a spurious reply, without requiring a separate STT.

The gate. With no STT there's no transcript to gatekeep, so the audio recognition layer tracks a turn-scoped signal — whether the turn's speech overlapped agent speech and was classified a backchannel — and surfaces it on the end-of-turn info. When set, the user turn is dropped and the buffered input audio is cleared, so no reply is generated.

Difference from the STT gate. The STT path is timestamp-windowed: it drops the backchannel portion of a turn and re-emits the rest. Realtime is all-or-nothing — clear_audio() wipes the whole input buffer and the model buffers the turn as one unit, so there's no per-timestamp split. It's correct for the dominant cases (pure backchannel, real interruption) and drops only on a confirmed backchannel; a slow verdict after the agent has stopped falls back to committing rather than silently dropping a possible real barge-in.

STT + realtime. If you want the finer-grained STT gate, pass an STT alongside the realtime model — the realtime drop path is skipped when an STT is present and transcript-based backchanneling takes over.

@rosetta-livekit-bot
rosetta-livekit-bot Bot requested a review from a team as a code owner July 23, 2026 13:28
@changeset-bot

changeset-bot Bot commented Jul 23, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 798b150

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

@rosetta-livekit-bot
rosetta-livekit-bot Bot requested a review from longcw July 23, 2026 13:29

@devin-ai-integration devin-ai-integration Bot left a comment

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.

✅ Devin Review: No Issues Found

Devin Review analyzed this PR and found no bugs or issues to report.

Open in Devin Review

Co-authored-by: Cursor <cursoragent@cursor.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant