Refactor vector search to utilize Qdrant VectorDB

This commit is contained in:
Riz Ashraf committed 2026-09-30 14:37:41 +01:00
1 parent 61c0e88ad8
commit 3add6c3d31
4 files changed
+99 -31

No files matched your search

+38 -25
View File
@@ -618,41 +618,54 @@ impl McpTool for SemanticCodeSearchHandler {
let query_emb = generate_embedding_async(tool_args.query.clone()).await?;
// For MVP, we search across snippets dynamically. A true background codebase indexer would be a separate subsystem.
let mut results = Vec::new();
let mut texts_to_embed = Vec::new();
let mut metadata = Vec::new();
let snippets = state.snippets.read_with(|snips| snips.clone());
for snippet in snippets {
let combined = format!("{} {} {}", snippet.name, snippet.description, snippet.code);
texts_to_embed.push(combined);
metadata.push((snippet.name, snippet.description));
}
let sticky = state.sticky.read_with(|s| s.clone());
for note in sticky {
texts_to_embed.push(note.content.clone());
metadata.push(("StickyNote".to_string(), note.content.chars().take(200).collect::<String>()));
}
if let Ok(embeddings) = generate_embeddings_async(texts_to_embed).await {
for (emb, meta) in embeddings.into_iter().zip(metadata) {
let sim = cosine_similarity(&query_emb, &emb);
results.push((sim, meta.0, meta.1));
// Search using VectorDB if available
let mut vdb_search = false;
if let Some(vdb) = &*state.vector_db.read().await {
vdb_search = true;
if let Ok(search_results) = vdb.search(query_emb.clone(), 5).await {
for res in search_results {
results.push((res.score, res.id, res.text));
}
}
}
results.sort_by(|a, b| b.0.partial_cmp(&a.0).unwrap_or(std::cmp::Ordering::Equal));
// Fallback to manual loop if VectorDB is not initialized
if !vdb_search {
let mut texts_to_embed = Vec::new();
let mut metadata = Vec::new();
let snippets = state.snippets.read_with(|snips| snips.clone());
for snippet in snippets {
let combined = format!("{} {} {}", snippet.name, snippet.description, snippet.code);
texts_to_embed.push(combined);
metadata.push((snippet.name, snippet.description));
}
let sticky = state.sticky.read_with(|s| s.clone());
for note in sticky {
texts_to_embed.push(note.content.clone());
metadata.push(("StickyNote".to_string(), note.content.chars().take(200).collect::<String>()));
}
if let Ok(embeddings) = generate_embeddings_async(texts_to_embed).await {
for (emb, meta) in embeddings.into_iter().zip(metadata) {
let sim = cosine_similarity(&query_emb, &emb);
results.push((sim, meta.0, meta.1));
}
}
results.sort_by(|a, b| b.0.partial_cmp(&a.0).unwrap_or(std::cmp::Ordering::Equal));
results.truncate(5);
}
let top_results: Vec<_> = results.into_iter().take(5).collect();
if top_results.is_empty() {
if results.is_empty() {
return Ok(format!("No semantic matches found for query: {}", tool_args.query));
}
let mut out = format!("Semantic Search Results for '{}':\n", tool_args.query);
for (score, title, desc) in top_results {
for (score, title, desc) in results {
out.push_str(&format!("- [{:.2}] {}: {}\n", score, title, desc));
}