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
-
Clear Descriptions: Provide detailed descriptions for tools and parameters so the agent understands when to use them.
-
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}`;
}
}
-
Type Safety: Use TypeScript types from
@distri/corefor better type safety. -
Async Operations: Tool handlers are async, so you can perform any asynchronous operations.
-
Minimal Responses: Return concise responses to avoid context bloat. Store detailed data separately if needed.
References
- Integrating within your product - Full integration example
- Using distri-client - Programmatic API usage
- Distri Core Types - Type definitions and utilities