Extractors
Extractors define how to pull structured data from natural language responses. They tell the LLM what format to look for and validate.
Available Extractors
Basic Extractors
name()
Extract a person's name from the response.
import { name } from "@andresaya/flowkit";
.ask("get_name", "What's your name?", name(), "customer_name")Examples:
- "I'm John" →
"John" - "My name is María García" →
"María García" - "Call me Bob" →
"Bob"
yesNo()
Extract a yes/no response.
import { yesNo } from "@andresaya/flowkit";
.ask("confirm", "Do you want to continue?", yesNo(), "wants_continue")Returns: "yes" or "no"
Examples:
- "Yes, please" →
"yes" - "Nope" →
"no" - "Sure!" →
"yes" - "I don't think so" →
"no"
text()
Extract free-form text (captures the entire meaningful response).
import { text } from "@andresaya/flowkit";
.ask("feedback", "Any additional comments?", text(), "comments")
.ask("description", "Describe the issue", text(), "issue_description")Examples:
- "The product is great but shipping was slow" →
"The product is great but shipping was slow"
number()
Extract a numeric value.
import { number } from "@andresaya/flowkit";
.ask("age", "How old are you?", number(), "user_age")
.ask("rating", "Rate from 1-10", number(), "rating")Returns: A number (as string in the slot)
Examples:
- "I'm 25" →
"25" - "Twenty five years old" →
"25" - "About 8" →
"8"
integer()
Extract a whole number (no decimals).
import { integer } from "@andresaya/flowkit";
.ask("quantity", "How many items?", integer(), "item_count")
.ask("floor", "Which floor?", integer(), "floor_number")Examples:
- "I want 5 items" →
5 - "Third floor" →
3 - "About 42" →
42
Contact Information
email()
Extract an email address.
import { email } from "@andresaya/flowkit";
.ask("contact", "What's your email?", email(), "user_email")Examples:
- "my email is john@example.com" →
"john@example.com" - "john@example.com" →
"john@example.com"
phone()
Extract a phone number.
import { phone } from "@andresaya/flowkit";
.ask("phone", "What's your phone number?", phone(), "user_phone")Examples:
- "It's 555-123-4567" →
"555-123-4567" - "Call me at +1 (555) 123-4567" →
"+1 (555) 123-4567"
address()
Extract a physical address.
import { address } from "@andresaya/flowkit";
.ask("location", "What's your address?", address(), "user_address")Examples:
- "123 Main St, New York, NY 10001" →
"123 Main St, New York, NY 10001" - "I live at 456 Oak Avenue" →
"456 Oak Avenue"
zipcode()
Extract postal/zip codes.
import { zipcode } from "@andresaya/flowkit";
.ask("zip", "What's your zip code?", zipcode(), "postal_code")Examples:
- "90210" →
"90210" - "10001-1234" →
"10001-1234" - "SW1A 1AA" →
"SW1A 1AA"
Date & Time
date()
Extract a date from the response.
import { date } from "@andresaya/flowkit";
.ask("birthday", "When is your birthday?", date(), "birth_date")Examples:
- "January 15, 2024" →
"2024-01-15" - "15/01/2024" →
"2024-01-15" - "Tomorrow" → relative date resolved
time()
Extract a time value from the response.
import { time } from "@andresaya/flowkit";
.ask("appointment", "What time works for you?", time(), "appointment_time")Examples:
- "3pm" →
"15:00" - "3:30 PM" →
"15:30" - "10 in the morning" →
"10:00" - "noon" →
"12:00"
URLs & Web
url()
Extract a URL from the response.
import { url } from "@andresaya/flowkit";
.ask("website", "What's your website?", url(), "user_website")Examples:
- "My site is https://example.com" →
"https://example.com" - "www.mysite.com" →
"https://www.mysite.com" - "Check out example.org/page" →
"https://example.org/page"
Financial
currency()
Extract monetary values with currency symbol.
import { currency } from "@andresaya/flowkit";
.ask("budget", "What's your budget?", currency(), "budget_amount")
.ask("price", "How much did it cost?", currency(), "item_price")Returns: Object { amount: number, currency: string }
Examples:
- "About $500" →
{ amount: 500, currency: "USD" } - "€150 euros" →
{ amount: 150, currency: "EUR" } - "50 dollars" →
{ amount: 50, currency: "USD" }
percentage()
Extract percentage values.
import { percentage } from "@andresaya/flowkit";
.ask("discount", "What discount do you want?", percentage(), "discount_rate")
.ask("complete", "How complete is the project?", percentage(), "progress")Examples:
- "About 75%" →
75 - "Twenty percent" →
20 - "Half done" →
50
creditCard()
Extract credit card numbers (validates format).
import { creditCard } from "@andresaya/flowkit";
.ask("card", "Enter your card number:", creditCard(), "card_number")Examples:
- "4111-1111-1111-1111" →
"4111111111111111" - "4111 1111 1111 1111" →
"4111111111111111"
Choice Extractors
oneOf(options)
Extract one value from a list of options.
import { oneOf } from "@andresaya/flowkit";
.ask("plan", "Which plan: basic, pro, or enterprise?", oneOf(["basic", "pro", "enterprise"]), "plan")Returns: One of the provided options
Examples:
- "I want the pro plan" →
"pro" - "Let's go with enterprise" →
"enterprise" - "The basic one" →
"basic"
multiSelect(options)
Extract multiple values from a list of options.
import { multiSelect } from "@andresaya/flowkit";
.ask("toppings", "What toppings? (cheese, pepperoni, mushrooms, olives)",
multiSelect(["cheese", "pepperoni", "mushrooms", "olives"]),
"selected_toppings")Returns: An array of selected options
Examples:
- "I want cheese and pepperoni" →
["cheese", "pepperoni"] - "All of them please" →
["cheese", "pepperoni", "mushrooms", "olives"] - "Just cheese" →
["cheese"]
Advanced Extractors
regex(pattern, flags?)
Extract using a custom regular expression pattern.
import { regex } from "@andresaya/flowkit";
// Extract product codes like ABC-123
.ask("code", "What's the product code?", regex("[A-Z]{3}-\\d{3}"), "product_code")
// With flags
.ask("id", "Enter your ID:", regex("[a-z]+\\d+", "i"), "user_id")Examples:
- "The code is ABC-123" →
"ABC-123" - "My ID is User42" →
"User42"
range(min, max)
Extract a value within a specific numeric range.
import { range } from "@andresaya/flowkit";
.ask("pain", "Rate your pain (1-10)", range(1, 10), "pain_level")
.ask("temp", "Temperature preference (-5 to 5)", range(-5, 5), "temp_pref")Examples:
- "About 7" →
7(validated within range) - "I'd say 3" →
3
length(minLength, maxLength?)
Extract text with length validation.
import { length } from "@andresaya/flowkit";
.ask("bio", "Write a short bio (10-200 chars)", length(10, 200), "user_bio")
.ask("code", "Enter the 6-digit code", length(6, 6), "verification_code")list(separator?, minItems?, maxItems?)
Extract a free-form list of items.
import { list } from "@andresaya/flowkit";
.ask("items", "What items do you need?", list(), "shopping_list")
.ask("skills", "What are your skills?", list(",", 1, 10), "user_skills")Returns: Array of strings
Examples:
- "I need milk, bread, and eggs" →
["milk", "bread", "eggs"] - "Python, JavaScript, TypeScript" →
["Python", "JavaScript", "TypeScript"]
rating(scale?)
Extract a rating value with optional max scale.
import { rating } from "@andresaya/flowkit";
.ask("score", "Rate our service (1-5 stars)", rating(5), "service_rating")
.ask("nps", "How likely to recommend? (0-10)", rating(10), "nps_score")Examples:
- "4 out of 5" →
4 - "I'd give it a 9" →
9 - "Three stars" →
3
code(prefix, digitCount)
Extract codes with a specific prefix and digit count.
import { code } from "@andresaya/flowkit";
.ask("order", "What's your order number?", code("ORD", 6), "order_number")
.ask("ticket", "Enter ticket ID", code("TKT", 8), "ticket_id")Examples:
- "Order ORD-123456" →
"ORD-123456" - "My ticket is TKT-12345678" →
"TKT-12345678"
Utility Extractors
age()
Extract a person's age (convenience wrapper for range(0, 150)).
import { age } from "@andresaya/flowkit";
.ask("age", "How old are you?", age(), "user_age")Examples:
- "I'm 25 years old" →
25 - "Twenty-five" →
25
quantity(max?)
Extract a quantity (starts from 1, optional max).
import { quantity } from "@andresaya/flowkit";
.ask("qty", "How many would you like?", quantity(100), "item_quantity")Examples:
- "I want 5" →
5 - "Just one" →
1
username()
Extract a username (alphanumeric with underscores, 3-20 chars).
import { username } from "@andresaya/flowkit";
.ask("user", "Choose a username:", username(), "chosen_username")Examples:
- "john_doe123" →
"john_doe123" - "MyUser" →
"MyUser"
password()
Extract a password (minimum 8 characters).
import { password } from "@andresaya/flowkit";
.ask("pwd", "Create a password:", password(), "user_password")color()
Extract color values (names or hex codes).
import { color } from "@andresaya/flowkit";
.ask("fav_color", "What's your favorite color?", color(), "favorite_color")Examples:
- "Blue" →
"blue" - "#FF5733" →
"#FF5733" - "rgb(255, 0, 0)" →
"rgb(255, 0, 0)"
country()
Extract country names or codes.
import { country } from "@andresaya/flowkit";
.ask("location", "Which country are you from?", country(), "user_country")Examples:
- "United States" →
"United States" - "USA" →
"USA" - "I'm from Mexico" →
"Mexico"
language()
Extract language names or codes.
import { language } from "@andresaya/flowkit";
.ask("lang", "What language do you speak?", language(), "preferred_language")Examples:
- "English" →
"English" - "Spanish" →
"Spanish" - "I speak French" →
"French"
filepath()
Extract file paths.
import { filepath } from "@andresaya/flowkit";
.ask("file", "Which file should I process?", filepath(), "target_file")Examples:
- "/home/user/docs/file.txt" →
"/home/user/docs/file.txt" - "C:\Users\file.docx" →
"C:\\Users\\file.docx"
custom(description)
Create a custom extractor with your own description.
import { custom } from "@andresaya/flowkit";
.ask("code", "Enter your access code:", custom("A 6-digit numeric code"), "access_code")
.ask("special", "Enter the data:", custom("A JSON object with name and value fields"), "special_data")Extractor Summary Table
| Extractor | Returns | Use Case |
|---|---|---|
name() | string | Person names |
yesNo() | "yes" | "no" | Confirmations |
text() | string | Free text |
number() | number | Any number |
integer() | number | Whole numbers |
email() | string | Email addresses |
phone() | string | Phone numbers |
address() | string | Physical addresses |
zipcode() | string | Postal codes |
date() | string | Dates |
time() | string (HH:MM) | Time values |
url() | string | URLs |
currency() | Money | |
percentage() | number | Percentages |
creditCard() | string | Card numbers |
oneOf(options) | string | Single choice |
multiSelect(options) | string[] | Multiple choices |
regex(pattern) | string | Custom patterns |
range(min, max) | number | Range values |
length(min, max) | string | Text with length |
list() | string[] | Free-form lists |
rating(max) | number | Star ratings |
code(prefix, digits) | string | Formatted codes |
age() | number | Ages |
quantity(max) | number | Quantities |
username() | string | Usernames |
password() | string | Passwords |
color() | string | Colors |
country() | string | Countries |
language() | string | Languages |
filepath() | string | File paths |
custom(desc) | varies | Custom logic |
How Extraction Works
- User responds with natural language
- LLM analyzes the response based on the extractor type
- Value extracted and stored in the specified slot
- Flow continues to the next step
Using with Branching
Extractors work seamlessly with .when():
// yes/no branching
.ask("confirm", "Ready to proceed?", yesNo(), "ready")
.when({ "yes": "continue", "no": "cancel" })
// oneOf branching
.ask("dept", "Sales, Support, or Other?", oneOf(["sales", "support", "other"]), "department")
.when({
"sales": "sales_flow",
"support": "support_flow",
"other": "general_flow"
})
// Wildcard fallback
.ask("level", "Choose: low, medium, high", oneOf(["low", "medium", "high"]), "priority")
.when({
"high": "urgent",
"*": "normal" // low and medium go here
})Creating Custom Types
You can create reusable custom extractors:
// Define reusable extractors
const productCode = () => regex("[A-Z]{3}-\\d{4}");
const orderNumber = () => code("ORD", 6);
const appointmentTime = () => time();
// Use in flows
.ask("product", "Enter product code:", productCode(), "product")
.ask("time", "What time works for you?", appointmentTime(), "time")
.ask("order", "What's your order number?", orderNumber(), "order_id")Tips
Use regex() for patterns - When you have a specific format to match
Use range() for bounded numbers - Better than plain number() when you have limits
Match extractor to question - Use
yesNo()for yes/no questions,oneOf()for choicesTest with variations - Users express things differently
Fallback handling - Use
*wildcard in.when()for unexpected valuesLLM quality matters - Smaller models may struggle with complex extraction
Combine with validation - Use middleware for additional validation if needed