relay_knowledge/storage/contracts/
search.rs1use std::ops::Deref;
2
3use crate::domain::{GraphVersion, RetrievalHit, RetrieverSource, TraversalProvenanceTrace};
4
5pub const MAX_GRAPH_SEARCH_QUERY_CHARS: usize = 10_000;
7pub const MAX_GRAPH_SEARCH_FTS_TOKENS: usize = 128;
9pub const MAX_GRAPH_SEARCH_FTS_CODEPOINTS: usize = 1_024;
11pub const MAX_GRAPH_SEARCH_TOKEN_BYTES: usize = 128;
13pub const MAX_GRAPH_SEARCH_LIMIT: usize = 1_000;
15
16#[derive(Debug, Clone, PartialEq, Eq)]
18pub struct GraphSearchRequest {
19 pub query: String,
20 pub source_scope: Option<String>,
21 pub graph_version: GraphVersion,
22 pub limit: usize,
23 pub disabled_retriever_sources: Vec<RetrieverSource>,
24}
25
26impl GraphSearchRequest {
27 pub fn allows_retriever_source(&self, source: RetrieverSource) -> bool {
29 !self.disabled_retriever_sources.contains(&source)
30 }
31
32 pub fn max_trace_items(&self) -> usize {
34 self.limit
35 .saturating_mul(4)
36 .max(self.limit.saturating_add(8))
37 }
38}
39
40#[derive(Debug, Clone, PartialEq)]
42pub struct GraphSearchOutcome {
43 pub hits: Vec<RetrievalHit>,
44 pub trace: TraversalProvenanceTrace,
45}
46
47impl GraphSearchOutcome {
48 pub fn from_hits(request: &GraphSearchRequest, hits: Vec<RetrievalHit>) -> Self {
50 let mut trace = TraversalProvenanceTrace::from_hits(
51 request.graph_version,
52 request.source_scope.clone(),
53 routed_intent(&request.query),
54 &hits,
55 );
56 trace.apply_budget(request.max_trace_items());
57
58 Self { hits, trace }
59 }
60}
61
62impl Deref for GraphSearchOutcome {
63 type Target = [RetrievalHit];
64
65 fn deref(&self) -> &Self::Target {
66 &self.hits
67 }
68}
69
70fn routed_intent(query: &str) -> String {
71 if query.split_whitespace().count() <= 3 {
72 "direct_context_lookup".to_owned()
73 } else {
74 "multi_term_context_lookup".to_owned()
75 }
76}
77
78#[cfg(test)]
79#[path = "search_tests.rs"]
80mod tests;