Plugin System
Create custom tools and plugins to extend PraisonAI TypeScript
PraisonAI TypeScript provides a powerful plugin system that allows you to create custom tools and extend agent capabilities. This matches the Python SDK’s extensibility pattern.
Quick Start
- Simple Usage
typescript import { tool } from 'praisonai'; const greet = tool({ name: 'greet', description: 'Greet a user', parameters: { type: 'object', properties: { name: { type: 'string' } }, required: ['name'] }, execute: async ({ name }) => `Hello, ${name}!`, }); - With Configuration
typescript import { BaseTool } from 'praisonai'; class EchoTool extends BaseTool { name = 'echo'; description = 'Echo input'; async run(params: { text: string }) { return { text: params.text }; } }
Overview
There are three ways to create custom tools:
- Class-based – Extend
BaseToolfor complex tools with state - Function-based – Use
createTool()for simple inline tools - Decorator-style – Use
tool()function for quick tool creation
BaseTool Class
The BaseTool abstract class is the foundation for creating custom tools:
import { BaseTool, ToolResult } from 'praisonai';
class WeatherTool extends BaseTool<
{ location: string; units?: string },
{ temp: number; condition: string }
> {
name = 'get_weather';
description = 'Get current weather for a location';
version = '1.0.0';
parameters = {
type: 'object' as const,
properties: {
location: { type: 'string', description: 'City name' },
units: { type: 'string', description: 'celsius or fahrenheit', default: 'celsius' }
},
required: ['location']
};
async run(params: { location: string; units?: string }) {
// Your implementation here
const response = await fetch(`https://api.weather.com/${params.location}`);
const data = await response.json();
return { temp: data.temperature, condition: data.condition };
}
}
// Usage
const weather = new WeatherTool();
const result = await weather.run({ location: 'New York' });BaseTool Methods
| Method | Description |
|---|---|
run(params) | Execute the tool (must implement) |
execute(params) | Alias for run() |
safeRun(params) | Execute with error handling, returns ToolResult |
getSchema() | Get OpenAI-compatible function schema |
validate() | Validate tool configuration |
Safe Execution
Use safeRun() for error handling:
const result = await weather.safeRun({ location: 'Paris' });
if (result.success) {
console.log('Temperature:', result.output.temp);
} else {
console.error('Error:', result.error);
}createTool Function
For simple tools, use the createTool() helper:
import { createTool } from 'praisonai';
const calculator = createTool({
name: 'calculator',
description: 'Evaluate a math expression',
parameters: {
type: 'object',
properties: {
expression: { type: 'string', description: 'Math expression' }
},
required: ['expression']
},
run: (params: { expression: string }) => {
return eval(params.expression);
}
});
// Use it
const result = await calculator.run({ expression: '10 * 5 + 2' });
console.log(result); // 52tool() Function
The tool() function provides a decorator-style approach:
import { tool, ToolRegistry } from 'praisonai';
const greeter = tool({
name: 'greeter',
description: 'Generate a personalized greeting',
parameters: {
type: 'object',
properties: {
name: { type: 'string', description: 'Name to greet' },
style: { type: 'string', enum: ['formal', 'casual'] }
},
required: ['name']
},
execute: async (params: { name: string; style?: string }) => {
if (params.style === 'formal') {
return `Good day, ${params.name}. How may I assist you?`;
}
return `Hey ${params.name}! What's up?`;
}
});Tool Registry
For the common case, register tools on the global registry with the Python-style register_tool / get_tool:
import { register_tool, get_tool, list_tools } from 'praisonai';
register_tool(greeter);
register_tool(calculator);
list_tools(); // ['greeter', 'calculator']
get_tool('calculator'); // look up by nameUse a scoped new ToolRegistry() only when you need an isolated registry:
import { ToolRegistry } from 'praisonai';
const registry = new ToolRegistry();
// The class method throws on duplicate names unless { overwrite: true }.
registry.register(greeter);
registry.register(calculator, { trustLevel: 'trusted' });
const tools = registry.list();
console.log('Available tools:', tools.map(t => t.name));
const calc = registry.get('calculator');
// Definitions advertise the registration key
const openaiTools = registry.toOpenAITools();Using Tools with Agents
Pass tools to agents for function calling:
import { Agent, createTool, ToolRegistry } from 'praisonai';
// Create tools
const searchTool = createTool({
name: 'web_search',
description: 'Search the web for information',
parameters: {
type: 'object',
properties: {
query: { type: 'string', description: 'Search query' }
},
required: ['query']
},
run: async (params) => {
// Implement search logic
return `Results for: ${params.query}`;
}
});
// Create agent with tools
const agent = new Agent({
name: 'Research Assistant',
instructions: 'You help users find information',
tools: [searchTool]
});
// Agent can now use the tool
const response = await agent.chat('Search for TypeScript best practices');Creating NPM Plugins
You can distribute tools as npm packages:
// my-praison-plugin/src/index.ts
import { BaseTool } from 'praisonai';
export class MyCustomTool extends BaseTool<{ input: string }, string> {
name = 'my_custom_tool';
description = 'A custom tool from my plugin';
async run(params: { input: string }) {
return `Processed: ${params.input}`;
}
}
// Export for easy use
export function createMyTool() {
return new MyCustomTool();
}Users can then install and use:
import { createMyTool } from 'my-praison-plugin';
import { Agent } from 'praisonai';
const agent = new Agent({
tools: [createMyTool()]
});Tool Validation
Validate tools before use:
import { validateTool, ToolValidationError } from 'praisonai';
try {
validateTool(myTool);
console.log('Tool is valid');
} catch (error) {
if (error instanceof ToolValidationError) {
console.error('Validation failed:', error.message);
}
}OpenAI Schema Generation
Get OpenAI-compatible schemas for any tool:
const schema = weather.getSchema();
console.log(JSON.stringify(schema, null, 2));
// Output:
// {
// "type": "function",
// "function": {
// "name": "get_weather",
// "description": "Get current weather for a location",
// "parameters": {
// "type": "object",
// "properties": {
// "location": { "type": "string", "description": "City name" },
// "units": { "type": "string", "description": "celsius or fahrenheit" }
// },
// "required": ["location"]
// }
// }
// }Best Practices
Guidelines
- Clear descriptions – Write detailed descriptions for LLM understanding
- Type safety – Use TypeScript generics for input/output types
- Error handling – Use
safeRun()or try/catch inrun() - Validation – Define
parametersschema for input validation - Versioning – Set
versionfor tracking tool changes - Testing – Write unit tests for your tools
Example: Complete Plugin
import { BaseTool, createTool, ToolRegistry } from 'praisonai';
// Class-based tool
class DatabaseTool extends BaseTool<
{ query: string; params?: any[] },
any[]
> {
name = 'database_query';
description = 'Execute a database query';
private db: any;
constructor(connectionString: string) {
super();
// Initialize database connection
}
async run(params: { query: string; params?: any[] }) {
return this.db.query(params.query, params.params);
}
}
// Function-based tool
const formatTool = createTool({
name: 'format_json',
description: 'Format JSON with indentation',
run: (params: { json: string; indent?: number }) => {
return JSON.stringify(JSON.parse(params.json), null, params.indent || 2);
}
});
// Register all tools
const registry = new ToolRegistry();
registry.register(new DatabaseTool('postgres://...'));
registry.register(formatTool);
export { registry, DatabaseTool, formatTool };