Skip to content
Merged
Show file tree
Hide file tree
Changes from 19 commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
d0e9b1c
Move Pipecat Flows source into pipecat.flows
kompfner Jun 24, 2026
fffbe91
Move Pipecat Flows tests into the pipecat test suite
kompfner Jun 24, 2026
cf616f2
Move Pipecat Flows examples into examples/flows
kompfner Jun 24, 2026
eccaa2d
Wire Pipecat Flows into the docs tooling
kompfner Jun 24, 2026
504078f
Document Pipecat Flows as part of core in the README
kompfner Jun 24, 2026
6da91ab
Name the Flows changelog fragment with its PR number
kompfner Jun 24, 2026
0fa1e6d
Fold Flows into the update-docs mapping by tier, not as a silo
kompfner Jun 24, 2026
c87b9c7
Drop redundant flows/__init__.py skip-list entry
kompfner Jun 24, 2026
81c6b02
Warn when the standalone pipecat-ai-flows is installed alongside core…
kompfner Jun 24, 2026
8b38aeb
Note the coexistence guard in the Flows changelog entry
kompfner Jun 24, 2026
42ba08e
Restructure README Getting started and Code examples sections
kompfner Jun 25, 2026
19627b6
Rename the developer-setup section to "Developing Pipecat"
kompfner Jun 25, 2026
aeedc19
Run the standalone-Flows guard on any pipecat import
kompfner Jun 25, 2026
aea32e5
Addressing some PR feedback
kompfner Jun 25, 2026
83c6419
Fix Flows deprecation directives so the registry generates correctly
kompfner Jun 25, 2026
bead163
Mark deprecated FlowResult with the @deprecated decorator
kompfner Jun 25, 2026
ba091bb
Lead the RESET_WITH_SUMMARY directive with its replacement symbol
kompfner Jun 25, 2026
8760481
Update comment to avoid referencing a deprecated field
kompfner Jun 25, 2026
3ec7e44
Use `pipecat init` in the README now that `create` is gone
kompfner Jun 25, 2026
bcbccf2
Update a link in the README, from the CLI reference to the Build Your…
kompfner Jun 26, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions .claude/skills/update-docs/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ Filter to files that could affect documentation:
- `src/pipecat/turns/**/*.py` (turn management)
- `src/pipecat/observers/**/*.py` (observers)
- `src/pipecat/pipeline/**/*.py` (pipeline core)
- `src/pipecat/flows/**/*.py` (Pipecat Flows)

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

Expand Down Expand Up @@ -138,12 +139,12 @@ For each doc page that needs updates, edit **only the sections that need changes

### Step 7: Update guides

Guides at `DOCS_PATH/pipecat/` reference specific class names, parameters, imports, and code patterns. After completing reference doc edits, check if any guides need updates too.
Guides at `DOCS_PATH/pipecat/` and `DOCS_PATH/pipecat-flows/` reference specific class names, parameters, imports, and code patterns. After completing reference doc edits, check if any guides need updates too.
Comment thread
markbackman marked this conversation as resolved.

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/pipecat/
grep -rl "ClassName\|old_param_name" DOCS_PATH/pipecat/ DOCS_PATH/pipecat-flows/
```

For each guide that references changed code:
Expand All @@ -159,6 +160,7 @@ Guide directories:
- `pipecat/fundamentals/` — practical how-tos (metrics, recording, transcripts, etc.)
- `pipecat/features/` — feature-specific guides (Gemini Live, OpenAI audio, WhatsApp, etc.)
- `pipecat/telephony/` — telephony integration guides (Twilio, Plivo, Telnyx, etc.)
- `pipecat-flows/guides/` — Pipecat Flows guides (nodes-and-messages, functions, context-strategies, state-management, actions); check these when `src/pipecat/flows/**` changed

### Step 8: Identify doc gaps

Expand Down Expand Up @@ -287,9 +289,11 @@ After all edits are complete, print a summary:
### Updated reference pages
- `api-reference/server/services/stt/deepgram.mdx` — Updated Configuration (added `new_param`), InputParams (updated `language` default)
- `api-reference/server/services/tts/elevenlabs.mdx` — Updated Event Handlers (added `on_connected`)
- `api-reference/pipecat-flows/flow-manager.mdx` — Updated FlowManager constructor (added `new_param`)

### Updated guides
- `pipecat/learn/speech-to-text.mdx` — Updated code example (renamed `old_param` → `new_param`)
- `pipecat-flows/guides/state-management.mdx` — Updated FlowManager init example

### New service pages
- `api-reference/server/services/tts/newprovider.mdx` — Created page, added to docs.json (Text-to-Speech), added to supported-services.mdx
Expand Down
5 changes: 5 additions & 0 deletions .claude/skills/update-docs/SOURCE_DOC_MAPPING.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,11 @@ These source paths don't follow the standard `services/{provider}/{type}.py` →
| `pipeline/worker.py` | `api-reference/server/pipeline/pipeline-worker.mdx` |
| `pipeline/runner.py` | `api-reference/server/utilities/runner/guide.mdx` |
| `transports/base_transport.py` | `api-reference/server/services/transport/transport-params.mdx` |
| `flows/types.py` | `api-reference/pipecat-flows/types.mdx` |
| `flows/manager.py` | `api-reference/pipecat-flows/flow-manager.mdx` |
| `flows/actions.py` | `api-reference/pipecat-flows/flow-manager.mdx` and `api-reference/pipecat-flows/types.mdx` |
| `flows/adapters.py` | `api-reference/pipecat-flows/overview.mdx` |
| `flows/exceptions.py` | `api-reference/pipecat-flows/exceptions.mdx` |

## Skip list

Expand Down
1 change: 1 addition & 0 deletions .github/workflows/update-docs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ on:
- "src/pipecat/turns/**"
- "src/pipecat/observers/**"
- "src/pipecat/pipeline/**"
- "src/pipecat/flows/**"
workflow_dispatch:
inputs:
pr_number:
Expand Down
77 changes: 45 additions & 32 deletions README.md

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions changelog/4882.added.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
- Pipecat Flows is now part of `pipecat-ai`. The conversation-flow framework previously published as the separate `pipecat-ai-flows` package now ships with Pipecat under the `pipecat.flows` namespace — `from pipecat.flows import FlowManager, NodeConfig` — so there is no longer a separate package to install or keep version-matched. Code importing from `pipecat_flows` should switch to `pipecat.flows`. If the deprecated `pipecat-ai-flows` package is still installed alongside this Pipecat, Pipecat logs an error prompting you to remove it. The standalone package's release history remains available in the archived [pipecat-flows repository](https://github.com/pipecat-ai/pipecat-flows/blob/main/CHANGELOG.md).
1 change: 1 addition & 0 deletions docs/api/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,7 @@ def import_core_modules():
"""Import core pipecat modules for autodoc to discover."""
core_modules = [
"pipecat",
"pipecat.flows",
"pipecat.frames",
"pipecat.pipeline",
"pipecat.processors",
Expand Down
6 changes: 5 additions & 1 deletion examples/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ This directory contains examples showing how to build voice and multimodal agent

## Setup

1. Follow the [README](https://github.com/pipecat-ai/pipecat/blob/main/README.md#%EF%B8%8F-contributing-to-the-framework) steps to get your local environment configured.
1. Follow the [README](https://github.com/pipecat-ai/pipecat/blob/main/README.md#%EF%B8%8F-developing-pipecat) steps to get your local environment configured.

> **Run from root directory**: Make sure you are running the steps from the root directory.

Expand Down Expand Up @@ -61,6 +61,10 @@ uv run getting-started/06-voice-agent.py -t twilio -x NGROK_HOST_NAME

Progressive introduction to Pipecat, from minimal TTS to a full voice agent with function calling.

### [`flows/`](./flows/)

Structured conversations with [Pipecat Flows](../src/pipecat/flows): predefined and dynamic conversation paths with state management, across multiple LLM providers.

### [`voice/`](./voice/)

Full STT + LLM + TTS voice agent pipelines showcasing different speech service providers (Deepgram, ElevenLabs, Cartesia, etc.)
Expand Down
51 changes: 51 additions & 0 deletions examples/flows/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
# Pipecat Flows Examples

[Pipecat Flows](../../src/pipecat/flows) is the structured-conversation framework built into Pipecat. It lets you build both predefined conversation paths and dynamically generated flows while handling the complexities of state management and LLM interactions. These examples show it in action.

## Hello, world

[`hello_world.py`](./hello_world.py) is the smallest possible Flow: a bot that asks for your favorite color and then says goodbye. It's a good first read — it shows the basics of nodes, functions, and transitions. To run it, see Setup below.

## Setup

1. Follow the [README](../../README.md#%EF%B8%8F-developing-pipecat) steps to configure your local environment. Run the commands from the repo root.

2. Copy the [`env.example`](../../env.example) file and add API keys for the services you plan to use:

```bash
cp env.example .env
# Edit .env with your API keys
```

3. Run any example:

```bash
uv run python examples/flows/food_ordering.py
```

4. Open the web interface at http://localhost:7860/client/ and click "Connect".

All examples support multiple LLM providers (OpenAI, Anthropic, Google Gemini, AWS Bedrock) to demonstrate cross-provider compatibility. Like the other Pipecat examples, they default to the SmallWebRTC transport and also support Daily (`-t daily`) and telephony providers (`-t twilio -x NGROK_HOST_NAME`) — see the [examples README](../README.md#running-examples-with-other-transports) for transport details.

## Examples

### Core flows

- [`food_ordering.py`](./food_ordering.py) — restaurant order flow demonstrating node and edge functions
- [`restaurant_reservation.py`](./restaurant_reservation.py) — reservation system with availability checking
- [`patient_intake.py`](./patient_intake.py) — medical intake system showing complex state management
- [`insurance_quote.py`](./insurance_quote.py) — insurance quote system with data collection
- [`podcast_interview.py`](./podcast_interview.py) — podcast interview flow

### Advanced features

- [`llm_switching.py`](./llm_switching.py) — switching between LLM providers during a conversation
- [`warm_transfer.py`](./warm_transfer.py) — transferring calls between flows (DailyTransport only)
- [`multi_worker_handoff.py`](./multi_worker_handoff.py) — composing Flows with Pipecat's multi-worker framework: a structured Flows reservation worker hands off to and from a free-form `LLMWorker` router over the bus, sharing a single conversation context
- [`food_ordering_advanced_functionschema.py`](./food_ordering_advanced_functionschema.py) — the food-ordering flow defined with `FlowsFunctionSchema`s instead of direct functions, for when you need to specify a function's schema explicitly

The examples define their functions as "direct functions" — async functions whose schema is derived from the signature and docstring — which is the recommended pattern. `food_ordering_advanced_functionschema.py` shows the alternative `FlowsFunctionSchema` approach.

## Learn more

See the [Pipecat Flows guide](https://docs.pipecat.ai/guides/features/pipecat-flows) for a full walkthrough of nodes, functions, context strategies, and actions.
7 changes: 7 additions & 0 deletions examples/flows/assets/hold_music/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# Hold Music Player

This project is a hold music player, based on the `wav_audio_send` example from the [daily-python repository](https://github.com/daily-co/daily-python/blob/main/demos/audio/wav_audio_send.py). It is designed to serve as a helper for other examples, providing a reusable component for scenarios that require hold music functionality.

The hold music WAV file used in this example was sourced from [No Copyright Music](https://www.no-copyright-music.com/).

To see this hold music player in action, check out the [warm transfer example](../warm_transfer.py).
147 changes: 147 additions & 0 deletions examples/flows/assets/hold_music/hold_music.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
#
# This demo will join a Daily meeting and send the audio from a WAV file into
# the meeting. It uses the asyncio library.
#
# Usage: python3 hold_music.py -m MEETING_URL -i FILE.wav
#

import argparse
import asyncio
import signal
import wave

from daily import *

SAMPLE_RATE = 16000
NUM_CHANNELS = 1


class AsyncSendWavApp:
def __init__(self, input_file_name, sample_rate, num_channels):
self.__mic_device = Daily.create_microphone_device(
"my-mic",
sample_rate=sample_rate,
channels=num_channels,
non_blocking=True,
)

self.__client = CallClient()

self.__client.update_subscription_profiles(
{"base": {"camera": "unsubscribed", "microphone": "unsubscribed"}}
)

self.__app_error = None

self.__start_event = asyncio.Event()
self.__task = asyncio.get_running_loop().create_task(self.send_wav_file(input_file_name))

async def run(self, meeting_url, meeting_token):
(data, error) = await self.join(meeting_url, meeting_token)

if error:
print(f"Unable to join meeting: {error}")
self.__app_error = error

self.__start_event.set()

await self.__task

async def join(self, meeting_url, meeting_token):
future = asyncio.get_running_loop().create_future()

def join_completion(data, error):
future.get_loop().call_soon_threadsafe(future.set_result, (data, error))

self.__client.join(
meeting_url,
meeting_token,
client_settings={
"inputs": {
"camera": False,
"microphone": {"isEnabled": True, "settings": {"deviceId": "my-mic"}},
}
},
completion=join_completion,
)

return await future

async def leave(self):
future = asyncio.get_running_loop().create_future()

def leave_completion(error):
future.get_loop().call_soon_threadsafe(future.set_result, error)

self.__client.leave(completion=leave_completion)

await future

self.__client.release()

self.__task.cancel()
await self.__task

async def write_frames(self, frames):
future = asyncio.get_running_loop().create_future()

def write_completion(count):
future.get_loop().call_soon_threadsafe(future.set_result, count)

self.__mic_device.write_frames(frames, completion=write_completion)

await future

async def send_wav_file(self, file_name):
await self.__start_event.wait()

if self.__app_error:
print(f"Unable to send WAV file!")
return

try:
wav = wave.open(file_name, "rb")

sent_frames = 0
total_frames = wav.getnframes()
sample_rate = wav.getframerate()
while sent_frames < total_frames:
# Read 100ms worth of audio frames.
frames = wav.readframes(int(sample_rate / 10))
if len(frames) > 0:
await self.write_frames(frames)
sent_frames += sample_rate / 10
except asyncio.CancelledError:
pass


async def sig_handler(app):
print("Ctrl-C detected. Exiting!")
await app.leave()


async def main():
parser = argparse.ArgumentParser()
parser.add_argument("-m", "--meeting", required=True, help="Meeting URL")
parser.add_argument("-t", "--token", required=True, help="Meeting token")
parser.add_argument("-i", "--input", required=True, help="WAV input file")
parser.add_argument(
"-c", "--channels", type=int, default=NUM_CHANNELS, help="Number of channels"
)
parser.add_argument("-r", "--rate", type=int, default=SAMPLE_RATE, help="Sample rate")

args = parser.parse_args()

Daily.init()

app = AsyncSendWavApp(args.input, args.rate, args.channels)

loop = asyncio.get_running_loop()

loop.add_signal_handler(signal.SIGINT, lambda *args: asyncio.create_task(sig_handler(app)))

await app.run(args.meeting, args.token)


if __name__ == "__main__":
asyncio.run(main())
Binary file added examples/flows/assets/hold_music/hold_music.wav
Binary file not shown.
Loading
Loading