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
File : src/tools/CustomDataTool.ts
Demonstrates the powerful Custom Data API with semantic vector search. The example uses a movie database, but the patterns work for any searchable content.
What Makes This Special
Vector Search = Semantic Understanding
Traditional search:
Query: “Inception” → Finds “Inception” ✅
Query: “dream movie” → Finds nothing ❌
Vector search:
Query: “Inception” → Finds “Inception” ✅
Query: “dream movie” → Finds “Inception”! ✅
Query: “mind-bending thriller” → Finds similar movies! ✅
import { LuaTool , Data } from 'lua-cli' ;
import { z } from 'zod' ;
export class CreateMovieTool implements LuaTool {
name = "create_movie" ;
description = "Add a new movie to the database" ;
inputSchema = z . object ({
title: z . string (),
director: z . string (),
year: z . number (),
genre: z . string (),
description: z . string (). optional ()
});
async execute ( input : z . infer < typeof this . inputSchema >) {
// ⭐ KEY: Create searchable text with all relevant info
const searchText = [
input . title ,
input . director ,
input . genre ,
input . description
]. filter ( Boolean ). join ( ' ' );
const movie = await Data . create ( 'movies' , input , searchText );
return {
id: movie . id ,
message: `Added " ${ input . title } " to database`
};
}
}
export class SearchMoviesTool implements LuaTool {
name = "search_movies" ;
description = "Search movies by title, director, genre, or theme" ;
inputSchema = z . object ({
query: z . string (). describe ( "Search query (can be descriptive)" )
});
async execute ( input : z . infer < typeof this . inputSchema >) {
// ⭐ Vector search with similarity threshold
const results = await Data . search (
'movies' ,
input . query ,
10 , // Max 10 results
0.7 // Min similarity score
);
return {
movies: results . map ( entry => ({
id: entry . id ,
title: entry . title ,
year: entry . year ,
director: entry . director ,
relevance: Math . round ( entry . score * 100 ) + '%'
})),
count: results . length
};
}
}
export class GetMovieByIdTool implements LuaTool {
name = "get_movie" ;
description = "Get detailed information about a specific movie" ;
inputSchema = z . object ({
id: z . string ()
});
async execute ( input : z . infer < typeof this . inputSchema >) {
const movie = await Data . getEntry ( 'movies' , input . id );
return movie . data ;
}
}
Key Concepts
1. Search Text is Critical
The searchText parameter determines what the AI can find:
// ✅ Good - Rich search text
const searchText = ` ${ input . title } ${ input . director } ${ input . genre } ${ input . description } ${ input . tags . join ( ' ' ) } ` ;
// ❌ Bad - Only title
const searchText = input . title ;
2. Similarity Scores
Understanding score thresholds:
1.0 = Perfect match
0.8-0.9 = Very similar
0.7-0.8 = Somewhat similar
0.6-0.7 = Loosely related
<0.6 = May be irrelevant
// Strict (high precision)
await Data . search ( 'movies' , query , 10 , 0.8 );
// Balanced (recommended)
await Data . search ( 'movies' , query , 10 , 0.7 );
// Loose (high recall)
await Data . search ( 'movies' , query , 10 , 0.6 );
3. Natural Language Queries
Users can search naturally:
// All of these work:
"sci-fi movies about space"
"Christopher Nolan films"
"thriller with plot twists"
"movies like Inception"
"romantic comedies from 2020"
Testing
Try semantic searches:
“mind-bending thriller” → Should find Inception
“Christopher Nolan movies” → Should find his films
“space exploration” → Should find relevant sci-fi
“romantic comedy” → Should find rom-coms
Use Cases
Knowledge Base
await Data . create ( 'articles' , {
title: 'How to Reset Password' ,
content: 'Step by step guide...' ,
category: 'Account'
}, 'password reset account help guide' );
// Users can find with:
// - "forgot password"
// - "can't log in"
// - "reset account"
Product Recommendations
await Data . create ( 'products' , {
name: 'Wireless Headphones' ,
description: 'Noise cancelling...'
}, 'wireless headphones bluetooth noise cancelling audio' );
// Users can find with:
// - "best headphones for travel"
// - "noise canceling earphones"
// - "bluetooth audio"
Customer Notes
await Data . create ( 'customers' , {
name: 'John Doe' ,
company: 'Acme Corp' ,
notes: 'Interested in enterprise plan'
}, 'John Doe Acme Corp enterprise interested sales' );
// Find with:
// - "enterprise customers"
// - "Acme contacts"
// - "sales leads"
Customization Ideas
Add Ratings
inputSchema = z . object ({
... existing ,
rating: z . number (). min ( 0 ). max ( 10 )
});
// Sort by rating
results . sort (( a , b ) => b . rating - a . rating );
Add Filters
// Search with filters
const results = await Data . search ( 'movies' , query , 50 , 0.7 );
// Filter by year
const recentMovies = results . filter ( m =>
m . year >= 2020
);
Update Movies
export class UpdateMovieTool implements LuaTool {
name = "update_movie" ;
description = "Update movie information" ;
inputSchema = z . object ({
id: z . string (),
data: z . object ({
rating: z . number (). optional (),
awards: z . array ( z . string ()). optional (),
description: z . string (). optional ()
}),
updateSearchText: z . boolean (). optional ()
});
async execute ( input : z . infer < typeof this . inputSchema >) {
const movie = await Data . getEntry ( 'movies' , input . id );
// Optionally update search text if description changed
const searchText = input . updateSearchText
? ` ${ movie . title } ${ movie . director } ${ input . data . description || '' } `
: undefined ;
await Data . update ( 'movies' , input . id , input . data , searchText );
return { success: true , message: `Updated movie ${ movie . title } ` };
}
}
Using save() Method
export class UpdateMovieRatingTool implements LuaTool {
name = "update_movie_rating" ;
description = "Update movie rating and review" ;
inputSchema = z . object ({
id: z . string (),
rating: z . number (). min ( 0 ). max ( 10 ),
review: z . string (). optional ()
});
async execute ( input : z . infer < typeof this . inputSchema >) {
// Get the entry
const movie = await Data . getEntry ( 'movies' , input . id );
// Modify properties directly
movie . rating = input . rating ;
if ( input . review ) {
movie . review = input . review ;
}
movie . updatedAt = new Date (). toISOString ();
// Save all changes at once
// Optionally update search text if review added
const searchText = input . review
? ` ${ movie . title } ${ movie . director } rating ${ input . rating } ${ input . review } `
: undefined ;
await movie . save ( searchText );
return {
success: true ,
message: `Updated " ${ movie . title } " rating to ${ input . rating } `
};
}
}
What You’ll Learn
Vector Search Semantic similarity search with AI
Custom Collections Store any data structure
Search Indexing Optimize for findability
Score Thresholds Tune precision vs recall
Next Steps
Data API Reference Complete Data API documentation
Build Your First Skill Uses Data API with vector search