Skip to main content

@ag-kit/tools API Reference

Complete API documentation for the @ag-kit/tools package. This reference covers all available tools, their interfaces, method signatures, and practical usage examples with the latest features including MultiEditTool, Transaction support, and enhanced toolkits.

API Overview

Installation

npm install @ag-kit/tools

Core Interfaces

BaseTool Interface

All tools extend the abstract BaseTool class with advanced generic support and lifecycle management:
abstract class BaseTool<
  TSchema extends z.ZodTypeAny = z.ZodTypeAny,
  TState = Record<string, unknown>,
  TOutput = any,
> {
  public name: string;
  public description?: string;
  public requiresApproval?: boolean;
  public readonly schema?: TSchema;

  constructor(options: IBaseToolOptions<TSchema>);

  // Public invocation method with validation and error handling
  async invoke<TInput extends TBaseToolInvokeInput<TSchema>>(
    input: TInput,
    context?: ToolExecutionContext<TState>
  ): Promise<ToolResult<TOutput>>;

  // Abstract method: must be implemented by subclasses
  protected abstract _invoke<TInput extends TBaseToolInvokeInput<TSchema>>(
    input: TInput,
    context?: ToolExecutionContext<TState>
  ): Promise<TOutput | ToolResult<TOutput>>;

  // Utility methods
  getDisplay(params: { name: string; input: any }): string;
  getMetadata(): { name: string; description?: string; schema: any };
  protected validateInput(input: any): ToolResult;
}
Key Features:
  • Generic Type Safety: Full TypeScript generics for schema, state, and output types
  • Automatic Validation: Built-in input validation using Zod schemas
  • Context Support: Execution context with conversation, user, and state tracking
  • Approval Workflow: Optional approval requirement for sensitive operations
  • Error Handling: Comprehensive error categorization and timing metrics
  • Metadata Access: Tool introspection and display customization

ToolResult Interface

Standardized result format implemented as a class with comprehensive error categorization:
class ToolResult<TOutput = any> {
  public success: boolean;
  public data?: TOutput;
  public error?: string;
  public executionTime?: number;
  public error_type?:
    | "validation"
    | "security"
    | "file_not_found"
    | "permission"
    | "execution"
    | "unknown";

  constructor({
    success,
    data,
    error,
    error_type,
    executionTime,
  }: {
    success: boolean;
    data?: TOutput;
    error?: string;
    error_type?: ToolResult["error_type"];
    executionTime?: number;
  });
}
Properties:
  • success: Boolean indicating operation success/failure
  • data: Tool output data (when successful) - strongly typed based on tool
  • error: Detailed error message (when failed)
  • error_type: Categorized error type for programmatic handling
  • executionTime: Execution duration in milliseconds for performance monitoring
Error Types:
  • validation: Input validation failures
  • security: Security violations (path traversal, unauthorized access)
  • file_not_found: Missing files or directories
  • permission: Access denied or insufficient permissions
  • execution: Runtime execution errors
  • unknown: Uncategorized errors

BaseToolkit Interface

Comprehensive toolkit class for organizing and managing collections of related tools:
class BaseToolkit<TState extends Record<string, unknown> = Record<string, unknown>> {
  public readonly name: string;
  public readonly description?: string;
  public context?: ToolExecutionContext<TState>;

  constructor(options: IToolkitOptions<TState>);

  // Lifecycle Management
  async initialize(): Promise<void>;
  async destroy(): Promise<void>;
  protected async onInitialize(): Promise<void>;  // Override in subclasses
  protected async onDestroy(): Promise<void>;     // Override in subclasses

  // Tool Management
  addTool(tool: BaseTool): this;
  addTools(tools: BaseTool[]): this;
  removeTool(toolName: string): boolean;
  getTool(name: string): BaseTool | undefined;
  getTools(): BaseTool[];
  getToolNames(): string[];
  hasTool(name: string): boolean;
  searchTools(query: string): BaseTool[];

  // Execution Management
  async invokeTool(toolName: string, input: any, context?: ToolExecutionContext<TState>): Promise<ToolResult>;
  async invokeTools(invocations: Array<{toolName: string; input: any; context?: ToolExecutionContext<TState>}>): Promise<ToolResult[]>;

  // Context Management
  setContext(context: ToolExecutionContext<TState>): this;
  getContext(): ToolExecutionContext<TState> | undefined;

  // Event System
  addEventListener(listener: ToolkitEventListener): this;
  removeEventListener(listener: ToolkitEventListener): boolean;

  // Utility Methods
  getMetadata(): { name: string; description?: string; toolCount: number; tools: any[]; initialized: boolean };
  validate(): { valid: boolean; errors: string[] };
  clone(newName?: string): BaseToolkit;
}
Key Features:
  • Generic State Support: Type-safe state management with generics
  • Lifecycle Hooks: Overridable onInitialize() and onDestroy() methods
  • Batch Operations: Execute multiple tools with invokeTools()
  • Tool Discovery: Search and filter tools by name or description
  • Event System: Listen to toolkit and tool lifecycle events
  • Context Sharing: Shared execution context across all tools
  • Validation: Built-in integrity checking and error reporting
  • Cloning: Create toolkit copies with different configurations

DynamicTool Class

Dynamic tool implementation for creating tools from functions without subclassing:
class DynamicTool<
  TSchema extends z.ZodTypeAny = z.ZodTypeAny,
  TState = Record<string, unknown>,
  TOutput = any,
> extends BaseTool<TSchema, TState, TOutput> {
  constructor(options: IDynamicToolOptions<TSchema, TState, TOutput>);
  protected async _invoke(input, context?): Promise<TOutput | ToolResult<TOutput>>;
}

interface IDynamicToolOptions<TSchema, TState, TOutput> extends IBaseToolOptions {
  schema: TSchema;
  func: (input: TInput, context?: ToolExecutionContext<TState>) => Promise<TOutput | ToolResult<TOutput>>;
}
Usage Example:
const dynamicTool = new DynamicTool({
  name: 'calculate',
  description: 'Perform mathematical calculations',
  schema: z.object({
    expression: z.string(),
    precision: z.number().optional()
  }),
  func: async (input, context) => {
    const result = eval(input.expression); // Don't use eval in production!
    return {
      result,
      precision: input.precision || 2,
      timestamp: new Date().toISOString()
    };
  }
});

tool() Helper Function

Convenient factory function for creating DynamicTool instances:
function tool<TSchema extends z.ZodTypeAny, TState, TOutput>(
  func: (input: TInput, context?: ToolExecutionContext<TState>) => Promise<TOutput | ToolResult<TOutput>>,
  options: {
    name: string;
    description?: string;
    schema: TSchema;
    requiresApproval?: boolean;
    getDisplay?: (params: { name: string; input: any }) => string;
  }
): DynamicTool<TSchema, TState, TOutput>
Usage Examples:
// Basic tool creation
const weatherTool = tool(
  async ({ city, units }) => {
    const weather = await fetchWeather(city, units);
    return { temperature: weather.temp, conditions: weather.desc };
  },
  {
    name: 'get_weather',
    description: 'Get current weather for a city',
    schema: z.object({
      city: z.string().describe('City name'),
      units: z.enum(['celsius', 'fahrenheit']).default('celsius')
    })
  }
);

// Tool with custom display and approval
const sensitiveDataTool = tool(
  async ({ query }) => {
    const data = await queryDatabase(query);
    return { results: data, count: data.length };
  },
  {
    name: 'query_sensitive_data',
    description: 'Query sensitive database information',
    requiresApproval: true,
    schema: z.object({
      query: z.string().describe('SQL query to execute')
    }),
    getDisplay: ({ name, input }) => `${name}: Executing query on sensitive data`
  }
);

// Tool with context usage
const statefulTool = tool(
  async ({ action }, context) => {
    const userId = context?.userId;
    const state = context?.state || {};

    switch (action) {
      case 'increment':
        state.counter = (state.counter || 0) + 1;
        break;
      case 'reset':
        state.counter = 0;
        break;
    }

    return { counter: state.counter, userId };
  },
  {
    name: 'counter_tool',
    description: 'Stateful counter operations',
    schema: z.object({
      action: z.enum(['increment', 'reset', 'get'])
    })
  }
);

ToolkitManager Class

Centralized manager for multiple toolkits with global tool discovery and lifecycle management:
class ToolkitManager {
  // Toolkit Registration
  register(toolkit: BaseToolkit): this;
  unregister(toolkitName: string): boolean;
  getToolkit(name: string): BaseToolkit | undefined;
  getToolkits(): BaseToolkit[];

  // Tool Discovery
  getAllTools(): Array<{ toolkit: string; tool: BaseTool }>;
  findTool(toolName: string): Array<{ toolkit: string; tool: BaseTool }>;

  // Lifecycle Management
  async initializeAll(): Promise<void>;
  async destroyAll(): Promise<void>;
}

// Singleton instance
export const toolkitManager = new ToolkitManager();
Usage Examples:
import { toolkitManager, BaseToolkit } from '@ag-kit/tools';

// Create and register toolkits
const weatherToolkit = new BaseToolkit({
  name: 'weather',
  description: 'Weather-related tools'
});

const fileToolkit = new BaseToolkit({
  name: 'filesystem',
  description: 'File system operations'
});

// Register toolkits
toolkitManager
  .register(weatherToolkit)
  .register(fileToolkit);

// Initialize all registered toolkits
await toolkitManager.initializeAll();

// Find tools across all toolkits
const weatherTools = toolkitManager.findTool('get_weather');
const allTools = toolkitManager.getAllTools();

console.log(`Found ${allTools.length} tools across ${toolkitManager.getToolkits().length} toolkits`);

// Cleanup all toolkits
await toolkitManager.destroyAll();

ToolkitEvent System

Comprehensive event system for monitoring toolkit and tool lifecycle:
type ToolkitEvent =
  | { type: "tool_added"; tool: BaseTool }
  | { type: "tool_removed"; toolName: string }
  | { type: "tool_executed"; toolName: string; result: ToolResult }
  | { type: "toolkit_initialized"; toolkit: BaseToolkit }
  | { type: "toolkit_destroyed"; toolkit: BaseToolkit };

type ToolkitEventListener = (event: ToolkitEvent) => void;
Event Handling Example:
const toolkit = new BaseToolkit({ name: 'example' });

// Add event listener
toolkit.addEventListener((event) => {
  switch (event.type) {
    case 'tool_added':
      console.log(`Tool added: ${event.tool.name}`);
      break;
    case 'tool_executed':
      console.log(`Tool executed: ${event.toolName}, success: ${event.result.success}`);
      break;
    case 'toolkit_initialized':
      console.log(`Toolkit initialized: ${event.toolkit.name}`);
      break;
  }
});

// Tools and operations will trigger events
toolkit.addTool(weatherTool);
await toolkit.initialize();
await toolkit.invokeTool('get_weather', { city: 'Tokyo' });

API Usage Patterns

Tool Creation

Create tools using factory functions, the tool() helper, or by extending BaseTool:
import {
  createReadTool,
  createMultieditTool,
  tool,
  BaseTool,
  DynamicTool,
  LocalFileOperator
} from '@ag-kit/tools';
import { z } from 'zod';

// Method 1: Using built-in factory functions (recommended for built-in tools)
const context = {
  workingDirectory: process.cwd(),
  fsOperator: new LocalFileOperator()
};

const readTool = createReadTool(context);
const multieditTool = createMultieditTool(context);

// Method 2: Using tool() helper for custom tools (recommended for simple tools)
const customTool = tool(
  async ({ input, options }) => {
    const result = `Processed: ${input}`;
    return {
      result: options?.format === 'json' ? { processed: input } : result,
      timestamp: new Date().toISOString()
    };
  },
  {
    name: 'example_tool',
    description: 'Example tool for demonstration',
    schema: z.object({
      input: z.string(),
      options: z.object({
        format: z.enum(['json', 'text']).default('text')
      }).optional()
    })
  }
);

// Method 3: Using DynamicTool class directly (for more control)
const dynamicTool = new DynamicTool({
  name: 'advanced_tool',
  description: 'Advanced tool with custom behavior',
  requiresApproval: true,
  schema: z.object({
    operation: z.enum(['create', 'update', 'delete']),
    data: z.any()
  }),
  func: async (input, context) => {
    // Access context for user info, state, etc.
    const userId = context?.userId;
    const timestamp = context?.timestamp || new Date();

    // Perform operation
    const result = await performOperation(input.operation, input.data, userId);

    return new ToolResult({
      success: true,
      data: { result, userId, timestamp }
    });
  }
});

// Method 4: Extending BaseTool class (for complex tools with custom logic)
class CustomBaseTool extends BaseTool<typeof customSchema, { counter: number }, CustomOutput> {
  constructor() {
    super({
      name: 'custom_base_tool',
      description: 'Custom tool extending BaseTool',
      schema: customSchema,
      requiresApproval: false
    });
  }

  protected async _invoke(input: CustomInput, context?: ToolExecutionContext<{ counter: number }>) {
    // Custom validation
    if (!this.validateCustomInput(input)) {
      return new ToolResult({
        success: false,
        error: 'Custom validation failed',
        error_type: 'validation'
      });
    }

    // Access and modify state
    const state = context?.state || { counter: 0 };
    state.counter++;

    // Perform operation
    const result = await this.performCustomOperation(input);

    return {
      output: result,
      counter: state.counter,
      processed_at: new Date().toISOString()
    };
  }

  private validateCustomInput(input: any): boolean {
    // Custom validation logic
    return true;
  }

  private async performCustomOperation(input: CustomInput): Promise<any> {
    // Custom operation logic
    return { success: true };
  }
}

Tool Invocation

All tools follow the same async invocation pattern with comprehensive error handling:
// Basic invocation
const result = await readTool.invoke({ file_path: 'package.json' });

if (result.success) {
  console.log('File content:', result.data.content);
  console.log('File size:', result.data.size);
} else {
  console.error('Error:', result.error);
  console.error('Type:', result.error_type);
}

// MultiEditTool example with detailed results
const editResult = await multieditTool.invoke({
  file_path: 'config.ts',
  edits: [
    { old_string: 'debug: false', new_string: 'debug: true' },
    { old_string: 'port: 3000', new_string: 'port: 8080' }
  ]
});

if (editResult.success) {
  console.log(`Applied ${editResult.data.edits_successful}/${editResult.data.edits_total} edits`);
  console.log(`Total replacements: ${editResult.data.total_replacements}`);
  editResult.data.edit_results.forEach((edit, i) => {
    console.log(`Edit ${i + 1}: ${edit.success ? 'SUCCESS' : 'FAILED'} (${edit.occurrences} replacements)`);
  });
}

Error Handling

Handle different error types with specific recovery strategies:
const result = await tool.invoke(input);

if (!result.success) {
  switch (result.error_type) {
    case 'validation':
      // Handle input validation errors - check schema requirements
      console.error('Invalid input:', result.error);
      break;
    case 'permission':
      // Handle permission/access errors - check file permissions
      console.error('Access denied:', result.error);
      break;
    case 'file_not_found':
      // Handle missing files - create or check path
      console.error('File not found:', result.error);
      break;
    case 'security':
      // Handle security violations - path traversal, etc.
      console.error('Security violation:', result.error);
      break;
    case 'execution':
      // Handle runtime execution errors - tool-specific issues
      console.error('Execution failed:', result.error);
      break;
    case 'network':
      // Handle network/connectivity errors - E2B, MCP connections
      console.error('Network error:', result.error);
      break;
    default:
      console.error('Unknown error:', result.error);
  }
}

// Transaction-based error recovery
import { withTransaction } from '@ag-kit/tools/fs/transaction';

try {
  await withTransaction(fsOperator, async (transactionOp) => {
    // Multiple operations that must succeed together
    await transactionOp.writeFile('config.json', newConfig);
    await transactionOp.writeFile('backup.json', oldConfig);
    // If any operation fails, all changes are rolled back
  });
} catch (error) {
  console.error('Transaction failed, all changes rolled back:', error);
}

API Features

Type Safety

  • Full TypeScript Support: Compile-time type checking for all tool inputs and outputs
  • Runtime Validation: Zod schema validation with detailed error messages
  • Strongly Typed Results: Tool-specific return types with IntelliSense support
  • Generic Interfaces: Flexible typing for custom tool development

Async Operations

  • Promise-based API: All operations return promises for async/await support
  • Timeout Control: Configurable timeouts for long-running operations
  • Resource Management: Automatic cleanup and resource disposal
  • Cancellation Support: AbortController integration for operation cancellation

Error Handling

  • Structured Error Types: Categorized errors for programmatic handling
  • Detailed Context: Rich error information with stack traces and metadata
  • Consistent Format: Uniform error structure across all tools
  • Performance Monitoring: Execution time tracking and performance metrics

Advanced Features

  • Transaction Support: Atomic operations with rollback capability
  • Multi-Backend Support: Local, In-Memory, and Sandbox execution environments
  • Batch Operations: MultiEditTool for efficient bulk operations
  • Toolkit Management: Organized tool collections with lifecycle management
  • Event System: Tool and toolkit lifecycle events for monitoring
  • Security Features: Path validation, sandboxing, and permission controls

Tool Categories

File System Tools

API for file and directory operations with multiple backend support, including:
  • Individual Tools: Read, Write, Edit, MultiEdit, Glob, Grep, Ls operations
  • Transaction Support: Atomic operations with rollback capability
  • Multiple Backends: Local, In-Memory, and Sandbox file operators
  • Enhanced Toolkit: Configurable modes for different use cases
View API Reference →

Code Execution Tools

Secure multi-language code execution with sandbox isolation: Executors:
  • BuiltInCodeExecutor: E2B sandbox execution with full isolation
  • UnsafeLocalCodeExecutor: Local execution for trusted environments
Supported Languages:
  • Python, JavaScript/Node.js, TypeScript, Bash, R, Java, Go, C++, and more
Features:
  • Timeout control, resource limits, file system integration
  • Real-time output streaming and error handling
View API Reference →

Command Line Tools

Shell command execution with security validation and multi-command support: Tools:
  • BashTool: Single command execution with environment control
  • MultiCommandTool: Sequential command execution with state persistence
Security Features:
  • Command validation, path restrictions, environment isolation
  • Built-in command builders for common operations
View API Reference →

Browser Automation Tools

Web automation with Playwright and E2B sandbox integration: Features:
  • Secure browser automation in isolated environments
  • Screenshot capture, element interaction, JavaScript execution
  • VNC access for visual debugging
View API Reference →

MCP Integration

Model Context Protocol integration for external tool ecosystems: Components:
  • MCPToolkit: Manage tools from multiple MCP servers
  • MCPClientManager: Connection management and tool discovery
  • Transport Support: stdio, SSE, HTTP streaming
View API Reference →

API Reference

Latest Features & Examples

New in This Version

MultiEditTool

Perform multiple sequential edits on a single file with atomic operations:
import { createMultieditTool } from '@ag-kit/tools';

const multieditTool = createMultieditTool(context);

const result = await multieditTool.invoke({
  file_path: 'config.ts',
  edits: [
    { old_string: 'debug: false', new_string: 'debug: true' },
    { old_string: 'port: 3000', new_string: 'port: 8080' },
    { old_string: 'env: "dev"', new_string: 'env: "prod"' }
  ]
});

// Detailed results for each edit
result.data.edit_results.forEach((edit, i) => {
  console.log(`Edit ${i + 1}: ${edit.success ? 'SUCCESS' : 'FAILED'}`);
  console.log(`Replacements: ${edit.occurrences}`);
});

Transaction Support

Group multiple file operations with automatic rollback on failure:
import { withTransaction } from '@ag-kit/tools/fs/transaction';

await withTransaction(fsOperator, async (transactionOp) => {
  // All operations succeed or all are rolled back
  await transactionOp.writeFile('config.json', newConfig);
  await transactionOp.writeFile('backup.json', oldConfig);
  await transactionOp.rename('old-file.txt', 'archived-file.txt');
});

Enhanced FilesystemToolkit

Choose the optimal tool configuration for your use case:
import { FilesystemToolkit } from '@ag-kit/tools';

// Enhanced mode: atomic tools + multi-edit
const toolkit = new FilesystemToolkit({
  context,
  config: { mode: "enhanced" }
});

// Get tools by category
const fileOps = toolkit.getFileOperationTools(); // read, write, edit, MultiEdit
const utilities = toolkit.getUtilityTools();     // glob, grep, ls

// Switch modes dynamically
toolkit.switchMode("integrated"); // Use str-replace-editor
toolkit.switchMode("enhanced");   // Back to enhanced mode

Toolkit Management

Organize and manage multiple toolkits:
import { toolkitManager } from '@ag-kit/tools';

// Register toolkits
toolkitManager.register(filesystemToolkit);
toolkitManager.register(mcpToolkit);

// Initialize all toolkits
await toolkitManager.initializeAll();

// Get all tools from all toolkits
const allTools = toolkitManager.getAllTools();

// Find specific tools
const readTools = toolkitManager.findTool('read');

// Cleanup
await toolkitManager.destroyAll();