Skip to main content

Working with External Tools

External tools allow you to extend Distri agents with custom functionality that runs in your application. These tools execute in your frontend or backend environment, giving you full control over the implementation.

Overview

External tools are functions that your agent can call during execution. Unlike built-in tools, external tools are defined and executed in your application code, allowing you to:

  • Integrate with your existing UI components
  • Access browser APIs and DOM
  • Call your backend services
  • Perform client-side operations

Defining External Tools

External tools are defined using the DistriFnTool type from @distri/core:

import type { DistriFnTool } from '@distri/core';

const myTool: DistriFnTool = {
name: 'tool_name',
description: 'What this tool does',
type: 'function',
parameters: {
type: 'object',
properties: {
param1: { type: 'string', description: 'Description of param1' },
param2: { type: 'number', description: 'Description of param2' },
},
required: ['param1'],
},
handler: async (input) => {
// Your tool implementation
const result = await doSomething(input.param1, input.param2);
return `Tool executed: ${result}`;
},
};

Tool Handler Return Types

Tool handlers can return different types:

String Response

handler: async (input) => {
return 'Simple text response';
}

Structured Data

import type { DistriPart } from '@distri/core';

handler: async (input): Promise<DistriPart[]> => {
return [{
part_type: 'data',
data: {
success: true,
result: { /* your data */ },
},
}];
}

Multiple Parts

handler: async (input): Promise<DistriPart[]> => {
return [
{ part_type: 'text', data: 'Text response' },
{ part_type: 'data', data: { key: 'value' } },
];
}

Example: Google Maps Tool

Here's a complete example of an external tool for Google Maps:

import type { DistriFnTool } from '@distri/core';
import type { GoogleMapsManagerRef } from './GoogleMapsManager';

export const createMapTools = (map: GoogleMapsManagerRef): DistriFnTool[] => [
{
name: 'set_map_center',
description: 'Center the map at a specific location',
type: 'function',
parameters: {
type: 'object',
properties: {
latitude: { type: 'number', description: 'Latitude coordinate' },
longitude: { type: 'number', description: 'Longitude coordinate' },
zoom: {
type: 'number',
minimum: 1,
maximum: 20,
default: 13,
description: 'Zoom level (1-20)',
},
},
required: ['latitude', 'longitude'],
},
handler: async ({ latitude, longitude, zoom }) => {
await map.setMapCenter({ latitude, longitude, zoom });
return `Map centered at ${latitude}, ${longitude}`;
},
},
{
name: 'add_marker',
description: 'Add a marker to the map',
type: 'function',
parameters: {
type: 'object',
properties: {
latitude: { type: 'number' },
longitude: { type: 'number' },
title: { type: 'string' },
description: { type: 'string' },
},
required: ['latitude', 'longitude', 'title'],
},
handler: async ({ latitude, longitude, title, description }) => {
await map.addMarker({ latitude, longitude, title, description });
return `Marker added: ${title}`;
},
},
];

Using External Tools in React

Pass external tools to the Chat component:

import { Chat, useAgent } from '@distri/react';
import { createMapTools } from './tools';

function MapsContent() {
const { agent } = useAgent({ agentIdOrDef: 'maps_agent' });
const [threadId] = useState(() => crypto.randomUUID());
const mapRef = useRef<GoogleMapsManagerRef>(null);
const [tools, setTools] = useState<DistriAnyTool[]>([]);

useEffect(() => {
if (mapRef.current) {
setTools(createMapTools(mapRef.current));
}
}, []);

return (
<Chat
agent={agent}
threadId={threadId}
externalTools={tools}
/>
);
}

Advanced: Backend Tool Integration

External tools can also call backend APIs:

export const createBackendTool = (apiBase: string): DistriFnTool => ({
name: 'search_database',
description: 'Search the application database',
type: 'function',
parameters: {
type: 'object',
properties: {
query: { type: 'string' },
limit: { type: 'number', default: 10 },
},
required: ['query'],
},
handler: async ({ query, limit }) => {
const response = await fetch(`${apiBase}/search`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ query, limit }),
});
const data = await response.json();
return JSON.stringify(data);
},
});

Tool Configuration in Agent Definition

In your agent.md file, specify that the agent uses external tools:

---
name = "my_agent"
description = "Agent that uses external tools"

[tools]
external = ["*"] # Allow all external tools
# Or specify specific tools:
# external = ["set_map_center", "add_marker"]
---

Best Practices

  1. Clear Descriptions: Provide detailed descriptions for tools and parameters so the agent understands when to use them.

  2. Error Handling: Always handle errors gracefully in tool handlers:

handler: async (input) => {
try {
const result = await performOperation(input);
return `Success: ${result}`;
} catch (error) {
return `Error: ${error.message}`;
}
}
  1. Type Safety: Use TypeScript types from @distri/core for better type safety.

  2. Async Operations: Tool handlers are async, so you can perform any asynchronous operations.

  3. Minimal Responses: Return concise responses to avoid context bloat. Store detailed data separately if needed.

References