Tool Specs¶
ToolSpec and the @tool decorator wrap plain Python functions with typed metadata — name, description, and a JSON-schema parameter definition. Agents accept ToolSpec objects exactly like raw callables, and you can export them to provider tool-schema formats with one call.
Quick start¶
from brain.patterns import tool, ReActAgent
from brain.providers import LocalEchoProvider
@tool("Search local notes for relevant information")
def search(query: str) -> str:
return f"[results: {query}]"
# Drop straight into any agent — no changes needed
agent = ReActAgent(tools={"search": search}, provider=LocalEchoProvider())
result = agent.run("Summarize the AI safety notes")
@tool decorator¶
from brain.patterns import tool
# Minimal — infers parameter schema from type hints
PAGES = {
"local://handbook": "SecondBrain tools should be offline-safe by default.",
}
@tool("Fetch the contents of a local fixture page")
def fetch_page(url: str, max_chars: int = 2000) -> str:
return PAGES.get(url, "Not found")[:max_chars]
# Override with a hand-crafted schema
@tool("Execute a database query", parameters={
"type": "object",
"properties": {
"sql": {"type": "string", "description": "SQL SELECT statement"},
"limit": {"type": "integer", "description": "Row limit", "default": 100},
},
"required": ["sql"],
})
def run_query(sql: str, limit: int = 100) -> str:
return db.execute(sql, limit=limit)
# Custom name
@tool("Internal alias", name="my_tool")
def my_function(x: str) -> str:
return x
Type-hint → JSON-schema mapping:
| Python type | JSON schema type |
|---|---|
str |
"string" |
int |
"integer" |
float |
"number" |
bool |
"boolean" |
list |
"array" |
dict |
"object" |
| (no hint) | "string" |
Schema export¶
# Provider function-calling format
schema = search.to_openai_schema()
# {
# "type": "function",
# "function": {
# "name": "search",
# "description": "Search the web for current information",
# "parameters": {"type": "object", "properties": {"query": {"type": "string"}}, "required": ["query"]}
# }
# }
# Anthropic-compatible tool-use format
schema = search.to_anthropic_schema()
# {"name": "search", "description": "...", "input_schema": {...}}
Bulk helpers¶
from brain.patterns import tools_to_dict, tools_to_openai_schemas
specs = [search, fetch_page, run_query]
# Convert to {name: callable} dict for agents
tools_dict = tools_to_dict(specs)
agent = ReActAgent(tools=tools_dict)
# Export all schemas for a provider payload
schemas = tools_to_openai_schemas(specs)
assert schemas[0]["type"] == "function"
ToolSpec direct construction¶
from brain.patterns import ToolSpec
calculator = ToolSpec(
name="calculator",
fn=lambda expr: str(eval(expr)),
description="Evaluate arithmetic expressions",
parameters={
"type": "object",
"properties": {"expr": {"type": "string"}},
"required": ["expr"],
},
)
print(calculator("2 + 2")) # "4"
print(calculator.to_openai_schema()) # {...}
Full example: ReAct with typed tools¶
from pathlib import Path
from brain.patterns import ReActAgent, tool, tools_to_dict
from brain.providers import LocalEchoProvider
@tool("Search local notes")
def local_search(query: str) -> str:
notes = {
"transformer": "Transformer architectures use attention over token sequences.",
"rag": "RAG combines retrieval with generation.",
}
return notes.get(query.lower(), "Not found")
@tool("Read a file from the filesystem")
def read_file(path: str) -> str:
return Path(path).read_text()
@tool("Look up a fact in the knowledge base")
def kb_lookup(topic: str, namespace: str = "global") -> str:
return knowledge_base.get(namespace, {}).get(topic, "Not found")
agent = ReActAgent(
tools=tools_to_dict([local_search, read_file, kb_lookup]),
provider=LocalEchoProvider(),
)
result = agent.run("Summarize transformer architecture notes")
print(result.answer)
API Reference¶
brain.patterns.tools.ToolSpec
dataclass
¶
A callable tool with typed metadata.
Attributes:
| Name | Type | Description |
|---|---|---|
name |
str
|
Unique identifier used by the agent (e.g. |
fn |
Callable[..., Any]
|
The underlying Python callable. |
description |
str
|
Human-readable description shown to the LLM. |
parameters |
dict[str, Any]
|
JSON-schema |
__call__
¶
to_openai_schema
¶
Return an OpenAI / Anthropic function-calling schema dict.
Compatible with openai.ChatCompletion tools parameter and
Anthropic tools parameter.
Returns:
| Type | Description |
|---|---|
dict[str, Any]
|
dict with keys |
dict[str, Any]
|
parameters). |
Source code in brain/patterns/tools.py
to_anthropic_schema
¶
Return an Anthropic tool-use schema dict.
Returns:
| Type | Description |
|---|---|
dict[str, Any]
|
dict with keys |
Source code in brain/patterns/tools.py
to_dict
¶
Plain dict representation (useful for JSON serialisation).
brain.patterns.tools.tool
¶
tool(description: str, *, name: str | None = None, parameters: dict[str, Any] | None = None) -> Callable[[Callable[..., Any]], ToolSpec]
Decorator that wraps a function as a :class:ToolSpec.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
description
|
str
|
Human-readable description shown to the LLM. |
required |
name
|
str | None
|
Override the tool name (default: function |
None
|
parameters
|
dict[str, Any] | None
|
Override the JSON-schema |
None
|
Returns:
| Name | Type | Description |
|---|---|---|
A |
Callable[[Callable[..., Any]], ToolSpec]
|
class: |
Example::
@tool("Search the web for current information")
def search(query: str) -> str:
return requests.get(f"https://api.search.com?q={query}").text
@tool("Look up a value in the database", parameters={
"type": "object",
"properties": {"key": {"type": "string"}},
"required": ["key"],
})
def db_lookup(key: str) -> str:
return db[key]
Source code in brain/patterns/tools.py
brain.patterns.tools.tools_to_dict
¶
tools_to_dict(specs: list[ToolSpec]) -> dict[str, Callable[..., Any]]
Convert a list of ToolSpecs to the {name: callable} dict that
agents accept.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
specs
|
list[ToolSpec]
|
List of :class: |
required |
Returns:
| Type | Description |
|---|---|
dict[str, Callable[..., Any]]
|
Dict mapping tool name → callable. |
Source code in brain/patterns/tools.py
brain.patterns.tools.tools_to_openai_schemas
¶
tools_to_openai_schemas(specs: list[ToolSpec]) -> list[dict[str, Any]]
Convert a list of ToolSpecs to OpenAI function-calling schemas.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
specs
|
list[ToolSpec]
|
List of :class: |
required |
Returns:
| Type | Description |
|---|---|
list[dict[str, Any]]
|
List of OpenAI-compatible schema dicts. |