AgentForge

Define a Tool

Create type-safe tools with defineTool() — Zod schemas, execution, and configuration.

Basic Usage

import { defineTool } from '@ahzan-agentforge/core';
import { z } from 'zod';

const calculator = defineTool({
  name: 'calculator',
  description: 'Perform arithmetic calculations',
  input: z.object({
    expression: z.string().describe('Math expression to evaluate'),
  }),
  output: z.object({
    result: z.number(),
  }),
  execute: async ({ expression }) => {
    const result = eval(expression); // Use a safe evaluator in production
    return { result };
  },
});
from agentforge import define_tool
from pydantic import BaseModel, Field

class CalcInput(BaseModel):
    expression: str = Field(description="Math expression to evaluate")

class CalcOutput(BaseModel):
    result: float

calculator = define_tool(
    name="calculator",
    description="Perform arithmetic calculations",
    input=CalcInput,
    output=CalcOutput,
    execute=lambda inp: CalcOutput(result=eval(inp.expression)),
)

ToolConfig

interface ToolConfig<TInput, TOutput> {
  name: string;                    // Tool name (used by LLM)
  description: string;             // What the tool does (sent to LLM)
  input: ZodSchema<TInput>;        // Input validation schema
  output: ZodSchema<TOutput>;      // Output validation schema
  execute: (input: TInput) => Promise<TOutput>;

  // Optional
  timeout?: number;                // Execution timeout in ms (default: 30000)
  tags?: string[];                 // Categorization tags
  cacheable?: boolean;             // Enable result caching (default: false)
  retry?: RetryConfig;             // Retry configuration
  compensate?: ((input: TInput, output: TOutput) => Promise<void>) | 'irreversible';
  version?: string;                // Tool version string
}

Tool Object

defineTool() returns a Tool object with resolved defaults:

interface Tool<TInput, TOutput> {
  name: string;
  description: string;
  inputSchema: ZodSchema<TInput>;
  outputSchema: ZodSchema<TOutput>;
  execute: (input: TInput) => Promise<TOutput>;
  timeout: number;                 // Default: 30000
  tags: string[];                  // Default: []
  cacheable: boolean;              // Default: false
  retry: Required<RetryConfig>;    // Default: { maxAttempts: 3, backoff: 'exponential', baseDelay: 1000 }
  compensate?: ((input: TInput, output: TOutput) => Promise<void>) | 'irreversible';
}

Schema Descriptions

Add .describe() to Zod fields — these become the tool's parameter descriptions sent to the LLM:

const searchTool = defineTool({
  name: 'search',
  description: 'Search a knowledge base',
  input: z.object({
    query: z.string().describe('Search query'),
    limit: z.number().optional().describe('Max results to return'),
    category: z.enum(['docs', 'api', 'blog']).describe('Category to search'),
  }),
  output: z.object({
    results: z.array(z.object({
      title: z.string(),
      snippet: z.string(),
      url: z.string(),
    })),
  }),
  execute: async (input) => {
    // ...
  },
});

Timeout

Tools have a 30-second default timeout. Override per-tool:

const slowTool = defineTool({
  name: 'generate-report',
  description: 'Generate a detailed report (slow)',
  input: z.object({ topic: z.string() }),
  output: z.object({ report: z.string() }),
  execute: async ({ topic }) => { /* ... */ },
  timeout: 120_000, // 2 minutes
});

Next Steps