Function Calling (Tools)
Transform your AI from a passive chatbot into an active assistant that can execute actions in your application.
What are Tools?
Tools (also called function calling) allow the AI to perform actions like:
- Creating or updating records
- Triggering workflows
- Filtering or sorting data
- Navigating between pages
- Executing business logic
How It Works
- You define tools - Specify what functions are available and their parameters
- AI decides when to call - Based on user intent, AI selects the appropriate tool
- Handler executes - Your JavaScript function runs
- AI uses result - AI incorporates the result into its response
Basic Example
import { InAppAI } from '@inappai/react';
import { useState } from 'react';
function CounterApp() {
const [count, setCount] = useState(0);
return (
<div>
<p>Counter: {count}</p>
<InAppAI
agentId="your-agent-id"
tools={[
{
name: 'incrementCounter',
description: 'Increment the counter by a specified amount',
parameters: {
type: 'object',
properties: {
amount: {
type: 'number',
description: 'Amount to increment (default: 1)',
},
},
required: [],
},
handler: async (params) => {
const amount = params.amount || 1;
setCount(prev => prev + amount);
return { success: true, newCount: count + amount };
},
},
]}
/>
</div>
);
}
User: “Increase the counter by 5” AI: [Calls incrementCounter({ amount: 5 })] “I’ve incremented the counter by 5. It’s now at 5.”
Tool Interface
interface Tool {
name: string; // Unique identifier
description: string; // When and how to use this tool
parameters: { // JSON Schema definition
type: 'object';
properties: Record<string, {
type: string; // 'string', 'number', 'boolean', 'array', 'object'
description: string; // Parameter explanation
enum?: string[]; // Optional: allowed values
}>;
required: string[]; // Required parameter names
};
handler: (params: any) => Promise<any>; // Async function
}
Complete Example: Todo App
Let the AI manage a todo list:
import { InAppAI } from '@inappai/react';
import { useState } from 'react';
function TodoApp() {
const [todos, setTodos] = useState([
{ id: 1, text: 'Buy groceries', completed: false },
{ id: 2, text: 'Call dentist', completed: false },
]);
return (
<InAppAI
agentId="your-agent-id"
tools={[
{
name: 'addTodo',
description: 'Create a new todo item',
parameters: {
type: 'object',
properties: {
text: {
type: 'string',
description: 'The task description',
},
},
required: ['text'],
},
handler: async (params) => {
const newTodo = {
id: Date.now(),
text: params.text,
completed: false,
};
setTodos([...todos, newTodo]);
return { success: true, todo: newTodo };
},
},
{
name: 'completeTodo',
description: 'Mark a todo as completed',
parameters: {
type: 'object',
properties: {
id: {
type: 'number',
description: 'The ID of the todo to complete',
},
},
required: ['id'],
},
handler: async (params) => {
const todo = todos.find(t => t.id === params.id);
if (!todo) {
return { success: false, message: 'Todo not found' };
}
setTodos(todos.map(t =>
t.id === params.id ? { ...t, completed: true } : t
));
return { success: true, message: `Completed: ${todo.text}` };
},
},
{
name: 'deleteTodo',
description: 'Delete a todo item',
parameters: {
type: 'object',
properties: {
id: {
type: 'number',
description: 'The ID of the todo to delete',
},
},
required: ['id'],
},
handler: async (params) => {
setTodos(todos.filter(t => t.id !== params.id));
return { success: true, message: 'Todo deleted' };
},
},
]}
/>
);
}
Conversation Example:
- User: “Add a task to finish the report”
- AI: [Calls addTodo({ text: ‘Finish the report’ })] “I’ve added ‘Finish the report’ to your todo list.”
- User: “Mark the groceries task as done”
- AI: [Calls completeTodo({ id: 1 })] “I’ve marked ‘Buy groceries’ as completed.”
Multiple Tools
You can provide multiple tools for different actions:
<InAppAI
agentId="your-agent-id"
tools={[
{
name: 'searchProducts',
description: 'Search for products by name or category',
parameters: {
type: 'object',
properties: {
query: { type: 'string', description: 'Search query' },
},
required: ['query'],
},
handler: async ({ query }) => {
const results = await fetch(`/api/products?q=${query}`);
return await results.json();
},
},
{
name: 'addToCart',
description: 'Add a product to the shopping cart',
parameters: {
type: 'object',
properties: {
productId: { type: 'string', description: 'Product ID' },
quantity: { type: 'number', description: 'Quantity to add' },
},
required: ['productId'],
},
handler: async ({ productId, quantity = 1 }) => {
// Add to cart logic
return { success: true, cartTotal: newTotal };
},
},
{
name: 'getCart',
description: 'Get current shopping cart contents',
parameters: {
type: 'object',
properties: {},
},
handler: async () => {
return {
items: cart,
total: calculateTotal(cart),
};
},
},
]}
/>
The AI will automatically choose the right tool based on user intent.
Parameter Types
String Parameters
{
name: 'sendEmail',
parameters: {
type: 'object',
properties: {
to: { type: 'string', description: 'Recipient email address' },
subject: { type: 'string', description: 'Email subject' },
body: { type: 'string', description: 'Email body content' },
},
required: ['to', 'subject', 'body'],
},
handler: async ({ to, subject, body }) => {
// Send email logic
},
}
Number Parameters
{
name: 'updateQuantity',
parameters: {
type: 'object',
properties: {
itemId: { type: 'number', description: 'Item ID' },
quantity: { type: 'number', description: 'New quantity' },
},
required: ['itemId', 'quantity'],
},
handler: async ({ itemId, quantity }) => {
// Update quantity logic
},
}
Enum Parameters (Constrained Values)
{
name: 'filterProducts',
parameters: {
type: 'object',
properties: {
category: {
type: 'string',
enum: ['electronics', 'clothing', 'books', 'home'],
description: 'Product category',
},
sortBy: {
type: 'string',
enum: ['price-asc', 'price-desc', 'name', 'rating'],
description: 'Sort order',
},
},
required: ['category'],
},
handler: async ({ category, sortBy = 'name' }) => {
// Filter and sort logic
},
}
Boolean Parameters
{
name: 'toggleFeature',
parameters: {
type: 'object',
properties: {
featureName: { type: 'string', description: 'Feature identifier' },
enabled: { type: 'boolean', description: 'Enable or disable' },
},
required: ['featureName', 'enabled'],
},
handler: async ({ featureName, enabled }) => {
// Toggle feature logic
},
}
Best Practices
1. Clear Descriptions
Write descriptions that explain when and why to use the tool:
// ❌ Vague
description: 'Updates a todo'
// ✅ Clear
description: 'Mark a todo as completed when the user indicates they finished a task'
2. Error Handling
Always handle errors gracefully:
handler: async (params) => {
try {
const result = await updateDatabase(params);
return { success: true, data: result };
} catch (error) {
console.error('Tool error:', error);
return {
success: false,
message: 'Failed to update. Please try again.',
};
}
}
3. Return Meaningful Data
Return information the AI can use in its response:
// ❌ Minimal
return { success: true };
// ✅ Informative
return {
success: true,
message: 'Todo added successfully',
todo: newTodo,
totalTodos: todos.length + 1,
};
4. Validate Inputs
Check parameters before executing:
handler: async ({ email, amount }) => {
if (!email || !email.includes('@')) {
return { success: false, message: 'Invalid email address' };
}
if (amount <= 0) {
return { success: false, message: 'Amount must be positive' };
}
// Proceed with logic
}
5. Async Operations
Use async/await for API calls or database operations:
handler: async ({ userId }) => {
const user = await fetch(`/api/users/${userId}`).then(r => r.json());
const orders = await fetch(`/api/users/${userId}/orders`).then(r => r.json());
return { user, orders };
}
Security Considerations
1. Validate User Permissions
Check if the user is authorized:
handler: async ({ itemId }) => {
const user = getCurrentUser();
if (!user.isAdmin) {
return { success: false, message: 'Permission denied' };
}
// Admin-only logic
}
2. Sanitize Inputs
Never trust tool parameters directly:
handler: async ({ query }) => {
// Sanitize query to prevent injection
const sanitized = query.replace(/[^\w\s]/gi, '');
const results = await searchDatabase(sanitized);
return results;
}
3. Rate Limiting
Prevent abuse by limiting calls:
const callCounts = new Map();
handler: async ({ action }) => {
const userId = getCurrentUser().id;
const count = callCounts.get(userId) || 0;
if (count > 10) {
return { success: false, message: 'Rate limit exceeded' };
}
callCounts.set(userId, count + 1);
// Execute action
}
Advanced Patterns
Tool Chaining
Tools can call other tools:
const tools = [
{
name: 'processOrder',
handler: async ({ orderId }) => {
// Validate order
const order = await validateOrder(orderId);
// Charge payment (could be another tool)
const payment = await chargePayment(order);
// Send confirmation (could be another tool)
await sendConfirmation(order.email);
return { success: true, order, payment };
},
},
];
Stateful Tools
Access and modify component state:
const [filter, setFilter] = useState('all');
const [sortBy, setSortBy] = useState('date');
tools={[
{
name: 'updateView',
description: 'Update the current view filter and sort order',
parameters: {
type: 'object',
properties: {
filter: { type: 'string', enum: ['all', 'active', 'completed'] },
sortBy: { type: 'string', enum: ['date', 'priority', 'name'] },
},
required: [],
},
handler: async ({ filter: newFilter, sortBy: newSort }) => {
if (newFilter) setFilter(newFilter);
if (newSort) setSortBy(newSort);
return {
success: true,
filter: newFilter || filter,
sortBy: newSort || sortBy,
};
},
},
]}
Debugging Tools
Use console logging to debug tool execution:
handler: async (params) => {
console.log('Tool called:', params);
const result = await executeLogic(params);
console.log('Tool result:', result);
return result;
}
Next Steps
- Context - Pass application state to AI
- Backend Settings - Configure AI provider and model
- Knowledge Base - Add custom documentation
- API Reference - Complete Tool type definition
- Live Demo - See function calling in action