Conversation-flow agents

When the cost of going off-script is high, payments, identity verification, structured booking, model the conversation as a flow. A flow is a typed state machine: nodes hold prompts, edges declare conditions, and the LLM still does the talking.

When a flow beats a single prompt

  • There is a sequence of facts you must collect in order.
  • Some branches need a tool call (lookup, charge, write to a system of record).
  • Compliance requires deterministic copy at certain steps (consent, disclosure).
  • You want a human-readable diagram of every path the agent can take.

Defining a flow

flow.ts
await saaya.agents.create({
  name: "Refund Resolver",
  flow: {
    start: "greet",
    nodes: {
      greet: {
        prompt: "Greet the caller and ask for their order id.",
        on: { collected: { orderId: "lookup" } },
      },
      lookup: {
        tool: "orders.fetch",
        args: { orderId: "{{vars.orderId}}" },
        on: { ok: "decide", notFound: "apologize" },
      },
      decide: {
        prompt:
          "Summarize the order. If within 30 days, offer a refund. Otherwise offer store credit.",
        branches: [
          { when: "{{order.daysOld}} <= 30", to: "refund" },
          { else: true,                        to: "credit"  },
        ],
      },
      refund:    { tool: "payments.refund", args: { orderId: "{{vars.orderId}}" }, on: { ok: "thank" } },
      credit:    { tool: "credits.issue",   args: { orderId: "{{vars.orderId}}" }, on: { ok: "thank" } },
      apologize: { prompt: "Apologize, take down their email, escalate.", on: { collected: { email: "end" } } },
      thank:     { prompt: "Confirm the outcome and end warmly.", end: true },
    },
  },
  voice: { provider: "elevenlabs", voiceId: "rachel" },
  llm:   { provider: "anthropic",  model: "claude-opus-4-7" },
});

Variables and validation

Every node can declare slots it expects to collect. Saaya validates them with a schema and re-prompts if the user gives a malformed answer (e.g. an email that is not RFC-shaped). Validation messages are part of the node, not the global prompt, they only fire on that step.

Fallbacks and escapes

A flow does not lock the user into a track. Each node has an implicit `fallback` edge that fires when the LLM cannot map the utterance to any declared transition. The fallback usually escalates, to the single-prompt fallback, to a human, or to a "what would help most right now?" reset.

Keep the flow shallow

Flows shine at 5–15 nodes. Past 30 nodes you are probably modelling business logic that belongs in your backend, call it via a tool and let the agent hand off cleanly.
Was this page helpful?