pipedog is an unofficial community port of Pipecat, not affiliated with Daily.
pipedog

Flows

Build structured conversations from nodes, functions and actions with @pipedog/flows, a port of Pipecat Flows.

Flows keeps a conversation on rails. Instead of one long prompt with every tool available at every moment, you describe the conversation as a graph of nodes. Each node gives the LLM one job (its task messages), the few tools it may call there, and optional actions to run on the way in or out. When the LLM calls a tool, the tool does its work and can send the conversation to the next node.

@pipedog/flows ports pipecat.flows. It works with any LLM service that does function calling: OpenAI, Anthropic and Google are covered by the package's end-to-end tests.

bun add @pipedog/flows

Concepts

ConceptWhat it is
NodeOne step of the conversation: a role, task messages, functions, actions and a context strategy.
FunctionA tool the LLM can call at a node. It does work, and may name the next node.
ActionSomething that happens around the LLM's turn at a node: speaking a line, ending the call, or your own code.
Context strategyWhat happens to the conversation history when a node is entered.
Flow managerFlowManager runs the graph: it holds the current node and the shared state, registers each node's tools with the LLM service, and performs transitions.
Flow configA flow described as YAML or JSON data, joined to your handlers with Flow.

Wiring it up

FlowManager needs the pipeline worker (to queue frames), the LLM service, and the context aggregators:

const flowManager = new FlowManager({
  worker,
  llm,
  contextAggregator: aggregators,
});

Then start in a node with flowManager.initialize(node). See Nodes for what a node contains, or Dynamic flows for a graph built at runtime.

Two ways to define a flow

  • In code. Node functions return NodeConfig objects, and a tool returns the next node. Nothing is fixed ahead of time, so the next node can depend on what the user said. See Dynamic flows.
  • As data. A FlowConfig lists the nodes and the edges between them, in YAML or JSON. Your code supplies only the tools' behavior. See Flow configs.

Both run on the same FlowManager.

State

flowManager.state is a plain object shared by every node and handler. Store what the conversation learns (a name, a booking) and read it back anywhere, including in {{ placeholders }} in a config.

Differences from Pipecat

The behavior matches upstream; the API follows TypeScript conventions:

  • NodeConfig and ActionConfig keys are camelCase (taskMessages, preActions). The YAML/JSON FlowConfig file format keeps upstream's snake_case keys.
  • A tool returns a two-element array, [result, nextNode], where Python returns a tuple.
  • Handlers are called as (args, flowManager).
  • A direct function's first parameter is named flowManager, and its description and parameter schemas are attached as metadata (JavaScript has no docstrings or type hints at runtime).
  • FlowConfig.fromFile and !include read files through a readFile function you pass in, so the package runs on every runtime.
  • Config validation is hand-written and throws ValidationError, listing every problem found.
  • Placeholders render with String() (objects as JSON) instead of Python's str().
  • Deprecated upstream APIs are not ported. RESET_WITH_SUMMARY is kept and logs a deprecation warning once.

pipedog is an unofficial community TypeScript port of Pipecat. It is not affiliated with or endorsed by Daily or the Pipecat project.

Portions adapted from the Pipecat documentation, Copyright (c) 2024–2025 Daily, BSD-2-Clause (see apps/docs/LICENSE-pipecat-docs).

On this page