Search for nodes by name, keyword, or semantic similarity. Uses hybrid search (FTS5 BM25 + vector embeddings merged via Reciprocal Rank Fusion) as the primary search path, with graceful fallback to keyword matching. Args: query: Search string to match against node names and
(
query: str,
kind: str | None = None,
limit: int = 20,
repo_root: str | None = None,
context_files: list[str] | None = None,
model: str | None = None,
provider: str | None = None,
detail_level: str = "standard",
)
| 374 | |
| 375 | |
| 376 | def semantic_search_nodes( |
| 377 | query: str, |
| 378 | kind: str | None = None, |
| 379 | limit: int = 20, |
| 380 | repo_root: str | None = None, |
| 381 | context_files: list[str] | None = None, |
| 382 | model: str | None = None, |
| 383 | provider: str | None = None, |
| 384 | detail_level: str = "standard", |
| 385 | ) -> dict[str, Any]: |
| 386 | """Search for nodes by name, keyword, or semantic similarity. |
| 387 | |
| 388 | Uses hybrid search (FTS5 BM25 + vector embeddings merged via Reciprocal |
| 389 | Rank Fusion) as the primary search path, with graceful fallback to |
| 390 | keyword matching. |
| 391 | |
| 392 | Args: |
| 393 | query: Search string to match against node names and qualified names. |
| 394 | kind: Optional filter by node kind (File, Class, Function, Type, Test). |
| 395 | limit: Maximum results to return (default: 20). |
| 396 | repo_root: Repository root path. Auto-detected if omitted. |
| 397 | context_files: Optional list of file paths. Nodes in these files |
| 398 | receive a relevance boost. |
| 399 | detail_level: "standard" (full output) or "minimal" (summary only). |
| 400 | |
| 401 | Returns: |
| 402 | Ranked list of matching nodes. |
| 403 | """ |
| 404 | store, root = _get_store(repo_root) |
| 405 | try: |
| 406 | results = hybrid_search( |
| 407 | store, query, kind=kind, limit=limit, context_files=context_files, |
| 408 | model=model, provider=provider, |
| 409 | ) |
| 410 | |
| 411 | search_mode = "hybrid" |
| 412 | if not results: |
| 413 | search_mode = "keyword" |
| 414 | |
| 415 | summary = f"Found {len(results)} node(s) matching '{query}'" + ( |
| 416 | f" (kind={kind})" if kind else "" |
| 417 | ) |
| 418 | |
| 419 | if detail_level == "minimal": |
| 420 | minimal_results = [ |
| 421 | { |
| 422 | k: r[k] |
| 423 | for k in ("name", "kind", "file_path", "score") |
| 424 | if k in r |
| 425 | } |
| 426 | for r in results[:5] |
| 427 | ] |
| 428 | return { |
| 429 | "status": "ok", |
| 430 | "query": query, |
| 431 | "search_mode": search_mode, |
| 432 | "summary": summary, |
| 433 | "results": minimal_results, |
no test coverage detected