diff --git a/src/tools/weather.ts b/src/tools/weather.ts index 5aa0d28..142f4fd 100644 --- a/src/tools/weather.ts +++ b/src/tools/weather.ts @@ -1603,18 +1603,26 @@ const KMA_TYPHOON_TRACK_URL = 'https://www.weather.go.kr/w/typhoon/ko/weather/ty // string like KMA's — nhc_active_storms resolves the right one, this just validates the // shape stays within nhc.noaa.gov's own graphics pages (no arbitrary path/host). const NHC_TRACK_URL_RE = /^https:\/\/www\.nhc\.noaa\.gov\/graphics_[a-z]+\d\.shtml(?:\?.*)?$/; +// JMA (RSMC Tokyo) is the actual regional warning center for the WHOLE Western North +// Pacific basin — unlike KMA's page (only shows the storm KMA itself has designated, +// i.e. ones close enough to threaten Korea) and NHC's page (Atlantic/EPac/CPac only). +// A typhoon sitting near Taiwan/Philippines/Guam/Japan with no Korea impact yet is +// invisible to both, so this plugs that gap. typhoon=all draws every active WNP storm's +// forecast track at once — no per-storm slot lookup needed, so (like KMA) this is a +// single fixed URL rather than something resolved per-storm. +const JMA_TYPHOON_MAP_URL = 'https://www.jma.go.jp/bosai/map.html#4/17.686/133.792/&elem=root&typhoon=all&contents=typhoon'; export const weatherMapScreenshotTool = { name: 'weather_map_screenshot', - description: 'Capture a real screenshot of a rendered weather map — the Windy embed (radar, satellite, wind, precipitation, etc.), the KMA typhoon forecast-track page, or an NHC forecast-track page (from nhc_active_storms) — so you can actually SEE it before describing it. Call this with the exact URL you just generated — do not guess what the map shows from the URL parameters alone.', + description: 'Capture a real screenshot of a rendered weather map — the Windy embed (radar, satellite, wind, precipitation, etc.), the KMA typhoon forecast-track page, the JMA (RSMC Tokyo) all-active-typhoons forecast-track map, or an NHC forecast-track page (from nhc_active_storms) — so you can actually SEE it before describing it. Call this with the exact URL you just generated — do not guess what the map shows from the URL parameters alone.', schema: { - url: `The exact https://embed.windy.com/embed2.html?... URL, the literal ${KMA_TYPHOON_TRACK_URL} for KMA, or an https://www.nhc.noaa.gov/graphics_XXN.shtml URL from nhc_active_storms`, + url: `The exact https://embed.windy.com/embed2.html?... URL, the literal ${KMA_TYPHOON_TRACK_URL} for KMA, the literal ${JMA_TYPHOON_MAP_URL} for JMA, or an https://www.nhc.noaa.gov/graphics_XXN.shtml URL from nhc_active_storms`, wait_ms: 'Milliseconds to wait for map tiles to finish loading before capturing (default 4000, max 8000)', }, jsonSchema: { type: 'object', properties: { - url: { type: 'string', description: 'The exact embed.windy.com, KMA typhoon track, or NHC graphics_XXN.shtml URL to capture' }, + url: { type: 'string', description: 'The exact embed.windy.com, KMA typhoon track, JMA typhoon track, or NHC graphics_XXN.shtml URL to capture' }, wait_ms: { type: 'number', description: 'Wait time in ms for tiles to load (default 4000, max 8000)' }, }, required: ['url'], @@ -1627,9 +1635,10 @@ export const weatherMapScreenshotTool = { let parsed: URL; try { parsed = new URL(urlStr); } catch { return { success: false, error: 'Invalid URL' }; } const isKmaTrack = urlStr === KMA_TYPHOON_TRACK_URL; + const isJmaTrack = urlStr === JMA_TYPHOON_MAP_URL; const isNhcTrack = NHC_TRACK_URL_RE.test(urlStr); - if (parsed.hostname !== 'embed.windy.com' && !isKmaTrack && !isNhcTrack) { - return { success: false, error: `Only embed.windy.com, ${KMA_TYPHOON_TRACK_URL}, or nhc.noaa.gov graphics_XXN.shtml URLs can be captured` }; + if (parsed.hostname !== 'embed.windy.com' && !isKmaTrack && !isJmaTrack && !isNhcTrack) { + return { success: false, error: `Only embed.windy.com, ${KMA_TYPHOON_TRACK_URL}, ${JMA_TYPHOON_MAP_URL}, or nhc.noaa.gov graphics_XXN.shtml URLs can be captured` }; } const waitMs = Math.min(Math.max(Number(args?.wait_ms) || 4000, 1000), 8000); @@ -1657,6 +1666,8 @@ export const weatherMapScreenshotTool = { const label = isKmaTrack ? 'KMA 태풍 예상진로 페이지 캡처 완료' + : isJmaTrack + ? 'JMA(RSMC 도쿄) 태풍 예상진로 지도 캡처 완료' : isNhcTrack ? 'NHC 허리케인 예상진로 페이지 캡처 완료' : `Windy 지도 캡처 완료 (overlay=${parsed.searchParams.get('overlay') || 'map'}, zoom=${parsed.searchParams.get('zoom') || '?'})`;