Skip to main content

argyph_locate/
lib.rs

1use std::path::Path;
2use std::sync::Arc;
3
4pub mod path;
5pub mod resolve;
6pub mod smart;
7pub mod strategy;
8pub mod types;
9
10pub use types::*;
11
12pub async fn locate(
13    store: Arc<dyn argyph_store::Store>,
14    embedder: Arc<dyn argyph_embed::Embedder>,
15    root: &Path,
16    req: Request,
17) -> anyhow::Result<Response> {
18    if req.query.is_none() && req.path.is_none() {
19        anyhow::bail!("INVALID_ARGUMENT: query or path required");
20    }
21    if req.file.is_some() && req.files.is_some() {
22        anyhow::bail!("INVALID_ARGUMENT: file and files are mutually exclusive");
23    }
24    if req.path.is_some() && req.query.is_some() && req.file.is_none() {
25        anyhow::bail!("INVALID_ARGUMENT: scoped query requires `file`");
26    }
27
28    let max_results = req.max_results.clamp(1, 10) as usize;
29
30    let single_file: Option<i64> = if let Some(ref f) = req.file {
31        store.get_file_id(&camino::Utf8PathBuf::from(f)).await?
32    } else {
33        None
34    };
35
36    let file_ids: Option<Vec<i64>> = if req.file.is_some() {
37        single_file.map(|id| vec![id])
38    } else {
39        None
40    };
41
42    let has_tier2 = true;
43    let coverage = types::IndexCoverage {
44        tier_1_5: "ready".into(),
45        tier_2: if has_tier2 {
46            "ready".into()
47        } else {
48            "building".into()
49        },
50    };
51
52    let p = strategy::plan(req.query.as_deref(), req.path.as_deref(), has_tier2);
53    let strategy_used = strategy::strategy_of(&p);
54
55    let spans = match p {
56        strategy::Plan::StructuralPath { locator } => {
57            resolve::resolve_structural_path(
58                store,
59                root,
60                &locator,
61                single_file,
62                req.max_bytes_per_span,
63            )
64            .await?
65        }
66        strategy::Plan::StructuralSearch { query } => {
67            resolve::resolve_structural_search(
68                Arc::clone(&store),
69                root,
70                &query,
71                file_ids.as_deref(),
72                max_results,
73                req.max_bytes_per_span,
74            )
75            .await?
76        }
77        strategy::Plan::Semantic { query } | strategy::Plan::Hybrid { query } => {
78            resolve::resolve_hybrid(
79                Arc::clone(&store),
80                root,
81                embedder,
82                &query,
83                file_ids.as_deref(),
84                max_results,
85                req.max_bytes_per_span,
86            )
87            .await?
88        }
89        strategy::Plan::ScopedSemantic { locator, query } => {
90            resolve::resolve_scoped_semantic(
91                Arc::clone(&store),
92                root,
93                embedder,
94                &locator,
95                &query,
96                single_file,
97                max_results,
98                req.max_bytes_per_span,
99            )
100            .await?
101        }
102    };
103
104    Ok(Response {
105        spans,
106        strategy_used,
107        index_coverage: coverage,
108    })
109}