# Livekit interrupt logic

**URL:** <https://community.livekit.io/t/livekit-interrupt-logic/1653>\
**Category:** Telephony\
**Tags:** agent-development, noise-cancellation\
**Created:** [July 15, 2026, 10:59am UTC](https://community.livekit.io/t/livekit-interrupt-logic/1653 "2026-07-15T10:59:40Z")\
**Posts on this page:** 6\
**Page:** 1

<div class="post-metadata">

**Author:** ![Vikas\_Salian](https://avatars.discourse-cdn.com/v4/letter/v/7ba0ec/32.png) [@Vikas\_Salian](https://community.livekit.io/u/Vikas_Salian)\
**Post date:** [July 15, 2026, 10:59am UTC](https://community.livekit.io/t/livekit-interrupt-logic/1653/1 "2026-07-15T10:59:40Z")

</div>

I’m building a voice marketing agent using Gemini 3.1 Flash Live (Realtime API) as the voice model, connected via SIP through LiveKit. Since I’m using the Realtime/Live model, STT, conversational reasoning, and TTS are all handled inside the same Gemini session — I’m not using separate STT/VAD/TTS components.

Issue: When the agent is mid-sentence and the user speaks (even briefly, e.g. a stray “hello”), the agent’s audio cuts off abruptly at that exact word. If the user then speaks again shortly after the agent resumes, the same cutoff happens again — producing a repeated stutter/break pattern through the conversation rather than a clean interruption.

I captured the raw PCM audio Gemini sent during one of these interruptions and compared it against the actual call audio. Gemini had already sent more audio past the point where the user interrupted (the sentence continued well beyond the word where the live call cut off) — but that audio was never played to the caller. Based on this, it looks like LiveKit’s playout pipeline is discarding already-received-but-not-yet-played audio frames on interrupt (buffer clear on SpeechHandle cancel), rather than letting the in-flight response finish playing out before stopping.

Question: Is there a way to configure LiveKit (or the Gemini Realtime integration specifically) so that once a response has already been generated and is in the outbound buffer, it plays out to completion rather than being discarded on interrupt? I understand this may be intentional default behavior for snappy interruptions in text/chat-style use cases, but for a live phone call it produces jarring mid-word cutoffs. Is there a “graceful drain instead of hard clear” option, or a recommended pattern for handling this in a telephony context?

---

<div class="post-metadata">

**Author:** ![darryncampbell](https://sea1.discourse-cdn.com/flex001/user_avatar/community.livekit.io/darryncampbell/32/20_2.png) [@darryncampbell](https://community.livekit.io/u/darryncampbell)\
**Post date:** [July 15, 2026, 1:18pm UTC](https://community.livekit.io/t/livekit-interrupt-logic/1653/2 "2026-07-15T13:18:56Z")

</div>

If I understand correctly:

- The agent is speaking
- The user interrupts the agent
- The agent stops speaking because they were interrupted
- Any audio in the pipeline that the agent had not already spoken is discarded
  - You would like to modify this behaviour so that the agent audio that has not already been heard is retained.

This behaviour is by design, since the assumption is you only want to retain the audio the user actually heard. **Otherwise your agent context will not match the user’s understanding of the conversation**.

Is the actual issue here that the agent is being interrupted too easily? And the agent stops speaking unnecessarily as part of the normal conversation? If so, you might try enabling LiveKit’s turn detector which works with Gemini, as described here:

> **[Turn detection - Gemini Live API plugin | LiveKit Documentation](https://docs.livekit.io/agents/models/realtime/plugins/gemini/#turn-detection)**
>
> Chat with a voice assistant built with LiveKit and the Gemini Live API | How to use the Gemini Live API with LiveKit Agents.

---

<div class="post-metadata">

**Author:** ![Vikas\_Salian](https://avatars.discourse-cdn.com/v4/letter/v/7ba0ec/32.png) [@Vikas\_Salian](https://community.livekit.io/u/Vikas_Salian)\
**Post date:** [July 16, 2026, 5:12am UTC](https://community.livekit.io/t/livekit-interrupt-logic/1653/3 "2026-07-16T05:12:08Z")

</div>

Thanks, Darryn — that’s really helpful and confirms what we saw in the PCM capture.

Our issue is a mix of genuine user barge-ins and the agent being interrupted a bit too aggressively on short filler words. We don’t want to disable interruption handling, just make recovery after a real interrupt feel smoother.

Before trying `TurnDetector` with `automatic_activity_detection.disabled=True`, I had two questions:

1. **Language support:** Our agent is Kannada/Kanglish, and `kn` doesn’t appear to be supported by TurnDetector. Does it fall back to a generic model, or would detection quality likely degrade compared to Gemini’s server-side activity detection?

2. **`generate_reply()` interaction:** I noticed `livekit/agents#5408` mentioning issues with AAD disabled and `generate_reply()`. Is that still relevant, especially for setups where we occasionally inject prompts programmatically?

Given this, we’re leaning toward improving recovery after real interruptions first, then evaluating the TurnDetector approach in a separate branch once the current flow is stable.

---

<div class="post-metadata">

**Author:** ![darryncampbell](https://sea1.discourse-cdn.com/flex001/user_avatar/community.livekit.io/darryncampbell/32/20_2.png) [@darryncampbell](https://community.livekit.io/u/darryncampbell)\
**Post date:** [July 16, 2026, 9:48am UTC](https://community.livekit.io/t/livekit-interrupt-logic/1653/4 "2026-07-16T09:48:39Z")

</div>

Interesting. Given what you’ve said, I agree with your approach. It’s strange the documentation does not list any configuration for the built-in turn detector, I did some tests with the `automatic_activity_detection`, [https://ai.google.dev/gemini-api/docs/live-api/capabilities](https://ai.google.dev/gemini-api/docs/live-api/capabilities) but I don’t see much difference in behaviour - it looks like the framework is passing the values through:

```python
llm=google.realtime.RealtimeModel(
            model="gemini-3.1-flash-live-preview",
            voice="Puck",
            realtime_input_config=types.RealtimeInputConfig(
                automatic_activity_detection=types.AutomaticActivityDetection(
                    start_of_speech_sensitivity=types.StartSensitivity.START_SENSITIVITY_HIGH,
                    end_of_speech_sensitivity=types.EndSensitivity.END_SENSITIVITY_LOW,
                    prefix_padding_ms=200, # audio kept before speech start is committed
                    silence_duration_ms=800, # trailing silence before the turn is closed
                ),
            ),
        ),

```

To answer your questions:

> Language support: Our agent is Kannada/Kanglish, and kn doesn’t appear to be supported by TurnDetector. Does it fall back to a generic model, or would detection quality likely degrade compared to Gemini’s server-side activity detection?

No, it would not fall back to a generic (VAD-based) model, I think it would just ‘do its best’ with the audio it has. Just because the turn detection model was trained on specific languages, it doesn’t mean it wouldn’t work well with similar languages. So, I think it’s worth a try, but I’m not sure how well it would work.

> generate\_reply() interaction: I noticed livekit/agents#5408 mentioning issues with AAD disabled and generate\_reply(). Is that still relevant, especially for setups where we occasionally inject prompts programmatically?

That only affects Gemini 3.1, as described here: [Gemini Live API plugin | LiveKit Documentation](https://docs.livekit.io/agents/models/realtime/plugins/gemini/#gemini-3-1-compatibility) . It IS still relevant unfortunately.

---

<div class="post-metadata">

**Author:** ![Vikas\_Salian](https://avatars.discourse-cdn.com/v4/letter/v/7ba0ec/32.png) [@Vikas\_Salian](https://community.livekit.io/u/Vikas_Salian)\
**Post date:** [July 16, 2026, 10:13am UTC](https://community.livekit.io/t/livekit-interrupt-logic/1653/5 "2026-07-16T10:13:56Z")

</div>

Thanks for testing that and for the detailed answer — very helpful on both counts.

The Gemini 3.1 compatibility note is honestly the more important finding for us right now. We’ve built our entire flow-control system today around injecting mid-session instructions via `send_client_content` (telling the model to speak specific locked lines at specific points — greetings, recovery re-asks, etc.), precisely because `generate_reply()`/`update_instructions()` didn’t work for us either. I hadn’t seen this documented as an official 3.1 limitation until your message — I assumed it was just this specific plugin version’s quirk, not a documented model-level restriction with a 1007 rejection after the first turn.

I’m going to go verify directly whether our injects are actually succeeding or being silently rejected — if some of what we thought was working today was coincidental (the model doing the right thing on its own) rather than caused by our injects actually landing, that would explain some inconsistent behavior we’ve seen. Is there a public tracking issue for the “long-term fix being investigated” mentioned in the docs, so we can watch for updates? And separately — do you know if there’s any recommended workaround pattern for getting deterministic mid-call instructions into a 3.1 session today, given `send_client_content` is restricted to initial history seeding only?

On the TurnDetector/Kannada point — that’s a fair characterization, “do its best, unknown quality” is honestly what I expected. Given the 3.1 compatibility issue you just confirmed is unfortunately still open, I think we’ll hold off on the TurnDetector experiment for now and focus on making sure our current setup’s mid-call instruction delivery is actually reliable — will follow up if we find something concrete on that front.

---

<div class="post-metadata">

**Author:** ![darryncampbell](https://sea1.discourse-cdn.com/flex001/user_avatar/community.livekit.io/darryncampbell/32/20_2.png) [@darryncampbell](https://community.livekit.io/u/darryncampbell)\
**Post date:** [July 16, 2026, 10:24am UTC](https://community.livekit.io/t/livekit-interrupt-logic/1653/6 "2026-07-16T10:24:41Z")

</div>

> Is there a public tracking issue for the “long-term fix being investigated” mentioned in the docs

Yes, it dates from when we first launched Gemini 3.1 and is here:

> <https://github.com/livekit/agents/issues/5260>
>
> \### Bug Description
> 
> When using gemini-3.1-flash-live-preview as the realtime mo…del, the agent fails to generate the first reply immediately after joining the room. It times out waiting for the generation\_created event. The exact same code with gemini-2.5-flash works without any issues.
> 
> \### Expected Behavior
> 
> Agent should generate and speak the first reply immediately after joining the room, same as it does with gemini-2.5-flash
> 
> \### Reproduction Steps
> 
> \`\`\`bash
> 1.Create an AgentSession with google.realtime.RealtimeModel using model gemini-3.1-flash-live-preview
> 2.Start the session with session.start()
> 3.Call session.generate\_reply() for the opening dialogue
> 
> \`\`\`
> 
> \### Minimal Reproducible Example
> \`\`\`bash
> from livekit import agents
> from livekit.plugins import google, silero
> from livekit.agents import AgentSession
> 
> @server.rtc\_session(agent\_name="my-agent")
> async def my\_agent(ctx: agents.JobContext):
> session = AgentSession(
> llm=google.realtime.RealtimeModel(
> model="gemini-3.1-flash-live-preview", # ❌ fails
> voice="Puck",
> ),
> vad=silero.VAD.load(),
> )
> 
> await session.start(ctx.room, participant=ctx.room.remote\_participants)
> await session.generate\_reply(
> instructions="Greet the user."
> )
> \`\`\`
> 
> \### Operating System
> 
> Windows11
> 
> \### Models Used
> 
> gemini-3.1-flash-live-preview
> 
> \### Package Versions
> 
> \`\`\`bash
> livekit-agents==1.5.1
> \`\`\`
> 
> \### Logs
> \`\`\`bash
> ERROR… livekit.…ns.google error in receive task: 1007 None.
> Request contains an invalid argument.
> 
> websockets.exceptions.ConnectionClosedError:
> received 1007 (invalid frame payload data) Request contains an invalid argument.;
> then sent 1007 (invalid frame payload data) Request contains an invalid argument.
> 
> google.genai.errors.APIError: 1007 None. Request contains an invalid argument.
> 
> ERROR… livekit.agents failed to generate a reply:
> generate\_reply timed out waiting for
> generation\_created event.
> 
> WARNI… livekit.…ns.google received server content but no active generation.
> \`\`\`

The best conversation in the community at the time is here:

> [@Gemini 3.1 Flash Live not working with LiveKit Agents 1.5.1](https://community.livekit.io/t/gemini-3-1-flash-live-not-working-with-livekit-agents-1-5-1/757/4):
>
> Hey Filippo, I was attempting to summarise DavidZhao’s response in the issue I linked, [generate\_reply times out on first dialogue with gemini-3.1-flash-live-preview — works fine with gemini-2.5-flash- · Issue #5260 · livekit/agents · GitHub](https://github.com/livekit/agents/issues/5260#issuecomment-4160219112) (David is our CTO) confirmed with gemini team that this is a temporary limitation with the model. they are working on improving the behavior on their side. in the next version we’ll raise an explicit error in generate\_reply to make the issue more clear Si…

Obviously you are aware of this possibility, but another option is to explore a different model, or (pipeline) architecture. This would give you a lot more flexibility and choice.
