Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 18 additions & 15 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ members = [
]

[workspace.package]
version = "2.2.12"
version = "2.2.13"
edition = "2021"
rust-version = "1.80"
license = "MIT"
Expand Down
1 change: 1 addition & 0 deletions crates/codegraph-api/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ anyhow = { workspace = true }
tokio = { workspace = true }

[dev-dependencies]
async-trait = { workspace = true }
tempfile = "3"
camino = { workspace = true }
tokio = { workspace = true, features = ["rt-multi-thread", "macros"] }
Expand Down
108 changes: 107 additions & 1 deletion crates/codegraph-api/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
//! mới nhất (`ensure_fresh`: rebuild khi version file đổi). Query surface mới
//! của semgraph: search/symbol/flow/search_flow/callers/callees/references.

use codegraph_context::ContextRequest;
use codegraph_context::{Candidate, ContextRequest, Judge, RerankInfo};
use codegraph_core::{
CallSiteResult, ClassInfo, DependenciesReport, Error, FileInfo, FlowResult, FullFlowPath,
FunctionScope, MemberInfo, ResolveResult, Result, SearchFlowResult, Symbol, SymbolKind,
Expand Down Expand Up @@ -176,6 +176,16 @@ pub struct ResumeSearchOutcome {
pub index_version: u64,
}

/// Kết quả `search_symbol_reranked`: symbol kèm xác suất (nếu có).
#[derive(Debug)]
pub struct RerankedSearch {
pub symbols: Vec<(Symbol, Option<f32>)>,
/// Tổng số khớp gốc của search (trước rerank) — không phải số phần tử trả về.
pub total: usize,
pub no_match: bool,
pub rerank: Option<RerankInfo>,
}

/// Kết quả resumable cho search trả `Vec<CallSiteResult>` (`codegraph_references`
/// / `codegraph_search_by_call`). Cùng hình dạng [`ResumeSearchOutcome`].
#[derive(Debug)]
Expand Down Expand Up @@ -331,6 +341,102 @@ impl GraphApi {
})
}

/// Symbol search có **rerank bằng Jev** — chỉ dùng cho trang đầu.
///
/// Pool rộng hơn `limit` (×4, cap `[jev] max_candidates`) để model có lựa
/// chọn, sau đó cắt về `limit`. Rerank phá tính ổn định của phân trang nên
/// chỉ nhận `offset = 0` và không có `resume`; caller phải từ chối hai
/// trường hợp đó trước khi gọi.
///
/// Fail-open: Jev lỗi/tắt → trả page theo thứ tự lexical kèm
/// `rerank.used = false`.
pub async fn search_symbol_reranked(
&self,
query: &str,
kind: Option<SymbolKind>,
mode: SymbolMatch,
limit: u32,
timeout_ms: u64,
judge: Option<&dyn Judge>,
) -> Result<RerankedSearch> {
let cfg = codegraph_core::jev_config();
let pool_limit = ((limit as usize) * 4)
.min(cfg.max_candidates)
.max(limit as usize) as u32;
let out = self
.search_symbol_paged_resumable(
query,
kind,
mode,
Pagination {
limit: pool_limit,
offset: 0,
},
None,
timeout_ms,
)
.await?;
if out.timed_out {
return Ok(RerankedSearch {
symbols: out.page.into_iter().map(|s| (s, None)).collect(),
total: out.total,
no_match: false,
rerank: Some(RerankInfo {
used: false,
reason: Some(
"search timed out — trả page thô, thử lại với timeout_ms lớn hơn".into(),
),
}),
});
}

let total = out.total;
let candidates: Vec<Candidate> = out
.page
.iter()
.map(|s| Candidate::symbol(s, None))
.collect();
let outcome =
codegraph_context::rank(query, cfg.repo.as_deref(), &candidates, cfg, judge).await;
if !outcome.used {
return Ok(RerankedSearch {
symbols: out
.page
.into_iter()
.take(limit as usize)
.map(|s| (s, None))
.collect(),
total,
no_match: false,
rerank: Some(outcome.info()),
});
}
let probabilities: std::collections::HashMap<u64, f32> =
outcome.ranking.iter().copied().collect();
let by_id: std::collections::HashMap<u64, Symbol> =
out.page.into_iter().map(|s| (s.id, s)).collect();
let symbols: Vec<(Symbol, Option<f32>)> = if outcome.no_match {
Vec::new()
} else {
outcome
.ranking
.iter()
.take(limit as usize)
.filter_map(|(id, _)| {
by_id
.get(id)
.map(|s| (s.clone(), probabilities.get(id).copied()))
})
.collect()
};
Ok(RerankedSearch {
symbols,
total,
no_match: outcome.no_match,
rerank: Some(outcome.info()),
})
}

/// Methods của class (compact projection).
pub async fn class_methods(&self, id: u64) -> Vec<MemberInfo> {
self.index().await.list_methods_of_class(id)
Expand Down
Loading
Loading