Schema-driven data extraction β’ Predictable conversations β’ Enterprise-ready
π Website β’ Features β’ Installation β’ Quick Start β’ Documentation β’ Examples
// User: "I want to book the Grand Hotel for 2 people next Friday"
// AI: "Sure! Which hotel would you like?" // π  Asked already!
// User: "Grand Hotel"
// AI: "How many guests?"                 // π  You just told me!
// User: "2 people"
// AI: "What date?"                        // π  I said Friday!// User: "I want to book the Grand Hotel for 2 people next Friday"
// AI: "Perfect! Booking confirmed for 2 guests at Grand Hotel on Friday!" 
// β
 Extracted all data from one message
// β
 Skipped unnecessary steps
// β
 Completed immediatelyNo more repetitive questions. No more guessing what the AI will ask next.
Intelligent Pre-Extraction - AI automatically captures ALL relevant data from user messages, then determines which step to start at based on what's missing.
After building production AI applications, we found existing solutions either:
- Too unpredictable - AI decides everything, including which tools to call (unreliable in production)
 - Too complex - Heavy Python frameworks with massive dependencies
 - Too basic - No structured data extraction or step management
 
@falai/agent gives you predictable AI - the creativity of LLMs with the reliability of code.
The key insight: Let AI do what it's good at (understanding intent, generating responses, extracting data), and let TypeScript handle the rest (step logic, tool execution, validation).
  | 
  | 
  | 
  | 
  | 
  | 
  | 
  | 
# Using bun (recommended)
bun add @falai/agent
# Using npm
npm install @falai/agent
# Using yarn
yarn add @falai/agentRequirements: Node.js 18+ or Bun 1.0+
Create a minimal conversational agent:
import {
  Agent,
  GeminiProvider,
  createMessageEvent,
  EventSource,
} from "@falai/agent";
// Create your agent
const agent = new Agent({
  name: "Assistant",
  description: "A helpful assistant",
  provider: new GeminiProvider({
    apiKey: process.env.GEMINI_API_KEY!,
    model: "models/gemini-2.5-flash",
  }),
});
// Create a simple route with sequential steps
agent.createRoute({
  title: "General Help",
  description: "Answers user questions",
  when: ["User needs help or asks a question"],
  steps: [
    {
      id: "answer_question",
      description: "Answer the user's question helpfully",
      prompt: "Answer the user's question helpfully",
    },
  ],
});
// Start chatting - simple message-based API
const response = await agent.respond("What can you do?");
console.log(response.message);That's it! You now have a working conversational AI agent.
Routes now support powerful condition patterns that combine AI context with programmatic logic:
// String-only conditions (AI context for routing decisions)
agent.createRoute({
  title: "Customer Support",
  when: "User needs help with their account",
  steps: [/* ... */]
});
// Function-only conditions (programmatic evaluation)
agent.createRoute({
  title: "Premium Features",
  when: (ctx) => ctx.data?.userType === 'premium',
  steps: [/* ... */]
});
// Mixed array conditions (AI context + programmatic logic)
agent.createRoute({
  title: "Booking Assistance",
  when: [
    "User wants to make a reservation", // AI context
    (ctx) => ctx.data?.isLoggedIn === true // Programmatic check
  ],
  steps: [/* ... */]
});
// Route skipIf - exclude routes dynamically
agent.createRoute({
  title: "Payment Processing",
  when: ["User wants to make a payment"],
  skipIf: [
    "Payment system is under maintenance", // AI context
    (ctx) => ctx.data?.paymentBlocked === true // Programmatic check
  ],
  steps: [/* ... */]
});Steps support the same flexible condition patterns:
agent.createRoute({
  title: "Order Process",
  steps: [
    {
      id: "collect_items",
      when: "User wants to add items to cart",
      prompt: "What would you like to order?",
      collect: ["items"]
    },
    {
      id: "payment_step",
      when: [
        "Ready to process payment", // AI context
        (ctx) => ctx.data?.items?.length > 0 // Programmatic check
      ],
      skipIf: (ctx) => ctx.data?.paymentComplete === true,
      prompt: "Let's process your payment",
      tools: ["process_payment"]
    },
    {
      id: "confirmation",
      when: "Order is ready for confirmation",
      skipIf: [
        "Order already confirmed", // AI context
        (ctx) => ctx.data?.orderConfirmed === true // Programmatic check
      ],
      prompt: "Your order is confirmed!",
      finalize: "send_confirmation_email"
    }
  ]
});Guidelines now support flexible conditions for context-aware behavior:
// Add guidelines with mixed condition types
agent.addGuideline({
  title: "Premium User Support",
  condition: [
    "User is asking for help", // AI context
    (ctx) => ctx.data?.userType === 'premium' // Programmatic check
  ],
  content: "Provide priority support with detailed explanations and offer direct phone support."
});
agent.addGuideline({
  title: "Maintenance Mode",
  condition: "System maintenance is active",
  content: "Inform users about scheduled maintenance and provide estimated completion time."
});
// Function-only guideline for specific conditions
agent.addGuideline({
  title: "High Value Customer",
  condition: (ctx) => ctx.data?.totalSpent > 10000,
  content: "Offer VIP treatment and exclusive deals."
});Key Benefits:
- β Hybrid Logic - Combine AI understanding with programmatic precision
 - β Context Awareness - AI sees string conditions for better routing decisions
 - β Performance - Functions execute first, strings only used when needed
 - β Flexibility - Use simple strings, functions, or arrays as needed
 
Create tools with minimal boilerplate using the unified Tool interface:
// Create a simple tool with the unified interface
agent.addTool({
  id: "validate_user",
  name: "User Data Validator",
  description: "Validate user data before processing",
  parameters: { type: "object", properties: {} },
  handler: async ({ context, data, updateData }) => {
    // Validation logic with helper methods
    if (!data.email?.includes("@")) {
      throw new Error("Invalid email address");
    }
    
    // Mark as validated using helper method
    await updateData({ emailValidated: true });
    
    return "User validation completed successfully";
  },
});
// Use tools in conversation flows and step lifecycle
agent.createRoute({
  title: "User Registration",
  steps: [
    {
      id: "collect_info",
      description: "Collect user information",
      collect: ["name", "email"],
      prompt: "Please provide your name and email.",
      prepare: "validate_user", // Tool executes before AI response
      tools: ["validate_user"], // Tool available during conversation
    },
  ],
});Benefits:
- β Simple API - Unified Tool interface with minimal complexity
 - β Type Safety - Full TypeScript support with automatic inference
 - β Flexible Returns - Return simple values or complex ToolResult objects
 - β Helper Methods - Built-in context and data update utilities
 - β Lifecycle Integration - Use tools as prepare/finalize hooks in steps
 
Now let's build an agent that intelligently collects structured data:
import {
  Agent,
  OpenAIProvider,
  createMessageEvent,
  EventSource,
} from "@falai/agent";
// 1οΈβ£ Define the data you want to collect
interface HotelBookingData {
  hotelName: string;
  date: string;
  guests: number;
}
// 2οΈβ£ Create your agent with centralized data schema
const agent = new Agent<{}, HotelBookingData>({
  name: "BookingBot",
  description: "A hotel booking assistant that collects information.",
  provider: new OpenAIProvider({
    apiKey: process.env.OPENAI_API_KEY,
    model: "gpt-4", // or your preferred model
  }),
  
  // Agent-level schema defines all possible data fields
  schema: {
    type: "object",
    properties: {
      hotelName: { type: "string", description: "The name of the hotel." },
      date: { type: "string", description: "The desired booking date." },
      guests: { type: "number", description: "The number of guests." },
    },
    required: ["hotelName", "date", "guests"],
  },
  
  // Agent-level data validation and enrichment
  hooks: {
    onDataUpdate: async (data, previousData) => {
      // Auto-validate and enrich data
      if (data.guests && data.guests > 10) {
        throw new Error("Maximum 10 guests allowed");
      }
      return data;
    }
  }
});
// 3οΈβ£ Define a tool using the unified Tool interface
agent.addTool({
  id: "book_hotel",
  name: "Hotel Booking System",
  description: "Books a hotel once all information is collected.",
  parameters: { type: "object", properties: {} },
  handler: async ({ context, data, updateContext }) => {
    // Tool receives complete agent data with simplified context and helper methods
    const bookingId = await hotelAPI.createBooking({
      hotel: data.hotelName,
      date: data.date,
      guests: data.guests,
    });
    
    // Use helper method to update context
    await updateContext({
      lastBookingId: bookingId,
      lastBookingDate: new Date().toISOString(),
    });
    
    return `Booking confirmed! Confirmation #${bookingId} for ${data.guests} guests at ${data.hotelName} on ${data.date}`;
  },
});
// 4οΈβ£ Create a route with required fields specification
agent.createRoute({
  title: "Book Hotel",
  description: "Guides the user through the hotel booking process.",
  when: ["User wants to book a hotel"],
  requiredFields: ["hotelName", "date", "guests"], // Required for route completion
  
  // 5οΈβ£ Define the flow to collect data step-by-step
  steps: [
    {
      id: "ask_hotel",
      description: "Ask which hotel they want to book",
      prompt: "Which hotel would you like to book?",
      collect: ["hotelName"],
      skipIf: (data: Partial<HotelBookingData>) => !!data.hotelName,
    },
    {
      id: "ask_date",
      description: "Ask for the booking date",
      prompt: "What date would you like to book for?",
      collect: ["date"],
      requires: ["hotelName"], // Prerequisites from agent data
      skipIf: (data: Partial<HotelBookingData>) => !!data.date,
    },
    {
      id: "ask_guests",
      description: "Ask for the number of guests",
      prompt: "How many guests will be staying?",
      collect: ["guests"],
      requires: ["hotelName", "date"], // Prerequisites from agent data
      skipIf: (data: Partial<HotelBookingData>) => data.guests !== undefined,
    },
    {
      id: "confirm_booking",
      description: "Confirm and book the hotel",
      prompt: "Let me confirm your booking details.",
      tools: ["book_hotel"], // Reference tool by ID
      requires: ["hotelName", "date", "guests"],
    },
  ],
});
// 5οΈβ£ Start conversing - simple message API
const response = await agent.respond("I want to book a room at the Grand Hotel for 2 people.");
// The agent sees that `hotelName` and `guests` are provided,
// skips the first and third steps, and only asks for the date.
console.log(response.message);
// Expected: "What date would you like to book for?"That's it! The data-driven agent will:
- β
 Understand the Goal - Route to the 
Book Hotelflow based on user intent. - β
 Extract Known Data - Automatically pull 
hotelNameandguestsfrom the first message. - β
 Skip Unneeded Steps - Use 
skipIfto bypass questions for data it already has. - β
 Collect Missing Data - Intelligently ask only for the missing 
date. - β
 Execute Deterministically - Call the 
bookHoteltool only when all required data is present. 
This creates a flexible and natural conversation, guided by a clear data structure.
π See more examples β | Full tutorial β
Streaming responses for real-time UX:
for await (const chunk of agent.respondStream("Hello")) {
  process.stdout.write(chunk.delta);
  if (chunk.done) {
    console.log("\nTool calls:", chunk.toolCalls);
  }
}Automatic session management for multi-turn conversations:
// Server-side: Create agent with sessionId
const agent = new Agent({
  name: "Assistant",
  provider: new OpenAIProvider({ apiKey: process.env.OPENAI_API_KEY }),
  persistence: { adapter: new PrismaAdapter({ prisma }) },
  sessionId: "user-123" // Automatically loads or creates session
});
// Simple conversation - no manual session management needed
const response = await agent.respond("Hello, how are you?");
console.log(response.message);
console.log(agent.session.id); // Session ID for clientAutomatic session persistence with any adapter:
import { PrismaAdapter } from "@falai/agent";
// Server endpoint - sessions managed automatically
app.post('/chat', async (req, res) => {
  const { sessionId, message } = req.body;
  
  const agent = new Agent({
    name: "ChatBot",
    provider: new OpenAIProvider({ apiKey: process.env.OPENAI_API_KEY }),
    persistence: { adapter: new PrismaAdapter({ prisma }) },
    sessionId // Automatically loads or creates this session
  });
  
  const response = await agent.respond(message);
  
  res.json({
    message: response.message,
    sessionId: agent.session.id, // Return session ID to client
    isComplete: response.isRouteComplete
  });
});π See full feature docs β
π Complete Documentation Index β - Searchable index of all docs
- Quick Start Guide - Build your first agent in 15 minutes
 
- Agent Orchestration - Agent lifecycle, configuration & hooks
 - Context Management - Dynamic context providers & updates
 - Session Management - Session persistence & state
 
- AI Providers - Gemini, OpenAI, Anthropic, OpenRouter
 - Prompt Composition - How prompts are built
 - Response Processing - Schema extraction & tool calls
 
- Tool Definition - Creating and configuring tools
 - Tool Execution - Dynamic tool calling and context updates
 - Tool Scoping - Agent, route, and step-level tool management
 
- Session Storage - Session persistence patterns
 - Database Adapters - Built-in adapter configurations
 
- Building Agents - Complete agent construction patterns
 - Advanced Patterns - Complex use cases & integrations
 - API Reference - Complete API documentation
 
Fundamental patterns every agent needs:
- Basic Agent - Minimal agent setup and configuration
 - Schema-Driven Extraction - Type-safe data collection with JSON Schema
 - Session Management - Multi-turn conversations with persistence
 - Context Providers - Dynamic context fetching and updates
 
Building intelligent dialogue systems:
- Simple Route - Basic route with linear step progression
 - Data-Driven Flows - Conditional logic with skipIf and requires
 - Conditional Branching - AI-powered branching decisions
 - Completion Transitions - Route transitions when flows complete
 
Integrating different AI services:
- Gemini Integration - Google Gemini with advanced features
 - OpenAI Integration - GPT-4 and GPT-3.5 Turbo
 - Anthropic Integration - Claude with streaming and tool calling
 - Custom Provider - Build your own AI provider integration
 
Session storage and data persistence:
- Memory Sessions - In-memory session management
 - Redis Persistence - High-performance Redis storage
 - Database Persistence - SQL/NoSQL database integration
 - Custom Adapter - Build custom persistence adapters
 
Tool creation and data manipulation:
- Basic Tools - Simple tool creation and execution
 - Data Enrichment Tools - Tools that modify collected data
 - Context Updating Tools - Tools that modify agent context
 - Domain Scoped Tools - Tool security and access control
 
Complex use cases and integrations:
- Multi-Turn Conversations - Complex dialogue flows with backtracking
 - Streaming Responses - Real-time response streaming
 - Route Lifecycle Hooks - Custom route behavior
 - Custom Response Schemas - Advanced schema patterns
 
External service integrations:
- Server Deployment - HTTP API with WebSocket streaming
 - Database Integration - Direct database access patterns
 - Webhook Integration - HTTP webhook handling
 - API Integration - External API calls and responses
 
π See all examples with detailed explanations β
@falai/agent uses a schema-first, pipeline-driven architecture with intelligent pre-extraction:
User Message + Session State
    β
βββββββββββββββββββββββββββββββββββββββββββ
β 1. ROUTING + PRE-EXTRACTION             β
β    β’ Evaluate routes (AI scoring)       β
β    β’ Pre-extract data from message      β
β    β’ Check route completion             β
βββββββββββββββββββββββββββββββββββββββββββ
    β
βββββββββββββββββββββββββββββββββββββββββββ
β 2. SMART STEP SELECTION                 β
β    β’ Filter steps (skipIf, requires)    β
β    β’ Skip steps with existing data      β
β    β’ Select optimal next step           β
βββββββββββββββββββββββββββββββββββββββββββ
    β
βββββββββββββββββββββββββββββββββββββββββββ
β 3. RESPONSE GENERATION                  β
β    β’ Build prompt with context          β
β    β’ Generate AI response               β
β    β’ Execute tools if needed            β
βββββββββββββββββββββββββββββββββββββββββββ
    β
βββββββββββββββββββββββββββββββββββββββββββ
β 4. COMPLETION HANDLING                  β
β    β’ Auto-complete when data collected  β
β    β’ Exclude completed routes           β
β    β’ Generate completion message        β
βββββββββββββββββββββββββββββββββββββββββββ
    β
Response + Updated Session State
β AI decides: Route selection, data extraction, message generation, tool calling β Code decides: Step flow control, route completion, lifecycle hooks, data validation β Result: Efficient conversations that don't waste user time
π― Pre-Extraction - Data extracted BEFORE entering steps (no repeated questions) π Auto-Completion - Routes complete automatically when required fields are collected π Completion Protection - Completed routes excluded from future selection β‘ Smart Skipping - Steps bypassed if their data is already present
π Read the detailed architecture β
We welcome contributions! See our Contributing Guide for details on:
- π Reporting bugs
 - π‘ Suggesting features
 - π Improving documentation
 - π¨ Submitting pull requests
 
This framework draws inspiration from Parlant by Emcie Co., an excellent Python framework for conversational AI agents. We've adapted and enhanced these concepts for the TypeScript ecosystem with additional type safety and modern patterns.
MIT Β© 2025
Choose your path:
πΆ New to AI agents? β Quick Start Guide ποΈ Building production app? β Agent Architecture π‘ Have questions? β Open a discussion
β Star us on GitHub
Help us reach more developers building production AI!
Report Bug β’ Request Feature β’ Contribute
Made with β€οΈ for the community