Added
-
Added a
normalizationfield toCartesiaTTSService.SettingsandCartesiaHttpTTSService.Settings, passing Cartesia's text normalization mode ("auto","off", or a locale code such as"en-GB") through to synthesis requests.
(PR #5430) -
Added
SarvamHttpSTTService, which sends each VAD speech segment to Sarvam's REST speech-to-text API (saaras:v4by default, orsaaras:v3) and yields the transcription fromrun_stt(). It takes the samemodeandkeytermsoptions asSarvamSTTService, and sends a segment longer than the API's 30-second limit as consecutive pieces whose transcripts are joined.stt = SarvamHttpSTTService( api_key=os.getenv("SARVAM_API_KEY"), settings=SarvamHttpSTTService.Settings(language=Language.HI_IN), )
(PR #5501)
-
Added
max_speakersandfilter_profanitytoAssemblyAISTTService.Settings, passing AssemblyAI's speaker-label cap and profanity filter through to the streaming session.
(PR #5530) -
CartesiaSTTService.Settingsnow exposes Cartesia'smin_volumeandmax_silence_duration_secs, which control the silence that triggers automatic transcript finalization on ink-whisper models.
(PR #5531) -
Added
speedto Inworld Realtime'sAudioOutput, so a session can set the agent's speaking rate.
(PR #5541) -
Added
noise_reductionto Inworld Realtime'sAudioInput, so a session can enable Inworld's near-field or far-field input filter.
(PR #5541) -
Added
threshold,prefix_padding_ms,silence_duration_msandidle_timeout_msto Inworld Realtime'sTurnDetection, sotype="server_vad"sessions can be tuned the way Inworld documents.
(PR #5541) -
Added
languageandpromptsto Inworld Realtime'sInputTranscription, so a session can pin the STT language and list expected words or phrases for the transcriber to recognize.
(PR #5541) -
Added an
instructionfield toInworldHttpTTSService.Settings, which passes Inworld's plain-English steering for a request (e.g."speak loudly and urgently") through toinworld-tts-2. The WebSocket API takes steering as inline[tags]in the text instead, soInworldTTSServiceignores the field.
(PR #5542) -
Added
pronunciation_dicttoMiniMaxHttpTTSService.Settings, passing MiniMax'spronunciation_dict.tonereplacements (e.g."Pipecat/(ˈpaɪpkæt)") through to synthesis requests.
(PR #5545) -
Added a
truncationfield to the OpenAI RealtimeSessionProperties, which sets what the server does once a long session outgrows the model's input token limit. By default it drops the oldest messages, only as many as each response needs.TruncationRetentionRatiodrops more at once so truncation happens less often and more input stays in the prompt cache, which OpenAI recommends for lowering the cost of long sessions;"disabled"returns an error instead of truncating.
(PR #5547) -
Added
delay,keywordsandlanguagesto the OpenAI RealtimeInputAudioTranscriptionsettings, exposing OpenAI's input-transcription latency/accuracy control and transcription hints.
(PR #5547) -
Added
speaker_id,length_scale,noise_scaleandnoise_w_scalesettings toPiperTTSServiceandPiperHttpTTSService, exposing Piper's speaker selection, speaking speed and variability controls.
(PR #5551) -
Added
apply_text_normalizationtoElevenLabsDialogueTTSService.Settings, which controls whether ElevenLabs converts numbers, dates and currencies to words before speaking them."on"always converts, so07/03/2026is read as "July third, twenty twenty-six";"off"skips the conversion;"auto"lets ElevenLabs decide. Left unset, ElevenLabs' default,"auto", applies.
(PR #5554) -
Added
keyterm,filler_words,vad_threshold,smart_turnandsmart_turn_timeouttoXAISTTSettings, covering the rest of xAI's streaming transcription query parameters: keyword biasing, disfluency retention, the voice-activity gate, and the server's semantic end-of-turn detection. All are unset by default, leaving the server's defaults in place.
(PR #5561) -
Added a
replacefield toXAIHttpTTSService.Settings, which passes xAI's pronunciation substitution map (up to 200 phrase-to-respelling entries) toPOST /v1/tts.
(PR #5562) -
Added
apply_custom_pronunciationstoResembleAITTSService.Settings, which asks Resemble AI to apply the team's custom pronunciations to matching words in the input text.
(PR #5563) -
Added
SegmentedSTTService.segment_sample_rate, which a subclass overrides to receive its segments at the sample rate its model reads.
(PR #6161) -
TTS services and output transports now log their audio sample rate at DEBUG level, and log when they start resampling audio.
(PR #6200) -
Added
GenesysAudioHookSerializer.create_pause_request()andcreate_resume_request(), which build thepauseandresumemessages that ask Genesys to pause or resume the audio stream. A session opened withstart_paused=Truenow starts paused and resumes once Genesys confirms a resume request; previously it could never be resumed.
(PR #6250) -
Added speaker diarization to
ElevenLabsSTTService(diarize),AWSTranscribeSTTService(show_speaker_label) andOpenAISTTServicewith diarization models such asgpt-4o-transcribe-diarize.
(PR #6269) -
Added
speakertoTranscriptionFrame,InterimTranscriptionFrameandEagerTranscriptionFrame: theTranscriptionSpeaker(provider label and speaker number) an STT service's diarization assigned to the text.
(PR #6269) -
DeepgramSTTService,DeepgramSageMakerSTTService,SonioxSTTService,XAISTTService,SmallestSTTService,MetaSTTServiceandZoomAISTTServicenow report the diarization speaker in the transcription frame'sspeaker.
(PR #6269) -
Added a
speaker_formatsetting to every STT service that supports speaker diarization, to write the speaker into the transcript text (e.g."[Speaker {speaker_number}] {text}").
(PR #6269) -
Added
ZoomAIRealtimeLLMService, speech-to-speech conversation with the Zoom AI Voice Agent. Install it withpipecat-ai[zoom-ai].pipecat initoffers it as "Zoom AI Voice Agent".- The Voice Agent detects turns and handles barge-in itself, so the pipeline needs no VAD analyzer.
Settings.speaksets the voice andSettings.listenthe custom vocabulary.Settings.providerruns the conversation on your own OpenAI or Anthropic account.
(PR #6353)
-
Added a
pause_frame_processingoption toElevenLabsTTSServiceandElevenLabsDialogueTTSService. It defaults toTrue; set it toFalseto let contexts synthesize concurrently on one socket, such as twoTTSSpeakFrames pushed at once or back-to-back turns. Audio still plays in order.
(PR #6392) -
Added
framingtoSimliVideoServicefor Simli Trinity-2 faces.SimliVideoService.Framing(...)sets the video's size (streaming_width,streaming_height, such as 1366x768 for 16:9), where the avatar sits in it (avatar_position_x,avatar_position_y), the camera it starts with (SimliVideoService.Camera(...)), and an uploadedbackground_idorforeground_id.
(PR #6400) -
Added
eou_timeout_mstoSmallestSTTService.Settings, exposing Pulse's end-of-utterance silence timeout (100-10000ms). Left unset, Pulse's own endpointing-dependent default (600ms/800ms) applies.
(PR #6459) -
ElevenLabsRealtimeSTTServicenow supports specifying secondary languages.
(PR #6475) -
Added
clone_strengthtoElevenLabsDialogueTTSService.Settings. It controls how closely a Professional Voice Clone fine-tuned for an Eleven v4 model follows its samples, and is sent only toeleven_v4models.
(PR #6483) -
Added
vad_force_turn_endpointtoZoomAISTTService. Withvad_force_turn_endpoint=True, Scribe's own voice activity detection is turned off and the service commits each turn onVADUserStoppedSpeakingFrame, so Pipecat's VAD and turn strategies (e.g. Smart Turn) decide when the user is done. The service then reports a TTFS P99 latency (ZOOM_AI_TTFS_P99, overridable withttfs_p99_latency) and leaves the default user turn strategies in place. The default (False) keeps Scribe's turn detection unchanged.
(PR #6497) -
Added "Google Gemini Interactions" to the LLMs
pipecat initoffers, which generates a bot usingGoogleInteractionsLLMService.
(PR #6504) -
Added
GoogleInteractionsLLMService, an LLM service for the Gemini Interactions API. It sends the full context each turn withstore=False, so Google keeps no conversation state. Import it frompipecat.services.google.interactions.llm; it needsgoogle-genai2.0.0 or later.- It takes the same settings as
GoogleLLMService, so switching is a change of class.top_k,frequency_penalty,presence_penaltyand a thinking budget have no Interactions API field and are ignored with a warning; thinking is set bythinking_level. - Thought signatures are stored in the context the same way
GoogleLLMServicestores them, so a conversation can move between the two services mid-call, including one with function calls. - Supports streaming text, function calls (parallel and sequential), thought summaries, images, audio and documents, built-in Gemini tools passed as
tools,run_inference()with aresponse_schema, and token usage metrics. - A completed response with no text and no function call logs a warning and pushes a non-fatal
ErrorFrame, so the application can react instead of the bot going silent. - See
examples/voice/voice-google-interactions.py,examples/function-calling/function-calling-google-interactions.py,examples/function-calling/function-calling-google-interactions-video.py,examples/function-calling/function-calling-google-interactions-async.py,examples/vision/vision-google-interactions.pyandexamples/thinking/thinking-functions-google-interactions.py.
(PR #6504)
- It takes the same settings as
-
Added
GoogleInteractionsVertexLLMService, which runsGoogleInteractionsLLMServiceon Vertex AI. Import it frompipecat.services.google.interactions.vertex.llm.- It authenticates with Google Cloud credentials (
credentials,credentials_path, or the application default credentials) for aproject_id, and refuses anapi_key. locationdefaults to"global". Vertex serves the Interactions API only fromglobal,usandeu, and only for Gemini 3 models and later; the default model isgemini-3.8-flash.gs://image and file URLs are passed to Vertex directly.- See
examples/function-calling/function-calling-google-interactions-vertex.py.
(PR #6508)
- It authenticates with Google Cloud credentials (
-
Added "Google Vertex AI Interactions" to the LLMs
pipecat initoffers, which generates a bot usingGoogleInteractionsVertexLLMService.
(PR #6508) -
Added
load_shared_model()inpipecat.utils.models, which loads a model off the event loop the first time it's asked for and hands the same one to every later caller with the same key, so a local model is loaded once a process however many pipelines use it. Pipecat Tone's reader and tagger load their models through it.
(PR #6519) -
Added
PipecatToneClassifierinpipecat.classifiers.tone.classifier, a classifier that runs Pipecat Tone's reader model on the CPU. It answers the questions built into the model, listed inPipecatToneClassifier.questions: the turn'semotionandmoveas choices, andsarcasmandbackchannel(whether the turn is only a listening sound, such as "mhm") as yes/no questions. The questions take their options from the model, whichsetup()loads, and any other question raises aClassifierError. The state is the turn's text, or{"user": ..., "assistant": ...}to read it with the bot's words before it.
(PR #6519) -
Added
PerceptionReaderto expressive conversation (alpha), a processor that reads how each user turn was said by asking classifiers. Place it after the STT service and give it itssources, each aPerceptionSource: a classifier, the questions it's asked and how long a transcription waits for its answers. A text classifier reads each final transcription, with the bot's previous reply, and one that hears, such asHumeAudioClassifier, hears the user's speech. The sources are asked at once and their answers added to the transcription'sperception, one signal per question, in the sources' order, after any signals the STT service read (replace_perception=Truereplaces them instead); a source that's late or fails leaves only its own signals out. AChoiceQuestionreports its likeliest options, aYesNoQuestionits probability and aScoreQuestionits position on the scale, and eachPerceptionQuestioncarries thedescriptionthe LLM is given for its signal.from pipecat.expressive.processors.perception_reader import ( PerceptionQuestion, PerceptionReader, PerceptionSource, ) from pipecat.expressive.processors.tone_reader import PipecatToneSource hume = PerceptionSource( classifier=HumeAudioClassifier(api_key=os.getenv("HUME_API_KEY")), questions={ "hesitation": PerceptionQuestion( question=YesNoQuestion(instructions="Is the user unsure?"), description="The chance the user is unsure, from 0 to 1.", ), }, ) reader = PerceptionReader(sources=[PipecatToneSource(), hume])
(PR #6519)
-
Added
SpeechSegmentBufferinpipecat.audio.speech_segment_buffer, which keeps one stretch of the user's speech with the audio just before it. Between stretches of speech it keeps the lastpre_speech_secs, 1 s by default, so a segment starts before the VAD reports speech. Fromstart()tostop()it keeps everything, or the lastmax_secs, andstop()returns the segment.SegmentedSTTServicekeeps its segments in one.
(PR #6523) -
Added
HumeAudioClassifierinpipecat.classifiers.hume.audio_decisions, a classifier backed by Hume's Audio Decisions API that hears a clip of the user's speech. Install it withpipecat-ai[hume]. As aPerceptionReadersource, it reads how the user sounded: seeexamples/expressive-conversation/expressive-conversation-hume-audio-decisions.py.
(PR #6530) -
Added
PerceptionFrame, whichPerceptionReaderbroadcasts with every reading as soon as it's made.
(PR #6530) -
Added audio to classifiers: a classifier whose
supports_audiois set hearsClassifierAudioclips passed ininputs=.
(PR #6555) -
Added
ErrorCategory.CONTENT_FILTEREDfor requests a provider's content policy rejected. It is not a permanent category, so it does not mark a service unusable. The OpenAI Chat Completions and Responses LLM services report acontent_filter400 with it.
(PR #6566) -
Added
enable_agent_text_inputtoSonioxSTTService.Settings, on by default. Each reply is sent to Soniox once the bot has said it, so the recognizer knows the bot's side of the conversation and words the bot used are recognized when the user repeats them. It takes effect only on models that support agent text input (stt-rt-v6and later); it stays off for older models.
(PR #6571) -
Added
enable_echo_cancellationtoSonioxSTTService.Settings. It sends the bot's reply word by word while it plays, so Soniox lines the words up with the audio and does not transcribe the bot's own voice as the user. Needs a TTS service that reports word timestamps, such asSonioxTTSService.agent_text_lead_ms(default 700) sets how far ahead of playback each word is sent.
(PR #6572) -
Added
BotSpeechObserver, which reports the text the bot will speak as the TTS service produces it, throughon_bot_text, and the end of the bot's speech, with whether it was interrupted, throughon_bot_speech_ended. A TTS service that reports word timestamps produces one word at a time, each with its presentation timestamp. Text of a reply the user cut off, and expression sounds and pauses, are left out.
(PR #6572) -
Added
JambonzFrameSerializer, for connecting a Pipecat pipeline to jambonz through itslistenverb. jambonz sends raw 16-bit PCM rather than base64 in a JSON envelope, and announces the call's sample rate, channel layout and identifiers in a preamble before any audio, so the rate is read from the connection rather than configured — a narrowband call needs no change. Later text frames are events: a DTMF digit becomes anInputDTMFFramewhen the verb setspassDtmf, andmarkandplayDonereplies are ignored.InterruptionFramesendskillAudio, anddisconnect_on_end(on by default) ends thelistenverb when the pipeline stops, which needs no API credentials.The verb has to set three things explicitly.
streamingdefaults to
false, and while it is, audio sent back is ignored and the caller simply
hears nothing.sampleRatedefaults to8000. And
bidirectionalAudio.sampleRatehas no default — omitted, your audio is read
at the call's negotiated codec rate, which depends on the carrier. jambonz
resamples whatever arrives at that rate, but this serializer sends at the
sampleRateit read from the preamble, so set the two to the same value, or
set the serializer'saudio_out_sample_rateto
bidirectionalAudio.sampleRate:{ "verb": "listen", "url": "wss://your-bot.example.com/ws", "sampleRate": 16000, "mixType": "mono", "bidirectionalAudio": { "enabled": true, "streaming": true, "sampleRate": 16000 } }from pipecat.serializers.jambonz import JambonzFrameSerializer transport = FastAPIWebsocketTransport( websocket=websocket, params=FastAPIWebsocketParams(serializer=JambonzFrameSerializer()), )
(PR #6573)
-
Added
audio_in_sample_rateandaudio_out_sample_ratetoFrameSerializer.InputParams, the sample rates of a serializer's wire format.FrameSerializerconverts audio between these rates and the pipeline's, so a serializer subclass only encodes and decodes.
(PR #6576) -
Added
max_buffer_delay_msandbuffer_char_thresholdconstructor arguments toInworldTTSService. These were previously only settable through the deprecatedInworldTTSService.InputParams, whose fields of the same name still apply when the arguments are not set.
(PR #6593) -
Added
inputs=to classifiers'ask(),yes_no(),choice()andscore(): the images, audio clips and files (ClassifierFile, such as a PDF or a video) that come with the state; a classifier lists the file types it takes infile_types.
(PR #6594) -
Added
SincStreamAudioResampler, a streaming resampler whose output keeps pace with its input: equal input chunks come out as equal output chunks. It runs in the newpipecat-resamplerpackage, now a core dependency.
(PR #6598) -
Added
RimeSTTService, streaming speech-to-text with Rime. Rime transcribes one utterance per stream, so the service needs VAD frames from the user aggregator or aVADProcessor, and streams each speech segment as its own request with interim transcripts and one final.Settingstake the language,mode(writtenorverbatim),context_termsandoutput_contract. Therimeextra now installs Rime'srimelabs-sdkalongside the TTS client, andpipecat initoffers Rime as a speech-to-text service.stt = RimeSTTService( api_key=os.getenv("RIME_API_KEY"), settings=RimeSTTService.Settings(language="en", context_terms=["Pipecat"]), )
(PR #6602)
-
Added
SincAudioResampler, a one-shot resampler for whole clips whose output lines up with its input. It runs inpipecat-resampler.
(PR #6625) -
Added an
enhance_generationfield toInworldHttpTTSService.Settings, which asks Inworld to denoise the synthesized audio. The WebSocket API has no equivalent, soInworldTTSServiceignores the field.
(PR #6654) -
MiniMaxHttpTTSService.Settingsnow has atext_normalization_modefield ("basic"or"quality"), MiniMax's replacement for the deprecatedvoice_setting.text_normalizationparameter.
(PR #6655) -
Added
complexitytoOpenAIImageGenService.Settings, OpenAI's control over how much a GPT Image model plans before rendering (low,medium,high).
(PR #6657) -
Added
strengthto OpenAI Realtime'sInputAudioNoiseReduction, so a session can set how much suppression the input noise filter applies.
(PR #6659) -
GrokLLMService.Settingsnow takesguidelines, xAI's per-category content guidelines (nsfw,violence,profanity).
(PR #6663) -
Added a
language_hintfield toDeepgramSTTService.Settings, which biases Nova-3 multilingual language detection toward the languages you expect.
(PR #6665) -
AzureSTTService.Settingsgainedpost_processing_option, which selects Azure'sTrueTextdisplay formatting orPostRefinementpost-stream refinement, the latter replacing each segment's final transcript with a more accurate one built from broader audio context. Azure's default applies when it's unset.
(PR #6667) -
Added a
redact_usagesetting to the Deepgram Flux STT services, which stores keyterms as[REDACTED]in Deepgram's usage records.
(PR #6668) -
DeepgramFluxTTSServiceandDeepgramFluxSageMakerTTSServicesettings gainednormalize_volume, Flux's control for levelling loudness across voices and turns. Unset leaves Flux at its default, which normalizes.
(PR #6669) -
Added
PipecatToneSourceinpipecat.expressive.processors.tone_reader, Pipecat Tone as one of aPerceptionReader's sources, so it reads a turn'semotionandsarcasmbeside other classifiers.
(PR #6673) -
Added
pipecat.audio.g711, withpcm_to_ulaw,ulaw_to_pcm,pcm_to_alawandalaw_to_pcmfor converting between 16-bit PCM and G.711 μ-law or A-law at the same sample rate. They produce the same bytes asaudioop, and the Twilio, Plivo, Genesys and Telnyx serializers use them.
(PR #6681) -
Added
STTService.send_sample_rate, the rate input audio is resampled to beforerun_stt(). A speech-to-text service whose provider takes only some rates overrides it.
(PR #6684) -
Added HeyGen Voice text-to-speech services. Both default to the
heygen-voice-1-turbomodel and the public voice Nadine, and both serveheygen-voice-1,heygen-voice-1-turboandheygen-voice-1-turbo-free.-
HeyGenTTSServicestreams text over HeyGen'smulti-stream-inputWebSocket. Per-character alignment drives word-level text frames, so an interruption commits only the words actually spoken. It takes HeyGen'senable_ssml_parsing,enable_loggingandend_user_idoptions, andapply_text_normalizationandexpressiveness_boostas settings. Withtext_aggregation_mode=TextAggregationMode.TOKENit streams LLM tokens, and HeyGen generates at each sentence end.pipecat createoffers it. -
HeyGenHttpTTSServicestreams raw PCM from the/v3/models/audio/tts/streamendpoint, one request per sentence. It also serves professional voice clones, with theheygen-voice-1model.from pipecat.services.heygen.tts import HeyGenTTSService tts = HeyGenTTSService( api_key=os.environ["HEYGEN_API_KEY"], settings=HeyGenTTSService.Settings(voice="<voice_id>"), )
(PR #6713)
-
-
RTVI
user-inputandstt-raw-textmessages now carry the transcription's diarizationspeaker(labelandnumber).
(PR #6714) -
Added
PipecatVoiceSourceandPipecatVoiceReaderinpipecat.expressive.processors.voice_reader, Pipecat Voice Reader as one of aPerceptionReader's sources and as a reader of its own. Each time the user stops speaking, it hears their speech and reports theirtoneof voice,arousal,laughter,speech_rateandsarcasm_voice, andsadwithsad=True. In onePerceptionReaderit goes besidePipecatToneSource, which reads the words: seeexamples/expressive-conversation/expressive-conversation-voice-reader.py.
(PR #6719) -
Added
PipecatVoiceClassifierinpipecat.classifiers.voice.classifier, a classifier that runs Pipecat Voice Reader on the CPU and hears how a clip of the user's speech sounds. It answers the questions built into the model, listed inPipecatVoiceClassifier.questions: the speaker'stoneof voice as a choice,sarcasm,laughterandsadas yes/no questions, andarousal,upsetandspeech_rateas scores. Any other question raises aClassifierError. Every call takes one clip of 0.8 to 8 seconds, andsarcasm_thresholdis the probability from which the model's release counts a turn as sarcastic. The model comes in two sizes (variant="base"or"tiny") and downloads from Hugging Face on first use. Install it withpipecat-ai[expressivity].
(PR #6719) -
Added
EvalRubric(pipecat.evals.simulation) to judge a conversation the eval harness didn't drive, such as a production call recorded byEvalConversationObserver. A rubric holds a simulation's judging keys,judge,successand judgedmetrics, with no persona or goal, andEvalSimulationJudgetakes one wherever it takes a simulation. In a scenario file, an entry withsuccess:and neitherpersona:norturns:is a rubric:EvalScenarioFile.load()returns it with the file's defaults merged in,pipecat eval runandpipecat eval suiteskip it, since it has nothing to run, andpipecat eval judge -s <entry>judges saved conversations with it.EvalRubric.from_dict()builds one from a mapping with the same keys. A measured metric needs a live run, so a rubric leaves out the ones it takes from the file'smetrics:and refuses one it lists itself.name: food_ordering judge: !include judge_text.yaml scenarios: - name: production success: "the bot took the caller's order and completed it" metrics: - name: politeness criterion: "the reply is courteous and helpful, never curt or dismissive" min_score: 1
rubric = EvalScenarioFile.load("food_ordering.yaml")["food_ordering/production"] judgement = await EvalSimulationJudge(rubric).judge(message.conversation)
(PR #6740)
-
Added
GoogleDecisionsClassifierinpipecat.classifiers.google.decisions.classifier, a classifier backed by Google's Decisions API that can also see images, hear clips of audio and read files. Install it withpipecat-ai[google].
(PR #6742) -
Added the
expressivityextra, which installs what Pipecat Tone's reader and tagger and Pipecat Voice Reader need to download and run their models:uv add "pipecat-ai[expressivity]".
(PR #6751)
Changed
-
InworldTTSServicenow creates its server-side context together with the first sentence of a turn instead of when the LLM response starts. Turns that produce no text no longer open a context.
(PR #6149) -
InworldTTSServicewithtext_aggregation_mode=TextAggregationMode.TOKENon aninworld-tts-2model now uses theSENTENCE_BOUNDARYauto-mode strategy, so the server splits streamed tokens at sentence boundaries instead of synthesizing fragments as they arrive.
(PR #6266) -
⚠️
AssemblyAISTTService,SpeechmaticsSTTServiceandNvidiaSTTServicenow put the diarization speaker inspeakerinstead ofuser_id, which keeps the transport participant id. Readframe.speakerinstead.
(PR #6269) -
⚠️
SpeechmaticsSTTServicewith the deprecatedInputParamsandenable_diarization=Trueno longer prefixes transcripts with@{speaker_id}:. Setspeaker_format="@{speaker}: {text}"to keep it.
(PR #6269) -
InworldTTSServicesendscancel_contextinstead ofclose_contextwhen a reply is interrupted or the websocket disconnects, so the server stops synthesizing text that will not be played. A completed turn still sendsclose_context.
(PR #6278) -
pipecat-ai[simli]now requiressimli-ai2.1. It fixes a leak in the SDK's frame reader, where every frame received left a task pending until the session ended, about 75 a second. A session that can't start now fails with Simli's reason, such as an invalid API key or face ID, instead of a genericFailed To Initialize SimliClient.
(PR #6400) -
SimliVideoServicenow sends the bot's audio to Simli as it arrives, whatever the face. Withis_trinity_avatar=Trueit used to hold back up to 4 seconds of TTS audio at the start and after each interruption, and play it withsendImmediate. That pre-buffer is removed, and every interruption now clears Simli's buffer. A user who starts speaking without interrupting the bot, as withOpenAILiveLLMService, no longer clears it, so the avatar keeps talking when the bot does.
(PR #6400) -
MetaSTTServicenow sends aUser-Agentheader identifying the Pipecat integration, consistent with the AssemblyAI and xAI services.
(PR #6456) -
ElevenLabsTTSServicenow warns at construction when given an Eleven v3 or v4 model, which its WebSocket endpoint doesn't serve, and points toElevenLabsDialogueTTSService(real-time) orElevenLabsHttpTTSService(HTTP streaming).
(PR #6483) -
PipecatToneReaderis now aPerceptionReaderthat asks aPipecatToneClassifierits emotion and sarcasm questions, with the same arguments and readings. It takes atimeout: a transcription waits at most 0.5 seconds for its reading by default. With metrics enabled, it pushes the classifier's processing metrics.
(PR #6519) -
⚠️
PipecatToneTaggermoved topipecat.expressive.processors.tone_tagger, besidePipecatToneReader, andpipecat.processors.toneis removed, since expressive conversation is alpha.
(PR #6519) -
⚠️
PipecatToneReadermoved topipecat.expressive.processors.tone_reader, besidePerceptionReader, and Pipecat Tone's reader model topipecat.classifiers.tone.model, besidePipecatToneClassifier. The oldpipecat.processors.tone.readerpaths are removed, since expressive conversation is alpha.
(PR #6519) -
With expressive conversation on, the user aggregator merges all the final readings of a user turn, instead of keeping only the last one, so a reading from earlier in the turn, such as a sarcastic first sentence, still reaches the LLM. The new
merge_perception()inpipecat.expressive.perceptionkeeps the higher of each signal: a value keeps its highest value, and labels keep every label read, each with its highest confidence, likeliest first. The merged reading is written at the head of the user message and reported inon_user_turn_stopped.
(PR #6554) -
Expressive conversation's instructions now name RCS, the Real-time Context Standard, and teach readings as the LLM's input only and tags as its output only.
(PR #6567) -
SonioxSTTServicenow defaults tostt-rt-v6, the model that supports agent text input. Passsettings=SonioxSTTService.Settings(model="stt-rt-v5")for the previous default.
(PR #6571) -
The
aicextra now requiresaic-sdk~=3.4.0, which uses core SDK 0.26.0 and model file version 8.AICQuailVADAnalyzernow defaults tovad-ms-2.1-xxs-16khz, andAICTytoObservernow defaults to Tyto 1.2,tyto-1.2-l-16khz. The SDK cannot download a model that has no version 8 file, such asquail-vf-2.2-l-16khz,tyto-1.1-l-16khzorvad-2.1-xxs-16khz. If you setmodel_idyourself, change to a current model, for examplequail-vf-2.3-l-16khz. See https://artifacts.ai-coustics.io/ for the available models.
(PR #6581) -
A custom classifier's
_ask()takesinputsinstead ofimages.
(PR #6594) -
⚠️
resampy, and with itnumbaandllvmlite, is no longer a core dependency, which roughly halves the default install. Installpipecat-ai[resampy]to keep using the deprecatedResampyResampler.
(PR #6595) -
create_stream_resampler()returnsSincStreamAudioResamplerinstead ofSOXRStreamAudioResampler. Resampled audio is delayed by a few milliseconds rather than held back.
(PR #6598) -
A function call that returns
"",{}orFalsenow runs the LLM. ReturnNoneto complete a call without a reply.
(PR #6603) -
create_file_resampler()returnsSincAudioResamplerinstead ofSOXRAudioResampler, andLocalSmartTurnAnalyzerV3andRNNoiseFilterresample withpipecat-resamplerinstead of soxr.
(PR #6625) -
⚠️
soxris no longer a core dependency. Installpipecat-ai[soxr]to keep using the deprecatedSOXRAudioResamplerandSOXRStreamAudioResampler.
(PR #6625) -
The Google image-generation voice example now uses
gemini-3.1-flash-lite-image, Google's replacement forgemini-2.5-flash-image, which is scheduled for shutdown and reachable only by projects that already used the Gemini 2.5 models.
(PR #6641) -
GeminiTTSServicenow picks its default model per backend:gemini-3.8-flash-lite-ttson the Gemini API, which retiresgemini-3.1-flash-tts-previewon November 17, 2026, andgemini-3.1-flash-tts-previewon Cloud Text-to-Speech, which serves no Gemini 3.8 model.
(PR #6643) -
The OpenAI usage examples in
LLMClassifier,features-classifiers.py,flows/python/utils.pyandmeasure_turn_completion.pynow namegpt-6-lunainstead ofgpt-4o-mini, which OpenAI shuts down on 2027-01-14.
(PR #6658) -
OpenAIResponsesLLMServiceno longer carries reasoning defaults foro1,o1-pro,o3-miniando4-mini, which OpenAI removed from the API on 2026-10-23.
(PR #6660) -
FishAudioTTSServicenow sendsSettings.languageas Fish Audio's BCP-47languagefield, which controls how numbers, dates, units and symbols are spelled out before synthesis. Unset, Fish Audio keeps detecting the language of each chunk.
(PR #6661) -
FishAudioTTSService's documentation no longer suggestss1, which Fish Audio retires on December 31, 2026, serving its requests withs2.1-profrom then on.
(PR #6661) -
Added
prompt_cache_keytoSmallestLLMService.Settings, Electron's key for grouping one conversation's requests so each turn reuses the prefix cache.
(PR #6662) -
AnthropicLLMServicenow sendsoutput_config.effort: "low"by default onclaude-fable-5-2, the lowest setting Anthropic documents for a model whose adaptive thinking can't be turned off.
(PR #6666) -
The
server/Dockerfilethatpipecat initgenerates now builds ondailyco/pipecat-base:latest-py3.14, so a deployed bot runs on the same Python version that uv picks for local development (the newest one the generatedpyproject.tomlallows).
(PR #6675) -
TTSServicenow resamples the audiorun_ttsyields to itssample_rate, so a TTS service can yield audio at the provider's own rate.
(PR #6676) -
AWSPollyTTSServicenow requests 8 kHz audio when the pipeline runs at 8 kHz.
(PR #6676) -
pipecat evalcaches the simulated user's voice at 24 kHz, so one cache serves every sample rate. Audio cached at another rate is regenerated once.
(PR #6676) -
Stream resamplers keep the audio they hold across pauses, instead of discarding it after 0.2 s without audio, so a pause no longer cuts a short gap into the audio. Call
reset()where one stream ends and an unrelated one starts.
(PR #6678) -
The
local-smart-turnextra no longer installstorchaudio, which pipecat doesn't use. If your own code importstorchaudio, add it to your project's dependencies.
(PR #6680) -
⚠️
audioop-ltsis no longer a core dependency on Python 3.13+, and importing pipecat no longer imports the standard library's deprecatedaudioopon Python 3.11 and 3.12. If your own code importsaudioopon Python 3.13+, addaudioop-ltsto your project's dependencies.
(PR #6681) -
Changed
DailyRESTHelper.get_token()to respectexpandis_ownerset inparamsinstead of silently overwriting them.expiry_time(default 1 hour) andowner(defaultTrue) are now only used whenparamsdoes not setexporis_owner. Callers passing noparamsget the same token as before.
(PR #6689) -
With
ExpressionGuidance.MATCH_STYLE, an LLM now laughs at a joke with a laugh sound more reliably, instead of only an amused delivery.
(PR #6721) -
A nested
!includenow resolves relative to the file that names it, not the top-level document's directory, in eval scenarios andFlowConfigalike. A nested include written against the top-level directory needs a path relative to its own file.
(PR #6738) -
The
googleextra now installsgoogle-genai3 (3.2.0 or later). Pipecat's Gemini Developer API services keep using API versionv1beta.
(PR #6741)
Deprecated
-
GenesysAudioHookSerializer.create_resumed_response()is deprecated in favor ofcreate_resume_request(), and theon_pauseevent in favor ofon_paused.create_resumed_response()built aresumedmessage, which only Genesys sends; it now returns aresumerequest.
(PR #6250) -
AssemblyAISTTService(speaker_format=...)is deprecated. Usesettings=AssemblyAISTTService.Settings(speaker_format=...)instead.
(PR #6269) -
The
diarization_max_speakerssetting ofNvidiaSTTServiceandNvidiaSegmentedSTTServiceis deprecated. Usemax_speakersinstead.
(PR #6269) -
SpeechmaticsSTTService.Settings(speaker_active_format=...)is deprecated. Usespeaker_formatinstead, with{speaker}in place of{speaker_id}.
(PR #6269) -
Deprecated
SimliVideoService(is_trinity_avatar=...). No replacement: it has no effect, since the bot's audio goes to Simli as it arrives for every face.
(PR #6400) -
Deprecated
HumeTTSService. No replacement: Hume shuts down its TTS API on November 13, 2026, after which the service can no longer synthesize speech. It will be removed in 2.0.0.
(PR #6556) -
Deprecated
sample_ratein the Twilio, Telnyx, Plivo, Exotel, Genesys and Vonage serializers'InputParams. It has no effect: incoming audio is converted toPipelineParams.audio_in_sample_rate.
(PR #6576) -
Deprecated
twilio_sample_rate,telnyx_sample_rate,plivo_sample_rate,exotel_sample_rate,genesys_sample_rateandvonage_sample_ratein the serializers'InputParams. Useaudio_in_sample_rateandaudio_out_sample_rateinstead.
(PR #6576) -
Deprecated
FrameSerializer.InputParams.resampler_clear_after_secs, with no replacement. It has no effect: the serializer resets the resampler of its outgoing audio on an interruption.
(PR #6576) -
images=on classifiers'ask(),yes_no(),choice()andscore()is deprecated. Pass the images ininputs=instead.
(PR #6594) -
RNNoiseFilter(resampler_quality=...)is deprecated and has no effect.
(PR #6625) -
SOXRAudioResamplerandSOXRStreamAudioResamplerare deprecated. UseSincAudioResamplerandSincStreamAudioResamplerinstead.
(PR #6625) -
MiniMaxHttpTTSService.Settings.text_normalizationis deprecated. Usetext_normalization_mode="basic"instead.
(PR #6655) -
Deprecated the
clear_after_secsargument ofSincStreamAudioResamplerandcreate_stream_resampler(). Useflush()orreset()at the end of each stream instead.
(PR #6678) -
ulaw_to_pcm,pcm_to_ulaw,alaw_to_pcmandpcm_to_alawinpipecat.audio.utilsare deprecated. Use the functions of the same name inpipecat.audio.g711, which are synchronous and don't resample, with a stream resampler when the rate changes.
(PR #6681) -
The
toneextra is deprecated. Useexpressivityinstead:uv add "pipecat-ai[expressivity]". Thetoneextra installs the same packages until 2.0.0.
(PR #6751)
Removed
pipecat initno longer offers Hume TTS, which stops working when Hume shuts down its TTS API on November 13, 2026.
(PR #6556)
Fixed
-
Fixed the
realtime-ultravox-textexample to useinworld-tts-2; Inworld discontinuedinworld-tts-1on 2026-06-15.
(PR #5542) -
Fixed
OpenAIRealtimeLLMServicegoing silent with thegpt-transcribeandgpt-live-transcribetranscription models. Thesession.updatedevent OpenAI sends back carries alanguagesfield thatInputAudioTranscriptionfailed to parse, which stopped the service from handling any further server events.InputAudioTranscriptionnow ignores transcription fields it doesn't model.
(PR #5547) -
Fixed
XAISTTService's docstring to listopusas an acceptedencoding.
(PR #5561) -
Fixed
GoogleSTTServicedropping the user's last utterance every time it restarts its stream at Google's four minute streaming limit. The response loop stopped on the limit before handling the response it had already received, so the final Google sends when the request stream half-closes was discarded. The loop now runs until Google closes the response stream, and the restart is unchanged.
(PR #5648) -
Fixed
expand_currencyreading an amount with a scale word as cents:"$2.5 billion"was spoken as "two dollars and fifty cents billion" and is now "two point five billion dollars".
(PR #5914) -
Fixed
expand_unitsreading "5M" and "5G" as "5 meters" and "5 grams". The single-letter unitsm,gandinnow match only in lowercase; liters matchlorL.
(PR #5955) -
Fixed
GeminiLiveLLMServiceleaving connection failures that the pipeline could not act on. A session that fails to open is now retried and reported like a dropped connection, giving up after repeated failures and a failed send now mark the service unusable, soProcessorUnusablePolicyapplies instead of the bot staying silent.
(PR #6030) -
Fixed
GeminiLiveLLMServiceleaving a bot reply open when the connection dropped mid-reply. The cut-off reply now ends withTTSStoppedFrameandLLMFullResponseEndFrame, so a laterEndFrameno longer waits 30 seconds, and anEndFramealready waiting for that reply is released instead of being discarded by the reconnect.
(PR #6030) -
Fixed
FastAPIWebsocketTransportloggingexception while closing the websocket: Cannot call "send" once a close message has been sent.at ERROR when the peer disconnected while audio was still being sent.disconnect()now skips the close when Starlette already marked the app side disconnected.
(PR #6152) -
Fixed
FunASRSTTServicereading the WAV header of each segment as audio.
(PR #6161) -
Fixed
WhisperSTTService,WhisperSTTServiceMLX,MoonshineSTTServiceandFunASRSTTServicemistranscribing audio when the input sample rate isn't 16 kHz (e.g. 8 kHz telephony).
(PR #6161) -
Fixed
TavusVideoServicenot passingBotStartedSpeakingFrameon. Processors before it in the pipeline, such as the user aggregator's user mute and user turn start strategies andUserIdleController, never saw the bot start speaking, so a user mute strategy did not mute the user while the Tavus avatar spoke.
(PR #6170) -
Fixed
FishAudioTTSServicelosing long sentences withlatency="normal". Fish returns their audio as a few large WebSocket messages, and one over thewebsocketsdefault of 1 MiB closed the connection with code 1009 (message too big). The service now accepts messages up to 16 MiB.
(PR #6217) -
Fixed
TTSServiceadding text to the assistant context when the TTS produced no audio for it (for example, a provider error, a provider that returns no audio, or a service that is no longer usable). Text from an audio context that ends without audio is now dropped with a warning.
(PR #6234) -
GenesysAudioHookSerializernow follows the AudioHook protocol for pausing. It pauses when Genesys sendspausedand resumes onresumed, dropping audio in both directions while paused, and fires the newon_pausedandon_resumedevents. Previously it waited for apausemessage that Genesys never sends and logged Genesys'spausedandresumedas unknown, so a hold went unnoticed.
(PR #6250) -
Fixed
DailyTransportSIP call transfer, SIP REFER and DTMF writingsessionIdinto the settings dict passed to them. A settings dict reused across calls no longer sends later requests to the first call's session.
(PR #6263) -
Fixed
AssemblyAISTTServicereportingUnknown message type: SpeakerRevisionerrors withspeaker_labelsenabled.
(PR #6269) -
Fixed
NvidiaSegmentedSTTServiceignoringspeaker_diarization. Speakers need a model that returns words, such asparakeet-ctc-1.1b-asr.
(PR #6269) -
Fixed
GeminiLiveLLMServiceconfiguring the session with only thesystem_instructionit was constructed with. The model now receives the full system instructionLLMServicecomposes, including the async-tool guidance, text added withappend_system_instruction(), and turn-completion instructions; the session reconnects on the first context to pick it up. As with other LLM services, when the composed instruction is all there is (nosystem_instructionof your own), it replaces asystemmessage in the context, so set the prompt onsystem_instructioninstead.
(PR #6289) -
LiveKitOutputTransportnow sends every button of a multi-digitOutputDTMFFrameorOutputDTMFUrgentFrameinstead of only the first one.
(PR #6371) -
Fixed
GeminiTTSService(Gemini API backend) playing audio at the wrong speed when the pipeline's output sample rate is not 24 kHz (e.g. 8 kHz telephony).
(PR #6380) -
Fixed
ElevenLabsTTSServiceandElevenLabsDialogueTTSServicemixing up words and word timestamps across contexts that synthesize at the same time, such as withpause_frame_processing=False. Each context now builds its words on its own clock.
(PR #6392) -
Fixed
SimliVideoServiceshowing no avatar withOpenAILiveLLMServiceand other services that stream their voice asSpeechOutputAudioRawFrame. It passed that audio through untouched, so the avatar never got any; it now animates from it as it does fromTTSAudioRawFrame, and pushes the avatar's voice as the same frame type.
(PR #6400) -
Fixed
SimliVideoServiceshowing no avatar until the bot first spoke. Its video and audio consumers waited for the bot's first audio, so Simli's idle video piled up unread and then played ahead of the answer, putting the avatar's video up to a few seconds behind its voice. Both now read from Simli as soon as it is connected: the avatar appears with Simli's idle video and stays in sync with its voice, and Simli's idle audio from before the bot first speaks is dropped.
(PR #6400) -
Fixed
WakePhraseUserTurnStartStrategyandWakeCheckFilternever matching a Chinese or Japanese wake phrase that is followed or preceded by more speech in the same transcript (e.g. "小助手今天天气怎么样"), because a word boundary was required next to characters of scripts written without spaces.
(PR #6405) -
Fixed
OpenAILiveLLMServicecutting long Chinese and Japanese context appends in the middle of a sentence: full-width。!?now count as sentence boundaries when the text is chunked.
(PR #6413) -
Fixed
strip_markdownandVoiceFormatterleaving link syntax in the spoken text when a Markdown link's URL or title contains parentheses ([Python](https://en.wikipedia.org/wiki/Python_(language))becamePython)) or its label contains brackets.
(PR #6423) -
Fixed context summarization writing each tool result into the summary transcript twice. A tool result now appears once, as its
TOOL_RESULTline.
(PR #6428) -
Fixed IPA stress placement for nasal vowels with Unicode-composed diacritics.
(PR #6438) -
Fixed
SyncParallelPipelinedropping theEndFramewhen a pipeline had output queued ahead of it.
(PR #6457) -
Fixed
ParallelPipeline, and soServiceSwitcherandLLMSwitcher, using more memory the longer a session ran.
(PR #6460) -
Fixed JSON worker-bus messages dropping explicit
Nonevalues, so settings updates sent between workers can now clear configured values.
(PR #6461) -
Fixed malformed Protobuf messages stopping WebSocket input processing. Invalid binary messages are skipped so subsequent frames can still be received.
(PR #6462) -
Fixed a
DeprecationWarningon Python 3.14+ when Pipecat Flows ran a custom action handler: it now usesinspect.iscoroutinefunctioninstead ofasyncio.iscoroutinefunction, which will be removed in Python 3.16.
(PR #6467) -
Fixed a
PipelineWorkerobserver that raised an exception in one of its callbacks receiving no more frames for the rest of the session, while every later frame was still queued for it. The exception is logged and the observer keeps receiving frames.
(PR #6470) -
Fixed
seconds_to_nanoseconds()returning one nanosecond less than the exact value for many inputs (e.g.1.001gave1000999999), which made TTS word timestamps print a microsecond early.
(PR #6472) -
Fixed
SonioxTTSServicebecoming unusable when an interruption's cancel crossed the end of its stream: Soniox'sinvalid_stream_stateanswer to that cancel is no longer reported as an error.
(PR #6480) -
Fixed memory leak in
LiveKitTransportwhenaudio_in_enabledisFalse: every subscribed participant's audio was still queued, with nothing reading it.
(PR #6484) -
Fixed WebSocket services leaving a provider connection open when their disconnect was cancelled before the connection closed, which could happen when a
CancelFramearrived during shutdown. The connection kept answering keepalive pings until the process exited, so providers that limit concurrent sessions, such as Deepgram Flux, could start refusing new connections (HTTP 429). A service that clears or replaces its connection while it is still open now aborts it, which covers every service built onWebsocketService.
(PR #6490) -
Chinese and Japanese speech can interrupt the bot under
MinWordsUserTurnStartStrategy: each character counts as a word, since those languages are written without spaces. The evalswordsmeasure uses the same count.
(PR #6499) -
Fixed
UserIdleControllertreating an async function call's intermediate result (is_final=False) as the call ending. The controller is meant to keep the idle timer off while function calls are still ongoing, since the bot's turn isn't over until the result comes back and the bot answers it. Only the final result or a cancel settles the call now.
(PR #6509) -
Fixed
SarvamTTSServiceandSarvamHttpTTSServiceignoring a voice given in a settings dict underspeaker, Sarvam's name for it, or undervoice_idforSarvamTTSService, as inTTSUpdateSettingsFrame(settings={"speaker": "priya"}). The model's default speaker (shubhon bulbul:v3) was used instead. Both services now readspeakerandvoice_idasvoice, andtarget_language_codeaslanguage.
(PR #6512) -
Fixed
SmallWebRTCTransportaudio going silent after arestart_pcwhen the bot was writing audio during the restart.
(PR #6516) -
Fixed
FrameSerializer.should_ignore_frameraisingAttributeErrorwhen anOutputTransportMessageFrameorOutputTransportMessageUrgentFramecarries amessagethat isn't a dict.messageis typedAny, but the RTVI label lookup assumed a dict, so the frame failed before reachingserialize(). Since it is a base-class method, every serializer inherited the failure.
(PR #6521) -
Fixed
DeepgramFluxSTTServiceignoring theWebsocketServicearguments it accepts (reconnect_backoff_min_wait,reconnect_backoff_max_wait,reconnect_on_error,ws_close_timeoutandws_send_timeout): it always used their defaults.
(PR #6527) -
Fixed
LocalFileStoragedeleting files it did not save. Trimming tomax_filesnow only counts and removes uploads, so other files in the uploads folder are left alone.
(PR #6532) -
Fixed
IdleFrameProcessorleaving its input and process tasks running after the pipeline ends, which was reported as dangling tasks.
(PR #6533) -
Fixed
AnthropicLLMServicespeaking Claude Haiku 5.5's reasoning before a tool call when neitherthinkingnoreffortis set. Haiku 5.5 now getseffort="low"by default instead ofthinking: disabled, which adds about 0.1 s to a turn with a clear answer and about 0.6 s to a turn where the model has to decide what to do.
(PR #6535) -
Fixed
OpenClawGatewayClientignoring theWebsocketServicearguments passed to it (reconnect_backoff_min_wait,reconnect_backoff_max_wait,ws_close_timeoutandws_send_timeout): it always used their defaults.
(PR #6536) -
Fixed
SonioxSTTServicenever pushing a final transcript for speech the local VAD missed, such as a short, quiet reply, which could leave the user turn open with no transcript. With the defaultvad_force_turn_endpoint=True, Soniox endpoint detection now stays on: a VAD stop still finalizes early, and the endpoint ends the transcript when the VAD misses the speech. Pipecat's user turn strategies still decide when the turn ends.
(PR #6537) -
Fixed
AssemblyAISTTServicereconnecting after its pipeline ended when the connection was down at shutdown (the first connect failed, the connection dropped, or a reconnect was in progress). It could open an AssemblyAI session that nothing used or closed, or keep reporting connection errors after the call. Ending the pipeline now stops a pending reconnect.
(PR #6538) -
Fixed
FrameLoggerlogging no frames at all whenignored_frame_typesis empty. It now logs every frame in that case.
(PR #6542) -
Fixed an event handler that removes itself while its event runs causing the next handler for that event to be skipped. Handlers added or removed during an event now take effect from the next event.
(PR #6543) -
Fixed
WakePhraseUserTurnStartStrategynever matching a wake phrase that contains punctuation, such as "let's talk" or "hey wall-e". Phrases now have their punctuation stripped like the transcript.
(PR #6544) -
Fixed
IVRProcessorcarrying the text of an interrupted response, including a half-streamed tag, into the next response. Its text aggregator is now reset on interruption.
(PR #6545) -
Fixed
StatelessTextTransformerreplacing each text frame with a plainTextFramepushed downstream. It now updates the frame's text in place, so the frame keeps its type (e.g.LLMTextFrame,TranscriptionFrame), its fields and its direction.
(PR #6549) -
Fixed
SentenceAggregatorkeeping a partial sentence across an interruption, which glued the cut-off text onto the start of the next reply. It now clears the partial sentence onInterruptionFrame.
(PR #6550) -
Fixed
EagerUserTurnStopStrategyleaving its speculation timer running aftercleanup(), which could withdraw a speculation after the session had ended.
(PR #6551) -
Fixed
RTVIObserversending the untransformed text inbot-outputprogress messages when a progress-aware bot output transform returned an empty string, such as after stripping a stage direction.
(PR #6552) -
Fixed direct functions describing a
typing.Anyparameter, orAnynested in a type such asdict[str, Any], as an empty object in the function schema, which told the model the value must be an object.
(PR #6558) -
Fixed
AzureVoiceLiveLLMServiceleaving the cached input tokens and the input and output audio tokens out of its LLM usage metrics.
(PR #6559) -
Fixed
JSONMessageSerializersending string enums such asKeypadEntryandLanguageas plain strings, so DTMF frames received over a Redis or PGMQ bus failed onbutton.value.
(PR #6560) -
Fixed
BaseOpenAILLMServicesubclasses (such asOpenAILLMServiceandAzureLLMService) andOpenAIResponsesHttpLLMServicemarking themselves unusable when a content filter rejects a request (an HTTP 400 withcode: content_filter). The rejection is about that request's content, so the service stays usable for the next one. Every other 400 is still treated as permanent.
(PR #6566) -
Fixed a reading of how the user sounded changing the turn completion marker of an LLM that filters incomplete turns in expressive conversation, such as ○ instead of ◐ when a hesitant user trailed off, which made the bot wait longer to prompt them.
(PR #6567) -
Fixed an LLM in expressive conversation, such as Claude, sometimes starting its reply with a reading of how the user sounded, which a bot that doesn't filter incomplete turns would speak.
(PR #6567) -
Fixed sentence aggregation sending numbered-list markers to TTS on their own:
1. Take a walk.was split into1.andTake a walk., giving each list item an extra TTS request. List items now stay whole, including when the TTS service streams LLM tokens.
(PR #6568) -
Updated
sentencexto 1.0.34, which fixes a crash in sentence aggregation when a one-letter word is followed by a non-breaking space (or other non-ASCII whitespace) and a period. The crash raisedpyo3_runtime.PanicException, whichexcept Exceptiondoes not catch. The update also stops French, German, Spanish, Italian and Portuguese text from splitting after title abbreviations such asM.inM. Dupont.
(PR #6568) -
Fixed
WhisperSTTServiceMLXnever filtering hallucinated segments: its compression-ratio check compared a computed value for equality against a fixed one, so it could not match.
(PR #6575) -
Fixed the telephony serializers sending the end of an interrupted reply at the start of the next one when audio keeps flowing, such as with a background sound mixer. They now discard the audio held in their output resampler on an interruption.
(PR #6576) -
Fixed
SentryMetricsnever sending a TTFB transaction to Sentry whenreport_only_initial_ttfbis enabled.
(PR #6579) -
Fixed eager end of turn answering a turn held open across several transcripts (for example by
FilterIncompleteUserTurnStrategies) with the earlier transcripts repeated and run together, as in "Hold on a second.Okay. I'm ready." after "Hold on a second." was already in the context. The speculative user message now holds only what the context doesn't hold yet: transcripts not yet written, joined with spaces, followed by the predicted text.
(PR #6584) -
Fixed
SyncParallelPipelinepushing system frames, such as input audio, a second time when its pipelines passed them on.
(PR #6596) -
Fixed bot audio leaving the telephony serializers in uneven bursts when the pipeline's output sample rate differs from the provider's, which some providers play back choppy.
(PR #6598) -
Fixed eval recordings losing the end of a track that had to be resampled to the recording's rate.
(PR #6598) -
Fixed
strip_markdownrewriting Markdown-like text inside inline code. Text between matching single or double backticks is kept as written, including literal backticks inside the span, so`__init__`is read as__init__rather thaninit, and`*args`and`# comment`keep their symbols.
(PR #6599) -
Fixed a function call that returns a falsy result such as
{},[]or0not running the LLM and recording"COMPLETED"instead of the value.
(PR #6603) -
Fixed RTVI
llm-function-call-stoppedmessages sending a falsy function call result such as{},[]or0asnull.
(PR #6605) -
Pipecat now reads and writes its own text files as UTF-8 on every platform, so Windows no longer falls back to the system's ANSI code page: the
pipecat evalworker's config and result files, thepipecat eval suiteresults file, thepipecat eval judgeoutput, and the Google STTcredentials_pathfile. Existing files read the same, since their contents are ASCII.
(PR #6616) -
A currency amount followed by a scale word is read without the trailing zeros of its fraction:
$2.50 millionreads "two point five million dollars" and$1.0 millionreads "one million dollars". A currency code written directly before the symbol stays a separate word:US$5reads "US five dollars" instead of "USfive dollars".
(PR #6618) -
A percentage written with a thousand separator is read as one number:
1,500%reads "one thousand, five hundred percent" instead of "1,five hundred percent".
(PR #6619) -
Fixed an action handler that is an object with an async
__call__, or a sync wrapper that returns a coroutine, being called and its coroutine left unawaited, so the action was logged as executed without running.
(PR #6621) -
Blank wake phrases no longer activate the bot in
WakeCheckFilterorWakePhraseUserTurnStartStrategy.
(PR #6637) -
MoonshineSTTServicenow decodes Arabic, Chinese, Japanese, Korean and Ukrainian with the raisedmax_tokens_per_secondMoonshine documents for those languages, so long utterances are no longer truncated mid-sentence.
(PR #6639) -
Fixed the WebSocket (server, FastAPI, client) and Tavus transports playing stereo audio at half speed.
(PR #6651) -
Fixed
MistralLLMServicefailing every completion whenSettings.seedwas set. Mistral'srandom_seednow travels in the request'sextra_body, which the OpenAI client accepts, instead of as a keyword argument it rejects.
(PR #6656) -
Fixed
uv syncfailing in projects created bypipecat initwhen Python 3.15 is the newest Python installed.onnxruntimepublishes no 3.15 wheels, so the generatedpyproject.tomlnow setsrequires-python = ">=3.11,<3.15"and uv chooses the newest supported Python.
(PR #6674) -
Fixed short gaps in the middle of TTS speech, and clipped endings, when the TTS service produces audio at a different sample rate than the pipeline's.
(PR #6676) -
Fixed
SimliVideoServicestarting a reply with the end of the one that was interrupted.
(PR #6677) -
Fixed the HeyGen and Tavus avatars dropping the last few milliseconds of each utterance when their audio is resampled.
(PR #6677) -
Fixed
HeyGenVideoServicecutting short gaps into the avatar's speech about once a second during long replies.
(PR #6677) -
Fixed
GenesysAudioHookSerializerstarting resumed audio with a few milliseconds of bot audio from before a short pause.
(PR #6678) -
Fixed
RimeSTTServicestarting a segment with the end of the previous one when they were less than 0.2 s apart.
(PR #6678) -
Fixed
AWSNovaSonicLLMServicesending the user's audio at the pipeline's input rate instead of its declaredinput_sample_rate.
(PR #6679) -
Fixed
AWSTranscribeSTTServicesending audio at the wrong rate when the pipeline's input rate isn't 8000 or 16000 Hz. It's now resampled to 16000 Hz.
(PR #6679) -
Preserve literal link and image markup inside inline code in
StripMarkdown.
(PR #6682) -
Fixed streaming speech-to-text services sending audio at the pipeline's input rate when constructed with a different
sample_rate. It's now resampled to that rate.
(PR #6684) -
Fixed
ElevenLabsRealtimeSTTServicesending audio at the pipeline's input rate while declaring 16 kHz when ElevenLabs doesn't take that rate. It's now resampled to 16 kHz.
(PR #6684) -
Fixed importing
pipecat.services.tts_serviceemitting aDeprecationWarningforAudioContextTTSServiceeven when the deprecated classes are not used.
(PR #6688) -
Fixed
DailyRESTHelper.get_token()sendingeject_at_token_exp: falseon every token. Daily treats any token-level eject setting, evenfalse, as an override of the room'seject_at_room_exp, so rooms set to eject at expiry never ejected these participants. The argument now defaults toNoneand is left out of the request unless you set it, or set it inparams. PassTrueorFalseto override the room setting.
(PR #6689) -
SUMMARY_TOKEN_BUFFERnow drives the summarization buffer instead of a repeated0.8literal, so changing the constant has an effect.
(PR #6690) -
LLMAssistantAggregatorno longer removes ●, ◐ and ○ from the assistant transcript when turn completion is off.
(PR #6696) -
Fixed
ElevenLabsTTSServicenot applying anapply_text_normalizationchange fromTTSUpdateSettingsFrameuntil its next reconnect. The change now reconnects right away.
(PR #6707) -
Fixed
AudioBufferProcessorrecordings playing a few milliseconds of earlier audio again when a bot reply starts or the user is unmuted.
(PR #6710) -
The
funasrextra now installstorchandkaldi-native-fbank, whichFunASRSTTServiceneeds to transcribe, and requiresfunasr>=1.4.5.
(PR #6711) -
Fixed
pipecat evalsometimes reporting a cancelled function call'sfunction_call_stoppedahead of thefunction_callthe bot sent before it, which failed scenarios that expect the cancel tool first.
(PR #6712) -
Fixed
normalize_datesreading the year as a cardinal quantity ("one thousand, nine hundred and ninety-nine"); it now reads it as a year ("nineteen ninety-nine").
(PR #6715) -
Fixed
expand_currencyreading an abbreviated scale wrongly:$2.5mread "two dollars and fifty centsm" and$5mbecame "$5 meters"; they now read "two point five million dollars" and "five million dollars" (k,m/mn,b/bn,t/tn).
(PR #6716) -
Fixed
pipecat evalblaming the bot when one of the harness's own services failed during a scripted run: a user voice or bot transcription error was reported as atimeoutor missing function call after the turn's full budget. The turn now fails at once with anerrorfailure carrying the service's error.
(PR #6718) -
Fixed
RTVIProcessorraisingAttributeErroron an inbound transport message that isn't a dict (for example a JSON array or string a client sent). Such messages are now ignored like any other non-RTVI message.
(PR #6720) -
Required simulation measurements fail with an error when no value is available.
(PR #6723)
Performance
-
ExternalUserTurnStopStrategyends the user's turn as soon as a finalized transcription arrives after the stop signal, instead of waiting itstimeoutfor more text. With Deepgram Flux, whose end-of-turn transcription is finalized, this saves up to 0.5 seconds when the transcription reaches the user aggregator after Flux's stop proposal.
(PR #6541) -
XTTSServicestarts playing sooner: it streams audio as it arrives instead of in one-second blocks.
(PR #6676)