parallel_search_arxiv
Execute multiple arXiv searches simultaneously to gather comprehensive academic research from diverse perspectives. Provide up to 5 search queries covering different methodologies and angles.
Instructions
Run multiple arXiv searches in parallel for comprehensive research coverage and diverse academic angles. For best results, provide multiple search queries that explore different research angles and methodologies. You can use expand_query to help generate diverse queries, or create them yourself.
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| searches | Yes | Array of arXiv search configurations to execute in parallel (maximum 5 searches for optimal performance) | |
| timeout | No | Timeout in milliseconds for all searches |
Implementation Reference
- src/tools/jina-tools.ts:459-486 (handler)The main handler function for the parallel_search_arxiv tool. It validates the bearer token, deduplicates search queries, creates a wrapper for executeArxivSearch, executes parallel searches using executeParallelSearches, formats results, and handles errors.async ({ searches, timeout }: { searches: SearchArxivArgs[]; timeout: number }) => { try { const props = getProps(); const tokenError = checkBearerToken(props.bearerToken); if (tokenError) { return tokenError; } const uniqueSearches = searches.filter((search, index, self) => index === self.findIndex(s => s.query === search.query) ); // Use the common arXiv search function const arxivSearchFunction = async (searchArgs: SearchArxivArgs) => { return executeArxivSearch(searchArgs, props.bearerToken); }; // Execute parallel searches using utility const results = await executeParallelSearches(uniqueSearches, arxivSearchFunction, { timeout }); return { content: formatParallelSearchResultsToContentItems(results), }; } catch (error) { return createErrorResponse(`Error: ${error instanceof Error ? error.message : String(error)}`); } },
- src/tools/jina-tools.ts:452-458 (schema)Zod schema defining the input parameters for the parallel_search_arxiv tool: an array of up to 5 search configurations (query, num, tbs) and an optional timeout.searches: z.array(z.object({ query: z.string().describe("Academic search terms, author names, or research topics"), num: z.number().default(30).describe("Maximum number of academic papers to return, between 1-100"), tbs: z.string().optional().describe("Time-based search parameter, e.g., 'qdr:h' for past hour") })).max(5).describe("Array of arXiv search configurations to execute in parallel (maximum 5 searches for optimal performance)"), timeout: z.number().default(30000).describe("Timeout in milliseconds for all searches") },
- src/tools/jina-tools.ts:448-487 (registration)Registration of the parallel_search_arxiv tool using server.tool(), including name, description, schema, and handler function.server.tool( "parallel_search_arxiv", "Run multiple arXiv searches in parallel for comprehensive research coverage and diverse academic angles. For best results, provide multiple search queries that explore different research angles and methodologies. You can use expand_query to help generate diverse queries, or create them yourself. 💡 Use this when you need to explore multiple research directions simultaneously for efficiency.", { searches: z.array(z.object({ query: z.string().describe("Academic search terms, author names, or research topics"), num: z.number().default(30).describe("Maximum number of academic papers to return, between 1-100"), tbs: z.string().optional().describe("Time-based search parameter, e.g., 'qdr:h' for past hour") })).max(5).describe("Array of arXiv search configurations to execute in parallel (maximum 5 searches for optimal performance)"), timeout: z.number().default(30000).describe("Timeout in milliseconds for all searches") }, async ({ searches, timeout }: { searches: SearchArxivArgs[]; timeout: number }) => { try { const props = getProps(); const tokenError = checkBearerToken(props.bearerToken); if (tokenError) { return tokenError; } const uniqueSearches = searches.filter((search, index, self) => index === self.findIndex(s => s.query === search.query) ); // Use the common arXiv search function const arxivSearchFunction = async (searchArgs: SearchArxivArgs) => { return executeArxivSearch(searchArgs, props.bearerToken); }; // Execute parallel searches using utility const results = await executeParallelSearches(uniqueSearches, arxivSearchFunction, { timeout }); return { content: formatParallelSearchResultsToContentItems(results), }; } catch (error) { return createErrorResponse(`Error: ${error instanceof Error ? error.message : String(error)}`); } }, );
- src/utils/search.ts:91-120 (helper)Helper function that executes a single arXiv search by making a POST request to Jina's search API with domain='arxiv'.export async function executeArxivSearch( searchArgs: SearchArxivArgs, bearerToken: string ): Promise<SearchResultOrError> { try { const response = await fetch('https://svip.jina.ai/', { method: 'POST', headers: { 'Accept': 'application/json', 'Content-Type': 'application/json', 'Authorization': `Bearer ${bearerToken}`, }, body: JSON.stringify({ q: searchArgs.query, domain: 'arxiv', num: searchArgs.num || 30, ...(searchArgs.tbs && { tbs: searchArgs.tbs }) }), }); if (!response.ok) { return { error: `arXiv search failed for query "${searchArgs.query}": ${response.statusText}` }; } const data = await response.json() as any; return { query: searchArgs.query, results: data.results || [] }; } catch (error) { return { error: `arXiv search failed for query "${searchArgs.query}": ${error instanceof Error ? error.message : String(error)}` }; } }
- src/utils/search.ts:165-197 (helper)Helper function that executes multiple search functions in parallel with timeout and error handling, used by the tool handler.export async function executeParallelSearches<T>( searches: T[], searchFunction: (searchArgs: T) => Promise<SearchResultOrError>, options: ParallelSearchOptions = {} ): Promise<ParallelSearchResult[]> { const { timeout = 30000 } = options; // Execute all searches in parallel const searchPromises = searches.map(async (searchArgs) => { try { return await searchFunction(searchArgs); } catch (error) { return { error: `Search failed: ${error instanceof Error ? error.message : String(error)}` }; } }); // Wait for all searches with timeout const results = await Promise.allSettled(searchPromises); const timeoutPromise = new Promise(resolve => setTimeout(() => resolve('timeout'), timeout)); const completedResults = await Promise.race([ Promise.all(results.map(result => result.status === 'fulfilled' ? result.value : { error: 'Promise rejected' } )), timeoutPromise ]); if (completedResults === 'timeout') { throw new Error(`Parallel search timed out after ${timeout}ms`); } return completedResults as ParallelSearchResult[]; }