Flows API
The flow() function creates a flow builder for defining conversation structure.
Basic Usage
import { agent, flow, name, yesNo } from "@andresaya/flowkit";
const myAgent = agent("Bot").build();
const myFlow = flow("greeting", myAgent)
.ask("name", "What's your name?", name(), "user_name")
.then("confirm")
.ask("confirm", "Is {{user_name}} correct?", yesNo(), "confirmed")
.when({ yes: "done", no: "name" })
.say("done", "Thanks {{user_name}}!")
.done()
.build();API Reference
flow(id: string, agent: AgentConfig)
Creates a new flow builder.
Parameters:
id- Unique identifier for the flowagent- The agent configuration to use
Returns: FlowBuilder
FlowBuilder Methods
.ask(id, message, extractor, slot)
Adds a step that asks a question and extracts data.
.ask("get_name", "What's your name?", name(), "user_name")Parameters:
id- Step identifiermessage- Question to ask (supportsinterpolation)extractor- Extractor function (name(),email(), etc.)slot- Slot name to store the extracted value
.say(id, message)
Adds a step that displays a message without extraction.
.say("welcome", "Welcome to our service!").then(stepId)
Sets the next step in sequence.
.ask("name", "What's your name?", name(), "user_name")
.then("email") // Go to "email" step next.when(branches)
Creates conditional branching based on the extracted value.
.ask("choice", "A or B?", oneOf(["A", "B"]), "choice")
.when({
A: "step_a",
B: "step_b"
}).done()
Marks the current step as an ending point.
.say("goodbye", "Thanks for chatting!")
.done().do(toolName, payload?)
Executes a registered tool.
.say("saving", "Saving your data...")
.do("save_to_db", { name: "{{user_name}}", email: "{{user_email}}" }).start(stepId)
Sets the starting step (defaults to first step).
.start("welcome").skipIf(condition)
Skips a step based on a condition.
.ask("email", "What's your email?", email(), "user_email")
.skipIf({ slot: "user_email", exists: true }).onlyIf(condition)
Only executes a step if condition is met.
.say("premium_offer", "Check out our premium plan!")
.onlyIf({ slot: "is_premium", equals: false }).build()
Builds and returns the FlowConfig.
Slot Interpolation
Use to insert slot values into messages:
.ask("name", "What's your name?", name(), "user_name")
.then("greet")
.say("greet", "Hello {{user_name}}! How can I help?")Flow Patterns
Linear Flow
flow("linear", agent)
.ask("step1", "...", extractor, "slot1")
.then("step2")
.ask("step2", "...", extractor, "slot2")
.then("step3")
.say("step3", "Done!")
.done()
.build();Branching Flow
flow("branching", agent)
.ask("choice", "Option A or B?", oneOf(["A", "B"]), "choice")
.when({ A: "path_a", B: "path_b" })
.say("path_a", "You chose A")
.done()
.say("path_b", "You chose B")
.done()
.build();Loop Flow
flow("loop", agent)
.ask("item", "Enter item (or 'done'):", text(), "item")
.then("check")
.ask("check", "Add more?", yesNo(), "more")
.when({ yes: "item", no: "finish" })
.say("finish", "All items collected!")
.done()
.build();Conditional Steps
flow("conditional", agent)
.ask("age", "How old are you?", number(), "age")
.then("offer")
.say("offer", "Special youth discount!")
.onlyIf({ slot: "age", lessThan: 25 })
.then("checkout")
.say("checkout", "Proceed to checkout")
.done()
.build();FlowConfig Type
interface FlowConfig {
id: string;
agent: AgentConfig;
steps: Record<string, StepConfig>;
startStep?: string;
}
interface StepConfig {
id: string;
message: string;
extract?: ExtractType;
slot?: string;
next?: string;
branches?: Record<string, string>;
end?: boolean;
action?: ActionConfig;
skipIf?: StepCondition;
onlyIf?: StepCondition;
}Best Practices
Step IDs
Use descriptive step IDs like ask_name, confirm_order, show_receipt.
Message Length
Keep messages concise. Long messages can confuse users and LLMs.
Always End
Ensure all flow paths eventually reach a .done() step.
Avoid Dead Ends
Make sure every step either has .then(), .when(), or .done().