Skip to main content

What is a Tool?

A tool is a single function that your AI agent can execute. Tools are the building blocks that give your agent real capabilities.

Think of it as:

A TypeScript function that does ONE specific thing - like “search products” or “check order status”
v3.0.0 Update: Tools are bundled into skills, which are then added to your agent through the LuaAgent class. See Agent Concept for the complete pattern.

Anatomy of a Tool

import { LuaTool } from 'lua-cli';
import { z } from 'zod';

class SearchProductsTool implements LuaTool {
  // 1. Name - unique identifier
  name = "search_products";
  
  // 2. Description - what it does
  description = "Search for products in catalog";
  
  // 3. Input Schema - what it needs
  inputSchema = z.object({
    query: z.string().describe("Search query")
  });
  
  // 4. Execute - what it does
  async execute(input: { query: string }) {
    // Call your API or external service
    const response = await fetch(`https://your-api.com/search?q=${input.query}`);
    return await response.json();
  }
}

Name

Unique identifier (snake_case)

Description

Clear explanation of purpose

Input Schema

Zod validation for inputs

Execute Function

The actual logic

Good vs Bad Tools

class BadTool implements LuaTool {
  name = "tool1";  // Unclear name
  description = "Does stuff";  // Vague description
  
  inputSchema = z.object({
    input: z.string()  // Unclear parameter
  });
  
  async execute(input) {
    // No error handling
    // No validation
    // Returns unclear data
    return "done";
  }
}
Problems:
  • Unclear name
  • Vague description
  • Generic input
  • No error handling
  • Unclear return value

Tool Types

1. External API Tools

Connect to any external service:
class GetWeatherTool implements LuaTool {
  name = "get_weather";
  description = "Get current weather for a city";
  
  inputSchema = z.object({
    city: z.string()
  });
  
  async execute(input: { city: string }) {
    // Call external weather API
    const response = await fetch(
      `https://api.weather.com/v1/current?city=${input.city}`
    );
    return await response.json();
  }
}

2. Platform API Tools

Use Lua’s built-in APIs:
import { Products } from 'lua-cli';

class SearchProductsTool implements LuaTool {
  name = "search_products";
  description = "Search product catalog";
  
  inputSchema = z.object({
    query: z.string()
  });
  
  async execute(input: { query: string }) {
    // Use Platform API
    return await Products.search(input.query);
  }
}

3. Hybrid Tools

Mix both approaches:
import { Data } from 'lua-cli';

class SmartSearchTool implements LuaTool {
  async execute(input: { query: string }) {
    // 1. Search YOUR external API
    const yourProducts = await fetch('https://your-api.com/search');
    
    // 2. Search Platform vector search
    const docs = await Data.search('help_docs', input.query);
    
    // 3. Combine results
    return { yourProducts, docs };
  }
}

4. Conditional Tools

Tools that are only available under certain conditions:
import { User } from 'lua-cli';

class PremiumFeatureTool implements LuaTool {
  name = "premium_feature";
  description = "Advanced feature for premium users";
  
  inputSchema = z.object({ query: z.string() });
  
  // Only show to premium users
  condition = async () => {
    const user = await User.get();
    return user.data?.isPremium === true;
  };
  
  async execute(input) {
    // Only runs if condition returned true
    return { result: "premium data" };
  }
}
The condition function runs before the tool is offered to the AI. If it returns false or throws an error, the tool is hidden from the conversation.
Use cases for conditional tools:
  • Premium/paid features
  • User verification status
  • Feature flags & A/B testing
  • Region-specific tools
  • Time-based access

Tool Best Practices

// ✅ Good
name = "search_products"
name = "create_order"
name = "cancel_booking"

// ❌ Bad
name = "search"  // Too generic
name = "tool1"   // Not descriptive
name = "do_stuff"  // Unclear
// ✅ Good
description = "Search product catalog by name, category, or keyword"

// ❌ Bad
description = "Searches stuff"
inputSchema = z.object({
  email: z.string().email(),
  age: z.number().min(0).max(120),
  priority: z.enum(['low', 'medium', 'high'])
});
async execute(input) {
  try {
    const result = await api.call(input);
    return result;
  } catch (error) {
    throw new Error(`Operation failed: ${error.message}`);
  }
}
// ✅ Good - Structured
return {
  success: true,
  data: { id, name, price },
  message: "Product found"
};

// ❌ Bad - Unstructured string
return "Product found: ID 123";

Testing Tools

lua test
  • Select specific tool
  • Enter test inputs
  • Verify output
  • Debug tool logic

Managing Tools

Create

Write tools in src/tools/

Bundle

Add to skills in src/index.ts

Test

lua test

Deploy

lua push
lua deploy

Next Steps