Skip to main content

Plugin System

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.

Overview

There are three ways to create custom tools:
  1. Class-based - Extend BaseTool for complex tools with state
  2. Function-based - Use createTool() for simple inline tools
  3. 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

MethodDescription
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); // 52

tool() 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

Register and manage tools with ToolRegistry:
import { ToolRegistry, tool } from 'praisonai';

const registry = new ToolRegistry();

// Register tools
registry.register(greeter);
registry.register(calculator);

// List all tools
const tools = registry.list();
console.log('Available tools:', tools.map(t => t.name));

// Get a specific tool
const calc = registry.get('calculator');

// Get OpenAI-compatible tool definitions
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

  1. Clear descriptions - Write detailed descriptions for LLM understanding
  2. Type safety - Use TypeScript generics for input/output types
  3. Error handling - Use safeRun() or try/catch in run()
  4. Validation - Define parameters schema for input validation
  5. Versioning - Set version for tracking tool changes
  6. 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 };