gobby_code/vector/code_symbols/
search.rs1use crate::config::{CODE_SYMBOL_COLLECTION_PREFIX, Context};
2
3use super::embedding::{embed_query_with_source, embedding_source_from_context};
4use super::qdrant::{collection_name, vector_search};
5use super::types::{CodeSymbolVectorSearchHit, CodeSymbolVectorSearchRequest};
6
7#[derive(Debug, Clone, PartialEq, Eq)]
8pub enum SearchError {
9 MissingQdrantConfig,
10 MissingEmbeddingConfig,
11 QueryEmbeddingFailed,
12 VectorSearch(String),
13}
14
15impl std::fmt::Display for SearchError {
16 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
17 match self {
18 Self::MissingQdrantConfig => write!(f, "Qdrant config is missing"),
19 Self::MissingEmbeddingConfig => write!(f, "embedding config is missing"),
20 Self::QueryEmbeddingFailed => write!(f, "query embedding failed"),
21 Self::VectorSearch(error) => write!(f, "semantic vector search failed: {error}"),
22 }
23 }
24}
25
26impl std::error::Error for SearchError {}
27
28pub fn search_code_symbols(
29 ctx: &Context,
30 request: &CodeSymbolVectorSearchRequest,
31) -> Result<Vec<CodeSymbolVectorSearchHit>, SearchError> {
32 let qdrant_config = match &ctx.qdrant {
33 Some(config) => config,
34 None => return Err(SearchError::MissingQdrantConfig),
35 };
36
37 let embedding_source = match embedding_source_from_context(ctx) {
38 Some(source) => source,
39 None => return Err(SearchError::MissingEmbeddingConfig),
40 };
41
42 let embedding = match embed_query_with_source(&embedding_source, &request.query) {
43 Some(embedding) => embedding,
44 None => return Err(SearchError::QueryEmbeddingFailed),
45 };
46
47 let collection = collection_name(&request.collection_prefix, &request.project_id);
48 match vector_search(qdrant_config, &collection, &embedding, request.limit) {
49 Ok(hits) => Ok(hits
50 .into_iter()
51 .map(|(symbol_id, score)| CodeSymbolVectorSearchHit { symbol_id, score })
52 .collect()),
53 Err(error) => Err(SearchError::VectorSearch(error.to_string())),
54 }
55}
56
57pub fn semantic_search(ctx: &Context, query: &str, limit: usize) -> Vec<(String, f64)> {
61 let request = CodeSymbolVectorSearchRequest {
62 project_id: ctx.project_id.clone(),
63 query: query.to_string(),
64 limit,
65 collection_prefix: CODE_SYMBOL_COLLECTION_PREFIX.to_string(),
66 };
67
68 match search_code_symbols(ctx, &request) {
69 Ok(hits) => hits
70 .into_iter()
71 .map(|hit| (hit.symbol_id, hit.score))
72 .collect(),
73 Err(error) => {
74 log::warn!("semantic vector search skipped: {error}");
75 Vec::new()
76 }
77 }
78}