Skip to content

feat(voice): forced-EOU rework and Smart Turn no-signal handling#123

Draft
sam-s10s wants to merge 1 commit into
mainfrom
pr/voice-forced-eou
Draft

feat(voice): forced-EOU rework and Smart Turn no-signal handling#123
sam-s10s wants to merge 1 commit into
mainfrom
pr/voice-forced-eou

Conversation

@sam-s10s

@sam-s10s sam-s10s commented Jul 20, 2026

Copy link
Copy Markdown
Member

Summary

The core turn-taking rework from the voice/v0.2.9-rc3 pre-release: make forced end-of-utterance (FEOU) the default path and simplify the surrounding state, plus add a "no signal" path for Smart Turn.

Changes

Forced-EOU

  • EndOfTurnConfig.use_forced_eou now defaults to True and is enforcedvalidate_config raises if it is False.
  • validate_config is now an explicit method (called after preset/overlay merging) instead of a pydantic @model_validator(mode="after"), so intermediate configs can be built without tripping cross-field validation. Removes the old "FIXED + FEOU without VAD" rule.
  • Collapses _uses_fixed_eou / _uses_forced_eou into a single _use_forced_eou flag; renames _uses_eot_prediction_emit_eot_predictions.
  • Simplifies finalize() (drops the unused end_of_turn arg), the EOU listener registration, and the EOT-prediction gating. Renames _vad_evaluation_speaker_start_stop_evaluation.
  • Presets drop the now-redundant EndOfTurnConfig(use_forced_eou=True).

Smart Turn "no signal"

  • New AnnotationFlags.SMART_TURN_NO_SIGNAL, applied when Smart Turn is active but has no result yet when the TTL fires (distinguished from a genuine false prediction / result.error).
  • EOT penalty table retuned: separate weights for Smart Turn true / false / no-signal, and VAD penalty gated on Smart Turn being inactive.

Tests

  • Reworked test_17_eou_feou; new test_18_feou_timestamp, test_19_no_feou_fix; offline tests switched to setting client._use_forced_eou = False and dropped EndOfTurnConfig(use_forced_eou=False) (now invalid).

Notes

  • ⚠️ Large file: tests/voice/assets/audio_10_16kHz.wav (~560 KB) is added for test_19 and exceeds the repo's 500 KB pre-commit limit. Needs a decision before merge (git-LFS, raise the limit, or a smaller fixture) — committed here with --no-verify.
  • Touches sdk/voice/speechmatics/voice/_client.py; sibling PRs pr/voice-ws-headers and pr/voice-8khz touch disjoint regions of the same file (clean merge, possible trivial rebase).
  • This is the one branch that resists further splitting — the flag rewrite, default flip, validation move, and Smart Turn no-signal work are interleaved across _models.py/_client.py.

Test plan

  • test_17/test_18/test_19 pass
  • Full voice suite passes
  • Confirm FEOU behaviour end-to-end against a live endpoint

Make forced end-of-utterance the default path: use_forced_eou defaults to True
and is enforced in validate_config (now an explicit method, not a pydantic
validator). Collapse _uses_fixed/forced_eou into a single _use_forced_eou flag
and rename _uses_eot_prediction -> _emit_eot_predictions. Add SMART_TURN_NO_SIGNAL
annotation + penalty for when Smart Turn is active but has no result yet.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

1 participant