Function Calling
Build AI agents that can use tools and take actions
Overview
Function calling (also called tool use) allows AI models to call functions you define, enabling agents that can query databases, call APIs, execute code, and take real-world actions.
Authentication: API Key or OAuth token
Required Scopes (OAuth): ai:chat
Capabilities
- External APIs - Weather, search, databases, third-party services
- Code Execution - Run calculations and data processing
- Actions - Send emails, create tasks, update records
- Real-time Data - Access current information beyond training cutoff
- Multi-step Agents - Chain multiple tool calls for complex workflows
Supported Models
Define and Call Functions
Create a chat completion with available tools.
Endpoint: POST /api/v1/chat/completions
import OpenAI from 'openai'
const client = new OpenAI({
apiKey: process.env.GATEWAY_API_KEY,
baseURL: 'https://hypery.ai/api/v1'
})
// Step 1: Define tools
const tools = [
{
type: 'function',
function: {
name: 'get_weather',
description: 'Get current weather for a city',
parameters: {
type: 'object',
properties: {
location: {
type: 'string',
description: 'City name (e.g., "Paris, FR")'
},
unit: {
type: 'string',
enum: ['celsius', 'fahrenheit']
}
},
required: ['location']
}
}
}
]
// Step 2: Ask the model
const response = await client.chat.completions.create({
model: 'anthropic/claude-3.5-sonnet',
messages: [
{ role: 'user', content: 'What is the weather in Paris?' }
],
tools
})
// Step 3: Check for tool calls
const toolCall = response.choices[0].message.tool_calls?.[0]
if (toolCall) {
const args = JSON.parse(toolCall.function.arguments)
console.log('Calling:', toolCall.function.name, args)
// Step 4: Execute your function
const weather = await getWeather(args.location)
// Step 5: Send result back
const final = await client.chat.completions.create({
model: 'anthropic/claude-3.5-sonnet',
messages: [
{ role: 'user', content: 'What is the weather in Paris?' },
response.choices[0].message,
{
role: 'tool',
tool_call_id: toolCall.id,
content: JSON.stringify(weather)
}
],
tools
})
console.log(final.choices[0].message.content)
}from openai import OpenAI
import json
client = OpenAI(
api_key="your-api-key",
base_url="https://hypery.ai/api/v1"
)
# Step 1: Define tools
tools = [
{
"type": "function",
"function": {
"name": "get_weather",
"description": "Get current weather for a city",
"parameters": {
"type": "object",
"properties": {
"location": {
"type": "string",
"description": "City name (e.g., 'Paris, FR')"
},
"unit": {
"type": "string",
"enum": ["celsius", "fahrenheit"]
}
},
"required": ["location"]
}
}
}
]
# Step 2: Ask the model
response = client.chat.completions.create(
model="anthropic/claude-3.5-sonnet",
messages=[
{"role": "user", "content": "What is the weather in Paris?"}
],
tools=tools
)
# Step 3: Check for tool calls
tool_call = response.choices[0].message.tool_calls[0] if response.choices[0].message.tool_calls else None
if tool_call:
args = json.loads(tool_call.function.arguments)
print(f"Calling: {tool_call.function.name}", args)
# Step 4: Execute your function
weather = get_weather(args["location"])
# Step 5: Send result back
final = client.chat.completions.create(
model="anthropic/claude-3.5-sonnet",
messages=[
{"role": "user", "content": "What is the weather in Paris?"},
response.choices[0].message,
{
"role": "tool",
"tool_call_id": tool_call.id,
"content": json.dumps(weather)
}
],
tools=tools
)
print(final.choices[0].message.content)# Step 1: Initial request with tools
curl https://hypery.ai/api/v1/chat/completions \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "anthropic/claude-3.5-sonnet",
"messages": [
{"role": "user", "content": "What is the weather in Paris?"}
],
"tools": [
{
"type": "function",
"function": {
"name": "get_weather",
"description": "Get current weather",
"parameters": {
"type": "object",
"properties": {
"location": {"type": "string"}
},
"required": ["location"]
}
}
}
]
}'
# Response includes tool_calls array
# Execute function, then send result back:
curl https://hypery.ai/api/v1/chat/completions \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "anthropic/claude-3.5-sonnet",
"messages": [
{"role": "user", "content": "What is the weather in Paris?"},
{
"role": "assistant",
"tool_calls": [
{
"id": "call_123",
"type": "function",
"function": {
"name": "get_weather",
"arguments": "{\"location\":\"Paris\"}"
}
}
]
},
{
"role": "tool",
"tool_call_id": "call_123",
"content": "{\"temp\":18,\"condition\":\"cloudy\"}"
}
],
"tools": [...]
}'Input Parameters
Tool Definition
Each tool must include:
Response when function is called:
{
"id": "chatcmpl-123",
"choices": [
{
"index": 0,
"message": {
"role": "assistant",
"content": null,
"tool_calls": [
{
"id": "call_abc123",
"type": "function",
"function": {
"name": "get_weather",
"arguments": "{\"location\":\"Paris\",\"unit\":\"celsius\"}"
}
}
]
},
"finish_reason": "tool_calls"
}
]
}Output Fields
Tool Choice
Control whether and how the model uses tools.
// Auto (default) - Model decides
await client.chat.completions.create({
model: 'anthropic/claude-3.5-sonnet',
messages: [{ role: 'user', content: 'Hello' }],
tools,
tool_choice: 'auto'
})
// Required - Must call a tool
await client.chat.completions.create({
model: 'anthropic/claude-3.5-sonnet',
messages: [{ role: 'user', content: 'Get weather' }],
tools,
tool_choice: 'required'
})
// None - Never call tools
await client.chat.completions.create({
model: 'anthropic/claude-3.5-sonnet',
messages: [{ role: 'user', content: 'Just chat' }],
tools,
tool_choice: 'none'
})
// Specific function
await client.chat.completions.create({
model: 'anthropic/claude-3.5-sonnet',
messages: [{ role: 'user', content: 'Search' }],
tools,
tool_choice: {
type: 'function',
function: { name: 'search_web' }
}
})# Auto (default) - Model decides
client.chat.completions.create(
model="anthropic/claude-3.5-sonnet",
messages=[{"role": "user", "content": "Hello"}],
tools=tools,
tool_choice="auto"
)
# Required - Must call a tool
client.chat.completions.create(
model="anthropic/claude-3.5-sonnet",
messages=[{"role": "user", "content": "Get weather"}],
tools=tools,
tool_choice="required"
)
# None - Never call tools
client.chat.completions.create(
model="anthropic/claude-3.5-sonnet",
messages=[{"role": "user", "content": "Just chat"}],
tools=tools,
tool_choice="none"
)
# Specific function
client.chat.completions.create(
model="anthropic/claude-3.5-sonnet",
messages=[{"role": "user", "content": "Search"}],
tools=tools,
tool_choice={
"type": "function",
"function": {"name": "search_web"}
}
)# Auto (default)
curl https://hypery.ai/api/v1/chat/completions \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"model": "anthropic/claude-3.5-sonnet", "messages": [...], "tools": [...], "tool_choice": "auto"}'
# Required
curl https://hypery.ai/api/v1/chat/completions \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"model": "anthropic/claude-3.5-sonnet", "messages": [...], "tools": [...], "tool_choice": "required"}'
# None
curl https://hypery.ai/api/v1/chat/completions \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"model": "anthropic/claude-3.5-sonnet", "messages": [...], "tools": [...], "tool_choice": "none"}'Tool Choice Options
Multiple Tools
Define multiple tools and let the model choose:
const tools = [
{
type: 'function',
function: {
name: 'get_weather',
description: 'Get weather for a location',
parameters: {
type: 'object',
properties: {
location: { type: 'string' }
},
required: ['location']
}
}
},
{
type: 'function',
function: {
name: 'search_web',
description: 'Search the web',
parameters: {
type: 'object',
properties: {
query: { type: 'string' }
},
required: ['query']
}
}
},
{
type: 'function',
function: {
name: 'calculate',
description: 'Perform math calculations',
parameters: {
type: 'object',
properties: {
expression: { type: 'string' }
},
required: ['expression']
}
}
}
]
const response = await client.chat.completions.create({
model: 'anthropic/claude-3.5-sonnet',
messages: [
{ role: 'user', content: 'What is the weather in Tokyo and 42 * 17?' }
],
tools
})
// Model may call multiple tools
for (const toolCall of response.choices[0].message.tool_calls || []) {
console.log(`Calling: ${toolCall.function.name}`)
}tools = [
{
"type": "function",
"function": {
"name": "get_weather",
"description": "Get weather for a location",
"parameters": {
"type": "object",
"properties": {
"location": {"type": "string"}
},
"required": ["location"]
}
}
},
{
"type": "function",
"function": {
"name": "search_web",
"description": "Search the web",
"parameters": {
"type": "object",
"properties": {
"query": {"type": "string"}
},
"required": ["query"]
}
}
},
{
"type": "function",
"function": {
"name": "calculate",
"description": "Perform math calculations",
"parameters": {
"type": "object",
"properties": {
"expression": {"type": "string"}
},
"required": ["expression"]
}
}
}
]
response = client.chat.completions.create(
model="anthropic/claude-3.5-sonnet",
messages=[
{"role": "user", "content": "What is the weather in Tokyo and 42 * 17?"}
],
tools=tools
)
# Model may call multiple tools
for tool_call in response.choices[0].message.tool_calls or []:
print(f"Calling: {tool_call.function.name}")Agent Loop
Build autonomous agents that call multiple tools:
async function runAgent(userMessage) {
const messages = [{ role: 'user', content: userMessage }]
const maxIterations = 10
for (let i = 0; i < maxIterations; i++) {
const response = await client.chat.completions.create({
model: 'anthropic/claude-3.5-sonnet',
messages,
tools
})
const message = response.choices[0].message
messages.push(message)
// Check if model called tools
if (message.tool_calls?.length > 0) {
// Execute all tool calls
for (const toolCall of message.tool_calls) {
const args = JSON.parse(toolCall.function.arguments)
const result = await executeFunction(toolCall.function.name, args)
messages.push({
role: 'tool',
tool_call_id: toolCall.id,
content: JSON.stringify(result)
})
}
} else {
// No more tools, return final answer
return message.content
}
}
throw new Error('Max iterations reached')
}
async function executeFunction(name, args) {
switch (name) {
case 'get_weather':
return await getWeather(args.location)
case 'search_web':
return await searchWeb(args.query)
case 'calculate':
return { result: eval(args.expression) }
default:
throw new Error(`Unknown function: ${name}`)
}
}
// Use it
const answer = await runAgent('What is the weather in Paris and Rome?')
console.log(answer)async def run_agent(user_message):
messages = [{"role": "user", "content": user_message}]
max_iterations = 10
for i in range(max_iterations):
response = client.chat.completions.create(
model="anthropic/claude-3.5-sonnet",
messages=messages,
tools=tools
)
message = response.choices[0].message
messages.append(message)
# Check if model called tools
if message.tool_calls:
# Execute all tool calls
for tool_call in message.tool_calls:
args = json.loads(tool_call.function.arguments)
result = execute_function(tool_call.function.name, args)
messages.append({
"role": "tool",
"tool_call_id": tool_call.id,
"content": json.dumps(result)
})
else:
# No more tools, return final answer
return message.content
raise Exception("Max iterations reached")
def execute_function(name, args):
if name == "get_weather":
return get_weather(args["location"])
elif name == "search_web":
return search_web(args["query"])
elif name == "calculate":
return {"result": eval(args["expression"])}
else:
raise Exception(f"Unknown function: {name}")
# Use it
answer = run_agent("What is the weather in Paris and Rome?")
print(answer)Parameter Schema
Define parameters using JSON Schema:
{
type: 'object',
properties: {
location: {
type: 'string',
description: 'City name and country (e.g., "Paris, FR")'
},
unit: {
type: 'string',
enum: ['celsius', 'fahrenheit', 'kelvin'],
description: 'Temperature unit'
},
include_forecast: {
type: 'boolean',
description: 'Include 5-day forecast'
}
},
required: ['location'] // Required parameters
}Supported Types
Best Practices
Write Clear Descriptions
// ❌ Bad
{
name: 'get_data',
description: 'Gets data'
}
// ✅ Good
{
name: 'get_weather',
description: 'Get current weather conditions including temperature, humidity, wind speed, and forecast for a specific city'
}Use Enums for Limited Options
{
unit: {
type: 'string',
enum: ['celsius', 'fahrenheit', 'kelvin'],
description: 'Temperature unit'
}
}Validate Arguments
const toolCall = response.choices[0].message.tool_calls?.[0]
if (toolCall) {
try {
const args = JSON.parse(toolCall.function.arguments)
// Validate types and required fields
if (!args.location || typeof args.location !== 'string') {
throw new Error('Invalid location parameter')
}
const result = await getWeather(args.location)
} catch (error) {
console.error('Function call error:', error)
}
}Provide Examples in Descriptions
{
location: {
type: 'string',
description: 'City and country code (e.g., "London, UK" or "Tokyo, JP")'
}
}Common Use Cases
Database Query
{
type: 'function',
function: {
name: 'query_customers',
description: 'Search customer database by email or name',
parameters: {
type: 'object',
properties: {
email: { type: 'string', description: 'Customer email' },
name: { type: 'string', description: 'Customer name' }
}
}
}
}API Integration
{
type: 'function',
function: {
name: 'create_ticket',
description: 'Create a support ticket',
parameters: {
type: 'object',
properties: {
title: { type: 'string' },
priority: {
type: 'string',
enum: ['low', 'medium', 'high', 'urgent']
}
},
required: ['title']
}
}
}File Operations
{
type: 'function',
function: {
name: 'read_file',
description: 'Read file contents from workspace',
parameters: {
type: 'object',
properties: {
path: {
type: 'string',
description: 'File path relative to workspace root'
}
},
required: ['path']
}
}
}