Frontend Tools

Build client-side tools that run in the browser

Create tools that run in the browser with access to DOM, state, and UI.


Why Frontend Tools?

  • Access browser APIs - DOM, localStorage, navigation
  • Use React state - Read/write app state directly
  • Show rich UI - Render components as results
  • Real-time updates - Stream results as they happen

Basic Tool

import { useTools } from '@yourgpt/copilot-sdk/react';
import { z } from 'zod';

function MyTools() {
  useTools({
    search_products: {
      description: 'Search the product catalog',
      parameters: z.object({
        query: z.string().describe('Search query'),
        limit: z.number().optional().default(10),
      }),
      handler: async ({ query, limit }) => {
        const results = await fetch(`/api/search?q=${query}&limit=${limit}`);
        return results.json();
      },
    },
  });

  return null;
}

Tool Structure

FieldRequiredDescription
descriptionYesWhat the tool does (AI reads this)
parametersYesZod schema for inputs
handlerYesAsync function that runs
requiresApprovalNoAsk user before running
hiddenNoHide tool from chat UI (still executes)

Multiple Tools

useTools({
  get_weather: {
    description: 'Get weather for a city',
    parameters: z.object({ city: z.string() }),
    handler: async ({ city }) => fetchWeather(city),
  },

  add_to_cart: {
    description: 'Add product to cart',
    parameters: z.object({
      productId: z.string(),
      quantity: z.number().default(1),
    }),
    handler: async ({ productId, quantity }) => {
      await cart.add(productId, quantity);
      return { success: true };
    },
  },

  navigate: {
    description: 'Go to a page in the app',
    parameters: z.object({ path: z.string() }),
    handler: async ({ path }) => {
      router.push(path);
      return { navigated: path };
    },
  },
});

With Approval

Require user confirmation before running:

useTools({
  delete_account: {
    description: 'Permanently delete user account',
    parameters: z.object({}),
    requiresApproval: true,
    handler: async () => {
      await deleteAccount();
      return { deleted: true };
    },
  },
});

Use requiresApproval: true for destructive or sensitive actions.


Hidden Tools

Hide tool execution from the chat UI while still executing normally:

useTools({
  navigate: {
    description: 'Navigate to a page in the app',
    parameters: z.object({ path: z.string() }),
    hidden: true, // Won't show in chat UI
    handler: async ({ path }) => {
      router.push(path);
      return { navigated: path };
    },
  },

  track_event: {
    description: 'Track analytics event',
    parameters: z.object({
      event: z.string(),
      properties: z.record(z.any()).optional(),
    }),
    hidden: true, // Silent background operation
    handler: async ({ event, properties }) => {
      analytics.track(event, properties);
      return { tracked: true };
    },
  },
});

Hidden tools are useful for navigation, analytics, or background operations that shouldn't clutter the chat UI.


AI Response Control

Control how the AI responds after tool execution:

handler: async ({ query }) => {
  const results = await search(query);

  return {
    data: results,
    _aiResponseMode: 'brief',      // 'verbose' | 'brief' | 'silent'
    _aiContext: `Found ${results.length} results`,
    _aiContent: 'Here are the results:',
  };
}
ModeBehavior
verboseAI explains results in detail
briefAI gives short summary
silentNo AI response, just show tool result

Error Handling

handler: async ({ query }) => {
  try {
    const results = await search(query);
    return { success: true, data: results };
  } catch (error) {
    return {
      success: false,
      error: error.message,
    };
  }
}

Best Practices

  1. Clear descriptions - AI uses this to decide when to call the tool
  2. Validate with Zod - Type safety and clear parameter docs
  3. Return structured data - AI understands JSON better than strings
  4. Handle errors - Return error info instead of throwing
  5. Use approval for destructive actions - Delete, purchase, send

Next Steps

On this page