Tools¶
Sonika AI Toolkit includes 18 built-in tools and supports custom tool creation via Pydantic.
Built-in Tools¶
Core File & System Tools¶
| Tool | Risk | Description |
|---|---|---|
RunBashTool |
2 | Execute shell commands (arbitrary code — always gated in ask mode) |
BashSafeTool |
1 | Restricted shell: rejects metacharacters (; \| & $ \ > <`…) and destructive binaries by basename. Risk-reduction, NOT a sandbox |
ReadFileTool |
1 | Read file contents (can exfiltrate any readable file into the model context) |
WriteFileTool |
1 | Write content to files |
ListDirTool |
0 | List directory contents |
DeleteFileTool |
2 | Delete files |
FindFileTool |
0 | Case-insensitive glob file search |
RunPythonTool |
2 | Execute Python code (arbitrary code — always gated in ask mode) |
All five file tools accept an optional root="/allowed/dir" constructor
kwarg: every path is realpath-resolved and must stay under root
(blocks ../ traversal and symlink escape). Without root the model can
touch any path the process can — including the orchestrator's own
MEMORY.md, whose contents are injected into future system prompts
(memory poisoning). Set root in any deployment handling untrusted input.
Network & API Tools¶
| Tool | Risk | Description |
|---|---|---|
CallApiTool |
1 | Make HTTP API calls |
SearchWebTool |
0 | Search the web (Serper API) |
FetchWebPageTool |
1 | Fetch and extract web page content |
EmailSMTPTool |
1 | Send emails via SMTP |
CallApiTool and FetchWebPageTool ship an SSRF guard: URLs whose host
resolves to loopback/private/link-local/reserved addresses (localhost, RFC1918
ranges, cloud metadata endpoints like 169.254.169.254) are rejected, and
redirects are followed manually so every hop is re-checked. Pass
allow_private_hosts=True at construction to call trusted internal hosts.
Secrets in tool args: values under keys matching
password/token/secret/api_key/authorization/credential are masked as "***"
in everything the orchestrator records (tools_executed, node_trace,
approval interrupts) — the tool itself still receives the real value. Prefer
sourcing credentials from env vars inside the tool over passing them as
LLM-visible arguments.
Risk gating: in mode="ask", any tool with risk > 0 requires approval via
a LangGraph interrupt. A tool that declares neither risk_level nor
risk_hint is treated as risk 1 (gated) — unclassified tools never bypass the
gate. In mode="auto" (the run/arun default) nothing is gated: only give
the bot tools you trust it to run unattended.
Database Tools¶
| Tool | Description |
|---|---|
SQLiteTool |
Query SQLite databases |
PostgreSQLTool |
Query PostgreSQL databases |
MySQLTool |
Query MySQL databases |
RedisTool |
Interact with Redis |
Integration Tools¶
| Tool | Description |
|---|---|
EmailTool |
Send emails (simplified) |
SaveContacto |
Save contact information |
Signal Tools (internal)¶
These tools perform no action — the agents intercept their calls and react to them. You never register them yourself:
| Tool | Registered by | Purpose |
|---|---|---|
ask_user |
enable_user_questions=True |
Structured questions to the caller (interrupt / BotResponse.questions) |
set_plan |
enable_planning=True (OrchestratorBot) |
Announce the structured execution plan |
update_step |
enable_planning=True (OrchestratorBot) |
Report per-step progress (running/done/skipped/error) |
Using Tools with Agents¶
from sonika_ai_toolkit import (
OrchestratorBot, OpenAILanguageModel,
RunBashTool, ReadFileTool, WriteFileTool, SearchWebTool,
)
llm = OpenAILanguageModel("sk-...", model_name="gpt-4o-mini")
bot = OrchestratorBot(
strong_model=llm,
fast_model=llm,
instructions="You are a helpful assistant.",
tools=[RunBashTool(), ReadFileTool(), WriteFileTool(), SearchWebTool()],
memory_path="/tmp/bot_memory",
)
result = bot.run("List all Python files in the current directory")
Creating Custom Tools¶
Define a custom tool using Pydantic for the argument schema:
from pydantic import BaseModel, Field
from langchain_core.tools import BaseTool
class WeatherInput(BaseModel):
city: str = Field(..., description="City name")
units: str = Field("celsius", description="Temperature units: celsius or fahrenheit")
class WeatherTool(BaseTool):
name: str = "get_weather"
description: str = "Get current weather for a city"
args_schema: type = WeatherInput
def _run(self, city: str, units: str = "celsius") -> str:
# Your implementation here
return f"Weather in {city}: 22°C, sunny"
# Use with any agent
bot = OrchestratorBot(strong_model=llm, fast_model=llm, instructions="...", tools=[WeatherTool()])
args_schema required
Tools must have an args_schema (Pydantic model) for the LLM to correctly generate parameters.
Tool Registry¶
from sonika_ai_toolkit.tools.registry import ToolRegistry
registry = ToolRegistry()
registry.register(WeatherTool())
registry.get("get_weather")
registry.list_tools()
# Get tool descriptions formatted for LLM prompts
descriptions = registry.get_tool_descriptions()