Skip to content

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.

typescript
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.

typescript
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).

typescript
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.

typescript
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).

typescript
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.

typescript
import { email } from "@andresaya/flowkit";

.ask("contact", "What's your email?", email(), "user_email")

Examples:


phone()

Extract a phone number.

typescript
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.

typescript
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.

typescript
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.

typescript
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.

typescript
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.

typescript
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.

typescript
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.

typescript
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).

typescript
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.

typescript
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.

typescript
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.

typescript
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.

typescript
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.

typescript
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.

typescript
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.

typescript
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.

typescript
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)).

typescript
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).

typescript
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).

typescript
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).

typescript
import { password } from "@andresaya/flowkit";

.ask("pwd", "Create a password:", password(), "user_password")

color()

Extract color values (names or hex codes).

typescript
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.

typescript
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.

typescript
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.

typescript
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.

typescript
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

ExtractorReturnsUse Case
name()stringPerson names
yesNo()"yes" | "no"Confirmations
text()stringFree text
number()numberAny number
integer()numberWhole numbers
email()stringEmail addresses
phone()stringPhone numbers
address()stringPhysical addresses
zipcode()stringPostal codes
date()stringDates
time()string (HH:MM)Time values
url()stringURLs
currency()Money
percentage()numberPercentages
creditCard()stringCard numbers
oneOf(options)stringSingle choice
multiSelect(options)string[]Multiple choices
regex(pattern)stringCustom patterns
range(min, max)numberRange values
length(min, max)stringText with length
list()string[]Free-form lists
rating(max)numberStar ratings
code(prefix, digits)stringFormatted codes
age()numberAges
quantity(max)numberQuantities
username()stringUsernames
password()stringPasswords
color()stringColors
country()stringCountries
language()stringLanguages
filepath()stringFile paths
custom(desc)variesCustom logic

How Extraction Works

  1. User responds with natural language
  2. LLM analyzes the response based on the extractor type
  3. Value extracted and stored in the specified slot
  4. Flow continues to the next step

Using with Branching

Extractors work seamlessly with .when():

typescript
// 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:

typescript
// 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

  1. Use regex() for patterns - When you have a specific format to match

  2. Use range() for bounded numbers - Better than plain number() when you have limits

  3. Match extractor to question - Use yesNo() for yes/no questions, oneOf() for choices

  4. Test with variations - Users express things differently

  5. Fallback handling - Use * wildcard in .when() for unexpected values

  6. LLM quality matters - Smaller models may struggle with complex extraction

  7. Combine with validation - Use middleware for additional validation if needed

Released under the MIT License.