Skip to content

Commit e90fed1

Browse files
committed
fix: honor short voice splitter chunks
1 parent 5e71d09 commit e90fed1

2 files changed

Lines changed: 39 additions & 1 deletion

File tree

src/agents/voice/result.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -201,7 +201,7 @@ async def _add_text(self, text: str):
201201

202202
combined_sentences, self._text_buffer = self.tts_settings.text_splitter(self._text_buffer)
203203

204-
if len(combined_sentences) >= 20:
204+
if combined_sentences:
205205
local_queue: asyncio.Queue[VoiceStreamEvent | None] = asyncio.Queue()
206206
self._ordered_tasks.append(local_queue)
207207
self._tasks.append(
@@ -220,6 +220,10 @@ async def _turn_done(self):
220220
)
221221
)
222222
self._text_buffer = ""
223+
elif self._started_processing_turn:
224+
local_queue: asyncio.Queue[VoiceStreamEvent | None] = asyncio.Queue()
225+
await local_queue.put(VoiceStreamEventLifecycle(event="turn_ended"))
226+
self._ordered_tasks.append(local_queue)
223227
self._done_processing = True
224228
if self._dispatcher_task is None:
225229
self._dispatcher_task = asyncio.create_task(self._dispatch_audio())

tests/voice/test_pipeline.py

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
from __future__ import annotations
22

33
import asyncio
4+
from collections.abc import AsyncIterator
45

56
import numpy as np
67
import numpy.typing as npt
@@ -82,6 +83,39 @@ async def run(self, text: str, settings: TTSModelSettings):
8283
assert audio_chunks == [np.array([1], dtype=np.int16).tobytes()]
8384

8485

86+
@pytest.mark.asyncio
87+
async def test_streamed_audio_result_sends_short_custom_splitter_chunks() -> None:
88+
class RecordingTTS(FakeTTS):
89+
def __init__(self) -> None:
90+
super().__init__()
91+
self.texts: list[str] = []
92+
93+
async def run(self, text: str, settings: TTSModelSettings) -> AsyncIterator[bytes]:
94+
del settings
95+
self.texts.append(text)
96+
yield np.zeros(2, dtype=np.int16).tobytes()
97+
98+
def split_immediately(text: str) -> tuple[str, str]:
99+
return text, ""
100+
101+
fake_tts = RecordingTTS()
102+
result = StreamedAudioResult(
103+
fake_tts,
104+
TTSModelSettings(buffer_size=1, text_splitter=split_immediately),
105+
VoicePipelineConfig(),
106+
)
107+
108+
await result._add_text("ok")
109+
await result._turn_done()
110+
await result._done()
111+
112+
events, audio_chunks = await extract_events(result)
113+
114+
assert fake_tts.texts == ["ok"]
115+
assert events == ["turn_started", "audio", "turn_ended", "session_ended"]
116+
assert len(audio_chunks) == 1
117+
118+
85119
@pytest.mark.asyncio
86120
async def test_voicepipeline_run_single_turn() -> None:
87121
# Single turn. Should produce a single audio output, which is the TTS output for "out_1".

0 commit comments

Comments
 (0)