If you've used pydantic-ai, you already know
the feeling: it's the first agent framework that feels like a regular
Python library. Typed RunContext, a clean FunctionToolset protocol,
model providers swapped behind one string. After a decade of frameworks
that pretended to be Pythonic, this one actually is.
And then you sit down to wire up your agent, and realize: pydantic-ai will happily call any tool you give it — but the tools themselves are still on you. Want the agent to read a file? You write the sandbox. Run a SQL query? You write the read-only guard and the schema introspection. Search local documents? Text splitter, vector index, cosine math, persistence — all you.
After the third project where you wrote those by hand, the shape stops being interesting. This is them, written once:
pip install pydantic-ai-toolboxfrom pydantic_ai import Agent
from pydantic_ai_toolbox import (
FilesystemToolset, SQLToolset, PandasToolset, MemoryToolset, RAGToolset,
)
agent = Agent(
"openai:gpt-4o-mini",
toolsets=[
FilesystemToolset(root="./workspace", read_only=False),
SQLToolset(dsn="postgresql://user:pwd@localhost/app"),
PandasToolset(),
MemoryToolset(storage_path="./memory.json"),
RAGToolset(embedder=my_embedder),
],
system_prompt="You are a data assistant.",
)
print(agent.run_sync("Read README.md from the workspace and summarise it.").output)That's the whole story. Five toolsets, one toolsets=[...], no new
framework on top of pydantic-ai — each toolset is a thin
FunctionToolset subclass, exactly what pydantic-ai expects.
Each toolset in isolation — runnable against a local/remote Ollama, no API keys:
- Filesystem — Example Create / Read / Append / Delete files
- SQL — Example INSERT, UPDATE, SELECT via SQLite
- Pandas — Example load a CSV, count rows by condition
- Memory — Example three-turn conversation with persisted facts
- RAG — Example retrieve-then-answer, override the model prior
- Quickstart — Example minimal one-tool smoke test
pip install pydantic-ai-toolboxThe base install gives you FilesystemToolset and MemoryToolset
(stdlib only). The rest are opt-in so you only pull in what you use:
pip install "pydantic-ai-toolbox[sql]" # + SQLAlchemy
pip install "pydantic-ai-toolbox[pandas]" # + pandas + pyarrow
pip install "pydantic-ai-toolbox[rag]" # + numpy
pip install "pydantic-ai-toolbox[all]" # everythingExtras are independent — picking up one doesn't pull in the others. Details: docs/INSTALL.md.
| Toolset | What an agent can do with it | Docs |
|---|---|---|
FilesystemToolset |
List, read, write, append, delete, mkdir, stat, glob — under one sandbox root, with path-escape rejection and an optional read-only mode. | docs/FILESYSTEM.md |
SQLToolset |
List tables/views, describe schemas, run parameterised reads, optional execute for writes. Single-statement read-only by default. |
docs/SQL.md |
PandasToolset |
Manage a named dataframe registry; load CSV/Parquet; head / describe / schema / query / aggregate / value_counts. | docs/PANDAS.md |
MemoryToolset |
Append/read/search messages; key-value scratchpad facts; optional atomic JSON persistence and per-namespace isolation. | docs/MEMORY.md |
RAGToolset |
Recursive character text splitter + in-memory numpy vector index with cosine search and per-document delete. | docs/RAG.md |
Tiny snippets to taste each one:
# Filesystem — sandbox a workspace, then let the agent edit files
FilesystemToolset(root="./workspace", read_only=False)
# SQL — read-only Postgres
SQLToolset(dsn="postgresql://user:pwd@localhost/app")
# Pandas — start with an empty registry, agent loads CSVs as needed
PandasToolset()
# Memory — persisted scratchpad, 200-message cap
MemoryToolset(storage_path="./memory.json", max_messages=200)
# RAG — bring your own embedder
RAGToolset(embedder=lambda texts: [embed(t) for t in texts])Runnable end-to-end scripts live in examples/ (see docs/EXAMPLES.md).
Before reaching for a toolset here, check whether pydantic-ai already
ships the capability you need — most of the time it does:
| Need | Use this |
|---|---|
| Web search | pydantic_ai.common_tools.{duckduckgo, exa, tavily} or native_tools.WebSearchTool |
| Fetch a page and convert to Markdown | pydantic_ai.common_tools.web_fetch.web_fetch_tool |
| Provider-side code execution / image gen | pydantic_ai.native_tools.{CodeExecutionTool, ImageGenerationTool, FileSearchTool} |
| Provider-managed long-term memory | pydantic_ai.native_tools.MemoryTool |
| Third-party MCP server (fs, postgres, …) | pydantic_ai.mcp.MCPServerStdio / MCPServerHTTP |
This package fills the gaps that aren't on that list — local sandboxed filesystem access, generic SQL via SQLAlchemy, in-memory dataframe ops, self-hosted conversation memory, and local RAG without an external vector DB.
A toolset is a BaseToolset subclass whose public methods carry @tool:
from pydantic_ai_toolbox import BaseToolset, tool
class WeatherToolset(BaseToolset):
"""Look up current weather for a configurable provider."""
def __init__(self, api_key: str, units: str = "metric") -> None:
self.api_key = api_key
self.units = units
super().__init__() # MUST be last — scans @tool methods
@tool
def current_temperature(self, city: str) -> float:
"""Return the current temperature for `city` in the configured units."""
...Full rules, schema-mapping table, and the contribution checklist: docs/CUSTOM.md, AGENTS.md.
pip install git+https://github.com/wachawo/pydantic-ai-toolkits.gitgit clone git@github.com:wachawo/pydantic-ai-toolbox.git
cd pydantic-ai-toolbox
python3 -m venv .venv
source .venv/bin/activate
pip install -e ".[all]"
pip install -r requirements-dev.txt
pytest --cov # 80% coverage gateRendered with MkDocs at docs/:
- Overview
- Install
- Toolsets: Filesystem, SQL, Pandas, Memory, RAG
- Write your own
- Examples
- Building the docs site
- Changelog
If something's off — a missing convenience method, an awkward signature, a default that doesn't match your use case — the API is intentionally small. Open an issue on GitHub and say what you'd want instead.
MIT.