1use anyhow::Result;
2use async_trait::async_trait;
3use chrono::{DateTime, Utc};
4
5use std::collections::HashMap;
6
7use crate::domain::models::{
8 AvecState, BatchRekeyResult, ChangeQueryResult, ConnectorMetadata, NodeDeleteRequest,
9 NodeDeleteResult, NodeQuery, NodeUpsertResult, SemanticTagNodeRef, SemanticTagQueryFilter,
10 SemanticTagRecord, SessionPurgeRequest, SttpNode, SyncCheckpoint, SyncCursor, ValidationResult,
11};
12
13#[async_trait]
18pub trait NodeStore: Send + Sync {
19 async fn query_nodes_async(&self, query: NodeQuery) -> Result<Vec<SttpNode>>;
21
22 async fn store_async(&self, node: SttpNode) -> Result<String> {
24 Ok(self.upsert_node_async(node).await?.node_id)
25 }
26
27 async fn upsert_node_async(&self, node: SttpNode) -> Result<NodeUpsertResult>;
29
30 async fn get_by_resonance_async(
32 &self,
33 session_id: &str,
34 current_avec: AvecState,
35 from_utc: Option<DateTime<Utc>>,
36 to_utc: Option<DateTime<Utc>>,
37 tiers: Option<&[String]>,
38 limit: usize,
39 ) -> Result<Vec<SttpNode>>;
40
41 async fn get_by_resonance_global_async(
43 &self,
44 current_avec: AvecState,
45 from_utc: Option<DateTime<Utc>>,
46 to_utc: Option<DateTime<Utc>>,
47 tiers: Option<&[String]>,
48 limit: usize,
49 ) -> Result<Vec<SttpNode>>;
50
51 async fn get_by_hybrid_async(
57 &self,
58 session_id: &str,
59 current_avec: AvecState,
60 from_utc: Option<DateTime<Utc>>,
61 to_utc: Option<DateTime<Utc>>,
62 tiers: Option<&[String]>,
63 query_embedding: Option<&[f32]>,
64 alpha: f32,
65 beta: f32,
66 limit: usize,
67 ) -> Result<Vec<SttpNode>> {
68 let _ = (query_embedding, alpha, beta);
69 self.get_by_resonance_async(session_id, current_avec, from_utc, to_utc, tiers, limit)
70 .await
71 }
72
73 async fn get_by_hybrid_global_async(
75 &self,
76 current_avec: AvecState,
77 from_utc: Option<DateTime<Utc>>,
78 to_utc: Option<DateTime<Utc>>,
79 tiers: Option<&[String]>,
80 query_embedding: Option<&[f32]>,
81 alpha: f32,
82 beta: f32,
83 limit: usize,
84 ) -> Result<Vec<SttpNode>> {
85 let _ = (query_embedding, alpha, beta);
86 self.get_by_resonance_global_async(current_avec, from_utc, to_utc, tiers, limit)
87 .await
88 }
89
90 async fn list_nodes_async(
92 &self,
93 limit: usize,
94 session_id: Option<&str>,
95 ) -> Result<Vec<SttpNode>>;
96
97 async fn get_last_avec_async(&self, session_id: &str) -> Result<Option<AvecState>>;
99
100 async fn get_trigger_history_async(&self, session_id: &str) -> Result<Vec<String>>;
102
103 async fn store_calibration_async(
105 &self,
106 session_id: &str,
107 avec: AvecState,
108 trigger: &str,
109 ) -> Result<()>;
110
111 async fn query_changes_since_async(
113 &self,
114 session_id: &str,
115 cursor: Option<SyncCursor>,
116 limit: usize,
117 ) -> Result<ChangeQueryResult>;
118
119 async fn get_checkpoint_async(
121 &self,
122 session_id: &str,
123 connector_id: &str,
124 ) -> Result<Option<SyncCheckpoint>>;
125
126 async fn put_checkpoint_async(&self, checkpoint: SyncCheckpoint) -> Result<()>;
128
129 async fn batch_rekey_scopes_async(
134 &self,
135 node_ids: Vec<String>,
136 target_tenant_id: &str,
137 target_session_id: &str,
138 dry_run: bool,
139 allow_merge: bool,
140 ) -> Result<BatchRekeyResult>;
141
142 async fn delete_nodes_async(&self, request: NodeDeleteRequest) -> Result<NodeDeleteResult>;
144
145 async fn purge_session_async(&self, request: SessionPurgeRequest) -> Result<NodeDeleteResult>;
147}
148
149#[derive(Debug, Clone)]
151pub struct TagEmbedding {
152 pub vector: Vec<f32>,
153 pub model: String,
154}
155
156#[async_trait]
158pub trait SemanticIndexStore: Send + Sync {
159 async fn sync_node_tags_async(
160 &self,
161 node_ref: SemanticTagNodeRef,
162 tags: &[String],
163 embeddings: Option<&HashMap<String, TagEmbedding>>,
164 ) -> Result<()>;
165
166 async fn delete_node_tags_async(&self, tenant_id: &str, sync_key: &str) -> Result<()>;
167
168 async fn find_sync_keys_by_tags_async(
169 &self,
170 tenant_id: &str,
171 tags: &[String],
172 match_all: bool,
173 session_id: Option<&str>,
174 limit: usize,
175 ) -> Result<Vec<String>>;
176
177 async fn find_tags_async(
178 &self,
179 tenant_id: &str,
180 prefix: Option<&str>,
181 limit: usize,
182 ) -> Result<Vec<String>>;
183
184 async fn query_tag_records_async(
185 &self,
186 filter: SemanticTagQueryFilter,
187 ) -> Result<Vec<SemanticTagRecord>>;
188}
189
190#[async_trait]
191pub trait SemanticIndexStoreInitializer: Send + Sync {
192 async fn initialize_async(&self) -> Result<()>;
193}
194
195#[async_trait]
196pub trait EmbeddingProvider: Send + Sync {
197 fn model_name(&self) -> &str;
198 async fn embed_async(&self, text: &str) -> Result<Vec<f32>>;
199}
200
201#[async_trait]
205pub trait NodeStoreInitializer: Send + Sync {
206 async fn initialize_async(&self) -> Result<()>;
207}
208
209pub trait NodeValidator: Send + Sync {
211 fn validate(&self, raw_node: &str) -> ValidationResult;
213 fn verify_psi(&self, node: &SttpNode) -> bool;
215}
216
217#[async_trait]
218pub trait SyncChangeSource: Send + Sync {
219 async fn read_changes_async(
220 &self,
221 session_id: &str,
222 connector_id: &str,
223 cursor: Option<SyncCursor>,
224 limit: usize,
225 ) -> Result<ChangeQueryResult>;
226}
227
228pub trait SyncCoordinatorPolicy: Send + Sync {
229 fn should_accept_node(&self, _node: &SttpNode) -> bool {
230 true
231 }
232
233 fn checkpoint_metadata(
234 &self,
235 _session_id: &str,
236 _connector_id: &str,
237 previous: Option<&SyncCheckpoint>,
238 _last_applied_node: Option<&SttpNode>,
239 _next_cursor: Option<&SyncCursor>,
240 ) -> Option<ConnectorMetadata> {
241 previous.and_then(|checkpoint| checkpoint.metadata.clone())
242 }
243}