Added
-
Added
MOQTransport, a Media over QUIC (MoQ) transport that gives bots a bidirectional, low-latency audio + RTVI channel over QUIC instead of WebRTC or WebSockets. Install withpip install pipecat-ai[moq]and seeexamples/transports/transports-moq.py.- The bot runs as its own MoQ server (
serve=True) and accepts the browser's direct connection, removing the need for a separatemoq-relayprocess in local dev; client mode (dialingan external relay) is wired up but not yet enabled. - Audio rides a single Opus track; RTVI messages (including the transcript) ride a compressed, ordered JSON stream track, so MoQ is on par with the Daily and WebSocket transports for RTVI support.
- The development runner (
pipecat.runner.run) gained--moq-serve,--moq-bind,--moq-tls-generate/--moq-tls-cert/--moq-tls-keyand related flags to configure the MoQ server and TLS for local dev.
(PR #4629)
- The bot runs as its own MoQ server (
-
Added
reasoningsupport toOpenAIResponsesLLMServiceandOpenAIResponsesHttpLLMService. Setsettings.reasoningto anOpenAIResponsesLLMService.ReasoningConfig(effort=..., summary=...)to control reasoning depth and, optionally, request a summary of the model's thinking. Summaries are surfaced the same way as Anthropic/Gemini thinking — as thought frames and theon_assistant_thoughtevent. Reasoning is only supported by reasoning-capable models (the gpt-5.x series and the o-series); the default model,gpt-4.1, does not reason — see OpenAI's reasoning guide to pick a model.The model's encrypted reasoning is captured and sent back on subsequent
turns automatically, preserving reasoning context across the conversation
(and, with function calling, across tool-call turns). See
examples/thinking/thinking-openai-responses.py(plus the-httpand
-functions-variants).When
reasoningis not configured, the mainline gpt series from gpt-5
onward defaults toeffort="none"(reasoning disabled) to keep latency low
for real-time voice — mirroring how the Gemini service disables thinking by
default — while every other model is left at its provider default.
Conversely, if you configurereasoningon a model known not to support it
(e.g.gpt-4.1), the service logs a clear error up front instead of leaving
you to decipher the raw API failure.
(PR #4933) -
Added
NO_RESPONSEto Pipecat Flows: a consolidated function can return(result, NO_RESPONSE)to finish the function call without transitioning to a new node or running the LLM. The next response can then be triggered by the next user utterance, or programmatically another way.
(PR #4995) -
Added
absent: trueto eval scenario expectations: the expectation passes only when no event of the given type arrives within thewithin_msbudget, and fails as soon as one does. Useful for duplicate-output regressions, e.g. asserting a bot responds exactly once after a multi-worker handoff.
(PR #4995) -
Added
CrusoeLLMService, an OpenAI-compatible LLM service for Crusoe Cloud's Managed Inference API.
(PR #5024) -
Added audio token usage to
LLMTokenUsagefor cost attribution with realtime models: optionalinput_audio_tokens,output_audio_tokens, andcache_read_input_audio_tokensfields.OpenAIRealtimeLLMService(and Azure realtime) now populates them from the Realtime API'sresponse.doneusage details, and they flow through the usage debug logs, RTVI client metrics (onlypresent when populated), and OTel span attributes (gen_ai.usage.audio.input_tokens,gen_ai.usage.audio.output_tokens,gen_ai.usage.audio.cache_read.input_tokens).
(PR #5050) -
Added audio token usage capture to
GeminiLiveLLMService: the AUDIO entries fromusage_metadata's per-modality breakdowns now populateLLMTokenUsage'sinput_audio_tokens,output_audio_tokens, andcache_read_input_audio_tokens, flowing through usage logs, RTVI client metrics, and thegen_ai.usage.audio.*span attributes. Absent modalities are reported as unset rather than zero, and text tokens are never derived from totals (Gemini's modality details don't always sum toprompt_token_count). Gemini Live spans also now include cached and reasoningtoken counts, which the metrics path reported but spans were missing.
(PR #5052) -
The development runner now prints a bordered startup banner flagging it as development-only, with a link to the deployment docs for running bots locally and in production.
(PR #5060) -
Added
DeepgramFluxTTSService, a websocket TTS service for Deepgram's Flux TTS (early access) atwss://api.deepgram.com/v2/speak. LLM tokens are streamed straight to the server as they arrive (TextAggregationMode.TOKEN, the default for this service; passtext_aggregation_mode=TextAggregationMode.SENTENCEto aggregate sentences instead) and each bot response is synthesized as a discrete turn, with prosody carried across turns on a single connection. Flux does not yet provide a way to cancel the active turn, so interruptions reconnect the websocket;examples/voice/voice-deepgram-flux.pyis now an all-Flux bot (Flux STT + Flux TTS).
(PR #5067) -
Added
BasetenLLMService, an OpenAI-compatible LLM service for Baseten's Model APIs and dedicated deployments.Defaults to Baseten's serverless Model APIs endpoint, which servesopen-weights models including GLM, Kimi, DeepSeek, Nemotron, and gpt-oss. To
use a model running on your own dedicated GPUs, pass that deployment's
/sync/v1URL asbase_urland setmodelto its served model name:```python llm = BasetenLLMService( api_key=os.getenv("BASETEN_API_KEY"), base_url=deployment_url, settings=BasetenLLMService.Settings( model="Qwen/Qwen2.5-3B-Instruct", ), ) ```(PR #5077)
-
DailyTransportnow broadcasts anSTTMetadataFramewith Deepgram's TTFS P99 latency whentranscription_enabled=Trueand transcription starts successfully, matching standalone STT services. Downstream consumers likeLLMUserAggregatorand the user-turn-stop strategies now use the correct STT latency instead of falling back to defaults.
(PR #5088)
Changed
-
Changed the default ElevenLabs TTS model from
eleven_turbo_v2_5toeleven_flash_v2_5inElevenLabsTTSServiceandElevenLabsHttpTTSService, sinceeleven_turbo_v2_5is now deprecated by ElevenLabs. This only affects users who don't explicitly set amodel.
(PR #4999) -
Bumped the minimum
nltkversion to 3.10.0.
(PR #5019) -
⚠️ The RTVIdtmfclient message now carriesbuttons— a list of keypad entries, e.g.{"type": "dtmf", "data": {"buttons": ["1", "2", "#"]}}— so a single message can press a whole key sequence. The previous single-keybuttonfield is no longer accepted, andRTVI.PROTOCOL_VERSIONis now2.1.0. TheRTVIProcessorpushes oneInputDTMFFrameper key, in order, so downstream DTMF handling (e.g. aDTMFAggregator) behaves exactly as before.
(PR #5030) -
Removed the
pyyaml-includedependency (GPL-3.0), replacing it with a small built-in!includeconstructor for eval scenarios.
(PR #5037) -
Updated tracing span attributes to the current OpenTelemetry GenAI semantic conventions:
gen_ai.provider.nameis nowazure.ai.openai(wasaz.ai.openai) forAzureLLMService,x_ai(wasxai) forGrokLLMService, andmistral_ai(wasmistral) forMistralLLMService; reasoning token usage is now reported asgen_ai.usage.reasoning.output_tokens(wasgen_ai.usage.reasoning_tokens). Update any dashboards or queries filtering on the old values.
(PR #5047) -
Changed OpenAI Realtime
llm_responsespan attributes to standard OTel GenAI names:tokens.prompt/tokens.completion/tokens.totalare nowgen_ai.usage.input_tokens/gen_ai.usage.output_tokens, plus the new cached/audio breakdown attributes. Update any dashboards or queries filtering on the oldtokens.*names.
(PR #5050) -
Changed Gemini Live
llm_responsespan attributes: the non-standardtokens.prompt/tokens.completion/tokens.totalwere removed in favor of the standardgen_ai.usage.input_tokens/gen_ai.usage.output_tokensattributes already present on the same spans. Update any dashboards or queries filtering on the oldtokens.*names.
(PR #5052) -
Updated the
runnerextra to requirepipecat-ai-prebuilt>=1.0.4.
(PR #5061) -
Updated the runner extra to require
pipecat-ai-prebuilt>=1.0.5to add support for the MoQ transport.
(PR #5073) -
TTSServicenow logsGenerating TTS [text]itself, just before invokingrun_tts: at debug level in sentence aggregation mode and at trace level when streaming tokens (TextAggregationMode.TOKEN), where the accumulated turn text is already logged at debug level at flush time. The duplicate per-service logs — which logged every token at debug level in token mode — wereremoved from all TTS services.
(PR #5079)
Deprecated
-
Deprecated
reset()onBaseUserTurnStartStrategyandBaseUserTurnStopStrategy. Strategy "reset" logic should now happen through the newhandle_user_turn_started()/handle_user_turn_stopped()lifecycle callbacks. For backward compatibility for strategy implementers who haven't implemented the new methods yet: by default, both start and stop strategies'handle_user_turn_started()invokereset(), and stop strategies'handle_user_turn_stopped()invokereset(). Because of this, a custom strategy that extends the base class and still overridesreset()keeps working. Overridingreset()emits aDeprecationWarningwhen the class is defined. To be removed in 2.0.0.
(PR #4967) -
Deprecated the
webrtcextra's dependency on OpenCV.opencv-python-headlesswill be removed from thewebrtcextra in 2.0.0. Video pipelines usingSmallWebRTCTransportshould startinstalling the newwebrtc-videoextra (pipecat-ai[webrtc-video]) instead.
(PR #4978) -
Deprecated
PronunciationDictionaryLocatorand thepronunciation_dictionary_locatorsparameter onElevenLabsTTSServiceandElevenLabsHttpTTSService. Pronunciation dictionary substitutions can rewrite the spoken words in ways that no longer match the text sent to synthesis, which breaks the alignment-based word-completion tracking used to attribute spoken text back to the conversation context. Use thetext_transformsparameter withreplace_text(added in 1.5.0) instead — those transforms run client-side and are tracked correctly. Will be removed in2.0.0.
(PR #4991)
Fixed
-
Fixed Gemini thinking-mode parallel tool calls: the adapter now groups the matching
function_responsemessages into a single turn alongside the mergedfunction_callmessages, so the response count matches the call count. The previous mismatch was rejected with a400by the Vertex AI endpoint (the Gemini Developer API currently tolerates it).
(PR #4103) -
Fixed
RTVIProcessorechoing the client's declared major version back inbot-readywhen connected to a legacy 1.x RTVI client, so the client's aggregator picks the code path that matches the wire format the server observer is actually sending.
(PR #4629) -
Fixed
BaseWorker.send_job_stream_endnot removing the finished job from_active_jobs. Streaming jobs stayed "active" after the stream ended, so a cancel or update that raced in afterwards was still processed (firingon_job_cancelledand sending aCANCELLEDresponse for an already-completed job) and the job leaked until worker shutdown. It now clears the job likesend_job_responsedoes.
(PR #4955) -
Fixed
normalize_datesrendering the month name via the locale-sensitivestrftime("%B"), which produced a mixed-language spoken date (e.g. "Mai 10th, two thousand and twenty-three") when the process locale was non-English. Month names are now always English, matching the rest of the spoken date.
(PR #4956) -
Fixed
SingleClientWebsocketServerTransportclosing the client connection as soon as anEndFramepassed the input transport, cutting off output still being flushed downstream, such asa farewell spoken viaTTSSpeakFrameor Pipecat Flows'end_conversationactiontext. The shared server is now reference-counted by the input and output transports and drained only once the last side has stopped, so the output finishes writing before the connection closes.
(PR #4964) -
Fixed
TurnAnalyzerUserTurnStopStrategykeeping stale speech state across externally-ended user turns. When a turn ended by any path other than the analyzer's own COMPLETE (a forced or external stop, or the stop watchdog timeout) while a mute strategy held audio back, the smart turn analyzer stayed frozen mid-speech and itsstop_secssilence timer later fired a phantom end-of-turn during the bot's response (spuriouson_user_turn_inference_triggered/on_user_turn_stopped, and with realtime services like Gemini Live a strayactivity_endthat could drop the user's next utterance).UserTurnControllernow notifies every stop strategy that the turn ended via ahandle_user_turn_stopped()callback — on every stop path, never at turn start — andTurnAnalyzerUserTurnStopStrategyclears its analyzer there. The clear can't happen in the strategy's shared per-turn reset, which also runs at turn start, because that would drop the continuously-fedpre_speech_msbuffer; the buffer refills from incoming audio, so the next turn regains its full pre-speech context withinpre_speech_msof the clear, and only a user restarting within that window (about half a second) sees one prediction with a shortened lead-in.
(PR #4967) -
Fixed
DeepgramSTTServicenot reporting STT TTFB metrics when the finalize response has an empty transcript. When Deepgram's own endpointing fires before theFinalizecommand, the transcript is sent in a regularis_finalresponse and the subsequentfrom_finalize=Trueresponse arrives with empty text.confirm_finalize()was inside thelen(transcript) > 0guard and was never called, sofinalizedwas never set andstop_ttfb_metrics()fell through to the 2-second timeout — arriving afterBotStartedSpeakingFrameand missing theUserBotLatencyObserverwindow.
(PR #4973) -
Fixed TTS text replacements (
text_transforms/text_filters, e.g.replace_text()) corrupting the conversation context in word-timestamp mode (e.g.CartesiaTTSService) when a replacement split one word into several ("BODYPUMP"→"body pump"), changed only case ("SQL"→"sql"), or changed only the connector between words ("BODYPUMP"→"body-pump"). Previously the spoken (replaced) text could leak into the LLM context instead of the original text, or be silently dropped. Acronym letter-spacing (e.g."API"→"A P I") and inline IPA pronunciation tags had the same underlying issue and are fixed as well.
(PR #4976) -
Fixed
SmallWebRTCTransportimporting OpenCV even for audio-only pipelines.cv2is now imported lazily, only when a non-RGB video frame actually needs converting. Thewebrtcextra'sOpenCV dependency also switched fromopencv-pythontoopencv-python-headless, avoiding GUI system library requirements.
(PR #4978) -
Fixed
SpeechTimeoutUserTurnStopStrategyending the user turn mid-utterance when a new turn'sreset()cleared VAD speaking state while the user was still talking without an interveningVADUserStoppedSpeakingFrame. A finalized transcript for a mid-utterance segment (as streaming STT services emit) was then treated as a standalone utterance with no active VAD reference,anduser_speech_timeoutfalsely ended the turn.reset()now leaves VAD speaking state untouched, since it reflects live physical VAD state rather than turn-scoped bookkeeping.
(PR #4983) -
Fixed
ToolsSchemaAdapterandLLMContextAdapterdropping aToolsSchema'scustom_tools(e.g. Gemini's built-ingoogle_searchtool) when serializing anLLMContextfor network bus transport, which broke provider-specific tools for distributed/multi-worker setups.
(PR #4988) -
Fixed
_send_tool_result()in the OpenAI, Inworld, and xAI (Grok) realtime LLM services double-JSON-encoding tool call results before sending them back to the model. Tool results were being serialized twice, so the model would receive a JSON string containing an escaped JSON string instead of the actual result.
(PR #4988) -
Fixed the Anthropic and AWS Bedrock LLM adapters silently discarding the entire conversation when a single message failed to convert to the provider's format (e.g. a malformed image dataURL). The Anthropic, AWS Bedrock, and Gemini adapters now raise
LLMContextConversionError, surfacing the real cause instead of a misleading downstream API error.
(PR #4990) -
Fixed a small amount of audio being dropped from the end of every bot turn.
BaseOutputTransportonly flushed completeaudio_out_10ms_chunks-sized chunks to the transport; any trailing audio shorter than one chunk was silently discarded whenTTSStoppedFramearrived, cutting off the last bit of speech (more noticeable with largeraudio_out_10ms_chunksvalues). That leftover audio is now padded with silence and flushed before the stop frame is processed.
(PR #4993) -
Fixed the
multi_worker_handoffFlows example repeating the assistant's reply after handing control back to the router. It now hands off withNO_RESPONSE, preventing the newly-deactivated worker from responding.
(PR #4995) -
Fixed word-completion tracking (used for bot text sync, interruptions, and
text_transforms) to correctly handle SSML tags in TTS output, such as ElevenLabs'<phoneme alphabet="ipa" ph="...">tag for custom pronunciations. Some TTS providers report a multi-attribute opening tag as several separate word-timestamp tokens (e.g.<phoneme,alphabet="ipa",ph="...">word); these fragments are now recognized as markup rather than being misrouted or prematurely completing a frame.
(PR #5000) -
Fixed a bug where TTS output containing a lone
<with no matching>(e.g."5 < 10"or an emoticon like"<3") got silently truncated in the user-facing text and LLM context, because word-completion tracking treated it as the start of a truncated SSML tag. Ordinary text like this is now preserved in full; only genuine mid-tag word-timestamp fragments (e.g. a multi-attribute SSML tag split across several tokens by some TTS providers) are still treated as markup.
(PR #5002) -
Fixed Google STT final results waiting for the fallback turn-stop timeout instead of finalizing immediately.
(PR #5018) -
Fixed
AnthropicLLMServiceandAWSBedrockLLMServicefailing with400 invalid_request_error: This model does not support assistant message prefillon Claude 4.6 and newer models. Requests whose message list ends with an assistant message — a tool-call preamble committed after tool results, or afilter_incomplete_user_turnsmarker landing mid-turn — now automatically get a minimal.user message appended at request time. The storedLLMContextis never modified, and models that still support assistant prefill (claude-haiku-4-5 and older) are left untouched.
(PR #5041) -
Fixed user turn-stop strategies ending a turn early when an STT service finalized a transcript mid-utterance. An interim transcription now clears the finalized-transcript fast-path, so atranscript finalized during a pause too short for VAD to report a stop no longer skips the STT safety-net timeout (or, with a turn analyzer, triggers the turn immediately) while the rest of the utterance is still being transcribed.
(PR #5043) -
Fixed traced LLM turns losing their
messages,tools, and system instruction span attributes (with anError setting up LLM tracing: Object of type LLMSpecificMessage is not JSON serializablewarning) when usingOpenAIResponsesLLMServicewith reasoning enabled. Reasoning messages now appear in the traced LLM input with theirencrypted_contentelided.
(PR #5047) -
Fixed TTS spans in OpenTelemetry traces missing some or all of the spoken text (regression in 1.2.0): with sentence aggregation, a turn's span only kept the last sentence's
textandmetrics.character_count, and for services that create their audio context insiderun_tts(e.g. the ElevenLabs websocket path) the first sentence was dropped — leaving single-sentence turns with no text at all. Text from everyrun_ttscall in an audio context now accumulates onto the span (joined text, summed character count), including text spoken before an interruption.
(PR #5049) -
Fixed the Gemini Live
llm_tool_resulttrace span never capturing any tool result attributes. The tracing decorator read the decorated_tool_resultmethod's first positional argument as a dict of result fields, but that argument is thetool_call_idstring, sotool.call_id,tool.function_name,tool.result, andtool.result_statuswere silently dropped. The decorator now reads the method's positional arguments (tool_call_id,tool_call_name,result) directly.
(PR #5051) -
Fixed Gemini Live tracing logging
Error extracting context system instructions: 'LLMContext' object has no attribute 'extract_system_instructions'on every setup span and never capturing the system instruction.llm_setupspans now emit the standardgen_ai.system_instructionsattribute, resolved the same way as for other LLM services: the service'ssettings.system_instructiontakes priority, falling back to an initial system message in the context.
(PR #5053) -
Fixed TTS word-timestamp tracking and RTVI progress reporting when using
TextAggregationMode.TOKEN. Previously, streaming tokens directly to the TTS service bypassed sentence-level tracking, so word-timestamp services and RTVI clients did not receive correctspoken_status/progress events. Streamed tokens are now regrouped into sentences internally, producing the same per-sentence progress frames and word-completion tracking asTextAggregationMode.SENTENCE.
(PR #5066) -
Fixed
TTSServiceapplyingappend_trailing_spaceinTextAggregationMode.TOKEN: appending a space to every token could split words across tokens on services that preserve inter-message whitespace (e.g.RimeTTSService). The trailing space is now applied in sentence aggregation mode only.
(PR #5067) -
Fixed TTS word-level captions dropping or misplacing terminal punctuation for languages that put a space before
?!:;(e.g. French "Comment ça va ?"). The punctuation arrives as its own word-timestamp token, which was being orphaned when the caption was marked complete on the preceding word — dropping the mark from the committed caption, and (for mid-sentence:/;) showing it a word late in progressive captions. The caption now stays open until the punctuation token arrives and drains it in place.
(PR #5089) -
Fixed an issue where
XAIHttpTTSServicecould intermittently crash the audio playback task and leave the bot mute for the rest of the session (buffer size must be a multiple of elementsize). xAI's/v1/ttsendpoint chops its PCM stream at arbitrary byte boundaries, so a chunk could end mid-sample; the service now emits only whole 16-bit samples.
(PR #5090)
Other
- Corrected the return type annotation of
BaseLLMAdapter.from_standard_tools()tolist[Any] | NotGiven | None, reflecting that tools passed in asNoneare returned unchanged. Improves type-checking accuracy for code built on custom adapters; no runtime behavior change.
(PR #5078)