> ## Documentation Index
> Fetch the complete documentation index at: https://anam.ai/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Tool Calling Example

> Create your first tool and enable function calling in your AI persona

## What You'll Build

In this guide, you'll create a complete AI persona with tool calling capabilities. By the end, you'll have:

* A knowledge base with uploaded documents
* Multiple tools (knowledge, webhook, and client)
* A working persona that can search documents, call APIs, and trigger client actions

<Warning>**Beta Feature**: Tools and Knowledge Base are currently in beta. You may encounter some issues as we continue to improve these features. Please report any feedback or issues to help us make them better.</Warning>

<Info>This guide takes approximately 15 minutes to complete. We'll use both the Anam Lab UI and API for a complete understanding.</Info>

## Prerequisites

Before starting, ensure you have:

* An Anam account (sign up at [anam.ai](https://anam.ai))
* An API key (create one at `/api-keys`)
* Basic familiarity with REST APIs
* (Optional) Node.js or Python for testing

## Step 1: Create a Knowledge Folder

Knowledge folders organize your documents for semantic search. Let's create one for product documentation.

<Tabs>
  <Tab title="UI">
    1. Navigate to the Knowledge Base page at `/knowledge`

    2. Click **Create Folder**

    3. Enter the following details:
       * **Name**: Product Documentation
       * **Description**: Technical guides and product information

    4. Click **Create**

    <Check>
      Your folder is created with a unique ID. Note this ID for later use.
    </Check>
  </Tab>

  <Tab title="API">
    ```javascript theme={"system"}
    const response = await fetch("https://api.anam.ai/v1/knowledge/groups", {
      method: "POST",
      headers: {
        Authorization: "Bearer YOUR_API_KEY",
        "Content-Type": "application/json",
      },
      body: JSON.stringify({
        name: "Product Documentation",
        description: "Technical guides and product information",
      }),
    });

    const folder = await response.json();
    console.log("Folder ID:", folder.id);
    ```
  </Tab>
</Tabs>

## Step 2: Upload Documents

Upload documents to make them searchable. We'll use a PDF user guide as an example.

<Tabs>
  <Tab title="UI">
    1. On the Knowledge Base page, click into your **Product Documentation** folder

    2. Click **Upload Documents**

    3. Drag and drop your PDF or click to browse

    4. Click **Upload**

    5. Wait for processing to complete (\~30 seconds)

    <Check>
      The document status changes from PROCESSING to READY. It's now searchable!
    </Check>
  </Tab>

  <Tab title="API">
    All documents uploaded via the API use a secure, three-step signed upload process:

    **Step 1: Request a Signed Upload URL**

    ```javascript theme={"system"}
    const uploadResponse = await fetch(
      `https://api.anam.ai/v1/knowledge/groups/${YOUR_FOLDER_ID}/documents/presigned-upload`,
      {
        method: "POST",
        headers: {
          Authorization: "Bearer YOUR_API_KEY",
          "Content-Type": "application/json",
        },
        body: JSON.stringify({
          filename: "user-guide.pdf",
          contentType: "application/pdf",
          fileSize: 2048000,
        }),
      }
    );

    const { uploadUrl, documentId } = await uploadResponse.json();
    ```

    **Step 2: Upload Your File to the URL**

    ```javascript theme={"system"}
    const file = document.querySelector('input[type="file"]').files[0]; // Your File object
    await fetch(uploadUrl, {
      method: "PUT",
      headers: {
        "Content-Type": file.type,
      },
      body: file,
    });
    ```

    **Step 3: Confirm the Upload**

    ```javascript theme={"system"}
    await fetch(
      `https://api.anam.ai/v1/knowledge/documents/${documentId}/confirm-upload`,
      {
        method: "POST",
        headers: {
          Authorization: "Bearer YOUR_API_KEY",
          "Content-Type": "application/json",
        },
        body: JSON.stringify({
          fileSize: 2048000,
        }),
      }
    );
    ```

    <Tip>
      For complete, copy-pasteable code examples in different languages, see the dedicated [Document Upload Guide](/personas/knowledge/uploading-documents).
    </Tip>
  </Tab>
</Tabs>

<Warning>Documents must be in READY status before they can be searched. Processing typically takes 30 seconds but may take longer for large files.</Warning>

## Step 3: Create a Session with Tools

Ephemeral personas support two ways to configure tools at runtime:

1. **Reference pre-created tools** using `toolIds` - Best for reusing tools across different sessions or personas
2. **Define tools inline** using `tools` array - Best for session-specific or dynamic tool configurations

<Tabs>
  <Tab title="Using toolIds (Reusable)">
    First, create reusable tools via the API. These can be used across multiple sessions and personas.

    <AccordionGroup>
      <Accordion title="Create a Knowledge Tool">
        ```javascript theme={"system"}
        const knowledgeTool = await fetch("https://api.anam.ai/v1/tools", {
          method: "POST",
          headers: {
            Authorization: "Bearer YOUR_API_KEY",
            "Content-Type": "application/json",
          },
          body: JSON.stringify({
            name: "search_product_docs",
            description: "Search product documentation when users ask technical questions about features, installation, or usage",
            type: "SERVER_RAG",
            config: {
              documentFolderIds: ["YOUR_FOLDER_ID"], // From Step 1
            },
          }),
        }).then(res => res.json());
        ```
      </Accordion>

      <Accordion title="Create a Webhook Tool">
        ```javascript theme={"system"}
        const webhookTool = await fetch("https://api.anam.ai/v1/tools", {
          method: "POST",
          headers: {
            Authorization: "Bearer YOUR_API_KEY",
            "Content-Type": "application/json",
          },
          body: JSON.stringify({
            name: "check_order_status",
            description: "Check the status of a customer order when they provide an order ID",
            type: "SERVER_WEBHOOK",
            config: {
              url: "https://your-api.com/orders/status",
              method: "POST",
              headers: {
                "X-API-Key": "your-api-key",
              },
            },
          }),
        }).then(res => res.json());
        ```
      </Accordion>

      <Accordion title="Create a Client Tool">
        ```javascript theme={"system"}
        const clientTool = await fetch("https://api.anam.ai/v1/tools", {
          method: "POST",
          headers: {
            Authorization: "Bearer YOUR_API_KEY",
            "Content-Type": "application/json",
          },
          body: JSON.stringify({
            name: "open_product_page",
            description: "Open a product page when the user wants to see more details about a product",
            type: "CLIENT",
            config: {
              parameters: {
                type: "object",
                properties: {
                  productId: {
                    type: "string",
                    description: "The ID of the product to display",
                  },
                },
                required: ["productId"],
              },
            },
          }),
        }).then(res => res.json());
        ```
      </Accordion>
    </AccordionGroup>

    **Reference tools by ID in session**

    ```javascript theme={"system"}
    const sessionTokenResponse = await fetch("https://api.anam.ai/v1/auth/session-token", {
      method: "POST",
      headers: {
        Authorization: "Bearer YOUR_API_KEY",
        "Content-Type": "application/json",
      },
      body: JSON.stringify({
        personaConfig: {
          name: "Product Support Agent",
          avatarId: "YOUR_AVATAR_ID",
          voiceId: "YOUR_VOICE_ID",
          llmId: "YOUR_LLM_ID",
          systemPrompt: `You are a helpful product support agent. You can:
    - Search product documentation to answer technical questions
    - Check order status for customers
    - Open product pages when customers want more details

    Be friendly, concise, and proactive in helping customers.`,
          toolIds: [
            knowledgeTool.id,
            webhookTool.id,
            clientTool.id,
          ],
        },
      }),
    });

    const { sessionToken } = await sessionTokenResponse.json();
    ```

    <Check>
      This approach lets you manage tools centrally and reuse them across multiple sessions and personas.
    </Check>
  </Tab>

  <Tab title="Inline tools (Dynamic)">
    Define the complete tool configuration directly in the session token request:

    ```javascript theme={"system"}
    const sessionTokenResponse = await fetch("https://api.anam.ai/v1/auth/session-token", {
      method: "POST",
      headers: {
        Authorization: "Bearer YOUR_API_KEY",
        "Content-Type": "application/json",
      },
      body: JSON.stringify({
        personaConfig: {
          name: "Product Support Agent",
          avatarId: "YOUR_AVATAR_ID",
          voiceId: "YOUR_VOICE_ID",
          llmId: "YOUR_LLM_ID",
          systemPrompt: `You are a helpful product support agent. You can:
    - Search product documentation to answer technical questions
    - Check order status for customers
    - Open product pages when customers want more details

    Be friendly, concise, and proactive in helping customers.`,
          tools: [
            // Knowledge Tool - searches your uploaded documents
            {
              type: "server",
              subtype: "knowledge",
              name: "search_product_docs",
              description: "Search product documentation when users ask technical questions about features, installation, or usage",
              documentFolderIds: ["YOUR_FOLDER_ID"], // Folder ID from Step 1
            },
            // Webhook Tool - calls your external API
            {
              type: "server",
              subtype: "webhook",
              name: "check_order_status",
              description: "Check the status of a customer order when they provide an order ID",
              url: "https://your-api.com/orders/status",
              method: "POST",
              headers: {
                "X-API-Key": "your-api-key",
              },
              parameters: {
                type: "object",
                properties: {
                  orderId: {
                    type: "string",
                    description: "The order ID to check",
                  },
                },
                required: ["orderId"],
              },
            },
            // Client Tool - triggers events in your app
            {
              type: "client",
              name: "open_product_page",
              description: "Open a product page when the user wants to see more details about a product",
              parameters: {
                type: "object",
                properties: {
                  productId: {
                    type: "string",
                    description: "The ID of the product to display",
                  },
                },
                required: ["productId"],
              },
              awaitResult: true,
            },
          ],
        },
      }),
    });

    const { sessionToken } = await sessionTokenResponse.json();
    ```

    <Tip>
      Inline tools are perfect for dynamic configurations, user-specific parameters, or when tool behavior needs to change per session.
    </Tip>
  </Tab>
</Tabs>

## Step 4: Initialize SDK and Handle Events

<Steps>
  <Step title="Initialize SDK client">
    ```javascript theme={"system"}
    import { AnamClient, AnamEvent } from '@anam-ai/js-sdk';

    const client = new AnamClient({
    sessionToken: sessionToken,
    });

    console.log('Anam client initialized');

    ```
  </Step>

  <Step title="Set up event listeners">
    ```javascript theme={"system"}
    // Register a handler for the client tool
    client.registerToolCallHandler('open_product_page', {
      onStart: async (payload) => {
        console.log('Tool called:', payload.toolName);
        console.log('Arguments:', payload.arguments);
        window.location.href = `/products/${payload.arguments.productId}`;
        return `Opened product ${payload.arguments.productId}`;
      },
    });

    // Register handlers for the webhook and knowledge tools

    client.registerToolCallHandler('check_order_status', {
      onComplete: async (payload) => {
        const { toolName, result, executionTime } = payload;
        console.log(`Tool ${toolName} completed in ${executionTime}ms:`, result);
      }
    })

    client.registerToolCallHandler('search_product_docs', {
      onComplete: async (payload) => {
        const { toolName, result, executionTime } = payload;
        console.log(`Tool ${toolName} completed in ${executionTime}ms:`, result);
      }
    })

    // alternatively you can use the emitted events to register generic handlers
    // client.addListener(AnamEvent.TOOL_CALL_COMPLETED, (event) => {
    //   console.log(`Tool completed: ${event.toolName} in ${event.executionTime}ms`);
    // })


    // Handle session ready
    client.addListener(AnamEvent.SESSION_READY, () => {
      console.log('Session ready - persona is active');
    });

    // Connect and start streaming
    await client.streamToVideoElement('persona-video');
    ```

    <Check>
      Your persona can now search documents, call APIs, and trigger client actions!
    </Check>
  </Step>
</Steps>

## Testing Your Tools

Let's test the complete setup with example conversations:

### Testing Knowledge Tool

**User**: "How do I install the product?"

**Expected flow**:

1. LLM recognizes this as a technical question
2. Invokes `search_product_docs` tool
3. Retrieves relevant chunks from your user guide
4. Responds with accurate installation steps

### Testing Webhook Tool

**User**: "What's the status of my order ORD-12345?"

**Expected flow**:

1. LLM extracts order ID `ORD-12345`
2. Calls `check_order_status` webhook with `orderId: "ORD-12345"`
3. Receives response from your API
4. Tells user the current order status

### Testing Client Tool

**User**: "Show me more details about the premium plan"

**Expected flow**:

1. LLM identifies product name "premium plan"
2. Calls `open_product_page` client tool
3. SDK triggers the registered `open_product_page` handler
4. Navigation happens: `window.location.href = '/products/premium-plan'`

<Tip>Use your browser's developer console to see tool call events in real-time. This helps debug and understand the execution flow.</Tip>

## Troubleshooting

<AccordionGroup>
  <Accordion title="Knowledge tool returns no results">
    **Possible causes**:

    * Document still processing (check status)
    * Query doesn't match document content
    * Folder ID incorrect

    **Solutions**:

    1. Wait for document status to be READY
    2. Verify lifecycle events are firing i.e. `TOOL_CALL_STARTED`, `TOOL_CALL_COMPLETED` and `TOOL_CALL_FAILED` events.
    3. Verify expected documents are being read see [ToolCallCompletedPayload.documentsAccessed](/javascript-sdk/reference/events#toolcallcompletedpayload)
    4. Verify folder ID in tool configuration
  </Accordion>

  <Accordion title="Webhook tool times out">
    **Possible causes**:

    * External API is slow (>60s timeout)
    * Network connectivity issues
    * Invalid endpoint URL

    **Solutions**:

    1. Check endpoint URL is correct
    2. Test endpoint independently with curl
    3. Ensure API returns response within 60 seconds
    4. Check authentication headers are valid
    5. Verify lifecycle events are firing i.e. `TOOL_CALL_STARTED`, `TOOL_CALL_COMPLETED` and `TOOL_CALL_FAILED` events.
  </Accordion>

  <Accordion title="Client tool event not received">
    **Possible causes**:

    * SDK client not properly initialized
    * Event listener not registered before session starts
    * Tool name mismatch

    **Solutions**:

    1. Verify SDK client is initialized with valid session token
    2. Register handler using `client.registerToolCallHandler(toolName, handler)` before calling `streamToVideoElement`
    3. Match tool name exactly in your handler (case-sensitive)
    4. Check browser console for any SDK initialization errors
  </Accordion>
</AccordionGroup>

## Best Practices

### Tool Naming

Use descriptive, action-oriented names:

```typescript theme={"system"}
// ✅ Good
search_product_docs;
check_order_status;
open_checkout_page;

// ❌ Bad
search;
api_call;
tool1;
```

### Tool Descriptions

Be specific about when the LLM should use the tool:

```typescript theme={"system"}
// ✅ Good
description: "Search product documentation when users ask technical questions about features, installation, troubleshooting, or usage";

// ❌ Bad
description: "Searches documents";
```

### System Prompts

Guide the LLM on how to use tools effectively:

```typescript theme={"system"}
systemPrompt: `You are a helpful support agent. You have access to:
- Product documentation (use search_product_docs for technical questions)
- Order tracking system (use check_order_status when users mention order numbers)
- Product pages (use open_product_page when users want to see details)

Always be helpful and proactive. If a user mentions an order number, offer to check its status.`;
```

## Next Steps

<CardGroup cols={2}>
  <Card title="Client Tool Events" icon="browser" href="/personas/tools/client-tools">
    Learn to handle client tool events in your application
  </Card>

  <Card title="Knowledge Tools Deep Dive" icon="magnifying-glass" href="/personas/knowledge/tools">
    Advanced knowledge tool configuration and optimization
  </Card>

  <Card title="Webhook Tools Guide" icon="webhook" href="/personas/tools/webhook-tools">
    Integrate external APIs with webhook tools
  </Card>

  <Card title="SDK Reference" icon="code" href="/javascript-sdk/reference/events#tool-call-events">
    Complete SDK documentation for tool events
  </Card>
</CardGroup>
