# Tool Calling

Agents that use Zod-validated function tools.

## Basic Tool

```typescript
import { Robota } from '@robota-sdk/agent-core';
import { createZodFunctionTool } from '@robota-sdk/agent-tools';
import { AnthropicProvider } from '@robota-sdk/agent-provider/anthropic';
import { z } from 'zod';

const provider = new AnthropicProvider({
  apiKey: process.env.ANTHROPIC_API_KEY,
});

const calculatorTool = createZodFunctionTool(
  'calculator',
  'Evaluate a math expression',
  z.object({
    expression: z.string().describe('The math expression to evaluate'),
  }),
  async ({ expression }) => ({
    data: String(eval(expression)),
  }),
);

const agent = new Robota({
  name: 'MathAgent',
  aiProviders: [provider],
  defaultModel: {
    provider: 'anthropic',
    model: 'claude-sonnet-4-6',
    systemMessage: 'You are a math assistant. Use the calculator tool for calculations.',
  },
  tools: [calculatorTool],
});

const response = await agent.run('What is (42 * 17) + 256?');
console.log(response);
// The agent calls calculator({ expression: '(42 * 17) + 256' }) and reports the result
```

## Multiple Tools

```typescript
const fileSearchTool = createZodFunctionTool(
  'search_files',
  'Search for files by name pattern',
  z.object({
    pattern: z.string().describe('Glob pattern'),
  }),
  async ({ pattern }) => {
    const { glob } = await import('fast-glob');
    const files = await glob(pattern);
    return { data: JSON.stringify(files) };
  },
);

const readFileTool = createZodFunctionTool(
  'read_file',
  'Read the contents of a file',
  z.object({
    path: z.string().describe('File path to read'),
  }),
  async ({ path }) => {
    const { readFileSync } = await import('fs');
    return { data: readFileSync(path, 'utf-8') };
  },
);

const agent = new Robota({
  name: 'FileAgent',
  aiProviders: [provider],
  defaultModel: { provider: 'anthropic', model: 'claude-sonnet-4-6' },
  tools: [fileSearchTool, readFileTool],
});

// The agent may call search_files first, then read_file on the results
const response = await agent.run('Find all .ts files in src/ and show me the smallest one');
```

## Using Built-in Tools

```typescript
import { bashTool, readTool, globTool, grepTool } from '@robota-sdk/agent-tools';

const agent = new Robota({
  name: 'DevAgent',
  aiProviders: [provider],
  defaultModel: { provider: 'anthropic', model: 'claude-sonnet-4-6' },
  tools: [bashTool, readTool, globTool, grepTool],
});

const response = await agent.run('Find all TODO comments in the project');
```

## Sandbox-Aware Built-in Tools

Use factory exports when Bash or file tools should run inside a provider sandbox instead of the host workspace:

```typescript
import {
  E2BSandboxClient,
  applyWorkspaceManifest,
  createBashTool,
  createEditTool,
  createReadTool,
  createWriteTool,
} from '@robota-sdk/agent-tools';
import { Sandbox } from 'e2b';

const sandbox = await Sandbox.create();
const sandboxClient = new E2BSandboxClient({ sandbox });

await applyWorkspaceManifest(sandboxClient, {
  entries: {
    'task.md': { type: 'file', content: 'Run the requested checks.\n' },
    output: { type: 'dir' },
  },
});

const agent = new Robota({
  name: 'SandboxedDevAgent',
  aiProviders: [provider],
  defaultModel: { provider: 'anthropic', model: 'claude-sonnet-4-6' },
  tools: [
    createBashTool({ sandboxClient }),
    createReadTool({ sandboxClient }),
    createWriteTool({ sandboxClient }),
    createEditTool({ sandboxClient }),
  ],
});
```

`E2BSandboxClient` is a structural adapter. Install and construct the concrete provider SDK in your application, then pass the adapter to Robota tools or `InteractiveSession`. Workspace manifests use the same sandbox port and prepare files/directories before the tools run. When a session store is present, snapshot-capable sandbox clients can persist a `sandboxSnapshotId` on shutdown and hydrate that workspace during non-fork resume.
