MCPcopy Index your code
hub / github.com/forloopcodes/contextplus / semanticIdentifierSearch

Function semanticIdentifierSearch

src/tools/semantic-identifiers.ts:347–423  ·  view source on GitHub ↗
(options: SemanticIdentifierSearchOptions)

Source from the content-addressed store, hash-verified

345}
346
347export async function semanticIdentifierSearch(options: SemanticIdentifierSearchOptions): Promise<string> {
348 const topK = Math.max(1, Math.floor(options.topK ?? 5));
349 const topCalls = Math.max(1, Math.floor(options.topCallsPerIdentifier ?? 10));
350 const semanticWeight = normalizeWeight(options.semanticWeight, 0.78);
351 const keywordWeight = normalizeWeight(options.keywordWeight, 0.22);
352 const includeKinds = normalizeKinds(options.includeKinds);
353
354 const index = await buildIdentifierIndex(options.rootDir);
355 if (index.docs.length === 0) {
356 return "No supported identifiers found for semantic identifier search.";
357 }
358
359 const [queryVec] = await fetchEmbedding(options.query);
360 const queryTerms = new Set(splitTerms(options.query));
361
362 const scored: RankedIdentifier[] = [];
363 for (let i = 0; i < index.docs.length; i++) {
364 const doc = index.docs[i];
365 if (includeKinds && !includeKinds.has(doc.kind.toLowerCase())) continue;
366
367 const semanticScore = Math.max(cosine(queryVec, index.vectors[i]), 0);
368 const keywordScore = getKeywordCoverage(queryTerms, `${doc.name} ${doc.signature} ${doc.path} ${doc.header}`);
369 const totalWeight = semanticWeight + keywordWeight;
370 const score = totalWeight > 0
371 ? clamp01((semanticWeight * semanticScore + keywordWeight * keywordScore) / totalWeight)
372 : semanticScore;
373
374 scored.push({ doc, semanticScore, keywordScore, score });
375 }
376
377 if (scored.length === 0) {
378 return "No identifiers matched the requested kind filters.";
379 }
380
381 const top = scored.sort((a, b) => b.score - a.score).slice(0, topK);
382 const cache = await loadEmbeddingCache(options.rootDir, IDENTIFIER_CACHE_FILE);
383
384 const lines: string[] = [
385 `Top ${top.length} identifier matches for: "${options.query}"`,
386 "",
387 ];
388
389 for (let i = 0; i < top.length; i++) {
390 const item = top[i];
391 const range = formatLineRange(item.doc.line, item.doc.endLine);
392 lines.push(`${i + 1}. ${item.doc.kind} ${item.doc.name} - ${item.doc.path} (${range})`);
393 lines.push(` Score: ${Math.round(item.score * 1000) / 10}% | Semantic: ${Math.round(item.semanticScore * 1000) / 10}% | Keyword: ${Math.round(item.keywordScore * 1000) / 10}%`);
394 lines.push(` Signature: ${item.doc.signature}`);
395 if (item.doc.parentName) lines.push(` Parent: ${item.doc.parentName}`);
396
397 const calls = await rankCallSites(
398 options.rootDir,
399 cache,
400 queryTerms,
401 queryVec,
402 item.doc,
403 index.fileLines,
404 topCalls,

Callers 1

index.tsFile · 0.85

Calls 12

normalizeKindsFunction · 0.85
buildIdentifierIndexFunction · 0.85
fetchEmbeddingFunction · 0.85
splitTermsFunction · 0.85
getKeywordCoverageFunction · 0.85
loadEmbeddingCacheFunction · 0.85
rankCallSitesFunction · 0.85
saveEmbeddingCacheFunction · 0.85
normalizeWeightFunction · 0.70
cosineFunction · 0.70
clamp01Function · 0.70
formatLineRangeFunction · 0.70

Tested by

no test coverage detected