Flows
Flows define the conversation structure - what questions to ask, what to say, and how to branch based on user responses.
Basic Structure
import { flow } from "@andresaya/flowkit";
const myFlow = flow("flow-id", agentConfig)
.ask(...) // Ask a question, extract data
.say(...) // Say something (no extraction)
.when(...) // Branch based on value
.then(...) // Go to next step
.do(...) // Execute a tool
.done() // Mark as final step
.build(); // Build the flowStep Types
.ask() - Ask and Extract
Ask a question and extract information from the user's response.
.ask(stepId, message, extractor, slotName)| Parameter | Type | Description |
|---|---|---|
stepId | string | Unique identifier for this step |
message | string | What to say (supports interpolation) |
extractor | ExtractType | What to extract from response |
slotName | string | Where to store the extracted value |
.ask("get_name", "What's your name?", name(), "customer_name")
.ask("get_age", "How old are you, {{customer_name}}?", number(), "age")
.ask("get_issue", "What brings you here?", oneOf(["billing", "tech", "other"]), "issue_type").say() - Just Say
Display a message without expecting specific data extraction.
.say(stepId, message).say("welcome", "Welcome to our service, {{customer_name}}!")
.say("transfer", "I'll transfer you to a specialist now.")
.say("bye", "Thanks for chatting! Have a great day! 👋").when() - Branch
Route to different steps based on the extracted value.
.when({ value1: "step1", value2: "step2", ... }).ask("choice", "Do you want A or B?", oneOf(["A", "B"]), "choice")
.when({ "A": "handle_a", "B": "handle_b" })
// With yes/no
.ask("confirm", "Is this correct?", yesNo(), "confirmed")
.when({ "yes": "proceed", "no": "retry" })
// Wildcard fallback
.when({ "billing": "billing_dept", "tech": "tech_dept", "*": "general" }).then() - Linear Next
Go to a specific step (for linear flows without branching).
.then(nextStepId).ask("name", "What's your name?", name(), "name")
.then("ask_email") // Always go to ask_email next
.ask("ask_email", "What's your email?", email(), "email")
.then("confirm").do() - Execute Tool
Execute a registered tool/action.
.do(toolName, payload).say("sending", "I'm sending your confirmation email...")
.do("send_email", { template: "confirmation" })
.then("done")
// Multiple actions
.say("processing", "Processing your request...")
.do("log_event", { event: "request_started" })
.do("notify_team", { channel: "support" })
.then("wait").done() - End Flow
Mark the current step as a terminal step (conversation ends here).
.say("goodbye", "Thanks for your time!")
.done()Flow Patterns
Linear Flow
flow("survey", agent)
.ask("q1", "How satisfied are you? (1-10)", number(), "satisfaction")
.then("q2")
.ask("q2", "Would you recommend us?", yesNo(), "recommend")
.then("q3")
.ask("q3", "Any comments?", text(), "comments")
.then("thanks")
.say("thanks", "Thank you for your feedback!")
.done()
.build();Branching Flow
flow("support", agent)
.ask("issue", "What's your issue?", oneOf(["billing", "tech", "other"]), "type")
.when({ "billing": "billing", "tech": "tech", "other": "general" })
.say("billing", "I'll connect you with billing.")
.do("transfer", { dept: "billing" })
.done()
.say("tech", "Let me get a technician.")
.do("transfer", { dept: "tech" })
.done()
.say("general", "How can I help?")
.done()
.build();Nested Branching
flow("qualification", agent)
.ask("company_size", "How many employees?", oneOf(["small", "medium", "large"]), "size")
.when({ "small": "small_flow", "medium": "medium_flow", "large": "large_flow" })
// Small company path
.ask("small_flow", "Are you looking for basic or pro plan?", oneOf(["basic", "pro"]), "plan")
.when({ "basic": "basic_signup", "pro": "pro_signup" })
.say("basic_signup", "Great! Sign up at example.com/basic")
.done()
.say("pro_signup", "Pro is perfect for growing teams!")
.do("schedule_demo", {})
.done()
// Medium/Large paths...
.build();Loop Back (Retry)
flow("verification", agent)
.ask("get_code", "Please enter your 6-digit code:", custom("6-digit number"), "code")
.then("verify")
.ask("verify", "Verifying... Is {{code}} correct?", yesNo(), "confirmed")
.when({ "yes": "success", "no": "get_code" }) // Loop back!
.say("success", "Verified! Welcome.")
.done()
.build();Slot Interpolation
Use to insert collected values into messages:
.ask("name", "What's your name?", name(), "user_name")
.then("greet")
.say("greet", "Hello {{user_name}}! How can I help?")
.then("bye")
.say("bye", "Goodbye {{user_name}}! Your session ID is {{session_id}}.")Tips
Unique step IDs - Each step needs a unique ID within the flow
Always end paths - Every branch should eventually reach a
.done()Use meaningful IDs -
ask_emailis better thanstep_3Test all branches - Make sure every path works
Keep messages concise - Especially in strict mode where exact messages are used