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 pub build_sha: Option<String>,
90}
91
92#[derive(Debug, Clone, Serialize, Deserialize)]
94pub struct ReadinessResponse {
95 pub ready: bool,
97 pub components: Option<HashMap<String, bool>>,
99}
100
101#[derive(Debug, Clone, Serialize, Deserialize)]
107pub struct NamespaceInfo {
108 #[serde(alias = "namespace")]
110 pub name: String,
111 #[serde(default)]
113 pub vector_count: u64,
114 #[serde(alias = "dimension")]
116 pub dimensions: Option<u32>,
117 pub index_type: Option<String>,
119 #[serde(default)]
121 pub created: Option<bool>,
122}
123
124#[derive(Debug, Clone, Serialize, Deserialize)]
126pub struct ListNamespacesResponse {
127 pub namespaces: Vec<String>,
129}
130
131#[derive(Debug, Clone, Serialize, Deserialize)]
137pub struct Vector {
138 pub id: String,
140 pub values: Vec<f32>,
142 #[serde(skip_serializing_if = "Option::is_none")]
144 pub metadata: Option<HashMap<String, serde_json::Value>>,
145}
146
147impl Vector {
148 pub fn new(id: impl Into<String>, values: Vec<f32>) -> Self {
150 Self {
151 id: id.into(),
152 values,
153 metadata: None,
154 }
155 }
156
157 pub fn with_metadata(
159 id: impl Into<String>,
160 values: Vec<f32>,
161 metadata: HashMap<String, serde_json::Value>,
162 ) -> Self {
163 Self {
164 id: id.into(),
165 values,
166 metadata: Some(metadata),
167 }
168 }
169}
170
171#[derive(Debug, Clone, Serialize, Deserialize)]
173pub struct UpsertRequest {
174 pub vectors: Vec<Vector>,
176}
177
178impl UpsertRequest {
179 pub fn single(vector: Vector) -> Self {
181 Self {
182 vectors: vec![vector],
183 }
184 }
185
186 pub fn batch(vectors: Vec<Vector>) -> Self {
188 Self { vectors }
189 }
190}
191
192#[derive(Debug, Clone, Serialize, Deserialize)]
194pub struct UpsertResponse {
195 pub upserted_count: u64,
197}
198
199#[derive(Debug, Clone, Serialize, Deserialize)]
216pub struct ColumnUpsertRequest {
217 pub ids: Vec<String>,
219 pub vectors: Vec<Vec<f32>>,
221 #[serde(default, skip_serializing_if = "HashMap::is_empty")]
224 pub attributes: HashMap<String, Vec<serde_json::Value>>,
225 #[serde(skip_serializing_if = "Option::is_none")]
227 pub ttl_seconds: Option<u64>,
228 #[serde(skip_serializing_if = "Option::is_none")]
230 pub dimension: Option<usize>,
231}
232
233impl ColumnUpsertRequest {
234 pub fn new(ids: Vec<String>, vectors: Vec<Vec<f32>>) -> Self {
236 Self {
237 ids,
238 vectors,
239 attributes: HashMap::new(),
240 ttl_seconds: None,
241 dimension: None,
242 }
243 }
244
245 pub fn with_attribute(
247 mut self,
248 name: impl Into<String>,
249 values: Vec<serde_json::Value>,
250 ) -> Self {
251 self.attributes.insert(name.into(), values);
252 self
253 }
254
255 pub fn with_ttl(mut self, seconds: u64) -> Self {
257 self.ttl_seconds = Some(seconds);
258 self
259 }
260
261 pub fn with_dimension(mut self, dim: usize) -> Self {
263 self.dimension = Some(dim);
264 self
265 }
266
267 pub fn len(&self) -> usize {
269 self.ids.len()
270 }
271
272 pub fn is_empty(&self) -> bool {
274 self.ids.is_empty()
275 }
276}
277
278#[derive(Debug, Clone, Serialize, Deserialize)]
280pub struct DeleteRequest {
281 pub ids: Vec<String>,
283}
284
285impl DeleteRequest {
286 pub fn single(id: impl Into<String>) -> Self {
288 Self {
289 ids: vec![id.into()],
290 }
291 }
292
293 pub fn batch(ids: Vec<String>) -> Self {
295 Self { ids }
296 }
297}
298
299#[derive(Debug, Clone, Serialize, Deserialize)]
301pub struct DeleteResponse {
302 pub deleted_count: u64,
304}
305
306#[derive(Debug, Clone, Copy, Default, Serialize, Deserialize, PartialEq, Eq)]
312#[serde(rename_all = "snake_case")]
313pub enum ReadConsistency {
314 Strong,
316 #[default]
318 Eventual,
319 #[serde(rename = "bounded_staleness")]
321 BoundedStaleness,
322}
323
324#[derive(Debug, Clone, Copy, Default, Serialize, Deserialize, PartialEq, Eq)]
326pub struct StalenessConfig {
327 #[serde(default = "default_max_staleness_ms")]
329 pub max_staleness_ms: u64,
330}
331
332fn default_max_staleness_ms() -> u64 {
333 5000 }
335
336impl StalenessConfig {
337 pub fn new(max_staleness_ms: u64) -> Self {
339 Self { max_staleness_ms }
340 }
341}
342
343#[derive(Debug, Clone, Copy, Default, Serialize, Deserialize, PartialEq, Eq)]
345#[serde(rename_all = "snake_case")]
346pub enum DistanceMetric {
347 #[default]
349 Cosine,
350 Euclidean,
352 DotProduct,
354}
355
356#[derive(Debug, Clone, Serialize, Deserialize)]
358pub struct QueryRequest {
359 pub vector: Vec<f32>,
361 pub top_k: u32,
363 #[serde(default)]
365 pub distance_metric: DistanceMetric,
366 #[serde(skip_serializing_if = "Option::is_none")]
368 pub filter: Option<serde_json::Value>,
369 #[serde(default = "default_true")]
371 pub include_metadata: bool,
372 #[serde(default)]
374 pub include_vectors: bool,
375 #[serde(default)]
377 pub consistency: ReadConsistency,
378 #[serde(skip_serializing_if = "Option::is_none")]
380 pub staleness_config: Option<StalenessConfig>,
381}
382
383fn default_true() -> bool {
384 true
385}
386
387impl QueryRequest {
388 pub fn new(vector: Vec<f32>, top_k: u32) -> Self {
390 Self {
391 vector,
392 top_k,
393 distance_metric: DistanceMetric::default(),
394 filter: None,
395 include_metadata: true,
396 include_vectors: false,
397 consistency: ReadConsistency::default(),
398 staleness_config: None,
399 }
400 }
401
402 pub fn with_filter(mut self, filter: serde_json::Value) -> Self {
404 self.filter = Some(filter);
405 self
406 }
407
408 pub fn include_metadata(mut self, include: bool) -> Self {
410 self.include_metadata = include;
411 self
412 }
413
414 pub fn include_vectors(mut self, include: bool) -> Self {
416 self.include_vectors = include;
417 self
418 }
419
420 pub fn with_distance_metric(mut self, metric: DistanceMetric) -> Self {
422 self.distance_metric = metric;
423 self
424 }
425
426 pub fn with_consistency(mut self, consistency: ReadConsistency) -> Self {
428 self.consistency = consistency;
429 self
430 }
431
432 pub fn with_bounded_staleness(mut self, max_staleness_ms: u64) -> Self {
434 self.consistency = ReadConsistency::BoundedStaleness;
435 self.staleness_config = Some(StalenessConfig::new(max_staleness_ms));
436 self
437 }
438
439 pub fn with_strong_consistency(mut self) -> Self {
441 self.consistency = ReadConsistency::Strong;
442 self
443 }
444}
445
446#[derive(Debug, Clone, Serialize, Deserialize)]
448pub struct Match {
449 pub id: String,
451 pub score: f32,
453 #[serde(skip_serializing_if = "Option::is_none")]
455 pub metadata: Option<HashMap<String, serde_json::Value>>,
456}
457
458#[derive(Debug, Clone, Serialize, Deserialize)]
460pub struct QueryResponse {
461 #[serde(alias = "matches")]
463 pub results: Vec<Match>,
464}
465
466#[derive(Debug, Clone, Serialize, Deserialize)]
472pub struct Document {
473 pub id: String,
475 pub text: String,
477 #[serde(skip_serializing_if = "Option::is_none")]
479 pub metadata: Option<HashMap<String, serde_json::Value>>,
480}
481
482impl Document {
483 pub fn new(id: impl Into<String>, text: impl Into<String>) -> Self {
485 Self {
486 id: id.into(),
487 text: text.into(),
488 metadata: None,
489 }
490 }
491
492 pub fn with_metadata(
494 id: impl Into<String>,
495 text: impl Into<String>,
496 metadata: HashMap<String, serde_json::Value>,
497 ) -> Self {
498 Self {
499 id: id.into(),
500 text: text.into(),
501 metadata: Some(metadata),
502 }
503 }
504}
505
506#[derive(Debug, Clone, Serialize, Deserialize)]
508pub struct IndexDocumentsRequest {
509 pub documents: Vec<Document>,
511}
512
513#[derive(Debug, Clone, Serialize, Deserialize)]
515pub struct IndexDocumentsResponse {
516 pub indexed_count: u64,
518}
519
520#[derive(Debug, Clone, Serialize, Deserialize)]
522pub struct FullTextSearchRequest {
523 pub query: String,
525 pub top_k: u32,
527 #[serde(skip_serializing_if = "Option::is_none")]
529 pub filter: Option<serde_json::Value>,
530}
531
532impl FullTextSearchRequest {
533 pub fn new(query: impl Into<String>, top_k: u32) -> Self {
535 Self {
536 query: query.into(),
537 top_k,
538 filter: None,
539 }
540 }
541
542 pub fn with_filter(mut self, filter: serde_json::Value) -> Self {
544 self.filter = Some(filter);
545 self
546 }
547}
548
549#[derive(Debug, Clone, Serialize, Deserialize)]
551pub struct FullTextMatch {
552 pub id: String,
554 pub score: f32,
556 #[serde(skip_serializing_if = "Option::is_none")]
558 pub text: Option<String>,
559 #[serde(skip_serializing_if = "Option::is_none")]
561 pub metadata: Option<HashMap<String, serde_json::Value>>,
562}
563
564#[derive(Debug, Clone, Serialize, Deserialize)]
566pub struct FullTextSearchResponse {
567 #[serde(alias = "matches")]
569 pub results: Vec<FullTextMatch>,
570}
571
572#[derive(Debug, Clone, Serialize, Deserialize)]
574pub struct FullTextStats {
575 pub document_count: u64,
577 pub term_count: u64,
579}
580
581#[derive(Debug, Clone, Serialize, Deserialize)]
590pub struct HybridSearchRequest {
591 #[serde(skip_serializing_if = "Option::is_none")]
593 pub vector: Option<Vec<f32>>,
594 pub text: String,
596 pub top_k: u32,
598 #[serde(default = "default_vector_weight")]
600 pub vector_weight: f32,
601 #[serde(skip_serializing_if = "Option::is_none")]
603 pub filter: Option<serde_json::Value>,
604}
605
606fn default_vector_weight() -> f32 {
607 0.5
608}
609
610impl HybridSearchRequest {
611 pub fn new(vector: Vec<f32>, text: impl Into<String>, top_k: u32) -> Self {
613 Self {
614 vector: Some(vector),
615 text: text.into(),
616 top_k,
617 vector_weight: 0.5,
618 filter: None,
619 }
620 }
621
622 pub fn text_only(text: impl Into<String>, top_k: u32) -> Self {
624 Self {
625 vector: None,
626 text: text.into(),
627 top_k,
628 vector_weight: 0.5,
629 filter: None,
630 }
631 }
632
633 pub fn with_vector_weight(mut self, weight: f32) -> Self {
635 self.vector_weight = weight.clamp(0.0, 1.0);
636 self
637 }
638
639 pub fn with_filter(mut self, filter: serde_json::Value) -> Self {
641 self.filter = Some(filter);
642 self
643 }
644}
645
646#[derive(Debug, Clone, Serialize, Deserialize)]
648pub struct HybridSearchResponse {
649 #[serde(alias = "matches")]
651 pub results: Vec<Match>,
652}
653
654#[derive(Debug, Clone, Serialize, Deserialize)]
660pub struct SystemDiagnostics {
661 pub system: SystemInfo,
663 pub resources: ResourceUsage,
665 pub components: ComponentHealth,
667 pub active_jobs: u64,
669}
670
671#[derive(Debug, Clone, Serialize, Deserialize)]
673pub struct SystemInfo {
674 pub version: String,
676 pub rust_version: String,
678 pub uptime_seconds: u64,
680 pub pid: u32,
682}
683
684#[derive(Debug, Clone, Serialize, Deserialize)]
686pub struct ResourceUsage {
687 pub memory_bytes: u64,
689 pub thread_count: u64,
691 pub open_fds: u64,
693 pub cpu_percent: Option<f64>,
695}
696
697#[derive(Debug, Clone, Serialize, Deserialize)]
699pub struct ComponentHealth {
700 pub storage: HealthStatus,
702 pub search_engine: HealthStatus,
704 pub cache: HealthStatus,
706 pub grpc: HealthStatus,
708}
709
710#[derive(Debug, Clone, Serialize, Deserialize)]
712pub struct HealthStatus {
713 pub healthy: bool,
715 pub message: String,
717 pub last_check: u64,
719}
720
721#[derive(Debug, Clone, Serialize, Deserialize)]
723pub struct JobInfo {
724 pub id: String,
726 pub job_type: String,
728 pub status: String,
730 pub created_at: u64,
732 #[serde(skip_serializing_if = "Option::is_none")]
734 pub started_at: Option<u64>,
735 #[serde(skip_serializing_if = "Option::is_none")]
737 pub completed_at: Option<u64>,
738 pub progress: u8,
740 #[serde(skip_serializing_if = "Option::is_none")]
742 pub message: Option<String>,
743 #[serde(default)]
745 pub metadata: std::collections::HashMap<String, String>,
746}
747
748#[derive(Debug, Clone, Serialize, Deserialize)]
750pub struct CompactionRequest {
751 #[serde(skip_serializing_if = "Option::is_none")]
753 pub namespace: Option<String>,
754 #[serde(default)]
756 pub force: bool,
757}
758
759#[derive(Debug, Clone, Serialize, Deserialize)]
761pub struct CompactionResponse {
762 pub job_id: String,
764 pub message: String,
766}
767
768#[derive(Debug, Clone, Copy, Default, Serialize, Deserialize, PartialEq, Eq)]
774#[serde(rename_all = "snake_case")]
775pub enum WarmingPriority {
776 Critical,
778 High,
780 #[default]
782 Normal,
783 Low,
785 Background,
787}
788
789#[derive(Debug, Clone, Copy, Default, Serialize, Deserialize, PartialEq, Eq)]
791#[serde(rename_all = "snake_case")]
792pub enum WarmingTargetTier {
793 L1,
795 #[default]
797 L2,
798 Both,
800}
801
802#[derive(Debug, Clone, Copy, Default, Serialize, Deserialize, PartialEq, Eq)]
804#[serde(rename_all = "snake_case")]
805pub enum AccessPatternHint {
806 #[default]
808 Random,
809 Sequential,
811 Temporal,
813 Spatial,
815}
816
817#[derive(Debug, Clone, Serialize, Deserialize)]
819pub struct WarmCacheRequest {
820 pub namespace: String,
822 #[serde(skip_serializing_if = "Option::is_none")]
824 pub vector_ids: Option<Vec<String>>,
825 #[serde(default)]
827 pub priority: WarmingPriority,
828 #[serde(default)]
830 pub target_tier: WarmingTargetTier,
831 #[serde(default)]
833 pub background: bool,
834 #[serde(skip_serializing_if = "Option::is_none")]
836 pub ttl_hint_seconds: Option<u64>,
837 #[serde(default)]
839 pub access_pattern: AccessPatternHint,
840 #[serde(skip_serializing_if = "Option::is_none")]
842 pub max_vectors: Option<usize>,
843}
844
845impl WarmCacheRequest {
846 pub fn new(namespace: impl Into<String>) -> Self {
848 Self {
849 namespace: namespace.into(),
850 vector_ids: None,
851 priority: WarmingPriority::default(),
852 target_tier: WarmingTargetTier::default(),
853 background: false,
854 ttl_hint_seconds: None,
855 access_pattern: AccessPatternHint::default(),
856 max_vectors: None,
857 }
858 }
859
860 pub fn with_vector_ids(mut self, ids: Vec<String>) -> Self {
862 self.vector_ids = Some(ids);
863 self
864 }
865
866 pub fn with_priority(mut self, priority: WarmingPriority) -> Self {
868 self.priority = priority;
869 self
870 }
871
872 pub fn with_target_tier(mut self, tier: WarmingTargetTier) -> Self {
874 self.target_tier = tier;
875 self
876 }
877
878 pub fn in_background(mut self) -> Self {
880 self.background = true;
881 self
882 }
883
884 pub fn with_ttl(mut self, seconds: u64) -> Self {
886 self.ttl_hint_seconds = Some(seconds);
887 self
888 }
889
890 pub fn with_access_pattern(mut self, pattern: AccessPatternHint) -> Self {
892 self.access_pattern = pattern;
893 self
894 }
895
896 pub fn with_max_vectors(mut self, max: usize) -> Self {
898 self.max_vectors = Some(max);
899 self
900 }
901}
902
903#[derive(Debug, Clone, Serialize, Deserialize)]
905pub struct WarmCacheResponse {
906 pub success: bool,
908 pub entries_warmed: u64,
910 pub entries_skipped: u64,
912 #[serde(skip_serializing_if = "Option::is_none")]
914 pub job_id: Option<String>,
915 pub message: String,
917 #[serde(skip_serializing_if = "Option::is_none")]
919 pub estimated_completion: Option<String>,
920 pub target_tier: WarmingTargetTier,
922 pub priority: WarmingPriority,
924 #[serde(skip_serializing_if = "Option::is_none")]
926 pub bytes_warmed: Option<u64>,
927}
928
929#[derive(Debug, Clone, Serialize, Deserialize)]
935pub struct ExportRequest {
936 #[serde(default = "default_export_top_k")]
938 pub top_k: usize,
939 #[serde(skip_serializing_if = "Option::is_none")]
941 pub cursor: Option<String>,
942 #[serde(default = "default_true")]
944 pub include_vectors: bool,
945 #[serde(default = "default_true")]
947 pub include_metadata: bool,
948}
949
950fn default_export_top_k() -> usize {
951 1000
952}
953
954impl Default for ExportRequest {
955 fn default() -> Self {
956 Self {
957 top_k: 1000,
958 cursor: None,
959 include_vectors: true,
960 include_metadata: true,
961 }
962 }
963}
964
965impl ExportRequest {
966 pub fn new() -> Self {
968 Self::default()
969 }
970
971 pub fn with_top_k(mut self, top_k: usize) -> Self {
973 self.top_k = top_k;
974 self
975 }
976
977 pub fn with_cursor(mut self, cursor: impl Into<String>) -> Self {
979 self.cursor = Some(cursor.into());
980 self
981 }
982
983 pub fn include_vectors(mut self, include: bool) -> Self {
985 self.include_vectors = include;
986 self
987 }
988
989 pub fn include_metadata(mut self, include: bool) -> Self {
991 self.include_metadata = include;
992 self
993 }
994}
995
996#[derive(Debug, Clone, Serialize, Deserialize)]
998pub struct ExportedVector {
999 pub id: String,
1001 #[serde(skip_serializing_if = "Option::is_none")]
1003 pub values: Option<Vec<f32>>,
1004 #[serde(skip_serializing_if = "Option::is_none")]
1006 pub metadata: Option<serde_json::Value>,
1007 #[serde(skip_serializing_if = "Option::is_none")]
1009 pub ttl_seconds: Option<u64>,
1010}
1011
1012#[derive(Debug, Clone, Serialize, Deserialize)]
1014pub struct ExportResponse {
1015 pub vectors: Vec<ExportedVector>,
1017 #[serde(skip_serializing_if = "Option::is_none")]
1019 pub next_cursor: Option<String>,
1020 pub total_count: usize,
1022 pub returned_count: usize,
1024}
1025
1026#[derive(Debug, Clone, Serialize, Deserialize)]
1032pub struct BatchQueryItem {
1033 #[serde(skip_serializing_if = "Option::is_none")]
1035 pub id: Option<String>,
1036 pub vector: Vec<f32>,
1038 #[serde(default = "default_batch_top_k")]
1040 pub top_k: u32,
1041 #[serde(skip_serializing_if = "Option::is_none")]
1043 pub filter: Option<serde_json::Value>,
1044 #[serde(default)]
1046 pub include_metadata: bool,
1047 #[serde(default)]
1049 pub consistency: ReadConsistency,
1050 #[serde(skip_serializing_if = "Option::is_none")]
1052 pub staleness_config: Option<StalenessConfig>,
1053}
1054
1055fn default_batch_top_k() -> u32 {
1056 10
1057}
1058
1059impl BatchQueryItem {
1060 pub fn new(vector: Vec<f32>, top_k: u32) -> Self {
1062 Self {
1063 id: None,
1064 vector,
1065 top_k,
1066 filter: None,
1067 include_metadata: true,
1068 consistency: ReadConsistency::default(),
1069 staleness_config: None,
1070 }
1071 }
1072
1073 pub fn with_id(mut self, id: impl Into<String>) -> Self {
1075 self.id = Some(id.into());
1076 self
1077 }
1078
1079 pub fn with_filter(mut self, filter: serde_json::Value) -> Self {
1081 self.filter = Some(filter);
1082 self
1083 }
1084
1085 pub fn include_metadata(mut self, include: bool) -> Self {
1087 self.include_metadata = include;
1088 self
1089 }
1090
1091 pub fn with_consistency(mut self, consistency: ReadConsistency) -> Self {
1093 self.consistency = consistency;
1094 self
1095 }
1096
1097 pub fn with_bounded_staleness(mut self, max_staleness_ms: u64) -> Self {
1099 self.consistency = ReadConsistency::BoundedStaleness;
1100 self.staleness_config = Some(StalenessConfig::new(max_staleness_ms));
1101 self
1102 }
1103}
1104
1105#[derive(Debug, Clone, Serialize, Deserialize)]
1107pub struct BatchQueryRequest {
1108 pub queries: Vec<BatchQueryItem>,
1110}
1111
1112impl BatchQueryRequest {
1113 pub fn new(queries: Vec<BatchQueryItem>) -> Self {
1115 Self { queries }
1116 }
1117
1118 pub fn single(query: BatchQueryItem) -> Self {
1120 Self {
1121 queries: vec![query],
1122 }
1123 }
1124}
1125
1126#[derive(Debug, Clone, Serialize, Deserialize)]
1128pub struct BatchQueryResult {
1129 #[serde(skip_serializing_if = "Option::is_none")]
1131 pub id: Option<String>,
1132 pub results: Vec<Match>,
1134 pub latency_ms: f64,
1136 #[serde(skip_serializing_if = "Option::is_none")]
1138 pub error: Option<String>,
1139}
1140
1141#[derive(Debug, Clone, Serialize, Deserialize)]
1143pub struct BatchQueryResponse {
1144 pub results: Vec<BatchQueryResult>,
1146 pub total_latency_ms: f64,
1148 pub query_count: usize,
1150}
1151
1152#[derive(Debug, Clone, Serialize, Deserialize)]
1158pub struct MultiVectorSearchRequest {
1159 pub positive_vectors: Vec<Vec<f32>>,
1161 #[serde(skip_serializing_if = "Option::is_none")]
1163 pub positive_weights: Option<Vec<f32>>,
1164 #[serde(skip_serializing_if = "Option::is_none")]
1166 pub negative_vectors: Option<Vec<Vec<f32>>>,
1167 #[serde(skip_serializing_if = "Option::is_none")]
1169 pub negative_weights: Option<Vec<f32>>,
1170 #[serde(default = "default_multi_vector_top_k")]
1172 pub top_k: u32,
1173 #[serde(default)]
1175 pub distance_metric: DistanceMetric,
1176 #[serde(skip_serializing_if = "Option::is_none")]
1178 pub score_threshold: Option<f32>,
1179 #[serde(default)]
1181 pub enable_mmr: bool,
1182 #[serde(default = "default_mmr_lambda")]
1184 pub mmr_lambda: f32,
1185 #[serde(default = "default_true")]
1187 pub include_metadata: bool,
1188 #[serde(default)]
1190 pub include_vectors: bool,
1191 #[serde(skip_serializing_if = "Option::is_none")]
1193 pub filter: Option<serde_json::Value>,
1194 #[serde(default)]
1196 pub consistency: ReadConsistency,
1197 #[serde(skip_serializing_if = "Option::is_none")]
1199 pub staleness_config: Option<StalenessConfig>,
1200}
1201
1202fn default_multi_vector_top_k() -> u32 {
1203 10
1204}
1205
1206fn default_mmr_lambda() -> f32 {
1207 0.5
1208}
1209
1210impl MultiVectorSearchRequest {
1211 pub fn new(positive_vectors: Vec<Vec<f32>>) -> Self {
1213 Self {
1214 positive_vectors,
1215 positive_weights: None,
1216 negative_vectors: None,
1217 negative_weights: None,
1218 top_k: 10,
1219 distance_metric: DistanceMetric::default(),
1220 score_threshold: None,
1221 enable_mmr: false,
1222 mmr_lambda: 0.5,
1223 include_metadata: true,
1224 include_vectors: false,
1225 filter: None,
1226 consistency: ReadConsistency::default(),
1227 staleness_config: None,
1228 }
1229 }
1230
1231 pub fn with_top_k(mut self, top_k: u32) -> Self {
1233 self.top_k = top_k;
1234 self
1235 }
1236
1237 pub fn with_positive_weights(mut self, weights: Vec<f32>) -> Self {
1239 self.positive_weights = Some(weights);
1240 self
1241 }
1242
1243 pub fn with_negative_vectors(mut self, vectors: Vec<Vec<f32>>) -> Self {
1245 self.negative_vectors = Some(vectors);
1246 self
1247 }
1248
1249 pub fn with_negative_weights(mut self, weights: Vec<f32>) -> Self {
1251 self.negative_weights = Some(weights);
1252 self
1253 }
1254
1255 pub fn with_distance_metric(mut self, metric: DistanceMetric) -> Self {
1257 self.distance_metric = metric;
1258 self
1259 }
1260
1261 pub fn with_score_threshold(mut self, threshold: f32) -> Self {
1263 self.score_threshold = Some(threshold);
1264 self
1265 }
1266
1267 pub fn with_mmr(mut self, lambda: f32) -> Self {
1269 self.enable_mmr = true;
1270 self.mmr_lambda = lambda.clamp(0.0, 1.0);
1271 self
1272 }
1273
1274 pub fn include_metadata(mut self, include: bool) -> Self {
1276 self.include_metadata = include;
1277 self
1278 }
1279
1280 pub fn include_vectors(mut self, include: bool) -> Self {
1282 self.include_vectors = include;
1283 self
1284 }
1285
1286 pub fn with_filter(mut self, filter: serde_json::Value) -> Self {
1288 self.filter = Some(filter);
1289 self
1290 }
1291
1292 pub fn with_consistency(mut self, consistency: ReadConsistency) -> Self {
1294 self.consistency = consistency;
1295 self
1296 }
1297}
1298
1299#[derive(Debug, Clone, Serialize, Deserialize)]
1301pub struct MultiVectorSearchResult {
1302 pub id: String,
1304 pub score: f32,
1306 #[serde(skip_serializing_if = "Option::is_none")]
1308 pub mmr_score: Option<f32>,
1309 #[serde(skip_serializing_if = "Option::is_none")]
1311 pub original_rank: Option<usize>,
1312 #[serde(skip_serializing_if = "Option::is_none")]
1314 pub metadata: Option<HashMap<String, serde_json::Value>>,
1315 #[serde(skip_serializing_if = "Option::is_none")]
1317 pub vector: Option<Vec<f32>>,
1318}
1319
1320#[derive(Debug, Clone, Serialize, Deserialize)]
1322pub struct MultiVectorSearchResponse {
1323 pub results: Vec<MultiVectorSearchResult>,
1325 #[serde(skip_serializing_if = "Option::is_none")]
1327 pub computed_query_vector: Option<Vec<f32>>,
1328}
1329
1330#[derive(Debug, Clone, Serialize, Deserialize)]
1336#[serde(untagged)]
1337pub enum AggregateFunction {
1338 Count,
1340 Sum { field: String },
1342 Avg { field: String },
1344 Min { field: String },
1346 Max { field: String },
1348}
1349
1350#[derive(Debug, Clone, Serialize, Deserialize)]
1352pub struct AggregationRequest {
1353 pub aggregate_by: HashMap<String, serde_json::Value>,
1356 #[serde(default, skip_serializing_if = "Vec::is_empty")]
1359 pub group_by: Vec<String>,
1360 #[serde(skip_serializing_if = "Option::is_none")]
1362 pub filter: Option<serde_json::Value>,
1363 #[serde(default = "default_agg_limit")]
1365 pub limit: usize,
1366}
1367
1368fn default_agg_limit() -> usize {
1369 100
1370}
1371
1372impl AggregationRequest {
1373 pub fn new() -> Self {
1375 Self {
1376 aggregate_by: HashMap::new(),
1377 group_by: Vec::new(),
1378 filter: None,
1379 limit: 100,
1380 }
1381 }
1382
1383 pub fn with_count(mut self, name: impl Into<String>) -> Self {
1385 self.aggregate_by
1386 .insert(name.into(), serde_json::json!(["Count"]));
1387 self
1388 }
1389
1390 pub fn with_sum(mut self, name: impl Into<String>, field: impl Into<String>) -> Self {
1392 self.aggregate_by
1393 .insert(name.into(), serde_json::json!(["Sum", field.into()]));
1394 self
1395 }
1396
1397 pub fn with_avg(mut self, name: impl Into<String>, field: impl Into<String>) -> Self {
1399 self.aggregate_by
1400 .insert(name.into(), serde_json::json!(["Avg", field.into()]));
1401 self
1402 }
1403
1404 pub fn with_min(mut self, name: impl Into<String>, field: impl Into<String>) -> Self {
1406 self.aggregate_by
1407 .insert(name.into(), serde_json::json!(["Min", field.into()]));
1408 self
1409 }
1410
1411 pub fn with_max(mut self, name: impl Into<String>, field: impl Into<String>) -> Self {
1413 self.aggregate_by
1414 .insert(name.into(), serde_json::json!(["Max", field.into()]));
1415 self
1416 }
1417
1418 pub fn group_by(mut self, fields: Vec<String>) -> Self {
1420 self.group_by = fields;
1421 self
1422 }
1423
1424 pub fn with_group_by(mut self, field: impl Into<String>) -> Self {
1426 self.group_by.push(field.into());
1427 self
1428 }
1429
1430 pub fn with_filter(mut self, filter: serde_json::Value) -> Self {
1432 self.filter = Some(filter);
1433 self
1434 }
1435
1436 pub fn with_limit(mut self, limit: usize) -> Self {
1438 self.limit = limit;
1439 self
1440 }
1441}
1442
1443impl Default for AggregationRequest {
1444 fn default() -> Self {
1445 Self::new()
1446 }
1447}
1448
1449#[derive(Debug, Clone, Serialize, Deserialize)]
1451pub struct AggregationResponse {
1452 #[serde(skip_serializing_if = "Option::is_none")]
1454 pub aggregations: Option<HashMap<String, serde_json::Value>>,
1455 #[serde(skip_serializing_if = "Option::is_none")]
1457 pub aggregation_groups: Option<Vec<AggregationGroup>>,
1458}
1459
1460#[derive(Debug, Clone, Serialize, Deserialize)]
1462pub struct AggregationGroup {
1463 #[serde(flatten)]
1465 pub group_key: HashMap<String, serde_json::Value>,
1466 #[serde(flatten)]
1468 pub aggregations: HashMap<String, serde_json::Value>,
1469}
1470
1471#[derive(Debug, Clone, Copy, Default, Serialize, Deserialize, PartialEq, Eq)]
1477pub enum VectorSearchMethod {
1478 #[default]
1480 ANN,
1481 #[serde(rename = "kNN")]
1483 KNN,
1484}
1485
1486#[derive(Debug, Clone, Copy, Default, Serialize, Deserialize, PartialEq, Eq)]
1488#[serde(rename_all = "lowercase")]
1489pub enum SortDirection {
1490 Asc,
1492 #[default]
1494 Desc,
1495}
1496
1497#[derive(Debug, Clone, Serialize, Deserialize)]
1500#[serde(untagged)]
1501pub enum RankBy {
1502 VectorSearch {
1504 field: String,
1505 method: VectorSearchMethod,
1506 query_vector: Vec<f32>,
1507 },
1508 FullTextSearch {
1510 field: String,
1511 method: String, query: String,
1513 },
1514 AttributeOrder {
1516 field: String,
1517 direction: SortDirection,
1518 },
1519 Sum(Vec<RankBy>),
1521 Max(Vec<RankBy>),
1523 Product { weight: f32, ranking: Box<RankBy> },
1525}
1526
1527impl RankBy {
1528 pub fn vector_ann(field: impl Into<String>, query_vector: Vec<f32>) -> Self {
1530 RankBy::VectorSearch {
1531 field: field.into(),
1532 method: VectorSearchMethod::ANN,
1533 query_vector,
1534 }
1535 }
1536
1537 pub fn ann(query_vector: Vec<f32>) -> Self {
1539 Self::vector_ann("vector", query_vector)
1540 }
1541
1542 pub fn vector_knn(field: impl Into<String>, query_vector: Vec<f32>) -> Self {
1544 RankBy::VectorSearch {
1545 field: field.into(),
1546 method: VectorSearchMethod::KNN,
1547 query_vector,
1548 }
1549 }
1550
1551 pub fn knn(query_vector: Vec<f32>) -> Self {
1553 Self::vector_knn("vector", query_vector)
1554 }
1555
1556 pub fn bm25(field: impl Into<String>, query: impl Into<String>) -> Self {
1558 RankBy::FullTextSearch {
1559 field: field.into(),
1560 method: "BM25".to_string(),
1561 query: query.into(),
1562 }
1563 }
1564
1565 pub fn asc(field: impl Into<String>) -> Self {
1567 RankBy::AttributeOrder {
1568 field: field.into(),
1569 direction: SortDirection::Asc,
1570 }
1571 }
1572
1573 pub fn desc(field: impl Into<String>) -> Self {
1575 RankBy::AttributeOrder {
1576 field: field.into(),
1577 direction: SortDirection::Desc,
1578 }
1579 }
1580
1581 pub fn sum(rankings: Vec<RankBy>) -> Self {
1583 RankBy::Sum(rankings)
1584 }
1585
1586 pub fn max(rankings: Vec<RankBy>) -> Self {
1588 RankBy::Max(rankings)
1589 }
1590
1591 pub fn product(weight: f32, ranking: RankBy) -> Self {
1593 RankBy::Product {
1594 weight,
1595 ranking: Box::new(ranking),
1596 }
1597 }
1598}
1599
1600#[derive(Debug, Clone, Serialize, Deserialize)]
1618pub struct UnifiedQueryRequest {
1619 pub rank_by: serde_json::Value,
1621 #[serde(default = "default_unified_top_k")]
1623 pub top_k: usize,
1624 #[serde(skip_serializing_if = "Option::is_none")]
1626 pub filter: Option<serde_json::Value>,
1627 #[serde(default = "default_true")]
1629 pub include_metadata: bool,
1630 #[serde(default)]
1632 pub include_vectors: bool,
1633 #[serde(default)]
1635 pub distance_metric: DistanceMetric,
1636}
1637
1638fn default_unified_top_k() -> usize {
1639 10
1640}
1641
1642impl UnifiedQueryRequest {
1643 pub fn vector_search(query_vector: Vec<f32>, top_k: usize) -> Self {
1645 Self {
1646 rank_by: serde_json::json!(["ANN", query_vector]),
1647 top_k,
1648 filter: None,
1649 include_metadata: true,
1650 include_vectors: false,
1651 distance_metric: DistanceMetric::default(),
1652 }
1653 }
1654
1655 pub fn vector_knn_search(query_vector: Vec<f32>, top_k: usize) -> Self {
1657 Self {
1658 rank_by: serde_json::json!(["kNN", query_vector]),
1659 top_k,
1660 filter: None,
1661 include_metadata: true,
1662 include_vectors: false,
1663 distance_metric: DistanceMetric::default(),
1664 }
1665 }
1666
1667 pub fn fulltext_search(
1669 field: impl Into<String>,
1670 query: impl Into<String>,
1671 top_k: usize,
1672 ) -> Self {
1673 Self {
1674 rank_by: serde_json::json!([field.into(), "BM25", query.into()]),
1675 top_k,
1676 filter: None,
1677 include_metadata: true,
1678 include_vectors: false,
1679 distance_metric: DistanceMetric::default(),
1680 }
1681 }
1682
1683 pub fn attribute_order(
1685 field: impl Into<String>,
1686 direction: SortDirection,
1687 top_k: usize,
1688 ) -> Self {
1689 let dir = match direction {
1690 SortDirection::Asc => "asc",
1691 SortDirection::Desc => "desc",
1692 };
1693 Self {
1694 rank_by: serde_json::json!([field.into(), dir]),
1695 top_k,
1696 filter: None,
1697 include_metadata: true,
1698 include_vectors: false,
1699 distance_metric: DistanceMetric::default(),
1700 }
1701 }
1702
1703 pub fn with_rank_by(rank_by: serde_json::Value, top_k: usize) -> Self {
1705 Self {
1706 rank_by,
1707 top_k,
1708 filter: None,
1709 include_metadata: true,
1710 include_vectors: false,
1711 distance_metric: DistanceMetric::default(),
1712 }
1713 }
1714
1715 pub fn with_filter(mut self, filter: serde_json::Value) -> Self {
1717 self.filter = Some(filter);
1718 self
1719 }
1720
1721 pub fn include_metadata(mut self, include: bool) -> Self {
1723 self.include_metadata = include;
1724 self
1725 }
1726
1727 pub fn include_vectors(mut self, include: bool) -> Self {
1729 self.include_vectors = include;
1730 self
1731 }
1732
1733 pub fn with_distance_metric(mut self, metric: DistanceMetric) -> Self {
1735 self.distance_metric = metric;
1736 self
1737 }
1738
1739 pub fn with_top_k(mut self, top_k: usize) -> Self {
1741 self.top_k = top_k;
1742 self
1743 }
1744}
1745
1746#[derive(Debug, Clone, Serialize, Deserialize)]
1748pub struct UnifiedSearchResult {
1749 pub id: String,
1751 #[serde(rename = "$dist", skip_serializing_if = "Option::is_none")]
1754 pub dist: Option<f32>,
1755 #[serde(skip_serializing_if = "Option::is_none")]
1757 pub metadata: Option<serde_json::Value>,
1758 #[serde(skip_serializing_if = "Option::is_none")]
1760 pub vector: Option<Vec<f32>>,
1761}
1762
1763#[derive(Debug, Clone, Serialize, Deserialize)]
1765pub struct UnifiedQueryResponse {
1766 pub results: Vec<UnifiedSearchResult>,
1768 #[serde(skip_serializing_if = "Option::is_none")]
1770 pub next_cursor: Option<String>,
1771}
1772
1773fn default_explain_top_k() -> usize {
1778 10
1779}
1780
1781#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
1783#[serde(rename_all = "snake_case")]
1784#[derive(Default)]
1785pub enum ExplainQueryType {
1786 #[default]
1788 VectorSearch,
1789 FullTextSearch,
1791 HybridSearch,
1793 MultiVector,
1795 BatchQuery,
1797}
1798
1799#[derive(Debug, Clone, Serialize, Deserialize)]
1801pub struct QueryExplainRequest {
1802 #[serde(default)]
1804 pub query_type: ExplainQueryType,
1805 #[serde(skip_serializing_if = "Option::is_none")]
1807 pub vector: Option<Vec<f32>>,
1808 #[serde(default = "default_explain_top_k")]
1810 pub top_k: usize,
1811 #[serde(skip_serializing_if = "Option::is_none")]
1813 pub filter: Option<serde_json::Value>,
1814 #[serde(skip_serializing_if = "Option::is_none")]
1816 pub text_query: Option<String>,
1817 #[serde(default = "default_distance_metric")]
1819 pub distance_metric: String,
1820 #[serde(default)]
1822 pub execute: bool,
1823 #[serde(default)]
1825 pub verbose: bool,
1826}
1827
1828fn default_distance_metric() -> String {
1829 "cosine".to_string()
1830}
1831
1832impl QueryExplainRequest {
1833 pub fn vector_search(vector: Vec<f32>, top_k: usize) -> Self {
1835 Self {
1836 query_type: ExplainQueryType::VectorSearch,
1837 vector: Some(vector),
1838 top_k,
1839 filter: None,
1840 text_query: None,
1841 distance_metric: "cosine".to_string(),
1842 execute: false,
1843 verbose: false,
1844 }
1845 }
1846
1847 pub fn fulltext_search(text_query: impl Into<String>, top_k: usize) -> Self {
1849 Self {
1850 query_type: ExplainQueryType::FullTextSearch,
1851 vector: None,
1852 top_k,
1853 filter: None,
1854 text_query: Some(text_query.into()),
1855 distance_metric: "bm25".to_string(),
1856 execute: false,
1857 verbose: false,
1858 }
1859 }
1860
1861 pub fn hybrid_search(vector: Vec<f32>, text_query: impl Into<String>, top_k: usize) -> Self {
1863 Self {
1864 query_type: ExplainQueryType::HybridSearch,
1865 vector: Some(vector),
1866 top_k,
1867 filter: None,
1868 text_query: Some(text_query.into()),
1869 distance_metric: "hybrid".to_string(),
1870 execute: false,
1871 verbose: false,
1872 }
1873 }
1874
1875 pub fn with_filter(mut self, filter: serde_json::Value) -> Self {
1877 self.filter = Some(filter);
1878 self
1879 }
1880
1881 pub fn with_distance_metric(mut self, metric: impl Into<String>) -> Self {
1883 self.distance_metric = metric.into();
1884 self
1885 }
1886
1887 pub fn with_execution(mut self) -> Self {
1889 self.execute = true;
1890 self
1891 }
1892
1893 pub fn with_verbose(mut self) -> Self {
1895 self.verbose = true;
1896 self
1897 }
1898}
1899
1900#[derive(Debug, Clone, Serialize, Deserialize)]
1902pub struct ExecutionStage {
1903 pub name: String,
1905 pub description: String,
1907 pub order: u32,
1909 pub estimated_input: u64,
1911 pub estimated_output: u64,
1913 pub estimated_cost: f64,
1915 #[serde(default)]
1917 pub details: HashMap<String, serde_json::Value>,
1918}
1919
1920#[derive(Debug, Clone, Serialize, Deserialize)]
1922pub struct CostEstimate {
1923 pub total_cost: f64,
1925 pub estimated_time_ms: u64,
1927 pub estimated_memory_bytes: u64,
1929 pub estimated_io_ops: u64,
1931 #[serde(default)]
1933 pub cost_breakdown: HashMap<String, f64>,
1934 pub confidence: f64,
1936}
1937
1938#[derive(Debug, Clone, Serialize, Deserialize)]
1940pub struct ActualStats {
1941 pub execution_time_ms: u64,
1943 pub results_returned: usize,
1945 pub vectors_scanned: u64,
1947 pub vectors_after_filter: u64,
1949 pub index_lookups: u64,
1951 pub cache_hits: u64,
1953 pub cache_misses: u64,
1955 pub memory_used_bytes: u64,
1957}
1958
1959#[derive(Debug, Clone, Serialize, Deserialize)]
1961pub struct Recommendation {
1962 pub recommendation_type: String,
1964 pub priority: String,
1966 pub description: String,
1968 pub expected_improvement: String,
1970 pub implementation: String,
1972}
1973
1974#[derive(Debug, Clone, Serialize, Deserialize)]
1976pub struct IndexSelection {
1977 pub index_type: String,
1979 pub selection_reason: String,
1981 #[serde(default)]
1983 pub alternatives_considered: Vec<IndexAlternative>,
1984 #[serde(default)]
1986 pub index_config: HashMap<String, serde_json::Value>,
1987 pub index_stats: IndexStatistics,
1989}
1990
1991#[derive(Debug, Clone, Serialize, Deserialize)]
1993pub struct IndexAlternative {
1994 pub index_type: String,
1996 pub rejection_reason: String,
1998 pub estimated_cost: f64,
2000}
2001
2002#[derive(Debug, Clone, Serialize, Deserialize)]
2004pub struct IndexStatistics {
2005 pub vector_count: u64,
2007 pub dimension: usize,
2009 pub memory_bytes: u64,
2011 #[serde(skip_serializing_if = "Option::is_none")]
2013 pub build_time_ms: Option<u64>,
2014 #[serde(skip_serializing_if = "Option::is_none")]
2016 pub last_updated: Option<u64>,
2017}
2018
2019#[derive(Debug, Clone, Serialize, Deserialize)]
2021pub struct QueryParams {
2022 pub top_k: usize,
2024 pub has_filter: bool,
2026 pub filter_complexity: String,
2028 #[serde(skip_serializing_if = "Option::is_none")]
2030 pub vector_dimension: Option<usize>,
2031 pub distance_metric: String,
2033 #[serde(skip_serializing_if = "Option::is_none")]
2035 pub text_query_length: Option<usize>,
2036}
2037
2038#[derive(Debug, Clone, Serialize, Deserialize)]
2040pub struct QueryExplainResponse {
2041 pub query_type: ExplainQueryType,
2043 pub namespace: String,
2045 pub index_selection: IndexSelection,
2047 pub stages: Vec<ExecutionStage>,
2049 pub cost_estimate: CostEstimate,
2051 #[serde(skip_serializing_if = "Option::is_none")]
2053 pub actual_stats: Option<ActualStats>,
2054 #[serde(default)]
2056 pub recommendations: Vec<Recommendation>,
2057 pub summary: String,
2059 pub query_params: QueryParams,
2061}
2062
2063#[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq)]
2069#[serde(rename_all = "kebab-case")]
2070pub enum EmbeddingModel {
2071 #[default]
2073 BgeLarge,
2074 Minilm,
2076 BgeSmall,
2078 E5Small,
2080}
2081
2082#[derive(Debug, Clone, Serialize, Deserialize)]
2084pub struct TextDocument {
2085 pub id: String,
2087 pub text: String,
2089 #[serde(skip_serializing_if = "Option::is_none")]
2091 pub metadata: Option<HashMap<String, serde_json::Value>>,
2092 #[serde(skip_serializing_if = "Option::is_none")]
2094 pub ttl_seconds: Option<u64>,
2095}
2096
2097impl TextDocument {
2098 pub fn new(id: impl Into<String>, text: impl Into<String>) -> Self {
2100 Self {
2101 id: id.into(),
2102 text: text.into(),
2103 metadata: None,
2104 ttl_seconds: None,
2105 }
2106 }
2107
2108 pub fn with_metadata(mut self, metadata: HashMap<String, serde_json::Value>) -> Self {
2110 self.metadata = Some(metadata);
2111 self
2112 }
2113
2114 pub fn with_ttl(mut self, ttl_seconds: u64) -> Self {
2116 self.ttl_seconds = Some(ttl_seconds);
2117 self
2118 }
2119}
2120
2121#[derive(Debug, Clone, Serialize, Deserialize)]
2123pub struct UpsertTextRequest {
2124 pub documents: Vec<TextDocument>,
2126 #[serde(skip_serializing_if = "Option::is_none")]
2128 pub model: Option<EmbeddingModel>,
2129}
2130
2131impl UpsertTextRequest {
2132 pub fn new(documents: Vec<TextDocument>) -> Self {
2134 Self {
2135 documents,
2136 model: None,
2137 }
2138 }
2139
2140 pub fn with_model(mut self, model: EmbeddingModel) -> Self {
2142 self.model = Some(model);
2143 self
2144 }
2145}
2146
2147#[derive(Debug, Clone, Serialize, Deserialize)]
2149pub struct TextUpsertResponse {
2150 pub upserted_count: u64,
2152 pub tokens_processed: u64,
2154 pub model: EmbeddingModel,
2156 pub embedding_time_ms: u64,
2158}
2159
2160#[derive(Debug, Clone, Serialize, Deserialize)]
2162pub struct TextSearchResult {
2163 pub id: String,
2165 pub score: f32,
2167 #[serde(skip_serializing_if = "Option::is_none")]
2169 pub text: Option<String>,
2170 #[serde(skip_serializing_if = "Option::is_none")]
2172 pub metadata: Option<HashMap<String, serde_json::Value>>,
2173 #[serde(skip_serializing_if = "Option::is_none")]
2175 pub vector: Option<Vec<f32>>,
2176}
2177
2178#[derive(Debug, Clone, Serialize, Deserialize)]
2180pub struct QueryTextRequest {
2181 pub text: String,
2183 pub top_k: u32,
2185 #[serde(skip_serializing_if = "Option::is_none")]
2187 pub filter: Option<serde_json::Value>,
2188 pub include_text: bool,
2190 pub include_vectors: bool,
2192 #[serde(skip_serializing_if = "Option::is_none")]
2194 pub model: Option<EmbeddingModel>,
2195}
2196
2197impl QueryTextRequest {
2198 pub fn new(text: impl Into<String>, top_k: u32) -> Self {
2200 Self {
2201 text: text.into(),
2202 top_k,
2203 filter: None,
2204 include_text: true,
2205 include_vectors: false,
2206 model: None,
2207 }
2208 }
2209
2210 pub fn with_filter(mut self, filter: serde_json::Value) -> Self {
2212 self.filter = Some(filter);
2213 self
2214 }
2215
2216 pub fn include_text(mut self, include: bool) -> Self {
2218 self.include_text = include;
2219 self
2220 }
2221
2222 pub fn include_vectors(mut self, include: bool) -> Self {
2224 self.include_vectors = include;
2225 self
2226 }
2227
2228 pub fn with_model(mut self, model: EmbeddingModel) -> Self {
2230 self.model = Some(model);
2231 self
2232 }
2233}
2234
2235#[derive(Debug, Clone, Serialize, Deserialize)]
2237pub struct TextQueryResponse {
2238 pub results: Vec<TextSearchResult>,
2240 pub model: EmbeddingModel,
2242 pub embedding_time_ms: u64,
2244 pub search_time_ms: u64,
2246}
2247
2248#[derive(Debug, Clone, Serialize, Deserialize)]
2250pub struct BatchQueryTextRequest {
2251 pub queries: Vec<String>,
2253 pub top_k: u32,
2255 #[serde(skip_serializing_if = "Option::is_none")]
2257 pub filter: Option<serde_json::Value>,
2258 pub include_vectors: bool,
2260 #[serde(skip_serializing_if = "Option::is_none")]
2262 pub model: Option<EmbeddingModel>,
2263}
2264
2265impl BatchQueryTextRequest {
2266 pub fn new(queries: Vec<String>, top_k: u32) -> Self {
2268 Self {
2269 queries,
2270 top_k,
2271 filter: None,
2272 include_vectors: false,
2273 model: None,
2274 }
2275 }
2276}
2277
2278#[derive(Debug, Clone, Serialize, Deserialize)]
2280pub struct BatchQueryTextResponse {
2281 pub results: Vec<Vec<TextSearchResult>>,
2283 pub model: EmbeddingModel,
2285 pub embedding_time_ms: u64,
2287 pub search_time_ms: u64,
2289}
2290
2291#[derive(Debug, Clone, Serialize, Deserialize)]
2297pub struct FetchRequest {
2298 pub ids: Vec<String>,
2300 pub include_values: bool,
2302 pub include_metadata: bool,
2304}
2305
2306impl FetchRequest {
2307 pub fn new(ids: Vec<String>) -> Self {
2309 Self {
2310 ids,
2311 include_values: true,
2312 include_metadata: true,
2313 }
2314 }
2315}
2316
2317#[derive(Debug, Clone, Serialize, Deserialize)]
2319pub struct FetchResponse {
2320 pub vectors: Vec<Vector>,
2322}
2323
2324#[derive(Debug, Clone, Serialize, Deserialize, Default)]
2330pub struct CreateNamespaceRequest {
2331 #[serde(rename = "dimension", skip_serializing_if = "Option::is_none")]
2333 pub dimensions: Option<u32>,
2334 #[serde(skip_serializing_if = "Option::is_none")]
2336 pub index_type: Option<String>,
2337 #[serde(skip_serializing_if = "Option::is_none")]
2339 pub metadata: Option<HashMap<String, serde_json::Value>>,
2340}
2341
2342impl CreateNamespaceRequest {
2343 pub fn new() -> Self {
2345 Self::default()
2346 }
2347
2348 pub fn with_dimensions(mut self, dimensions: u32) -> Self {
2350 self.dimensions = Some(dimensions);
2351 self
2352 }
2353
2354 pub fn with_index_type(mut self, index_type: impl Into<String>) -> Self {
2356 self.index_type = Some(index_type.into());
2357 self
2358 }
2359}
2360
2361#[derive(Debug, Clone, Serialize, Deserialize)]
2366pub struct ConfigureNamespaceRequest {
2367 pub dimension: usize,
2369 #[serde(skip_serializing_if = "Option::is_none")]
2371 pub distance: Option<DistanceMetric>,
2372}
2373
2374impl ConfigureNamespaceRequest {
2375 pub fn new(dimension: usize) -> Self {
2377 Self {
2378 dimension,
2379 distance: None,
2380 }
2381 }
2382
2383 pub fn with_distance(mut self, distance: DistanceMetric) -> Self {
2385 self.distance = Some(distance);
2386 self
2387 }
2388}
2389
2390#[derive(Debug, Clone, Serialize, Deserialize)]
2392pub struct ConfigureNamespaceResponse {
2393 pub namespace: String,
2395 pub dimension: usize,
2397 pub distance: DistanceMetric,
2399 pub created: bool,
2401}
2402
2403#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
2409#[serde(rename_all = "snake_case")]
2410pub enum EdgeType {
2411 RelatedTo,
2413 SharesEntity,
2415 Precedes,
2417 #[default]
2419 LinkedBy,
2420}
2421
2422#[derive(Debug, Clone, Serialize, Deserialize)]
2424pub struct GraphEdge {
2425 pub id: String,
2427 pub source_id: String,
2429 pub target_id: String,
2431 pub edge_type: EdgeType,
2433 pub weight: f64,
2435 pub created_at: i64,
2437}
2438
2439#[derive(Debug, Clone, Serialize, Deserialize)]
2441pub struct GraphNode {
2442 pub memory_id: String,
2444 pub content_preview: String,
2446 pub importance: f64,
2448 pub depth: u32,
2450}
2451
2452#[derive(Debug, Clone, Serialize, Deserialize)]
2454pub struct MemoryGraph {
2455 pub root_id: String,
2457 pub depth: u32,
2459 pub nodes: Vec<GraphNode>,
2461 pub edges: Vec<GraphEdge>,
2463}
2464
2465#[derive(Debug, Clone, Serialize, Deserialize)]
2467pub struct GraphPath {
2468 pub source_id: String,
2470 pub target_id: String,
2472 pub path: Vec<String>,
2474 pub hops: i32,
2476 pub edges: Vec<GraphEdge>,
2478}
2479
2480#[derive(Debug, Clone, Serialize, Deserialize)]
2482pub struct GraphLinkRequest {
2483 pub target_id: String,
2485 pub edge_type: EdgeType,
2487}
2488
2489#[derive(Debug, Clone, Serialize, Deserialize)]
2491pub struct GraphLinkResponse {
2492 pub edge: GraphEdge,
2494}
2495
2496#[derive(Debug, Clone, Serialize, Deserialize)]
2498pub struct GraphExport {
2499 pub agent_id: String,
2501 pub format: String,
2503 pub data: String,
2505 pub node_count: u64,
2507 pub edge_count: u64,
2509}
2510
2511#[derive(Debug, Clone, Default)]
2513pub struct GraphOptions {
2514 pub depth: Option<u32>,
2516 pub types: Option<Vec<EdgeType>>,
2518}
2519
2520impl GraphOptions {
2521 pub fn new() -> Self {
2523 Self::default()
2524 }
2525
2526 pub fn depth(mut self, depth: u32) -> Self {
2528 self.depth = Some(depth);
2529 self
2530 }
2531
2532 pub fn types(mut self, types: Vec<EdgeType>) -> Self {
2534 self.types = Some(types);
2535 self
2536 }
2537}
2538
2539#[derive(Debug, Clone, Serialize, Deserialize, Default)]
2545pub struct NamespaceNerConfig {
2546 pub extract_entities: bool,
2547 #[serde(skip_serializing_if = "Option::is_none")]
2548 pub entity_types: Option<Vec<String>>,
2549}
2550
2551#[derive(Debug, Clone, Serialize, Deserialize)]
2553pub struct ExtractedEntity {
2554 pub entity_type: String,
2555 pub value: String,
2556 pub score: f64,
2557}
2558
2559#[derive(Debug, Clone, Serialize, Deserialize)]
2561pub struct EntityExtractionResponse {
2562 pub entities: Vec<ExtractedEntity>,
2563}
2564
2565#[derive(Debug, Clone, Serialize, Deserialize)]
2567pub struct MemoryEntitiesResponse {
2568 pub memory_id: String,
2569 pub entities: Vec<ExtractedEntity>,
2570}
2571
2572#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
2584#[serde(rename_all = "lowercase")]
2585pub enum FeedbackSignal {
2586 Upvote,
2587 Downvote,
2588 Flag,
2589 Positive,
2590 Negative,
2591}
2592
2593#[derive(Debug, Clone, Serialize, Deserialize)]
2595pub struct FeedbackHistoryEntry {
2596 pub signal: FeedbackSignal,
2597 pub timestamp: u64,
2599 pub old_importance: f32,
2600 pub new_importance: f32,
2601}
2602
2603#[derive(Debug, Clone, Serialize, Deserialize)]
2605pub struct MemoryFeedbackBody {
2606 pub agent_id: String,
2607 pub signal: FeedbackSignal,
2608}
2609
2610#[derive(Debug, Clone, Serialize, Deserialize)]
2612pub struct MemoryImportancePatch {
2613 pub agent_id: String,
2614 pub importance: f32,
2615}
2616
2617#[derive(Debug, Clone, Serialize, Deserialize)]
2619pub struct FeedbackResponse {
2620 pub memory_id: String,
2621 pub new_importance: f32,
2623 pub signal: FeedbackSignal,
2624}
2625
2626#[derive(Debug, Clone, Serialize, Deserialize)]
2628pub struct FeedbackHistoryResponse {
2629 pub memory_id: String,
2630 pub entries: Vec<FeedbackHistoryEntry>,
2632}
2633
2634#[derive(Debug, Clone, Serialize, Deserialize)]
2636pub struct AgentFeedbackSummary {
2637 pub agent_id: String,
2638 pub upvotes: u64,
2639 pub downvotes: u64,
2640 pub flags: u64,
2641 pub total_feedback: u64,
2642 pub health_score: f32,
2644}
2645
2646#[derive(Debug, Clone, Serialize, Deserialize)]
2648pub struct FeedbackHealthResponse {
2649 pub agent_id: String,
2650 pub health_score: f32,
2652 pub memory_count: usize,
2653 pub avg_importance: f32,
2654}
2655
2656#[derive(Debug, Clone, Serialize, Deserialize)]
2662pub struct OdeEntity {
2663 pub text: String,
2665 pub label: String,
2667 pub start: usize,
2669 pub end: usize,
2671 pub score: f32,
2673}
2674
2675#[derive(Debug, Clone, Serialize, Deserialize)]
2677pub struct ExtractEntitiesRequest {
2678 pub content: String,
2680 pub agent_id: String,
2682 #[serde(skip_serializing_if = "Option::is_none")]
2684 pub memory_id: Option<String>,
2685 #[serde(skip_serializing_if = "Option::is_none")]
2688 pub entity_types: Option<Vec<String>>,
2689}
2690
2691#[derive(Debug, Clone, Serialize, Deserialize)]
2693pub struct ExtractEntitiesResponse {
2694 pub entities: Vec<OdeEntity>,
2696 pub model: String,
2698 pub processing_time_ms: u64,
2700}
2701
2702#[derive(Debug, Clone, Serialize, Deserialize)]
2708pub struct KgQueryResponse {
2709 pub agent_id: String,
2711 pub node_count: usize,
2713 pub edge_count: usize,
2715 pub edges: Vec<GraphEdge>,
2717}
2718
2719#[derive(Debug, Clone, Serialize, Deserialize)]
2721pub struct KgPathResponse {
2722 pub agent_id: String,
2724 pub from_id: String,
2726 pub to_id: String,
2728 pub hop_count: usize,
2730 pub path: Vec<String>,
2732}
2733
2734#[derive(Debug, Clone, Serialize, Deserialize)]
2736pub struct KgExportResponse {
2737 pub agent_id: String,
2739 pub format: String,
2741 pub node_count: usize,
2743 pub edge_count: usize,
2745 pub edges: Vec<GraphEdge>,
2747}
2748
2749#[derive(Debug, Clone, Serialize, Deserialize)]
2761pub struct MemoryPolicy {
2762 #[serde(skip_serializing_if = "Option::is_none")]
2765 pub working_ttl_seconds: Option<u64>,
2766 #[serde(skip_serializing_if = "Option::is_none")]
2768 pub episodic_ttl_seconds: Option<u64>,
2769 #[serde(skip_serializing_if = "Option::is_none")]
2771 pub semantic_ttl_seconds: Option<u64>,
2772 #[serde(skip_serializing_if = "Option::is_none")]
2774 pub procedural_ttl_seconds: Option<u64>,
2775
2776 #[serde(skip_serializing_if = "Option::is_none")]
2779 pub working_decay: Option<String>,
2780 #[serde(skip_serializing_if = "Option::is_none")]
2782 pub episodic_decay: Option<String>,
2783 #[serde(skip_serializing_if = "Option::is_none")]
2785 pub semantic_decay: Option<String>,
2786 #[serde(skip_serializing_if = "Option::is_none")]
2788 pub procedural_decay: Option<String>,
2789
2790 #[serde(skip_serializing_if = "Option::is_none")]
2794 pub spaced_repetition_factor: Option<f64>,
2795 #[serde(skip_serializing_if = "Option::is_none")]
2797 pub spaced_repetition_base_interval_seconds: Option<u64>,
2798
2799 #[serde(skip_serializing_if = "Option::is_none")]
2804 pub consolidation_enabled: Option<bool>,
2805 #[serde(skip_serializing_if = "Option::is_none")]
2808 pub consolidation_threshold: Option<f32>,
2809 #[serde(skip_serializing_if = "Option::is_none")]
2811 pub consolidation_interval_hours: Option<u32>,
2812 #[serde(skip_serializing_if = "Option::is_none")]
2817 pub consolidated_count: Option<u64>,
2818
2819 #[serde(skip_serializing_if = "Option::is_none")]
2822 pub rate_limit_enabled: Option<bool>,
2823 #[serde(skip_serializing_if = "Option::is_none")]
2825 pub rate_limit_stores_per_minute: Option<u32>,
2826 #[serde(skip_serializing_if = "Option::is_none")]
2828 pub rate_limit_recalls_per_minute: Option<u32>,
2829
2830 #[serde(skip_serializing_if = "Option::is_none")]
2837 pub dedup_on_store: Option<bool>,
2838 #[serde(skip_serializing_if = "Option::is_none")]
2843 pub dedup_threshold: Option<f32>,
2844}
2845
2846impl Default for MemoryPolicy {
2847 fn default() -> Self {
2848 Self {
2849 working_ttl_seconds: Some(14_400),
2850 episodic_ttl_seconds: Some(2_592_000),
2851 semantic_ttl_seconds: Some(31_536_000),
2852 procedural_ttl_seconds: Some(63_072_000),
2853 working_decay: Some("exponential".to_string()),
2854 episodic_decay: Some("power_law".to_string()),
2855 semantic_decay: Some("logarithmic".to_string()),
2856 procedural_decay: Some("flat".to_string()),
2857 spaced_repetition_factor: Some(1.0),
2858 spaced_repetition_base_interval_seconds: Some(86_400),
2859 consolidation_enabled: Some(false),
2860 consolidation_threshold: Some(0.92),
2861 consolidation_interval_hours: Some(24),
2862 consolidated_count: Some(0),
2863 rate_limit_enabled: Some(false),
2864 rate_limit_stores_per_minute: None,
2865 rate_limit_recalls_per_minute: None,
2866 dedup_on_store: Some(false),
2867 dedup_threshold: Some(0.92),
2868 }
2869 }
2870}
2871
2872#[derive(Debug, Clone, Serialize, Deserialize)]
2878pub struct BulkUpdateRequest {
2879 pub filter: serde_json::Value,
2880 pub update: serde_json::Value,
2881}
2882
2883#[derive(Debug, Clone, Serialize, Deserialize)]
2885pub struct BulkUpdateResponse {
2886 pub updated: u64,
2887 pub failed: u64,
2888 pub errors: Vec<String>,
2889}
2890
2891#[derive(Debug, Clone, Serialize, Deserialize)]
2893pub struct BulkDeleteRequest {
2894 pub filter: serde_json::Value,
2895}
2896
2897#[derive(Debug, Clone, Serialize, Deserialize)]
2899pub struct BulkDeleteResponse {
2900 pub deleted: u64,
2901 pub failed: u64,
2902 pub errors: Vec<String>,
2903}
2904
2905#[derive(Debug, Clone, Serialize, Deserialize)]
2907pub struct CountVectorsRequest {
2908 #[serde(skip_serializing_if = "Option::is_none")]
2909 pub filter: Option<serde_json::Value>,
2910}
2911
2912#[derive(Debug, Clone, Serialize, Deserialize)]
2914pub struct CountVectorsResponse {
2915 pub count: u64,
2916 pub namespace: String,
2917}
2918
2919#[derive(Debug, Clone, Serialize, Deserialize)]
2921pub struct AgentConsolidateResponse {
2922 pub agent_id: String,
2923 pub memories_scanned: u64,
2924 pub clusters_found: u64,
2925 pub memories_deprecated: u64,
2926 pub anchor_ids: Vec<String>,
2927 pub deprecated_ids: Vec<String>,
2928 #[serde(skip_serializing_if = "Option::is_none")]
2929 pub skipped: Option<bool>,
2930 #[serde(skip_serializing_if = "Option::is_none")]
2931 pub reason: Option<String>,
2932}
2933
2934#[derive(Debug, Clone, Serialize, Deserialize)]
2936pub struct AgentConsolidationLogEntry {
2937 pub timestamp: u64,
2938 pub clusters_found: u64,
2939 pub memories_deprecated: u64,
2940 pub anchor_ids: Vec<String>,
2941 pub deprecated_ids: Vec<String>,
2942}
2943
2944#[derive(Debug, Clone, Default, Serialize, Deserialize)]
2946pub struct ConsolidationConfigPatch {
2947 #[serde(skip_serializing_if = "Option::is_none")]
2948 pub enabled: Option<bool>,
2949 #[serde(skip_serializing_if = "Option::is_none")]
2950 pub epsilon: Option<f64>,
2951 #[serde(skip_serializing_if = "Option::is_none")]
2952 pub min_samples: Option<u32>,
2953 #[serde(skip_serializing_if = "Option::is_none")]
2954 pub soft_deprecation_days: Option<u32>,
2955}
2956
2957#[derive(Debug, Clone, Serialize, Deserialize)]
2959pub struct AgentConsolidationConfig {
2960 pub enabled: bool,
2961 pub epsilon: f64,
2962 pub min_samples: u32,
2963 pub soft_deprecation_days: u32,
2964}
2965
2966#[derive(Debug, Clone, Serialize, Deserialize)]
2968pub struct NamespaceEntityConfig {
2969 pub namespace: String,
2970 pub extract_entities: bool,
2971 pub entity_types: Vec<String>,
2972}
2973
2974#[derive(Debug, Clone, Serialize, Deserialize)]
2976pub struct NamespaceExtractorConfig {
2977 pub provider: String,
2978 #[serde(skip_serializing_if = "Option::is_none")]
2979 pub model: Option<String>,
2980 #[serde(skip_serializing_if = "Option::is_none")]
2981 pub base_url: Option<String>,
2982}
2983
2984#[derive(Debug, Clone, Serialize, Deserialize)]
2990pub struct NodeReplicationLag {
2991 pub node_id: String,
2992 pub lag_ms: u64,
2993 pub status: String,
2994}
2995
2996#[derive(Debug, Clone, Serialize, Deserialize)]
2998pub struct ReplicationStatus {
2999 pub replication_factor: u32,
3000 pub healthy_replicas: u32,
3001 pub total_nodes: u32,
3002 #[serde(default)]
3003 pub replication_lag: Vec<NodeReplicationLag>,
3004}
3005
3006#[derive(Debug, Clone, Serialize, Deserialize)]
3008pub struct ShardInfo {
3009 pub shard_id: String,
3010 pub namespace: String,
3011 pub primary_node: String,
3012 #[serde(default)]
3013 pub replica_nodes: Vec<String>,
3014 pub state: String,
3015 pub vector_count: u64,
3016 pub size_bytes: u64,
3017}
3018
3019#[derive(Debug, Clone, Serialize, Deserialize)]
3021pub struct ShardListResponse {
3022 pub shards: Vec<ShardInfo>,
3023 pub total: u32,
3024}
3025
3026#[derive(Debug, Clone, Serialize, Deserialize, Default)]
3028pub struct ShardRebalanceRequest {
3029 #[serde(default, skip_serializing_if = "Vec::is_empty")]
3030 pub shard_ids: Vec<String>,
3031 #[serde(default)]
3032 pub dry_run: bool,
3033}
3034
3035#[derive(Debug, Clone, Serialize, Deserialize)]
3037pub struct ShardMove {
3038 pub shard_id: String,
3039 pub from_node: String,
3040 pub to_node: String,
3041}
3042
3043#[derive(Debug, Clone, Serialize, Deserialize)]
3045pub struct ShardRebalanceResponse {
3046 pub initiated: bool,
3047 pub operation_id: String,
3048 pub shards_affected: u32,
3049 #[serde(skip_serializing_if = "Option::is_none")]
3050 pub estimated_seconds: Option<u64>,
3051 #[serde(default)]
3052 pub planned_moves: Vec<ShardMove>,
3053}
3054
3055#[derive(Debug, Clone, Serialize, Deserialize)]
3057pub struct MaintenanceStatus {
3058 pub enabled: bool,
3059 #[serde(skip_serializing_if = "Option::is_none")]
3060 pub reason: Option<String>,
3061 #[serde(skip_serializing_if = "Option::is_none")]
3062 pub enabled_at: Option<u64>,
3063 #[serde(skip_serializing_if = "Option::is_none")]
3064 pub scheduled_end: Option<u64>,
3065 #[serde(default)]
3066 pub nodes_in_maintenance: Vec<String>,
3067 pub rejecting_requests: bool,
3068}
3069
3070#[derive(Debug, Clone, Serialize, Deserialize)]
3072pub struct EnableMaintenanceRequest {
3073 pub reason: String,
3074 #[serde(default, skip_serializing_if = "Vec::is_empty")]
3075 pub node_ids: Vec<String>,
3076 #[serde(default)]
3077 pub reject_requests: bool,
3078 #[serde(skip_serializing_if = "Option::is_none")]
3079 pub duration_minutes: Option<u32>,
3080}
3081
3082#[derive(Debug, Clone, Serialize, Deserialize, Default)]
3084pub struct DisableMaintenanceRequest {
3085 #[serde(skip_serializing_if = "Option::is_none")]
3086 pub force: Option<bool>,
3087}
3088
3089#[derive(Debug, Clone, Serialize, Deserialize, Default)]
3091pub struct QuotaConfig {
3092 #[serde(skip_serializing_if = "Option::is_none")]
3093 pub max_vectors: Option<u64>,
3094 #[serde(skip_serializing_if = "Option::is_none")]
3095 pub max_storage_bytes: Option<u64>,
3096 #[serde(skip_serializing_if = "Option::is_none")]
3097 pub max_dimensions: Option<usize>,
3098 #[serde(skip_serializing_if = "Option::is_none")]
3099 pub max_metadata_bytes: Option<usize>,
3100 #[serde(default)]
3101 pub enforcement: String,
3102}
3103
3104#[derive(Debug, Clone, Serialize, Deserialize, Default)]
3106pub struct QuotaUsage {
3107 pub vector_count: u64,
3108 pub storage_bytes: u64,
3109 #[serde(skip_serializing_if = "Option::is_none")]
3110 pub avg_dimensions: Option<usize>,
3111 #[serde(skip_serializing_if = "Option::is_none")]
3112 pub avg_metadata_bytes: Option<usize>,
3113 pub last_updated: u64,
3114}
3115
3116#[derive(Debug, Clone, Serialize, Deserialize)]
3118pub struct QuotaStatus {
3119 pub namespace: String,
3120 pub config: QuotaConfig,
3121 pub usage: QuotaUsage,
3122 #[serde(skip_serializing_if = "Option::is_none")]
3123 pub vector_usage_percent: Option<f32>,
3124 #[serde(skip_serializing_if = "Option::is_none")]
3125 pub storage_usage_percent: Option<f32>,
3126 pub is_exceeded: bool,
3127 #[serde(default, skip_serializing_if = "Vec::is_empty")]
3128 pub exceeded_quotas: Vec<String>,
3129}
3130
3131#[derive(Debug, Clone, Serialize, Deserialize)]
3133pub struct QuotaListResponse {
3134 pub quotas: Vec<QuotaStatus>,
3135 pub total: u64,
3136 #[serde(skip_serializing_if = "Option::is_none")]
3137 pub default_config: Option<QuotaConfig>,
3138}
3139
3140#[derive(Debug, Clone, Serialize, Deserialize)]
3142pub struct DefaultQuotaResponse {
3143 pub config: Option<QuotaConfig>,
3144}
3145
3146#[derive(Debug, Clone, Serialize, Deserialize, Default)]
3148pub struct SetDefaultQuotaRequest {
3149 pub config: Option<QuotaConfig>,
3150}
3151
3152#[derive(Debug, Clone, Serialize, Deserialize)]
3154pub struct SetQuotaRequest {
3155 pub config: QuotaConfig,
3156}
3157
3158#[derive(Debug, Clone, Serialize, Deserialize)]
3160pub struct SetQuotaResponse {
3161 pub success: bool,
3162 pub namespace: String,
3163 pub config: QuotaConfig,
3164 pub message: String,
3165}
3166
3167#[derive(Debug, Clone, Serialize, Deserialize)]
3169pub struct QuotaCheckRequest {
3170 pub vector_ids: Vec<String>,
3171 #[serde(skip_serializing_if = "Option::is_none")]
3172 pub dimensions: Option<usize>,
3173 #[serde(skip_serializing_if = "Option::is_none")]
3174 pub metadata_bytes: Option<usize>,
3175}
3176
3177#[derive(Debug, Clone, Serialize, Deserialize)]
3179pub struct QuotaCheckResult {
3180 pub allowed: bool,
3181 #[serde(skip_serializing_if = "Option::is_none")]
3182 pub reason: Option<String>,
3183 pub usage: QuotaUsage,
3184 #[serde(skip_serializing_if = "Option::is_none")]
3185 pub exceeded_quota: Option<String>,
3186}
3187
3188#[derive(Debug, Clone, Serialize, Deserialize)]
3190pub struct AdminBackupInfo {
3191 pub backup_id: String,
3192 pub name: String,
3193 pub backup_type: String,
3194 pub status: String,
3195 #[serde(default)]
3196 pub namespaces: Vec<String>,
3197 pub vector_count: u64,
3198 pub size_bytes: u64,
3199 pub created_at: u64,
3200 #[serde(skip_serializing_if = "Option::is_none")]
3201 pub completed_at: Option<u64>,
3202 #[serde(skip_serializing_if = "Option::is_none")]
3203 pub duration_seconds: Option<u64>,
3204 #[serde(skip_serializing_if = "Option::is_none")]
3205 pub storage_path: Option<String>,
3206 #[serde(skip_serializing_if = "Option::is_none")]
3207 pub error: Option<String>,
3208 pub encrypted: bool,
3209 #[serde(skip_serializing_if = "Option::is_none")]
3210 pub compression: Option<String>,
3211}
3212
3213#[derive(Debug, Clone, Serialize, Deserialize)]
3215pub struct BackupListResponse {
3216 pub backups: Vec<AdminBackupInfo>,
3217 pub total: u64,
3218}
3219
3220#[derive(Debug, Clone, Serialize, Deserialize)]
3222pub struct CreateBackupRequest {
3223 pub name: String,
3224 #[serde(skip_serializing_if = "Option::is_none")]
3225 pub backup_type: Option<String>,
3226 #[serde(skip_serializing_if = "Option::is_none")]
3227 pub namespaces: Option<Vec<String>>,
3228 #[serde(skip_serializing_if = "Option::is_none")]
3229 pub encrypt: Option<bool>,
3230 #[serde(skip_serializing_if = "Option::is_none")]
3231 pub compression: Option<String>,
3232}
3233
3234#[derive(Debug, Clone, Serialize, Deserialize)]
3236pub struct CreateBackupResponse {
3237 pub backup: AdminBackupInfo,
3238 #[serde(skip_serializing_if = "Option::is_none")]
3239 pub estimated_completion: Option<u64>,
3240}
3241
3242#[derive(Debug, Clone, Serialize, Deserialize)]
3244pub struct RestoreBackupRequest {
3245 pub backup_id: String,
3246 #[serde(skip_serializing_if = "Option::is_none")]
3247 pub target_namespaces: Option<Vec<String>>,
3248 #[serde(skip_serializing_if = "Option::is_none")]
3249 pub overwrite: Option<bool>,
3250 #[serde(skip_serializing_if = "Option::is_none")]
3251 pub point_in_time: Option<u64>,
3252}
3253
3254#[derive(Debug, Clone, Serialize, Deserialize)]
3256pub struct RestoreBackupResponse {
3257 pub restore_id: String,
3258 pub status: String,
3259 pub backup_id: String,
3260 #[serde(default)]
3261 pub namespaces: Vec<String>,
3262 pub started_at: u64,
3263 #[serde(skip_serializing_if = "Option::is_none")]
3264 pub estimated_completion: Option<u64>,
3265 #[serde(skip_serializing_if = "Option::is_none")]
3266 pub progress_percent: Option<u8>,
3267 #[serde(skip_serializing_if = "Option::is_none")]
3268 pub vectors_restored: Option<u64>,
3269 #[serde(skip_serializing_if = "Option::is_none")]
3270 pub completed_at: Option<u64>,
3271 #[serde(skip_serializing_if = "Option::is_none")]
3272 pub duration_seconds: Option<u64>,
3273 #[serde(skip_serializing_if = "Option::is_none")]
3274 pub error: Option<String>,
3275}
3276
3277#[derive(Debug, Clone, Serialize, Deserialize)]
3279pub struct BackupSchedule {
3280 pub enabled: bool,
3281 #[serde(skip_serializing_if = "Option::is_none")]
3282 pub cron: Option<String>,
3283 pub backup_type: String,
3284 pub retention_days: u32,
3285 pub max_backups: u32,
3286 #[serde(default)]
3287 pub namespaces: Vec<String>,
3288 pub encrypt: bool,
3289 #[serde(skip_serializing_if = "Option::is_none")]
3290 pub compression: Option<String>,
3291 #[serde(skip_serializing_if = "Option::is_none")]
3292 pub last_backup_at: Option<u64>,
3293 #[serde(skip_serializing_if = "Option::is_none")]
3294 pub next_backup_at: Option<u64>,
3295}
3296
3297#[derive(Debug, Clone, Serialize, Deserialize, Default)]
3299pub struct UpdateBackupScheduleRequest {
3300 #[serde(skip_serializing_if = "Option::is_none")]
3301 pub enabled: Option<bool>,
3302 #[serde(skip_serializing_if = "Option::is_none")]
3303 pub cron: Option<String>,
3304 #[serde(skip_serializing_if = "Option::is_none")]
3305 pub backup_type: Option<String>,
3306 #[serde(skip_serializing_if = "Option::is_none")]
3307 pub retention_days: Option<u32>,
3308 #[serde(skip_serializing_if = "Option::is_none")]
3309 pub max_backups: Option<u32>,
3310 #[serde(skip_serializing_if = "Option::is_none")]
3311 pub namespaces: Option<Vec<String>>,
3312 #[serde(skip_serializing_if = "Option::is_none")]
3313 pub encrypt: Option<bool>,
3314 #[serde(skip_serializing_if = "Option::is_none")]
3315 pub compression: Option<String>,
3316}
3317
3318fn default_route_top_k() -> usize {
3323 3
3324}
3325
3326fn default_route_min_similarity() -> f32 {
3327 0.3
3328}
3329
3330#[derive(Debug, Clone, Serialize, Deserialize)]
3332pub struct RouteRequest {
3333 pub query: String,
3335 #[serde(default = "default_route_top_k")]
3337 pub top_k: usize,
3338 #[serde(default = "default_route_min_similarity")]
3340 pub min_similarity: f32,
3341 #[serde(skip_serializing_if = "Option::is_none")]
3343 pub model: Option<String>,
3344}
3345
3346#[derive(Debug, Clone, Serialize, Deserialize)]
3348pub struct RouteMatch {
3349 pub namespace: String,
3351 pub similarity: f64,
3353 #[serde(skip_serializing_if = "Option::is_none")]
3355 pub description: Option<String>,
3356}
3357
3358#[derive(Debug, Clone, Serialize, Deserialize)]
3360pub struct RouteResponse {
3361 pub routes: Vec<RouteMatch>,
3363 pub model: String,
3365 pub embedding_time_ms: u64,
3367}
3368
3369#[derive(Debug, Clone, Serialize, Deserialize)]
3375pub struct ImportJobStatus {
3376 pub job_id: String,
3378 pub status: String,
3380 pub format: String,
3382 pub total: usize,
3384 pub imported: usize,
3386 pub skipped: usize,
3388 #[serde(default)]
3390 pub errors: Vec<String>,
3391 pub started_at: u64,
3393 #[serde(skip_serializing_if = "Option::is_none")]
3395 pub finished_at: Option<u64>,
3396}
3397
3398#[derive(Debug, Clone, Serialize, Deserialize)]
3404pub struct TierInfo {
3405 pub name: String,
3407 pub tier_type: String,
3409 pub technology: String,
3411 pub description: String,
3413 pub target_latency: String,
3415 #[serde(skip_serializing_if = "Option::is_none")]
3417 pub capacity: Option<String>,
3418 pub status: String,
3420 pub current_count: u64,
3422 pub hit_count: u64,
3424 pub hit_rate: f64,
3426}
3427
3428#[derive(Debug, Clone, Serialize, Deserialize)]
3430pub struct TierConfig {
3431 pub hot_tier_capacity: usize,
3433 pub hot_to_warm_threshold_secs: u64,
3435 pub warm_to_cold_threshold_secs: u64,
3437 pub auto_tier_enabled: bool,
3439 pub tier_check_interval_secs: u64,
3441}
3442
3443#[derive(Debug, Clone, Serialize, Deserialize)]
3445pub struct TierActivity {
3446 pub promotions: u64,
3448 pub demotions: u64,
3450 pub cache_hit_rate: f64,
3452 pub storage_backend: String,
3454 pub promotions_to_hot: u64,
3456 pub demotions_to_warm: u64,
3458 pub demotions_to_cold: u64,
3460}
3461
3462#[derive(Debug, Clone, Serialize, Deserialize)]
3464pub struct StorageTierOverview {
3465 pub tiers_enabled: bool,
3467 pub architecture: Vec<TierInfo>,
3469 pub config: TierConfig,
3471 pub activity: TierActivity,
3473}
3474
3475#[derive(Debug, Clone, Serialize, Deserialize)]
3481pub struct MemoryTypeStatsResponse {
3482 pub total: u64,
3484 pub working: u64,
3486 pub episodic: u64,
3488 pub semantic: u64,
3490 pub procedural: u64,
3492 pub agent_namespaces: u64,
3494}
3495
3496fn default_target_dimension() -> usize {
3501 1024
3502}
3503
3504#[derive(Debug, Clone, Serialize, Deserialize)]
3506pub struct MigrateNamespaceDimensionsRequest {
3507 #[serde(default)]
3509 pub namespaces: Vec<String>,
3510 #[serde(default = "default_target_dimension")]
3512 pub target_dimension: usize,
3513}
3514
3515#[derive(Debug, Clone, Serialize, Deserialize)]
3517pub struct NamespaceMigrationResult {
3518 pub namespace: String,
3520 pub original_dimension: usize,
3522 pub vectors_migrated: usize,
3524 pub vectors_skipped: usize,
3526 pub status: String,
3528 #[serde(skip_serializing_if = "Option::is_none")]
3530 pub error: Option<String>,
3531}
3532
3533#[derive(Debug, Clone, Serialize, Deserialize)]
3535pub struct MigrateDimensionsResponse {
3536 pub migrated: usize,
3538 pub failed: usize,
3540 pub already_current: usize,
3542 pub results: Vec<NamespaceMigrationResult>,
3544}
3545
3546#[derive(Debug, Clone, Default, Serialize, Deserialize)]
3548pub struct DrainReembedRequest {
3549 #[serde(skip_serializing_if = "Option::is_none")]
3551 pub timeout_secs: Option<u64>,
3552 #[serde(skip_serializing_if = "Option::is_none")]
3554 pub batch_size: Option<usize>,
3555 #[serde(skip_serializing_if = "Option::is_none")]
3557 pub min_importance: Option<f32>,
3558}
3559
3560#[derive(Debug, Clone, Serialize, Deserialize)]
3565pub struct DrainReembedResponse {
3566 pub processed: usize,
3568 pub remaining: usize,
3570 pub elapsed_ms: u128,
3572 pub cycles: usize,
3574 pub timed_out: bool,
3576}