Security: - Add token+secret auth to /setup-webhook and /webhook-info endpoints - Disable /api/test in production environment (ENVIRONMENT=production) Performance: - Add retryWithBackoff to weather-tool (maxRetries: 2) - Add KV caching to executeLookupDocs (1h TTL) Code Quality: - Centralize error messages in src/constants/messages.ts - Update 5 files to use centralized error constants Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
93 lines
2.4 KiB
TypeScript
93 lines
2.4 KiB
TypeScript
// Weather Tool - wttr.in integration
|
|
import type { Env } from '../types';
|
|
import { retryWithBackoff } from '../utils/retry';
|
|
import { ERROR_MESSAGES } from '../constants/messages';
|
|
|
|
// wttr.in API 응답 타입 정의
|
|
interface WttrCurrentCondition {
|
|
temp_C: string;
|
|
FeelsLikeC: string;
|
|
weatherDesc: Array<{ value: string }>;
|
|
humidity: string;
|
|
windspeedKmph: string;
|
|
winddir16Point: string;
|
|
uvIndex: string;
|
|
visibility: string;
|
|
}
|
|
|
|
interface WttrWeatherDay {
|
|
date: string;
|
|
maxtempC: string;
|
|
mintempC: string;
|
|
hourly: Array<{
|
|
time: string;
|
|
tempC: string;
|
|
weatherDesc: Array<{ value: string }>;
|
|
chanceofrain: string;
|
|
}>;
|
|
}
|
|
|
|
interface WttrResponse {
|
|
current_condition: WttrCurrentCondition[];
|
|
weather: WttrWeatherDay[];
|
|
nearest_area: Array<{
|
|
areaName: Array<{ value: string }>;
|
|
country: Array<{ value: string }>;
|
|
}>;
|
|
}
|
|
|
|
export const weatherTool = {
|
|
type: 'function',
|
|
function: {
|
|
name: 'get_weather',
|
|
description: '특정 도시의 현재 날씨 정보를 가져옵니다',
|
|
parameters: {
|
|
type: 'object',
|
|
properties: {
|
|
city: {
|
|
type: 'string',
|
|
description: '도시 이름 (예: Seoul, Tokyo, New York)',
|
|
},
|
|
},
|
|
required: ['city'],
|
|
},
|
|
},
|
|
};
|
|
|
|
export async function executeWeather(args: { city: string }, env?: Env): Promise<string> {
|
|
const city = args.city || 'Seoul';
|
|
try {
|
|
const wttrUrl = env?.WTTR_IN_URL || 'https://wttr.in';
|
|
const response = await retryWithBackoff(
|
|
() => fetch(`${wttrUrl}/${encodeURIComponent(city)}?format=j1`),
|
|
{ maxRetries: 2, initialDelayMs: 500 }
|
|
);
|
|
|
|
if (!response.ok) {
|
|
throw new Error(`API 응답 실패: ${response.status}`);
|
|
}
|
|
|
|
const data = await response.json() as WttrResponse;
|
|
|
|
// 안전한 접근 - 데이터 유효성 확인
|
|
if (!data.current_condition?.[0]) {
|
|
return `${ERROR_MESSAGES.WEATHER_SERVICE_UNAVAILABLE}: ${city}`;
|
|
}
|
|
|
|
const current = data.current_condition[0];
|
|
|
|
// weatherDesc 배열 존재 확인
|
|
if (!current.weatherDesc?.[0]?.value) {
|
|
return `날씨 정보가 불완전합니다: ${city}`;
|
|
}
|
|
|
|
return `🌤 ${city} 날씨
|
|
온도: ${current.temp_C}°C (체감 ${current.FeelsLikeC}°C)
|
|
상태: ${current.weatherDesc[0].value}
|
|
습도: ${current.humidity}%
|
|
풍속: ${current.windspeedKmph} km/h`;
|
|
} catch (error) {
|
|
return `${ERROR_MESSAGES.WEATHER_SERVICE_UNAVAILABLE}: ${city}`;
|
|
}
|
|
}
|