search_collection_enhanced
Search and filter collection content by type, category, and relevance with paginated results for precise discovery.
Instructions
Enhanced search for collection content with pagination, filtering, and sorting. Use this for advanced searches when users need specific content types or want to browse results in pages.
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| query | Yes | Search query for finding content. Examples: 'creative writer', 'explain like I'm five', 'coding assistant'. | |
| elementType | No | Filter by content type: personas, skills, agents, templates, tools, memories, prompts | |
| category | No | Filter by category: creative, professional, educational, personal, gaming | |
| page | No | Page number for paginated results (default: 1) | |
| pageSize | No | Number of results per page (default: 25, max: 100) | |
| sortBy | No | Sort results by relevance, name, or date |
Implementation Reference
- src/server/tools/CollectionTools.ts:47-95 (registration)Tool registration for 'search_collection_enhanced' including full input schema and thin handler that passes arguments to server.searchCollectionEnhanced{ tool: { name: "search_collection_enhanced", description: "Enhanced search for collection content with pagination, filtering, and sorting. Use this for advanced searches when users need specific content types or want to browse results in pages.", inputSchema: { type: "object", properties: { query: { type: "string", description: "Search query for finding content. Examples: 'creative writer', 'explain like I'm five', 'coding assistant'.", }, elementType: { type: "string", description: "Filter by content type: personas, skills, agents, templates, tools, memories, prompts", enum: ["personas", "skills", "agents", "templates", "tools", "memories", "prompts"] }, category: { type: "string", description: "Filter by category: creative, professional, educational, personal, gaming", enum: ["creative", "professional", "educational", "personal", "gaming"] }, page: { type: "number", description: "Page number for paginated results (default: 1)", minimum: 1 }, pageSize: { type: "number", description: "Number of results per page (default: 25, max: 100)", minimum: 1, maximum: 100 }, sortBy: { type: "string", description: "Sort results by relevance, name, or date", enum: ["relevance", "name", "date"] } }, required: ["query"], }, }, handler: (args: any) => server.searchCollectionEnhanced(args.query, { elementType: args.elementType, category: args.category, page: args.page, pageSize: args.pageSize, sortBy: args.sortBy }) },
- src/server/types.ts:36-36 (schema)TypeScript interface definition for the server.searchCollectionEnhanced method signature used by the tool handlersearchCollectionEnhanced(query: string, options?: any): Promise<any>;
- src/collection/CollectionSearch.ts:30-61 (handler)Core handler logic for enhanced collection search: validates query, attempts index-based search with filtering/pagination/sorting, falls back to legacy GitHub API/cache/seed search, converts results to consistent formatasync searchCollectionWithOptions(query: string, options: SearchOptions = {}): Promise<SearchResults> { const startTime = Date.now(); logger.debug(`CollectionSearch.searchCollectionWithOptions called with query: "${query}"`, options); // Validate search query for security try { validateSearchQuery(query, 1000); } catch (error) { const errorMessage = error instanceof Error ? error.message : String(error); logger.error('Search query validation failed:', { query, error: errorMessage }); ErrorHandler.logError('CollectionSearch.searchWithOptions.validateQuery', error, { query }); return this.createEmptySearchResults(query, options); } try { // Try index-based search first const indexResults = await this.searchFromIndex(query, options); const searchTime = Date.now() - startTime; logger.debug(`Index search completed in ${searchTime}ms with ${indexResults.items.length} results`); return { ...indexResults, searchTime }; } catch (error) { logger.debug('Index search failed, falling back to legacy search:', error); // Fallback to legacy search const legacyResults = await this.searchCollection(query); const searchTime = Date.now() - startTime; // Convert legacy results to new format return this.convertLegacyResults(legacyResults, query, options, searchTime); } }
- Index-based search helper: loads collection index, applies elementType/category filters, performs text matching across name/description/path/tags, sorts by relevance/name/date, applies pagination/** * Search from collection index with full featured search and pagination */ private async searchFromIndex(query: string, options: SearchOptions): Promise<SearchResults> { const index = await this.indexCache.getIndex(); const allEntries = this.flattenIndexEntries(index); // Filter by element type if specified let filteredEntries = allEntries; if (options.elementType) { filteredEntries = allEntries.filter(entry => entry.type === options.elementType); } // Filter by category if specified if (options.category) { filteredEntries = filteredEntries.filter(entry => entry.category === options.category); } // Search matching const matchedEntries = this.performIndexSearch(query, filteredEntries); // Sort results const sortedEntries = this.sortSearchResults(matchedEntries, options.sortBy || 'relevance', query); // Apply pagination const page = options.page || 1; const pageSize = options.pageSize || 25; const startIndex = (page - 1) * pageSize; const endIndex = startIndex + pageSize; const paginatedEntries = sortedEntries.slice(startIndex, endIndex); return { items: paginatedEntries, total: sortedEntries.length, page, pageSize, hasMore: endIndex < sortedEntries.length, query, searchTime: 0 // Will be set by caller }; }
- Helper for formatting enhanced search results with pagination indicators, content type icons, detailed metadata, and tool call suggestionsformatSearchResultsWithPagination(results: SearchResults, personaIndicator: string = ''): string { if (results.total === 0) { return `${personaIndicator}🔍 No content found for query: "${results.query}"`; } const startItem = (results.page - 1) * results.pageSize + 1; const endItem = Math.min(results.page * results.pageSize, results.total); const textParts = [ `${personaIndicator}🔍 **Search Results for "${results.query}"**\n`, `📊 Showing ${startItem}-${endItem} of ${results.total} results (Page ${results.page})\n`, `⚡ Search time: ${results.searchTime}ms\n\n` ]; results.items.forEach((item: IndexEntry) => { const contentIcons: { [key: string]: string } = { 'personas': '🎭', 'skills': '🛠️', 'agents': '🤖', 'prompts': '💬', 'templates': '📄', 'tools': '🔧', 'ensembles': '🎼', 'memories': '🧠' }; const icon = contentIcons[item.type] || '📄'; textParts.push( ` ${icon} **${item.name}** (${item.type})\n`, ` 📝 ${item.description}\n`, ` 🏷️ Tags: ${item.tags.join(', ')}\n`, ` 📂 Path: ${item.path}\n`, ` 📥 Install: \`install_collection_content "${item.path}"\`\n`, ` 👁️ Details: \`get_collection_content "${item.path}"\`\n\n` ); }); // Add pagination info if (results.hasMore) { const nextPage = results.page + 1; textParts.push(`📄 More results available. Use page ${nextPage} to see next ${results.pageSize} items.\n`); } return textParts.join(''); }