0
# Function Tool Classes
1
2
Function tool classes wrap Python functions and provide methods for schema generation, parameter validation, and execution. They are typically created automatically by the `@beta_tool` and `@beta_async_tool` decorators but can also be instantiated directly for more control.
3
4
## Capabilities
5
6
### Synchronous Function Tool
7
8
Wrapper class for synchronous tool functions that handles schema generation, validation, and execution.
9
10
```python { .api }
11
class BetaFunctionTool:
12
"""
13
Synchronous function tool wrapper.
14
15
Wraps a Python function and provides:
16
- Automatic JSON schema generation from type hints
17
- Parameter validation using Pydantic
18
- Description extraction from docstrings
19
- Tool definition for Claude API
20
21
Attributes:
22
func: The wrapped function
23
name: Tool name sent to the API
24
description: Tool description
25
input_schema: JSON schema for tool parameters
26
"""
27
28
def __init__(
29
self,
30
func: Callable[..., str | Iterable[BetaContent]],
31
*,
32
name: str | None = None,
33
description: str | None = None,
34
input_schema: dict | type[BaseModel] | None = None
35
) -> None:
36
"""
37
Create a synchronous function tool.
38
39
Args:
40
func: The function to wrap (must be synchronous)
41
name: Custom tool name (defaults to func.__name__)
42
description: Tool description (defaults to func.__doc__)
43
input_schema: Custom JSON schema or Pydantic model for parameters
44
(defaults to auto-generated from function signature)
45
46
Raises:
47
RuntimeError: If used with Pydantic v1 (requires Pydantic v2)
48
"""
49
50
def to_dict(self) -> ToolParam:
51
"""
52
Convert tool to API parameter dictionary.
53
54
Returns:
55
Dictionary with name, description, and input_schema keys
56
suitable for passing to the messages.create() tools parameter
57
"""
58
59
def call(self, input: object) -> str | Iterable[BetaContent]:
60
"""
61
Execute the wrapped function with validated input.
62
63
Args:
64
input: Dictionary of parameters to pass to the function
65
66
Returns:
67
Function result as string or content blocks
68
69
Raises:
70
RuntimeError: If attempting to call an async function synchronously
71
TypeError: If input is not a dictionary
72
ValueError: If input fails validation
73
"""
74
75
@property
76
def __call__(self) -> Callable[..., str | Iterable[BetaContent]]:
77
"""
78
Access the wrapped function directly.
79
80
Returns:
81
The original function
82
"""
83
```
84
85
#### Usage Examples
86
87
**Direct instantiation:**
88
89
```python
90
from anthropic.lib.tools import BetaFunctionTool
91
92
def multiply(x: float, y: float) -> str:
93
"""Multiply two numbers.
94
95
Args:
96
x: First number
97
y: Second number
98
"""
99
return str(x * y)
100
101
# Create tool wrapper directly
102
multiply_tool = BetaFunctionTool(multiply)
103
104
# Use with Claude
105
tool_dict = multiply_tool.to_dict()
106
print(tool_dict)
107
# {
108
# "name": "multiply",
109
# "description": "Multiply two numbers.",
110
# "input_schema": {
111
# "type": "object",
112
# "properties": {
113
# "x": {"type": "number"},
114
# "y": {"type": "number"}
115
# },
116
# "required": ["x", "y"]
117
# }
118
# }
119
```
120
121
**Custom name and description:**
122
123
```python
124
def internal_calc(a: int, b: int) -> str:
125
return str(a + b)
126
127
tool = BetaFunctionTool(
128
internal_calc,
129
name="add_numbers",
130
description="Add two integers together"
131
)
132
```
133
134
**Custom schema with Pydantic:**
135
136
```python
137
from pydantic import BaseModel, Field
138
139
class EmailParams(BaseModel):
140
to: str = Field(description="Recipient email address")
141
subject: str = Field(description="Email subject line")
142
body: str = Field(description="Email body content")
143
cc: list[str] = Field(default_factory=list, description="CC recipients")
144
145
def send_email(to: str, subject: str, body: str, cc: list[str] = None) -> str:
146
"""Send an email."""
147
cc = cc or []
148
# Email sending logic
149
return f"Email sent to {to}"
150
151
email_tool = BetaFunctionTool(
152
send_email,
153
input_schema=EmailParams
154
)
155
```
156
157
**Manual tool execution:**
158
159
```python
160
from anthropic import Anthropic
161
162
# Create tool
163
@beta_tool
164
def get_time(timezone: str = "UTC") -> str:
165
"""Get current time in timezone.
166
167
Args:
168
timezone: IANA timezone name
169
"""
170
from datetime import datetime
171
import zoneinfo
172
tz = zoneinfo.ZoneInfo(timezone)
173
return datetime.now(tz).strftime("%Y-%m-%d %H:%M:%S")
174
175
client = Anthropic()
176
177
# First request
178
message = client.beta.messages.create(
179
model="claude-3-5-sonnet-20241022",
180
max_tokens=1024,
181
tools=[get_time.to_dict()],
182
messages=[{"role": "user", "content": "What time is it in Tokyo?"}]
183
)
184
185
# Extract and execute tool call
186
if message.stop_reason == "tool_use":
187
tool_use = next(block for block in message.content if block.type == "tool_use")
188
result = get_time.call(tool_use.input)
189
190
# Send result back to Claude
191
response = client.beta.messages.create(
192
model="claude-3-5-sonnet-20241022",
193
max_tokens=1024,
194
tools=[get_time.to_dict()],
195
messages=[
196
{"role": "user", "content": "What time is it in Tokyo?"},
197
{"role": "assistant", "content": message.content},
198
{
199
"role": "user",
200
"content": [
201
{
202
"type": "tool_result",
203
"tool_use_id": tool_use.id,
204
"content": result
205
}
206
]
207
}
208
]
209
)
210
print(response.content[0].text)
211
```
212
213
**Complex return types:**
214
215
```python
216
from anthropic.types.beta import BetaTextBlockParam
217
218
@beta_tool
219
def format_report(data: dict) -> list[BetaTextBlockParam]:
220
"""Format data as structured report.
221
222
Args:
223
data: Dictionary of report data
224
"""
225
return [
226
{"type": "text", "text": "# Report\n\n"},
227
{"type": "text", "text": f"Total: {data.get('total', 0)}\n"},
228
{"type": "text", "text": f"Status: {data.get('status', 'unknown')}"}
229
]
230
231
# Tool call returns multiple content blocks
232
result = format_report.call({"total": 100, "status": "complete"})
233
```
234
235
### Asynchronous Function Tool
236
237
Wrapper class for asynchronous tool functions that handles schema generation, validation, and async execution.
238
239
```python { .api }
240
class BetaAsyncFunctionTool:
241
"""
242
Asynchronous function tool wrapper.
243
244
Wraps an async Python function and provides the same features as
245
BetaFunctionTool but with async execution support.
246
247
Attributes:
248
func: The wrapped async function
249
name: Tool name sent to the API
250
description: Tool description
251
input_schema: JSON schema for tool parameters
252
"""
253
254
def __init__(
255
self,
256
func: Callable[..., Coroutine[Any, Any, str | Iterable[BetaContent]]],
257
*,
258
name: str | None = None,
259
description: str | None = None,
260
input_schema: dict | type[BaseModel] | None = None
261
) -> None:
262
"""
263
Create an asynchronous function tool.
264
265
Args:
266
func: The async function to wrap (must be defined with async def)
267
name: Custom tool name (defaults to func.__name__)
268
description: Tool description (defaults to func.__doc__)
269
input_schema: Custom JSON schema or Pydantic model for parameters
270
271
Raises:
272
RuntimeError: If used with Pydantic v1 (requires Pydantic v2)
273
"""
274
275
def to_dict(self) -> ToolParam:
276
"""
277
Convert tool to API parameter dictionary.
278
279
Returns:
280
Dictionary with name, description, and input_schema keys
281
"""
282
283
async def call(self, input: object) -> str | Iterable[BetaContent]:
284
"""
285
Execute the wrapped async function with validated input.
286
287
Args:
288
input: Dictionary of parameters to pass to the function
289
290
Returns:
291
Function result as string or content blocks
292
293
Raises:
294
RuntimeError: If attempting to call a sync function asynchronously
295
TypeError: If input is not a dictionary
296
ValueError: If input fails validation
297
"""
298
299
@property
300
def __call__(self) -> Callable[..., Coroutine[Any, Any, str | Iterable[BetaContent]]]:
301
"""
302
Access the wrapped async function directly.
303
304
Returns:
305
The original async function
306
"""
307
```
308
309
#### Usage Examples
310
311
**Basic async tool:**
312
313
```python
314
from anthropic.lib.tools import BetaAsyncFunctionTool
315
import httpx
316
317
async def fetch_url(url: str) -> str:
318
"""Fetch content from URL.
319
320
Args:
321
url: The URL to fetch
322
"""
323
async with httpx.AsyncClient() as client:
324
response = await client.get(url)
325
return response.text[:500]
326
327
# Create async tool
328
fetch_tool = BetaAsyncFunctionTool(fetch_url)
329
330
# Execute manually
331
result = await fetch_tool.call({"url": "https://example.com"})
332
```
333
334
**Async tool with database:**
335
336
```python
337
@beta_async_tool
338
async def save_to_db(table: str, data: dict) -> str:
339
"""Save data to database table.
340
341
Args:
342
table: Database table name
343
data: Data to save as key-value pairs
344
"""
345
# Using hypothetical async database library
346
async with db.transaction() as txn:
347
await txn.execute(f"INSERT INTO {table} VALUES (?)", data)
348
await txn.commit()
349
return f"Saved {len(data)} fields to {table}"
350
```
351
352
**Async tool with error handling:**
353
354
```python
355
@beta_async_tool
356
async def call_api(endpoint: str, params: dict = None) -> str:
357
"""Call external API endpoint.
358
359
Args:
360
endpoint: API endpoint path
361
params: Query parameters
362
"""
363
try:
364
async with httpx.AsyncClient() as client:
365
response = await client.get(
366
f"https://api.example.com/{endpoint}",
367
params=params or {}
368
)
369
response.raise_for_status()
370
return response.text
371
except httpx.HTTPError as e:
372
return f"API Error: {str(e)}"
373
```
374
375
**Manual async tool execution:**
376
377
```python
378
from anthropic import AsyncAnthropic
379
380
@beta_async_tool
381
async def async_computation(n: int) -> str:
382
"""Perform async computation.
383
384
Args:
385
n: Input number
386
"""
387
await asyncio.sleep(0.1) # Simulate work
388
return f"Result: {n * 2}"
389
390
client = AsyncAnthropic()
391
392
# Get tool use from Claude
393
message = await client.beta.messages.create(
394
model="claude-3-5-sonnet-20241022",
395
max_tokens=1024,
396
tools=[async_computation.to_dict()],
397
messages=[{"role": "user", "content": "Double the number 42"}]
398
)
399
400
# Execute async tool
401
if message.stop_reason == "tool_use":
402
tool_use = next(block for block in message.content if block.type == "tool_use")
403
result = await async_computation.call(tool_use.input)
404
print(result) # "Result: 84"
405
```
406
407
## Types
408
409
### Tool Parameter Schema
410
411
```python { .api }
412
class ToolParam(TypedDict):
413
"""
414
Tool definition for the API.
415
"""
416
name: str
417
description: str
418
input_schema: dict
419
```
420
421
### Input Schema Type
422
423
```python { .api }
424
InputSchema = dict
425
```
426
427
JSON schema dictionary or Pydantic model defining tool parameters.
428