crewai-ts
Version:
TypeScript port of crewAI for agent-based workflows
107 lines (106 loc) • 3.9 kB
JavaScript
/**
* WebSearchTool implementation
* Provides search capabilities for agents to gather information from the web
* Optimized for performance and error handling
*/
import { z } from 'zod';
import { createStructuredTool } from '../StructuredTool.js';
// Input schema for web search
const searchInputSchema = z.object({
query: z.string().min(1, "Search query cannot be empty"),
numResults: z.number().int().positive().default(5).optional(),
includeUrls: z.boolean().default(true).optional(),
includeDomains: z.array(z.string()).optional(),
excludeDomains: z.array(z.string()).optional(),
});
/**
* LRU Cache implementation for search results
*/
class LRUCache {
cache = new Map();
maxSize;
expiration; // Time in milliseconds
constructor(maxSize = 100, expiration = 3600000) {
this.maxSize = maxSize;
this.expiration = expiration;
}
get(key) {
const item = this.cache.get(key);
if (!item)
return undefined;
// Check if item has expired
if (Date.now() - item.timestamp > this.expiration) {
this.cache.delete(key);
return undefined;
}
// Refresh item position in cache (most recently used)
this.cache.delete(key);
this.cache.set(key, item);
return item.value;
}
set(key, value) {
// If cache is at capacity, remove least recently used item with optimized type safety
if (this.cache.size >= this.maxSize) {
// Handle potential undefined value with explicit type checks for memory optimization
const iterator = this.cache.keys();
const next = iterator.next();
// Verify that the iterator has a value before attempting to delete
if (!next.done && next.value !== undefined) {
const lruKey = next.value;
this.cache.delete(lruKey);
}
}
this.cache.set(key, { value, timestamp: Date.now() });
}
clear() {
this.cache.clear();
}
}
/**
* Default search implementation with fallback strategy
* This is a placeholder that would be replaced with actual API calls
*/
async function defaultSearch(input) {
// This would be implemented with actual search API calls
// For now just return a fallback result
return [{
title: "Search API not configured",
snippet: "Please configure a search API or provide a custom search function",
position: 1
}];
}
/**
* Creates a web search tool with the specified configuration
*/
export function createWebSearchTool(options = {}) {
// Configure search function
const searchFunction = options.customSearchFunction || defaultSearch;
// Set up caching if enabled
const resultCache = options.cacheResults ?
new LRUCache(100, options.cacheExpiration) :
undefined;
// Tool implementation
const toolOptions = {
name: "web_search",
description: "Search the web for information on a specific topic or query",
inputSchema: searchInputSchema,
cacheResults: !!options.cacheResults,
timeout: options.timeoutMs,
maxRetries: options.maxRetries,
func: async (input, runOptions) => {
// Use custom cache implementation if provided
if (resultCache) {
const cacheKey = JSON.stringify(input);
const cachedResult = resultCache.get(cacheKey);
if (cachedResult)
return cachedResult;
const results = await searchFunction(input);
resultCache.set(cacheKey, results);
return results;
}
// Without custom cache, rely on the tool's built-in caching
return await searchFunction(input);
}
};
return createStructuredTool(toolOptions);
}