Skip to main content

Overview

Create custom tools that agents can use alongside built-in tools.

Defining Tools

import { Agent, defineTool } from '@runtools/sdk';

const myDatabaseTool = defineTool({
  name: 'query_database',
  description: 'Query the application database',
  parameters: {
    type: 'object',
    properties: {
      sql: { 
        type: 'string', 
        description: 'SQL query to execute' 
      },
    },
    required: ['sql'],
  },
  execute: async ({ sql }) => {
    const result = await myDb.query(sql);
    return JSON.stringify(result.rows);
  },
});

Using Custom Tools

const agent = new Agent({
  apiKey: process.env.RUNTOOLS_API_KEY,
  systemPrompt: 'You help users query their data...',
  model: 'claude-opus-4-5',
  tools: [
    // Built-in tools
    'bash',
    'read_file',
    'edit_file',
    
    // Custom tools
    myDatabaseTool,
  ],
});

const result = await agent.run('Show me all users created this month');

Tool Parameters

const weatherTool = defineTool({
  name: 'get_weather',
  description: 'Get current weather for a location',
  parameters: {
    type: 'object',
    properties: {
      city: {
        type: 'string',
        description: 'City name',
      },
      units: {
        type: 'string',
        enum: ['celsius', 'fahrenheit'],
        description: 'Temperature units',
        default: 'celsius',
      },
    },
    required: ['city'],
  },
  execute: async ({ city, units = 'celsius' }) => {
    const weather = await fetchWeather(city, units);
    return JSON.stringify(weather);
  },
});

Async Tools

const slowApiTool = defineTool({
  name: 'slow_api_call',
  description: 'Call a slow external API',
  parameters: {
    type: 'object',
    properties: {
      endpoint: { type: 'string' },
    },
    required: ['endpoint'],
  },
  execute: async ({ endpoint }) => {
    // Async operations are fully supported
    const response = await fetch(endpoint);
    const data = await response.json();
    return JSON.stringify(data);
  },
});

Error Handling

const riskyTool = defineTool({
  name: 'risky_operation',
  description: 'Perform a risky operation',
  parameters: {
    type: 'object',
    properties: {
      input: { type: 'string' },
    },
    required: ['input'],
  },
  execute: async ({ input }) => {
    try {
      const result = await riskyOperation(input);
      return JSON.stringify({ success: true, result });
    } catch (error) {
      // Return error as result (agent will see it)
      return JSON.stringify({ 
        success: false, 
        error: error.message 
      });
    }
  },
});

Accessing Context

const contextAwareTool = defineTool({
  name: 'user_lookup',
  description: 'Look up information about the current user',
  parameters: {
    type: 'object',
    properties: {},
  },
  execute: async (params, context) => {
    // Access run context
    const userId = context.params?.userId;
    const user = await getUser(userId);
    return JSON.stringify(user);
  },
});

Composing Tools

const sendNotification = defineTool({
  name: 'send_notification',
  description: 'Send a notification to a user',
  parameters: {
    type: 'object',
    properties: {
      userId: { type: 'string' },
      message: { type: 'string' },
      channel: { 
        type: 'string', 
        enum: ['email', 'slack', 'sms'] 
      },
    },
    required: ['userId', 'message', 'channel'],
  },
  execute: async ({ userId, message, channel }) => {
    switch (channel) {
      case 'email':
        await sendEmail(userId, message);
        break;
      case 'slack':
        await sendSlack(userId, message);
        break;
      case 'sms':
        await sendSMS(userId, message);
        break;
    }
    return JSON.stringify({ sent: true, channel });
  },
});

Publishing Custom Tools

Share tools with your organization:
// Create tool in marketplace (org-private)
const tool = await rt.myTools.create({
  slug: 'my-internal-api',
  name: 'Internal API Tool',
  description: 'Query our internal API',
  parameters: { ... },
  code: `
    export async function execute({ endpoint }) {
      const res = await fetch(\`https://internal.mycompany.com\${endpoint}\`);
      return await res.json();
    }
  `,
});

// Now usable by all agents in your org
const agent = new Agent({
  tools: ['bash', 'my-internal-api'],
});

Tool Validation

const validatedTool = defineTool({
  name: 'process_order',
  description: 'Process a customer order',
  parameters: {
    type: 'object',
    properties: {
      orderId: { 
        type: 'string',
        pattern: '^ORD-[0-9]+$',
      },
      action: {
        type: 'string',
        enum: ['approve', 'reject', 'hold'],
      },
    },
    required: ['orderId', 'action'],
  },
  // Validation happens before execute
  execute: async ({ orderId, action }) => {
    // orderId is guaranteed to match pattern
    // action is guaranteed to be one of the enum values
    return processOrder(orderId, action);
  },
});

Types

import type { 
  Tool,
  ToolDefinition,
  ToolParameters,
  ToolContext,
} from '@runtools/sdk';

const tool: ToolDefinition = {
  name: 'my_tool',
  description: '...',
  parameters: { ... },
  execute: async (params, context) => { ... },
};