Documentation Index Fetch the complete documentation index at: https://docs.ag-kit.dev/llms.txt
Use this file to discover all available pages before exploring further.
AG-Kit provides a powerful framework for creating custom tools that extend your AI agents’ capabilities. Build specialized tools for your specific use cases with full type safety and seamless integration.
Create tools from TypeScript/JavaScript functions:
Simple Functions Convert functions into AI-accessible tools
Async Operations Handle asynchronous operations and promises
Complex Parameters Define complex input schemas with validation
Error Handling Implement robust error handling patterns
Organize related tools into reusable toolkits:
Custom Toolkits Build specialized tool collections
Toolkit Management Manage and organize multiple toolkits
Built-in Toolkits Use pre-built toolkit collections
MCP Integration Connect external MCP servers
Quick Start
Create a simple custom tool:
import { tool } from '@ag-kit/tools' ;
import { z } from 'zod' ;
const weatherTool = tool (
async ({ city , units }) => {
try {
// Fetch weather data
const response = await fetch (
`https://api.weather.com/v1/current?city= ${ city } &units= ${ units } `
);
if ( ! response . ok ) {
return {
success: false ,
error: `Weather API error: ${ response . statusText } ` ,
error_type: 'network'
};
}
const data = await response . json ();
return {
success: true ,
data: {
city ,
temperature: data . temperature ,
condition: data . condition ,
humidity: data . humidity ,
units
}
};
} catch ( error ) {
return {
success: false ,
error: error . message ,
error_type: 'execution'
};
}
},
{
name: 'get_weather' ,
description: 'Get current weather information for a city' ,
schema: z . object ({
city: z . string (). describe ( 'City name' ),
units: z . enum ([ 'celsius' , 'fahrenheit' ]). default ( 'celsius' )
})
}
);
Use custom tools with agents:
import { Agent } from '@ag-kit/core' ;
import { OpenAIProvider } from '@ag-kit/providers/openai' ;
const provider = new OpenAIProvider ({
apiKey: process . env . OPENAI_API_KEY ! ,
model: 'gpt-4'
});
const agent = new Agent ({
name: 'weather-agent' ,
model: provider ,
tools: [ weatherTool ],
instructions: 'You can check weather information for any city.'
});
const response = await agent . run ({
input: 'What \' s the weather like in San Francisco?'
});
All tools implement the standardized interface:
interface BaseTool < TInput = any , TOutput = any > {
name : string ;
description : string ;
schema : ZodSchema < TInput >;
invoke ( input : TInput ) : Promise < ToolResult < TOutput >>;
}
Consistent result format across all tools:
interface ToolResult < T = any > {
success : boolean ;
data ?: T ;
error ?: string ;
error_type ?: "validation" | "execution" | "permission" | "network" ;
executionTime ?: number ;
}
Schema Validation
Use Zod for input validation:
import { z } from 'zod' ;
const complexSchema = z . object ({
// Required fields
id: z . string (). uuid (),
name: z . string (). min ( 1 ). max ( 100 ),
// Optional fields with defaults
priority: z . enum ([ 'low' , 'medium' , 'high' ]). default ( 'medium' ),
tags: z . array ( z . string ()). default ([]),
// Nested objects
metadata: z . object ({
created: z . date (),
author: z . string ()
}). optional (),
// Conditional validation
config: z . union ([
z . object ({ type: z . literal ( 'simple' ), value: z . string () }),
z . object ({ type: z . literal ( 'complex' ), settings: z . record ( z . any ()) })
])
});
Create custom toolkits to organize related tools:
import { BaseToolkit , tool } from '@ag-kit/tools' ;
import { z } from 'zod' ;
class WeatherToolkit extends BaseToolkit {
constructor () {
super ({
name: 'weather-toolkit' ,
description: 'Comprehensive weather information toolkit'
});
}
protected async onInitialize () : Promise < void > {
// Add weather tools
this . addTool ( this . createCurrentWeatherTool ());
this . addTool ( this . createForecastTool ());
this . addTool ( this . createHistoricalTool ());
}
private createCurrentWeatherTool () {
return tool (
async ({ city , units }) => {
// Implementation
return { success: true , data: { temperature: 22 , condition: 'sunny' } };
},
{
name: 'current_weather' ,
description: 'Get current weather conditions' ,
schema: z . object ({
city: z . string (),
units: z . enum ([ 'celsius' , 'fahrenheit' ]). default ( 'celsius' )
})
}
);
}
private createForecastTool () {
return tool (
async ({ city , days }) => {
// Implementation
return { success: true , data: { forecast: [] } };
},
{
name: 'weather_forecast' ,
description: 'Get weather forecast' ,
schema: z . object ({
city: z . string (),
days: z . number (). min ( 1 ). max ( 14 ). default ( 5 )
})
}
);
}
private createHistoricalTool () {
return tool (
async ({ city , date }) => {
// Implementation
return { success: true , data: { historical: {} } };
},
{
name: 'historical_weather' ,
description: 'Get historical weather data' ,
schema: z . object ({
city: z . string (),
date: z . string (). describe ( 'Date in YYYY-MM-DD format' )
})
}
);
}
}
Initialize and use custom toolkits with agents:
// Create and initialize toolkit
const weatherToolkit = new WeatherToolkit ();
await weatherToolkit . initialize ();
// Get all tools from toolkit
const weatherTools = weatherToolkit . getTools ();
Use the toolkit manager for centralized toolkit management:
import { ToolkitManager } from '@ag-kit/tools' ;
const toolkitManager = new ToolkitManager ();
// Register toolkit
toolkitManager . register ( weatherToolkit );
// Get toolkit by name
const toolkit = toolkitManager . getToolkit ( 'weather-toolkit' );
// Get all tools from all registered toolkits
const allTools = toolkitManager . getAllTools ();
// Find specific tool across all toolkits
const currentWeatherTools = toolkitManager . findTool ( 'current_weather' );
// Initialize all registered toolkits
await toolkitManager . initializeAll ();
// Cleanup all toolkits
await toolkitManager . destroyAll ();
Listen to toolkit lifecycle events:
weatherToolkit . addEventListener (( event ) => {
switch ( event . type ) {
case 'toolkit_initialized' :
console . log ( `Toolkit ${ event . toolkit . name } initialized` );
break ;
case 'tool_added' :
console . log ( `Tool ${ event . tool . name } added` );
break ;
case 'tool_executed' :
console . log ( `Tool ${ event . toolName } executed` );
break ;
case 'toolkit_destroyed' :
console . log ( `Toolkit ${ event . toolkit . name } destroyed` );
break ;
}
});
Unit Testing
Test custom tools thoroughly:
import { describe , it , expect } from 'jest/globals' ;
describe ( 'weatherTool' , () => {
it ( 'should return weather data for valid city' , async () => {
const result = await weatherTool . invoke ({
city: 'San Francisco' ,
units: 'celsius'
});
expect ( result . success ). toBe ( true );
expect ( result . data ). toHaveProperty ( 'temperature' );
expect ( result . data . city ). toBe ( 'San Francisco' );
expect ( result . data . units ). toBe ( 'celsius' );
});
it ( 'should handle invalid city gracefully' , async () => {
const result = await weatherTool . invoke ({
city: 'InvalidCity123' ,
units: 'celsius'
});
expect ( result . success ). toBe ( false );
expect ( result . error_type ). toBe ( 'network' );
});
it ( 'should validate input schema' , async () => {
const result = await weatherTool . invoke ({
city: '' , // Invalid empty city
units: 'celsius'
});
expect ( result . success ). toBe ( false );
expect ( result . error_type ). toBe ( 'validation' );
});
});
Test custom toolkits comprehensively:
import { describe , it , expect , beforeEach , afterEach } from 'jest/globals' ;
describe ( 'WeatherToolkit' , () => {
let weatherToolkit : WeatherToolkit ;
beforeEach ( async () => {
weatherToolkit = new WeatherToolkit ();
await weatherToolkit . initialize ();
});
afterEach ( async () => {
await weatherToolkit . destroy ();
});
it ( 'should initialize with correct tools' , () => {
const toolNames = weatherToolkit . getToolNames ();
expect ( toolNames ). toContain ( 'current_weather' );
expect ( toolNames ). toContain ( 'weather_forecast' );
expect ( toolNames ). toContain ( 'historical_weather' );
expect ( weatherToolkit . getTools ()). toHaveLength ( 3 );
});
it ( 'should execute tools correctly' , async () => {
const result = await weatherToolkit . invokeTool ( 'current_weather' , {
city: 'San Francisco' ,
units: 'celsius'
});
expect ( result . success ). toBe ( true );
expect ( result . data ). toHaveProperty ( 'temperature' );
});
it ( 'should handle batch tool execution' , async () => {
const results = await weatherToolkit . invokeTools ([
{ toolName: 'current_weather' , input: { city: 'Tokyo' } },
{ toolName: 'weather_forecast' , input: { city: 'Tokyo' , days: 3 } }
]);
expect ( results ). toHaveLength ( 2 );
expect ( results . every ( r => r . success )). toBe ( true );
});
it ( 'should validate toolkit integrity' , () => {
const validation = weatherToolkit . validate ();
expect ( validation . valid ). toBe ( true );
expect ( validation . errors ). toHaveLength ( 0 );
});
it ( 'should emit events correctly' , async () => {
const events : any [] = [];
const newToolkit = new WeatherToolkit ();
newToolkit . addEventListener (( event ) => {
events . push ( event );
});
await newToolkit . initialize ();
await newToolkit . invokeTool ( 'current_weather' , { city: 'London' });
await newToolkit . destroy ();
expect ( events . some ( e => e . type === 'toolkit_initialized' )). toBe ( true );
expect ( events . some ( e => e . type === 'tool_executed' )). toBe ( true );
expect ( events . some ( e => e . type === 'toolkit_destroyed' )). toBe ( true );
});
});
Caching
Implement caching for expensive operations:
const cache = new Map ();
const cachedWeatherTool = tool (
async ({ city , units }) => {
const cacheKey = ` ${ city } - ${ units } ` ;
const cached = cache . get ( cacheKey );
if ( cached && Date . now () - cached . timestamp < 300000 ) { // 5 minutes
return {
success: true ,
data: { ... cached . data , cached: true }
};
}
const result = await fetchWeatherData ( city , units );
if ( result . success ) {
cache . set ( cacheKey , {
data: result . data ,
timestamp: Date . now ()
});
}
return result ;
},
{
name: 'get_weather_cached' ,
description: 'Get weather with caching' ,
schema: z . object ({
city: z . string (),
units: z . enum ([ 'celsius' , 'fahrenheit' ]). default ( 'celsius' )
})
}
);
Connection Pooling
Reuse connections for better performance:
class DatabaseConnectionPool {
private pool : any [] = [];
async getConnection () {
if ( this . pool . length > 0 ) {
return this . pool . pop ();
}
return await createNewConnection ();
}
releaseConnection ( connection : any ) {
if ( this . pool . length < 10 ) {
this . pool . push ( connection );
} else {
connection . close ();
}
}
}
const pool = new DatabaseConnectionPool ();
const optimizedDbTool = tool (
async ({ query , parameters }) => {
const connection = await pool . getConnection ();
try {
const result = await connection . query ( query , parameters );
return { success: true , data: result };
} finally {
pool . releaseConnection ( connection );
}
},
{
name: 'optimized_db_query' ,
description: 'Database query with connection pooling' ,
schema: z . object ({
query: z . string (),
parameters: z . array ( z . any ()). default ([])
})
}
);
Next Steps
Function Tools Create tools from TypeScript functions
MCP Integration Connect external MCP servers