import { ToolHandler, ToolResult } from '../types/index.js';
export class FlightStatusTool implements ToolHandler {
private readonly apiKey: string;
private readonly baseUrl = 'http://api.aviationstack.com/v1/flights';
constructor() {
// For demo purposes, we'll use a placeholder key
// In production, this should come from environment variables
this.apiKey = process.env.AVIATIONSTACK_API_KEY || 'demo_key';
}
async execute(args: Record<string, any>): Promise<ToolResult> {
const { flightNumber, airlineIata } = args;
if (!flightNumber) {
return {
content: [
{
type: 'text',
text: 'Error: Flight number is required',
},
],
isError: true,
};
}
try {
// If no API key is provided, return mock data
if (this.apiKey === 'demo_key') {
return this.getMockFlightData(flightNumber, airlineIata);
}
const response = await this.fetchFlightData(flightNumber, airlineIata);
return this.formatFlightResponse(response);
} catch (error) {
return {
content: [
{
type: 'text',
text: `Error fetching flight data: ${error instanceof Error ? error.message : 'Unknown error'}`,
},
],
isError: true,
};
}
}
private async fetchFlightData(flightNumber: string, airlineIata?: string): Promise<any> {
const params = new URLSearchParams({
access_key: this.apiKey,
flight_iata: airlineIata ? `${airlineIata}${flightNumber}` : flightNumber,
limit: '1',
});
const url = `${this.baseUrl}?${params.toString()}`;
const response = await fetch(url);
if (!response.ok) {
throw new Error(`API request failed: ${response.status} ${response.statusText}`);
}
const data = await response.json() as any;
if (data.error) {
throw new Error(`API Error: ${data.error.message || 'Unknown API error'}`);
}
return data;
}
private getMockFlightData(flightNumber: string, airlineIata?: string): ToolResult {
const mockStatuses = ['scheduled', 'active', 'landed', 'cancelled', 'delayed'];
const mockAirlines = ['AA', 'DL', 'UA', 'BA', 'LH'];
const mockAirports = [
{ code: 'JFK', name: 'John F. Kennedy International Airport', city: 'New York' },
{ code: 'LAX', name: 'Los Angeles International Airport', city: 'Los Angeles' },
{ code: 'LHR', name: 'London Heathrow Airport', city: 'London' },
{ code: 'CDG', name: 'Charles de Gaulle Airport', city: 'Paris' },
{ code: 'NRT', name: 'Narita International Airport', city: 'Tokyo' },
];
const airline = airlineIata || mockAirlines[Math.floor(Math.random() * mockAirlines.length)];
const status = mockStatuses[Math.floor(Math.random() * mockStatuses.length)];
const departure = mockAirports[Math.floor(Math.random() * mockAirports.length)];
const arrival = mockAirports[Math.floor(Math.random() * mockAirports.length)];
const now = new Date();
const departureTime = new Date(now.getTime() + Math.random() * 24 * 60 * 60 * 1000);
const arrivalTime = new Date(departureTime.getTime() + (2 + Math.random() * 10) * 60 * 60 * 1000);
const mockFlight = {
flight: {
iata: `${airline}${flightNumber}`,
number: flightNumber,
},
flight_status: status,
departure: {
airport: departure.name,
iata: departure.code,
scheduled: departureTime.toISOString(),
timezone: 'UTC',
},
arrival: {
airport: arrival.name,
iata: arrival.code,
scheduled: arrivalTime.toISOString(),
timezone: 'UTC',
},
airline: {
name: this.getAirlineName(airline),
iata: airline,
},
};
return this.formatMockFlightResponse(mockFlight);
}
private getAirlineName(iata: string): string {
const airlines: Record<string, string> = {
'AA': 'American Airlines',
'DL': 'Delta Air Lines',
'UA': 'United Airlines',
'BA': 'British Airways',
'LH': 'Lufthansa',
};
return airlines[iata] || `${iata} Airlines`;
}
private formatFlightResponse(data: any): ToolResult {
if (!data.data || data.data.length === 0) {
return {
content: [
{
type: 'text',
text: 'No flight data found for the specified flight number.',
},
],
};
}
const flight = data.data[0];
return this.formatMockFlightResponse(flight);
}
private formatMockFlightResponse(flight: any): ToolResult {
const formatTime = (timestamp: string) => {
return new Date(timestamp).toLocaleString('en-US', {
timeZone: 'UTC',
year: 'numeric',
month: '2-digit',
day: '2-digit',
hour: '2-digit',
minute: '2-digit',
timeZoneName: 'short',
});
};
const statusEmoji = this.getStatusEmoji(flight.flight_status);
const flightInfo = `
š©ļø **Flight Status: ${flight.flight.iata}**
${statusEmoji} **Status**: ${flight.flight_status.toUpperCase()}
āļø **Airline**: ${flight.airline.name} (${flight.airline.iata})
š« **Departure**
Airport: ${flight.departure.airport} (${flight.departure.iata})
Scheduled: ${formatTime(flight.departure.scheduled)}
š¬ **Arrival**
Airport: ${flight.arrival.airport} (${flight.arrival.iata})
Scheduled: ${formatTime(flight.arrival.scheduled)}
š **Route**: ${flight.departure.iata} ā ${flight.arrival.iata}
`.trim();
return {
content: [
{
type: 'text',
text: flightInfo,
},
],
};
}
private getStatusEmoji(status: string): string {
const statusEmojis: Record<string, string> = {
'scheduled': 'š',
'active': 'š©ļø',
'landed': 'ā
',
'cancelled': 'ā',
'delayed': 'ā°',
'diverted': 'š',
};
return statusEmojis[status.toLowerCase()] || 'š';
}
}