feat: add web search tool using SearXNG

Add WebSearchTool that queries the self-hosted SearXNG metasearch engine
for current information, documentation, and facts beyond training data.

- Add SEARXNG_URL and SEARXNG_TIMEOUT config settings
- Create WebSearchTool with query, num_results, categories params
- Register web_search tool with explore agent
- Add 10 tests for search functionality

Usage: Agents can now use web_search(query="...") to find current info.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
2026-01-11 14:09:21 +01:00
co-authored by Claude Opus 4.5
parent f6256363a2
commit 82a816a5b5
6 changed files with 434 additions and 2 deletions
@@ -11,6 +11,7 @@ from src.domains.tools.file.glob import GlobFilesTool
from src.domains.tools.file.edit import EditFileTool
from src.domains.tools.file.write import WriteFileTool
from src.domains.tools.search.grep import GrepContentTool
from src.domains.tools.search.web import WebSearchTool
from src.domains.tools.shell.bash import BashReadOnlyTool
from src.domains.tools.shell.bash_full import BashTool
@@ -271,3 +272,42 @@ def register_explore_tools(agent: Agent[AgentContext, str]) -> None:
timeout=min(timeout, ctx.deps.timeout_seconds)
)
return result.to_string()
# === Web search ===
@agent.tool
async def web_search(
ctx: RunContext[AgentContext],
query: str,
num_results: int = 5,
categories: str | None = None
) -> str:
"""Search the web for current information.
Args:
query: Search query (e.g., "Python 3.12 new features")
num_results: Number of results to return (1-10, default: 5)
categories: Optional category filter ("general", "it", "news", "science")
Returns:
Search results with titles, URLs, and snippets.
Use this for:
- Current events or recent information
- Documentation updates since your training
- Facts you're uncertain about
- Technical references with URLs
IMPORTANT: Always include a "Sources:" section with URLs in your response.
Examples:
- query="FastAPI best practices 2024"
- query="CVE-2024" categories="it"
"""
tool = WebSearchTool()
result = await tool.execute(
query=query,
num_results=num_results,
categories=categories
)
return result.to_string()