-
Notifications
You must be signed in to change notification settings - Fork 1
Improve RAG context injection #223
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,2 @@ | ||
export const VECTOR_STORE_NAME = process.env.VECTOR_STORE_NAME || 'docs'; | ||
export const vectorSearchNumber = 20; | ||
export const vectorSearchNumber = 10; |
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
@@ -1,80 +1,190 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
import type { AgentContext } from '@agentuity/sdk'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
import type { ChunkMetadata } from '../doc-processing/types'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
import { VECTOR_STORE_NAME, vectorSearchNumber } from '../../../config'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
import type { RelevantDoc } from './types'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
export async function retrieveRelevantDocs(ctx: AgentContext, prompt: string): Promise<RelevantDoc[]> { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const dbQuery = { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
query: prompt, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
limit: vectorSearchNumber | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
/** | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
* Expands a group of chunks from the same path by creating a set of all needed chunk indices | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
* and querying for them once | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
*/ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
async function expandPathGroup( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
ctx: AgentContext, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
path: string, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
pathChunks: Array<{ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
path: string; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
content: string; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
relevanceScore?: number; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
chunkIndex?: number; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
}> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
): Promise<RelevantDoc | null> { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const contextWindow = 1; // Get 1 chunk before and after each chunk | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const expandedChunkIndices = new Set<number>(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// Add neighbors for each chunk to the set | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
for (const chunk of pathChunks) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if (chunk.chunkIndex !== undefined) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const targetIndex = chunk.chunkIndex; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// Add the chunk itself and its neighbors | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
expandedChunkIndices.add(targetIndex - contextWindow); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
expandedChunkIndices.add(targetIndex); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
expandedChunkIndices.add(targetIndex + contextWindow); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
try { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const vectors = await ctx.vector.search(VECTOR_STORE_NAME, dbQuery); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Comment on lines
+26
to
+35
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 💡 Verification agent 🧩 Analysis chainAdd upper bound validation for chunk indices. The code adds neighboring chunk indices without checking against First, let's verify if totalChunks metadata is available: If available, add upper bound checking: // Add neighbors for each chunk to the set
for (const chunk of pathChunks) {
if (chunk.chunkIndex !== undefined) {
const targetIndex = chunk.chunkIndex;
+ // Assuming totalChunks is available in metadata
+ const totalChunks = chunk.totalChunks || Number.MAX_SAFE_INTEGER;
// Add the chunk itself and its neighbors
- expandedChunkIndices.add(targetIndex - contextWindow);
+ if (targetIndex - contextWindow >= 0) {
+ expandedChunkIndices.add(targetIndex - contextWindow);
+ }
expandedChunkIndices.add(targetIndex);
- expandedChunkIndices.add(targetIndex + contextWindow);
+ if (targetIndex + contextWindow < totalChunks) {
+ expandedChunkIndices.add(targetIndex + contextWindow);
+ }
}
} 🏁 Script executed: #!/bin/bash
# Check if totalChunks is part of the chunk metadata
rg -A 5 "totalChunks" --type ts Length of output: 1901 Ensure upper‐bound validation when expanding chunk indices Add checks against
Suggested diff: for (const chunk of pathChunks) {
if (chunk.chunkIndex !== undefined) {
const targetIndex = chunk.chunkIndex;
+ const totalChunks = chunk.totalChunks;
- expandedChunkIndices.add(targetIndex - contextWindow);
+ if (targetIndex - contextWindow >= 0) {
+ expandedChunkIndices.add(targetIndex - contextWindow);
+ }
expandedChunkIndices.add(targetIndex);
- expandedChunkIndices.add(targetIndex + contextWindow);
+ if (targetIndex + contextWindow < totalChunks) {
+ expandedChunkIndices.add(targetIndex + contextWindow);
+ }
}
} This guarantees all added indices stay within 📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const uniquePaths = new Set<string>(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// Remove negative indices | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const validIndices = Array.from(expandedChunkIndices).filter(index => index >= 0); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
vectors.forEach(vec => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if (!vec.metadata) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
ctx.logger.warn('Vector missing metadata'); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
return; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const path = typeof vec.metadata.path === 'string' ? vec.metadata.path : undefined; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if (!path) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
ctx.logger.warn('Vector metadata path is not a string'); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
return; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
uniquePaths.add(path); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
}); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if (validIndices.length === 0) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
ctx.logger.warn('No valid chunk indices found for path: %s', path); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
return null; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const docs = await Promise.all( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Array.from(uniquePaths).map(async path => ({ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
path, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
content: await retrieveDocumentBasedOnPath(ctx, path) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
})) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// Sort indices | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
validIndices.sort((a, b) => a - b); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
return docs; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} catch (err) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
ctx.logger.error('Error retrieving relevant docs: %o', err); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
return []; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
try { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// Query for all chunks at once | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const chunkQueries = validIndices.map(index => | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
ctx.vector.search(VECTOR_STORE_NAME, { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
query: ' ', | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
limit: 1, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
metadata: { path: path, chunkIndex: index } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
}) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const results = await Promise.all(chunkQueries); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// Collect found chunks | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const foundChunks: Array<{ index: number; text: string }> = []; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
for (const result of results) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if (result.length > 0 && result[0] && result[0].metadata) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const metadata = result[0].metadata; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if (typeof metadata.chunkIndex === 'number' && typeof metadata.text === 'string') { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
foundChunks.push({ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
index: metadata.chunkIndex, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
text: metadata.text | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
}); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if (foundChunks.length === 0) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
ctx.logger.warn('No chunks found for path: %s', path); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
return null; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// Sort by index and combine content | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const sortedChunks = foundChunks.sort((a, b) => a.index - b.index); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const expandedContent = sortedChunks.map(chunk => chunk.text).join('\n\n'); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// Find the best relevance score from the original chunks | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const bestScore = Math.max(...pathChunks.map(chunk => chunk.relevanceScore || 0)); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Handle empty array case for Math.max.
- const bestScore = Math.max(...pathChunks.map(chunk => chunk.relevanceScore || 0));
+ const scores = pathChunks.map(chunk => chunk.relevanceScore || 0);
+ const bestScore = scores.length > 0 ? Math.max(...scores) : 0; 📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// Create chunk range | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const minIndex = Math.min(...sortedChunks.map(c => c.index)); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const maxIndex = Math.max(...sortedChunks.map(c => c.index)); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const chunkRange = minIndex === maxIndex ? `${minIndex}` : `${minIndex}-${maxIndex}`; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
ctx.logger.debug('Expanded path %s with %d chunks (range: %s) score %d', path, foundChunks.length, chunkRange, bestScore); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
return { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
path, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
content: expandedContent, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
relevanceScore: bestScore, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
chunkRange, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
chunkIndex: undefined // Not applicable for grouped chunks | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
}; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} catch (err) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
ctx.logger.error('Error expanding path group %s: %o', path, err); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
return null; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
async function retrieveDocumentBasedOnPath(ctx: AgentContext, path: string): Promise<string> { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const dbQuery = { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
query: ' ', | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
limit: 1000, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
metadata: { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
path: path | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
export async function retrieveRelevantDocs(ctx: AgentContext, prompt: string): Promise<RelevantDoc[]> { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const dbQuery = { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
query: prompt, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
limit: vectorSearchNumber | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
try { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const vectors = await ctx.vector.search(VECTOR_STORE_NAME, dbQuery); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
ctx.logger.debug('Vector search returned %d results. First vector structure: %o', | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
vectors.length, vectors[0]); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// Process each relevant chunk and expand with context | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const relevantChunks: Array<{ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
path: string; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
content: string; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
relevanceScore?: number; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
chunkIndex?: number; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
}> = []; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
for (const vector of vectors) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if (!vector.metadata) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
ctx.logger.warn('Vector missing metadata, skipping'); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
continue; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
try { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const vectors = await ctx.vector.search(VECTOR_STORE_NAME, dbQuery); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// Sort vectors by chunk index and concatenate text | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const sortedVectors = vectors | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
.map(vec => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const metadata = vec.metadata; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if (!metadata || typeof metadata.chunkIndex !== 'number' || typeof metadata.text !== 'string') { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
ctx.logger.warn('Invalid chunk metadata structure for path %s', path); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
return null; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
return { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
metadata, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
index: metadata.chunkIndex as number | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
}; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
}) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
.filter(item => item !== null) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
.sort((a, b) => a.index - b.index); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const fullText = sortedVectors | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
.map(vec => vec.metadata.text) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
.join('\n\n'); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
return fullText; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} catch (err) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
ctx.logger.error('Error retrieving document by path %s: %o', path, err); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
return ''; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const path = typeof vector.metadata.path === 'string' ? vector.metadata.path : undefined; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const text = typeof vector.metadata.text === 'string' ? vector.metadata.text : ''; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const chunkIndex = typeof vector.metadata.chunkIndex === 'number' ? vector.metadata.chunkIndex : undefined; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if (!path) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
ctx.logger.warn('Vector metadata path is not a string, skipping'); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
continue; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const relevanceScore = (vector as any).similarity; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
ctx.logger.debug('Vector for path %s, chunk %d: similarity=%s, relevanceScore=%s', | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
path, chunkIndex, (vector as any).similarity, relevanceScore); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
relevantChunks.push({ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
path, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
content: text, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
relevanceScore, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
chunkIndex: chunkIndex | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
}); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// Group chunks by path | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const chunksByPath = new Map<string, Array<{ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
path: string; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
content: string; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
relevanceScore?: number; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
chunkIndex?: number; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
}>>(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
for (const chunk of relevantChunks) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if (!chunksByPath.has(chunk.path)) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
chunksByPath.set(chunk.path, []); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const pathChunks = chunksByPath.get(chunk.path); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if (pathChunks) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
pathChunks.push(chunk); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// Expand each path group together | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const relevantDocs: RelevantDoc[] = []; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
for (const [path, pathChunks] of chunksByPath) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const expandedDoc = await expandPathGroup(ctx, path, pathChunks); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if (expandedDoc) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
relevantDocs.push(expandedDoc); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
ctx.logger.info('Retrieved and expanded %d relevant chunks from vector search', relevantDocs.length); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
return relevantDocs; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} catch (err) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
ctx.logger.error('Error retrieving relevant docs: %o', err); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
return []; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💡 Verification agent
🧩 Analysis chain
Consider batch deletion for better performance.
Deleting vectors one by one could be inefficient, especially with 100 vectors per batch. This results in 100 individual API calls per iteration.
Check if the vector API supports batch deletion:
If batch deletion is available, consider refactoring:
🏁 Script executed:
Length of output: 335
Unify and parallelize vector deletions for improved performance and reliability
No native batch‐delete method was found in the SDK, so we should at least run deletions in parallel and add error handling. Replace the sequential
for…await
loop with something like:• This runs all deletions concurrently to reduce overall latency.
• Using
Promise.allSettled
lets us log failures without aborting the entire batch.• For very large batches, consider chunking the
vectors
array to limit in‐flight requests.📝 Committable suggestion
🤖 Prompt for AI Agents