Implementation:Anthropics Anthropic sdk python Beta Tool Decorator
| Knowledge Sources | |
|---|---|
| Domains | Tool_Use, LLM, Function_Calling |
| Last Updated | 2026-02-15 00:00 GMT |
Overview
The beta_tool decorator converts a Python function into a BetaFunctionTool with automatic JSON Schema inference from type annotations, docstring extraction, and Pydantic-based input validation. It supports both bare (@beta_tool) and parameterized (@beta_tool(name=...)) usage patterns.
API Signature
def beta_tool(
func: FunctionT | None = None,
*,
name: str | None = None,
description: str | None = None,
input_schema: InputSchema | type[BaseModel] | None = None,
defer_loading: bool | None = None,
) -> BetaFunctionTool[FunctionT] | Callable[[FunctionT], BetaFunctionTool[FunctionT]]
Source Location
File: src/anthropic/lib/tools/_beta_functions.py, lines 205-265
Import
from anthropic import beta_tool
Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
func |
None | None |
The function to wrap. Provided implicitly when using bare @beta_tool syntax.
|
name |
None | None |
Override the tool name. Defaults to func.__name__.
|
description |
None | None |
Override the tool description. Defaults to the docstring's short + long description. |
input_schema |
type[BaseModel] | None | None |
Override the input schema. Can be a JSON Schema dict or a Pydantic BaseModel class. Defaults to auto-inference from type hints. |
defer_loading |
None | None |
When set, adds defer_loading to the tool definition sent to the API.
|
Return Value
Returns a BetaFunctionTool[FunctionT] instance (when func is provided) or a Callable[[FunctionT], BetaFunctionTool[FunctionT]] decorator (when called with keyword arguments only).
The BetaFunctionTool class provides:
| Method/Property | Type | Description |
|---|---|---|
.to_dict() |
BetaToolParam |
Produces the API-ready tool definition dict with name, description, and input_schema
|
.call(input) |
BetaFunctionToolResultType |
Executes the wrapped function with validated input |
.name |
str |
The tool's name |
.description |
str |
The tool's description |
.input_schema |
InputSchema |
The JSON Schema dict for the tool's parameters |
.func |
FunctionT |
Reference to the original wrapped function |
Overload Variants
The function uses three @overload signatures (lines 205-226):
# Bare decorator: @beta_tool
@overload
def beta_tool(func: FunctionT) -> BetaFunctionTool[FunctionT]: ...
# Direct call with func: beta_tool(my_func, name="custom")
@overload
def beta_tool(
func: FunctionT,
*,
name: str | None = None,
description: str | None = None,
input_schema: InputSchema | type[BaseModel] | None = None,
) -> BetaFunctionTool[FunctionT]: ...
# Parameterized decorator: @beta_tool(name="custom")
@overload
def beta_tool(
*,
name: str | None = None,
description: str | None = None,
input_schema: InputSchema | type[BaseModel] | None = None,
defer_loading: bool | None = None,
) -> Callable[[FunctionT], BetaFunctionTool[FunctionT]]: ...
Auto-Inference Pipeline
When defaults are used, the tool metadata is inferred as follows:
Name: From func.__name__ (line 88):
self.name = name or func.__name__
Description: From the docstring via docstring_parser (lines 119-126):
def _get_description_from_docstring(self) -> str:
if self._parsed_docstring.short_description:
description = self._parsed_docstring.short_description
if self._parsed_docstring.long_description:
description += f"\n\n{self._parsed_docstring.long_description}"
return description
return ""
Schema: Via Pydantic TypeAdapter with a custom GenerateJsonSchema subclass that enriches property descriptions from docstring Args: sections (lines 128-170).
Usage Examples
Bare decorator (all metadata inferred):
from anthropic import beta_tool
@beta_tool
def get_weather(city: str, unit: str = "celsius") -> str:
"""Get the current weather for a city.
Args:
city: The city name
unit: Temperature unit (celsius or fahrenheit)
"""
return f"The weather in {city} is 22 degrees {unit}"
Parameterized decorator:
@beta_tool(name="weather_lookup", description="Fetch current weather data")
def get_weather(city: str) -> str:
return f"The weather in {city} is 22 degrees"
Using the tool object:
# Get the API-ready dict
tool_dict = get_weather.to_dict()
# {'name': 'get_weather', 'description': 'Get the current weather...', 'input_schema': {...}}
# Pass to messages.create
message = client.messages.create(
model="claude-sonnet-4-20250514",
max_tokens=1024,
tools=[get_weather.to_dict()],
messages=[{"role": "user", "content": "What's the weather in London?"}]
)
Async Variant
For asynchronous functions, use beta_async_tool (lines 268-337):
from anthropic import beta_async_tool
@beta_async_tool
async def get_weather(city: str) -> str:
"""Get the current weather for a city."""
async with httpx.AsyncClient() as client:
resp = await client.get(f"https://weather.example.com/{city}")
return resp.text
This returns a BetaAsyncFunctionTool whose .call() method is a coroutine.
Dependencies
- pydantic (v2 required):
validate_call,TypeAdapter,BaseModel,GenerateJsonSchema - docstring_parser: Parses Google/NumPy/reStructuredText docstring formats to extract parameter descriptions
- typing_extensions: For
TypeAlias,override
Error Conditions
| Error | Condition |
|---|---|
RuntimeError("Tool functions are only supported with Pydantic v2") |
Raised at decoration time if Pydantic v1 is installed |
ValueError("Invalid arguments for function {name}") |
Raised by .call() when input fails Pydantic validation
|
TypeError("Input must be a dictionary, got {type}") |
Raised by .call() when input is not a dict
|
RuntimeError("Cannot call a coroutine function synchronously...") |
Raised by BetaFunctionTool.call() when the wrapped function is async
|