UNPKG

codevault

Version:

AI-powered semantic code search via Model Context Protocol

134 lines 4.99 kB
function getAPIUrl() { return process.env.CODEVAULT_RERANK_API_URL || ''; } function getAPIKey() { return process.env.CODEVAULT_RERANK_API_KEY || ''; } function getModel() { return process.env.CODEVAULT_RERANK_MODEL || 'rerank-v3.5'; } function getMaxFromEnv() { const envMax = Number.parseInt(process.env.CODEVAULT_RERANKER_MAX || '50', 10); return Number.isFinite(envMax) && envMax > 0 ? envMax : 50; } function getMaxTokensFromEnv() { const envMax = Number.parseInt(process.env.CODEVAULT_RERANKER_MAX_TOKENS || '8192', 10); return Number.isFinite(envMax) && envMax > 0 ? envMax : 8192; } function truncateText(text, maxTokens) { if (!text || typeof text !== 'string') { return ''; } const maxChars = maxTokens * 4; if (text.length <= maxChars) { return text; } return text.slice(0, maxChars); } export function isAPIRerankingConfigured() { const url = getAPIUrl(); const key = getAPIKey(); return Boolean(url && key); } async function callRerankAPI(query, documents, config = {}) { const apiUrl = config.apiUrl || getAPIUrl(); const apiKey = config.apiKey || getAPIKey(); const model = config.model || getModel(); if (!apiUrl) { throw new Error('CODEVAULT_RERANK_API_URL is not configured'); } if (!apiKey) { throw new Error('CODEVAULT_RERANK_API_KEY is not configured'); } // Standard reranking API format (Novita, Cohere, Jina AI, Voyage AI) const requestBody = { model: model, query: query, documents: documents, top_n: documents.length }; const response = await fetch(apiUrl, { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${apiKey}` }, body: JSON.stringify(requestBody) }); if (!response.ok) { const errorText = await response.text().catch(() => 'Unknown error'); throw new Error(`Rerank API error (${response.status}): ${errorText}`); } const data = await response.json(); // Handle standard reranking response format // Most providers (Novita, Cohere, Jina AI, Voyage AI) use this format if (data.results && Array.isArray(data.results)) { return data.results; } // Alternative response format (some providers use data array) if (data.data && Array.isArray(data.data)) { return data.data; } // Fallback for direct array response if (Array.isArray(data)) { return data; } throw new Error(`Unexpected rerank API response format. Expected {results: [...]} but got: ${JSON.stringify(data).slice(0, 200)}`); } export async function rerankWithAPI(query, candidates, options = {}) { if (!Array.isArray(candidates) || candidates.length <= 1) { return candidates; } const maxCandidates = Math.min(typeof options.max === 'number' && Number.isFinite(options.max) && options.max > 0 ? Math.floor(options.max) : getMaxFromEnv(), candidates.length); if (maxCandidates <= 1) { return candidates; } const topCandidates = candidates.slice(0, maxCandidates); const maxTokens = options.maxTokens || getMaxTokensFromEnv(); try { const texts = await Promise.all(topCandidates.map(async (candidate) => { let text; if (options.getTextAsync && typeof options.getTextAsync === 'function') { text = await options.getTextAsync(candidate); } else if (options.getText && typeof options.getText === 'function') { text = options.getText(candidate); } else { text = ''; } const textStr = typeof text === 'string' ? text : ''; return truncateText(textStr, maxTokens); })); const apiConfig = { apiUrl: options.apiUrl, apiKey: options.apiKey, model: options.model }; const results = await callRerankAPI(query, texts, apiConfig); const scoreMap = new Map(); for (const result of results) { const index = result.index; const score = result.relevance_score || result.score || 0; scoreMap.set(index, score); } const scored = topCandidates.map((candidate, index) => ({ candidate, score: scoreMap.get(index) || 0 })).sort((a, b) => b.score - a.score); scored.forEach((entry, index) => { entry.candidate.rerankerScore = entry.score; entry.candidate.rerankerRank = index + 1; }); const rerankedTop = scored.map(entry => entry.candidate); const remainder = candidates.slice(maxCandidates); return [...rerankedTop, ...remainder]; } catch (error) { console.error('API reranking failed:', error.message); return candidates; } } //# sourceMappingURL=api-reranker.js.map