Tool Calling
Use function calling and tool use with the Token101 API
Tool Calling
Tool calling (also called function calling) lets you define functions that the model can invoke. Instead of the model generating text for everything, it can return structured calls to your code — and you handle the actual execution.
Token101 supports tool calling on both the Anthropic Messages API and the OpenAI Chat Completions API.
How Tool Calling Works
- You send a request with a list of tool definitions (name, description, parameters)
- The model decides whether to call a tool based on the user's request
- If the model calls a tool, it returns a tool call instead of (or alongside) text
- Your code executes the tool and sends the result back to the model
- The model generates a final response using the tool result
Anthropic Messages API
Define tools
Tools are passed in a tools array. Each tool has a name, description, and input_schema.
import anthropic
import os
client = anthropic.Anthropic(
api_key=os.environ.get("TOKEN101_API_KEY"),
base_url="https://token.ppthub.shop/api",
)
tools = [
{
"name": "get_weather",
"description": "Get the current weather for a given city.",
"input_schema": {
"type": "object",
"properties": {
"city": {
"type": "string",
"description": "The city name, e.g. San Francisco"
},
"unit": {
"type": "string",
"enum": ["celsius", "fahrenheit"],
"description": "Temperature unit"
}
},
"required": ["city"]
}
}
]
response = client.messages.create(
model="gpt-5.2",
max_tokens=1024,
tools=tools,
messages=[
{"role": "user", "content": "What's the weather in Tokyo?"}
]
)
print(response.stop_reason) # "tool_use" if a tool was called
print(response.content)Handle tool calls
When stop_reason is "tool_use", iterate over content blocks to find tool calls:
import json
def get_weather(city: str, unit: str = "celsius") -> dict:
# Your actual implementation here
return {"city": city, "temperature": 22, "unit": unit, "condition": "sunny"}
# First turn — model decides to call a tool
response = client.messages.create(
model="gpt-5.2",
max_tokens=1024,
tools=tools,
messages=[{"role": "user", "content": "What's the weather in Tokyo?"}]
)
# Collect tool calls
tool_calls = [block for block in response.content if block.type == "tool_use"]
if tool_calls:
# Execute all tool calls
tool_results = []
for tool_call in tool_calls:
if tool_call.name == "get_weather":
result = get_weather(**tool_call.input)
tool_results.append({
"type": "tool_result",
"tool_use_id": tool_call.id,
"content": json.dumps(result, ensure_ascii=False)
})
# Second turn — send results back
final_response = client.messages.create(
model="gpt-5.2",
max_tokens=1024,
tools=tools,
messages=[
{"role": "user", "content": "What's the weather in Tokyo?"},
{"role": "assistant", "content": response.content},
{"role": "user", "content": tool_results}
]
)
print(final_response.content[0].text)Node.js / TypeScript
import Anthropic from '@anthropic-ai/sdk';
const client = new Anthropic({
apiKey: process.env.TOKEN101_API_KEY,
baseURL: 'https://token.ppthub.shop/api',
});
const tools: Anthropic.Tool[] = [
{
name: 'get_weather',
description: 'Get the current weather for a city.',
input_schema: {
type: 'object' as const,
properties: {
city: { type: 'string', description: 'The city name' },
},
required: ['city'],
},
},
];
const response = await client.messages.create({
model: 'gpt-5.2',
max_tokens: 1024,
tools,
messages: [{ role: 'user', content: "What's the weather in Paris?" }],
});
for (const block of response.content) {
if (block.type === 'tool_use') {
console.log(`Tool called: ${block.name}`);
console.log('Input:', block.input);
}
}Tool calling with streaming
Tool results are delivered as content_block_delta events of type input_json_delta:
with client.messages.stream(
model="gpt-5.2",
max_tokens=1024,
tools=tools,
messages=[{"role": "user", "content": "What's the weather in London?"}],
) as stream:
for event in stream:
if hasattr(event, 'type'):
if event.type == 'content_block_start' and hasattr(event, 'content_block'):
if event.content_block.type == 'tool_use':
print(f"Tool: {event.content_block.name}")OpenAI Chat Completions API
Define tools
from openai import OpenAI
import os
import json
client = OpenAI(
api_key=os.environ.get("TOKEN101_API_KEY"),
base_url="https://token.ppthub.shop/api/v1",
)
tools = [
{
"type": "function",
"function": {
"name": "get_weather",
"description": "Get the current weather for a city.",
"parameters": {
"type": "object",
"properties": {
"city": {
"type": "string",
"description": "The city name"
},
"unit": {
"type": "string",
"enum": ["celsius", "fahrenheit"]
}
},
"required": ["city"]
}
}
}
]
response = client.chat.completions.create(
model="gpt-5.2",
messages=[{"role": "user", "content": "What's the weather in Tokyo?"}],
tools=tools,
tool_choice="auto" # let the model decide
)
message = response.choices[0].message
print(message.tool_calls) # list of tool calls, or NoneHandle tool calls
def get_weather(city: str, unit: str = "celsius") -> dict:
return {"city": city, "temperature": 22, "unit": unit, "condition": "sunny"}
messages = [{"role": "user", "content": "What's the weather in Tokyo?"}]
# First turn
response = client.chat.completions.create(
model="gpt-5.2",
messages=messages,
tools=tools,
tool_choice="auto"
)
assistant_message = response.choices[0].message
messages.append(assistant_message) # add assistant response to history
if assistant_message.tool_calls:
for tool_call in assistant_message.tool_calls:
args = json.loads(tool_call.function.arguments)
if tool_call.function.name == "get_weather":
result = get_weather(**args)
# Append tool result
messages.append({
"role": "tool",
"tool_call_id": tool_call.id,
"content": json.dumps(result, ensure_ascii=False)
})
# Second turn — get final response
final_response = client.chat.completions.create(
model="gpt-5.2",
messages=messages,
tools=tools
)
print(final_response.choices[0].message.content)Node.js / TypeScript
import OpenAI from 'openai';
const client = new OpenAI({
apiKey: process.env.TOKEN101_API_KEY,
baseURL: 'https://token.ppthub.shop/api/v1',
});
const tools: OpenAI.ChatCompletionTool[] = [
{
type: 'function',
function: {
name: 'get_weather',
description: 'Get the current weather for a city.',
parameters: {
type: 'object',
properties: {
city: { type: 'string' },
},
required: ['city'],
},
},
},
];
const response = await client.chat.completions.create({
model: 'gpt-5.2',
messages: [{ role: 'user', content: "What's the weather in Paris?" }],
tools,
tool_choice: 'auto',
});
const message = response.choices[0].message;
if (message.tool_calls) {
for (const toolCall of message.tool_calls) {
console.log(`Tool: ${toolCall.function.name}`);
console.log('Args:', JSON.parse(toolCall.function.arguments));
}
}Tool calling with streaming
const stream = await client.chat.completions.create({
model: 'gpt-5.2',
messages: [{ role: 'user', content: "What's the weather in London?" }],
tools,
stream: true,
});
let toolCallAccumulator = '';
for await (const chunk of stream) {
const delta = chunk.choices[0]?.delta;
if (delta?.tool_calls) {
for (const toolCall of delta.tool_calls) {
if (toolCall.function?.arguments) {
toolCallAccumulator += toolCall.function.arguments;
}
}
}
}
if (toolCallAccumulator) {
const args = JSON.parse(toolCallAccumulator);
console.log('Tool arguments:', args);
}Tool Calling Reference
Anthropic tool fields
| Field | Type | Description |
|---|---|---|
name | string | Tool name (snake_case recommended) |
description | string | What the tool does — the model uses this to decide when to call it |
input_schema | object | JSON Schema for the tool's input parameters |
OpenAI tool fields
| Field | Type | Description |
|---|---|---|
type | "function" | Always "function" |
function.name | string | Function name |
function.description | string | What the function does |
function.parameters | object | JSON Schema for parameters |
tool_choice / tool_use options
| Value | Behavior |
|---|---|
"auto" (OpenAI) | Model decides whether to call a tool |
"required" (OpenAI) | Model must call at least one tool |
{"type": "none"} (OpenAI) | Disable tool calling |
{"type": "auto"} (Anthropic) | Model decides (default) |
{"type": "any"} (Anthropic) | Must call at least one tool |
{"type": "tool", "name": "..."} (Anthropic) | Must call specific tool |
Best Practices
Write clear descriptions — the model relies on descriptions to decide when to call each tool. Be specific about what inputs are expected and what the tool returns.
Handle errors gracefully — tool calls can fail. Always wrap your tool execution in try/catch and return meaningful error messages back to the model.
Validate inputs — even though you define the schema, models may occasionally send unexpected values. Validate inputs before executing tools.
Limit tool count — having too many tools can reduce accuracy. For complex systems, consider exposing only the tools relevant to the current task.
Use parallel tool calls — both Anthropic and OpenAI models can call multiple tools in a single response. Handle all tool calls before sending results back.
Next Steps
- Streaming — combine tool calling with streaming responses
- Supported Models — see which models support tool calling
- API Reference — full endpoint documentation