1use serde::{Deserialize, Serialize};
4use std::collections::HashMap;
5
6#[derive(Debug, Clone)]
12pub struct RetryConfig {
13 pub max_retries: u32,
15 pub base_delay: std::time::Duration,
17 pub max_delay: std::time::Duration,
19 pub jitter: bool,
21}
22
23impl Default for RetryConfig {
24 fn default() -> Self {
25 Self {
26 max_retries: 3,
27 base_delay: std::time::Duration::from_millis(100),
28 max_delay: std::time::Duration::from_secs(60),
29 jitter: true,
30 }
31 }
32}
33
34#[derive(Debug, Clone, Default)]
43pub struct RateLimitHeaders {
44 pub limit: Option<u64>,
46 pub remaining: Option<u64>,
48 pub reset: Option<u64>,
50 pub quota_used: Option<u64>,
52 pub quota_limit: Option<u64>,
54}
55
56impl RateLimitHeaders {
57 pub fn from_response(response: &reqwest::Response) -> Self {
59 let headers = response.headers();
60 fn parse(h: &reqwest::header::HeaderMap, name: &str) -> Option<u64> {
61 h.get(name)
62 .and_then(|v| v.to_str().ok())
63 .and_then(|s| s.parse().ok())
64 }
65 Self {
66 limit: parse(headers, "X-RateLimit-Limit"),
67 remaining: parse(headers, "X-RateLimit-Remaining"),
68 reset: parse(headers, "X-RateLimit-Reset"),
69 quota_used: parse(headers, "X-Quota-Used"),
70 quota_limit: parse(headers, "X-Quota-Limit"),
71 }
72 }
73}
74
75#[derive(Debug, Clone, Serialize, Deserialize)]
81pub struct HealthResponse {
82 pub healthy: bool,
84 pub version: Option<String>,
86 pub uptime_seconds: Option<u64>,
88}
89
90#[derive(Debug, Clone, Serialize, Deserialize)]
92pub struct ReadinessResponse {
93 pub ready: bool,
95 pub components: Option<HashMap<String, bool>>,
97}
98
99#[derive(Debug, Clone, Serialize, Deserialize)]
105pub struct NamespaceInfo {
106 #[serde(alias = "namespace")]
108 pub name: String,
109 #[serde(default)]
111 pub vector_count: u64,
112 #[serde(alias = "dimension")]
114 pub dimensions: Option<u32>,
115 pub index_type: Option<String>,
117 #[serde(default)]
119 pub created: Option<bool>,
120}
121
122#[derive(Debug, Clone, Serialize, Deserialize)]
124pub struct ListNamespacesResponse {
125 pub namespaces: Vec<String>,
127}
128
129#[derive(Debug, Clone, Serialize, Deserialize)]
135pub struct Vector {
136 pub id: String,
138 pub values: Vec<f32>,
140 #[serde(skip_serializing_if = "Option::is_none")]
142 pub metadata: Option<HashMap<String, serde_json::Value>>,
143}
144
145impl Vector {
146 pub fn new(id: impl Into<String>, values: Vec<f32>) -> Self {
148 Self {
149 id: id.into(),
150 values,
151 metadata: None,
152 }
153 }
154
155 pub fn with_metadata(
157 id: impl Into<String>,
158 values: Vec<f32>,
159 metadata: HashMap<String, serde_json::Value>,
160 ) -> Self {
161 Self {
162 id: id.into(),
163 values,
164 metadata: Some(metadata),
165 }
166 }
167}
168
169#[derive(Debug, Clone, Serialize, Deserialize)]
171pub struct UpsertRequest {
172 pub vectors: Vec<Vector>,
174}
175
176impl UpsertRequest {
177 pub fn single(vector: Vector) -> Self {
179 Self {
180 vectors: vec![vector],
181 }
182 }
183
184 pub fn batch(vectors: Vec<Vector>) -> Self {
186 Self { vectors }
187 }
188}
189
190#[derive(Debug, Clone, Serialize, Deserialize)]
192pub struct UpsertResponse {
193 pub upserted_count: u64,
195}
196
197#[derive(Debug, Clone, Serialize, Deserialize)]
214pub struct ColumnUpsertRequest {
215 pub ids: Vec<String>,
217 pub vectors: Vec<Vec<f32>>,
219 #[serde(default, skip_serializing_if = "HashMap::is_empty")]
222 pub attributes: HashMap<String, Vec<serde_json::Value>>,
223 #[serde(skip_serializing_if = "Option::is_none")]
225 pub ttl_seconds: Option<u64>,
226 #[serde(skip_serializing_if = "Option::is_none")]
228 pub dimension: Option<usize>,
229}
230
231impl ColumnUpsertRequest {
232 pub fn new(ids: Vec<String>, vectors: Vec<Vec<f32>>) -> Self {
234 Self {
235 ids,
236 vectors,
237 attributes: HashMap::new(),
238 ttl_seconds: None,
239 dimension: None,
240 }
241 }
242
243 pub fn with_attribute(
245 mut self,
246 name: impl Into<String>,
247 values: Vec<serde_json::Value>,
248 ) -> Self {
249 self.attributes.insert(name.into(), values);
250 self
251 }
252
253 pub fn with_ttl(mut self, seconds: u64) -> Self {
255 self.ttl_seconds = Some(seconds);
256 self
257 }
258
259 pub fn with_dimension(mut self, dim: usize) -> Self {
261 self.dimension = Some(dim);
262 self
263 }
264
265 pub fn len(&self) -> usize {
267 self.ids.len()
268 }
269
270 pub fn is_empty(&self) -> bool {
272 self.ids.is_empty()
273 }
274}
275
276#[derive(Debug, Clone, Serialize, Deserialize)]
278pub struct DeleteRequest {
279 pub ids: Vec<String>,
281}
282
283impl DeleteRequest {
284 pub fn single(id: impl Into<String>) -> Self {
286 Self {
287 ids: vec![id.into()],
288 }
289 }
290
291 pub fn batch(ids: Vec<String>) -> Self {
293 Self { ids }
294 }
295}
296
297#[derive(Debug, Clone, Serialize, Deserialize)]
299pub struct DeleteResponse {
300 pub deleted_count: u64,
302}
303
304#[derive(Debug, Clone, Copy, Default, Serialize, Deserialize, PartialEq, Eq)]
310#[serde(rename_all = "snake_case")]
311pub enum ReadConsistency {
312 Strong,
314 #[default]
316 Eventual,
317 #[serde(rename = "bounded_staleness")]
319 BoundedStaleness,
320}
321
322#[derive(Debug, Clone, Copy, Default, Serialize, Deserialize, PartialEq, Eq)]
324pub struct StalenessConfig {
325 #[serde(default = "default_max_staleness_ms")]
327 pub max_staleness_ms: u64,
328}
329
330fn default_max_staleness_ms() -> u64 {
331 5000 }
333
334impl StalenessConfig {
335 pub fn new(max_staleness_ms: u64) -> Self {
337 Self { max_staleness_ms }
338 }
339}
340
341#[derive(Debug, Clone, Copy, Default, Serialize, Deserialize, PartialEq, Eq)]
343#[serde(rename_all = "snake_case")]
344pub enum DistanceMetric {
345 #[default]
347 Cosine,
348 Euclidean,
350 DotProduct,
352}
353
354#[derive(Debug, Clone, Serialize, Deserialize)]
356pub struct QueryRequest {
357 pub vector: Vec<f32>,
359 pub top_k: u32,
361 #[serde(default)]
363 pub distance_metric: DistanceMetric,
364 #[serde(skip_serializing_if = "Option::is_none")]
366 pub filter: Option<serde_json::Value>,
367 #[serde(default = "default_true")]
369 pub include_metadata: bool,
370 #[serde(default)]
372 pub include_vectors: bool,
373 #[serde(default)]
375 pub consistency: ReadConsistency,
376 #[serde(skip_serializing_if = "Option::is_none")]
378 pub staleness_config: Option<StalenessConfig>,
379}
380
381fn default_true() -> bool {
382 true
383}
384
385impl QueryRequest {
386 pub fn new(vector: Vec<f32>, top_k: u32) -> Self {
388 Self {
389 vector,
390 top_k,
391 distance_metric: DistanceMetric::default(),
392 filter: None,
393 include_metadata: true,
394 include_vectors: false,
395 consistency: ReadConsistency::default(),
396 staleness_config: None,
397 }
398 }
399
400 pub fn with_filter(mut self, filter: serde_json::Value) -> Self {
402 self.filter = Some(filter);
403 self
404 }
405
406 pub fn include_metadata(mut self, include: bool) -> Self {
408 self.include_metadata = include;
409 self
410 }
411
412 pub fn include_vectors(mut self, include: bool) -> Self {
414 self.include_vectors = include;
415 self
416 }
417
418 pub fn with_distance_metric(mut self, metric: DistanceMetric) -> Self {
420 self.distance_metric = metric;
421 self
422 }
423
424 pub fn with_consistency(mut self, consistency: ReadConsistency) -> Self {
426 self.consistency = consistency;
427 self
428 }
429
430 pub fn with_bounded_staleness(mut self, max_staleness_ms: u64) -> Self {
432 self.consistency = ReadConsistency::BoundedStaleness;
433 self.staleness_config = Some(StalenessConfig::new(max_staleness_ms));
434 self
435 }
436
437 pub fn with_strong_consistency(mut self) -> Self {
439 self.consistency = ReadConsistency::Strong;
440 self
441 }
442}
443
444#[derive(Debug, Clone, Serialize, Deserialize)]
446pub struct Match {
447 pub id: String,
449 pub score: f32,
451 #[serde(skip_serializing_if = "Option::is_none")]
453 pub metadata: Option<HashMap<String, serde_json::Value>>,
454}
455
456#[derive(Debug, Clone, Serialize, Deserialize)]
458pub struct QueryResponse {
459 #[serde(alias = "matches")]
461 pub results: Vec<Match>,
462}
463
464#[derive(Debug, Clone, Serialize, Deserialize)]
470pub struct Document {
471 pub id: String,
473 pub text: String,
475 #[serde(skip_serializing_if = "Option::is_none")]
477 pub metadata: Option<HashMap<String, serde_json::Value>>,
478}
479
480impl Document {
481 pub fn new(id: impl Into<String>, text: impl Into<String>) -> Self {
483 Self {
484 id: id.into(),
485 text: text.into(),
486 metadata: None,
487 }
488 }
489
490 pub fn with_metadata(
492 id: impl Into<String>,
493 text: impl Into<String>,
494 metadata: HashMap<String, serde_json::Value>,
495 ) -> Self {
496 Self {
497 id: id.into(),
498 text: text.into(),
499 metadata: Some(metadata),
500 }
501 }
502}
503
504#[derive(Debug, Clone, Serialize, Deserialize)]
506pub struct IndexDocumentsRequest {
507 pub documents: Vec<Document>,
509}
510
511#[derive(Debug, Clone, Serialize, Deserialize)]
513pub struct IndexDocumentsResponse {
514 pub indexed_count: u64,
516}
517
518#[derive(Debug, Clone, Serialize, Deserialize)]
520pub struct FullTextSearchRequest {
521 pub query: String,
523 pub top_k: u32,
525 #[serde(skip_serializing_if = "Option::is_none")]
527 pub filter: Option<serde_json::Value>,
528}
529
530impl FullTextSearchRequest {
531 pub fn new(query: impl Into<String>, top_k: u32) -> Self {
533 Self {
534 query: query.into(),
535 top_k,
536 filter: None,
537 }
538 }
539
540 pub fn with_filter(mut self, filter: serde_json::Value) -> Self {
542 self.filter = Some(filter);
543 self
544 }
545}
546
547#[derive(Debug, Clone, Serialize, Deserialize)]
549pub struct FullTextMatch {
550 pub id: String,
552 pub score: f32,
554 #[serde(skip_serializing_if = "Option::is_none")]
556 pub text: Option<String>,
557 #[serde(skip_serializing_if = "Option::is_none")]
559 pub metadata: Option<HashMap<String, serde_json::Value>>,
560}
561
562#[derive(Debug, Clone, Serialize, Deserialize)]
564pub struct FullTextSearchResponse {
565 #[serde(alias = "matches")]
567 pub results: Vec<FullTextMatch>,
568}
569
570#[derive(Debug, Clone, Serialize, Deserialize)]
572pub struct FullTextStats {
573 pub document_count: u64,
575 pub term_count: u64,
577}
578
579#[derive(Debug, Clone, Serialize, Deserialize)]
588pub struct HybridSearchRequest {
589 #[serde(skip_serializing_if = "Option::is_none")]
591 pub vector: Option<Vec<f32>>,
592 pub text: String,
594 pub top_k: u32,
596 #[serde(default = "default_vector_weight")]
598 pub vector_weight: f32,
599 #[serde(skip_serializing_if = "Option::is_none")]
601 pub filter: Option<serde_json::Value>,
602}
603
604fn default_vector_weight() -> f32 {
605 0.5
606}
607
608impl HybridSearchRequest {
609 pub fn new(vector: Vec<f32>, text: impl Into<String>, top_k: u32) -> Self {
611 Self {
612 vector: Some(vector),
613 text: text.into(),
614 top_k,
615 vector_weight: 0.5,
616 filter: None,
617 }
618 }
619
620 pub fn text_only(text: impl Into<String>, top_k: u32) -> Self {
622 Self {
623 vector: None,
624 text: text.into(),
625 top_k,
626 vector_weight: 0.5,
627 filter: None,
628 }
629 }
630
631 pub fn with_vector_weight(mut self, weight: f32) -> Self {
633 self.vector_weight = weight.clamp(0.0, 1.0);
634 self
635 }
636
637 pub fn with_filter(mut self, filter: serde_json::Value) -> Self {
639 self.filter = Some(filter);
640 self
641 }
642}
643
644#[derive(Debug, Clone, Serialize, Deserialize)]
646pub struct HybridSearchResponse {
647 #[serde(alias = "matches")]
649 pub results: Vec<Match>,
650}
651
652#[derive(Debug, Clone, Serialize, Deserialize)]
658pub struct SystemDiagnostics {
659 pub system: SystemInfo,
661 pub resources: ResourceUsage,
663 pub components: ComponentHealth,
665 pub active_jobs: u64,
667}
668
669#[derive(Debug, Clone, Serialize, Deserialize)]
671pub struct SystemInfo {
672 pub version: String,
674 pub rust_version: String,
676 pub uptime_seconds: u64,
678 pub pid: u32,
680}
681
682#[derive(Debug, Clone, Serialize, Deserialize)]
684pub struct ResourceUsage {
685 pub memory_bytes: u64,
687 pub thread_count: u64,
689 pub open_fds: u64,
691 pub cpu_percent: Option<f64>,
693}
694
695#[derive(Debug, Clone, Serialize, Deserialize)]
697pub struct ComponentHealth {
698 pub storage: HealthStatus,
700 pub search_engine: HealthStatus,
702 pub cache: HealthStatus,
704 pub grpc: HealthStatus,
706}
707
708#[derive(Debug, Clone, Serialize, Deserialize)]
710pub struct HealthStatus {
711 pub healthy: bool,
713 pub message: String,
715 pub last_check: u64,
717}
718
719#[derive(Debug, Clone, Serialize, Deserialize)]
721pub struct JobInfo {
722 pub id: String,
724 pub job_type: String,
726 pub status: String,
728 pub created_at: u64,
730 #[serde(skip_serializing_if = "Option::is_none")]
732 pub started_at: Option<u64>,
733 #[serde(skip_serializing_if = "Option::is_none")]
735 pub completed_at: Option<u64>,
736 pub progress: u8,
738 #[serde(skip_serializing_if = "Option::is_none")]
740 pub message: Option<String>,
741 #[serde(default)]
743 pub metadata: std::collections::HashMap<String, String>,
744}
745
746#[derive(Debug, Clone, Serialize, Deserialize)]
748pub struct CompactionRequest {
749 #[serde(skip_serializing_if = "Option::is_none")]
751 pub namespace: Option<String>,
752 #[serde(default)]
754 pub force: bool,
755}
756
757#[derive(Debug, Clone, Serialize, Deserialize)]
759pub struct CompactionResponse {
760 pub job_id: String,
762 pub message: String,
764}
765
766#[derive(Debug, Clone, Copy, Default, Serialize, Deserialize, PartialEq, Eq)]
772#[serde(rename_all = "snake_case")]
773pub enum WarmingPriority {
774 Critical,
776 High,
778 #[default]
780 Normal,
781 Low,
783 Background,
785}
786
787#[derive(Debug, Clone, Copy, Default, Serialize, Deserialize, PartialEq, Eq)]
789#[serde(rename_all = "snake_case")]
790pub enum WarmingTargetTier {
791 L1,
793 #[default]
795 L2,
796 Both,
798}
799
800#[derive(Debug, Clone, Copy, Default, Serialize, Deserialize, PartialEq, Eq)]
802#[serde(rename_all = "snake_case")]
803pub enum AccessPatternHint {
804 #[default]
806 Random,
807 Sequential,
809 Temporal,
811 Spatial,
813}
814
815#[derive(Debug, Clone, Serialize, Deserialize)]
817pub struct WarmCacheRequest {
818 pub namespace: String,
820 #[serde(skip_serializing_if = "Option::is_none")]
822 pub vector_ids: Option<Vec<String>>,
823 #[serde(default)]
825 pub priority: WarmingPriority,
826 #[serde(default)]
828 pub target_tier: WarmingTargetTier,
829 #[serde(default)]
831 pub background: bool,
832 #[serde(skip_serializing_if = "Option::is_none")]
834 pub ttl_hint_seconds: Option<u64>,
835 #[serde(default)]
837 pub access_pattern: AccessPatternHint,
838 #[serde(skip_serializing_if = "Option::is_none")]
840 pub max_vectors: Option<usize>,
841}
842
843impl WarmCacheRequest {
844 pub fn new(namespace: impl Into<String>) -> Self {
846 Self {
847 namespace: namespace.into(),
848 vector_ids: None,
849 priority: WarmingPriority::default(),
850 target_tier: WarmingTargetTier::default(),
851 background: false,
852 ttl_hint_seconds: None,
853 access_pattern: AccessPatternHint::default(),
854 max_vectors: None,
855 }
856 }
857
858 pub fn with_vector_ids(mut self, ids: Vec<String>) -> Self {
860 self.vector_ids = Some(ids);
861 self
862 }
863
864 pub fn with_priority(mut self, priority: WarmingPriority) -> Self {
866 self.priority = priority;
867 self
868 }
869
870 pub fn with_target_tier(mut self, tier: WarmingTargetTier) -> Self {
872 self.target_tier = tier;
873 self
874 }
875
876 pub fn in_background(mut self) -> Self {
878 self.background = true;
879 self
880 }
881
882 pub fn with_ttl(mut self, seconds: u64) -> Self {
884 self.ttl_hint_seconds = Some(seconds);
885 self
886 }
887
888 pub fn with_access_pattern(mut self, pattern: AccessPatternHint) -> Self {
890 self.access_pattern = pattern;
891 self
892 }
893
894 pub fn with_max_vectors(mut self, max: usize) -> Self {
896 self.max_vectors = Some(max);
897 self
898 }
899}
900
901#[derive(Debug, Clone, Serialize, Deserialize)]
903pub struct WarmCacheResponse {
904 pub success: bool,
906 pub entries_warmed: u64,
908 pub entries_skipped: u64,
910 #[serde(skip_serializing_if = "Option::is_none")]
912 pub job_id: Option<String>,
913 pub message: String,
915 #[serde(skip_serializing_if = "Option::is_none")]
917 pub estimated_completion: Option<String>,
918 pub target_tier: WarmingTargetTier,
920 pub priority: WarmingPriority,
922 #[serde(skip_serializing_if = "Option::is_none")]
924 pub bytes_warmed: Option<u64>,
925}
926
927#[derive(Debug, Clone, Serialize, Deserialize)]
933pub struct ExportRequest {
934 #[serde(default = "default_export_top_k")]
936 pub top_k: usize,
937 #[serde(skip_serializing_if = "Option::is_none")]
939 pub cursor: Option<String>,
940 #[serde(default = "default_true")]
942 pub include_vectors: bool,
943 #[serde(default = "default_true")]
945 pub include_metadata: bool,
946}
947
948fn default_export_top_k() -> usize {
949 1000
950}
951
952impl Default for ExportRequest {
953 fn default() -> Self {
954 Self {
955 top_k: 1000,
956 cursor: None,
957 include_vectors: true,
958 include_metadata: true,
959 }
960 }
961}
962
963impl ExportRequest {
964 pub fn new() -> Self {
966 Self::default()
967 }
968
969 pub fn with_top_k(mut self, top_k: usize) -> Self {
971 self.top_k = top_k;
972 self
973 }
974
975 pub fn with_cursor(mut self, cursor: impl Into<String>) -> Self {
977 self.cursor = Some(cursor.into());
978 self
979 }
980
981 pub fn include_vectors(mut self, include: bool) -> Self {
983 self.include_vectors = include;
984 self
985 }
986
987 pub fn include_metadata(mut self, include: bool) -> Self {
989 self.include_metadata = include;
990 self
991 }
992}
993
994#[derive(Debug, Clone, Serialize, Deserialize)]
996pub struct ExportedVector {
997 pub id: String,
999 #[serde(skip_serializing_if = "Option::is_none")]
1001 pub values: Option<Vec<f32>>,
1002 #[serde(skip_serializing_if = "Option::is_none")]
1004 pub metadata: Option<serde_json::Value>,
1005 #[serde(skip_serializing_if = "Option::is_none")]
1007 pub ttl_seconds: Option<u64>,
1008}
1009
1010#[derive(Debug, Clone, Serialize, Deserialize)]
1012pub struct ExportResponse {
1013 pub vectors: Vec<ExportedVector>,
1015 #[serde(skip_serializing_if = "Option::is_none")]
1017 pub next_cursor: Option<String>,
1018 pub total_count: usize,
1020 pub returned_count: usize,
1022}
1023
1024#[derive(Debug, Clone, Serialize, Deserialize)]
1030pub struct BatchQueryItem {
1031 #[serde(skip_serializing_if = "Option::is_none")]
1033 pub id: Option<String>,
1034 pub vector: Vec<f32>,
1036 #[serde(default = "default_batch_top_k")]
1038 pub top_k: u32,
1039 #[serde(skip_serializing_if = "Option::is_none")]
1041 pub filter: Option<serde_json::Value>,
1042 #[serde(default)]
1044 pub include_metadata: bool,
1045 #[serde(default)]
1047 pub consistency: ReadConsistency,
1048 #[serde(skip_serializing_if = "Option::is_none")]
1050 pub staleness_config: Option<StalenessConfig>,
1051}
1052
1053fn default_batch_top_k() -> u32 {
1054 10
1055}
1056
1057impl BatchQueryItem {
1058 pub fn new(vector: Vec<f32>, top_k: u32) -> Self {
1060 Self {
1061 id: None,
1062 vector,
1063 top_k,
1064 filter: None,
1065 include_metadata: true,
1066 consistency: ReadConsistency::default(),
1067 staleness_config: None,
1068 }
1069 }
1070
1071 pub fn with_id(mut self, id: impl Into<String>) -> Self {
1073 self.id = Some(id.into());
1074 self
1075 }
1076
1077 pub fn with_filter(mut self, filter: serde_json::Value) -> Self {
1079 self.filter = Some(filter);
1080 self
1081 }
1082
1083 pub fn include_metadata(mut self, include: bool) -> Self {
1085 self.include_metadata = include;
1086 self
1087 }
1088
1089 pub fn with_consistency(mut self, consistency: ReadConsistency) -> Self {
1091 self.consistency = consistency;
1092 self
1093 }
1094
1095 pub fn with_bounded_staleness(mut self, max_staleness_ms: u64) -> Self {
1097 self.consistency = ReadConsistency::BoundedStaleness;
1098 self.staleness_config = Some(StalenessConfig::new(max_staleness_ms));
1099 self
1100 }
1101}
1102
1103#[derive(Debug, Clone, Serialize, Deserialize)]
1105pub struct BatchQueryRequest {
1106 pub queries: Vec<BatchQueryItem>,
1108}
1109
1110impl BatchQueryRequest {
1111 pub fn new(queries: Vec<BatchQueryItem>) -> Self {
1113 Self { queries }
1114 }
1115
1116 pub fn single(query: BatchQueryItem) -> Self {
1118 Self {
1119 queries: vec![query],
1120 }
1121 }
1122}
1123
1124#[derive(Debug, Clone, Serialize, Deserialize)]
1126pub struct BatchQueryResult {
1127 #[serde(skip_serializing_if = "Option::is_none")]
1129 pub id: Option<String>,
1130 pub results: Vec<Match>,
1132 pub latency_ms: f64,
1134 #[serde(skip_serializing_if = "Option::is_none")]
1136 pub error: Option<String>,
1137}
1138
1139#[derive(Debug, Clone, Serialize, Deserialize)]
1141pub struct BatchQueryResponse {
1142 pub results: Vec<BatchQueryResult>,
1144 pub total_latency_ms: f64,
1146 pub query_count: usize,
1148}
1149
1150#[derive(Debug, Clone, Serialize, Deserialize)]
1156pub struct MultiVectorSearchRequest {
1157 pub positive_vectors: Vec<Vec<f32>>,
1159 #[serde(skip_serializing_if = "Option::is_none")]
1161 pub positive_weights: Option<Vec<f32>>,
1162 #[serde(skip_serializing_if = "Option::is_none")]
1164 pub negative_vectors: Option<Vec<Vec<f32>>>,
1165 #[serde(skip_serializing_if = "Option::is_none")]
1167 pub negative_weights: Option<Vec<f32>>,
1168 #[serde(default = "default_multi_vector_top_k")]
1170 pub top_k: u32,
1171 #[serde(default)]
1173 pub distance_metric: DistanceMetric,
1174 #[serde(skip_serializing_if = "Option::is_none")]
1176 pub score_threshold: Option<f32>,
1177 #[serde(default)]
1179 pub enable_mmr: bool,
1180 #[serde(default = "default_mmr_lambda")]
1182 pub mmr_lambda: f32,
1183 #[serde(default = "default_true")]
1185 pub include_metadata: bool,
1186 #[serde(default)]
1188 pub include_vectors: bool,
1189 #[serde(skip_serializing_if = "Option::is_none")]
1191 pub filter: Option<serde_json::Value>,
1192 #[serde(default)]
1194 pub consistency: ReadConsistency,
1195 #[serde(skip_serializing_if = "Option::is_none")]
1197 pub staleness_config: Option<StalenessConfig>,
1198}
1199
1200fn default_multi_vector_top_k() -> u32 {
1201 10
1202}
1203
1204fn default_mmr_lambda() -> f32 {
1205 0.5
1206}
1207
1208impl MultiVectorSearchRequest {
1209 pub fn new(positive_vectors: Vec<Vec<f32>>) -> Self {
1211 Self {
1212 positive_vectors,
1213 positive_weights: None,
1214 negative_vectors: None,
1215 negative_weights: None,
1216 top_k: 10,
1217 distance_metric: DistanceMetric::default(),
1218 score_threshold: None,
1219 enable_mmr: false,
1220 mmr_lambda: 0.5,
1221 include_metadata: true,
1222 include_vectors: false,
1223 filter: None,
1224 consistency: ReadConsistency::default(),
1225 staleness_config: None,
1226 }
1227 }
1228
1229 pub fn with_top_k(mut self, top_k: u32) -> Self {
1231 self.top_k = top_k;
1232 self
1233 }
1234
1235 pub fn with_positive_weights(mut self, weights: Vec<f32>) -> Self {
1237 self.positive_weights = Some(weights);
1238 self
1239 }
1240
1241 pub fn with_negative_vectors(mut self, vectors: Vec<Vec<f32>>) -> Self {
1243 self.negative_vectors = Some(vectors);
1244 self
1245 }
1246
1247 pub fn with_negative_weights(mut self, weights: Vec<f32>) -> Self {
1249 self.negative_weights = Some(weights);
1250 self
1251 }
1252
1253 pub fn with_distance_metric(mut self, metric: DistanceMetric) -> Self {
1255 self.distance_metric = metric;
1256 self
1257 }
1258
1259 pub fn with_score_threshold(mut self, threshold: f32) -> Self {
1261 self.score_threshold = Some(threshold);
1262 self
1263 }
1264
1265 pub fn with_mmr(mut self, lambda: f32) -> Self {
1267 self.enable_mmr = true;
1268 self.mmr_lambda = lambda.clamp(0.0, 1.0);
1269 self
1270 }
1271
1272 pub fn include_metadata(mut self, include: bool) -> Self {
1274 self.include_metadata = include;
1275 self
1276 }
1277
1278 pub fn include_vectors(mut self, include: bool) -> Self {
1280 self.include_vectors = include;
1281 self
1282 }
1283
1284 pub fn with_filter(mut self, filter: serde_json::Value) -> Self {
1286 self.filter = Some(filter);
1287 self
1288 }
1289
1290 pub fn with_consistency(mut self, consistency: ReadConsistency) -> Self {
1292 self.consistency = consistency;
1293 self
1294 }
1295}
1296
1297#[derive(Debug, Clone, Serialize, Deserialize)]
1299pub struct MultiVectorSearchResult {
1300 pub id: String,
1302 pub score: f32,
1304 #[serde(skip_serializing_if = "Option::is_none")]
1306 pub mmr_score: Option<f32>,
1307 #[serde(skip_serializing_if = "Option::is_none")]
1309 pub original_rank: Option<usize>,
1310 #[serde(skip_serializing_if = "Option::is_none")]
1312 pub metadata: Option<HashMap<String, serde_json::Value>>,
1313 #[serde(skip_serializing_if = "Option::is_none")]
1315 pub vector: Option<Vec<f32>>,
1316}
1317
1318#[derive(Debug, Clone, Serialize, Deserialize)]
1320pub struct MultiVectorSearchResponse {
1321 pub results: Vec<MultiVectorSearchResult>,
1323 #[serde(skip_serializing_if = "Option::is_none")]
1325 pub computed_query_vector: Option<Vec<f32>>,
1326}
1327
1328#[derive(Debug, Clone, Serialize, Deserialize)]
1334#[serde(untagged)]
1335pub enum AggregateFunction {
1336 Count,
1338 Sum { field: String },
1340 Avg { field: String },
1342 Min { field: String },
1344 Max { field: String },
1346}
1347
1348#[derive(Debug, Clone, Serialize, Deserialize)]
1350pub struct AggregationRequest {
1351 pub aggregate_by: HashMap<String, serde_json::Value>,
1354 #[serde(default, skip_serializing_if = "Vec::is_empty")]
1357 pub group_by: Vec<String>,
1358 #[serde(skip_serializing_if = "Option::is_none")]
1360 pub filter: Option<serde_json::Value>,
1361 #[serde(default = "default_agg_limit")]
1363 pub limit: usize,
1364}
1365
1366fn default_agg_limit() -> usize {
1367 100
1368}
1369
1370impl AggregationRequest {
1371 pub fn new() -> Self {
1373 Self {
1374 aggregate_by: HashMap::new(),
1375 group_by: Vec::new(),
1376 filter: None,
1377 limit: 100,
1378 }
1379 }
1380
1381 pub fn with_count(mut self, name: impl Into<String>) -> Self {
1383 self.aggregate_by
1384 .insert(name.into(), serde_json::json!(["Count"]));
1385 self
1386 }
1387
1388 pub fn with_sum(mut self, name: impl Into<String>, field: impl Into<String>) -> Self {
1390 self.aggregate_by
1391 .insert(name.into(), serde_json::json!(["Sum", field.into()]));
1392 self
1393 }
1394
1395 pub fn with_avg(mut self, name: impl Into<String>, field: impl Into<String>) -> Self {
1397 self.aggregate_by
1398 .insert(name.into(), serde_json::json!(["Avg", field.into()]));
1399 self
1400 }
1401
1402 pub fn with_min(mut self, name: impl Into<String>, field: impl Into<String>) -> Self {
1404 self.aggregate_by
1405 .insert(name.into(), serde_json::json!(["Min", field.into()]));
1406 self
1407 }
1408
1409 pub fn with_max(mut self, name: impl Into<String>, field: impl Into<String>) -> Self {
1411 self.aggregate_by
1412 .insert(name.into(), serde_json::json!(["Max", field.into()]));
1413 self
1414 }
1415
1416 pub fn group_by(mut self, fields: Vec<String>) -> Self {
1418 self.group_by = fields;
1419 self
1420 }
1421
1422 pub fn with_group_by(mut self, field: impl Into<String>) -> Self {
1424 self.group_by.push(field.into());
1425 self
1426 }
1427
1428 pub fn with_filter(mut self, filter: serde_json::Value) -> Self {
1430 self.filter = Some(filter);
1431 self
1432 }
1433
1434 pub fn with_limit(mut self, limit: usize) -> Self {
1436 self.limit = limit;
1437 self
1438 }
1439}
1440
1441impl Default for AggregationRequest {
1442 fn default() -> Self {
1443 Self::new()
1444 }
1445}
1446
1447#[derive(Debug, Clone, Serialize, Deserialize)]
1449pub struct AggregationResponse {
1450 #[serde(skip_serializing_if = "Option::is_none")]
1452 pub aggregations: Option<HashMap<String, serde_json::Value>>,
1453 #[serde(skip_serializing_if = "Option::is_none")]
1455 pub aggregation_groups: Option<Vec<AggregationGroup>>,
1456}
1457
1458#[derive(Debug, Clone, Serialize, Deserialize)]
1460pub struct AggregationGroup {
1461 #[serde(flatten)]
1463 pub group_key: HashMap<String, serde_json::Value>,
1464 #[serde(flatten)]
1466 pub aggregations: HashMap<String, serde_json::Value>,
1467}
1468
1469#[derive(Debug, Clone, Copy, Default, Serialize, Deserialize, PartialEq, Eq)]
1475pub enum VectorSearchMethod {
1476 #[default]
1478 ANN,
1479 #[serde(rename = "kNN")]
1481 KNN,
1482}
1483
1484#[derive(Debug, Clone, Copy, Default, Serialize, Deserialize, PartialEq, Eq)]
1486#[serde(rename_all = "lowercase")]
1487pub enum SortDirection {
1488 Asc,
1490 #[default]
1492 Desc,
1493}
1494
1495#[derive(Debug, Clone, Serialize, Deserialize)]
1498#[serde(untagged)]
1499pub enum RankBy {
1500 VectorSearch {
1502 field: String,
1503 method: VectorSearchMethod,
1504 query_vector: Vec<f32>,
1505 },
1506 FullTextSearch {
1508 field: String,
1509 method: String, query: String,
1511 },
1512 AttributeOrder {
1514 field: String,
1515 direction: SortDirection,
1516 },
1517 Sum(Vec<RankBy>),
1519 Max(Vec<RankBy>),
1521 Product { weight: f32, ranking: Box<RankBy> },
1523}
1524
1525impl RankBy {
1526 pub fn vector_ann(field: impl Into<String>, query_vector: Vec<f32>) -> Self {
1528 RankBy::VectorSearch {
1529 field: field.into(),
1530 method: VectorSearchMethod::ANN,
1531 query_vector,
1532 }
1533 }
1534
1535 pub fn ann(query_vector: Vec<f32>) -> Self {
1537 Self::vector_ann("vector", query_vector)
1538 }
1539
1540 pub fn vector_knn(field: impl Into<String>, query_vector: Vec<f32>) -> Self {
1542 RankBy::VectorSearch {
1543 field: field.into(),
1544 method: VectorSearchMethod::KNN,
1545 query_vector,
1546 }
1547 }
1548
1549 pub fn knn(query_vector: Vec<f32>) -> Self {
1551 Self::vector_knn("vector", query_vector)
1552 }
1553
1554 pub fn bm25(field: impl Into<String>, query: impl Into<String>) -> Self {
1556 RankBy::FullTextSearch {
1557 field: field.into(),
1558 method: "BM25".to_string(),
1559 query: query.into(),
1560 }
1561 }
1562
1563 pub fn asc(field: impl Into<String>) -> Self {
1565 RankBy::AttributeOrder {
1566 field: field.into(),
1567 direction: SortDirection::Asc,
1568 }
1569 }
1570
1571 pub fn desc(field: impl Into<String>) -> Self {
1573 RankBy::AttributeOrder {
1574 field: field.into(),
1575 direction: SortDirection::Desc,
1576 }
1577 }
1578
1579 pub fn sum(rankings: Vec<RankBy>) -> Self {
1581 RankBy::Sum(rankings)
1582 }
1583
1584 pub fn max(rankings: Vec<RankBy>) -> Self {
1586 RankBy::Max(rankings)
1587 }
1588
1589 pub fn product(weight: f32, ranking: RankBy) -> Self {
1591 RankBy::Product {
1592 weight,
1593 ranking: Box::new(ranking),
1594 }
1595 }
1596}
1597
1598#[derive(Debug, Clone, Serialize, Deserialize)]
1616pub struct UnifiedQueryRequest {
1617 pub rank_by: serde_json::Value,
1619 #[serde(default = "default_unified_top_k")]
1621 pub top_k: usize,
1622 #[serde(skip_serializing_if = "Option::is_none")]
1624 pub filter: Option<serde_json::Value>,
1625 #[serde(default = "default_true")]
1627 pub include_metadata: bool,
1628 #[serde(default)]
1630 pub include_vectors: bool,
1631 #[serde(default)]
1633 pub distance_metric: DistanceMetric,
1634}
1635
1636fn default_unified_top_k() -> usize {
1637 10
1638}
1639
1640impl UnifiedQueryRequest {
1641 pub fn vector_search(query_vector: Vec<f32>, top_k: usize) -> Self {
1643 Self {
1644 rank_by: serde_json::json!(["ANN", query_vector]),
1645 top_k,
1646 filter: None,
1647 include_metadata: true,
1648 include_vectors: false,
1649 distance_metric: DistanceMetric::default(),
1650 }
1651 }
1652
1653 pub fn vector_knn_search(query_vector: Vec<f32>, top_k: usize) -> Self {
1655 Self {
1656 rank_by: serde_json::json!(["kNN", query_vector]),
1657 top_k,
1658 filter: None,
1659 include_metadata: true,
1660 include_vectors: false,
1661 distance_metric: DistanceMetric::default(),
1662 }
1663 }
1664
1665 pub fn fulltext_search(
1667 field: impl Into<String>,
1668 query: impl Into<String>,
1669 top_k: usize,
1670 ) -> Self {
1671 Self {
1672 rank_by: serde_json::json!([field.into(), "BM25", query.into()]),
1673 top_k,
1674 filter: None,
1675 include_metadata: true,
1676 include_vectors: false,
1677 distance_metric: DistanceMetric::default(),
1678 }
1679 }
1680
1681 pub fn attribute_order(
1683 field: impl Into<String>,
1684 direction: SortDirection,
1685 top_k: usize,
1686 ) -> Self {
1687 let dir = match direction {
1688 SortDirection::Asc => "asc",
1689 SortDirection::Desc => "desc",
1690 };
1691 Self {
1692 rank_by: serde_json::json!([field.into(), dir]),
1693 top_k,
1694 filter: None,
1695 include_metadata: true,
1696 include_vectors: false,
1697 distance_metric: DistanceMetric::default(),
1698 }
1699 }
1700
1701 pub fn with_rank_by(rank_by: serde_json::Value, top_k: usize) -> Self {
1703 Self {
1704 rank_by,
1705 top_k,
1706 filter: None,
1707 include_metadata: true,
1708 include_vectors: false,
1709 distance_metric: DistanceMetric::default(),
1710 }
1711 }
1712
1713 pub fn with_filter(mut self, filter: serde_json::Value) -> Self {
1715 self.filter = Some(filter);
1716 self
1717 }
1718
1719 pub fn include_metadata(mut self, include: bool) -> Self {
1721 self.include_metadata = include;
1722 self
1723 }
1724
1725 pub fn include_vectors(mut self, include: bool) -> Self {
1727 self.include_vectors = include;
1728 self
1729 }
1730
1731 pub fn with_distance_metric(mut self, metric: DistanceMetric) -> Self {
1733 self.distance_metric = metric;
1734 self
1735 }
1736
1737 pub fn with_top_k(mut self, top_k: usize) -> Self {
1739 self.top_k = top_k;
1740 self
1741 }
1742}
1743
1744#[derive(Debug, Clone, Serialize, Deserialize)]
1746pub struct UnifiedSearchResult {
1747 pub id: String,
1749 #[serde(rename = "$dist", skip_serializing_if = "Option::is_none")]
1752 pub dist: Option<f32>,
1753 #[serde(skip_serializing_if = "Option::is_none")]
1755 pub metadata: Option<serde_json::Value>,
1756 #[serde(skip_serializing_if = "Option::is_none")]
1758 pub vector: Option<Vec<f32>>,
1759}
1760
1761#[derive(Debug, Clone, Serialize, Deserialize)]
1763pub struct UnifiedQueryResponse {
1764 pub results: Vec<UnifiedSearchResult>,
1766 #[serde(skip_serializing_if = "Option::is_none")]
1768 pub next_cursor: Option<String>,
1769}
1770
1771fn default_explain_top_k() -> usize {
1776 10
1777}
1778
1779#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
1781#[serde(rename_all = "snake_case")]
1782#[derive(Default)]
1783pub enum ExplainQueryType {
1784 #[default]
1786 VectorSearch,
1787 FullTextSearch,
1789 HybridSearch,
1791 MultiVector,
1793 BatchQuery,
1795}
1796
1797#[derive(Debug, Clone, Serialize, Deserialize)]
1799pub struct QueryExplainRequest {
1800 #[serde(default)]
1802 pub query_type: ExplainQueryType,
1803 #[serde(skip_serializing_if = "Option::is_none")]
1805 pub vector: Option<Vec<f32>>,
1806 #[serde(default = "default_explain_top_k")]
1808 pub top_k: usize,
1809 #[serde(skip_serializing_if = "Option::is_none")]
1811 pub filter: Option<serde_json::Value>,
1812 #[serde(skip_serializing_if = "Option::is_none")]
1814 pub text_query: Option<String>,
1815 #[serde(default = "default_distance_metric")]
1817 pub distance_metric: String,
1818 #[serde(default)]
1820 pub execute: bool,
1821 #[serde(default)]
1823 pub verbose: bool,
1824}
1825
1826fn default_distance_metric() -> String {
1827 "cosine".to_string()
1828}
1829
1830impl QueryExplainRequest {
1831 pub fn vector_search(vector: Vec<f32>, top_k: usize) -> Self {
1833 Self {
1834 query_type: ExplainQueryType::VectorSearch,
1835 vector: Some(vector),
1836 top_k,
1837 filter: None,
1838 text_query: None,
1839 distance_metric: "cosine".to_string(),
1840 execute: false,
1841 verbose: false,
1842 }
1843 }
1844
1845 pub fn fulltext_search(text_query: impl Into<String>, top_k: usize) -> Self {
1847 Self {
1848 query_type: ExplainQueryType::FullTextSearch,
1849 vector: None,
1850 top_k,
1851 filter: None,
1852 text_query: Some(text_query.into()),
1853 distance_metric: "bm25".to_string(),
1854 execute: false,
1855 verbose: false,
1856 }
1857 }
1858
1859 pub fn hybrid_search(vector: Vec<f32>, text_query: impl Into<String>, top_k: usize) -> Self {
1861 Self {
1862 query_type: ExplainQueryType::HybridSearch,
1863 vector: Some(vector),
1864 top_k,
1865 filter: None,
1866 text_query: Some(text_query.into()),
1867 distance_metric: "hybrid".to_string(),
1868 execute: false,
1869 verbose: false,
1870 }
1871 }
1872
1873 pub fn with_filter(mut self, filter: serde_json::Value) -> Self {
1875 self.filter = Some(filter);
1876 self
1877 }
1878
1879 pub fn with_distance_metric(mut self, metric: impl Into<String>) -> Self {
1881 self.distance_metric = metric.into();
1882 self
1883 }
1884
1885 pub fn with_execution(mut self) -> Self {
1887 self.execute = true;
1888 self
1889 }
1890
1891 pub fn with_verbose(mut self) -> Self {
1893 self.verbose = true;
1894 self
1895 }
1896}
1897
1898#[derive(Debug, Clone, Serialize, Deserialize)]
1900pub struct ExecutionStage {
1901 pub name: String,
1903 pub description: String,
1905 pub order: u32,
1907 pub estimated_input: u64,
1909 pub estimated_output: u64,
1911 pub estimated_cost: f64,
1913 #[serde(default)]
1915 pub details: HashMap<String, serde_json::Value>,
1916}
1917
1918#[derive(Debug, Clone, Serialize, Deserialize)]
1920pub struct CostEstimate {
1921 pub total_cost: f64,
1923 pub estimated_time_ms: u64,
1925 pub estimated_memory_bytes: u64,
1927 pub estimated_io_ops: u64,
1929 #[serde(default)]
1931 pub cost_breakdown: HashMap<String, f64>,
1932 pub confidence: f64,
1934}
1935
1936#[derive(Debug, Clone, Serialize, Deserialize)]
1938pub struct ActualStats {
1939 pub execution_time_ms: u64,
1941 pub results_returned: usize,
1943 pub vectors_scanned: u64,
1945 pub vectors_after_filter: u64,
1947 pub index_lookups: u64,
1949 pub cache_hits: u64,
1951 pub cache_misses: u64,
1953 pub memory_used_bytes: u64,
1955}
1956
1957#[derive(Debug, Clone, Serialize, Deserialize)]
1959pub struct Recommendation {
1960 pub recommendation_type: String,
1962 pub priority: String,
1964 pub description: String,
1966 pub expected_improvement: String,
1968 pub implementation: String,
1970}
1971
1972#[derive(Debug, Clone, Serialize, Deserialize)]
1974pub struct IndexSelection {
1975 pub index_type: String,
1977 pub selection_reason: String,
1979 #[serde(default)]
1981 pub alternatives_considered: Vec<IndexAlternative>,
1982 #[serde(default)]
1984 pub index_config: HashMap<String, serde_json::Value>,
1985 pub index_stats: IndexStatistics,
1987}
1988
1989#[derive(Debug, Clone, Serialize, Deserialize)]
1991pub struct IndexAlternative {
1992 pub index_type: String,
1994 pub rejection_reason: String,
1996 pub estimated_cost: f64,
1998}
1999
2000#[derive(Debug, Clone, Serialize, Deserialize)]
2002pub struct IndexStatistics {
2003 pub vector_count: u64,
2005 pub dimension: usize,
2007 pub memory_bytes: u64,
2009 #[serde(skip_serializing_if = "Option::is_none")]
2011 pub build_time_ms: Option<u64>,
2012 #[serde(skip_serializing_if = "Option::is_none")]
2014 pub last_updated: Option<u64>,
2015}
2016
2017#[derive(Debug, Clone, Serialize, Deserialize)]
2019pub struct QueryParams {
2020 pub top_k: usize,
2022 pub has_filter: bool,
2024 pub filter_complexity: String,
2026 #[serde(skip_serializing_if = "Option::is_none")]
2028 pub vector_dimension: Option<usize>,
2029 pub distance_metric: String,
2031 #[serde(skip_serializing_if = "Option::is_none")]
2033 pub text_query_length: Option<usize>,
2034}
2035
2036#[derive(Debug, Clone, Serialize, Deserialize)]
2038pub struct QueryExplainResponse {
2039 pub query_type: ExplainQueryType,
2041 pub namespace: String,
2043 pub index_selection: IndexSelection,
2045 pub stages: Vec<ExecutionStage>,
2047 pub cost_estimate: CostEstimate,
2049 #[serde(skip_serializing_if = "Option::is_none")]
2051 pub actual_stats: Option<ActualStats>,
2052 #[serde(default)]
2054 pub recommendations: Vec<Recommendation>,
2055 pub summary: String,
2057 pub query_params: QueryParams,
2059}
2060
2061#[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq)]
2067#[serde(rename_all = "kebab-case")]
2068pub enum EmbeddingModel {
2069 #[default]
2071 BgeLarge,
2072 Minilm,
2074 BgeSmall,
2076 E5Small,
2078}
2079
2080#[derive(Debug, Clone, Serialize, Deserialize)]
2082pub struct TextDocument {
2083 pub id: String,
2085 pub text: String,
2087 #[serde(skip_serializing_if = "Option::is_none")]
2089 pub metadata: Option<HashMap<String, serde_json::Value>>,
2090 #[serde(skip_serializing_if = "Option::is_none")]
2092 pub ttl_seconds: Option<u64>,
2093}
2094
2095impl TextDocument {
2096 pub fn new(id: impl Into<String>, text: impl Into<String>) -> Self {
2098 Self {
2099 id: id.into(),
2100 text: text.into(),
2101 metadata: None,
2102 ttl_seconds: None,
2103 }
2104 }
2105
2106 pub fn with_metadata(mut self, metadata: HashMap<String, serde_json::Value>) -> Self {
2108 self.metadata = Some(metadata);
2109 self
2110 }
2111
2112 pub fn with_ttl(mut self, ttl_seconds: u64) -> Self {
2114 self.ttl_seconds = Some(ttl_seconds);
2115 self
2116 }
2117}
2118
2119#[derive(Debug, Clone, Serialize, Deserialize)]
2121pub struct UpsertTextRequest {
2122 pub documents: Vec<TextDocument>,
2124 #[serde(skip_serializing_if = "Option::is_none")]
2126 pub model: Option<EmbeddingModel>,
2127}
2128
2129impl UpsertTextRequest {
2130 pub fn new(documents: Vec<TextDocument>) -> Self {
2132 Self {
2133 documents,
2134 model: None,
2135 }
2136 }
2137
2138 pub fn with_model(mut self, model: EmbeddingModel) -> Self {
2140 self.model = Some(model);
2141 self
2142 }
2143}
2144
2145#[derive(Debug, Clone, Serialize, Deserialize)]
2147pub struct TextUpsertResponse {
2148 pub upserted_count: u64,
2150 pub tokens_processed: u64,
2152 pub model: EmbeddingModel,
2154 pub embedding_time_ms: u64,
2156}
2157
2158#[derive(Debug, Clone, Serialize, Deserialize)]
2160pub struct TextSearchResult {
2161 pub id: String,
2163 pub score: f32,
2165 #[serde(skip_serializing_if = "Option::is_none")]
2167 pub text: Option<String>,
2168 #[serde(skip_serializing_if = "Option::is_none")]
2170 pub metadata: Option<HashMap<String, serde_json::Value>>,
2171 #[serde(skip_serializing_if = "Option::is_none")]
2173 pub vector: Option<Vec<f32>>,
2174}
2175
2176#[derive(Debug, Clone, Serialize, Deserialize)]
2178pub struct QueryTextRequest {
2179 pub text: String,
2181 pub top_k: u32,
2183 #[serde(skip_serializing_if = "Option::is_none")]
2185 pub filter: Option<serde_json::Value>,
2186 pub include_text: bool,
2188 pub include_vectors: bool,
2190 #[serde(skip_serializing_if = "Option::is_none")]
2192 pub model: Option<EmbeddingModel>,
2193}
2194
2195impl QueryTextRequest {
2196 pub fn new(text: impl Into<String>, top_k: u32) -> Self {
2198 Self {
2199 text: text.into(),
2200 top_k,
2201 filter: None,
2202 include_text: true,
2203 include_vectors: false,
2204 model: None,
2205 }
2206 }
2207
2208 pub fn with_filter(mut self, filter: serde_json::Value) -> Self {
2210 self.filter = Some(filter);
2211 self
2212 }
2213
2214 pub fn include_text(mut self, include: bool) -> Self {
2216 self.include_text = include;
2217 self
2218 }
2219
2220 pub fn include_vectors(mut self, include: bool) -> Self {
2222 self.include_vectors = include;
2223 self
2224 }
2225
2226 pub fn with_model(mut self, model: EmbeddingModel) -> Self {
2228 self.model = Some(model);
2229 self
2230 }
2231}
2232
2233#[derive(Debug, Clone, Serialize, Deserialize)]
2235pub struct TextQueryResponse {
2236 pub results: Vec<TextSearchResult>,
2238 pub model: EmbeddingModel,
2240 pub embedding_time_ms: u64,
2242 pub search_time_ms: u64,
2244}
2245
2246#[derive(Debug, Clone, Serialize, Deserialize)]
2248pub struct BatchQueryTextRequest {
2249 pub queries: Vec<String>,
2251 pub top_k: u32,
2253 #[serde(skip_serializing_if = "Option::is_none")]
2255 pub filter: Option<serde_json::Value>,
2256 pub include_vectors: bool,
2258 #[serde(skip_serializing_if = "Option::is_none")]
2260 pub model: Option<EmbeddingModel>,
2261}
2262
2263impl BatchQueryTextRequest {
2264 pub fn new(queries: Vec<String>, top_k: u32) -> Self {
2266 Self {
2267 queries,
2268 top_k,
2269 filter: None,
2270 include_vectors: false,
2271 model: None,
2272 }
2273 }
2274}
2275
2276#[derive(Debug, Clone, Serialize, Deserialize)]
2278pub struct BatchQueryTextResponse {
2279 pub results: Vec<Vec<TextSearchResult>>,
2281 pub model: EmbeddingModel,
2283 pub embedding_time_ms: u64,
2285 pub search_time_ms: u64,
2287}
2288
2289#[derive(Debug, Clone, Serialize, Deserialize)]
2295pub struct FetchRequest {
2296 pub ids: Vec<String>,
2298 pub include_values: bool,
2300 pub include_metadata: bool,
2302}
2303
2304impl FetchRequest {
2305 pub fn new(ids: Vec<String>) -> Self {
2307 Self {
2308 ids,
2309 include_values: true,
2310 include_metadata: true,
2311 }
2312 }
2313}
2314
2315#[derive(Debug, Clone, Serialize, Deserialize)]
2317pub struct FetchResponse {
2318 pub vectors: Vec<Vector>,
2320}
2321
2322#[derive(Debug, Clone, Serialize, Deserialize, Default)]
2328pub struct CreateNamespaceRequest {
2329 #[serde(rename = "dimension", skip_serializing_if = "Option::is_none")]
2331 pub dimensions: Option<u32>,
2332 #[serde(skip_serializing_if = "Option::is_none")]
2334 pub index_type: Option<String>,
2335 #[serde(skip_serializing_if = "Option::is_none")]
2337 pub metadata: Option<HashMap<String, serde_json::Value>>,
2338}
2339
2340impl CreateNamespaceRequest {
2341 pub fn new() -> Self {
2343 Self::default()
2344 }
2345
2346 pub fn with_dimensions(mut self, dimensions: u32) -> Self {
2348 self.dimensions = Some(dimensions);
2349 self
2350 }
2351
2352 pub fn with_index_type(mut self, index_type: impl Into<String>) -> Self {
2354 self.index_type = Some(index_type.into());
2355 self
2356 }
2357}
2358
2359#[derive(Debug, Clone, Serialize, Deserialize)]
2364pub struct ConfigureNamespaceRequest {
2365 pub dimension: usize,
2367 #[serde(skip_serializing_if = "Option::is_none")]
2369 pub distance: Option<DistanceMetric>,
2370}
2371
2372impl ConfigureNamespaceRequest {
2373 pub fn new(dimension: usize) -> Self {
2375 Self {
2376 dimension,
2377 distance: None,
2378 }
2379 }
2380
2381 pub fn with_distance(mut self, distance: DistanceMetric) -> Self {
2383 self.distance = Some(distance);
2384 self
2385 }
2386}
2387
2388#[derive(Debug, Clone, Serialize, Deserialize)]
2390pub struct ConfigureNamespaceResponse {
2391 pub namespace: String,
2393 pub dimension: usize,
2395 pub distance: DistanceMetric,
2397 pub created: bool,
2399}
2400
2401#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
2407#[serde(rename_all = "snake_case")]
2408pub enum EdgeType {
2409 RelatedTo,
2411 SharesEntity,
2413 Precedes,
2415 #[default]
2417 LinkedBy,
2418}
2419
2420#[derive(Debug, Clone, Serialize, Deserialize)]
2422pub struct GraphEdge {
2423 pub id: String,
2425 pub source_id: String,
2427 pub target_id: String,
2429 pub edge_type: EdgeType,
2431 pub weight: f64,
2433 pub created_at: i64,
2435}
2436
2437#[derive(Debug, Clone, Serialize, Deserialize)]
2439pub struct GraphNode {
2440 pub memory_id: String,
2442 pub content_preview: String,
2444 pub importance: f64,
2446 pub depth: u32,
2448}
2449
2450#[derive(Debug, Clone, Serialize, Deserialize)]
2452pub struct MemoryGraph {
2453 pub root_id: String,
2455 pub depth: u32,
2457 pub nodes: Vec<GraphNode>,
2459 pub edges: Vec<GraphEdge>,
2461}
2462
2463#[derive(Debug, Clone, Serialize, Deserialize)]
2465pub struct GraphPath {
2466 pub source_id: String,
2468 pub target_id: String,
2470 pub path: Vec<String>,
2472 pub hops: i32,
2474 pub edges: Vec<GraphEdge>,
2476}
2477
2478#[derive(Debug, Clone, Serialize, Deserialize)]
2480pub struct GraphLinkRequest {
2481 pub target_id: String,
2483 pub edge_type: EdgeType,
2485}
2486
2487#[derive(Debug, Clone, Serialize, Deserialize)]
2489pub struct GraphLinkResponse {
2490 pub edge: GraphEdge,
2492}
2493
2494#[derive(Debug, Clone, Serialize, Deserialize)]
2496pub struct GraphExport {
2497 pub agent_id: String,
2499 pub format: String,
2501 pub data: String,
2503 pub node_count: u64,
2505 pub edge_count: u64,
2507}
2508
2509#[derive(Debug, Clone, Default)]
2511pub struct GraphOptions {
2512 pub depth: Option<u32>,
2514 pub types: Option<Vec<EdgeType>>,
2516}
2517
2518impl GraphOptions {
2519 pub fn new() -> Self {
2521 Self::default()
2522 }
2523
2524 pub fn depth(mut self, depth: u32) -> Self {
2526 self.depth = Some(depth);
2527 self
2528 }
2529
2530 pub fn types(mut self, types: Vec<EdgeType>) -> Self {
2532 self.types = Some(types);
2533 self
2534 }
2535}
2536
2537#[derive(Debug, Clone, Serialize, Deserialize, Default)]
2543pub struct NamespaceNerConfig {
2544 pub extract_entities: bool,
2545 #[serde(skip_serializing_if = "Option::is_none")]
2546 pub entity_types: Option<Vec<String>>,
2547}
2548
2549#[derive(Debug, Clone, Serialize, Deserialize)]
2551pub struct ExtractedEntity {
2552 pub entity_type: String,
2553 pub value: String,
2554 pub score: f64,
2555}
2556
2557#[derive(Debug, Clone, Serialize, Deserialize)]
2559pub struct EntityExtractionResponse {
2560 pub entities: Vec<ExtractedEntity>,
2561}
2562
2563#[derive(Debug, Clone, Serialize, Deserialize)]
2565pub struct MemoryEntitiesResponse {
2566 pub memory_id: String,
2567 pub entities: Vec<ExtractedEntity>,
2568}
2569
2570#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
2582#[serde(rename_all = "lowercase")]
2583pub enum FeedbackSignal {
2584 Upvote,
2585 Downvote,
2586 Flag,
2587 Positive,
2588 Negative,
2589}
2590
2591#[derive(Debug, Clone, Serialize, Deserialize)]
2593pub struct FeedbackHistoryEntry {
2594 pub signal: FeedbackSignal,
2595 pub timestamp: u64,
2597 pub old_importance: f32,
2598 pub new_importance: f32,
2599}
2600
2601#[derive(Debug, Clone, Serialize, Deserialize)]
2603pub struct MemoryFeedbackBody {
2604 pub agent_id: String,
2605 pub signal: FeedbackSignal,
2606}
2607
2608#[derive(Debug, Clone, Serialize, Deserialize)]
2610pub struct MemoryImportancePatch {
2611 pub agent_id: String,
2612 pub importance: f32,
2613}
2614
2615#[derive(Debug, Clone, Serialize, Deserialize)]
2617pub struct FeedbackResponse {
2618 pub memory_id: String,
2619 pub new_importance: f32,
2621 pub signal: FeedbackSignal,
2622}
2623
2624#[derive(Debug, Clone, Serialize, Deserialize)]
2626pub struct FeedbackHistoryResponse {
2627 pub memory_id: String,
2628 pub entries: Vec<FeedbackHistoryEntry>,
2630}
2631
2632#[derive(Debug, Clone, Serialize, Deserialize)]
2634pub struct AgentFeedbackSummary {
2635 pub agent_id: String,
2636 pub upvotes: u64,
2637 pub downvotes: u64,
2638 pub flags: u64,
2639 pub total_feedback: u64,
2640 pub health_score: f32,
2642}
2643
2644#[derive(Debug, Clone, Serialize, Deserialize)]
2646pub struct FeedbackHealthResponse {
2647 pub agent_id: String,
2648 pub health_score: f32,
2650 pub memory_count: usize,
2651 pub avg_importance: f32,
2652}
2653
2654#[derive(Debug, Clone, Serialize, Deserialize)]
2660pub struct OdeEntity {
2661 pub text: String,
2663 pub label: String,
2665 pub start: usize,
2667 pub end: usize,
2669 pub score: f32,
2671}
2672
2673#[derive(Debug, Clone, Serialize, Deserialize)]
2675pub struct ExtractEntitiesRequest {
2676 pub content: String,
2678 pub agent_id: String,
2680 #[serde(skip_serializing_if = "Option::is_none")]
2682 pub memory_id: Option<String>,
2683 #[serde(skip_serializing_if = "Option::is_none")]
2686 pub entity_types: Option<Vec<String>>,
2687}
2688
2689#[derive(Debug, Clone, Serialize, Deserialize)]
2691pub struct ExtractEntitiesResponse {
2692 pub entities: Vec<OdeEntity>,
2694 pub model: String,
2696 pub processing_time_ms: u64,
2698}
2699
2700#[derive(Debug, Clone, Serialize, Deserialize)]
2706pub struct KgQueryResponse {
2707 pub agent_id: String,
2709 pub node_count: usize,
2711 pub edge_count: usize,
2713 pub edges: Vec<GraphEdge>,
2715}
2716
2717#[derive(Debug, Clone, Serialize, Deserialize)]
2719pub struct KgPathResponse {
2720 pub agent_id: String,
2722 pub from_id: String,
2724 pub to_id: String,
2726 pub hop_count: usize,
2728 pub path: Vec<String>,
2730}
2731
2732#[derive(Debug, Clone, Serialize, Deserialize)]
2734pub struct KgExportResponse {
2735 pub agent_id: String,
2737 pub format: String,
2739 pub node_count: usize,
2741 pub edge_count: usize,
2743 pub edges: Vec<GraphEdge>,
2745}
2746
2747#[derive(Debug, Clone, Serialize, Deserialize)]
2759pub struct MemoryPolicy {
2760 #[serde(skip_serializing_if = "Option::is_none")]
2763 pub working_ttl_seconds: Option<u64>,
2764 #[serde(skip_serializing_if = "Option::is_none")]
2766 pub episodic_ttl_seconds: Option<u64>,
2767 #[serde(skip_serializing_if = "Option::is_none")]
2769 pub semantic_ttl_seconds: Option<u64>,
2770 #[serde(skip_serializing_if = "Option::is_none")]
2772 pub procedural_ttl_seconds: Option<u64>,
2773
2774 #[serde(skip_serializing_if = "Option::is_none")]
2777 pub working_decay: Option<String>,
2778 #[serde(skip_serializing_if = "Option::is_none")]
2780 pub episodic_decay: Option<String>,
2781 #[serde(skip_serializing_if = "Option::is_none")]
2783 pub semantic_decay: Option<String>,
2784 #[serde(skip_serializing_if = "Option::is_none")]
2786 pub procedural_decay: Option<String>,
2787
2788 #[serde(skip_serializing_if = "Option::is_none")]
2792 pub spaced_repetition_factor: Option<f64>,
2793 #[serde(skip_serializing_if = "Option::is_none")]
2795 pub spaced_repetition_base_interval_seconds: Option<u64>,
2796
2797 #[serde(skip_serializing_if = "Option::is_none")]
2802 pub consolidation_enabled: Option<bool>,
2803 #[serde(skip_serializing_if = "Option::is_none")]
2806 pub consolidation_threshold: Option<f32>,
2807 #[serde(skip_serializing_if = "Option::is_none")]
2809 pub consolidation_interval_hours: Option<u32>,
2810 #[serde(skip_serializing_if = "Option::is_none")]
2815 pub consolidated_count: Option<u64>,
2816
2817 #[serde(skip_serializing_if = "Option::is_none")]
2820 pub rate_limit_enabled: Option<bool>,
2821 #[serde(skip_serializing_if = "Option::is_none")]
2823 pub rate_limit_stores_per_minute: Option<u32>,
2824 #[serde(skip_serializing_if = "Option::is_none")]
2826 pub rate_limit_recalls_per_minute: Option<u32>,
2827
2828 #[serde(skip_serializing_if = "Option::is_none")]
2835 pub dedup_on_store: Option<bool>,
2836 #[serde(skip_serializing_if = "Option::is_none")]
2841 pub dedup_threshold: Option<f32>,
2842}
2843
2844impl Default for MemoryPolicy {
2845 fn default() -> Self {
2846 Self {
2847 working_ttl_seconds: Some(14_400),
2848 episodic_ttl_seconds: Some(2_592_000),
2849 semantic_ttl_seconds: Some(31_536_000),
2850 procedural_ttl_seconds: Some(63_072_000),
2851 working_decay: Some("exponential".to_string()),
2852 episodic_decay: Some("power_law".to_string()),
2853 semantic_decay: Some("logarithmic".to_string()),
2854 procedural_decay: Some("flat".to_string()),
2855 spaced_repetition_factor: Some(1.0),
2856 spaced_repetition_base_interval_seconds: Some(86_400),
2857 consolidation_enabled: Some(false),
2858 consolidation_threshold: Some(0.92),
2859 consolidation_interval_hours: Some(24),
2860 consolidated_count: Some(0),
2861 rate_limit_enabled: Some(false),
2862 rate_limit_stores_per_minute: None,
2863 rate_limit_recalls_per_minute: None,
2864 dedup_on_store: Some(false),
2865 dedup_threshold: Some(0.92),
2866 }
2867 }
2868}
2869
2870#[derive(Debug, Clone, Serialize, Deserialize)]
2876pub struct BulkUpdateRequest {
2877 pub filter: serde_json::Value,
2878 pub update: serde_json::Value,
2879}
2880
2881#[derive(Debug, Clone, Serialize, Deserialize)]
2883pub struct BulkUpdateResponse {
2884 pub updated: u64,
2885 pub failed: u64,
2886 pub errors: Vec<String>,
2887}
2888
2889#[derive(Debug, Clone, Serialize, Deserialize)]
2891pub struct BulkDeleteRequest {
2892 pub filter: serde_json::Value,
2893}
2894
2895#[derive(Debug, Clone, Serialize, Deserialize)]
2897pub struct BulkDeleteResponse {
2898 pub deleted: u64,
2899 pub failed: u64,
2900 pub errors: Vec<String>,
2901}
2902
2903#[derive(Debug, Clone, Serialize, Deserialize)]
2905pub struct CountVectorsRequest {
2906 #[serde(skip_serializing_if = "Option::is_none")]
2907 pub filter: Option<serde_json::Value>,
2908}
2909
2910#[derive(Debug, Clone, Serialize, Deserialize)]
2912pub struct CountVectorsResponse {
2913 pub count: u64,
2914 pub namespace: String,
2915}
2916
2917#[derive(Debug, Clone, Serialize, Deserialize)]
2919pub struct AgentConsolidateResponse {
2920 pub agent_id: String,
2921 pub memories_scanned: u64,
2922 pub clusters_found: u64,
2923 pub memories_deprecated: u64,
2924 pub anchor_ids: Vec<String>,
2925 pub deprecated_ids: Vec<String>,
2926 #[serde(skip_serializing_if = "Option::is_none")]
2927 pub skipped: Option<bool>,
2928 #[serde(skip_serializing_if = "Option::is_none")]
2929 pub reason: Option<String>,
2930}
2931
2932#[derive(Debug, Clone, Serialize, Deserialize)]
2934pub struct AgentConsolidationLogEntry {
2935 pub timestamp: u64,
2936 pub clusters_found: u64,
2937 pub memories_deprecated: u64,
2938 pub anchor_ids: Vec<String>,
2939 pub deprecated_ids: Vec<String>,
2940}
2941
2942#[derive(Debug, Clone, Default, Serialize, Deserialize)]
2944pub struct ConsolidationConfigPatch {
2945 #[serde(skip_serializing_if = "Option::is_none")]
2946 pub enabled: Option<bool>,
2947 #[serde(skip_serializing_if = "Option::is_none")]
2948 pub epsilon: Option<f64>,
2949 #[serde(skip_serializing_if = "Option::is_none")]
2950 pub min_samples: Option<u32>,
2951 #[serde(skip_serializing_if = "Option::is_none")]
2952 pub soft_deprecation_days: Option<u32>,
2953}
2954
2955#[derive(Debug, Clone, Serialize, Deserialize)]
2957pub struct AgentConsolidationConfig {
2958 pub enabled: bool,
2959 pub epsilon: f64,
2960 pub min_samples: u32,
2961 pub soft_deprecation_days: u32,
2962}
2963
2964#[derive(Debug, Clone, Serialize, Deserialize)]
2966pub struct NamespaceEntityConfig {
2967 pub namespace: String,
2968 pub extract_entities: bool,
2969 pub entity_types: Vec<String>,
2970}
2971
2972#[derive(Debug, Clone, Serialize, Deserialize)]
2974pub struct NamespaceExtractorConfig {
2975 pub provider: String,
2976 #[serde(skip_serializing_if = "Option::is_none")]
2977 pub model: Option<String>,
2978 #[serde(skip_serializing_if = "Option::is_none")]
2979 pub base_url: Option<String>,
2980}
2981
2982#[derive(Debug, Clone, Serialize, Deserialize)]
2988pub struct NodeReplicationLag {
2989 pub node_id: String,
2990 pub lag_ms: u64,
2991 pub status: String,
2992}
2993
2994#[derive(Debug, Clone, Serialize, Deserialize)]
2996pub struct ReplicationStatus {
2997 pub replication_factor: u32,
2998 pub healthy_replicas: u32,
2999 pub total_nodes: u32,
3000 #[serde(default)]
3001 pub replication_lag: Vec<NodeReplicationLag>,
3002}
3003
3004#[derive(Debug, Clone, Serialize, Deserialize)]
3006pub struct ShardInfo {
3007 pub shard_id: String,
3008 pub namespace: String,
3009 pub primary_node: String,
3010 #[serde(default)]
3011 pub replica_nodes: Vec<String>,
3012 pub state: String,
3013 pub vector_count: u64,
3014 pub size_bytes: u64,
3015}
3016
3017#[derive(Debug, Clone, Serialize, Deserialize)]
3019pub struct ShardListResponse {
3020 pub shards: Vec<ShardInfo>,
3021 pub total: u32,
3022}
3023
3024#[derive(Debug, Clone, Serialize, Deserialize, Default)]
3026pub struct ShardRebalanceRequest {
3027 #[serde(default, skip_serializing_if = "Vec::is_empty")]
3028 pub shard_ids: Vec<String>,
3029 #[serde(default)]
3030 pub dry_run: bool,
3031}
3032
3033#[derive(Debug, Clone, Serialize, Deserialize)]
3035pub struct ShardMove {
3036 pub shard_id: String,
3037 pub from_node: String,
3038 pub to_node: String,
3039}
3040
3041#[derive(Debug, Clone, Serialize, Deserialize)]
3043pub struct ShardRebalanceResponse {
3044 pub initiated: bool,
3045 pub operation_id: String,
3046 pub shards_affected: u32,
3047 #[serde(skip_serializing_if = "Option::is_none")]
3048 pub estimated_seconds: Option<u64>,
3049 #[serde(default)]
3050 pub planned_moves: Vec<ShardMove>,
3051}
3052
3053#[derive(Debug, Clone, Serialize, Deserialize)]
3055pub struct MaintenanceStatus {
3056 pub enabled: bool,
3057 #[serde(skip_serializing_if = "Option::is_none")]
3058 pub reason: Option<String>,
3059 #[serde(skip_serializing_if = "Option::is_none")]
3060 pub enabled_at: Option<u64>,
3061 #[serde(skip_serializing_if = "Option::is_none")]
3062 pub scheduled_end: Option<u64>,
3063 #[serde(default)]
3064 pub nodes_in_maintenance: Vec<String>,
3065 pub rejecting_requests: bool,
3066}
3067
3068#[derive(Debug, Clone, Serialize, Deserialize)]
3070pub struct EnableMaintenanceRequest {
3071 pub reason: String,
3072 #[serde(default, skip_serializing_if = "Vec::is_empty")]
3073 pub node_ids: Vec<String>,
3074 #[serde(default)]
3075 pub reject_requests: bool,
3076 #[serde(skip_serializing_if = "Option::is_none")]
3077 pub duration_minutes: Option<u32>,
3078}
3079
3080#[derive(Debug, Clone, Serialize, Deserialize, Default)]
3082pub struct DisableMaintenanceRequest {
3083 #[serde(skip_serializing_if = "Option::is_none")]
3084 pub force: Option<bool>,
3085}
3086
3087#[derive(Debug, Clone, Serialize, Deserialize, Default)]
3089pub struct QuotaConfig {
3090 #[serde(skip_serializing_if = "Option::is_none")]
3091 pub max_vectors: Option<u64>,
3092 #[serde(skip_serializing_if = "Option::is_none")]
3093 pub max_storage_bytes: Option<u64>,
3094 #[serde(skip_serializing_if = "Option::is_none")]
3095 pub max_dimensions: Option<usize>,
3096 #[serde(skip_serializing_if = "Option::is_none")]
3097 pub max_metadata_bytes: Option<usize>,
3098 #[serde(default)]
3099 pub enforcement: String,
3100}
3101
3102#[derive(Debug, Clone, Serialize, Deserialize, Default)]
3104pub struct QuotaUsage {
3105 pub vector_count: u64,
3106 pub storage_bytes: u64,
3107 #[serde(skip_serializing_if = "Option::is_none")]
3108 pub avg_dimensions: Option<usize>,
3109 #[serde(skip_serializing_if = "Option::is_none")]
3110 pub avg_metadata_bytes: Option<usize>,
3111 pub last_updated: u64,
3112}
3113
3114#[derive(Debug, Clone, Serialize, Deserialize)]
3116pub struct QuotaStatus {
3117 pub namespace: String,
3118 pub config: QuotaConfig,
3119 pub usage: QuotaUsage,
3120 #[serde(skip_serializing_if = "Option::is_none")]
3121 pub vector_usage_percent: Option<f32>,
3122 #[serde(skip_serializing_if = "Option::is_none")]
3123 pub storage_usage_percent: Option<f32>,
3124 pub is_exceeded: bool,
3125 #[serde(default, skip_serializing_if = "Vec::is_empty")]
3126 pub exceeded_quotas: Vec<String>,
3127}
3128
3129#[derive(Debug, Clone, Serialize, Deserialize)]
3131pub struct QuotaListResponse {
3132 pub quotas: Vec<QuotaStatus>,
3133 pub total: u64,
3134 #[serde(skip_serializing_if = "Option::is_none")]
3135 pub default_config: Option<QuotaConfig>,
3136}
3137
3138#[derive(Debug, Clone, Serialize, Deserialize)]
3140pub struct DefaultQuotaResponse {
3141 pub config: Option<QuotaConfig>,
3142}
3143
3144#[derive(Debug, Clone, Serialize, Deserialize, Default)]
3146pub struct SetDefaultQuotaRequest {
3147 pub config: Option<QuotaConfig>,
3148}
3149
3150#[derive(Debug, Clone, Serialize, Deserialize)]
3152pub struct SetQuotaRequest {
3153 pub config: QuotaConfig,
3154}
3155
3156#[derive(Debug, Clone, Serialize, Deserialize)]
3158pub struct SetQuotaResponse {
3159 pub success: bool,
3160 pub namespace: String,
3161 pub config: QuotaConfig,
3162 pub message: String,
3163}
3164
3165#[derive(Debug, Clone, Serialize, Deserialize)]
3167pub struct QuotaCheckRequest {
3168 pub vector_ids: Vec<String>,
3169 #[serde(skip_serializing_if = "Option::is_none")]
3170 pub dimensions: Option<usize>,
3171 #[serde(skip_serializing_if = "Option::is_none")]
3172 pub metadata_bytes: Option<usize>,
3173}
3174
3175#[derive(Debug, Clone, Serialize, Deserialize)]
3177pub struct QuotaCheckResult {
3178 pub allowed: bool,
3179 #[serde(skip_serializing_if = "Option::is_none")]
3180 pub reason: Option<String>,
3181 pub usage: QuotaUsage,
3182 #[serde(skip_serializing_if = "Option::is_none")]
3183 pub exceeded_quota: Option<String>,
3184}
3185
3186#[derive(Debug, Clone, Serialize, Deserialize)]
3188pub struct AdminBackupInfo {
3189 pub backup_id: String,
3190 pub name: String,
3191 pub backup_type: String,
3192 pub status: String,
3193 #[serde(default)]
3194 pub namespaces: Vec<String>,
3195 pub vector_count: u64,
3196 pub size_bytes: u64,
3197 pub created_at: u64,
3198 #[serde(skip_serializing_if = "Option::is_none")]
3199 pub completed_at: Option<u64>,
3200 #[serde(skip_serializing_if = "Option::is_none")]
3201 pub duration_seconds: Option<u64>,
3202 #[serde(skip_serializing_if = "Option::is_none")]
3203 pub storage_path: Option<String>,
3204 #[serde(skip_serializing_if = "Option::is_none")]
3205 pub error: Option<String>,
3206 pub encrypted: bool,
3207 #[serde(skip_serializing_if = "Option::is_none")]
3208 pub compression: Option<String>,
3209}
3210
3211#[derive(Debug, Clone, Serialize, Deserialize)]
3213pub struct BackupListResponse {
3214 pub backups: Vec<AdminBackupInfo>,
3215 pub total: u64,
3216}
3217
3218#[derive(Debug, Clone, Serialize, Deserialize)]
3220pub struct CreateBackupRequest {
3221 pub name: String,
3222 #[serde(skip_serializing_if = "Option::is_none")]
3223 pub backup_type: Option<String>,
3224 #[serde(skip_serializing_if = "Option::is_none")]
3225 pub namespaces: Option<Vec<String>>,
3226 #[serde(skip_serializing_if = "Option::is_none")]
3227 pub encrypt: Option<bool>,
3228 #[serde(skip_serializing_if = "Option::is_none")]
3229 pub compression: Option<String>,
3230}
3231
3232#[derive(Debug, Clone, Serialize, Deserialize)]
3234pub struct CreateBackupResponse {
3235 pub backup: AdminBackupInfo,
3236 #[serde(skip_serializing_if = "Option::is_none")]
3237 pub estimated_completion: Option<u64>,
3238}
3239
3240#[derive(Debug, Clone, Serialize, Deserialize)]
3242pub struct RestoreBackupRequest {
3243 pub backup_id: String,
3244 #[serde(skip_serializing_if = "Option::is_none")]
3245 pub target_namespaces: Option<Vec<String>>,
3246 #[serde(skip_serializing_if = "Option::is_none")]
3247 pub overwrite: Option<bool>,
3248 #[serde(skip_serializing_if = "Option::is_none")]
3249 pub point_in_time: Option<u64>,
3250}
3251
3252#[derive(Debug, Clone, Serialize, Deserialize)]
3254pub struct RestoreBackupResponse {
3255 pub restore_id: String,
3256 pub status: String,
3257 pub backup_id: String,
3258 #[serde(default)]
3259 pub namespaces: Vec<String>,
3260 pub started_at: u64,
3261 #[serde(skip_serializing_if = "Option::is_none")]
3262 pub estimated_completion: Option<u64>,
3263 #[serde(skip_serializing_if = "Option::is_none")]
3264 pub progress_percent: Option<u8>,
3265 #[serde(skip_serializing_if = "Option::is_none")]
3266 pub vectors_restored: Option<u64>,
3267 #[serde(skip_serializing_if = "Option::is_none")]
3268 pub completed_at: Option<u64>,
3269 #[serde(skip_serializing_if = "Option::is_none")]
3270 pub duration_seconds: Option<u64>,
3271 #[serde(skip_serializing_if = "Option::is_none")]
3272 pub error: Option<String>,
3273}
3274
3275#[derive(Debug, Clone, Serialize, Deserialize)]
3277pub struct BackupSchedule {
3278 pub enabled: bool,
3279 #[serde(skip_serializing_if = "Option::is_none")]
3280 pub cron: Option<String>,
3281 pub backup_type: String,
3282 pub retention_days: u32,
3283 pub max_backups: u32,
3284 #[serde(default)]
3285 pub namespaces: Vec<String>,
3286 pub encrypt: bool,
3287 #[serde(skip_serializing_if = "Option::is_none")]
3288 pub compression: Option<String>,
3289 #[serde(skip_serializing_if = "Option::is_none")]
3290 pub last_backup_at: Option<u64>,
3291 #[serde(skip_serializing_if = "Option::is_none")]
3292 pub next_backup_at: Option<u64>,
3293}
3294
3295#[derive(Debug, Clone, Serialize, Deserialize, Default)]
3297pub struct UpdateBackupScheduleRequest {
3298 #[serde(skip_serializing_if = "Option::is_none")]
3299 pub enabled: Option<bool>,
3300 #[serde(skip_serializing_if = "Option::is_none")]
3301 pub cron: Option<String>,
3302 #[serde(skip_serializing_if = "Option::is_none")]
3303 pub backup_type: Option<String>,
3304 #[serde(skip_serializing_if = "Option::is_none")]
3305 pub retention_days: Option<u32>,
3306 #[serde(skip_serializing_if = "Option::is_none")]
3307 pub max_backups: Option<u32>,
3308 #[serde(skip_serializing_if = "Option::is_none")]
3309 pub namespaces: Option<Vec<String>>,
3310 #[serde(skip_serializing_if = "Option::is_none")]
3311 pub encrypt: Option<bool>,
3312 #[serde(skip_serializing_if = "Option::is_none")]
3313 pub compression: Option<String>,
3314}
3315
3316fn default_route_top_k() -> usize {
3321 3
3322}
3323
3324fn default_route_min_similarity() -> f32 {
3325 0.3
3326}
3327
3328#[derive(Debug, Clone, Serialize, Deserialize)]
3330pub struct RouteRequest {
3331 pub query: String,
3333 #[serde(default = "default_route_top_k")]
3335 pub top_k: usize,
3336 #[serde(default = "default_route_min_similarity")]
3338 pub min_similarity: f32,
3339 #[serde(skip_serializing_if = "Option::is_none")]
3341 pub model: Option<String>,
3342}
3343
3344#[derive(Debug, Clone, Serialize, Deserialize)]
3346pub struct RouteMatch {
3347 pub namespace: String,
3349 pub similarity: f64,
3351 #[serde(skip_serializing_if = "Option::is_none")]
3353 pub description: Option<String>,
3354}
3355
3356#[derive(Debug, Clone, Serialize, Deserialize)]
3358pub struct RouteResponse {
3359 pub routes: Vec<RouteMatch>,
3361 pub model: String,
3363 pub embedding_time_ms: u64,
3365}
3366
3367#[derive(Debug, Clone, Serialize, Deserialize)]
3373pub struct ImportJobStatus {
3374 pub job_id: String,
3376 pub status: String,
3378 pub format: String,
3380 pub total: usize,
3382 pub imported: usize,
3384 pub skipped: usize,
3386 #[serde(default)]
3388 pub errors: Vec<String>,
3389 pub started_at: u64,
3391 #[serde(skip_serializing_if = "Option::is_none")]
3393 pub finished_at: Option<u64>,
3394}
3395
3396#[derive(Debug, Clone, Serialize, Deserialize)]
3402pub struct TierInfo {
3403 pub name: String,
3405 pub tier_type: String,
3407 pub technology: String,
3409 pub description: String,
3411 pub target_latency: String,
3413 #[serde(skip_serializing_if = "Option::is_none")]
3415 pub capacity: Option<String>,
3416 pub status: String,
3418 pub current_count: u64,
3420 pub hit_count: u64,
3422 pub hit_rate: f64,
3424}
3425
3426#[derive(Debug, Clone, Serialize, Deserialize)]
3428pub struct TierConfig {
3429 pub hot_tier_capacity: usize,
3431 pub hot_to_warm_threshold_secs: u64,
3433 pub warm_to_cold_threshold_secs: u64,
3435 pub auto_tier_enabled: bool,
3437 pub tier_check_interval_secs: u64,
3439}
3440
3441#[derive(Debug, Clone, Serialize, Deserialize)]
3443pub struct TierActivity {
3444 pub promotions: u64,
3446 pub demotions: u64,
3448 pub cache_hit_rate: f64,
3450 pub storage_backend: String,
3452 pub promotions_to_hot: u64,
3454 pub demotions_to_warm: u64,
3456 pub demotions_to_cold: u64,
3458}
3459
3460#[derive(Debug, Clone, Serialize, Deserialize)]
3462pub struct StorageTierOverview {
3463 pub tiers_enabled: bool,
3465 pub architecture: Vec<TierInfo>,
3467 pub config: TierConfig,
3469 pub activity: TierActivity,
3471}
3472
3473#[derive(Debug, Clone, Serialize, Deserialize)]
3479pub struct MemoryTypeStatsResponse {
3480 pub total: u64,
3482 pub working: u64,
3484 pub episodic: u64,
3486 pub semantic: u64,
3488 pub procedural: u64,
3490 pub agent_namespaces: u64,
3492}
3493
3494fn default_target_dimension() -> usize {
3499 1024
3500}
3501
3502#[derive(Debug, Clone, Serialize, Deserialize)]
3504pub struct MigrateNamespaceDimensionsRequest {
3505 #[serde(default)]
3507 pub namespaces: Vec<String>,
3508 #[serde(default = "default_target_dimension")]
3510 pub target_dimension: usize,
3511}
3512
3513#[derive(Debug, Clone, Serialize, Deserialize)]
3515pub struct NamespaceMigrationResult {
3516 pub namespace: String,
3518 pub original_dimension: usize,
3520 pub vectors_migrated: usize,
3522 pub vectors_skipped: usize,
3524 pub status: String,
3526 #[serde(skip_serializing_if = "Option::is_none")]
3528 pub error: Option<String>,
3529}
3530
3531#[derive(Debug, Clone, Serialize, Deserialize)]
3533pub struct MigrateDimensionsResponse {
3534 pub migrated: usize,
3536 pub failed: usize,
3538 pub already_current: usize,
3540 pub results: Vec<NamespaceMigrationResult>,
3542}