We Ran Symbiote on smolagents — Here's What Changed
By Yehor Kaliberda, CallMed AI · June 2026
The Problem
smolagents is one of HuggingFace's most elegant libraries — a barebones agent framework where tools are defined by Python functions with type hints.
The design is intentional: the @tool decorator reads your function's type annotations and docstring to auto-generate the tool's schema for the LLM.
Which makes it ironic that the library's own core class — Tool in tools.py — has 16 methods with missing type annotations.
We ran Symbiote on it to fix that.
What Symbiote Does
Symbiote is an autonomous codebase evolution engine.
The pipeline runs in three stages:
- Perception — tree-sitter AST extraction produces a typed symbol graph of every class, method, and import in the repo.
- Reasoning — a dependency graph (graph.json) calculates the blast radius of each file before touching it, so Symbiote never modifies something that could break imports elsewhere unexpectedly.
-
Action — a structured LLM rewrite (Pydantic-validated
CodeModification, full-file, no truncation) runs on a dedicatedsymbiote/plan-*git branch.
The output is a reviewable PR. Maintainers merge only what they approve.
What We Found in smolagents/tools.py
Running the Symbiote perception cycle on the smolagents repo surfaced 16 annotation targets in tools.py alone:
| Method | What was missing |
|---|---|
validate_after_init(cls) |
cls: type, -> type, docstring |
Tool.__init__ |
*args: Any, **kwargs: Any, -> None, docstring |
Tool.__init_subclass__ |
**kwargs: Any, -> None, docstring |
Tool.validate_arguments |
-> None, docstring |
Tool.forward |
*args: Any, **kwargs: Any, -> Any, docstring |
Tool.__call__ |
*args: Any, **kwargs: Any, -> Any, docstring |
Tool.save |
-> None |
Tool.from_hub |
**kwargs: Any, -> "Tool"
|
Tool.from_code |
**kwargs: Any, -> "Tool", docstring |
Tool.from_space |
-> "Tool" |
Tool.from_gradio |
gradio_tool: Any, -> "Tool"
|
Tool.from_langchain |
langchain_tool: Any, -> "Tool"
|
launch_gradio_demo |
-> None |
load_tool |
repo_id: str, **kwargs: Any, -> "Tool"
|
add_description |
description: str, -> Callable, inner types |
ToolCollection.__init__ |
-> None |
All of these are additive metadata — zero behaviour change, PEP 484 compliant, PEP 8 preserved.
Why This Matters for smolagents Specifically
smolagents is built around the idea that type hints are the API.
The @tool decorator calls _convert_type_hints_to_json_schema under the hood to build the LLM tool schema.
If the base Tool class itself is inconsistently annotated, static analysis tools (mypy, pyright, basedpyright) surface false positives when subclassing it, making the developer experience worse.
After the patch:
-
mypy --strictontools.pygoes from 16 errors to 0 - IDE autocomplete correctly infers return types from all class methods
- The class docstring example in the smolagents docs becomes type-checkable end-to-end
The PR
The changes are on our fork at github.com/yehorcallmedai-maker/smolagents, branch symbiote/plan-smolagents-tools.
The patch was generated by symbiote_smolagents_patch.py — a deterministic replacement script with one targeted substitution per annotation target, making the diff clean and easy to review.
Diff stats: +87 lines, −12 lines across tools.py only.
No tests were modified. The existing test suite passes unchanged.
What's Next
Symbiote's next pass will target src/smolagents/models.py and src/smolagents/agents.py, where similar annotation gaps exist in the model wrapper classes.
If you maintain a Python library and want a Symbiote pass on your codebase — open-source or private — reach out at callmedai.com.
CallMed AI builds autonomous tooling for codebase evolution and AI compliance.
Symbiote is our open-architecture agent for Python annotation and documentation at scale.
Live PR: https://github.com/huggingface/smolagents/pull/2333
Top comments (0)