Skip to content

Commit 651cccd

Browse files
authored
Merge pull request #18 from pipecat-ai/mb/yaml-document-model
Rebuild the editor around Pipecat's FlowConfig YAML
2 parents 227718b + a6a35ec commit 651cccd

134 files changed

Lines changed: 10704 additions & 5572 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.claude/settings.json

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"attribution": {
3+
"commit": "",
4+
"pr": "",
5+
"sessionUrl": false
6+
}
7+
}

.github/workflows/ci.yml

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
name: CI
2+
3+
on:
4+
pull_request:
5+
push:
6+
branches: [main]
7+
8+
jobs:
9+
check:
10+
runs-on: ubuntu-latest
11+
steps:
12+
- uses: actions/checkout@v4
13+
- uses: actions/setup-node@v4
14+
with:
15+
node-version: 22
16+
cache: npm
17+
- run: npm ci
18+
- run: npm test
19+
- run: npm run lint
20+
- run: npm run typecheck

.prettierignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,5 @@ package-lock.json
1111
yarn.lock
1212
pnpm-lock.yaml
1313

14+
# Vendored verbatim from Pipecat; kept byte-identical to the upstream file.
15+
lib/schema/flow_config.schema.json

LICENSE

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
BSD 2-Clause License
22

3-
Copyright (c) 2025, Daily
3+
Copyright (c) 2025-2026, Daily
44

55
Redistribution and use in source and binary forms, with or without
66
modification, are permitted provided that the following conditions are met:

README.md

Lines changed: 44 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,25 @@
11
# Pipecat Flows Editor
22

3-
Next.js + TypeScript + Tailwind + React Flow visual editor tailored to Pipecat Flows. The editor runs entirely in the browser, syncs state to `localStorage`, and exports Pipecat-ready JSON _and_ Python code.
3+
A visual editor for Pipecat Flows. Build a flow with a coding agent, then visualize it here: validate it, fix it, and export it to your Pipecat project. The document it edits is Pipecat's `FlowConfig` YAML: the nodes of a conversation, what each one says, which tools each offers, and where each tool leads. The canvas is a view of that file. The editor runs entirely in the browser, keeps a draft in `localStorage`, and saves the same YAML your Pipecat application loads.
44

55
## References
66

77
- Online editor: https://flows.pipecat.ai
8-
- Pipecat Flows repo: https://github.com/pipecat-ai/pipecat-flows
8+
- Pipecat repo: https://github.com/pipecat-ai/pipecat
99
- Feature guide: https://docs.pipecat.ai/guides/features/pipecat-flows
10-
- API reference: https://reference-flows.pipecat.ai/en/latest/
10+
- Flows API reference: https://reference-flows.pipecat.ai/en/latest/
1111

1212
## Highlights
1313

14-
- **NodeConfig-first modeling** – Nodes map 1:1 to Pipecat `NodeConfig` objects (`role_messages`, `task_messages`, `functions`, actions, context strategy, etc.).
15-
- **Inspector-driven editing** – Schema-backed forms for messages, function schemas, decisions, actions, context strategy, and response controls.
16-
- **Decision routing visualized** – Function-level decisions appear as inline decision nodes and translate directly to Python conditionals.
17-
- **JSON + Python export** – Download the validated flow JSON or generate runnable Python scaffolding via the built-in code generator.
18-
- **Schema validation** – TypeBox + Ajv plus custom graph rules (unique IDs, valid references) before import/export.
19-
- **Local-first UX** – Autosave, undo/redo, keyboard shortcuts, dark mode, example flows, and Monaco JSON viewer.
14+
- **The YAML is the document** – Open a `FlowConfig` file, edit it on the canvas or in the YAML pane, and save it. Comments, key order, block scalar styles, and every key in a hand-written file survive the round trip; the one change on save is that long lines, folded or plain, are re-wrapped at 80 columns.
15+
- **Two views, one document** – The canvas and the YAML pane stay in step: a change on either side updates the other, with problems shown inline in the pane.
16+
- **Routing as data** – A function is a tool name and a destination: a node, or a branch table keyed on a field of the tool's result. A function that only moves the conversation is written in the config alone, as a transition-only entry with a description, and needs no Python. A node card lists its functions as rows, a branch's cases as sub-rows, and each row has its own port.
17+
- **Pipecat's schema and checks** – Validation uses the JSON Schema Pipecat ships for `FlowConfig`, vendored and pinned, plus the same cross-reference checks its loader makes and the same graph warnings it reports: unreachable nodes, dead ends, and branches that always go one place. Every finding uses Pipecat's `FlowIssue` shape and codes.
18+
- **The handoff to code is a list** – The Flow panel lists every tool and action handler the config references and every `{{ key }}` placeholder its prompts read from the manager's state, so you know what the Python side must provide.
19+
- **What a node does, on the card** – Besides its functions, a card shows the node's actions as a short script: what it says or runs on entry above the functions, what it says or runs on exit below. Click a line to open the node's actions.
20+
- **Built for flows that arrive written** – Most flows are written by an agent or by hand and opened here to be seen and corrected. The start screen offers four ways in: open a file, paste YAML, start from an example, or a blank flow. A file dropped anywhere or YAML pasted anywhere opens at once.
21+
- **Local-first UX** – Autosave, undo/redo, keyboard shortcuts, light and dark themes, auto-layout on open, and Pipecat's own example flows.
22+
- **pipecat.ai's design language** – Zinc tokens, Geist type, hairline chrome, and the site's pixel-stream animation on the landing page and start screen, so the editor and the site read as one product.
2023

2124
## Getting Started
2225

@@ -32,61 +35,65 @@ Run the dev server:
3235
npm run dev
3336
```
3437

35-
Open http://localhost:3000 to launch the editor.
38+
Open http://localhost:3000 for the landing page, or http://localhost:3000/editor to go straight to the editor's start screen.
3639

3740
## Testing
3841

3942
```bash
4043
npm test # Vitest (unit + component tests)
41-
npm run lint # ESLint + TypeScript rules
44+
npm run lint # ESLint
45+
npm run typecheck # TypeScript
4246
```
4347

4448
## Working With Flows
4549

46-
- Flows are saved as JSON documents that follow `lib/schema/flow.schema.ts`. Detailed field descriptions live in [docs/SCHEMA.md](./docs/SCHEMA.md).
47-
- The node palette includes `initial`, `node`, and `end` templates. All nodes ultimately emit the same Pipecat `NodeConfig`, but templates give sensible defaults.
48-
- Routing is controlled by function metadata:
49-
- `next_node_id` wires one function directly to the next node.
50-
- `decision` objects attach Python snippets and conditionals that become decision nodes in the canvas and `if/elif` blocks in generated Python.
51-
- Decision nodes shown on the canvas are visualization helpers; they are not persisted as standalone nodes. Instead, decision metadata is stored on the originating function.
52-
- Edges are derived automatically from function routing. When you delete or rename nodes, the UI surfaces broken references so you can fix them before exporting.
50+
- A flow is a `FlowConfig` YAML file. Its shape is defined by Pipecat's JSON Schema, vendored at `lib/schema/flow_config.schema.json`; the field descriptions there are Pipecat's own. See [docs/INTEGRATION.md](./docs/INTEGRATION.md) for the format and how a Pipecat application loads it.
51+
- The canvas owns structure and the inspector owns content. Hover a node and press its "+" to add a function: leading to a next node, an end node, or a branch on the tool's result, or staying on the node. Every node is reachable by construction. A branch has an "add case" row. Double-click a node name, a tool name, or a case value to rename it in place; hover a row for its "×". Delete removes what is selected: an edge's route, a row, or a node.
52+
- A card lists the node's pre-actions above its functions and its post-actions below: a `tts_say` as its text in quotes, a `function` action or custom type by its handler or name. Each block shows two lines and folds the rest into one; hover a line for the full sentence, click it to open the node's Actions tab. A node whose post-actions end the conversation is drawn as an end node instead.
53+
- Every node needs task messages; the role message is optional and persists across transitions until another node sets its own, so setting it on the initial node covers the whole flow.
54+
- The initial node is whichever node `initial_node` names; use "Make initial node" in a node's context menu to move it. An end node is one with an `end_conversation` post-action. Every node has the same shape.
55+
- A node's name is its key in the config. Renaming a node rewrites every destination that pointed at it.
56+
- Routing lives on functions as `transition_to`: a node name, or a branch table with `field`, `cases`, and an optional `default`. Dragging from a row's port sets that row's destination; dragging from the node's bottom handle adds a function, and from a branch's "add case" row adds a case.
57+
- A `role_message` or a message's `content` may be `!include path`, which Pipecat fills in from a file beside the config when it loads. The editor keeps the reference as written and shows it as `!include path`; it cannot read the file, so placeholders in it are not listed. Type the same form into a field to make one.
58+
- Tool descriptions and parameters are not in the config. They come from the direct functions in your Python handlers, referenced by name. The exception is a transition-only function, which the config defines entirely: a name, a description for the LLM, and the node it leads to. Toggle it on a function in the sidebar.
59+
- `{{ key }}` in a role message, a task message, or a `tts_say` text is filled from `flow_manager.state` each time the node is entered. `{{ order.size }}` reads into a stored mapping, and `\{{ key }}` is a literal. The Flow panel lists the keys the prompts read.
60+
- Edges are derived from the routing data. Deleting or renaming nodes surfaces broken references on the canvas and in the YAML pane.
61+
- Canvas positions are not part of the document. A freshly opened file is auto-laid out; positions are then kept in `localStorage`, keyed by flow name.
5362

5463
### Persistence
5564

5665
- Every edit debounces into `localStorage`, so reloading the page restores the last working draft.
57-
- No server calls are made; the editor operates entirely client-side.
66+
- The editor makes no network calls; it operates entirely client-side. The landing page fetches the Pipecat repository's star count from GitHub when it renders, revalidated daily, and leaves the badge out if that fails.
5867

59-
### Import / Export
68+
### Open / Save
6069

6170
Toolbar actions let you:
6271

63-
- **Import JSON**Validates against the schema plus custom graph rules, then rehydrates the canvas.
64-
- **Export JSON**Serializes the current graph into Pipecat Flow JSON.
65-
- **Export Python**Validates the flow, runs `lib/codegen/pythonGenerator.ts`, and downloads a Python file with `NodeConfig` factories, handler scaffolding, optional decision routing, and FlowManager wiring comments.
66-
67-
See [docs/INTEGRATION.md](./docs/INTEGRATION.md) for full integration steps.
72+
- **Open**Read a `FlowConfig` file as YAML or JSON, validate it, and lay it out. A file in the editor's old JSON format is converted; what cannot convert (tool schemas, decisions) is reported by name.
73+
- **Save**Download the flow as `<name>.yaml`, merged into the document it was opened from so comments are preserved.
74+
- **Layout**Lay the nodes out automatically, the way a freshly opened file is.
75+
- **Sidebar** – Always open: it shows the selected node, or the flow when nothing is selected, with the flow's name, its global functions, the issues Pipecat would report, and the tools, action handlers, and state placeholders the config refers to. It collapses from its header and reopens from the toolbar.
76+
- **YAML** – The tab on the canvas's bottom edge, and the "Node YAML" button in the inspector, open the document itself, with parse, schema, and reference problems marked inline.
6877

6978
### Example Flows
7079

71-
Example definitions live in `lib/examples/` (e.g., `minimal.json`, `food_ordering.json`). Load them via **Load Example** in the toolbar to see end-to-end patterns.
80+
The examples under **Load Example** are served from `public/examples/`. Hello world, food ordering, restaurant reservation, patient intake, insurance quote, and podcast interview are Pipecat's own: each is the `flow.yaml` of a directory under `examples/flows/yaml/` in the Pipecat repository, copied verbatim, with a `handlers.py` and a `bot.py` beside it there. Order status and lead qualification are written for the editor; their header comments list the handlers the Python must define and the state keys the prompts read.
7281

7382
## Tech Stack
7483

7584
- **Next.js 16** (App Router)
7685
- **React 19** + **@xyflow/react** for the canvas
77-
- **TypeScript**
78-
- **Tailwind CSS v4** + custom UI primitives
79-
- **Monaco Editor** for JSON inspection
80-
- **TypeBox + Ajv** for schema + validation
86+
- **TypeScript**, with the `FlowConfig` types generated from Pipecat's schema
87+
- **Tailwind CSS v4** + custom UI primitives, on pipecat.ai's zinc tokens and Geist type (via `next/font`) so the editor and the site read as one product
88+
- **yaml** for parsing with comment preservation, **Ajv** for schema validation, **dagre** for auto-layout
89+
- **Monaco Editor** for the YAML pane
8190
- **Zustand** for editor state
8291

8392
## Contributing
8493

85-
When expanding capabilities:
86-
87-
1. Update `lib/schema/flow.schema.ts` and `docs/SCHEMA.md` for any schema changes.
88-
2. Add or tweak templates in `lib/nodes/templates.ts`.
89-
3. Extend inspector forms under `components/inspector/forms/` to expose new fields.
90-
4. Update tests (`tests/`) and docs as needed.
94+
`npm run check:schema` compares the vendored schema with Pipecat's at the pinned commit, and `npm run check:schema -- main` with what has shipped. When Pipecat's `FlowConfig` changes:
9195

92-
See [docs/SCHEMA.md](./docs/SCHEMA.md) for authoritative schema details.
96+
1. Copy the new `flow_config.schema.json` over `lib/schema/flow_config.schema.json` and update the source record in `lib/schema/flowConfig.ts`.
97+
2. Run `npm run gen:types` to regenerate `lib/schema/flowConfig.generated.ts`.
98+
3. Mirror any new validator in `lib/validation/flowConfigValidator.ts`.
99+
4. Extend the inspector forms under `components/inspector/forms/` to expose new fields, and update tests under `tests/`.

app/favicon.ico

10.6 KB
Binary file not shown.

app/icon.svg

Lines changed: 7 additions & 0 deletions
Loading

app/layout.tsx

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,14 @@
11
import "../styles/globals.css";
22

33
import type { Metadata } from "next";
4+
import { Geist, Geist_Mono } from "next/font/google";
45

56
import { ThemeProvider } from "@/components/ThemeProvider";
67

8+
// The same faces pipecat.ai sets, so the editor reads as the same product
9+
const geistSans = Geist({ variable: "--font-geist-sans", subsets: ["latin"] });
10+
const geistMono = Geist_Mono({ variable: "--font-geist-mono", subsets: ["latin"] });
11+
712
// eslint-disable-next-line react-refresh/only-export-components
813
export const metadata: Metadata = {
914
title: "Pipecat Flows Editor",
@@ -12,8 +17,12 @@ export const metadata: Metadata = {
1217

1318
export default function RootLayout({ children }: Readonly<{ children: React.ReactNode }>) {
1419
return (
15-
<html lang="en" suppressHydrationWarning className="h-full">
16-
<body className="min-h-screen bg-background text-foreground antialiased">
20+
<html
21+
lang="en"
22+
suppressHydrationWarning
23+
className={`${geistSans.variable} ${geistMono.variable} h-full`}
24+
>
25+
<body className="min-h-screen bg-background font-sans text-foreground antialiased">
1726
<ThemeProvider attribute="class" defaultTheme="system" enableSystem>
1827
{children}
1928
</ThemeProvider>

0 commit comments

Comments
 (0)