Interruptions
This recipe shows how to script a user interrupting the agent mid-reply, and explains how the SDK handles the interrupt signal differently depending on whether the adapter supports native barge-in or falls back to VAD-driven detection.
Pattern
Two equivalent forms produce identical runtime behaviour.
Unrolled form
scenario.user("Tell me about my billing"),
scenario.agent(wait=False), # start agent reply in background
scenario.user("Wait — I meant account support"), # interrupt when agent begins speaking
scenario.agent(), # let the agent finish the recovery turnagent(wait=False) / agent({ wait: false }) starts the adapter's reply in the
background without blocking the script. The following steps run while the agent
keeps speaking; the next user() turn fires the interrupt and sends the
replacement user audio. (In TypeScript, scenario.voiceAgent({ wait: false }) is
an exported alias of the same step.)
Sugar form
scenario.user("Tell me about every product feature you offer"),
scenario.interrupt("Sorry — what are your business hours?"),
scenario.agent(),scenario.interrupt(...) is shorthand for the unrolled form above. Prefer it when
you only need to express a single interrupt. In TypeScript, interrupt takes
an options object with three trigger modes:
scenario.interrupt({ after: 2, content: "Wait, that's wrong!" }); // time-based
scenario.interrupt({ afterWords: 5, content: "No, that's not it" }); // word-count (needs streaming transcripts)
scenario.interrupt({ content: "Hold on—" }); // first-chunk barge-inafterWords requires an adapter with streaming transcripts; otherwise it raises
voice.UnsupportedCapabilityError suggesting interrupt({ content }) instead.
Native barge-in vs VAD-driven barge-in
When user() fires the interrupt, the SDK checks whether the adapter reports native
interrupt support (the interruption column in the capability matrix).
| Mode | How it works |
|---|---|
| Native barge-in | The adapter sends a provider-side cancel signal (response.cancel for OpenAI Realtime, clear for Twilio, etc.). The agent's TTS stops immediately and the user turn is queued. |
| VAD barge-in | No provider cancel signal is available. The user audio overlaps with the agent TTS and the SUT's Voice Activity Detection detects barge-in and stops the agent. Requires native_vad support on the adapter side. |
Check the adapter row in the capability matrix to see which mode applies to your deployment.
Random interruptions across a proceed loop
The patterns above script a single deterministic barge-in. For multi-turn
probabilistic interruptions (where any agent turn may be cut off with a given
probability), set interruptProbability on the user simulator. This is the
parity-clean knob shared by both SDKs: it drives barge-ins on any plain
scenario.proceed() loop, and the SDK builds the interruption config
internally.
scenario.userSimulatorAgent({
voice: "openai/nova",
interruptProbability: 0.5, // interrupt ~50% of agent turns
})Then let the conversation run with a plain proceed(); barge-ins fire
automatically per interruptProbability:
script: [
scenario.agent(), // capture the opening greeting
scenario.user("I need help with my account"),
scenario.proceed(5), // barge-ins fire per interruptProbability
scenario.judge(),
]interruptProbability controls how often a turn is interrupted. The
interruption's timing (a short delay after the agent starts speaking) and its
phrasing (a canned interjection) use built-in defaults; they are not
separately configurable from the public API. InterruptionConfig remains
exported under the voice namespace for inspection, but it is constructed
internally.
Worked example
Python:interruption_recovery.py
— demonstrates both unrolled and sugar forms back-to-back in a single scenario, with a
JudgeAgent verifying the agent recovered from both interruptions.
Adapter-specific variants:
random_interruptions.py— randomised interrupt timing across turnsgemini_live_interruption.py— Gemini Live adapter with native barge-inelevenlabs_interruption.py— ElevenLabs adapter interrupt path
interruption-recovery.test.ts— unrolled and sugar forms in a multi-turn Pipecat scenario, with a JudgeAgent verifying recoverygemini-live-interruption.test.ts— Gemini Live adapter with server-side native barge-inelevenlabs-interruption.test.ts— ElevenLabs adapter interrupt path
See also
- Capability matrix —
interruptionandnative_vadcolumns per adapter - Multi-turn recipe — scripting multi-step conversations
- Observability recipe — capture interrupt timing via latency metrics
