Enable AI models to invoke custom functions and interact with external APIs through powerful function calling capabilities. Build sophisticated applications that perform actions, retrieve data, and integrate with existing systems.
import { AnimusClient } from 'animus-client';
const tools = [
{
type: "function",
function: {
name: "get_weather",
description: "Get the current weather for a specific location",
parameters: {
type: "object",
properties: {
location: {
type: "string",
description: "The city and state, e.g. San Francisco, CA"
},
unit: {
type: "string",
enum: ["celsius", "fahrenheit"],
description: "The temperature unit to use"
}
},
required: ["location"]
}
}
},
{
type: "function",
function: {
name: "calculate_tip",
description: "Calculate tip amount based on bill total and tip percentage",
parameters: {
type: "object",
properties: {
bill_amount: {
type: "number",
description: "The total bill amount"
},
tip_percentage: {
type: "number",
description: "The tip percentage (e.g., 15 for 15%)"
}
},
required: ["bill_amount", "tip_percentage"]
}
}
}
];
const client = new AnimusClient({
tokenProviderUrl: 'https://your-backend.com/api/get-animus-token',
chat: {
model: 'vivian-llama3.1-70b-1.0-fp8',
systemMessage: 'You are a helpful assistant with access to various tools.'
}
});
// Tool function implementations
async function getWeather(location: string, unit: string = 'fahrenheit') {
// Simulate API call to weather service
const weatherData = {
location,
temperature: unit === 'celsius' ? 22 : 72,
condition: 'Sunny',
humidity: 45,
unit
};
return {
location: weatherData.location,
temperature: `${weatherData.temperature}°${unit === 'celsius' ? 'C' : 'F'}`,
condition: weatherData.condition,
humidity: `${weatherData.humidity}%`
};
}
function calculateTip(billAmount: number, tipPercentage: number) {
const tipAmount = (billAmount * tipPercentage) / 100;
const total = billAmount + tipAmount;
return {
bill_amount: billAmount,
tip_percentage: tipPercentage,
tip_amount: tipAmount.toFixed(2),
total_amount: total.toFixed(2)
};
}
// Tool registry for easy lookup
const toolFunctions = {
get_weather: getWeather,
calculate_tip: calculateTip
};
async function handleToolCalling() {
try {
const response = await client.chat.completions({
messages: [
{ role: 'user', content: 'What\'s the weather like in New York, NY?' }
],
tools: tools,
tool_choice: 'auto' // Let the model decide when to use tools
});
const message = response.choices[0].message;
// Check if the model wants to call a tool
if (message.tool_calls && message.tool_calls.length > 0) {
console.log('AI wants to call tools:', message.tool_calls);
// Process each tool call
const toolResults = await Promise.all(
message.tool_calls.map(async (toolCall) => {
const functionName = toolCall.function.name;
const functionArgs = JSON.parse(toolCall.function.arguments);
console.log(`Calling ${functionName} with args:`, functionArgs);
// Call the actual function
const result = await toolFunctions[functionName](...Object.values(functionArgs));
return {
tool_call_id: toolCall.id,
role: 'tool' as const,
content: JSON.stringify(result)
};
})
);
// Send tool results back to the model
const finalResponse = await client.chat.completions({
messages: [
{ role: 'user', content: 'What\'s the weather like in New York, NY?' },
message, // The assistant's message with tool calls
...toolResults // The tool results
],
tools: tools
});
console.log('Final response:', finalResponse.choices[0].message.content);
} else {
console.log('No tools called:', message.content);
}
} catch (error) {
console.error('Tool calling error:', error);
}
}
const advancedTools = [
{
type: "function",
function: {
name: "search_database",
description: "Search a database with complex filters and sorting",
parameters: {
type: "object",
properties: {
query: {
type: "string",
description: "The search query"
},
filters: {
type: "object",
properties: {
category: {
type: "string",
enum: ["products", "users", "orders"]
},
date_range: {
type: "object",
properties: {
start: { type: "string", format: "date" },
end: { type: "string", format: "date" }
}
},
price_range: {
type: "object",
properties: {
min: { type: "number" },
max: { type: "number" }
}
}
}
},
sort: {
type: "object",
properties: {
field: { type: "string" },
order: { type: "string", enum: ["asc", "desc"] }
}
},
limit: {
type: "number",
minimum: 1,
maximum: 100,
default: 10
}
},
required: ["query"]
}
}
}
];
// Force the model to use a specific tool
const response = await client.chat.completions({
messages: [{ role: 'user', content: 'Calculate a 20% tip on $85' }],
tools: tools,
tool_choice: {
type: "function",
function: { name: "calculate_tip" }
}
});
// Prevent tool usage (force text response)
const textOnlyResponse = await client.chat.completions({
messages: [{ role: 'user', content: 'What\'s the weather like today?' }],
tools: tools,
tool_choice: 'none'
});
// Let the model decide (default)
const autoResponse = await client.chat.completions({
messages: [{ role: 'user', content: 'Help me with something' }],
tools: tools,
tool_choice: 'auto'
});
async function executeToolCall(toolCall: any) {
try {
const functionName = toolCall.function.name;
const functionArgs = JSON.parse(toolCall.function.arguments);
// Validate function exists
if (!toolFunctions[functionName]) {
throw new Error(`Unknown function: ${functionName}`);
}
// Validate arguments
const result = await toolFunctions[functionName](...Object.values(functionArgs));
return {
tool_call_id: toolCall.id,
role: 'tool' as const,
content: JSON.stringify({
success: true,
data: result
})
};
} catch (error) {
console.error(`Tool execution error for ${toolCall.function.name}:`, error);
return {
tool_call_id: toolCall.id,
role: 'tool' as const,
content: JSON.stringify({
success: false,
error: error.message || 'Tool execution failed'
})
};
}
}
class ToolEnabledChat {
private client: AnimusClient;
private tools: any[];
private conversation: any[] = [];
constructor(client: AnimusClient, tools: any[]) {
this.client = client;
this.tools = tools;
}
async sendMessage(userMessage: string) {
// Add user message to conversation
this.conversation.push({
role: 'user',
content: userMessage
});
try {
const response = await this.client.chat.completions({
messages: this.conversation,
tools: this.tools,
tool_choice: 'auto'
});
const assistantMessage = response.choices[0].message;
this.conversation.push(assistantMessage);
// Handle tool calls if present
if (assistantMessage.tool_calls && assistantMessage.tool_calls.length > 0) {
const toolResults = await Promise.all(
assistantMessage.tool_calls.map(toolCall => this.executeToolCall(toolCall))
);
// Add tool results to conversation
this.conversation.push(...toolResults);
// Get final response after tool execution
const finalResponse = await this.client.chat.completions({
messages: this.conversation,
tools: this.tools
});
const finalMessage = finalResponse.choices[0].message;
this.conversation.push(finalMessage);
return finalMessage.content;
}
return assistantMessage.content;
} catch (error) {
console.error('Chat error:', error);
throw error;
}
}
async executeToolCall(toolCall: any) {
// Implementation from previous example
return executeToolCall(toolCall);
}
getConversationHistory() {
return [...this.conversation];
}
clearHistory() {
this.conversation = [];
}
}
// Usage
const toolChat = new ToolEnabledChat(client, tools);
const response1 = await toolChat.sendMessage("What's the weather in Boston?");
console.log(response1);
const response2 = await toolChat.sendMessage("What about in Los Angeles?");
console.log(response2);
const apiTools = [
{
type: "function",
function: {
name: "fetch_user_data",
description: "Fetch user data from the API",
parameters: {
type: "object",
properties: {
user_id: {
type: "string",
description: "The user ID to fetch data for"
},
include_preferences: {
type: "boolean",
description: "Whether to include user preferences",
default: false
}
},
required: ["user_id"]
}
}
}
];
async function fetchUserData(userId: string, includePreferences: boolean = false) {
try {
const response = await fetch(`/api/users/${userId}?preferences=${includePreferences}`, {
headers: {
'Authorization': 'Bearer ' + await getAuthToken()
}
});
if (!response.ok) {
throw new Error(`API request failed: ${response.status}`);
}
return await response.json();
} catch (error) {
throw new Error(`Failed to fetch user data: ${error.message}`);
}
}
const databaseTools = [
{
type: "function",
function: {
name: "query_orders",
description: "Query customer orders with filters",
parameters: {
type: "object",
properties: {
customer_id: { type: "string" },
status: {
type: "string",
enum: ["pending", "processing", "shipped", "delivered", "cancelled"]
},
date_from: { type: "string", format: "date" },
date_to: { type: "string", format: "date" },
limit: { type: "number", minimum: 1, maximum: 50, default: 10 }
}
}
}
}
];
async function queryOrders(filters: any) {
// Simulate database query
const query = buildSQLQuery(filters);
const results = await database.query(query);
return {
total_count: results.length,
orders: results.map(order => ({
id: order.id,
status: order.status,
total: order.total,
created_at: order.created_at
}))
};
}
const fileSystemTools = [
{
type: "function",
function: {
name: "read_file",
description: "Read contents of a file",
parameters: {
type: "object",
properties: {
file_path: {
type: "string",
description: "Path to the file to read"
},
encoding: {
type: "string",
enum: ["utf8", "base64"],
default: "utf8"
}
},
required: ["file_path"]
}
}
},
{
type: "function",
function: {
name: "list_directory",
description: "List contents of a directory",
parameters: {
type: "object",
properties: {
directory_path: {
type: "string",
description: "Path to the directory"
},
include_hidden: {
type: "boolean",
default: false
}
},
required: ["directory_path"]
}
}
}
];
const client = new AnimusClient({
tokenProviderUrl: 'https://your-backend.com/api/get-animus-token',
chat: {
model: 'vivian-llama3.1-70b-1.0-fp8',
systemMessage: 'You are a helpful assistant with access to various tools.',
autoTurn: true // Enable conversational turns
}
});
// Tool calling works seamlessly with auto-turn
client.on('messageComplete', (data) => {
console.log(`${data.messageType} message: ${data.content}`);
displayMessage(data.content);
});
// Send message that might trigger both tool calling and auto-turn
client.chat.send("Hey, I'm planning a road trip next week. Can you check the weather for San Francisco, Portland, and Seattle?");
// Good: Clear, specific tool description
{
name: "get_stock_price",
description: "Get the current stock price for a specific company by ticker symbol",
parameters: {
type: "object",
properties: {
ticker: {
type: "string",
description: "Stock ticker symbol (e.g., AAPL, GOOGL)",
pattern: "^[A-Z]{1,5}$"
}
},
required: ["ticker"]
}
}
// Bad: Vague description, unclear parameters
{
name: "get_data",
description: "Gets some data",
parameters: {
type: "object",
properties: {
input: { type: "string" }
}
}
}
// Comprehensive error handling
async function safeToolExecution(toolCall: any) {
try {
// Validate input
if (!toolCall.function.name) {
throw new Error('Missing function name');
}
// Parse arguments safely
let args;
try {
args = JSON.parse(toolCall.function.arguments);
} catch (e) {
throw new Error('Invalid function arguments JSON');
}
// Execute with timeout
const result = await Promise.race([
toolFunctions[toolCall.function.name](args),
new Promise((_, reject) =>
setTimeout(() => reject(new Error('Tool execution timeout')), 30000)
)
]);
return {
tool_call_id: toolCall.id,
role: 'tool' as const,
content: JSON.stringify({ success: true, data: result })
};
} catch (error) {
return {
tool_call_id: toolCall.id,
role: 'tool' as const,
content: JSON.stringify({
success: false,
error: error.message,
timestamp: new Date().toISOString()
})
};
}
}
// Validate and sanitize tool inputs
function validateToolInput(functionName: string, args: any) {
const allowedFunctions = ['get_weather', 'calculate_tip', 'search_database'];
if (!allowedFunctions.includes(functionName)) {
throw new Error(`Function ${functionName} is not allowed`);
}
// Sanitize string inputs
if (typeof args === 'object') {
for (const [key, value] of Object.entries(args)) {
if (typeof value === 'string') {
args[key] = sanitizeString(value);
}
}
}
return args;
}
function sanitizeString(input: string): string {
// Remove potentially dangerous characters
return input.replace(/[<>\"'&]/g, '');
}