# AI with Tools

This guide demonstrates how to use Robota with tool calling capabilities, allowing AI agents to automatically call functions to retrieve information or perform actions.

## Overview

The tool calling example shows how to:

- Define tools using manual JSON schemas with `createFunctionTool`
- Create AI agents that automatically call appropriate tools
- Handle tool execution results
- Monitor tool usage and statistics

## Code Example

```typescript
/**
 * 02-tool-calling.ts
 *
 * This example demonstrates tool calling functionality:
 * - Define tools using JSON schemas
 * - AI agent automatically calls appropriate tools
 * - Handle tool execution results
 * - Show tool usage statistics
 */

import { Robota, createFunctionTool } from '@robota-sdk/agent-core';
import { OpenAIProvider } from '@robota-sdk/agent-provider-openai';
import OpenAI from 'openai';
import dotenv from 'dotenv';

// Load environment variables from examples directory
dotenv.config();

// Define tool functions using createFunctionTool with manual JSON schema
const calculateTool = createFunctionTool(
  'calculate',
  'Performs basic mathematical calculations (add, subtract, multiply, divide)',
  {
    type: 'object',
    properties: {
      operation: {
        type: 'string',
        enum: ['add', 'subtract', 'multiply', 'divide'],
        description: 'Mathematical operation to perform',
      },
      a: {
        type: 'number',
        description: 'First number',
      },
      b: {
        type: 'number',
        description: 'Second number',
      },
    },
    required: ['operation', 'a', 'b'],
  },
  async (params) => {
    const { operation, a, b } = params;
    console.log(`🧮 Calculating: ${a} ${operation} ${b}`);

    let result: number;
    switch (operation) {
      case 'add':
        result = a + b;
        break;
      case 'subtract':
        result = a - b;
        break;
      case 'multiply':
        result = a * b;
        break;
      case 'divide':
        if (b === 0) throw new Error('Division by zero is not allowed');
        result = a / b;
        break;
      default:
        throw new Error(`Unknown operation: ${operation}`);
    }

    return { result, operation: `${a} ${operation} ${b} = ${result}` };
  },
);

async function main() {
  try {
    console.log('🛠️ Tool Calling Example Started...\n');

    // Validate API key
    const apiKey = process.env.OPENAI_API_KEY;
    if (!apiKey) {
      throw new Error('OPENAI_API_KEY environment variable is required');
    }

    // Create OpenAI client and provider
    const openaiClient = new OpenAI({ apiKey });
    const openaiProvider = new OpenAIProvider({
      client: openaiClient,
    });

    // Create Robota instance with tools
    const robota = new Robota({
      name: 'ToolAgent',
      aiProviders: [openaiProvider],
      defaultModel: {
        provider: 'openai',
        model: 'gpt-3.5-turbo',
        systemMessage: 'You are a helpful assistant that can perform calculations.',
      },
      tools: [calculateTool],
      logging: {
        level: 'info',
        enabled: true,
      },
    });

    // Test queries
    const queries = ['Hi', 'What is 5 plus 3?'];

    console.log(`📝 Executing ${queries.length} queries`);

    // Process each query with error handling
    for (let i = 0; i < queries.length; i++) {
      const query = queries[i];
      console.log(`\n${i + 1}. User: ${query}`);

      try {
        const response = await robota.run(query);
        console.log(`   Assistant: ${response}`);
      } catch (error) {
        console.error(`   Error: ${error}`);
        break;
      }

      if (i < queries.length - 1) {
        console.log('   ' + '─'.repeat(50));
      }
    }

    // Show Final Statistics
    console.log('\n📊 Final Statistics:');
    const stats = robota.getStats();
    console.log(`- Agent name: ${stats.name}`);
    console.log(`- Tools registered: ${stats.tools.join(', ')}`);
    console.log(`- History length: ${stats.historyLength}`);
    console.log(`- Uptime: ${Math.round(stats.uptime)}ms`);

    console.log('\n✅ Tool Calling Example Completed!');

    // Clean up resources
    await robota.destroy();
    process.exit(0);
  } catch (error) {
    console.error('❌ Error occurred:', error);
    process.exit(1);
  }
}

// Execute
main();
```

## Expected Output

```
🛠️ Tool Calling Example Started...

📝 Executing 2 queries

1. User: Hi
   Assistant: Hello! I'm a helpful assistant that can perform calculations. How can I help you today?

────────────────────────────────────────────────

2. User: What is 5 plus 3?
🧮 Calculating: 5 add 3
   Assistant: 5 plus 3 equals 8.

📊 Final Statistics:
- Agent name: ToolAgent
- Tools registered: calculate
- History length: 4
- Current provider: openai
- Uptime: 2347ms

✅ Tool Calling Example Completed!
```

## Key Features

### 1. **Function Tool Creation**

```typescript
const calculateTool = createFunctionTool(
  'calculate',
  'Tool description',
  {
    type: 'object',
    properties: {
      operation: {
        type: 'string',
        enum: ['add', 'subtract', 'multiply', 'divide'],
      },
    },
    required: ['operation', 'a', 'b'],
  },
  async (params) => {
    // Tool implementation
    return result;
  },
);
```

### 2. **Tool Registration**

```typescript
const robota = new Robota({
  tools: [calculateTool],
  systemMessage: 'You are a helpful assistant that can perform calculations.',
});
```

### 3. **Automatic Tool Calling**

The AI automatically determines when to use tools based on the user's request. No manual tool invocation needed.

### 4. **Tool Statistics**

Monitor tool usage through the agent's statistics:

```typescript
const stats = robota.getStats();
console.log(`Tools registered: ${stats.tools.join(', ')}`);
```

## Advanced Features

### Error Handling

Tools can throw errors that are handled gracefully:

```typescript
if (b === 0) throw new Error('Division by zero is not allowed');
```

### Multiple Tools

Register multiple tools for complex functionality:

```typescript
const robota = new Robota({
  tools: [calculateTool, weatherTool, timeTool],
});
```

### Tool Metadata

Access detailed execution information through conversation history and statistics.

## Best Practices

1. **Clear Tool Descriptions**: Provide detailed descriptions so the AI knows when to use each tool
2. **Parameter Validation**: Use JSON schema validation for robust parameter handling
3. **Error Handling**: Implement proper error handling in tool implementations
4. **Resource Cleanup**: Always call `robota.destroy()` to clean up resources
5. **Logging**: Enable logging to monitor tool execution and debug issues
