Full Code of pipecat-ai/pipecat for AI

main 6806891f0613
1335 files
10.6 MB
2.8M tokens
Copy disabled (too large)
Showing preview only (11,316K chars total). The displayed content is truncated. Use the JSON API for full output.
Repository: pipecat-ai/pipecat
Branch: main
Commit: 6806891f0613
Files: 1335
Total size: 10.6 MB

Directory structure:
gitextract_fjd7zain/

├── .claude/
│   ├── settings.json
│   └── skills/
│       ├── changelog/
│       │   └── SKILL.md
│       ├── cleanup/
│       │   └── SKILL.md
│       ├── code-review/
│       │   └── SKILL.md
│       ├── docstring/
│       │   └── SKILL.md
│       ├── pr-description/
│       │   └── SKILL.md
│       ├── pr-submit/
│       │   └── SKILL.md
│       ├── squash-commits/
│       │   └── SKILL.md
│       └── update-docs/
│           ├── SKILL.md
│           └── SOURCE_DOC_MAPPING.md
├── .claude-plugin/
│   └── marketplace.json
├── .github/
│   ├── ISSUE_TEMPLATE/
│   │   ├── 1-bug_report.yml
│   │   ├── 2-question.yml
│   │   ├── 3-feature_request.yml
│   │   ├── 4-service-issue.yml
│   │   ├── 5-new-service.yml
│   │   ├── 6-dependency.yml
│   │   ├── 7-troubleshooting.yml
│   │   └── config.yml
│   ├── PULL_REQUEST_TEMPLATE.md
│   └── workflows/
│       ├── build.yaml
│       ├── coverage.yaml
│       ├── format.yaml
│       ├── generate-changelog.yml
│       ├── publish.yaml
│       ├── publish_test.yaml
│       ├── python-compatibility.yaml
│       ├── tests.yaml
│       └── update-docs.yml
├── .gitignore
├── .pre-commit-config.yaml
├── .readthedocs.yaml
├── AGENTS.md
├── CHANGELOG.md
├── CLAUDE.md
├── COMMUNITY_INTEGRATIONS.md
├── CONTRIBUTING.md
├── LICENSE
├── MANIFEST.in
├── README.md
├── SECURITY.md
├── changelog/
│   ├── 4483.fixed.md
│   ├── 4519.fixed.md
│   ├── 4533.added.2.md
│   ├── 4533.added.3.md
│   ├── 4533.added.4.md
│   ├── 4533.added.5.md
│   ├── 4533.added.md
│   ├── 4533.changed.2.md
│   ├── 4533.changed.3.md
│   ├── 4533.changed.md
│   ├── 4533.fixed.2.md
│   ├── 4533.fixed.3.md
│   ├── 4533.fixed.4.md
│   ├── 4533.fixed.5.md
│   ├── 4533.fixed.md
│   ├── 4535.changed.md
│   ├── 4549.added.md
│   ├── 4578.fixed.md
│   ├── 4588.added.md
│   ├── 4588.changed.md
│   ├── 4588.deprecated.md
│   ├── 4592.changed.md
│   ├── 4593.added.md
│   ├── 4597.added.md
│   ├── 4597.fixed.md
│   ├── 4599.added.md
│   ├── 4599.fixed.md
│   ├── 4612.added.md
│   ├── 4620.added.md
│   ├── 4620.changed.md
│   ├── 4622.added.md
│   ├── 4622.deprecated.md
│   ├── 4622.fixed.md
│   ├── 4626.changed.md
│   ├── 4626.deprecated.md
│   ├── 4631.added.2.md
│   ├── 4631.added.md
│   ├── 4632.changed.2.md
│   ├── 4632.changed.md
│   ├── 4634.changed.md
│   ├── 4635.fixed.md
│   ├── 4636.added.md
│   ├── 4639.fixed.md
│   ├── 4642.changed.md
│   ├── 4642.deprecated.md
│   ├── 4643.changed.md
│   ├── 4644.fixed.md
│   ├── 4650.fixed.md
│   ├── 4653.fixed.md
│   ├── 4654.added.2.md
│   ├── 4654.added.3.md
│   ├── 4654.added.md
│   ├── 4655.added.2.md
│   ├── 4655.added.3.md
│   ├── 4655.added.md
│   ├── 4656.fixed.md
│   ├── 4658.changed.md
│   ├── 4660.security.md
│   ├── 4664.added.md
│   ├── 4665.fixed.md
│   ├── 4667.fixed.md
│   ├── 4671.changed.md
│   ├── 4671.deprecated.md
│   ├── 4674.added.md
│   ├── 4682.added.md
│   ├── 4683.added.md
│   ├── 4684.changed.md
│   ├── 4684.fixed.md
│   ├── 4685.changed.md
│   ├── 4686.added.md
│   ├── 4687.fixed.md
│   ├── 4688.fixed.md
│   ├── 4690.changed.md
│   ├── 4691.fixed.md
│   ├── 4692.changed.md
│   ├── 4703.fixed.md
│   ├── 4704.security.md
│   ├── 4705.changed.md
│   ├── 4705.deprecated.md
│   ├── 4709.added.md
│   ├── 4709.changed.md
│   ├── 4709.fixed.2.md
│   ├── 4709.fixed.md
│   ├── 4710.added.md
│   ├── 4714.fixed.md
│   ├── 4715.added.md
│   ├── 4715.fixed.md
│   ├── 4726.changed.2.md
│   ├── 4726.changed.md
│   └── _template.md.j2
├── codecov.yml
├── docs/
│   └── api/
│       ├── Makefile
│       ├── README.md
│       ├── build-docs.sh
│       ├── conf.py
│       ├── index.rst
│       ├── make.bat
│       └── rtd-test.sh
├── env.example
├── examples/
│   ├── README.md
│   ├── assets/
│   │   └── rag-content.txt
│   ├── audio/
│   │   ├── audio-bot-background-sound.py
│   │   ├── audio-recording.py
│   │   └── audio-sound-effects.py
│   ├── context-summarization/
│   │   ├── context-summarization-dedicated-llm.py
│   │   ├── context-summarization-google.py
│   │   ├── context-summarization-manual-openai.py
│   │   └── context-summarization-openai.py
│   ├── features/
│   │   ├── features-add-tool-change-messages.py
│   │   ├── features-app-resources.py
│   │   ├── features-before-and-after-events.py
│   │   ├── features-concurrent-llm-evaluation.py
│   │   ├── features-concurrent-llm-rtvi-ignored-sources.py
│   │   ├── features-custom-frame-processor.py
│   │   ├── features-gpu-container-local-bot.py
│   │   ├── features-live-translation.py
│   │   ├── features-pattern-pair-voice-switching.py
│   │   ├── features-service-switcher.py
│   │   ├── features-switch-languages.py
│   │   ├── features-switch-voices.py
│   │   ├── features-user-email-gathering.py
│   │   ├── features-voicemail-detection.py
│   │   └── features-wake-phrase.py
│   ├── function-calling/
│   │   ├── function-calling-anthropic-async-stream.py
│   │   ├── function-calling-anthropic-async.py
│   │   ├── function-calling-anthropic-video.py
│   │   ├── function-calling-anthropic.py
│   │   ├── function-calling-aws-video.py
│   │   ├── function-calling-aws.py
│   │   ├── function-calling-azure.py
│   │   ├── function-calling-cerebras.py
│   │   ├── function-calling-deepseek.py
│   │   ├── function-calling-direct.py
│   │   ├── function-calling-fireworks.py
│   │   ├── function-calling-google-async-stream.py
│   │   ├── function-calling-google-async.py
│   │   ├── function-calling-google-vertex.py
│   │   ├── function-calling-google-video.py
│   │   ├── function-calling-google.py
│   │   ├── function-calling-grok.py
│   │   ├── function-calling-groq.py
│   │   ├── function-calling-inception.py
│   │   ├── function-calling-missing-handler.py
│   │   ├── function-calling-mistral.py
│   │   ├── function-calling-moondream-video.py
│   │   ├── function-calling-nebius.py
│   │   ├── function-calling-novita.py
│   │   ├── function-calling-nvidia.py
│   │   ├── function-calling-ollama.py
│   │   ├── function-calling-openai-async-stream.py
│   │   ├── function-calling-openai-async.py
│   │   ├── function-calling-openai-responses-async-stream.py
│   │   ├── function-calling-openai-responses-async.py
│   │   ├── function-calling-openai-responses-http.py
│   │   ├── function-calling-openai-responses-video-http.py
│   │   ├── function-calling-openai-responses-video.py
│   │   ├── function-calling-openai-responses.py
│   │   ├── function-calling-openai-video.py
│   │   ├── function-calling-openai.py
│   │   ├── function-calling-openrouter.py
│   │   ├── function-calling-perplexity.py
│   │   ├── function-calling-qwen.py
│   │   ├── function-calling-sambanova.py
│   │   ├── function-calling-sarvam.py
│   │   ├── function-calling-schema-handler.py
│   │   └── function-calling-together.py
│   ├── getting-started/
│   │   ├── 01-say-one-thing.py
│   │   ├── 01a-local-audio.py
│   │   ├── 02-llm-say-one-thing.py
│   │   ├── 03-still-frame.py
│   │   ├── 03a-local-still-frame.py
│   │   ├── 04-sync-speech-and-image.py
│   │   ├── 05-speaking-state.py
│   │   ├── 06-voice-agent.py
│   │   ├── 06a-voice-agent-local.py
│   │   └── 07-function-calling.py
│   ├── mcp/
│   │   ├── mcp-multiple-mcp.py
│   │   ├── mcp-stdio.py
│   │   ├── mcp-streamable-http-gemini-live.py
│   │   └── mcp-streamable-http.py
│   ├── multi-worker/
│   │   ├── README.md
│   │   ├── code-assistant/
│   │   │   ├── README.md
│   │   │   ├── code-assistant.py
│   │   │   └── code_worker.py
│   │   ├── distributed-handoff/
│   │   │   ├── pgmq-handoff/
│   │   │   │   ├── README.md
│   │   │   │   ├── llm.py
│   │   │   │   └── main.py
│   │   │   └── redis-handoff/
│   │   │       ├── README.md
│   │   │       ├── llm.py
│   │   │       └── main.py
│   │   ├── env.example
│   │   ├── local-handoff/
│   │   │   ├── README.md
│   │   │   ├── local-handoff-two-agents-tts.py
│   │   │   └── local-handoff-two-agents.py
│   │   ├── parallel-debate/
│   │   │   ├── README.md
│   │   │   └── parallel-debate.py
│   │   ├── remote-proxy-assistant/
│   │   │   ├── README.md
│   │   │   ├── assistant.py
│   │   │   └── main.py
│   │   ├── sensor-controller/
│   │   │   ├── README.md
│   │   │   ├── sensor-controller.py
│   │   │   └── sensor.py
│   │   └── ui-worker/
│   │       ├── async-tasks/
│   │       │   ├── README.md
│   │       │   ├── bot.py
│   │       │   └── client/
│   │       │       ├── index.html
│   │       │       ├── main.js
│   │       │       ├── package.json
│   │       │       ├── styles.css
│   │       │       └── vite.config.js
│   │       ├── deixis/
│   │       │   ├── README.md
│   │       │   ├── bot.py
│   │       │   └── client/
│   │       │       ├── index.html
│   │       │       ├── main.js
│   │       │       ├── package.json
│   │       │       ├── styles.css
│   │       │       └── vite.config.js
│   │       ├── document-review/
│   │       │   ├── README.md
│   │       │   ├── bot.py
│   │       │   └── client/
│   │       │       ├── index.html
│   │       │       ├── main.js
│   │       │       ├── package.json
│   │       │       ├── styles.css
│   │       │       └── vite.config.js
│   │       ├── form-fill/
│   │       │   ├── README.md
│   │       │   ├── bot.py
│   │       │   └── client/
│   │       │       ├── index.html
│   │       │       ├── main.js
│   │       │       ├── package.json
│   │       │       ├── styles.css
│   │       │       └── vite.config.js
│   │       ├── hello-snapshot/
│   │       │   ├── README.md
│   │       │   ├── bot.py
│   │       │   └── client/
│   │       │       ├── index.html
│   │       │       ├── main.js
│   │       │       ├── package.json
│   │       │       ├── styles.css
│   │       │       └── vite.config.js
│   │       └── shopping-list/
│   │           ├── README.md
│   │           ├── bot.py
│   │           └── client/
│   │               ├── index.html
│   │               ├── main.js
│   │               ├── package.json
│   │               ├── styles.css
│   │               └── vite.config.js
│   ├── observability/
│   │   ├── observability-heartbeats.py
│   │   ├── observability-observer.py
│   │   └── observability-sentry-metrics.py
│   ├── persistent-context/
│   │   ├── persistent-context-anthropic.py
│   │   ├── persistent-context-aws-nova-sonic.py
│   │   ├── persistent-context-gemini.py
│   │   ├── persistent-context-grok-realtime.py
│   │   ├── persistent-context-openai-realtime.py
│   │   ├── persistent-context-openai-responses-http.py
│   │   ├── persistent-context-openai-responses.py
│   │   └── persistent-context-openai.py
│   ├── rag/
│   │   ├── rag-gemini-grounding-metadata.py
│   │   ├── rag-gemini.py
│   │   └── rag-mem0.py
│   ├── realtime/
│   │   ├── realtime-aws-nova-sonic-async-tool.py
│   │   ├── realtime-aws-nova-sonic.py
│   │   ├── realtime-azure-async-tool.py
│   │   ├── realtime-azure.py
│   │   ├── realtime-gemini-live-async-tool.py
│   │   ├── realtime-gemini-live-files-api.py
│   │   ├── realtime-gemini-live-google-search.py
│   │   ├── realtime-gemini-live-graceful-end.py
│   │   ├── realtime-gemini-live-grounding-metadata.py
│   │   ├── realtime-gemini-live-locally-driven-turns.py
│   │   ├── realtime-gemini-live-vertex.py
│   │   ├── realtime-gemini-live-video.py
│   │   ├── realtime-gemini-live.py
│   │   ├── realtime-grok-async-tool.py
│   │   ├── realtime-grok-locally-driven-turns.py
│   │   ├── realtime-grok.py
│   │   ├── realtime-inworld-locally-driven-turns.py
│   │   ├── realtime-inworld.py
│   │   ├── realtime-openai-async-tool.py
│   │   ├── realtime-openai-live-video.py
│   │   ├── realtime-openai-locally-driven-turns.py
│   │   ├── realtime-openai-text.py
│   │   ├── realtime-openai.py
│   │   ├── realtime-ultravox-async-tool.py
│   │   ├── realtime-ultravox-text.py
│   │   └── realtime-ultravox.py
│   ├── thinking/
│   │   ├── thinking-anthropic.py
│   │   ├── thinking-functions-anthropic.py
│   │   ├── thinking-functions-google.py
│   │   └── thinking-google.py
│   ├── transcription/
│   │   ├── transcription-assemblyai.py
│   │   ├── transcription-azure.py
│   │   ├── transcription-cartesia-turns.py
│   │   ├── transcription-cartesia.py
│   │   ├── transcription-deepgram-flux.py
│   │   ├── transcription-deepgram.py
│   │   ├── transcription-elevenlabs.py
│   │   ├── transcription-gladia-translation.py
│   │   ├── transcription-gladia.py
│   │   ├── transcription-google-llm.py
│   │   ├── transcription-gradium.py
│   │   ├── transcription-mistral.py
│   │   ├── transcription-openai.py
│   │   ├── transcription-soniox.py
│   │   ├── transcription-speechmatics.py
│   │   ├── transcription-whisper-local.py
│   │   ├── transcription-whisper-mlx.py
│   │   ├── transcription-whisper.py
│   │   └── transcription-xai.py
│   ├── transports/
│   │   ├── transports-daily.py
│   │   ├── transports-livekit.py
│   │   ├── transports-small-webrtc.py
│   │   └── transports-vonage.py
│   ├── turn-management/
│   │   ├── turn-management-detect-user-idle.py
│   │   ├── turn-management-filter-incomplete-turns-function-calling.py
│   │   ├── turn-management-filter-incomplete-turns.py
│   │   ├── turn-management-interruption-config.py
│   │   ├── turn-management-smart-turn-local-coreml.py
│   │   ├── turn-management-smart-turn-local.py
│   │   ├── turn-management-turn-tracking-observer.py
│   │   ├── turn-management-user-assistant-turns.py
│   │   └── turn-management-user-mute-strategy.py
│   ├── update-settings/
│   │   ├── llm/
│   │   │   ├── llm-anthropic.py
│   │   │   ├── llm-aws-bedrock.py
│   │   │   ├── llm-aws-nova-sonic.py
│   │   │   ├── llm-azure-realtime.py
│   │   │   ├── llm-azure.py
│   │   │   ├── llm-cerebras.py
│   │   │   ├── llm-deepseek.py
│   │   │   ├── llm-fireworks.py
│   │   │   ├── llm-gemini-live-vertex.py
│   │   │   ├── llm-gemini-live.py
│   │   │   ├── llm-google-vertex.py
│   │   │   ├── llm-google.py
│   │   │   ├── llm-grok-realtime.py
│   │   │   ├── llm-grok.py
│   │   │   ├── llm-groq.py
│   │   │   ├── llm-mistral.py
│   │   │   ├── llm-nvidia.py
│   │   │   ├── llm-ollama.py
│   │   │   ├── llm-openai-realtime.py
│   │   │   ├── llm-openai-responses-http.py
│   │   │   ├── llm-openai-responses.py
│   │   │   ├── llm-openai.py
│   │   │   ├── llm-openrouter.py
│   │   │   ├── llm-perplexity.py
│   │   │   ├── llm-qwen.py
│   │   │   ├── llm-sambanova.py
│   │   │   ├── llm-sarvam.py
│   │   │   ├── llm-together.py
│   │   │   └── llm-ultravox-realtime.py
│   │   ├── stt/
│   │   │   ├── stt-assemblyai.py
│   │   │   ├── stt-aws-transcribe.py
│   │   │   ├── stt-azure.py
│   │   │   ├── stt-cartesia.py
│   │   │   ├── stt-deepgram-flux.py
│   │   │   ├── stt-deepgram-sagemaker.py
│   │   │   ├── stt-deepgram.py
│   │   │   ├── stt-elevenlabs-realtime.py
│   │   │   ├── stt-elevenlabs.py
│   │   │   ├── stt-fal.py
│   │   │   ├── stt-gladia.py
│   │   │   ├── stt-google.py
│   │   │   ├── stt-gradium.py
│   │   │   ├── stt-groq.py
│   │   │   ├── stt-nvidia-segmented.py
│   │   │   ├── stt-nvidia.py
│   │   │   ├── stt-openai-realtime.py
│   │   │   ├── stt-sarvam.py
│   │   │   ├── stt-soniox.py
│   │   │   ├── stt-speechmatics.py
│   │   │   ├── stt-whisper-api.py
│   │   │   ├── stt-whisper-mlx.py
│   │   │   └── stt-whisper.py
│   │   └── tts/
│   │       ├── tts-asyncai-http.py
│   │       ├── tts-asyncai.py
│   │       ├── tts-aws-polly.py
│   │       ├── tts-azure-http.py
│   │       ├── tts-azure.py
│   │       ├── tts-camb.py
│   │       ├── tts-cartesia-http.py
│   │       ├── tts-cartesia.py
│   │       ├── tts-deepgram-http.py
│   │       ├── tts-deepgram-sagemaker.py
│   │       ├── tts-deepgram.py
│   │       ├── tts-elevenlabs-http.py
│   │       ├── tts-elevenlabs.py
│   │       ├── tts-fish.py
│   │       ├── tts-gemini.py
│   │       ├── tts-google-http.py
│   │       ├── tts-google-stream.py
│   │       ├── tts-gradium.py
│   │       ├── tts-groq.py
│   │       ├── tts-hume.py
│   │       ├── tts-inworld-http.py
│   │       ├── tts-inworld.py
│   │       ├── tts-kokoro.py
│   │       ├── tts-lmnt.py
│   │       ├── tts-minimax.py
│   │       ├── tts-neuphonic-http.py
│   │       ├── tts-neuphonic.py
│   │       ├── tts-nvidia.py
│   │       ├── tts-openai.py
│   │       ├── tts-piper-http.py
│   │       ├── tts-piper.py
│   │       ├── tts-resembleai.py
│   │       ├── tts-rime-http.py
│   │       ├── tts-rime.py
│   │       ├── tts-sarvam-http.py
│   │       ├── tts-sarvam.py
│   │       ├── tts-speechmatics.py
│   │       └── tts-xtts.py
│   ├── video-avatar/
│   │   ├── video-avatar-heygen-transport.py
│   │   ├── video-avatar-heygen-video-service.py
│   │   ├── video-avatar-lemonslice-transport.py
│   │   ├── video-avatar-simli-video-service.py
│   │   ├── video-avatar-tavus-transport.py
│   │   └── video-avatar-tavus-video-service.py
│   ├── video-processing/
│   │   ├── video-processing-custom-video-track.py
│   │   ├── video-processing-gstreamer-filesrc.py
│   │   ├── video-processing-gstreamer-videotestsrc.py
│   │   ├── video-processing-local-mirror.py
│   │   ├── video-processing-mirror.py
│   │   └── video-processing.py
│   ├── vision/
│   │   ├── vision-anthropic.py
│   │   ├── vision-aws.py
│   │   ├── vision-gemini-flash.py
│   │   ├── vision-moondream.py
│   │   ├── vision-openai-responses-http.py
│   │   ├── vision-openai-responses.py
│   │   └── vision-openai.py
│   └── voice/
│       ├── voice-aicoustics-vad-only.py
│       ├── voice-aicoustics.py
│       ├── voice-assemblyai-turn-detection.py
│       ├── voice-assemblyai.py
│       ├── voice-asyncai-http.py
│       ├── voice-asyncai.py
│       ├── voice-aws-strands.py
│       ├── voice-aws.py
│       ├── voice-azure-http.py
│       ├── voice-azure.py
│       ├── voice-camb.py
│       ├── voice-cartesia-http.py
│       ├── voice-cartesia-turns.py
│       ├── voice-cartesia.py
│       ├── voice-deepgram-flux-sagemaker.py
│       ├── voice-deepgram-flux.py
│       ├── voice-deepgram-http.py
│       ├── voice-deepgram-sagemaker.py
│       ├── voice-deepgram.py
│       ├── voice-elevenlabs-http.py
│       ├── voice-elevenlabs.py
│       ├── voice-fal.py
│       ├── voice-fish.py
│       ├── voice-gladia-vad.py
│       ├── voice-gladia.py
│       ├── voice-google-audio-in.py
│       ├── voice-google-gemini-tts.py
│       ├── voice-google-http.py
│       ├── voice-google-image.py
│       ├── voice-google.py
│       ├── voice-gradium.py
│       ├── voice-groq.py
│       ├── voice-hume.py
│       ├── voice-inworld-http.py
│       ├── voice-inworld.py
│       ├── voice-kokoro.py
│       ├── voice-krisp-viva.py
│       ├── voice-langchain.py
│       ├── voice-lmnt.py
│       ├── voice-minimax.py
│       ├── voice-mistral.py
│       ├── voice-moonshine.py
│       ├── voice-neuphonic-http.py
│       ├── voice-neuphonic.py
│       ├── voice-nvidia-sagemaker.py
│       ├── voice-nvidia.py
│       ├── voice-openai-http.py
│       ├── voice-openai-responses-http.py
│       ├── voice-openai-responses.py
│       ├── voice-openai.py
│       ├── voice-piper.py
│       ├── voice-resemble.py
│       ├── voice-rime-http.py
│       ├── voice-rime.py
│       ├── voice-sarvam-http.py
│       ├── voice-sarvam.py
│       ├── voice-smallest.py
│       ├── voice-soniox.py
│       ├── voice-speechmatics-vad.py
│       ├── voice-speechmatics.py
│       ├── voice-xai-http.py
│       ├── voice-xai.py
│       └── voice-xtts.py
├── pyproject.toml
├── pyrightconfig.json
├── scripts/
│   ├── cli/
│   │   ├── check_registry.py
│   │   ├── configs/
│   │   │   ├── config_generator.py
│   │   │   └── update_configs.py
│   │   ├── imports/
│   │   │   ├── import_generator.py
│   │   │   └── update_imports.py
│   │   └── update_registry.py
│   ├── daily/
│   │   └── test_tavus_transport.py
│   ├── deprecations/
│   │   ├── __init__.py
│   │   ├── deprecations.json
│   │   ├── generate.py
│   │   └── scan.py
│   ├── dtmf/
│   │   └── generate_dtmf.sh
│   ├── fix-ruff-and-typecheck.sh
│   ├── krisp/
│   │   ├── audio_file_utils.py
│   │   ├── test_krisp_viva_filter_audiofile.py
│   │   └── test_krisp_viva_turn_audiofile.py
│   ├── mem-watch.sh
│   ├── release-changelog.py
│   └── release-evals/
│       ├── README.md
│       ├── manifest.yaml
│       ├── run.sh
│       └── scenarios/
│           ├── capital_question.yaml
│           ├── describe_image.yaml
│           ├── interruption_audio.yaml
│           ├── interruption_text.yaml
│           ├── item_price.yaml
│           ├── judge_audio.yaml
│           ├── judge_text.yaml
│           ├── language_switch.yaml
│           ├── multi_turn.yaml
│           ├── user_audio.yaml
│           ├── vision-cat.json
│           ├── vision_describe.yaml
│           ├── weather.yaml
│           ├── weather_and_restaurant.yaml
│           └── weather_function_call.yaml
├── src/
│   └── pipecat/
│       ├── __init__.py
│       ├── adapters/
│       │   ├── __init__.py
│       │   ├── base_llm_adapter.py
│       │   ├── schemas/
│       │   │   ├── __init__.py
│       │   │   ├── direct_function.py
│       │   │   ├── function_schema.py
│       │   │   └── tools_schema.py
│       │   └── services/
│       │       ├── __init__.py
│       │       ├── anthropic_adapter.py
│       │       ├── aws_nova_sonic_adapter.py
│       │       ├── bedrock_adapter.py
│       │       ├── gemini_adapter.py
│       │       ├── grok_realtime_adapter.py
│       │       ├── inworld_realtime_adapter.py
│       │       ├── mistral_adapter.py
│       │       ├── open_ai_adapter.py
│       │       ├── open_ai_realtime_adapter.py
│       │       ├── open_ai_responses_adapter.py
│       │       └── perplexity_adapter.py
│       ├── audio/
│       │   ├── __init__.py
│       │   ├── dtmf/
│       │   │   ├── __init__.py
│       │   │   ├── types.py
│       │   │   └── utils.py
│       │   ├── filters/
│       │   │   ├── __init__.py
│       │   │   ├── aic_filter.py
│       │   │   ├── base_audio_filter.py
│       │   │   ├── koala_filter.py
│       │   │   ├── krisp_viva_filter.py
│       │   │   └── rnnoise_filter.py
│       │   ├── krisp_instance.py
│       │   ├── mixers/
│       │   │   ├── __init__.py
│       │   │   ├── base_audio_mixer.py
│       │   │   └── soundfile_mixer.py
│       │   ├── resamplers/
│       │   │   ├── __init__.py
│       │   │   ├── base_audio_resampler.py
│       │   │   ├── resampy_resampler.py
│       │   │   ├── soxr_resampler.py
│       │   │   └── soxr_stream_resampler.py
│       │   ├── turn/
│       │   │   ├── __init__.py
│       │   │   ├── base_turn_analyzer.py
│       │   │   ├── krisp_viva_turn.py
│       │   │   └── smart_turn/
│       │   │       ├── __init__.py
│       │   │       ├── _whisper_features.py
│       │   │       ├── base_smart_turn.py
│       │   │       ├── data/
│       │   │       │   ├── __init__.py
│       │   │       │   └── smart-turn-v3.2-cpu.onnx
│       │   │       ├── http_smart_turn.py
│       │   │       ├── local_coreml_smart_turn.py
│       │   │       ├── local_smart_turn_v2.py
│       │   │       └── local_smart_turn_v3.py
│       │   ├── utils.py
│       │   └── vad/
│       │       ├── __init__.py
│       │       ├── aic_quail_vad.py
│       │       ├── aic_vad.py
│       │       ├── data/
│       │       │   ├── __init__.py
│       │       │   └── silero_vad.onnx
│       │       ├── krisp_viva_vad.py
│       │       ├── silero.py
│       │       ├── vad_analyzer.py
│       │       └── vad_controller.py
│       ├── bus/
│       │   ├── __init__.py
│       │   ├── adapters/
│       │   │   ├── __init__.py
│       │   │   ├── base.py
│       │   │   ├── llm_context_adapter.py
│       │   │   └── tools_schema_adapter.py
│       │   ├── bridge_processor.py
│       │   ├── bus.py
│       │   ├── local/
│       │   │   ├── __init__.py
│       │   │   └── async_queue.py
│       │   ├── messages.py
│       │   ├── network/
│       │   │   ├── __init__.py
│       │   │   ├── pgmq.py
│       │   │   ├── pgmq_backends.py
│       │   │   └── redis.py
│       │   ├── queue.py
│       │   ├── serializers/
│       │   │   ├── __init__.py
│       │   │   ├── base.py
│       │   │   └── json.py
│       │   ├── subscriber.py
│       │   └── ui/
│       │       ├── __init__.py
│       │       └── messages.py
│       ├── cli/
│       │   ├── __init__.py
│       │   ├── agent_templates/
│       │   │   ├── AGENTS.md
│       │   │   ├── CLAUDE.md
│       │   │   └── GETTING_STARTED.md
│       │   ├── commands/
│       │   │   ├── __init__.py
│       │   │   ├── create.py
│       │   │   ├── eval.py
│       │   │   └── init.py
│       │   ├── config_validator.py
│       │   ├── generators/
│       │   │   ├── __init__.py
│       │   │   └── project.py
│       │   ├── main.py
│       │   ├── prompts/
│       │   │   ├── __init__.py
│       │   │   └── questions.py
│       │   ├── registry/
│       │   │   ├── __init__.py
│       │   │   ├── _configs.py
│       │   │   ├── _imports.py
│       │   │   ├── service_loader.py
│       │   │   └── service_metadata.py
│       │   └── templates/
│       │       ├── README.md.jinja2
│       │       ├── _readme_blocks/
│       │       │   ├── how_it_works_daily_pstn.jinja2
│       │       │   ├── how_it_works_twilio_daily_sip.jinja2
│       │       │   ├── project_structure_daily_pstn.jinja2
│       │       │   ├── project_structure_twilio_daily_sip.jinja2
│       │       │   ├── setup_daily_pstn.jinja2
│       │       │   ├── setup_telnyx.jinja2
│       │       │   ├── setup_twilio.jinja2
│       │       │   └── setup_twilio_daily_sip.jinja2
│       │       ├── client/
│       │       │   ├── react-nextjs/
│       │       │   │   ├── .gitignore
│       │       │   │   ├── env.example
│       │       │   │   ├── eslint.config.mjs
│       │       │   │   ├── next.config.ts
│       │       │   │   ├── package.json.jinja2
│       │       │   │   ├── postcss.config.mjs
│       │       │   │   ├── src/
│       │       │   │   │   ├── app/
│       │       │   │   │   │   ├── api/
│       │       │   │   │   │   │   ├── sessions/
│       │       │   │   │   │   │   │   └── [sessionId]/
│       │       │   │   │   │   │   │       └── [...path]/
│       │       │   │   │   │   │   │           └── route.ts
│       │       │   │   │   │   │   └── start/
│       │       │   │   │   │   │       └── route.ts
│       │       │   │   │   │   ├── components/
│       │       │   │   │   │   │   ├── App.tsx
│       │       │   │   │   │   │   └── TransportSelect.tsx
│       │       │   │   │   │   ├── globals.css
│       │       │   │   │   │   ├── layout.tsx
│       │       │   │   │   │   └── page.tsx
│       │       │   │   │   └── config.ts.jinja2
│       │       │   │   └── tsconfig.json
│       │       │   ├── react-vite/
│       │       │   │   ├── .gitignore
│       │       │   │   ├── env.example
│       │       │   │   ├── eslint.config.js
│       │       │   │   ├── index.html
│       │       │   │   ├── package.json.jinja2
│       │       │   │   ├── src/
│       │       │   │   │   ├── components/
│       │       │   │   │   │   ├── App.tsx
│       │       │   │   │   │   └── TransportSelect.tsx
│       │       │   │   │   ├── config.ts.jinja2
│       │       │   │   │   ├── index.css
│       │       │   │   │   └── main.tsx
│       │       │   │   ├── tsconfig.app.json
│       │       │   │   ├── tsconfig.json
│       │       │   │   ├── tsconfig.node.json
│       │       │   │   └── vite.config.ts
│       │       │   └── vanilla-js-vite/
│       │       │       ├── env.example
│       │       │       ├── index.html
│       │       │       ├── package.json.jinja2
│       │       │       └── src/
│       │       │           ├── app.js
│       │       │           ├── config.js.jinja2
│       │       │           └── style.css
│       │       ├── gitignore.jinja2
│       │       └── server/
│       │           ├── Dockerfile.jinja2
│       │           ├── _blocks/
│       │           │   ├── bot_entry_daily_pstn.jinja2
│       │           │   ├── bot_entry_twilio_daily_sip.jinja2
│       │           │   ├── run_bot_logic_cascade.jinja2
│       │           │   └── run_bot_logic_realtime.jinja2
│       │           ├── _macros/
│       │           │   ├── event_handlers.jinja2
│       │           │   ├── helper_functions.jinja2
│       │           │   ├── pipeline_components.jinja2
│       │           │   └── transport_setup.jinja2
│       │           ├── bot_cascade.py.jinja2
│       │           ├── bot_realtime.py.jinja2
│       │           ├── env.example.jinja2
│       │           ├── evals/
│       │           │   ├── starter_audio.yaml.jinja2
│       │           │   └── starter_text.yaml.jinja2
│       │           ├── pcc-deploy.toml.jinja2
│       │           ├── pyproject.toml.jinja2
│       │           ├── server_pstn_dialout.py.jinja2
│       │           ├── server_twilio_daily_sip_dialin.py.jinja2
│       │           ├── server_twilio_daily_sip_dialout.py.jinja2
│       │           ├── server_utils_pstn_dialout.py.jinja2
│       │           ├── server_utils_twilio_daily_sip_dialin.py.jinja2
│       │           └── server_utils_twilio_daily_sip_dialout.py.jinja2
│       ├── clocks/
│       │   ├── __init__.py
│       │   ├── base_clock.py
│       │   └── system_clock.py
│       ├── evals/
│       │   ├── __init__.py
│       │   ├── __main__.py
│       │   ├── harness.py
│       │   ├── judge.py
│       │   ├── scenario.py
│       │   ├── serializer.py
│       │   ├── services.py
│       │   ├── speech.py
│       │   ├── suite.py
│       │   ├── transcribe.py
│       │   └── transport.py
│       ├── extensions/
│       │   ├── __init__.py
│       │   ├── ivr/
│       │   │   ├── __init__.py
│       │   │   └── ivr_navigator.py
│       │   └── voicemail/
│       │       ├── __init__.py
│       │       └── voicemail_detector.py
│       ├── frames/
│       │   ├── __init__.py
│       │   ├── frames.proto
│       │   ├── frames.py
│       │   └── protobufs/
│       │       └── frames_pb2.py
│       ├── metrics/
│       │   ├── __init__.py
│       │   └── metrics.py
│       ├── observers/
│       │   ├── __init__.py
│       │   ├── base_observer.py
│       │   ├── loggers/
│       │   │   ├── __init__.py
│       │   │   ├── debug_log_observer.py
│       │   │   ├── llm_log_observer.py
│       │   │   ├── metrics_log_observer.py
│       │   │   └── transcription_log_observer.py
│       │   ├── startup_timing_observer.py
│       │   ├── turn_tracking_observer.py
│       │   └── user_bot_latency_observer.py
│       ├── pipeline/
│       │   ├── __init__.py
│       │   ├── base_pipeline.py
│       │   ├── job_context.py
│       │   ├── job_decorator.py
│       │   ├── llm_switcher.py
│       │   ├── parallel_pipeline.py
│       │   ├── pipeline.py
│       │   ├── runner.py
│       │   ├── service_switcher.py
│       │   ├── sync_parallel_pipeline.py
│       │   ├── task.py
│       │   ├── worker.py
│       │   ├── worker_observer.py
│       │   └── worker_ready_decorator.py
│       ├── processors/
│       │   ├── __init__.py
│       │   ├── aggregators/
│       │   │   ├── __init__.py
│       │   │   ├── async_tool_messages.py
│       │   │   ├── dtmf_aggregator.py
│       │   │   ├── gated.py
│       │   │   ├── gated_llm_context.py
│       │   │   ├── llm_context.py
│       │   │   ├── llm_context_summarizer.py
│       │   │   ├── llm_response.py
│       │   │   ├── llm_response_universal.py
│       │   │   ├── llm_text_processor.py
│       │   │   └── sentence.py
│       │   ├── async_generator.py
│       │   ├── audio/
│       │   │   ├── __init__.py
│       │   │   ├── audio_buffer_processor.py
│       │   │   └── vad_processor.py
│       │   ├── consumer_processor.py
│       │   ├── filters/
│       │   │   ├── __init__.py
│       │   │   ├── frame_filter.py
│       │   │   ├── function_filter.py
│       │   │   ├── identity_filter.py
│       │   │   ├── null_filter.py
│       │   │   ├── wake_check_filter.py
│       │   │   └── wake_notifier_filter.py
│       │   ├── frame_processor.py
│       │   ├── frameworks/
│       │   │   ├── __init__.py
│       │   │   ├── langchain.py
│       │   │   ├── rtvi/
│       │   │   │   ├── __init__.py
│       │   │   │   ├── frames.py
│       │   │   │   ├── models.py
│       │   │   │   ├── observer.py
│       │   │   │   └── processor.py
│       │   │   └── strands_agents.py
│       │   ├── gstreamer/
│       │   │   ├── __init__.py
│       │   │   └── pipeline_source.py
│       │   ├── idle_frame_processor.py
│       │   ├── logger.py
│       │   ├── metrics/
│       │   │   ├── __init__.py
│       │   │   ├── frame_processor_metrics.py
│       │   │   └── sentry.py
│       │   ├── producer_processor.py
│       │   └── text_transformer.py
│       ├── py.typed
│       ├── registry/
│       │   ├── __init__.py
│       │   ├── registry.py
│       │   └── types.py
│       ├── runner/
│       │   ├── __init__.py
│       │   ├── daily.py
│       │   ├── livekit.py
│       │   ├── run.py
│       │   ├── types.py
│       │   ├── utils.py
│       │   └── vonage.py
│       ├── serializers/
│       │   ├── __init__.py
│       │   ├── base_serializer.py
│       │   ├── exotel.py
│       │   ├── genesys.py
│       │   ├── plivo.py
│       │   ├── protobuf.py
│       │   ├── telnyx.py
│       │   ├── twilio.py
│       │   └── vonage.py
│       ├── services/
│       │   ├── __init__.py
│       │   ├── ai_service.py
│       │   ├── anthropic/
│       │   │   ├── __init__.py
│       │   │   └── llm.py
│       │   ├── assemblyai/
│       │   │   ├── __init__.py
│       │   │   ├── models.py
│       │   │   └── stt.py
│       │   ├── asyncai/
│       │   │   ├── __init__.py
│       │   │   └── tts.py
│       │   ├── aws/
│       │   │   ├── __init__.py
│       │   │   ├── agent_core.py
│       │   │   ├── llm.py
│       │   │   ├── nova_sonic/
│       │   │   │   ├── __init__.py
│       │   │   │   ├── llm.py
│       │   │   │   └── session_continuation.py
│       │   │   ├── sagemaker/
│       │   │   │   ├── __init__.py
│       │   │   │   └── bidi_client.py
│       │   │   ├── stt.py
│       │   │   ├── tts.py
│       │   │   └── utils.py
│       │   ├── azure/
│       │   │   ├── __init__.py
│       │   │   ├── common.py
│       │   │   ├── image.py
│       │   │   ├── llm.py
│       │   │   ├── realtime/
│       │   │   │   ├── __init__.py
│       │   │   │   └── llm.py
│       │   │   ├── stt.py
│       │   │   └── tts.py
│       │   ├── camb/
│       │   │   ├── __init__.py
│       │   │   └── tts.py
│       │   ├── cartesia/
│       │   │   ├── __init__.py
│       │   │   ├── stt.py
│       │   │   ├── tts.py
│       │   │   └── turns/
│       │   │       ├── __init__.py
│       │   │       └── stt.py
│       │   ├── cerebras/
│       │   │   ├── __init__.py
│       │   │   └── llm.py
│       │   ├── deepgram/
│       │   │   ├── __init__.py
│       │   │   ├── flux/
│       │   │   │   ├── __init__.py
│       │   │   │   ├── base.py
│       │   │   │   ├── sagemaker/
│       │   │   │   │   ├── __init__.py
│       │   │   │   │   └── stt.py
│       │   │   │   └── stt.py
│       │   │   ├── sagemaker/
│       │   │   │   ├── __init__.py
│       │   │   │   ├── stt.py
│       │   │   │   └── tts.py
│       │   │   ├── stt.py
│       │   │   └── tts.py
│       │   ├── deepseek/
│       │   │   ├── __init__.py
│       │   │   └── llm.py
│       │   ├── elevenlabs/
│       │   │   ├── __init__.py
│       │   │   ├── stt.py
│       │   │   └── tts.py
│       │   ├── fal/
│       │   │   ├── __init__.py
│       │   │   ├── image.py
│       │   │   └── stt.py
│       │   ├── fireworks/
│       │   │   ├── __init__.py
│       │   │   └── llm.py
│       │   ├── fish/
│       │   │   ├── __init__.py
│       │   │   └── tts.py
│       │   ├── gladia/
│       │   │   ├── __init__.py
│       │   │   ├── config.py
│       │   │   └── stt.py
│       │   ├── google/
│       │   │   ├── __init__.py
│       │   │   ├── frames.py
│       │   │   ├── gemini_live/
│       │   │   │   ├── __init__.py
│       │   │   │   ├── file_api.py
│       │   │   │   ├── llm.py
│       │   │   │   └── vertex/
│       │   │   │       ├── __init__.py
│       │   │   │       └── llm.py
│       │   │   ├── image.py
│       │   │   ├── llm.py
│       │   │   ├── rtvi.py
│       │   │   ├── stt.py
│       │   │   ├── tts.py
│       │   │   ├── utils.py
│       │   │   └── vertex/
│       │   │       ├── __init__.py
│       │   │       └── llm.py
│       │   ├── gradium/
│       │   │   ├── __init__.py
│       │   │   ├── stt.py
│       │   │   └── tts.py
│       │   ├── grok/
│       │   │   ├── __init__.py
│       │   │   ├── llm.py
│       │   │   └── realtime/
│       │   │       ├── __init__.py
│       │   │       ├── events.py
│       │   │       └── llm.py
│       │   ├── groq/
│       │   │   ├── __init__.py
│       │   │   ├── llm.py
│       │   │   ├── stt.py
│       │   │   └── tts.py
│       │   ├── heygen/
│       │   │   ├── __init__.py
│       │   │   ├── api_interactive_avatar.py
│       │   │   ├── api_liveavatar.py
│       │   │   ├── base_api.py
│       │   │   ├── client.py
│       │   │   └── video.py
│       │   ├── hume/
│       │   │   ├── __init__.py
│       │   │   └── tts.py
│       │   ├── image_service.py
│       │   ├── inception/
│       │   │   ├── __init__.py
│       │   │   └── llm.py
│       │   ├── inworld/
│       │   │   ├── __init__.py
│       │   │   ├── realtime/
│       │   │   │   ├── __init__.py
│       │   │   │   ├── events.py
│       │   │   │   └── llm.py
│       │   │   └── tts.py
│       │   ├── kokoro/
│       │   │   ├── __init__.py
│       │   │   └── tts.py
│       │   ├── llm_service.py
│       │   ├── lmnt/
│       │   │   ├── __init__.py
│       │   │   └── tts.py
│       │   ├── mcp_service.py
│       │   ├── mem0/
│       │   │   ├── __init__.py
│       │   │   └── memory.py
│       │   ├── minimax/
│       │   │   ├── __init__.py
│       │   │   └── tts.py
│       │   ├── mistral/
│       │   │   ├── __init__.py
│       │   │   ├── llm.py
│       │   │   ├── stt.py
│       │   │   └── tts.py
│       │   ├── moondream/
│       │   │   ├── __init__.py
│       │   │   └── vision.py
│       │   ├── moonshine/
│       │   │   ├── __init__.py
│       │   │   └── stt.py
│       │   ├── nebius/
│       │   │   ├── __init__.py
│       │   │   └── llm.py
│       │   ├── neuphonic/
│       │   │   ├── __init__.py
│       │   │   └── tts.py
│       │   ├── novita/
│       │   │   ├── __init__.py
│       │   │   └── llm.py
│       │   ├── nvidia/
│       │   │   ├── __init__.py
│       │   │   ├── llm.py
│       │   │   ├── sagemaker/
│       │   │   │   ├── __init__.py
│       │   │   │   ├── stt.py
│       │   │   │   └── tts.py
│       │   │   ├── stt.py
│       │   │   └── tts.py
│       │   ├── ollama/
│       │   │   ├── __init__.py
│       │   │   └── llm.py
│       │   ├── openai/
│       │   │   ├── __init__.py
│       │   │   ├── _constants.py
│       │   │   ├── base_llm.py
│       │   │   ├── image.py
│       │   │   ├── llm.py
│       │   │   ├── realtime/
│       │   │   │   ├── __init__.py
│       │   │   │   ├── events.py
│       │   │   │   └── llm.py
│       │   │   ├── responses/
│       │   │   │   ├── __init__.py
│       │   │   │   └── llm.py
│       │   │   ├── stt.py
│       │   │   └── tts.py
│       │   ├── openrouter/
│       │   │   ├── __init__.py
│       │   │   └── llm.py
│       │   ├── perplexity/
│       │   │   ├── __init__.py
│       │   │   └── llm.py
│       │   ├── piper/
│       │   │   ├── __init__.py
│       │   │   └── tts.py
│       │   ├── qwen/
│       │   │   ├── __init__.py
│       │   │   └── llm.py
│       │   ├── resembleai/
│       │   │   ├── __init__.py
│       │   │   └── tts.py
│       │   ├── rime/
│       │   │   ├── __init__.py
│       │   │   └── tts.py
│       │   ├── sambanova/
│       │   │   ├── __init__.py
│       │   │   └── llm.py
│       │   ├── sarvam/
│       │   │   ├── __init__.py
│       │   │   ├── _sdk.py
│       │   │   ├── llm.py
│       │   │   ├── stt.py
│       │   │   └── tts.py
│       │   ├── settings.py
│       │   ├── simli/
│       │   │   ├── __init__.py
│       │   │   └── video.py
│       │   ├── smallest/
│       │   │   ├── __init__.py
│       │   │   ├── stt.py
│       │   │   └── tts.py
│       │   ├── soniox/
│       │   │   ├── __init__.py
│       │   │   ├── stt.py
│       │   │   └── tts.py
│       │   ├── speechmatics/
│       │   │   ├── __init__.py
│       │   │   ├── stt.py
│       │   │   └── tts.py
│       │   ├── stt_latency.py
│       │   ├── stt_service.py
│       │   ├── tavus/
│       │   │   ├── __init__.py
│       │   │   └── video.py
│       │   ├── together/
│       │   │   ├── __init__.py
│       │   │   └── llm.py
│       │   ├── tts_service.py
│       │   ├── ultravox/
│       │   │   ├── __init__.py
│       │   │   └── llm.py
│       │   ├── vision_service.py
│       │   ├── websocket_service.py
│       │   ├── whisper/
│       │   │   ├── __init__.py
│       │   │   ├── base_stt.py
│       │   │   ├── stt.py
│       │   │   └── utils.py
│       │   ├── xai/
│       │   │   ├── __init__.py
│       │   │   ├── llm.py
│       │   │   ├── realtime/
│       │   │   │   ├── __init__.py
│       │   │   │   ├── events.py
│       │   │   │   └── llm.py
│       │   │   ├── stt.py
│       │   │   └── tts.py
│       │   └── xtts/
│       │       ├── __init__.py
│       │       └── tts.py
│       ├── tests/
│       │   ├── __init__.py
│       │   └── utils.py
│       ├── transcriptions/
│       │   ├── __init__.py
│       │   └── language.py
│       ├── transports/
│       │   ├── __init__.py
│       │   ├── base_input.py
│       │   ├── base_output.py
│       │   ├── base_transport.py
│       │   ├── daily/
│       │   │   ├── __init__.py
│       │   │   ├── transport.py
│       │   │   └── utils.py
│       │   ├── heygen/
│       │   │   ├── __init__.py
│       │   │   └── transport.py
│       │   ├── lemonslice/
│       │   │   ├── __init__.py
│       │   │   ├── api.py
│       │   │   └── transport.py
│       │   ├── livekit/
│       │   │   ├── __init__.py
│       │   │   ├── transport.py
│       │   │   └── utils.py
│       │   ├── local/
│       │   │   ├── __init__.py
│       │   │   ├── audio.py
│       │   │   └── tk.py
│       │   ├── smallwebrtc/
│       │   │   ├── __init__.py
│       │   │   ├── connection.py
│       │   │   ├── request_handler.py
│       │   │   └── transport.py
│       │   ├── tavus/
│       │   │   ├── __init__.py
│       │   │   └── transport.py
│       │   ├── vonage/
│       │   │   ├── __init__.py
│       │   │   ├── client.py
│       │   │   ├── utils.py
│       │   │   └── video_connector.py
│       │   ├── websocket/
│       │   │   ├── __init__.py
│       │   │   ├── client.py
│       │   │   ├── fastapi.py
│       │   │   └── server.py
│       │   └── whatsapp/
│       │       ├── __init__.py
│       │       ├── api.py
│       │       └── client.py
│       ├── turns/
│       │   ├── __init__.py
│       │   ├── types.py
│       │   ├── user_idle_controller.py
│       │   ├── user_mute/
│       │   │   ├── __init__.py
│       │   │   ├── always_user_mute_strategy.py
│       │   │   ├── base_user_mute_strategy.py
│       │   │   ├── first_speech_user_mute_strategy.py
│       │   │   ├── function_call_user_mute_strategy.py
│       │   │   └── mute_until_first_bot_complete_user_mute_strategy.py
│       │   ├── user_start/
│       │   │   ├── __init__.py
│       │   │   ├── base_user_turn_start_strategy.py
│       │   │   ├── external_user_turn_start_strategy.py
│       │   │   ├── krisp_viva_ip_user_turn_start_strategy.py
│       │   │   ├── min_words_user_turn_start_strategy.py
│       │   │   ├── transcription_user_turn_start_strategy.py
│       │   │   ├── vad_user_turn_start_strategy.py
│       │   │   └── wake_phrase_user_turn_start_strategy.py
│       │   ├── user_stop/
│       │   │   ├── __init__.py
│       │   │   ├── base_user_turn_stop_strategy.py
│       │   │   ├── deferred_user_turn_stop_strategy.py
│       │   │   ├── external_user_turn_completion_stop_strategy.py
│       │   │   ├── external_user_turn_stop_strategy.py
│       │   │   ├── llm_turn_completion_user_turn_stop_strategy.py
│       │   │   ├── speech_timeout_user_turn_stop_strategy.py
│       │   │   └── turn_analyzer_user_turn_stop_strategy.py
│       │   ├── user_turn_completion_mixin.py
│       │   ├── user_turn_controller.py
│       │   ├── user_turn_processor.py
│       │   └── user_turn_strategies.py
│       ├── utils/
│       │   ├── __init__.py
│       │   ├── async_tool_cancellation.py
│       │   ├── asyncio/
│       │   │   ├── __init__.py
│       │   │   └── task_manager.py
│       │   ├── base_object.py
│       │   ├── context/
│       │   │   ├── __init__.py
│       │   │   ├── aggregated_frame_sequencer.py
│       │   │   ├── llm_context_summarization.py
│       │   │   └── word_completion_tracker.py
│       │   ├── deprecation.py
│       │   ├── env.py
│       │   ├── frame_queue.py
│       │   ├── network.py
│       │   ├── security/
│       │   │   ├── __init__.py
│       │   │   └── allowed_origins.py
│       │   ├── startup.py
│       │   ├── string.py
│       │   ├── sync/
│       │   │   ├── __init__.py
│       │   │   ├── base_notifier.py
│       │   │   └── event_notifier.py
│       │   ├── text/
│       │   │   ├── __init__.py
│       │   │   ├── base_text_aggregator.py
│       │   │   ├── base_text_filter.py
│       │   │   ├── markdown_text_filter.py
│       │   │   ├── pattern_pair_aggregator.py
│       │   │   ├── simple_text_aggregator.py
│       │   │   ├── skip_tags_aggregator.py
│       │   │   └── word_timestamp_utils.py
│       │   ├── time.py
│       │   ├── tracing/
│       │   │   ├── __init__.py
│       │   │   ├── service_attributes.py
│       │   │   ├── service_decorators.py
│       │   │   ├── setup.py
│       │   │   ├── tracing_context.py
│       │   │   └── turn_trace_observer.py
│       │   └── utils.py
│       └── workers/
│           ├── base_worker.py
│           ├── llm/
│           │   ├── __init__.py
│           │   ├── llm_context_worker.py
│           │   ├── llm_worker.py
│           │   └── tool_decorator.py
│           ├── proxy/
│           │   ├── __init__.py
│           │   └── websocket/
│           │       ├── __init__.py
│           │       ├── client.py
│           │       └── server.py
│           ├── runner.py
│           └── ui/
│               ├── __init__.py
│               ├── ui_event_decorator.py
│               ├── ui_job_context.py
│               ├── ui_prompts.py
│               ├── ui_tools.py
│               └── ui_worker.py
└── tests/
    ├── __init__.py
    ├── aic_mocks.py
    ├── cli/
    │   ├── conftest.py
    │   ├── test_cli_extensions.py
    │   ├── test_client_generation.py
    │   ├── test_config_validator.py
    │   ├── test_create_command.py
    │   ├── test_create_in_place.py
    │   ├── test_init_agent_ready.py
    │   ├── test_list_options.py
    │   ├── test_project_generation.py
    │   ├── test_questions.py
    │   ├── test_quickstart.py
    │   └── test_service_registry.py
    ├── genesys/
    │   ├── __init__.py
    │   ├── conftest.py
    │   └── test_genesys_serializer.py
    ├── integration/
    │   └── test_integration_unified_function_calling.py
    ├── test_aggregated_frame_sequencer.py
    ├── test_aggregators.py
    ├── test_aic_filter.py
    ├── test_aic_filter_vad_factory_deprecation.py
    ├── test_aic_quail_vad.py
    ├── test_aic_vad.py
    ├── test_aic_vad_deprecation.py
    ├── test_app_resources.py
    ├── test_assemblyai_stt.py
    ├── test_async_tool_messages.py
    ├── test_audio_buffer_processor.py
    ├── test_auto_register_tools.py
    ├── test_aws_credentials.py
    ├── test_azure_stt.py
    ├── test_azure_tts.py
    ├── test_base_input_transport.py
    ├── test_base_output_transport.py
    ├── test_base_smart_turn_buffer.py
    ├── test_base_worker.py
    ├── test_bridge_processor.py
    ├── test_bus.py
    ├── test_bus_network.py
    ├── test_cartesia_stt.py
    ├── test_cartesia_tts.py
    ├── test_context_aggregators_universal.py
    ├── test_context_summarization.py
    ├── test_daily_transport_service.py
    ├── test_deepgram_stt.py
    ├── test_deprecation_markers.py
    ├── test_direct_functions.py
    ├── test_dtmf_aggregator.py
    ├── test_elevenlabs_stt.py
    ├── test_elevenlabs_tts.py
    ├── test_evals_harness.py
    ├── test_evals_judge.py
    ├── test_evals_scenario.py
    ├── test_evals_serializer.py
    ├── test_evals_services.py
    ├── test_evals_suite.py
    ├── test_evals_transport.py
    ├── test_fastapi_websocket.py
    ├── test_filters.py
    ├── test_frame_adapters.py
    ├── test_frame_processor.py
    ├── test_function_calling_adapters.py
    ├── test_gemini_live_user_audio.py
    ├── test_get_llm_invocation_params.py
    ├── test_google_utils.py
    ├── test_idle_frame_processor.py
    ├── test_inworld_tts_language.py
    ├── test_ivr_navigation.py
    ├── test_job_group.py
    ├── test_krisp_ip_user_turn_start_strategy.py
    ├── test_krisp_sdk_manager.py
    ├── test_krisp_viva_filter.py
    ├── test_krisp_viva_vad.py
    ├── test_langchain.py
    ├── test_livekit_transport.py
    ├── test_llm_context.py
    ├── test_llm_context_summarizer.py
    ├── test_llm_response.py
    ├── test_llm_service.py
    ├── test_llm_switcher.py
    ├── test_llm_worker.py
    ├── test_local_smart_turn_v3_features.py
    ├── test_local_smart_turn_v3_resample.py
    ├── test_markdown_text_filter.py
    ├── test_messages.py
    ├── test_novita_llm.py
    ├── test_openai_llm_timeout.py
    ├── test_openai_realtime_audio_frames.py
    ├── test_openai_realtime_reasoning.py
    ├── test_openai_realtime_user_audio.py
    ├── test_openai_responses_http.py
    ├── test_openai_responses_websocket.py
    ├── test_pattern_pair_aggregator.py
    ├── test_pgmq_backends.py
    ├── test_pgmq_bus.py
    ├── test_pipeline.py
    ├── test_pipeline_worker_ui_bridge.py
    ├── test_piper_tts.py
    ├── test_producer_consumer.py
    ├── test_protobuf_serializer.py
    ├── test_realtime_tool_sync.py
    ├── test_redis_bus.py
    ├── test_registry.py
    ├── test_resampy_resampler.py
    ├── test_rnnoise_cancellation.py
    ├── test_rnnoise_filter.py
    ├── test_rnnoise_resampling.py
    ├── test_rtvi_observer_config.py
    ├── test_rtvi_processor.py
    ├── test_rtvi_ui.py
    ├── test_run_inference.py
    ├── test_runner.py
    ├── test_runner_downloads.py
    ├── test_runner_run.py
    ├── test_runner_utils.py
    ├── test_sambanova_llm.py
    ├── test_serializers.py
    ├── test_service_init.py
    ├── test_service_language.py
    ├── test_service_switcher.py
    ├── test_settings.py
    ├── test_simple_text_aggregator.py
    ├── test_skip_tags_aggregator.py
    ├── test_smallest_tts.py
    ├── test_smallwebrtc_transport.py
    ├── test_soniox_stt.py
    ├── test_soxr_resamplers.py
    ├── test_startup_timing_observer.py
    ├── test_sync_parallel_pipeline.py
    ├── test_task_manager.py
    ├── test_tracing_context.py
    ├── test_tts_frame_ordering.py
    ├── test_turn_trace_observer.py
    ├── test_turn_tracking_observer.py
    ├── test_ui_commands.py
    ├── test_ui_job_lifecycle.py
    ├── test_ui_tools.py
    ├── test_ui_worker.py
    ├── test_user_bot_latency_observer.py
    ├── test_user_idle_controller.py
    ├── test_user_mute_strategy.py
    ├── test_user_turn_completion_mixin.py
    ├── test_user_turn_controller.py
    ├── test_user_turn_processor.py
    ├── test_user_turn_start_strategy.py
    ├── test_user_turn_stop_strategy.py
    ├── test_utils_network.py
    ├── test_utils_string.py
    ├── test_vad_controller.py
    ├── test_vad_processor.py
    ├── test_version_banner.py
    ├── test_vonage_video_connector.py
    ├── test_wake_phrase_user_turn_start_strategy.py
    ├── test_websocket_proxy.py
    ├── test_websocket_service.py
    ├── test_websocket_transport.py
    ├── test_word_completion_tracker.py
    ├── test_word_timestamp_utils.py
    └── test_xai_tts.py

================================================
FILE CONTENTS
================================================

================================================
FILE: .claude/settings.json
================================================
{
  "attribution": {
    "commit": ""
  }
}


================================================
FILE: .claude/skills/changelog/SKILL.md
================================================
---
name: changelog
description: Create changelog files for important commits in a PR
---

Create changelog files for the important commits in this PR. The PR number is provided as an argument.

## Instructions

1. Skip changelog for: documentation-only, internal refactoring, test-only, CI changes.

2. First, check what commits are on the current branch compared to main:
   ```
   git log main..HEAD --oneline
   ```

3. For each significant change, create a changelog file in the `changelog/` folder using the format:
   Allowed types: `added`, `changed`, `deprecated`, `removed`, `fixed`, `security`, `performance`, `other`
   - `{PR_NUMBER}.added.md` - for new features
   - `{PR_NUMBER}.added.2.md`, `{PR_NUMBER}.added.3.md` - for additional entries of the same type
   - `{PR_NUMBER}.changed.md` - for changes to existing functionality
   - `{PR_NUMBER}.fixed.md` - for bug fixes
   - `{PR_NUMBER}.deprecated.md` - for deprecations
   - `{PR_NUMBER}.removed.md` - for removed features
   - `{PR_NUMBER}.security.md` - for security fixes
   - `{PR_NUMBER}.performance.md` - for performance improvements
   - `{PR_NUMBER}.other.md` - for other changes

4. Each changelog file should at least contain a main single line starting with `- ` followed by a clear description of the change. No line wrapping.

5. If the change is complicated, changelog files can have indented lines after the main line with additional details or code samples.

6. Use ⚠️ emoji prefix for breaking changes.

7. **Write changes in user-facing terms first.** Lead with what users of the framework will notice: new APIs, changed behavior, new parameters, fixed bugs they might have hit, etc. Implementation details (internal refactoring, how something is wired up under the hood) can be included as secondary context after the user-facing description, but should never be the *only* content of a changelog entry when there is a user-visible effect.

   **Good** (user-facing first, implementation detail as context):
   ```
   - Turn completion instructions now persist correctly across full context updates when using `system_instruction`. Previously they were injected as a context system message, which caused warning spam and didn't survive context updates.
   ```

   **Bad** (implementation detail only, no user-facing framing):
   ```
   - Fixed turn completion instructions being injected as a context system message instead of using `system_instruction`.
   ```

   Ask yourself: "If I'm a developer building on Pipecat, what would I notice changed?" Start there.

## Example

For PR #3519 with a new feature and a bug fix:

`changelog/3519.added.md`:
```
- Added `SomeNewFeature` for doing something useful.
```

`changelog/3519.fixed.md`:
```
- Fixed an issue where something was not working correctly in some user-visible scenario. The root cause was an internal implementation detail.
```


================================================
FILE: .claude/skills/cleanup/SKILL.md
================================================
---
name: cleanup
description: Review, refactor, document, and validate code changes in the current branch
---

# Code Cleanup Skill

The **Code Cleanup Skill** reviews, refactors, and documents code changes in your current branch, ensuring alignment with **Pipecat's architecture, coding standards, and example patterns**.
It focuses on **readability, correctness, performance, and consistency**, while avoiding breaking changes.

---

## Skill Overview

This skill analyzes all changes introduced in your branch and performs the following actions:

1. **Analyze Branch Changes**
   - Review uncommitted changes and outgoing commits
2. **Refactor for Readability**
   - Improve clarity, naming, structure, and modern Python usage
3. **Enhance Performance**
   - Identify safe, conservative optimization opportunities
4. **Add Documentation**
   - Apply Pipecat-style, Google-format docstrings
5. **Ensure Pattern Consistency**
   - Match existing Pipecat services, pipelines, and examples
6. **Validate Examples**
   - Ensure examples follow foundational patterns (e.g. `07-interruptible.py`)

---

## Usage

Invoke the skill using any of the following commands:

- "Clean up my branch code"
- "Refactor the changes in my branch"
- "Review and improve my branch code"
- `/cleanup`

---

## What This Skill Does

### 1. Analyze Branch Changes

The skill retrieves all uncommitted changes and outgoing commits to understand:

- New files added
- Modified files
- Code additions and deletions
- Overall scope and intent of changes

---

### 2. Code Refactoring

#### Readability Improvements

- Replace tuples with named classes or dataclasses
- Improve variable, method, and class naming
- Extract complex logic into well-named helper methods
- Add missing type hints
- Simplify nested or complex conditionals
- Replace deprecated methods and features
- Normalize formatting to match Pipecat style

#### Performance Enhancements

- Identify inefficient loops or repeated work
- Suggest appropriate data structures
- Optimize async workflows and I/O
- Remove redundant operations

> Performance changes are conservative and non-breaking.

---

### 3. Documentation

Documentation follows **Google-style docstrings**, consistent with Pipecat conventions.

#### Class Documentation

```python
class ExampleService:
    """Brief one-line description.

    Detailed explanation of the class purpose, responsibilities,
    and important behaviors.

    Supported features:

    - Feature 1
    - Feature 2
    - Feature 3
    """
```

#### Method Documentation

```python
def process_data(self, data: str, options: Optional[dict] = None) -> bool:
    """Process incoming data with optional configuration.

    Args:
        data: The input data to process.
        options: Optional configuration dictionary.

    Returns:
        True if processing succeeded, False otherwise.

    Raises:
        ValueError: If data is empty or invalid.
    """
```

#### Pydantic Model Parameters

```python
class InputParams(BaseModel):
    """Configuration parameters for the service.

    Parameters:
        timeout: Request timeout in seconds.
        retry_count: Number of retry attempts.
        enable_logging: Whether to enable debug logging.
    """

    timeout: Optional[float] = None
    retry_count: int = 3
    enable_logging: bool = False
```

---

### 4. Pattern Consistency Checks

#### Service Classes

- Correct inheritance (`TTSService`, `STTService`, `LLMService`)
- Consistent constructor signatures
- Frame emission patterns
- Metrics support:
  - `can_generate_metrics()`
  - TTFB metrics
  - Usage metrics
- Alignment with similar existing services

#### Examples

Validated against `examples/07-interruptible.py`:

- Proper `create_transport()` usage
- Correct pipeline structure
- Task setup and observers
- Event handler registration
- Runner and bot entrypoint consistency

---

### 5. Specific Implementation Patterns

#### Service Implementation

```python
class ExampleTTSService(TTSService):

    def __init__(self, *, api_key: Optional[str] = None, **kwargs):
        super().__init__(**kwargs)
        self._api_key = api_key or os.getenv("SERVICE_API_KEY")

    def can_generate_metrics(self) -> bool:
        return True

    async def run_tts(self, text: str) -> AsyncGenerator[Frame, None]:
        try:
            await self.start_ttfb_metrics()
            yield TTSStartedFrame()
            # ... processing ...
            yield TTSAudioRawFrame(...)
        finally:
            await self.stop_ttfb_metrics()
```

---

#### Example Structure Pattern

```python
transport_params = {
    "daily": lambda: DailyParams(...),
    "twilio": lambda: FastAPIWebsocketParams(...),
    "webrtc": lambda: TransportParams(...),
}

async def run_bot(transport: BaseTransport, runner_args: RunnerArguments):
    stt = DeepgramSTTService(...)
    tts = SomeTTSService(...)
    llm = OpenAILLMService(...)

    context = LLMContext(messages)
    user_aggregator, assistant_aggregator = LLMContextAggregatorPair(...)

    pipeline = Pipeline([...])
    task = PipelineTask(pipeline, params=..., observers=[...])

    @transport.event_handler("on_client_connected")
    async def on_client_connected(transport, client):
        await task.queue_frames([LLMRunFrame()])

    runner = PipelineRunner(handle_sigint=runner_args.handle_sigint)
    await runner.run(task)

async def bot(runner_args: RunnerArguments):
    """Main bot entry point compatible with Pipecat Cloud."""
    transport = await create_transport(runner_args, transport_params)
    await run_bot(transport, runner_args)
```

---

## Execution Flow

1. Fetch uncommitted and outgoing changes
2. Categorize files (services, examples, tests, utilities)
3. Analyze each file:
   - Readability
   - Performance
   - Documentation
   - Pattern consistency
4. Generate actionable recommendations
5. Apply Pipecat standards

---

## Examples

### Before: Tuple Usage

```python
def get_audio_info(self) -> Tuple[int, int]:
    return (48000, 1)
```

### After: Named Class

```python
class AudioInfo:
    """Audio configuration information.

    Parameters:
        sample_rate: Sample rate in Hz.
        num_channels: Number of audio channels.
    """

    sample_rate: int
    num_channels: int

def get_audio_info(self) -> AudioInfo:
    return AudioInfo(sample_rate=48000, num_channels=1)
```

---

### Before: Missing Documentation

```python
class NewTTSService(TTSService):
    def __init__(self, api_key: str, voice: str):
        self._api_key = api_key
        self._voice = voice
```

### After: Fully Documented

```python
class NewTTSService(TTSService):
    """Text-to-speech service using NewProvider API.

    Streams PCM audio and emits TTSAudioRawFrame frames compatible
    with Pipecat transports.

    Supported features:
    - Text-to-speech synthesis
    - Streaming PCM audio
    - Voice customization
    - TTFB metrics
    """

    def __init__(self, *, api_key: str, voice: str, **kwargs):
        """Initialize the NewTTSService.

        Args:
            api_key: API key for authentication.
            voice: Voice identifier to use.
            **kwargs: Additional arguments passed to the parent service.
        """
        super().__init__(**kwargs)
        self._api_key = api_key
        self.set_voice(voice)
```

---

## Notes

- Non-breaking improvements only
- Backward compatibility preserved
- Conservative performance changes
- Google-style docstrings
- Pattern checks follow recent Pipecat code


================================================
FILE: .claude/skills/code-review/SKILL.md
================================================
---
name: code-review
description: Automated code review for pull requests using multiple specialized agents
disable-model-invocation: true
allowed-tools: Bash(gh issue view:*), Bash(gh search:*), Bash(gh issue list:*), Bash(gh pr comment:*), Bash(gh pr diff:*), Bash(gh pr view:*), Bash(gh pr list:*)
---

Provide a code review for the given pull request.

**Agent assumptions (applies to all agents and subagents):**

- All tools are functional and will work without error. Do not test tools or make exploratory calls. Make sure this is clear to every subagent that is launched.
- Only call a tool if it is required to complete the task. Every tool call should have a clear purpose.

To do this, follow these steps precisely:

1. Launch a haiku agent to check if any of the following are true:
   - The pull request is closed
   - The pull request is a draft
   - The pull request does not need code review (e.g. automated PR, trivial change that is obviously correct)
   - Claude has already commented on this PR (check `gh pr view <PR> --comments` for comments left by claude)

   If any condition is true, stop and do not proceed.

Note: Still review Claude generated PR's.

2. Launch a haiku agent to return a list of file paths (not their contents) for all relevant CLAUDE.md files including:
   - The root CLAUDE.md file, if it exists
   - Any CLAUDE.md files in directories containing files modified by the pull request

3. Launch a sonnet agent to view the pull request and return a summary of the changes

4. Launch 4 agents in parallel to independently review the changes. Each agent should return the list of issues, where each issue includes a description and the reason it was flagged (e.g. "CLAUDE.md adherence", "bug"). The agents should do the following:

   Agents 1 + 2: CLAUDE.md compliance sonnet agents
   Audit changes for CLAUDE.md compliance in parallel. Note: When evaluating CLAUDE.md compliance for a file, you should only consider CLAUDE.md files that share a file path with the file or parents.

   Agent 3: Opus bug agent (parallel subagent with agent 4)
   Scan for obvious bugs. Focus only on the diff itself without reading extra context. Flag only significant bugs; ignore nitpicks and likely false positives. Do not flag issues that you cannot validate without looking at context outside of the git diff.

   Agent 4: Opus bug agent (parallel subagent with agent 3)
   Look for problems that exist in the introduced code. This could be security issues, incorrect logic, etc. Only look for issues that fall within the changed code.

   **CRITICAL: We only want HIGH SIGNAL issues.** Flag issues where:
   - The code will fail to compile or parse (syntax errors, type errors, missing imports, unresolved references)
   - The code will definitely produce wrong results regardless of inputs (clear logic errors)
   - Clear, unambiguous CLAUDE.md violations where you can quote the exact rule being broken

   Do NOT flag:
   - Code style or quality concerns
   - Potential issues that depend on specific inputs or state
   - Subjective suggestions or improvements

   If you are not certain an issue is real, do not flag it. False positives erode trust and waste reviewer time.

   In addition to the above, each subagent should be told the PR title and description. This will help provide context regarding the author's intent.

5. For each issue found in the previous step by agents 3 and 4, launch parallel subagents to validate the issue. These subagents should get the PR title and description along with a description of the issue. The agent's job is to review the issue to validate that the stated issue is truly an issue with high confidence. For example, if an issue such as "variable is not defined" was flagged, the subagent's job would be to validate that is actually true in the code. Another example would be CLAUDE.md issues. The agent should validate that the CLAUDE.md rule that was violated is scoped for this file and is actually violated. Use Opus subagents for bugs and logic issues, and sonnet agents for CLAUDE.md violations.

6. Filter out any issues that were not validated in step 5. This step will give us our list of high signal issues for our review.

7. If issues were found, skip to step 8 to post comments.

   If NO issues were found, post a summary comment using `gh pr comment` (if `--comment` argument is provided):
   "No issues found. Checked for bugs and CLAUDE.md compliance."

8. Create a list of all comments that you plan on leaving. This is only for you to make sure you are comfortable with the comments. Do not post this list anywhere.

9. Post inline comments for each issue using `gh pr review` with inline comments. For each comment:
   - Provide a brief description of the issue
   - For small, self-contained fixes, include a committable suggestion block
   - For larger fixes (6+ lines, structural changes, or changes spanning multiple locations), describe the issue and suggested fix without a suggestion block
   - Never post a committable suggestion UNLESS committing the suggestion fixes the issue entirely. If follow up steps are required, do not leave a committable suggestion.

   **IMPORTANT: Only post ONE comment per unique issue. Do not post duplicate comments.**

Use this list when evaluating issues in Steps 4 and 5 (these are false positives, do NOT flag):

- Pre-existing issues
- Something that appears to be a bug but is actually correct
- Pedantic nitpicks that a senior engineer would not flag
- Issues that a linter will catch (do not run the linter to verify)
- General code quality concerns (e.g., lack of test coverage, general security issues) unless explicitly required in CLAUDE.md
- Issues mentioned in CLAUDE.md but explicitly silenced in the code (e.g., via a lint ignore comment)

Notes:

- Use gh CLI to interact with GitHub (e.g., fetch pull requests, create comments). Do not use web fetch.
- Create a todo list before starting.
- You must cite and link each issue in inline comments (e.g., if referring to a CLAUDE.md, include a link to it).
- If no issues are found, post a comment with the following format:

---

## Code review

No issues found. Checked for bugs and CLAUDE.md compliance.

---

- When linking to code in inline comments, follow the following format precisely, otherwise the Markdown preview won't render correctly: `https://github.com/OWNER/REPO/blob/FULL_SHA/path/to/file.py#L10-L15`
  - Requires full git sha
  - You must provide the full sha. Commands like `https://github.com/owner/repo/blob/$(git rev-parse HEAD)/foo/bar` will not work, since your comment will be directly rendered in Markdown.
  - Repo name must match the repo you're code reviewing
  - # sign after the file name
  - Line range format is L[start]-L[end]
  - Provide at least 1 line of context before and after, centered on the line you are commenting about (eg. if you are commenting about lines 5-6, you should link to `L4-7`)


================================================
FILE: .claude/skills/docstring/SKILL.md
================================================
---
name: docstring
description: Document a Python module and its classes using Google style
---

Document a Python module or class using Google-style docstrings following project conventions. The argument can be a class name or a module path.

## Instructions

1. Determine what to document based on the argument:

   **If a module path is provided** (e.g. `src/pipecat/audio/vad/vad_analyzer.py`):
   - Use that file directly

   **If a class name is provided** (e.g. `VADAnalyzer`):
   - Search for `class ClassName` in `src/pipecat/`
   - If multiple files contain that class name, list all matches with their file paths, ask the user which one they want to document, and wait for confirmation

2. Once the file is identified, read the module to understand its structure:
   - Identify all classes, functions, and important type aliases
   - Understand the purpose of each component

4. Apply documentation in this order:
   - Module docstring (at top, after imports)
   - Class docstrings
   - `__init__` methods (always document constructor parameters)
   - Public methods (not starting with `_`)
   - Dataclass/config classes with field descriptions

5. Skip documentation for:
   - Private methods (starting with `_`)
   - Simple dunder methods (`__str__`, `__repr__`, `__post_init__`)
   - Very simple pass-through properties
   - **Already documented code** - If a class, method, or function already has a complete docstring that follows the project style, do not modify it. A docstring is complete if it has:
     - A one-line summary
     - Args section (if it has parameters)
     - Returns section (if it returns something meaningful)
   - Only add or improve documentation where it is missing or incomplete

## Module Docstring Format

```python
"""[One-line description of module purpose].

[Optional: Longer explanation of functionality, key classes, or use cases.]
"""
```

Example:
```python
"""Neuphonic text-to-speech service implementations.

This module provides WebSocket and HTTP-based integrations with Neuphonic's
text-to-speech API for real-time audio synthesis.
"""
```

## Class Docstring Format

```python
class ClassName:
    """One-line summary describing what the class does.

    [Longer description explaining purpose, behavior, and key features.
    Use action-oriented language.]

    [Optional: Event handlers, usage notes, or important caveats.]
    """
```

Example:
```python
class FrameProcessor(BaseObject):
    """Base class for all frame processors in the pipeline.

    Frame processors are the building blocks of Pipecat pipelines, they can be
    linked to form complex processing pipelines. They receive frames, process
    them, and pass them to the next or previous processor in the chain.

    Event handlers available:

    - on_before_process_frame: Called before a frame is processed
    - on_after_process_frame: Called after a frame is processed

    Example::

        @processor.event_handler("on_before_process_frame")
        async def on_before_process_frame(processor, frame):
            ...

        @processor.event_handler("on_after_process_frame")
        async def on_after_process_frame(processor, frame):
            ...
    """
```

Note: When listing event handlers, do NOT use backticks. Include an `Example::` section (with double colon for Sphinx) showing the decorator pattern and function signature for each event.

## Constructor (`__init__`) Format

```python
def __init__(self, *, param1: Type, param2: Type = default, **kwargs):
    """Initialize the [ClassName].

    Args:
        param1: Description of param1 and its purpose.
        param2: Description of param2. Defaults to [default].
        **kwargs: Additional arguments passed to parent class.
    """
```

Example:
```python
def __init__(
    self,
    *,
    api_key: str,
    voice_id: Optional[str] = None,
    sample_rate: Optional[int] = 22050,
    **kwargs,
):
    """Initialize the Neuphonic TTS service.

    Args:
        api_key: Neuphonic API key for authentication.
        voice_id: ID of the voice to use for synthesis.
        sample_rate: Audio sample rate in Hz. Defaults to 22050.
        **kwargs: Additional arguments passed to parent InterruptibleTTSService.
    """
```

## Method Docstring Format

```python
async def method_name(self, param1: Type) -> ReturnType:
    """One-line summary of what method does.

    [Longer description if behavior isn't obvious.]

    Args:
        param1: Description of param1.

    Returns:
        Description of return value.

    Raises:
        ExceptionType: When this exception is raised.
    """
```

Example:
```python
async def put(self, item: Tuple[Frame, FrameDirection, FrameCallback]):
    """Put an item into the priority queue.

    System frames (`SystemFrame`) have higher priority than any other
    frames. If a non-frame item is provided it will have the highest priority.

    Args:
        item: The item to enqueue.
    """
```

## Dataclass/Config Format

```python
@dataclass
class ConfigName:
    """One-line description of configuration.

    [Explanation of when/how to use this config.]

    Parameters:
        field1: Description of field1.
        field2: Description of field2. Defaults to [default].
    """

    field1: Type
    field2: Type = default_value
```

Example:
```python
@dataclass
class FrameProcessorSetup:
    """Configuration parameters for frame processor initialization.

    Parameters:
        clock: The clock instance for timing operations.
        task_manager: The task manager for handling async operations.
        observer: Optional observer for monitoring frame processing events.
    """

    clock: BaseClock
    task_manager: BaseTaskManager
    observer: Optional[BaseObserver] = None
```

## Enum Documentation Format

```python
class EnumName(Enum):
    """One-line description of the enum purpose.

    [Longer description of how the enum is used.]

    Parameters:
        VALUE1: Description of VALUE1.
        VALUE2: Description of VALUE2.
    """

    VALUE1 = 1
    VALUE2 = 2
```

## Writing Style Guidelines

- **Concise and professional** - No casual language or filler words
- **Action-oriented** - Start with verbs: "Processes...", "Manages...", "Converts..."
- **Purpose before implementation** - Explain WHY before HOW
- **Clear parameter descriptions** - Include type hints, defaults, and purpose
- **No redundant type info** - Type hints are in the signature, don't repeat in description
- **Use backticks for code references** - Wrap class names, method names, event names, parameter names, and code snippets in backticks

Good: "Neuphonic API key for authentication."
Bad: "str: The API key (string) that is used for authenticating with Neuphonic."

Good: "Triggers `on_speech_started` when the `VADAnalyzer` detects speech."
Bad: "Triggers on_speech_started when the VADAnalyzer detects speech."

## Deprecation Notice Format

When documenting deprecated code:

```python
"""[Description].

.. deprecated:: X.X.X
    `ClassName` is deprecated and will be removed in a future version.
    Use `NewClassName` instead.
"""
```

## Checklist

Before finishing, verify:

- [ ] Module has a docstring at the top (after copyright header and imports)
- [ ] All public classes have docstrings
- [ ] All `__init__` methods document their parameters
- [ ] All public methods have docstrings with Args/Returns/Raises as needed
- [ ] Dataclasses use "Parameters:" section for field descriptions
- [ ] Enums document each value in "Parameters:" section
- [ ] Writing is concise and action-oriented
- [ ] No documentation added to private methods (starting with `_`)
- [ ] Existing complete docstrings were left unchanged


================================================
FILE: .claude/skills/pr-description/SKILL.md
================================================
---
name: pr-description
description: Update a GitHub PR description with a summary of changes
---

Update a GitHub pull request description based on the changes in the PR.

## Arguments

```
/pr-description <PR_NUMBER> [--fixes <ISSUE_NUMBERS>]
```

- `PR_NUMBER` (required): The pull request number to update
- `--fixes` (optional): Comma-separated issue numbers that this PR fixes (e.g., `--fixes 123,456`)

Examples:
- `/pr-description 3534`
- `/pr-description 3534 --fixes 123`
- `/pr-description 3534 --fixes 123,456,789`

## Instructions

1. First, gather information about the PR:
   - Use GitHub plugin to get PR details (title, current description, base branch)
   - Use local git to get commits: `git log main..HEAD --oneline`
   - Use local git to get the diff: `git diff main..HEAD`
   - Parse any `--fixes` argument for issue numbers

2. Check the existing PR description:
   - If it already has a complete, accurate description that reflects the changes, do nothing
   - If it's missing sections, incomplete, or outdated compared to the actual changes, proceed to update
   - If it only has the template placeholder text, generate a full description

3. Analyze the changes:
   - Understand the purpose of each commit
   - Identify any breaking changes (API changes, removed features, behavior changes)
   - Look for new features, bug fixes, refactoring, or documentation changes
   - Collect issue numbers from:
     - The `--fixes` argument (if provided)
     - Commit messages (patterns like "Fixes #123", "Closes #456", "Resolves #789")

4. Generate or update the PR description with these sections:

## PR Description Format

### Summary (always include)

Brief bullet points describing what changed and why. Focus on the *purpose* and *impact*, not implementation details.

```markdown
## Summary

- Added X to enable Y
- Fixed bug where Z would happen
- Refactored W for better maintainability
```

### Breaking Changes (include only if applicable)

Document any changes that affect existing users or APIs.

```markdown
## Breaking Changes

- `ClassName.method()` now requires a `param` argument
- Removed deprecated `old_function()` - use `new_function()` instead
```

### Testing (include when non-obvious)

How to verify the changes work. Skip for trivial changes.

```markdown
## Testing

- Run `uv run pytest tests/test_feature.py` to verify the fix
- Example usage: `uv run examples/new_feature.py`
```

### Fixes (include if issues are provided or found in commits)

List issues this PR fixes. GitHub will automatically close these issues when the PR is merged.

```markdown
## Fixes

- Fixes #123
- Fixes #456
```

Note: Use "Fixes #X" format (not "Closes" or "Resolves") for consistency. Each issue should be on its own line with "Fixes" to ensure GitHub auto-closes them.

## Guidelines

- **Be concise** - Reviewers should understand the PR in 30 seconds
- **Focus on why** - The diff shows *what* changed, explain *why*
- **Skip empty sections** - Only include sections that have content
- **Use bullet points** - Easier to scan than paragraphs
- **Don't duplicate the diff** - Avoid listing every file or line changed

## Example Output

```markdown
## Summary

- Added `/docstring` skill for documenting Python modules with Google-style docstrings
- Skill finds classes by name and handles conflicts when multiple matches exist
- Skips already-documented code to avoid unnecessary changes

## Testing

/docstring ClassName

## Fixes

- Fixes #123
```

## Checklist

Before updating the PR:

- [ ] Verified existing description needs updating (not already complete)
- [ ] Summary accurately reflects the changes
- [ ] Breaking changes are clearly documented (if any)
- [ ] No unnecessary sections included
- [ ] Description is concise and scannable


================================================
FILE: .claude/skills/pr-submit/SKILL.md
================================================
---
name: pr-submit
description: Create and submit a GitHub PR from the current branch
---

Submit the current changes as a GitHub pull request.

## Instructions

1. Check the current state of the repository:
   - Run `git status` to see staged, unstaged, and untracked changes
   - Run `git diff` to see current changes
   - Run `git log --oneline -10` to see recent commits

2. If there are uncommitted changes relevant to the PR:
   - Ask the user if they want a specific prefix for the branch name (e.g., `alice/`, `fix/`, `feat/`)
   - Create a new branch based on the current branch
   - Commit the changes using multiple commits if the changes are unrelated

3. Push the branch and create the PR:
   - Push with `-u` flag to set upstream tracking
   - Create the PR using `gh pr create`

4. After the PR is created:
   - Run `/changelog <pr_number>` to generate changelog files, then commit and push them
   - Run `/pr-description <pr_number>` to update the PR description

5. Return the PR URL to the user.


================================================
FILE: .claude/skills/squash-commits/SKILL.md
================================================
---
name: squash-commits
description: Reorganize messy branch commits into a small set of logical, meaningful commits without changing any content. Drops merge-from-main commits. Safe: creates a backup branch first.
---

Reorganize the commits on the current branch into a small number of logical commits. Do NOT change any file content — only the commit structure changes.

## Instructions

### 1. Safety check

```bash
git status --short
```

If there are uncommitted changes, stop and tell the user to commit or stash them first.

### 2. Inspect the branch

```bash
git log main..HEAD --oneline
git diff main..HEAD --name-only
```

List every file changed vs `main` and every commit on the branch (excluding merge commits from main).

### 3. Create a backup branch

```bash
git branch backup/<current-branch-name>
```

Tell the user the backup exists so they can recover if needed.

### 4. Soft-reset to main and unstage everything

```bash
git reset --soft main
git restore --staged .
```

All branch changes are now in the working tree, unstaged. No content has changed.

### 5. Plan the logical groups

Read the changed files and the original commit messages to understand what the work covers. Group related files into logical commits. Typical groups:

- Core feature or fix (new source files + modified core files)
- Secondary features or fixes (each as its own commit if distinct)
- Refactoring or renames
- Tests
- Changelogs / docs

Use the changelog files (if any) as a strong hint — each changelog entry often maps to one commit.

Present the proposed grouping to the user and ask for confirmation before committing.

### 6. Commit in logical groups

For each group, stage only the relevant files and commit with a clear message following the project's conventions:

```bash
git add <file1> <file2> ...
git commit -m "..."
```

Use conventional commit prefixes if the project uses them (`feat:`, `fix:`, `refactor:`, `test:`, `chore:`).

### 7. Verify

```bash
git log main..HEAD --oneline
git diff main..HEAD --name-only
git status --short
```

Confirm:
- Commit count is small and each message is meaningful
- The set of changed files vs `main` is identical to before
- Working tree is clean

### 8. Remind about force-push

The branch history has been rewritten. Tell the user they will need to `git push --force-with-lease` when they are ready to update the remote. Do NOT push automatically.

## Rules

- Never change file contents. If you find yourself editing a file, stop.
- Never skip the backup branch step.
- Never force-push without explicit user instruction.
- If any step fails or the result looks wrong, tell the user and suggest restoring from the backup: `git reset --hard backup/<branch-name>`.


================================================
FILE: .claude/skills/update-docs/SKILL.md
================================================
---
name: update-docs
description: Update documentation pages to match source code changes on the current branch
---

Update documentation pages to reflect source code changes on the current branch. Analyzes the diff against main, maps changed source files to their corresponding doc pages, and makes targeted edits.

## Arguments

```
/update-docs [DOCS_PATH]
```

- `DOCS_PATH` (optional): Path to the docs repository root. If not provided, ask the user.

Examples:
- `/update-docs /Users/me/src/docs`
- `/update-docs`

## Instructions

### Step 1: Resolve docs path

If `DOCS_PATH` was provided as an argument, use it. Otherwise, ask the user for the path to their docs repository.

Verify the path exists and contains `server/services/` subdirectory.

### Step 2: Create docs branch

Get the current pipecat branch name:
```bash
git rev-parse --abbrev-ref HEAD
```

In the docs repo, create a new branch off main with a matching name:
```bash
cd DOCS_PATH && git checkout main && git pull && git checkout -b {branch-name}-docs
```

For example, if the pipecat branch is `feat/new-service`, the docs branch becomes `feat/new-service-docs`.

All doc edits in subsequent steps are made on this branch.

### Step 3: Detect changed source files

Run:
```bash
git diff main..HEAD --name-only
```

Filter to files that could affect documentation:
- `src/pipecat/services/**/*.py` (service implementations)
- `src/pipecat/transports/**/*.py` (transport implementations)
- `src/pipecat/serializers/**/*.py` (serializer implementations)
- `src/pipecat/processors/**/*.py` (processor implementations)
- `src/pipecat/audio/**/*.py` (audio utilities)
- `src/pipecat/turns/**/*.py` (turn management)
- `src/pipecat/observers/**/*.py` (observers)
- `src/pipecat/pipeline/**/*.py` (pipeline core)

Ignore `__init__.py`, `__pycache__`, test files, and files that only contain type re-exports.

### Step 4: Map source files to doc pages

For each changed source file, find the corresponding doc page. Read the mapping file at `.claude/skills/update-docs/SOURCE_DOC_MAPPING.md` and apply its tiered lookup: tier 1 (known exceptions) → tier 2 (pattern matching) → tier 3 (search fallback). **First match wins.**

### Step 5: Analyze each source-doc pair

For each mapped pair:

1. **Read the full source file** to understand current state
2. **Read the diff** for that file: `git diff main..HEAD -- <source_file>`
3. **Read the current doc page** in full

Identify what changed by comparing source to docs:

- **Constructor parameters**: Compare `__init__` signature to the Configuration section's `<ParamField>` entries
- **InputParams fields**: Compare `InputParams(BaseModel)` class fields to the InputParams table
- **Event handlers**: Compare `_register_event_handler` calls and event handler definitions to Event Handlers section
- **Class names / imports**: Check if Usage examples reference correct names
- **Behavioral changes**: Check if Notes section needs updating

### Step 6: Make targeted edits

For each doc page that needs updates, edit **only the sections that need changes**. Preserve all other content exactly as-is.

#### Rules

- **Never remove content** unless the corresponding source code was removed
- **Never rewrite sections** that are already accurate
- **Match existing formatting** — if the page uses `<ParamField>` tags, use them; if it uses tables, use tables
- **Keep descriptions concise** — match the tone and length of surrounding content
- **Preserve CardGroup, links, and examples** unless they reference removed functionality
- **Don't touch frontmatter** unless the class was renamed

#### Section-specific guidance

**Configuration** (constructor params):
- Use `<ParamField path="name" type="type" default="value">` format if the page already uses it
- Add new params in logical order (required first, then optional)
- Remove params that no longer exist in source
- Update types/defaults that changed

**InputParams** (runtime settings):
- Use markdown table format: `| Parameter | Type | Default | Description |`
- Match the field names and types from the `InputParams(BaseModel)` class
- Include the default values from the source

**Usage** (code examples):
- Update import paths, class names, and parameter names
- Only modify examples if they would break or be misleading with the new API
- Don't rewrite working examples just to add new optional params

**Notes**:
- Add notes for new behavioral gotchas or breaking changes
- Remove notes about limitations that were fixed
- Keep existing notes that are still accurate

**Event Handlers**:
- Update the event table and example code
- Add new events, remove deleted ones
- Update handler signatures if they changed

**Overview / Key Features / Prerequisites**:
- Only update if the PR fundamentally changes what the service does (new capability, removed capability, renamed class)
- Most PRs will NOT need changes to these sections

### Step 7: Update guides

Guides at `DOCS_PATH/guides/` reference specific class names, parameters, imports, and code patterns. After completing reference doc edits, check if any guides need updates too.

For each changed source file, collect the class names, renamed parameters, and changed imports from the diff. Search the guides directory:
```bash
grep -rl "ClassName\|old_param_name" DOCS_PATH/guides/
```

For each guide that references changed code:
1. Read the full guide
2. Update class names, parameter names, import paths, and code examples that are now incorrect
3. **Don't rewrite prose** — only fix the specific references that changed
4. Leave guides alone if they reference the service generally but don't use any changed APIs

Guide directories:
- `guides/learn/` — conceptual tutorials (pipeline, LLM, STT, TTS, etc.)
- `guides/fundamentals/` — practical how-tos (metrics, recording, transcripts, etc.)
- `guides/features/` — feature-specific guides (Gemini Live, OpenAI audio, WhatsApp, etc.)
- `guides/telephony/` — telephony integration guides (Twilio, Plivo, Telnyx, etc.)

### Step 8: Identify doc gaps

After processing all mapped pairs, check for two kinds of gaps:

**Missing pages**: Source files that had no doc page mapping (neither tier 1, 2, nor 3) and are not marked as "(skip)". For each, tell the user:
- The source file path
- The main class(es) it defines
- Whether a new doc page should be created

**Missing sections**: Mapped doc pages that are missing standard sections compared to the source. For example, a transport page with no Configuration section, or a service page with no InputParams table when the source defines `InputParams(BaseModel)`. Flag these and offer to add the missing sections.

If the user wants a new page, do all three of the following:

#### 8a: Create the doc page

Create the new `.mdx` file using this template structure:
```
---
title: "Service Name"
description: "Brief description"
---

## Overview

[Description from class docstring or source analysis]

<CardGroup cols={2}>
  [Cards for API reference and examples if available]
</CardGroup>

## Installation

```bash
uv add "pipecat-ai[package-name]"
```

## Prerequisites

[Environment variables and account setup]

## Configuration

[ParamField entries for constructor params]

## InputParams

[Table of InputParams fields, if the service has them]

## Usage

### Basic Setup

```python
[Minimal working example]
```

## Notes

[Important caveats]

## Event Handlers

[Event table and example code]
```

#### 8b: Add to docs.json

Add the new page path to `DOCS_PATH/docs.json` in the correct navigation group. The path format is `server/services/{category}/{provider}` (without the `.mdx` extension).

Find the matching group in the navigation structure:
- **STT** → `"group": "Speech-to-Text"` under Services
- **TTS** → `"group": "Text-to-Speech"` under Services
- **LLM** → `"group": "LLM"` under Services
- **S2S** → `"group": "Speech-to-Speech"` under Services
- **Transport** → `"group": "Transport"` under Services
- **Serializer** → `"group": "Serializers"` under Services
- **Image generation** → `"group": "Image Generation"` under Services
- **Video** → `"group": "Video"` under Services
- **Memory** → `"group": "Memory"` under Services
- **Vision** → `"group": "Vision"` under Services
- **Analytics** → `"group": "Analytics & Monitoring"` under Services

Insert the new entry **alphabetically** within the group's `pages` array. For example, adding a new STT service "foo":
```json
{
  "group": "Speech-to-Text",
  "pages": [
    "server/services/stt/assemblyai",
    "server/services/stt/aws",
    ...
    "server/services/stt/foo",
    ...
  ]
}
```

#### 8c: Add to supported-services.mdx

Add a new row to the correct category table in `DOCS_PATH/server/services/supported-services.mdx`.

Use this format:
```
| [DisplayName](/server/services/{category}/{provider}) | `uv add "pipecat-ai[package]"` |
```

To determine the correct values:
- **DisplayName**: Use the service's human-readable name (e.g., "ElevenLabs", "AWS Polly", "Google Gemini")
- **package**: Look at the service's `pyproject.toml` extras or the import pattern in the source code. For example, if the service is in `src/pipecat/services/foo/`, the package is typically `foo`.
- If no pip dependencies are required, use `No dependencies required` instead.

Insert the new row **alphabetically** within the table. Match the column alignment of the existing rows.

### Step 9: Output summary

After all edits are complete, print a summary:

```
## Documentation Updates

### Updated reference pages
- `server/services/stt/deepgram.mdx` — Updated Configuration (added `new_param`), InputParams (updated `language` default)
- `server/services/tts/elevenlabs.mdx` — Updated Event Handlers (added `on_connected`)

### Updated guides
- `guides/learn/speech-to-text.mdx` — Updated code example (renamed `old_param` → `new_param`)

### New service pages
- `server/services/tts/newprovider.mdx` — Created page, added to docs.json (Text-to-Speech), added to supported-services.mdx

### Unmapped source files
- `src/pipecat/services/newprovider/tts.py` — NewProviderTTSService (no doc page exists)

### Skipped files
- `src/pipecat/services/ai_service.py` — internal base class
```

## Guidelines

- **Be conservative** — only change what the diff warrants. Don't "improve" docs beyond what changed in source.
- **Read before editing** — always read the full doc page before making changes so you understand the existing structure.
- **Preserve voice** — match the writing style of the existing doc page, don't impose a different tone.
- **One PR at a time** — this skill operates on the current branch's diff against main. Don't look at other branches.
- **Parallel analysis** — when multiple source files map to different doc pages, analyze and edit them in parallel for efficiency.
- **Shared source files** — files like `services/google/google.py` are shared bases. Check which services import from them and update all affected doc pages.

## Checklist

Before finishing, verify:

- [ ] All changed source files were checked against the mapping table
- [ ] Each doc page edit matches the actual source code change (not guessed)
- [ ] No content was removed unless the corresponding source was removed
- [ ] New parameters have accurate types and defaults from source
- [ ] Formatting matches the existing page style
- [ ] Guides referencing changed APIs were checked and updated
- [ ] New service pages were added to `docs.json` in the correct group, alphabetically
- [ ] New service pages were added to `supported-services.mdx` in the correct table, alphabetically
- [ ] Unmapped files were reported to the user


================================================
FILE: .claude/skills/update-docs/SOURCE_DOC_MAPPING.md
================================================
# Source-to-Doc Mapping

Maps pipecat source files to their documentation pages. Source paths are relative to `src/pipecat/`. Doc paths are relative to `DOCS_PATH`.

## Name mismatches

These source paths don't follow the standard `services/{provider}/{type}.py` → `server/services/{type}/{provider}.mdx` pattern.

| Source path | Doc page |
|---|---|
| `services/google/llm.py` | `server/services/llm/gemini.mdx` |
| `services/google/llm_vertex.py` | `server/services/llm/google-vertex.mdx` |
| `services/google/google.py` | (shared base — check which services use it) |
| `services/google/gemini_live/**` | `server/services/s2s/gemini-live.mdx` |
| `services/google/gemini_live/llm_vertex.py` | `server/services/s2s/gemini-live-vertex.mdx` |
| `services/aws_nova_sonic/**` | `server/services/s2s/aws.mdx` |
| `services/ultravox/**` | `server/services/s2s/ultravox.mdx` |
| `services/grok/realtime/**` | `server/services/s2s/grok.mdx` |
| `services/openai/realtime/**` | `server/services/s2s/openai.mdx` |
| `processors/frameworks/rtvi.py` | `server/frameworks/rtvi/rtvi-processor.mdx` and `server/frameworks/rtvi/rtvi-observer.mdx` |
| `processors/transcript_processor.py` | `server/utilities/transcript-processor.mdx` |
| `processors/user_idle_processor.py` | `server/utilities/user-idle-processor.mdx` |
| `processors/idle_frame_processor.py` | `server/pipeline/pipeline-idle-detection.mdx` |
| `pipeline/task.py` | `server/pipeline/pipeline-task.mdx` |
| `pipeline/runner.py` | `server/utilities/runner/guide.mdx` |
| `transports/base_transport.py` | `server/services/transport/transport-params.mdx` |

## Skip list

These files should never trigger doc updates.

| Pattern | Reason |
|---|---|
| `services/ai_service.py` | Internal base class |
| `services/stt_service.py` | Internal base class |
| `services/tts_service.py` | Internal base class |
| `services/llm_service.py` | Internal base class |
| `services/websocket_service.py` | Internal base class |
| `services/openai_realtime_beta/**` | Deprecated |
| `services/openai_realtime/**` | Deprecated |
| `services/gemini_multimodal_live/**` | Deprecated |
| `services/aws/agent_core.py` | Internal |
| `services/aws/sagemaker/**` | No doc page |
| `transports/base_input.py` | Internal base class |
| `transports/base_output.py` | Internal base class |
| `transports/websocket/client.py` | No doc page |
| `serializers/base_serializer.py` | Internal base class |
| `serializers/protobuf.py` | Internal |
| `processors/audio/**` | Internal |
| `pipeline/pipeline.py` | Core architecture, not a service doc |

## Pattern matching

For files not in the tables above, apply these patterns. Convert underscores to hyphens in provider names for doc filenames.

| Source pattern | Doc pattern |
|---|---|
| `services/{provider}/stt*.py` | `server/services/stt/{provider}.mdx` |
| `services/{provider}/tts*.py` | `server/services/tts/{provider}.mdx` |
| `services/{provider}/llm*.py` | `server/services/llm/{provider}.mdx` |
| `services/{provider}/image*.py` | `server/services/image-generation/{provider}.mdx` |
| `services/{provider}/video*.py` | `server/services/video/{provider}.mdx` |
| `services/{provider}/realtime/**` | `server/services/s2s/{provider}.mdx` |
| `transports/{name}/**` | `server/services/transport/{name}.mdx` |
| `serializers/{name}.py` | `server/services/serializers/{name}.mdx` |
| `observers/**` | `server/utilities/observers/` (match by class name) |
| `audio/vad/**` | `server/utilities/audio/` (match by class name) |
| `audio/filters/**` | `server/utilities/audio/` (match by class name) |
| `audio/mixers/**` | `server/utilities/audio/` (match by class name) |
| `processors/filters/**` | `server/utilities/filters/` (match by class name) |

If the doc file doesn't exist at the resolved path, the file is **unmapped**.

## Search fallback

For files that don't match any table or pattern above:
1. Extract the main class name(s) from the source file
2. Search the docs directory for that class name: `grep -r "ClassName" DOCS_PATH/server/`
3. If found in a doc page, use that as the mapping


================================================
FILE: .claude-plugin/marketplace.json
================================================
{
  "name": "pipecat-dev-skills",
  "owner": {
    "name": "Pipecat"
  },
  "metadata": {
    "description": "Development workflow skills for contributing to the Pipecat project",
    "version": "1.0.0"
  },
  "plugins": [
    {
      "name": "pipecat-dev",
      "description": "Development workflow skills for contributing to the Pipecat project",
      "version": "1.0.0",
      "source": "./",
      "skills": [
        "./.claude/skills/changelog",
        "./.claude/skills/cleanup",
        "./.claude/skills/code-review",
        "./.claude/skills/docstring",
        "./.claude/skills/pr-description",
        "./.claude/skills/pr-submit",
        "./.claude/skills/update-docs"
      ]
    }
  ]
}


================================================
FILE: .github/ISSUE_TEMPLATE/1-bug_report.yml
================================================
name: Bug report
description: Report a bug or unexpected behavior
type: Bug
body:
  - type: markdown
    attributes:
      value: |
        ## Bug Report

        Thank you for taking the time to fill out this bug report.

  - type: markdown
    attributes:
      value: |
        ### Environment

  - type: input
    id: pipecat-version
    attributes:
      label: pipecat version
      description: Which version are you using?
      placeholder: e.g., 0.0.63
    validations:
      required: true

  - type: input
    id: python-version
    attributes:
      label: Python version
      description: Which Python version are you using?
      placeholder: e.g., 3.12.8
    validations:
      required: true

  - type: input
    id: os
    attributes:
      label: Operating System
      description: Which OS are you using?
      placeholder: e.g., Ubuntu 24.04, Windows 11, macOS 12.5
    validations:
      required: true

  - type: textarea
    id: description
    attributes:
      label: Issue description
      description: Provide a clear description of the issue.
    validations:
      required: true

  - type: textarea
    id: repro
    attributes:
      label: Reproduction steps
      description: List the steps to reproduce the issue.
      placeholder: |
        1. Do this...
        2. Then do that...
        3. Observe the error...
    validations:
      required: true

  - type: textarea
    id: expected
    attributes:
      label: Expected behavior
      description: What did you expect to happen?
    validations:
      required: true

  - type: textarea
    id: actual
    attributes:
      label: Actual behavior
      description: What actually happened?
    validations:
      required: true

  - type: textarea
    id: logs
    attributes:
      label: Logs
      description: If applicable, include any relevant logs or error messages
      render: shell
    validations:
      required: false


================================================
FILE: .github/ISSUE_TEMPLATE/2-question.yml
================================================
name: Question
description: Ask a question or get help
type: Question
body:
  - type: markdown
    attributes:
      value: |
        ## Question

        Use this form to ask a question about pipecat.

  - type: markdown
    attributes:
      value: |
        ### Environment (if applicable)

  - type: input
    id: pipecat-version
    attributes:
      label: pipecat version
      description: Which version are you using? (if applicable)
      placeholder: e.g., 0.0.63
    validations:
      required: false

  - type: input
    id: python-version
    attributes:
      label: Python version
      description: Which Python version are you using? (if applicable)
      placeholder: e.g., 3.12.8
    validations:
      required: false

  - type: input
    id: os
    attributes:
      label: Operating System
      description: Which OS are you using? (if applicable)
      placeholder: e.g., Ubuntu 24.04, Windows 11, macOS 12.5
    validations:
      required: false

  - type: textarea
    id: question
    attributes:
      label: Question
      description: Provide your question in detail here.
    validations:
      required: true

  - type: textarea
    id: tried
    attributes:
      label: What I've tried
      description: Describe what you've already tried or research you've done.
      placeholder: I've looked at the documentation and tried...
    validations:
      required: false

  - type: textarea
    id: context
    attributes:
      label: Context
      description: Any additional context or information that might help others understand your question better.
    validations:
      required: false


================================================
FILE: .github/ISSUE_TEMPLATE/3-feature_request.yml
================================================
name: Feature request
description: Suggest an enhancement or new feature
type: Enhancement
body:
  - type: markdown
    attributes:
      value: |
        ## Feature Request

        Thank you for suggesting an enhancement to pipecat.

  - type: textarea
    id: problem
    attributes:
      label: Problem Statement
      description: A clear description of the problem this feature would solve.
      placeholder: I'm always frustrated when...
    validations:
      required: true

  - type: textarea
    id: solution
    attributes:
      label: Proposed Solution
      description: A clear and concise description of what you want to happen.
    validations:
      required: true

  - type: textarea
    id: alternatives
    attributes:
      label: Alternative Solutions
      description: Any alternative solutions or features you've considered.
    validations:
      required: false

  - type: textarea
    id: context
    attributes:
      label: Additional Context
      description: Add any other context, mockups, or screenshots about the feature request here.
      placeholder: You can drag and drop images here to include them.
    validations:
      required: false

  - type: checkboxes
    id: contribution
    attributes:
      label: Would you be willing to help implement this feature?
      options:
        - label: Yes, I'd like to contribute
        - label: No, I'm just suggesting


================================================
FILE: .github/ISSUE_TEMPLATE/4-service-issue.yml
================================================
name: Service Issue
description: An issue with a third-party service
type: Service Issue
body:
  - type: markdown
    attributes:
      value: |
        ## Service Issue

        Use this form to report an issue with a third-party service integration.

  - type: input
    id: pipecat-version
    attributes:
      label: pipecat version
      description: Which version are you using?
      placeholder: e.g., 0.0.63
    validations:
      required: true

  - type: input
    id: service-name
    attributes:
      label: Service Name
      description: Which third-party service is having issues?
      placeholder: e.g., OpenAI, ElevenLabs, Anthropic
    validations:
      required: true

  - type: input
    id: service-version
    attributes:
      label: Service or model version
      description: Which version of the service API or model are you using?
      placeholder: e.g., v1, gpt-4.1
    validations:
      required: false

  - type: textarea
    id: description
    attributes:
      label: Issue Description
      description: Provide a clear description of the service issue.
    validations:
      required: true

  - type: textarea
    id: reproduction
    attributes:
      label: Reproduction Steps
      description: Provide steps to reproduce the issue.
      placeholder: |
        1. Configure service X
        2. Call method Y
        3. See error Z
    validations:
      required: true

  - type: textarea
    id: expected
    attributes:
      label: Expected Behavior
      description: What did you expect to happen?
    validations:
      required: true

  - type: textarea
    id: actual
    attributes:
      label: Actual Behavior
      description: What actually happened?
    validations:
      required: true

  - type: textarea
    id: logs
    attributes:
      label: Error Logs
      description: If available, include any error messages or logs.
      render: shell
    validations:
      required: false


================================================
FILE: .github/ISSUE_TEMPLATE/5-new-service.yml
================================================
name: New Service
description: Request to support a new third-party service
type: New Service
body:
  - type: markdown
    attributes:
      value: |
        ## New Service Request

        Use this form to request support for a new third-party service in pipecat.

  - type: input
    id: service-name
    attributes:
      label: Service Name
      description: What is the name of the third-party service?
      placeholder: e.g., NewAPI, SomeService
    validations:
      required: true

  - type: input
    id: service-website
    attributes:
      label: Service Website
      description: Link to the service's website or documentation
      placeholder: e.g., https://newapi.com
    validations:
      required: true

  - type: textarea
    id: service-description
    attributes:
      label: Service Description
      description: Briefly describe what this service does and how it works.
    validations:
      required: true

  - type: textarea
    id: api-info
    attributes:
      label: API Information
      description: If available, provide details about the service's API.
      placeholder: |
        - API documentation link
        - Authentication method
        - Key endpoints you'd like supported
    validations:
      required: false

  - type: checkboxes
    id: contribution
    attributes:
      label: Would you be willing to help implement this service?
      options:
        - label: Yes, I'd like to contribute
        - label: No, I'm just suggesting


================================================
FILE: .github/ISSUE_TEMPLATE/6-dependency.yml
================================================
name: Dependency Issue
description: An issue with a Pipecat dependency (not a third-party service)
type: Dependency Issue
body:
  - type: markdown
    attributes:
      value: |
        ## Dependency Issue

        Use this form to report an issue with a Pipecat dependency.

  - type: input
    id: pipecat-version
    attributes:
      label: pipecat version
      description: Which version are you using?
      placeholder: e.g., 0.0.63
    validations:
      required: true

  - type: input
    id: dependency-name
    attributes:
      label: Dependency Name
      description: Which Pipecat dependency is causing the issue?
      placeholder: e.g., openai, anthropic, fastapi
    validations:
      required: true

  - type: input
    id: dependency-version
    attributes:
      label: Dependency Version
      description: Which version of the dependency are you using?
      placeholder: e.g., 1.2.3
    validations:
      required: true

  - type: textarea
    id: description
    attributes:
      label: Issue Description
      description: Provide a clear description of the dependency issue.
    validations:
      required: true

  - type: textarea
    id: impact
    attributes:
      label: Impact
      description: How is this dependency issue affecting your usage of pipecat?
    validations:
      required: true

  - type: textarea
    id: reproduction
    attributes:
      label: Reproduction Steps
      description: If applicable, provide steps to reproduce the issue.
      placeholder: |
        1. Install dependency X
        2. Run command Y
        3. See error Z
    validations:
      required: false

  - type: textarea
    id: logs
    attributes:
      label: Error Logs
      description: If applicable, include any relevant error messages or logs.
      render: shell
    validations:
      required: false


================================================
FILE: .github/ISSUE_TEMPLATE/7-troubleshooting.yml
================================================
name: Troubleshooting
description: Help with a specific use case
type: Troubleshooting
body:
  - type: markdown
    attributes:
      value: |
        ## Troubleshooting Request

        Use this form to get help with a specific use case or implementation.

  - type: input
    id: pipecat-version
    attributes:
      label: pipecat version
      description: Which version are you using?
      placeholder: e.g., 0.0.63
    validations:
      required: true

  - type: input
    id: python-version
    attributes:
      label: Python version
      description: Which version of Python are you using?
      placeholder: e.g., 3.12.8
    validations:
      required: true

  - type: input
    id: os
    attributes:
      label: Operating System
      description: Which OS are you using?
      placeholder: e.g., Ubuntu 24.04, Windows 11, macOS 12.5
    validations:
      required: true

  - type: textarea
    id: use-case
    attributes:
      label: Use Case Description
      description: Describe what you're trying to accomplish with pipecat.
    validations:
      required: true

  - type: textarea
    id: current-approach
    attributes:
      label: Current Approach
      description: What have you tried so far? Include code snippets if relevant.
      render: python
    validations:
      required: true

  - type: textarea
    id: errors
    attributes:
      label: Errors or Unexpected Behavior
      description: Describe any errors or unexpected behavior you're encountering.
    validations:
      required: true

  - type: textarea
    id: additional-context
    attributes:
      label: Additional Context
      description: Any other information that might help us understand your situation.
    validations:
      required: false


================================================
FILE: .github/ISSUE_TEMPLATE/config.yml
================================================
blank_issues_enabled: false


================================================
FILE: .github/PULL_REQUEST_TEMPLATE.md
================================================
#### Please describe the changes in your PR. If it is addressing an issue, please reference that as well.

================================================
FILE: .github/workflows/build.yaml
================================================
name: build

on:
  workflow_dispatch:
  push:
    branches:
      - main
  pull_request:
    branches:
      - "**"
    paths-ignore:
      - "docs/**"

concurrency:
  group: build-${{ github.event.pull_request.number || github.ref }}
  cancel-in-progress: true

jobs:
  build:
    name: "Build and Install"
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Install uv
        uses: astral-sh/setup-uv@v3
        with:
          version: "latest"

      - name: Set up Python
        run: uv python install 3.12

      - name: Install development dependencies
        run: uv sync --group dev

      - name: Build project
        run: uv build

      - name: Install project in editable mode
        run: uv pip install --editable .


================================================
FILE: .github/workflows/coverage.yaml
================================================
name: coverage

on:
  workflow_dispatch:
  push:
    branches:
      - main
  pull_request:
    branches:
      - "**"
    paths-ignore:
      - "docs/**"

jobs:
  coverage:
    name: "Coverage"
    runs-on: ubuntu-latest
    steps:
      - name: Checkout repo
        uses: actions/checkout@v4

      - name: Install uv
        uses: astral-sh/setup-uv@v3
        with:
          version: "latest"

      - name: Set up Python
        run: uv python install 3.12

      - name: Install system packages
        run: |
          sudo apt-get update
          sudo apt-get install -y portaudio19-dev

      - name: Install dependencies
        run: |
          uv sync --group dev \
            --extra anthropic \
            --extra aws \
            --extra azure \
            --extra cli \
            --extra daily \
            --extra deepgram \
            --extra google \
            --extra langchain \
            --extra livekit \
            --extra pgmq \
            --extra piper \
            --extra redis \
            --extra runner \
            --extra sagemaker \
            --extra tracing \
            --extra websocket

      - name: Run tests with coverage
        run: |
          uv run coverage run
          uv run coverage xml

      - name: Upload coverage to Codecov
        uses: codecov/codecov-action@v5
        with:
          token: ${{ secrets.CODECOV_TOKEN }}
          slug: pipecat-ai/pipecat


================================================
FILE: .github/workflows/format.yaml
================================================
name: format

on:
  workflow_dispatch:
  push:
    branches:
      - main
  pull_request:
    branches:
      - "**"
    paths-ignore:
      - "docs/**"

concurrency:
  group: build-format-${{ github.event.pull_request.number || github.ref }}
  cancel-in-progress: true

jobs:
  ruff-format:
    name: "Code quality checks"
    runs-on: ubuntu-latest
    steps:
      - name: Checkout repo
        uses: actions/checkout@v4

      - name: Install uv
        uses: astral-sh/setup-uv@v3
        with:
          version: "latest"

      - name: Set up Python
        run: uv python install 3.12

      - name: Install development dependencies
        # `--all-extras` (matching the dev setup in README.md) so pyright can
        # resolve types from various optional dependencies.
        run: uv sync --group dev --all-extras --no-extra gstreamer --no-extra local

      - name: Ruff formatter
        id: ruff-format
        run: uv run ruff format --diff

      - name: Ruff linter (all rules)
        id: ruff-check
        run: uv run ruff check

      - name: Type check (pyright)
        id: pyright
        run: uv run pyright

      - name: CLI registry drift check
        id: registry-drift
        # Regenerate the CLI's service registry against the source and fail if it drifted.
        # This runs here because regenerating _configs.py introspects constructor
        # signatures and needs the service SDKs, which this job already installs via
        # --all-extras. Catches both import-path and constructor-signature drift, and
        # backstops commits made with --no-verify or without the pre-commit hook.
        run: |
          uv run scripts/cli/update_registry.py
          git diff --exit-code src/pipecat/cli/registry/_imports.py src/pipecat/cli/registry/_configs.py


================================================
FILE: .github/workflows/generate-changelog.yml
================================================
name: Generate Changelog for Release

on:
  workflow_dispatch:
    inputs:
      version:
        description: "Release version (e.g., 0.0.97)"
        required: true
        type: string
      date:
        description: "Release date (YYYY-MM-DD format, defaults to today)"
        required: false
        type: string
        default: ""

permissions:
  contents: write
  pull-requests: write

jobs:
  generate-changelog:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout repository
        uses: actions/checkout@v4
        with:
          fetch-depth: 0

      - name: Set up Python
        uses: actions/setup-python@v5
        with:
          python-version: "3.12"

      - name: Install uv
        uses: astral-sh/setup-uv@v4
        with:
          enable-cache: true

      - name: Install dependencies
        run: |
          uv sync --group dev

      - name: Set release date
        id: set_date
        run: |
          if [ -z "${{ inputs.date }}" ]; then
            RELEASE_DATE=$(date +%Y-%m-%d)
            echo "Using today's date: $RELEASE_DATE"
          else
            RELEASE_DATE="${{ inputs.date }}"
            echo "Using provided date: $RELEASE_DATE"
          fi
          echo "release_date=$RELEASE_DATE" >> $GITHUB_OUTPUT

      - name: Validate inputs
        run: |
          # Validate version format (basic check)
          if ! [[ "${{ inputs.version }}" =~ ^[0-9]+\.[0-9]+\.[0-9]+.*$ ]]; then
            echo "Error: Version must be in format X.Y.Z (e.g., 0.0.97)"
            exit 1
          fi

          # Validate date format if provided
          if [ -n "${{ inputs.date }}" ]; then
            if ! date -d "${{ inputs.date }}" >/dev/null 2>&1; then
              # Try macOS date format
              if ! date -j -f "%Y-%m-%d" "${{ inputs.date }}" >/dev/null 2>&1; then
                echo "Error: Date must be in YYYY-MM-DD format (e.g., 2025-12-04)"
                exit 1
              fi
            fi
          fi

      - name: Check for changelog fragments
        id: check_fragments
        run: |
          FRAGMENT_COUNT=$(find changelog -name "*.md" ! -name "_template.md.j2" | wc -l | tr -d ' ')
          echo "fragment_count=$FRAGMENT_COUNT" >> $GITHUB_OUTPUT

          if [ "$FRAGMENT_COUNT" -eq "0" ]; then
            echo "❌ Error: No changelog fragments found in changelog/"
            echo ""
            echo "Cannot create a release without changelog entries."
            echo "Add changelog fragments to the changelog/ directory (e.g., 1234.added.md) and try again."
            exit 1
          fi

          # Validate fragment types
          VALID_TYPES="added changed deprecated removed fixed performance security other"
          INVALID_FRAGMENTS=""

          for file in changelog/*.md; do
            # Skip template
            if [[ "$file" == "changelog/_template.md.j2" ]]; then
              continue
            fi
            
            # Extract type from filename (e.g., 1234.added.md -> added)
            filename=$(basename "$file")
            # Handle both 1234.added.md and 1234.added.2.md patterns
            type=$(echo "$filename" | sed -E 's/^[0-9]+\.([a-z]+)(\.[0-9]+)?\.md$/\1/')
            
            # Check if type is valid
            if ! echo "$VALID_TYPES" | grep -wq "$type"; then
              INVALID_FRAGMENTS="$INVALID_FRAGMENTS\n  - $filename (type: '$type')"
            fi
          done

          if [ -n "$INVALID_FRAGMENTS" ]; then
            echo "❌ Error: Invalid changelog fragment types found:"
            echo -e "$INVALID_FRAGMENTS"
            echo ""
            echo "Valid types are: $VALID_TYPES"
            echo "Example: 1234.added.md, 5678.fixed.md"
            exit 1
          fi

          echo "✓ Found $FRAGMENT_COUNT changelog fragment(s)"
          echo "has_fragments=true" >> $GITHUB_OUTPUT

      - name: Preview changelog
        run: |
          echo "## Preview of changelog for version ${{ inputs.version }}"
          echo ""
          uv run towncrier build --draft --version "${{ inputs.version }}" --date "${{ steps.set_date.outputs.release_date }}"

      - name: Build changelog
        run: |
          uv run towncrier build --version "${{ inputs.version }}" --date "${{ steps.set_date.outputs.release_date }}" --yes

      - name: Create Pull Request
        uses: peter-evans/create-pull-request@v7
        with:
          token: ${{ secrets.GITHUB_TOKEN }}
          commit-message: "Update changelog for version ${{ inputs.version }}"
          title: "Release ${{ inputs.version }} - Changelog Update"
          body: |
            ## Changelog Update for Release ${{ inputs.version }}

            This PR updates the CHANGELOG.md with all changes for version **${{ inputs.version }}**.

            ### Summary
            - **Version:** ${{ inputs.version }}
            - **Date:** ${{ steps.set_date.outputs.release_date }}
            - **Fragments processed:** ${{ steps.check_fragments.outputs.fragment_count }}

            ### What this PR does
            - ✅ Adds new release section to CHANGELOG.md
            - ✅ Removes processed changelog fragments
            - ✅ Ready to merge for release

            ### Next Steps
            1. Review the changelog entries below
            2. Make any necessary edits to CHANGELOG.md if needed
            3. Merge this PR
            4. Continue with your release process

            ---

            <details>
            <summary>📋 Preview of changes</summary>

            The changelog has been updated with entries from the following fragments:

            ```bash
            ${{ steps.check_fragments.outputs.fragment_count }} fragments processed
            ```

            </details>
          branch: changelog-${{ inputs.version }}
          delete-branch: true
          labels: |
            changelog
            release


================================================
FILE: .github/workflows/publish.yaml
================================================
name: publish

on:
  workflow_dispatch:
    inputs:
      gitref:
        type: string
        description: 'what git tag to build (e.g. v0.0.74)'
        required: true

jobs:
  build:
    name: 'Build and upload wheels'
    runs-on: ubuntu-latest
    steps:
      - name: Checkout repo
        uses: actions/checkout@v4
        with:
          ref: ${{ github.event.inputs.gitref }}

      - name: Install uv
        uses: astral-sh/setup-uv@v3
        with:
          version: 'latest'
      - name: Set up Python
        run: uv python install 3.12
      - name: Install development dependencies
        run: uv sync --group dev
      - name: Build project
        run: uv build
      - name: Upload wheels
        uses: actions/upload-artifact@v4
        with:
          name: wheels
          path: ./dist

  publish-to-pypi:
    name: 'Publish to PyPI'
    runs-on: ubuntu-latest
    needs: [build]
    environment:
      name: pypi
      url: https://pypi.org/p/pipecat-ai
    permissions:
      id-token: write
    steps:
      - name: Download wheels
        uses: actions/download-artifact@v4
        with:
          name: wheels
          path: ./dist
      - name: Publish to PyPI
        uses: pypa/gh-action-pypi-publish@release/v1
        with:
          verbose: true
          print-hash: true

  publish-to-test-pypi:
    name: 'Publish to Test PyPI'
    runs-on: ubuntu-latest
    needs: [build]
    environment:
      name: testpypi
      url: https://test.pypi.org/p/pipecat-ai
    permissions:
      id-token: write
    steps:
      - name: Download wheels
        uses: actions/download-artifact@v4
        with:
          name: wheels
          path: ./dist
      - name: Publish to Test PyPI
        uses: pypa/gh-action-pypi-publish@release/v1
        with:
          verbose: true
          print-hash: true
          repository-url: https://test.pypi.org/legacy/


================================================
FILE: .github/workflows/publish_test.yaml
================================================
name: publish-test

on: workflow_dispatch

jobs:
  build:
    name: 'Build and upload wheels'
    runs-on: ubuntu-latest
    steps:
      - name: Checkout repo
        uses: actions/checkout@v4
        with:
          fetch-tags: true
          fetch-depth: 100
      - name: Install uv
        uses: astral-sh/setup-uv@v3
        with:
          version: 'latest'
      - name: Set up Python
        run: uv python install 3.12
      - name: Install development dependencies
        run: uv sync --group dev
      - name: Build project
        run: uv build
      - name: Upload wheels
        uses: actions/upload-artifact@v4
        with:
          name: wheels
          path: ./dist

  publish-to-test-pypi:
    name: 'Publish to Test PyPI'
    runs-on: ubuntu-latest
    needs: [build]
    environment:
      name: testpypi
      url: https://test.pypi.org/p/pipecat-ai
    permissions:
      id-token: write
    steps:
      - name: Download wheels
        uses: actions/download-artifact@v4
        with:
          name: wheels
          path: ./dist
      - name: Publish to Test PyPI
        uses: pypa/gh-action-pypi-publish@release/v1
        with:
          verbose: true
          print-hash: true
          repository-url: https://test.pypi.org/legacy/


================================================
FILE: .github/workflows/python-compatibility.yaml
================================================
name: Python Compatibility Test

on:
  push:
    branches: [main, develop]
    paths: ['pyproject.toml']
  pull_request:
    branches: [main, develop]
    paths: ['pyproject.toml']

jobs:
  test-compatibility:
    runs-on: ubuntu-latest
    strategy:
      fail-fast: false
      matrix:
        python-version: ['3.11.15', '3.12.13', '3.13.12', '3.14.3']

    name: Python ${{ matrix.python-version }}
    steps:
      - name: Checkout code
        uses: actions/checkout@v4

      - name: Install system dependencies
        run: |
          sudo apt-get update
          sudo apt-get install -y \
            portaudio19-dev \
            libcairo2-dev \
            libgirepository1.0-dev \
            pkg-config

      - name: Install uv
        uses: astral-sh/setup-uv@v4
        with:
          version: 'latest'

      - name: Set up Python ${{ matrix.python-version }}
        run: |
          uv python install ${{ matrix.python-version }}
          uv python pin ${{ matrix.python-version }}

      - name: Test uv sync with all extras
        run: |
          uv sync --group dev --all-extras

      - name: Verify installation
        run: |
          uv run python --version
          uv run python -c "import pipecat; print('✅ Pipecat imports successfully')"


================================================
FILE: .github/workflows/tests.yaml
================================================
name: tests

on:
  workflow_dispatch:
  push:
    branches:
      - main
  pull_request:
    branches:
      - "**"
    paths-ignore:
      - "docs/**"

concurrency:
  group: build-test-${{ github.event.pull_request.number || github.ref }}
  cancel-in-progress: true

jobs:
  test:
    name: "Unit and Integration Tests"
    runs-on: ubuntu-latest
    steps:
      - name: Checkout repo
        uses: actions/checkout@v4

      - name: Install uv
        uses: astral-sh/setup-uv@v3
        with:
          version: "latest"

      - name: Set up Python
        run: uv python install 3.12

      - name: Install system packages
        run: |
          sudo apt-get update
          sudo apt-get install -y portaudio19-dev

      - name: Install dependencies
        run: |
          uv sync --group dev \
            --extra anthropic \
            --extra aws \
            --extra azure \
            --extra cli \
            --extra daily \
            --extra deepgram \
            --extra google \
            --extra langchain \
            --extra livekit \
            --extra pgmq \
            --extra piper \
            --extra redis \
            --extra runner \
            --extra sagemaker \
            --extra tracing \
            --extra websocket

      - name: Test with pytest
        run: |
          uv run pytest


================================================
FILE: .github/workflows/update-docs.yml
================================================
name: Update Documentation on PR Merge

on:
  pull_request_target:
    types: [closed]
    branches: [main]
    paths:
      - "src/pipecat/services/**"
      - "src/pipecat/transports/**"
      - "src/pipecat/serializers/**"
      - "src/pipecat/processors/**"
      - "src/pipecat/audio/**"
      - "src/pipecat/turns/**"
      - "src/pipecat/observers/**"
      - "src/pipecat/pipeline/**"
  workflow_dispatch:
    inputs:
      pr_number:
        description: "PR number to generate docs for"
        required: true
        type: string

jobs:
  update-docs:
    if: >-
      github.event_name == 'workflow_dispatch' ||
      github.event.pull_request.merged == true
    runs-on: ubuntu-latest
    timeout-minutes: 15
    permissions:
      contents: read
      pull-requests: read
      id-token: write
    steps:
      - name: Checkout pipecat
        uses: actions/checkout@v4
        with:
          fetch-depth: 0

      - name: Checkout docs
        uses: actions/checkout@v4
        with:
          repository: pipecat-ai/docs
          token: ${{ secrets.DOCS_SYNC_TOKEN }}
          path: _docs

      - name: Resolve PR number
        id: pr
        run: |
          if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then
            echo "number=${{ inputs.pr_number }}" >> "$GITHUB_OUTPUT"
          else
            echo "number=${{ github.event.pull_request.number }}" >> "$GITHUB_OUTPUT"
          fi

      - name: Update documentation
        uses: anthropics/claude-code-action@v1
        env:
          DOCS_SYNC_TOKEN: ${{ secrets.DOCS_SYNC_TOKEN }}
        with:
          anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
          github_token: ${{ secrets.GITHUB_TOKEN }}
          prompt: |
            You are updating documentation for the pipecat-ai/docs repository based on
            changes merged in PR #${{ steps.pr.outputs.number }} of pipecat-ai/pipecat.

            ## Setup

            1. Read the skill instructions at `.claude/skills/update-docs/SKILL.md`
            2. Read the source-to-doc mapping at `.claude/skills/update-docs/SOURCE_DOC_MAPPING.md`
            3. The docs repository is checked out at `./_docs/`

            ## Get the diff

            Run `gh pr diff ${{ steps.pr.outputs.number }}` to see what changed in the PR.
            Also run `gh pr diff ${{ steps.pr.outputs.number }} --name-only` to get the list of changed files.
            Filter to source files matching the directories listed in SKILL.md Step 3.

            If no relevant source files were changed, exit with "No documentation changes needed."

            ## Follow the skill instructions

            Apply the SKILL.md workflow (Steps 3-9) with these adaptations for automation:

            ### Docs path
            Use `./_docs/` — it's already checked out. Do not ask for a path.

            ### Branch management
            - Branch name: `docs/pr-${{ steps.pr.outputs.number }}`
            - Work inside `./_docs/` for all doc edits and git operations
            - Check if the branch already exists on the remote:
              ```bash
              cd _docs && git fetch origin docs/pr-${{ steps.pr.outputs.number }} 2>/dev/null
              ```
              - If it exists: check it out (supports workflow re-runs)
              - If not: create it from main

            ### Git config
            Before committing in `_docs`, set:
            ```bash
            git config user.name "github-actions[bot]"
            git config user.email "github-actions[bot]@users.noreply.github.com"
            ```

            ### No interactive questions
            Do not ask questions. If you encounter gaps (unmapped files, missing sections,
            ambiguous changes), note them in the PR body under "## Gaps identified".

            ### Creating the docs PR
            After committing all changes in `_docs`, push and create a PR:
            ```bash
            cd _docs
            git push -u origin docs/pr-${{ steps.pr.outputs.number }}
            GH_TOKEN=$DOCS_SYNC_TOKEN gh pr create \
              --repo pipecat-ai/docs \
              --label auto-docs \
              --label pipecat \
              --title "docs: update for pipecat PR #${{ steps.pr.outputs.number }}" \
              --body "$(cat <<'BODY'
            Automated documentation update for [pipecat PR #${{ steps.pr.outputs.number }}](https://github.com/pipecat-ai/pipecat/pull/${{ steps.pr.outputs.number }}).

            ## Changes
            <summarize each doc page updated and what changed>

            ## Gaps identified
            <any unmapped files, missing doc pages, or missing sections — or "None">
            BODY
            )"
            ```

            ### Re-run handling
            If `gh pr create` fails because a PR from that branch already exists,
            push the updated commits and use `gh pr edit` to update the body instead.

            ### No-op
            If after analyzing the diff you determine no documentation changes are needed
            (e.g., only skip-listed files changed, or changes don't affect public API docs),
            exit cleanly without creating a branch or PR. Output "No documentation changes needed."

            ## Important rules
            - Only modify files inside `./_docs/` — never modify pipecat source code
            - Follow the conservative editing rules from SKILL.md Step 6
            - Read each doc page fully before editing (SKILL.md Guidelines)
            - Use `GH_TOKEN=$DOCS_SYNC_TOKEN` for all `gh` commands targeting pipecat-ai/docs
          claude_args: |
            --model claude-sonnet-4-5-20250929
            --max-turns 30
            --allowedTools "Read,Write,Edit,Glob,Grep,Bash"


================================================
FILE: .gitignore
================================================
.vscode
env/
__pycache__/
*~
venv
.venv
.idea
.gradle
.next
next-env.d.ts
local.properties
*.log
*.lock
smart_turn_audio_log
#*#

# Distribution / Packaging
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
share/python-wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST
.DS_Store
.env*
fly.toml

# Examples
examples/**/node_modules/
examples/**/.expo/
examples/**/dist/
examples/**/.vite/
examples/**/*.local
examples/**/npm-debug.*
examples/**/*.jks
examples/**/*.p8
examples/**/*.p12
examples/**/*.key
examples/**/*.mobileprovision
examples/**/*.orig.*
examples/**/web-build/

# macOS
.DS_Store

# Documentation
docs/api/_build/
docs/api/api

# uv
.python-version

# Pipecat
whisker_setup.py

================================================
FILE: .pre-commit-config.yaml
================================================
repos:
  - repo: local
    hooks:
      - id: ruff
        name: ruff
        entry: uv run ruff check --fix
        language: system
        types: [python]
      - id: ruff-format
        name: ruff-format
        entry: uv run ruff format
        language: system
        types: [python]
      # Keep the CLI's service registry in sync with the source. The imports hook
      # regenerates _imports.py (AST-based, no service SDKs needed) when a service
      # module or the metadata changes; if the result differs, the commit aborts so
      # you review + re-stage the regenerated file (same auto-fix flow as ruff above).
      # NOTE: _configs.py is NOT regenerated here — it introspects constructor
      # signatures and needs the full service SDKs (uv sync --all-extras), so signature
      # drift is caught by the CI drift-check, not pre-commit.
      - id: pipecat-cli-registry-imports
        name: regenerate CLI service imports (_imports.py)
        entry: uv run python scripts/cli/imports/update_imports.py
        language: system
        pass_filenames: false
        files: ^(src/pipecat/(services|transports|serializers)/.*\.py|src/pipecat/cli/registry/service_metadata\.py)$
      - id: pipecat-cli-registry-check
        name: check CLI service registry completeness
        entry: uv run python scripts/cli/check_registry.py
        language: system
        pass_filenames: false
        files: ^src/pipecat/cli/registry/.*\.py$
      # Keep the deprecation registry (scripts/deprecations/deprecations.json) in
      # sync with the source. Regenerates it from the .. deprecated:: directives
      # and @deprecated decorators (AST-based, refuses on malformed markers); if
      # the result differs, the commit aborts so you review + re-stage — the same
      # auto-fix flow as the CLI registry imports hook above. The CI drift check
      # (tests.yaml) is the backstop for commits made with --no-verify.
      - id: pipecat-deprecation-registry
        name: regenerate deprecation registry (deprecations.json)
        entry: uv run python scripts/deprecations/generate.py
        language: system
        pass_filenames: false
        files: ^(src/pipecat/.*\.py|scripts/deprecations/.*)$
      # Audit deprecation markers: every @deprecated message matches the canonical
      # template (subject/version/replacement consistent), every `.. deprecated::`
      # directive parses with a removal version, and the registry is up to date.
      # AST-based and whole-tree, so runs once when any relevant file changes.
      # Same check CI runs (tests.yaml), reused here for fast local feedback.
      - id: pipecat-deprecation-markers
        name: check deprecation markers
        entry: uv run pytest tests/test_deprecation_markers.py -q
        language: system
        pass_filenames: false
        files: ^(src/pipecat/.*\.py|scripts/deprecations/.*|tests/test_deprecation_markers\.py)$


================================================
FILE: .readthedocs.yaml
================================================
version: 2

build:
  os: ubuntu-22.04
  tools:
    python: '3.12'
  apt_packages:
    - portaudio19-dev
    - python3-dev
    - libasound2-dev
  jobs:
    post_install:
      - pip install uv
      - UV_PROJECT_ENVIRONMENT=$READTHEDOCS_VIRTUALENV_PATH uv sync --group docs --all-extras --no-extra gstreamer --no-extra local_smart_turn --no-extra moondream --no-extra mlx-whisper

sphinx:
  configuration: docs/api/conf.py
  fail_on_warning: false

search:
  ranking:
    api/*: 5
    getting-started/*: 4
    guides/*: 3

submodules:
  include: all
  recursive: true


================================================
FILE: AGENTS.md
================================================
# AGENTS.md

This file provides guidance to AI coding agents when working with code in this repository.

## Project Overview

Pipecat is an open-source Python framework for building real-time voice and multimodal conversational AI agents. It orchestrates audio/video, AI services, transports, and conversation pipelines using a frame-based architecture.

## Common Commands

```bash
# Setup development environment
uv sync --group dev --all-extras --no-extra gstreamer --no-extra local

# Install pre-commit hooks
uv run pre-commit install

# Run all tests
uv run pytest

# Run a single test file
uv run pytest tests/test_name.py

# Run a specific test
uv run pytest tests/test_name.py::test_function_name

# Preview changelog
uv run towncrier build --draft --version Unreleased

# Lint and format check
uv run ruff check
uv run ruff format --check

# Update dependencies (after editing pyproject.toml)
uv lock && uv sync
```

## Architecture

### Frame-Based Pipeline Processing

All data flows as **Frame** objects through a pipeline of **FrameProcessors**:

```
[Processor1] → [Processor2] → ... → [ProcessorN]
```

**Key components:**

- **Frames** (`src/pipecat/frames/frames.py`): Data units (audio, text, video) and control signals. Flow DOWNSTREAM (input→output) or UPSTREAM (acknowledgments/errors).

- **FrameProcessor** (`src/pipecat/processors/frame_processor.py`): Base processing unit. Each processor receives frames, processes them, and pushes results downstream.

- **Pipeline** (`src/pipecat/pipeline/pipeline.py`): Chains processors together.

- **ParallelPipeline** (`src/pipecat/pipeline/parallel_pipeline.py`): Runs multiple pipelines in parallel.

- **Transports** (`src/pipecat/transports/`): Transports are frame processors used for external I/O layer (Daily WebRTC, LiveKit WebRTC, WebSocket, Local). Abstract interface via `BaseTransport`, `BaseInputTransport` and `BaseOutputTransport`.

- **Workers (`src/pipecat/workers/`)**: A **worker** is the top-level runnable unit (it replaces the old "pipeline task"). `BaseWorker` (`src/pipecat/workers/base_worker.py`) is the abstract base: it owns activation, end/cancel, bus subscription, job RPC, and a default `run()` for bus-only workers. `WorkerParams` configures it. Specialized workers live under `src/pipecat/workers/llm/` (`LLMWorker` adds `@tool` collection; `LLMContextWorker` adds an `LLMContext` plus aggregator pair) and `src/pipecat/workers/ui/` (`UIWorker`).

- **Pipeline Worker (`src/pipecat/pipeline/worker.py`)**: `PipelineWorker` is the `BaseWorker` subclass that wraps a user-defined pipeline — the common single-bot case. It sends the first frame, `StartFrame`, so processors know they can start processing and pushing frames, and internally wraps the pipeline with a source processor (before the pipeline) and a sink processor (at the end) used for error handling, worker-level events, heartbeat monitoring, etc. Optional `bridged=` adds bus edge processors so the pipeline can exchange frames with other workers. `PipelineTask` is a deprecated (1.3.0) alias — construct `PipelineWorker` instead.

- **Worker Runner (`src/pipecat/workers/runner.py`)**: `WorkerRunner` is the high-level entry point for executing workers. It owns the shared `WorkerBus` and `WorkerRegistry` and handles signal management (SIGINT/SIGTERM) for graceful shutdown. Register workers with `await runner.add_workers(*workers)`, then `await runner.run()`. By default (`auto_end=True`) the runner ends once every root worker finishes — so a single-pipeline bot ends when its pipeline does; pass `auto_end=False` for long-lived hosts (e.g. a FastAPI server) that add/remove workers across sessions. `PipelineRunner`, and passing a worker directly to `run(worker)`, are deprecated (1.3.0).

- **Services** (`src/pipecat/services/`): 60+ AI provider integrations (STT, TTS, LLM, etc.). Extend base classes: `AIService`, `LLMService`, `STTService`, `TTSService`, `VisionService`.

- **Serializers** (`src/pipecat/serializers/`): Convert frames to/from wire formats for WebSocket transports. `FrameSerializer` base class defines `serialize()` and `deserialize()`. Telephony serializers (Twilio, Plivo, Vonage, Telnyx, Exotel, Genesys) handle provider-specific protocols and audio encoding (e.g., μ-law).

- **RTVI** (`src/pipecat/processors/frameworks/rtvi.py`): Real-Time Voice Interface protocol bridging clients and the pipeline. `RTVIProcessor` handles incoming client messages (text input, audio, function call results). `RTVIObserver` converts pipeline frames to outgoing messages: user/bot speaking events, transcriptions, LLM/TTS lifecycle, function calls, metrics, and audio levels.

- **Observers** (`src/pipecat/observers/`): Monitor frame flow without modifying the pipeline. Passed to `PipelineWorker` via the `observers` parameter. Implement `on_process_frame()` and `on_push_frame()` callbacks.

### Workers, Bus, and Jobs

Beyond the single-pipeline case, Pipecat supports multiple cooperating **workers** coordinated by a shared bus (folded in from the former `pipecat-subagents` package). Terminology note: a "worker" is a runnable unit, "task" now refers only to asyncio tasks, and cross-worker RPC uses "jobs" and "job groups".

- **Bus** (`src/pipecat/bus/`): `WorkerBus` is the abstract pub/sub message bus; `AsyncQueueBus` (`bus/local/async_queue.py`) is the default in-process implementation, with `PgmqBus` / `RedisBus` (`bus/network/`) for distributed workers. Typed messages live in `bus/messages.py` (a `BusMessage` hierarchy split into normal-priority data messages and high-priority system messages, covering frame transport, worker lifecycle, and job RPC). `BusBridgeProcessor` (`bus/bridge_processor.py`) bridges a pipeline to the bus; `BusSubscriber` is the receive-side mixin.

- **Registry** (`src/pipecat/registry/`): `WorkerRegistry` tracks local and remote workers. The runner manages registration; code uses `watch(name, handler)` (or the `@worker_ready(name=...)` decorator) to be notified when a named worker becomes ready.

- **Jobs** (`src/pipecat/pipeline/job_context.py`, `job_decorator.py`, `worker_ready_decorator.py`): A worker exposes handlers with `@job(name=..., sequential=...)`. A caller opens `async with self.job(worker_name, ...)` (single worker) or `self.job_group(*worker_names, ...)` (fan-out) to send a request and await `JobStatus` results / streamed updates over the bus.

- **LLM tools** (`src/pipecat/workers/llm/tool_decorator.py`): On an `LLMWorker`, methods marked `@tool` are auto-collected and registered with the LLM service (supports `cancel_on_interruption` and `timeout`).

Runnable examples live in `examples/multi-worker/` (local handoff, distributed handoff via pgmq/redis, parallel debate, remote proxy, UI worker).

### Important Patterns

- **Context Aggregation**: `LLMContext` accumulates messages for LLM calls; the aggregators created by `LLMContextAggregatorPair` keep it updated with user and assistant turns

- **Turn Management**: Turn management is done through `LLMUserAggregator` and
  `LLMAssistantAggregator`, created with `LLMContextAggregatorPair`

- **User turn strategies**: Detection of when the user starts and stops speaking is done via user turn start/stop strategies. They push `UserStartedSpeakingFrame` and `UserStoppedSpeakingFrame` respectively.

- **Interruptions**: Interruptions are usually triggered by a user turn start strategy (e.g. `VADUserTurnStartStrategy`), but any processor can trigger one by calling `await self.broadcast_interruption()`, which broadcasts an `InterruptionFrame` both upstream and downstream. The old `push_interruption_task_frame_and_wait()` is deprecated and delegates to `broadcast_interruption()`.

- **Uninterruptible Frames**: These are frames that will not be removed from internal queues even if there's an interruption. For example, `EndFrame` and `StopFrame`.

- **Events**: Most classes in Pipecat have `BaseObject` as the very base class. `BaseObject` has support for events. Events can run in the background in an async task (default) or synchronously (`sync=True`) if we want immediate action. Synchronous event handlers need to execute fast.

- **Async Task Management**: Always use `self.create_task(coroutine, name)` instead of raw `asyncio.create_task()`. The `TaskManager` automatically tracks tasks and cleans them up on processor shutdown. Use `await self.cancel_task(task, timeout)` for cancellation.

- **Error Handling**: Use `await self.push_error(msg, exception, fatal)` to push errors upstream. Services should use `fatal=False` (the default) so application code can handle errors and take action (e.g. switch to another service).

- **Accessing the worker**: Reach the running worker via the `pipeline_worker` property on `FrameProcessor` and the `pipeline_worker` field on `FunctionCallParams`. Both are required once the processor is set up (the property raises if accessed before setup). The old `pipeline_task` accessor is deprecated (1.3.0).

### Key Directories

| Directory                  | Purpose                                            |
| -------------------------- | -------------------------------------------------- |
| `src/pipecat/frames/`      | Frame definitions (100+ types)                     |
| `src/pipecat/processors/`  | FrameProcessor base + aggregators, filters, audio  |
| `src/pipecat/pipeline/`    | Pipeline orchestration; PipelineWorker + job RPC   |
| `src/pipecat/workers/`     | Worker model: BaseWorker, runner, LLM/UI workers   |
| `src/pipecat/bus/`         | Inter-worker message bus (local + pgmq/redis)      |
| `src/pipecat/registry/`    | Worker registry (local + remote tracking)          |
| `src/pipecat/services/`    | AI service integrations (60+ providers)            |
| `src/pipecat/transports/`  | Transport layer (Daily, LiveKit, WebSocket, Local) |
| `src/pipecat/serializers/` | Frame serialization for WebSocket protocols        |
| `src/pipecat/observers/`   | Pipeline observers for monitoring frame flow       |
| `src/pipecat/audio/`       | VAD, filters, mixers, turn detection, DTMF         |
| `src/pipecat/turns/`       | User turn management                               |
| `src/pipecat/adapters/`    | LLM provider adapters (context/tools conversion)   |
| `src/pipecat/runner/`      | Development runner (multi-transport bot hosting)   |
| `src/pipecat/cli/`         | `pipecat` CLI (`init`, `eval`)                     |
| `src/pipecat/evals/`       | Behavioral eval framework (run via `pipecat eval`) |
| `src/pipecat/metrics/`     | Metrics data models                                |

## Code Style

- **Docstrings**: Google-style. Classes describe purpose; `__init__` has `Args:` section; dataclasses use `Parameters:` section.
- **Deprecations**: Every deprecation needs a `.. deprecated:: <version>` directive in the docstring (never inline `[DEPRECATED]` tags) — it's the registry's source of truth. Its body must **lead with the replacement as the first reference** — `Use :class:`X` instead.` / `Moved to :mod:`X`.` / `Merged into :class:`X`.` — or state `No replacement.` explicitly; **never lead with a contextual reference** (the deprecated thing itself, a `DeprecationWarning`, or a related-but-not-replacement API), and don't rely on incidental words like "no longer" to signal no-replacement. Prefer Sphinx roles (`:class:`/`:meth:`/`:func:`/`:attr:`/`:mod:`) over plain backticks, but use a backtick when a role wouldn't resolve (aliases like `Service.Settings`, usage idioms, parameters). For the runtime warning: **classes, functions, methods, and properties** use the PEP 702 `@deprecated` decorator from `pipecat.utils.deprecation` with a string-literal message matching the canonical template — `` `Subject` is deprecated since X.Y.Z and will be removed in A.B.C. Use `Replacement` instead. `` — where the removal is a concrete version (e.g. `2.0.0`, never "a future release") and the tail is `No replacement.` when nothing replaces it. Parameters, module moves, and behavior/value changes can't use the decorator — call `warnings.warn(..., DeprecationWarning)` by hand. Enforced by `tests/test_deprecation_markers.py`; full conventions in `CONTRIBUTING.md`.
- **Linting**: Ruff (line length 100). Pre-commit hooks enforce formatting.
- **Type hints**: Required for complex async code.
- **Dataclass vs Pydantic**: Use `@dataclass` for frames and internal pipeline data (high-frequency, no validation needed). Use Pydantic `BaseModel` for configuration, parameters, metrics, and external API data (benefits from validation and serialization). Specifically:
  - `@dataclass`: Frame types, context aggregator pairs, internal data containers
  - `BaseModel`: Service `InputParams`, transport/VAD/turn params, metrics data, API request/response models, serializer params

### Docstring Example

```python
class MyService(LLMService):
    """Description of what the service does.

    More detailed description.

    Event handlers available:

    - on_connected: Called when we are connected

    Example::

        @service.event_handler("on_connected")
        async def on_connected(service, frame):
            ...
    """

    def __init__(self, param1: str, **kwargs):
        """Initialize the service.

        Args:
            param1: Description of param1.
            **kwargs: Additional arguments passed to parent.
        """
        super().__init__(**kwargs)


# Pydantic params class with a deprecated field
class MyParams(BaseModel):
    """Configuration parameters for MyService.

    Parameters:
        new_setting: Replacement for ``old_setting``.
        old_setting: Legacy setting, no longer used.

            .. deprecated:: 1.2.0
                Use ``new_setting`` instead. Will be removed in 2.0.0.
    """

    new_setting: str = "default"
    old_setting: str | None = None
```

## Writing for Future Readers

This applies to everything that documents the code — comments, docstrings, commit messages, changelog entries, PR descriptions. Write for a future reader of the codebase, NOT for whoever is reviewing and collaborating on the work right now.

- **Leave the current moment out of it.** Detail that feels important while making a change — alternatives considered and not taken, what the code used to do, shorthand that only made sense while the work was in progress — usually isn't worth a future reader's time, and may not even make sense to them. Include it only when they genuinely need it to understand the code as it stands.
- **Match the weight of the prose to the code.** Keep it general, high-level, and concise. Reserve long comments for architecturally salient pieces, genuinely tricky sections, or decisions non-obvious enough that a reader would otherwise be puzzled. Routine code needs a short note or none at all.

## Service Implementation

When adding a new service:

1. Extend the appropriate base class (`STTService`, `TTSService`, `LLMService`, etc.)
2. Implement required abstract methods
3. Handle necessary frames
4. By default, all frames should be pushed in the direction they came
5. Push `ErrorFrame` on failures
6. Add metrics tracking via `MetricsData` if relevant
7. Follow the pattern of existing services in `src/pipecat/services/`

## Testing

Test utilities live in `src/pipecat/tests/utils.py`. Use `run_test()` to send frames through a pipeline and assert expected output frames in each direction. Use `SleepFrame(sleep=N)` to add delays between frames.


================================================
FILE: CHANGELOG.md
================================================
# Changelog

All notable changes to **Pipecat** will be documented in this file.

The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

<!-- towncrier release notes start -->

## [1.3.0] - 2026-05-28

### Added

- Pipecat pipelines are multi-agent compatible by default. The new multi-agent
  framework (`pipecat.workers`) turns every `PipelineWorker` (previously
  `PipelineTask`) into a peer on a shared bus that passes typed messages,
  dispatches `@job` work, and coordinates with siblings, while existing
  single-pipeline code keeps running untouched. `examples/multi-worker/` ships
  ready-to-run patterns: LLM handoff, parallel debate, sidecar code assistants
  and hardware controllers, distributed deployments over Redis or PGMQ,
  point-to-point WebSocket proxies, and UI workers driving a web client over
  RTVI.  (PR [#4493](https://github.com/pipecat-ai/pipecat/pull/4493))

- Added `UIWorker` (`pipecat.workers.ui`): an LLM worker that observes and
  drives a client web UI over the RTVI UI channel — for voice agents that act
  on what the user is looking at. It reads the page's accessibility snapshots,
  routes client UI events to `@ui_event` handlers, drives the page with UI
  commands (`scroll_to`, `highlight`, `select_text`, `click`,
  `set_input_value`), and answers screen-grounded questions. `PipelineWorker`
  connects it to the client automatically when RTVI is enabled — no extra
  wiring.
    - A voice agent delegates a turn via the built-in `respond` job; the worker
      returns an answer for the voice LLM to speak, or speaks it verbatim through
      the agent's TTS with `respond_to_job(answer, tts_speak=True)`.
    - `ReplyToolMixin` provides a ready-made `reply` tool (a spoken answer plus
      the standard UI actions).
    - `ui_job_group(...)` fans work out to peer workers, surfaced to the client
      as cancellable progress cards.
    - `UI_STATE_PROMPT_GUIDE` is drop-in system-prompt text that teaches the
       LLM the `<ui_state>` wire format.
  (PR [#4540](https://github.com/pipecat-ai/pipecat/pull/4540))

- Added `VonageVideoConnectorTransport`, a new transport integration for
  real-time Vonage WebRTC sessions using the Vonage Video Connector library.
  (PR [#4052](https://github.com/pipecat-ai/pipecat/pull/4052))

- Added `InceptionLLMService` for Inception's Mercury 2 diffusion reasoning
  model, with support for `reasoning_effort` and `realtime` settings.
  (PR [#4423](https://github.com/pipecat-ai/pipecat/pull/4423))

- Added plain WebSocket transport support to the development runner. Bots can
  now accept connections from non-telephony WebSocket clients (e.g., browser
  apps using protobuf framing) via the `/ws-client` endpoint alongside other
  transports.
  (PR [#4442](https://github.com/pipecat-ai/pipecat/pull/4442))

- Added `GET /status` endpoint to the development runner that reports which
  transports the running instance accepts (all by default, or the single
  transport passed via `-t`).
  (PR [#4442](https://github.com/pipecat-ai/pipecat/pull/4442))

- Added support for the Rime `coda` TTS model to `RimeTTSService` and
  `RimeHttpTTSService`. The `temperature`, `top_p`, and `repetition_penalty`
  settings are not used by `coda`. Also added a `timeScaleFactor` setting (for
  the `arcana` and `coda` models) to both services — values above 1.0 slow down
  audio playback; values below 1.0 speed it up.
  (PR [#4511](https://github.com/pipecat-ai/pipecat/pull/4511))

- Added `max_endpoint_delay_ms` to `SonioxSTTService.Settings`, controlling the
  maximum delay (500-3000 ms) before endpoint detection finalizes a turn.
  (PR [#4521](https://github.com/pipecat-ai/pipecat/pull/4521))

- Added `LLMService.append_system_instruction(...)`: append durable text to a
  service's system instruction so it's included on every inference and survives
  context resets.
  (PR [#4540](https://github.com/pipecat-ai/pipecat/pull/4540))

- Added `CartesiaTurnsSTTService` for streaming speech-to-text against the
  Cartesia Streaming ASR v2 (Ink-2) turn-based WebSocket endpoint
  (`/stt/turns/websocket`). The server drives turn boundaries via `turn.start`
  / `turn.update` / `turn.end` messages, which the service translates into
  `UserStartedSpeakingFrame`, finalized `TranscriptionFrame`, and
  `UserStoppedSpeakingFrame`. Eager end-of-turn predictions and turn resumes
  (`turn.eager_end` and `turn.resume`) are surfaced via the `on_turn_eager_end`
  and `on_turn_resume` event handlers.
  (PR [#4552](https://github.com/pipecat-ai/pipecat/pull/4552))

- Added the `STTService.supports_ttfs` property, which subclasses can override
  to return `False` when TTFS doesn't apply to their architecture (e.g.
  turn-based STTs where the server defines turn boundaries). When `False`,
  `STTMetadataFrame` is broadcast with `ttfs_p99_latency=0.0` and the
  "ttfs_p99_latency not set" warning is suppressed.
  (PR [#4585](https://github.com/pipecat-ai/pipecat/pull/4585))

### Changed

- ⚠️ The development runner now supports all transports (WebRTC, Daily,
  telephony, plain WebSocket) simultaneously from a single server. The `/start`
  endpoint accepts a `"transport"` field to select the transport per-request;
  omitting `-t` at startup enables all transports instead of defaulting to
  WebRTC. The Daily browser-redirect route moved from `GET /` to `GET /daily`.
  (PR [#4442](https://github.com/pipecat-ai/pipecat/pull/4442))

- Changed the default model for `RimeTTSService` and `RimeHttpTTSService` from
  `arcana` to `coda`. Code that relied on the implicit default should set
  `model="arcana"` explicitly to preserve previous behavior.
  (PR [#4511](https://github.com/pipecat-ai/pipecat/pull/4511))

- OpenRouter LLM service now defaults to `openai/gpt-4.1`.
  (PR [#4513](https://github.com/pipecat-ai/pipecat/pull/4513))

- OpenRouter LLM requests now convert `developer` messages to `user` messages
  by default for broader model compatibility. Override this by subclassing
  `OpenRouterLLMService` or setting `llm.supports_developer_role = True` for
  models that support the `developer` role.
  (PR [#4513](https://github.com/pipecat-ai/pipecat/pull/4513))

- `SonioxSTTService` now applies settings updates (e.g. via
  `STTUpdateSettingsFrame`) using a graceful reconnect instead of a hard
  disconnect/reconnect, preserving the service's reconnect retry behavior.
  (PR [#4521](https://github.com/pipecat-ai/pipecat/pull/4521))

- Updated the default p99 TTFS latency values for Smallest AI, Mistral, and XAI
  STT so turn stop timing uses measured values instead of the conservative
  fallback.
  (PR [#4522](https://github.com/pipecat-ai/pipecat/pull/4522))

- Updated the development runner startup banner to show the prebuilt client URL
  once and list enabled or disabled transports with install hints.
  (PR [#4524](https://github.com/pipecat-ai/pipecat/pull/4524))

- Services and transports with missing optional dependencies now raise
  `ImportError` instead of a bare `Exception` when their module is imported
  without the required extra installed. The original `ModuleNotFoundError` is
  preserved as `__cause__`, so code that wraps these imports can now use
  `except ImportError:` cleanly instead of `except Exception:`.
  (PR [#4525](https://github.com/pipecat-ai/pipecat/pull/4525))

- Bumped `pipecat-ai-prebuilt` to 1.0.1 in the `runner` extra, updating the
  prebuilt client UI served by the development runner.
  (PR [#4531](https://github.com/pipecat-ai/pipecat/pull/4531))

- Replaced the `transformers.WhisperFeatureExtractor` dependency in
  `LocalSmartTurnAnalyzerV3` with a vendored numpy-only implementation,
  reducing peak RSS at import from ~566 MB to ~60 MB and cold-start time from
  ~5.0 s to ~0.3 s. Behavior is numerically equivalent (matches the reference
  numpy code path within 1e-5 absolute tolerance; ONNX model output is
  bit-identical on representative inputs).
    - Smart Turn v3 no longer imports `transformers` at module load.
    - Prepares the ground for making `transformers` an optional dependency in a
      future release.
    - The vendored STFT is vectorized via
  `numpy.lib.stride_tricks.sliding_window_view` + batched `np.fft.rfft`,
  cutting `_power_spectrogram` runtime by ~55% (~4.0 ms → ~1.8 ms per call on a
  typical 8-second segment at 16 kHz) while preserving the same parity
  tolerances against the reference implementation.
  (PR [#4536](https://github.com/pipecat-ai/pipecat/pull/4536))

- ⚠️ Renamed the RTVI UI Worker Protocol's vocabulary from the
  `pipecat-subagents` `task`/`agent` terms to Pipecat's native `job`/`worker`.
  This spans the wire messages (`ui-task` → `ui-job-group`, `ui-cancel-task` →
  `ui-cancel-job-group`), their envelope `kind`s and fields (`task_id` →
  `job_id`, `agents`/`agent_name` → `workers`/`worker_name`), the paired Python
  models/frames (`UITask*` → `UIJobGroup*`, `RTVIUITask*Frame` →
  `RTVIUIJobGroup*Frame`), and the `@pipecat-ai/client-js` / `client-react`
  APIs (`RTVIEvent.UITask` → `UIJobGroup`, `cancelUITask` → `cancelUIJobGroup`,
  `useUITasks` → `useUIJobGroups`, `UITasksProvider` → `UIJobGroupsProvider`).
  These primitives shipped in 1.2.0 but were never documented, so no real
  consumers are affected.
  (PR [#4540](https://github.com/pipecat-ai/pipecat/pull/4540))

- `transformers` is no longer a base dependency, so `pip install pipecat-ai` no
  longer pulls it in. This follows Smart Turn v3 dropping its `transformers`
  import; the only remaining users (the deprecated
  `LocalSmartTurnAnalyzerV2`/CoreML analyzers and the Moondream service)
  already require the `local-smart-turn` and `moondream` extras, which continue
  to install `transformers`.
  (PR [#4546](https://github.com/pipecat-ai/pipecat/pull/4546))

- Widened the `deepgram` extra to `deepgram-sdk>=6.1.1,<8` so installations can
  resolve to either deepgram-sdk 6.x or 7.x. `DeepgramSTTService` now handles
  the `agent_rest` keyword argument that deepgram-sdk 7.2.0 added to
  `DeepgramClientEnvironment`, so custom `base_url` configuration keeps working
  on both 6.x and 7.x.
  (PR [#4565](https://github.com/pipecat-ai/pipecat/pull/4565))

- Dropped the upper bound on the `websockets-base` extra (`websockets>=13.1`)
  so downstream deployments can resolve to websockets 16.x and beyond.
  Pipecat's `websockets` usage relies only on the modern `websockets.asyncio`
  API plus a handful of public symbols, all of which are retained in 16.x.
  (PR [#4565](https://github.com/pipecat-ai/pipecat/pull/4565))

- Changed the default voice for `GradiumTTSService` to `_6Aslh2DxfmnRLmP`.
  (PR [#4569](https://github.com/pipecat-ai/pipecat/pull/4569))

- `InworldRealtimeLLMService` now defaults the STT model to
  `inworld/inworld-stt-1`.
  (PR [#4573](https://github.com/pipecat-ai/pipecat/pull/4573))

### Deprecated

- `FrameProcessor.pipeline_task` is deprecated; read
  `FrameProcessor.pipeline_worker` instead. The old name still works but emits
  a `DeprecationWarning` and will be removed in a future release.
  (PR [#4493](https://github.com/pipecat-ai/pipecat/pull/4493))

- Passing a worker to `WorkerRunner.run()` is deprecated. Register the worker
  with `WorkerRunner.add_workers()` before calling `run()` instead. The
  `worker` argument still works but emits a `DeprecationWarning` and will be
  removed in a future release.
  (PR [#4493](https://github.com/pipecat-ai/pipecat/pull/4493))

- `PipelineTask`, `PipelineTaskParams`, and the `pipecat.pipeline.task` module
  have been renamed to `PipelineWorker`, `WorkerParams`, and
  `pipecat.pipeline.worker`. The old names still resolve (the module re-exports
  the new symbols) but constructing `PipelineTask` / `PipelineTaskParams` emits
  a `DeprecationWarning`; they will be removed in a future release.
  (PR [#4493](https://github.com/pipecat-ai/pipecat/pull/4493))

- `PipelineRunner` has been renamed to `WorkerRunner` and moved to
  `pipecat.workers.runner`, since the runner now runs workers (of which
  `PipelineWorker` is one kind), not just pipelines. Import `WorkerRunner` from
  `pipecat.workers.runner`. The old `pipecat.pipeline.runner` module still
  re-exports both names, and `PipelineRunner` still works as a subclass alias,
  but it emits a `DeprecationWarning` and will be removed in a future release.
  (PR [#4589](https://github.com/pipecat-ai/pipecat/pull/4589))

### Removed

- Removed the unsupported Georgian (`Language.KA`) language mapping from
  `SonioxSTTService`.
  (PR [#4521](https://github.com/pipecat-ai/pipecat/pull/4521))

### Fixed

- Fixed Azure TTS last word being missed by observers and RTVI UI. The
  completion signal was racing with word timestamp processing, causing the
  final word's `TTSTextFrame` to arrive after `TTSStoppedFrame`. Completion is
  now routed through the word boundary queue to ensure all words are processed
  before signaling stream end.
  (PR [#4306](https://github.com/pipecat-ai/pipecat/pull/4306))

- Fixed skipped TTS frames (e.g. code blocks filtered via
  `skip_aggregator_types`) being emitted to the assistant context immediately
  instead of waiting for preceding spoken frames to finish. They now hold their
  position in the frame sequence and are flushed only after all earlier spoken
  sentences are complete, keeping context ordering correct.
  (PR [#4380](https://github.com/pipecat-ai/pipecat/pull/4380))

- Fixed Cartesia word timestamps leaking SSML tag text (e.g. `<spell>`,
  `<emotion>`, `<break>`) into word entries. Tags are now stripped before
  processing, so word-to-text attribution remains accurate when SSML markup is
  present in the TTS input.
  (PR [#4380](https://github.com/pipecat-ai/pipecat/pull/4380))

- Fixed `BaseOutputTransport` reordering frames that share the same
  presentation timestamp. Frames with equal PTS values are now emitted in
  insertion order, preventing subtle audio/text sequencing bugs when multiple
  frames arrive at the same time.
  (PR [#4380](https://github.com/pipecat-ai/pipecat/pull/4380))

- Fixed `TTSTextFrame` entries losing their original text structure when word
  timestamps are enabled. Each `TTSTextFrame` now carries a `raw_text` field
  containing the corresponding span of the original LLM-produced text
  (including pattern delimiters such as `<card>4111 1111 1111 1111</card>`), so
  the assistant context receives properly-tagged content rather than the
  cleaned words returned by the TTS provider. Also handles words that straddle
  two sentence boundaries by splitting them and attributing each part to its
  correct source frame.
  (PR [#4380](https://github.com/pipecat-ai/pipecat/pull/4380))

- Fixed `PipelineTask.cancel()` hanging when cancellation is requested before
  the initial `StartFrame` reaches the pipeline sink.
  (PR [#4455](https://github.com/pipecat-ai/pipecat/pull/4455))

- Fixed `SmallWebRTCClient.read_audio_frame` and `read_video_frame`
  busy-looping on `MediaStreamError`. When a track raises `MediaStreamError`, the
  generator now clears the track reference (`_audio_input_track` /
  `_video_input_track` / `_screen_video_track`) so the loop parks on the
  existing `is None` gate instead of re-entering `recv()` at ~100 Hz on a
  permanently-failed track. Renegotiation still resumes seamlessly: when
  `_handle_client_connected` reassigns a fresh track, the loop picks up frames
  from the new track.
  (PR [#4491](https://github.com/pipecat-ai/pipecat/pull/4491))

- Fixed `ElevenLabsSTTService` crashing when `language` was passed as `None`.
  When `language` is not set, the service now lets ElevenLabs auto-detect the
  audio language.
  (PR [#4507](https://github.com/pipecat-ai/pipecat/pull/4507))

- Fixed `NvidiaSTTService` so unexpected gRPC stream drops reconnect cleanly
  using the active audio iterator, while service shutdown and cancellation
  still close that iterator and stop the streaming worker without leaving it
  stuck waiting for more audio.
  (PR [#4512](https://github.com/pipecat-ai/pipecat/pull/4512))

- Fixed websocket STT connection setup failures so services clear stale
  websocket state and emit non-fatal error frames, allowing `ServiceSwitcher`
  failover to keep agents running.
  (PR [#4514](https://github.com/pipecat-ai/pipecat/pull/4514))

- Fixed `ElevenLabsTTSService` and `ElevenLabsHttpTTSService` inserting
  unwanted spaces between words when synthesizing Chinese or Japanese. Word
  timestamps for these languages already include their own spacing, so they are
  now forwarded with `includes_inter_frame_spaces=True` to avoid double-spacing
  in transcripts and context.
  (PR [#4517](https://github.com/pipecat-ai/pipecat/pull/4517))

- Fixed the development runner so missing optional transport dependencies
  disable only their related routes instead of failing startup in all-transport
  mode.
  (PR [#4524](https://github.com/pipecat-ai/pipecat/pull/4524))

- Fixed a race in `ElevenLabsTTSService` where the periodic keepalive could be
  sent for a new turn's context before that context's `voice_settings`
  initialization message, causing ElevenLabs to close the WebSocket with a 1008
  policy violation (`voice_settings field must be provided in the first message
  ...`). The keepalive now only targets a context once its context-init has
  been sent.
  (PR [#4527](https://github.com/pipecat-ai/pipecat/pull/4527))

- Switched `BaseSmartTurn` from `time.time()` to `time.monotonic()` for its
  three internal interval-math sites (audio-buffer timestamps, speech-start
  tracking, and the pre-speech buffer-trim loop). Wall-clock time can step
  forward or backward when NTP adjusts the system clock, which would silently
  corrupt the buffer trim (prune everything / prune nothing) and the
  speech-window extraction. The corrected primitive is monotonic and matches
  the existing `time.perf_counter()` usage already in place for
  inference-latency metrics.
  (PR [#4542](https://github.com/pipecat-ai/pipecat/pull/4542))

- Fixed `SOXRAudioResampler` and `SOXRStreamAudioResampler` ignoring the
  configured quality setting. Both resamplers were hardcoded to `VHQ`, which
  meant `RNNoiseFilter`'s `resampler_quality` argument (defaulting to `QQ`
  for low-latency real-time use) had no effect. The resamplers now honor
  the configured quality, with `VHQ` retained as the default.
  (PR [#4551](https://github.com/pipecat-ai/pipecat/pull/4551))

- Fixed `GeminiLiveLLMService` (and `GeminiVertexLiveLLMService`) crashing with
  `'ContextWindowCompressionParams' object has no attribute 'get'` when
  `context_window_compression` was supplied through the `settings` API (e.g.
  `settings=GeminiLiveLLMService.Settings(context_window_compression=ContextWindowCompressionParams(...))`).
  The setting is now handled whether it arrives as a
  `ContextWindowCompressionParams` object or as a dict.
  (PR [#4563](https://github.com/pipecat-ai/pipecat/pull/4563))

- Fixed `AudioBufferProcessor` concatenating utterances separated by a silent
  gap. When no user audio arrives for more than 200 ms, silence proportional to
  the wall-clock gap is now inserted into the user buffer; the same fix is
  applied symmetrically to the bot buffer, so two bot utterances spoken seconds
  apart (e.g. progressive hold messages played while a slow function call runs)
  remain temporally separated in the recorded audio.
  (PR [#4567](https://github.com/pipecat-ai/pipecat/pull/4567))

- `InworldRealtimeLLMService` no longer logs `WARNING`s for unrecognized
  realtime server events (e.g. `response.output_text.done`); they are now
  logged at `DEBUG`.
  (PR [#4573](https://github.com/pipecat-ai/pipecat/pull/4573))

- Fixed a spurious `ttfs_p99_latency not set, using default 1.0s` warning
  emitted by turn-based STT services (`CartesiaTurnsSTTService`,
  `DeepgramFluxSTTService`) at pipeline start. These services have no
  meaningful "speech end → final transcript" interval to measure, because the
  server defines turn boundaries directly.
  (PR [#4585](https://github.com/pipecat-ai/pipecat/pull/4585))

### Performance

- `BaseSmartTurn` now stores raw `int16` PCM views in its audio buffer and
  defers the `float32` conversion to the once-per-turn segment extraction,
  eliminating ~50 per-frame numpy allocations per second per analyzer. Output
  is bit-identical to the previous per-frame conversion path because `int16 →
  float32 / 32768.0` distributes over concatenation; subclasses
  (`LocalSmartTurnAnalyzerV3`, `LocalCoreMLSmartTurnAnalyzer`,
  `HttpSmartTurnAnalyzer`) all receive the same float32 `audio_array` they did
  before. Also removes a spurious `np.frombuffer(audio_int16, dtype=np.int16)`
  re-wrap that was a no-op view-of-a-view of already-int16 data.
  (PR [#4542](https://github.com/pipecat-ai/pipecat/pull/4542))

- Reduced the `soxr` resampling quality preset in `LocalSmartTurnAnalyzerV3`
  from `VHQ` (~26-tap polyphase) to `HQ` (~16-tap), cutting resample CPU time
  by 30–50% on non-16 kHz audio sources (~3–10 ms saved per turn at 24/48 kHz).
  Pipelines already delivering 16 kHz audio are unaffected — the existing
  `actual_rate == _MODEL_SAMPLE_RATE` fast path skips resampling entirely. The
  two quality presets differ in filter length, not cutoff or interpolation
  semantics; on a Whisper-style log-mel feature representation the audible
  difference sits well below the mel filterbank's quantization noise floor, so
  model predictions are unchanged on representative inputs.
  (PR [#4542](https://github.com/pipecat-ai/pipecat/pull/4542))

## [1.2.1] - 2026-05-15

### Changed

- Changed the default WebSocket endpoints for `GradiumSTTService` and
  `GradiumTTSService` to the region-neutral
  `wss://api.gradium.ai/api/speech/asr` and
  `wss://api.gradium.ai/api/speech/tts`. Gradium now automatically routes
  traffic to the nearest endpoint. Override the url to pin to a specific
  region.
  (PR [#4500](https://github.com/pipecat-ai/pipecat/pull/4500))

### Fixed

- Fixed bot hangs when `filter_incomplete_user_turns` was enabled and the LLM
  responded by calling a tool. The user turn never finalized, so the assistant
  aggregator gated the tool-result context push and the LLM continuation never
  ran. Tool calls now finalize the turn the moment they start, before the
  function dispatches.
  (PR [#4501](https://github.com/pipecat-ai/pipecat/pull/4501))

## [1.2.0] - 2026-05-14

### Added

- Added a `session_id` field to `RunnerArguments` so bots can log or trace a
  per-session identifier in local development the same way they can in Pipecat
  Cloud. The development runner now mints a UUID at every construction site,
  and paths that already returned a `sessionId` to the caller (Daily `/start`,
  dial-in webhook) share that same UUID with the runner args instead of
  generating two. The SmallWebRTC `/api/offer` endpoint also accepts an
  optional `session_id` query parameter so the `/sessions/{session_id}/...`
  proxy can thread it through.
  (PR [#4385](https://github.com/pipecat-ai/pipecat/pull/4385))

- Added a `max_buffer_delay_ms` constructor argument to `CartesiaTTSService`
  for controlling Cartesia's server-side text buffering. When unset, Pipecat
  picks a sensible default based on `text_aggregation_mode`: `0` in `SENTENCE`
  mode (custom buffering — avoids stacking client-side aggregation on top of
  Cartesia's default 3000ms server buffer) and unset in `TOKEN` mode
  (Cartesia's managed buffering applies). Pass an explicit value (0–5000ms) to
  override.
  (PR [#4390](https://github.com/pipecat-ai/pipecat/pull/4390))

- Added a `mip_opt_out` constructor argument to `DeepgramTTSService` and
  `DeepgramHttpTTSService` so callers can opt out of the Deepgram Model
  Improvement Program. When set, the value is forwarded to Deepgram as a query
  parameter on the speak request. Defaults to `None`, which preserves the
  existing behavior. See https://dpgr.am/deepgram-mip for pricing implications
  before enabling.
  (PR [#4400](https://github.com/pipecat-ai/pipecat/pull/4400))

- Added an opt-in `add_tool_change_messages` flag to the LLM aggregators (set
  via `LLMContextAggregatorPair(..., add_tool_change_messages=True)`) that
  appends a developer-role message to the context whenever `LLMSetToolsFrame`
  changes the set of advertised standard tools. Helps the LLM stay coherent
  across mid-conversation tool changes, mitigating several flavors of
  tool-call-related hallucination: calling tools that have been removed,
  avoiding tools that have been re-added, and hallucinating output (made-up
  answers or tool-call-shaped non-tool-calls) when tools are unavailable.
  (PR [#4404](https://github.com/pipecat-ai/pipecat/pull/4404))

- Added `deferred(strategy)` and `DeferredUserTurnStopStrategy` in
  `pipecat.turns.user_stop`. Wraps a stop strategy so it fires only the
  inference-triggered event and suppresses `on_user_turn_stopped`, leaving
  finalization to another strategy in the chain such as
  `LLMTurnCompletionUserTurnStopStrategy`.
  (PR [#4405](https://github.com/pipecat-ai/pipecat/pull/4405))

- Added `ExternalUserTurnCompletionStopStrategy` in `pipecat.turns.user_stop` —
  a generic stop strategy that finalizes the user turn whenever a
  `UserTurnInferenceCompletedFrame` arrives, regardless of which component
  produced it. `LLMTurnCompletionUserTurnStopStrategy` now extends this base;
  future producers (Flux, custom end-of-turn classifiers, etc.) can use the
  base directly or subclass it to add producer-specific setup.
  (PR [#4405](https://github.com/pipecat-ai/pipecat/pull/4405))

- Added `on_user_turn_inference_triggered`, a new event on the user turn
  controller, processor, aggregator and stop strategies that fires when a
  strategy has enough signal to start LLM inference. By default it fires
  together with `on_user_turn_stopped`; a gating strategy can fire only the
  inference-triggered event and defer finalization to a peer.
  (PR [#4405](https://github.com/pipecat-ai/pipecat/pull/4405))

- Added `FilterIncompleteUserTurnStrategies` in
  `pipecat.turns.user_turn_strategies` — a `UserTurnStrategies` specialization
  that wraps the detector chain with `deferred(...)` and appends
  `LLMTurnCompletionUserTurnStopStrategy` as the finalizer. Common case:
  `user_turn_strategies=FilterIncompleteUserTurnStrategies()`. Pass
  `config=UserTurnCompletionConfig(...)` to customize timeouts and prompts.
  (PR [#4405](https://github.com/pipecat-ai/pipecat/pull/4405))

- Added `LLMTurnCompletionUserTurnStopStrategy` in `pipecat.turns.user_stop`.
  When installed, the strategy gates `on_user_turn_stopped` on a
  `UserTurnInferenceCompletedFrame` (a new fieldless system frame emitted by
  any component that can judge turn completeness — e.g. the
  `UserTurnCompletionLLMServiceMixin` on `✓`). A `finalization_timeout`
  provides a safety net if no completion frame ever arrives.
  (PR [#4405](https://github.com/pipecat-ai/pipecat/pull/4405))

- Added first-class RTVI support for the UI Agent Protocol:
    - Adds `ui-event`, `ui-snapshot`, and `ui-cancel-task` client-to-server
  messages, plus `ui-command` and `ui-task` server-to-client messages, with
  paired `*Data` / `*Message` pydantic models.
    - Adds built-in command payload models for `Toast`, `Navigate`, `ScrollTo`,
  `Highlight`, `Focus`, `Click`, `SetInputValue`, and `SelectText`; matching
  default handlers live in `@pipecat-ai/client-react`.
    - Adds `RTVIProcessor.on_ui_message` for inbound `ui-event`, `ui-snapshot`,
  and `ui-cancel-task` messages.
    - Adds five UI pipeline frames, mirroring the `client-message`
  frame-and-event pattern: downstream code pushes `RTVIUICommandFrame` /
  `RTVIUITaskFrame` for the observer to wrap into outbound `UICommandMessage` /
  `UITaskMessage` envelopes, while the processor pushes inbound
  `RTVIUIEventFrame`, `RTVIUISnapshotFrame`, and `RTVIUICancelTaskFrame`
  alongside `on_ui_message`.
    - Bumps the RTVI `PROTOCOL_VERSION` from `1.2.0` to `1.3.0`.
  (PR [#4407](https://github.com/pipecat-ai/pipecat/pull/4407))

- AWS Transcribe STT, Polly TTS, Bedrock LLM, and the Bedrock AgentCore
  processor now resolve credentials via the standard boto3 provider chain (EC2
  instance profiles, EKS pod roles / IRSA, ECS task roles, SSO,
  `~/.aws/credentials`) when explicit credentials and `AWS_*` environment
  variables are absent. Services running with IAM roles no longer need to
  export static credentials.
  (PR [#4416](https://github.com/pipecat-ai/pipecat/pull/4416))

- Added `keyterms` support to ElevenLabs STT services so Scribe V2 callers can
  bias transcription for both file-based and realtime transcription.
  (PR [#4426](https://github.com/pipecat-ai/pipecat/pull/4426))

- Added `watchdog_min_timeout` parameter to `DeepgramFluxSTT` and
  `DeepgramFluxSageMakerSTT` (default `0.5` seconds) to control the minimum
  silence duration before the watchdog sends a silence packet to prevent
  dangling turns. The actual threshold is `max(chunk_duration * 2,
  watchdog_min_timeout)`, so it also adapts automatically to the audio chunk
  size in use.
  (PR [#4430](https://github.com/pipecat-ai/pipecat/pull/4430))

- Added `cancel_on_interruption=False` support for `GeminiLiveLLMService` on
  models that support Gemini's NON_BLOCKING tool mechanism (currently Gemini
  2.x); the conversation now continues while the tool runs. On models that
  don't yet support NON_BLOCKING (Gemini 3.x), the service surfaces a one-time
  warning explaining the limitation. (Note: an intermittent 1008 error can
  occasionally fire on Gemini 2.5 during long-running tool calls; we
  auto-reconnect.)
  (PR [#4448](https://github.com/pipecat-ai/pipecat/pull/4448))

- Added `NvidiaSageMakerWebsocketSTTService` for streaming speech recognition
  using NVIDIA Nemotron ASR via an AWS SageMaker bidirectional-stream endpoint.
  Produces `InterimTranscriptionFrame` and `TranscriptionFrame` frames, is
  VAD-aware, and automatically reconnects on error.
  (PR [#4464](https://github.com/pipecat-ai/pipecat/pull/4464))

- Added NVIDIA Magpie TTS services via AWS SageMaker:
  `NvidiaSageMakerHTTPTTSService` (single HTTP invocation, streams raw PCM
  back) and `NvidiaSageMakerWebsocketTTSService` (persistent HTTP/2 bidi-stream
  with full interruption support via `InterruptibleTTSService`).
  (PR [#4464](https://github.com/pipecat-ai/pipecat/pull/4464))

- Added support for `reasoning` configuration on `OpenAIRealtimeLLMService`,
  for use with reasoning-capable Realtime models such as `gpt-realtime-2`.
  (PR [#4470](https://github.com/pipecat-ai/pipecat/pull/4470))

- Inworld TTS updates:
    - Added `delivery_mode` setting (`STABLE`/`BALANCED`/`CREATIVE`) to
  `InworldTTSService` and `InworldHttpTTSService`, enabling the
  stability-vs-creativity tradeoff in `inworld-tts-2`.
    - Added language support to `InworldTTSService` and
  `InworldHttpTTSService`. The `language` setting is now forwarded to the API,
  and a new `language_to_inworld_language()` helper normalizes Pipecat
  `Language` enums to Inworld's BCP-47 locale tags.
  (PR [#4473](https://github.com/pipecat-ai/pipecat/pull/4473))

### Changed

- Updated the default `SonioxTTSService` model from `tts-rt-v1-preview` to the
  generally available `tts-rt-v1`.
  (PR [#4386](https://github.com/pipecat-ai/pipecat/pull/4386))

- Default `cartesia_version` for `CartesiaTTSService` bumped from `2025-04-16`
  to `2026-03-01`, matching `CartesiaHttpTTSService` and unlocking the
  `use_normalized_timestamps` and `max_buffer_delay_ms` fields.
  (PR [#4390](https://github.com/pipecat-ai/pipecat/pull/4390))

- ⚠️ `CartesiaTTSService` now sends `use_normalized_timestamps: true` instead
  of the deprecated `use_original_timestamps` field. Word timestamps now
  reflect what was actually spoken (post text-normalization and
  pronunciation-dictionary substitution), matching the convention Pipecat uses
  for ElevenLabs. This is a behavior change for `sonic-3` users, who were
  previously receiving timestamps tied to the input transcript.
  (PR [#4390](https://github.com/pipecat-ai/pipecat/pull/4390))

- Broadened `tool_resources` to `app_resources` for easy access not just in
  tool handlers but in other places like custom `FrameProcessor`s. Three
  changes: a rename (`tool_resources` → `app_resources`), a new `app_resources`
  property on `PipelineTask`, and a new `pipeline_task` property on
  `FrameProcessor`. Tool handlers now read `params.app_resources`; custom
  processors read `self.pipeline_task.app_resources`. The previous
  `tool_resources` aliases (on `PipelineTask`, `FunctionCallParams`, and
  `FrameProcessorSetup`) keep working but are deprecated as of 1.2.0 and emit
  `DeprecationWarning`s.
  (PR [#4395](https://github.com/pipecat-ai/pipecat/pull/4395))

- Lowered the per-message log in
  `SmallWebRTCInputTransport._handle_app_message` from `debug` to `trace`. App
  messages can be high-frequency and were noisy at debug level; set the loguru
  level to `TRACE` to see them again.
  (PR [#4397](https://github.com/pipecat-ai/pipecat/pull/4397))

- Changed the default model for `GrokRealtimeLLMService` to
  `grok-voice-think-fast-1.0`, xAI's recommended Voice Agent model. The
  previous default of `grok-voice-fast-1.0` has been deprecated by xAI and is
  being removed.
  (PR [#4401](https://github.com/pipecat-ai/pipecat/pull/4401))

- Changed the default Inworld TTS model from `inworld-tts-1.5-max` to
  `inworld-tts-2` (Realtime TTS-2) across `InworldHttpTTSService`,
  `InworldTTSService`, and the `InworldRealtimeLLMService` cascade. Existing
  users can pin the prior model explicitly via the `model`/`tts_model`
  argument; both `inworld-tts-1.5-max` and `inworld-tts-1.5-mini` remain valid
  model IDs.
  (PR [#4422](https://github.com/pipecat-ai/pipecat/pull/4422))

- Changed the default model for `GrokLLMService` from `grok-3` to
  `grok-4.20-non-reasoning`. xAI is retiring `grok-3` on May 15, 2026.
  (PR [#4429](https://github.com/pipecat-ai/pipecat/pull/4429))

- `DeepgramFluxSTT` watchdog silence threshold is now dynamic:
  `max(chunk_duration * 2, watchdog_min_timeout)` instead of a fixed 500 ms.
  This prevents false silence injections when large audio chunks are sent at
  lower frequency.
  (PR [#4430](https://github.com/pipecat-ai/pipecat/pull/4430))

- `ElevenLabsTTSService` now sends `close_context` to the server as soon as the
  turn is complete (on `on_turn_context_completed`) rather than waiting until
  all audio has finished playing back. The `isFinal` message from ElevenLabs is
  now used to signal `TTSStoppedFrame` and clean up the audio context,
  improving turn transition timing.
  (PR [#4433](https://github.com/pipecat-ai/pipecat/pull/4433))

- Updated `InworldHttpTTSService` and `InworldTTSService` to use PCM audio
  encoding by default, which returns audio bytes without headers.
  (PR [#4446](https://github.com/pipecat-ai/pipecat/pull/4446))

- Moved `create_task`, `cancel_task`, the `task_manager` property, and
  `setup(task_manager)` up from `FrameProcessor` to `BaseObject`. Custom
  `BaseObject` subclasses (turn strategies, controllers, etc.) now inherit
  these methods directly instead of reimplementing the task manager wiring.
  Owners propagate the task manager to their child `BaseObject`s via `await
  child.setup(task_manager)`.
  (PR [#4449](https://github.com/pipecat-ai/pipecat/pull/4449))

- Changed the default OpenAI Realtime input audio transcription model from
  `gpt-4o-transcribe` to `gpt-realtime-whisper` for both
  `OpenAIRealtimeSTTService` and `OpenAIRealtimeLLMService`. The new model does
  not accept the `prompt` parameter; if a prompt is supplied alongside
  `gpt-realtime-whisper`, it is dropped automatically and a warning is logged.
  To keep using prompt hints, explicitly pin `model="gpt-4o-transcribe"` (or
  `"gpt-4o-mini-transcribe"`).
  (PR [#4450](https://github.com/pipecat-ai/pipecat/pull/4450))

- Updated the default model for `CartesiaTTSService` and
  `CartesiaHttpTTSService` from `sonic-3` to `sonic-3.5`.
  (PR [#4462](https://github.com/pipecat-ai/pipecat/pull/4462))

- Changed the default model for `OpenAIRealtimeLLMService` from
  `gpt-realtime-1.5` to `gpt-realtime-2`.
  (PR [#4472](https://github.com/pipecat-ai/pipecat/pull/4472))

### Deprecated

- Deprecated `LLMUserAggregatorParams.filter_incomplete_user_turns`. Use
  `user_turn_strategies=FilterIncompleteUserTurnStrategies()` (or add
  `LLMTurnCompletionUserTurnStopStrategy` to a custom
  `user_turn_strategies.stop`) instead. Setting the legacy flag still works for
  one release: the aggregator emits a `DeprecationWarning` and rewires the
  strategies as if you had passed `FilterIncompleteUserTurnStrategies`
  directly.
  (PR [#4405](https://github.com/pipecat-ai/pipecat/pull/4405))

- Deprecated `ResampyResampler` in favor of `SOXRAudioResampler` (or the
  `create_file_resampler()` / `create_stream_resampler()` factories).
  Instantiating `ResampyResampler` now emits a `DeprecationWarning`. The class
  will be removed in Pipecat 2.0 along with the default `resampy` and `numba`
  dependencies.
  (PR [#4428](https://github.com/pipecat-ai/pipecat/pull/4428))

### Fixed

- Fixed `CartesiaTTSService` surfacing `flush_done` messages from Cartesia as
  `ErrorFrame`s. The latest API emits a `flush_done` per transcript when
  server-side buffering is disabled; Pipecat now consumes them silently since
  each turn already has its own `context_id`.
  (PR [#4390](https://github.com/pipecat-ai/pipecat/pull/4390))

- Fixed Cartesia tag helpers (`SPELL`, `EMOTION_TAG`, `PAUSE_TAG`,
  `VOLUME_TAG`, `SPEED_TAG`) raising `TypeError` when called on an instance
  (e.g. `tts.SPELL("hi")`). They're now `@staticmethod` and callable from both
  the class and an instance.
  (PR [#4390](https://github.com/pipecat-ai/pipecat/pull/4390))

- Fixed `CartesiaHttpTTSService` pushing two `ErrorFrame`s on a non-200
  response — one with the API's error text and a second, less informative
  "Unknown error" frame from the outer exception handler. It now pushes a
  single frame that includes the HTTP status code and returns cleanly.
  (PR [#4390](https://github.com/pipecat-ai/pipecat/pull/4390))

- Fixed an issue where `LocalSmartTurnAnalyzerV3` was imported unconditionally
  for user turn stop strategies. It is now only imported when
  `default_user_turn_stop_strategies()` is called. This improves startup time
  and removes the `transformers` "PyTorch/TensorFlow/Flax not found" warning
  when the default stop strategies are not used.
  (PR [#4393](https://github.com/pipecat-ai/pipecat/pull/4393))

- Fixed `GrokRealtimeLLMService` ignoring the configured model. The model was
  stored in `Settings` but never sent to xAI, so every session silently fell
  back to xAI's server-side default. The model is now passed via the `?model=`
  query parameter on the WebSocket URL as xAI's Voice Agent API requires.
  (PR [#4401](https://github.com/pipecat-ai/pipecat/pull/4401))

- Fixed `on_user_turn_stopped` firing prematurely when
  `filter_incomplete_user_turns` was enabled. The event now fires only after
  the LLM confirms the user turn is complete (`✓`); previously the smart-turn
  detector's tentative stop was bubbling up before the LLM had a chance to veto
  it, causing observers, transcript appenders and UI indicators to receive an
  early — and sometimes duplicated — signal.
  (PR [#4405](https://github.com/pipecat-ai/pipecat/pull/4405))

- Fixed `TTSSpeakFrame(append_to_context=True)` greetings sometimes splitting
  across two assistant messages in the LLM context and not surfacing in
  `on_assistant_turn_stopped`. The `LLMAssistantPushAggregationFrame` emitted
  at the end of a TTS context now carries a PTS just past the last word so it
  can't overtake clock-queued `TTSTextFrame`s in the transport's output, and
  `LLMAssistantAggregator` now triggers
  `on_assistant_turn_started`/`on_assistant_turn_stopped` when it receives the
  frame outside an LLM response cycle (restoring v0.0.104 behavior for greeting
  transcripts).
  (PR [#4414](https://github.com/pipecat-ai/pipecat/pull/4414))

- Fixed `ElevenLabsTTSService` and `ElevenLabsHttpTTSService` producing merged
  words (e.g. `bookLook`) when using Flash models. Flash often splits sentences
  mid-stream into alignment chunks that begin with a real inter-word space, but
  the previous fix unconditionally stripped that space from every chunk.
  Leading spaces are now stripped only on the first alignment chunk of an
  utterance, so subsequent chunks correctly flush partial words across
  boundaries.
  (PR [#4415](https://github.com/pipecat-ai/pipecat/pull/4415))

- Fixed AWS Polly TTS, Bedrock LLM, and the Bedrock AgentCore processor
  erroring out when only one o
gitextract_fjd7zain/

├── .claude/
│   ├── settings.json
│   └── skills/
│       ├── changelog/
│       │   └── SKILL.md
│       ├── cleanup/
│       │   └── SKILL.md
│       ├── code-review/
│       │   └── SKILL.md
│       ├── docstring/
│       │   └── SKILL.md
│       ├── pr-description/
│       │   └── SKILL.md
│       ├── pr-submit/
│       │   └── SKILL.md
│       ├── squash-commits/
│       │   └── SKILL.md
│       └── update-docs/
│           ├── SKILL.md
│           └── SOURCE_DOC_MAPPING.md
├── .claude-plugin/
│   └── marketplace.json
├── .github/
│   ├── ISSUE_TEMPLATE/
│   │   ├── 1-bug_report.yml
│   │   ├── 2-question.yml
│   │   ├── 3-feature_request.yml
│   │   ├── 4-service-issue.yml
│   │   ├── 5-new-service.yml
│   │   ├── 6-dependency.yml
│   │   ├── 7-troubleshooting.yml
│   │   └── config.yml
│   ├── PULL_REQUEST_TEMPLATE.md
│   └── workflows/
│       ├── build.yaml
│       ├── coverage.yaml
│       ├── format.yaml
│       ├── generate-changelog.yml
│       ├── publish.yaml
│       ├── publish_test.yaml
│       ├── python-compatibility.yaml
│       ├── tests.yaml
│       └── update-docs.yml
├── .gitignore
├── .pre-commit-config.yaml
├── .readthedocs.yaml
├── AGENTS.md
├── CHANGELOG.md
├── CLAUDE.md
├── COMMUNITY_INTEGRATIONS.md
├── CONTRIBUTING.md
├── LICENSE
├── MANIFEST.in
├── README.md
├── SECURITY.md
├── changelog/
│   ├── 4483.fixed.md
│   ├── 4519.fixed.md
│   ├── 4533.added.2.md
│   ├── 4533.added.3.md
│   ├── 4533.added.4.md
│   ├── 4533.added.5.md
│   ├── 4533.added.md
│   ├── 4533.changed.2.md
│   ├── 4533.changed.3.md
│   ├── 4533.changed.md
│   ├── 4533.fixed.2.md
│   ├── 4533.fixed.3.md
│   ├── 4533.fixed.4.md
│   ├── 4533.fixed.5.md
│   ├── 4533.fixed.md
│   ├── 4535.changed.md
│   ├── 4549.added.md
│   ├── 4578.fixed.md
│   ├── 4588.added.md
│   ├── 4588.changed.md
│   ├── 4588.deprecated.md
│   ├── 4592.changed.md
│   ├── 4593.added.md
│   ├── 4597.added.md
│   ├── 4597.fixed.md
│   ├── 4599.added.md
│   ├── 4599.fixed.md
│   ├── 4612.added.md
│   ├── 4620.added.md
│   ├── 4620.changed.md
│   ├── 4622.added.md
│   ├── 4622.deprecated.md
│   ├── 4622.fixed.md
│   ├── 4626.changed.md
│   ├── 4626.deprecated.md
│   ├── 4631.added.2.md
│   ├── 4631.added.md
│   ├── 4632.changed.2.md
│   ├── 4632.changed.md
│   ├── 4634.changed.md
│   ├── 4635.fixed.md
│   ├── 4636.added.md
│   ├── 4639.fixed.md
│   ├── 4642.changed.md
│   ├── 4642.deprecated.md
│   ├── 4643.changed.md
│   ├── 4644.fixed.md
│   ├── 4650.fixed.md
│   ├── 4653.fixed.md
│   ├── 4654.added.2.md
│   ├── 4654.added.3.md
│   ├── 4654.added.md
│   ├── 4655.added.2.md
│   ├── 4655.added.3.md
│   ├── 4655.added.md
│   ├── 4656.fixed.md
│   ├── 4658.changed.md
│   ├── 4660.security.md
│   ├── 4664.added.md
│   ├── 4665.fixed.md
│   ├── 4667.fixed.md
│   ├── 4671.changed.md
│   ├── 4671.deprecated.md
│   ├── 4674.added.md
│   ├── 4682.added.md
│   ├── 4683.added.md
│   ├── 4684.changed.md
│   ├── 4684.fixed.md
│   ├── 4685.changed.md
│   ├── 4686.added.md
│   ├── 4687.fixed.md
│   ├── 4688.fixed.md
│   ├── 4690.changed.md
│   ├── 4691.fixed.md
│   ├── 4692.changed.md
│   ├── 4703.fixed.md
│   ├── 4704.security.md
│   ├── 4705.changed.md
│   ├── 4705.deprecated.md
│   ├── 4709.added.md
│   ├── 4709.changed.md
│   ├── 4709.fixed.2.md
│   ├── 4709.fixed.md
│   ├── 4710.added.md
│   ├── 4714.fixed.md
│   ├── 4715.added.md
│   ├── 4715.fixed.md
│   ├── 4726.changed.2.md
│   ├── 4726.changed.md
│   └── _template.md.j2
├── codecov.yml
├── docs/
│   └── api/
│       ├── Makefile
│       ├── README.md
│       ├── build-docs.sh
│       ├── conf.py
│       ├── index.rst
│       ├── make.bat
│       └── rtd-test.sh
├── env.example
├── examples/
│   ├── README.md
│   ├── assets/
│   │   └── rag-content.txt
│   ├── audio/
│   │   ├── audio-bot-background-sound.py
│   │   ├── audio-recording.py
│   │   └── audio-sound-effects.py
│   ├── context-summarization/
│   │   ├── context-summarization-dedicated-llm.py
│   │   ├── context-summarization-google.py
│   │   ├── context-summarization-manual-openai.py
│   │   └── context-summarization-openai.py
│   ├── features/
│   │   ├── features-add-tool-change-messages.py
│   │   ├── features-app-resources.py
│   │   ├── features-before-and-after-events.py
│   │   ├── features-concurrent-llm-evaluation.py
│   │   ├── features-concurrent-llm-rtvi-ignored-sources.py
│   │   ├── features-custom-frame-processor.py
│   │   ├── features-gpu-container-local-bot.py
│   │   ├── features-live-translation.py
│   │   ├── features-pattern-pair-voice-switching.py
│   │   ├── features-service-switcher.py
│   │   ├── features-switch-languages.py
│   │   ├── features-switch-voices.py
│   │   ├── features-user-email-gathering.py
│   │   ├── features-voicemail-detection.py
│   │   └── features-wake-phrase.py
│   ├── function-calling/
│   │   ├── function-calling-anthropic-async-stream.py
│   │   ├── function-calling-anthropic-async.py
│   │   ├── function-calling-anthropic-video.py
│   │   ├── function-calling-anthropic.py
│   │   ├── function-calling-aws-video.py
│   │   ├── function-calling-aws.py
│   │   ├── function-calling-azure.py
│   │   ├── function-calling-cerebras.py
│   │   ├── function-calling-deepseek.py
│   │   ├── function-calling-direct.py
│   │   ├── function-calling-fireworks.py
│   │   ├── function-calling-google-async-stream.py
│   │   ├── function-calling-google-async.py
│   │   ├── function-calling-google-vertex.py
│   │   ├── function-calling-google-video.py
│   │   ├── function-calling-google.py
│   │   ├── function-calling-grok.py
│   │   ├── function-calling-groq.py
│   │   ├── function-calling-inception.py
│   │   ├── function-calling-missing-handler.py
│   │   ├── function-calling-mistral.py
│   │   ├── function-calling-moondream-video.py
│   │   ├── function-calling-nebius.py
│   │   ├── function-calling-novita.py
│   │   ├── function-calling-nvidia.py
│   │   ├── function-calling-ollama.py
│   │   ├── function-calling-openai-async-stream.py
│   │   ├── function-calling-openai-async.py
│   │   ├── function-calling-openai-responses-async-stream.py
│   │   ├── function-calling-openai-responses-async.py
│   │   ├── function-calling-openai-responses-http.py
│   │   ├── function-calling-openai-responses-video-http.py
│   │   ├── function-calling-openai-responses-video.py
│   │   ├── function-calling-openai-responses.py
│   │   ├── function-calling-openai-video.py
│   │   ├── function-calling-openai.py
│   │   ├── function-calling-openrouter.py
│   │   ├── function-calling-perplexity.py
│   │   ├── function-calling-qwen.py
│   │   ├── function-calling-sambanova.py
│   │   ├── function-calling-sarvam.py
│   │   ├── function-calling-schema-handler.py
│   │   └── function-calling-together.py
│   ├── getting-started/
│   │   ├── 01-say-one-thing.py
│   │   ├── 01a-local-audio.py
│   │   ├── 02-llm-say-one-thing.py
│   │   ├── 03-still-frame.py
│   │   ├── 03a-local-still-frame.py
│   │   ├── 04-sync-speech-and-image.py
│   │   ├── 05-speaking-state.py
│   │   ├── 06-voice-agent.py
│   │   ├── 06a-voice-agent-local.py
│   │   └── 07-function-calling.py
│   ├── mcp/
│   │   ├── mcp-multiple-mcp.py
│   │   ├── mcp-stdio.py
│   │   ├── mcp-streamable-http-gemini-live.py
│   │   └── mcp-streamable-http.py
│   ├── multi-worker/
│   │   ├── README.md
│   │   ├── code-assistant/
│   │   │   ├── README.md
│   │   │   ├── code-assistant.py
│   │   │   └── code_worker.py
│   │   ├── distributed-handoff/
│   │   │   ├── pgmq-handoff/
│   │   │   │   ├── README.md
│   │   │   │   ├── llm.py
│   │   │   │   └── main.py
│   │   │   └── redis-handoff/
│   │   │       ├── README.md
│   │   │       ├── llm.py
│   │   │       └── main.py
│   │   ├── env.example
│   │   ├── local-handoff/
│   │   │   ├── README.md
│   │   │   ├── local-handoff-two-agents-tts.py
│   │   │   └── local-handoff-two-agents.py
│   │   ├── parallel-debate/
│   │   │   ├── README.md
│   │   │   └── parallel-debate.py
│   │   ├── remote-proxy-assistant/
│   │   │   ├── README.md
│   │   │   ├── assistant.py
│   │   │   └── main.py
│   │   ├── sensor-controller/
│   │   │   ├── README.md
│   │   │   ├── sensor-controller.py
│   │   │   └── sensor.py
│   │   └── ui-worker/
│   │       ├── async-tasks/
│   │       │   ├── README.md
│   │       │   ├── bot.py
│   │       │   └── client/
│   │       │       ├── index.html
│   │       │       ├── main.js
│   │       │       ├── package.json
│   │       │       ├── styles.css
│   │       │       └── vite.config.js
│   │       ├── deixis/
│   │       │   ├── README.md
│   │       │   ├── bot.py
│   │       │   └── client/
│   │       │       ├── index.html
│   │       │       ├── main.js
│   │       │       ├── package.json
│   │       │       ├── styles.css
│   │       │       └── vite.config.js
│   │       ├── document-review/
│   │       │   ├── README.md
│   │       │   ├── bot.py
│   │       │   └── client/
│   │       │       ├── index.html
│   │       │       ├── main.js
│   │       │       ├── package.json
│   │       │       ├── styles.css
│   │       │       └── vite.config.js
│   │       ├── form-fill/
│   │       │   ├── README.md
│   │       │   ├── bot.py
│   │       │   └── client/
│   │       │       ├── index.html
│   │       │       ├── main.js
│   │       │       ├── package.json
│   │       │       ├── styles.css
│   │       │       └── vite.config.js
│   │       ├── hello-snapshot/
│   │       │   ├── README.md
│   │       │   ├── bot.py
│   │       │   └── client/
│   │       │       ├── index.html
│   │       │       ├── main.js
│   │       │       ├── package.json
│   │       │       ├── styles.css
│   │       │       └── vite.config.js
│   │       └── shopping-list/
│   │           ├── README.md
│   │           ├── bot.py
│   │           └── client/
│   │               ├── index.html
│   │               ├── main.js
│   │               ├── package.json
│   │               ├── styles.css
│   │               └── vite.config.js
│   ├── observability/
│   │   ├── observability-heartbeats.py
│   │   ├── observability-observer.py
│   │   └── observability-sentry-metrics.py
│   ├── persistent-context/
│   │   ├── persistent-context-anthropic.py
│   │   ├── persistent-context-aws-nova-sonic.py
│   │   ├── persistent-context-gemini.py
│   │   ├── persistent-context-grok-realtime.py
│   │   ├── persistent-context-openai-realtime.py
│   │   ├── persistent-context-openai-responses-http.py
│   │   ├── persistent-context-openai-responses.py
│   │   └── persistent-context-openai.py
│   ├── rag/
│   │   ├── rag-gemini-grounding-metadata.py
│   │   ├── rag-gemini.py
│   │   └── rag-mem0.py
│   ├── realtime/
│   │   ├── realtime-aws-nova-sonic-async-tool.py
│   │   ├── realtime-aws-nova-sonic.py
│   │   ├── realtime-azure-async-tool.py
│   │   ├── realtime-azure.py
│   │   ├── realtime-gemini-live-async-tool.py
│   │   ├── realtime-gemini-live-files-api.py
│   │   ├── realtime-gemini-live-google-search.py
│   │   ├── realtime-gemini-live-graceful-end.py
│   │   ├── realtime-gemini-live-grounding-metadata.py
│   │   ├── realtime-gemini-live-locally-driven-turns.py
│   │   ├── realtime-gemini-live-vertex.py
│   │   ├── realtime-gemini-live-video.py
│   │   ├── realtime-gemini-live.py
│   │   ├── realtime-grok-async-tool.py
│   │   ├── realtime-grok-locally-driven-turns.py
│   │   ├── realtime-grok.py
│   │   ├── realtime-inworld-locally-driven-turns.py
│   │   ├── realtime-inworld.py
│   │   ├── realtime-openai-async-tool.py
│   │   ├── realtime-openai-live-video.py
│   │   ├── realtime-openai-locally-driven-turns.py
│   │   ├── realtime-openai-text.py
│   │   ├── realtime-openai.py
│   │   ├── realtime-ultravox-async-tool.py
│   │   ├── realtime-ultravox-text.py
│   │   └── realtime-ultravox.py
│   ├── thinking/
│   │   ├── thinking-anthropic.py
│   │   ├── thinking-functions-anthropic.py
│   │   ├── thinking-functions-google.py
│   │   └── thinking-google.py
│   ├── transcription/
│   │   ├── transcription-assemblyai.py
│   │   ├── transcription-azure.py
│   │   ├── transcription-cartesia-turns.py
│   │   ├── transcription-cartesia.py
│   │   ├── transcription-deepgram-flux.py
│   │   ├── transcription-deepgram.py
│   │   ├── transcription-elevenlabs.py
│   │   ├── transcription-gladia-translation.py
│   │   ├── transcription-gladia.py
│   │   ├── transcription-google-llm.py
│   │   ├── transcription-gradium.py
│   │   ├── transcription-mistral.py
│   │   ├── transcription-openai.py
│   │   ├── transcription-soniox.py
│   │   ├── transcription-speechmatics.py
│   │   ├── transcription-whisper-local.py
│   │   ├── transcription-whisper-mlx.py
│   │   ├── transcription-whisper.py
│   │   └── transcription-xai.py
│   ├── transports/
│   │   ├── transports-daily.py
│   │   ├── transports-livekit.py
│   │   ├── transports-small-webrtc.py
│   │   └── transports-vonage.py
│   ├── turn-management/
│   │   ├── turn-management-detect-user-idle.py
│   │   ├── turn-management-filter-incomplete-turns-function-calling.py
│   │   ├── turn-management-filter-incomplete-turns.py
│   │   ├── turn-management-interruption-config.py
│   │   ├── turn-management-smart-turn-local-coreml.py
│   │   ├── turn-management-smart-turn-local.py
│   │   ├── turn-management-turn-tracking-observer.py
│   │   ├── turn-management-user-assistant-turns.py
│   │   └── turn-management-user-mute-strategy.py
│   ├── update-settings/
│   │   ├── llm/
│   │   │   ├── llm-anthropic.py
│   │   │   ├── llm-aws-bedrock.py
│   │   │   ├── llm-aws-nova-sonic.py
│   │   │   ├── llm-azure-realtime.py
│   │   │   ├── llm-azure.py
│   │   │   ├── llm-cerebras.py
│   │   │   ├── llm-deepseek.py
│   │   │   ├── llm-fireworks.py
│   │   │   ├── llm-gemini-live-vertex.py
│   │   │   ├── llm-gemini-live.py
│   │   │   ├── llm-google-vertex.py
│   │   │   ├── llm-google.py
│   │   │   ├── llm-grok-realtime.py
│   │   │   ├── llm-grok.py
│   │   │   ├── llm-groq.py
│   │   │   ├── llm-mistral.py
│   │   │   ├── llm-nvidia.py
│   │   │   ├── llm-ollama.py
│   │   │   ├── llm-openai-realtime.py
│   │   │   ├── llm-openai-responses-http.py
│   │   │   ├── llm-openai-responses.py
│   │   │   ├── llm-openai.py
│   │   │   ├── llm-openrouter.py
│   │   │   ├── llm-perplexity.py
│   │   │   ├── llm-qwen.py
│   │   │   ├── llm-sambanova.py
│   │   │   ├── llm-sarvam.py
│   │   │   ├── llm-together.py
│   │   │   └── llm-ultravox-realtime.py
│   │   ├── stt/
│   │   │   ├── stt-assemblyai.py
│   │   │   ├── stt-aws-transcribe.py
│   │   │   ├── stt-azure.py
│   │   │   ├── stt-cartesia.py
│   │   │   ├── stt-deepgram-flux.py
│   │   │   ├── stt-deepgram-sagemaker.py
│   │   │   ├── stt-deepgram.py
│   │   │   ├── stt-elevenlabs-realtime.py
│   │   │   ├── stt-elevenlabs.py
│   │   │   ├── stt-fal.py
│   │   │   ├── stt-gladia.py
│   │   │   ├── stt-google.py
│   │   │   ├── stt-gradium.py
│   │   │   ├── stt-groq.py
│   │   │   ├── stt-nvidia-segmented.py
│   │   │   ├── stt-nvidia.py
│   │   │   ├── stt-openai-realtime.py
│   │   │   ├── stt-sarvam.py
│   │   │   ├── stt-soniox.py
│   │   │   ├── stt-speechmatics.py
│   │   │   ├── stt-whisper-api.py
│   │   │   ├── stt-whisper-mlx.py
│   │   │   └── stt-whisper.py
│   │   └── tts/
│   │       ├── tts-asyncai-http.py
│   │       ├── tts-asyncai.py
│   │       ├── tts-aws-polly.py
│   │       ├── tts-azure-http.py
│   │       ├── tts-azure.py
│   │       ├── tts-camb.py
│   │       ├── tts-cartesia-http.py
│   │       ├── tts-cartesia.py
│   │       ├── tts-deepgram-http.py
│   │       ├── tts-deepgram-sagemaker.py
│   │       ├── tts-deepgram.py
│   │       ├── tts-elevenlabs-http.py
│   │       ├── tts-elevenlabs.py
│   │       ├── tts-fish.py
│   │       ├── tts-gemini.py
│   │       ├── tts-google-http.py
│   │       ├── tts-google-stream.py
│   │       ├── tts-gradium.py
│   │       ├── tts-groq.py
│   │       ├── tts-hume.py
│   │       ├── tts-inworld-http.py
│   │       ├── tts-inworld.py
│   │       ├── tts-kokoro.py
│   │       ├── tts-lmnt.py
│   │       ├── tts-minimax.py
│   │       ├── tts-neuphonic-http.py
│   │       ├── tts-neuphonic.py
│   │       ├── tts-nvidia.py
│   │       ├── tts-openai.py
│   │       ├── tts-piper-http.py
│   │       ├── tts-piper.py
│   │       ├── tts-resembleai.py
│   │       ├── tts-rime-http.py
│   │       ├── tts-rime.py
│   │       ├── tts-sarvam-http.py
│   │       ├── tts-sarvam.py
│   │       ├── tts-speechmatics.py
│   │       └── tts-xtts.py
│   ├── video-avatar/
│   │   ├── video-avatar-heygen-transport.py
│   │   ├── video-avatar-heygen-video-service.py
│   │   ├── video-avatar-lemonslice-transport.py
│   │   ├── video-avatar-simli-video-service.py
│   │   ├── video-avatar-tavus-transport.py
│   │   └── video-avatar-tavus-video-service.py
│   ├── video-processing/
│   │   ├── video-processing-custom-video-track.py
│   │   ├── video-processing-gstreamer-filesrc.py
│   │   ├── video-processing-gstreamer-videotestsrc.py
│   │   ├── video-processing-local-mirror.py
│   │   ├── video-processing-mirror.py
│   │   └── video-processing.py
│   ├── vision/
│   │   ├── vision-anthropic.py
│   │   ├── vision-aws.py
│   │   ├── vision-gemini-flash.py
│   │   ├── vision-moondream.py
│   │   ├── vision-openai-responses-http.py
│   │   ├── vision-openai-responses.py
│   │   └── vision-openai.py
│   └── voice/
│       ├── voice-aicoustics-vad-only.py
│       ├── voice-aicoustics.py
│       ├── voice-assemblyai-turn-detection.py
│       ├── voice-assemblyai.py
│       ├── voice-asyncai-http.py
│       ├── voice-asyncai.py
│       ├── voice-aws-strands.py
│       ├── voice-aws.py
│       ├── voice-azure-http.py
│       ├── voice-azure.py
│       ├── voice-camb.py
│       ├── voice-cartesia-http.py
│       ├── voice-cartesia-turns.py
│       ├── voice-cartesia.py
│       ├── voice-deepgram-flux-sagemaker.py
│       ├── voice-deepgram-flux.py
│       ├── voice-deepgram-http.py
│       ├── voice-deepgram-sagemaker.py
│       ├── voice-deepgram.py
│       ├── voice-elevenlabs-http.py
│       ├── voice-elevenlabs.py
│       ├── voice-fal.py
│       ├── voice-fish.py
│       ├── voice-gladia-vad.py
│       ├── voice-gladia.py
│       ├── voice-google-audio-in.py
│       ├── voice-google-gemini-tts.py
│       ├── voice-google-http.py
│       ├── voice-google-image.py
│       ├── voice-google.py
│       ├── voice-gradium.py
│       ├── voice-groq.py
│       ├── voice-hume.py
│       ├── voice-inworld-http.py
│       ├── voice-inworld.py
│       ├── voice-kokoro.py
│       ├── voice-krisp-viva.py
│       ├── voice-langchain.py
│       ├── voice-lmnt.py
│       ├── voice-minimax.py
│       ├── voice-mistral.py
│       ├── voice-moonshine.py
│       ├── voice-neuphonic-http.py
│       ├── voice-neuphonic.py
│       ├── voice-nvidia-sagemaker.py
│       ├── voice-nvidia.py
│       ├── voice-openai-http.py
│       ├── voice-openai-responses-http.py
│       ├── voice-openai-responses.py
│       ├── voice-openai.py
│       ├── voice-piper.py
│       ├── voice-resemble.py
│       ├── voice-rime-http.py
│       ├── voice-rime.py
│       ├── voice-sarvam-http.py
│       ├── voice-sarvam.py
│       ├── voice-smallest.py
│       ├── voice-soniox.py
│       ├── voice-speechmatics-vad.py
│       ├── voice-speechmatics.py
│       ├── voice-xai-http.py
│       ├── voice-xai.py
│       └── voice-xtts.py
├── pyproject.toml
├── pyrightconfig.json
├── scripts/
│   ├── cli/
│   │   ├── check_registry.py
│   │   ├── configs/
│   │   │   ├── config_generator.py
│   │   │   └── update_configs.py
│   │   ├── imports/
│   │   │   ├── import_generator.py
│   │   │   └── update_imports.py
│   │   └── update_registry.py
│   ├── daily/
│   │   └── test_tavus_transport.py
│   ├── deprecations/
│   │   ├── __init__.py
│   │   ├── deprecations.json
│   │   ├── generate.py
│   │   └── scan.py
│   ├── dtmf/
│   │   └── generate_dtmf.sh
│   ├── fix-ruff-and-typecheck.sh
│   ├── krisp/
│   │   ├── audio_file_utils.py
│   │   ├── test_krisp_viva_filter_audiofile.py
│   │   └── test_krisp_viva_turn_audiofile.py
│   ├── mem-watch.sh
│   ├── release-changelog.py
│   └── release-evals/
│       ├── README.md
│       ├── manifest.yaml
│       ├── run.sh
│       └── scenarios/
│           ├── capital_question.yaml
│           ├── describe_image.yaml
│           ├── interruption_audio.yaml
│           ├── interruption_text.yaml
│           ├── item_price.yaml
│           ├── judge_audio.yaml
│           ├── judge_text.yaml
│           ├── language_switch.yaml
│           ├── multi_turn.yaml
│           ├── user_audio.yaml
│           ├── vision-cat.json
│           ├── vision_describe.yaml
│           ├── weather.yaml
│           ├── weather_and_restaurant.yaml
│           └── weather_function_call.yaml
├── src/
│   └── pipecat/
│       ├── __init__.py
│       ├── adapters/
│       │   ├── __init__.py
│       │   ├── base_llm_adapter.py
│       │   ├── schemas/
│       │   │   ├── __init__.py
│       │   │   ├── direct_function.py
│       │   │   ├── function_schema.py
│       │   │   └── tools_schema.py
│       │   └── services/
│       │       ├── __init__.py
│       │       ├── anthropic_adapter.py
│       │       ├── aws_nova_sonic_adapter.py
│       │       ├── bedrock_adapter.py
│       │       ├── gemini_adapter.py
│       │       ├── grok_realtime_adapter.py
│       │       ├── inworld_realtime_adapter.py
│       │       ├── mistral_adapter.py
│       │       ├── open_ai_adapter.py
│       │       ├── open_ai_realtime_adapter.py
│       │       ├── open_ai_responses_adapter.py
│       │       └── perplexity_adapter.py
│       ├── audio/
│       │   ├── __init__.py
│       │   ├── dtmf/
│       │   │   ├── __init__.py
│       │   │   ├── types.py
│       │   │   └── utils.py
│       │   ├── filters/
│       │   │   ├── __init__.py
│       │   │   ├── aic_filter.py
│       │   │   ├── base_audio_filter.py
│       │   │   ├── koala_filter.py
│       │   │   ├── krisp_viva_filter.py
│       │   │   └── rnnoise_filter.py
│       │   ├── krisp_instance.py
│       │   ├── mixers/
│       │   │   ├── __init__.py
│       │   │   ├── base_audio_mixer.py
│       │   │   └── soundfile_mixer.py
│       │   ├── resamplers/
│       │   │   ├── __init__.py
│       │   │   ├── base_audio_resampler.py
│       │   │   ├── resampy_resampler.py
│       │   │   ├── soxr_resampler.py
│       │   │   └── soxr_stream_resampler.py
│       │   ├── turn/
│       │   │   ├── __init__.py
│       │   │   ├── base_turn_analyzer.py
│       │   │   ├── krisp_viva_turn.py
│       │   │   └── smart_turn/
│       │   │       ├── __init__.py
│       │   │       ├── _whisper_features.py
│       │   │       ├── base_smart_turn.py
│       │   │       ├── data/
│       │   │       │   ├── __init__.py
│       │   │       │   └── smart-turn-v3.2-cpu.onnx
│       │   │       ├── http_smart_turn.py
│       │   │       ├── local_coreml_smart_turn.py
│       │   │       ├── local_smart_turn_v2.py
│       │   │       └── local_smart_turn_v3.py
│       │   ├── utils.py
│       │   └── vad/
│       │       ├── __init__.py
│       │       ├── aic_quail_vad.py
│       │       ├── aic_vad.py
│       │       ├── data/
│       │       │   ├── __init__.py
│       │       │   └── silero_vad.onnx
│       │       ├── krisp_viva_vad.py
│       │       ├── silero.py
│       │       ├── vad_analyzer.py
│       │       └── vad_controller.py
│       ├── bus/
│       │   ├── __init__.py
│       │   ├── adapters/
│       │   │   ├── __init__.py
│       │   │   ├── base.py
│       │   │   ├── llm_context_adapter.py
│       │   │   └── tools_schema_adapter.py
│       │   ├── bridge_processor.py
│       │   ├── bus.py
│       │   ├── local/
│       │   │   ├── __init__.py
│       │   │   └── async_queue.py
│       │   ├── messages.py
│       │   ├── network/
│       │   │   ├── __init__.py
│       │   │   ├── pgmq.py
│       │   │   ├── pgmq_backends.py
│       │   │   └── redis.py
│       │   ├── queue.py
│       │   ├── serializers/
│       │   │   ├── __init__.py
│       │   │   ├── base.py
│       │   │   └── json.py
│       │   ├── subscriber.py
│       │   └── ui/
│       │       ├── __init__.py
│       │       └── messages.py
│       ├── cli/
│       │   ├── __init__.py
│       │   ├── agent_templates/
│       │   │   ├── AGENTS.md
│       │   │   ├── CLAUDE.md
│       │   │   └── GETTING_STARTED.md
│       │   ├── commands/
│       │   │   ├── __init__.py
│       │   │   ├── create.py
│       │   │   ├── eval.py
│       │   │   └── init.py
│       │   ├── config_validator.py
│       │   ├── generators/
│       │   │   ├── __init__.py
│       │   │   └── project.py
│       │   ├── main.py
│       │   ├── prompts/
│       │   │   ├── __init__.py
│       │   │   └── questions.py
│       │   ├── registry/
│       │   │   ├── __init__.py
│       │   │   ├── _configs.py
│       │   │   ├── _imports.py
│       │   │   ├── service_loader.py
│       │   │   └── service_metadata.py
│       │   └── templates/
│       │       ├── README.md.jinja2
│       │       ├── _readme_blocks/
│       │       │   ├── how_it_works_daily_pstn.jinja2
│       │       │   ├── how_it_works_twilio_daily_sip.jinja2
│       │       │   ├── project_structure_daily_pstn.jinja2
│       │       │   ├── project_structure_twilio_daily_sip.jinja2
│       │       │   ├── setup_daily_pstn.jinja2
│       │       │   ├── setup_telnyx.jinja2
│       │       │   ├── setup_twilio.jinja2
│       │       │   └── setup_twilio_daily_sip.jinja2
│       │       ├── client/
│       │       │   ├── react-nextjs/
│       │       │   │   ├── .gitignore
│       │       │   │   ├── env.example
│       │       │   │   ├── eslint.config.mjs
│       │       │   │   ├── next.config.ts
│       │       │   │   ├── package.json.jinja2
│       │       │   │   ├── postcss.config.mjs
│       │       │   │   ├── src/
│       │       │   │   │   ├── app/
│       │       │   │   │   │   ├── api/
│       │       │   │   │   │   │   ├── sessions/
│       │       │   │   │   │   │   │   └── [sessionId]/
│       │       │   │   │   │   │   │       └── [...path]/
│       │       │   │   │   │   │   │           └── route.ts
│       │       │   │   │   │   │   └── start/
│       │       │   │   │   │   │       └── route.ts
│       │       │   │   │   │   ├── components/
│       │       │   │   │   │   │   ├── App.tsx
│       │       │   │   │   │   │   └── TransportSelect.tsx
│       │       │   │   │   │   ├── globals.css
│       │       │   │   │   │   ├── layout.tsx
│       │       │   │   │   │   └── page.tsx
│       │       │   │   │   └── config.ts.jinja2
│       │       │   │   └── tsconfig.json
│       │       │   ├── react-vite/
│       │       │   │   ├── .gitignore
│       │       │   │   ├── env.example
│       │       │   │   ├── eslint.config.js
│       │       │   │   ├── index.html
│       │       │   │   ├── package.json.jinja2
│       │       │   │   ├── src/
│       │       │   │   │   ├── components/
│       │       │   │   │   │   ├── App.tsx
│       │       │   │   │   │   └── TransportSelect.tsx
│       │       │   │   │   ├── config.ts.jinja2
│       │       │   │   │   ├── index.css
│       │       │   │   │   └── main.tsx
│       │       │   │   ├── tsconfig.app.json
│       │       │   │   ├── tsconfig.json
│       │       │   │   ├── tsconfig.node.json
│       │       │   │   └── vite.config.ts
│       │       │   └── vanilla-js-vite/
│       │       │       ├── env.example
│       │       │       ├── index.html
│       │       │       ├── package.json.jinja2
│       │       │       └── src/
│       │       │           ├── app.js
│       │       │           ├── config.js.jinja2
│       │       │           └── style.css
│       │       ├── gitignore.jinja2
│       │       └── server/
│       │           ├── Dockerfile.jinja2
│       │           ├── _blocks/
│       │           │   ├── bot_entry_daily_pstn.jinja2
│       │           │   ├── bot_entry_twilio_daily_sip.jinja2
│       │           │   ├── run_bot_logic_cascade.jinja2
│       │           │   └── run_bot_logic_realtime.jinja2
│       │           ├── _macros/
│       │           │   ├── event_handlers.jinja2
│       │           │   ├── helper_functions.jinja2
│       │           │   ├── pipeline_components.jinja2
│       │           │   └── transport_setup.jinja2
│       │           ├── bot_cascade.py.jinja2
│       │           ├── bot_realtime.py.jinja2
│       │           ├── env.example.jinja2
│       │           ├── evals/
│       │           │   ├── starter_audio.yaml.jinja2
│       │           │   └── starter_text.yaml.jinja2
│       │           ├── pcc-deploy.toml.jinja2
│       │           ├── pyproject.toml.jinja2
│       │           ├── server_pstn_dialout.py.jinja2
│       │           ├── server_twilio_daily_sip_dialin.py.jinja2
│       │           ├── server_twilio_daily_sip_dialout.py.jinja2
│       │           ├── server_utils_pstn_dialout.py.jinja2
│       │           ├── server_utils_twilio_daily_sip_dialin.py.jinja2
│       │           └── server_utils_twilio_daily_sip_dialout.py.jinja2
│       ├── clocks/
│       │   ├── __init__.py
│       │   ├── base_clock.py
│       │   └── system_clock.py
│       ├── evals/
│       │   ├── __init__.py
│       │   ├── __main__.py
│       │   ├── harness.py
│       │   ├── judge.py
│       │   ├── scenario.py
│       │   ├── serializer.py
│       │   ├── services.py
│       │   ├── speech.py
│       │   ├── suite.py
│       │   ├── transcribe.py
│       │   └── transport.py
│       ├── extensions/
│       │   ├── __init__.py
│       │   ├── ivr/
│       │   │   ├── __init__.py
│       │   │   └── ivr_navigator.py
│       │   └── voicemail/
│       │       ├── __init__.py
│       │       └── voicemail_detector.py
│       ├── frames/
│       │   ├── __init__.py
│       │   ├── frames.proto
│       │   ├── frames.py
│       │   └── protobufs/
│       │       └── frames_pb2.py
│       ├── metrics/
│       │   ├── __init__.py
│       │   └── metrics.py
│       ├── observers/
│       │   ├── __init__.py
│       │   ├── base_observer.py
│       │   ├── loggers/
│       │   │   ├── __init__.py
│       │   │   ├── debug_log_observer.py
│       │   │   ├── llm_log_observer.py
│       │   │   ├── metrics_log_observer.py
│       │   │   └── transcription_log_observer.py
│       │   ├── startup_timing_observer.py
│       │   ├── turn_tracking_observer.py
│       │   └── user_bot_latency_observer.py
│       ├── pipeline/
│       │   ├── __init__.py
│       │   ├── base_pipeline.py
│       │   ├── job_context.py
│       │   ├── job_decorator.py
│       │   ├── llm_switcher.py
│       │   ├── parallel_pipeline.py
│       │   ├── pipeline.py
│       │   ├── runner.py
│       │   ├── service_switcher.py
│       │   ├── sync_parallel_pipeline.py
│       │   ├── task.py
│       │   ├── worker.py
│       │   ├── worker_observer.py
│       │   └── worker_ready_decorator.py
│       ├── processors/
│       │   ├── __init__.py
│       │   ├── aggregators/
│       │   │   ├── __init__.py
│       │   │   ├── async_tool_messages.py
│       │   │   ├── dtmf_aggregator.py
│       │   │   ├── gated.py
│       │   │   ├── gated_llm_context.py
│       │   │   ├── llm_context.py
│       │   │   ├── llm_context_summarizer.py
│       │   │   ├── llm_response.py
│       │   │   ├── llm_response_universal.py
│       │   │   ├── llm_text_processor.py
│       │   │   └── sentence.py
│       │   ├── async_generator.py
│       │   ├── audio/
│       │   │   ├── __init__.py
│       │   │   ├── audio_buffer_processor.py
│       │   │   └── vad_processor.py
│       │   ├── consumer_processor.py
│       │   ├── filters/
│       │   │   ├── __init__.py
│       │   │   ├── frame_filter.py
│       │   │   ├── function_filter.py
│       │   │   ├── identity_filter.py
│       │   │   ├── null_filter.py
│       │   │   ├── wake_check_filter.py
│       │   │   └── wake_notifier_filter.py
│       │   ├── frame_processor.py
│       │   ├── frameworks/
│       │   │   ├── __init__.py
│       │   │   ├── langchain.py
│       │   │   ├── rtvi/
│       │   │   │   ├── __init__.py
│       │   │   │   ├── frames.py
│       │   │   │   ├── models.py
│       │   │   │   ├── observer.py
│       │   │   │   └── processor.py
│       │   │   └── strands_agents.py
│       │   ├── gstreamer/
│       │   │   ├── __init__.py
│       │   │   └── pipeline_source.py
│       │   ├── idle_frame_processor.py
│       │   ├── logger.py
│       │   ├── metrics/
│       │   │   ├── __init__.py
│       │   │   ├── frame_processor_metrics.py
│       │   │   └── sentry.py
│       │   ├── producer_processor.py
│       │   └── text_transformer.py
│       ├── py.typed
│       ├── registry/
│       │   ├── __init__.py
│       │   ├── registry.py
│       │   └── types.py
│       ├── runner/
│       │   ├── __init__.py
│       │   ├── daily.py
│       │   ├── livekit.py
│       │   ├── run.py
│       │   ├── types.py
│       │   ├── utils.py
│       │   └── vonage.py
│       ├── serializers/
│       │   ├── __init__.py
│       │   ├── base_serializer.py
│       │   ├── exotel.py
│       │   ├── genesys.py
│       │   ├── plivo.py
│       │   ├── protobuf.py
│       │   ├── telnyx.py
│       │   ├── twilio.py
│       │   └── vonage.py
│       ├── services/
│       │   ├── __init__.py
│       │   ├── ai_service.py
│       │   ├── anthropic/
│       │   │   ├── __init__.py
│       │   │   └── llm.py
│       │   ├── assemblyai/
│       │   │   ├── __init__.py
│       │   │   ├── models.py
│       │   │   └── stt.py
│       │   ├── asyncai/
│       │   │   ├── __init__.py
│       │   │   └── tts.py
│       │   ├── aws/
│       │   │   ├── __init__.py
│       │   │   ├── agent_core.py
│       │   │   ├── llm.py
│       │   │   ├── nova_sonic/
│       │   │   │   ├── __init__.py
│       │   │   │   ├── llm.py
│       │   │   │   └── session_continuation.py
│       │   │   ├── sagemaker/
│       │   │   │   ├── __init__.py
│       │   │   │   └── bidi_client.py
│       │   │   ├── stt.py
│       │   │   ├── tts.py
│       │   │   └── utils.py
│       │   ├── azure/
│       │   │   ├── __init__.py
│       │   │   ├── common.py
│       │   │   ├── image.py
│       │   │   ├── llm.py
│       │   │   ├── realtime/
│       │   │   │   ├── __init__.py
│       │   │   │   └── llm.py
│       │   │   ├── stt.py
│       │   │   └── tts.py
│       │   ├── camb/
│       │   │   ├── __init__.py
│       │   │   └── tts.py
│       │   ├── cartesia/
│       │   │   ├── __init__.py
│       │   │   ├── stt.py
│       │   │   ├── tts.py
│       │   │   └── turns/
│       │   │       ├── __init__.py
│       │   │       └── stt.py
│       │   ├── cerebras/
│       │   │   ├── __init__.py
│       │   │   └── llm.py
│       │   ├── deepgram/
│       │   │   ├── __init__.py
│       │   │   ├── flux/
│       │   │   │   ├── __init__.py
│       │   │   │   ├── base.py
│       │   │   │   ├── sagemaker/
│       │   │   │   │   ├── __init__.py
│       │   │   │   │   └── stt.py
│       │   │   │   └── stt.py
│       │   │   ├── sagemaker/
│       │   │   │   ├── __init__.py
│       │   │   │   ├── stt.py
│       │   │   │   └── tts.py
│       │   │   ├── stt.py
│       │   │   └── tts.py
│       │   ├── deepseek/
│       │   │   ├── __init__.py
│       │   │   └── llm.py
│       │   ├── elevenlabs/
│       │   │   ├── __init__.py
│       │   │   ├── stt.py
│       │   │   └── tts.py
│       │   ├── fal/
│       │   │   ├── __init__.py
│       │   │   ├── image.py
│       │   │   └── stt.py
│       │   ├── fireworks/
│       │   │   ├── __init__.py
│       │   │   └── llm.py
│       │   ├── fish/
│       │   │   ├── __init__.py
│       │   │   └── tts.py
│       │   ├── gladia/
│       │   │   ├── __init__.py
│       │   │   ├── config.py
│       │   │   └── stt.py
│       │   ├── google/
│       │   │   ├── __init__.py
│       │   │   ├── frames.py
│       │   │   ├── gemini_live/
│       │   │   │   ├── __init__.py
│       │   │   │   ├── file_api.py
│       │   │   │   ├── llm.py
│       │   │   │   └── vertex/
│       │   │   │       ├── __init__.py
│       │   │   │       └── llm.py
│       │   │   ├── image.py
│       │   │   ├── llm.py
│       │   │   ├── rtvi.py
│       │   │   ├── stt.py
│       │   │   ├── tts.py
│       │   │   ├── utils.py
│       │   │   └── vertex/
│       │   │       ├── __init__.py
│       │   │       └── llm.py
│       │   ├── gradium/
│       │   │   ├── __init__.py
│       │   │   ├── stt.py
│       │   │   └── tts.py
│       │   ├── grok/
│       │   │   ├── __init__.py
│       │   │   ├── llm.py
│       │   │   └── realtime/
│       │   │       ├── __init__.py
│       │   │       ├── events.py
│       │   │       └── llm.py
│       │   ├── groq/
│       │   │   ├── __init__.py
│       │   │   ├── llm.py
│       │   │   ├── stt.py
│       │   │   └── tts.py
│       │   ├── heygen/
│       │   │   ├── __init__.py
│       │   │   ├── api_interactive_avatar.py
│       │   │   ├── api_liveavatar.py
│       │   │   ├── base_api.py
│       │   │   ├── client.py
│       │   │   └── video.py
│       │   ├── hume/
│       │   │   ├── __init__.py
│       │   │   └── tts.py
│       │   ├── image_service.py
│       │   ├── inception/
│       │   │   ├── __init__.py
│       │   │   └── llm.py
│       │   ├── inworld/
│       │   │   ├── __init__.py
│       │   │   ├── realtime/
│       │   │   │   ├── __init__.py
│       │   │   │   ├── events.py
│       │   │   │   └── llm.py
│       │   │   └── tts.py
│       │   ├── kokoro/
│       │   │   ├── __init__.py
│       │   │   └── tts.py
│       │   ├── llm_service.py
│       │   ├── lmnt/
│       │   │   ├── __init__.py
│       │   │   └── tts.py
│       │   ├── mcp_service.py
│       │   ├── mem0/
│       │   │   ├── __init__.py
│       │   │   └── memory.py
│       │   ├── minimax/
│       │   │   ├── __init__.py
│       │   │   └── tts.py
│       │   ├── mistral/
│       │   │   ├── __init__.py
│       │   │   ├── llm.py
│       │   │   ├── stt.py
│       │   │   └── tts.py
│       │   ├── moondream/
│       │   │   ├── __init__.py
│       │   │   └── vision.py
│       │   ├── moonshine/
│       │   │   ├── __init__.py
│       │   │   └── stt.py
│       │   ├── nebius/
│       │   │   ├── __init__.py
│       │   │   └── llm.py
│       │   ├── neuphonic/
│       │   │   ├── __init__.py
│       │   │   └── tts.py
│       │   ├── novita/
│       │   │   ├── __init__.py
│       │   │   └── llm.py
│       │   ├── nvidia/
│       │   │   ├── __init__.py
│       │   │   ├── llm.py
│       │   │   ├── sagemaker/
│       │   │   │   ├── __init__.py
│       │   │   │   ├── stt.py
│       │   │   │   └── tts.py
│       │   │   ├── stt.py
│       │   │   └── tts.py
│       │   ├── ollama/
│       │   │   ├── __init__.py
│       │   │   └── llm.py
│       │   ├── openai/
│       │   │   ├── __init__.py
│       │   │   ├── _constants.py
│       │   │   ├── base_llm.py
│       │   │   ├── image.py
│       │   │   ├── llm.py
│       │   │   ├── realtime/
│       │   │   │   ├── __init__.py
│       │   │   │   ├── events.py
│       │   │   │   └── llm.py
│       │   │   ├── responses/
│       │   │   │   ├── __init__.py
│       │   │   │   └── llm.py
│       │   │   ├── stt.py
│       │   │   └── tts.py
│       │   ├── openrouter/
│       │   │   ├── __init__.py
│       │   │   └── llm.py
│       │   ├── perplexity/
│       │   │   ├── __init__.py
│       │   │   └── llm.py
│       │   ├── piper/
│       │   │   ├── __init__.py
│       │   │   └── tts.py
│       │   ├── qwen/
│       │   │   ├── __init__.py
│       │   │   └── llm.py
│       │   ├── resembleai/
│       │   │   ├── __init__.py
│       │   │   └── tts.py
│       │   ├── rime/
│       │   │   ├── __init__.py
│       │   │   └── tts.py
│       │   ├── sambanova/
│       │   │   ├── __init__.py
│       │   │   └── llm.py
│       │   ├── sarvam/
│       │   │   ├── __init__.py
│       │   │   ├── _sdk.py
│       │   │   ├── llm.py
│       │   │   ├── stt.py
│       │   │   └── tts.py
│       │   ├── settings.py
│       │   ├── simli/
│       │   │   ├── __init__.py
│       │   │   └── video.py
│       │   ├── smallest/
│       │   │   ├── __init__.py
│       │   │   ├── stt.py
│       │   │   └── tts.py
│       │   ├── soniox/
│       │   │   ├── __init__.py
│       │   │   ├── stt.py
│       │   │   └── tts.py
│       │   ├── speechmatics/
│       │   │   ├── __init__.py
│       │   │   ├── stt.py
│       │   │   └── tts.py
│       │   ├── stt_latency.py
│       │   ├── stt_service.py
│       │   ├── tavus/
│       │   │   ├── __init__.py
│       │   │   └── video.py
│       │   ├── together/
│       │   │   ├── __init__.py
│       │   │   └── llm.py
│       │   ├── tts_service.py
│       │   ├── ultravox/
│       │   │   ├── __init__.py
│       │   │   └── llm.py
│       │   ├── vision_service.py
│       │   ├── websocket_service.py
│       │   ├── whisper/
│       │   │   ├── __init__.py
│       │   │   ├── base_stt.py
│       │   │   ├── stt.py
│       │   │   └── utils.py
│       │   ├── xai/
│       │   │   ├── __init__.py
│       │   │   ├── llm.py
│       │   │   ├── realtime/
│       │   │   │   ├── __init__.py
│       │   │   │   ├── events.py
│       │   │   │   └── llm.py
│       │   │   ├── stt.py
│       │   │   └── tts.py
│       │   └── xtts/
│       │       ├── __init__.py
│       │       └── tts.py
│       ├── tests/
│       │   ├── __init__.py
│       │   └── utils.py
│       ├── transcriptions/
│       │   ├── __init__.py
│       │   └── language.py
│       ├── transports/
│       │   ├── __init__.py
│       │   ├── base_input.py
│       │   ├── base_output.py
│       │   ├── base_transport.py
│       │   ├── daily/
│       │   │   ├── __init__.py
│       │   │   ├── transport.py
│       │   │   └── utils.py
│       │   ├── heygen/
│       │   │   ├── __init__.py
│       │   │   └── transport.py
│       │   ├── lemonslice/
│       │   │   ├── __init__.py
│       │   │   ├── api.py
│       │   │   └── transport.py
│       │   ├── livekit/
│       │   │   ├── __init__.py
│       │   │   ├── transport.py
│       │   │   └── utils.py
│       │   ├── local/
│       │   │   ├── __init__.py
│       │   │   ├── audio.py
│       │   │   └── tk.py
│       │   ├── smallwebrtc/
│       │   │   ├── __init__.py
│       │   │   ├── connection.py
│       │   │   ├── request_handler.py
│       │   │   └── transport.py
│       │   ├── tavus/
│       │   │   ├── __init__.py
│       │   │   └── transport.py
│       │   ├── vonage/
│       │   │   ├── __init__.py
│       │   │   ├── client.py
│       │   │   ├── utils.py
│       │   │   └── video_connector.py
│       │   ├── websocket/
│       │   │   ├── __init__.py
│       │   │   ├── client.py
│       │   │   ├── fastapi.py
│       │   │   └── server.py
│       │   └── whatsapp/
│       │       ├── __init__.py
│       │       ├── api.py
│       │       └── client.py
│       ├── turns/
│       │   ├── __init__.py
│       │   ├── types.py
│       │   ├── user_idle_controller.py
│       │   ├── user_mute/
│       │   │   ├── __init__.py
│       │   │   ├── always_user_mute_strategy.py
│       │   │   ├── base_user_mute_strategy.py
│       │   │   ├── first_speech_user_mute_strategy.py
│       │   │   ├── function_call_user_mute_strategy.py
│       │   │   └── mute_until_first_bot_complete_user_mute_strategy.py
│       │   ├── user_start/
│       │   │   ├── __init__.py
│       │   │   ├── base_user_turn_start_strategy.py
│       │   │   ├── external_user_turn_start_strategy.py
│       │   │   ├── krisp_viva_ip_user_turn_start_strategy.py
│       │   │   ├── min_words_user_turn_start_strategy.py
│       │   │   ├── transcription_user_turn_start_strategy.py
│       │   │   ├── vad_user_turn_start_strategy.py
│       │   │   └── wake_phrase_user_turn_start_strategy.py
│       │   ├── user_stop/
│       │   │   ├── __init__.py
│       │   │   ├── base_user_turn_stop_strategy.py
│       │   │   ├── deferred_user_turn_stop_strategy.py
│       │   │   ├── external_user_turn_completion_stop_strategy.py
│       │   │   ├── external_user_turn_stop_strategy.py
│       │   │   ├── llm_turn_completion_user_turn_stop_strategy.py
│       │   │   ├── speech_timeout_user_turn_stop_strategy.py
│       │   │   └── turn_analyzer_user_turn_stop_strategy.py
│       │   ├── user_turn_completion_mixin.py
│       │   ├── user_turn_controller.py
│       │   ├── user_turn_processor.py
│       │   └── user_turn_strategies.py
│       ├── utils/
│       │   ├── __init__.py
│       │   ├── async_tool_cancellation.py
│       │   ├── asyncio/
│       │   │   ├── __init__.py
│       │   │   └── task_manager.py
│       │   ├── base_object.py
│       │   ├── context/
│       │   │   ├── __init__.py
│       │   │   ├── aggregated_frame_sequencer.py
│       │   │   ├── llm_context_summarization.py
│       │   │   └── word_completion_tracker.py
│       │   ├── deprecation.py
│       │   ├── env.py
│       │   ├── frame_queue.py
│       │   ├── network.py
│       │   ├── security/
│       │   │   ├── __init__.py
│       │   │   └── allowed_origins.py
│       │   ├── startup.py
│       │   ├── string.py
│       │   ├── sync/
│       │   │   ├── __init__.py
│       │   │   ├── base_notifier.py
│       │   │   └── event_notifier.py
│       │   ├── text/
│       │   │   ├── __init__.py
│       │   │   ├── base_text_aggregator.py
│       │   │   ├── base_text_filter.py
│       │   │   ├── markdown_text_filter.py
│       │   │   ├── pattern_pair_aggregator.py
│       │   │   ├── simple_text_aggregator.py
│       │   │   ├── skip_tags_aggregator.py
│       │   │   └── word_timestamp_utils.py
│       │   ├── time.py
│       │   ├── tracing/
│       │   │   ├── __init__.py
│       │   │   ├── service_attributes.py
│       │   │   ├── service_decorators.py
│       │   │   ├── setup.py
│       │   │   ├── tracing_context.py
│       │   │   └── turn_trace_observer.py
│       │   └── utils.py
│       └── workers/
│           ├── base_worker.py
│           ├── llm/
│           │   ├── __init__.py
│           │   ├── llm_context_worker.py
│           │   ├── llm_worker.py
│           │   └── tool_decorator.py
│           ├── proxy/
│           │   ├── __init__.py
│           │   └── websocket/
│           │       ├── __init__.py
│           │       ├── client.py
│           │       └── server.py
│           ├── runner.py
│           └── ui/
│               ├── __init__.py
│               ├── ui_event_decorator.py
│               ├── ui_job_context.py
│               ├── ui_prompts.py
│               ├── ui_tools.py
│               └── ui_worker.py
└── tests/
    ├── __init__.py
    ├── aic_mocks.py
    ├── cli/
    │   ├── conftest.py
    │   ├── test_cli_extensions.py
    │   ├── test_client_generation.py
    │   ├── test_config_validator.py
    │   ├── test_create_command.py
    │   ├── test_create_in_place.py
    │   ├── test_init_agent_ready.py
    │   ├── test_list_options.py
    │   ├── test_project_generation.py
    │   ├── test_questions.py
    │   ├── test_quickstart.py
    │   └── test_service_registry.py
    ├── genesys/
    │   ├── __init__.py
    │   ├── conftest.py
    │   └── test_genesys_serializer.py
    ├── integration/
    │   └── test_integration_unified_function_calling.py
    ├── test_aggregated_frame_sequencer.py
    ├── test_aggregators.py
    ├── test_aic_filter.py
    ├── test_aic_filter_vad_factory_deprecation.py
    ├── test_aic_quail_vad.py
    ├── test_aic_vad.py
    ├── test_aic_vad_deprecation.py
    ├── test_app_resources.py
    ├── test_assemblyai_stt.py
    ├── test_async_tool_messages.py
    ├── test_audio_buffer_processor.py
    ├── test_auto_register_tools.py
    ├── test_aws_credentials.py
    ├── test_azure_stt.py
    ├── test_azure_tts.py
    ├── test_base_input_transport.py
    ├── test_base_output_transport.py
    ├── test_base_smart_turn_buffer.py
    ├── test_base_worker.py
    ├── test_bridge_processor.py
    ├── test_bus.py
    ├── test_bus_network.py
    ├── test_cartesia_stt.py
    ├── test_cartesia_tts.py
    ├── test_context_aggregators_universal.py
    ├── test_context_summarization.py
    ├── test_daily_transport_service.py
    ├── test_deepgram_stt.py
    ├── test_deprecation_markers.py
    ├── test_direct_functions.py
    ├── test_dtmf_aggregator.py
    ├── test_elevenlabs_stt.py
    ├── test_elevenlabs_tts.py
    ├── test_evals_harness.py
    ├── test_evals_judge.py
    ├── test_evals_scenario.py
    ├── test_evals_serializer.py
    ├── test_evals_services.py
    ├── test_evals_suite.py
    ├── test_evals_transport.py
    ├── test_fastapi_websocket.py
    ├── test_filters.py
    ├── test_frame_adapters.py
    ├── test_frame_processor.py
    ├── test_function_calling_adapters.py
    ├── test_gemini_live_user_audio.py
    ├── test_get_llm_invocation_params.py
    ├── test_google_utils.py
    ├── test_idle_frame_processor.py
    ├── test_inworld_tts_language.py
    ├── test_ivr_navigation.py
    ├── test_job_group.py
    ├── test_krisp_ip_user_turn_start_strategy.py
    ├── test_krisp_sdk_manager.py
    ├── test_krisp_viva_filter.py
    ├── test_krisp_viva_vad.py
    ├── test_langchain.py
    ├── test_livekit_transport.py
    ├── test_llm_context.py
    ├── test_llm_context_summarizer.py
    ├── test_llm_response.py
    ├── test_llm_service.py
    ├── test_llm_switcher.py
    ├── test_llm_worker.py
    ├── test_local_smart_turn_v3_features.py
    ├── test_local_smart_turn_v3_resample.py
    ├── test_markdown_text_filter.py
    ├── test_messages.py
    ├── test_novita_llm.py
    ├── test_openai_llm_timeout.py
    ├── test_openai_realtime_audio_frames.py
    ├── test_openai_realtime_reasoning.py
    ├── test_openai_realtime_user_audio.py
    ├── test_openai_responses_http.py
    ├── test_openai_responses_websocket.py
    ├── test_pattern_pair_aggregator.py
    ├── test_pgmq_backends.py
    ├── test_pgmq_bus.py
    ├── test_pipeline.py
    ├── test_pipeline_worker_ui_bridge.py
    ├── test_piper_tts.py
    ├── test_producer_consumer.py
    ├── test_protobuf_serializer.py
    ├── test_realtime_tool_sync.py
    ├── test_redis_bus.py
    ├── test_registry.py
    ├── test_resampy_resampler.py
    ├── test_rnnoise_cancellation.py
    ├── test_rnnoise_filter.py
    ├── test_rnnoise_resampling.py
    ├── test_rtvi_observer_config.py
    ├── test_rtvi_processor.py
    ├── test_rtvi_ui.py
    ├── test_run_inference.py
    ├── test_runner.py
    ├── test_runner_downloads.py
    ├── test_runner_run.py
    ├── test_runner_utils.py
    ├── test_sambanova_llm.py
    ├── test_serializers.py
    ├── test_service_init.py
    ├── test_service_language.py
    ├── test_service_switcher.py
    ├── test_settings.py
    ├── test_simple_text_aggregator.py
    ├── test_skip_tags_aggregator.py
    ├── test_smallest_tts.py
    ├── test_smallwebrtc_transport.py
    ├── test_soniox_stt.py
    ├── test_soxr_resamplers.py
    ├── test_startup_timing_observer.py
    ├── test_sync_parallel_pipeline.py
    ├── test_task_manager.py
    ├── test_tracing_context.py
    ├── test_tts_frame_ordering.py
    ├── test_turn_trace_observer.py
    ├── test_turn_tracking_observer.py
    ├── test_ui_commands.py
    ├── test_ui_job_lifecycle.py
    ├── test_ui_tools.py
    ├── test_ui_worker.py
    ├── test_user_bot_latency_observer.py
    ├── test_user_idle_controller.py
    ├── test_user_mute_strategy.py
    ├── test_user_turn_completion_mixin.py
    ├── test_user_turn_controller.py
    ├── test_user_turn_processor.py
    ├── test_user_turn_start_strategy.py
    ├── test_user_turn_stop_strategy.py
    ├── test_utils_network.py
    ├── test_utils_string.py
    ├── test_vad_controller.py
    ├── test_vad_processor.py
    ├── test_version_banner.py
    ├── test_vonage_video_connector.py
    ├── test_wake_phrase_user_turn_start_strategy.py
    ├── test_websocket_proxy.py
    ├── test_websocket_service.py
    ├── test_websocket_transport.py
    ├── test_word_completion_tracker.py
    ├── test_word_timestamp_utils.py
    └── test_xai_tts.py
Copy disabled (too large)
Condensed preview — 1333 files, each showing path, character count, and a content snippet. Download the .json file for the full structured content (11,618K chars).
[
  {
    "path": ".claude/settings.json",
    "chars": 44,
    "preview": "{\n  \"attribution\": {\n    \"commit\": \"\"\n  }\n}\n"
  },
  {
    "path": ".claude/skills/changelog/SKILL.md",
    "chars": 2882,
    "preview": "---\nname: changelog\ndescription: Create changelog files for important commits in a PR\n---\n\nCreate changelog files for th..."
  },
  {
    "path": ".claude/skills/cleanup/SKILL.md",
    "chars": 7511,
    "preview": "---\nname: cleanup\ndescription: Review, refactor, document, and validate code changes in the current branch\n---\n\n# Code C..."
  },
  {
    "path": ".claude/skills/code-review/SKILL.md",
    "chars": 6942,
    "preview": "---\nname: code-review\ndescription: Automated code review for pull requests using multiple specialized agents\ndisable-mod..."
  },
  {
    "path": ".claude/skills/docstring/SKILL.md",
    "chars": 7698,
    "preview": "---\nname: docstring\ndescription: Document a Python module and its classes using Google style\n---\n\nDocument a Python modu..."
  },
  {
    "path": ".claude/skills/pr-description/SKILL.md",
    "chars": 3784,
    "preview": "---\nname: pr-description\ndescription: Update a GitHub PR description with a summary of changes\n---\n\nUpdate a GitHub pull..."
  },
  {
    "path": ".claude/skills/pr-submit/SKILL.md",
    "chars": 1015,
    "preview": "---\nname: pr-submit\ndescription: Create and submit a GitHub PR from the current branch\n---\n\nSubmit the current changes a..."
  },
  {
    "path": ".claude/skills/squash-commits/SKILL.md",
    "chars": 2726,
    "preview": "---\nname: squash-commits\ndescription: Reorganize messy branch commits into a small set of logical, meaningful commits wi..."
  },
  {
    "path": ".claude/skills/update-docs/SKILL.md",
    "chars": 11633,
    "preview": "---\nname: update-docs\ndescription: Update documentation pages to match source code changes on the current branch\n---\n\nUp..."
  },
  {
    "path": ".claude/skills/update-docs/SOURCE_DOC_MAPPING.md",
    "chars": 4078,
    "preview": "# Source-to-Doc Mapping\n\nMaps pipecat source files to their documentation pages. Source paths are relative to `src/pipec..."
  },
  {
    "path": ".claude-plugin/marketplace.json",
    "chars": 708,
    "preview": "{\n  \"name\": \"pipecat-dev-skills\",\n  \"owner\": {\n    \"name\": \"Pipecat\"\n  },\n  \"metadata\": {\n    \"description\": \"Developmen..."
  },
  {
    "path": ".github/ISSUE_TEMPLATE/1-bug_report.yml",
    "chars": 1930,
    "preview": "name: Bug report\ndescription: Report a bug or unexpected behavior\ntype: Bug\nbody:\n  - type: markdown\n    attributes:..."
  },
  {
    "path": ".github/ISSUE_TEMPLATE/2-question.yml",
    "chars": 1631,
    "preview": "name: Question\ndescription: Ask a question or get help\ntype: Question\nbody:\n  - type: markdown\n    attributes:\n      val..."
  },
  {
    "path": ".github/ISSUE_TEMPLATE/3-feature_request.yml",
    "chars": 1410,
    "preview": "name: Feature request\ndescription: Suggest an enhancement or new feature\ntype: Enhancement\nbody:\n  - type: markdown..."
  },
  {
    "path": ".github/ISSUE_TEMPLATE/4-service-issue.yml",
    "chars": 1951,
    "preview": "name: Service Issue\ndescription: An issue with a third-party service\ntype: Service Issue\nbody:\n  - type: markdown\n    at..."
  },
  {
    "path": ".github/ISSUE_TEMPLATE/5-new-service.yml",
    "chars": 1490,
    "preview": "name: New Service\ndescription: Request to support a new third-party service\ntype: New Service\nbody:\n  - type: markdown..."
  },
  {
    "path": ".github/ISSUE_TEMPLATE/6-dependency.yml",
    "chars": 1847,
    "preview": "name: Dependency Issue\ndescription: An issue with a Pipecat dependency (not a third-party service)\ntype: Dependency Issu..."
  },
  {
    "path": ".github/ISSUE_TEMPLATE/7-troubleshooting.yml",
    "chars": 1758,
    "preview": "name: Troubleshooting\ndescription: Help with a specific use case\ntype: Troubleshooting\nbody:\n  - type: markdown\n    attr..."
  },
  {
    "path": ".github/ISSUE_TEMPLATE/config.yml",
    "chars": 28,
    "preview": "blank_issues_enabled: false\n"
  },
  {
    "path": ".github/PULL_REQUEST_TEMPLATE.md",
    "chars": 105,
    "preview": "#### Please describe the changes in your PR. If it is addressing an issue, please reference that as well."
  },
  {
    "path": ".github/workflows/build.yaml",
    "chars": 770,
    "preview": "name: build\n\non:\n  workflow_dispatch:\n  push:\n    branches:\n      - main\n  pull_request:\n    branches:\n      - \"**\"..."
  },
  {
    "path": ".github/workflows/coverage.yaml",
    "chars": 1438,
    "preview": "name: coverage\n\non:\n  workflow_dispatch:\n  push:\n    branches:\n      - main\n  pull_request:\n    branches:\n      - \"**\"..."
  },
  {
    "path": ".github/workflows/format.yaml",
    "chars": 1794,
    "preview": "name: format\n\non:\n  workflow_dispatch:\n  push:\n    branches:\n      - main\n  pull_request:\n    branches:\n      - \"**\"..."
  },
  {
    "path": ".github/workflows/generate-changelog.yml",
    "chars": 5892,
    "preview": "name: Generate Changelog for Release\n\non:\n  workflow_dispatch:\n    inputs:\n      version:\n        description: \"Release..."
  },
  {
    "path": ".github/workflows/publish.yaml",
    "chars": 1892,
    "preview": "name: publish\n\non:\n  workflow_dispatch:\n    inputs:\n      gitref:\n        type: string\n        description: 'what git ta..."
  },
  {
    "path": ".github/workflows/publish_test.yaml",
    "chars": 1268,
    "preview": "name: publish-test\n\non: workflow_dispatch\n\njobs:\n  build:\n    name: 'Build and upload wheels'\n    runs-on: ubuntu-latest..."
  },
  {
    "path": ".github/workflows/python-compatibility.yaml",
    "chars": 1276,
    "preview": "name: Python Compatibility Test\n\non:\n  push:\n    branches: [main, develop]\n    paths: ['pyproject.toml']\n  pull_request:..."
  },
  {
    "path": ".github/workflows/tests.yaml",
    "chars": 1344,
    "preview": "name: tests\n\non:\n  workflow_dispatch:\n  push:\n    branches:\n      - main\n  pull_request:\n    branches:\n      - \"**\"..."
  },
  {
    "path": ".github/workflows/update-docs.yml",
    "chars": 5743,
    "preview": "name: Update Documentation on PR Merge\n\non:\n  pull_request_target:\n    types: [closed]\n    branches: [main]\n    paths:..."
  },
  {
    "path": ".gitignore",
    "chars": 741,
    "preview": ".vscode\nenv/\n__pycache__/\n*~\nvenv\n.venv\n.idea\n.gradle\n.next\nnext-env.d.ts\nlocal.properties\n*.log\n*.lock\nsmart_turn_audio..."
  },
  {
    "path": ".pre-commit-config.yaml",
    "chars": 2920,
    "preview": "repos:\n  - repo: local\n    hooks:\n      - id: ruff\n        name: ruff\n        entry: uv run ruff check --fix\n        lan..."
  },
  {
    "path": ".readthedocs.yaml",
    "chars": 567,
    "preview": "version: 2\n\nbuild:\n  os: ubuntu-22.04\n  tools:\n    python: '3.12'\n  apt_packages:\n    - portaudio19-dev\n    - python3-de..."
  },
  {
    "path": "AGENTS.md",
    "chars": 15451,
    "preview": "# AGENTS.md\n\nThis file provides guidance to AI coding agents when working with code in this repository.\n\n## Project Over..."
  },
  {
    "path": "CHANGELOG.md",
    "chars": 477772,
    "preview": "# Changelog\n\nAll notable changes to **Pipecat** will be documented in this file.\n\nThe format is based on [Keep a Changel..."
  },
  {
    "path": "CLAUDE.md",
    "chars": 11,
    "preview": "@AGENTS.md\n"
  },
  {
    "path": "COMMUNITY_INTEGRATIONS.md",
    "chars": 19701,
    "preview": "# Community Integrations Guide\n\nPipecat welcomes community-maintained integrations! As our ecosystem grows, we've establ..."
  },
  {
    "path": "CONTRIBUTING.md",
    "chars": 17372,
    "preview": "## Contributing to Pipecat\n\n**Want to add a new service integration?**\nWe encourage community-maintained integrations! P..."
  },
  {
    "path": "LICENSE",
    "chars": 1299,
    "preview": "BSD 2-Clause License\n\nCopyright (c) 2024–2026, Daily\n\nRedistribution and use in source and binary forms, with or without..."
  },
  {
    "path": "MANIFEST.in",
    "chars": 298,
    "preview": "prune docs\nprune examples\nprune scripts\nprune tests\n\n# Ship the CLI scaffolding templates in the sdist (jinja + client t..."
  },
  {
    "path": "README.md",
    "chars": 40609,
    "preview": "<h1><div align=\"center\">\n <img alt=\"pipecat\" width=\"300px\" height=\"auto\" src=\"https://raw.githubusercontent.com/pipecat-..."
  },
  {
    "path": "SECURITY.md",
    "chars": 86,
    "preview": "# Security Policy\n\n## Reporting a Vulnerability\n\nPlease email `disclosures@daily.co`.\n"
  },
  {
    "path": "changelog/4483.fixed.md",
    "chars": 183,
    "preview": "- Fixed output image resizing for generated images when video output dimensions differ from the source image size by con..."
  },
  {
    "path": "changelog/4519.fixed.md",
    "chars": 166,
    "preview": "- Fixed a benign `ERROR` log line emitted by `UltravoxRealtimeLLMService` during client-driven teardown. Adds an excepti..."
  },
  {
    "path": "changelog/4533.added.2.md",
    "chars": 638,
    "preview": "- Added `on_user_turn_message_added` event handler on `LLMUserAggregator`, with a new `UserTurnMessageAddedMessage` arg..."
  },
  {
    "path": "changelog/4533.added.3.md",
    "chars": 654,
    "preview": "- Added `RealtimeServiceMetadataFrame`, broadcast at pipeline start by realtime LLM services (OpenAI Realtime, Azure Rea..."
  },
  {
    "path": "changelog/4533.added.4.md",
    "chars": 918,
    "preview": "- Added a startup WARNING log on realtime LLM services that don't emit `UserStartedSpeakingFrame`/`UserStoppedSpeakingFr..."
  },
  {
    "path": "changelog/4533.added.5.md",
    "chars": 456,
    "preview": "- Added to our examples \"locally-driven-turns\" variants for:\n  - OpenAI Realtime (`realtime-openai-locally-driven-turns...."
  },
  {
    "path": "changelog/4533.added.md",
    "chars": 1959,
    "preview": "- Added a `realtime_service_mode: bool` kwarg on `LLMContextAggregatorPair`, for opting into a set of behaviors tailored..."
  },
  {
    "path": "changelog/4533.changed.2.md",
    "chars": 374,
    "preview": "- `UserTurnStoppedMessage.content` is now typed `str | None`. In realtime mode (`realtime_service_mode=True` on `LLMCont..."
  },
  {
    "path": "changelog/4533.changed.3.md",
    "chars": 525,
    "preview": "- `SpeechTimeoutUserTurnStopStrategy`, `TurnAnalyzerUserTurnStopStrategy`, and `ExternalUserTurnStopStrategy` now accept..."
  },
  {
    "path": "changelog/4533.changed.md",
    "chars": 1179,
    "preview": "- Migrated all realtime LLM service examples (OpenAI Realtime, Azure Realtime, Inworld, Grok/xAI Realtime, Gemini Live,..."
  },
  {
    "path": "changelog/4533.fixed.2.md",
    "chars": 660,
    "preview": "- Fixed Ultravox Realtime not surfacing server-side interruption. The server sends a `playback_clear_buffer` message whe..."
  },
  {
    "path": "changelog/4533.fixed.3.md",
    "chars": 786,
    "preview": "- Fixed `InworldRealtimeLLMService` not supporting manual-mode turn detection (`session_properties.audio.input.turn_dete..."
  },
  {
    "path": "changelog/4533.fixed.4.md",
    "chars": 1002,
    "preview": "- Fixed `GrokRealtimeLLMService` stalling the conversation when Grok returns an error in response to a `response.cancel`..."
  },
  {
    "path": "changelog/4533.fixed.5.md",
    "chars": 642,
    "preview": "- `InworldRealtimeLLMService` and `GrokRealtimeLLMService` no longer broadcast `UserStartedSpeakingFrame`/`UserStoppedSp..."
  },
  {
    "path": "changelog/4533.fixed.md",
    "chars": 656,
    "preview": "- Fixed AWS Nova Sonic not surfacing server-side interruption. When the user interrupted the bot mid-response, the `INTE..."
  },
  {
    "path": "changelog/4535.changed.md",
    "chars": 638,
    "preview": "- Updated Smallest AI TTS plugin for Waves v4.0.0 API:\n  - New WebSocket endpoint `/waves/v1/tts/live` (previously `/wav..."
  },
  {
    "path": "changelog/4549.added.md",
    "chars": 189,
    "preview": "- Added `private_endpoint` parameter to `AzureTTSService` and `AzureHttpTTSService` for connecting via Private Link or c..."
  },
  {
    "path": "changelog/4578.fixed.md",
    "chars": 168,
    "preview": "- Fixed pipeline shutdown hanging on LiveKit when the remote peer disconnected mid-stream. The trailing `audio_out_end_s..."
  },
  {
    "path": "changelog/4588.added.md",
    "chars": 447,
    "preview": "- Added `AICQuailVADAnalyzer` (`pipecat.audio.vad.aic_quail_vad`), a noise-robust\n  Voice Activity Detection analyzer po..."
  },
  {
    "path": "changelog/4588.changed.md",
    "chars": 222,
    "preview": "- Updated `aic-sdk` dependency to `~=2.3.0`. The `AIC_SDK_LICENSE`\n  environment variable replaces the previous `AIC_LIC..."
  },
  {
    "path": "changelog/4588.deprecated.md",
    "chars": 423,
    "preview": "- ⚠️ Deprecated `AICVADAnalyzer` (`pipecat.audio.vad.aic_vad`) and\n  `AICFilter.create_vad_analyzer()`. Both are tied to..."
  },
  {
    "path": "changelog/4592.changed.md",
    "chars": 214,
    "preview": "- Aligned the deprecation docstrings in `LLMUserAggregatorParams` with the\n  project's documented convention by removing..."
  },
  {
    "path": "changelog/4593.added.md",
    "chars": 450,
    "preview": "- Added `continuous_partials` and `interruption_delay` connection parameters to\n  the AssemblyAI streaming STT service (..."
  },
  {
    "path": "changelog/4597.added.md",
    "chars": 431,
    "preview": "- Added a `user_audio_preroll_secs` parameter to `GeminiLiveLLMService` controlling how much \"pre-roll\" audio is replaye..."
  },
  {
    "path": "changelog/4597.fixed.md",
    "chars": 440,
    "preview": "- Fixed the start of user speech being clipped from transcripts when `GeminiLiveLLMService` is configured for locally-dr..."
  },
  {
    "path": "changelog/4599.added.md",
    "chars": 464,
    "preview": "- Added a `user_audio_preroll_secs` parameter to `OpenAIRealtimeLLMService` controlling how much \"pre-roll\" audio is rep..."
  },
  {
    "path": "changelog/4599.fixed.md",
    "chars": 502,
    "preview": "- Fixed the start of user speech being clipped from transcripts when `OpenAIRealtimeLLMService` is configured for locall..."
  },
  {
    "path": "changelog/4612.added.md",
    "chars": 599,
    "preview": "- Added word-level timestamp support to `SmallestTTSService`. Enabled by default\n  via the `word_timestamps` constructor..."
  },
  {
    "path": "changelog/4620.added.md",
    "chars": 536,
    "preview": "- Added a `profanity` setting to `AzureSTTService` (via `settings=AzureSTTService.Settings(profanity=...)`) controlling..."
  },
  {
    "path": "changelog/4620.changed.md",
    "chars": 401,
    "preview": "- `AzureSTTService` now marks final transcripts as finalized. Azure's `RecognizedSpeech` event is by definition the fina..."
  },
  {
    "path": "changelog/4622.added.md",
    "chars": 277,
    "preview": "- WhatsApp `connection_callback` now receives the full call metadata (`WhatsAppConnectCall`) as a second argument, avail..."
  },
  {
    "path": "changelog/4622.deprecated.md",
    "chars": 316,
    "preview": "- The single-argument `connection_callback(connection)` signature for `WhatsAppClient.handle_webhook_request` is depreca..."
  },
  {
    "path": "changelog/4622.fixed.md",
    "chars": 232,
    "preview": "- 422 validation errors now log the full error details and raw request body for all transports (WhatsApp, WebRTC, teleph..."
  },
  {
    "path": "changelog/4626.changed.md",
    "chars": 517,
    "preview": "- ⚠️ The `mem0` extra now requires `mem0ai>=2,<3`. `Mem0MemoryService` was updated for the mem0 2.0.0 breaking changes:..."
  },
  {
    "path": "changelog/4626.deprecated.md",
    "chars": 207,
    "preview": "- Deprecated `Mem0MemoryService.InputParams.api_version`. It is no longer used — mem0 2.0.0 removed the `api_version`/`o..."
  },
  {
    "path": "changelog/4631.added.2.md",
    "chars": 355,
    "preview": "`pipecat create` takes an optional target directory: pass a path — for example `pipecat create .` — to scaffold **direct..."
  },
  {
    "path": "changelog/4631.added.md",
    "chars": 369,
    "preview": "Added the `pipecat create` project-scaffolding CLI to `pipecat-ai`, available via the optional `cli` extra. Install it w..."
  },
  {
    "path": "changelog/4632.changed.2.md",
    "chars": 79,
    "preview": "- `GradiumSTTService` has an updated `ttfs_p99_latency` value of 0.62 seconds.\n"
  },
  {
    "path": "changelog/4632.changed.md",
    "chars": 284,
    "preview": "- `GradiumSTTService` now defaults `delay_in_frames` to `12` (960ms) instead of leaving it unset (which used the server..."
  },
  {
    "path": "changelog/4634.changed.md",
    "chars": 129,
    "preview": "- Bumped `pipecat-ai-prebuilt` to 1.0.2 in the `runner` extra, updating the prebuilt client UI served by the development..."
  },
  {
    "path": "changelog/4635.fixed.md",
    "chars": 341,
    "preview": "- Fixed `InworldTTSService` logging a spurious \"no websocket connected, will try to reconnect\" warning and firing a redu..."
  },
  {
    "path": "changelog/4636.added.md",
    "chars": 326,
    "preview": "- Added `websocket` to the development runner's `-t`/`--transport` choices, so you can now run `python bot.py -t websock..."
  },
  {
    "path": "changelog/4639.fixed.md",
    "chars": 626,
    "preview": "- Fixed `SarvamTTSService` (WebSocket) emitting `BotStoppedSpeakingFrame` late. The service never produced a `TTSStopped..."
  },
  {
    "path": "changelog/4642.changed.md",
    "chars": 773,
    "preview": "- ⚠️ Changed the default of `TTSSpeakFrame.append_to_context` from `None` to\n  `True`. The old `None` behavior was situa..."
  },
  {
    "path": "changelog/4642.deprecated.md",
    "chars": 351,
    "preview": "- Deprecated passing `append_to_context=None` to `TTSSpeakFrame` (and\n  `BusTTSSpeakMessage`). `None` is no longer a sup..."
  },
  {
    "path": "changelog/4643.changed.md",
    "chars": 390,
    "preview": "- Switched the `aws` extra from `aioboto3` to `aiobotocore`. Pipecat only uses the low-level client API, and `aiobotocor..."
  },
  {
    "path": "changelog/4644.fixed.md",
    "chars": 890,
    "preview": "- Fixed a spurious `RuntimeWarning: coroutine '...' was never awaited` emitted by `TaskManager.create_task()` when a tas..."
  },
  {
    "path": "changelog/4650.fixed.md",
    "chars": 443,
    "preview": "- Fixed `LiveKitTransport` leaking audio/video stream readers when a track is unsubscribed: the owned `rtc.AudioStream`/..."
  },
  {
    "path": "changelog/4653.fixed.md",
    "chars": 354,
    "preview": "- Fixed `TTSService` emitting a second `LLMFullResponseEndFrame` (with a new id) at the end of an audio context when `pu..."
  },
  {
    "path": "changelog/4654.added.2.md",
    "chars": 152,
    "preview": "- `LLMContext(tools=...)` and `LLMSetToolsFrame` now accept a plain list of direct functions and/or `FunctionSchema` obj..."
  },
  {
    "path": "changelog/4654.added.3.md",
    "chars": 167,
    "preview": "- Added an optional `@tool_options(cancel_on_interruption=..., timeout_secs=...)` decorator for overriding a direct func..."
  },
  {
    "path": "changelog/4654.added.md",
    "chars": 416,
    "preview": "- Direct functions advertised in an `LLMContext` are now registered automatically — no separate registration call. List..."
  },
  {
    "path": "changelog/4655.added.2.md",
    "chars": 213,
    "preview": "- Added a `bot-interrupted` RTVI server message, emitted when the bot's in-flight output is cut off (a VAD-detected user..."
  },
  {
    "path": "changelog/4655.added.3.md",
    "chars": 498,
    "preview": "- Added `PipelineFlushFrame`, a control frame for draining the pipeline. Push it downstream and the pipeline worker boun..."
  },
  {
    "path": "changelog/4655.added.md",
    "chars": 941,
    "preview": "- Added `pipecat.evals`, a behavioral eval framework for Pipecat bots, usable both as a library and from the CLI. A YAML..."
  },
  {
    "path": "changelog/4656.fixed.md",
    "chars": 625,
    "preview": "- Fixed a frame-ordering race in bridged workers: frames received from the `WorkerBus` were pushed directly into the pip..."
  },
  {
    "path": "changelog/4658.changed.md",
    "chars": 451,
    "preview": "- `websockets` is now a core dependency of `pipecat-ai` instead of the `websockets-base` optional extra. The `websockets..."
  },
  {
    "path": "changelog/4660.security.md",
    "chars": 754,
    "preview": "- Added optional HMAC token authentication for WebSocket connections in the development runner. Set `PIPECAT_WEBSOCKET_A..."
  },
  {
    "path": "changelog/4664.added.md",
    "chars": 936,
    "preview": "- Added an opt-in `--eval` flag to `pipecat create` (and an `Enable evals?` wizard prompt, off by default) that makes th..."
  },
  {
    "path": "changelog/4665.fixed.md",
    "chars": 795,
    "preview": "- Fixed interruption handling for standalone `TTSSpeakFrame(append_to_context=True)` utterances (those not part of an LL..."
  },
  {
    "path": "changelog/4667.fixed.md",
    "chars": 653,
    "preview": "- Fixed `OpenAIResponsesHttpLLMService` raising `'NoneType' object has no attribute 'cached_tokens'` on every turn when..."
  },
  {
    "path": "changelog/4671.changed.md",
    "chars": 189,
    "preview": "- Renamed the `@tool` decorator's `timeout` argument to `timeout_secs`, matching `register_function()`. `timeout` still..."
  },
  {
    "path": "changelog/4671.deprecated.md",
    "chars": 326,
    "preview": "- Deprecated `LLMService.register_direct_function()` / `unregister_direct_function()` and `LLMSwitcher.register_direct_f..."
  },
  {
    "path": "changelog/4674.added.md",
    "chars": 128,
    "preview": "- Added `filter_repeated_sequences` parameter to `MarkdownTextFilter.InputParams` to allow disabling repeated sequence r..."
  },
  {
    "path": "changelog/4682.added.md",
    "chars": 62,
    "preview": "- Added support for Belgium german in transcription languages\n"
  },
  {
    "path": "changelog/4683.added.md",
    "chars": 621,
    "preview": "- Added `MoonshineSTTService`, a local speech-to-text service backed by [Moonshine](https://github.com/moonshine-ai/moon..."
  },
  {
    "path": "changelog/4684.changed.md",
    "chars": 203,
    "preview": "- `WhisperSTTService`'s `Model` and `MLXModel` are now `StrEnum`, so a member is the string itself (e.g. `Model.TINY ==..."
  },
  {
    "path": "changelog/4684.fixed.md",
    "chars": 360,
    "preview": "- Fixed importing `pipecat.services.whisper.stt` failing on non-macOS platforms when the `mlx-whisper` extra happened to..."
  },
  {
    "path": "changelog/4685.changed.md",
    "chars": 73,
    "preview": "- Bumped the `daily` extra's `daily-python` dependency to `>=0.29.1,<1`.\n"
  },
  {
    "path": "changelog/4686.added.md",
    "chars": 170,
    "preview": "- New features for the Vonage WebRTC transport\n  - Captions support\n  - Individual audio stream subscription support\n  -..."
  },
  {
    "path": "changelog/4687.fixed.md",
    "chars": 194,
    "preview": "- Fixed `SambaNovaLLMService` failing every completion with its default model: SambaNova Cloud removed `Llama-4-Maverick..."
  },
  {
    "path": "changelog/4688.fixed.md",
    "chars": 272,
    "preview": "- Fixed `NebiusLLMService` function calls never executing with its default model: Nebius streams `openai/gpt-oss-120b` t..."
  },
  {
    "path": "changelog/4690.changed.md",
    "chars": 337,
    "preview": "- `LLMWorker` now enables the worker's automatic RTVI support when it is not bridged (`bridged=None`), so a standalone `..."
  },
  {
    "path": "changelog/4691.fixed.md",
    "chars": 429,
    "preview": "- Fixed a worker-handoff race where `activate_worker(deactivate_self=True)` left both workers briefly active: the caller..."
  },
  {
    "path": "changelog/4692.changed.md",
    "chars": 239,
    "preview": "- Removed the `asyncio.sleep(0)` workarounds that let a just-created timer task start before a possible immediate cancel..."
  },
  {
    "path": "changelog/4703.fixed.md",
    "chars": 371,
    "preview": "- Fixed `AzureTTSService` producing no audio when running in a pipeline without an output transport (e.g. headless/offli..."
  },
  {
    "path": "changelog/4704.security.md",
    "chars": 836,
    "preview": "- Added origin restriction support to `WebsocketServerTransport`, `FastAPIWebsocketTransport`, and the development runne..."
  },
  {
    "path": "changelog/4705.changed.md",
    "chars": 216,
    "preview": "- Worker frames (e.g. `EndWorkerFrame`) should now be pushed downstream with a plain `push_frame(frame)`, so frames queu..."
  },
  {
    "path": "changelog/4705.deprecated.md",
    "chars": 408,
    "preview": "- ⚠️ Deprecated `TaskFrame`, `TaskSystemFrame`, `EndTaskFrame`, `StopTaskFrame`, `CancelTaskFrame` and `InterruptionTask..."
  },
  {
    "path": "changelog/4709.added.md",
    "chars": 688,
    "preview": "- `FunctionSchema` now accepts an optional `handler`. When set, the LLM service registers it automatically wherever the..."
  },
  {
    "path": "changelog/4709.changed.md",
    "chars": 314,
    "preview": "- `register_function` now reads a handler's call options (`cancel_on_interruption`, `timeout_secs`) from its `@tool_opti..."
  },
  {
    "path": "changelog/4709.fixed.2.md",
    "chars": 500,
    "preview": "- Fixed `LLMSwitcher.register_direct_function` overriding a direct function's `@tool_options` call options. Its `cancel_..."
  },
  {
    "path": "changelog/4709.fixed.md",
    "chars": 612,
    "preview": "- Fixed a regression from #4654 where unregistering a tool's handler on its own — via `unregister_function` / `unregiste..."
  },
  {
    "path": "changelog/4710.added.md",
    "chars": 780,
    "preview": "- Added `pipecat init`, which makes a project agent-ready by writing a Pipecat coding-agent guide (`AGENTS.md` plus a `C..."
  },
  {
    "path": "changelog/4714.fixed.md",
    "chars": 259,
    "preview": "- Fixed an audible 200-300 ms gap in audio mixer output (e.g. `SoundfileMixer` background sound) on every interruption...."
  },
  {
    "path": "changelog/4715.added.md",
    "chars": 217,
    "preview": "- Added the \"Add a WebRTC transport for local testing?\" option to the Daily PSTN and Twilio + Daily SIP scenarios in `pi..."
  },
  {
    "path": "changelog/4715.fixed.md",
    "chars": 508,
    "preview": "- Fixed `pipecat init` silently ignoring the \"Enable evals?\" option for the Daily PSTN Dial-out and Twilio + Daily SIP s..."
  },
  {
    "path": "changelog/4726.changed.2.md",
    "chars": 246,
    "preview": "- `BaseLLMAdapter.from_standard_tools` now raises `UserWarning` instead of `DeprecationWarning` when built-in tools can'..."
  },
  {
    "path": "changelog/4726.changed.md",
    "chars": 461,
    "preview": "- Deprecated classes and functions are now marked with the PEP 702 `@deprecated` decorator, so type checkers and IDEs (p..."
  },
  {
    "path": "changelog/_template.md.j2",
    "chars": 380,
    "preview": "{% for section, _ in sections.items() %}\n{% if sections[section] %}\n{% for category, val in definitions.items() if categ..."
  },
  {
    "path": "codecov.yml",
    "chars": 326,
    "preview": "coverage:\n  range: 50..90 # coverage lower than 50 is red, higher than 90 green, between color code\n\n  status:\n    proje..."
  },
  {
    "path": "docs/api/Makefile",
    "chars": 634,
    "preview": "# Minimal makefile for Sphinx documentation\n#\n\n# You can set these variables from the command line, and also\n# from the..."
  },
  {
    "path": "docs/api/README.md",
    "chars": 2154,
    "preview": "# Pipecat API Documentation\n\nThis directory contains the source files for auto-generating Pipecat's API reference docume..."
  },
  {
    "path": "docs/api/build-docs.sh",
    "chars": 879,
    "preview": "#!/bin/bash\n\n# Usage: ./build-docs.sh [--strict]\n#   --strict: Treat warnings as errors (default: warnings only)\n\nSPHINX..."
  },
  {
    "path": "docs/api/conf.py",
    "chars": 6885,
    "preview": "import logging\nimport os\nimport sys\nfrom datetime import datetime\nfrom pathlib import Path\n\n# Fix Pydantic v2 + Sphinx a..."
  },
  {
    "path": "docs/api/index.rst",
    "chars": 1072,
    "preview": "Pipecat API Reference\n=====================\n\nWelcome to the Pipecat API reference.\n\nUse the navigation on the left to br..."
  },
  {
    "path": "docs/api/make.bat",
    "chars": 800,
    "preview": "@ECHO OFF\r\n\r\npushd %~dp0\r\n\r\nREM Command file for Sphinx documentation\r\n\r\nif \"%SPHINXBUILD%\" == \"\" (\r\n\tset SPHINXBUILD=sp..."
  },
  {
    "path": "docs/api/rtd-test.sh",
    "chars": 949,
    "preview": "#!/bin/bash\nset -e\n\n# Configuration\nDOCS_DIR=$(pwd)\nPROJECT_ROOT=$(cd ../../ && pwd)\nTEST_DIR=\"/tmp/rtd-test-$(date +%Y%..."
  },
  {
    "path": "env.example",
    "chars": 4184,
    "preview": "# AI-COUSTICS\nAIC_SDK_LICENSE=...\n\n# Anthropic\nANTHROPIC_API_KEY=...\n\n# Assembly AI\nASSEMBLYAI_API_KEY=...\n\n# Async\nASYN..."
  },
  {
    "path": "examples/README.md",
    "chars": 4687,
    "preview": "# Pipecat Examples\n\nThis directory contains examples showing how to build voice and multimodal agents with Pipecat.\n\n##..."
  },
  {
    "path": "examples/assets/rag-content.txt",
    "chars": 141793,
    "preview": "The Open\nContents\nGeneral Information\n1.01 – The Open\n1.02 – Athletes\n1.03 – Drug Testing\n\nRegistration\n1.04 – Open Regi..."
  },
  {
    "path": "examples/audio/audio-bot-background-sound.py",
    "chars": 5590,
    "preview": "#\n# Copyright (c) 2024-2026, Daily\n#\n# SPDX-License-Identifier: BSD 2-Clause License\n#\n\n\nimport asyncio\nimport os\n\nfrom..."
  },
  {
    "path": "examples/audio/audio-recording.py",
    "chars": 7491,
    "preview": "#\n# Copyright (c) 2024-2026, Daily\n#\n# SPDX-License-Identifier: BSD 2-Clause License\n#\n\n\"\"\"Audio Recording Example with..."
  },
  {
    "path": "examples/audio/audio-sound-effects.py",
    "chars": 6039,
    "preview": "#\n# Copyright (c) 2024-2026, Daily\n#\n# SPDX-License-Identifier: BSD 2-Clause License\n#\n\nimport os\nimport wave\n\nfrom dote..."
  },
  {
    "path": "examples/context-summarization/context-summarization-dedicated-llm.py",
    "chars": 8629,
    "preview": "#\n# Copyright (c) 2024-2026, Daily\n#\n# SPDX-License-Identifier: BSD 2-Clause License\n#\n\n\"\"\"Example demonstrating advance..."
  },
  {
    "path": "examples/context-summarization/context-summarization-google.py",
    "chars": 7044,
    "preview": "#\n# Copyright (c) 2024-2026, Daily\n#\n# SPDX-License-Identifier: BSD 2-Clause License\n#\n\n\"\"\"Example demonstrating context..."
  },
  {
    "path": "examples/context-summarization/context-summarization-manual-openai.py",
    "chars": 6154,
    "preview": "#\n# Copyright (c) 2024-2026, Daily\n#\n# SPDX-License-Identifier: BSD 2-Clause License\n#\n\n\"\"\"Example demonstrating manual..."
  },
  {
    "path": "examples/context-summarization/context-summarization-openai.py",
    "chars": 7044,
    "preview": "#\n# Copyright (c) 2024-2026, Daily\n#\n# SPDX-License-Identifier: BSD 2-Clause License\n#\n\n\"\"\"Example demonstrating context..."
  },
  {
    "path": "examples/features/features-add-tool-change-messages.py",
    "chars": 8823,
    "preview": "#\n# Copyright (c) 2024-2026, Daily\n#\n# SPDX-License-Identifier: BSD 2-Clause License\n#\n\n\"\"\"Manual validation harness for..."
  },
  {
    "path": "examples/features/features-app-resources.py",
    "chars": 11808,
    "preview": "#\n# Copyright (c) 2024-2026, Daily\n#\n# SPDX-License-Identifier: BSD 2-Clause License\n#\n\n\"\"\"Example demonstrating ``Pipel..."
  },
  {
    "path": "examples/features/features-before-and-after-events.py",
    "chars": 5232,
    "preview": "#\n# Copyright (c) 2024-2026, Daily\n#\n# SPDX-License-Identifier: BSD 2-Clause License\n#\n\nimport os\nfrom dataclasses impor..."
  },
  {
    "path": "examples/features/features-concurrent-llm-evaluation.py",
    "chars": 6598,
    "preview": "#\n# Copyright (c) 2024-2026, Daily\n#\n# SPDX-License-Identifier: BSD 2-Clause License\n#\n\n\nimport os\n\nfrom dotenv import l..."
  },
  {
    "path": "examples/features/features-concurrent-llm-rtvi-ignored-sources.py",
    "chars": 7146,
    "preview": "#\n# Copyright (c) 2024-2026, Daily\n#\n# SPDX-License-Identifier: BSD 2-Clause License\n#\n\n\"\"\"RTVIObserver ignored sources..."
  },
  {
    "path": "examples/features/features-custom-frame-processor.py",
    "chars": 5583,
    "preview": "#\n# Copyright (c) 2024-2026, Daily\n#\n# SPDX-License-Identifier: BSD 2-Clause License\n#\n\nimport os\n\nfrom dotenv import lo..."
  },
  {
    "path": "examples/features/features-gpu-container-local-bot.py",
    "chars": 5983,
    "preview": "#\n# Copyright (c) 2024-2026, Daily\n#\n# SPDX-License-Identifier: BSD 2-Clause License\n#\n\n\nimport os\n\nfrom dotenv import l..."
  },
  {
    "path": "examples/features/features-live-translation.py",
    "chars": 5134,
    "preview": "#\n# Copyright (c) 2024-2026, Daily\n#\n# SPDX-License-Identifier: BSD 2-Clause License\n#\n\n\nimport os\n\nfrom dotenv import l..."
  },
  {
    "path": "examples/features/features-pattern-pair-voice-switching.py",
    "chars": 8805,
    "preview": "#\n# Copyright (c) 2024-2026, Daily\n#\n# SPDX-License-Identifier: BSD 2-Clause License\n#\n\n\"\"\"Pattern Pair Voice Switching..."
  },
  {
    "path": "examples/features/features-service-switcher.py",
    "chars": 7001,
    "preview": "#\n# Copyright (c) 2024-2026, Daily\n#\n# SPDX-License-Identifier: BSD 2-Clause License\n#\n\nimport asyncio\nimport os\n\nfrom d..."
  },
  {
    "path": "examples/features/features-switch-languages.py",
    "chars": 6444,
    "preview": "#\n# Copyright (c) 2024-2026, Daily\n#\n# SPDX-License-Identifier: BSD 2-Clause License\n#\n\n\nimport os\n\nfrom dotenv import l..."
  },
  {
    "path": "examples/features/features-switch-voices.py",
    "chars": 6812,
    "preview": "#\n# Copyright (c) 2024-2026, Daily\n#\n# SPDX-License-Identifier: BSD 2-Clause License\n#\n\n\nimport os\n\nfrom dotenv import l..."
  },
  {
    "path": "examples/features/features-user-email-gathering.py",
    "chars": 5343,
    "preview": "#\n# Copyright (c) 2024-2026, Daily\n#\n# SPDX-License-Identifier: BSD 2-Clause License\n#\n\n\nimport os\n\nfrom dotenv import l..."
  },
  {
    "path": "examples/features/features-voicemail-detection.py",
    "chars": 5207,
    "preview": "#\n# Copyright (c) 2024-2026, Daily\n#\n# SPDX-License-Identifier: BSD 2-Clause License\n#\n\nimport os\n\nfrom dotenv import lo..."
  },
  {
    "path": "examples/features/features-wake-phrase.py",
    "chars": 5044,
    "preview": "#\n# Copyright (c) 2024-2026, Daily\n#\n# SPDX-License-Identifier: BSD 2-Clause License\n#\n\nimport os\n\nfrom dotenv import lo..."
  },
  {
    "path": "examples/function-calling/function-calling-anthropic-async-stream.py",
    "chars": 7285,
    "preview": "#\n# Copyright (c) 2024-2026, Daily\n#\n# SPDX-License-Identifier: BSD 2-Clause License\n#\n\n\"\"\"Example: async function call..."
  },
  {
    "path": "examples/function-calling/function-calling-anthropic-async.py",
    "chars": 5796,
    "preview": "#\n# Copyright (c) 2024-2026, Daily\n#\n# SPDX-License-Identifier: BSD 2-Clause License\n#\n\nimport asyncio\nimport os\n\nfrom d..."
  },
  {
    "path": "examples/function-calling/function-calling-anthropic-video.py",
    "chars": 6451,
    "preview": "#\n# Copyright (c) 2024-2026, Daily\n#\n# SPDX-License-Identifier: BSD 2-Clause License\n#\n\nimport os\n\nfrom dotenv import lo..."
  },
  {
    "path": "examples/function-calling/function-calling-anthropic.py",
    "chars": 5138,
    "preview": "#\n# Copyright (c) 2024-2026, Daily\n#\n# SPDX-License-Identifier: BSD 2-Clause License\n#\n\n\nimport os\n\nfrom dotenv import l..."
  },
  {
    "path": "examples/function-calling/function-calling-aws-video.py",
    "chars": 6741,
    "preview": "#\n# Copyright (c) 2024-2026, Daily\n#\n# SPDX-License-Identifier: BSD 2-Clause License\n#\n\nimport os\n\nfrom dotenv import lo..."
  },
  {
    "path": "examples/function-calling/function-calling-aws.py",
    "chars": 5165,
    "preview": "#\n# Copyright (c) 2024-2026, Daily\n#\n# SPDX-License-Identifier: BSD 2-Clause License\n#\n\n\nfrom dotenv import load_dotenv..."
  },
  {
    "path": "examples/function-calling/function-calling-azure.py",
    "chars": 5421,
    "preview": "#\n# Copyright (c) 2024-2026, Daily\n#\n# SPDX-License-Identifier: BSD 2-Clause License\n#\n\n\nimport os\n\nfrom dotenv import l..."
  },
  {
    "path": "examples/function-calling/function-calling-cerebras.py",
    "chars": 5707,
    "preview": "#\n# Copyright (c) 2024-2026, Daily\n#\n# SPDX-License-Identifier: BSD 2-Clause License\n#\n\n\nimport os\n\nfrom dotenv import l..."
  },
  {
    "path": "examples/function-calling/function-calling-deepseek.py",
    "chars": 5742,
    "preview": "#\n# Copyright (c) 2024-2026, Daily\n#\n# SPDX-License-Identifier: BSD 2-Clause License\n#\n\n\nimport os\n\nfrom dotenv import l..."
  },
  {
    "path": "examples/function-calling/function-calling-direct.py",
    "chars": 5399,
    "preview": "#\n# Copyright (c) 2024-2026, Daily\n#\n# SPDX-License-Identifier: BSD 2-Clause License\n#\n\n\nimport os\n\nfrom dotenv import l..."
  },
  {
    "path": "examples/function-calling/function-calling-fireworks.py",
    "chars": 5650,
    "preview": "#\n# Copyright (c) 2024-2026, Daily\n#\n# SPDX-License-Identifier: BSD 2-Clause License\n#\n\n\nimport os\n\nfrom dotenv import l..."
  },
  {
    "path": "examples/function-calling/function-calling-google-async-stream.py",
    "chars": 7503,
    "preview": "#\n# Copyright (c) 2024-2026, Daily\n#\n# SPDX-License-Identifier: BSD 2-Clause License\n#\n\n\"\"\"Example: async function call..."
  },
  {
    "path": "examples/function-calling/function-calling-google-async.py",
    "chars": 8124,
    "preview": "#\n# Copyright (c) 2024-2026, Daily\n#\n# SPDX-License-Identifier: BSD 2-Clause License\n#\n\nimport asyncio\nimport os\n\nfrom d..."
  },
  {
    "path": "examples/function-calling/function-calling-google-vertex.py",
    "chars": 5668,
    "preview": "#\n# Copyright (c) 2024-2026, Daily\n#\n# SPDX-License-Identifier: BSD 2-Clause License\n#\n\n\nimport os\n\nfrom dotenv import l..."
  },
  {
    "path": "examples/function-calling/function-calling-google-video.py",
    "chars": 6446,
    "preview": "#\n# Copyright (c) 2024-2026, Daily\n#\n# SPDX-License-Identifier: BSD 2-Clause License\n#\n\nimport os\n\nfrom dotenv import lo..."
  },
  {
    "path": "examples/function-calling/function-calling-google.py",
    "chars": 7454,
    "preview": "#\n# Copyright (c) 2024-2026, Daily\n#\n# SPDX-License-Identifier: BSD 2-Clause License\n#\n\n\nimport os\n\nfrom dotenv import l..."
  },
  {
    "path": "examples/function-calling/function-calling-grok.py",
    "chars": 5340,
    "preview": "#\n# Copyright (c) 2024-2026, Daily\n#\n# SPDX-License-Identifier: BSD 2-Clause License\n#\n\n\nimport os\n\nimport aiohttp\nfrom..."
  },
  {
    "path": "examples/function-calling/function-calling-groq.py",
    "chars": 5297,
    "preview": "#\n# Copyright (c) 2024-2026, Daily\n#\n# SPDX-License-Identifier: BSD 2-Clause License\n#\n\n\nimport os\n\nfrom dotenv import l..."
  },
  {
    "path": "examples/function-calling/function-calling-inception.py",
    "chars": 5348,
    "preview": "#\n# Copyright (c) 2024-2026, Daily\n#\n# SPDX-License-Identifier: BSD 2-Clause License\n#\n\n\nimport os\n\nfrom dotenv import l..."
  },
  {
    "path": "examples/function-calling/function-calling-missing-handler.py",
    "chars": 7100,
    "preview": "#\n# Copyright (c) 2024-2026, Daily\n#\n# SPDX-License-Identifier: BSD 2-Clause License\n#\n\n\"\"\"Manual demonstration of the m..."
  },
  {
    "path": "examples/function-calling/function-calling-mistral.py",
    "chars": 5111,
    "preview": "#\n# Copyright (c) 2024-2026, Daily\n#\n# SPDX-License-Identifier: BSD 2-Clause License\n#\n\nimport os\n\nfrom dotenv import lo..."
  },
  {
    "path": "examples/function-calling/function-calling-moondream-video.py",
    "chars": 7952,
    "preview": "#\n# Copyright (c) 2024-2026, Daily\n#\n# SPDX-License-Identifier: BSD 2-Clause License\n#\n\nimport os\n\nfrom dotenv import lo..."
  },
  {
    "path": "examples/function-calling/function-calling-nebius.py",
    "chars": 5310,
    "preview": "#\n# Copyright (c) 2024-2026, Daily\n#\n# SPDX-License-Identifier: BSD 2-Clause License\n#\n\nimport os\n\nfrom dotenv import lo..."
  },
  {
    "path": "examples/function-calling/function-calling-novita.py",
    "chars": 5351,
    "preview": "#\n# Copyright (c) 2024-2026, Daily\n#\n# SPDX-License-Identifier: BSD 2-Clause License\n#\n\nimport os\n\nfrom dotenv import lo..."
  },
  {
    "path": "examples/function-calling/function-calling-nvidia.py",
    "chars": 5464,
    "preview": "#\n# Copyright (c) 2024-2026, Daily\n#\n# SPDX-License-Identifier: BSD 2-Clause License\n#\n\n\nimport os\n\nfrom dotenv import l..."
  },
  {
    "path": "examples/function-calling/function-calling-ollama.py",
    "chars": 5341,
    "preview": "#\n# Copyright (c) 2024-2026, Daily\n#\n# SPDX-License-Identifier: BSD 2-Clause License\n#\n\n\nimport os\n\nfrom dotenv import l..."
  },
  {
    "path": "examples/function-calling/function-calling-openai-async-stream.py",
    "chars": 7506,
    "preview": "#\n# Copyright (c) 2024-2026, Daily\n#\n# SPDX-License-Identifier: BSD 2-Clause License\n#\n\n\"\"\"Example: async function call..."
  },
  {
    "path": "examples/function-calling/function-calling-openai-async.py",
    "chars": 5917,
    "preview": "#\n# Copyright (c) 2024-2026, Daily\n#\n# SPDX-License-Identifier: BSD 2-Clause License\n#\n\nimport asyncio\nimport os\n\nfrom d..."
  },
  {
    "path": "examples/function-calling/function-calling-openai-responses-async-stream.py",
    "chars": 7621,
    "preview": "#\n# Copyright (c) 2024-2026, Daily\n#\n# SPDX-License-Identifier: BSD 2-Clause License\n#\n\n\"\"\"Example: async function call..."
  },
  {
    "path": "examples/function-calling/function-calling-openai-responses-async.py",
    "chars": 6429,
    "preview": "#\n# Copyright (c) 2024-2026, Daily\n#\n# SPDX-License-Identifier: BSD 2-Clause License\n#\n\nimport asyncio\nimport os\n\nfrom d..."
  },
  {
    "path": "examples/function-calling/function-calling-openai-responses-http.py",
    "chars": 5359,
    "preview": "#\n# Copyright (c) 2024-2026, Daily\n#\n# SPDX-License-Identifier: BSD 2-Clause License\n#\n\nimport os\n\nfrom dotenv import lo..."
  },
  {
    "path": "examples/function-calling/function-calling-openai-responses-video-http.py",
    "chars": 6576,
    "preview": "#\n# Copyright (c) 2024-2026, Daily\n#\n# SPDX-License-Identifier: BSD 2-Clause License\n#\n\n\nimport os\n\nfrom dotenv import l..."
  },
  {
    "path": "examples/function-calling/function-calling-openai-responses-video.py",
    "chars": 6564,
    "preview": "#\n# Copyright (c) 2024-2026, Daily\n#\n# SPDX-License-Identifier: BSD 2-Clause License\n#\n\n\nimport os\n\nfrom dotenv import l..."
  },
  {
    "path": "examples/function-calling/function-calling-openai-responses.py",
    "chars": 5782,
    "preview": "#\n# Copyright (c) 2024-2026, Daily\n#\n# SPDX-License-Identifier: BSD 2-Clause License\n#\n\nimport os\n\nfrom dotenv import lo..."
  },
  {
    "path": "examples/function-calling/function-calling-openai-video.py",
    "chars": 6527,
    "preview": "#\n# Copyright (c) 2024-2026, Daily\n#\n# SPDX-License-Identifier: BSD 2-Clause License\n#\n\n\nimport os\n\nfrom dotenv import l..."
  },
  {
    "path": "examples/function-calling/function-calling-openai.py",
    "chars": 5261,
    "preview": "#\n# Copyright (c) 2024-2026, Daily\n#\n# SPDX-License-Identifier: BSD 2-Clause License\n#\n\nimport os\n\nfrom dotenv import lo..."
  }
]

// ... and 1133 more files (download for full content)

About this extraction

This page contains the full source code of the pipecat-ai/pipecat GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 1335 files (10.6 MB), approximately 2.8M tokens. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!