Repository: livekit/agents
File: livekit-agents/livekit/agents/voice/agent_activity.py (Python)

Code before:
                audio=audio,
                add_to_chat_ctx=add_to_chat_ctx,
                model_settings=model_settings,
            )

    async def _tts_task_impl(
        self,
        speech_handle: SpeechHandle,
        text: str | AsyncIterable[str],
        audio: AsyncIterable[rtc.AudioFrame] | None,
        add_to_chat_ctx: bool,
        model_settings: ModelSettings,
    ) -> None:
        current_span = trace.get_current_span()
        current_span.set_attribute(trace_types.ATTR_SPEECH_ID, speech_handle.id)

        tr_output = (
            self._session.output.transcription
            if self._session.output.transcription_enabled
            else None
        )
        audio_output = self._session.output.audio if self._session.output.audio_enabled else None

        wait_for_authorization = asyncio.ensure_future(speech_handle._wait_for_authorization())
        # See discussion in https://github.com/livekit/agents/issues/4432
        wait_for_user_silence = (
            asyncio.ensure_future(self._user_silence_event.wait())
            if speech_handle.allow_interruptions
            else asyncio.ensure_future(asyncio.sleep(0))
        )
        await speech_handle.wait_if_not_interrupted([wait_for_authorization, wait_for_user_silence])
        speech_handle._clear_authorization()

        if speech_handle.interrupted:
            current_span.set_attribute(trace_types.ATTR_SPEECH_INTERRUPTED, True)
            await utils.aio.cancel_and_wait(wait_for_authorization, wait_for_user_silence)
            return

        text_source: AsyncIterable[str] | None = None
        audio_source: AsyncIterable[str] | None = None

        tee: utils.aio.itertools.Tee[str] | None = None
        if isinstance(text, AsyncIterable):
            tee = utils.aio.itertools.tee(text, 2)
            text_source, audio_source = tee
        elif isinstance(text, str):

            async def _read_text() -> AsyncIterable[str]:
                yield text

            text_source = _read_text()

Review comment (security):
I would suggest to use a list of tasks instead of creating an empty one
```python
        authorization_tasks = [asyncio.ensure_future(speech_handle._wait_for_authorization())]
        if speech_handle.allow_interruptions:
            authorization_tasks.append(asyncio.ensure_future(self._user_silence_event.wait()))
        await speech_handle.wait_if_not_interrupted(authorization_tasks)
```

Code after:
                audio=audio,
                add_to_chat_ctx=add_to_chat_ctx,
                model_settings=model_settings,
            )

    async def _tts_task_impl(
        self,
        speech_handle: SpeechHandle,
        text: str | AsyncIterable[str],
        audio: AsyncIterable[rtc.AudioFrame] | None,
        add_to_chat_ctx: bool,
        model_settings: ModelSettings,
    ) -> None:
        current_span = trace.get_current_span()
        current_span.set_attribute(trace_types.ATTR_SPEECH_ID, speech_handle.id)

        tr_output = (
            self._session.output.transcription
            if self._session.output.transcription_enabled
            else None
        )
        audio_output = self._session.output.audio if self._session.output.audio_enabled else None

        # See discussion in https://github.com/livekit/agents/issues/4432
        authorization_tasks: list[asyncio.Future[Any]] = [
            asyncio.ensure_future(speech_handle._wait_for_authorization())
        ]
        if speech_handle.allow_interruptions:
            authorization_tasks.append(asyncio.ensure_future(self._user_silence_event.wait()))
        await speech_handle.wait_if_not_interrupted(authorization_tasks)
        speech_handle._clear_authorization()

        if speech_handle.interrupted:
            current_span.set_attribute(trace_types.ATTR_SPEECH_INTERRUPTED, True)
            await utils.aio.cancel_and_wait(*authorization_tasks)
            return

        text_source: AsyncIterable[str] | None = None
        audio_source: AsyncIterable[str] | None = None

        tee: utils.aio.itertools.Tee[str] | None = None
        if isinstance(text, AsyncIterable):
            tee = utils.aio.itertools.tee(text, 2)
            text_source, audio_source = tee
        elif isinstance(text, str):

            async def _read_text() -> AsyncIterable[str]:
                yield text

            text_source = _read_text()
            audio_source = _read_text()