ArctenArcten Docs

Tools

Add custom functionality to your agent with tools

Tools allow your agent to interact with your application by calling custom functions. The agent can intelligently decide when to use these tools based on user requests.

We believe in simplicity, so tools are just functions you provide to the agent. Our agent framework looks at function headers and reconstructs type schemas on the server in order to learn how to use your custom functions.

Overview

There are two types of tools:

  • tools: Require user confirmation before execution
  • safeTools: Auto-execute without confirmation

Basic Usage

import { ArctenAgent } from "@arcteninc/core";

function saveUserPreferences(theme: string, language: string) {
  localStorage.setItem('theme', theme);
  localStorage.setItem('language', language);
  return `Saved preferences: theme=${theme}, language=${language}`;
}

function getUserPreferences() {
  return {
    theme: localStorage.getItem('theme') || 'light',
    language: localStorage.getItem('language') || 'en'
  };
}

<ArctenAgent
  tools={[saveUserPreferences]}      // requires user confirmation
  safeTools={[getUserPreferences]}   // runs without confirmation
/>

Regular Tools

Regular tools show an approval UI before execution. Use these for actions that:

  • Modify or delete data
  • Send communications (emails, notifications)
  • Incur costs or have side effects
  • Require explicit user approval
function deleteUserAccount(userId: string) {
  // Delete account logic
  return `Account ${userId} deleted`;
}

function sendEmail(to: string, subject: string, body: string) {
  // Send email logic
  return `Email sent to ${to}`;
}

function purchaseItem(itemId: string, quantity: number) {
  // Purchase logic
  return `Purchased ${quantity}x item ${itemId}`;
}

<ArctenAgent
  tools={[deleteUserAccount, sendEmail, purchaseItem]}
/>

Safe Tools

Safe tools execute automatically without user confirmation. Use these for:

  • Read-only operations (fetching data, searching)
  • Non-destructive actions (getting current time, reading preferences)
  • Actions that don't modify important user data
function getUserProfile(userId: string) {
  return { id: userId, name: "John Doe", email: "john@example.com" };
}

function searchProducts(query: string) {
  return [
    { id: 1, name: "Product 1", price: 29.99 },
    { id: 2, name: "Product 2", price: 49.99 }
  ];
}

function getCurrentTime() {
  return new Date().toLocaleString();
}

function getWeather(city: string) {
  // Fetch weather data
  return { city, temp: 72, condition: "sunny" };
}

<ArctenAgent
  safeTools={[getUserProfile, searchProducts, getCurrentTime, getWeather]}
/>

Best Practices

Naming Functions

Use clear, descriptive function names. The agent reads these names to understand what each tool does.

// Good
function getUserOrderHistory(userId: string) { ... }
function cancelOrder(orderId: string) { ... }
function searchProductsByCategory(category: string) { ... }

// Bad
function func1(id: string) { ... }
function doStuff(x: string) { ... }
function handler(arg: string) { ... }

Parameter Names

Use descriptive parameter names. The agent uses these to understand what values to pass.

// Good - clear parameter names
function createInvoice(customerId: string, amount: number, dueDate: string) {
  return `Invoice created for customer ${customerId}: $${amount}, due ${dueDate}`;
}

// Less clear
function createInvoice(id: string, amt: number, date: string) {
  return `Invoice created`;
}

Return Values

Return meaningful, descriptive results. The agent reads these to understand what happened and communicate back to the user.

// Good
function updateSettings(theme: string, notifications: boolean) {
  localStorage.setItem('theme', theme);
  localStorage.setItem('notifications', String(notifications));
  return `Settings updated: theme set to ${theme}, notifications ${notifications ? 'enabled' : 'disabled'}`;
}

// Less helpful
function updateSettings(theme: string, notifications: boolean) {
  localStorage.setItem('theme', theme);
  localStorage.setItem('notifications', String(notifications));
  return "OK";
}

Type Safety

Use TypeScript types for better agent understanding:

function createUser(name: string, email: string, age: number) {
  // The agent will understand that age must be a number
  return { id: crypto.randomUUID(), name, email, age };
}

function toggleFeature(featureName: string, enabled: boolean) {
  // The agent will understand that enabled is a boolean
  return `Feature ${featureName} ${enabled ? 'enabled' : 'disabled'}`;
}

Complex Examples

API Calls

async function fetchUserData(userId: string) {
  const response = await fetch(`/api/users/${userId}`);
  const data = await response.json();
  return data;
}

async function updateUserProfile(userId: string, name: string, bio: string) {
  const response = await fetch(`/api/users/${userId}`, {
    method: 'PATCH',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ name, bio })
  });
  const data = await response.json();
  return `Profile updated: ${data.name}`;
}

<ArctenAgent
  safeTools={[fetchUserData]}
  tools={[updateUserProfile]}
/>

Database Operations

async function searchOrders(userId: string, status: string) {
  const orders = await db.orders.findMany({
    where: { userId, status }
  });
  return orders;
}

async function cancelOrder(orderId: string) {
  const order = await db.orders.update({
    where: { id: orderId },
    data: { status: 'cancelled' }
  });
  return `Order ${orderId} cancelled successfully`;
}

<ArctenAgent
  safeTools={[searchOrders]}
  tools={[cancelOrder]}
/>

State Management

function getCartItems() {
  const cart = useCartStore.getState().items;
  return cart;
}

function addToCart(productId: string, quantity: number) {
  useCartStore.getState().addItem(productId, quantity);
  return `Added ${quantity}x product ${productId} to cart`;
}

function clearCart() {
  useCartStore.getState().clear();
  return "Cart cleared";
}

<ArctenAgent
  safeTools={[getCartItems]}
  tools={[addToCart, clearCart]}
/>

DOM Manipulation

Tools can interact with the DOM to control UI elements, scroll positions, and more.

function scrollToSection(sectionId: string) {
  const element = document.getElementById(sectionId);
  if (!element) {
    return `Section "${sectionId}" not found`;
  }
  element.scrollIntoView({ behavior: 'smooth', block: 'start' });
  return `Scrolled to ${sectionId}`;
}

function highlightElement(elementId: string) {
  const element = document.getElementById(elementId);
  if (!element) {
    return `Element "${elementId}" not found`;
  }
  element.classList.add('highlight');
  setTimeout(() => element.classList.remove('highlight'), 2000);
  return `Highlighted ${elementId}`;
}

function toggleSidebar() {
  const sidebar = document.getElementById('sidebar');
  if (!sidebar) {
    return 'Sidebar not found';
  }
  sidebar.classList.toggle('collapsed');
  const isCollapsed = sidebar.classList.contains('collapsed');
  return `Sidebar ${isCollapsed ? 'collapsed' : 'expanded'}`;
}

function getCurrentScrollPosition() {
  return {
    x: window.scrollX,
    y: window.scrollY,
    viewportHeight: window.innerHeight,
    documentHeight: document.documentElement.scrollHeight
  };
}

<ArctenAgent
  safeTools={[getCurrentScrollPosition]}
  tools={[scrollToSection, highlightElement, toggleSidebar]}
/>

Error Handling

Tools should handle errors gracefully and return descriptive error messages:

async function deletePost(postId: string) {
  try {
    const response = await fetch(`/api/posts/${postId}`, {
      method: 'DELETE'
    });

    if (!response.ok) {
      throw new Error(`Failed to delete: ${response.statusText}`);
    }

    return `Post ${postId} deleted successfully`;
  } catch (error) {
    return `Error deleting post: ${error.message}`;
  }
}

Tips

  • Start with a few essential tools and add more as needed
  • Test your tools thoroughly before adding them to the agent
  • Use safeTools for read operations to provide faster responses
  • Keep tool functions focused on a single responsibility
  • Document complex tools with clear return values and types
  • In failure cases, return descriptive error messages (or the default verbose error message) so the agent can plan around errors and use other functions to help the user