Core
Tool calls
Functions on the chat completions endpoint, the full cycle of a tool call, and the models that accept tools. Messages and Responses use their own tool format.
On /v1/chat/completions, send tools and, if necessary, tool_choice. The two fields have the
OpenAI format, and we send them to the model.
tools = [{
"type": "function",
"function": {
"name": "get_weather",
"description": "Current weather for a city.",
"parameters": {
"type": "object",
"properties": {"city": {"type": "string"}},
"required": ["city"],
},
},
}]
reply = client.chat.completions.create(
model="claude-sonnet-5-5",
messages=[{"role": "user", "content": "What is the weather in Nairobi?"}],
tools=tools,
)
call = reply.choices[0].message.tool_calls[0]
print(call.function.name, call.function.arguments)When the model asks for a tool, finish_reason is tool_calls and content is empty. This means
that the model wants you to run the function.
Send the result back
Add the message of the model to the conversation. Then add a message with role: "tool" and the
tool_call_id of the call:
messages = [
{"role": "user", "content": "What is the weather in Nairobi?"},
reply.choices[0].message,
{
"role": "tool",
"tool_call_id": call.id,
"content": '{"temp_c": 24, "conditions": "clear"}',
},
]
final = client.chat.completions.create(model="claude-sonnet-5-5", messages=messages, tools=tools)
print(final.choices[0].message.content)Models that accept tools
Look at supported_parameters in GET /v1/models, or at the table on Models. If you
send tools to a model that does not show tools, you get a 400 error that names the parameter. We
do not charge for that request.
Tool calls in a stream
Tool calls also come in a stream. delta.tool_calls has an index, and the arguments come in small
parts. The last frame has finish_reason: "tool_calls". The SDKs join the parts for you. See
Streams.
Messages and Responses
On /v1/messages and /v1/responses, use the tool format of Anthropic or of OpenAI Responses. We send
your tools to the model as you wrote them.