(options: { rootDir: string; relativePaths: string[] })
| 429 | } |
| 430 | |
| 431 | export async function refreshIdentifierEmbeddings(options: { rootDir: string; relativePaths: string[] }): Promise<number> { |
| 432 | const uniquePaths = Array.from(new Set(options.relativePaths.map(normalizeRelativePath).filter(Boolean))); |
| 433 | if (uniquePaths.length === 0) return 0; |
| 434 | |
| 435 | const cache = await loadEmbeddingCache(options.rootDir, IDENTIFIER_CACHE_FILE); |
| 436 | const pending: { key: string; hash: string; text: string }[] = []; |
| 437 | |
| 438 | for (const relativePath of uniquePaths) { |
| 439 | removeFileScopedCacheEntries(cache, relativePath); |
| 440 | const docs = await buildIdentifierDocsForFile(options.rootDir, relativePath); |
| 441 | for (const doc of docs) { |
| 442 | const key = `id:${doc.id}`; |
| 443 | const hash = hashContent(doc.text); |
| 444 | pending.push({ key, hash, text: doc.text }); |
| 445 | } |
| 446 | } |
| 447 | |
| 448 | if (pending.length > 0) { |
| 449 | const batchSize = getEmbeddingBatchSize(); |
| 450 | for (let i = 0; i < pending.length; i += batchSize) { |
| 451 | const batch = pending.slice(i, i + batchSize); |
| 452 | const vectors = await fetchEmbedding(batch.map((entry) => entry.text)); |
| 453 | for (let j = 0; j < batch.length; j++) { |
| 454 | cache[batch[j].key] = { hash: batch[j].hash, vector: vectors[j] }; |
| 455 | } |
| 456 | } |
| 457 | } |
| 458 | |
| 459 | await saveEmbeddingCache(options.rootDir, cache, IDENTIFIER_CACHE_FILE); |
| 460 | invalidateIdentifierSearchCache(); |
| 461 | return pending.length; |
| 462 | } |
no test coverage detected