From dfea18d68984cff637deaf3bc0ab98ed8a3523f3 Mon Sep 17 00:00:00 2001 From: Harshit Sharma <66710144+harshitethic@users.noreply.github.com> Date: Mon, 31 Aug 2026 18:40:23 +0530 Subject: [PATCH 1/4] fix: normalize TTS dtype configuration --- src/agents/voice/model.py | 7 +++++++ tests/voice/test_tts_model_settings.py | 23 +++++++++++++++++++++++ 2 files changed, 30 insertions(+) create mode 100644 tests/voice/test_tts_model_settings.py diff --git a/src/agents/voice/model.py b/src/agents/voice/model.py index 3b4a8e85b5..c4dce67e96 100644 --- a/src/agents/voice/model.py +++ b/src/agents/voice/model.py @@ -87,6 +87,12 @@ class TTSModelSettings: speed: float | None = None """The speed with which the TTS model will read the text. Between 0.25 and 4.0.""" + def __post_init__(self) -> None: + # Configurations loaded from JSON/YAML commonly represent NumPy dtypes as strings. + # Normalize those spellings once at the settings boundary so downstream consumers can + # compare against the supported NumPy dtypes consistently. + self.dtype = np.dtype(self.dtype) + class TTSModel(abc.ABC): """A text-to-speech model that can convert text into audio output.""" @@ -228,3 +234,4 @@ def get_stt_model(self, model_name: str | None) -> STTModel: @abc.abstractmethod def get_tts_model(self, model_name: str | None) -> TTSModel: """Get a text-to-speech model by name.""" + pass diff --git a/tests/voice/test_tts_model_settings.py b/tests/voice/test_tts_model_settings.py new file mode 100644 index 0000000000..db2470c234 --- /dev/null +++ b/tests/voice/test_tts_model_settings.py @@ -0,0 +1,23 @@ +from __future__ import annotations + +import numpy as np + +from agents.voice import TTSModelSettings + + +def test_tts_model_settings_normalizes_string_dtype() -> None: + settings = TTSModelSettings(dtype="float32") + + assert settings.dtype == np.dtype("float32") + + +def test_tts_model_settings_normalizes_int16_dtype() -> None: + settings = TTSModelSettings(dtype="int16") + + assert settings.dtype == np.dtype("int16") + + +def test_tts_model_settings_accepts_numpy_dtype() -> None: + settings = TTSModelSettings(dtype=np.float32) + + assert settings.dtype == np.dtype("float32") From a4fdfa13e550af993504e5c2f651db3976dbf48d Mon Sep 17 00:00:00 2001 From: Harshit Sharma <66710144+harshitethic@users.noreply.github.com> Date: Wed, 2 Sep 2026 03:13:57 +0530 Subject: [PATCH 2/4] fix(voice): preserve dtype error contract --- src/agents/voice/model.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/agents/voice/model.py b/src/agents/voice/model.py index c4dce67e96..28e5b9d8da 100644 --- a/src/agents/voice/model.py +++ b/src/agents/voice/model.py @@ -7,6 +7,7 @@ from typing_extensions import TypedDict +from .exceptions import UserError from .imports import np, npt from .input import AudioInput, StreamedAudioInput from .utils import get_sentence_based_splitter @@ -91,7 +92,10 @@ def __post_init__(self) -> None: # Configurations loaded from JSON/YAML commonly represent NumPy dtypes as strings. # Normalize those spellings once at the settings boundary so downstream consumers can # compare against the supported NumPy dtypes consistently. - self.dtype = np.dtype(self.dtype) + try: + self.dtype = np.dtype(self.dtype) + except (TypeError, ValueError) as error: + raise UserError("Invalid output dtype") from error class TTSModel(abc.ABC): @@ -180,9 +184,6 @@ async def transcribe( Args: input: The audio input to transcribe. - settings: The settings to use for the transcription. - trace_include_sensitive_data: Whether to include sensitive data in traces. - trace_include_sensitive_audio_data: Whether to include sensitive audio data in traces. Returns: The text transcription of the audio input. @@ -234,4 +235,3 @@ def get_stt_model(self, model_name: str | None) -> STTModel: @abc.abstractmethod def get_tts_model(self, model_name: str | None) -> TTSModel: """Get a text-to-speech model by name.""" - pass From 733d194115b652229b5011e7bc746ce59dfc6255 Mon Sep 17 00:00:00 2001 From: Harshit Sharma <66710144+harshitethic@users.noreply.github.com> Date: Wed, 2 Sep 2026 03:14:14 +0530 Subject: [PATCH 3/4] test(voice): cover configured TTS dtype behavior --- tests/voice/test_tts_model_settings.py | 64 ++++++++++++++++++-------- 1 file changed, 44 insertions(+), 20 deletions(-) diff --git a/tests/voice/test_tts_model_settings.py b/tests/voice/test_tts_model_settings.py index db2470c234..2b3ea77294 100644 --- a/tests/voice/test_tts_model_settings.py +++ b/tests/voice/test_tts_model_settings.py @@ -1,23 +1,47 @@ from __future__ import annotations import numpy as np - -from agents.voice import TTSModelSettings - - -def test_tts_model_settings_normalizes_string_dtype() -> None: - settings = TTSModelSettings(dtype="float32") - - assert settings.dtype == np.dtype("float32") - - -def test_tts_model_settings_normalizes_int16_dtype() -> None: - settings = TTSModelSettings(dtype="int16") - - assert settings.dtype == np.dtype("int16") - - -def test_tts_model_settings_accepts_numpy_dtype() -> None: - settings = TTSModelSettings(dtype=np.float32) - - assert settings.dtype == np.dtype("float32") +import pytest + +from agents.exceptions import UserError +from agents.voice import AudioInput, TTSModelSettings, VoicePipeline + +from .helpers import extract_events +from .pipeline_test_models import QueuedSTTModel, QueuedVoiceWorkflow, ZeroPcmTTSModel + + +@pytest.mark.asyncio +@pytest.mark.parametrize( + ("dtype", "expected_dtype"), + [("int16", np.int16), ("float32", np.float32), ("f4", np.float32)], + ids=["int16-string", "float32-string", "float32-alias"], +) +async def test_voicepipeline_accepts_string_tts_dtype_from_dictionary_config( + dtype: str, + expected_dtype: type[np.int16] | type[np.float32], +) -> None: + fake_stt = QueuedSTTModel(["first"]) + fake_tts = ZeroPcmTTSModel() + pipeline = VoicePipeline( + workflow=QueuedVoiceWorkflow([["out_1"]]), + stt_model=fake_stt, + tts_model=fake_tts, + config={"tts_settings": {"buffer_size": 1, "dtype": dtype}}, + ) + + result = await pipeline.run(AudioInput(buffer=np.zeros(2, dtype=np.int16))) + events, audio_chunks = await extract_events(result) + + assert events == ["turn_started", "audio", "turn_ended", "session_ended"] + decoded_audio = np.frombuffer(audio_chunks[0], dtype=expected_dtype) + assert decoded_audio.dtype == np.dtype(expected_dtype) + + +@pytest.mark.parametrize( + "dtype", + ["not-a-dtype", {"names": ["x"], "formats": []}], + ids=["unparseable-string", "malformed-structured-dtype"], +) +def test_tts_model_settings_preserves_user_error_for_invalid_dtype(dtype: object) -> None: + with pytest.raises(UserError, match="Invalid output dtype"): + TTSModelSettings(dtype=dtype) # type: ignore[arg-type] From 29d544682b9bd06ae3838fd6fb4936426511cec0 Mon Sep 17 00:00:00 2001 From: Harshit Sharma <66710144+harshitethic@users.noreply.github.com> Date: Wed, 2 Sep 2026 03:14:38 +0530 Subject: [PATCH 4/4] style(voice): restore TTS settings documentation --- src/agents/voice/model.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/agents/voice/model.py b/src/agents/voice/model.py index 28e5b9d8da..079704e56e 100644 --- a/src/agents/voice/model.py +++ b/src/agents/voice/model.py @@ -184,6 +184,9 @@ async def transcribe( Args: input: The audio input to transcribe. + settings: The settings to use for the transcription. + trace_include_sensitive_data: Whether to include sensitive data in traces. + trace_include_sensitive_audio_data: Whether to include sensitive audio data in traces. Returns: The text transcription of the audio input.