Skip to content

fix: end ElevenLabs server VAD turns#5998

Open
he-yufeng wants to merge 1 commit into
livekit:mainfrom
he-yufeng:fix/elevenlabs-server-vad-eos-v2
Open

fix: end ElevenLabs server VAD turns#5998
he-yufeng wants to merge 1 commit into
livekit:mainfrom
he-yufeng:fix/elevenlabs-server-vad-eos-v2

Conversation

@he-yufeng

Copy link
Copy Markdown
Contributor

Summary

  • emit END_OF_SPEECH after non-empty ElevenLabs server-VAD committed transcripts
  • keep manual commit behavior unchanged so empty commits still delimit speech segments
  • add focused ElevenLabs STT tests for both server-VAD and manual commit paths

Fixes #5849.

To verify

  • python -m py_compile livekit-plugins\livekit-plugins-elevenlabs\livekit\plugins\elevenlabs\stt.py tests\test_plugin_elevenlabs_stt.py
  • python -m ruff check livekit-plugins\livekit-plugins-elevenlabs\livekit\plugins\elevenlabs\stt.py tests\test_plugin_elevenlabs_stt.py
  • python -m ruff format --check livekit-plugins\livekit-plugins-elevenlabs\livekit\plugins\elevenlabs\stt.py tests\test_plugin_elevenlabs_stt.py
  • PYTHONPATH=livekit-agents;livekit-plugins\livekit-plugins-elevenlabs python -m pytest tests\test_plugin_elevenlabs_stt.py -q

@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 found 2 potential issues.

View 1 additional finding in Devin Review.

Open in Devin Review

from livekit.plugins.elevenlabs import STT
from livekit.plugins.elevenlabs.stt import SpeechStream, VADOptions

pytestmark = [pytest.mark.unit, pytest.mark.plugin("elevenlabs")]

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.

🟑 Test module declares two category markers, violating "exactly one category" rule

The test file uses pytestmark = [pytest.mark.unit, pytest.mark.plugin("elevenlabs")] which declares two categories. AGENTS.md explicitly states: "Every test module declares exactly one category via a module-level marker." All other plugin tests (e.g., tests/test_plugin_elevenlabs_tts.py:13, tests/test_plugin_assemblyai_stt.py:13) use only pytest.mark.plugin("..."). Having both unit and plugin means this test will be collected during --unit runs (the CI unit gate), even though it imports from livekit.plugins.elevenlabs β€” the unit category is defined as "fast, hermetic, no external providers/credentials/network." The correct marker should be pytestmark = pytest.mark.plugin("elevenlabs") only, consistent with all other plugin test files.

Suggested change
pytestmark = [pytest.mark.unit, pytest.mark.plugin("elevenlabs")]
pytestmark = pytest.mark.plugin("elevenlabs")
Open in Devin Review

Was this helpful? React with πŸ‘ or πŸ‘Ž to provide feedback.

Comment on lines +600 to +602
if is_given(self._opts.server_vad) and self._opts.server_vad is not None:
self._event_ch.send_nowait(stt.SpeechEvent(type=SpeechEventType.END_OF_SPEECH))
self._speaking = False

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.

🚩 Pre-existing inconsistency: _connect_ws commit_strategy check vs new _process_stream_event check

The new code at livekit-plugins/livekit-plugins-elevenlabs/livekit/plugins/elevenlabs/stt.py:600 correctly uses is_given(self._opts.server_vad) and self._opts.server_vad is not None to determine whether server VAD is active. However, the pre-existing code at livekit-plugins/livekit-plugins-elevenlabs/livekit/plugins/elevenlabs/stt.py:484 uses self._opts.server_vad is None to determine commit_strategy. Since NotGiven.__bool__ returns False but NOT_GIVEN is None is False, when server_vad is NOT_GIVEN (the default), _connect_ws incorrectly sets commit_strategy="vad" instead of "manual". This means the WebSocket connects in VAD mode even when no server VAD was requested. Line 494's walrus assignment if server_vad := self._opts.server_vad: is saved by NotGiven.__bool__ returning False, so no crash occurs on the .get() calls. The fix would be to change line 484 to something like commit_strategy = "vad" if is_given(self._opts.server_vad) and self._opts.server_vad is not None else "manual".

Open in Devin Review

Was this helpful? React with πŸ‘ or πŸ‘Ž to provide feedback.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

ElevenLabs server_vad with turn_detection="stt" does not end user turns

1 participant