Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.heylua.ai/llms.txt

Use this file to discover all available pages before exploring further.

Overview

Restaurant AI assistant for menu browsing, food ordering, and table reservations using Lua Platform APIs. What it does:
  • Browse menu with search
  • Create food orders
  • Make table reservations
  • Track order status
  • Handle special dietary requests
APIs used: Lua Products API (menu), Data API (orders, reservations)

Complete Implementation

src/index.ts

import { LuaAgent, LuaSkill } from "lua-cli";
import {
  BrowseMenuTool,
  SearchMenuTool,
  CreateOrderTool,
  TrackOrderTool,
  MakeReservationTool,
  CheckReservationTool
} from "./tools/RestaurantTools";

// Restaurant ordering skill
const restaurantSkill = new LuaSkill({
  name: "restaurant-assistant",
  description: "Restaurant ordering and reservation assistant",
  context: `
    This skill helps customers order food and make reservations.
    
    Menu & Ordering:
    - browse_menu: Show all menu items or filter by category
    - search_menu: Find specific dishes
    - create_order: Place food order (confirm items first!)
    - track_order: Check order preparation status
    
    Reservations:
    - make_reservation: Book a table
    - check_reservation: Look up reservation details
    
    Always mention daily specials.
    Ask about dietary restrictions and allergies.
    Confirm order details and total before submitting.
  `,
  tools: [
    new BrowseMenuTool(),
    new SearchMenuTool(),
    new CreateOrderTool(),
    new TrackOrderTool(),
    new MakeReservationTool(),
    new CheckReservationTool()
  ]
});

// Configure agent (v3.0.0)
export const agent = new LuaAgent({
  name: "restaurant-assistant",
  
  persona: `You are a friendly restaurant host and server.
  
Your role:
- Help guests browse the menu
- Take food and drink orders
- Make table reservations
- Answer questions about ingredients and preparation
- Accommodate dietary restrictions

Communication style:
- Warm and welcoming
- Enthusiastic about the food
- Attentive to details
- Patient with questions
- Knowledgeable about the menu

Best practices:
- Always mention today's specials
- Ask about dietary restrictions and allergies
- Confirm order details before submitting
- Suggest wine pairings or desserts
- Provide estimated wait times
- Thank guests warmly

Menu knowledge:
- All dishes and ingredients
- Preparation methods
- Portion sizes
- Dietary information (vegan, gluten-free, etc.)
- Chef's recommendations`,

  
  skills: [restaurantSkill]
});
v3.0.0 Pattern: This demo now uses LuaAgent to configure the agent’s persona, welcome message, and skills.

src/tools/RestaurantTools.ts

import { LuaTool, Products, Data } from "lua-cli";
import { z } from "zod";

// 1. Browse Menu
export class BrowseMenuTool implements LuaTool {
  name = "browse_menu";
  description = "Browse restaurant menu items";
  
  inputSchema = z.object({
    category: z.enum(['appetizers', 'entrees', 'desserts', 'drinks', 'all']).default('all')
  });

  async execute(input: z.infer<typeof this.inputSchema>) {
    // Use Products API for menu items (page 1, limit 100)
    const allItems = await Products.get(1, 100);
    
    let items = allItems.data;
    if (input.category !== 'all') {
      items = items.filter(item => item.category === input.category);
    }
    
    return {
      category: input.category,
      items: items.map(item => ({
        id: item.id,
        name: item.name,
        description: item.description,
        price: `$${item.price.toFixed(2)}`,
        category: item.category,
        dietary: item.metadata?.dietary || []
      })),
      dailySpecial: "Chef's seafood pasta - $24.99",
      message: `Showing ${items.length} ${input.category} items`
    };
  }
}

// 2. Search Menu
export class SearchMenuTool implements LuaTool {
  name = "search_menu";
  description = "Search menu by dish name or ingredient";
  
  inputSchema = z.object({
    query: z.string().describe("Search query (dish name, ingredient, dietary requirement)")
  });

  async execute(input: z.infer<typeof this.inputSchema>) {
    const results = await Products.search(input.query);
    
    return {
      results: results.map(item => ({
        id: item.id,
        name: item.name,
        price: `$${item.price.toFixed(2)}`,
        description: item.description,
        dietary: item.metadata?.dietary
      })),
      count: results.length
    };
  }
}

// 3. Create Order
export class CreateOrderTool implements LuaTool {
  name = "create_order";
  description = "Place a food order";
  
  inputSchema = z.object({
    items: z.array(z.object({
      productId: z.string(),
      quantity: z.number().min(1),
      specialInstructions: z.string().optional()
    })),
    customerName: z.string(),
    customerPhone: z.string(),
    orderType: z.enum(['dine-in', 'takeout', 'delivery']).default('dine-in'),
    deliveryAddress: z.string().optional()
  });

  async execute(input: z.infer<typeof this.inputSchema>) {
    // Get all product details and calculate total
    let total = 0;
    const orderItems = [];
    
    for (const item of input.items) {
      const product = await Products.getById(item.productId);
      
      if (!product) {
        throw new Error(`Menu item not found: ${item.productId}`);
      }
      
      const itemTotal = product.price * item.quantity;
      total += itemTotal;
      
      orderItems.push({
        name: product.name,
        quantity: item.quantity,
        price: product.price,
        subtotal: itemTotal,
        specialInstructions: item.specialInstructions
      });
    }
    
    // Add delivery fee if applicable
    if (input.orderType === 'delivery') {
      total += 5.99; // Delivery fee
    }
    
    // Create order
    const order = await Data.create('restaurant_orders', {
      items: orderItems,
      total,
      customerName: input.customerName,
      customerPhone: input.customerPhone,
      orderType: input.orderType,
      deliveryAddress: input.deliveryAddress,
      status: 'preparing',
      orderNumber: this.generateOrderNumber(),
      createdAt: new Date().toISOString()
    });
    
    return {
      success: true,
      orderId: order.id,
      orderNumber: order.data.orderNumber,
      items: orderItems,
      total: `$${total.toFixed(2)}`,
      estimatedTime: input.orderType === 'dine-in' ? '20-25 minutes' : '30-40 minutes',
      message: `Order #${order.data.orderNumber} placed! Estimated time: ${input.orderType === 'dine-in' ? '20-25' : '30-40'} minutes`
    };
  }
  
  private generateOrderNumber(): string {
    return 'ORD-' + Date.now().toString().slice(-6);
  }
  
  private calculateNights(checkIn: string, checkOut: string): number {
    const start = new Date(checkIn);
    const end = new Date(checkOut);
    return Math.ceil((end.getTime() - start.getTime()) / (1000 * 60 * 60 * 24));
  }
}

// 4. Track Order
export class TrackOrderTool implements LuaTool {
  name = "track_order";
  description = "Check order preparation status";
  
  inputSchema = z.object({
    orderNumber: z.string().describe("Order number")
  });

  async execute(input: z.infer<typeof this.inputSchema>) {
    const results = await Data.get('restaurant_orders', {
      orderNumber: input.orderNumber
    });
    
    if (results.data.length === 0) {
      throw new Error(`Order not found: ${input.orderNumber}`);
    }
    
    const order = results.data[0];
    
    const statusMessages = {
      preparing: "🍳 Your order is being prepared",
      ready: "✅ Your order is ready for pickup!",
      delivered: "🎉 Order delivered!",
      cancelled: "❌ Order was cancelled"
    };
    
    return {
      orderNumber: order.data.orderNumber,
      status: order.data.status,
      statusMessage: statusMessages[order.data.status],
      items: order.data.items,
      total: `$${order.data.total.toFixed(2)}`,
      orderType: order.data.orderType
    };
  }
}

// 5. Make Reservation
export class MakeReservationTool implements LuaTool {
  name = "make_reservation";
  description = "Reserve a table at the restaurant";
  
  inputSchema = z.object({
    date: z.string().describe("Reservation date (YYYY-MM-DD)"),
    time: z.string().describe("Reservation time (HH:MM)"),
    partySize: z.number().min(1).max(20),
    customerName: z.string(),
    customerPhone: z.string(),
    specialRequests: z.string().optional()
  });

  async execute(input: z.infer<typeof this.inputSchema>) {
    // Create reservation
    const reservation = await Data.create('table_reservations', {
      date: input.date,
      time: input.time,
      partySize: input.partySize,
      customerName: input.customerName,
      customerPhone: input.customerPhone,
      specialRequests: input.specialRequests,
      status: 'confirmed',
      confirmationCode: this.generateConfirmationCode(),
      createdAt: new Date().toISOString()
    }, `${input.customerName} ${input.date} ${input.time}`);
    
    return {
      success: true,
      confirmationCode: reservation.data.confirmationCode,
      date: input.date,
      time: input.time,
      partySize: input.partySize,
      message: `Table reserved for ${input.partySize} on ${input.date} at ${input.time}. Confirmation: ${reservation.data.confirmationCode}`
    };
  }
  
  private generateConfirmationCode(): string {
    return 'RES-' + Math.random().toString(36).substring(2, 10).toUpperCase();
  }
}

// 6. Check Reservation
export class CheckReservationTool implements LuaTool {
  name = "check_reservation";
  description = "Look up table reservation";
  
  inputSchema = z.object({
    confirmationCode: z.string(),
    phone: z.string()
  });

  async execute(input: z.infer<typeof this.inputSchema>) {
    const results = await Data.get('table_reservations', {
      confirmationCode: input.confirmationCode,
      customerPhone: input.phone
    });
    
    if (results.data.length === 0) {
      throw new Error('Reservation not found');
    }
    
    const reservation = results.data[0];
    
    return {
      confirmationCode: reservation.data.confirmationCode,
      customerName: reservation.data.customerName,
      date: reservation.data.date,
      time: reservation.data.time,
      partySize: reservation.data.partySize,
      status: reservation.data.status,
      specialRequests: reservation.data.specialRequests
    };
  }
}

Key Features

Platform APIs

Uses Products API for menu

Data API

Orders and reservations

Full Featured

Complete restaurant solution

Dietary Info

Handles dietary restrictions