Rename RealTimeSearchTool → WeatherTool, fetch Balashikha weather via SearXNG
WeatherTool queries SearXNG with a fixed 'weather Balashikha Moscow now' query instead of passing the user message as-is. SearXNG has external internet access and returns snippets with actual current conditions. Direct wttr.in fetch not possible — deepagents container has no external internet routing. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
4
agent.py
4
agent.py
@@ -24,7 +24,7 @@ from langchain_core.tools import Tool
|
||||
from vram_manager import VRAMManager
|
||||
from router import Router
|
||||
from agent_factory import build_medium_agent, build_complex_agent
|
||||
from fast_tools import FastToolRunner, RealTimeSearchTool
|
||||
from fast_tools import FastToolRunner, WeatherTool
|
||||
import channels
|
||||
|
||||
# Bifrost gateway — all LLM inference goes through here
|
||||
@@ -121,7 +121,7 @@ _memory_search_tool = None
|
||||
|
||||
# Fast tools run before the LLM — classifier + context enricher
|
||||
_fast_tool_runner = FastToolRunner([
|
||||
RealTimeSearchTool(searxng_url=SEARXNG_URL),
|
||||
WeatherTool(searxng_url=SEARXNG_URL),
|
||||
])
|
||||
|
||||
# GPU mutex: one LLM inference at a time
|
||||
|
||||
@@ -35,55 +35,61 @@ class FastTool(ABC):
|
||||
async def run(self, message: str) -> str: ...
|
||||
|
||||
|
||||
class RealTimeSearchTool(FastTool):
|
||||
class WeatherTool(FastTool):
|
||||
"""
|
||||
Injects live SearXNG search snippets for queries that require real-time data:
|
||||
weather, news, prices, scores, business hours.
|
||||
Fetches current weather for the user's location (Balashikha, Moscow region)
|
||||
by querying SearXNG, which has external internet access.
|
||||
|
||||
Matched queries are also forced to medium tier by the Router so the richer
|
||||
model handles the injected context.
|
||||
Triggered by any weather-related query. The Router also forces medium tier
|
||||
when this tool matches so the richer model handles the injected data.
|
||||
"""
|
||||
|
||||
_PATTERN = re.compile(
|
||||
r"\b(weather|forecast|temperature|rain(ing)?|snow(ing)?|humidity|wind\s*speed"
|
||||
r"|today.?s news|breaking news|latest news|news today|current events"
|
||||
r"|bitcoin price|crypto price|stock price|exchange rate"
|
||||
r"|right now|currently|at the moment|live score|score now|score today"
|
||||
r"|open now|hours today|is .+ open)\b",
|
||||
r"|холодно|тепло|погода|прогноз погоды"
|
||||
r"|how (hot|cold|warm) is it|what.?s the (weather|temp)|dress for the weather)\b",
|
||||
re.IGNORECASE,
|
||||
)
|
||||
|
||||
# Fixed query — always fetch home location weather
|
||||
_SEARCH_QUERY = "weather Balashikha Moscow now"
|
||||
|
||||
def __init__(self, searxng_url: str):
|
||||
self._searxng_url = searxng_url
|
||||
|
||||
@property
|
||||
def name(self) -> str:
|
||||
return "real_time_search"
|
||||
return "weather"
|
||||
|
||||
def matches(self, message: str) -> bool:
|
||||
return bool(self._PATTERN.search(message))
|
||||
|
||||
async def run(self, message: str) -> str:
|
||||
"""Search SearXNG and return top snippets as a context block."""
|
||||
"""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": message, "format": "json"},
|
||||
params={"q": self._SEARCH_QUERY, "format": "json"},
|
||||
)
|
||||
r.raise_for_status()
|
||||
items = r.json().get("results", [])[:4]
|
||||
items = r.json().get("results", [])[:5]
|
||||
except Exception as e:
|
||||
return f"[real_time_search error: {e}]"
|
||||
return f"[weather error: {e}]"
|
||||
|
||||
if not items:
|
||||
return ""
|
||||
lines = [f"Live web search results for: {message}\n"]
|
||||
for i, item in enumerate(items, 1):
|
||||
|
||||
# Prefer results whose snippets contain actual current conditions
|
||||
lines = ["Current weather data for Balashikha, Moscow region:\n"]
|
||||
for item in items:
|
||||
snippet = item.get("content", "")
|
||||
title = item.get("title", "")
|
||||
url = item.get("url", "")
|
||||
snippet = item.get("content", "")[:400]
|
||||
lines.append(f"[{i}] {title}\nURL: {url}\n{snippet}\n")
|
||||
return "\n".join(lines)
|
||||
if snippet:
|
||||
lines.append(f"[{title}]\n{snippet}\nSource: {url}\n")
|
||||
|
||||
return "\n".join(lines) if len(lines) > 1 else ""
|
||||
|
||||
|
||||
class FastToolRunner:
|
||||
|
||||
Reference in New Issue
Block a user