Tools
Plain Python tools available to AI agents.
Tools in HyperSaaS are plain Python functions with no framework-specific decorators. Each agent handler wraps them for its own runtime.
Available Tools
| Tool | File | Description |
|---|---|---|
| Web Search | chat/tools/web_search.py | Search Google through SerpApi |
| Weather | chat/tools/weather.py | Get current weather via WeatherAPI.com |
| Location | chat/tools/location.py | Find a place's coordinates via the Google Geocoding API |
| Knowledge Base | documents/rag_tool.py | Search attached knowledge bases (RAG) |
| URL Ingest | documents/url_ingest_tool.py | Ingest content from a URL |
Tool Architecture
Tools are defined as plain functions in chat/tools/:
# chat/tools/weather.py
def get_weather(location: str) -> str:
"""Get current weather for a location."""
# Pure Python — no @tool decorator, no framework imports
response = requests.get(WEATHER_API_URL, params={"q": location, "key": API_KEY})
return response.json()Each handler wraps them differently:
LangGraph (in chat/handlers/langgraph/tools.py):
from langchain_core.tools import tool
from backend.chat.tools.weather import get_weather as get_weather_impl
@tool
def get_weather(location: str) -> str:
"""Get current weather for a location."""
return get_weather_impl(location)PydanticAI (in chat/handlers/pydantic_ai/agent.py):
@agent.tool_plain
def get_weather(location: str) -> str:
"""Get current weather for a location."""
return get_weather_impl(location)Tool registration in the LangGraph wrapper module is guarded by except ImportError blocks that log a warning naming the disabled tool — a broken dependency degrades that one capability visibly instead of silently removing it from every agent session.
Knowledge Base Search Tool
The RAG tool is special — it needs access to the chat session to know which knowledge bases to search:
# documents/rag_tool.py
def search_knowledge_base_impl(query: str, session) -> str:
"""Pure function — no framework dependency."""
results = search_documents(
query=query,
session_id=str(session.id),
workspace_id=str(session.workspace_id),
)
return json.dumps(results)The LangGraph wrapper uses InjectedToolArg to inject the session at runtime:
@tool
def search_knowledge_base(
query: str,
config: Annotated[RunnableConfig, InjectedToolArg],
) -> str:
session = config["configurable"]["session"]
return search_knowledge_base_impl(query, session)Knowledge-Base Questions
When a chat has knowledge bases attached, the LangGraph agent's first step for each question is a knowledge-base search, made by the graph rather than left to the model. Models told to search still answer questions that look like general knowledge from memory. On the benchmark, every answer graded below 4 out of 5 was one where the agent had skipped the search. Answers must cite the results they used.
Agent Limits
An agent run stops after 10 steps (recursion_limit), so one message can't loop through tools indefinitely. Tool results reach the model marked as untrusted data.
Paid Tools and Credit
Web search, location and weather call paid APIs. Each call that returns an answer is recorded as AIUsage with purpose tool_call, at a fixed price per call, against the chat's workspace and the person asking. Both agent frameworks record under the LangGraph tools' names:
# workspaces/usage.py
TOOL_CALL_PRICES = {
"google_search_serp_api_tool": Decimal("0.015"), # SerpApi Developer: $75 for 5,000 searches
"get_location_coordinates": Decimal("0.005"), # Google Geocoding API: $5 per 1,000 requests
"get_weather_forecast": Decimal("0.0001"), # WeatherAPI.com
}A call that comes back with an error (a missing key, bad input, an outage) costs nothing. Change the prices to match your plans. The knowledge-base search records its own model calls (rewriting, embedding, reranking) as it runs.
Adding a New Tool
- Create
chat/tools/your_tool.pywith a plain Python function - Add the LangChain wrapper in
chat/handlers/langgraph/tools.py - Add the PydanticAI wrapper in
chat/handlers/pydantic_ai/agent.py - Update the system prompt in
chat/handlers/langgraph/nodes.pyto describe the tool - If it calls a paid API, add its price to
TOOL_CALL_PRICES, keyed by the tool's name
Required API Keys
| Tool | Environment Variable |
|---|---|
| Web Search | SERPAPI_API_KEY |
| Weather | WEATHERAPI_COM_API_KEY |
| Location | GOOGLE_MAPS_API_KEY |
| Knowledge Base | OPENAI_API_KEY (for embeddings) |