Skip to main content
Glama
result-formatter.ts6.51 kB
/** * Format search results for AI consumption */ import type { BaseDocument } from '../schema/base-schema.js'; import type { SearchResult } from './search-engine.js'; import type { PropertyInfo, ParameterInfo } from '../extractor/types.js'; /** * Formatted result item for display/AI consumption */ export interface FormattedItem { id: string; type: 'type' | 'method' | 'function' | 'script'; name: string; library: string; category: string; description: string; // For types typeKind?: string; properties?: PropertyInfo[]; nestedTypes?: string[]; typeDefinition?: string; // For methods/functions parameters?: ParameterInfo[]; returnType?: string; returnTypeDefinition?: string; signature?: string; className?: string; // For scripts filePath?: string; keywords?: string[]; } /** * Formatted search result */ export interface FormattedResult { summary: string; items: FormattedItem[]; totalMatches: number; facets: Record<string, Record<string, number>>; pagination: { offset: number; limit: number; hasMore: boolean; }; searchTime: number; } /** * Options for formatting results */ export interface FormatOptions { /** Maximum properties to include for types */ maxProperties?: number; /** Include file paths for scripts */ includeFilePaths?: boolean; } /** * Format search results for structured output */ export function formatResults( searchResult: SearchResult<BaseDocument>, options: FormatOptions = {} ): FormattedResult { const { maxProperties = 10, includeFilePaths = false } = options; const items = searchResult.results.map((doc) => formatDocument(doc, { maxProperties, includeFilePaths }) ); const resultCount = searchResult.results.length; const total = searchResult.totalMatches; let summary: string; if (resultCount === 0) { summary = 'No results found.'; } else if (resultCount === total) { summary = `Found ${total} result${total === 1 ? '' : 's'}.`; } else { summary = `Showing ${resultCount} of ${total} results.`; } return { summary, items, totalMatches: searchResult.totalMatches, facets: searchResult.facets, pagination: { offset: 0, // Would need to track this from search options limit: resultCount, hasMore: resultCount < total, }, searchTime: searchResult.searchTime, }; } /** * Format a single document */ function formatDocument( doc: BaseDocument, options: FormatOptions ): FormattedItem { const base: FormattedItem = { id: doc.id, type: doc.documentType as FormattedItem['type'], name: doc.name, library: doc.library, category: doc.category, description: doc.description, }; switch (doc.documentType) { case 'type': return formatTypeDocument(doc, base, options); case 'method': return formatMethodDocument(doc, base); case 'function': return formatFunctionDocument(doc, base); case 'script': return formatScriptDocument(doc, base, options); default: return base; } } /** * Format a type document */ function formatTypeDocument( doc: BaseDocument, base: FormattedItem, options: FormatOptions ): FormattedItem { let properties: PropertyInfo[] = []; try { properties = doc.properties ? JSON.parse(doc.properties) : []; } catch { // Ignore parse errors } const nestedTypes = doc.nestedTypes ? doc.nestedTypes.split(',').map((t) => t.trim()).filter(Boolean) : []; return { ...base, typeKind: doc.typeKind, properties: properties.slice(0, options.maxProperties || 10), nestedTypes, typeDefinition: doc.typeDefinition || undefined, }; } /** * Format a method document */ function formatMethodDocument( doc: BaseDocument, base: FormattedItem ): FormattedItem { let parameters: ParameterInfo[] = []; try { parameters = doc.parameters ? JSON.parse(doc.parameters) : []; } catch { // Ignore parse errors } return { ...base, parameters, returnType: doc.returnType || undefined, returnTypeDefinition: doc.returnTypeDefinition || undefined, signature: doc.signature || undefined, className: doc.className || undefined, }; } /** * Format a function document */ function formatFunctionDocument( doc: BaseDocument, base: FormattedItem ): FormattedItem { let parameters: ParameterInfo[] = []; try { parameters = doc.parameters ? JSON.parse(doc.parameters) : []; } catch { // Ignore parse errors } return { ...base, parameters, returnType: doc.returnType || undefined, signature: doc.signature || undefined, }; } /** * Format a script document */ function formatScriptDocument( doc: BaseDocument, base: FormattedItem, options: FormatOptions ): FormattedItem { const keywords = doc.keywords ? doc.keywords.split(' ').filter(Boolean) : []; return { ...base, filePath: options.includeFilePaths ? doc.filePath : undefined, keywords: keywords.length > 0 ? keywords : undefined, }; } /** * Format results as a string for AI consumption */ export function formatForAI( searchResult: SearchResult<BaseDocument>, options: FormatOptions = {} ): string { const formatted = formatResults(searchResult, options); const lines: string[] = [formatted.summary, '']; for (const item of formatted.items) { lines.push(`## ${item.name} (${item.type})`); lines.push(`Library: ${item.library}`); lines.push(`Category: ${item.category}`); lines.push(`Description: ${item.description}`); if (item.signature) { lines.push(`Signature: ${item.signature}`); } if (item.parameters && item.parameters.length > 0) { lines.push('Parameters:'); for (const param of item.parameters) { const opt = param.optional ? '?' : ''; const typeDef = param.typeDefinition ? ` = ${param.typeDefinition}` : ''; lines.push(` - ${param.name}${opt}: ${param.type}${typeDef}`); } } if (item.returnType) { const returnDef = item.returnTypeDefinition ? ` = ${item.returnTypeDefinition}` : ''; lines.push(`Returns: ${item.returnType}${returnDef}`); } if (item.properties && item.properties.length > 0) { lines.push('Properties:'); for (const prop of item.properties) { const opt = prop.optional ? '?' : ''; lines.push(` - ${prop.name}${opt}: ${prop.type}`); } } lines.push(''); } return lines.join('\n'); }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/harche/ProDisco'

If you have feedback or need assistance with the MCP directory API, please join our Discord server