Third-Party Tools
Integrate tools from popular external libraries and frameworks
ADK TypeScript is designed for extensibility, allowing integration with tools from other AI agent frameworks. While ADK doesn't currently include built-in wrappers for third-party frameworks, you can manually integrate external tools using the existing BaseTool and FunctionTool components.
Integration Approach
Third-party tool integration provides several key benefits:
- Faster Development: Leverage existing tools instead of building from scratch
- Ecosystem Access: Tap into established tool libraries and communities
- Best Practices: Use proven tools with established patterns
- Interoperability: Connect different AI frameworks and platforms
Manual Integration
ADK TypeScript currently requires manual integration of third-party tools. Built-in wrapper classes for popular frameworks are planned for future releases.
Integration Methods
🔧 Function Wrappers
Wrap external functions as ADK tools
🛠️ Custom Tool Classes
Create custom tool classes that extend BaseTool
📦 Library Integration
Integrate entire libraries with multiple tools
Function Wrapper Pattern
The simplest approach for integrating external tools is to wrap their functions using FunctionTool.
Basic Function Wrapping
import { FunctionTool } from '@iqai/adk';
// Example: Integrating a hypothetical search library
import { searchWeb } from 'some-search-library';
async function wrappedSearch(query: string, maxResults: number = 10) {
try {
const results = await searchWeb({
query,
limit: maxResults
});
return {
success: true,
results: results.map(r => ({
title: r.title,
url: r.url,
snippet: r.description
}))
};
} catch (error) {
return {
success: false,
error: error instanceof Error ? error.message : 'Search failed'
};
}
}
const searchTool = new FunctionTool(wrappedSearch, {
name: 'web_search',
description: 'Search the web for information on any topic'
});
Advanced Function Integration
For more complex external tools with multiple configuration options:
import { FunctionTool } from '@iqai/adk';
import { DatabaseClient } from 'some-database-library';
// Configure the external library
const dbClient = new DatabaseClient({
host: process.env.DB_HOST,
apiKey: process.env.DB_API_KEY
});
async function queryDatabase(
query: string,
table: string,
limit: number = 100
) {
try {
const result = await dbClient.query({
sql: query,
table,
maxRows: limit
});
return {
success: true,
data: result.rows,
count: result.count
};
} catch (error) {
return {
success: false,
error: `Database query failed: ${error instanceof Error ? error.message : 'Unknown error'}`
};
}
}
const dbTool = new FunctionTool(queryDatabase, {
name: 'query_database',
description: 'Execute SQL queries against the database'
});
Custom Tool Class Pattern
For more sophisticated integrations, create custom tool classes that extend BaseTool.
Basic Custom Tool
import { BaseTool } from '@iqai/adk';
import { ExternalService } from 'external-library';
interface ExternalToolConfig {
apiKey: string;
baseUrl?: string;
timeout?: number;
}
class ExternalTool extends BaseTool {
private client: ExternalService;
constructor(config: ExternalToolConfig) {
super({
name: 'external_tool',
description: 'Integration with external service'
});
this.client = new ExternalService({
apiKey: config.apiKey,
baseUrl: config.baseUrl || 'https://api.example.com',
timeout: config.timeout || 30000
});
}
async runAsync(args: {
operation: string;
parameters: Record<string, any>;
}) {
try {
switch (args.operation) {
case 'search':
return await this.client.search(args.parameters);
case 'create':
return await this.client.create(args.parameters);
case 'update':
return await this.client.update(args.parameters);
default:
return { error: `Unknown operation: ${args.operation}` };
}
} catch (error) {
return {
error: `External service error: ${error instanceof Error ? error.message : String(error)}`
};
}
}
getDeclaration() {
return {
name: this.name,
description: this.description,
parameters: {
type: 'object',
properties: {
operation: {
type: 'string',
description: 'Operation to perform',
enum: ['search', 'create', 'update']
},
parameters: {
type: 'object',
description: 'Parameters for the operation'
}
},
required: ['operation', 'parameters']
}
};
}
}
Multi-Operation Tool
For libraries with multiple related functions:
import { BaseTool } from '@iqai/adk';
class MultiOperationTool extends BaseTool {
constructor() {
super({
name: 'multi_tool',
description: 'Tool that can perform multiple operations'
});
}
async runAsync(args: {
operation: 'analyze' | 'process' | 'transform';
data: any;
options?: Record<string, any>;
}) {
const { operation, data, options = {} } = args;
try {
switch (operation) {
case 'analyze':
return await this.analyzeData(data, options);
case 'process':
return await this.processData(data, options);
case 'transform':
return await this.transformData(data, options);
default:
return { error: `Unknown operation: ${operation}` };
}
} catch (error) {
return {
error: `Operation failed: ${error instanceof Error ? error.message : String(error)}`
};
}
}
private async analyzeData(data: any, options: Record<string, any>) {
// Integration with external analysis library
// Return analysis results
return { analysis: 'result' };
}
private async processData(data: any, options: Record<string, any>) {
// Integration with external processing library
// Return processed data
return { processed: data };
}
private async transformData(data: any, options: Record<string, any>) {
// Integration with external transformation library
// Return transformed data
return { transformed: data };
}
getDeclaration() {
return {
name: this.name,
description: this.description,
parameters: {
type: 'object',
properties: {
operation: {
type: 'string',
description: 'Operation to perform',
enum: ['analyze', 'process', 'transform']
},
data: {
type: 'any',
description: 'Data to operate on'
},
options: {
type: 'object',
description: 'Optional parameters for the operation'
}
},
required: ['operation', 'data']
}
};
}
}
Integration Examples
LangChain-style Tools
If you want to integrate tools similar to LangChain's approach:
import { FunctionTool } from '@iqai/adk';
// Example: Creating a search tool similar to LangChain patterns
async function tavilySearch(query: string) {
// Integration with Tavily search API
const response = await fetch('https://api.tavily.com/search', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${process.env.TAVILY_API_KEY}`
},
body: JSON.stringify({ query })
});
if (!response.ok) {
return { error: 'Search failed' };
}
const data = await response.json();
return {
results: data.results.map((r: any) => ({
title: r.title,
url: r.url,
content: r.content
}))
};
}
const tavilyTool = new FunctionTool(tavilySearch, {
name: 'tavily_search',
description: 'Search the internet using Tavily search engine'
});
CrewAI-style Tools
For tools similar to CrewAI's approach:
import { BaseTool } from '@iqai/adk';
class SerperSearchTool extends BaseTool {
private apiKey: string;
constructor(apiKey: string) {
super({
name: 'serper_search',
description: 'Search Google using Serper API for real-time results'
});
this.apiKey = apiKey;
}
async runAsync(args: { query: string; type?: string; num?: number }) {
try {
const response = await fetch('https://google.serper.dev/search', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-API-KEY': this.apiKey
},
body: JSON.stringify({
q: args.query,
type: args.type || 'search',
num: args.num || 10
})
});
if (!response.ok) {
return { error: `Search failed: ${response.statusText}` };
}
const data = await response.json();
return {
organic: data.organic || [],
answerBox: data.answerBox,
knowledgeGraph: data.knowledgeGraph
};
} catch (error) {
return {
error: `Serper search failed: ${error instanceof Error ? error.message : String(error)}`
};
}
}
getDeclaration() {
return {
name: this.name,
description: this.description,
parameters: {
type: 'object',
properties: {
query: {
type: 'string',
description: 'Search query'
},
type: {
type: 'string',
description: 'Type of search (search, images, news)',
enum: ['search', 'images', 'news']
},
num: {
type: 'number',
description: 'Number of results to return (max 100)'
}
},
required: ['query']
}
};
}
}
Authentication and Configuration
Environment-based Configuration
interface ToolConfig {
apiKey?: string;
baseUrl?: string;
timeout?: number;
retries?: number;
}
class ConfigurableTool extends BaseTool {
private config: ToolConfig;
constructor(config: ToolConfig = {}) {
super({
name: 'configurable_tool',
description: 'Tool with flexible configuration'
});
this.config = {
apiKey: config.apiKey || process.env.TOOL_API_KEY,
baseUrl: config.baseUrl || process.env.TOOL_BASE_URL || 'https://api.example.com',
timeout: config.timeout || 30000,
retries: config.retries || 3
};
if (!this.config.apiKey) {
throw new Error('API key is required');
}
}
async runAsync(args: any) {
// Implementation using this.config
return { success: true };
}
getDeclaration() {
return {
name: this.name,
description: this.description,
parameters: {
type: 'object',
properties: {
// Define parameters
}
}
};
}
}
Error Handling and Reliability
Robust Error Handling
async function resilientToolWrapper(externalFunction: Function, ...args: any[]) {
const maxRetries = 3;
const backoffMs = 1000;
for (let attempt = 1; attempt <= maxRetries; attempt++) {
try {
const result = await externalFunction(...args);
return { success: true, data: result };
} catch (error) {
if (attempt === maxRetries) {
return {
success: false,
error: `Failed after ${maxRetries} attempts: ${error instanceof Error ? error.message : String(error)}`
};
}
// Exponential backoff
await new Promise(resolve => setTimeout(resolve, backoffMs * Math.pow(2, attempt - 1)));
}
}
}
Circuit Breaker Pattern
class CircuitBreakerTool extends BaseTool {
private failures = 0;
private lastFailureTime = 0;
private isOpen = false;
private readonly failureThreshold = 5;
private readonly resetTimeoutMs = 60000; // 1 minute
constructor() {
super({
name: 'circuit_breaker_tool',
description: 'Tool with circuit breaker for reliability'
});
}
async runAsync(args: any) {
if (this.isCircuitOpen()) {
return { error: 'Circuit breaker is open - service unavailable' };
}
try {
const result = await this.callExternalService(args);
this.onSuccess();
return result;
} catch (error) {
this.onFailure();
throw error;
}
}
private isCircuitOpen(): boolean {
if (this.isOpen && Date.now() - this.lastFailureTime > this.resetTimeoutMs) {
this.isOpen = false;
this.failures = 0;
}
return this.isOpen;
}
private onSuccess() {
this.failures = 0;
this.isOpen = false;
}
private onFailure() {
this.failures++;
this.lastFailureTime = Date.now();
if (this.failures >= this.failureThreshold) {
this.isOpen = true;
}
}
private async callExternalService(args: any) {
// Call external service
return { success: true };
}
getDeclaration() {
return {
name: this.name,
description: this.description,
parameters: {
type: 'object',
properties: {}
}
};
}
}
Future Development
Planned Features
Future versions of ADK TypeScript will include:
- Built-in wrapper classes for popular frameworks
- Automatic tool discovery and registration
- Enhanced type safety for third-party integrations
- Plugin architecture for easier extensibility
Expected Enhancements
- LangChainTool Class: Automatic wrapper for LangChain tools
- CrewAITool Class: Native integration with CrewAI tools
- Plugin System: Simplified plugin architecture
- Type Generation: Automatic TypeScript types from external schemas
- Tool Discovery: Automatic discovery of compatible tools
Best Practices
Integration Guidelines
- Clear Abstractions: Create clean interfaces between ADK and external tools
- Error Handling: Implement comprehensive error handling and recovery
- Type Safety: Maintain TypeScript type safety across integrations
- Documentation: Provide clear descriptions for LLM understanding
Performance Considerations
- Async Operations: Use non-blocking operations where possible
- Connection Pooling: Reuse connections for external services
- Caching: Cache results from expensive operations
- Timeout Management: Set appropriate timeouts for external calls
Security Practices
- Credential Management: Store credentials securely
- Input Validation: Validate all inputs before external calls
- Access Controls: Implement proper permission checks
- Audit Logging: Track usage and access patterns