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/GetWeatherTool.ts
The Weather Tool demonstrates external API integration using the free Open-Meteo API (no API key required).
What It Does
- Fetches real-time weather for any city worldwide
- Two-step process: geocoding + weather data
- Error handling for invalid cities
- No API key or authentication required
Complete Code
import { LuaTool } from 'lua-cli';
import { z } from 'zod';
export default class GetWeatherTool implements LuaTool {
name = "get_weather";
description = "Get current weather conditions for any city";
inputSchema = z.object({
city: z.string().describe("City name (e.g., 'London', 'Tokyo')")
});
async execute(input: z.infer<typeof this.inputSchema>) {
// Step 1: Convert city name to coordinates
const geoUrl = `https://geocoding-api.open-meteo.com/v1/search?name=${encodeURIComponent(input.city)}&count=1`;
const geoRes = await fetch(geoUrl);
const geoData = await geoRes.json();
if (!geoData.results?.[0]) {
throw new Error(`City not found: ${input.city}`);
}
const { latitude, longitude, name } = geoData.results[0];
// Step 2: Get weather for coordinates
const weatherUrl = `https://api.open-meteo.com/v1/forecast?latitude=${latitude}&longitude=${longitude}¤t_weather=true`;
const weatherRes = await fetch(weatherUrl);
const weatherData = await weatherRes.json();
return {
city: name,
temperature: weatherData.current_weather.temperature,
windSpeed: weatherData.current_weather.windspeed,
weatherCode: weatherData.current_weather.weathercode
};
}
}
Key Concepts
1. Two-Step API Call
Why? Weather APIs need coordinates, but users provide city names.
// Step 1: City name → Coordinates
const geoData = await fetch(geocodingUrl);
const { latitude, longitude } = geoData.results[0];
// Step 2: Coordinates → Weather
const weatherData = await fetch(weatherUrl);
2. URL Encoding
Always encode user input in URLs:
const geoUrl = `https://geocoding-api.open-meteo.com/v1/search?name=${encodeURIComponent(input.city)}&count=1`;
3. Error Handling
Check if city exists before proceeding:
if (!geoData.results?.[0]) {
throw new Error(`City not found: ${input.city}`);
}
4. Structured Return
Return organized data, not raw API response:
return {
city: name, // Clean city name
temperature: data.temp, // Extract what's needed
windSpeed: data.wind // No extra data
};
Testing
Try different cities:
London - Should work
Tokyo - Should work
New York - Should work
XYZ123 - Should fail gracefully
Customization Ideas
Add Temperature Units
inputSchema = z.object({
city: z.string(),
units: z.enum(['metric', 'imperial']).default('metric')
});
// In URL
const weatherUrl = `...&temperature_unit=${units === 'imperial' ? 'fahrenheit' : 'celsius'}`;
Add Weather Recommendations
return {
...weatherData,
recommendation: temperature < 10
? "🧥 Bring a warm jacket"
: temperature < 20
? "👕 Light jacket recommended"
: "☀️ T-shirt weather!"
};
Add Forecast
const forecastUrl = `...&forecast_days=7`;
const forecast = await fetch(forecastUrl);
return {
current: {...},
forecast: forecast.daily
};
What You’ll Learn
External APIs
How to call external REST APIs
Error Handling
Graceful error messages
Data Transformation
Converting API responses to clean output
URL Encoding
Safely encoding user input in URLs
Next Steps
User Data Example
Learn platform API usage
Payment Example
See authenticated external API