Overview
The defineTool() function defines tools (functions) that language models can call during generation. Tools enable models to access external data, perform calculations, or trigger actions beyond text generation.
Function Signature
export function defineTool(
options: ToolDefinition
): ToolDefinition
type ToolDefinition = {
name: string;
description: string;
parameters: z.ZodType;
};
Parameters
The unique name of the tool. This is what the model uses to identify and call the tool.Should be descriptive and follow snake_case convention (e.g., get_weather, search_database).
A clear description of what the tool does. This helps the model understand when and how to use it.Should explain the tool’s purpose, expected inputs, and what it returns.
Zod schema defining the tool’s input parameters. The model will generate arguments matching this schema.
Return Value
Returns the same ToolDefinition object that was passed in. This is a type-safe helper that provides IDE autocompletion and validation.
Examples
import { defineTool } from '@coreai/core';
import { z } from 'zod';
const weatherTool = defineTool({
name: 'get_weather',
description: 'Get the current weather for a location',
parameters: z.object({
location: z.string().describe('City name or zip code')
})
});
const searchTool = defineTool({
name: 'search_database',
description: 'Search the product database with filters',
parameters: z.object({
query: z.string().describe('Search query'),
category: z.string().optional().describe('Product category filter'),
maxResults: z.number().min(1).max(100).default(10)
.describe('Maximum number of results to return')
})
});
import { generate, defineTool } from '@coreai/core';
import { openai } from '@coreai/openai';
import { z } from 'zod';
const calculatorTool = defineTool({
name: 'calculate',
description: 'Perform mathematical calculations',
parameters: z.object({
expression: z.string().describe('Math expression to evaluate')
})
});
const result = await generate({
model: openai('gpt-4'),
messages: [
{ role: 'user', content: 'What is 142 * 89?' }
],
tools: {
calculate: calculatorTool
}
});
if (result.toolCalls.length > 0) {
const toolCall = result.toolCalls[0];
console.log('Tool:', toolCall.name);
console.log('Arguments:', toolCall.arguments);
// Output: { expression: '142 * 89' }
}
const tools = {
get_weather: defineTool({
name: 'get_weather',
description: 'Get weather for a location',
parameters: z.object({
location: z.string()
})
}),
get_time: defineTool({
name: 'get_time',
description: 'Get current time in a timezone',
parameters: z.object({
timezone: z.string().describe('IANA timezone name')
})
})
};
// Implement tool handlers
const toolHandlers = {
get_weather: async (args: { location: string }) => {
// Call weather API
return `The weather in ${args.location} is sunny, 72°F`;
},
get_time: async (args: { timezone: string }) => {
const time = new Date().toLocaleString('en-US', {
timeZone: args.timezone
});
return `Current time in ${args.timezone}: ${time}`;
}
};
const messages = [
{ role: 'user' as const, content: 'What\'s the weather in Tokyo?' }
];
let result = await generate({
model: openai('gpt-4'),
messages,
tools
});
// Execute tools and continue conversation
while (result.toolCalls.length > 0) {
for (const toolCall of result.toolCalls) {
const handler = toolHandlers[toolCall.name as keyof typeof toolHandlers];
const toolResult = await handler(toolCall.arguments as any);
messages.push({
role: 'assistant',
parts: result.parts
});
messages.push({
role: 'tool',
toolCallId: toolCall.id,
content: toolResult
});
}
result = await generate({
model: openai('gpt-4'),
messages,
tools
});
}
console.log(result.content);
// Output: "The weather in Tokyo is sunny, 72°F"
Complex Parameters with Nested Objects
const createEventTool = defineTool({
name: 'create_calendar_event',
description: 'Create a new calendar event',
parameters: z.object({
title: z.string().describe('Event title'),
startTime: z.string().datetime().describe('ISO 8601 start time'),
endTime: z.string().datetime().describe('ISO 8601 end time'),
attendees: z.array(
z.object({
name: z.string(),
email: z.string().email()
})
).optional().describe('List of attendees'),
location: z.string().optional(),
reminders: z.object({
email: z.boolean().default(true),
popup: z.number().min(0).optional()
.describe('Minutes before event for popup')
}).optional()
})
});
const analyzeSentimentTool = defineTool({
name: 'analyze_sentiment',
description: 'Analyze the sentiment of text',
parameters: z.object({
text: z.string().describe('Text to analyze'),
language: z.enum(['en', 'es', 'fr', 'de'])
.default('en')
.describe('Language of the text'),
includeScore: z.boolean()
.default(false)
.describe('Include numerical sentiment score')
})
});
const tools = {
search_web: defineTool({
name: 'search_web',
description: 'Search the web for information',
parameters: z.object({
query: z.string()
})
}),
get_stock_price: defineTool({
name: 'get_stock_price',
description: 'Get current stock price',
parameters: z.object({
symbol: z.string().describe('Stock ticker symbol')
})
}),
convert_currency: defineTool({
name: 'convert_currency',
description: 'Convert between currencies',
parameters: z.object({
amount: z.number(),
from: z.string().describe('Source currency code'),
to: z.string().describe('Target currency code')
})
})
};
const result = await generate({
model: openai('gpt-4'),
messages: [
{ role: 'user', content: 'What\'s Tesla\'s stock price in euros?' }
],
tools
});
// Model might call get_stock_price then convert_currency
// Auto: Model decides whether to use tools
const result1 = await generate({
model: openai('gpt-4'),
messages: [{ role: 'user', content: 'Hello' }],
tools: { get_weather: weatherTool },
toolChoice: 'auto' // Default
});
// Required: Model must use a tool
const result2 = await generate({
model: openai('gpt-4'),
messages: [{ role: 'user', content: 'Get weather' }],
tools: { get_weather: weatherTool },
toolChoice: 'required'
});
// Force specific tool
const result3 = await generate({
model: openai('gpt-4'),
messages: [{ role: 'user', content: 'Get weather' }],
tools: {
get_weather: weatherTool,
get_time: timeTool
},
toolChoice: { type: 'tool', toolName: 'get_weather' }
});
// None: Disable tools
const result4 = await generate({
model: openai('gpt-4'),
messages: [{ role: 'user', content: 'Hello' }],
tools: { get_weather: weatherTool },
toolChoice: 'none'
});
Type Safety
The tool definition is fully type-safe:
const userTool = defineTool({
name: 'get_user',
description: 'Get user information',
parameters: z.object({
userId: z.number(),
includeProfile: z.boolean().optional()
})
});
// TypeScript knows the parameter types
type ToolParams = z.infer<typeof userTool.parameters>;
// { userId: number; includeProfile?: boolean | undefined }
const handler = async (args: ToolParams) => {
const userId: number = args.userId; // Type-safe
const include: boolean | undefined = args.includeProfile; // Type-safe
// Fetch and return user data
};
Best Practices
Use descriptive tool names that clearly indicate their purpose. Follow the snake_case convention.
Write clear descriptions that explain what the tool does, when to use it, and what it returns. Good descriptions improve model accuracy.
Use Zod’s .describe() method on parameters to provide additional context to the model.
Always validate tool results before passing them back to the model. Handle errors gracefully.
Common Patterns
1. Database Queries
const queryTool = defineTool({
name: 'query_database',
description: 'Query the database for records',
parameters: z.object({
table: z.enum(['users', 'products', 'orders']),
filters: z.record(z.unknown()).optional()
})
});
2. API Calls
const apiTool = defineTool({
name: 'call_api',
description: 'Make an HTTP API request',
parameters: z.object({
endpoint: z.string(),
method: z.enum(['GET', 'POST', 'PUT', 'DELETE']),
body: z.record(z.unknown()).optional()
})
});
3. File Operations
const fileTool = defineTool({
name: 'read_file',
description: 'Read contents of a file',
parameters: z.object({
path: z.string(),
encoding: z.enum(['utf8', 'base64']).default('utf8')
})
});
Source Location
~/workspace/source/packages/core-ai/src/tool.ts:4