transport
WebSocket server transport for the eval harness.
A subclass of SingleClientWebsocketServerTransport
that adds eval-only behavior driven by per-connection query flags the harness
sets:
?skip_tts=truesilences the bot’s output for the session (text mode), including any on-connect greeting. This is pushed as anLLMConfigureOutputFramebeforeon_client_connectedfires: pipecat processes frames in order, and a bot that greets inon_client_connectedqueues its greeting there, so a config sent afterwards (as a client message) would arrive too late.?capture_bot_audio=truemakes the serializer forward the bot’s synthesized audio to the harness (fortts_responsetranscription).?record=<path>records the conversation audio (user + bot) to<path>. The recorder is anAudioBufferProcessorplaced after the real output transport (so both input and output audio flow through it);output()returns that composite. Recording starts on connect and is written on disconnect, before the bot’son_client_disconnectedhandler fires (a bot that cancels its pipeline there may exit right after, so the write must land first). Recording is eval-only — the generic transport is untouched.
The input side runs a virtual microphone (EvalMicrophone), enabled
per connection by ?user_audio=true (audio-mode scenarios): the harness sends
each user utterance as a few large raw-audio messages, and the input
transport plays them into the pipeline at real-time cadence (~20ms frames) with
locally generated silence in between — so VADs, turn models, and streaming STTs
see exactly what a live client’s mic would produce, without a continuous frame
stream crossing the wire. Text-mode scenarios leave the mic off, so no silence
is ever fed into the bot’s STT.
Client disconnects behave as on any transport: the bot’s
on_client_disconnected handler fires normally, and whether the pipeline
survives the disconnect is the application’s choice. The server itself keeps
running either way, so a bot that opts not to cancel can serve several
sequential eval connections.
- class pipecat.evals.transport.EvalMicrophone(push: Callable[[bytes, int], Awaitable[None]])[source]
Bases:
objectPlays harness-sent utterances into the pipeline at real-time cadence.
The harness sends each user utterance as a few large
raw-audiomessages (cheap on the wire — no continuous frame stream to encode and ship). A real microphone, though, delivers small frames at real-time pace, and timing-sensitive consumers rely on that: VAD start windows, Krisp IP/turn models, and turn-detecting STTs all break if a whole utterance floods the pipeline at once. This class is the eval transport’s virtual microphone: every ~20ms tick it pushes one frame — utterance audio when queued, locally generated silence otherwise — so the bot hears exactly what a live client would produce, including the silence that lets its VAD end each turn.Speech that falls behind after a late wake-up is sent back-to-back until caught up (the utterance content must stay gap-free); silence never catches up (the end-of-turn gap must stay honest).
- __init__(push: Callable[[bytes, int], Awaitable[None]])[source]
Initialize the microphone.
- Parameters:
push – Async callable
(pcm: bytes, sample_rate: int)invoked with each ~20ms mic frame.
- class pipecat.evals.transport.EvalTransportParams(*, audio_out_enabled: bool = False, audio_out_sample_rate: int | None = None, audio_out_channels: int = 1, audio_out_bitrate: int = 96000, audio_out_10ms_chunks: int = 4, audio_out_mixer: Mapping[str | None, ~pipecat.audio.mixers.base_audio_mixer.BaseAudioMixer] | None=None, audio_out_destinations: list[str] = <factory>, audio_out_end_silence_secs: int = 2, audio_out_auto_silence: bool = True, audio_in_enabled: bool = False, audio_in_sample_rate: int | None = None, audio_in_channels: int = 1, audio_in_filter: BaseAudioFilter | None = None, audio_in_stream_on_start: bool = True, audio_in_passthrough: bool = True, video_in_enabled: bool = False, video_out_enabled: bool = False, video_out_is_live: bool = False, video_out_width: int = 1024, video_out_height: int = 768, video_out_bitrate: int | None = None, video_out_framerate: int = 30, video_out_color_format: str = 'RGB', video_out_codec: str | None = None, video_out_destinations: list[str] = <factory>, add_wav_header: bool = False, serializer: FrameSerializer | None = None, session_timeout: int | None = None, allowed_origins: list[str] = <factory>)[source]
Bases:
SingleClientWebsocketServerParamsTransport parameters for the eval harness.
A thin subclass of
SingleClientWebsocketServerParamsthat gives the eval transport its own parameter type. Bots configure the"eval"entry oftransport_paramswith this class so the eval setup reads as eval-specific rather than leaking the underlying WebSocket server transport.- add_wav_header: bool
- serializer: FrameSerializer | None
- session_timeout: int | None
- allowed_origins: list[str]
- class pipecat.evals.transport.EvalInputTransport(*args, **kwargs)[source]
Bases:
SingleClientWebsocketServerInputTransportInput transport that plays a virtual mic and serves the harness’s images.
Audio: the harness sends each user utterance as a few large
raw-audiomessages; instead of letting them flood the VAD path at once, they are queued on anEvalMicrophonethat plays them into the pipeline at real-time cadence with locally generated silence in between — a virtual microphone. The mic is enabled per connection by the harness’s?user_audio=trueflag (audio-mode scenarios only — a text-mode scenario must not feed silence into the bot’s STT, which costs real streaming-STT minutes) and starts when the client signals ready (theclient-ready→InputTransportStartAudioStreamingFramepath).Images: a function-calling-video bot pushes a
UserImageRequestFrameupstream when it needs the user’s camera image. There is no camera under eval, so we serve the image the harness registered for the turn (aneval-imagemessage, stored on the serializer) as aUserImageRawFrame— mirroringdaily/transport.pybut sourcing the image from the serializer instead of a live video frame.- async configure_mic(enabled: bool) None[source]
Configure the virtual mic for a new eval client.
Drops any utterance audio a previous client left queued, and enables or disables the mic for this connection (the harness sets
?user_audio=truefor audio-mode scenarios). Disabling stops a mic a previous audio-mode client left running, so a following text-mode scenario doesn’t stream silence into the bot’s STT.- Parameters:
enabled – Whether this connection’s scenario sends user audio.
- async process_frame(frame: Frame, direction: FrameDirection)[source]
Route utterance audio to the virtual mic; serve image requests.
- async cancel(frame: CancelFrame)[source]
Cancel the virtual mic, then the transport.
- class pipecat.evals.transport.EvalOutputTransport(transport: BaseTransport, params: SingleClientWebsocketServerParams, **kwargs)[source]
Bases:
SingleClientWebsocketServerOutputTransportOutput transport used by the eval harness.
The eval harness sends the bot’s output over the same WebSocket connection as any client, so this currently adds no behavior beyond
SingleClientWebsocketServerOutputTransport. It exists for naming symmetry withEvalInputTransportand as a hook for any future eval-specific output behavior.
- class pipecat.evals.transport.EvalTransport(*args, **kwargs)[source]
Bases:
SingleClientWebsocketServerTransportWebSocket server transport used by the eval harness (see the module docstring).
- __init__(*args, **kwargs)[source]
Initialize the transport and the (lazily built) recording composite.
- input() SingleClientWebsocketServerInputTransport[source]
Return an input transport that can serve harness-provided images.