diff --git a/engine/core/duplex_pipeline.py b/engine/core/duplex_pipeline.py
index 06052b0..44d3cad 100644
--- a/engine/core/duplex_pipeline.py
+++ b/engine/core/duplex_pipeline.py
@@ -73,6 +73,7 @@ class DuplexPipeline:
_ASR_DELTA_THROTTLE_MS = 500
_LLM_DELTA_THROTTLE_MS = 80
_ASR_CAPTURE_MAX_MS = 15000
+ _OPENER_PRE_ROLL_MS = 180
_DEFAULT_TOOL_SCHEMAS: Dict[str, Dict[str, Any]] = {
"current_time": {
"name": "current_time",
@@ -781,6 +782,9 @@ class DuplexPipeline:
)
await self.conversation.add_assistant_turn(greeting_to_speak)
+ # Give client mic capture a short head start so opener can be interrupted immediately.
+ await asyncio.sleep(self._OPENER_PRE_ROLL_MS / 1000.0)
+
used_preloaded_audio = await self._play_preloaded_opener_audio()
if self._tts_output_enabled() and not used_preloaded_audio:
# Keep opener text ahead of opener voice start.
diff --git a/web/pages/Assistants.tsx b/web/pages/Assistants.tsx
index e8af420..cb79bfd 100644
--- a/web/pages/Assistants.tsx
+++ b/web/pages/Assistants.tsx
@@ -178,7 +178,7 @@ export const AssistantsPage: React.FC = () => {
hotwords: [],
tools: [],
botCannotBeInterrupted: false,
- interruptionSensitivity: 500,
+ interruptionSensitivity: 180,
configMode: 'platform',
};
try {
@@ -1049,7 +1049,7 @@ export const AssistantsPage: React.FC = () => {
updateAssistant('interruptionSensitivity', parseInt(e.target.value) || 0)}
className="w-20 h-8 text-right pr-7 text-xs font-mono bg-black/40 border-white/5"
/>
@@ -1063,7 +1063,7 @@ export const AssistantsPage: React.FC = () => {
min="0"
max="2000"
step="50"
- value={selectedAssistant.interruptionSensitivity || 500}
+ value={selectedAssistant.interruptionSensitivity || 180}
onChange={(e) => updateAssistant('interruptionSensitivity', parseInt(e.target.value))}
className="flex-1 h-1.5 bg-secondary rounded-lg appearance-none cursor-pointer accent-primary"
/>
@@ -2075,13 +2075,14 @@ export const DebugDrawer: React.FC<{
setWsError('');
setDynamicVariablesError('');
closeWs();
- if (textTtsEnabled) await ensureAudioContext();
- await ensureWsSession();
- await startVoiceCapture();
- setCallStatus('active');
- } catch (e) {
- console.error(e);
- stopVoiceCapture();
+ if (textTtsEnabled) await ensureAudioContext();
+ // Start mic capture before session.start so barge-in works from opener start.
+ await startVoiceCapture();
+ await ensureWsSession();
+ setCallStatus('active');
+ } catch (e) {
+ console.error(e);
+ stopVoiceCapture();
setCallStatus('idle');
const err = e as Error & { __dynamicVariables?: boolean };
if (err.__dynamicVariables) {
@@ -2378,7 +2379,7 @@ export const DebugDrawer: React.FC<{
generatedOpenerEnabled: assistant.generatedOpenerEnabled === true,
bargeIn: {
enabled: assistant.botCannotBeInterrupted !== true,
- minDurationMs: assistant.interruptionSensitivity || 500,
+ minDurationMs: Math.max(0, Number(assistant.interruptionSensitivity ?? 180)),
},
knowledgeBaseId,
knowledge,