Defining Tools
UsedefineTool() to create a tool definition:
import { defineTool } from '@agentlib/core'
const searchTool = defineTool({
schema: {
name: 'search',
description: 'Search the web for information',
parameters: {
type: 'object',
properties: {
query: { type: 'string', description: 'Search query' },
},
required: ['query'],
},
},
async execute({ query }) {
// Call search API
return { results: [`Result for: ${query}`] }
},
})
Tool Schema
The schema follows JSON Schema format and is sent to the LLM:const calculatorTool = defineTool({
schema: {
name: 'calculator',
description: 'Evaluate a mathematical expression',
parameters: {
type: 'object',
properties: {
expression: {
type: 'string',
description: 'Math expression to evaluate (e.g., "2 + 2")',
},
precision: {
type: 'number',
description: 'Decimal places for the result',
},
},
required: ['expression'],
},
},
async execute({ expression, precision = 2 }) {
const result = eval(String(expression))
return {
result: Number(result.toFixed(precision)),
expression
}
},
})
Never use
eval() in production. Use a safe math parser like mathjs instead.Adding Tools to Agents
Register Individual Tools
Add tools one at a time using
.tool():import { createAgent } from '@agentlib/core'
import { openai } from '@agentlib/openai'
const agent = createAgent({ name: 'assistant' })
.provider(openai({ apiKey: process.env.OPENAI_API_KEY }))
.tool(searchTool)
.tool(calculatorTool)
Accessing Execution Context
Tools have access to the execution context including agent data:interface AppData {
userId: string
apiKey: string
}
const databaseTool = defineTool({
schema: {
name: 'query_database',
description: 'Query the user database',
parameters: {
type: 'object',
properties: {
sql: { type: 'string', description: 'SQL query' },
},
required: ['sql'],
},
},
async execute({ sql }, ctx) {
// Access agent data from context
const userId = ctx.data.userId
const apiKey = ctx.data.apiKey
console.log(`User ${userId} querying database`)
// Execute query with user credentials
const results = await db.query(sql, { userId, apiKey })
return results
},
})
const agent = createAgent<AppData>({
name: 'db-agent',
data: { userId: 'user-123', apiKey: 'sk-...' },
})
.provider(model)
.tool(databaseTool)
Complex Tool Examples
File Operations
import fs from 'fs/promises'
import path from 'path'
const writeFileTool = defineTool({
schema: {
name: 'write_file',
description: 'Write content to a file',
parameters: {
type: 'object',
properties: {
path: { type: 'string', description: 'File path' },
content: { type: 'string', description: 'File content' },
},
required: ['path', 'content'],
},
},
async execute({ path: filePath, content }) {
await fs.writeFile(filePath, content, 'utf-8')
return { success: true, path: filePath }
},
})
const readFileTool = defineTool({
schema: {
name: 'read_file',
description: 'Read the contents of a file',
parameters: {
type: 'object',
properties: {
path: { type: 'string', description: 'File path' },
},
required: ['path'],
},
},
async execute({ path: filePath }) {
const content = await fs.readFile(filePath, 'utf-8')
return { content, path: filePath }
},
})
API Calls
const fetchDataTool = defineTool({
schema: {
name: 'fetch_data',
description: 'Fetch data from an API endpoint',
parameters: {
type: 'object',
properties: {
url: { type: 'string', description: 'API URL' },
method: {
type: 'string',
enum: ['GET', 'POST', 'PUT', 'DELETE'],
description: 'HTTP method'
},
body: { type: 'object', description: 'Request body for POST/PUT' },
},
required: ['url'],
},
},
async execute({ url, method = 'GET', body }) {
const response = await fetch(url, {
method,
headers: { 'Content-Type': 'application/json' },
body: body ? JSON.stringify(body) : undefined,
})
const data = await response.json()
return { data, status: response.status }
},
})
Database Operations
import { sql } from '@vercel/postgres'
const queryTool = defineTool({
schema: {
name: 'query_users',
description: 'Query user information from the database',
parameters: {
type: 'object',
properties: {
userId: { type: 'string', description: 'User ID to query' },
},
required: ['userId'],
},
},
async execute({ userId }) {
const result = await sql`
SELECT * FROM users WHERE id = ${userId}
`
return result.rows[0]
},
})
Tool Error Handling
Handle errors gracefully in tools:const riskyTool = defineTool({
schema: {
name: 'risky_operation',
description: 'Perform a potentially failing operation',
parameters: {
type: 'object',
properties: {
input: { type: 'string' },
},
required: ['input'],
},
},
async execute({ input }) {
try {
const result = await someRiskyOperation(input)
return { success: true, result }
} catch (error) {
// Return structured error instead of throwing
return {
success: false,
error: error.message,
suggestion: 'Try a different input format',
}
}
},
})
Returning error information instead of throwing allows the agent to see what went wrong and potentially retry with corrected input.
Restricting Tool Access
Control which tools an agent can use with policies:const agent = createAgent({ name: 'limited-agent' })
.provider(model)
.tool(searchTool)
.tool(calculatorTool)
.tool(writeFileTool)
.policy({
allowedTools: ['search', 'calculator'], // Only these tools allowed
})
const result = await agent.run('Search for AI news and write to file.txt')
// The agent will use search and calculator, but cannot use write_file
Observing Tool Calls
Monitor tool usage with event listeners:agent.on('tool:before', ({ name, args }) => {
console.log(`[TOOL] Calling ${name} with:`, args)
})
agent.on('tool:after', ({ name, result, error }) => {
if (error) {
console.error(`[TOOL] ${name} failed:`, error)
} else {
console.log(`[TOOL] ${name} returned:`, result)
}
})
const result = await agent.run('What is 2+2 and search for AI news?')
Complete Tool Example
import 'dotenv/config'
import { createAgent, defineTool } from '@agentlib/core'
import { openai } from '@agentlib/openai'
const searchTool = defineTool({
schema: {
name: 'search',
description: 'Search the web for information',
parameters: {
type: 'object',
properties: {
query: { type: 'string' },
},
required: ['query'],
},
},
async execute({ query }) {
return { results: [`Result for: ${query}`] }
},
})
const calculatorTool = defineTool({
schema: {
name: 'calculator',
description: 'Evaluate a math expression',
parameters: {
type: 'object',
properties: {
expression: { type: 'string' },
},
required: ['expression'],
},
},
async execute({ expression }) {
return { result: eval(String(expression)) }
},
})
const agent = createAgent({ name: 'react-agent' })
.provider(openai({
apiKey: process.env.OPENAI_API_KEY,
model: 'gpt-4o',
}))
.tool(searchTool)
.tool(calculatorTool)
agent.on('tool:after', ({ name, result }) => {
console.log(`✓ ${name}:`, result)
})
const result = await agent.run(
'What is the population of Tokyo multiplied by 2?'
)
console.log('\nFinal answer:', result.output)
Next Steps
- Reasoning Engines - Learn how different engines use tools
- Middleware System - Intercept and modify tool calls
- Event Handling - Monitor tool execution