Introduce FastTools: pre-flight classifier + context enrichment
New fast_tools.py module: - FastTool base class (matches + run interface) - RealTimeSearchTool: SearXNG search for weather/news/prices/scores - FastToolRunner: classifier that checks all tools, runs matching ones concurrently and returns combined context Router accepts FastToolRunner; any_matches() forces medium tier before LLM classification (replaces _MEDIUM_FORCE_PATTERNS regex). agent.py: _REALTIME_RE and _searxng_search_async removed; pre-flight gather now includes fast_tool_runner.run_matching() alongside URL fetch and memory retrieval. To add a new fast tool: subclass FastTool, add to the list in agent.py. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
21
router.py
21
router.py
@@ -1,6 +1,7 @@
|
||||
import re
|
||||
from typing import Optional
|
||||
from langchain_core.messages import SystemMessage, HumanMessage
|
||||
from fast_tools import FastToolRunner
|
||||
|
||||
# ── Regex pre-classifier ──────────────────────────────────────────────────────
|
||||
# Catches obvious light-tier patterns before calling the LLM.
|
||||
@@ -23,16 +24,6 @@ _LIGHT_PATTERNS = re.compile(
|
||||
re.IGNORECASE,
|
||||
)
|
||||
|
||||
# Queries that require live data — never answer from static knowledge
|
||||
_MEDIUM_FORCE_PATTERNS = re.compile(
|
||||
r"\b(weather|forecast|temperature|rain(ing)?|snow(ing)?|humidity|wind speed"
|
||||
r"|today.?s news|breaking news|latest news|news today|current events"
|
||||
r"|bitcoin price|crypto price|stock price|exchange rate|usd|eur|btc"
|
||||
r"|right now|currently|at the moment|live score|score now|score today"
|
||||
r"|open now|hours today|is .+ open)\b",
|
||||
re.IGNORECASE,
|
||||
)
|
||||
|
||||
# ── LLM classification prompt ─────────────────────────────────────────────────
|
||||
CLASSIFY_PROMPT = """Classify the message. Output ONLY one word: light, medium, or complex.
|
||||
|
||||
@@ -83,8 +74,9 @@ def _parse_tier(text: str) -> str:
|
||||
|
||||
|
||||
class Router:
|
||||
def __init__(self, model):
|
||||
def __init__(self, model, fast_tool_runner: FastToolRunner | None = None):
|
||||
self.model = model
|
||||
self._fast_tool_runner = fast_tool_runner
|
||||
|
||||
async def route(
|
||||
self,
|
||||
@@ -100,9 +92,10 @@ class Router:
|
||||
if force_complex:
|
||||
return "complex", None
|
||||
|
||||
# Step 0a: force medium for real-time / live-data queries
|
||||
if _MEDIUM_FORCE_PATTERNS.search(message.strip()):
|
||||
print(f"[router] regex→medium (real-time query)", flush=True)
|
||||
# Step 0a: force medium if any fast tool matches (live-data queries)
|
||||
if self._fast_tool_runner and self._fast_tool_runner.any_matches(message.strip()):
|
||||
names = self._fast_tool_runner.matching_names(message.strip())
|
||||
print(f"[router] fast_tool_match={names} → medium", flush=True)
|
||||
return "medium", None
|
||||
|
||||
# Step 0b: regex pre-classification for obvious light patterns
|
||||
|
||||
Reference in New Issue
Block a user