WeatherTool: fetch open-meteo directly, skip LLM for fast tool replies
- Replace SearXNG search with direct open-meteo.com API call (no key needed) - WeatherTool now returns a ready-to-deliver reply string - agent.py: short-circuit router+LLM when fast tools return a result (tier=fast) - router.py: fast tool match no longer triggers light reply generation Weather latency: 105-190s → ~1s Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -35,13 +35,22 @@ class FastTool(ABC):
|
||||
async def run(self, message: str) -> str: ...
|
||||
|
||||
|
||||
_WMO_CODES = {
|
||||
0: "clear sky", 1: "mainly clear", 2: "partly cloudy", 3: "overcast",
|
||||
45: "fog", 48: "icy fog",
|
||||
51: "light drizzle", 53: "drizzle", 55: "heavy drizzle",
|
||||
61: "light rain", 63: "rain", 65: "heavy rain",
|
||||
71: "light snow", 73: "snow", 75: "heavy snow", 77: "snow grains",
|
||||
80: "light showers", 81: "showers", 82: "heavy showers",
|
||||
85: "snow showers", 86: "heavy snow showers",
|
||||
95: "thunderstorm", 96: "thunderstorm with hail", 99: "thunderstorm with heavy hail",
|
||||
}
|
||||
|
||||
|
||||
class WeatherTool(FastTool):
|
||||
"""
|
||||
Fetches current weather for the user's location (Balashikha, Moscow region)
|
||||
by querying SearXNG, which has external internet access.
|
||||
|
||||
Triggered by any weather-related query. The Router also forces medium tier
|
||||
when this tool matches so the richer model handles the injected data.
|
||||
Fetches current weather for Balashikha, Moscow region directly from open-meteo.com.
|
||||
No API key required. Returns a ready-to-deliver reply — no LLM reformatting needed.
|
||||
"""
|
||||
|
||||
_PATTERN = re.compile(
|
||||
@@ -51,11 +60,13 @@ class WeatherTool(FastTool):
|
||||
re.IGNORECASE,
|
||||
)
|
||||
|
||||
# Fixed query — always fetch home location weather
|
||||
_SEARCH_QUERY = "погода Балашиха сейчас" # Russian query → Celsius sources
|
||||
|
||||
def __init__(self, searxng_url: str):
|
||||
self._searxng_url = searxng_url
|
||||
_URL = (
|
||||
"https://api.open-meteo.com/v1/forecast"
|
||||
"?latitude=55.7963&longitude=37.9382"
|
||||
"¤t=temperature_2m,apparent_temperature,relative_humidity_2m"
|
||||
",wind_speed_10m,weather_code"
|
||||
"&wind_speed_unit=ms"
|
||||
)
|
||||
|
||||
@property
|
||||
def name(self) -> str:
|
||||
@@ -65,31 +76,24 @@ class WeatherTool(FastTool):
|
||||
return bool(self._PATTERN.search(message))
|
||||
|
||||
async def run(self, message: str) -> str:
|
||||
"""Query SearXNG for Balashikha weather and return current conditions snippet."""
|
||||
try:
|
||||
async with httpx.AsyncClient(timeout=15) as client:
|
||||
r = await client.get(
|
||||
f"{self._searxng_url}/search",
|
||||
params={"q": self._SEARCH_QUERY, "format": "json"},
|
||||
)
|
||||
async with httpx.AsyncClient(timeout=10) as client:
|
||||
r = await client.get(self._URL)
|
||||
r.raise_for_status()
|
||||
items = r.json().get("results", [])[:5]
|
||||
c = r.json()["current"]
|
||||
except Exception as e:
|
||||
return f"[weather error: {e}]"
|
||||
|
||||
if not items:
|
||||
return ""
|
||||
temp = c["temperature_2m"]
|
||||
feels = c["apparent_temperature"]
|
||||
humidity = c["relative_humidity_2m"]
|
||||
wind = c["wind_speed_10m"]
|
||||
condition = _WMO_CODES.get(c.get("weather_code", 0), "unknown")
|
||||
|
||||
# Prefer results whose snippets contain actual current conditions
|
||||
lines = ["Current weather data for Balashikha, Moscow region (temperatures in °C):\n"]
|
||||
for item in items:
|
||||
snippet = item.get("content", "")
|
||||
title = item.get("title", "")
|
||||
url = item.get("url", "")
|
||||
if snippet:
|
||||
lines.append(f"[{title}]\n{snippet}\nSource: {url}\n")
|
||||
|
||||
return "\n".join(lines) if len(lines) > 1 else ""
|
||||
return (
|
||||
f"Balashikha: {condition}, {temp:+.0f}°C (feels like {feels:+.0f}°C), "
|
||||
f"wind {wind:.1f} m/s, humidity {humidity}%."
|
||||
)
|
||||
|
||||
|
||||
class CommuteTool(FastTool):
|
||||
|
||||
Reference in New Issue
Block a user