72 lines
2.3 KiB
Python
Executable File
72 lines
2.3 KiB
Python
Executable File
"""
|
|
Web Search Tool
|
|
Uses DuckDuckGo for free web search (no API key needed).
|
|
"""
|
|
from typing import Dict, Any, Optional
|
|
from duckduckgo_search import DDGS
|
|
from loguru import logger
|
|
|
|
from tools.base import BaseTool, ToolResult
|
|
|
|
|
|
class WebSearchTool(BaseTool):
|
|
"""Web search using DuckDuckGo."""
|
|
|
|
@property
|
|
def name(self) -> str:
|
|
return "web_search"
|
|
|
|
@property
|
|
def description(self) -> str:
|
|
return "Search the web for current information. Use this for recent events, news, or topics not in your training data."
|
|
|
|
@property
|
|
def parameters(self) -> Dict[str, Any]:
|
|
return {
|
|
"type": "object",
|
|
"properties": {
|
|
"query": {
|
|
"type": "string",
|
|
"description": "The search query"
|
|
},
|
|
"max_results": {
|
|
"type": "integer",
|
|
"description": "Maximum number of results to return (default: 5)",
|
|
"default": 5
|
|
}
|
|
},
|
|
"required": ["query"]
|
|
}
|
|
|
|
async def execute(self, query: str, max_results: int = 5, **kwargs) -> ToolResult:
|
|
"""Execute web search."""
|
|
self._log_execution({"query": query, "max_results": max_results})
|
|
|
|
try:
|
|
with DDGS() as ddgs:
|
|
results = list(ddgs.text(query, max_results=max_results))
|
|
|
|
if not results:
|
|
return ToolResult(
|
|
success=True,
|
|
data="No search results found."
|
|
)
|
|
|
|
# Format results
|
|
formatted_results = []
|
|
for i, result in enumerate(results, 1):
|
|
formatted_results.append(
|
|
f"{i}. {result.get('title', 'No title')}\n"
|
|
f" {result.get('body', 'No description')}\n"
|
|
f" Source: {result.get('href', 'No URL')}"
|
|
)
|
|
|
|
output = f"Web search results for '{query}':\n\n" + "\n\n".join(formatted_results)
|
|
|
|
self._log_success(output[:100])
|
|
return ToolResult(success=True, data=output)
|
|
|
|
except Exception as e:
|
|
self._log_error(str(e))
|
|
return ToolResult(success=False, error=str(e))
|