-- plugins/weather.lua-- Weather plugin using wttr.in (no API key required).-- Accepts a location (city name, airport code, zip, coordinates, etc.)-- and returns current conditions.clm.tool_register("get_weather", { description = [[Get current weather for a location using wttr.in.If the user does not specify a location or just asks for the weather, use the empty string "".Accepts city names, airport codes (3 letters), zip/area codes,or GPS coordinates (e.g. '-78.46,106.79').]], params_schema = { type = "object", properties = { location = { type = "string", description = "city name, airport code, zip code, or " .. "GPS coordinates", }, }, required = { "location" }, }, timeout_ms = 15000, invoke = function(args, ctx) local loc = args.location or "" if loc ~= "" then loc = string.gsub(loc, " ", "+") end local url = "https://wttr.in/" .. loc .. "?format=j1" local resp, err = http.get(url) if err then ctx:fail("HTTP request failed: " .. err) return end if resp.status ~= 200 then ctx:fail("wttr.in returned status " .. tostring(resp.status)) return end local data = json.decode(resp.body) if not data or not data.current_condition then ctx:fail("unexpected response format from wttr.in") return end local cc = data.current_condition[1] if not cc then ctx:fail("no current_condition in response") return end -- Extract the weather description text. local desc = "unknown" if cc.weatherDesc and cc.weatherDesc[1] then desc = cc.weatherDesc[1].value or "unknown" end -- Get the human-readable location name. The JSON API returns -- junk areaNames for IP queries, but format=%l always works. local area = args.location local loc_url = "https://wttr.in/" .. loc .. "?format=%l" local lr, lerr = http.get(loc_url) if lr and lr.status == 200 and lr.body and lr.body ~= "" then -- Trim trailing whitespace/newline. area = string.gsub(lr.body, "%s+$", "") end local result = string.format( "%s: %s\n" .. "Temperature: %s°F (feels like %s°F)\n" .. "Wind: %s mph %s\n" .. "Humidity: %s%%\n" .. "Cloud cover: %s%%\n" .. "Visibility: %s miles", area, desc, cc.temp_F or "?", cc.FeelsLikeF or "?", cc.windspeedMiles or "?", cc.winddir16Point or "", cc.humidity or "?", cc.cloudcover or "?", cc.visibilityMiles or "?") ctx:complete(result) end,})
-- plugins/weather.lua
-- Weather plugin using wttr.in (no API key required).
-- Accepts a location (city name, airport code, zip, coordinates, etc.)
-- and returns current conditions.
clm.tool_register("get_weather", {
description = [[
Get current weather for a location using wttr.in.
If the user does not specify a location or just asks for the weather, use the empty string "".
Accepts city names, airport codes (3 letters), zip/area codes,
or GPS coordinates (e.g. '-78.46,106.79').]],
params_schema = {
type = "object",
properties = {
location = {
type = "string",
description = "city name, airport code, zip code, or "
.. "GPS coordinates",
},
},
required = { "location" },
},
timeout_ms = 15000,
invoke = function(args, ctx)
local loc = args.location or ""
if loc ~= "" then
loc = string.gsub(loc, " ", "+")
end
local url = "https://wttr.in/" .. loc .. "?format=j1"
local resp, err = http.get(url)
if err then
ctx:fail("HTTP request failed: " .. err)
return
end
if resp.status ~= 200 then
ctx:fail("wttr.in returned status " .. tostring(resp.status))
return
end
local data = json.decode(resp.body)
if not data or not data.current_condition then
ctx:fail("unexpected response format from wttr.in")
return
end
local cc = data.current_condition[1]
if not cc then
ctx:fail("no current_condition in response")
return
end
-- Extract the weather description text.
local desc = "unknown"
if cc.weatherDesc and cc.weatherDesc[1] then
desc = cc.weatherDesc[1].value or "unknown"
end
-- Get the human-readable location name. The JSON API returns
-- junk areaNames for IP queries, but format=%l always works.
local area = args.location
local loc_url = "https://wttr.in/" .. loc .. "?format=%l"
local lr, lerr = http.get(loc_url)
if lr and lr.status == 200 and lr.body and lr.body ~= "" then
-- Trim trailing whitespace/newline.
area = string.gsub(lr.body, "%s+$", "")
end
local result = string.format(
"%s: %s\n"
.. "Temperature: %s°F (feels like %s°F)\n"
.. "Wind: %s mph %s\n"
.. "Humidity: %s%%\n"
.. "Cloud cover: %s%%\n"
.. "Visibility: %s miles",
area, desc,
cc.temp_F or "?", cc.FeelsLikeF or "?",
cc.windspeedMiles or "?", cc.winddir16Point or "",
cc.humidity or "?",
cc.cloudcover or "?",
cc.visibilityMiles or "?")
ctx:complete(result)
end,
})