# Dynamic flows

> Build each node at runtime from what the conversation has learned.

Source: https://polvallverdu.github.io/pipedog/docs/flows/dynamic-flows/



In a dynamic flow, nodes are functions that return a `NodeConfig`, and a tool's handler returns the
node to go to next. Because the next node is built when the tool is called, it can depend on
arguments, state or anything else you can compute.

This flow books a slot in three steps. The hour node is built for the day the caller picked, and
the last node confirms the slot and ends the call:

```ts
interface Slot {
  day: string;
  hour: number;
}

function createDayNode(): NodeConfig {
  return {
    name: "day",
    taskMessages: [{ role: "developer", content: "Ask which weekday the caller prefers." }],
    functions: [
      new FlowsFunctionSchema({
        name: "choose_day",
        description: "Record the preferred weekday.",
        properties: { day: { type: "string" } },
        required: ["day"],
        handler: async (args, fm) => {
          fm.state.day = args.day;
          // Build the next node from what the caller just said.
          return [{ day: args.day }, createHourNode(String(args.day))];
        },
      }),
    ],
  };
}

function createHourNode(day: string): NodeConfig {
  return {
    name: "hour",
    taskMessages: [{ role: "developer", content: `Offer times on ${day} and ask which one.` }],
    functions: [
      new FlowsFunctionSchema({
        name: "choose_hour",
        description: "Record the chosen hour.",
        properties: { hour: { type: "integer" } },
        required: ["hour"],
        handler: async (args, fm) => {
          const slot: Slot = { day, hour: Number(args.hour) };
          fm.state.slot = slot;
          return [slot, createDoneNode(slot)];
        },
      }),
    ],
  };
}

function createDoneNode(slot: Slot): NodeConfig {
  return {
    name: "done",
    taskMessages: [
      { role: "developer", content: `Confirm ${slot.day} at ${slot.hour}:00, then say goodbye.` },
    ],
    postActions: [{ type: "end_conversation" }],
  };
}

await flowManager.setNodeFromConfig(createDayNode());
```

Each handler returns `[result, nextNode]`. The result goes back to the LLM as the tool result;
the manager then enters the next node, which swaps in its task messages and tools and asks the LLM to
respond. A handler can return `null` as the node to stay put, or `NO_RESPONSE` to stay quiet.

Start it with `flowManager.initialize(createDayNode())`, or enter it later with
`setNodeFromConfig`. Use [flow configs](https://polvallverdu.github.io/pipedog/docs/flows/flow-configs.md) instead when the graph is fixed
and you want it reviewable as data.
