Three ways a turn gets detected
Every agent uses exactly one of these. The right choice follows from how your pipeline is shaped.| Mode | Who decides the turn | Use it when |
|---|---|---|
| On-device VAD (default) | The runtime, on the caller’s audio frames | Cascaded ASR → LLM → TTS agents (for example Deepgram → your LLM → ElevenLabs). Works on any transport. |
server_vad | The realtime provider’s own endpointing | Realtime speech-to-speech models that already emit speech-start / speech-stop events (OpenAI Realtime, Gemini Live). |
| Client-commit | Your app / the runtime’s local detector | Self-hosted speech-to-speech models that expose no server-side VAD — turn boundaries are committed explicitly. |
server_vad — the realtime session owns
the audio path end to end, so a local detector would never actually run.
Two on-device backends exist: a lightweight built-in energy gate
(
type: "energy") and a higher-accuracy on-device VAD model, which is the
default you get by omitting type. Both feed the identical turn-taking and
barge-in logic below, so switching backends never changes your timing knobs.Configure turn detection per agent
Turn detection lives in your agent config underturn_detection. Every field
is optional — omit the block entirely and you get the phone-safe defaults.
"type": "energy" on a
realtime agent to force local detection instead. An explicit type wins over the
default in every case.
Set this on the agent from your workspace console at agent.telequick.dev, or
push it through the control-plane API. See
Runtime configuration for the full
agent-config shape.
Tune when the agent replies
Start with the defaults, then reach for these. Lower for snappier replies; raise for callers who pause to gather their thoughts.| Field | Default | What it does | When to change |
|---|---|---|---|
silence_duration_ms | 500 | Trailing silence before end-of-turn fires | Lower (~300) for snappier replies; raise (~800) for deliberate callers |
prefix_padding_ms | 300 | Pre-speech audio kept ahead of the speech-start marker | Raise if the ASR clips first syllables |
threshold | 0.5 | Speech-probability gate for the on-device VAD model | Raise on noisy trunks to reject background chatter |
params.answer_min_speech_ms | 150 | Shortest burst that counts as a real answer once the agent has yielded | Keep low so terse replies (“yes”, a digit) still commit |
params.response_min_speech_ms | 600 | Shortest burst that counts as a real interruption over the agent | Raise to suppress more backchannels; lower to barge more eagerly |
params.silence_floor | 5 | Accumulator level treated as “quiet again” | Rarely touched; lower on very quiet lines |
answer_min_speech_ms and response_min_speech_ms is
deliberate: a short burst means opposite things depending on when it lands. In
the answering window (the agent has stopped and is waiting), even a
one-syllable “yes” is a real turn. Over the agent while it is talking, that same
short burst is almost always a continuer (“mhm”, “ok”, “right”) — so the
over-agent floor is higher, and backchannels never cancel the response.
Hold-and-confirm barge-in
Barge-in is armed automatically whenever the agent is speaking. The mechanism is hold-and-confirm, controlled byparams.barge_confirm_ms (default 300):
Onset arms a pending barge
The instant the caller starts speaking over the agent, a pending barge is
armed — but the agent is not cancelled yet.
Sustained speech confirms it
Only if that speech continues past
barge_confirm_ms does the runtime actually
fire the interrupt and cancel the in-flight response.barge_confirm_ms: 0 to disable the hold and fire the interrupt on the very
first frame of over-talk. Use 0 only on transports with client-side echo
cancellation (the browser path), where a snappy cut is wanted and the agent’s
own audio cannot bleed back into the mic.
Backchannel suppression here is acoustic only — it is based on how long the
caller speaks, not what they say. Lexical gating (treating “stop” differently
from “uh-huh”) and provider-side semantic endpointing are not built today. If
you need word-aware interrupts, handle them in your own tool logic.
Where barge-in actually works
Barge-in quality depends on whether the downstream provider can be cancelled mid-flight. The on-device VAD always detects the interruption; whether the agent’s audio actually stops cleanly is the honest question. A “partial” row is a known limitation, not a misconfiguration.| Provider path | Mid-flight cancel | What happens on barge |
|---|---|---|
OpenAI Realtime / Gemini Live (server_vad) | Clean | Runtime sends the provider’s interrupt/truncate; the session stops generating |
| Streaming TTS (ElevenLabs, Deepgram, and similar) | Clean | Outbound audio buffer is flushed within a frame; playback halts immediately |
| Streaming ASR | Clean | Cancel propagates; the partial transcript is discarded |
| HTTP (non-streaming) LLM | Partial | Playback is silenced locally, but the request runs to completion server-side and is still billed |
| Transport | Interrupt source | Status |
|---|---|---|
| SIP / RTP (PSTN trunk) | On-device VAD on the caller’s RTP → runtime cancel | End to end |
| Browser (WebTransport / media-over-QUIC) | Caller mic decoded → on-device VAD | Same path as PSTN |
| WebRTC fallback leg | Server-side WebRTC termination → on-device VAD | Same path as PSTN |
| External vendor bridge (LiveKit / Vapi / Twilio) | Depends on the vendor’s own interrupt event | Varies by adapter |
Idle watchdog
The flip side of barge-in is silence. When both the caller and the agent have gone quiet, the idle watchdog can re-engage or end the call — configured underturn_detection.idle:
soft_prompt_s— after this many idle seconds, nudge the model to speak (soft_prompt_text, or a bare re-engage on a realtime model).hangup_s— after this many idle seconds, drop the AI leg.
0 (off) in the raw schema, but the runtime ships sensible
ceilings — a re-engage prompt, a hangup, a capped response length, and a hard
maximum session duration — so a stuck agent can’t burn a call forever. See
Session lifecycle for those
guardrails.
Common gotchas
Related
Runtime configuration
The full agent-config shape, including where
turn_detection lives.Handoffs
What a barge-in and end-of-turn feed into when you transfer to a human.
Bring your own speech-to-speech
The client-commit path for self-hosted realtime models with no server VAD.
Debug barge-in
Trace why an interrupt did or didn’t fire on a live call.